@reformer/core 11.0.0-beta.2 → 11.0.0-beta.4

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 (115) hide show
  1. package/dist/behaviors.d.ts +1 -1
  2. package/dist/behaviors.js +37 -37
  3. package/dist/create-model-Dxh9cfLp.js +97 -0
  4. package/dist/form/behaviors/collections.d.ts +50 -0
  5. package/dist/form/behaviors/context.d.ts +23 -0
  6. package/dist/form/behaviors/index.d.ts +28 -0
  7. package/dist/form/behaviors/internals.d.ts +26 -0
  8. package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +3 -3
  9. package/dist/form/behaviors/operators.d.ts +51 -0
  10. package/dist/form/behaviors/types.d.ts +17 -0
  11. package/dist/form/create-core-form.d.ts +70 -0
  12. package/dist/form/create-form.d.ts +1 -1
  13. package/dist/form/index.d.ts +12 -12
  14. package/dist/form/nodes/model-array-node.d.ts +1 -1
  15. package/dist/form/types/contracts.d.ts +9 -6
  16. package/dist/form/types/validation-schema.d.ts +1 -1
  17. package/dist/form/validation/config.d.ts +73 -0
  18. package/dist/form/validation/context.d.ts +27 -0
  19. package/dist/form/{error-handler.d.ts → validation/error-handler.d.ts} +1 -1
  20. package/dist/form/validation/index.d.ts +23 -28
  21. package/dist/form/validation/operators.d.ts +42 -0
  22. package/dist/form/validation/run.d.ts +45 -0
  23. package/dist/form/{validation-strategy.d.ts → validation/strategy.d.ts} +10 -4
  24. package/dist/form/validation/types.d.ts +28 -0
  25. package/dist/form/{validation/validators → validators}/date-utils.d.ts +1 -1
  26. package/dist/form/{validation/validators → validators}/email.d.ts +1 -1
  27. package/dist/form/{validation/validators → validators}/file-type.d.ts +1 -1
  28. package/dist/form/{validation/validators → validators}/file-utils.d.ts +1 -1
  29. package/dist/form/{validation/validators → validators}/future-date.d.ts +1 -1
  30. package/dist/form/{validation/validators → validators}/index.d.ts +6 -4
  31. package/dist/form/{validation/validators → validators}/integer.d.ts +1 -1
  32. package/dist/form/{validation/validators → validators}/is-date.d.ts +1 -1
  33. package/dist/form/{validation/validators → validators}/is-number.d.ts +1 -1
  34. package/dist/form/{validation/validators → validators}/max-age.d.ts +1 -1
  35. package/dist/form/{validation/validators → validators}/max-date.d.ts +1 -1
  36. package/dist/form/{validation/validators → validators}/max-file-size.d.ts +1 -1
  37. package/dist/form/{validation/validators → validators}/max-files.d.ts +1 -1
  38. package/dist/form/{validation/validators → validators}/max-length.d.ts +1 -1
  39. package/dist/form/{validation/validators → validators}/max-total-file-size.d.ts +1 -1
  40. package/dist/form/{validation/validators → validators}/max.d.ts +1 -1
  41. package/dist/form/{validation/validators → validators}/min-age.d.ts +1 -1
  42. package/dist/form/{validation/validators → validators}/min-date.d.ts +1 -1
  43. package/dist/form/{validation/validators → validators}/min-file-size.d.ts +1 -1
  44. package/dist/form/{validation/validators → validators}/min-files.d.ts +1 -1
  45. package/dist/form/{validation/validators → validators}/min-length.d.ts +1 -1
  46. package/dist/form/{validation/validators → validators}/min.d.ts +1 -1
  47. package/dist/form/{validation/validators → validators}/multiple-of.d.ts +1 -1
  48. package/dist/form/{validation/validators → validators}/non-negative.d.ts +1 -1
  49. package/dist/form/{validation/validators → validators}/non-zero.d.ts +1 -1
  50. package/dist/form/{validation/validators → validators}/past-date.d.ts +1 -1
  51. package/dist/form/{validation/validators → validators}/pattern.d.ts +1 -1
  52. package/dist/form/{validation/validators → validators}/phone.d.ts +1 -1
  53. package/dist/form/{validation/validators → validators}/required.d.ts +1 -1
  54. package/dist/form/{validation/validators → validators}/url.d.ts +1 -1
  55. package/dist/index.d.ts +7 -4
  56. package/dist/index.js +708 -479
  57. package/dist/{state/form-model.d.ts → model/create-model.d.ts} +0 -14
  58. package/dist/{state → model}/index.d.ts +10 -11
  59. package/dist/model/model-nodes.d.ts +60 -0
  60. package/dist/model/model-signals-proxy.d.ts +32 -0
  61. package/dist/model/model-value-proxy.d.ts +3 -0
  62. package/dist/{state → model}/safe-effect.d.ts +1 -1
  63. package/dist/model-signals-proxy-mV3WGdlO.js +233 -0
  64. package/dist/model.d.ts +2 -0
  65. package/dist/model.js +21 -0
  66. package/dist/{form → platforms/react}/hooks/types.d.ts +1 -1
  67. package/dist/platforms/react/hooks/use-form-bundle.d.ts +26 -0
  68. package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +3 -3
  69. package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +1 -1
  70. package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +3 -3
  71. package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +2 -2
  72. package/dist/platforms/react/index.d.ts +23 -0
  73. package/dist/signals.d.ts +1 -1
  74. package/dist/strategy-DA3JwxsR.js +170 -0
  75. package/dist/validation.d.ts +1 -1
  76. package/dist/validation.js +10 -165
  77. package/dist/validators/email.d.ts +1 -1
  78. package/dist/validators/future-date.d.ts +1 -1
  79. package/dist/validators/integer.d.ts +1 -1
  80. package/dist/validators/is-date.d.ts +1 -1
  81. package/dist/validators/is-number.d.ts +1 -1
  82. package/dist/validators/max-age.d.ts +1 -1
  83. package/dist/validators/max-date.d.ts +1 -1
  84. package/dist/validators/max-length.d.ts +1 -1
  85. package/dist/validators/max.d.ts +1 -1
  86. package/dist/validators/min-age.d.ts +1 -1
  87. package/dist/validators/min-date.d.ts +1 -1
  88. package/dist/validators/min-length.d.ts +1 -1
  89. package/dist/validators/min.d.ts +1 -1
  90. package/dist/validators/multiple-of.d.ts +1 -1
  91. package/dist/validators/non-negative.d.ts +1 -1
  92. package/dist/validators/non-zero.d.ts +1 -1
  93. package/dist/validators/past-date.d.ts +1 -1
  94. package/dist/validators/pattern.d.ts +1 -1
  95. package/dist/validators/phone.d.ts +1 -1
  96. package/dist/validators/required.d.ts +1 -1
  97. package/dist/validators/url.d.ts +1 -1
  98. package/dist/validators.d.ts +1 -1
  99. package/docs/llms/02-quick-start.md +14 -7
  100. package/docs/llms/15-project-structure.md +12 -8
  101. package/llms.txt +329 -53
  102. package/package.json +4 -4
  103. package/dist/form/behaviors.d.ts +0 -133
  104. package/dist/form/validation-schema.d.ts +0 -106
  105. package/dist/form/validators.d.ts +0 -11
  106. package/dist/form-model-DhW2HZOB.js +0 -323
  107. package/dist/state.d.ts +0 -2
  108. package/dist/state.js +0 -21
  109. package/dist/subscription-manager-705bls97.js +0 -171
  110. /package/dist/{state → form/nodes}/subscription-manager.d.ts +0 -0
  111. /package/dist/{state → model}/behaviors-value.d.ts +0 -0
  112. /package/dist/{state → model}/derived-registry.d.ts +0 -0
  113. /package/dist/{state → model}/types.d.ts +0 -0
  114. /package/dist/{behaviors-node-DGEFMTQu.js → node-DGEFMTQu.js} +0 -0
  115. /package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +0 -0
