@reformer/core 11.0.0-beta.8 → 11.0.0-beta.9

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 (224) hide show
  1. package/README.md +91 -73
  2. package/dist/behaviors-value-HA_Q03hc.js +108 -0
  3. package/dist/behaviors.js +370 -242
  4. package/dist/{create-model-BBRHhHwK.js → create-model-BvcbNPgL.js} +6 -6
  5. package/dist/date-utils-90-qZbse.js +43 -0
  6. package/dist/{en-CjAqn7h0.js → en-HP8XEych.js} +6 -3
  7. package/dist/form/aggregate-signals.d.ts +21 -63
  8. package/dist/form/behaviors/collections.d.ts +28 -7
  9. package/dist/form/behaviors/context.d.ts +19 -2
  10. package/dist/form/behaviors/index.d.ts +3 -3
  11. package/dist/form/behaviors/internals.d.ts +9 -2
  12. package/dist/form/behaviors/node.d.ts +25 -2
  13. package/dist/form/behaviors/operators.d.ts +17 -9
  14. package/dist/form/behaviors/schema-operators.d.ts +6 -4
  15. package/dist/form/behaviors/types.d.ts +12 -4
  16. package/dist/form/create-form.d.ts +47 -35
  17. package/dist/form/flow/flow.d.ts +87 -0
  18. package/dist/form/form-bundle.d.ts +45 -28
  19. package/dist/form/form-config-base.d.ts +46 -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 +16 -21
  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 +30 -14
  37. package/dist/form/signal-node-registry.d.ts +6 -7
  38. package/dist/form/submission.d.ts +93 -0
  39. package/dist/form/type-guards.d.ts +14 -73
  40. package/dist/form/types/contracts.d.ts +19 -92
  41. package/dist/form/types/field-config.d.ts +27 -0
  42. package/dist/form/types/index.d.ts +5 -57
  43. package/dist/form/types/nodes.d.ts +159 -0
  44. package/dist/form/types/schema-node.d.ts +139 -63
  45. package/dist/form/types/validation-schema.d.ts +23 -27
  46. package/dist/form/validation/context.d.ts +42 -7
  47. package/dist/form/validation/index.d.ts +9 -8
  48. package/dist/form/validation/operators.d.ts +22 -30
  49. package/dist/form/validation/run.d.ts +93 -18
  50. package/dist/form/validation/strategy.d.ts +41 -13
  51. package/dist/form/validation/types.d.ts +74 -20
  52. package/dist/form/validators/date-utils.d.ts +13 -1
  53. package/dist/form/validators/email.d.ts +8 -7
  54. package/dist/form/validators/file-type.d.ts +8 -7
  55. package/dist/form/validators/file-utils.d.ts +2 -1
  56. package/dist/form/validators/future-date.d.ts +8 -7
  57. package/dist/form/validators/index.d.ts +1 -1
  58. package/dist/form/validators/integer.d.ts +8 -7
  59. package/dist/form/validators/is-date.d.ts +11 -9
  60. package/dist/form/validators/is-number.d.ts +11 -9
  61. package/dist/form/validators/max-age.d.ts +13 -9
  62. package/dist/form/validators/max-date.d.ts +8 -7
  63. package/dist/form/validators/max-file-size.d.ts +8 -7
  64. package/dist/form/validators/max-files.d.ts +8 -7
  65. package/dist/form/validators/max-length.d.ts +14 -7
  66. package/dist/form/validators/max-total-file-size.d.ts +8 -7
  67. package/dist/form/validators/max.d.ts +10 -8
  68. package/dist/form/validators/min-age.d.ts +12 -9
  69. package/dist/form/validators/min-date.d.ts +8 -7
  70. package/dist/form/validators/min-file-size.d.ts +8 -7
  71. package/dist/form/validators/min-files.d.ts +11 -9
  72. package/dist/form/validators/min-length.d.ts +14 -7
  73. package/dist/form/validators/min.d.ts +10 -8
  74. package/dist/form/validators/multiple-of.d.ts +10 -8
  75. package/dist/form/validators/non-negative.d.ts +8 -7
  76. package/dist/form/validators/non-zero.d.ts +8 -7
  77. package/dist/form/validators/past-date.d.ts +8 -7
  78. package/dist/form/validators/pattern.d.ts +9 -8
  79. package/dist/form/validators/phone.d.ts +8 -7
  80. package/dist/form/validators/required.d.ts +11 -9
  81. package/dist/form/validators/url.d.ts +20 -13
  82. package/dist/form/validators/validation-issue.d.ts +8 -0
  83. package/dist/i18n/descriptor.d.ts +1 -1
  84. package/dist/i18n/en.json.d.ts +5 -1
  85. package/dist/i18n/locale-store.d.ts +7 -0
  86. package/dist/i18n/message-format.d.ts +24 -4
  87. package/dist/i18n/ru.json.d.ts +5 -1
  88. package/dist/i18n/translator.d.ts +11 -0
  89. package/dist/i18n/validation-message.d.ts +42 -7
  90. package/dist/i18n.d.ts +7 -12
  91. package/dist/i18n.js +66 -283
  92. package/dist/index.d.ts +16 -7
  93. package/dist/index.js +924 -2855
  94. package/dist/loader-BWkigpVe.js +52 -0
  95. package/dist/locale/en.js +1 -1
  96. package/dist/locale/en.json +4 -1
  97. package/dist/locale/ru.js +4 -1
  98. package/dist/locale/ru.json +4 -1
  99. package/dist/locale-CG54AU2Q.js +219 -0
  100. package/dist/locale.js +1 -1
  101. package/dist/model/behaviors-value.d.ts +24 -6
  102. package/dist/model/create-model.d.ts +2 -2
  103. package/dist/model/derived-registry.d.ts +1 -1
  104. package/dist/model/index.d.ts +11 -5
  105. package/dist/model/model-nodes.d.ts +79 -12
  106. package/dist/model/model-signals-proxy.d.ts +5 -6
  107. package/dist/model/model-value-proxy.d.ts +20 -15
  108. package/dist/model/safe-effect.d.ts +33 -1
  109. package/dist/model/types.d.ts +63 -13
  110. package/dist/model.js +20 -18
  111. package/dist/node-kind-C-r6ZMdo.js +15 -0
  112. package/dist/platforms/react/field-binding/field-adapter.d.ts +1 -1
  113. package/dist/platforms/react/field-binding/field-handle.d.ts +5 -2
  114. package/dist/platforms/react/form-bundle-context.d.ts +2 -2
  115. package/dist/platforms/react/hooks/types.d.ts +57 -38
  116. package/dist/platforms/react/hooks/use-form-bundle.d.ts +19 -4
  117. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  118. package/dist/platforms/react/hooks/use-form-validation.d.ts +12 -6
  119. package/dist/platforms/react/hooks/useArrayLength.d.ts +6 -6
  120. package/dist/platforms/react/hooks/useFormControl.d.ts +7 -9
  121. package/dist/platforms/react/hooks/useFormControlValue.d.ts +18 -19
  122. package/dist/platforms/react/hooks/useSignalSubscription.d.ts +9 -1
  123. package/dist/platforms/react/i18n/context.d.ts +6 -1
  124. package/dist/platforms/react/i18n/hooks.d.ts +16 -10
  125. package/dist/platforms/react/i18n/provider.d.ts +9 -2
  126. package/dist/platforms/react/index.d.ts +6 -4
  127. package/dist/react.d.ts +22 -0
  128. package/dist/react.js +505 -0
  129. package/dist/runtime-token.d.ts +1 -2
  130. package/dist/safe-effect-BbtX3KuN.js +643 -0
  131. package/dist/schema-controller-CpiO2JoK.js +143 -0
  132. package/dist/signals.d.ts +15 -9
  133. package/dist/signals.js +11 -6
  134. package/dist/strategy-CoFSemuP.js +375 -0
  135. package/dist/type-guards-D-N_5Ddh.js +19 -0
  136. package/dist/validation-issue-B9mjI8jz.js +7 -0
  137. package/dist/validation-message-Ced9MGxs.js +194 -0
  138. package/dist/validation.js +9 -9
  139. package/dist/validators/email.js +5 -5
  140. package/dist/validators/future-date.js +8 -8
  141. package/dist/validators/integer.js +3 -3
  142. package/dist/validators/is-date.js +4 -4
  143. package/dist/validators/is-number.js +4 -4
  144. package/dist/validators/max-age.js +8 -9
  145. package/dist/validators/max-date.js +8 -8
  146. package/dist/validators/max-length.js +7 -7
  147. package/dist/validators/max.js +4 -4
  148. package/dist/validators/min-age.js +10 -8
  149. package/dist/validators/min-date.js +3 -3
  150. package/dist/validators/min-length.js +5 -5
  151. package/dist/validators/min.js +4 -4
  152. package/dist/validators/multiple-of.js +11 -7
  153. package/dist/validators/non-negative.js +3 -3
  154. package/dist/validators/non-zero.js +3 -3
  155. package/dist/validators/past-date.js +8 -8
  156. package/dist/validators/pattern.js +5 -5
  157. package/dist/validators/phone.js +11 -9
  158. package/dist/validators/required.js +2 -2
  159. package/dist/validators/url.js +48 -12
  160. package/dist/validators.js +17 -17
  161. package/docs/llms/01-api-reference.md +60 -34
  162. package/docs/llms/02-quick-start.md +111 -80
  163. package/docs/llms/03-api-signatures.md +368 -153
  164. package/docs/llms/04-common-patterns.md +58 -56
  165. package/docs/llms/05-common-mistakes.md +69 -44
  166. package/docs/llms/06-troubleshooting.md +14 -9
  167. package/docs/llms/07-complete-import.md +74 -43
  168. package/docs/llms/08-form-types.md +11 -4
  169. package/docs/llms/09-formschema.md +129 -81
  170. package/docs/llms/10-arrays.md +106 -75
  171. package/docs/llms/11-async-watchfield.md +2 -2
  172. package/docs/llms/13-multi-step.md +134 -63
  173. package/docs/llms/14-extended-mistakes.md +20 -17
  174. package/docs/llms/15-project-structure.md +221 -74
  175. package/docs/llms/16-ui-components.md +55 -42
  176. package/docs/llms/17-nonexistent-api.md +199 -32
  177. package/docs/llms/18-conditional-fields.md +66 -32
  178. package/docs/llms/19-reading-values.md +15 -3
  179. package/docs/llms/20-compute-vs-watch.md +16 -10
  180. package/docs/llms/21-array-operations.md +51 -27
  181. package/docs/llms/22-cycle-detection.md +1 -1
  182. package/docs/llms/23-copy-from.md +2 -2
  183. package/docs/llms/24-sync-fields.md +6 -5
  184. package/docs/llms/25-reset-when.md +14 -7
  185. package/docs/llms/26-transform-value.md +4 -4
  186. package/docs/llms/27-revalidate-when.md +16 -15
  187. package/docs/llms/28-submit-and-reset.md +276 -128
  188. package/docs/llms/29-async-preload.md +39 -29
  189. package/docs/llms/30-type-safety-recipes.md +105 -51
  190. package/docs/llms/31-async-validator-debounce.md +96 -53
  191. package/docs/llms/33-validation-strategy.md +177 -65
  192. package/docs/llms/34-i18n.md +69 -43
  193. package/docs/llms/35-unified-contract.md +100 -39
  194. package/docs/llms/36-issue-messages.md +284 -0
  195. package/docs/llms/37-compiled-schema.md +332 -0
  196. package/docs/llms/38-form-flow.md +397 -0
  197. package/llms-index.json +1 -1
  198. package/llms.txt +6084 -3420
  199. package/package.json +23 -4
  200. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  201. package/dist/date-utils-dTT_x_Be.js +0 -31
  202. package/dist/form/create-core-form.d.ts +0 -72
  203. package/dist/form/factories/index.d.ts +0 -6
  204. package/dist/form/factories/node-factory.d.ts +0 -189
  205. package/dist/form/form-submitter.d.ts +0 -121
  206. package/dist/form/nodes/array-node.d.ts +0 -276
  207. package/dist/form/nodes/field-node.d.ts +0 -297
  208. package/dist/form/nodes/form-node.d.ts +0 -326
  209. package/dist/form/nodes/group-node.d.ts +0 -284
  210. package/dist/form/nodes/model-array-node.d.ts +0 -126
  211. package/dist/form/nodes/subscription-manager.d.ts +0 -180
  212. package/dist/form/status-machine.d.ts +0 -115
  213. package/dist/form/types/deep-schema.d.ts +0 -107
  214. package/dist/form/types/form-proxy.d.ts +0 -141
  215. package/dist/form/unique-id.d.ts +0 -45
  216. package/dist/form/validation/config.d.ts +0 -73
  217. package/dist/form/validation/error-handler.d.ts +0 -166
  218. package/dist/form/validators/validation-error.d.ts +0 -8
  219. package/dist/index-BrNkQj1y.js +0 -105
  220. package/dist/loader-Dv_Hl7JC.js +0 -216
  221. package/dist/model-value-proxy-caTmAiUd.js +0 -419
  222. package/dist/node-BeV_lV5i.js +0 -100
  223. package/dist/strategy-DgzELWno.js +0 -204
  224. package/dist/validation-error-B-U3RsV0.js +0 -11
