@reformer/core 10.2.0 → 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.
Files changed (285) hide show
  1. package/README.md +90 -68
  2. package/dist/behaviors-value-D05z3my6.js +109 -0
  3. package/dist/behaviors.d.ts +1 -1
  4. package/dist/behaviors.js +376 -211
  5. package/dist/create-model-DPSG3I0O.js +30 -0
  6. package/dist/date-utils-90-qZbse.js +43 -0
  7. package/dist/en-HP8XEych.js +44 -0
  8. package/dist/form/aggregate-signals.d.ts +21 -63
  9. package/dist/form/behaviors/collections.d.ts +84 -0
  10. package/dist/form/behaviors/context.d.ts +56 -0
  11. package/dist/form/behaviors/index.d.ts +30 -0
  12. package/dist/form/behaviors/internals.d.ts +41 -0
  13. package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +28 -5
  14. package/dist/form/behaviors/operators.d.ts +59 -0
  15. package/dist/form/behaviors/schema-operators.d.ts +83 -0
  16. package/dist/form/behaviors/types.d.ts +37 -0
  17. package/dist/form/create-form.d.ts +59 -70
  18. package/dist/form/flow/flow.d.ts +87 -0
  19. package/dist/form/form-bundle.d.ts +153 -0
  20. package/dist/form/form-level.d.ts +121 -0
  21. package/dist/form/form-proxy-builder.d.ts +6 -22
  22. package/dist/form/index.d.ts +23 -27
  23. package/dist/form/nodes/form-array-node.d.ts +100 -0
  24. package/dist/form/nodes/form-control-node.d.ts +73 -0
  25. package/dist/form/nodes/form-group-node.d.ts +66 -0
  26. package/dist/form/nodes/node-kind.d.ts +29 -0
  27. package/dist/form/nodes/state/availability.d.ts +6 -0
  28. package/dist/form/nodes/state/component.d.ts +6 -0
  29. package/dist/form/nodes/state/index.d.ts +12 -0
  30. package/dist/form/nodes/state/interaction.d.ts +13 -0
  31. package/dist/form/nodes/state/issues.d.ts +9 -0
  32. package/dist/form/nodes/state/pending.d.ts +6 -0
  33. package/dist/form/schema/compile.d.ts +59 -0
  34. package/dist/form/schema/compiled.d.ts +143 -0
  35. package/dist/form/schema/row-key.d.ts +11 -0
  36. package/dist/form/schema-controller.d.ts +159 -0
  37. package/dist/form/schema-subtree.d.ts +28 -0
  38. package/dist/form/signal-node-registry.d.ts +27 -22
  39. package/dist/form/submission.d.ts +93 -0
  40. package/dist/form/type-guards.d.ts +14 -73
  41. package/dist/form/types/contracts.d.ts +21 -91
  42. package/dist/form/types/field-config.d.ts +27 -0
  43. package/dist/form/types/index.d.ts +5 -91
  44. package/dist/form/types/nodes.d.ts +159 -0
  45. package/dist/form/types/schema-node.d.ts +148 -50
  46. package/dist/form/types/validation-schema.d.ts +24 -41
  47. package/dist/form/validation/context.d.ts +67 -0
  48. package/dist/form/validation/index.d.ts +24 -28
  49. package/dist/form/validation/operators.d.ts +101 -0
  50. package/dist/form/validation/run.d.ts +120 -0
  51. package/dist/form/validation/strategy.d.ts +89 -0
  52. package/dist/form/validation/types.d.ts +83 -0
  53. package/dist/form/validators/date-utils.d.ts +42 -0
  54. package/dist/form/validators/email.d.ts +23 -0
  55. package/dist/form/{validation/validators → validators}/file-type.d.ts +10 -10
  56. package/dist/form/{validation/validators → validators}/file-utils.d.ts +3 -2
  57. package/dist/form/validators/future-date.d.ts +23 -0
  58. package/dist/form/{validation/validators → validators}/index.d.ts +7 -4
  59. package/dist/form/validators/integer.d.ts +22 -0
  60. package/dist/form/validators/is-date.d.ts +24 -0
  61. package/dist/form/validators/is-number.d.ts +25 -0
  62. package/dist/form/validators/max-age.d.ts +28 -0
  63. package/dist/form/validators/max-date.d.ts +25 -0
  64. package/dist/form/{validation/validators → validators}/max-file-size.d.ts +10 -10
  65. package/dist/form/validators/max-files.d.ts +26 -0
  66. package/dist/form/validators/max-length.d.ts +33 -0
  67. package/dist/form/validators/max-total-file-size.d.ts +26 -0
  68. package/dist/form/validators/max.d.ts +26 -0
  69. package/dist/form/validators/min-age.d.ts +27 -0
  70. package/dist/form/validators/min-date.d.ts +25 -0
  71. package/dist/form/{validation/validators → validators}/min-file-size.d.ts +10 -10
  72. package/dist/form/validators/min-files.d.ts +27 -0
  73. package/dist/form/validators/min-length.d.ts +33 -0
  74. package/dist/form/validators/min.d.ts +26 -0
  75. package/dist/form/validators/multiple-of.d.ts +25 -0
  76. package/dist/form/validators/non-negative.d.ts +22 -0
  77. package/dist/form/validators/non-zero.d.ts +22 -0
  78. package/dist/form/validators/past-date.d.ts +23 -0
  79. package/dist/form/validators/pattern.d.ts +26 -0
  80. package/dist/form/{validation/validators → validators}/phone.d.ts +11 -11
  81. package/dist/form/validators/required.d.ts +29 -0
  82. package/dist/form/validators/url.d.ts +45 -0
  83. package/dist/form/validators/validation-issue.d.ts +8 -0
  84. package/dist/i18n/descriptor.d.ts +54 -0
  85. package/dist/i18n/en.json.d.ts +49 -0
  86. package/dist/i18n/loader.d.ts +71 -0
  87. package/dist/i18n/locale-store.d.ts +46 -0
  88. package/dist/i18n/locale.d.ts +90 -0
  89. package/dist/i18n/message-format.d.ts +136 -0
  90. package/dist/i18n/resolve-localized.d.ts +17 -0
  91. package/dist/i18n/ru.json.d.ts +49 -0
  92. package/dist/i18n/translator.d.ts +61 -0
  93. package/dist/i18n/validation-message.d.ts +53 -0
  94. package/dist/i18n.d.ts +26 -0
  95. package/dist/i18n.js +86 -0
  96. package/dist/index.d.ts +18 -6
  97. package/dist/index.js +932 -2779
  98. package/dist/loader-BWkigpVe.js +52 -0
  99. package/dist/locale/en.d.ts +2 -0
  100. package/dist/locale/en.js +5 -0
  101. package/dist/locale/en.json +45 -0
  102. package/dist/locale/index.d.ts +18 -0
  103. package/dist/locale/ru.d.ts +2 -0
  104. package/dist/locale/ru.js +44 -0
  105. package/dist/locale/ru.json +45 -0
  106. package/dist/locale-CG54AU2Q.js +219 -0
  107. package/dist/locale.d.ts +2 -0
  108. package/dist/locale.js +9 -0
  109. package/dist/{state → model}/behaviors-value.d.ts +24 -6
  110. package/dist/{state/form-model.d.ts → model/create-model.d.ts} +18 -4
  111. package/dist/{state → model}/derived-registry.d.ts +1 -1
  112. package/dist/model/index.d.ts +42 -0
  113. package/dist/model/model-nodes.d.ts +190 -0
  114. package/dist/model/model-signals-proxy.d.ts +63 -0
  115. package/dist/model/model-value-proxy.d.ts +84 -0
  116. package/dist/{state → model}/safe-effect.d.ts +50 -2
  117. package/dist/model/types.d.ts +239 -0
  118. package/dist/model.d.ts +2 -0
  119. package/dist/model.js +27 -0
  120. package/dist/node-kind-C-r6ZMdo.js +15 -0
  121. package/dist/platforms/react/field-binding/field-adapter.d.ts +87 -0
  122. package/dist/platforms/react/field-binding/field-handle.d.ts +53 -0
  123. package/dist/platforms/react/form-bundle-context.d.ts +27 -0
  124. package/dist/{form → platforms/react}/hooks/types.d.ts +60 -38
  125. package/dist/platforms/react/hooks/use-form-bundle.d.ts +41 -0
  126. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  127. package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +13 -7
  128. package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +6 -6
  129. package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +7 -9
  130. package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +18 -18
  131. package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +9 -1
  132. package/dist/platforms/react/i18n/context.d.ts +18 -0
  133. package/dist/platforms/react/i18n/hooks.d.ts +65 -0
  134. package/dist/platforms/react/i18n/provider.d.ts +59 -0
  135. package/dist/platforms/react/index.d.ts +30 -0
  136. package/dist/react.d.ts +22 -0
  137. package/dist/react.js +505 -0
  138. package/dist/runtime-token.d.ts +22 -0
  139. package/dist/safe-effect-BazLOv1g.js +669 -0
  140. package/dist/schema-controller-CpiO2JoK.js +143 -0
  141. package/dist/signals.d.ts +15 -9
  142. package/dist/signals.js +11 -6
  143. package/dist/strategy-DzvnsWLh.js +375 -0
  144. package/dist/type-guards-D-N_5Ddh.js +19 -0
  145. package/dist/validation-issue-B9mjI8jz.js +7 -0
  146. package/dist/validation-message-Ced9MGxs.js +194 -0
  147. package/dist/validation.d.ts +1 -1
  148. package/dist/validation.js +11 -165
  149. package/dist/validators/email.d.ts +1 -1
  150. package/dist/validators/email.js +5 -8
  151. package/dist/validators/future-date.d.ts +1 -1
  152. package/dist/validators/future-date.js +10 -13
  153. package/dist/validators/integer.d.ts +1 -1
  154. package/dist/validators/integer.js +4 -7
  155. package/dist/validators/is-date.d.ts +1 -1
  156. package/dist/validators/is-date.js +5 -8
  157. package/dist/validators/is-number.d.ts +1 -1
  158. package/dist/validators/is-number.js +4 -7
  159. package/dist/validators/max-age.d.ts +1 -1
  160. package/dist/validators/max-age.js +8 -12
  161. package/dist/validators/max-date.d.ts +1 -1
  162. package/dist/validators/max-date.js +10 -13
  163. package/dist/validators/max-length.d.ts +1 -1
  164. package/dist/validators/max-length.js +7 -10
  165. package/dist/validators/max.d.ts +1 -1
  166. package/dist/validators/max.js +4 -7
  167. package/dist/validators/min-age.d.ts +1 -1
  168. package/dist/validators/min-age.js +10 -11
  169. package/dist/validators/min-date.d.ts +1 -1
  170. package/dist/validators/min-date.js +8 -11
  171. package/dist/validators/min-length.d.ts +1 -1
  172. package/dist/validators/min-length.js +4 -7
  173. package/dist/validators/min.d.ts +1 -1
  174. package/dist/validators/min.js +4 -7
  175. package/dist/validators/multiple-of.d.ts +1 -1
  176. package/dist/validators/multiple-of.js +11 -10
  177. package/dist/validators/non-negative.d.ts +1 -1
  178. package/dist/validators/non-negative.js +2 -5
  179. package/dist/validators/non-zero.d.ts +1 -1
  180. package/dist/validators/non-zero.js +4 -7
  181. package/dist/validators/past-date.d.ts +1 -1
  182. package/dist/validators/past-date.js +10 -13
  183. package/dist/validators/pattern.d.ts +1 -1
  184. package/dist/validators/pattern.js +5 -8
  185. package/dist/validators/phone.d.ts +1 -1
  186. package/dist/validators/phone.js +10 -11
  187. package/dist/validators/required.d.ts +1 -1
  188. package/dist/validators/required.js +4 -7
  189. package/dist/validators/url.d.ts +1 -1
  190. package/dist/validators/url.js +48 -17
  191. package/dist/validators.d.ts +1 -5
  192. package/dist/validators.js +98 -154
  193. package/docs/llms/01-api-reference.md +89 -0
  194. package/docs/llms/02-quick-start.md +181 -0
  195. package/docs/llms/03-api-signatures.md +494 -0
  196. package/docs/llms/04-common-patterns.md +204 -0
  197. package/docs/llms/05-common-mistakes.md +192 -0
  198. package/docs/llms/06-troubleshooting.md +16 -0
  199. package/docs/llms/07-complete-import.md +130 -0
  200. package/docs/llms/08-form-types.md +54 -0
  201. package/docs/llms/09-formschema.md +191 -0
  202. package/docs/llms/10-arrays.md +241 -0
  203. package/docs/llms/11-async-watchfield.md +53 -0
  204. package/docs/llms/12-array-cleanup.md +31 -0
  205. package/docs/llms/13-multi-step.md +162 -0
  206. package/docs/llms/14-extended-mistakes.md +101 -0
  207. package/docs/llms/15-project-structure.md +279 -0
  208. package/docs/llms/16-ui-components.md +229 -0
  209. package/docs/llms/17-nonexistent-api.md +278 -0
  210. package/docs/llms/18-conditional-fields.md +222 -0
  211. package/docs/llms/19-reading-values.md +100 -0
  212. package/docs/llms/20-compute-vs-watch.md +153 -0
  213. package/docs/llms/21-array-operations.md +163 -0
  214. package/docs/llms/22-cycle-detection.md +86 -0
  215. package/docs/llms/23-copy-from.md +141 -0
  216. package/docs/llms/24-sync-fields.md +115 -0
  217. package/docs/llms/25-reset-when.md +122 -0
  218. package/docs/llms/26-transform-value.md +136 -0
  219. package/docs/llms/27-revalidate-when.md +133 -0
  220. package/docs/llms/28-submit-and-reset.md +409 -0
  221. package/docs/llms/29-async-preload.md +203 -0
  222. package/docs/llms/30-type-safety-recipes.md +213 -0
  223. package/docs/llms/31-async-validator-debounce.md +178 -0
  224. package/docs/llms/32-async-options-loading.md +108 -0
  225. package/docs/llms/33-validation-strategy.md +305 -0
  226. package/docs/llms/34-i18n.md +298 -0
  227. package/docs/llms/35-unified-contract.md +309 -0
  228. package/docs/llms/36-issue-messages.md +284 -0
  229. package/docs/llms/37-compiled-schema.md +332 -0
  230. package/docs/llms/38-form-flow.md +396 -0
  231. package/llms-index.json +1 -0
  232. package/llms.txt +10014 -3826
  233. package/package.json +77 -15
  234. package/dist/behaviors-node-DGEFMTQu.js +0 -18
  235. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  236. package/dist/date-utils-dTT_x_Be.js +0 -31
  237. package/dist/derived-registry-CluZCQ7U.js +0 -16
  238. package/dist/form/behaviors.d.ts +0 -133
  239. package/dist/form/error-handler.d.ts +0 -166
  240. package/dist/form/factories/index.d.ts +0 -6
  241. package/dist/form/factories/node-factory.d.ts +0 -188
  242. package/dist/form/form-submitter.d.ts +0 -125
  243. package/dist/form/nodes/array-node.d.ts +0 -360
  244. package/dist/form/nodes/field-node.d.ts +0 -294
  245. package/dist/form/nodes/form-node.d.ts +0 -340
  246. package/dist/form/nodes/group-node.d.ts +0 -288
  247. package/dist/form/nodes/model-array-node.d.ts +0 -121
  248. package/dist/form/status-machine.d.ts +0 -153
  249. package/dist/form/types/deep-schema.d.ts +0 -116
  250. package/dist/form/types/form-proxy.d.ts +0 -141
  251. package/dist/form/unique-id.d.ts +0 -53
  252. package/dist/form/validation/validators/date-utils.d.ts +0 -30
  253. package/dist/form/validation/validators/email.d.ts +0 -23
  254. package/dist/form/validation/validators/future-date.d.ts +0 -23
  255. package/dist/form/validation/validators/integer.d.ts +0 -22
  256. package/dist/form/validation/validators/is-date.d.ts +0 -23
  257. package/dist/form/validation/validators/is-number.d.ts +0 -24
  258. package/dist/form/validation/validators/max-age.d.ts +0 -25
  259. package/dist/form/validation/validators/max-date.d.ts +0 -25
  260. package/dist/form/validation/validators/max-files.d.ts +0 -26
  261. package/dist/form/validation/validators/max-length.d.ts +0 -27
  262. package/dist/form/validation/validators/max-total-file-size.d.ts +0 -26
  263. package/dist/form/validation/validators/max.d.ts +0 -25
  264. package/dist/form/validation/validators/min-age.d.ts +0 -25
  265. package/dist/form/validation/validators/min-date.d.ts +0 -25
  266. package/dist/form/validation/validators/min-files.d.ts +0 -26
  267. package/dist/form/validation/validators/min-length.d.ts +0 -27
  268. package/dist/form/validation/validators/min.d.ts +0 -25
  269. package/dist/form/validation/validators/multiple-of.d.ts +0 -24
  270. package/dist/form/validation/validators/non-negative.d.ts +0 -22
  271. package/dist/form/validation/validators/non-zero.d.ts +0 -22
  272. package/dist/form/validation/validators/past-date.d.ts +0 -23
  273. package/dist/form/validation/validators/pattern.d.ts +0 -33
  274. package/dist/form/validation/validators/required.d.ts +0 -32
  275. package/dist/form/validation/validators/url.d.ts +0 -43
  276. package/dist/form/validation-schema.d.ts +0 -106
  277. package/dist/form/validation-strategy.d.ts +0 -55
  278. package/dist/form/validators.d.ts +0 -6
  279. package/dist/form-model-DYCzGGKF.js +0 -286
  280. package/dist/state/index.d.ts +0 -31
  281. package/dist/state/subscription-manager.d.ts +0 -180
  282. package/dist/state/types.d.ts +0 -144
  283. package/dist/state.d.ts +0 -2
  284. package/dist/state.js +0 -21
  285. package/dist/subscription-manager-705bls97.js +0 -171