package/llms.txt CHANGED
@@ -113,14 +113,15 @@ const { value, errors, disabled } = useFormControl(control.loanType);
113
113
  > `Checkbox`-обёртки с `label`-prop'ами — это anti-pattern. См.
114
114
  > `find_recipe(package="@reformer/ui-kit", topic="form-field-integration")`.
115
115
 
116
- Архитектура M1: сначала создаётся **модель данных** (`createModel`), затем **форма**
117
- (`createForm({ model, schema })`), где схема привязывает поля к сигналам модели
118
- (`model.$.field`). Layout-схема НЕ несёт валидаторов — валидация живёт в отдельной
116
+ Архитектура M1: **модель данных** — источник истины, схема привязывает поля к её сигналам
117
+ (`model.$.field`), а сборка идёт ОДНИМ вызовом `createCoreForm` (для рендера ui-kit;
118
+ в рендерерах — `createReactForm` / `createJsonForm`), который создаёт модель, строит форму,
119
+ запускает поведение и собирает валидацию. Layout-схема НЕ несёт валидаторов — валидация живёт в отдельной
119
120
  схеме `defineValidationSchema` из `@reformer/core/validation` и запускается внешним
120
121
  раннером `validateModel(model, schema)`.
121
122
 
122
123
  ```typescript
123
- import { createModel, createForm, type FormProxy } from '@reformer/core';
124
+ import { createCoreForm, createModel, useFormBundle, type FormProxy } from '@reformer/core';
124
125
  import { defineValidationSchema, validate, validateModel } from '@reformer/core/validation';
125
126
  import { required, email } from '@reformer/core/validators';
126
127
  import { FormField, Input, Button } from '@reformer/ui-kit';
@@ -155,8 +156,14 @@ const contactValidation = defineValidationSchema<ContactForm>(({ model }) => {
155
156
  validate(model.$.email, [required({ message: 'Email is required' }), email({ message: 'Invalid email' })]);
156
157
  });
157
158
 
158
- // 5. Form — ноды поверх сигналов модели
159
- const form = createForm<ContactForm>({ model, schema });
159
+ // 5. Сборка ОДНИМ вызовом: модель + ноды поверх её сигналов + валидация.
160
+ // В React оборачивают в useFormBundle — ленивый useState, фабрика зовётся один раз.
161
+ const contact = createCoreForm<ContactForm>({
162
+ model,
163
+ schema: buildSchema, // билдер (model) => tree
164
+ validation: contactValidation,
165
+ });
166
+ const form = contact.form;
160
167
 
161
168
  // 6. Use in React component — thin JSX, FormField does ALL heavy lifting
162
169
  function ContactFormComponent() {
@@ -227,7 +234,7 @@ const schema = {
227
234
  properties: { array: model.properties, item: propertyItem },
228
235
  };
229
236
 
230
- const form = createForm<MyForm>({ model, schema });
237
+ const { form } = createCoreForm<MyForm>({ model, schema: () => schema });
231
238
 
232
239
  // Операции над массивом — на модели:
233
240
  model.properties.push({ type: 'apartment', description: '', estimatedValue: 0 });
@@ -1653,7 +1660,7 @@ src/
1653
1660
  │
1654
1661
  ├── forms/
1655
1662
  │ └── [form-name]/ # Form module — flat, one file per concern
1656
- │ ├── index.tsx # entry + whole form: createModel→createForm→<FormWizard> with all steps inline; arrays via FormArraySection
1663
+ │ ├── index.tsx # entry + whole form: ONE createCoreForm call → <FormWizard> with all steps inline; arrays via FormArraySection
1657
1664
  │ ├── types.ts # form type + enums + { value, label } option type + constant dictionaries
1658
1665
  │ ├── model.ts # createModel + initial values + empty-array-element factories
1659
1666
  │ ├── form.schema.ts # FormSchema: { value: model.$.x, component, componentProps }
@@ -1698,11 +1705,15 @@ export const creditApplicationBehavior = defineFormBehavior<CreditApplicationFor
1698
1705
  });
1699
1706
 
1700
1707
  // forms/credit-application/index.tsx — entry: assembles the form, renders <FormWizard> with all steps inline
1701
- import { createForm } from '@reformer/core';
1702
- export const createCreditApplicationForm = () => {
1703
- const model = createCreditApplicationModel();
1704
- return createForm({ model, schema: creditApplicationSchema(model), behavior: creditApplicationBehavior });
1705
- };
1708
+ import { createCoreForm } from '@reformer/core';
1709
+ // ONE call: model + form + behavior + validation. In the page: useFormBundle(createCreditApplicationForm).
1710
+ export const createCreditApplicationForm = () =>
1711
+ createCoreForm({
1712
+ model: createCreditApplicationModel(),
1713
+ schema: creditApplicationSchema, // builder (model) => tree
1714
+ behavior: creditApplicationBehavior,
1715
+ validation: creditApplicationValidation, // { steps, extras } → bundle.validation
1716
+ });
1706
1717
  ```
