form-father 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## 0.7.0 - 2026-04-27
6
+
7
+ ### Added
8
+
9
+ - Added `docs/api/README.md` with a compact public API, options, methods, validators, adapters, and helpers reference.
10
+ - Added `docs/demo/README.md` with manual demo scenarios and demo coverage notes.
11
+ - Added a Public API demo panel covering `setValues()`, `validateField()`, `setErrors()`, `getValues()`, and
12
+ `clearErrors()`.
13
+ - Added `npm run docs:check` to verify documentation files, version references, package README sync, and demo coverage.
14
+
15
+ ### Changed
16
+
17
+ - `npm run release:check` now includes documentation checks before build and package smoke checks.
18
+ - Package smoke checks now verify the broader public export surface and package documentation files.
19
+
20
+ ### Tests
21
+
22
+ - Release gate remains at 122 tests plus docs/package smoke checks.
23
+
5
24
  ## 0.6.0 - 2026-04-27
6
25
 
7
26
  ### Added
package/README.md CHANGED
@@ -410,9 +410,12 @@ registerSchemaValidator('company-email', z.string().email(), 'Введите к
410
410
 
411
411
  ## Демо и рецепты
412
412
 
413
- - `demos/index.html` — статическое демо login/callback/search/upload после `npm run build`.
413
+ - `demos/index.html` — статическое демо login/callback/search/upload/public API после `npm run build`.
414
414
  - `npm run demos` — сборка и запуск Vite-сервера для демо.
415
+ - `docs/api/README.md` — компактный справочник публичного API, опций, методов и экспортов.
416
+ - `docs/demo/README.md` — сценарии ручной проверки демо и описание demo forms.
415
417
  - `docs/recipes/README.md` — короткие рецепты по API, data-атрибутам, adapters и server errors.
418
+ - `CHANGELOG.md` — история релизов и baseline покрытия.
416
419
 
417
420
  ## Сборка и разработка
418
421
 
@@ -420,6 +423,7 @@ registerSchemaValidator('company-email', z.string().email(), 'Введите к
420
423
 
421
424
  - **npm run build**: Сборка проекта.
422
425
  - **npm run watch**: Сборка в режиме наблюдения.
426
+ - **npm run docs:check**: Проверка версии, ссылок документации, demo-файлов и package README.
423
427
  - **npm run demos**: Запуск демо-версии с использованием Vite.
424
428
 
425
429
  ## Вклад
package/demos/index.html CHANGED
@@ -145,6 +145,43 @@
145
145
  <button type="submit">Отправить</button>
146
146
  </form>
147
147
  </section>
148
+
149
+ <section class="demo-panel demo-panel--wide">
150
+ <div class="panel-title">
151
+ <p class="eyebrow">Public API</p>
152
+ <h2>Programmatic control</h2>
153
+ </div>
154
+ <form data-form-father action="/demo/api" method="post" data-demo="api" novalidate>
155
+ <div data-form-father-summary hidden></div>
156
+
157
+ <label class="field">
158
+ <span>Имя</span>
159
+ <input class="input" name="name" data-validate="required" data-error-required="Укажите имя" />
160
+ </label>
161
+
162
+ <label class="field">
163
+ <span>Email</span>
164
+ <input class="input" name="email" type="email" data-validate="required|email" />
165
+ </label>
166
+
167
+ <label class="field">
168
+ <span>Тариф</span>
169
+ <select class="input" name="plan">
170
+ <option value="starter">Starter</option>
171
+ <option value="team">Team</option>
172
+ <option value="enterprise">Enterprise</option>
173
+ </select>
174
+ </label>
175
+
176
+ <div class="demo-actions" aria-label="Public API actions">
177
+ <button type="button" data-api-action="fill">setValues()</button>
178
+ <button type="button" data-api-action="validate-email">validateField()</button>
179
+ <button type="button" data-api-action="server-errors">setErrors()</button>
180
+ <button type="button" data-api-action="values">getValues()</button>
181
+ <button type="button" data-api-action="clear">clearErrors()</button>
182
+ </div>
183
+ </form>
184
+ </section>
148
185
  </main>
149
186
 
150
187
  <section class="demo-output">
package/demos/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const api = window.FormFather || {};
2
2
  const Form = api.default || api.Form || api;
3
- const { createLengthValidator, registerValidator, sameAsField } = api;
3
+ const { FORM_ERROR_FIELD, createLengthValidator, registerValidator, sameAsField } = api;
4
4
  const output = document.querySelector('#demo-output');
5
5
 
6
6
  function writeOutput(title, payload) {
@@ -54,6 +54,14 @@ window.fetch = async (url, options = {}) => {
54
54
  });
55
55
  }
56
56
 
57
+ if (requestUrl.startsWith('/demo/api')) {
58
+ return json({
59
+ success: true,
60
+ message: 'Programmatic API form accepted',
61
+ method,
62
+ });
63
+ }
64
+
57
65
  return json({ success: false, error: true, 'error-msg': `No demo route for ${requestUrl}` }, 404);
58
66
  };