@@ -1,326 +0,0 @@
1
- import { ReadonlySignal, Signal } from '@preact/signals-core';
2
- import { FieldStatus, ValidationError, ErrorFilterOptions } from '../types/index';
3
- /**
4
- * Опции для setValue
5
- * @group Nodes
6
- */
7
- export interface SetValueOptions {
8
- /** Не вызывать событие изменения (не триггерить валидацию) */
9
- emitEvent?: boolean;
10
- }
11
- /**
12
- * Абстрактный базовый класс для всех узлов формы.
13
- *
14
- * Все узлы (поля, группы, массивы) наследуют от этого класса и реализуют
15
- * единый интерфейс для работы с состоянием и валидацией.
16
- *
17
- * Template Method паттерн используется для управления состоянием:
18
- * общие signals (`_touched`, `_dirty`, `_status`) живут в базовом классе,
19
- * publi-методы (`markAsTouched`, `disable`, …) реализованы здесь, а protected
20
- * hooks (`onMarkAsTouched`, `onDisable`, …) переопределяются в наследниках.
21
- *
22
- * @group Nodes
23
- *
24
- * @example
25
- * ```typescript
26
- * // FormNode не используется напрямую — экземпляры приходят из getReformerForm.
27
- * import { getReformerForm, FormNode } from '@reformer/core';
28
- *
29
- * const form = getReformerForm({ email: '' });
30
- * form.email instanceof FormNode; // true
31
- * form.email.markAsTouched();
32
- * ```
33
- */
34
- export declare abstract class FormNode<T> {
35
- /**
36
- * Пользователь взаимодействовал с узлом (touched)
37
- * Protected: наследники могут читать/изменять через методы
38
- */
39
- protected _touched: Signal<boolean>;
40
- /**
41
- * Значение узла было изменено (dirty)
42
- * Protected: наследники могут читать/изменять через методы
43
- */
44
- protected _dirty: Signal<boolean>;
45
- /**
46
- * Текущий статус узла
47
- * Protected: наследники могут читать/изменять через методы
48
- */
49
- protected _status: Signal<FieldStatus>;
50
- /**
51
- * Пользователь взаимодействовал с узлом (touched)
52
- * Computed из _touched для предоставления readonly интерфейса
53
- */
54
- readonly touched: ReadonlySignal<boolean>;
55
- /**
56
- * Значение узла было изменено (dirty)
57
- * Computed из _dirty для предоставления readonly интерфейса
58
- */
59
- readonly dirty: ReadonlySignal<boolean>;
60
- /**
61
- * Текущий статус узла
62
- * Computed из _status для предоставления readonly интерфейса
63
- */
64
- readonly status: ReadonlySignal<FieldStatus>;
65
- /**
66
- * Узел отключен (disabled)
67
- */
68
- readonly disabled: ReadonlySignal<boolean>;
69
- /**
70
- * Текущее значение узла
71
- * - Для FieldNode: значение поля
72
- * - Для GroupNode: объект со значениями всех полей
73
- * - Для ArrayNode: массив значений элементов
74
- */
75
- abstract readonly value: ReadonlySignal<T>;
76
- /**
77
- * Узел валиден (все валидаторы прошли успешно)
78
- */
79
- abstract readonly valid: ReadonlySignal<boolean>;
80
- /**
81
- * Узел невалиден (есть ошибки валидации)
82
- */
83
- abstract readonly invalid: ReadonlySignal<boolean>;
84
- /**
85
- * Выполняется асинхронная валидация
86
- */
87
- abstract readonly pending: ReadonlySignal<boolean>;
88
- /**
89
- * Массив ошибок валидации
90
- */
91
- abstract readonly errors: ReadonlySignal<ValidationError[]>;
92
- /**
93
- * Получить значение узла (non-reactive)
94
- * Использует .peek() для получения значения без создания зависимости
95
- */
96
- abstract getValue(): T;
97
- /**
98
- * Установить значение узла
99
- * @param value - новое значение
100
- * @param options - опции установки значения
101
- */
102
- abstract setValue(value: T, options?: SetValueOptions): void;
103
- /**
104
- * Частично обновить значение узла
105
- * Для FieldNode: работает как setValue
106
- * Для GroupNode: обновляет только указанные поля
107
- * Для ArrayNode: обновляет только указанные элементы
108
- *
109
- * @param value - частичное значение для обновления
110
- */
111
- abstract patchValue(value: Partial<T>): void;
112
- /**
113
- * Сбросить узел к начальному состоянию
114
- * @param value - опциональное новое начальное значение
115
- */
116
- abstract reset(value?: T): void;
117
- /**
118
- * Запустить валидацию узла
119
- * @returns `Promise<boolean>` - true если валидация успешна
120
- */
121
- abstract validate(): Promise<boolean>;
122
- /**
123
- * Установить ошибки валидации извне
124
- * @param errors - массив ошибок
125
- */
126
- abstract setErrors(errors: ValidationError[]): void;
127
- /**
128
- * Очистить ошибки валидации
129
- */
130
- abstract clearErrors(): void;
131
- /**
132
- * Получить ошибки валидации с фильтрацией
133
- *
134
- * Позволяет фильтровать ошибки по различным критериям:
135
- * - По коду ошибки
136
- * - По сообщению (частичное совпадение)
137
- * - По параметрам
138
- * - Через кастомный предикат
139
- *
140
- * Без параметров возвращает все ошибки (эквивалент errors.value)
141
- *
142
- * @param options - Опции фильтрации ошибок
143
- * @returns Отфильтрованный массив ошибок валидации
144
- *
145
- * @example
146
- * ```typescript
147
- * // Все ошибки
148
- * const allErrors = form.getErrors();
149
- *
150
- * // Ошибки с конкретным кодом
151
- * const requiredErrors = form.getErrors({ code: 'required' });
152
- *
153
- * // Ошибки с несколькими кодами
154
- * const errors = form.getErrors({ code: ['required', 'email'] });
155
- *
156
- * // Ошибки по сообщению
157
- * const passwordErrors = form.getErrors({ message: 'Password' });
158
- *
159
- * // Ошибки по параметрам
160
- * const minLengthErrors = form.getErrors({
161
- * params: { minLength: 8 }
162
- * });
163
- *
164
- * // Кастомная фильтрация
165
- * const customErrors = form.getErrors({
166
- * predicate: (err) => err.code.startsWith('custom_')
167
- * });
168
- * ```
169
- */
170
- getErrors(options?: ErrorFilterOptions): ValidationError[];
171
- /**
172
- * Отметить узел как touched (пользователь взаимодействовал)
173
- *
174
- * Template Method: обновляет signal в базовом классе,
175
- * вызывает hook для кастомной логики в наследниках
176
- */
177
- markAsTouched(): void;
178
- /**
179
- * Отметить узел как untouched
180
- *
181
- * Template Method: обновляет signal в базовом классе,
182
- * вызывает hook для кастомной логики в наследниках
183
- */
184
- markAsUntouched(): void;
185
- /**
186
- * Отметить узел как dirty (значение изменено)
187
- *
188
- * Template Method: обновляет signal в базовом классе,
189
- * вызывает hook для кастомной логики в наследниках
190
- */
191
- markAsDirty(): void;
192
- /**
193
- * Отметить узел как pristine (значение не изменено)
194
- *
195
- * Template Method: обновляет signal в базовом классе,
196
- * вызывает hook для кастомной логики в наследниках
197
- */
198
- markAsPristine(): void;
199
- /**
200
- * Пометить все поля (включая вложенные) как touched
201
- * Алиас для markAsTouched(), но более явно показывает намерение
202
- * пометить ВСЕ поля рекурсивно
203
- *
204
- * Полезно для:
205
- * - Показа всех ошибок валидации перед submit
206
- * - Принудительного отображения ошибок при нажатии "Validate All"
207
- * - Отображения невалидных полей в wizard/step form
208
- *
209
- * @example
210
- * ```typescript
211
- * // Показать все ошибки перед submit
212
- * form.touchAll();
213
- * const isValid = await form.validate();
214
- * if (!isValid) {
215
- * // Все ошибки теперь видны пользователю
216
- * }
217
- *
218
- * // Или использовать submit() который уже вызывает touchAll
219
- * await form.submit(async (values) => {
220
- * await api.save(values);
221
- * });
222
- * ```
223
- */
224
- touchAll(): void;
225
- /**
226
- * Отключить узел
227
- *
228
- * Template Method: обновляет статус в базовом классе,
229
- * вызывает hook для кастомной логики в наследниках
230
- *
231
- * Отключенные узлы не проходят валидацию и не включаются в getValue()
232
- */
233
- disable(): void;
234
- /**
235
- * Включить узел
236
- *
237
- * Template Method: обновляет статус в базовом классе,
238
- * вызывает hook для кастомной логики в наследниках
239
- */
240
- enable(): void;
241
- /**
242
- * Очистить все ресурсы узла
243
- * Должен вызываться при unmount компонента для предотвращения memory leaks
244
- *
245
- * @example
246
- * ```typescript
247
- * // React component
248
- * useEffect(() => {
249
- * return () => {
250
- * form.dispose(); // Cleanup при unmount
251
- * };
252
- * }, []);
253
- * ```
254
- */
255
- dispose?(): void;
256
- /**
257
- * Hook: вызывается после markAsTouched()
258
- *
259
- * Переопределите в наследниках для дополнительной логики:
260
- * - GroupNode: пометить все дочерние узлы как touched
261
- * - ArrayNode: пометить все элементы массива как touched
262
- * - FieldNode: пустая реализация (нет дочерних узлов)
263
- *
264
- * @example
265
- * ```typescript
266
- * // GroupNode
267
- * protected onMarkAsTouched(): void {
268
- * this.fields.forEach(field => field.markAsTouched());
269
- * }
270
- * ```
271
- */
272
- protected onMarkAsTouched(): void;
273
- /**
274
- * Hook: вызывается после markAsUntouched()
275
- *
276
- * Переопределите в наследниках для дополнительной логики:
277
- * - GroupNode: пометить все дочерние узлы как untouched
278
- * - ArrayNode: пометить все элементы массива как untouched
279
- * - FieldNode: пустая реализация (нет дочерних узлов)
280
- */
281
- protected onMarkAsUntouched(): void;
282
- /**
283
- * Hook: вызывается после markAsDirty()
284
- *
285
- * Переопределите в наследниках для дополнительной логики:
286
- * - GroupNode: может обновить родительскую форму
287
- * - ArrayNode: может обновить родительскую форму
288
- * - FieldNode: пустая реализация
289
- */
290
- protected onMarkAsDirty(): void;
291
- /**
292
- * Hook: вызывается после markAsPristine()
293
- *
294
- * Переопределите в наследниках для дополнительной логики:
295
- * - GroupNode: пометить все дочерние узлы как pristine
296
- * - ArrayNode: пометить все элементы массива как pristine
297
- * - FieldNode: пустая реализация
298
- */
299
- protected onMarkAsPristine(): void;
300
- /**
301
- * Hook: вызывается после disable()
302
- *
303
- * Переопределите в наследниках для дополнительной логики:
304
- * - GroupNode: отключить все дочерние узлы
305
- * - ArrayNode: отключить все элементы массива
306
- * - FieldNode: очистить ошибки валидации
307
- *
308
- * @example
309
- * ```typescript
310
- * // GroupNode
311
- * protected onDisable(): void {
312
- * this.fields.forEach(field => field.disable());
313
- * }
314
- * ```
315
- */
316
- protected onDisable(): void;
317
- /**
318
- * Hook: вызывается после enable()
319
- *
320
- * Переопределите в наследниках для дополнительной логики:
321
- * - GroupNode: включить все дочерние узлы
322
- * - ArrayNode: включить все элементы массива
323
- * - FieldNode: пустая реализация
324
- */
325
- protected onEnable(): void;
326
- }
@@ -1,284 +0,0 @@
1
- import { Signal, ReadonlySignal } from '@preact/signals-core';
2
- import { FormNode, SetValueOptions } from './form-node';
3
- import { ValidationError, FieldStatus, FormSchema, GroupNodeConfig, FormValue } from '../types/index';
4
- import { FormProxy } from '../types/form-proxy';
5
- import { SubmitOptions, SubmitResult } from '../form-submitter';
6
- /**
7
- * GroupNode - узел для группы полей
8
- *
9
- * Создаётся из {@link FormSchema} (дерево field-конфигов). Обычно строится через `createForm`
10
- * (M1: `createFormFromModel({ model, schema })`); schema-валидация/behavior живут на слое модели
11
- * (`validateModel` из `@reformer/core/validation`, `computeFrom`/`enableWhen`/…), а не на ноде.
12
- *
13
- * @group Nodes
14
- *
15
- * @example
16
- * ```typescript
17
- * const form = new GroupNode({
18
- * email: { valueSignal: model.$.email, component: Input },
19
- * password: { valueSignal: model.$.password, component: Input },
20
- * });
21
- *
22
- * // Прямой доступ к полям через Proxy
23
- * const proxy = form.getProxy();
24
- * proxy.email.setValue('test@mail.com');
25
- * await proxy.validate();
26
- * console.log(proxy.valid.value);
27
- * ```
28
- */
29
- export declare class GroupNode<T> extends FormNode<T> {
30
- id: `${string}-${string}-${string}-${string}-${string}`;
31
- /**
32
- * Коллекция полей формы (упрощённый Map вместо FieldRegistry)
33
- */
34
- private readonly _fields;
35
- /**
36
- * Менеджер подписок для централизованного cleanup
37
- */
38
- private disposers;
39
- /**
40
- * Ссылка на Proxy-инстанс
41
- */
42
- private _proxyInstance?;
43
- /**
44
- * Cleanup декларативной схемы поведения (createForm({ behavior })). Вызывается в dispose().
45
- */
46
- private _behaviorCleanup?;
47
- /**
48
- * Фабрика для создания узлов формы
49
- */
50
- private readonly nodeFactory;
51
- /** Управление отправкой формы */
52
- private readonly formSubmitter;
53
- /** Флаг disabled состояния */
54
- private readonly _disabled;
55
- /** Form-level validation errors */
56
- private readonly _formErrors;
57
- /**
58
- * M1: связь листовой ноды-ребёнка → её сигнал модели (тот, что помечает `markDerived`).
59
- * Нужна bulk-сеттерам (`setValue`/`patchValue`), чтобы корректно определять derived-поля:
60
- * `field.value` — computed-обёртка, отличная от записываемого сигнала модели. @internal
61
- */
62
- private readonly _fieldSignals;
63
- readonly value: ReadonlySignal<T>;
64
- readonly valid: ReadonlySignal<boolean>;
65
- readonly invalid: ReadonlySignal<boolean>;
66
- readonly touched: ReadonlySignal<boolean>;
67
- readonly dirty: ReadonlySignal<boolean>;
68
- readonly pending: ReadonlySignal<boolean>;
69
- readonly errors: ReadonlySignal<ValidationError[]>;
70
- readonly status: ReadonlySignal<FieldStatus>;
71
- readonly submitting: ReadonlySignal<boolean>;
72
- /**
73
- * Создать GroupNode только со схемой формы (обратная совместимость)
74
- */
75
- constructor(schema: FormSchema<T>);
76
- /**
77
- * Создать GroupNode с полной конфигурацией (form, behavior, validation)
78
- */
79
- constructor(config: GroupNodeConfig<T>);
80
- /**
81
- * Создать Proxy для типобезопасного доступа к полям
82
- * @see buildFormProxy
83
- */
84
- private buildProxy;
85
- getValue(): T;
86
- setValue(value: T, options?: SetValueOptions): void;
87
- patchValue(value: Partial<T>): void;
88
- /**
89
- * Сбросить форму к указанным значениям (или к initialValues)
90
- *
91
- * @param value - опциональный объект со значениями для сброса
92
- *
93
- * @remarks
94
- * Рекурсивно вызывает reset() для всех полей формы
95
- *
96
- * @example
97
- * ```typescript
98
- * // Сброс к initialValues
99
- * form.reset();
100
- *
101
- * // Сброс к новым значениям
102
- * form.reset({ email: 'new@mail.com', password: '' });
103
- * ```
104
- */
105
- reset(value?: T): void;
106
- /**
107
- * Сбросить форму к исходным значениям (initialValues)
108
- */
109
- resetToInitial(): void;
110
- validate(): Promise<boolean>;
111
- /**
112
- * Установить form-level validation errors
113
- */
114
- setErrors(errors: ValidationError[]): void;
115
- /**
116
- * Очистить все errors (form-level + field-level)
117
- */
118
- clearErrors(): void;
119
- /**
120
- * Получить поле по ключу
121
- */
122
- getField<K extends keyof T>(key: K): FormNode<T[K]> | undefined;
123
- /**
124
- * Получить Map всех полей формы (для совместимости)
125
- */
126
- get fields(): Map<keyof T, FormNode<FormValue>>;
127
- /**
128
- * Получить Proxy-инстанс для прямого доступа к полям
129
- *
130
- * Proxy позволяет обращаться к полям формы напрямую через точечную нотацию:
131
- * - form.email вместо form.fields.get('email')
132
- * - form.address.city вместо form.fields.get('address').fields.get('city')
133
- *
134
- * @returns Proxy-инстанс с типобезопасным доступом к полям или сама форма, если proxy не доступен
135
- *
136
- * @example
137
- * ```typescript
138
- * const form = new GroupNode({
139
- * email: { value: '', component: Input },
140
- * name: { value: '', component: Input },
141
- * });
142
- *
143
- * const proxy = form.getProxy();
144
- * console.log(proxy.email.value.value); // Прямой доступ к полю
145
- * ```
146
- */
147
- getProxy(): FormProxy<T>;
148
- /**
149
- * Получить все поля формы как итератор
150
- */
151
- getAllFields(): IterableIterator<FormNode<FormValue>>;
152
- protected onMarkAsTouched(): void;
153
- protected onMarkAsUntouched(): void;
154
- protected onMarkAsDirty(): void;
155
- protected onMarkAsPristine(): void;
156
- /**
157
- * Отправить форму
158
- *
159
- * @param onSubmit - Callback для отправки данных
160
- * @param options - Опции submit (skipValidation, skipTouch)
161
- * @returns Результат от onSubmit или `null` если валидация не пройдена
162
- *
163
- * @remarks
164
- * `null` перегружен: он означает и «валидация не пройдена», и легитимный `null`-результат
165
- * `onSubmit` (или void-обработчик). Если вызывающей стороне нужно различать эти случаи —
166
- * используйте {@link submitWithResult}, который возвращает явный флаг `success`.
167
- */
168
- submit<R>(onSubmit: (values: T) => Promise<R> | R, options?: SubmitOptions): Promise<R | null>;
169
- /**
170
- * Отправить форму с расширенным результатом
171
- *
172
- * @param onSubmit - Callback для отправки данных
173
- * @param options - Опции submit
174
- * @returns Объект SubmitResult с данными, статусом и возможной ошибкой
175
- */
176
- submitWithResult<R>(onSubmit: (values: T) => Promise<R> | R, options?: SubmitOptions): Promise<SubmitResult<R>>;
177
- /**
178
- * Получить вложенное поле по пути
179
- *
180
- * Поддерживаемые форматы путей:
181
- * - Simple: "email" - получить поле верхнего уровня
182
- * - Nested: "address.city" - получить вложенное поле
183
- * - Array index: "items[0]" - получить элемент массива по индексу
184
- * - Combined: "items[0].name" - получить поле элемента массива
185
- *
186
- * @param path - Путь к полю
187
- * @returns FormNode если найдено, undefined если путь не существует
188
- *
189
- * @example
190
- * ```typescript
191
- * const form = new GroupNode({
192
- * email: { value: '', component: Input },
193
- * address: {
194
- * city: { value: '', component: Input }
195
- * },
196
- * items: [{ name: { value: '', component: Input } }]
197
- * });
198
- *
199
- * form.getFieldByPath('email'); // FieldNode
200
- * form.getFieldByPath('address.city'); // FieldNode
201
- * form.getFieldByPath('items[0]'); // GroupNode
202
- * form.getFieldByPath('items[0].name'); // FieldNode
203
- * form.getFieldByPath('invalid.path'); // undefined
204
- * ```
205
- */
206
- getFieldByPath(path: string): FormNode<FormValue> | undefined;
207
- /**
208
- * Создать узел на основе конфигурации
209
- *
210
- * ✅ РЕФАКТОРИНГ: Полное делегирование NodeFactory
211
- *
212
- * NodeFactory теперь обрабатывает:
213
- * - Массивы [schema, ...items]
214
- * - FieldConfig
215
- * - GroupConfig
216
- * - ArrayConfig
217
- *
218
- * @param config Конфигурация узла
219
- * @returns Созданный узел формы
220
- * @private
221
- */
222
- private createNode;
223
- /**
224
- * Связывает два поля: при изменении source автоматически обновляется target
225
- */
226
- linkFields<K1 extends keyof T, K2 extends keyof T>(sourceKey: K1, targetKey: K2, transform?: (value: T[K1]) => T[K2]): () => void;
227
- /**
228
- * Подписка на изменения вложенного поля по строковому пути
229
- * Поддерживает вложенные пути типа "address.city"
230
- *
231
- * @param fieldPath - Строковый путь к полю (например, "address.city")
232
- * @param callback - Функция, вызываемая при изменении поля
233
- * @returns Функция отписки для cleanup
234
- *
235
- * @example
236
- * ```typescript
237
- * // Подписка на изменение страны для загрузки городов
238
- * const dispose = form.watchField(
239
- * 'registrationAddress.country',
240
- * async (countryCode) => {
241
- * if (countryCode) {
242
- * const cities = await fetchCitiesByCountry(countryCode);
243
- * form.registrationAddress.city.updateComponentProps({
244
- * options: cities
245
- * });
246
- * }
247
- * }
248
- * );
249
- *
250
- * // Cleanup
251
- * useEffect(() => dispose, []);
252
- * ```
253
- */
254
- /** Подписка на top-level поле — value типизирован как `T[K]`. */
255
- watchField<K extends keyof T & string>(fieldPath: K, callback: (value: T[K]) => void | Promise<void>): () => void;
256
- /**
257
- * Подписка на вложенное поле по строковому пути ("address.city").
258
- * Путь нельзя выразить в типах узла → value честно `unknown`, потребитель сужает.
259
- */
260
- watchFieldByPath(path: string, callback: (value: unknown) => void | Promise<void>): () => void;
261
- /**
262
- * Hook: вызывается после disable()
263
- */
264
- protected onDisable(): void;
265
- /**
266
- * Hook: вызывается после enable()
267
- */
268
- protected onEnable(): void;
269
- /**
270
- * Прикрепить cleanup декларативной схемы поведения (вызывается createForm).
271
- * @internal
272
- */
273
- attachBehaviorCleanup(cleanup: () => void): void;
274
- /**
275
- * Связать листовую ноду-ребёнка с её сигналом модели (M1). Вызывается `createForm` для каждого
276
- * листового поля на его владеющей группе — используется bulk-сеттерами для derived-guard (F9).
277
- * @internal
278
- */
279
- registerFieldSignal(node: FormNode<any>, signal: Signal<unknown>): void;
280
- /**
281
- * Очистить все ресурсы узла
282
- */
283
- dispose(): void;
284
- }