1707
1718
 
1708
1719
  ### Scaling up: folders (large forms)
@@ -1728,10 +1739,10 @@ forms/
1728
1739
  │
1729
1740
  ├── schema/ # The form definition
1730
1741
  │ ├── model.ts # createModel factory + initial values + array-element factories
1731
- │ ├── schema.ts # createForm schema tree ({ value: model.$.x, component })
1742
+ │ ├── schema.ts # schema builder (model) => tree ({ value: model.$.x, component })
1732
1743
  │ ├── validation.ts # defineValidationSchema + validateModel config ({ validateStep, validateAll })
1733
1744
  │ ├── behavior.ts # defineFormBehavior(...)
1734
- │ └── create-form.ts # Assembly: createForm({ model, schema, behavior })
1745
+ │ └── create-form.ts # Assembly: createCoreForm({ model, schema, behavior, validation })
1735
1746
  │
1736
1747
  └── components/
1737
1748
  ├── steps/ # One component per wizard step
@@ -4526,7 +4537,7 @@ Add Phone
4526
4537
  - {@link useFormControl} - хук для получения состояния
4527
4538
  - {@link FieldControlState} - состояние для полей
4528
4539
 
4529
- _Source: src/form/hooks/types.ts_
4540
+ _Source: src/platforms/react/hooks/types.ts_
4530
4541
 
4531
4542
  ### ArrayNode
4532
4543
 
@@ -4644,7 +4655,44 @@ _Source: src/form/types/contracts.ts_
4644
4655
  export type BehaviorCleanup = () => void;
4645
4656
  ```
4646
4657
 
4647
- _Source: src/state/behaviors-value.ts_
4658
+ _Source: src/model/behaviors-value.ts_
4659
+
4660
+ ### buildValidation
4661
+
4662
+ **Kind:** `function`
4663
+
4664
+ Собрать {@link FormValidationBundle} из правил. Принимает либо готовую схему (сахар для простых
4665
+ форм), либо {@link FormValidation} с шагами и стратегией.
4666
+
4667
+ Схема для `validateAll` собирается ОДИН раз на бандл — иначе ломается дедупликация прогонов.
4668
+
4669
+ **Signature:**
4670
+ ```typescript
4671
+ export function buildValidation<T>(
4672
+ model: FormModel<T>,
4673
+ validation?: FormValidation<T> | ValidationSchema<T>
4674
+ ): FormValidationBundle<T> | undefined
4675
+ ```
4676
+
4677
+ **Parameters:**
4678
+ - `model` — - Модель, по которой идут прогоны.
4679
+ - `validation` — - Правила; `undefined` — валидации у формы нет.
4680
+
4681
+ **Returns:** Бандл валидации либо `undefined`, если правила не заданы.
4682
+
4683
+ **Examples:**
4684
+
4685
+ ```ts
4686
+ const v = buildValidation(model, {
4687
+ steps: { loan: loanRules, applicant: applicantRules, confirm: null },
4688
+ extras: crossFieldRules,
4689
+ strategy: 'blur',
4690
+ });
4691
+ await v!.validateStep(1); // правила шага `loan`
4692
+ await v!.validateAll(); // все шаги + extras
4693
+ ```
4694
+
4695
+ _Source: src/form/validation/config.ts_
4648
4696
 
4649
4697
  ### computeFrom
4650
4698
 
@@ -4675,7 +4723,7 @@ export function computeFrom<R>(
4675
4723
  computeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price * qty);
4676
4724
  ```
