@reformer/core 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/behaviors/compute-from.d.ts +2 -0
  2. package/dist/behaviors/compute-from.js +31 -0
  3. package/dist/behaviors/copy-from.d.ts +2 -0
  4. package/dist/behaviors/copy-from.js +29 -0
  5. package/dist/behaviors/enable-when.d.ts +2 -0
  6. package/dist/behaviors/enable-when.js +25 -0
  7. package/dist/behaviors/reset-when.d.ts +2 -0
  8. package/dist/behaviors/reset-when.js +24 -0
  9. package/dist/behaviors/revalidate-when.d.ts +2 -0
  10. package/dist/behaviors/revalidate-when.js +18 -0
  11. package/dist/behaviors/sync-fields.d.ts +2 -0
  12. package/dist/behaviors/sync-fields.js +41 -0
  13. package/dist/behaviors/transform-value.d.ts +2 -0
  14. package/dist/behaviors/transform-value.js +45 -0
  15. package/dist/behaviors/watch-field.d.ts +2 -0
  16. package/dist/behaviors/watch-field.js +21 -0
  17. package/dist/behaviors.js +26 -19
  18. package/dist/core/behavior/behavior-context.d.ts +26 -12
  19. package/dist/core/behavior/behavior-registry.d.ts +15 -27
  20. package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
  21. package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
  22. package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
  23. package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
  24. package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
  25. package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
  26. package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
  27. package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
  28. package/dist/core/behavior/compose-behavior.d.ts +2 -12
  29. package/dist/core/behavior/index.d.ts +0 -1
  30. package/dist/core/behavior/types.d.ts +2 -8
  31. package/dist/core/factories/node-factory.d.ts +6 -29
  32. package/dist/core/nodes/array-node.d.ts +39 -19
  33. package/dist/core/nodes/field-node.d.ts +51 -26
  34. package/dist/core/nodes/form-node.d.ts +18 -20
  35. package/dist/core/nodes/group-node.d.ts +25 -21
  36. package/dist/core/types/deep-schema.d.ts +2 -12
  37. package/dist/core/types/field-path.d.ts +1 -1
  38. package/dist/core/types/form-context.d.ts +26 -26
  39. package/dist/core/types/form-proxy.d.ts +2 -32
  40. package/dist/core/types/index.d.ts +51 -5
  41. package/dist/core/types/validation-schema.d.ts +3 -12
  42. package/dist/core/utils/abstract-registry.d.ts +74 -0
  43. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  44. package/dist/core/utils/create-form.d.ts +1 -18
  45. package/dist/core/utils/error-handler.d.ts +1 -18
  46. package/dist/core/utils/field-path-navigator.d.ts +1 -1
  47. package/dist/core/utils/field-path.d.ts +23 -11
  48. package/dist/core/utils/form-observer.d.ts +176 -0
  49. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  50. package/dist/core/utils/form-submitter.d.ts +121 -0
  51. package/dist/core/utils/index.d.ts +9 -2
  52. package/dist/core/utils/registry-helpers.d.ts +0 -7
  53. package/dist/core/utils/safe-effect.d.ts +73 -0
  54. package/dist/core/utils/status-machine.d.ts +153 -0
  55. package/dist/core/utils/type-guards.d.ts +5 -23
  56. package/dist/core/utils/unique-id.d.ts +53 -0
  57. package/dist/core/validation/core/apply-when.d.ts +3 -9
  58. package/dist/core/validation/core/apply.d.ts +2 -13
  59. package/dist/core/validation/core/validate-async.d.ts +2 -8
  60. package/dist/core/validation/core/validate-tree.d.ts +0 -6
  61. package/dist/core/validation/core/validate.d.ts +1 -7
  62. package/dist/core/validation/index.d.ts +8 -2
  63. package/dist/core/validation/validate-form.d.ts +1 -38
  64. package/dist/core/validation/validation-applicator.d.ts +2 -21
  65. package/dist/core/validation/validation-context.d.ts +58 -42
  66. package/dist/core/validation/validation-registry.d.ts +11 -25
  67. package/dist/core/validation/validators/array-validators.d.ts +2 -12
  68. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  69. package/dist/core/validation/validators/email.d.ts +2 -9
  70. package/dist/core/validation/validators/future-date.d.ts +35 -0
  71. package/dist/core/validation/validators/index.d.ts +7 -1
  72. package/dist/core/validation/validators/is-date.d.ts +36 -0
  73. package/dist/core/validation/validators/max-age.d.ts +36 -0
  74. package/dist/core/validation/validators/max-date.d.ts +36 -0
  75. package/dist/core/validation/validators/max-length.d.ts +3 -10
  76. package/dist/core/validation/validators/max.d.ts +3 -10
  77. package/dist/core/validation/validators/min-age.d.ts +36 -0
  78. package/dist/core/validation/validators/min-date.d.ts +36 -0
  79. package/dist/core/validation/validators/min-length.d.ts +3 -10
  80. package/dist/core/validation/validators/min.d.ts +3 -10
  81. package/dist/core/validation/validators/number.d.ts +2 -9
  82. package/dist/core/validation/validators/past-date.d.ts +35 -0
  83. package/dist/core/validation/validators/pattern.d.ts +2 -9
  84. package/dist/core/validation/validators/phone.d.ts +2 -9
  85. package/dist/core/validation/validators/required.d.ts +2 -9
  86. package/dist/core/validation/validators/url.d.ts +2 -9
  87. package/dist/date-utils-xUWFslTj.js +29 -0
  88. package/dist/field-path-DuKdGcIE.js +66 -0
  89. package/dist/hooks/types.d.ts +1 -1
  90. package/dist/hooks/useArrayLength.d.ts +31 -0
  91. package/dist/hooks/useFormControl.d.ts +4 -4
  92. package/dist/hooks/useFormControlValue.d.ts +2 -2
  93. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  94. package/dist/hooks/useSignalSubscription.d.ts +1 -1
  95. package/dist/index-D25LsbRm.js +73 -0
  96. package/dist/index.d.ts +2 -0
  97. package/dist/index.js +1171 -786
  98. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  99. package/dist/safe-effect-Dh8uw81c.js +20 -0
  100. package/dist/validate-C3XiA_zf.js +10 -0
  101. package/dist/validators/email.d.ts +2 -0
  102. package/dist/validators/email.js +13 -0
  103. package/dist/validators/future-date.d.ts +2 -0
  104. package/dist/validators/future-date.js +20 -0
  105. package/dist/validators/is-date.d.ts +2 -0
  106. package/dist/validators/is-date.js +12 -0
  107. package/dist/validators/max-age.d.ts +2 -0
  108. package/dist/validators/max-age.js +20 -0
  109. package/dist/validators/max-date.d.ts +2 -0
  110. package/dist/validators/max-date.js +20 -0
  111. package/dist/validators/max-length.d.ts +2 -0
  112. package/dist/validators/max-length.js +11 -0
  113. package/dist/validators/max.d.ts +2 -0
  114. package/dist/validators/max.js +11 -0
  115. package/dist/validators/min-age.d.ts +2 -0
  116. package/dist/validators/min-age.js +20 -0
  117. package/dist/validators/min-date.d.ts +2 -0
  118. package/dist/validators/min-date.js +20 -0
  119. package/dist/validators/min-length.d.ts +2 -0
  120. package/dist/validators/min-length.js +11 -0
  121. package/dist/validators/min.d.ts +2 -0
  122. package/dist/validators/min.js +11 -0
  123. package/dist/validators/number.d.ts +2 -0
  124. package/dist/validators/number.js +35 -0
  125. package/dist/validators/past-date.d.ts +2 -0
  126. package/dist/validators/past-date.js +20 -0
  127. package/dist/validators/pattern.d.ts +2 -0
  128. package/dist/validators/pattern.js +11 -0
  129. package/dist/validators/phone.d.ts +2 -0
  130. package/dist/validators/phone.js +35 -0
  131. package/dist/validators/required.d.ts +2 -0
  132. package/dist/validators/required.js +15 -0
  133. package/dist/validators/url.d.ts +2 -0
  134. package/dist/validators/url.js +19 -0
  135. package/dist/validators-BGsNOgT1.js +207 -0
  136. package/dist/validators.js +54 -29
  137. package/llms.txt +7878 -311
  138. package/package.json +83 -9
  139. package/dist/behaviors-DzYL8kY_.js +0 -499
  140. package/dist/core/behavior/create-field-path.d.ts +0 -7
  141. package/dist/core/context/form-context-impl.d.ts +0 -29
  142. package/dist/core/utils/debounce.d.ts +0 -160
  143. package/dist/core/utils/resources.d.ts +0 -41
  144. package/dist/core/validation/field-path.d.ts +0 -7
  145. package/dist/core/validation/validators/date.d.ts +0 -38
  146. package/dist/registry-helpers-BRxAr6nG.js +0 -490
  147. package/dist/validators-gXoHPdqM.js +0 -418
