@reformer/core 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +143 -0
- 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.d.ts +6 -0
- package/dist/behaviors.js +29 -0
- package/dist/core/behavior/behavior-context.d.ts +47 -0
- package/dist/core/behavior/behavior-registry.d.ts +85 -0
- package/dist/core/behavior/behaviors/compute-from.d.ts +70 -0
- package/dist/core/behavior/behaviors/copy-from.d.ts +56 -0
- package/dist/core/behavior/behaviors/enable-when.d.ts +118 -0
- package/dist/core/behavior/behaviors/index.d.ts +11 -0
- package/dist/core/behavior/behaviors/reset-when.d.ts +64 -0
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +53 -0
- package/dist/core/behavior/behaviors/sync-fields.d.ts +48 -0
- package/dist/core/behavior/behaviors/transform-value.d.ts +192 -0
- package/dist/core/behavior/behaviors/watch-field.d.ts +80 -0
- package/dist/core/behavior/compose-behavior.d.ts +96 -0
- package/dist/core/behavior/index.d.ts +11 -0
- package/dist/core/behavior/types.d.ts +146 -0
- package/dist/core/factories/index.d.ts +6 -0
- package/dist/core/factories/node-factory.d.ts +186 -0
- package/dist/core/nodes/array-node.d.ts +328 -0
- package/dist/core/nodes/field-node.d.ts +294 -0
- package/dist/core/nodes/form-node.d.ts +340 -0
- package/dist/core/nodes/group-node.d.ts +319 -0
- package/dist/core/types/deep-schema.d.ts +68 -0
- package/dist/core/types/field-path.d.ts +42 -0
- package/dist/core/types/form-context.d.ts +89 -0
- package/dist/core/types/form-proxy.d.ts +105 -0
- package/dist/core/types/index.d.ts +209 -0
- package/dist/core/types/validation-schema.d.ts +95 -0
- 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 +44 -0
- package/dist/core/utils/error-handler.d.ts +163 -0
- package/dist/core/utils/field-path-navigator.d.ts +240 -0
- package/dist/core/utils/field-path.d.ts +60 -0
- 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 +22 -0
- package/dist/core/utils/registry-helpers.d.ts +43 -0
- package/dist/core/utils/registry-stack.d.ts +69 -0
- package/dist/core/utils/safe-effect.d.ts +73 -0
- package/dist/core/utils/status-machine.d.ts +153 -0
- package/dist/core/utils/subscription-manager.d.ts +180 -0
- package/dist/core/utils/type-guards.d.ts +98 -0
- package/dist/core/utils/unique-id.d.ts +53 -0
- package/dist/core/validation/core/apply-when.d.ts +22 -0
- package/dist/core/validation/core/apply.d.ts +52 -0
- package/dist/core/validation/core/index.d.ts +8 -0
- package/dist/core/validation/core/validate-async.d.ts +36 -0
- package/dist/core/validation/core/validate-tree.d.ts +35 -0
- package/dist/core/validation/core/validate.d.ts +26 -0
- package/dist/core/validation/index.d.ts +27 -0
- package/dist/core/validation/validate-form.d.ts +48 -0
- package/dist/core/validation/validation-applicator.d.ts +70 -0
- package/dist/core/validation/validation-context.d.ts +86 -0
- package/dist/core/validation/validation-registry.d.ts +142 -0
- package/dist/core/validation/validators/array-validators.d.ts +53 -0
- package/dist/core/validation/validators/date-utils.d.ts +26 -0
- package/dist/core/validation/validators/email.d.ts +37 -0
- package/dist/core/validation/validators/future-date.d.ts +35 -0
- package/dist/core/validation/validators/index.d.ts +20 -0
- 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 +38 -0
- package/dist/core/validation/validators/max.d.ts +38 -0
- 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 +38 -0
- package/dist/core/validation/validators/min.d.ts +38 -0
- package/dist/core/validation/validators/number.d.ts +31 -0
- package/dist/core/validation/validators/past-date.d.ts +35 -0
- package/dist/core/validation/validators/pattern.d.ts +40 -0
- package/dist/core/validation/validators/phone.d.ts +27 -0
- package/dist/core/validation/validators/required.d.ts +41 -0
- package/dist/core/validation/validators/url.d.ts +22 -0
- package/dist/date-utils-xUWFslTj.js +29 -0
- package/dist/field-path-DuKdGcIE.js +66 -0
- package/dist/hooks/types.d.ts +328 -0
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +24 -0
- package/dist/hooks/useFormControlValue.d.ts +167 -0
- package/dist/hooks/useHiddenCondition.d.ts +25 -0
- package/dist/hooks/useSignalSubscription.d.ts +17 -0
- package/dist/index-D25LsbRm.js +73 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +3271 -0
- 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.d.ts +6 -0
- package/dist/validators.js +56 -0
- package/llms.txt +9351 -0
- package/package.json +166 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { FieldPathNode } from '../../types';
|
|
2
|
+
import { BehaviorContext, WatchFieldOptions } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Выполняет callback при изменении поля
|
|
5
|
+
*
|
|
6
|
+
* @group Behaviors
|
|
7
|
+
* @category Behavior Rules
|
|
8
|
+
*
|
|
9
|
+
* @param field - Поле для отслеживания
|
|
10
|
+
* @param callback - Функция обратного вызова
|
|
11
|
+
* @param options - Опции (`debounce`, `immediate`)
|
|
12
|
+
*
|
|
13
|
+
* @example Async loader with try/catch + guard + debounce
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { watchField, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
16
|
+
*
|
|
17
|
+
* interface AddressForm { region: string; city: string }
|
|
18
|
+
*
|
|
19
|
+
* export const addressBehavior: BehaviorSchemaFn<AddressForm> = (path) => {
|
|
20
|
+
* watchField(
|
|
21
|
+
* path.region,
|
|
22
|
+
* async (region, ctx) => {
|
|
23
|
+
* if (!region) {
|
|
24
|
+
* ctx.form.city.updateComponentProps({ options: [] });
|
|
25
|
+
* return; // guard: пустое значение не триггерит fetch
|
|
26
|
+
* }
|
|
27
|
+
* try {
|
|
28
|
+
* const { data: cities } = await fetchCities(region);
|
|
29
|
+
* ctx.form.city.updateComponentProps({ options: cities });
|
|
30
|
+
* } catch (error) {
|
|
31
|
+
* console.error('[addressBehavior] failed to load cities:', error);
|
|
32
|
+
* ctx.form.city.updateComponentProps({ options: [] });
|
|
33
|
+
* }
|
|
34
|
+
* },
|
|
35
|
+
* { immediate: false, debounce: 300 }, // обязательные опции для async
|
|
36
|
+
* );
|
|
37
|
+
* };
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example Sync handler с консолидацией нескольких зависимостей в один watcher
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { watchField, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
43
|
+
*
|
|
44
|
+
* interface InsuranceForm {
|
|
45
|
+
* insuranceType: 'casco' | 'osago' | 'property' | '';
|
|
46
|
+
* vehicleVin: string;
|
|
47
|
+
* propertyType: string;
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* export const insuranceBehavior: BehaviorSchemaFn<InsuranceForm> = (path) => {
|
|
51
|
+
* // ОДИН watchField на trigger-поле — несколько watcher'ов на одно поле = "Cycle detected"
|
|
52
|
+
* watchField(
|
|
53
|
+
* path.insuranceType,
|
|
54
|
+
* (type, ctx) => {
|
|
55
|
+
* const isVehicle = type === 'casco' || type === 'osago';
|
|
56
|
+
* const isProperty = type === 'property';
|
|
57
|
+
*
|
|
58
|
+
* // Guard — ставим только если состояние реально меняется
|
|
59
|
+
* if (isVehicle) {
|
|
60
|
+
* if (ctx.form.vehicleVin.disabled.value) ctx.form.vehicleVin.enable();
|
|
61
|
+
* } else {
|
|
62
|
+
* if (!ctx.form.vehicleVin.disabled.value) ctx.form.vehicleVin.disable();
|
|
63
|
+
* if (ctx.form.vehicleVin.getValue() !== '') ctx.form.vehicleVin.setValue('');
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* if (isProperty) {
|
|
67
|
+
* if (ctx.form.propertyType.disabled.value) ctx.form.propertyType.enable();
|
|
68
|
+
* } else {
|
|
69
|
+
* if (!ctx.form.propertyType.disabled.value) ctx.form.propertyType.disable();
|
|
70
|
+
* if (ctx.form.propertyType.getValue() !== '') ctx.form.propertyType.setValue('');
|
|
71
|
+
* }
|
|
72
|
+
* },
|
|
73
|
+
* { immediate: false }, // CRITICAL: предотвращает запуск во время инициализации
|
|
74
|
+
* );
|
|
75
|
+
* };
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @see [docs/llms/22-cycle-detection.md](../../../../docs/llms/22-cycle-detection.md)
|
|
79
|
+
*/
|
|
80
|
+
export declare function watchField<TForm, TField>(field: FieldPathNode<TForm, TField>, callback: (value: TField, ctx: BehaviorContext<TForm>) => void | Promise<void>, options?: WatchFieldOptions): void;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { FieldPath, FieldPathNode, FormFields, FormValue } from '../types';
|
|
2
|
+
import { BehaviorSchemaFn } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Преобразовать FieldPath во вложенный путь для композиции behavior схем
|
|
5
|
+
*
|
|
6
|
+
* Аналог toFieldPath из validation API.
|
|
7
|
+
*
|
|
8
|
+
* @param fieldPath - Поле для преобразования
|
|
9
|
+
* @returns Вложенный FieldPath
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // address-behavior.ts
|
|
14
|
+
* export const addressBehavior = (path: FieldPath<Address>) => {
|
|
15
|
+
* watchField(path.country, async (country, ctx) => {
|
|
16
|
+
* const regions = await fetchRegions(country);
|
|
17
|
+
* ctx.updateComponentProps(path.region, { options: regions });
|
|
18
|
+
* });
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* // user-behavior.ts
|
|
22
|
+
* export const userBehavior = (path: FieldPath<User>) => {
|
|
23
|
+
* // Композиция: применяем addressBehavior к вложенному полю
|
|
24
|
+
* addressBehavior(toBehaviorFieldPath(path.address));
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function toBehaviorFieldPath<TForm, TField>(fieldPath: FieldPathNode<TForm, TField> | undefined): FieldPath<TField>;
|
|
29
|
+
/**
|
|
30
|
+
* Применить behavior схему к вложенному полю или полям
|
|
31
|
+
*
|
|
32
|
+
* Поддерживает:
|
|
33
|
+
* - Одно поле или массив полей
|
|
34
|
+
* - Одну схему или массив схем
|
|
35
|
+
* - Все комбинации (поле + схема, поле + схемы, поля + схема, поля + схемы)
|
|
36
|
+
*
|
|
37
|
+
* @param fields - Одно поле или массив полей
|
|
38
|
+
* @param behaviors - Одна схема или массив схем
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* // Одна схема к одному полю
|
|
43
|
+
* apply(path.registrationAddress, addressBehavior);
|
|
44
|
+
*
|
|
45
|
+
* // Одна схема к нескольким полям
|
|
46
|
+
* apply([path.registrationAddress, path.residenceAddress], addressBehavior);
|
|
47
|
+
*
|
|
48
|
+
* // Несколько схем к одному полю
|
|
49
|
+
* apply(path.properties, [propertyBehavior, arrayBehavior]);
|
|
50
|
+
*
|
|
51
|
+
* // Несколько схем к нескольким полям
|
|
52
|
+
* apply(
|
|
53
|
+
* [path.registrationAddress, path.residenceAddress],
|
|
54
|
+
* [addressBehavior, validationBehavior]
|
|
55
|
+
* );
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function apply<TForm, TField>(fields: FieldPathNode<TForm, TField> | Array<FieldPathNode<TForm, TField> | undefined> | undefined, behaviors: BehaviorSchemaFn<TField> | Array<BehaviorSchemaFn<TField>>): void;
|
|
59
|
+
/**
|
|
60
|
+
* Условное применение behavior схем (аналог applyWhen из validation API)
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ ВАЖНО: Эта функция НЕ создаёт новые behaviors при каждом изменении условия!
|
|
63
|
+
* Вместо этого behaviors регистрируются ОДИН РАЗ при первом вызове и затем
|
|
64
|
+
* просто не выполняются, если условие не выполнено.
|
|
65
|
+
*
|
|
66
|
+
* Это отличается от старой реализации, которая создавала утечку памяти,
|
|
67
|
+
* регистрируя behaviors при каждом изменении conditionField.
|
|
68
|
+
*
|
|
69
|
+
* @param conditionField - Поле для проверки условия
|
|
70
|
+
* @param condition - Функция проверки условия
|
|
71
|
+
* @param callback - Callback для применения behavior схем
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* // Применить addressBehavior только когда sameAsRegistration === false
|
|
76
|
+
* applyWhen(
|
|
77
|
+
* path.sameAsRegistration,
|
|
78
|
+
* (value) => value === false,
|
|
79
|
+
* (path) => {
|
|
80
|
+
* apply(path.residenceAddress, addressBehavior);
|
|
81
|
+
* }
|
|
82
|
+
* );
|
|
83
|
+
*
|
|
84
|
+
* // Или с прямым использованием path
|
|
85
|
+
* applyWhen(
|
|
86
|
+
* path.hasProperty,
|
|
87
|
+
* (value) => value === true,
|
|
88
|
+
* (path) => {
|
|
89
|
+
* apply(path.properties, propertyBehavior);
|
|
90
|
+
* // Можно применить несколько схем
|
|
91
|
+
* apply([path.properties, path.items], arrayBehavior);
|
|
92
|
+
* }
|
|
93
|
+
* );
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function applyWhen<TForm extends FormFields, TValue extends FormValue>(conditionField: FieldPathNode<TForm, TValue> | undefined, condition: (value: TValue) => boolean, callback: (path: FieldPath<TForm>) => void): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behavior Schema API - Декларативное описание реактивного поведения форм
|
|
3
|
+
*
|
|
4
|
+
* @group Behaviors
|
|
5
|
+
* @module behaviors
|
|
6
|
+
*/
|
|
7
|
+
export type { BehaviorSchemaFn, BehaviorContext, BehaviorHandlerFn, BehaviorOptions, CopyFromOptions, EnableWhenOptions, ComputeFromOptions, WatchFieldOptions, RevalidateWhenOptions, SyncFieldsOptions, } from './types';
|
|
8
|
+
export * from './behaviors';
|
|
9
|
+
export { apply, applyWhen, toBehaviorFieldPath } from './compose-behavior';
|
|
10
|
+
export { BehaviorRegistry } from './behavior-registry';
|
|
11
|
+
export { BehaviorContextImpl } from './behavior-context';
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { FieldPath } from '../types/field-path';
|
|
3
|
+
import { FormContext } from '../types/form-context';
|
|
4
|
+
/**
|
|
5
|
+
* Тип функции behavior схемы
|
|
6
|
+
* Принимает FieldPath и описывает поведение формы
|
|
7
|
+
*
|
|
8
|
+
* @group Behaviors
|
|
9
|
+
* @category Behavior Types
|
|
10
|
+
*/
|
|
11
|
+
export type BehaviorSchemaFn<T> = (path: FieldPath<T>) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Контекст для behavior callback функций
|
|
14
|
+
* Алиас для FormContext
|
|
15
|
+
*
|
|
16
|
+
* @group Behaviors
|
|
17
|
+
* @category Behavior Types
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* watchField(path.country, async (country, ctx) => {
|
|
22
|
+
* // Прямой типизированный доступ к полям
|
|
23
|
+
* const cities = await fetchCities(country);
|
|
24
|
+
* ctx.form.city.updateComponentProps({ options: cities });
|
|
25
|
+
*
|
|
26
|
+
* // Безопасная установка значения (без циклов)
|
|
27
|
+
* ctx.setFieldValue('city', null);
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export type BehaviorContext<TForm> = FormContext<TForm>;
|
|
32
|
+
/**
|
|
33
|
+
* Функция-handler для behavior
|
|
34
|
+
*
|
|
35
|
+
* Создает effect подписку для реактивного поведения формы.
|
|
36
|
+
*
|
|
37
|
+
* @group Behaviors
|
|
38
|
+
* @category Behavior Types
|
|
39
|
+
*
|
|
40
|
+
* @template TForm - Тип формы
|
|
41
|
+
* @param form - Корневой узел формы (GroupNode)
|
|
42
|
+
* @param context - Контекст для работы с формой
|
|
43
|
+
* @param withDebounce - Функция-обертка для debounce
|
|
44
|
+
* @returns Функция cleanup для отписки от effect или null
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const handler: BehaviorHandlerFn<MyForm> = (form, context, withDebounce) => {
|
|
49
|
+
* const sourceNode = form.getFieldByPath('email');
|
|
50
|
+
*
|
|
51
|
+
* return effect(() => {
|
|
52
|
+
* const value = sourceNode.value.value;
|
|
53
|
+
* withDebounce(() => {
|
|
54
|
+
* // Логика behavior
|
|
55
|
+
* });
|
|
56
|
+
* });
|
|
57
|
+
* };
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export type BehaviorHandlerFn<TForm> = (form: GroupNode<TForm>, context: BehaviorContext<TForm>, withDebounce: (callback: () => void) => void) => (() => void) | null;
|
|
61
|
+
/**
|
|
62
|
+
* Общие опции для behavior
|
|
63
|
+
*
|
|
64
|
+
* @group Behaviors
|
|
65
|
+
* @category Behavior Types
|
|
66
|
+
*/
|
|
67
|
+
export interface BehaviorOptions {
|
|
68
|
+
/** Debounce в миллисекундах */
|
|
69
|
+
debounce?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Опции для copyFrom
|
|
73
|
+
*
|
|
74
|
+
* @group Behaviors
|
|
75
|
+
* @category Behavior Types
|
|
76
|
+
*/
|
|
77
|
+
export interface CopyFromOptions<TSource, TForm = unknown> {
|
|
78
|
+
/** Условие копирования */
|
|
79
|
+
when?: (form: TForm) => boolean;
|
|
80
|
+
/** Какие поля копировать (для групп) */
|
|
81
|
+
fields?: (keyof TSource)[] | 'all';
|
|
82
|
+
/** Трансформация значения */
|
|
83
|
+
transform?: (value: TSource) => unknown;
|
|
84
|
+
/** Debounce в мс */
|
|
85
|
+
debounce?: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Опции для enableWhen/disableWhen
|
|
89
|
+
*
|
|
90
|
+
* @group Behaviors
|
|
91
|
+
* @category Behavior Types
|
|
92
|
+
*/
|
|
93
|
+
export interface EnableWhenOptions {
|
|
94
|
+
/** Сбросить значение при disable */
|
|
95
|
+
resetOnDisable?: boolean;
|
|
96
|
+
/** Debounce в мс */
|
|
97
|
+
debounce?: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Опции для computeFrom
|
|
101
|
+
*
|
|
102
|
+
* @group Behaviors
|
|
103
|
+
* @category Behavior Types
|
|
104
|
+
*/
|
|
105
|
+
export interface ComputeFromOptions<TForm> {
|
|
106
|
+
/** Когда вычислять */
|
|
107
|
+
trigger?: 'change' | 'blur';
|
|
108
|
+
/** Debounce в мс */
|
|
109
|
+
debounce?: number;
|
|
110
|
+
/** Условие применения */
|
|
111
|
+
condition?: (form: TForm) => boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Опции для watchField
|
|
115
|
+
*
|
|
116
|
+
* @group Behaviors
|
|
117
|
+
* @category Behavior Types
|
|
118
|
+
*/
|
|
119
|
+
export interface WatchFieldOptions {
|
|
120
|
+
/** Debounce в мс */
|
|
121
|
+
debounce?: number;
|
|
122
|
+
/** Вызвать сразу при инициализации */
|
|
123
|
+
immediate?: boolean;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Опции для revalidateWhen
|
|
127
|
+
*
|
|
128
|
+
* @group Behaviors
|
|
129
|
+
* @category Behavior Types
|
|
130
|
+
*/
|
|
131
|
+
export interface RevalidateWhenOptions {
|
|
132
|
+
/** Debounce в мс */
|
|
133
|
+
debounce?: number;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Опции для syncFields
|
|
137
|
+
*
|
|
138
|
+
* @group Behaviors
|
|
139
|
+
* @category Behavior Types
|
|
140
|
+
*/
|
|
141
|
+
export interface SyncFieldsOptions<T> {
|
|
142
|
+
/** Трансформация значения */
|
|
143
|
+
transform?: (value: T) => T;
|
|
144
|
+
/** Debounce в мс */
|
|
145
|
+
debounce?: number;
|
|
146
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { FormNode } from '../nodes/form-node';
|
|
2
|
+
/**
|
|
3
|
+
* Фабрика для создания узлов формы.
|
|
4
|
+
*
|
|
5
|
+
* Определяет тип конфига и создаёт соответствующий узел (FieldNode, GroupNode, ArrayNode).
|
|
6
|
+
* Используется внутри `getReformerForm`/`group`/`array` — явно вызывать обычно не нужно.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { NodeFactory } from '@reformer/core';
|
|
11
|
+
*
|
|
12
|
+
* const node = NodeFactory.create({ value: '' }); // → FieldNode<string>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class NodeFactory {
|
|
16
|
+
/**
|
|
17
|
+
* Создает узел формы на основе конфигурации
|
|
18
|
+
*
|
|
19
|
+
* ✅ ОБНОВЛЕНО: Теперь поддерживает массивы напрямую
|
|
20
|
+
*
|
|
21
|
+
* Автоматически определяет тип узла:
|
|
22
|
+
* - FieldNode: имеет value и component
|
|
23
|
+
* - ArrayNode: массив [schema, ...items] или { schema, initialItems }
|
|
24
|
+
* - GroupNode: объект без value, component, schema
|
|
25
|
+
*
|
|
26
|
+
* @param config Конфигурация узла
|
|
27
|
+
* @returns Экземпляр FieldNode, GroupNode или ArrayNode
|
|
28
|
+
* @throws Error если конфиг не соответствует ни одному типу
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const factory = new NodeFactory();
|
|
33
|
+
*
|
|
34
|
+
* // FieldNode
|
|
35
|
+
* const field = factory.createNode({
|
|
36
|
+
* value: 'test@mail.com',
|
|
37
|
+
* component: Input,
|
|
38
|
+
* validators: [required, email]
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // GroupNode
|
|
42
|
+
* const group = factory.createNode({
|
|
43
|
+
* email: { value: '', component: Input },
|
|
44
|
+
* password: { value: '', component: Input }
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // ArrayNode (объект)
|
|
48
|
+
* const array = factory.createNode({
|
|
49
|
+
* schema: { title: { value: '', component: Input } },
|
|
50
|
+
* initialItems: [{ title: 'Item 1' }]
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* // ArrayNode (массив) - новый формат
|
|
54
|
+
* const array2 = factory.createNode([
|
|
55
|
+
* { title: { value: '', component: Input } }, // schema
|
|
56
|
+
* { title: 'Item 1' }, // initial item 1
|
|
57
|
+
* { title: 'Item 2' } // initial item 2
|
|
58
|
+
* ]);
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
createNode<T>(config: unknown): FormNode<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Создать ArrayNode из массива [schema, ...initialItems]
|
|
64
|
+
*
|
|
65
|
+
* ✅ НОВОЕ: Извлечено из GroupNode для централизации логики
|
|
66
|
+
*
|
|
67
|
+
* Формат: [itemSchema, ...initialItems]
|
|
68
|
+
* - Первый элемент - схема элемента массива
|
|
69
|
+
* - Остальные элементы - начальные значения
|
|
70
|
+
*
|
|
71
|
+
* @param config Массив с схемой и начальными элементами
|
|
72
|
+
* @returns ArrayNode
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const factory = new NodeFactory();
|
|
77
|
+
*
|
|
78
|
+
* // Массив с начальными элементами
|
|
79
|
+
* const array = factory.createArrayNodeFromArray([
|
|
80
|
+
* { title: { value: '', component: Input } }, // schema
|
|
81
|
+
* { title: 'Item 1' }, // initial value
|
|
82
|
+
* { title: 'Item 2' } // initial value
|
|
83
|
+
* ]);
|
|
84
|
+
* ```
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
private createArrayNodeFromArray;
|
|
88
|
+
/**
|
|
89
|
+
* Извлечь значения из схемы (рекурсивно)
|
|
90
|
+
*
|
|
91
|
+
* ✅ НОВОЕ: Извлечено из GroupNode для централизации логики
|
|
92
|
+
*
|
|
93
|
+
* Преобразует схему формы в объект со значениями:
|
|
94
|
+
* - `{ name: { value: 'John', component: Input } } → { name: 'John' }`
|
|
95
|
+
* - Поддерживает вложенные группы
|
|
96
|
+
* - Поддерживает массивы
|
|
97
|
+
*
|
|
98
|
+
* @param schema Схема формы
|
|
99
|
+
* @returns Объект со значениями полей
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const factory = new NodeFactory();
|
|
104
|
+
*
|
|
105
|
+
* const schema = {
|
|
106
|
+
* name: { value: 'John', component: Input },
|
|
107
|
+
* age: { value: 30, component: Input },
|
|
108
|
+
* address: {
|
|
109
|
+
* city: { value: 'Moscow', component: Input }
|
|
110
|
+
* }
|
|
111
|
+
* };
|
|
112
|
+
*
|
|
113
|
+
* factory.extractValues(schema);
|
|
114
|
+
* // { name: 'John', age: 30, address: { city: 'Moscow' } }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
extractValues(schema: unknown): unknown;
|
|
118
|
+
/**
|
|
119
|
+
* Проверяет, является ли конфиг конфигурацией поля (FieldConfig)
|
|
120
|
+
*
|
|
121
|
+
* FieldConfig имеет обязательные свойства:
|
|
122
|
+
* - value: начальное значение поля
|
|
123
|
+
* - component: React-компонент для отображения
|
|
124
|
+
*
|
|
125
|
+
* @param config Проверяемая конфигурация
|
|
126
|
+
* @returns true если config является FieldConfig
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const factory = new NodeFactory();
|
|
131
|
+
*
|
|
132
|
+
* factory.isFieldConfig({ value: '', component: Input }); // true
|
|
133
|
+
* factory.isFieldConfig({ email: { value: '' } }); // false
|
|
134
|
+
* factory.isFieldConfig(null); // false
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
isFieldConfig(config: unknown): boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Проверяет, является ли конфиг конфигурацией массива (ArrayConfig)
|
|
140
|
+
*
|
|
141
|
+
* ArrayConfig имеет обязательное свойство:
|
|
142
|
+
* - schema: схема для элементов массива
|
|
143
|
+
*
|
|
144
|
+
* И НЕ имеет:
|
|
145
|
+
* - value (отличие от FieldConfig)
|
|
146
|
+
*
|
|
147
|
+
* @param config Проверяемая конфигурация
|
|
148
|
+
* @returns true если config является ArrayConfig
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const factory = new NodeFactory();
|
|
153
|
+
*
|
|
154
|
+
* factory.isArrayConfig({ schema: {}, initialItems: [] }); // true
|
|
155
|
+
* factory.isArrayConfig({ value: '', component: Input }); // false
|
|
156
|
+
* factory.isArrayConfig({ email: { value: '' } }); // false
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
isArrayConfig(config: unknown): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Проверяет, является ли конфиг конфигурацией группы (GroupConfig)
|
|
162
|
+
*
|
|
163
|
+
* GroupConfig - это объект, который:
|
|
164
|
+
* - НЕ является FieldConfig (нет value/component)
|
|
165
|
+
* - НЕ является ArrayConfig (нет schema)
|
|
166
|
+
* - Содержит вложенные конфиги полей/групп/массивов
|
|
167
|
+
*
|
|
168
|
+
* @param config Проверяемая конфигурация
|
|
169
|
+
* @returns true если config является GroupConfig
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const factory = new NodeFactory();
|
|
174
|
+
*
|
|
175
|
+
* factory.isGroupConfig({
|
|
176
|
+
* email: { value: '', component: Input },
|
|
177
|
+
* password: { value: '', component: Input }
|
|
178
|
+
* }); // true
|
|
179
|
+
*
|
|
180
|
+
* factory.isGroupConfig({ value: '', component: Input }); // false
|
|
181
|
+
* factory.isGroupConfig({ schema: {} }); // false
|
|
182
|
+
* factory.isGroupConfig(null); // false
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
isGroupConfig(config: unknown): boolean;
|
|
186
|
+
}
|