4677
4725
 
4678
- _Source: src/state/behaviors-value.ts_
4726
+ _Source: src/model/behaviors-value.ts_
4679
4727
 
4680
4728
  ### ConfigWithSchema
4681
4729
 
@@ -4729,7 +4777,7 @@ export function copyFrom<T>(
4729
4777
  copyFrom(model.$.email, model.$.emailAdditional, { when: () => model.sameEmail });
4730
4778
  ```
4731
4779
 
4732
- _Source: src/state/behaviors-value.ts_
4780
+ _Source: src/model/behaviors-value.ts_
4733
4781
 
4734
4782
  ### CORE_RUNTIME_TOKEN
4735
4783
 
@@ -4765,6 +4813,75 @@ stampRuntime('@reformer/core', CORE_RUNTIME_TOKEN);
4765
4813
 
4766
4814
  _Source: src/runtime-token.ts_
4767
4815
 
4816
+ ### CoreForm
4817
+
4818
+ **Kind:** `interface`
4819
+
4820
+ Результат {@link createCoreForm}: модель, форма и (если заданы правила) собранная валидация.
4821
+
4822
+ **Signature:**
4823
+ ```typescript
4824
+ export interface CoreForm<T> {
4825
+ model: FormModel<T>;
4826
+ form: FormProxy<T>;
4827
+ validation?: FormValidationBundle<T>;
4828
+ }
4829
+ ```
4830
+
4831
+ _Source: src/form/create-core-form.ts_
4832
+
4833
+ ### createCoreForm
4834
+
4835
+ **Kind:** `function`
4836
+
4837
+ Собрать модель, форму и валидацию за один проход.
4838
+
4839
+ **Signature:**
4840
+ ```typescript
4841
+ export function createCoreForm<T extends object>(config: CreateCoreFormConfig<T>): CoreForm<T>
4842
+ ```
4843
+
4844
+ **Parameters:**
4845
+ - `config` — - {@link CreateCoreFormConfig}: (`initial` | `model`) + опц. `schema`, `behavior`,
4846
+ `validation`, `seed`, `setup`.
4847
+
4848
+ **Returns:**
4849
+
4850
+ **Examples:**
4851
+
4852
+ ```tsx
4853
+ const credit = useFormBundle(() =>
4854
+ createCoreForm<CreditForm>({
4855
+ model: createCreditModel(),
4856
+ schema: buildCreditSchema,
4857
+ behavior: creditBehavior,
4858
+ validation: { steps: { loan: loanRules, confirm: null }, extras: crossRules },
4859
+ })
4860
+ );
4861
+ return <FormWizard form={credit.form} config={credit.validation} steps={STEPS} />;
4862
+ ```
4863
+
4864
+ _Source: src/form/create-core-form.ts_
4865
+
4866
+ ### CreateCoreFormConfig
4867
+
4868
+ **Kind:** `interface`
4869
+
4870
+ Конфиг {@link createCoreForm}.
4871
+
4872
+ **Signature:**
4873
+ ```typescript
4874
+ export interface CreateCoreFormConfig<T> extends CreateFormConfigBase<T, CoreForm<T>> {
4875
+ /**
4876
+ * Билдер схемы формы. Именно функция, а не готовое дерево: листья схемы держат сами сигналы
4877
+ * модели (`value: model.$.email`), поэтому построить дерево до модели нечем.
4878
+ */
4879
+ schema?: (model: FormModel<T>) => FormSchemaNode;
4880
+ }
4881
+ ```
4882
+
4883
+ _Source: src/form/create-core-form.ts_
4884
+
4768
4885
  ### createForm
4769
4886
 
4770
4887
  **Kind:** `function`
@@ -4817,6 +4934,40 @@ const ok = await validateModel(model, validation);
4817
4934
 
4818
4935
  _Source: src/form/create-form.ts_
4819
4936
 
4937
+ ### CreateFormConfigBase
4938
+
4939
+ **Kind:** `interface`
4940
+
4941
+ Общая часть конфига всех фабрик формы.
4942
+
4943
+ **Signature:**
4944
+ ```typescript
4945
+ export interface CreateFormConfigBase<T, B> {
4946
+ /** Начальные значения — из них создаётся модель. Взаимоисключимо с `model`. */
4947
+ initial?: T;
4948
+ /** Готовая модель (если создана отдельной фабрикой). Приоритетнее `initial`. */
4949
+ model?: FormModel<T>;
4950
+ /** Декларативное поведение модели (compute/copyFrom/enableWhen/onChange). */
4951
+ behavior?: FormBehavior<T>;
4952
+ /** Правила валидации: готовая схема либо {@link FormValidation} со стратегией и шагами. */
4953
+ validation?: FormValidation<T> | ValidationSchema<T>;
4954
+ /**
4955
+ * Правка модели ДО сборки формы. Нужна там, где значение обязано существовать к моменту
4956
+ * построения нод — например, массив, наполняемый из вычислений (реактивные `onChange` на
4957
+ * инициализации не срабатывают).
4958
+ */
4959
+ seed?: (model: FormModel<T>) => void;
4960
+ /**
4961
+ * Донастройка ПОСЛЕ сборки. Единственное место для правок, которые обязаны идти следом за
4962
+ * `createForm`: поле, чьё значение уже массив, ноды не получает (см. `buildModelConfig`),
4963
+ * поэтому такой префилл выполняется здесь.
4964
+ */
4965
+ setup?: (bundle: B) => void;
4966
+ }
4967
+ ```
4968
+
4969
+ _Source: src/form/create-core-form.ts_
4970
+
4820
4971
  ### createFormFromModel
4821
4972
 
4822
4973
  **Kind:** `function`
@@ -4936,7 +5087,7 @@ model.tags.push('x');
4936
5087
  model.get(); // { email: 'a@b.c', profile: { name: 'Ada' }, tags: ['x'] }
4937
5088
  ```
4938
5089
 
4939
- _Source: src/state/form-model.ts_
5090
+ _Source: src/model/create-model.ts_
4940
5091
 
4941
5092
  ### disableWhen
4942
5093
 
@@ -4968,7 +5119,28 @@ export function disableWhen(
4968
5119
  disableWhen(model.$.discount, () => model.plan !== 'promo', { resetOnDisable: true });
4969
5120
  ```
4970
5121
 
4971
- _Source: src/form/behaviors-node.ts_
5122
+ _Source: src/form/behaviors/node.ts_
5123
+
5124
+ ### eachLeafSignal
5125
+
5126
+ **Kind:** `function`
5127
+
5128
+ Обойти ВСЕ листовые сигналы модели (включая элементы массивов), вызвав `visit` на каждом.
5129
+
5130
+ Внутри реактивного `effect` служит подпиской «любое поле изменилось»: `visit(sig => void sig.value)`
5131
+ подписывает на значения листьев, а обход массивов через `items.value` — на их состав. Так строятся
5132
+ триггеры `change`/`blur` стратегий валидации (см. `createFormValidation`), тем же паттерном, что
5133
+ `revalidateWhen`, но без ручного перечисления зависимостей.
5134
+
5135
+ **Signature:**
5136
+ ```typescript
5137
+ export function eachLeafSignal<T>(
5138
+ model: FormModel<T>,
5139
+ visit: (signal: PathAwareSignal<unknown>) => void
5140
+ ): void
5141
+ ```
5142
+
5143
+ _Source: src/model/create-model.ts_
4972
5144
 
4973
5145
  ### enableWhen
4974
5146
 
@@ -5012,7 +5184,7 @@ compute(model.$.initialPayment, () => model.propertyValue * 0.2, {
5012
5184
  });
5013
5185
  ```
5014
5186
 
5015
- _Source: src/form/behaviors-node.ts_
5187
+ _Source: src/form/behaviors/node.ts_
5016
5188
 
5017
5189
  ### ErrorFilterOptions
5018
5190
 
@@ -5070,7 +5242,7 @@ export enum ErrorStrategy {
5070
5242
  }
5071
5243
  ```
5072
5244
 
5073
- _Source: src/form/error-handler.ts_
5245
+ _Source: src/form/validation/error-handler.ts_
5074
5246
 
5075
5247
  ### FieldConfig
5076
5248
 
@@ -5332,7 +5504,7 @@ onChange={e => control.setValue(e.target.value)}
5332
5504
  - {@link useFormControl} - хук для получения состояния
5333
5505
  - {@link ArrayControlState} - состояние для массивов
5334
5506
 
5335
- _Source: src/form/hooks/types.ts_
5507
+ _Source: src/platforms/react/hooks/types.ts_
5336
5508
 
5337
5509
  ### FieldNode
5338
5510
 
@@ -5431,6 +5603,21 @@ todos.forEach((item, i) => {
5431
5603
 
5432
5604
  _Source: src/form/types/form-proxy.ts_
5433
5605
 
5606
+ ### FormBundleLike
5607
+
5608
+ **Kind:** `interface`
5609
+
5610
+ Минимум, который хук ожидает от бандла: опциональный контроллер живой валидации.
5611
+
5612
+ **Signature:**
5613
+ ```typescript
5614
+ export interface FormBundleLike {
5615
+ validation?: { controller: FormValidationController };
5616
+ }
5617
+ ```
5618
+
5619
+ _Source: src/platforms/react/hooks/use-form-bundle.ts_
5620
+
5434
5621
  ### FormControlsProxy
5435
5622
 
5436
5623
  **Kind:** `type`
@@ -5543,7 +5730,7 @@ try {
5543
5730
  }
5544
5731
  ```
5545
5732
 
5546
- _Source: src/form/error-handler.ts_
5733
+ _Source: src/form/validation/error-handler.ts_
5547
5734
 
5548
5735
  ### FormModel
5549
5736
 
@@ -5558,7 +5745,7 @@ FormModel — под-модель объекта `T`: value-доступ ({@link
5558
5745
  export type FormModel<T> = ModelObject<T> & ModelApi<T>;
5559
5746
  ```
5560
5747
 
5561
- _Source: src/state/types.ts_
5748
+ _Source: src/model/types.ts_
5562
5749
 
5563
5750
  ### FormNode
5564
5751
 
@@ -5823,6 +6010,70 @@ if (submitter.submitting.value) {
5823
6010
 
5824
6011
  _Source: src/form/form-submitter.ts_
5825
6012
 
6013
+ ### FormValidation
6014
+
6015
+ **Kind:** `interface`
6016
+
6017
+ Правила валидации формы — ДАННЫЕ (без привязки к рендеру).
6018
+
6019
+ ⚠️ `schema` и значения `steps` обязаны быть **стабильными ссылками**: отмена устаревших прогонов
6020
+ ключуется по паре `(model, schema)` через `WeakMap`, поэтому инлайн-стрелка ломает дедупликацию —
6021
+ валидация начнёт возвращать `false` от уже отменённых прогонов. Держите их
6022
+ module-level-константами (`defineValidationSchema`).
6023
+
6024
+ **Signature:**
6025
+ ```typescript
6026
+ export interface FormValidation<T> {
6027
+ /** Полный набор правил — для submit и `validateAll`. Без него собирается из `steps` + `extras`. */
6028
+ schema?: ValidationSchema<T>;
6029
+ /**
6030
+ * Пошаговая валидация визарда: ключ = `selector` шага. `null` означает «шаг без правил» ЯВНО —
6031
+ * чтобы опечатка в ключе не выглядела как пустой шаг.
6032
+ */
6033
+ steps?: Record<string, ValidationSchema<T> | null>;
6034
+ /** Cross-field правила, которые проверяются только целиком (в `validateAll`), но не по шагам. */
6035
+ extras?: ValidationSchema<T>;
6036
+ /** Когда запускать живую валидацию. По умолчанию `'submit'` (реактивно молчит). */
6037
+ strategy?: ValidationStrategyKind;
6038
+ debounce?: number;
6039
+ /** Режим live-фазы для `afterFirstSubmit`. По умолчанию `'change'`. */
6040
+ liveAfterSubmit?: 'change' | 'blur';
6041
+ }
6042
+ ```
6043
+
6044
+ _Source: src/form/validation/config.ts_
6045
+
6046
+ ### FormValidationBundle
6047
+
6048
+ **Kind:** `interface`
6049
+
6050
+ Собранная валидация формы. Структурно совместима с `FormWizardConfig` и `StepValidationConfig`
6051
+ из `@reformer/cdk`, поэтому уходит в визард как есть: `config={bundle.validation}` либо
6052
+ `patchProps({ form, ...bundle.validation })`.
6053
+
6054
+ **Signature:**
6055
+ ```typescript
6056
+ export interface FormValidationBundle<T> {
6057
+ /** Полная схема (стабильная ссылка) — та, по которой идёт `validateAll`. */
6058
+ readonly schema: ValidationSchema<T>;
6059
+ /** Селекторы шагов в порядке объявления. Пусто, если `steps` не заданы. */
6060
+ readonly stepSelectors: readonly string[];
6061
+ /** Полный прогон с раскрытием ошибок. Синоним {@link FormValidationBundle.validateAll}. */
6062
+ validate(): Promise<boolean>;
6063
+ validateAll(): Promise<boolean>;
6064
+ /** Прогон правил одного шага: по номеру (1-based, как у визарда) или по селектору. */
6065
+ validateStep(step: number | string): Promise<boolean>;
6066
+ /** Контроллер живой валидации ШАГА; `null` — у шага нет правил либо стратегия `submit`. */
6067
+ createStepController(step: number | string): FormValidationController | null;
6068
+ /** Контроллер живой валидации ФОРМЫ. Армится хуком (`useFormBundle`), не фабрикой. */
6069
+ readonly controller: FormValidationController;
6070
+ /** Идёт ли прогон — реактивный сигнал (для тонкой подписки в UI). */
6071
+ readonly validating: ReadonlySignal<boolean>;
6072
+ }
6073
+ ```
6074
+
6075
+ _Source: src/form/validation/config.ts_
6076
+
5826
6077
  ### FormValue
5827
6078
 
5828
6079
  **Kind:** `type`
@@ -6024,7 +6275,7 @@ if (!isDerived(model.$.total)) {
6024
6275
  **See also:**
6025
6276
  - {@link markDerived} - пометить сигнал производным
6026
6277
 
6027
- _Source: src/state/derived-registry.ts_
6278
+ _Source: src/model/derived-registry.ts_
6028
6279
 
6029
6280
  ### isFieldNode
6030
6281
 
@@ -6136,7 +6387,7 @@ export function isModelContainerSignal(value: unknown): boolean
6136
6387
  const isLeaf = (v: unknown) => isSignalLike(v) && !isModelContainerSignal(v);
6137
6388
  ```
6138
6389
 
6139
- _Source: src/state/form-model.ts_
6390
+ _Source: src/model/model-signals-proxy.ts_
6140
6391
 
6141
6392
  ### markDerived
6142
6393
 
@@ -6172,7 +6423,7 @@ markDerived(model.$.total);
6172
6423
  - {@link isDerived} - проверка пометки
6173
6424
  - {@link unmarkDerived} - снять пометку при dispose оператора
6174
6425
 
6175
- _Source: src/state/derived-registry.ts_
6426
+ _Source: src/model/derived-registry.ts_
6176
6427
 
6177
6428
  ### ModelApi
6178
6429
 
@@ -6215,7 +6466,7 @@ export interface ModelApi<T> {
6215
6466
  }
6216
6467
  ```
6217
6468
 
6218
- _Source: src/state/types.ts_
6469
+ _Source: src/model/types.ts_
6219
6470
 
6220
6471
  ### ModelArray
6221
6472
 
@@ -6261,7 +6512,7 @@ export interface ModelArray<U> {
6261
6512
  }
6262
6513
  ```
6263
6514
 
6264
- _Source: src/state/types.ts_
6515
+ _Source: src/model/types.ts_
6265
6516
 
6266
6517
  ### ModelArrayControl
6267
6518
 
@@ -6350,7 +6601,7 @@ export type ModelArraySignals<U, V> = ContainerSignal<V, 'length'> & {
6350
6601
  };
6351
6602
  ```
6352
6603
 
6353
- _Source: src/state/types.ts_
6604
+ _Source: src/model/types.ts_
6354
6605
 
6355
6606
  ### ModelGroupSignals
6356
6607
 
@@ -6367,7 +6618,7 @@ _Source: src/state/types.ts_
6367
6618
  export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>;
6368
6619
  ```
6369
6620
 
6370
- _Source: src/state/types.ts_
6621
+ _Source: src/model/types.ts_
6371
6622
 
6372
6623
  ### ModelObject
6373
6624
 
@@ -6384,7 +6635,7 @@ export type ModelObject<T> = {
6384
6635
  };
6385
6636
  ```
6386
6637
 
6387
- _Source: src/state/types.ts_
6638
+ _Source: src/model/types.ts_
6388
6639
 
6389
6640
  ### ModelSignals
6390
6641
 
@@ -6400,7 +6651,7 @@ export type ModelSignals<T> = {
6400
6651
  };
6401
6652
  ```
6402
6653
 
6403
- _Source: src/state/types.ts_
6654
+ _Source: src/model/types.ts_
6404
6655
 
6405
6656
  ### ModelValue
6406
6657
 
@@ -6425,7 +6676,7 @@ export type ModelValue<V> =
6425
6676
  : V;
6426
6677
  ```
6427
6678
 
6428
- _Source: src/state/types.ts_
6679
+ _Source: src/model/types.ts_
6429
6680
 
6430
6681
  ### NodeFactory
6431
6682
 
@@ -6512,7 +6763,7 @@ export type PathAwareSignal<T> = Signal<T> & {
6512
6763
  };
6513
6764
  ```
6514
6765
 
6515
- _Source: src/state/types.ts_
6766
+ _Source: src/model/types.ts_
6516
6767
 
6517
6768
  ### registerSignalNode
6518
6769
 
@@ -6569,7 +6820,7 @@ export function resetWhen<T>(
6569
6820
  resetWhen(model.$.cardNumber, () => model.paymentType !== 'card', { resetValue: '' });
6570
6821
  ```
6571
6822
 
6572
- _Source: src/state/behaviors-value.ts_
6823
+ _Source: src/model/behaviors-value.ts_
6573
6824
 
6574
6825
  ### revalidateWhen
6575
6826
 
@@ -6592,7 +6843,7 @@ export function revalidateWhen(
6592
6843
  revalidateWhen([model.$.maxAmount], () => void validateModel(model, schema));
6593
6844
  ```
6594
6845
 
6595
- _Source: src/state/behaviors-value.ts_
6846
+ _Source: src/model/behaviors-value.ts_
6596
6847
 
6597
6848
  ### runOutsideEffect
6598
6849
 
@@ -6626,7 +6877,7 @@ effect(() => {
6626
6877
  });
6627
6878
  ```
6628
6879
 
6629
- _Source: src/state/safe-effect.ts_
6880
+ _Source: src/model/safe-effect.ts_
6630
6881
 
6631
6882
  ### safeCallback
6632
6883
 
@@ -6665,7 +6916,7 @@ effect(() => {
6665
6916
  });
6666
6917
  ```
6667
6918
 
6668
- _Source: src/state/safe-effect.ts_
6919
+ _Source: src/model/safe-effect.ts_
6669
6920
 
6670
6921
  ### safeDebouncedCallback
6671
6922
 
@@ -6703,7 +6954,7 @@ return effect(() => {
6703
6954
  });
6704
6955
  ```
6705
6956
 
6706
- _Source: src/state/safe-effect.ts_
6957
+ _Source: src/model/safe-effect.ts_
6707
6958
 
6708
6959
  ### SchemaArrayControl
6709
6960
 
@@ -6846,7 +7097,7 @@ class FieldNode {
6846
7097
  }
6847
7098
  ```
6848
7099
 
6849
- _Source: src/state/subscription-manager.ts_
7100
+ _Source: src/form/nodes/subscription-manager.ts_
6850
7101
 
6851
7102
  ### syncFields
6852
7103
 
@@ -6870,7 +7121,7 @@ export function syncFields<T>(
6870
7121
  syncFields(model.$.field1, model.$.field2);
6871
7122
  ```
6872
7123
 
6873
- _Source: src/state/behaviors-value.ts_
7124
+ _Source: src/model/behaviors-value.ts_
6874
7125
 
6875
7126
  ### transformValue
6876
7127
 
@@ -6893,7 +7144,7 @@ export function transformValue<T>(
6893
7144
  transformValue(model.$.promoCode, (v) => (v ?? '').toUpperCase());
6894
7145
  ```
6895
7146
 
6896
- _Source: src/state/behaviors-value.ts_
7147
+ _Source: src/model/behaviors-value.ts_
6897
7148
 
6898
7149
  ### UnknownRecord
6899
7150
 
@@ -6943,7 +7194,7 @@ onDispose(() => unmarkDerived(model.$.total)); // при снятии compute с
6943
7194
  **See also:**
6944
7195
  - {@link markDerived} - пометить сигнал производным
6945
7196
 
6946
- _Source: src/state/derived-registry.ts_
7197
+ _Source: src/model/derived-registry.ts_
6947
7198
 
6948
7199
  ### useArrayLength
6949
7200
 
@@ -6981,7 +7232,32 @@ function ArrayRenderer({ arrayNode }) {
6981
7232
  }
6982
7233
  ```
6983
7234
 
6984
- _Source: src/form/hooks/useArrayLength.ts_
7235
+ _Source: src/platforms/react/hooks/useArrayLength.ts_
7236
+
7237
+ ### useFormBundle
7238
+
7239
+ **Kind:** `function`
7240
+
7241
+ Собрать форму один раз и держать её стабильной; живую стратегию валидации армировать в эффекте
7242
+ (не при SSR — там эффекты не выполняются).
7243
+
7244
+ **Signature:**
7245
+ ```typescript
7246
+ export function useFormBundle<B extends FormBundleLike>(factory: () => B): B
7247
+ ```
7248
+
7249
+ **Parameters:**
7250
+ - `factory` — - Фабрика бандла, обычно `() => createCoreForm({…})`.
7251
+
7252
+ **Returns:** Стабильный бандл.
7253
+
7254
+ **Examples:**
7255
+
7256
+ ```tsx
7257
+ const credit = useFormBundle(() => createCoreForm<CreditForm>({ model: createCreditModel() }));
7258
+ ```
7259
+
7260
+ _Source: src/platforms/react/hooks/use-form-bundle.ts_
6985
7261
 
6986
7262
  ### useFormControl
6987
7263
 
@@ -7215,7 +7491,7 @@ return <div>Items: {length}</div>;
7215
7491
  - {@link FieldControlState} - тип состояния для FieldNode
7216
7492
  - {@link ArrayControlState} - тип состояния для ArrayNode
7217
7493
 
7218
- _Source: src/form/hooks/useFormControl.ts_
7494
+ _Source: src/platforms/react/hooks/useFormControl.ts_
7219
7495
 
7220
7496
  ### useFormControlValue
7221
7497
 
@@ -7396,7 +7672,7 @@ return (
7396
7672
  - {@link useFormControl} - для полного состояния поля
7397
7673
  - {@link FieldNode} - тип контрола поля
7398
7674
 
7399
- _Source: src/form/hooks/useFormControlValue.ts_
7675
+ _Source: src/platforms/react/hooks/useFormControlValue.ts_
7400
7676
 
7401
7677
  ### useFormValidation
7402
7678
 
@@ -7431,7 +7707,7 @@ function MyForm() {
7431
7707
  }
7432
7708
  ```
7433
7709
 
7434
- _Source: src/form/hooks/use-form-validation.ts_
7710
+ _Source: src/platforms/react/hooks/use-form-validation.ts_
7435
7711
 
7436
7712
  ### UseFormValidationArgs
7437
7713
 
@@ -7453,7 +7729,7 @@ export interface UseFormValidationArgs<T> {
7453
7729
  }
7454
7730
  ```
7455
7731
 
7456
- _Source: src/form/hooks/use-form-validation.ts_
7732
+ _Source: src/platforms/react/hooks/use-form-validation.ts_
7457
7733
 
7458
7734
  ### UseFormValidationResult
7459
7735
 
@@ -7471,7 +7747,7 @@ export interface UseFormValidationResult {
7471
7747
  }
7472
7748
  ```
7473
7749
 
7474
- _Source: src/form/hooks/use-form-validation.ts_
7750
+ _Source: src/platforms/react/hooks/use-form-validation.ts_
7475
7751
 
7476
7752
  ### ValidateOptions
7477
7753
 
@@ -7574,4 +7850,4 @@ watchField(model.$.country, async (country) => {
7574
7850
  });
7575
7851
  ```
7576
7852
 
7577
- _Source: src/state/behaviors-value.ts_
7853
+ _Source: src/model/behaviors-value.ts_