@reformer/core 11.0.0-beta.1 → 11.0.0-beta.10
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/README.md +90 -68
- package/dist/behaviors-value-D05z3my6.js +109 -0
- package/dist/behaviors.d.ts +1 -1
- package/dist/behaviors.js +376 -211
- package/dist/create-model-DPSG3I0O.js +30 -0
- package/dist/date-utils-90-qZbse.js +43 -0
- package/dist/en-HP8XEych.js +44 -0
- package/dist/form/aggregate-signals.d.ts +21 -63
- package/dist/form/behaviors/collections.d.ts +84 -0
- package/dist/form/behaviors/context.d.ts +56 -0
- package/dist/form/behaviors/index.d.ts +30 -0
- package/dist/form/behaviors/internals.d.ts +41 -0
- package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +28 -5
- package/dist/form/behaviors/operators.d.ts +59 -0
- package/dist/form/behaviors/schema-operators.d.ts +83 -0
- package/dist/form/behaviors/types.d.ts +37 -0
- package/dist/form/create-form.d.ts +59 -70
- package/dist/form/flow/flow.d.ts +87 -0
- package/dist/form/form-bundle.d.ts +153 -0
- package/dist/form/form-level.d.ts +121 -0
- package/dist/form/form-proxy-builder.d.ts +6 -22
- package/dist/form/index.d.ts +23 -24
- package/dist/form/nodes/form-array-node.d.ts +100 -0
- package/dist/form/nodes/form-control-node.d.ts +73 -0
- package/dist/form/nodes/form-group-node.d.ts +66 -0
- package/dist/form/nodes/node-kind.d.ts +29 -0
- package/dist/form/nodes/state/availability.d.ts +6 -0
- package/dist/form/nodes/state/component.d.ts +6 -0
- package/dist/form/nodes/state/index.d.ts +12 -0
- package/dist/form/nodes/state/interaction.d.ts +13 -0
- package/dist/form/nodes/state/issues.d.ts +9 -0
- package/dist/form/nodes/state/pending.d.ts +6 -0
- package/dist/form/schema/compile.d.ts +59 -0
- package/dist/form/schema/compiled.d.ts +143 -0
- package/dist/form/schema/row-key.d.ts +11 -0
- package/dist/form/schema-controller.d.ts +159 -0
- package/dist/form/schema-subtree.d.ts +28 -0
- package/dist/form/signal-node-registry.d.ts +27 -22
- package/dist/form/submission.d.ts +93 -0
- package/dist/form/type-guards.d.ts +14 -73
- package/dist/form/types/contracts.d.ts +21 -85
- package/dist/form/types/field-config.d.ts +27 -0
- package/dist/form/types/index.d.ts +5 -57
- package/dist/form/types/nodes.d.ts +159 -0
- package/dist/form/types/schema-node.d.ts +147 -46
- package/dist/form/types/validation-schema.d.ts +25 -17
- package/dist/form/validation/context.d.ts +67 -0
- package/dist/form/validation/index.d.ts +24 -28
- package/dist/form/validation/operators.d.ts +101 -0
- package/dist/form/validation/run.d.ts +120 -0
- package/dist/form/validation/strategy.d.ts +89 -0
- package/dist/form/validation/types.d.ts +83 -0
- package/dist/form/validators/date-utils.d.ts +42 -0
- package/dist/form/validators/email.d.ts +23 -0
- package/dist/form/{validation/validators → validators}/file-type.d.ts +10 -10
- package/dist/form/{validation/validators → validators}/file-utils.d.ts +3 -2
- package/dist/form/validators/future-date.d.ts +23 -0
- package/dist/form/{validation/validators → validators}/index.d.ts +7 -4
- package/dist/form/validators/integer.d.ts +22 -0
- package/dist/form/validators/is-date.d.ts +24 -0
- package/dist/form/validators/is-number.d.ts +25 -0
- package/dist/form/validators/max-age.d.ts +28 -0
- package/dist/form/validators/max-date.d.ts +25 -0
- package/dist/form/{validation/validators → validators}/max-file-size.d.ts +10 -10
- package/dist/form/validators/max-files.d.ts +26 -0
- package/dist/form/validators/max-length.d.ts +33 -0
- package/dist/form/validators/max-total-file-size.d.ts +26 -0
- package/dist/form/validators/max.d.ts +26 -0
- package/dist/form/validators/min-age.d.ts +27 -0
- package/dist/form/validators/min-date.d.ts +25 -0
- package/dist/form/{validation/validators → validators}/min-file-size.d.ts +10 -10
- package/dist/form/validators/min-files.d.ts +27 -0
- package/dist/form/validators/min-length.d.ts +33 -0
- package/dist/form/validators/min.d.ts +26 -0
- package/dist/form/validators/multiple-of.d.ts +25 -0
- package/dist/form/validators/non-negative.d.ts +22 -0
- package/dist/form/validators/non-zero.d.ts +22 -0
- package/dist/form/validators/past-date.d.ts +23 -0
- package/dist/form/validators/pattern.d.ts +26 -0
- package/dist/form/{validation/validators → validators}/phone.d.ts +11 -11
- package/dist/form/validators/required.d.ts +29 -0
- package/dist/form/validators/url.d.ts +45 -0
- package/dist/form/validators/validation-issue.d.ts +8 -0
- package/dist/i18n/descriptor.d.ts +54 -0
- package/dist/i18n/en.json.d.ts +49 -0
- package/dist/i18n/loader.d.ts +71 -0
- package/dist/i18n/locale-store.d.ts +46 -0
- package/dist/i18n/locale.d.ts +90 -0
- package/dist/i18n/message-format.d.ts +136 -0
- package/dist/i18n/resolve-localized.d.ts +17 -0
- package/dist/i18n/ru.json.d.ts +49 -0
- package/dist/i18n/translator.d.ts +61 -0
- package/dist/i18n/validation-message.d.ts +53 -0
- package/dist/i18n.d.ts +26 -0
- package/dist/i18n.js +86 -0
- package/dist/index.d.ts +17 -5
- package/dist/index.js +942 -2601
- package/dist/loader-BWkigpVe.js +52 -0
- package/dist/locale/en.d.ts +2 -0
- package/dist/locale/en.js +5 -0
- package/dist/locale/en.json +45 -0
- package/dist/locale/index.d.ts +18 -0
- package/dist/locale/ru.d.ts +2 -0
- package/dist/locale/ru.js +44 -0
- package/dist/locale/ru.json +45 -0
- package/dist/locale-CG54AU2Q.js +219 -0
- package/dist/locale.d.ts +2 -0
- package/dist/locale.js +9 -0
- package/dist/{state → model}/behaviors-value.d.ts +24 -6
- package/dist/{state/form-model.d.ts → model/create-model.d.ts} +18 -4
- package/dist/{state → model}/derived-registry.d.ts +1 -1
- package/dist/model/index.d.ts +42 -0
- package/dist/model/model-nodes.d.ts +190 -0
- package/dist/model/model-signals-proxy.d.ts +63 -0
- package/dist/model/model-value-proxy.d.ts +84 -0
- package/dist/{state → model}/safe-effect.d.ts +50 -2
- package/dist/model/types.d.ts +239 -0
- package/dist/model.d.ts +2 -0
- package/dist/model.js +27 -0
- package/dist/node-kind-C-r6ZMdo.js +15 -0
- package/dist/platforms/react/field-binding/field-adapter.d.ts +87 -0
- package/dist/platforms/react/field-binding/field-handle.d.ts +53 -0
- package/dist/platforms/react/form-bundle-context.d.ts +27 -0
- package/dist/{form → platforms/react}/hooks/types.d.ts +58 -36
- package/dist/platforms/react/hooks/use-form-bundle.d.ts +41 -0
- package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
- package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +13 -7
- package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +6 -6
- package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +7 -9
- package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +18 -18
- package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +9 -1
- package/dist/platforms/react/i18n/context.d.ts +18 -0
- package/dist/platforms/react/i18n/hooks.d.ts +65 -0
- package/dist/platforms/react/i18n/provider.d.ts +59 -0
- package/dist/platforms/react/index.d.ts +30 -0
- package/dist/react.d.ts +22 -0
- package/dist/react.js +505 -0
- package/dist/runtime-token.d.ts +1 -2
- package/dist/safe-effect-BazLOv1g.js +669 -0
- package/dist/schema-controller-CpiO2JoK.js +143 -0
- package/dist/signals.d.ts +15 -9
- package/dist/signals.js +11 -6
- package/dist/strategy-DzvnsWLh.js +375 -0
- package/dist/type-guards-D-N_5Ddh.js +19 -0
- package/dist/validation-issue-B9mjI8jz.js +7 -0
- package/dist/validation-message-Ced9MGxs.js +194 -0
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +11 -165
- package/dist/validators/email.d.ts +1 -1
- package/dist/validators/email.js +5 -8
- package/dist/validators/future-date.d.ts +1 -1
- package/dist/validators/future-date.js +10 -13
- package/dist/validators/integer.d.ts +1 -1
- package/dist/validators/integer.js +4 -7
- package/dist/validators/is-date.d.ts +1 -1
- package/dist/validators/is-date.js +5 -8
- package/dist/validators/is-number.d.ts +1 -1
- package/dist/validators/is-number.js +4 -7
- package/dist/validators/max-age.d.ts +1 -1
- package/dist/validators/max-age.js +8 -12
- package/dist/validators/max-date.d.ts +1 -1
- package/dist/validators/max-date.js +10 -13
- package/dist/validators/max-length.d.ts +1 -1
- package/dist/validators/max-length.js +7 -10
- package/dist/validators/max.d.ts +1 -1
- package/dist/validators/max.js +4 -7
- package/dist/validators/min-age.d.ts +1 -1
- package/dist/validators/min-age.js +10 -11
- package/dist/validators/min-date.d.ts +1 -1
- package/dist/validators/min-date.js +8 -11
- package/dist/validators/min-length.d.ts +1 -1
- package/dist/validators/min-length.js +4 -7
- package/dist/validators/min.d.ts +1 -1
- package/dist/validators/min.js +4 -7
- package/dist/validators/multiple-of.d.ts +1 -1
- package/dist/validators/multiple-of.js +11 -10
- package/dist/validators/non-negative.d.ts +1 -1
- package/dist/validators/non-negative.js +2 -5
- package/dist/validators/non-zero.d.ts +1 -1
- package/dist/validators/non-zero.js +4 -7
- package/dist/validators/past-date.d.ts +1 -1
- package/dist/validators/past-date.js +10 -13
- package/dist/validators/pattern.d.ts +1 -1
- package/dist/validators/pattern.js +5 -8
- package/dist/validators/phone.d.ts +1 -1
- package/dist/validators/phone.js +10 -11
- package/dist/validators/required.d.ts +1 -1
- package/dist/validators/required.js +4 -7
- package/dist/validators/url.d.ts +1 -1
- package/dist/validators/url.js +48 -17
- package/dist/validators.d.ts +1 -1
- package/dist/validators.js +86 -108
- package/docs/llms/01-api-reference.md +60 -34
- package/docs/llms/02-quick-start.md +112 -74
- package/docs/llms/03-api-signatures.md +369 -148
- package/docs/llms/04-common-patterns.md +58 -56
- package/docs/llms/05-common-mistakes.md +69 -44
- package/docs/llms/06-troubleshooting.md +14 -9
- package/docs/llms/07-complete-import.md +74 -43
- package/docs/llms/08-form-types.md +11 -4
- package/docs/llms/09-formschema.md +132 -84
- package/docs/llms/10-arrays.md +141 -61
- package/docs/llms/11-async-watchfield.md +2 -2
- package/docs/llms/13-multi-step.md +134 -63
- package/docs/llms/14-extended-mistakes.md +20 -17
- package/docs/llms/15-project-structure.md +224 -70
- package/docs/llms/16-ui-components.md +86 -46
- package/docs/llms/17-nonexistent-api.md +217 -32
- package/docs/llms/18-conditional-fields.md +71 -32
- package/docs/llms/19-reading-values.md +45 -4
- package/docs/llms/20-compute-vs-watch.md +25 -10
- package/docs/llms/21-array-operations.md +76 -26
- package/docs/llms/22-cycle-detection.md +1 -1
- package/docs/llms/23-copy-from.md +2 -2
- package/docs/llms/24-sync-fields.md +6 -5
- package/docs/llms/25-reset-when.md +14 -7
- package/docs/llms/26-transform-value.md +4 -4
- package/docs/llms/27-revalidate-when.md +16 -15
- package/docs/llms/28-submit-and-reset.md +278 -128
- package/docs/llms/29-async-preload.md +41 -31
- package/docs/llms/30-type-safety-recipes.md +105 -51
- package/docs/llms/31-async-validator-debounce.md +96 -53
- package/docs/llms/33-validation-strategy.md +178 -66
- package/docs/llms/34-i18n.md +298 -0
- package/docs/llms/35-unified-contract.md +309 -0
- package/docs/llms/36-issue-messages.md +284 -0
- package/docs/llms/37-compiled-schema.md +332 -0
- package/docs/llms/38-form-flow.md +396 -0
- package/llms-index.json +1 -0
- package/llms.txt +10690 -3089
- package/package.json +48 -9
- package/dist/behaviors-node-DGEFMTQu.js +0 -18
- package/dist/behaviors-value-C7dSEhCc.js +0 -134
- package/dist/date-utils-dTT_x_Be.js +0 -31
- package/dist/derived-registry-CluZCQ7U.js +0 -16
- package/dist/form/behaviors.d.ts +0 -133
- package/dist/form/error-handler.d.ts +0 -166
- package/dist/form/factories/index.d.ts +0 -6
- package/dist/form/factories/node-factory.d.ts +0 -188
- package/dist/form/form-submitter.d.ts +0 -121
- package/dist/form/nodes/array-node.d.ts +0 -276
- package/dist/form/nodes/field-node.d.ts +0 -294
- package/dist/form/nodes/form-node.d.ts +0 -326
- package/dist/form/nodes/group-node.d.ts +0 -284
- package/dist/form/nodes/model-array-node.d.ts +0 -121
- package/dist/form/status-machine.d.ts +0 -115
- package/dist/form/types/deep-schema.d.ts +0 -107
- package/dist/form/types/form-proxy.d.ts +0 -141
- package/dist/form/unique-id.d.ts +0 -45
- package/dist/form/validation/validators/date-utils.d.ts +0 -30
- package/dist/form/validation/validators/email.d.ts +0 -23
- package/dist/form/validation/validators/future-date.d.ts +0 -23
- package/dist/form/validation/validators/integer.d.ts +0 -22
- package/dist/form/validation/validators/is-date.d.ts +0 -23
- package/dist/form/validation/validators/is-number.d.ts +0 -24
- package/dist/form/validation/validators/max-age.d.ts +0 -25
- package/dist/form/validation/validators/max-date.d.ts +0 -25
- package/dist/form/validation/validators/max-files.d.ts +0 -26
- package/dist/form/validation/validators/max-length.d.ts +0 -27
- package/dist/form/validation/validators/max-total-file-size.d.ts +0 -26
- package/dist/form/validation/validators/max.d.ts +0 -25
- package/dist/form/validation/validators/min-age.d.ts +0 -25
- package/dist/form/validation/validators/min-date.d.ts +0 -25
- package/dist/form/validation/validators/min-files.d.ts +0 -26
- package/dist/form/validation/validators/min-length.d.ts +0 -27
- package/dist/form/validation/validators/min.d.ts +0 -25
- package/dist/form/validation/validators/multiple-of.d.ts +0 -24
- package/dist/form/validation/validators/non-negative.d.ts +0 -22
- package/dist/form/validation/validators/non-zero.d.ts +0 -22
- package/dist/form/validation/validators/past-date.d.ts +0 -23
- package/dist/form/validation/validators/pattern.d.ts +0 -33
- package/dist/form/validation/validators/required.d.ts +0 -32
- package/dist/form/validation/validators/url.d.ts +0 -43
- package/dist/form/validation-schema.d.ts +0 -106
- package/dist/form/validation-strategy.d.ts +0 -55
- package/dist/form/validators.d.ts +0 -11
- package/dist/form-model-DYCzGGKF.js +0 -286
- package/dist/state/index.d.ts +0 -31
- package/dist/state/subscription-manager.d.ts +0 -180
- package/dist/state/types.d.ts +0 -144
- package/dist/state.d.ts +0 -2
- package/dist/state.js +0 -21
- package/dist/subscription-manager-705bls97.js +0 -171
|
@@ -2,52 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
### Imports (CRITICALLY IMPORTANT)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
| What | Where
|
|
8
|
-
| ------------------------------------------------------------------------------------------------------ |
|
|
9
|
-
| `createModel`, `createForm`
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
5
|
+
Значения живут в **модели** (`createModel`), а форма (`createForm`) строит ноды поверх сигналов модели. Схема, правила и поведение привязываются к ручкам модели (`model.$.field`), а не к строковым путям.
|
|
6
|
+
|
|
7
|
+
| What | Where |
|
|
8
|
+
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------ |
|
|
9
|
+
| `createModel`, `createForm`, `createFormFromModel`, `disposeForm`, `arrayOf`, `modelOf` | `@reformer/core` |
|
|
10
|
+
| `compileSchema`, `createFormFlow`, `createFormLevel`, `createSubmission`, `getNodeForSignal` | `@reformer/core` |
|
|
11
|
+
| `isFormNode`, `isFormControl`, `isFormGroup`, `isFormArray` (гарды нод) | `@reformer/core` |
|
|
12
|
+
| `FormModel`, `FormBundle`, `FormNode`, `FormControl`, `FormGroup`, `FormArray`, `FormFields` | `@reformer/core` |
|
|
13
|
+
| `ModelSignals`, `ModelArray`, `ModelValue`, `ModelObject`, `PathAwareSignal` | `@reformer/core` |
|
|
14
|
+
| `ValidationIssue`, `RuleOptions`, `FormSchemaNode`, `ComponentRef`, `CompiledSchema` | `@reformer/core` |
|
|
15
|
+
| `FormValidation`, `FormFlowConfig`, `FormFlow`, `FlowTransition`, `SubmitResult` | `@reformer/core` |
|
|
16
|
+
| `FormSubmission`, `SubmissionDependencies`, `ActionCheck` (отправка) | `@reformer/core` |
|
|
17
|
+
| `defineValidation`, `validate`, `validateAsync`, `validateWhen`, `apply`, `applyEach` | `@reformer/core/validation` |
|
|
18
|
+
| `validateModel`, `runValidation`, `applyValidationResult` (раннер), `createFormValidation` | `@reformer/core/validation` |
|
|
19
|
+
| `Rule`, `AsyncRule`, `ValidationDefinition`, `ValidationScope`, `ValidationResult` (типы) | `@reformer/core/validation` |
|
|
20
|
+
| `FormValidationController`, `FormValidationRunOptions`, `ValidationStrategyKind` (типы стратегии) | `@reformer/core/validation` |
|
|
21
|
+
| `useFormBundle`, `useFormControl`, `useFormControlValue`, `useArrayLength`, `useFormValidation` | `@reformer/core/react` |
|
|
22
|
+
| `useFormFlow`, `FormBundleContext`, `useFormBundleContext` | `@reformer/core/react` |
|
|
23
|
+
| `bindFieldProps`, `getFieldAdapter`, `FieldAdapter`, `FieldHandle`, `FieldControlState` (связка поля) | `@reformer/core/react` |
|
|
24
|
+
| `I18nProvider`, `useI18n`, `useMessages`, `useIssueMessage` | `@reformer/core/react` |
|
|
25
|
+
| `defineIssueMessages`, `resolveIssueMessage`, `createI18n`, `extendLocale`, `createLocaleLoader` | `@reformer/core/i18n` |
|
|
26
|
+
| `computeFrom`, `copyFrom`, `watchField`, `transformValue`, `resetWhen`, `syncFields`, `revalidateWhen` | `@reformer/core/model` (примитивы над сигналами) |
|
|
27
|
+
| `deepEqual`, `deferredWritesSettled` (сравнение значений, ожидание отложенных записей поведения) | `@reformer/core/model` |
|
|
28
|
+
| `required`, `min`, `max`, `minLength`, `maxLength`, `email`, `pattern`, `url`, `phone` | `@reformer/core/validators` |
|
|
29
|
+
| `isNumber`, `integer`, `multipleOf`, `nonNegative`, `nonZero` | `@reformer/core/validators` |
|
|
30
|
+
| `isDate`, `minDate`, `maxDate`, `pastDate`, `futureDate`, `minAge`, `maxAge` | `@reformer/core/validators` |
|
|
31
|
+
| `defineFormBehavior`, `compute`, `computeFrom`, `copyFrom`, `onChange`, `enableWhen`, `disableWhen` | `@reformer/core/behaviors` |
|
|
32
|
+
| `transformValue`, `resetWhen`, `syncFields`, `revalidateWhen`, `apply`, `applyEach`, `aggregateInto` | `@reformer/core/behaviors` |
|
|
33
|
+
| `exclusiveFlag`, `onDispose`, `getScope`, `effect`, `defer` | `@reformer/core/behaviors` |
|
|
34
|
+
| `hideWhen`, `onComponentEvent`, `renderEffect`, `onInit`, `onMount`, `onUnmount` (узлы схемы) | `@reformer/core/behaviors` |
|
|
35
|
+
|
|
36
|
+
> **Корень `@reformer/core` без React.** Хуки, контекст сборки, связка поля с контролом и
|
|
37
|
+
> провайдер локали — только из `@reformer/core/react`. Корень работает на сервере и с любым слоем
|
|
38
|
+
> представления.
|
|
39
|
+
|
|
40
|
+
> **Поведение формы — `@reformer/core/behaviors`.** Декларативный DSL (`defineFormBehavior` +
|
|
41
|
+
> операторы) регистрирует cleanup сам и передаётся в `createForm({ behavior })`. Примитивы над
|
|
42
|
+
> сигналами (`computeFrom`, `copyFrom`, `watchField`, …) в корень `@reformer/core` не входят: они
|
|
43
|
+
> лежат в сабпате `@reformer/core/model`, принимают **сигналы** (`model.$.x`), возвращают
|
|
44
|
+
> **cleanup-функцию** и нужны вне формы. `enableWhen` / `disableWhen` существуют только как
|
|
45
|
+
> операторы поведения. См. `20-compute-vs-watch.md`.
|
|
46
|
+
|
|
47
|
+
> **Валидация — отдельный слой.** Схема формы правил НЕ несёт. Правила живут в
|
|
48
|
+
> `defineValidation<T>(({ model, cross }) => { validate(model.$.x, [required(), min(50000)]); ... })`
|
|
33
49
|
> из `@reformer/core/validation`; фабрики `required()`, `min(50000)`, `email()` возвращают
|
|
34
|
-
> `Rule<T> = (value) =>
|
|
35
|
-
>
|
|
36
|
-
>
|
|
50
|
+
> `Rule<T> = (value: T) => ValidationIssue | null` и передаются массивом в `validate(sig, [...])`.
|
|
51
|
+
> Правила отдают сборке: `createForm({ validation, flow })`. Запуск — уровнем формы:
|
|
52
|
+
> `bundle.validate()` (`ValidationResult` со статусом `valid` / `invalid` / `error` / `cancelled`),
|
|
53
|
+
> `bundle.validateStep(id)`, отправка `bundle.submission.submit(handler)` (`SubmitResult`). Без
|
|
54
|
+
> сборки — раннер `validateModel(model, rules)` (`Promise<boolean>`) либо `runValidation` (полный
|
|
55
|
+
> результат). Снять сборку — `bundle.dispose()`. См. `38-form-flow.md`.
|
|
56
|
+
|
|
57
|
+
> **Текста у замечания нет.** `ValidationIssue = { code, params?, severity? }`; строку по коду
|
|
58
|
+
> даёт словарь формы (`defineIssueMessages`) поверх словаря локали. Опции правил —
|
|
59
|
+
> `RuleOptions = { code?, params? }`. См. `36-issue-messages.md`.
|
|
37
60
|
|
|
38
61
|
### Type Values
|
|
39
62
|
|
|
40
63
|
- Опциональные числа: `number | null` (конвенция «пользователь очистил поле»)
|
|
41
64
|
- Опциональные строки: `string` (по умолчанию пустая строка) или `string | null`
|
|
42
|
-
-
|
|
65
|
+
- Форму данных объявляй через `interface` или `type` — оба варианта работают, см.
|
|
66
|
+
`30-type-safety-recipes.md`
|
|
43
67
|
|
|
44
68
|
### React Hooks Comparison (CRITICALLY IMPORTANT)
|
|
45
69
|
|
|
46
70
|
| Hook | Return Type | Subscribes To | Use Case |
|
|
47
71
|
|------|-------------|---------------|----------|
|
|
48
|
-
| `useFormControl(field)` | `{ value,
|
|
72
|
+
| `useFormControl(field)` | `{ value, issues, disabled, touched, dirty, valid, invalid, pending, shouldShowError, shouldShowIssues, componentProps }` | Все сигналы поля | Полное состояние поля, инпуты |
|
|
49
73
|
| `useFormControlValue(field)` | `T` (значение напрямую) | Только сигнал value | Условный рендеринг |
|
|
50
74
|
| `useArrayLength(array)` | `number` | Только длина массива | Реактивная длина массива |
|
|
75
|
+
| `useFormFlow(bundle.flow)` | `{ current, index, completed, isFirst, isLast, validating }` | Сигналы потока шагов | Свои кнопки и индикатор шагов |
|
|
76
|
+
| `useIssueMessage(messages?)` | `(issue) => string` | Локаль | Текст замечания в своём компоненте |
|
|
51
77
|
|
|
52
78
|
**CRITICAL**: Не деструктурируй `useFormControlValue`! Он возвращает `T` напрямую, НЕ `{ value: T }`.
|
|
53
79
|
|
|
@@ -59,5 +85,5 @@ const { value: loanType } = useFormControlValue(control.loanType);
|
|
|
59
85
|
const loanType = useFormControlValue(control.loanType);
|
|
60
86
|
|
|
61
87
|
// CORRECT - useFormControl returns object, destructuring OK
|
|
62
|
-
const { value,
|
|
88
|
+
const { value, issues, disabled } = useFormControl(control.loanType);
|
|
63
89
|
```
|
|
@@ -1,80 +1,99 @@
|
|
|
1
1
|
## 1.5 QUICK START - Minimal Working Form
|
|
2
2
|
|
|
3
3
|
> **Schema-driven UI rule (read first)**: компонент И его пропсы (label, placeholder,
|
|
4
|
-
> options, type) объявляются в
|
|
4
|
+
> options, type) объявляются в **узле схемы** (`component` + `componentProps`).
|
|
5
5
|
> В JSX рендерится один универсальный `<FormField control={form.x} />` из
|
|
6
6
|
> `@reformer/ui-kit` БЕЗ дополнительных props. Не пиши свои `Input`/`Select`/
|
|
7
7
|
> `Checkbox`-обёртки с `label`-prop'ами — это anti-pattern. См.
|
|
8
8
|
> `find_recipe(package="@reformer/ui-kit", topic="form-field-integration")`.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
(`
|
|
12
|
-
|
|
13
|
-
схеме `
|
|
14
|
-
|
|
10
|
+
**Модель данных** — источник истины значений. Схема — дерево узлов, привязанных к ручкам модели
|
|
11
|
+
(`model: model.$.field`). Сборка идёт ОДНИМ вызовом `createForm`: он создаёт модель, строит форму,
|
|
12
|
+
запускает поведение и собирает уровень формы — проверку и отправку. Правил в схеме нет — они
|
|
13
|
+
живут в отдельной схеме `defineValidation` из `@reformer/core/validation` и уходят в сборку полем
|
|
14
|
+
`validation`; запускает их `bundle.submission.submit(handler)` / `bundle.validate()`. Текста у
|
|
15
|
+
правил нет: правило несёт код, строку по коду даёт словарь формы (`defineIssueMessages`).
|
|
15
16
|
|
|
16
17
|
```typescript
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
18
|
+
import { createForm, type FormModel, type FormGroup, type FormSchemaNode } from '@reformer/core';
|
|
19
|
+
import { useFormBundle } from '@reformer/core/react';
|
|
20
|
+
import { defineIssueMessages } from '@reformer/core/i18n';
|
|
21
|
+
import { defineValidation, validate } from '@reformer/core/validation';
|
|
19
22
|
import { required, email } from '@reformer/core/validators';
|
|
23
|
+
import { ValidationMessagesProvider } from '@reformer/cdk';
|
|
20
24
|
import { FormField, Input, Button } from '@reformer/ui-kit';
|
|
21
25
|
|
|
22
|
-
// 1.
|
|
23
|
-
|
|
26
|
+
// 1. Form data type — `interface` or `type`, both work
|
|
27
|
+
interface ContactForm {
|
|
24
28
|
name: string;
|
|
25
29
|
email: string;
|
|
26
|
-
}
|
|
30
|
+
}
|
|
27
31
|
|
|
28
|
-
// 2.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
// 2. Схема — билдер (model) => дерево узлов. Узел поля: привязка `model` + component/componentProps.
|
|
33
|
+
// Вложенные узлы лежат в `children`. Правил здесь нет — они в отдельной схеме (шаг 3).
|
|
34
|
+
const contactSchema = (model: FormModel<ContactForm>): FormSchemaNode => ({
|
|
35
|
+
children: [
|
|
36
|
+
{
|
|
37
|
+
model: model.$.name,
|
|
38
|
+
component: Input,
|
|
39
|
+
componentProps: { label: 'Name', placeholder: 'Your name' },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
model: model.$.email,
|
|
43
|
+
component: Input,
|
|
44
|
+
componentProps: { label: 'Email', type: 'email' },
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 3. Схема валидации — отдельный слой (@reformer/core/validation). Правило несёт код, не текст.
|
|
50
|
+
const contactValidation = defineValidation<ContactForm>(({ model }) => {
|
|
51
|
+
validate(model.$.name, [required({ code: 'name.required' })]);
|
|
52
|
+
validate(model.$.email, [required({ code: 'email.required' }), email()]);
|
|
53
|
+
});
|
|
45
54
|
|
|
46
|
-
// 4.
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
// 4. Тексты замечаний по кодам — словарь формы (встроенный код `email` берёт текст из локали)
|
|
56
|
+
const contactMessages = defineIssueMessages({
|
|
57
|
+
'name.required': 'Укажите имя',
|
|
58
|
+
'email.required': 'Укажите email',
|
|
50
59
|
});
|
|
51
60
|
|
|
52
|
-
// 5.
|
|
53
|
-
const
|
|
61
|
+
// 5. Сборка ОДНИМ вызовом: модель из initial + ноды поверх её сигналов + уровень формы.
|
|
62
|
+
const createContactForm = () =>
|
|
63
|
+
createForm<ContactForm>({
|
|
64
|
+
initial: { name: '', email: '' },
|
|
65
|
+
schema: contactSchema,
|
|
66
|
+
validation: contactValidation,
|
|
67
|
+
});
|
|
54
68
|
|
|
55
69
|
// 6. Use in React component — thin JSX, FormField does ALL heavy lifting
|
|
56
70
|
function ContactFormComponent() {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
// useFormBundle зовёт фабрику ровно один раз и держит сборку стабильной между рендерами.
|
|
72
|
+
const contact = useFormBundle(createContactForm);
|
|
73
|
+
const { form } = contact;
|
|
74
|
+
|
|
75
|
+
const handleSubmit = async (event: React.FormEvent) => {
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
// Один прогон всех правил: при замечаниях обработчик не вызывается, а вся форма помечается
|
|
78
|
+
// тронутой — FormField покажет замечания.
|
|
79
|
+
const outcome = await contact.submission.submit((values) => api.send(values));
|
|
80
|
+
if (outcome.status === 'submitted') console.log('Form submitted');
|
|
64
81
|
};
|
|
65
82
|
|
|
66
83
|
return (
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
84
|
+
<ValidationMessagesProvider messages={contactMessages}>
|
|
85
|
+
<form onSubmit={handleSubmit}>
|
|
86
|
+
<FormField control={form.name} testId="name" />
|
|
87
|
+
<FormField control={form.email} testId="email" />
|
|
88
|
+
<Button type="submit">Send</Button>
|
|
89
|
+
</form>
|
|
90
|
+
</ValidationMessagesProvider>
|
|
72
91
|
);
|
|
73
92
|
}
|
|
74
93
|
|
|
75
94
|
// 7. Pass form to child components via props (NOT context!)
|
|
76
95
|
type FormStepProps = {
|
|
77
|
-
form:
|
|
96
|
+
form: FormGroup<ContactForm>;
|
|
78
97
|
};
|
|
79
98
|
|
|
80
99
|
function FormStep({ form }: FormStepProps) {
|
|
@@ -82,16 +101,27 @@ function FormStep({ form }: FormStepProps) {
|
|
|
82
101
|
}
|
|
83
102
|
```
|
|
84
103
|
|
|
85
|
-
> **Стабильность
|
|
86
|
-
>
|
|
104
|
+
> **Стабильность сборки.** Форму создают ОДИН раз: в React — `useFormBundle(фабрика)`, вне React —
|
|
105
|
+
> константой модуля. Иначе форма пересоздаётся на каждый рендер. См. `28-submit-and-reset.md`,
|
|
106
|
+
> `29-async-preload.md`.
|
|
87
107
|
|
|
88
|
-
|
|
108
|
+
> **Проверка и отправка — уровень формы.** Отправка — отдельный объект сборки:
|
|
109
|
+
> `bundle.submission.submit(handler)` прогоняет все правила один раз и зовёт обработчик только при
|
|
110
|
+
> статусе `valid`; результат — `SubmitResult` (`submitted` / `invalid` / `error` / `cancelled` /
|
|
111
|
+
> `failed`). `bundle.validate()` проверяет всю форму и отвечает `ValidationResult`. У нод методов
|
|
112
|
+
> `validate()` / `submit()` нет. Многошаговая форма — `createForm({ flow: { steps: [{ id, rules }] } })`,
|
|
113
|
+
> см. `38-form-flow.md`. Вне React сборку снимают `bundle.dispose()`, когда форма больше не нужна.
|
|
89
114
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
### Arrays of objects — узел `{ model, item }`
|
|
116
|
+
|
|
117
|
+
Массивы объектов принадлежат модели (`model.arrayField`). В схеме массив под-форм объявляется узлом
|
|
118
|
+
`{ model: model.$.<path>, item: (itemModel) => узел }`, где `item` строит разметку одной строки из
|
|
119
|
+
её под-модели (`FormModel<Item>`):
|
|
93
120
|
|
|
94
121
|
```typescript
|
|
122
|
+
import { arrayOf, createForm, type FormModel, type FormSchemaNode } from '@reformer/core';
|
|
123
|
+
import { FieldArray, InputNumber, SelectAsync, Textarea } from '@reformer/ui-kit';
|
|
124
|
+
|
|
95
125
|
type PropertyItem = {
|
|
96
126
|
type: 'apartment' | 'house';
|
|
97
127
|
description: string;
|
|
@@ -100,33 +130,41 @@ type PropertyItem = {
|
|
|
100
130
|
|
|
101
131
|
type MyForm = { properties: PropertyItem[] };
|
|
102
132
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
// шаблон новой строки — его кладёт `push()` без значения и кнопка «Добавить»
|
|
134
|
+
const blankProperty = (): PropertyItem => ({ type: 'apartment', description: '', estimatedValue: 0 });
|
|
135
|
+
|
|
136
|
+
// разметка одной строки: item.$.field — ручка под-модели строки
|
|
137
|
+
const propertyRow = (item: FormModel<PropertyItem>): FormSchemaNode => ({
|
|
138
|
+
children: [
|
|
139
|
+
{
|
|
140
|
+
model: item.$.type,
|
|
141
|
+
component: SelectAsync,
|
|
142
|
+
componentProps: { label: 'Тип', options: [/* ... */] },
|
|
143
|
+
},
|
|
144
|
+
{ model: item.$.description, component: Textarea, componentProps: { label: 'Описание' } },
|
|
145
|
+
{
|
|
146
|
+
model: item.$.estimatedValue,
|
|
147
|
+
component: InputNumber,
|
|
148
|
+
componentProps: { label: 'Стоимость' },
|
|
149
|
+
},
|
|
150
|
+
],
|
|
118
151
|
});
|
|
119
152
|
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
153
|
+
const { model, form } = createForm<MyForm>({
|
|
154
|
+
initial: { properties: arrayOf(blankProperty) },
|
|
155
|
+
schema: (model) => ({
|
|
156
|
+
children: [{ model: model.$.properties, component: FieldArray, item: propertyRow }],
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
125
159
|
|
|
126
160
|
// Операции над массивом — на модели:
|
|
127
|
-
model.properties.push(
|
|
161
|
+
model.properties.push(); // новая строка по шаблону
|
|
162
|
+
model.properties.push({ type: 'house', description: '', estimatedValue: 0 });
|
|
128
163
|
model.properties.removeAt(0);
|
|
129
164
|
model.properties.length; // реактивная длина
|
|
165
|
+
form.properties.at(0); // форма строки (FormGroup<PropertyItem>)
|
|
166
|
+
form.properties.length; // число строк (число, не сигнал)
|
|
167
|
+
form.properties.keyAt(0); // стабильный ключ строки — для React `key`
|
|
130
168
|
```
|
|
131
169
|
|
|
132
170
|
Подробнее в `10-arrays.md`, `21-array-operations.md` и `find_recipe(topic="form-array")`.
|