@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,8 +1,70 @@
|
|
|
1
1
|
import { Signal } from '@preact/signals-core';
|
|
2
2
|
import { PathAwareSignal } from './types';
|
|
3
3
|
export declare const isIndexKey: (key: string) => boolean;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Глубокое сравнение значений модели: объекты и массивы — по содержимому, даты — по времени,
|
|
6
|
+
* `NaN` равен себе, остальное (включая файлы) — по ссылке.
|
|
7
|
+
*
|
|
8
|
+
* То же сравнение стоит за `isDirty` модели и за сверкой «модель изменилась, пока шла проверка»
|
|
9
|
+
* при отправке и переходе шага: значение, изменённое и возвращённое, изменением не считается.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* deepEqual({ date: new Date(0), tags: ['a'] }, { date: new Date(0), tags: ['a'] }); // true
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const deepEqual: (a: unknown, b: unknown) => boolean;
|
|
17
|
+
/** Фабрика нового элемента массива. */
|
|
18
|
+
type Blank = () => unknown;
|
|
19
|
+
/**
|
|
20
|
+
* Образец того же места модели внутри шаблона родительского массива. Ленивый: шаблон родителя
|
|
21
|
+
* ради него вызывается, только когда образец действительно понадобился.
|
|
22
|
+
*/
|
|
23
|
+
type Shape = () => unknown;
|
|
24
|
+
/**
|
|
25
|
+
* Массив модели с шаблоном нового элемента.
|
|
26
|
+
*
|
|
27
|
+
* Шаблон — фабрика значения, которое получает `push()` / `insertAt(i)` без аргумента: кнопка
|
|
28
|
+
* «Добавить» секции массива, `model.items.push()` в поведении. Частичное значение
|
|
29
|
+
* (`push({ type: 'house' })`) дополняется из шаблона. Объявляется там же, где остальные
|
|
30
|
+
* начальные значения, — в модели; схеме и JSX знать его не нужно.
|
|
31
|
+
*
|
|
32
|
+
* Возвращает обычный массив: тип поля остаётся `U[]`. Шаблон переживает `set` / `patch` / `reset`
|
|
33
|
+
* модели. Вложенные массивы объявляются внутри шаблона элемента — тогда и элементы, пришедшие
|
|
34
|
+
* обычными данными (загрузка с сервера), получают их шаблоны.
|
|
35
|
+
*
|
|
36
|
+
* Шаблон привязан к самому массиву, поэтому до `createModel` его нельзя копировать:
|
|
37
|
+
* `structuredClone`, `JSON.parse(JSON.stringify(…))` и `[...array]` отдают массив без шаблона, и
|
|
38
|
+
* `push()` без значения бросит ошибку. Начальные значения с `arrayOf` держат в фабрике
|
|
39
|
+
* (`const initial = () => ({ items: arrayOf(blank) })`), а не в константе, которую клонируют.
|
|
40
|
+
*
|
|
41
|
+
* @typeParam U - Тип элемента массива.
|
|
42
|
+
* @param blank - Фабрика нового элемента. Вызывается на каждое добавление — значение не делится
|
|
43
|
+
* между элементами.
|
|
44
|
+
* @param items - Начальные элементы. По умолчанию массив пуст.
|
|
45
|
+
* @returns Массив начальных значений с шаблоном.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const blankPhone = () => ({ number: '' });
|
|
50
|
+
* const blankCoBorrower = () => ({ name: '', phones: arrayOf(blankPhone) });
|
|
51
|
+
*
|
|
52
|
+
* const model = createModel({ coBorrowers: arrayOf(blankCoBorrower) });
|
|
53
|
+
*
|
|
54
|
+
* model.coBorrowers.push(); // { name: '', phones: [] }
|
|
55
|
+
* model.coBorrowers.at(0).phones.push(); // { number: '' }
|
|
56
|
+
* model.coBorrowers.push({ name: 'Анна' }); // { name: 'Анна', phones: [] } — остальное из шаблона
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @group Model
|
|
60
|
+
*/
|
|
61
|
+
export declare function arrayOf<U>(blank: () => U, items?: readonly U[]): U[];
|
|
62
|
+
export type ModelNode = ModelLeafNode | ModelGroupNode | ModelArrayNode;
|
|
63
|
+
/** Лист модели, чей это сигнал; `undefined` — сигнал не из модели. @internal */
|
|
64
|
+
export declare function leafOfSignal(handle: object): {
|
|
65
|
+
reference(): unknown;
|
|
66
|
+
} | undefined;
|
|
67
|
+
declare class ModelLeafNode {
|
|
6
68
|
path: string;
|
|
7
69
|
readonly kind: "leaf";
|
|
8
70
|
readonly signal: PathAwareSignal<unknown>;
|
|
@@ -14,34 +76,93 @@ declare class LeafNode {
|
|
|
14
76
|
/** Нереактивный снимок. */
|
|
15
77
|
peek(): unknown;
|
|
16
78
|
set(value: unknown): void;
|
|
79
|
+
/**
|
|
80
|
+
* Вернуть значение к снимку. Производное поле (цель `compute`, поле сервера с `markDerived`)
|
|
81
|
+
* сброс не пишет — как `set` и `patch`: значением владеет поведение, а снимок такого поля снят
|
|
82
|
+
* до первого расчёта, и `compute` пересчитал бы его только при смене источников.
|
|
83
|
+
*/
|
|
17
84
|
resetToInitial(): void;
|
|
18
85
|
captureInitial(): void;
|
|
86
|
+
/** Значение точки отсчёта — копия: правка полученного снимок не трогает. */
|
|
87
|
+
reference(): unknown;
|
|
19
88
|
dirty(): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Отличается ли значение от снимка. Производное поле отличием не считается: его пишет поведение,
|
|
91
|
+
* а не пользователь — иначе форма без единой правки была бы «изменённой».
|
|
92
|
+
*/
|
|
93
|
+
differsFrom(snapshot: unknown): boolean;
|
|
20
94
|
}
|
|
21
|
-
export declare class
|
|
95
|
+
export declare class ModelGroupNode {
|
|
22
96
|
path: string;
|
|
23
97
|
readonly kind: "group";
|
|
24
98
|
readonly children: Map<string, ModelNode>;
|
|
25
|
-
|
|
99
|
+
/**
|
|
100
|
+
* @param shape Образец той же группы из шаблона родительского массива: из него вложенные
|
|
101
|
+
* массивы берут шаблоны, если значение пришло обычными данными (см. {@link ModelArrayNode}).
|
|
102
|
+
*/
|
|
103
|
+
constructor(initial: Record<string, unknown>, path: string, shape?: Shape);
|
|
26
104
|
rebase(path: string): void;
|
|
27
105
|
/** Реактивное чтение поддерева (внутри effect/computed подписывает на все листья группы). */
|
|
28
106
|
read(): Record<string, unknown>;
|
|
29
107
|
peek(): Record<string, unknown>;
|
|
108
|
+
/**
|
|
109
|
+
* Полная установка: значение ожидается целиком. Ключи, которых в нём нет, остаются прежними —
|
|
110
|
+
* как у {@link patch}, — но в dev о них сообщает предупреждение: неполный объект в `set` — почти
|
|
111
|
+
* всегда ошибка вызывающего кода, а не намерение.
|
|
112
|
+
*/
|
|
30
113
|
set(value: unknown): void;
|
|
114
|
+
/**
|
|
115
|
+
* Частичное обновление: записываются только переданные ключи. Вложенная группа сливается так
|
|
116
|
+
* же, массив заменяется целиком.
|
|
117
|
+
*/
|
|
118
|
+
patch(value: unknown): void;
|
|
119
|
+
/**
|
|
120
|
+
* Запись значения по ключам группы. Лишние ключи значения игнорируются, производные поля не
|
|
121
|
+
* затираются.
|
|
122
|
+
*
|
|
123
|
+
* @param missing - Куда складывать пути ключей, для которых значение не пришло. Передаётся при
|
|
124
|
+
* полной установке ({@link set}); при частичной ({@link patch}) — `undefined`.
|
|
125
|
+
* @param partial - Частичное обновление: ключ со значением `undefined` — «не трогать», как в
|
|
126
|
+
* частичном значении элемента массива (`DeepPartial` допускает `{ ключ: undefined }`).
|
|
127
|
+
*/
|
|
128
|
+
private write;
|
|
31
129
|
resetToInitial(): void;
|
|
32
130
|
captureInitial(): void;
|
|
33
131
|
dirty(): boolean;
|
|
132
|
+
/** Отличается ли группа от снимка её значения (строка массива сверяется со снимком массива). */
|
|
133
|
+
differsFrom(snapshot: unknown): boolean;
|
|
34
134
|
}
|
|
35
|
-
export declare class
|
|
135
|
+
export declare class ModelArrayNode {
|
|
36
136
|
path: string;
|
|
137
|
+
private readonly shape?;
|
|
37
138
|
readonly kind: "array";
|
|
38
139
|
readonly items: Signal<ModelNode[]>;
|
|
39
140
|
private initial;
|
|
40
|
-
|
|
141
|
+
private blank;
|
|
142
|
+
private fallback;
|
|
143
|
+
private sample;
|
|
144
|
+
/** @param shape Образец того же массива из шаблона родителя (см. {@link ModelGroupNode}). */
|
|
145
|
+
constructor(initial: unknown[], path: string, shape?: Shape | undefined);
|
|
146
|
+
/** Шаблон по старшинству: свой (`arrayOf`) → из шаблона родителя → запасной извне. */
|
|
147
|
+
private template;
|
|
148
|
+
private readonly itemShape;
|
|
149
|
+
private build;
|
|
150
|
+
/**
|
|
151
|
+
* Значение нового элемента: из шаблона; переданный объект накладывается поверх шаблона —
|
|
152
|
+
* недостающие ключи берутся из шаблона, поэтому `push({ type: 'house' })` даёт полный элемент.
|
|
153
|
+
*/
|
|
154
|
+
private fresh;
|
|
155
|
+
/** Запасной шаблон извне (сборка формы передаёт `initialValue`): шаблон модели главнее. */
|
|
156
|
+
provideBlank(blank: Blank): void;
|
|
41
157
|
rebase(path: string): void;
|
|
42
158
|
private reindex;
|
|
43
|
-
|
|
44
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Индекс за концом массива — ошибка, а не «в конец»: `splice` молча сдвигал бы элемент на
|
|
161
|
+
* другой индекс, и вызывающий код получал бы путь, которого не просил.
|
|
162
|
+
*/
|
|
163
|
+
private beyondEnd;
|
|
164
|
+
push(value?: unknown): void;
|
|
165
|
+
insertAt(index: number, value?: unknown): void;
|
|
45
166
|
removeAt(index: number): void;
|
|
46
167
|
move(from: number, to: number): void;
|
|
47
168
|
swap(a: number, b: number): void;
|
|
@@ -55,6 +176,15 @@ export declare class ArrayNode {
|
|
|
55
176
|
set(value: unknown): void;
|
|
56
177
|
resetToInitial(): void;
|
|
57
178
|
captureInitial(): void;
|
|
179
|
+
/** Элементы точки отсчёта — копия: правка полученного снимок не трогает. */
|
|
180
|
+
reference(): unknown[];
|
|
58
181
|
dirty(): boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Отличается ли массив от снимка: другая длина либо отличается элемент. Сверка идёт по узлам, а
|
|
184
|
+
* не по значению целиком — производные поля строк (цели `compute` поведения строки) не в счёт.
|
|
185
|
+
*/
|
|
186
|
+
differsFrom(snapshot: unknown): boolean;
|
|
59
187
|
}
|
|
188
|
+
/** Начальное значение элемента как шаблон: фабрика — как есть, значение — копией. */
|
|
189
|
+
export declare const blankFrom: (initialValue: unknown) => Blank;
|
|
60
190
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Signal } from '@preact/signals-core';
|
|
2
2
|
import { PathAwareSignal } from './types';
|
|
3
|
-
import { ModelNode,
|
|
3
|
+
import { ModelNode, ModelGroupNode, ModelArrayNode } from './model-nodes';
|
|
4
4
|
/**
|
|
5
5
|
* Узел дерева `$`: лист → сам {@link PathAwareSignal}, группа/массив → контейнерный узел —
|
|
6
6
|
* {@link ReadonlySignal} агрегированного значения ПЛЮС доступ к детям по имени/индексу.
|
|
@@ -20,6 +20,13 @@ import { ModelNode, GroupNode } from './model-nodes';
|
|
|
20
20
|
* полей, а потребители, перечисляющие модель, не видят служебных ключей.
|
|
21
21
|
*/
|
|
22
22
|
export declare function signalsProxy(node: ModelNode): any;
|
|
23
|
+
/**
|
|
24
|
+
* Узел модели за контейнерной ручкой дерева `$` (группа или массив). Для листа и для всего, что
|
|
25
|
+
* ручкой не является, — `undefined`.
|
|
26
|
+
*
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
export declare function containerNodeOf(handle: unknown): ModelGroupNode | ModelArrayNode | undefined;
|
|
23
30
|
/**
|
|
24
31
|
* Узел дерева `model.$` — контейнер (группа/массив), а не лист?
|
|
25
32
|
*
|
|
@@ -37,12 +44,11 @@ export declare function isModelContainerSignal(value: unknown): boolean;
|
|
|
37
44
|
/** Узел-массив дерева `model.$` — ручка значения массива целиком. */
|
|
38
45
|
export declare function isModelArraySignal(value: unknown): boolean;
|
|
39
46
|
/**
|
|
40
|
-
* «Ручка значения», к которой можно привязать поле: лист (
|
|
47
|
+
* «Ручка значения», к которой можно привязать поле: лист (сигнал, не контейнер) либо узел-массив
|
|
41
48
|
* дерева `model.$` (значение — массив целиком, `.value` читается и пишется).
|
|
42
49
|
*
|
|
43
50
|
* Группа сюда не входит: она читается целиком, но не пишется и полем не бывает. Этой проверкой
|
|
44
|
-
* `createForm` и рендереры отличают узел-поле схемы (`{
|
|
45
|
-
* вместо голого `value instanceof Signal`, который узел-массив не проходит.
|
|
51
|
+
* `createForm` и рендереры отличают узел-поле схемы (`{ model, component }`) от контейнера.
|
|
46
52
|
*
|
|
47
53
|
* @group Model
|
|
48
54
|
* @example
|
|
@@ -54,4 +60,4 @@ export declare function isModelArraySignal(value: unknown): boolean;
|
|
|
54
60
|
* ```
|
|
55
61
|
*/
|
|
56
62
|
export declare function isValueSignal(value: unknown): value is Signal<unknown>;
|
|
57
|
-
export declare function resolveSignalAt(root:
|
|
63
|
+
export declare function resolveSignalAt(root: ModelGroupNode, path: string): PathAwareSignal<unknown> | undefined;
|
|
@@ -1,3 +1,84 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare
|
|
1
|
+
import { ModelGroupNode } from './model-nodes';
|
|
2
|
+
import { FormModel, ModelArray } from './types';
|
|
3
|
+
export declare const rootByFacade: WeakMap<object, ModelGroupNode>;
|
|
4
|
+
export declare function makeFormModel(group: ModelGroupNode): any;
|
|
5
|
+
/**
|
|
6
|
+
* Value-фасад для ручки {@link modelOf}: массив → {@link ModelArray}, объект → под-модель
|
|
7
|
+
* {@link FormModel}.
|
|
8
|
+
*
|
|
9
|
+
* @group Model
|
|
10
|
+
*/
|
|
11
|
+
export type ModelOf<V> = NonNullable<V> extends ReadonlyArray<infer U> ? ModelArray<U> : FormModel<NonNullable<V>>;
|
|
12
|
+
/**
|
|
13
|
+
* Value-фасад по ручке дерева `model.$`: группа → под-модель {@link FormModel}, массив →
|
|
14
|
+
* {@link ModelArray}. Обратная операция к `model.$`: `modelOf(model.$.address) === model.address`.
|
|
15
|
+
*
|
|
16
|
+
* Ручка находит фасад по ИДЕНТИЧНОСТИ, а не по пути. Путь для этого не годится: он абсолютный
|
|
17
|
+
* (`items.0.phones`) и меняется при перестановке строк, а области поведения и формы строк
|
|
18
|
+
* вложенные — поиск по пути от под-модели строки ничего не находит.
|
|
19
|
+
*
|
|
20
|
+
* Лист ручкой контейнера не является — функция бросает. В частности, группа или массив,
|
|
21
|
+
* созданные из начального `null`, в модели — лист: вид узла фиксируется при создании.
|
|
22
|
+
*
|
|
23
|
+
* @typeParam V - Значение, которое хранит ручка (выводится из `peek()`).
|
|
24
|
+
* @param handle - Узел-группа или узел-массив дерева `model.$`.
|
|
25
|
+
* @returns Под-модель группы либо фасад массива.
|
|
26
|
+
* @throws TypeError если `handle` — лист или не ручка модели.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const model = createModel({ address: { city: '' }, phones: [{ number: '' }] });
|
|
31
|
+
*
|
|
32
|
+
* modelOf(model.$.address).city = 'Казань'; // под-модель: чтение, запись, get/set/patch
|
|
33
|
+
* modelOf(model.$.phones).push({ number: '+7' }); // фасад массива: мутации и обход
|
|
34
|
+
* modelOf(model.$.phones[0]).number; // строка массива — тоже группа
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @group Model
|
|
38
|
+
*/
|
|
39
|
+
export declare function modelOf<V extends object | null | undefined>(handle: {
|
|
40
|
+
peek(): V;
|
|
41
|
+
}): ModelOf<V>;
|
|
42
|
+
/**
|
|
43
|
+
* Ручка массива по привязке: сама ручка `model.$.<массив>` либо value-фасад `model.<массив>`.
|
|
44
|
+
* Для всего остального — `undefined`.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function arrayHandleOf(binding: unknown): object | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Ручка группы по привязке: `model.$.<группа>` либо под-модель `model.<группа>`. Для всего
|
|
51
|
+
* остального — `undefined`.
|
|
52
|
+
*
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
export declare function groupHandleOf(binding: unknown): object | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Запасной шаблон нового элемента массива — от того, кто строит модель извне: сборка формы
|
|
58
|
+
* передаёт сюда `initialValue` узла-массива. Действует, только если модель своего шаблона не
|
|
59
|
+
* объявила (`arrayOf`): так живут формы, чья модель строится из данных без кода. Что это узел
|
|
60
|
+
* схемы, модель не знает.
|
|
61
|
+
*
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export declare function provideArrayBlank(handle: unknown, initialValue: unknown): void;
|
|
65
|
+
/**
|
|
66
|
+
* Value-фасад модели (под-модель или фасад массива), а не обычный объект?
|
|
67
|
+
*
|
|
68
|
+
* Обходчикам чужих деревьев, в которых могут лежать фасады модели, в фасад спускаться нельзя:
|
|
69
|
+
* чтение его ключей — это реактивное чтение значений модели.
|
|
70
|
+
*
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Точка отсчёта модели по ручке, к которой привязана нода формы: сигналу листа или фасаду
|
|
75
|
+
* массива. К ней сброс формы (`form.reset()`) возвращает ноду — к тому же, к чему `model.reset()`
|
|
76
|
+
* возвращает модель: последний `captureInitial` либо значение создания модели.
|
|
77
|
+
*
|
|
78
|
+
* `undefined` — ручка не из модели (нода над собственным сигналом): сбрасывать её не к чему,
|
|
79
|
+
* кроме значения, с которым она создана. @internal
|
|
80
|
+
*/
|
|
81
|
+
export declare function referenceOf(handle: unknown): {
|
|
82
|
+
readonly value: unknown;
|
|
83
|
+
} | undefined;
|
|
84
|
+
export declare function isModelFacade(value: unknown): boolean;
|
|
@@ -68,6 +68,38 @@ export declare function safeCallback<TArgs extends unknown[]>(callback: (...args
|
|
|
68
68
|
* ```
|
|
69
69
|
*/
|
|
70
70
|
export declare function runOutsideEffect(fn: () => void | Promise<void>): () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Дождаться, пока отработают отложенные записи текущего тика — вместе с теми, что они породили
|
|
73
|
+
* (цепочка расчётов: каждая запись будит следующий расчёт, а тот снова пишет отложенно).
|
|
74
|
+
*
|
|
75
|
+
* Ждёт только микротаски: запись после таймера (debounce) или после `await` в async-callback сюда не
|
|
76
|
+
* входит — это уже не «тот же тик».
|
|
77
|
+
*
|
|
78
|
+
* Счётчик общий для рантайма, а не для одной модели: отложенные записи ставит {@link runOutsideEffect},
|
|
79
|
+
* а он моделей не различает. Нужен проверкам «по действию» — отправке и переходу шага: правила должны
|
|
80
|
+
* увидеть модель после записей поведения того же тика (колбэк `onChange`, сброс `resetOnDisable`).
|
|
81
|
+
*
|
|
82
|
+
* @returns Промис ожидания; `undefined` — отложенных записей сейчас нет, ждать нечего.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* model.loanType = 'mortgage'; // поведение допишет зависимые поля на микротаске
|
|
87
|
+
* await deferredWritesSettled();
|
|
88
|
+
* const values = model.get(); // уже с записями поведения
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function deferredWritesSettled(): Promise<void> | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Отложенные записи одной операции: задание выполняется на микротаске ({@link runOutsideEffect}),
|
|
94
|
+
* а `cancelAll` отменяет все ещё не выполненные — при снятии операции (запись после cleanup не
|
|
95
|
+
* случится) или когда новое задание делает ожидающие устаревшими (побеждает последнее).
|
|
96
|
+
*
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
export declare function deferredWrites(): {
|
|
100
|
+
schedule(job: () => void): void;
|
|
101
|
+
cancelAll(): void;
|
|
102
|
+
};
|
|
71
103
|
/**
|
|
72
104
|
* Создает версию callback с поддержкой debounce, безопасную для effect
|
|
73
105
|
*
|
|
@@ -76,7 +108,7 @@ export declare function runOutsideEffect(fn: () => void | Promise<void>): () =>
|
|
|
76
108
|
* async-rejection) маршрутизируются dev-логгером (logDeferError).
|
|
77
109
|
*
|
|
78
110
|
* @param callback - Функция для выполнения
|
|
79
|
-
* @param withDebounce -
|
|
111
|
+
* @param withDebounce - Обёртка, откладывающая вызов (debounce)
|
|
80
112
|
* @returns Обёрнутая функция
|
|
81
113
|
*
|
|
82
114
|
* @example
|
package/dist/model/types.d.ts
CHANGED
|
@@ -14,6 +14,33 @@ export type PathAwareSignal<T> = Signal<T> & {
|
|
|
14
14
|
* @internal
|
|
15
15
|
*/
|
|
16
16
|
type Opaque = Date | File | Blob;
|
|
17
|
+
/**
|
|
18
|
+
* Значение одного ключа в {@link DeepPartial}: вложенная группа — частично, массив и спец-объект
|
|
19
|
+
* (Date/File/Blob) — целиком.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
type DeepPartialValue<V> = NonNullable<V> extends ReadonlyArray<unknown> | Opaque ? V : NonNullable<V> extends object ? DeepPartial<NonNullable<V>> | Extract<V, null | undefined> : V;
|
|
23
|
+
/**
|
|
24
|
+
* Частичное значение модели для {@link ModelApi.patch}: любой ключ можно опустить на любой
|
|
25
|
+
* глубине вложенных групп. Массив передаётся целиком — он заменяется, а не сливается.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* type Profile = { name: string; address: { city: string; street: string }; tags: string[] };
|
|
30
|
+
* const update: DeepPartial<Profile> = { address: { city: 'Казань' } };
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @group Model
|
|
34
|
+
*/
|
|
35
|
+
export type DeepPartial<T> = {
|
|
36
|
+
[K in keyof T]?: DeepPartialValue<T[K]>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* `null` входит в тип `V`. Без `strictNullChecks` у потребителя `null` подходит любому типу —
|
|
40
|
+
* тогда признак ложен, и тип контейнера остаётся фасадом, как без `null`.
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
type IncludesNull<V> = null extends string ? false : null extends V ? true : false;
|
|
17
44
|
/**
|
|
18
45
|
* Фасад элемента массива при обходе (`at`/`map`/`forEach`): массив → {@link ModelArray},
|
|
19
46
|
* Opaque (Date/File/Blob) и примитив → значение, объект → под-модель {@link FormModel}.
|
|
@@ -21,7 +48,7 @@ type Opaque = Date | File | Blob;
|
|
|
21
48
|
* чтобы `files: File[]`/`dates: Date[]`/вложенные массивы не мис-типизировались как `FormModel`.
|
|
22
49
|
* @internal
|
|
23
50
|
*/
|
|
24
|
-
type ModelArrayItem<U> = NonNullable<U> extends ReadonlyArray<infer E> ? ModelArray<E> : NonNullable<U> extends Opaque ? U : NonNullable<U> extends object ? FormModel<NonNullable<U>> : U;
|
|
51
|
+
type ModelArrayItem<U> = IncludesNull<U> extends true ? U : NonNullable<U> extends ReadonlyArray<infer E> ? ModelArray<E> : NonNullable<U> extends Opaque ? U : NonNullable<U> extends object ? FormModel<NonNullable<U>> : U;
|
|
25
52
|
/**
|
|
26
53
|
* Значение поля в value-доступе модели:
|
|
27
54
|
* - массив → {@link ModelArray}
|
|
@@ -29,10 +56,13 @@ type ModelArrayItem<U> = NonNullable<U> extends ReadonlyArray<infer E> ? ModelAr
|
|
|
29
56
|
* - объект → под-модель {@link FormModel} (value-доступ + `.$`-сигналы + API get/set/patch/…);
|
|
30
57
|
* промоутится рантаймом (`makeFormModel`); сигналы идентичны `model.$.<path>`
|
|
31
58
|
* - примитив → значение
|
|
59
|
+
* - тип с `null` (`File[] | null`, `Address | null`) → значение как есть, без фасада: поле,
|
|
60
|
+
* которое бывает `null`, начинают с `null`, а такое поле в рантайме — лист (значение целиком).
|
|
61
|
+
* Контейнер, созданный из `[]` или `{}`, стал бы фасадом — nullable-контейнер начинают с `null`.
|
|
32
62
|
*
|
|
33
63
|
* @group Model
|
|
34
64
|
*/
|
|
35
|
-
export type ModelValue<V> = NonNullable<V> extends ReadonlyArray<infer U> ? ModelArray<U> : NonNullable<V> extends Opaque ? V : NonNullable<V> extends object ? FormModel<NonNullable<V>> : V;
|
|
65
|
+
export type ModelValue<V> = IncludesNull<V> extends true ? V : NonNullable<V> extends ReadonlyArray<infer U> ? ModelArray<U> : NonNullable<V> extends Opaque ? V : NonNullable<V> extends object ? FormModel<NonNullable<V>> : V;
|
|
36
66
|
/**
|
|
37
67
|
* Карта value-полей объекта (value-половина {@link FormModel}): поля доступны как обычные свойства
|
|
38
68
|
* (чтение реактивно внутри `effect`/`computed`, запись — присваиванием). Вложенные объекты-поля
|
|
@@ -57,10 +87,13 @@ export interface ModelArray<U> {
|
|
|
57
87
|
readonly __path: string;
|
|
58
88
|
/** Реактивная длина. */
|
|
59
89
|
readonly length: number;
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Добавить элемент в конец (значение элемента целиком). Без значения — элемент по шаблону
|
|
92
|
+
* массива (`arrayOf(blank)` в модели); шаблона нет — ошибка.
|
|
93
|
+
*/
|
|
94
|
+
push(item?: U): void;
|
|
95
|
+
/** Вставить элемент по индексу. Без значения — элемент по шаблону, как у {@link push}. */
|
|
96
|
+
insertAt(index: number, item?: U): void;
|
|
64
97
|
/** Удалить элемент по индексу. */
|
|
65
98
|
removeAt(index: number): void;
|
|
66
99
|
/** Переместить элемент. */
|
|
@@ -77,6 +110,8 @@ export interface ModelArray<U> {
|
|
|
77
110
|
forEach(fn: (item: ModelArrayItem<U>, index: number) => void): void;
|
|
78
111
|
/** Снимок массива значений (без подписки). */
|
|
79
112
|
toArray(): U[];
|
|
113
|
+
/** Обход `for…of` / spread — те же элементы, что у {@link forEach}. */
|
|
114
|
+
[Symbol.iterator](): IterableIterator<ModelArrayItem<U>>;
|
|
80
115
|
/** Индексный value-доступ. */
|
|
81
116
|
[index: number]: ModelValue<U>;
|
|
82
117
|
}
|
|
@@ -112,13 +147,13 @@ export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>
|
|
|
112
147
|
* push/removeAt/move).
|
|
113
148
|
*
|
|
114
149
|
* В отличие от группы, узел ЗАПИСЫВАЕМ: `model.$.tags.value = ['a']` заменяет массив целиком. Это
|
|
115
|
-
* делает его {@link PathAwareSignal} — к нему привязывают поле (`{
|
|
150
|
+
* делает его {@link PathAwareSignal} — к нему привязывают поле (`{ model: model.$.tags, component }`),
|
|
116
151
|
* правило (`validate(model.$.tags, …)`) и поведение, как к листу. Так массив служит ОДНИМ значением
|
|
117
152
|
* поля: мультивыбор, теги, список файлов.
|
|
118
153
|
*
|
|
119
|
-
* `V` — объявленный тип поля, включая `
|
|
120
|
-
*
|
|
121
|
-
*
|
|
154
|
+
* `V` — объявленный тип поля, включая `undefined`. Поле с `null` в типе (`string[] | null`) — не
|
|
155
|
+
* узел-массив, а лист {@link PathAwareSignal}: его начинают с `null`, и `length` с индексами у него
|
|
156
|
+
* в рантайме нет (см. {@link ModelValue}).
|
|
122
157
|
*
|
|
123
158
|
* @group Model
|
|
124
159
|
*/
|
|
@@ -132,10 +167,11 @@ export type ModelArraySignals<U, V> = Signal<V> & {
|
|
|
132
167
|
* Узел дерева сигналов `model.$`: массив → {@link ModelArraySignals}, Opaque (Date/File/Blob)
|
|
133
168
|
* и примитив → {@link PathAwareSignal}, объект → {@link ModelGroupSignals}. Для примитивных
|
|
134
169
|
* и Opaque массивов элемент — сам сигнал листа (а не под-дерево), поэтому `model.$.tags[0]` — это
|
|
135
|
-
* `PathAwareSignal<string>`, а не `ModelGroupSignals<never>`.
|
|
170
|
+
* `PathAwareSignal<string>`, а не `ModelGroupSignals<never>`. Тип с `null` — лист
|
|
171
|
+
* {@link PathAwareSignal}: такое поле начинают с `null`, и под-сигналов у него нет.
|
|
136
172
|
* @internal
|
|
137
173
|
*/
|
|
138
|
-
type ModelSignalNode<V> = NonNullable<V> extends ReadonlyArray<infer U> ? ModelArraySignals<U, V> : NonNullable<V> extends Opaque ? PathAwareSignal<V> : NonNullable<V> extends object ? ModelGroupSignals<NonNullable<V>> : PathAwareSignal<V>;
|
|
174
|
+
type ModelSignalNode<V> = IncludesNull<V> extends true ? PathAwareSignal<V> : NonNullable<V> extends ReadonlyArray<infer U> ? ModelArraySignals<U, V> : NonNullable<V> extends Opaque ? PathAwareSignal<V> : NonNullable<V> extends object ? ModelGroupSignals<NonNullable<V>> : PathAwareSignal<V>;
|
|
139
175
|
/**
|
|
140
176
|
* API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).
|
|
141
177
|
*
|
|
@@ -156,18 +192,35 @@ export interface ModelApi<T> {
|
|
|
156
192
|
* Полная установка значений: принимает объект целиком (все ключи `T`) и записывает их в модель.
|
|
157
193
|
* Производными полями (цели `compute`) владеет compute — их значения из payload игнорируются.
|
|
158
194
|
* Не меняет initial-снимок. Для частичного обновления (только переданные ключи) — {@link ModelApi.patch}.
|
|
195
|
+
*
|
|
196
|
+
* Если в объекте не хватает ключей (значение пришло без типа — например, с сервера), эти поля
|
|
197
|
+
* остаются прежними, а в dev выводится предупреждение со списком.
|
|
159
198
|
*/
|
|
160
199
|
set(value: T): void;
|
|
161
200
|
/**
|
|
162
201
|
* Частичное слияние значений (load/patch с сервера): обновляет только переданные ключи,
|
|
163
|
-
* отсутствующие ключи НЕ трогаются.
|
|
202
|
+
* отсутствующие ключи НЕ трогаются. Вложенные группы сливаются так же, массив заменяется
|
|
203
|
+
* целиком. Не меняет initial-снимок.
|
|
204
|
+
*/
|
|
205
|
+
patch(value: DeepPartial<T>): void;
|
|
206
|
+
/**
|
|
207
|
+
* Отличаются ли текущие значения от initial-снимка (value-diff). Производные поля — цели
|
|
208
|
+
* `compute` / `computeFrom` и поля с `markDerived` — не в счёт: их пишет поведение, а не
|
|
209
|
+
* пользователь, и форма без единой правки изменённой не считается.
|
|
164
210
|
*/
|
|
165
|
-
patch(value: Partial<T>): void;
|
|
166
|
-
/** Отличаются ли текущие значения от initial-снимка (value-diff). */
|
|
167
211
|
isDirty(): boolean;
|
|
168
|
-
/**
|
|
212
|
+
/**
|
|
213
|
+
* Сбросить значения к initial-снимку. Производные поля сброс не пишет, как `set` и `patch`:
|
|
214
|
+
* цель `compute` пересчитает поведение, когда вернутся её источники.
|
|
215
|
+
*
|
|
216
|
+
* Ноды формы не трогает: замечания погаснут при следующей проверке. Сброс для пользователя —
|
|
217
|
+
* `form.reset()`: та же точка отсчёта и чистые ноды.
|
|
218
|
+
*/
|
|
169
219
|
reset(): void;
|
|
170
|
-
/**
|
|
220
|
+
/**
|
|
221
|
+
* Зафиксировать текущие значения как новый initial-снимок («точка отсчёта»). К нему возвращают
|
|
222
|
+
* и `model.reset()`, и `form.reset()`.
|
|
223
|
+
*/
|
|
171
224
|
captureInitial(): void;
|
|
172
225
|
/**
|
|
173
226
|
* Резолв строкового пути в сигнал (для error-routing/мостов): лист либо массив целиком
|
package/dist/model.js
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import { c as s, e as r, a as
|
|
2
|
-
import {
|
|
3
|
-
import { c as
|
|
1
|
+
import { c as s, e as r, a as l } from "./create-model-BvcbNPgL.js";
|
|
2
|
+
import { a as d, g as o, f as t, d as c, i as f, b as n, c as m, m as u, r as p, s as b, e as g, u as h } from "./safe-effect-BbtX3KuN.js";
|
|
3
|
+
import { c as k, a as v, r as D, b as F, s as x, t as y, w as C } from "./behaviors-value-HA_Q03hc.js";
|
|
4
4
|
export {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
d as arrayOf,
|
|
6
|
+
k as computeFrom,
|
|
7
|
+
v as copyFrom,
|
|
7
8
|
s as createModel,
|
|
9
|
+
o as deepEqual,
|
|
10
|
+
t as deferredWritesSettled,
|
|
8
11
|
r as eachLeafSignal,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
l as eachValueSignal,
|
|
13
|
+
c as isDerived,
|
|
14
|
+
f as isModelContainerSignal,
|
|
12
15
|
n as isValueSignal,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
m as markDerived,
|
|
17
|
+
u as modelOf,
|
|
18
|
+
D as resetWhen,
|
|
19
|
+
F as revalidateWhen,
|
|
16
20
|
p as runOutsideEffect,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
b as safeCallback,
|
|
22
|
+
g as safeDebouncedCallback,
|
|
23
|
+
x as syncFields,
|
|
24
|
+
y as transformValue,
|
|
25
|
+
h as unmarkDerived,
|
|
26
|
+
C as watchField
|
|
23
27
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const n = Symbol.for("@reformer/core/form-node-kind"), e = Symbol.for("@reformer/core/form-node-raw");
|
|
2
|
+
function t(r) {
|
|
3
|
+
if (typeof r != "object" || r === null) return;
|
|
4
|
+
const o = r[n];
|
|
5
|
+
return o === "control" || o === "group" || o === "array" ? o : void 0;
|
|
6
|
+
}
|
|
7
|
+
function f(r) {
|
|
8
|
+
return r[e] ?? r;
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
n as N,
|
|
12
|
+
e as R,
|
|
13
|
+
t as k,
|
|
14
|
+
f as r
|
|
15
|
+
};
|
|
@@ -41,7 +41,7 @@ export interface FieldAdapter {
|
|
|
41
41
|
strip?: string[];
|
|
42
42
|
/**
|
|
43
43
|
* Передавать ли контролу ноду формы пропом `control` (только рендерер). По умолчанию `false`:
|
|
44
|
-
*
|
|
44
|
+
* issues/touched обслуживает обёртка поля. Ставь `true`, если контрол сам вызывает
|
|
45
45
|
* `useFormControl(control)`.
|
|
46
46
|
*/
|
|
47
47
|
passControl?: boolean;
|
|
@@ -43,8 +43,11 @@ export declare function makeElementFieldHandle(el: RefObject<HTMLElement | null>
|
|
|
43
43
|
export declare function useFieldHandleRef<H = FieldHandle>(outerRef: Ref<H> | undefined): RefObject<unknown>;
|
|
44
44
|
/**
|
|
45
45
|
* Что публиковать потребителю по ref контрола: handle композита как есть, иначе (DOM-узел или
|
|
46
|
-
* ещё пусто) — базовый {@link FieldHandle}, читающий узел лениво из `inner`.
|
|
46
|
+
* ещё пусто) — базовый {@link FieldHandle}, читающий узел лениво из `inner`. С `cache` базовый
|
|
47
|
+
* handle создаётся один раз и дальше переиспользуется.
|
|
47
48
|
*
|
|
48
49
|
* @internal Экспортируется для юнит-тестов.
|
|
49
50
|
*/
|
|
50
|
-
export declare function resolveFieldHandle(inner: RefObject<unknown
|
|
51
|
+
export declare function resolveFieldHandle(inner: RefObject<unknown>, cache?: {
|
|
52
|
+
current: FieldHandle | null;
|
|
53
|
+
}): unknown;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FormBundle } from '../../form/form-bundle';
|
|
2
|
+
/**
|
|
3
|
+
* Контекст сборки. Значение — бандл `createForm`; вне рендерера — `null`.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <FormBundleContext.Provider value={bundle}>
|
|
8
|
+
* <MyWizard />
|
|
9
|
+
* </FormBundleContext.Provider>
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const FormBundleContext: import('react').Context<FormBundle<any> | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Бандл сборки, внутри которой отрисован компонент; `null` — компонент стоит вне рендерера
|
|
15
|
+
* (например, визард в разметке React-руками получает форму и поток шагов пропсами).
|
|
16
|
+
*
|
|
17
|
+
* @typeParam T - Форма данных модели.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* function StepFooter() {
|
|
22
|
+
* const bundle = useFormBundleContext<CreditForm>();
|
|
23
|
+
* return <button onClick={() => void bundle?.validate()}>Проверить</button>;
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function useFormBundleContext<T = unknown>(): FormBundle<T> | null;
|