@@ -1,12 +1,6 @@
1
- /**
2
- * Типы и интерфейсы для Behavior Schema API
3
- *
4
- * @group Behaviors
5
- * @category Behavior Types
6
- */
7
1
  import { GroupNode } from '../nodes/group-node';
8
- import type { FieldPath } from '../types/field-path';
9
- import type { FormContext } from '../types/form-context';
2
+ import { FieldPath } from '../types/field-path';
3
+ import { FormContext } from '../types/form-context';
10
4
  /**
11
5
  * Тип функции behavior схемы
12
6
  * Принимает FieldPath и описывает поведение формы
@@ -1,40 +1,17 @@
1
+ import { FormNode } from '../nodes/form-node';
1
2
  /**
2
- * NodeFactory - фабрика для создания узлов формы
3
+ * Фабрика для создания узлов формы.
3
4
  *
4
- * Инкапсулирует логику определения типа конфига и создания соответствующего узла.
5
- * Используется в GroupNode и ArrayNode для создания дочерних узлов.
6
- *
7
- * Паттерн Factory Method упрощает создание узлов и делает код более читаемым:
8
- * - Вместо if-else в GroupNode/ArrayNode
9
- * - Единая точка для создания узлов
10
- * - Легко добавлять новые типы узлов
5
+ * Определяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).
6
+ * Используется внутри `getReformerForm`/`group`/`array` явно вызывать обычно не нужно.
11
7
  *
12
8
  * @example
13
9
  * ```typescript
14
- * const factory = new NodeFactory();
15
- *
16
- * // Создание FieldNode
17
- * const field = factory.createNode({ value: '', component: Input });
18
- *
19
- * // Создание GroupNode
20
- * const group = factory.createNode({
21
- * email: { value: '', component: Input },
22
- * password: { value: '', component: Input }
23
- * });
10
+ * import { NodeFactory } from '@reformer/core';
24
11
  *
25
- * // Создание ArrayNode
26
- * const array = factory.createNode({
27
- * schema: { title: { value: '', component: Input } },
28
- * initialItems: []
29
- * });
12
+ * const node = NodeFactory.create({ value: '' }); // FieldNode<string>
30
13
  * ```
31
14
  */
