@reformer/core 9.0.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -57
- package/dist/behaviors-node-BMOI2JJF.js +26 -0
- package/dist/behaviors-value-lCpqicfa.js +148 -0
- package/dist/behaviors.d.ts +2 -133
- package/dist/behaviors.js +148 -147
- package/dist/{core/utils → form}/aggregate-signals.d.ts +2 -2
- package/dist/form/behaviors-node.d.ts +55 -0
- package/dist/form/behaviors.d.ts +133 -0
- package/dist/{core/utils → form}/create-form.d.ts +5 -4
- package/dist/{core/utils → form}/error-handler.d.ts +1 -1
- package/dist/{core → form}/factories/node-factory.d.ts +1 -1
- package/dist/{core/utils → form}/form-proxy-builder.d.ts +2 -2
- package/dist/{core/utils → form}/form-submitter.d.ts +6 -1
- package/dist/{hooks → form/hooks}/types.d.ts +31 -1
- package/dist/{hooks → form/hooks}/useArrayLength.d.ts +1 -1
- package/dist/{hooks → form/hooks}/useFormControl.d.ts +3 -3
- package/dist/{hooks → form/hooks}/useFormControlValue.d.ts +2 -2
- package/dist/{hooks → form/hooks}/useSignalSubscription.d.ts +8 -1
- package/dist/form/index.d.ts +36 -0
- package/dist/{core → form}/nodes/array-node.d.ts +1 -1
- package/dist/{core → form}/nodes/field-node.d.ts +1 -1
- package/dist/{core → form}/nodes/form-node.d.ts +1 -1
- package/dist/{core → form}/nodes/group-node.d.ts +34 -4
- package/dist/{core → form}/nodes/model-array-node.d.ts +10 -3
- package/dist/{core/utils → form}/signal-node-registry.d.ts +1 -1
- package/dist/{core/utils → form}/status-machine.d.ts +1 -1
- package/dist/{core/utils → form}/type-guards.d.ts +5 -5
- package/dist/{core/types/index.d.ts → form/types/contracts.d.ts} +11 -90
- package/dist/{core → form}/types/deep-schema.d.ts +23 -1
- package/dist/{core → form}/types/form-proxy.d.ts +26 -1
- package/dist/form/types/index.d.ts +91 -0
- package/dist/{core → form}/types/schema-node.d.ts +1 -1
- package/dist/{core → form}/types/validation-schema.d.ts +19 -9
- package/dist/{core/model/validate-model.d.ts → form/validate-model-core.d.ts} +25 -25
- package/dist/form/validate-model.d.ts +27 -0
- package/dist/{core → form}/validation/validators/required.d.ts +2 -1
- package/dist/form/validators.d.ts +6 -0
- package/dist/form-model-C8Fi83k4.js +439 -0
- package/dist/index.d.ts +11 -16
- package/dist/index.js +666 -1011
- package/dist/{core/model/behaviors.d.ts → state/behaviors-value.d.ts} +0 -38
- package/dist/{core/utils → state}/derived-registry.d.ts +29 -0
- package/dist/state/form-model.d.ts +26 -0
- package/dist/state/index.d.ts +31 -0
- package/dist/state/safe-effect.d.ts +93 -0
- package/dist/{core/model → state}/types.d.ts +14 -11
- package/dist/state.d.ts +2 -0
- package/dist/state.js +19 -0
- package/dist/validators/email.d.ts +1 -1
- package/dist/validators/future-date.d.ts +1 -1
- package/dist/validators/integer.d.ts +1 -1
- package/dist/validators/is-date.d.ts +1 -1
- package/dist/validators/is-number.d.ts +1 -1
- package/dist/validators/max-age.d.ts +1 -1
- package/dist/validators/max-date.d.ts +1 -1
- package/dist/validators/max-length.d.ts +1 -1
- package/dist/validators/max.d.ts +1 -1
- package/dist/validators/min-age.d.ts +1 -1
- package/dist/validators/min-date.d.ts +1 -1
- package/dist/validators/min-length.d.ts +1 -1
- package/dist/validators/min.d.ts +1 -1
- package/dist/validators/multiple-of.d.ts +1 -1
- package/dist/validators/non-negative.d.ts +1 -1
- package/dist/validators/non-zero.d.ts +1 -1
- package/dist/validators/past-date.d.ts +1 -1
- package/dist/validators/pattern.d.ts +1 -1
- package/dist/validators/pattern.js +7 -6
- package/dist/validators/phone.d.ts +1 -1
- package/dist/validators/required.d.ts +1 -1
- package/dist/validators/required.js +5 -9
- package/dist/validators/url.d.ts +1 -1
- package/dist/validators.d.ts +6 -6
- package/llms.txt +307 -166
- package/package.json +5 -1
- package/dist/behaviors-O9a1Djj9.js +0 -147
- package/dist/core/model/form-model.d.ts +0 -18
- package/dist/core/model/index.d.ts +0 -12
- package/dist/core/utils/index.d.ts +0 -18
- package/dist/core/utils/safe-effect.d.ts +0 -73
- /package/dist/{core → form}/factories/index.d.ts +0 -0
- /package/dist/{core/utils → form}/unique-id.d.ts +0 -0
- /package/dist/{core → form}/validation/index.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/date-utils.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/email.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/future-date.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/index.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/integer.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/is-date.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/is-number.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/max-age.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/max-date.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/max-length.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/max.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/min-age.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/min-date.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/min-length.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/min.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/multiple-of.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/non-negative.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/non-zero.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/past-date.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/pattern.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/phone.d.ts +0 -0
- /package/dist/{core → form}/validation/validators/url.d.ts +0 -0
- /package/dist/{core/utils → state}/subscription-manager.d.ts +0 -0
|
@@ -48,44 +48,6 @@ export declare function copyFrom<T>(source: ReadonlySignal<T>, target: Signal<T>
|
|
|
48
48
|
export declare function watchField<T>(source: ReadonlySignal<T>, cb: (value: T) => void, options?: {
|
|
49
49
|
immediate?: boolean;
|
|
50
50
|
}): BehaviorCleanup;
|
|
51
|
-
/**
|
|
52
|
-
* Условное включение поля (state-операция). Резолвит ноду по сигналу-цели через реестр
|
|
53
|
-
* сигнал→нода (заполняется `createForm`) и вызывает `enable()`/`disable()` (+`reset()` при
|
|
54
|
-
* `resetOnDisable`). `condition` реактивен (читает свои сигналы модели).
|
|
55
|
-
*
|
|
56
|
-
* Запись состояния отложена через `runOutsideEffect` (микротаск) для защиты от «Cycle detected».
|
|
57
|
-
* ⚠️ Поле должно быть материализовано в форме (`createForm`) — иначе ноды в реестре нет (например,
|
|
58
|
-
* элемент массива, который строится per-item).
|
|
59
|
-
*
|
|
60
|
-
* @group Model
|
|
61
|
-
* @example
|
|
62
|
-
* ```typescript
|
|
63
|
-
* enableWhen(model.$.propertyValue, () => model.loanType === 'mortgage', { resetOnDisable: true });
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export declare function enableWhen(target: ReadonlySignal<unknown>, condition: () => boolean, options?: {
|
|
67
|
-
resetOnDisable?: boolean;
|
|
68
|
-
}): BehaviorCleanup;
|
|
69
|
-
/**
|
|
70
|
-
* Условное выключение поля (инверсия {@link enableWhen}). Резолвит ноду по сигналу-цели через реестр
|
|
71
|
-
* сигнал→нода и вызывает `disable()`, когда `condition` истинно (+`reset()` при `resetOnDisable`).
|
|
72
|
-
* `condition` реактивен (читает свои сигналы модели).
|
|
73
|
-
*
|
|
74
|
-
* @group Model
|
|
75
|
-
* @param target Сигнал-цель поля (`model.$.<path>`).
|
|
76
|
-
* @param condition Реактивное условие; при `true` поле выключается.
|
|
77
|
-
* @param options.resetOnDisable Сбросить значение при выключении (по умолчанию `false`).
|
|
78
|
-
* @returns Cleanup для отписки.
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```typescript
|
|
82
|
-
* // Поле скидки недоступно, пока не выбран промо-тариф
|
|
83
|
-
* disableWhen(model.$.discount, () => model.plan !== 'promo', { resetOnDisable: true });
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
export declare function disableWhen(target: ReadonlySignal<unknown>, condition: () => boolean, options?: {
|
|
87
|
-
resetOnDisable?: boolean;
|
|
88
|
-
}): BehaviorCleanup;
|
|
89
51
|
/**
|
|
90
52
|
* Трансформация значения поля (идемпотентная): при изменении пишет `transformer(value)` обратно.
|
|
91
53
|
* Запись отложена (`runOutsideEffect`) во избежание «Cycle detected» (эффект читает и пишет один сигнал).
|
|
@@ -6,6 +6,9 @@ import { Signal } from '@preact/signals-core';
|
|
|
6
6
|
* bulk-сеттеры (`model.set`/`model.patch`, `patchValue`/`setValue`) пропускают это поле, чтобы
|
|
7
7
|
* значение из payload не затирало вычисляемое. Прикладной код напрямую обычно не вызывает.
|
|
8
8
|
*
|
|
9
|
+
* Идемпотентна на уровне флага: повторные вызовы наращивают счётчик ссылок, чтобы каждый оператор,
|
|
10
|
+
* пишущий в этот сигнал, был сбалансирован своим {@link unmarkDerived} при dispose.
|
|
11
|
+
*
|
|
9
12
|
* @param signal - Сигнал значения из {@link FormModel}, которым владеет compute
|
|
10
13
|
*
|
|
11
14
|
* @example
|
|
@@ -17,9 +20,35 @@ import { Signal } from '@preact/signals-core';
|
|
|
17
20
|
* ```
|
|
18
21
|
*
|
|
19
22
|
* @see {@link isDerived} - проверка пометки
|
|
23
|
+
* @see {@link unmarkDerived} - снять пометку при dispose оператора
|
|
20
24
|
* @group Utilities
|
|
21
25
|
*/
|
|
22
26
|
export declare function markDerived(signal: Signal<any>): void;
|
|
27
|
+
/**
|
|
28
|
+
* Снять пометку производного сигнала (обратная операция к {@link markDerived}).
|
|
29
|
+
*
|
|
30
|
+
* Вызывается из очистки (`onDispose`) оператора `compute`/`computeFrom`, когда поведение снимается,
|
|
31
|
+
* но модель/сигнал продолжают жить (динамическая перекоммутация: удалить под-схему → сохранить модель
|
|
32
|
+
* → bulk-set). Без этого сигнал остаётся помеченным навсегда, и bulk-сеттеры навсегда пропускают
|
|
33
|
+
* поле, которое больше ничем не вычисляется.
|
|
34
|
+
*
|
|
35
|
+
* Учитывает счётчик ссылок: пометка снимается только когда снят последний владелец. Вызов на
|
|
36
|
+
* непомеченном сигнале — безопасный no-op.
|
|
37
|
+
*
|
|
38
|
+
* @param signal - Сигнал значения из {@link FormModel}, ранее помеченный {@link markDerived}
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { markDerived, unmarkDerived } from '@reformer/core';
|
|
43
|
+
*
|
|
44
|
+
* markDerived(model.$.total);
|
|
45
|
+
* onDispose(() => unmarkDerived(model.$.total)); // при снятии compute снова разрешаем bulk-set
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @see {@link markDerived} - пометить сигнал производным
|
|
49
|
+
* @group Utilities
|
|
50
|
+
*/
|
|
51
|
+
export declare function unmarkDerived(signal: Signal<any>): void;
|
|
23
52
|
/**
|
|
24
53
|
* Производный ли сигнал (помечен через {@link markDerived}).
|
|
25
54
|
*
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FormModel } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Создать реактивную модель данных формы (слой M1).
|
|
4
|
+
*
|
|
5
|
+
* @group Model
|
|
6
|
+
* @param initial Начальные значения (объект). Определяют форму данных и initial-снимок.
|
|
7
|
+
* @returns {@link FormModel} с value-доступом, `$`-сигналами и API (get/set/patch/isDirty/reset/signalAt).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const model = createModel<{ email: string; profile: { name: string }; tags: string[] }>({
|
|
12
|
+
* email: '',
|
|
13
|
+
* profile: { name: '' },
|
|
14
|
+
* tags: [],
|
|
15
|
+
* });
|
|
16
|
+
* model.email = 'a@b.c';
|
|
17
|
+
* model.$.email.value; // 'a@b.c' (сигнал)
|
|
18
|
+
* // вложенная объект-группа — под-модель FormModel (value-доступ + `.$` + API):
|
|
19
|
+
* model.profile.name = 'Ada'; // value-запись
|
|
20
|
+
* model.$.profile.name.value; // 'Ada' (сигнал; ≡ model.profile.$.name у под-модели)
|
|
21
|
+
* model.profile.get(); // { name: 'Ada' }
|
|
22
|
+
* model.tags.push('x');
|
|
23
|
+
* model.get(); // { email: 'a@b.c', profile: { name: 'Ada' }, tags: ['x'] }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function createModel<T extends object>(initial: T): FormModel<T>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@reformer/core/state` — низкоуровневый реактивный **state-субстрат** (M1) и barrel модуля `state`.
|
|
3
|
+
*
|
|
4
|
+
* Это «прокси-объект с сигналами» и инструментарий для построения доменных модулей поверх него
|
|
5
|
+
* (form, table, …). Модуль СТРОГО реактивный: НИЧЕГО связанного с формами/валидацией/схемами здесь
|
|
6
|
+
* нет — только модель, value-операции, producer-флаг и утилиты субстрата. Граница state⇏form
|
|
7
|
+
* зафиксирована ESLint-правилом (`no-restricted-imports` на `src/state/**`).
|
|
8
|
+
*
|
|
9
|
+
* Реактивный рантайм (`signal/computed/effect/…`) живёт в отдельном subpath `@reformer/core/signals`
|
|
10
|
+
* (единый владелец `@preact/signals-core`) — импортируй его оттуда; здесь он НЕ реэкспортируется,
|
|
11
|
+
* чтобы зонтичный barrel `.` не разрастался рантаймом.
|
|
12
|
+
*
|
|
13
|
+
* Состав (реэкспорты — из тех же файлов, что использует зонтик `.`, поэтому `.` и `/state` — один
|
|
14
|
+
* module-инстанс: общий `derived`-WeakMap, единая идентичность `Signal`):
|
|
15
|
+
* - **модель** — `createModel` + типы `FormModel`/`ModelArray`/… + `PathAwareSignal`;
|
|
16
|
+
* - **value-операции** (реактивные правила) — `computeFrom`/`copyFrom`/`watchField`/`transformValue`/
|
|
17
|
+
* `resetWhen`/`syncFields`/`revalidateWhen`;
|
|
18
|
+
* - **producer-owned флаг** — `markDerived`/`isDerived`/`unmarkDerived`;
|
|
19
|
+
* - **утилиты субстрата** — `runOutsideEffect`/`safeCallback`/`safeDebouncedCallback`,
|
|
20
|
+
* `SubscriptionManager`.
|
|
21
|
+
*
|
|
22
|
+
* @group State
|
|
23
|
+
* @module state
|
|
24
|
+
*/
|
|
25
|
+
export { createModel } from './form-model';
|
|
26
|
+
export type { FormModel, ModelArray, ModelObject, ModelValue, ModelSignals, ModelApi, PathAwareSignal, } from './types';
|
|
27
|
+
export { computeFrom, copyFrom, watchField, transformValue, resetWhen, syncFields, revalidateWhen, } from './behaviors-value';
|
|
28
|
+
export type { BehaviorCleanup } from './behaviors-value';
|
|
29
|
+
export { markDerived, isDerived, unmarkDerived } from './derived-registry';
|
|
30
|
+
export { runOutsideEffect, safeCallback, safeDebouncedCallback } from './safe-effect';
|
|
31
|
+
export { SubscriptionManager } from './subscription-manager';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Утилиты для безопасной работы с сигналами в effect контексте
|
|
3
|
+
*
|
|
4
|
+
* Эти утилиты решают проблему "Cycle detected" в @preact/signals-core,
|
|
5
|
+
* которая возникает при модификации сигналов внутри effect.
|
|
6
|
+
*
|
|
7
|
+
* Отложенная запись ({@link runOutsideEffect}) откладывается на микротаск и при этом:
|
|
8
|
+
* - маршрутизирует синхронные throws и async-rejection dev-логгером (logDeferError) вместо того,
|
|
9
|
+
* чтобы они всплывали неперехваченными в точке микротаска / тонули как unhandledRejection;
|
|
10
|
+
* - возвращает отменитель (canceller) для liveness — вызывающий может отменить ещё не выполненную
|
|
11
|
+
* запись при dispose, чтобы она не сработала против снесённого узла/формы.
|
|
12
|
+
*
|
|
13
|
+
* NB: намеренно НЕ оборачиваем записи в `batch()`. Реципрокные guard'ы слоя данных (например
|
|
14
|
+
* `syncFields` в модуле state/behaviors-value) держат флаг «идёт синхронизация» и сбрасывают его
|
|
15
|
+
* в `finally` ПОСЛЕ записи, полагаясь на то, что встречный эффект флашится СИНХРОННО во время записи
|
|
16
|
+
* (вне batch). `batch()` отложил бы встречный флаш за пределы сброса флага и сломал бы эту защиту
|
|
17
|
+
* (сходимость осталась бы за peek-guard'ом, но появились бы лишние круги). Коалесинг записей в один
|
|
18
|
+
* batch — законная оптимизация, но она требует, чтобы эти guard'ы стали batch-aware, поэтому делается
|
|
19
|
+
* не здесь. См. также `aggregateInto`, где коалесинг реализован на уровне самого оператора.
|
|
20
|
+
*
|
|
21
|
+
* @group Utils
|
|
22
|
+
* @module utils/safe-effect
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Создает callback, который выполняется вне контекста effect
|
|
26
|
+
*
|
|
27
|
+
* Откладывает вызов через {@link runOutsideEffect} — то есть получает маршрутизацию ошибок и
|
|
28
|
+
* обработку async-rejection «бесплатно».
|
|
29
|
+
*
|
|
30
|
+
* @param callback - Функция для выполнения
|
|
31
|
+
* @returns Обёрнутая функция, безопасная для вызова внутри effect
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* // Вместо:
|
|
36
|
+
* effect(() => {
|
|
37
|
+
* queueMicrotask(() => {
|
|
38
|
+
* callback(value, context);
|
|
39
|
+
* });
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Используем:
|
|
43
|
+
* effect(() => {
|
|
44
|
+
* safeCallback(callback)(value, context);
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function safeCallback<TArgs extends unknown[]>(callback: (...args: TArgs) => void | Promise<void>): (...args: TArgs) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Выполняет функцию вне контекста effect (отложенная запись на микротаск).
|
|
51
|
+
*
|
|
52
|
+
* Сбои fn (синхронный throw и async-rejection) маршрутизируются dev-логгером (logDeferError), а не
|
|
53
|
+
* всплывают неперехваченными. Возвращает отменитель: вызов до срабатывания микротаска отменяет запись
|
|
54
|
+
* (liveness-охрана — не писать против снесённого узла при dispose в том же тике).
|
|
55
|
+
*
|
|
56
|
+
* @param fn - Функция для выполнения
|
|
57
|
+
* @returns Отменитель ещё не выполненной записи (no-op, если запись уже выполнена)
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* effect(() => {
|
|
62
|
+
* const value = signal.value;
|
|
63
|
+
* const cancel = runOutsideEffect(() => {
|
|
64
|
+
* otherSignal.value = transform(value);
|
|
65
|
+
* });
|
|
66
|
+
* onDispose(cancel); // отменить ожидающую запись, если узел снесут в этом же тике
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function runOutsideEffect(fn: () => void | Promise<void>): () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Создает версию callback с поддержкой debounce, безопасную для effect
|
|
73
|
+
*
|
|
74
|
+
* `withDebounce` уже откладывает вызов (таймер) — этого достаточно для выхода из effect-контекста,
|
|
75
|
+
* поэтому дополнительного `queueMicrotask` нет (устранён двойной defer). Сбои callback (в т.ч.
|
|
76
|
+
* async-rejection) маршрутизируются dev-логгером (logDeferError).
|
|
77
|
+
*
|
|
78
|
+
* @param callback - Функция для выполнения
|
|
79
|
+
* @param withDebounce - Функция debounce обёртки из BehaviorRegistry
|
|
80
|
+
* @returns Обёрнутая функция
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* return effect(() => {
|
|
85
|
+
* const value = node.value.value;
|
|
86
|
+
* safeDebouncedCallback(
|
|
87
|
+
* () => callback(value, context),
|
|
88
|
+
* withDebounce
|
|
89
|
+
* )();
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function safeDebouncedCallback(callback: () => void | Promise<void>, withDebounce: (fn: () => void) => void): () => void;
|
|
@@ -26,15 +26,17 @@ type ModelArrayItem<U> = NonNullable<U> extends ReadonlyArray<infer E> ? ModelAr
|
|
|
26
26
|
* Значение поля в value-доступе модели:
|
|
27
27
|
* - массив → {@link ModelArray}
|
|
28
28
|
* - спец-объект (Date/File/Blob) → как есть
|
|
29
|
-
* - объект →
|
|
29
|
+
* - объект → под-модель {@link FormModel} (value-доступ + `.$`-сигналы + API get/set/patch/…);
|
|
30
|
+
* промоутится рантаймом (`makeFormModel`); сигналы идентичны `model.$.<path>`
|
|
30
31
|
* - примитив → значение
|
|
31
32
|
*
|
|
32
33
|
* @group Model
|
|
33
34
|
*/
|
|
34
|
-
export type ModelValue<V> = NonNullable<V> extends ReadonlyArray<infer U> ? ModelArray<U> : NonNullable<V> extends Opaque ? V : NonNullable<V> extends object ?
|
|
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;
|
|
35
36
|
/**
|
|
36
|
-
* value
|
|
37
|
-
* внутри `effect`/`computed`, запись — присваиванием).
|
|
37
|
+
* Карта value-полей объекта (value-половина {@link FormModel}): поля доступны как обычные свойства
|
|
38
|
+
* (чтение реактивно внутри `effect`/`computed`, запись — присваиванием). Вложенные объекты-поля
|
|
39
|
+
* резолвятся в под-модели {@link FormModel} (см. {@link ModelValue}), массивы — в {@link ModelArray}.
|
|
38
40
|
*
|
|
39
41
|
* @group Model
|
|
40
42
|
*/
|
|
@@ -99,7 +101,7 @@ type ModelSignalNode<V> = NonNullable<V> extends ReadonlyArray<infer U> ? {
|
|
|
99
101
|
readonly [index: number]: ModelSignalNode<U>;
|
|
100
102
|
} : NonNullable<V> extends Opaque ? PathAwareSignal<V> : NonNullable<V> extends object ? ModelSignals<NonNullable<V>> : PathAwareSignal<V>;
|
|
101
103
|
/**
|
|
102
|
-
* API уровня модели (доступно на
|
|
104
|
+
* API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).
|
|
103
105
|
*
|
|
104
106
|
* ⚠️ Имена методов (`$`/`get`/`set`/`patch`/`isDirty`/`reset`/`signalAt`/`captureInitial`)
|
|
105
107
|
* зарезервированы: одноимённое поле формы их затеняет (редкий краевой случай).
|
|
@@ -112,12 +114,11 @@ export interface ModelApi<T> {
|
|
|
112
114
|
/** Снимок значений (без подписки) — для submit. */
|
|
113
115
|
get(): T;
|
|
114
116
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* `patch({ ...defaults, ...dto })` явно. Не меняет initial-снимок.
|
|
117
|
+
* Полная установка значений: принимает объект целиком (все ключи `T`) и записывает их в модель.
|
|
118
|
+
* Производными полями (цели `compute`) владеет compute — их значения из payload игнорируются.
|
|
119
|
+
* Не меняет initial-снимок. Для частичного обновления (только переданные ключи) — {@link ModelApi.patch}.
|
|
119
120
|
*/
|
|
120
|
-
set(value:
|
|
121
|
+
set(value: T): void;
|
|
121
122
|
/**
|
|
122
123
|
* Частичное слияние значений (load/patch с сервера): обновляет только переданные ключи,
|
|
123
124
|
* отсутствующие ключи НЕ трогаются. Не меняет initial-снимок.
|
|
@@ -133,7 +134,9 @@ export interface ModelApi<T> {
|
|
|
133
134
|
signalAt(path: string): PathAwareSignal<unknown> | undefined;
|
|
134
135
|
}
|
|
135
136
|
/**
|
|
136
|
-
* FormModel —
|
|
137
|
+
* FormModel — под-модель объекта `T`: value-доступ ({@link ModelObject}) + `.$`-сигналы + {@link ModelApi}
|
|
138
|
+
* (get/set/patch/isDirty/reset/signalAt). Вложенные объекты-группы модели — тоже {@link FormModel}
|
|
139
|
+
* (доступны как `model.<group>`), поэтому `model.<group>.$.<field>` эквивалентно `model.$.<group>.<field>`.
|
|
137
140
|
*
|
|
138
141
|
* @group Model
|
|
139
142
|
*/
|
package/dist/state.d.ts
ADDED
package/dist/state.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { S as s, c as r } from "./form-model-C8Fi83k4.js";
|
|
2
|
+
import { c as o, a as t, i, m as d, r as l, b as m, d as n, e as f, f as u, s as b, t as p, u as k, w as v } from "./behaviors-value-lCpqicfa.js";
|
|
3
|
+
export {
|
|
4
|
+
s as SubscriptionManager,
|
|
5
|
+
o as computeFrom,
|
|
6
|
+
t as copyFrom,
|
|
7
|
+
r as createModel,
|
|
8
|
+
i as isDerived,
|
|
9
|
+
d as markDerived,
|
|
10
|
+
l as resetWhen,
|
|
11
|
+
m as revalidateWhen,
|
|
12
|
+
n as runOutsideEffect,
|
|
13
|
+
f as safeCallback,
|
|
14
|
+
u as safeDebouncedCallback,
|
|
15
|
+
b as syncFields,
|
|
16
|
+
p as transformValue,
|
|
17
|
+
k as unmarkDerived,
|
|
18
|
+
v as watchField
|
|
19
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/email'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/future-date'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/integer'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/is-date'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/is-number'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/max-age'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/max-date'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/max-length'
|
|
2
2
|
export {}
|
package/dist/validators/max.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/max'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/min-age'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/min-date'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/min-length'
|
|
2
2
|
export {}
|
package/dist/validators/min.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/min'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/multiple-of'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/non-negative'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/non-zero'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/past-date'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/pattern'
|
|
2
2
|
export {}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
1
|
+
function s(e, r) {
|
|
2
|
+
const t = new RegExp(e.source, e.flags);
|
|
3
|
+
return (n) => n ? (t.lastIndex = 0, t.test(n) ? null : {
|
|
3
4
|
code: "pattern",
|
|
4
|
-
message:
|
|
5
|
-
params: { pattern:
|
|
6
|
-
} : null;
|
|
5
|
+
message: r?.message ?? "",
|
|
6
|
+
params: { pattern: e.source, ...r?.params }
|
|
7
|
+
}) : null;
|
|
7
8
|
}
|
|
8
9
|
export {
|
|
9
|
-
|
|
10
|
+
s as pattern
|
|
10
11
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/phone'
|
|
2
2
|
export {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/required'
|
|
2
2
|
export {}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
function
|
|
2
|
-
return (
|
|
1
|
+
function n(e) {
|
|
2
|
+
return (r) => r == null || r === "" || Array.isArray(r) && r.length === 0 || typeof r == "boolean" && r !== !0 ? {
|
|
3
3
|
code: "required",
|
|
4
|
-
message:
|
|
5
|
-
params:
|
|
6
|
-
} : typeof e == "boolean" && e !== !0 ? {
|
|
7
|
-
code: "required",
|
|
8
|
-
message: r?.message ?? "invalid",
|
|
9
|
-
params: r?.params
|
|
4
|
+
message: e?.message ?? "",
|
|
5
|
+
params: e?.params
|
|
10
6
|
} : null;
|
|
11
7
|
}
|
|
12
8
|
export {
|
|
13
|
-
|
|
9
|
+
n as required
|
|
14
10
|
};
|
package/dist/validators/url.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from '../
|
|
1
|
+
export * from '../form/validation/validators/url'
|
|
2
2
|
export {}
|
package/dist/validators.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
export
|
|
1
|
+
export * from './form/validators'
|
|
2
|
+
export {}
|
|
3
|
+
import _default from './form/validators'
|
|
4
|
+
export default _default
|
|
5
|
+
export * from './form/validators'
|
|
6
|
+
export {}
|