@reformer/core 11.0.0-beta.7 → 11.0.0-beta.9
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/README.md +90 -68
- package/dist/behaviors-value-HA_Q03hc.js +108 -0
- package/dist/behaviors.js +382 -217
- package/dist/create-model-BvcbNPgL.js +30 -0
- package/dist/date-utils-90-qZbse.js +43 -0
- package/dist/{en-CjAqn7h0.js → en-HP8XEych.js} +6 -3
- package/dist/form/aggregate-signals.d.ts +21 -63
- package/dist/form/behaviors/collections.d.ts +42 -8
- package/dist/form/behaviors/context.d.ts +37 -4
- package/dist/form/behaviors/index.d.ts +6 -4
- package/dist/form/behaviors/internals.d.ts +9 -3
- package/dist/form/behaviors/node.d.ts +25 -2
- package/dist/form/behaviors/operators.d.ts +17 -9
- package/dist/form/behaviors/schema-operators.d.ts +78 -0
- package/dist/form/behaviors/types.d.ts +25 -5
- package/dist/form/create-form.d.ts +57 -70
- package/dist/form/flow/flow.d.ts +87 -0
- package/dist/form/form-bundle.d.ts +153 -0
- package/dist/form/form-config-base.d.ts +46 -0
- package/dist/form/form-level.d.ts +121 -0
- package/dist/form/form-proxy-builder.d.ts +6 -22
- package/dist/form/index.d.ts +20 -20
- package/dist/form/nodes/form-array-node.d.ts +100 -0
- package/dist/form/nodes/form-control-node.d.ts +73 -0
- package/dist/form/nodes/form-group-node.d.ts +66 -0
- package/dist/form/nodes/node-kind.d.ts +29 -0
- package/dist/form/nodes/state/availability.d.ts +6 -0
- package/dist/form/nodes/state/component.d.ts +6 -0
- package/dist/form/nodes/state/index.d.ts +12 -0
- package/dist/form/nodes/state/interaction.d.ts +13 -0
- package/dist/form/nodes/state/issues.d.ts +9 -0
- package/dist/form/nodes/state/pending.d.ts +6 -0
- package/dist/form/schema/compile.d.ts +59 -0
- package/dist/form/schema/compiled.d.ts +143 -0
- package/dist/form/schema/row-key.d.ts +11 -0
- package/dist/form/schema-controller.d.ts +153 -0
- package/dist/form/schema-subtree.d.ts +28 -0
- package/dist/form/signal-node-registry.d.ts +27 -22
- package/dist/form/submission.d.ts +93 -0
- package/dist/form/type-guards.d.ts +14 -73
- package/dist/form/types/contracts.d.ts +19 -92
- package/dist/form/types/field-config.d.ts +27 -0
- package/dist/form/types/index.d.ts +5 -57
- package/dist/form/types/nodes.d.ts +159 -0
- package/dist/form/types/schema-node.d.ts +147 -46
- package/dist/form/types/validation-schema.d.ts +23 -27
- package/dist/form/validation/context.d.ts +46 -6
- package/dist/form/validation/index.d.ts +9 -8
- package/dist/form/validation/operators.d.ts +71 -17
- package/dist/form/validation/run.d.ts +93 -18
- package/dist/form/validation/strategy.d.ts +41 -13
- package/dist/form/validation/types.d.ts +74 -19
- package/dist/form/validators/date-utils.d.ts +13 -1
- package/dist/form/validators/email.d.ts +8 -7
- package/dist/form/validators/file-type.d.ts +8 -7
- package/dist/form/validators/file-utils.d.ts +2 -1
- package/dist/form/validators/future-date.d.ts +8 -7
- package/dist/form/validators/index.d.ts +1 -1
- package/dist/form/validators/integer.d.ts +8 -7
- package/dist/form/validators/is-date.d.ts +11 -9
- package/dist/form/validators/is-number.d.ts +11 -9
- package/dist/form/validators/max-age.d.ts +13 -9
- package/dist/form/validators/max-date.d.ts +8 -7
- package/dist/form/validators/max-file-size.d.ts +8 -7
- package/dist/form/validators/max-files.d.ts +8 -7
- package/dist/form/validators/max-length.d.ts +14 -7
- package/dist/form/validators/max-total-file-size.d.ts +8 -7
- package/dist/form/validators/max.d.ts +10 -8
- package/dist/form/validators/min-age.d.ts +12 -9
- package/dist/form/validators/min-date.d.ts +8 -7
- package/dist/form/validators/min-file-size.d.ts +8 -7
- package/dist/form/validators/min-files.d.ts +11 -9
- package/dist/form/validators/min-length.d.ts +14 -7
- package/dist/form/validators/min.d.ts +10 -8
- package/dist/form/validators/multiple-of.d.ts +10 -8
- package/dist/form/validators/non-negative.d.ts +8 -7
- package/dist/form/validators/non-zero.d.ts +8 -7
- package/dist/form/validators/past-date.d.ts +8 -7
- package/dist/form/validators/pattern.d.ts +9 -8
- package/dist/form/validators/phone.d.ts +8 -7
- package/dist/form/validators/required.d.ts +11 -9
- package/dist/form/validators/url.d.ts +20 -13
- package/dist/form/validators/validation-issue.d.ts +8 -0
- package/dist/i18n/descriptor.d.ts +1 -1
- package/dist/i18n/en.json.d.ts +5 -1
- package/dist/i18n/locale-store.d.ts +7 -0
- package/dist/i18n/message-format.d.ts +24 -4
- package/dist/i18n/ru.json.d.ts +5 -1
- package/dist/i18n/translator.d.ts +11 -0
- package/dist/i18n/validation-message.d.ts +42 -7
- package/dist/i18n.d.ts +7 -12
- package/dist/i18n.js +66 -283
- package/dist/index.d.ts +16 -7
- package/dist/index.js +958 -2798
- package/dist/loader-BWkigpVe.js +52 -0
- package/dist/locale/en.js +1 -1
- package/dist/locale/en.json +4 -1
- package/dist/locale/ru.js +4 -1
- package/dist/locale/ru.json +4 -1
- package/dist/locale-CG54AU2Q.js +219 -0
- package/dist/locale.js +1 -1
- package/dist/model/behaviors-value.d.ts +24 -6
- package/dist/model/create-model.d.ts +2 -2
- package/dist/model/derived-registry.d.ts +1 -1
- package/dist/model/index.d.ts +16 -5
- package/dist/model/model-nodes.d.ts +138 -8
- package/dist/model/model-signals-proxy.d.ts +11 -5
- package/dist/model/model-value-proxy.d.ts +84 -3
- package/dist/model/safe-effect.d.ts +33 -1
- package/dist/model/types.d.ts +70 -17
- package/dist/model.js +21 -17
- package/dist/node-kind-C-r6ZMdo.js +15 -0
- package/dist/platforms/react/field-binding/field-adapter.d.ts +1 -1
- package/dist/platforms/react/field-binding/field-handle.d.ts +5 -2
- package/dist/platforms/react/form-bundle-context.d.ts +27 -0
- package/dist/platforms/react/hooks/types.d.ts +57 -38
- package/dist/platforms/react/hooks/use-form-bundle.d.ts +19 -4
- package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
- package/dist/platforms/react/hooks/use-form-validation.d.ts +12 -6
- package/dist/platforms/react/hooks/useArrayLength.d.ts +6 -6
- package/dist/platforms/react/hooks/useFormControl.d.ts +7 -9
- package/dist/platforms/react/hooks/useFormControlValue.d.ts +18 -19
- package/dist/platforms/react/hooks/useSignalSubscription.d.ts +9 -1
- package/dist/platforms/react/i18n/context.d.ts +6 -1
- package/dist/platforms/react/i18n/hooks.d.ts +16 -10
- package/dist/platforms/react/i18n/provider.d.ts +9 -2
- package/dist/platforms/react/index.d.ts +7 -4
- package/dist/react.d.ts +22 -0
- package/dist/react.js +505 -0
- package/dist/runtime-token.d.ts +1 -2
- package/dist/safe-effect-BbtX3KuN.js +643 -0
- package/dist/schema-controller-CpiO2JoK.js +143 -0
- package/dist/signals.d.ts +15 -9
- package/dist/signals.js +11 -6
- package/dist/strategy-CoFSemuP.js +375 -0
- package/dist/type-guards-D-N_5Ddh.js +19 -0
- package/dist/validation-issue-B9mjI8jz.js +7 -0
- package/dist/validation-message-Ced9MGxs.js +194 -0
- package/dist/validation.js +9 -8
- package/dist/validators/email.js +5 -5
- package/dist/validators/future-date.js +8 -8
- package/dist/validators/integer.js +3 -3
- package/dist/validators/is-date.js +4 -4
- package/dist/validators/is-number.js +4 -4
- package/dist/validators/max-age.js +8 -9
- package/dist/validators/max-date.js +8 -8
- package/dist/validators/max-length.js +7 -7
- package/dist/validators/max.js +4 -4
- package/dist/validators/min-age.js +10 -8
- package/dist/validators/min-date.js +3 -3
- package/dist/validators/min-length.js +5 -5
- package/dist/validators/min.js +4 -4
- package/dist/validators/multiple-of.js +11 -7
- package/dist/validators/non-negative.js +3 -3
- package/dist/validators/non-zero.js +3 -3
- package/dist/validators/past-date.js +8 -8
- package/dist/validators/pattern.js +5 -5
- package/dist/validators/phone.js +11 -9
- package/dist/validators/required.js +2 -2
- package/dist/validators/url.js +48 -12
- package/dist/validators.js +17 -17
- package/docs/llms/01-api-reference.md +60 -34
- package/docs/llms/02-quick-start.md +111 -80
- package/docs/llms/03-api-signatures.md +368 -153
- package/docs/llms/04-common-patterns.md +58 -56
- package/docs/llms/05-common-mistakes.md +69 -44
- package/docs/llms/06-troubleshooting.md +14 -9
- package/docs/llms/07-complete-import.md +74 -43
- package/docs/llms/08-form-types.md +11 -4
- package/docs/llms/09-formschema.md +131 -83
- package/docs/llms/10-arrays.md +119 -69
- package/docs/llms/11-async-watchfield.md +2 -2
- package/docs/llms/13-multi-step.md +134 -63
- package/docs/llms/14-extended-mistakes.md +20 -17
- package/docs/llms/15-project-structure.md +221 -74
- package/docs/llms/16-ui-components.md +55 -42
- package/docs/llms/17-nonexistent-api.md +199 -32
- package/docs/llms/18-conditional-fields.md +66 -32
- package/docs/llms/19-reading-values.md +15 -3
- package/docs/llms/20-compute-vs-watch.md +16 -10
- package/docs/llms/21-array-operations.md +76 -26
- package/docs/llms/22-cycle-detection.md +1 -1
- package/docs/llms/23-copy-from.md +2 -2
- package/docs/llms/24-sync-fields.md +6 -5
- package/docs/llms/25-reset-when.md +14 -7
- package/docs/llms/26-transform-value.md +4 -4
- package/docs/llms/27-revalidate-when.md +16 -15
- package/docs/llms/28-submit-and-reset.md +276 -128
- package/docs/llms/29-async-preload.md +40 -30
- package/docs/llms/30-type-safety-recipes.md +105 -51
- package/docs/llms/31-async-validator-debounce.md +96 -53
- package/docs/llms/33-validation-strategy.md +178 -66
- package/docs/llms/34-i18n.md +69 -43
- package/docs/llms/35-unified-contract.md +307 -0
- package/docs/llms/36-issue-messages.md +284 -0
- package/docs/llms/37-compiled-schema.md +332 -0
- package/docs/llms/38-form-flow.md +397 -0
- package/llms-index.json +1 -1
- package/llms.txt +6968 -3278
- package/package.json +23 -4
- package/dist/behaviors-value-C7dSEhCc.js +0 -134
- package/dist/create-model-B8U-COv-.js +0 -103
- package/dist/date-utils-dTT_x_Be.js +0 -31
- package/dist/form/create-core-form.d.ts +0 -70
- package/dist/form/factories/index.d.ts +0 -6
- package/dist/form/factories/node-factory.d.ts +0 -189
- package/dist/form/form-submitter.d.ts +0 -121
- package/dist/form/nodes/array-node.d.ts +0 -276
- package/dist/form/nodes/field-node.d.ts +0 -297
- package/dist/form/nodes/form-node.d.ts +0 -326
- package/dist/form/nodes/group-node.d.ts +0 -284
- package/dist/form/nodes/model-array-node.d.ts +0 -121
- package/dist/form/nodes/subscription-manager.d.ts +0 -180
- package/dist/form/status-machine.d.ts +0 -115
- package/dist/form/types/deep-schema.d.ts +0 -107
- package/dist/form/types/form-proxy.d.ts +0 -141
- package/dist/form/unique-id.d.ts +0 -45
- package/dist/form/validation/config.d.ts +0 -73
- package/dist/form/validation/error-handler.d.ts +0 -166
- package/dist/form/validators/validation-error.d.ts +0 -8
- package/dist/index-BrNkQj1y.js +0 -105
- package/dist/loader-Dv_Hl7JC.js +0 -216
- package/dist/model-signals-proxy-2vqS243J.js +0 -250
- package/dist/node-DGEFMTQu.js +0 -18
- package/dist/strategy-BXS_gBfz.js +0 -170
- package/dist/validation-error-B-U3RsV0.js +0 -11
|
@@ -1,57 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type {
|
|
4
|
-
export type {
|
|
5
|
-
export type {
|
|
6
|
-
export type { FormSchema } from './deep-schema';
|
|
7
|
-
export type { FormSchemaNode, SchemaArrayControl } from './schema-node';
|
|
8
|
-
export type { FormControlsProxy, FormProxy, FormArrayProxy } from './form-proxy';
|
|
9
|
-
/**
|
|
10
|
-
* Конфигурация GroupNode.
|
|
11
|
-
*
|
|
12
|
-
* Под M1 группа создаётся из плоской {@link FormSchema} (дерево field-конфигов). Обёртка
|
|
13
|
-
* `{ form }` сохранена для совместимости вызова, legacy behavior/validation-схемы удалены (Ф7).
|
|
14
|
-
*
|
|
15
|
-
* @group Types
|
|
16
|
-
* @category Configuration Types
|
|
17
|
-
*/
|
|
18
|
-
export interface GroupNodeConfig<T> {
|
|
19
|
-
/** Схема структуры формы (поля и их конфигурация) */
|
|
20
|
-
form: FormSchema<T>;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Тип для Record с unknown значениями
|
|
24
|
-
* Используется вместо инлайнового `Record<string, unknown>`
|
|
25
|
-
* @internal
|
|
26
|
-
*/
|
|
27
|
-
export type UnknownRecord = Record<string, unknown>;
|
|
28
|
-
/**
|
|
29
|
-
* Интерфейс для узлов, похожих на ArrayNode (с методом at)
|
|
30
|
-
* Используется для duck typing при обходе путей
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
export interface ArrayNodeLike {
|
|
34
|
-
at(index: number): FormNode<unknown> | undefined;
|
|
35
|
-
length: unknown;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Конфиг с полем schema (для ArrayConfig)
|
|
39
|
-
* @internal
|
|
40
|
-
*/
|
|
41
|
-
export interface ConfigWithSchema {
|
|
42
|
-
schema: unknown;
|
|
43
|
-
initialItems?: unknown[];
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Конфиг с полем value (для извлечения значений)
|
|
47
|
-
* @internal
|
|
48
|
-
*/
|
|
49
|
-
export interface ConfigWithValue {
|
|
50
|
-
value: unknown;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Тип для проверки на функцию в conditional types
|
|
54
|
-
* Используется вместо Function для type narrowing
|
|
55
|
-
* @internal
|
|
56
|
-
*/
|
|
57
|
-
export type AnyFunction = (...args: never[]) => unknown;
|
|
1
|
+
export type { ValidationIssue } from './contracts';
|
|
2
|
+
export type { FieldConfig } from './field-config';
|
|
3
|
+
export type { RuleOptions } from './validation-schema';
|
|
4
|
+
export type { ComponentRef, FormSchemaNode, SchemaFieldNode, SchemaArrayNode, SchemaPartNode, SchemaContainerNode, SchemaChild, SchemaValueHandle, SchemaArrayHandle, SchemaGroupHandle, SchemaArrayControl, } from './schema-node';
|
|
5
|
+
export type { FormNode, FormControl, FormGroup, FormArray, FormFields } from './nodes';
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { ReadonlySignal } from '@preact/signals-core';
|
|
2
|
+
import { ValidationIssue } from './contracts';
|
|
3
|
+
import { ComponentRef } from './schema-node';
|
|
4
|
+
/**
|
|
5
|
+
* Общий контракт ноды формы — поля, группы и массива под-форм.
|
|
6
|
+
*
|
|
7
|
+
* Значением нода не владеет: источник истины — модель (`model.$.<путь>`), нода держит состояние
|
|
8
|
+
* взаимодействия (`touched`, `dirty`), доступность и замечания валидации.
|
|
9
|
+
*
|
|
10
|
+
* @typeParam T - Значение ноды
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const { form } = createForm<{ email: string }>({ initial: { email: '' } });
|
|
15
|
+
* form.email.setValue('user@mail.com');
|
|
16
|
+
* form.email.markAsTouched();
|
|
17
|
+
* form.valid.value; // true — замечаний нет
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export interface FormNode<T> {
|
|
21
|
+
/** Текущее значение. */
|
|
22
|
+
readonly value: ReadonlySignal<T>;
|
|
23
|
+
/** Замечаний, которые блокируют отправку, нет; нода включена и не ждёт проверки. */
|
|
24
|
+
readonly valid: ReadonlySignal<boolean>;
|
|
25
|
+
/** Есть блокирующие замечания; нода включена и не ждёт проверки. */
|
|
26
|
+
readonly invalid: ReadonlySignal<boolean>;
|
|
27
|
+
/** Идёт асинхронная проверка. */
|
|
28
|
+
readonly pending: ReadonlySignal<boolean>;
|
|
29
|
+
/** Нода отключена: её замечания сняты, в проверку она не входит. */
|
|
30
|
+
readonly disabled: ReadonlySignal<boolean>;
|
|
31
|
+
/** Пользователь взаимодействовал с нодой. */
|
|
32
|
+
readonly touched: ReadonlySignal<boolean>;
|
|
33
|
+
/** Значение меняли после создания или сброса. */
|
|
34
|
+
readonly dirty: ReadonlySignal<boolean>;
|
|
35
|
+
/** Замечания ноды; у группы и массива — свои и всех детей. */
|
|
36
|
+
readonly issues: ReadonlySignal<readonly ValidationIssue[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Собственные замечания ноды — без замечаний детей: у группы и массива это правила на их ручке
|
|
39
|
+
* (`minLength` массива, `cross` группы), у поля — то же, что `issues`.
|
|
40
|
+
*/
|
|
41
|
+
readonly ownIssues: ReadonlySignal<readonly ValidationIssue[]>;
|
|
42
|
+
/** Значение без подписки. */
|
|
43
|
+
getValue(): T;
|
|
44
|
+
/** Записать значение в модель. */
|
|
45
|
+
setValue(value: T): void;
|
|
46
|
+
/**
|
|
47
|
+
* Вернуть значение и состояние к начальным; с аргументом — к переданному значению. В цель
|
|
48
|
+
* `compute` значение не пишется (кроме явного `reset(значение)` самого поля): ею владеет
|
|
49
|
+
* поведение — сбрасывается только состояние.
|
|
50
|
+
*/
|
|
51
|
+
reset(value?: T): void;
|
|
52
|
+
markAsTouched(): void;
|
|
53
|
+
markAsUntouched(): void;
|
|
54
|
+
enable(): void;
|
|
55
|
+
disable(): void;
|
|
56
|
+
/** Поставить замечания извне (ответ сервера, своя проверка). */
|
|
57
|
+
setIssues(issues: readonly ValidationIssue[]): void;
|
|
58
|
+
clearIssues(): void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Поле формы: нода над листом модели и состояние его компонента.
|
|
62
|
+
*
|
|
63
|
+
* @typeParam T - Значение поля
|
|
64
|
+
*/
|
|
65
|
+
export interface FormControl<T> extends FormNode<T> {
|
|
66
|
+
/** Компонент поля из узла схемы. */
|
|
67
|
+
readonly component: ComponentRef | undefined;
|
|
68
|
+
/** Пропсы компонента: из узла схемы и правок {@link FormControl.updateComponentProps}. */
|
|
69
|
+
readonly componentProps: ReadonlySignal<Readonly<Record<string, unknown>>>;
|
|
70
|
+
/**
|
|
71
|
+
* Показывать ли состояние ошибки (`aria-invalid`, рамка): поле невалидно и его трогали или
|
|
72
|
+
* меняли. Предупреждение (`severity: 'warning'`) поле невалидным не делает — тексты замечаний
|
|
73
|
+
* показывают по {@link FormControl.shouldShowIssues}.
|
|
74
|
+
*/
|
|
75
|
+
readonly shouldShowError: ReadonlySignal<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* Показывать ли тексты замечаний: у поля есть замечания — ошибки или предупреждения, — и его
|
|
78
|
+
* трогали или меняли. Условия те же, что у {@link FormControl.shouldShowError} (не выключено,
|
|
79
|
+
* проверка не идёт), но в счёт идёт любое замечание, а не только блокирующее.
|
|
80
|
+
*/
|
|
81
|
+
readonly shouldShowIssues: ReadonlySignal<boolean>;
|
|
82
|
+
/** Слить правку в пропсы компонента (например, опции после загрузки справочника). */
|
|
83
|
+
updateComponentProps(patch: Record<string, unknown>): void;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Массив под-форм: строка — {@link FormGroup} над элементом массива модели.
|
|
87
|
+
*
|
|
88
|
+
* Данными массив не владеет: мутации уходят в массив модели, формы строк держатся за под-модели
|
|
89
|
+
* и при `move`/`swap` не пересоздаются.
|
|
90
|
+
*
|
|
91
|
+
* Индексы (`at`, `keyAt`, `insert`, `removeAt`, `move`, `swap`) — по строкам формы. Элемент `null`
|
|
92
|
+
* в массиве модели строкой не становится, и индекс строки может не совпасть с индексом модели.
|
|
93
|
+
*
|
|
94
|
+
* @typeParam T - Элемент массива
|
|
95
|
+
*/
|
|
96
|
+
export interface FormArray<T extends object> extends FormNode<T[]> {
|
|
97
|
+
/** Число строк; чтение в эффекте или `computed` подписывает на изменения. */
|
|
98
|
+
readonly length: number;
|
|
99
|
+
at(index: number): FormGroup<T> | undefined;
|
|
100
|
+
map<R>(callback: (row: FormGroup<T>, index: number) => R): R[];
|
|
101
|
+
forEach(callback: (row: FormGroup<T>, index: number) => void): void;
|
|
102
|
+
/** Стабильный ключ строки: держится за элемент модели и не меняется при `move` и `swap`. */
|
|
103
|
+
keyAt(index: number): string;
|
|
104
|
+
/** Добавить строку; без значения — по шаблону массива модели (`arrayOf(blank)`). */
|
|
105
|
+
push(item?: T): void;
|
|
106
|
+
insert(index: number, item?: T): void;
|
|
107
|
+
removeAt(index: number): void;
|
|
108
|
+
move(from: number, to: number): void;
|
|
109
|
+
swap(first: number, second: number): void;
|
|
110
|
+
clear(): void;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Признак «объект-группа»: обычный объект, а не массив, дата, файл, функция или примитив.
|
|
114
|
+
* `extends object` ловит и `interface`, и `type` (интерфейс не приводится к `Record`).
|
|
115
|
+
* Значение неизвестной формы (`unknown`, `{}`) — поле: у него нет известных полей, и словарь
|
|
116
|
+
* `Record<string, unknown>` остаётся группой полей, а не группой групп — иначе такая группа не
|
|
117
|
+
* приводилась бы к `FormGroup<any>` внутри обобщённых типов (контекст React, элементы списка).
|
|
118
|
+
*
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
type IsGroupObject<V> = V extends ReadonlyArray<unknown> ? false : V extends Date | File | Blob ? false : V extends (...args: never[]) => unknown ? false : V extends object ? Record<never, never> extends V ? false : true : false;
|
|
122
|
+
/** `T` — это `any`. @internal */
|
|
123
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
124
|
+
/**
|
|
125
|
+
* Ноды полей группы по именам полей данных: массив объектов — {@link FormArray}, объект —
|
|
126
|
+
* {@link FormGroup}, остальное (примитивы, массивы примитивов, даты, файлы) — {@link FormControl}.
|
|
127
|
+
* Опциональность снята: нода есть у каждого поля, опционально лишь значение.
|
|
128
|
+
*
|
|
129
|
+
* `FormFields<any>` — нестрогий словарь: так группа любой формы приводится к `FormGroup<any>`
|
|
130
|
+
* (контекст React, обобщённые компоненты), а не упирается в отображение полей типа `any`.
|
|
131
|
+
*
|
|
132
|
+
* @typeParam T - Значение группы
|
|
133
|
+
*/
|
|
134
|
+
export type FormFields<T> = IsAny<T> extends true ? Record<string, any> : {
|
|
135
|
+
[K in keyof T]-?: NonNullable<T[K]> extends ReadonlyArray<infer U> ? IsGroupObject<U> extends true ? FormArray<U & object> : FormControl<T[K]> : IsGroupObject<NonNullable<T[K]>> extends true ? FormGroup<NonNullable<T[K]>> : FormControl<T[K]>;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Группа полей: нода над группой модели и доступ к нодам полей.
|
|
139
|
+
*
|
|
140
|
+
* `form.email` — нода поля; поле с именем члена {@link FormNode} (`value`, `issues`, `reset`, …)
|
|
141
|
+
* недостижимо точкой и доступно через `form.$`: `form.$.value`. Остальные имена полей данных
|
|
142
|
+
* (`id`, `status`, `fields`, `submit`, …) ничем не затенены.
|
|
143
|
+
*
|
|
144
|
+
* @typeParam T - Значение группы
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* interface Order { status: string; value: number; customer: { name: string } }
|
|
149
|
+
* const { form } = createForm<Order>({ initial: { status: 'new', value: 0, customer: { name: '' } } });
|
|
150
|
+
* form.status.setValue('paid'); // поле данных
|
|
151
|
+
* form.$.value.setValue(100); // поле, затенённое членом ноды
|
|
152
|
+
* form.customer.name.markAsTouched();
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export type FormGroup<T> = FormNode<T> & Omit<FormFields<T>, keyof FormNode<T>> & {
|
|
156
|
+
/** Ноды всех полей по имени, включая затенённые членами {@link FormNode}. */
|
|
157
|
+
readonly $: FormFields<T>;
|
|
158
|
+
};
|
|
159
|
+
export {};
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
-
import { ElementType } from 'react';
|
|
2
1
|
import { Signal } from '../../signals';
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Ссылка на компонент узла схемы: то, что слой представления умеет нарисовать. Для React это
|
|
4
|
+
* компонент (функция либо объект `forwardRef`/`memo`) или имя HTML-тега (`'div'`, `'h3'`).
|
|
5
|
+
*
|
|
6
|
+
* Ядро ссылку не интерпретирует и о слое представления не знает: она доезжает до рендерера как
|
|
7
|
+
* есть, а к типу своего UI-слоя её приводит уже он.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const byComponent: ComponentRef = Input; // React-компонент
|
|
12
|
+
* const byTag: ComponentRef = 'section'; // HTML-тег
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @group Types
|
|
16
|
+
*/
|
|
17
|
+
export type ComponentRef = string | object;
|
|
18
|
+
/**
|
|
19
|
+
* Контракт реактивного массива модели — фасада `model.<массив>`. Рендерерский
|
|
6
20
|
* `RenderModelArrayControl` — его расширение (добавляет `move`).
|
|
7
21
|
*
|
|
8
22
|
* @group Types
|
|
@@ -13,68 +27,155 @@ export interface SchemaArrayControl {
|
|
|
13
27
|
/** Реактивная длина. */
|
|
14
28
|
readonly length: number;
|
|
15
29
|
at(index: number): unknown;
|
|
16
|
-
push(item
|
|
30
|
+
push(item?: unknown): void;
|
|
17
31
|
removeAt(index: number): void;
|
|
18
32
|
}
|
|
19
33
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
34
|
+
* Ручка значения из дерева `model.$`: лист (`model.$.email`) или массив целиком
|
|
35
|
+
* (`model.$.tags`). Группа ручкой значения не является — у неё нет пути.
|
|
22
36
|
*
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
* @group Types
|
|
38
|
+
*/
|
|
39
|
+
export type SchemaValueHandle = Signal<any> & {
|
|
40
|
+
readonly __path: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Ручка массива из дерева `model.$` (`model.$.phones`) — ручка значения с длиной.
|
|
28
44
|
*
|
|
29
|
-
*
|
|
30
|
-
|
|
45
|
+
* @group Types
|
|
46
|
+
*/
|
|
47
|
+
export type SchemaArrayHandle = SchemaValueHandle & {
|
|
48
|
+
readonly length: number;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Ручка группы из дерева `model.$` (`model.$.address`).
|
|
31
52
|
*
|
|
32
53
|
* @group Types
|
|
33
54
|
*/
|
|
34
|
-
export interface
|
|
55
|
+
export interface SchemaGroupHandle {
|
|
56
|
+
peek(): object | null | undefined;
|
|
57
|
+
/** Признак «не ручка значения»: у листа и массива путь есть, у группы — нет. */
|
|
58
|
+
readonly __path?: never;
|
|
59
|
+
}
|
|
60
|
+
/** Ключи, общие для узла любого вида. */
|
|
61
|
+
interface SchemaNodeBase {
|
|
35
62
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
63
|
+
* UI-компонент либо нативный HTML-тег (`'div'`, `'p'`, `'h3'`) для презентационной вёрстки
|
|
64
|
+
* прямо в схеме. Опционален: ядро работает без UI и `component` не интерпретирует — он доезжает
|
|
65
|
+
* до рендерера как есть.
|
|
39
66
|
*/
|
|
40
|
-
|
|
67
|
+
component?: ComponentRef;
|
|
41
68
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* не интерпретирует — он доезжает до рендерера как есть.
|
|
69
|
+
* Пропсы компонента. Вложенных узлов здесь нет: обход схемы в пропсы не заглядывает, дети узла
|
|
70
|
+
* пишутся в `children`.
|
|
45
71
|
*/
|
|
46
|
-
component?: ElementType;
|
|
47
|
-
/** Props компонента. Также «клапан» для вложенности под-узлов (напр. steps визарда). */
|
|
48
72
|
componentProps?: Record<string, unknown>;
|
|
49
|
-
|
|
50
|
-
disabled?: boolean;
|
|
51
|
-
/** Задержка (мс) перед запуском асинхронной валидации. */
|
|
52
|
-
debounce?: number;
|
|
53
|
-
/** Идентификатор узла (для wizard/tabs/renderBehavior). */
|
|
73
|
+
/** Идентификатор узла: по нему узел адресуют поведение (`schema.node(...)`) и шаги визарда. */
|
|
54
74
|
selector?: string;
|
|
55
75
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
76
|
+
* Прежний ключ привязки поля — его нет: пишите `model: model.$.<поле>`.
|
|
77
|
+
*
|
|
78
|
+
* Запрет объявлен явно: в `children` узел стоит в объединении с реактивным текстом
|
|
79
|
+
* (`Signal`, у которого есть `value`), и без него прежний ключ проходил проверку лишних ключей.
|
|
59
80
|
*/
|
|
60
|
-
|
|
81
|
+
value?: never;
|
|
82
|
+
/** Прежний ключ привязки массива — его нет: пишите `model: model.$.<массив>` вместе с `item`. */
|
|
83
|
+
array?: never;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Поле: узел, привязанный к ручке значения — листу или массиву целиком (мультивыбор, теги, файлы).
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* { model: model.$.email, component: Input, componentProps: { label: 'Email' } }
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @group Types
|
|
94
|
+
*/
|
|
95
|
+
export interface SchemaFieldNode extends SchemaNodeBase {
|
|
96
|
+
/** Привязка поля — ручка значения `model.$.<лист | массив>`. */
|
|
97
|
+
model: SchemaValueHandle;
|
|
61
98
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* выводит на своём месте в порядке следования.
|
|
99
|
+
* Поле создаётся отключённым — и остаётся: это постоянная блокировка (вычисляемые `total`,
|
|
100
|
+
* `fullName`). `enable()` группы, массива или формы её не снимает; снимает только явный
|
|
101
|
+
* `enable()` самого поля либо оператор `enableWhen` на нём.
|
|
66
102
|
*/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
103
|
+
disabled?: boolean;
|
|
104
|
+
item?: never;
|
|
105
|
+
part?: never;
|
|
106
|
+
children?: never;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Массив под-форм: у каждой строки своя форма, разметку строки строит `item`.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* { model: model.$.phones, component: FieldArray, item: (row) => ({ children: [...] }) }
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @group Types
|
|
117
|
+
*/
|
|
118
|
+
export interface SchemaArrayNode extends SchemaNodeBase {
|
|
119
|
+
/** Привязка — ручка массива `model.$.<массив>`. */
|
|
120
|
+
model: SchemaArrayHandle;
|
|
121
|
+
/** Схема строки: под-модель строки → узел поддерева. */
|
|
122
|
+
item: (model: any) => FormSchemaNode;
|
|
72
123
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
124
|
+
* Шаблон нового элемента массива для кнопки «Добавить»: либо готовое значение, либо фабрика
|
|
125
|
+
* `() => value`. Запасной путь — для форм, чья модель создаётся из данных без кода: шаблон,
|
|
126
|
+
* объявленный в модели (`arrayOf(blank)`), главнее.
|
|
127
|
+
*
|
|
128
|
+
* Тип не различает варианты (union `unknown | (() => unknown)` схлопывается в `unknown`) —
|
|
129
|
+
* рантайм различает по `typeof initialValue === 'function'`.
|
|
76
130
|
*/
|
|
77
131
|
initialValue?: unknown;
|
|
78
|
-
|
|
79
|
-
|
|
132
|
+
part?: never;
|
|
133
|
+
children?: never;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Подформа: часть схемы, подключённая к группе модели. Часть объявляется один раз и подключается
|
|
137
|
+
* к любой группе той же формы данных; привязки внутри части идут через `$` полученной под-модели.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* { model: model.$.registrationAddress, part: address }
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* @group Types
|
|
145
|
+
*/
|
|
146
|
+
export interface SchemaPartNode extends SchemaNodeBase {
|
|
147
|
+
/** Привязка — ручка группы `model.$.<группа>`. */
|
|
148
|
+
model: SchemaGroupHandle;
|
|
149
|
+
/** Часть схемы: под-модель группы → узел поддерева. */
|
|
150
|
+
part: (model: any) => FormSchemaNode;
|
|
151
|
+
item?: never;
|
|
152
|
+
children?: never;
|
|
153
|
+
}
|
|
154
|
+
/** Ребёнок контейнера: вложенный узел либо текстовая часть — литерал, число, сигнал модели. */
|
|
155
|
+
export type SchemaChild = FormSchemaNode | string | number | Signal<any>;
|
|
156
|
+
/**
|
|
157
|
+
* Контейнер: узел с детьми (секция, шаг визарда, html-тег). Текст — такой же ребёнок, как узел:
|
|
158
|
+
* ядро его не интерпретирует, а рендерер выводит на своём месте в порядке следования.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* { component: Section, componentProps: { title: 'Контакты' }, children: [phoneField, emailField] }
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* @group Types
|
|
166
|
+
*/
|
|
167
|
+
export interface SchemaContainerNode extends SchemaNodeBase {
|
|
168
|
+
children?: readonly SchemaChild[];
|
|
169
|
+
model?: never;
|
|
170
|
+
item?: never;
|
|
171
|
+
part?: never;
|
|
80
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Узел схемы формы: поле, массив под-форм, подформа или контейнер — см. описание модуля.
|
|
175
|
+
*
|
|
176
|
+
* Тип закрыт: опечатка в ключе, группа без `part` и `item` не на массиве — ошибки компиляции.
|
|
177
|
+
*
|
|
178
|
+
* @group Types
|
|
179
|
+
*/
|
|
180
|
+
export type FormSchemaNode = SchemaFieldNode | SchemaArrayNode | SchemaPartNode | SchemaContainerNode;
|
|
181
|
+
export {};
|
|
@@ -1,36 +1,32 @@
|
|
|
1
|
-
import { FormValue, ValidationError } from './index';
|
|
2
|
-
import { FormModel } from '../../model/types';
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
2
|
+
* Типы фабрик валидаторов (`@reformer/core/validators`).
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
* `validateModel(model, schema)`. Cross-field — оператор `cross(sig, (f) => …)` над снапшотом
|
|
10
|
-
* `model.get()` (третий аргумент `root` больше не нужен). Тип экспортируется только ради
|
|
11
|
-
* обратной совместимости (`SchemaValidator`-union).
|
|
4
|
+
* Контракт валидации — `@reformer/core/validation`: `defineValidation` + операторы
|
|
5
|
+
* (`validate`/`validateAsync`/`validateWhen`/`cross`/`apply`/`applyEach`) и раннер
|
|
6
|
+
* `validateModel(model, definition)`; правила там — `Rule<T> = (value) => issue | null`.
|
|
12
7
|
*/
|
|
13
|
-
export type Validator<TForm, TField> = (value: TField, scope: unknown, root: FormModel<TForm>) => ValidationError | null;
|
|
14
8
|
/**
|
|
15
9
|
* Опции валидатора-фабрики (`required()`/`pattern()`/…). Передаются вторым (или последним)
|
|
16
|
-
* аргументом в фабрику и попадают в
|
|
10
|
+
* аргументом в фабрику и попадают в возвращаемое {@link ValidationIssue}.
|
|
11
|
+
*
|
|
12
|
+
* Текста среди опций нет: правило сообщает только код и параметры, а строку по коду даёт слой
|
|
13
|
+
* представления (`resolveIssueMessage` из `@reformer/core/i18n`). Нужен свой текст для
|
|
14
|
+
* конкретного поля — дайте правилу свой код и запись в словаре формы.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* // правило
|
|
19
|
+
* required({ code: 'loanAmount.required' });
|
|
20
|
+
* // словарь формы (`defineIssueMessages`)
|
|
21
|
+
* const messages = defineIssueMessages({ 'loanAmount.required': 'Укажите сумму кредита' });
|
|
22
|
+
* ```
|
|
17
23
|
*/
|
|
18
|
-
export interface
|
|
19
|
-
/** Готовое сообщение об ошибке. Если не задано, валидаторы кладут `''`, и отображаемый текст
|
|
20
|
-
* берётся из словаря локали по `code` (`validation.<code>`; см. `resolveValidationError` в
|
|
21
|
-
* `@reformer/core/i18n`). Явное сообщение важнее словаря, но не переключается вместе с языком —
|
|
22
|
-
* для локализуемого текста используйте {@link ValidateOptions.messageKey}. */
|
|
23
|
-
message?: string;
|
|
24
|
+
export interface RuleOptions {
|
|
24
25
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* ```ts
|
|
30
|
-
* required({ messageKey: 'profile.name.required', message: 'Name is required' });
|
|
31
|
-
* ```
|
|
26
|
+
* Свой код вместо встроенного. По нему текст ищется сначала в словаре формы, затем в локали
|
|
27
|
+
* (`validation.<code>`); принято именовать `<поле>.<правило>`.
|
|
32
28
|
*/
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
params?: Record<string,
|
|
29
|
+
code?: string;
|
|
30
|
+
/** Дополнительные параметры замечания: подставляются в текст поверх параметров правила. */
|
|
31
|
+
params?: Readonly<Record<string, unknown>>;
|
|
36
32
|
}
|
|
@@ -1,16 +1,46 @@
|
|
|
1
|
-
import { FormModel, PathAwareSignal
|
|
1
|
+
import { FormModel, PathAwareSignal } from '../../model/types';
|
|
2
|
+
import { ValidationIssue } from '../types/contracts';
|
|
3
|
+
import { ValidationFailure } from './types';
|
|
2
4
|
/** Сток одного прогона: модель scope, накопленные ошибки, незавершённые async-правила, гейты. */
|
|
3
5
|
export interface VContext {
|
|
4
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Модель текущей области — источник снапшота для `cross` и модель для `apply`. В корне прогона
|
|
8
|
+
* это вся модель; внутри `apply(ручка, схема)` / `applyEach` — под-модель группы или строки.
|
|
9
|
+
*/
|
|
5
10
|
model: FormModel<unknown>;
|
|
6
|
-
/**
|
|
7
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Накопленные ошибки по сигналу (ключ — идентичность `PathAwareSignal`). Здесь и поля выключенной
|
|
13
|
+
* ветки `validateWhen` — с пустым списком: при разносе их прежние ошибки гасятся.
|
|
14
|
+
*/
|
|
15
|
+
issues: Map<PathAwareSignal<unknown>, ValidationIssue[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Поля, правила которых в этом прогоне действительно выполнялись — ветка активна. Только их разнос
|
|
18
|
+
* с `touch` помечает тронутыми: поле выключенной ветки пользователь не видел.
|
|
19
|
+
*/
|
|
20
|
+
checked: Set<PathAwareSignal<unknown>>;
|
|
8
21
|
/** Незавершённые async-правила (раннер их дожидается). */
|
|
9
22
|
pending: Promise<void>[];
|
|
23
|
+
/** Поля с async-правилами: на время ожидания раннер держит их ноды в `pending`. */
|
|
24
|
+
asyncFields: Set<PathAwareSignal<unknown>>;
|
|
25
|
+
/**
|
|
26
|
+
* Правила, которые не вернули результат. Список — один на весь прогон: области `apply` /
|
|
27
|
+
* `applyEach` получают поверхностную копию контекста и пишут в ту же ссылку.
|
|
28
|
+
*/
|
|
29
|
+
failures: ValidationFailure[];
|
|
10
30
|
/** Стек активных условий `validateWhen` (все должны быть истинны, чтобы правило сработало). */
|
|
11
31
|
whenStack: Array<() => boolean>;
|
|
12
32
|
/** Отмена устаревшего прогона: прокидывается в async-правила, гасит роутинг после await. */
|
|
13
33
|
signal: AbortSignal;
|
|
34
|
+
/**
|
|
35
|
+
* Определение, правила которого исполняются сейчас: корень прогона либо схема, подключённая
|
|
36
|
+
* `apply` / `applyEach`. Замечание помечается им: так разнос отличает замечания одного
|
|
37
|
+
* определения, полученные разными прогонами (шаг и вся форма), от замечаний чужого.
|
|
38
|
+
*/
|
|
39
|
+
origin: object;
|
|
40
|
+
/** Замечания по полю и определению-источнику. Одна ссылка на весь прогон, как `failures`. */
|
|
41
|
+
origins: Map<PathAwareSignal<unknown>, Map<object, ValidationIssue[]>>;
|
|
42
|
+
/** Определения, исполненные в прогоне: за их замечания на проверенных полях прогон отвечает. */
|
|
43
|
+
executed: Set<object>;
|
|
14
44
|
}
|
|
15
45
|
/**
|
|
16
46
|
* Открыть ambient-окно на время `fn` и закрыть его в `finally`.
|
|
@@ -21,7 +51,17 @@ export interface VContext {
|
|
|
21
51
|
export declare function runWithContext<R>(ctx: VContext, fn: () => R): R;
|
|
22
52
|
/** Контекст активного прогона либо понятная ошибка, если оператор вызван вне схемы. */
|
|
23
53
|
export declare function requireCtx(op: string): VContext;
|
|
24
|
-
/**
|
|
25
|
-
|
|
54
|
+
/**
|
|
55
|
+
* «Тронуть» сигнал: гарантирует его наличие в замечаниях прогона (даже пустым) → он попадёт в
|
|
56
|
+
* очистку. Возвращает список текущего определения ({@link VContext.origin}): в него и пишут правила.
|
|
57
|
+
*/
|
|
58
|
+
export declare function touch(ctx: VContext, sig: PathAwareSignal<unknown>): ValidationIssue[];
|
|
59
|
+
/** Исполнить определение: его замечания помечаются им же. */
|
|
60
|
+
export declare function withOrigin(ctx: VContext, origin: object, fn: () => void): void;
|
|
26
61
|
/** Активна ли текущая ветка (все `validateWhen`-условия истинны). */
|
|
27
62
|
export declare const gated: (ctx: VContext) => boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Правила поля выполняются: ветка активна. Поле запоминается проверенным ({@link VContext.checked}).
|
|
65
|
+
* Без активной ветки — `false`, и поле остаётся только в `issues` для гашения.
|
|
66
|
+
*/
|
|
67
|
+
export declare function checking(ctx: VContext, sig: PathAwareSignal<unknown>): boolean;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Декларативный контракт СХЕМЫ ВАЛИДАЦИИ — `@reformer/core/validation`.
|
|
3
3
|
*
|
|
4
|
-
* Схема валидации — обычная функция `(
|
|
5
|
-
* (`validate`/`validateAsync`/`validateWhen`/`
|
|
6
|
-
* текущего прогона — автор не видит ни коллектора, ни `getNodeForSignal`, ни `.push`.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Схема валидации — обычная функция `({ model, cross }) => void`. Внутри вызываются свободные операторы
|
|
5
|
+
* (`validate`/`validateAsync`/`validateWhen`/`apply`/`applyEach`) и `cross` области, которые САМИ пишут ошибки в
|
|
6
|
+
* ambient-сток текущего прогона — автор не видит ни коллектора, ни `getNodeForSignal`, ни `.push`.
|
|
7
|
+
* Раннер открывает ambient-окно на время СИНХРОННОГО прогона схемы и дожидается async-правил
|
|
8
|
+
* ({@link runValidation} — сбор результата), затем разносит ошибки по нодам формы, гася поля, ставшие
|
|
9
|
+
* валидными ({@link applyValidationResult}); {@link validateModel} делает оба шага и отвечает `boolean`.
|
|
9
10
|
*
|
|
10
11
|
* Зеркалит контракт поведения (`@reformer/core/behaviors`): тот же ambient-стиль, но отдельный слой —
|
|
11
12
|
* валидация НЕ реактивна (прогон по требованию: submit/шаг), поведение — реактивно (живые подписки).
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
* @group Validation
|
|
18
19
|
* @module form/validation
|
|
19
20
|
*/
|
|
20
|
-
export type { Rule, AsyncRule,
|
|
21
|
-
export { validate, validateAsync, validateWhen,
|
|
22
|
-
export {
|
|
21
|
+
export type { Rule, AsyncRule, ValidationDefinition, ValidationScope, ValidationStatus, ValidationFailure, ValidationResult, } from './types';
|
|
22
|
+
export { validate, validateAsync, validateWhen, apply, applyEach } from './operators';
|
|
23
|
+
export { defineValidation, runValidation, applyValidationResult, validateModel } from './run';
|
|
23
24
|
export * from './strategy';
|