59
67
 
@@ -68,7 +76,7 @@ registerValidator(
68
76
  { override: true },
69
77
  );
70
78
 
71
- Form.initAll('form[data-form-father]', {
79
+ const forms = Form.initAll('form[data-form-father]', {
72
80
  inputSelector: '.input',
73
81
  inputWrapperSelector: '.field',
74
82
  validateOn: ['blur', 'change'],
@@ -93,3 +101,49 @@ Form.initAll('form[data-form-father]', {
93
101
  }
94
102
  },
95
103
  });
104
+
105
+ const formByDemo = new Map(forms.map(form => [form.$el.dataset.demo, form]));
106
+ const apiForm = formByDemo.get('api');
107
+
108
+ document.querySelectorAll('[data-api-action]').forEach(button => {
109
+ button.addEventListener('click', async () => {
110
+ if (!apiForm) return;
111
+
112
+ switch (button.dataset.apiAction) {
113
+ case 'fill':
114
+ apiForm.setValues({
115
+ name: 'Ada Lovelace',
116
+ email: 'ada@example.com',
117
+ plan: 'team',
118
+ });
119
+ writeOutput('setValues()', apiForm.getValues());
120
+ break;
121
+
122
+ case 'validate-email': {
123
+ const valid = await apiForm.validateField('email');
124
+ writeOutput('validateField("email")', {
125
+ valid,
126
+ errors: apiForm.getErrors(),
127
+ });
128
+ break;
129
+ }
130
+
131
+ case 'server-errors':
132
+ apiForm.setErrors({
133
+ email: 'Этот email уже зарегистрирован',
134
+ [FORM_ERROR_FIELD]: 'Сервер попросил проверить форму',
135
+ });
136
+ writeOutput('setErrors()', apiForm.getErrors());
137
+ break;
138
+
139
+ case 'values':
140
+ writeOutput('getValues()', apiForm.getValues());
141
+ break;
142
+
143
+ case 'clear':
144
+ apiForm.clearErrors();
145
+ writeOutput('clearErrors()', apiForm.getErrors());
146
+ break;
147
+ }
148
+ });
149
+ });
package/demos/styles.css CHANGED
@@ -102,6 +102,10 @@ button:focus-visible {
102
102
  padding: 22px;
103
103
  }
104
104
 
105
+ .demo-panel--wide {
106
+ grid-column: 1 / -1;
107
+ }
108
+
105
109
  .panel-title {
106
110
  margin-bottom: 18px;
107
111
  }
@@ -156,6 +160,17 @@ form {
156
160
  color: var(--accent-strong);
157
161
  }
158
162
 
163
+ .demo-actions {
164
+ display: flex;
165
+ flex-wrap: wrap;
166
+ gap: 8px;
167
+ }
168
+
169
+ .demo-actions button {
170
+ min-height: 38px;
171
+ padding-inline: 12px;
172
+ }
173
+
159
174
  .field {
160
175
  display: grid;
161
176
  gap: 6px;
@@ -0,0 +1,153 @@
1
+ # Form Father API Reference
2
+
3
+ This page is a compact reference for the public API exported by `form-father`.
4
+
5
+ ## Main Import
6
+
7
+ ```ts
8
+ import Form from 'form-father';
9
+ ```
10
+
11
+ `Form` is the default export and is constructed with a native `<form>` element.
12
+
13
+ ```ts
14
+ const form = new Form(document.querySelector('form')!, {
15
+ inputWrapperSelector: '.field',
16
+ validateOn: ['blur', 'change'],
17
+ revalidateOn: ['input', 'change'],
18
+ errorSummary: true,
19
+ });
20
+ ```
21
+
22
+ ## Form Options
23
+
24
+ | Option | Type | Default | Notes |
25
+ | --- | --- | --- | --- |
26
+ | `inputSelector` | `string` | `.input` | Selector used by legacy input collection helpers. |
27
+ | `inputWrapperSelector` | `string` | `.input-primary` | Field wrapper selector used for inline error rendering. |
28
+ | `showLoaderButton` | `boolean` | `true` | Adds a loader to submit buttons while a request is pending. |
29
+ | `loaderColor` | `string` | `#fff` | Loader SVG color. |
30
+ | `scrollToFirstErroredInput` | `boolean` | `true` | Scrolls to the first invalid field. |
31
+ | `focusFirstErroredInput` | `boolean` | `false` | Focuses the first invalid field after validation. |
32
+ | `validateOn` | `ValidationTrigger | ValidationTrigger[]` | `submit` | Live validation triggers: `submit`, `input`, `blur`, `change`. |
33
+ | `revalidateOn` | `ValidationTrigger | ValidationTrigger[]` | `input`, `change` | Rechecks fields that are already invalid. |
34
+ | `validationDebounce` | `number` | `0` | Delay for live validation. |
35
+ | `validationSchema` | `ValidationSchema` | built in defaults | Field rules matched by selectors or `data-validate`. |
36
+ | `formValidators` | `FormValidator | FormValidator[]` | none | Cross-field and form-level validation. |
37
+ | `errorContainerAttribute` | `string` | `data-error-container` | Attribute containing a selector for a custom error container. |
38
+ | `validationStateAttribute` | `string` | `data-form-father-state` | Field state attribute: `validating`, `valid`, `invalid`. |
39
+ | `ariaDescribeErrors` | `boolean` | `true` | Links inline errors to fields with `aria-describedby`. |
40
+ | `errorIdPrefix` | `string` | `form-father-error` | Prefix for generated error element ids. |
41
+ | `errorSummary` | `boolean | ErrorSummaryOptions` | `false` | Enables an accessible form error summary. |
42
+ | `observeMutations` | `boolean` | `false` | Rebinds controls when fields/buttons are added dynamically. |
43
+ | `wrapData` | `(data) => data` | none | Transforms form values before request body creation. |
44
+ | `logging` | `boolean` | `false` | Logs submitted `FormData` values. |
45
+
46
+ ## Lifecycle Callbacks
47
+
48
+ | Callback | When it runs |
49
+ | --- | --- |
50
+ | `onBeforeValidate(form)` | Before submit-time validation. |
51
+ | `onAfterValidate(isValid, form)` | After validation and before submit. |
52
+ | `onValidationError(errors, form)` | When client-side validation fails. |
53
+ | `onBeforeSubmit(form)` | Before a valid form is sent. Return `false` to cancel. |
54
+ | `onSubmit(form)` | When request sending starts. |
55
+ | `onResponse(body, form)` | After a response body is parsed. |
56
+ | `onResponseSuccess(body, form)` | For successful HTTP responses with `success: true`. |
57
+ | `onResponseUnsuccess(body, form)` | For non-OK responses, `success !== true`, or invalid JSON. |
58
+ | `onSubmitError(error, form)` | When sending or response parsing throws. |
59
+
60
+ ## Instance Methods
61
+
62
+ | Method | Returns | Purpose |
63
+ | --- | --- | --- |
64
+ | `validate()` | `Promise<boolean>` | Validates the whole form. |
65
+ | `validateField(field)` | `Promise<boolean>` | Validates one field by `name` or element. |
66
+ | `submit()` | `Promise<SubmitResult | undefined>` | Sends the form programmatically. |
67
+ | `showFieldError(field, message, source?)` | `boolean` | Shows a field error manually. |
68
+ | `setErrors(errors, source?)` | `this` | Applies backend, form-level, or manual errors. |
69
+ | `getErrors()` | `ValidationError[]` | Returns current error records. |
70
+ | `getValues()` | `Record<string, any>` | Serializes the form into a plain object. |
71
+ | `setValues(values)` | `this` | Sets field values by `name` and dispatches `input`/`change`. |
72
+ | `clearErrors()` | `this` | Clears field and form errors. |
73
+ | `reset(options?)` | `this` | Calls native `form.reset()` and clears errors by default. |
74
+ | `clearInputs()` | `void` | Clears input values without resetting native defaults. |
75
+ | `updateOptions(options)` | `this` | Updates options and rebinds listeners. |
76
+ | `destroy()` | `void` | Removes listeners, loaders, error nodes, and runtime state. |
77
+
78
+ ## Static Methods and Constants
79
+
80
+ ```ts
81
+ Form.initAll('form[data-form-father]', options);
82
+ Form.setDefaultParams({ inputWrapperSelector: '.field' });
83
+ Form.defaultValidationSchema = {};
84
+ ```
85
+
86
+ | Export | Purpose |
87
+ | --- | --- |
88
+ | `FORM_ERROR_FIELD` | Constant for form-level errors in `getErrors()` and `setErrors()`. |
89
+ | `Form.initAll(selector, options)` | Initializes matching forms and reuses existing instances. |
90
+ | `Form.setDefaultParams(params)` | Merges global default options for future instances. |
91
+ | `Form.defaultValidationSchema` | Global default validation schema. |
92
+
93
+ ## Validators
94
+
95
+ ```ts
96
+ import {
97
+ createLengthValidator,
98
+ createPatternValidator,
99
+ registerFieldValidator,
100
+ registerValidator,
101
+ } from 'form-father';
102
+ ```
103
+
104
+ | Export | Purpose |
105
+ | --- | --- |
106
+ | `registerValidator(name, fn, message, options?)` | Registers a full validator. |
107
+ | `registerFieldValidator(name, predicate, message, options?)` | Registers a predicate-only field validator. |
108
+ | `getValidator(name)` | Reads one validator definition. |
109
+ | `getAllValidators()` | Reads the validator registry. |
110
+ | `createPatternValidator(pattern)` | Builds a regex validator. |
111
+ | `createLengthValidator(options)` | Builds min/max length validation. |
112
+
113
+ ## Form Validators
114
+
115
+ ```ts
116
+ import { dateOrder, requiredIf, sameAsField } from 'form-father';
117
+ ```
118
+
119
+ | Export | Purpose |
120
+ | --- | --- |
121
+ | `createFormValidator(predicate, issue)` | Builds a reusable cross-field validator. |
122
+ | `sameAsField(field, otherField, message?, rule?)` | Checks that two values match. |
123
+ | `requiredIf(field, condition, message?, rule?)` | Makes a field required when a predicate is true. |
124
+ | `dateOrder(startField, endField, message?, rule?)` | Checks chronological field order. |
125
+
126
+ ## Schema Adapters
127
+
128
+ ```ts
129
+ import { createSchemaValidator, registerSchemaValidator } from 'form-father';
130
+ ```
131
+
132
+ Adapters expect a schema-like object with either `safeParse(value)` or `parse(value)`.
133
+
134
+ | Export | Purpose |
135
+ | --- | --- |
136
+ | `createSchemaValidator(schema, message?)` | Converts a schema into a field validator function. |
137
+ | `registerSchemaValidator(name, schema, message?, options?)` | Registers a schema-backed rule. |
138
+ | `createFieldValidator(predicate, message)` | Creates a simple predicate validator. |
139
+
140
+ ## Helpers
141
+
142
+ | Export | Purpose |
143
+ | --- | --- |
144
+ | `serializeToFormData(element)` | Serializes a form-like element into `FormData`. |
145
+ | `serializeFormToJSON(form)` | Serializes a form into a plain object. |
146
+ | `isEmailValid(value)` | Checks email format. |
147
+ | `isUrlValid(value)` | Checks URLs, domains, IPs, and `localhost`. |
148
+ | `isPhoneValid(value)` | Checks Russian `+7XXXXXXXXXX` phone numbers. |
149
+ | `closest(element, selector)` | Finds a closest matching ancestor. |
150
+ | `parseCommonResponseProperties(body)` | Normalizes common response flags. |
151
+ | `blockScrollBody()` | Locks body scrolling. |
152
+ | `unblockScrollBody()` | Restores body scrolling. |
153
+
@@ -0,0 +1,37 @@
1
+ # Demo Guide
2
+
3
+ The demo is a static, dependency-light page that exercises common Form Father flows after a package build.
4
+
5
+ ```bash
6
+ npm run build
7
+ npm run demos
8
+ ```
9
+
10
+ Open the Vite URL printed by the command. The page loads `dist/FormFather.min.js` and `demos/main.js`, so it reflects the
11
+ actual browser bundle.
12
+
13
+ ## Demo Forms
14
+
15
+ | Form | What it demonstrates |
16
+ | --- | --- |
17
+ | Login | Live validation, async validator state, password confirmation, and custom error containers. |
18
+ | Callback | Server-side field errors and form-level API errors. |
19
+ | Search | `GET` forms and query-string body handling. |
20
+ | Multipart | Browser-managed `FormData` upload flow. |
21
+ | Public API | `setValues()`, `validateField()`, `setErrors()`, `getValues()`, and `clearErrors()`. |
22
+
23
+ ## Useful Manual Checks
24
+
25
+ - Enter `taken@example.com` in the Login email field to see async validation fail.
26
+ - Submit Callback with a valid phone to see backend field errors applied after the mocked response.
27
+ - Clear the Search query and submit to inspect the accessible error summary.
28
+ - Use Public API buttons to inspect programmatic state changes in the Output panel.
29
+
30
+ ## Files
31
+
32
+ | File | Purpose |
33
+ | --- | --- |
34
+ | `demos/index.html` | Demo markup and forms. |
35
+ | `demos/main.js` | Mock API, validator registration, `Form.initAll()`, and public API playground actions. |
36
+ | `demos/styles.css` | Minimal UI styling for fields, summaries, output, and loading states. |
37
+
package/docs/en/README.md CHANGED
@@ -226,9 +226,12 @@ For simple checks, use `createFieldValidator(predicate, message)`.
226
226
 
227
227
  ## Demos and Recipes
228
228
 
229
- - `demos/index.html` is a static login/callback/search/upload demo after `npm run build`.
229
+ - `demos/index.html` is a static login/callback/search/upload/public API demo after `npm run build`.
230
230
  - `npm run demos` builds the package and starts the Vite demo server.
231
+ - `docs/api/README.md` is a compact reference for public API, options, methods, and exports.
232
+ - `docs/demo/README.md` explains manual demo checks and demo form coverage.
231
233
  - `docs/recipes/README.md` contains short API, data-attribute, adapter, and server-error recipes.
234
+ - `CHANGELOG.md` tracks releases and coverage baselines.
232
235
 
233
236
  ## Helpers
234
237
 
@@ -250,6 +253,7 @@ The library provides a number of utility functions:
250
253
 
251
254
  - **npm run build**: Builds the project.
252
255
  - **npm run watch**: Builds the project in watch mode.
256
+ - **npm run docs:check**: Checks docs links, version references, demo files, and package README sync.
253
257
  - **npm run demos**: Runs a demo version using Vite.
254
258
 
255
259
  ## Contributing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-father",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Form Father: Библиотека для обработки форм",
5
5
  "type": "module",
6
6
  "files": ["dist", "README.md", "LICENSE", "RESPONSE_API.md", "CHANGELOG.md", "docs", "demos"],
@@ -14,7 +14,8 @@
14
14
  "build": "rollup -c",
15
15
  "watch": "rollup -c -w",
16
16
  "release": "node scripts/release.js",
17
- "release:check": "npm test -- --runInBand --watchman=false && npm run build && npm run smoke:package && npm run pack:dry-run",
17
+ "release:check": "npm test -- --runInBand --watchman=false && npm run docs:check && npm run build && npm run smoke:package && npm run pack:dry-run",
18
+ "docs:check": "node scripts/check-docs.mjs",
18
19
  "test": "jest --coverage",
19
20
  "prepublishOnly": "npm test -- --runInBand --watchman=false && npm run build",
20
21
  "pack:dry-run": "npm_config_cache=/tmp/form-father-npm-cache npm pack --dry-run",