32
- import type { FormNode } from '../nodes/form-node';
33
- /**
34
- * Фабрика для создания узлов формы
35
- *
36
- * Определяет тип конфига и создает соответствующий узел (FieldNode, GroupNode, ArrayNode)
37
- */
38
15
  export declare class NodeFactory {
39
16
  /**
40
17
  * Создает узел формы на основе конфигурации
@@ -1,18 +1,8 @@
1
- /**
2
- * ArrayNode - узел формы для работы с массивами
3
- *
4
- * Управляет массивом форм с поддержкой:
5
- * - Динамического добавления/удаления элементов
6
- * - Валидации всех элементов
7
- * - Реактивного состояния через signals
8
- *
9
- * @group Nodes
10
- */
11
- import type { ReadonlySignal } from '@preact/signals-core';
12
- import { FormNode, type SetValueOptions } from './form-node';
13
- import type { FieldStatus, ValidationError, FormFields } from '../types';
14
- import type { FormSchema } from '../types/deep-schema';
15
- import type { FormProxy } from '../types/form-proxy';
1
+ import { ReadonlySignal } from '@preact/signals-core';
2
+ import { FormNode, SetValueOptions } from './form-node';
3
+ import { FieldStatus, ValidationError, FormFields } from '../types';
4
+ import { FormSchema } from '../types/deep-schema';
5
+ import { FormProxy } from '../types/form-proxy';
16
6
  /**
17
7
  * ArrayNode - массив форм с реактивным состоянием
18
8
  *
@@ -39,6 +29,8 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
39
29
  * Использует SubscriptionManager вместо массива для управления подписками
40
30
  */
41
31
  private disposers;
32
+ /** Array-level validation errors (e.g., "минимум 1 элемент") */
33
+ private readonly _arrayErrors;
42
34
  private validationSchemaFn?;
43
35
  private behaviorSchemaFn?;
44
36
  readonly value: ReadonlySignal<T[]>;
@@ -59,6 +51,9 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
59
51
  /**
60
52
  * Удалить элемент по индексу
61
53
  * @param index - Индекс элемента для удаления
54
+ *
55
+ * @remarks
56
+ * Вызывает dispose() на удаляемом элементе для очистки подписок
62
57
  */
63
58
  removeAt(index: number): void;
64
59
  /**
@@ -69,12 +64,15 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
69
64
  insert(index: number, initialValue?: Partial<T>): void;
70
65
  /**
71
66
  * Удалить все элементы массива
67
+ *
68
+ * @remarks
69
+ * Вызывает dispose() на всех элементах для очистки подписок
72
70
  */
73
71
  clear(): void;
74
72
  /**
75
73
  * Получить элемент по индексу
76
74
  * @param index - Индекс элемента
77
- * @returns Типизированный GroupNode или undefined если индекс вне границ
75
+ * @returns Типизированный GroupNode proxy или undefined если индекс вне границ
78
76
  */
79
77
  at(index: number): FormProxy<T> | undefined;
80
78
  getValue(): T[];
@@ -128,7 +126,29 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
128
126
  */
129
127
  resetToInitial(): void;
130
128
  validate(): Promise<boolean>;
131
- setErrors(_errors: ValidationError[]): void;
129
+ /**
130
+ * Установить array-level validation errors
131
+ *
132
+ * @param errors - Массив ошибок валидации уровня массива
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * arrayNode.setErrors([{
137
+ * code: 'minItems',
138
+ * message: 'Минимум 1 элемент обязателен',
139
+ * }]);
140
+ * ```
141
+ */
142
+ setErrors(errors: ValidationError[]): void;
143
+ /**
144
+ * Очистить все errors (array-level + item-level)
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * arrayNode.clearErrors();
149
+ * console.log(arrayNode.errors.value); // []
150
+ * ```
151
+ */
132
152
  clearErrors(): void;
133
153
  /**
134
154
  * Hook: вызывается после markAsTouched()
@@ -156,12 +176,12 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
156
176
  protected onMarkAsPristine(): void;
157
177
  /**
158
178
  * Итерировать по элементам массива
159
- * @param callback - Функция, вызываемая для каждого элемента с типизированным GroupNode
179
+ * @param callback - Функция, вызываемая для каждого элемента с типизированным GroupNode proxy
160
180
  */
161
181
  forEach(callback: (item: FormProxy<T>, index: number) => void): void;
162
182
  /**
163
183
  * Маппинг элементов массива
164
- * @param callback - Функция преобразования с типизированным GroupNode
184
+ * @param callback - Функция преобразования с типизированным GroupNode proxy
165
185
  * @returns Новый массив результатов
166
186
  */
167
187
  map<R>(callback: (item: FormProxy<T>, index: number) => R): R[];
@@ -1,15 +1,6 @@
1
- /**
2
- * FieldNode - узел поля формы
3
- *
4
- * Представляет одно поле формы с валидацией и состоянием
5
- * Наследует от FormNode и реализует все его абстрактные методы
6
- *
7
- * @group Nodes
8
- */
9
- import type { ReadonlySignal } from '@preact/signals-core';
10
- import { FormNode } from './form-node';
11
- import type { SetValueOptions } from './form-node';
12
- import type { FieldConfig, ValidationError } from '../types';
1
+ import { ReadonlySignal } from '@preact/signals-core';
2
+ import { FormNode, SetValueOptions } from './form-node';
3
+ import { FieldConfig, FieldStatus, ValidationError } from '../types';
13
4
  /**
14
5
  * FieldNode - узел для отдельного поля формы
15
6
  *
@@ -31,12 +22,18 @@ import type { FieldConfig, ValidationError } from '../types';
31
22
  export declare class FieldNode<T> extends FormNode<T> {
32
23
  private _value;
33
24
  private _errors;
34
- private _pending;
35
25
  private _componentProps;
26
+ /**
27
+ * State machine для управления статусом поля
28
+ * Централизует логику переходов между valid/invalid/pending/disabled
29
+ */
30
+ private readonly statusMachine;
36
31
  readonly value: ReadonlySignal<T>;
37
32
  readonly valid: ReadonlySignal<boolean>;
38
33
  readonly invalid: ReadonlySignal<boolean>;
39
34
  readonly pending: ReadonlySignal<boolean>;
35
+ readonly status: ReadonlySignal<FieldStatus>;
36
+ readonly disabled: ReadonlySignal<boolean>;
40
37
  readonly errors: ReadonlySignal<ValidationError[]>;
41
38
  readonly componentProps: ReadonlySignal<Record<string, any>>;
42
39
  /**
@@ -48,10 +45,14 @@ export declare class FieldNode<T> extends FormNode<T> {
48
45
  private asyncValidators;
49
46
  private updateOn;
50
47
  private initialValue;
51
- private currentValidationId;
48
+ private currentAbortController?;
52
49
  private debounceMs;
53
50
  private validateDebounceTimer?;
54
- private validateDebounceResolve?;
51
+ /**
52
+ * Pending debounced validation state
53
+ * Contains resolve function and AbortController for cancellation
54
+ */
55
+ private pendingValidation?;
55
56
  /**
56
57
  * Менеджер подписок для централизованного cleanup
57
58
  * Использует SubscriptionManager вместо массива для управления подписками
@@ -112,13 +113,23 @@ export declare class FieldNode<T> extends FormNode<T> {
112
113
  * ```
113
114
  */
114
115
  resetToInitial(): void;
116
+ /**
117
+ * Cancel any pending validation (debounced or running)
118
+ * @private
119
+ * @remarks
120
+ * Centralizes all cancellation logic:
121
+ * - Aborts pending debounced validation and resolves its promise
122
+ * - Clears debounce timer
123
+ * - Aborts currently running async validation
124
+ */
125
+ private cancelPendingValidation;
115
126
  /**
116
127
  * Запустить валидацию поля
117
128
  * @param options - опции валидации
118
129
  * @returns `Promise<boolean>` - true если поле валидно
119
130
  *
120
131
  * @remarks
121
- * Метод защищен от race conditions через validationId.
132
+ * Метод защищен от race conditions через AbortController.
122
133
  * При быстром вводе только последняя валидация применяет результаты.
123
134
  *
124
135
  * @example
@@ -136,13 +147,12 @@ export declare class FieldNode<T> extends FormNode<T> {
136
147
  /**
137
148
  * Немедленная валидация без debounce
138
149
  * @private
150
+ * @param providedController - AbortController from debounced validate()
139
151
  * @remarks
140
- * Защищена от race conditions:
141
- * - Проверка validationId после синхронной валидации
142
- * - Проверка перед установкой pending
143
- * - Проверка после Promise.all
144
- * - Проверка перед обработкой async результатов
145
- * - Проверка перед очисткой errors
152
+ * Защищена от race conditions через AbortController:
153
+ * - Отменяет предыдущую валидацию при запуске новой (if no controller provided)
154
+ * - Передаёт AbortSignal в async валидаторы для отмены операций (например, fetch)
155
+ * - Проверяет signal.aborted в ключевых точках
146
156
  */
147
157
  private validateImmediate;
148
158
  setErrors(errors: ValidationError[]): void;
@@ -156,13 +166,13 @@ export declare class FieldNode<T> extends FormNode<T> {
156
166
  /**
157
167
  * Hook: вызывается после disable()
158
168
  *
159
- * Для FieldNode: очищаем ошибки валидации
169
+ * Для FieldNode: синхронизируем statusMachine и очищаем ошибки
160
170
  */
161
171
  protected onDisable(): void;
162
172
  /**
163
173
  * Hook: вызывается после enable()
164
174
  *
165
- * Для FieldNode: запускаем валидацию
175
+ * Для FieldNode: синхронизируем statusMachine и запускаем валидацию
166
176
  */
167
177
  protected onEnable(): void;
168
178
  /**
@@ -215,20 +225,28 @@ export declare class FieldNode<T> extends FormNode<T> {
215
225
  * Подписка на изменения значения поля
216
226
  * Автоматически отслеживает изменения через @preact/signals effect
217
227
  *
218
- * @param callback - Функция, вызываемая при изменении значения
228
+ * @param callback - Функция, вызываемая при изменении значения.
229
+ * Для async операций передается AbortSignal во втором параметре.
219
230
  * @returns Функция отписки для cleanup
220
231
  *
221
232
  * @example
222
233
  * ```typescript
234
+ * // Синхронный callback
223
235
  * const unsubscribe = form.email.watch((value) => {
224
236
  * console.log('Email changed:', value);
225
237
  * });
226
238
  *
239
+ * // Асинхронный callback с поддержкой отмены
240
+ * const unsubscribe = form.email.watch(async (value, signal) => {
241
+ * const result = await fetch('/api/validate', { signal });
242
+ * // ...
243
+ * });
244
+ *
227
245
  * // Cleanup
228
246
  * useEffect(() => unsubscribe, []);
229
247
  * ```
230
248
  */
231
- watch(callback: (value: T) => void | Promise<void>): () => void;
249
+ watch(callback: (value: T, signal: AbortSignal) => void | Promise<void>): () => void;
232
250
  /**
233
251
  * Вычисляемое значение из других полей
234
252
  * Автоматически обновляет текущее поле при изменении источников
@@ -256,6 +274,13 @@ export declare class FieldNode<T> extends FormNode<T> {
256
274
  * Очистить все ресурсы и таймеры
257
275
  * Должен вызываться при unmount компонента
258
276
  *
277
+ * @remarks
278
+ * Освобождает все ресурсы:
279
+ * - Отписывает все subscriptions через SubscriptionManager
280
+ * - Отменяет pending/running валидации через cancelPendingValidation()
281
+ *
282
+ * Использует try-finally для гарантированного cleanup даже при ошибках.
283
+ *
259
284
  * @example
260
285
  * ```typescript
261
286
  * useEffect(() => {
@@ -1,17 +1,5 @@
1
- /**
2
- * FormNode - абстрактный базовый класс для всех узлов формы
3
- *
4
- * Аналог AbstractControl из Angular Forms
5
- * Унифицирует работу с полями (FieldNode), группами (GroupNode) и массивами (ArrayNode)
6
- *
7
- * Использует Template Method паттерн для управления состоянием:
8
- * - Публичные методы (markAsTouched, disable и т.д.) реализованы в базовом классе
9
- * - Protected hooks (onMarkAsTouched, onDisable и т.д.) переопределяются в наследниках
10
- *
11
- * @group Nodes
12
- */
13
- import { type ReadonlySignal, type Signal } from '@preact/signals-core';
14
- import type { FieldStatus, ValidationError, ErrorFilterOptions } from '../types';
1
+ import { ReadonlySignal, Signal } from '@preact/signals-core';
2
+ import { FieldStatus, ValidationError, ErrorFilterOptions } from '../types';
15
3
  /**
16
4
  * Опции для setValue
17
5
  * @group Nodes
@@ -23,17 +11,27 @@ export interface SetValueOptions {
23
11
  onlySelf?: boolean;
24
12
  }
25
13
  /**
26
- * Абстрактный базовый класс для всех узлов формы
14
+ * Абстрактный базовый класс для всех узлов формы.
27
15
  *
28
- * Все узлы (поля, группы, массивы) наследуют от этого класса
29
- * и реализуют единый интерфейс для работы с состоянием и валидацией
16
+ * Все узлы (поля, группы, массивы) наследуют от этого класса и реализуют
17
+ * единый интерфейс для работы с состоянием и валидацией.
30
18
  *
31
19
  * Template Method паттерн используется для управления состоянием:
32
- * - Общие signals (_touched, _dirty, _status) определены в базовом классе
33
- * - Публичные методы (markAsTouched, disable и т.д.) реализованы здесь
34
- * - Protected hooks (onMarkAsTouched, onDisable и т.д.) переопределяются в наследниках
20
+ * общие signals (`_touched`, `_dirty`, `_status`) живут в базовом классе,
21
+ * publi-методы (`markAsTouched`, `disable`, ) реализованы здесь, а protected
22
+ * hooks (`onMarkAsTouched`, `onDisable`, ) переопределяются в наследниках.
35
23
  *
36
24
  * @group Nodes
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // FormNode не используется напрямую — экземпляры приходят из getReformerForm.
29
+ * import { getReformerForm, FormNode } from '@reformer/core';
30
+ *
31
+ * const form = getReformerForm({ email: '' });
32
+ * form.email instanceof FormNode; // true
33
+ * form.email.markAsTouched();
34
+ * ```
37
35
  */
38
36
  export declare abstract class FormNode<T> {
39
37
  /**
@@ -1,20 +1,9 @@
1
- /**
2
- * GroupNode - узел группы полей формы
3
- *
4
- * Представляет группу полей (объект), где каждое поле может быть:
5
- * - FieldNode (простое поле)
6
- * - GroupNode (вложенная группа)
7
- * - ArrayNode (массив форм)
8
- *
9
- * Наследует от FormNode и реализует все его абстрактные методы
10
- *
11
- * @group Nodes
12
- */
13
- import type { ReadonlySignal } from '@preact/signals-core';
14
- import { FormNode, type SetValueOptions } from './form-node';
15
- import type { ValidationError, FieldStatus, ValidationSchemaFn, ValidatorRegistration, FormSchema, GroupNodeConfig, FormValue } from '../types';
16
- import type { FormProxy } from '../types/form-proxy';
17
- import type { BehaviorSchemaFn } from '../behavior/types';
1
+ import { ReadonlySignal } from '@preact/signals-core';
2
+ import { FormNode, SetValueOptions } from './form-node';
3
+ import { ValidationError, FieldStatus, ValidationSchemaFn, ValidatorRegistration, FormSchema, GroupNodeConfig, FormValue } from '../types';
4
+ import { FormProxy } from '../types/form-proxy';
5
+ import { BehaviorSchemaFn } from '../behavior/types';
6
+ import { SubmitOptions, SubmitResult } from '../utils/form-submitter';
18
7
  /**
19
8
  * GroupNode - узел для группы полей
20
9
  *
@@ -56,7 +45,7 @@ import type { BehaviorSchemaFn } from '../behavior/types';
56
45
  * ```
57
46
  */
58
47
  export declare class GroupNode<T> extends FormNode<T> {
59
- id: string;
48
+ id: `${string}-${string}-${string}-${string}-${string}`;
60
49
  /**
61
50
  * Коллекция полей формы (упрощённый Map вместо FieldRegistry)
62
51
  */
@@ -79,18 +68,20 @@ export declare class GroupNode<T> extends FormNode<T> {
79
68
  private readonly nodeFactory;
80
69
  /**
81
70
  * Реестр валидаторов для этой формы
71
+ * Может быть инжектирован через config._validationRegistry для тестирования
82
72
  */
83
73
  private readonly validationRegistry;
84
74
  /**
85
75
  * Реестр behaviors для этой формы
76
+ * Может быть инжектирован через config._behaviorRegistry для тестирования
86
77
  */
87
78
  private readonly behaviorRegistry;
88
79
  /**
89
80
  * Аппликатор для применения валидаторов к форме
90
81
  */
91
82
  private readonly validationApplicator;
92
- /** Флаг отправки формы */
93
- private readonly _submitting;
83
+ /** Управление отправкой формы */
84
+ private readonly formSubmitter;
94
85
  /** Флаг disabled состояния */
95
86
  private readonly _disabled;
96
87
  /** Form-level validation errors */
@@ -114,6 +105,7 @@ export declare class GroupNode<T> extends FormNode<T> {
114
105
  constructor(config: GroupNodeConfig<T>);
115
106
  /**
116
107
  * Создать Proxy для типобезопасного доступа к полям
108
+ * @see buildFormProxy
117
109
  */
118
110
  private buildProxy;
119
111
  getValue(): T;
@@ -195,8 +187,20 @@ export declare class GroupNode<T> extends FormNode<T> {
195
187
  protected onMarkAsPristine(): void;
196
188
  /**
197
189
  * Отправить форму
190
+ *
191
+ * @param onSubmit - Callback для отправки данных
192
+ * @param options - Опции submit (skipValidation, skipTouch)
193
+ * @returns Результат от onSubmit или null если валидация не пройдена
194
+ */
195
+ submit<R>(onSubmit: (values: T) => Promise<R> | R, options?: SubmitOptions): Promise<R | null>;
196
+ /**
197
+ * Отправить форму с расширенным результатом
198
+ *
199
+ * @param onSubmit - Callback для отправки данных
200
+ * @param options - Опции submit
201
+ * @returns Объект SubmitResult с данными, статусом и возможной ошибкой
198
202
  */
199
- submit<R>(onSubmit: (values: T) => Promise<R> | R): Promise<R | null>;
203
+ submitWithResult<R>(onSubmit: (values: T) => Promise<R> | R, options?: SubmitOptions): Promise<SubmitResult<R>>;
200
204
  /**
201
205
  * Применить validation schema к форме
202
206
  *
@@ -1,15 +1,5 @@
1
- /**
2
- * Типы для схемы формы (Deep Schema)
3
- *
4
- * Автоматическое определение типов схемы на основе структуры данных:
5
- * - `[{...}]` → массив форм
6
- * - `{...}` → вложенная группа
7
- * - `{value, component}` → конфигурация поля
8
- *
9
- * @group Types
10
- */
11
- import type { ComponentType } from 'react';
12
- import type { ValidatorFn, AsyncValidatorFn, FormFields, AnyFunction } from './index';
1
+ import { ComponentType } from 'react';
2
+ import { ValidatorFn, AsyncValidatorFn, FormFields, AnyFunction } from './index';
13
3
  /**
14
4
  * Конфигурация поля
15
5
  * @group Types
@@ -1,4 +1,4 @@
1
- import type { AnyFunction } from './index';
1
+ import { AnyFunction } from './index';
2
2
  /**
3
3
  * FieldPath предоставляет типобезопасный доступ к путям полей формы
4
4
  *
@@ -1,29 +1,7 @@
1
- /**
2
- * Единый контекст для работы с формой
3
- *
4
- * Используется в:
5
- * - Behavior схемах (watchField, copyFrom, transformValue, etc.)
6
- * - Validation схемах (validate, validateAsync, validateTree)
7
- *
8
- * @example
9
- * ```typescript
10
- * // Behavior
11
- * watchField(path.country, (country, ctx) => {
12
- * ctx.form.city.updateComponentProps({ options: cities });
13
- * ctx.setFieldValue('city', null);
14
- * });
15
- *
16
- * // Validation
17
- * validate(path.email, (value, ctx) => {
18
- * if (!value) return { code: 'required', message: 'Required' };
19
- * const confirm = ctx.form.confirmEmail.value.value;
20
- * if (value !== confirm) return { code: 'mismatch', message: 'Emails must match' };
21
- * return null;
22
- * });
23
- * ```
24
- */
25
- import type { FormProxy } from './form-proxy';
26
- import type { FieldPathNode } from './field-path';
1
+ import { FormProxy } from './form-proxy';
2
+ import { FieldPathNode } from './field-path';
3
+ import { FormNode } from '../nodes/form-node';
4
+ import { FormValue } from './index';
27
5
  /**
28
6
  * Единый контекст для работы с формой
29
7
  *
@@ -86,4 +64,26 @@ export interface FormContext<TForm> {
86
64
  * ```
87
65
  */
88
66
  setFieldValue(path: string | FieldPathNode<TForm, unknown>, value: unknown): void;
67
+ /**
68
+ * Получить поле формы по строковому пути
69
+ *
70
+ * Используется для динамического доступа к вложенным полям,
71
+ * особенно в модульных behavior схемах, применяемых через apply().
72
+ *
73
+ * @param path - Строковый путь к полю (например "address.city")
74
+ * @returns FormNode или undefined если поле не найдено
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * // В модульной behavior схеме, применяемой к вложенному полю:
79
+ * // apply([path.registrationAddress, path.residenceAddress], addressBehavior)
80
+ *
81
+ * watchField(path.region, (region, ctx) => {
82
+ * // path.city.__path = "registrationAddress.city" или "residenceAddress.city"
83
+ * const cityField = ctx.getFieldByPath(path.city.__path);
84
+ * cityField?.updateComponentProps({ options: cities });
85
+ * });
86
+ * ```
87
+ */
88
+ getFieldByPath(path: string): FormNode<FormValue> | undefined;
89
89
  }
@@ -1,34 +1,4 @@
1
- /**
2
- * Типы для Proxy-доступа к полям формы
3
- *
4
- * Решает проблему типизации, когда GroupNode<T> использует Proxy для прямого доступа к полям.
5
- * TypeScript не может автоматически определить правильные типы для вложенных форм и массивов.
6
- *
7
- * @group Types
8
- *
9
- * @example
10
- * ```typescript
11
- * interface MyForm {
12
- * name: string;
13
- * address: {
14
- * city: string;
15
- * };
16
- * items: Array<{ title: string }>;
17
- * }
18
- *
19
- * const form: FormProxy<MyForm> = new GroupNode(schema);
20
- *
21
- * // TypeScript знает, что это FieldNode<string>
22
- * form.name.setValue('John');
23
- *
24
- * // TypeScript знает, что это GroupNode<{city: string}>
25
- * form.address.city.setValue('Moscow');
26
- *
27
- * // TypeScript знает, что это ArrayNode<{title: string}>
28
- * form.items.push({ title: 'New Item' });
29
- * ```
30
- */
31
- import type { FormFields } from './index';
1
+ import { FormFields } from './index';
32
2
  type FieldNode<_T> = any;
33
3
  type GroupNode<_T> = any;
34
4
  type ArrayNode<_T> = any;
@@ -72,7 +42,7 @@ export type FormControlsProxy<T> = {
72
42
  * };
73
43
  * }
74
44
  *
75
- * const form: FormProxy<UserForm> = new GroupNode(schema);
45
+ * const form = createForm<UserForm>(schema);
76
46
  *
77
47
  * // Доступ к методам GroupNode
78
48
  * await form.validate();