@reformer/core 2.0.1 → 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.
- 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 +27 -13
- 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 +42 -22
- package/dist/core/nodes/field-node.d.ts +51 -26
- package/dist/core/nodes/form-node.d.ts +18 -20
- package/dist/core/nodes/group-node.d.ts +26 -22
- 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 +27 -27
- package/dist/core/types/{group-node-proxy.d.ts → form-proxy.d.ts} +12 -42
- package/dist/core/types/index.d.ts +52 -6
- 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 +3 -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 +9 -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 +53 -0
- 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 +59 -43
- package/dist/core/validation/validation-registry.d.ts +11 -25
- 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 +1171 -786
- 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 +7885 -318
- package/package.json +83 -8
- package/dist/behaviors-DzYL8kY_.js +0 -499
- 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-BRxAr6nG.js +0 -490
- package/dist/validators-gXoHPdqM.js +0 -418
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FormNode } from '../nodes/form-node';
|
|
2
|
+
import { FormProxy } from '../types/form-proxy';
|
|
3
|
+
/**
|
|
4
|
+
* Создать Proxy для типобезопасного доступа к полям GroupNode
|
|
5
|
+
*
|
|
6
|
+
* Proxy обеспечивает:
|
|
7
|
+
* - Доступ к полям через точечную нотацию (form.email, form.address.city)
|
|
8
|
+
* - Приоритет собственных свойств GroupNode над полями
|
|
9
|
+
* - Цепочку proxy для вложенных GroupNode
|
|
10
|
+
* - Блокировку прямого присваивания полям (только через setValue/patchValue)
|
|
11
|
+
*
|
|
12
|
+
* @param target - GroupNode для которого создаётся proxy
|
|
13
|
+
* @param fields - Map полей формы
|
|
14
|
+
* @returns Типизированный Proxy
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const proxy = buildFormProxy(groupNode, groupNode._fields);
|
|
21
|
+
* proxy.email.setValue('test@example.com');
|
|
22
|
+
* console.log(proxy.email.value.value);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildFormProxy<T>(target: FormNode<T>, fields: Map<keyof T, FormNode<unknown>>): FormProxy<T>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ReadonlySignal } from '@preact/signals-core';
|
|
2
|
+
import { FormFields } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Интерфейс формы для FormSubmitter
|
|
5
|
+
* Минимальный контракт для работы с любой формой
|
|
6
|
+
*/
|
|
7
|
+
export interface SubmittableForm<T extends FormFields> {
|
|
8
|
+
/** Пометить все поля как touched */
|
|
9
|
+
markAsTouched(): void;
|
|
10
|
+
/** Валидировать форму */
|
|
11
|
+
validate(): Promise<boolean>;
|
|
12
|
+
/** Получить значения формы */
|
|
13
|
+
getValue(): T;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Опции для submit
|
|
17
|
+
*/
|
|
18
|
+
export interface SubmitOptions {
|
|
19
|
+
/** Пропустить валидацию перед submit */
|
|
20
|
+
skipValidation?: boolean;
|
|
21
|
+
/** Пропустить markAsTouched перед submit */
|
|
22
|
+
skipTouch?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Результат submit
|
|
26
|
+
*/
|
|
27
|
+
export interface SubmitResult<R> {
|
|
28
|
+
/** Успешно ли выполнен submit */
|
|
29
|
+
success: boolean;
|
|
30
|
+
/** Результат от onSubmit callback */
|
|
31
|
+
data: R | null;
|
|
32
|
+
/** Ошибка, если submit не удался */
|
|
33
|
+
error?: Error;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* FormSubmitter - управляет процессом отправки формы
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const submitter = new FormSubmitter(form);
|
|
41
|
+
*
|
|
42
|
+
* // Простой submit
|
|
43
|
+
* const result = await submitter.submit(async (values) => {
|
|
44
|
+
* return await api.saveForm(values);
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // Проверка состояния
|
|
48
|
+
* if (submitter.submitting.value) {
|
|
49
|
+
* console.log('Форма отправляется...');
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare class FormSubmitter<T extends FormFields> {
|
|
54
|
+
private readonly form;
|
|
55
|
+
/** Внутренний сигнал состояния отправки */
|
|
56
|
+
private readonly _submitting;
|
|
57
|
+
/** Публичный read-only сигнал состояния отправки */
|
|
58
|
+
readonly submitting: ReadonlySignal<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* @param form - Форма для отправки
|
|
61
|
+
*/
|
|
62
|
+
constructor(form: SubmittableForm<T>);
|
|
63
|
+
/**
|
|
64
|
+
* Отправить форму
|
|
65
|
+
*
|
|
66
|
+
* Процесс:
|
|
67
|
+
* 1. Помечает все поля как touched (для отображения ошибок)
|
|
68
|
+
* 2. Валидирует форму
|
|
69
|
+
* 3. Если валидация успешна - вызывает onSubmit
|
|
70
|
+
* 4. Управляет состоянием submitting
|
|
71
|
+
*
|
|
72
|
+
* @param onSubmit - Callback для отправки данных
|
|
73
|
+
* @param options - Опции submit
|
|
74
|
+
* @returns Результат от onSubmit или null если валидация не пройдена
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const result = await submitter.submit(async (values) => {
|
|
79
|
+
* const response = await fetch('/api/form', {
|
|
80
|
+
* method: 'POST',
|
|
81
|
+
* body: JSON.stringify(values)
|
|
82
|
+
* });
|
|
83
|
+
* return response.json();
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* if (result === null) {
|
|
87
|
+
* console.log('Форма не прошла валидацию');
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
submit<R>(onSubmit: (values: T) => Promise<R> | R, options?: SubmitOptions): Promise<R | null>;
|
|
92
|
+
/**
|
|
93
|
+
* Отправить форму с расширенным результатом
|
|
94
|
+
*
|
|
95
|
+
* В отличие от submit(), возвращает объект с информацией об успехе/ошибке
|
|
96
|
+
*
|
|
97
|
+
* @param onSubmit - Callback для отправки данных
|
|
98
|
+
* @param options - Опции submit
|
|
99
|
+
* @returns Объект SubmitResult с данными и статусом
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const result = await submitter.submitWithResult(async (values) => {
|
|
104
|
+
* return await api.saveForm(values);
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* if (result.success) {
|
|
108
|
+
* console.log('Сохранено:', result.data);
|
|
109
|
+
* } else if (result.error) {
|
|
110
|
+
* console.error('Ошибка:', result.error.message);
|
|
111
|
+
* } else {
|
|
112
|
+
* console.log('Валидация не пройдена');
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
submitWithResult<R>(onSubmit: (values: T) => Promise<R> | R, options?: SubmitOptions): Promise<SubmitResult<R>>;
|
|
117
|
+
/**
|
|
118
|
+
* Проверить, идет ли отправка формы
|
|
119
|
+
*/
|
|
120
|
+
isSubmitting(): boolean;
|
|
121
|
+
}
|
|
@@ -9,7 +9,14 @@ export { SubscriptionManager } from './subscription-manager';
|
|
|
9
9
|
export { getCurrentValidationRegistry, getCurrentBehaviorRegistry } from './registry-helpers';
|
|
10
10
|
export { RegistryStack } from './registry-stack';
|
|
11
11
|
export { isFormNode, isFieldNode, isGroupNode, isArrayNode, getNodeType } from './type-guards';
|
|
12
|
-
export { Debouncer } from './debounce';
|
|
13
12
|
export { FormErrorHandler, ErrorStrategy } from './error-handler';
|
|
14
13
|
export { createForm } from './create-form';
|
|
15
|
-
export
|
|
14
|
+
export { uniqueId } from './unique-id';
|
|
15
|
+
export { safeCallback, runOutsideEffect, safeDebouncedCallback } from './safe-effect';
|
|
16
|
+
export { AbstractRegistry } from './abstract-registry';
|
|
17
|
+
export { FormSubmitter } from './form-submitter';
|
|
18
|
+
export type { SubmittableForm, SubmitOptions, SubmitResult } from './form-submitter';
|
|
19
|
+
export { FormStatusMachine } from './status-machine';
|
|
20
|
+
export type { StatusEvent } from './status-machine';
|
|
21
|
+
export { FormObserver } from './form-observer';
|
|
22
|
+
export type { FormChangeType, FormChangeEvent, FormChangeCallback, FormObserverOptions, ObservableForm, ObservableFormNode, } from './form-observer';
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Вспомогательные функции для работы с реестрами
|
|
3
|
-
*
|
|
4
|
-
* Централизует логику получения текущего активного реестра валидации/поведения
|
|
5
|
-
* из context stack, избегая дублирования кода в schema-validators.ts,
|
|
6
|
-
* array-validators.ts и schema-behaviors.ts
|
|
7
|
-
*/
|
|
8
1
|
import { ValidationRegistry } from '../validation/validation-registry';
|
|
9
2
|
import { BehaviorRegistry } from '../behavior/behavior-registry';
|
|
10
3
|
/**
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Утилиты для безопасной работы с сигналами в effect контексте
|
|
3
|
+
*
|
|
4
|
+
* Эти утилиты решают проблему "Cycle detected" в @preact/signals-core,
|
|
5
|
+
* которая возникает при модификации сигналов внутри effect.
|
|
6
|
+
*
|
|
7
|
+
* @group Utils
|
|
8
|
+
* @module utils/safe-effect
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Создает callback, который выполняется вне контекста effect
|
|
12
|
+
*
|
|
13
|
+
* Использует queueMicrotask для отложенного выполнения,
|
|
14
|
+
* что позволяет модифицировать сигналы без вызова "Cycle detected"
|
|
15
|
+
*
|
|
16
|
+
* @param callback - Функция для выполнения
|
|
17
|
+
* @returns Обёрнутая функция, безопасная для вызова внутри effect
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Вместо:
|
|
22
|
+
* effect(() => {
|
|
23
|
+
* queueMicrotask(() => {
|
|
24
|
+
* callback(value, context);
|
|
25
|
+
* });
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Используем:
|
|
29
|
+
* effect(() => {
|
|
30
|
+
* safeCallback(callback)(value, context);
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function safeCallback<TArgs extends unknown[]>(callback: (...args: TArgs) => void | Promise<void>): (...args: TArgs) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Выполняет функцию вне контекста effect
|
|
37
|
+
*
|
|
38
|
+
* Более простой вариант для одиночного вызова
|
|
39
|
+
*
|
|
40
|
+
* @param fn - Функция для выполнения
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* effect(() => {
|
|
45
|
+
* const value = signal.value;
|
|
46
|
+
* runOutsideEffect(() => {
|
|
47
|
+
* otherSignal.value = transform(value);
|
|
48
|
+
* });
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function runOutsideEffect(fn: () => void | Promise<void>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Создает версию callback с поддержкой debounce, безопасную для effect
|
|
55
|
+
*
|
|
56
|
+
* Комбинирует debounce логику с выходом из effect контекста
|
|
57
|
+
*
|
|
58
|
+
* @param callback - Функция для выполнения
|
|
59
|
+
* @param withDebounce - Функция debounce обёртки из BehaviorRegistry
|
|
60
|
+
* @returns Обёрнутая функция
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* return effect(() => {
|
|
65
|
+
* const value = node.value.value;
|
|
66
|
+
* safeDebouncedCallback(
|
|
67
|
+
* () => callback(value, context),
|
|
68
|
+
* withDebounce
|
|
69
|
+
* )();
|
|
70
|
+
* });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function safeDebouncedCallback(callback: () => void | Promise<void>, withDebounce: (fn: () => void) => void): () => void;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { ReadonlySignal } from '@preact/signals-core';
|
|
2
|
+
import { FieldStatus } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* События для State Machine
|
|
5
|
+
*/
|
|
6
|
+
export type StatusEvent = {
|
|
7
|
+
type: 'START_VALIDATION';
|
|
8
|
+
} | {
|
|
9
|
+
type: 'VALIDATION_SUCCESS';
|
|
10
|
+
} | {
|
|
11
|
+
type: 'VALIDATION_FAILURE';
|
|
12
|
+
} | {
|
|
13
|
+
type: 'DISABLE';
|
|
14
|
+
} | {
|
|
15
|
+
type: 'ENABLE';
|
|
16
|
+
hasErrors?: boolean;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'SET_ERRORS';
|
|
19
|
+
hasErrors: boolean;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* FormStatusMachine - управляет состоянием поля формы
|
|
23
|
+
*
|
|
24
|
+
* Предоставляет:
|
|
25
|
+
* - Единый источник истины для статуса
|
|
26
|
+
* - Computed signals для derived состояний (valid, invalid, pending, disabled)
|
|
27
|
+
* - Валидацию переходов между состояниями
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const statusMachine = new FormStatusMachine('valid');
|
|
32
|
+
*
|
|
33
|
+
* // Начало валидации
|
|
34
|
+
* statusMachine.startValidation();
|
|
35
|
+
* console.log(statusMachine.pending.value); // true
|
|
36
|
+
*
|
|
37
|
+
* // Завершение валидации с ошибками
|
|
38
|
+
* statusMachine.completeValidation(true);
|
|
39
|
+
* console.log(statusMachine.invalid.value); // true
|
|
40
|
+
*
|
|
41
|
+
* // Отключение поля
|
|
42
|
+
* statusMachine.disable();
|
|
43
|
+
* console.log(statusMachine.disabled.value); // true
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class FormStatusMachine {
|
|
47
|
+
/** Внутренний сигнал статуса */
|
|
48
|
+
private readonly _status;
|
|
49
|
+
/** Публичный read-only сигнал статуса */
|
|
50
|
+
readonly status: ReadonlySignal<FieldStatus>;
|
|
51
|
+
/** Поле валидно */
|
|
52
|
+
readonly valid: ReadonlySignal<boolean>;
|
|
53
|
+
/** Поле невалидно */
|
|
54
|
+
readonly invalid: ReadonlySignal<boolean>;
|
|
55
|
+
/** Идет валидация */
|
|
56
|
+
readonly pending: ReadonlySignal<boolean>;
|
|
57
|
+
/** Поле отключено */
|
|
58
|
+
readonly disabled: ReadonlySignal<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* @param initial - Начальный статус (по умолчанию 'valid')
|
|
61
|
+
*/
|
|
62
|
+
constructor(initial?: FieldStatus);
|
|
63
|
+
/**
|
|
64
|
+
* Начать валидацию
|
|
65
|
+
*
|
|
66
|
+
* Переводит статус в 'pending' если поле не отключено
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* statusMachine.startValidation();
|
|
71
|
+
* // status: 'pending'
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
startValidation(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Завершить валидацию
|
|
77
|
+
*
|
|
78
|
+
* @param hasErrors - Есть ли ошибки валидации
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Валидация успешна
|
|
83
|
+
* statusMachine.completeValidation(false);
|
|
84
|
+
* // status: 'valid'
|
|
85
|
+
*
|
|
86
|
+
* // Есть ошибки
|
|
87
|
+
* statusMachine.completeValidation(true);
|
|
88
|
+
* // status: 'invalid'
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
completeValidation(hasErrors: boolean): void;
|
|
92
|
+
/**
|
|
93
|
+
* Установить ошибки напрямую (без перехода через pending)
|
|
94
|
+
*
|
|
95
|
+
* Используется для синхронной валидации или установки ошибок извне
|
|
96
|
+
*
|
|
97
|
+
* @param hasErrors - Есть ли ошибки
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* statusMachine.setErrors(true);
|
|
102
|
+
* // status: 'invalid'
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
setErrors(hasErrors: boolean): void;
|
|
106
|
+
/**
|
|
107
|
+
* Отключить поле
|
|
108
|
+
*
|
|
109
|
+
* Переводит статус в 'disabled'
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* statusMachine.disable();
|
|
114
|
+
* // status: 'disabled'
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
disable(): void;
|
|
118
|
+
/**
|
|
119
|
+
* Включить поле
|
|
120
|
+
*
|
|
121
|
+
* @param hasErrors - Есть ли ошибки (определяет valid/invalid)
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* statusMachine.enable(false);
|
|
126
|
+
* // status: 'valid'
|
|
127
|
+
*
|
|
128
|
+
* statusMachine.enable(true);
|
|
129
|
+
* // status: 'invalid'
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
enable(hasErrors?: boolean): void;
|
|
133
|
+
/**
|
|
134
|
+
* Обработать событие (альтернативный API)
|
|
135
|
+
*
|
|
136
|
+
* @param event - Событие для обработки
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* statusMachine.dispatch({ type: 'START_VALIDATION' });
|
|
141
|
+
* statusMachine.dispatch({ type: 'VALIDATION_FAILURE' });
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
dispatch(event: StatusEvent): void;
|
|
145
|
+
/**
|
|
146
|
+
* Получить текущий статус
|
|
147
|
+
*/
|
|
148
|
+
getStatus(): FieldStatus;
|
|
149
|
+
/**
|
|
150
|
+
* Проверить, можно ли начать валидацию
|
|
151
|
+
*/
|
|
152
|
+
canValidate(): boolean;
|
|
153
|
+
}
|
|
@@ -1,26 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* @group Utilities
|
|
7
|
-
* @category Type Guards
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* import { isFieldNode, isGroupNode } from '@/core/utils/type-guards';
|
|
12
|
-
*
|
|
13
|
-
* if (isFieldNode(node)) {
|
|
14
|
-
* // TypeScript знает, что node это FieldNode
|
|
15
|
-
* node.validators;
|
|
16
|
-
* }
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
import type { FormNode } from '../nodes/form-node';
|
|
20
|
-
import type { FieldNode } from '../nodes/field-node';
|
|
21
|
-
import type { GroupNode } from '../nodes/group-node';
|
|
22
|
-
import type { ArrayNode } from '../nodes/array-node';
|
|
23
|
-
import type { FormFields, FormValue } from '../types';
|
|
1
|
+
import { FormNode } from '../nodes/form-node';
|
|
2
|
+
import { FieldNode } from '../nodes/field-node';
|
|
3
|
+
import { GroupNode } from '../nodes/group-node';
|
|
4
|
+
import { ArrayNode } from '../nodes/array-node';
|
|
5
|
+
import { FormFields, FormValue } from '../types';
|
|
24
6
|
/**
|
|
25
7
|
* Проверить, является ли значение любым FormNode
|
|
26
8
|
*
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Генератор уникальных идентификаторов
|
|
3
|
+
*
|
|
4
|
+
* Использует атомный счётчик для генерации гарантированно уникальных ключей.
|
|
5
|
+
* Решает проблему возможного дублирования ключей при использовании
|
|
6
|
+
* Date.now() + Math.random() в быстрых последовательных вызовах.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const key1 = uniqueId(SubscriptionKey.Watch); // "watch-1"
|
|
11
|
+
* const key2 = uniqueId(SubscriptionKey.Watch); // "watch-2"
|
|
12
|
+
* const key3 = uniqueId(SubscriptionKey.ComputeFrom); // "computeFrom-3"
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Типобезопасные ключи для подписок
|
|
17
|
+
* Используются с uniqueId() для генерации уникальных идентификаторов
|
|
18
|
+
*/
|
|
19
|
+
export declare const SubscriptionKey: {
|
|
20
|
+
/** FieldNode.watch() */
|
|
21
|
+
readonly Watch: "watch";
|
|
22
|
+
/** FieldNode.computeFrom() */
|
|
23
|
+
readonly ComputeFrom: "computeFrom";
|
|
24
|
+
/** GroupNode.linkFields() */
|
|
25
|
+
readonly LinkFields: "linkFields";
|
|
26
|
+
/** GroupNode.watchField() */
|
|
27
|
+
readonly WatchField: "watchField";
|
|
28
|
+
/** ArrayNode.watchItems() */
|
|
29
|
+
readonly WatchItems: "watchItems";
|
|
30
|
+
/** ArrayNode.watchLength() */
|
|
31
|
+
readonly WatchLength: "watchLength";
|
|
32
|
+
};
|
|
33
|
+
export type SubscriptionKeyType = (typeof SubscriptionKey)[keyof typeof SubscriptionKey];
|
|
34
|
+
/**
|
|
35
|
+
* Генерирует уникальный идентификатор с указанным префиксом.
|
|
36
|
+
*
|
|
37
|
+
* @param prefix - Префикс для идентификатора (используйте {@link SubscriptionKey}).
|
|
38
|
+
* @returns Уникальный идентификатор в формате `${prefix}-${counter}`.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { uniqueId, SubscriptionKey } from '@reformer/core';
|
|
43
|
+
*
|
|
44
|
+
* uniqueId(SubscriptionKey.WatchField); // → 'watchField-1'
|
|
45
|
+
* uniqueId(SubscriptionKey.WatchField); // → 'watchField-2'
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function uniqueId(prefix: SubscriptionKeyType): string;
|
|
49
|
+
/**
|
|
50
|
+
* Сбросить счётчик (только для тестов)
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
export declare function resetUniqueIdCounter(): void;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* @group Validation
|
|
5
|
-
* @category Core Functions
|
|
6
|
-
*/
|
|
7
|
-
import type { FieldPath } from '../../types/field-path';
|
|
8
|
-
import type { ConditionFn } from '../../types/validation-schema';
|
|
9
|
-
import type { FieldPathNode } from '../../types';
|
|
1
|
+
import { FieldPath } from '../../types/field-path';
|
|
2
|
+
import { ConditionFn } from '../../types/validation-schema';
|
|
3
|
+
import { FieldPathNode } from '../../types';
|
|
10
4
|
/**
|
|
11
5
|
* Применить валидацию только при выполнении условия
|
|
12
6
|
*
|
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Предоставляет функции для переиспользования validation схем:
|
|
5
|
-
* - apply: применение схемы к полям (новый API)
|
|
6
|
-
*
|
|
7
|
-
* Дополняет существующий toFieldPath и applyWhen.
|
|
8
|
-
*
|
|
9
|
-
* @group Validation
|
|
10
|
-
* @category Core Functions
|
|
11
|
-
*/
|
|
12
|
-
import type { FieldPathNode, FieldPath } from '../../types';
|
|
13
|
-
import type { ValidationSchemaFn } from '../../types/validation-schema';
|
|
1
|
+
import { FieldPathNode, FieldPath } from '../../types';
|
|
2
|
+
import { ValidationSchemaFn } from '../../types/validation-schema';
|
|
14
3
|
/**
|
|
15
4
|
* Применить validation схему к корневому path формы
|
|
16
5
|
*
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @group Validation
|
|
5
|
-
* @category Core Functions
|
|
6
|
-
*/
|
|
7
|
-
import type { ContextualAsyncValidatorFn, ValidateAsyncOptions } from '../../types/validation-schema';
|
|
8
|
-
import type { FieldPathNode } from '../../types';
|
|
1
|
+
import { ContextualAsyncValidatorFn, ValidateAsyncOptions } from '../../types/validation-schema';
|
|
2
|
+
import { FieldPathNode } from '../../types';
|
|
9
3
|
/**
|
|
10
4
|
* Зарегистрировать асинхронный валидатор для поля
|
|
11
5
|
*
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Кастомная синхронная валидация поля
|
|
3
|
-
*
|
|
4
|
-
* @group Validation
|
|
5
|
-
* @category Core Functions
|
|
6
|
-
*/
|
|
7
|
-
import type { ContextualValidatorFn, FieldPathNode, ValidateOptions } from '../../types';
|
|
1
|
+
import { ContextualValidatorFn, FieldPathNode, ValidateOptions } from '../../types';
|
|
8
2
|
/**
|
|
9
3
|
* Зарегистрировать кастомный синхронный валидатор для поля
|
|
10
4
|
* Поддерживает опциональные поля
|
|
@@ -13,9 +13,15 @@ export { pattern } from './validators/pattern';
|
|
|
13
13
|
export { url } from './validators/url';
|
|
14
14
|
export { phone, type PhoneFormat } from './validators/phone';
|
|
15
15
|
export { number } from './validators/number';
|
|
16
|
-
export {
|
|
16
|
+
export { isDate } from './validators/is-date';
|
|
17
|
+
export { minDate } from './validators/min-date';
|
|
18
|
+
export { maxDate } from './validators/max-date';
|
|
19
|
+
export { pastDate } from './validators/past-date';
|
|
20
|
+
export { futureDate } from './validators/future-date';
|
|
21
|
+
export { minAge } from './validators/min-age';
|
|
22
|
+
export { maxAge } from './validators/max-age';
|
|
17
23
|
export { notEmpty, validateItems } from './validators/array-validators';
|
|
18
|
-
export { createFieldPath, extractPath, extractKey, toFieldPath } from '
|
|
24
|
+
export { createFieldPath, extractPath, extractKey, toFieldPath } from '../utils/field-path';
|
|
19
25
|
export { validateForm } from './validate-form';
|
|
20
26
|
export { ValidationRegistry } from './validation-registry';
|
|
21
27
|
export { ValidationContextImpl, TreeValidationContextImpl } from './validation-context';
|
|
@@ -1,42 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* validateForm - утилита для валидации формы в соответствии со схемой
|
|
3
|
-
*
|
|
4
|
-
* Позволяет применить validation schema к форме без изменения
|
|
5
|
-
* зарегистрированной схемы в ValidationRegistry.
|
|
6
|
-
*
|
|
7
|
-
* ## Использование
|
|
8
|
-
*
|
|
9
|
-
* - **Multi-step формы**: валидация только полей текущего шага
|
|
10
|
-
* - **Условная валидация**: применение разных схем в зависимости от состояния
|
|
11
|
-
* - **Временная валидация**: проверка без сохранения в реестр
|
|
12
|
-
*
|
|
13
|
-
* ## Как это работает
|
|
14
|
-
*
|
|
15
|
-
* 1. Создаётся временный ValidationRegistry для схемы
|
|
16
|
-
* 2. Валидируются все FieldNode (field-level валидаторы из FieldConfig)
|
|
17
|
-
* 3. Применяются ТОЛЬКО contextual validators из переданной схемы
|
|
18
|
-
* 4. Временный реестр отменяется (не сохраняется в форму)
|
|
19
|
-
*
|
|
20
|
-
* ## Важно для multi-step форм
|
|
21
|
-
*
|
|
22
|
-
* Форма может быть создана С полной схемой валидации:
|
|
23
|
-
* ```typescript
|
|
24
|
-
* createForm({
|
|
25
|
-
* form: schema,
|
|
26
|
-
* validation: fullValidation, // Полная схема
|
|
27
|
-
* });
|
|
28
|
-
* ```
|
|
29
|
-
*
|
|
30
|
-
* При этом `validateForm(form, stepSchema)` будет применять
|
|
31
|
-
* только валидаторы из `stepSchema`, игнорируя валидаторы
|
|
32
|
-
* из других шагов.
|
|
33
|
-
*
|
|
34
|
-
* @see docs/multi-step-validation.md для подробной документации
|
|
35
|
-
*
|
|
36
|
-
* @module validation
|
|
37
|
-
*/
|
|
38
1
|
import { GroupNode } from '../nodes/group-node';
|
|
39
|
-
import
|
|
2
|
+
import { ValidationSchemaFn, FormFields } from '../types';
|
|
40
3
|
/**
|
|
41
4
|
* Валидировать форму в соответствии с указанной схемой
|
|
42
5
|
*
|
|
@@ -1,24 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Извлечено из GroupNode для соблюдения SRP (Single Responsibility Principle).
|
|
5
|
-
* Отвечает только за логику применения валидаторов к полям формы.
|
|
6
|
-
*
|
|
7
|
-
* @template T Тип формы
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* class GroupNode {
|
|
12
|
-
* private readonly validationApplicator = new ValidationApplicator(this);
|
|
13
|
-
*
|
|
14
|
-
* async applyContextualValidators(validators: ValidatorRegistration[]) {
|
|
15
|
-
* await this.validationApplicator.apply(validators);
|
|
16
|
-
* }
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
import type { GroupNode } from '../nodes/group-node';
|
|
21
|
-
import type { ValidatorRegistration } from '../types';
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { ValidatorRegistration } from '../types';
|
|
22
3
|
/**
|
|
23
4
|
* Класс для применения валидаторов к форме
|
|
24
5
|
*
|