@reformer/core 2.0.0-beta.7 → 2.0.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/behaviors/compute-from.d.ts +2 -0
- package/dist/behaviors/compute-from.js +31 -0
- package/dist/behaviors/copy-from.d.ts +2 -0
- package/dist/behaviors/copy-from.js +29 -0
- package/dist/behaviors/enable-when.d.ts +2 -0
- package/dist/behaviors/enable-when.js +25 -0
- package/dist/behaviors/reset-when.d.ts +2 -0
- package/dist/behaviors/reset-when.js +24 -0
- package/dist/behaviors/revalidate-when.d.ts +2 -0
- package/dist/behaviors/revalidate-when.js +18 -0
- package/dist/behaviors/sync-fields.d.ts +2 -0
- package/dist/behaviors/sync-fields.js +41 -0
- package/dist/behaviors/transform-value.d.ts +2 -0
- package/dist/behaviors/transform-value.js +45 -0
- package/dist/behaviors/watch-field.d.ts +2 -0
- package/dist/behaviors/watch-field.js +21 -0
- package/dist/behaviors.js +26 -19
- package/dist/core/behavior/behavior-context.d.ts +26 -12
- package/dist/core/behavior/behavior-registry.d.ts +15 -27
- package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
- package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
- package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
- package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
- package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
- package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
- package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
- package/dist/core/behavior/compose-behavior.d.ts +2 -12
- package/dist/core/behavior/index.d.ts +0 -1
- package/dist/core/behavior/types.d.ts +2 -8
- package/dist/core/factories/node-factory.d.ts +6 -29
- package/dist/core/nodes/array-node.d.ts +11 -15
- package/dist/core/nodes/field-node.d.ts +43 -24
- package/dist/core/nodes/form-node.d.ts +18 -20
- package/dist/core/nodes/group-node.d.ts +25 -21
- package/dist/core/types/deep-schema.d.ts +2 -12
- package/dist/core/types/field-path.d.ts +1 -1
- package/dist/core/types/form-context.d.ts +26 -26
- package/dist/core/types/form-proxy.d.ts +1 -31
- package/dist/core/types/index.d.ts +16 -4
- package/dist/core/types/validation-schema.d.ts +3 -12
- package/dist/core/utils/abstract-registry.d.ts +74 -0
- package/dist/core/utils/aggregate-signals.d.ts +71 -0
- package/dist/core/utils/create-form.d.ts +1 -20
- package/dist/core/utils/error-handler.d.ts +1 -18
- package/dist/core/utils/field-path-navigator.d.ts +1 -1
- package/dist/core/utils/field-path.d.ts +23 -11
- package/dist/core/utils/form-observer.d.ts +176 -0
- package/dist/core/utils/form-proxy-builder.d.ts +25 -0
- package/dist/core/utils/form-submitter.d.ts +121 -0
- package/dist/core/utils/index.d.ts +8 -2
- package/dist/core/utils/registry-helpers.d.ts +0 -7
- package/dist/core/utils/safe-effect.d.ts +73 -0
- package/dist/core/utils/status-machine.d.ts +153 -0
- package/dist/core/utils/type-guards.d.ts +5 -23
- package/dist/core/utils/unique-id.d.ts +34 -7
- package/dist/core/validation/core/apply-when.d.ts +3 -9
- package/dist/core/validation/core/apply.d.ts +2 -13
- package/dist/core/validation/core/validate-async.d.ts +2 -8
- package/dist/core/validation/core/validate-tree.d.ts +0 -6
- package/dist/core/validation/core/validate.d.ts +1 -7
- package/dist/core/validation/index.d.ts +8 -2
- package/dist/core/validation/validate-form.d.ts +1 -38
- package/dist/core/validation/validation-applicator.d.ts +2 -21
- package/dist/core/validation/validation-context.d.ts +38 -14
- package/dist/core/validation/validation-registry.d.ts +11 -20
- package/dist/core/validation/validators/array-validators.d.ts +2 -12
- package/dist/core/validation/validators/date-utils.d.ts +26 -0
- package/dist/core/validation/validators/email.d.ts +2 -9
- package/dist/core/validation/validators/future-date.d.ts +35 -0
- package/dist/core/validation/validators/index.d.ts +7 -1
- package/dist/core/validation/validators/is-date.d.ts +36 -0
- package/dist/core/validation/validators/max-age.d.ts +36 -0
- package/dist/core/validation/validators/max-date.d.ts +36 -0
- package/dist/core/validation/validators/max-length.d.ts +3 -10
- package/dist/core/validation/validators/max.d.ts +3 -10
- package/dist/core/validation/validators/min-age.d.ts +36 -0
- package/dist/core/validation/validators/min-date.d.ts +36 -0
- package/dist/core/validation/validators/min-length.d.ts +3 -10
- package/dist/core/validation/validators/min.d.ts +3 -10
- package/dist/core/validation/validators/number.d.ts +2 -9
- package/dist/core/validation/validators/past-date.d.ts +35 -0
- package/dist/core/validation/validators/pattern.d.ts +2 -9
- package/dist/core/validation/validators/phone.d.ts +2 -9
- package/dist/core/validation/validators/required.d.ts +2 -9
- package/dist/core/validation/validators/url.d.ts +2 -9
- package/dist/date-utils-xUWFslTj.js +29 -0
- package/dist/field-path-DuKdGcIE.js +66 -0
- package/dist/hooks/types.d.ts +1 -1
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +4 -4
- package/dist/hooks/useFormControlValue.d.ts +2 -2
- package/dist/hooks/useHiddenCondition.d.ts +25 -0
- package/dist/hooks/useSignalSubscription.d.ts +1 -1
- package/dist/index-D25LsbRm.js +73 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1031 -714
- package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
- package/dist/safe-effect-Dh8uw81c.js +20 -0
- package/dist/validate-C3XiA_zf.js +10 -0
- package/dist/validators/email.d.ts +2 -0
- package/dist/validators/email.js +13 -0
- package/dist/validators/future-date.d.ts +2 -0
- package/dist/validators/future-date.js +20 -0
- package/dist/validators/is-date.d.ts +2 -0
- package/dist/validators/is-date.js +12 -0
- package/dist/validators/max-age.d.ts +2 -0
- package/dist/validators/max-age.js +20 -0
- package/dist/validators/max-date.d.ts +2 -0
- package/dist/validators/max-date.js +20 -0
- package/dist/validators/max-length.d.ts +2 -0
- package/dist/validators/max-length.js +11 -0
- package/dist/validators/max.d.ts +2 -0
- package/dist/validators/max.js +11 -0
- package/dist/validators/min-age.d.ts +2 -0
- package/dist/validators/min-age.js +20 -0
- package/dist/validators/min-date.d.ts +2 -0
- package/dist/validators/min-date.js +20 -0
- package/dist/validators/min-length.d.ts +2 -0
- package/dist/validators/min-length.js +11 -0
- package/dist/validators/min.d.ts +2 -0
- package/dist/validators/min.js +11 -0
- package/dist/validators/number.d.ts +2 -0
- package/dist/validators/number.js +35 -0
- package/dist/validators/past-date.d.ts +2 -0
- package/dist/validators/past-date.js +20 -0
- package/dist/validators/pattern.d.ts +2 -0
- package/dist/validators/pattern.js +11 -0
- package/dist/validators/phone.d.ts +2 -0
- package/dist/validators/phone.js +35 -0
- package/dist/validators/required.d.ts +2 -0
- package/dist/validators/required.js +15 -0
- package/dist/validators/url.d.ts +2 -0
- package/dist/validators/url.js +19 -0
- package/dist/validators-BGsNOgT1.js +207 -0
- package/dist/validators.js +54 -29
- package/llms.txt +7878 -311
- package/package.json +83 -9
- package/dist/behaviors-DyPzh2-X.js +0 -508
- package/dist/core/behavior/create-field-path.d.ts +0 -7
- package/dist/core/context/form-context-impl.d.ts +0 -29
- package/dist/core/utils/debounce.d.ts +0 -160
- package/dist/core/utils/resources.d.ts +0 -41
- package/dist/core/validation/field-path.d.ts +0 -7
- package/dist/core/validation/validators/date.d.ts +0 -38
- package/dist/registry-helpers--8-OogF8.js +0 -477
- package/dist/validators-CWdzevnC.js +0 -397
|
@@ -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
|
|
9
|
-
import
|
|
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
|
-
*
|
|
3
|
+
* Фабрика для создания узлов формы.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
* Используется
|
|
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
|
-
*
|
|
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
|
-
* //
|
|
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
|
-
|
|
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
|
*
|
|
@@ -61,6 +51,9 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
|
|
|
61
51
|
/**
|
|
62
52
|
* Удалить элемент по индексу
|
|
63
53
|
* @param index - Индекс элемента для удаления
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* Вызывает dispose() на удаляемом элементе для очистки подписок
|
|
64
57
|
*/
|
|
65
58
|
removeAt(index: number): void;
|
|
66
59
|
/**
|
|
@@ -71,6 +64,9 @@ export declare class ArrayNode<T extends FormFields> extends FormNode<T[]> {
|
|
|
71
64
|
insert(index: number, initialValue?: Partial<T>): void;
|
|
72
65
|
/**
|
|
73
66
|
* Удалить все элементы массива
|
|
67
|
+
*
|
|
68
|
+
* @remarks
|
|
69
|
+
* Вызывает dispose() на всех элементах для очистки подписок
|
|
74
70
|
*/
|
|
75
71
|
clear(): void;
|
|
76
72
|
/**
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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,11 +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;
|
|
52
48
|
private currentAbortController?;
|
|
53
49
|
private debounceMs;
|
|
54
50
|
private validateDebounceTimer?;
|
|
55
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Pending debounced validation state
|
|
53
|
+
* Contains resolve function and AbortController for cancellation
|
|
54
|
+
*/
|
|
55
|
+
private pendingValidation?;
|
|
56
56
|
/**
|
|
57
57
|
* Менеджер подписок для централизованного cleanup
|
|
58
58
|
* Использует SubscriptionManager вместо массива для управления подписками
|
|
@@ -113,13 +113,23 @@ export declare class FieldNode<T> extends FormNode<T> {
|
|
|
113
113
|
* ```
|
|
114
114
|
*/
|
|
115
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;
|
|
116
126
|
/**
|
|
117
127
|
* Запустить валидацию поля
|
|
118
128
|
* @param options - опции валидации
|
|
119
129
|
* @returns `Promise<boolean>` - true если поле валидно
|
|
120
130
|
*
|
|
121
131
|
* @remarks
|
|
122
|
-
* Метод защищен от race conditions через
|
|
132
|
+
* Метод защищен от race conditions через AbortController.
|
|
123
133
|
* При быстром вводе только последняя валидация применяет результаты.
|
|
124
134
|
*
|
|
125
135
|
* @example
|
|
@@ -137,9 +147,10 @@ export declare class FieldNode<T> extends FormNode<T> {
|
|
|
137
147
|
/**
|
|
138
148
|
* Немедленная валидация без debounce
|
|
139
149
|
* @private
|
|
150
|
+
* @param providedController - AbortController from debounced validate()
|
|
140
151
|
* @remarks
|
|
141
152
|
* Защищена от race conditions через AbortController:
|
|
142
|
-
* - Отменяет предыдущую валидацию при запуске новой
|
|
153
|
+
* - Отменяет предыдущую валидацию при запуске новой (if no controller provided)
|
|
143
154
|
* - Передаёт AbortSignal в async валидаторы для отмены операций (например, fetch)
|
|
144
155
|
* - Проверяет signal.aborted в ключевых точках
|
|
145
156
|
*/
|
|
@@ -155,13 +166,13 @@ export declare class FieldNode<T> extends FormNode<T> {
|
|
|
155
166
|
/**
|
|
156
167
|
* Hook: вызывается после disable()
|
|
157
168
|
*
|
|
158
|
-
* Для FieldNode: очищаем ошибки
|
|
169
|
+
* Для FieldNode: синхронизируем statusMachine и очищаем ошибки
|
|
159
170
|
*/
|
|
160
171
|
protected onDisable(): void;
|
|
161
172
|
/**
|
|
162
173
|
* Hook: вызывается после enable()
|
|
163
174
|
*
|
|
164
|
-
* Для FieldNode: запускаем валидацию
|
|
175
|
+
* Для FieldNode: синхронизируем statusMachine и запускаем валидацию
|
|
165
176
|
*/
|
|
166
177
|
protected onEnable(): void;
|
|
167
178
|
/**
|
|
@@ -214,20 +225,28 @@ export declare class FieldNode<T> extends FormNode<T> {
|
|
|
214
225
|
* Подписка на изменения значения поля
|
|
215
226
|
* Автоматически отслеживает изменения через @preact/signals effect
|
|
216
227
|
*
|
|
217
|
-
* @param callback - Функция, вызываемая при изменении
|
|
228
|
+
* @param callback - Функция, вызываемая при изменении значения.
|
|
229
|
+
* Для async операций передается AbortSignal во втором параметре.
|
|
218
230
|
* @returns Функция отписки для cleanup
|
|
219
231
|
*
|
|
220
232
|
* @example
|
|
221
233
|
* ```typescript
|
|
234
|
+
* // Синхронный callback
|
|
222
235
|
* const unsubscribe = form.email.watch((value) => {
|
|
223
236
|
* console.log('Email changed:', value);
|
|
224
237
|
* });
|
|
225
238
|
*
|
|
239
|
+
* // Асинхронный callback с поддержкой отмены
|
|
240
|
+
* const unsubscribe = form.email.watch(async (value, signal) => {
|
|
241
|
+
* const result = await fetch('/api/validate', { signal });
|
|
242
|
+
* // ...
|
|
243
|
+
* });
|
|
244
|
+
*
|
|
226
245
|
* // Cleanup
|
|
227
246
|
* useEffect(() => unsubscribe, []);
|
|
228
247
|
* ```
|
|
229
248
|
*/
|
|
230
|
-
watch(callback: (value: T) => void | Promise<void>): () => void;
|
|
249
|
+
watch(callback: (value: T, signal: AbortSignal) => void | Promise<void>): () => void;
|
|
231
250
|
/**
|
|
232
251
|
* Вычисляемое значение из других полей
|
|
233
252
|
* Автоматически обновляет текущее поле при изменении источников
|
|
@@ -258,9 +277,9 @@ export declare class FieldNode<T> extends FormNode<T> {
|
|
|
258
277
|
* @remarks
|
|
259
278
|
* Освобождает все ресурсы:
|
|
260
279
|
* - Отписывает все subscriptions через SubscriptionManager
|
|
261
|
-
* -
|
|
262
|
-
*
|
|
263
|
-
* -
|
|
280
|
+
* - Отменяет pending/running валидации через cancelPendingValidation()
|
|
281
|
+
*
|
|
282
|
+
* Использует try-finally для гарантированного cleanup даже при ошибках.
|
|
264
283
|
*
|
|
265
284
|
* @example
|
|
266
285
|
* ```typescript
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,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 = createForm<MyForm>(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;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { BehaviorSchemaFn } from '../behavior/types';
|
|
2
|
+
import { FormSchema } from './deep-schema';
|
|
3
|
+
import { ValidationSchemaFn } from './validation-schema';
|
|
4
|
+
import { FormNode } from '../nodes/form-node';
|
|
1
5
|
/**
|
|
2
6
|
* Represents any valid form value type
|
|
3
7
|
* Use this instead of 'any' for form values to maintain type safety
|
|
@@ -99,9 +103,6 @@ export type { ContextualValidatorFn, ContextualAsyncValidatorFn, TreeValidatorFn
|
|
|
99
103
|
export type { FormSchema, ArrayConfig } from './deep-schema';
|
|
100
104
|
export type { FormContext } from './form-context';
|
|
101
105
|
export type { FormControlsProxy, FormProxy, FormArrayProxy } from './form-proxy';
|
|
102
|
-
import type { BehaviorSchemaFn } from '../behavior/types';
|
|
103
|
-
import type { FormSchema } from './deep-schema';
|
|
104
|
-
import type { ValidationSchemaFn } from './validation-schema';
|
|
105
106
|
/**
|
|
106
107
|
* Конфигурация GroupNode с поддержкой схем
|
|
107
108
|
* Используется для создания форм с автоматическим применением behavior и validation схем
|
|
@@ -116,6 +117,18 @@ export interface GroupNodeConfig<T> {
|
|
|
116
117
|
behavior?: BehaviorSchemaFn<T>;
|
|
117
118
|
/** Схема валидации (required, email, minLength и т.д.) */
|
|
118
119
|
validation?: ValidationSchemaFn<T>;
|
|
120
|
+
/**
|
|
121
|
+
* Опциональный ValidationRegistry для dependency injection
|
|
122
|
+
* Используется для тестирования с mock-реестрами
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
_validationRegistry?: unknown;
|
|
126
|
+
/**
|
|
127
|
+
* Опциональный BehaviorRegistry для dependency injection
|
|
128
|
+
* Используется для тестирования с mock-реестрами
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
_behaviorRegistry?: unknown;
|
|
119
132
|
}
|
|
120
133
|
/**
|
|
121
134
|
* Тип для Record с unknown значениями
|
|
@@ -146,7 +159,6 @@ export interface ArrayNodeLike {
|
|
|
146
159
|
at(index: number): FormNode<unknown> | undefined;
|
|
147
160
|
length: unknown;
|
|
148
161
|
}
|
|
149
|
-
import type { FormNode } from '../nodes/form-node';
|
|
150
162
|
/**
|
|
151
163
|
* Конфиг с полем schema (для ArrayConfig)
|
|
152
164
|
* @internal
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Основано на Angular Signal Forms подходе:
|
|
5
|
-
* - Валидация определяется отдельно от схемы полей
|
|
6
|
-
* - Поддержка условной валидации (applyWhen)
|
|
7
|
-
* - Cross-field валидация (validateTree)
|
|
8
|
-
* - Асинхронная валидация с контекстом
|
|
9
|
-
*/
|
|
10
|
-
import type { FormFields, ValidationError } from './index';
|
|
11
|
-
import type { FieldPath } from './field-path';
|
|
12
|
-
import type { FormContext } from './form-context';
|
|
1
|
+
import { FormFields, ValidationError } from './index';
|
|
2
|
+
import { FieldPath } from './field-path';
|
|
3
|
+
import { FormContext } from './form-context';
|
|
13
4
|
/**
|
|
14
5
|
* Функция валидации поля с контекстом
|
|
15
6
|
*
|