@reformer/core 1.1.0 → 2.0.0-beta.11
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.d.ts +6 -2
- package/dist/behaviors.js +27 -228
- package/dist/core/behavior/behavior-context.d.ts +32 -14
- 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 +37 -212
- 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 +36 -30
- 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/{validation → utils}/field-path.d.ts +23 -6
- 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 +10 -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 +10 -10
- 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 +67 -28
- 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 +328 -0
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +15 -39
- 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 +8 -1
- package/dist/index.js +3271 -8
- 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 -2
- package/dist/validators.js +54 -296
- package/llms.txt +8887 -59
- package/package.json +87 -8
- package/dist/core/behavior/behavior-applicator.d.ts +0 -71
- package/dist/core/behavior/behavior-applicator.js +0 -92
- package/dist/core/behavior/behavior-context.js +0 -38
- package/dist/core/behavior/behavior-registry.js +0 -198
- package/dist/core/behavior/behaviors/compute-from.js +0 -84
- package/dist/core/behavior/behaviors/copy-from.js +0 -64
- package/dist/core/behavior/behaviors/enable-when.js +0 -81
- package/dist/core/behavior/behaviors/index.js +0 -11
- package/dist/core/behavior/behaviors/reset-when.js +0 -63
- package/dist/core/behavior/behaviors/revalidate-when.js +0 -51
- package/dist/core/behavior/behaviors/sync-fields.js +0 -66
- package/dist/core/behavior/behaviors/transform-value.js +0 -110
- package/dist/core/behavior/behaviors/watch-field.js +0 -56
- package/dist/core/behavior/compose-behavior.js +0 -166
- package/dist/core/behavior/create-field-path.d.ts +0 -20
- package/dist/core/behavior/create-field-path.js +0 -69
- package/dist/core/behavior/index.js +0 -17
- package/dist/core/behavior/types.js +0 -7
- package/dist/core/context/form-context-impl.d.ts +0 -29
- package/dist/core/context/form-context-impl.js +0 -37
- package/dist/core/factories/index.js +0 -6
- package/dist/core/factories/node-factory.js +0 -281
- package/dist/core/nodes/array-node.js +0 -534
- package/dist/core/nodes/field-node.js +0 -510
- package/dist/core/nodes/form-node.js +0 -343
- package/dist/core/nodes/group-node/field-registry.d.ts +0 -191
- package/dist/core/nodes/group-node/field-registry.js +0 -215
- package/dist/core/nodes/group-node/index.d.ts +0 -11
- package/dist/core/nodes/group-node/index.js +0 -11
- package/dist/core/nodes/group-node/proxy-builder.d.ts +0 -71
- package/dist/core/nodes/group-node/proxy-builder.js +0 -161
- package/dist/core/nodes/group-node/state-manager.d.ts +0 -184
- package/dist/core/nodes/group-node/state-manager.js +0 -265
- package/dist/core/nodes/group-node.js +0 -770
- package/dist/core/types/deep-schema.js +0 -11
- package/dist/core/types/field-path.js +0 -4
- package/dist/core/types/form-context.js +0 -25
- package/dist/core/types/group-node-proxy.js +0 -31
- package/dist/core/types/index.js +0 -4
- package/dist/core/types/validation-schema.js +0 -10
- package/dist/core/utils/create-form.js +0 -24
- package/dist/core/utils/debounce.d.ts +0 -160
- package/dist/core/utils/debounce.js +0 -197
- package/dist/core/utils/error-handler.js +0 -226
- package/dist/core/utils/field-path-navigator.js +0 -374
- package/dist/core/utils/index.js +0 -14
- package/dist/core/utils/registry-helpers.js +0 -79
- package/dist/core/utils/registry-stack.js +0 -86
- package/dist/core/utils/resources.d.ts +0 -41
- package/dist/core/utils/resources.js +0 -69
- package/dist/core/utils/subscription-manager.js +0 -214
- package/dist/core/utils/type-guards.js +0 -169
- package/dist/core/validation/core/apply-when.js +0 -41
- package/dist/core/validation/core/apply.js +0 -38
- package/dist/core/validation/core/index.js +0 -8
- package/dist/core/validation/core/validate-async.js +0 -45
- package/dist/core/validation/core/validate-tree.js +0 -37
- package/dist/core/validation/core/validate.js +0 -38
- package/dist/core/validation/field-path.js +0 -147
- package/dist/core/validation/index.js +0 -33
- package/dist/core/validation/validate-form.js +0 -152
- package/dist/core/validation/validation-applicator.js +0 -217
- package/dist/core/validation/validation-context.js +0 -75
- package/dist/core/validation/validation-registry.js +0 -298
- package/dist/core/validation/validators/array-validators.js +0 -86
- package/dist/core/validation/validators/date.d.ts +0 -38
- package/dist/core/validation/validators/date.js +0 -117
- package/dist/core/validation/validators/email.js +0 -60
- package/dist/core/validation/validators/index.js +0 -14
- package/dist/core/validation/validators/max-length.js +0 -60
- package/dist/core/validation/validators/max.js +0 -60
- package/dist/core/validation/validators/min-length.js +0 -60
- package/dist/core/validation/validators/min.js +0 -60
- package/dist/core/validation/validators/number.js +0 -90
- package/dist/core/validation/validators/pattern.js +0 -62
- package/dist/core/validation/validators/phone.js +0 -58
- package/dist/core/validation/validators/required.js +0 -69
- package/dist/core/validation/validators/url.js +0 -55
- package/dist/create-field-path-CdPF3lIK.js +0 -704
- package/dist/hooks/useFormControl.js +0 -298
- package/dist/node-factory-D7DOnSSN.js +0 -3200
|
@@ -1,21 +1,25 @@
|
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { BehaviorHandlerFn, BehaviorOptions } from './types';
|
|
3
|
+
import { AbstractRegistry } from '../utils/abstract-registry';
|
|
4
|
+
import { FormFields } from '../types';
|
|
1
5
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Аналогично ValidationRegistry, но для реактивного поведения форм
|
|
6
|
+
* Зарегистрированный behavior с опциями
|
|
5
7
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
export interface RegisteredBehavior {
|
|
9
|
+
/** Handler функция behavior */
|
|
10
|
+
handler: BehaviorHandlerFn<FormFields>;
|
|
11
|
+
/** Debounce в миллисекундах */
|
|
12
|
+
debounce?: number;
|
|
13
|
+
}
|
|
9
14
|
/**
|
|
10
15
|
* Реестр behaviors для формы
|
|
11
16
|
*
|
|
12
17
|
* Каждый экземпляр GroupNode создает собственный реестр (композиция).
|
|
13
18
|
* Устраняет race conditions и изолирует формы друг от друга.
|
|
14
19
|
*
|
|
15
|
-
*
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
18
|
-
* - getCurrent() возвращает текущий активный реестр
|
|
20
|
+
* Наследует AbstractRegistry для унификации:
|
|
21
|
+
* - Управления global stack
|
|
22
|
+
* - Template methods begin/end registration
|
|
19
23
|
*
|
|
20
24
|
* @example
|
|
21
25
|
* ```typescript
|
|
@@ -30,14 +34,7 @@ import { FormFields } from '../types';
|
|
|
30
34
|
* }
|
|
31
35
|
* ```
|
|
32
36
|
*/
|
|
33
|
-
export declare class BehaviorRegistry {
|
|
34
|
-
/**
|
|
35
|
-
* Stack активных контекстов регистрации
|
|
36
|
-
* Используется для изоляции форм друг от друга
|
|
37
|
-
*/
|
|
38
|
-
private static contextStack;
|
|
39
|
-
private registrations;
|
|
40
|
-
private isRegistering;
|
|
37
|
+
export declare class BehaviorRegistry extends AbstractRegistry<RegisteredBehavior> {
|
|
41
38
|
/**
|
|
42
39
|
* Получить текущий активный реестр из context stack
|
|
43
40
|
*
|
|
@@ -55,13 +52,6 @@ export declare class BehaviorRegistry {
|
|
|
55
52
|
* ```
|
|
56
53
|
*/
|
|
57
54
|
static getCurrent(): BehaviorRegistry | null;
|
|
58
|
-
/**
|
|
59
|
-
* Начать регистрацию behaviors
|
|
60
|
-
* Вызывается перед применением схемы
|
|
61
|
-
*
|
|
62
|
-
* Помещает this в context stack для изоляции форм
|
|
63
|
-
*/
|
|
64
|
-
beginRegistration(): void;
|
|
65
55
|
/**
|
|
66
56
|
* Зарегистрировать behavior handler
|
|
67
57
|
* Вызывается функциями из schema-behaviors.ts
|
|
@@ -80,8 +70,6 @@ export declare class BehaviorRegistry {
|
|
|
80
70
|
* Завершить регистрацию и применить behaviors к форме
|
|
81
71
|
* Создает effect подписки для всех зарегистрированных behaviors
|
|
82
72
|
*
|
|
83
|
-
* Извлекает this из context stack
|
|
84
|
-
*
|
|
85
73
|
* @param form - GroupNode формы
|
|
86
74
|
* @returns Количество зарегистрированных behaviors и функция cleanup
|
|
87
75
|
*/
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @group Behaviors
|
|
5
|
-
* @category Behavior Rules
|
|
6
|
-
* @module behaviors/computeFrom
|
|
7
|
-
*/
|
|
8
|
-
import type { FieldPathNode } from '../../types';
|
|
9
|
-
import type { ComputeFromOptions } from '../types';
|
|
1
|
+
import { FieldPathNode } from '../../types';
|
|
2
|
+
import { ComputeFromOptions } from '../types';
|
|
10
3
|
/**
|
|
11
4
|
* Автоматически вычисляет значение поля на основе других полей
|
|
12
5
|
*
|
|
@@ -16,26 +9,62 @@ import type { ComputeFromOptions } from '../types';
|
|
|
16
9
|
* @param sources - Массив полей-зависимостей
|
|
17
10
|
* @param target - Поле для записи результата
|
|
18
11
|
* @param computeFn - Функция вычисления (принимает объект с именами полей)
|
|
19
|
-
* @param options - Опции
|
|
12
|
+
* @param options - Опции (`debounce`, `condition`, `trigger`)
|
|
20
13
|
*
|
|
21
|
-
* @example
|
|
14
|
+
* @example Многополевой расчёт — total = price × quantity
|
|
22
15
|
* ```typescript
|
|
23
|
-
*
|
|
24
|
-
* // Автоматический расчет минимального взноса
|
|
25
|
-
* computeFrom(
|
|
26
|
-
* [path.propertyValue],
|
|
27
|
-
* path.initialPayment,
|
|
28
|
-
* (values) => values.propertyValue ? values.propertyValue * 0.2 : null,
|
|
29
|
-
* { debounce: 300 }
|
|
30
|
-
* );
|
|
16
|
+
* import { computeFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
31
17
|
*
|
|
32
|
-
*
|
|
18
|
+
* interface OrderForm {
|
|
19
|
+
* price: number;
|
|
20
|
+
* quantity: number;
|
|
21
|
+
* total: number;
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* export const orderBehavior: BehaviorSchemaFn<OrderForm> = (path) => {
|
|
33
25
|
* computeFrom(
|
|
34
26
|
* [path.price, path.quantity],
|
|
35
27
|
* path.total,
|
|
36
|
-
* (values) =>
|
|
28
|
+
* (values) =>
|
|
29
|
+
* (typeof values.price === 'number' ? values.price : 0) *
|
|
30
|
+
* (typeof values.quantity === 'number' ? values.quantity : 0),
|
|
31
|
+
* );
|
|
32
|
+
* };
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example Edge case — async-like дорогие вычисления с `debounce` и условием
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { computeFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
38
|
+
*
|
|
39
|
+
* interface MortgageForm {
|
|
40
|
+
* loanType: 'mortgage' | 'consumer';
|
|
41
|
+
* loanAmount: number;
|
|
42
|
+
* loanTerm: number;
|
|
43
|
+
* interestRate: number;
|
|
44
|
+
* monthlyPayment: number;
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* function annuity(values: MortgageForm): number {
|
|
48
|
+
* const { loanAmount, loanTerm, interestRate } = values;
|
|
49
|
+
* if (!loanAmount || !loanTerm || !interestRate) return 0;
|
|
50
|
+
* const r = interestRate / 100 / 12;
|
|
51
|
+
* const n = loanTerm;
|
|
52
|
+
* return Math.round((loanAmount * r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1));
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* export const mortgageBehavior: BehaviorSchemaFn<MortgageForm> = (path) => {
|
|
56
|
+
* computeFrom(
|
|
57
|
+
* [path.loanAmount, path.loanTerm, path.interestRate],
|
|
58
|
+
* path.monthlyPayment,
|
|
59
|
+
* annuity,
|
|
60
|
+
* {
|
|
61
|
+
* debounce: 300, // не пересчитываем на каждый keystroke
|
|
62
|
+
* condition: (form) => form.loanType === 'mortgage', // считаем только для ипотеки
|
|
63
|
+
* },
|
|
37
64
|
* );
|
|
38
65
|
* };
|
|
39
66
|
* ```
|
|
67
|
+
*
|
|
68
|
+
* @see [docs/llms/20-compute-vs-watch.md](../../../../docs/llms/20-compute-vs-watch.md)
|
|
40
69
|
*/
|
|
41
70
|
export declare function computeFrom<TForm, TTarget>(sources: FieldPathNode<TForm, any>[], target: FieldPathNode<TForm, TTarget>, computeFn: (values: TForm) => TTarget, options?: ComputeFromOptions<TForm>): void;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @group Behaviors
|
|
5
|
-
* @category Behavior Rules
|
|
6
|
-
* @module behaviors/copyFrom
|
|
7
|
-
*/
|
|
8
|
-
import type { FieldPathNode } from '../../types';
|
|
9
|
-
import type { CopyFromOptions } from '../types';
|
|
1
|
+
import { FieldPathNode } from '../../types';
|
|
2
|
+
import { CopyFromOptions } from '../types';
|
|
10
3
|
/**
|
|
11
4
|
* Копирует значения из одного поля/группы в другое при выполнении условия
|
|
12
5
|
*
|
|
@@ -15,17 +8,49 @@ import type { CopyFromOptions } from '../types';
|
|
|
15
8
|
*
|
|
16
9
|
* @param source - Откуда копировать
|
|
17
10
|
* @param target - Куда копировать
|
|
18
|
-
* @param options - Опции копирования
|
|
11
|
+
* @param options - Опции копирования (`when`, `fields`, `transform`, `debounce`)
|
|
19
12
|
*
|
|
20
|
-
* @example
|
|
13
|
+
* @example Скаляр → скаляр с условием
|
|
21
14
|
* ```typescript
|
|
22
|
-
*
|
|
23
|
-
*
|
|
15
|
+
* import { copyFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
16
|
+
*
|
|
17
|
+
* interface ContactForm {
|
|
18
|
+
* sameEmail: boolean;
|
|
19
|
+
* email: string;
|
|
20
|
+
* emailAdditional: string;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* export const contactBehavior: BehaviorSchemaFn<ContactForm> = (path) => {
|
|
24
|
+
* copyFrom(path.email, path.emailAdditional, {
|
|
25
|
+
* when: (form) => form.sameEmail === true,
|
|
26
|
+
* });
|
|
27
|
+
* };
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example Копирование группы с подмножеством полей и `transform`
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { copyFrom, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
33
|
+
*
|
|
34
|
+
* interface Address { country: string; region: string; city: string; street: string }
|
|
35
|
+
* interface ProfileForm {
|
|
36
|
+
* sameAsRegistration: boolean;
|
|
37
|
+
* registrationAddress: Address;
|
|
38
|
+
* residenceAddress: Address;
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* export const profileBehavior: BehaviorSchemaFn<ProfileForm> = (path) => {
|
|
24
42
|
* copyFrom(path.registrationAddress, path.residenceAddress, {
|
|
25
43
|
* when: (form) => form.sameAsRegistration === true,
|
|
26
|
-
* fields: '
|
|
44
|
+
* fields: ['country', 'region', 'city'], // street НЕ копируем
|
|
45
|
+
* transform: (addr) => ({
|
|
46
|
+
* ...addr,
|
|
47
|
+
* country: addr.country.toUpperCase(), // нормализация при копировании
|
|
48
|
+
* }),
|
|
49
|
+
* debounce: 200,
|
|
27
50
|
* });
|
|
28
51
|
* };
|
|
29
52
|
* ```
|
|
53
|
+
*
|
|
54
|
+
* @see [docs/llms/23-copy-from.md](../../../../docs/llms/23-copy-from.md)
|
|
30
55
|
*/
|
|
31
56
|
export declare function copyFrom<TForm, TSource, TTarget>(source: FieldPathNode<TForm, TSource>, target: FieldPathNode<TForm, TTarget>, options?: CopyFromOptions<TSource, TForm>): void;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @group Behaviors
|
|
5
|
-
* @category Behavior Rules
|
|
6
|
-
* @module behaviors/enableWhen
|
|
7
|
-
*/
|
|
8
|
-
import type { FieldPathNode } from '../../types';
|
|
9
|
-
import type { EnableWhenOptions } from '../types';
|
|
1
|
+
import { FieldPathNode } from '../../types';
|
|
2
|
+
import { EnableWhenOptions } from '../types';
|
|
10
3
|
/**
|
|
11
4
|
* Условное включение поля на основе значений других полей
|
|
12
5
|
*
|
|
@@ -15,17 +8,68 @@ import type { EnableWhenOptions } from '../types';
|
|
|
15
8
|
*
|
|
16
9
|
* @param field - Поле для включения/выключения
|
|
17
10
|
* @param condition - Функция условия (true = enable, false = disable)
|
|
18
|
-
* @param options - Опции
|
|
11
|
+
* @param options - Опции (`resetOnDisable`, `debounce`)
|
|
19
12
|
*
|
|
20
|
-
* @example
|
|
13
|
+
* @example Базовый сценарий с `resetOnDisable: true`
|
|
21
14
|
* ```typescript
|
|
22
|
-
*
|
|
23
|
-
*
|
|
15
|
+
* import { enableWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
16
|
+
*
|
|
17
|
+
* interface LoanForm {
|
|
18
|
+
* loanType: 'mortgage' | 'consumer' | 'car';
|
|
19
|
+
* propertyValue: number;
|
|
20
|
+
* initialPayment: number;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* export const loanBehavior: BehaviorSchemaFn<LoanForm> = (path) => {
|
|
24
|
+
* // Поля ипотеки активны только для loanType === 'mortgage'.
|
|
25
|
+
* // resetOnDisable: true гарантирует чистые initial values при переключении.
|
|
24
26
|
* enableWhen(path.propertyValue, (form) => form.loanType === 'mortgage', {
|
|
25
|
-
* resetOnDisable: true
|
|
27
|
+
* resetOnDisable: true,
|
|
28
|
+
* });
|
|
29
|
+
* enableWhen(path.initialPayment, (form) => form.loanType === 'mortgage', {
|
|
30
|
+
* resetOnDisable: true,
|
|
26
31
|
* });
|
|
27
32
|
* };
|
|
28
33
|
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example Множественные independent условия + cycle prevention
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { enableWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
38
|
+
*
|
|
39
|
+
* interface ProfileForm {
|
|
40
|
+
* sameAsRegistration: boolean;
|
|
41
|
+
* employmentStatus: 'employed' | 'selfEmployed' | 'unemployed';
|
|
42
|
+
* residenceAddress: { city: string; street: string };
|
|
43
|
+
* companyName: string;
|
|
44
|
+
* companyInn: string;
|
|
45
|
+
* businessType: string;
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* export const profileBehavior: BehaviorSchemaFn<ProfileForm> = (path) => {
|
|
49
|
+
* // Адрес проживания: enabled, когда НЕ совпадает с регистрационным
|
|
50
|
+
* enableWhen(path.residenceAddress, (form) => form.sameAsRegistration === false, {
|
|
51
|
+
* resetOnDisable: true,
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* // Поля работодателя: только для employed
|
|
55
|
+
* enableWhen(path.companyName, (form) => form.employmentStatus === 'employed', {
|
|
56
|
+
* resetOnDisable: true,
|
|
57
|
+
* });
|
|
58
|
+
* enableWhen(path.companyInn, (form) => form.employmentStatus === 'employed', {
|
|
59
|
+
* resetOnDisable: true,
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* // ИП-поля: только для selfEmployed
|
|
63
|
+
* enableWhen(path.businessType, (form) => form.employmentStatus === 'selfEmployed', {
|
|
64
|
+
* resetOnDisable: true,
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* // ВАЖНО: condition не должен читать значение САМОГО поля — иначе цикл.
|
|
68
|
+
* // condition зависит ТОЛЬКО от независимых триггеров (loanType, employmentStatus, ...).
|
|
69
|
+
* };
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @see [docs/llms/22-cycle-detection.md](../../../../docs/llms/22-cycle-detection.md)
|
|
29
73
|
*/
|
|
30
74
|
export declare function enableWhen<TForm>(field: FieldPathNode<TForm, any>, condition: (form: TForm) => boolean, options?: EnableWhenOptions): void;
|
|
31
75
|
/**
|
|
@@ -36,13 +80,38 @@ export declare function enableWhen<TForm>(field: FieldPathNode<TForm, any>, cond
|
|
|
36
80
|
*
|
|
37
81
|
* @param field - Поле для выключения
|
|
38
82
|
* @param condition - Функция условия (true = disable, false = enable)
|
|
39
|
-
* @param options - Опции
|
|
83
|
+
* @param options - Опции (`resetOnDisable`, `debounce`)
|
|
40
84
|
*
|
|
41
|
-
* @example
|
|
85
|
+
* @example Базовый сценарий — readonly после подтверждения
|
|
42
86
|
* ```typescript
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
87
|
+
* import { disableWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
88
|
+
*
|
|
89
|
+
* interface ConfirmForm {
|
|
90
|
+
* isConfirmed: boolean;
|
|
91
|
+
* editableField: string;
|
|
92
|
+
* }
|
|
93
|
+
*
|
|
94
|
+
* export const confirmBehavior: BehaviorSchemaFn<ConfirmForm> = (path) => {
|
|
95
|
+
* // Поле блокируется после установки чекбокса подтверждения
|
|
96
|
+
* disableWhen(path.editableField, (form) => form.isConfirmed === true);
|
|
97
|
+
* // resetOnDisable НЕ ставим — сохраняем введённый текст
|
|
98
|
+
* };
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @example С `resetOnDisable` для очистки заблокированного поля
|
|
102
|
+
* ```typescript
|
|
103
|
+
* import { disableWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
104
|
+
*
|
|
105
|
+
* interface PromoForm {
|
|
106
|
+
* loanType: 'mortgage' | 'consumer';
|
|
107
|
+
* promoCode: string;
|
|
108
|
+
* }
|
|
109
|
+
*
|
|
110
|
+
* export const promoBehavior: BehaviorSchemaFn<PromoForm> = (path) => {
|
|
111
|
+
* // Промокод недоступен для потребительских кредитов и сбрасывается
|
|
112
|
+
* disableWhen(path.promoCode, (form) => form.loanType === 'consumer', {
|
|
113
|
+
* resetOnDisable: true,
|
|
114
|
+
* });
|
|
46
115
|
* };
|
|
47
116
|
* ```
|
|
48
117
|
*/
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Условный сброс полей
|
|
3
|
-
*
|
|
4
|
-
* @group Behaviors
|
|
5
|
-
* @category Behavior Rules
|
|
6
|
-
* @module behaviors/resetWhen
|
|
7
|
-
*/
|
|
8
|
-
import type { FieldPathNode, FormFields, FormValue } from '../../types';
|
|
1
|
+
import { FieldPathNode, FormFields, FormValue } from '../../types';
|
|
9
2
|
/**
|
|
10
3
|
* Опции для resetWhen
|
|
11
4
|
*
|
|
@@ -26,25 +19,45 @@ export interface ResetWhenOptions {
|
|
|
26
19
|
*
|
|
27
20
|
* @param field - Поле для сброса
|
|
28
21
|
* @param condition - Функция условия (true = reset)
|
|
29
|
-
* @param options - Опции
|
|
22
|
+
* @param options - Опции (`resetValue`, `onlyIfDirty`, `debounce`)
|
|
30
23
|
*
|
|
31
|
-
* @example
|
|
24
|
+
* @example Сброс зависимого поля при смене типа платежа
|
|
32
25
|
* ```typescript
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
26
|
+
* import { resetWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
27
|
+
*
|
|
28
|
+
* interface CheckoutForm {
|
|
29
|
+
* paymentType: 'card' | 'cash';
|
|
30
|
+
* cardNumber: string;
|
|
31
|
+
* }
|
|
36
32
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
33
|
+
* export const checkoutBehavior: BehaviorSchemaFn<CheckoutForm> = (path) => {
|
|
34
|
+
* // Когда выбрано НЕ card — обнуляем номер карты в пустую строку
|
|
35
|
+
* resetWhen(path.cardNumber, (form) => form.paymentType !== 'card', {
|
|
36
|
+
* resetValue: '',
|
|
40
37
|
* });
|
|
38
|
+
* };
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example `onlyIfDirty` — не трогаем нетронутые initial значения
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { resetWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
44
|
+
*
|
|
45
|
+
* interface CarForm {
|
|
46
|
+
* loanType: 'mortgage' | 'car' | 'consumer';
|
|
47
|
+
* carPrice: number;
|
|
48
|
+
* }
|
|
41
49
|
*
|
|
42
|
-
*
|
|
50
|
+
* export const carBehavior: BehaviorSchemaFn<CarForm> = (path) => {
|
|
51
|
+
* // Если пользователь не вводил carPrice — оставляем default из схемы.
|
|
52
|
+
* // Сбрасываем только если поле dirty (была пользовательская правка).
|
|
43
53
|
* resetWhen(path.carPrice, (form) => form.loanType !== 'car', {
|
|
44
|
-
*
|
|
54
|
+
* resetValue: 0,
|
|
55
|
+
* onlyIfDirty: true,
|
|
45
56
|
* });
|
|
46
57
|
* };
|
|
47
58
|
* ```
|
|
59
|
+
*
|
|
60
|
+
* @see [docs/llms/25-reset-when.md](../../../../docs/llms/25-reset-when.md)
|
|
48
61
|
*/
|
|
49
62
|
export declare function resetWhen<TForm extends FormFields>(field: FieldPathNode<TForm, FormValue>, condition: (form: TForm) => boolean, options?: ResetWhenOptions & {
|
|
50
63
|
debounce?: number;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @group Behaviors
|
|
5
|
-
* @category Behavior Rules
|
|
6
|
-
* @module behaviors/revalidateWhen
|
|
7
|
-
*/
|
|
8
|
-
import type { FieldPathNode, FormValue } from '../../types';
|
|
9
|
-
import type { RevalidateWhenOptions } from '../types';
|
|
1
|
+
import { FieldPathNode, FormValue } from '../../types';
|
|
2
|
+
import { RevalidateWhenOptions } from '../types';
|
|
10
3
|
/**
|
|
11
4
|
* Перевалидирует поле при изменении других полей
|
|
12
5
|
*
|
|
@@ -14,17 +7,47 @@ import type { RevalidateWhenOptions } from '../types';
|
|
|
14
7
|
* @category Behavior Rules
|
|
15
8
|
*
|
|
16
9
|
* @param target - Поле для перевалидации
|
|
17
|
-
* @param triggers - Поля-триггеры
|
|
18
|
-
* @param options - Опции
|
|
10
|
+
* @param triggers - Поля-триггеры (НЕ должно содержать `target`)
|
|
11
|
+
* @param options - Опции (`debounce`)
|
|
12
|
+
*
|
|
13
|
+
* @example Парная перевалидация — confirmPassword при смене password
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { revalidateWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
16
|
+
* import { equalTo } from '@reformer/core/validators';
|
|
17
|
+
* import type { FieldPath } from '@reformer/core';
|
|
18
|
+
*
|
|
19
|
+
* interface RegistrationForm { password: string; confirmPassword: string }
|
|
19
20
|
*
|
|
20
|
-
*
|
|
21
|
+
* export const validation = (path: FieldPath<RegistrationForm>) => {
|
|
22
|
+
* equalTo(path.confirmPassword, path.password, { message: 'Пароли не совпадают' });
|
|
23
|
+
* };
|
|
24
|
+
*
|
|
25
|
+
* export const behavior: BehaviorSchemaFn<RegistrationForm> = (path) => {
|
|
26
|
+
* // Если пользователь сначала ввёл confirm, потом меняет password —
|
|
27
|
+
* // без revalidateWhen ошибка confirmPassword останется устаревшей.
|
|
28
|
+
* revalidateWhen(path.confirmPassword, [path.password]);
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example Несколько триггеров + `debounce` для async-валидаторов
|
|
21
33
|
* ```typescript
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
34
|
+
* import { revalidateWhen, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
35
|
+
*
|
|
36
|
+
* interface MortgageForm {
|
|
37
|
+
* propertyValue: number;
|
|
38
|
+
* loanAmount: number;
|
|
39
|
+
* initialPayment: number; // правило: initialPayment >= propertyValue * 0.2 - loanAmount
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* export const mortgageBehavior: BehaviorSchemaFn<MortgageForm> = (path) => {
|
|
43
|
+
* revalidateWhen(
|
|
44
|
+
* path.initialPayment,
|
|
45
|
+
* [path.propertyValue, path.loanAmount],
|
|
46
|
+
* { debounce: 300 }, // не дёргаем сервер на каждый keystroke
|
|
47
|
+
* );
|
|
27
48
|
* };
|
|
28
49
|
* ```
|
|
50
|
+
*
|
|
51
|
+
* @see [docs/llms/27-revalidate-when.md](../../../../docs/llms/27-revalidate-when.md)
|
|
29
52
|
*/
|
|
30
53
|
export declare function revalidateWhen<TForm>(target: FieldPathNode<TForm, FormValue>, triggers: FieldPathNode<TForm, FormValue>[], options?: RevalidateWhenOptions): void;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @group Behaviors
|
|
5
|
-
* @category Behavior Rules
|
|
6
|
-
* @module behaviors/syncFields
|
|
7
|
-
*/
|
|
8
|
-
import type { FieldPathNode, FormFields, FormValue } from '../../types';
|
|
9
|
-
import type { SyncFieldsOptions } from '../types';
|
|
1
|
+
import { FieldPathNode, FormFields, FormValue } from '../../types';
|
|
2
|
+
import { SyncFieldsOptions } from '../types';
|
|
10
3
|
/**
|
|
11
4
|
* Двусторонняя синхронизация двух полей
|
|
12
5
|
*
|
|
@@ -15,14 +8,41 @@ import type { SyncFieldsOptions } from '../types';
|
|
|
15
8
|
*
|
|
16
9
|
* @param field1 - Первое поле
|
|
17
10
|
* @param field2 - Второе поле
|
|
18
|
-
* @param options - Опции
|
|
11
|
+
* @param options - Опции (`transform` асимметричен — применяется только field1 → field2; `debounce`)
|
|
12
|
+
*
|
|
13
|
+
* @example Базовый mirror двух текстовых полей
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { syncFields, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
19
16
|
*
|
|
20
|
-
*
|
|
17
|
+
* interface MirrorForm {
|
|
18
|
+
* syncField1: string;
|
|
19
|
+
* syncField2: string;
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* export const mirrorBehavior: BehaviorSchemaFn<MirrorForm> = (path) => {
|
|
23
|
+
* syncFields(path.syncField1, path.syncField2);
|
|
24
|
+
* };
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example С `transform` (асимметричный) и `debounce` для защиты от частых перезаписей
|
|
21
28
|
* ```typescript
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
29
|
+
* import { syncFields, type BehaviorSchemaFn } from '@reformer/core/behaviors';
|
|
30
|
+
*
|
|
31
|
+
* interface CodeForm {
|
|
32
|
+
* internalCode: string; // канонический формат
|
|
33
|
+
* displayCode: string; // показываем пользователю
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* export const codeBehavior: BehaviorSchemaFn<CodeForm> = (path) => {
|
|
37
|
+
* // internalCode → displayCode: применяется toUpperCase
|
|
38
|
+
* // displayCode → internalCode: пишется как есть
|
|
39
|
+
* syncFields(path.internalCode, path.displayCode, {
|
|
40
|
+
* transform: (value) => (typeof value === 'string' ? value.toUpperCase() : value),
|
|
41
|
+
* debounce: 150, // сглаживает дёргание каретки
|
|
42
|
+
* });
|
|
25
43
|
* };
|
|
26
44
|
* ```
|
|
45
|
+
*
|
|
46
|
+
* @see [docs/llms/24-sync-fields.md](../../../../docs/llms/24-sync-fields.md)
|
|
27
47
|
*/
|
|
28
48
|
export declare function syncFields<TForm extends FormFields, T extends FormValue>(field1: FieldPathNode<TForm, T>, field2: FieldPathNode<TForm, T>, options?: SyncFieldsOptions<T>): void;
|