@@ -0,0 +1,89 @@
1
+ ## 1. API Reference
2
+
3
+ ### Imports (CRITICALLY IMPORTANT)
4
+
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)]); ... })`
49
+ > из `@reformer/core/validation`; фабрики `required()`, `min(50000)`, `email()` возвращают
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`.
60
+
61
+ ### Type Values
62
+
63
+ - Опциональные числа: `number | null` (конвенция «пользователь очистил поле»)
64
+ - Опциональные строки: `string` (по умолчанию пустая строка) или `string | null`
65
+ - Форму данных объявляй через `interface` или `type` — оба варианта работают, см.
66
+ `30-type-safety-recipes.md`
67
+
68
+ ### React Hooks Comparison (CRITICALLY IMPORTANT)
69
+
70
+ | Hook | Return Type | Subscribes To | Use Case |
71
+ |------|-------------|---------------|----------|
72
+ | `useFormControl(field)` | `{ value, issues, disabled, touched, dirty, valid, invalid, pending, shouldShowError, shouldShowIssues, componentProps }` | Все сигналы поля | Полное состояние поля, инпуты |
73
+ | `useFormControlValue(field)` | `T` (значение напрямую) | Только сигнал value | Условный рендеринг |
74
+ | `useArrayLength(array)` | `number` | Только длина массива | Реактивная длина массива |
75
+ | `useFormFlow(bundle.flow)` | `{ current, index, completed, isFirst, isLast, validating }` | Сигналы потока шагов | Свои кнопки и индикатор шагов |
76
+ | `useIssueMessage(messages?)` | `(issue) => string` | Локаль | Текст замечания в своём компоненте |
77
+
78
+ **CRITICAL**: Не деструктурируй `useFormControlValue`! Он возвращает `T` напрямую, НЕ `{ value: T }`.
79
+
80
+ ```typescript
81
+ // WRONG - will always be undefined!
82
+ const { value: loanType } = useFormControlValue(control.loanType);
83
+
84
+ // CORRECT
85
+ const loanType = useFormControlValue(control.loanType);
86
+
87
+ // CORRECT - useFormControl returns object, destructuring OK
88
+ const { value, issues, disabled } = useFormControl(control.loanType);
89
+ ```
@@ -0,0 +1,181 @@
1
+ ## 1.5 QUICK START - Minimal Working Form
2
+
3
+ > **Schema-driven UI rule (read first)**: компонент И его пропсы (label, placeholder,
4
+ > options, type) объявляются в **узле схемы** (`component` + `componentProps`).
5
+ > В JSX рендерится один универсальный `<FormField control={form.x} />` из
6
+ > `@reformer/ui-kit` БЕЗ дополнительных props. Не пиши свои `Input`/`Select`/
7
+ > `Checkbox`-обёртки с `label`-prop'ами — это anti-pattern. См.
8
+ > `find_recipe(package="@reformer/ui-kit", topic="form-field-integration")`.
9
+
10
+ **Модель данных** — источник истины значений. Схема — дерево узлов, привязанных к ручкам модели
11
+ (`model: model.$.field`). Сборка идёт ОДНИМ вызовом `createForm`: он создаёт модель, строит форму,
12
+ запускает поведение и собирает уровень формы — проверку и отправку. Правил в схеме нет — они
13
+ живут в отдельной схеме `defineValidation` из `@reformer/core/validation` и уходят в сборку полем
14
+ `validation`; запускает их `bundle.submission.submit(handler)` / `bundle.validate()`. Текста у
15
+ правил нет: правило несёт код, строку по коду даёт словарь формы (`defineIssueMessages`).
16
+
17
+ ```typescript
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';
22
+ import { required, email } from '@reformer/core/validators';
23
+ import { ValidationMessagesProvider } from '@reformer/cdk';
24
+ import { FormField, Input, Button } from '@reformer/ui-kit';
25
+
26
+ // 1. Form data type — `interface` or `type`, both work
27
+ interface ContactForm {
28
+ name: string;
29
+ email: string;
30
+ }
31
+
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
+ });
54
+
55
+ // 4. Тексты замечаний по кодам — словарь формы (встроенный код `email` берёт текст из локали)
56
+ const contactMessages = defineIssueMessages({
57
+ 'name.required': 'Укажите имя',
58
+ 'email.required': 'Укажите email',
59
+ });
60
+
61
+ // 5. Сборка ОДНИМ вызовом: модель из initial + ноды поверх её сигналов + уровень формы.
62
+ const createContactForm = () =>
63
+ createForm<ContactForm>({
64
+ initial: { name: '', email: '' },
65
+ schema: contactSchema,
66
+ validation: contactValidation,
67
+ });
68
+
69
+ // 6. Use in React component — thin JSX, FormField does ALL heavy lifting
70
+ function ContactFormComponent() {
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');
81
+ };
82
+
83
+ return (
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>
91
+ );
92
+ }
93
+
94
+ // 7. Pass form to child components via props (NOT context!)
95
+ type FormStepProps = {
96
+ form: FormGroup<ContactForm>;
97
+ };
98
+
99
+ function FormStep({ form }: FormStepProps) {
100
+ return <FormField control={form.name} testId="name" />;
101
+ }
102
+ ```
103
+
104
+ > **Стабильность сборки.** Форму создают ОДИН раз: в React — `useFormBundle(фабрика)`, вне React —
105
+ > константой модуля. Иначе форма пересоздаётся на каждый рендер. См. `28-submit-and-reset.md`,
106
+ > `29-async-preload.md`.
107
+
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()`, когда форма больше не нужна.
114
+
115
+ ### Arrays of objects — узел `{ model, item }`
116
+
117
+ Массивы объектов принадлежат модели (`model.arrayField`). В схеме массив под-форм объявляется узлом
118
+ `{ model: model.$.<path>, item: (itemModel) => узел }`, где `item` строит разметку одной строки из
119
+ её под-модели (`FormModel<Item>`):
120
+
121
+ ```typescript
122
+ import { arrayOf, createForm, type FormModel, type FormSchemaNode } from '@reformer/core';
123
+ import { FieldArray, InputNumber, SelectAsync, Textarea } from '@reformer/ui-kit';
124
+
125
+ type PropertyItem = {
126
+ type: 'apartment' | 'house';
127
+ description: string;
128
+ estimatedValue: number;
129
+ };
130
+
131
+ type MyForm = { properties: PropertyItem[] };
132
+
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
+ ],
151
+ });
152
+
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
+ });
159
+
160
+ // Операции над массивом — на модели:
161
+ model.properties.push(); // новая строка по шаблону
162
+ model.properties.push({ type: 'house', description: '', estimatedValue: 0 });
163
+ model.properties.removeAt(0);
164
+ model.properties.length; // реактивная длина
165
+ form.properties.at(0); // форма строки (FormGroup<PropertyItem>)
166
+ form.properties.length; // число строк (число, не сигнал)
167
+ form.properties.keyAt(0); // стабильный ключ строки — для React `key`
168
+ ```
169
+
170
+ Подробнее в `10-arrays.md`, `21-array-operations.md` и `find_recipe(topic="form-array")`.
171
+
172
+ ### When to write your own field components (advanced — rare)
173
+
174
+ Свои компоненты нужны ТОЛЬКО если:
175
+
176
+ - ты намеренно избегаешь `@reformer/ui-kit` (например, проект уже имеет свою design system)
177
+ - нужен особый низкоуровневый input, который не покрывается `FormField` + `componentProps`
178
+
179
+ В этом случае см. секцию `## 14.5 UI COMPONENT PATTERNS` ниже — но даже там
180
+ паттерн **schema-driven** (label/options не из JSX-props, а из `componentProps` через
181
+ `useFormControl(...).componentProps`).