@reformer/core 10.1.0 → 10.2.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.
@@ -0,0 +1,55 @@
1
+ import { ReadonlySignal } from '@preact/signals-core';
2
+ import { FormModel } from '../index';
3
+ import { ValidationSchema } from './validation-schema';
4
+ /**
5
+ * Когда запускается schema-валидация:
6
+ * - `submit` (по умолчанию) — только явным вызовом `validate()` (на отправке);
7
+ * - `blur` — при потере фокуса поля (смена `touched` любого листа);
8
+ * - `change` — на каждый ввод (с опц. `debounce`);
9
+ * - `afterFirstSubmit` — тихо до первого `validate()`, затем live (см. `liveAfterSubmit`).
10
+ */
11
+ export type ValidationStrategyKind = 'submit' | 'blur' | 'change' | 'afterFirstSubmit';
12
+ export interface ValidationStrategyOptions {
13
+ /** Стратегия запуска. Default `'submit'`. */
14
+ strategy?: ValidationStrategyKind;
15
+ /** Debounce (мс) для live-фаз (`change` и live-часть `afterFirstSubmit`). Default `0`. */
16
+ debounce?: number;
17
+ /** Режим live-фазы для `afterFirstSubmit`. Default `'change'`. */
18
+ liveAfterSubmit?: 'change' | 'blur';
19
+ }
20
+ export interface FormValidationController {
21
+ /**
22
+ * Полный прогон схемы с раскрытием ошибок (`touch: true`) — для submit. Также переводит
23
+ * `afterFirstSubmit` в live-фазу. Возвращает `false`, если есть блокирующие ошибки.
24
+ */
25
+ validate(): Promise<boolean>;
26
+ /** Армировать реактивные подписки стратегии. Идемпотентно. Возвращает `dispose`. НЕ звать при SSR. */
27
+ start(): () => void;
28
+ /** Снять подписки/таймеры. Идемпотентно. */
29
+ dispose(): void;
30
+ /** Идёт ли прогон (submit или live) — снапшот. */
31
+ readonly isValidating: boolean;
32
+ /** Реактивный сигнал состояния прогона (для тонкой подписки в UI). */
33
+ readonly validating: ReadonlySignal<boolean>;
34
+ }
35
+ /**
36
+ * Собрать контроллер валидации формы с выбранной стратегией запуска. Переиспользует
37
+ * {@link validateModel} как единственный движок прогона.
38
+ *
39
+ * Фабрика ЧИСТАЯ до `start()` (никаких подписок) — безопасна для SSR/headless. Реактивные триггеры
40
+ * арминуются только в `start()` (в React — из `useEffect`).
41
+ *
42
+ * @typeParam T - Форма данных модели.
43
+ * @param model - Модель данных.
44
+ * @param schema - Схема валидации. **Стабильная ссылка** (иначе `validateModel` не отменит устаревший прогон).
45
+ * @param options - {@link ValidationStrategyOptions}.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const ctrl = createFormValidation(model, schema, { strategy: 'afterFirstSubmit', debounce: 300 });
50
+ * const dispose = ctrl.start(); // на клиенте
51
+ * const ok = await ctrl.validate(); // submit → раскрыть все ошибки
52
+ * dispose();
53
+ * ```
54
+ */
55
+ export declare function createFormValidation<T>(model: FormModel<T>, schema: ValidationSchema<T>, options?: ValidationStrategyOptions): FormValidationController;
@@ -0,0 +1,286 @@
1
+ import { signal as k } from "@preact/signals-core";
2
+ import { i as b } from "./derived-registry-CluZCQ7U.js";
3
+ const h = (e) => !(e === null || typeof e != "object" || Array.isArray(e) || e instanceof Date || typeof Blob < "u" && e instanceof Blob || typeof File < "u" && e instanceof File), a = (e, i) => e === "" ? String(i) : `${e}.${i}`, p = (e) => /^\d+$/.test(e), o = (e) => {
4
+ if (Array.isArray(e)) return e.map(o);
5
+ if (h(e)) {
6
+ const i = {};
7
+ for (const t of Object.keys(e)) i[t] = o(e[t]);
8
+ return i;
9
+ }
10
+ return e;
11
+ }, u = (e, i) => {
12
+ if (e === i) return !0;
13
+ if (Array.isArray(e) && Array.isArray(i))
14
+ return e.length !== i.length ? !1 : e.every((t, r) => u(t, i[r]));
15
+ if (h(e) && h(i)) {
16
+ const t = Object.keys(e), r = Object.keys(i);
17
+ return t.length !== r.length ? !1 : t.every((n) => u(e[n], i[n]));
18
+ }
19
+ return !1;
20
+ };
21
+ class x {
22
+ constructor(i, t) {
23
+ this.path = t;
24
+ const r = k(i);
25
+ r.__path = t, this.signal = r, this.initial = o(i);
26
+ }
27
+ kind = "leaf";
28
+ signal;
29
+ initial;
30
+ rebase(i) {
31
+ this.path = i, this.signal.__path = i;
32
+ }
33
+ /** Реактивное чтение (внутри effect/computed создаёт зависимость). */
34
+ read() {
35
+ return this.signal.value;
36
+ }
37
+ /** Нереактивный снимок. */
38
+ peek() {
39
+ return this.signal.peek();
40
+ }
41
+ set(i) {
42
+ this.signal.value = i;
43
+ }
44
+ resetToInitial() {
45
+ this.signal.value = o(this.initial);
46
+ }
47
+ captureInitial() {
48
+ this.initial = o(this.signal.peek());
49
+ }
50
+ dirty() {
51
+ return !u(this.signal.peek(), this.initial);
52
+ }
53
+ }
54
+ class A {
55
+ constructor(i, t) {
56
+ this.path = t;
57
+ for (const r of Object.keys(i))
58
+ this.children.set(r, c(i[r], a(t, r)));
59
+ }
60
+ kind = "group";
61
+ children = /* @__PURE__ */ new Map();
62
+ rebase(i) {
63
+ this.path = i;
64
+ for (const [t, r] of this.children) r.rebase(a(i, t));
65
+ }
66
+ peek() {
67
+ const i = {};
68
+ for (const [t, r] of this.children) i[t] = r.peek();
69
+ return i;
70
+ }
71
+ set(i) {
72
+ if (i == null || typeof i != "object") return;
73
+ const t = i;
74
+ for (const [r, n] of this.children)
75
+ r in t && (n.kind === "leaf" && b(n.signal) || n.set(t[r]));
76
+ }
77
+ resetToInitial() {
78
+ for (const i of this.children.values()) i.resetToInitial();
79
+ }
80
+ captureInitial() {
81
+ for (const i of this.children.values()) i.captureInitial();
82
+ }
83
+ dirty() {
84
+ for (const i of this.children.values()) if (i.dirty()) return !0;
85
+ return !1;
86
+ }
87
+ }
88
+ class I {
89
+ constructor(i, t) {
90
+ this.path = t, this.items = k(i.map((r, n) => c(r, a(t, n)))), this.initial = o(i);
91
+ }
92
+ kind = "array";
93
+ items;
94
+ initial;
95
+ rebase(i) {
96
+ this.path = i, this.items.peek().forEach((t, r) => t.rebase(a(i, r)));
97
+ }
98
+ reindex() {
99
+ this.items.peek().forEach((i, t) => i.rebase(a(this.path, t)));
100
+ }
101
+ push(i) {
102
+ const t = this.items.peek();
103
+ this.items.value = [...t, c(i, a(this.path, t.length))];
104
+ }
105
+ insertAt(i, t) {
106
+ const r = [...this.items.peek()];
107
+ r.splice(i, 0, c(t, a(this.path, i))), this.items.value = r, this.reindex();
108
+ }
109
+ removeAt(i) {
110
+ const t = [...this.items.peek()];
111
+ t.splice(i, 1), this.items.value = t, this.reindex();
112
+ }
113
+ move(i, t) {
114
+ const r = [...this.items.peek()], [n] = r.splice(i, 1);
115
+ n && r.splice(t, 0, n), this.items.value = r, this.reindex();
116
+ }
117
+ swap(i, t) {
118
+ const r = [...this.items.peek()];
119
+ i < 0 || t < 0 || i >= r.length || t >= r.length || i === t || ([r[i], r[t]] = [r[t], r[i]], this.items.value = r, this.reindex());
120
+ }
121
+ clear() {
122
+ this.items.value = [];
123
+ }
124
+ peek() {
125
+ return this.items.peek().map((i) => i.peek());
126
+ }
127
+ set(i) {
128
+ const t = Array.isArray(i) ? i : [];
129
+ this.items.value = t.map((r, n) => c(r, a(this.path, n)));
130
+ }
131
+ resetToInitial() {
132
+ this.set(o(this.initial));
133
+ }
134
+ captureInitial() {
135
+ this.initial = o(this.peek());
136
+ }
137
+ dirty() {
138
+ return !u(this.peek(), this.initial);
139
+ }
140
+ }
141
+ function c(e, i) {
142
+ return Array.isArray(e) ? new I(e, i) : h(e) ? new A(e, i) : new x(e, i);
143
+ }
144
+ function l(e) {
145
+ if (e)
146
+ return e.kind === "group" ? _(e) : e.kind === "array" ? P(e) : e.read();
147
+ }
148
+ function P(e) {
149
+ const i = {
150
+ get length() {
151
+ return e.items.value.length;
152
+ },
153
+ push: (t) => e.push(t),
154
+ insertAt: (t, r) => e.insertAt(t, r),
155
+ removeAt: (t) => e.removeAt(t),
156
+ move: (t, r) => e.move(t, r),
157
+ swap: (t, r) => e.swap(t, r),
158
+ clear: () => e.clear(),
159
+ at: (t) => l(e.items.value[t]),
160
+ map: (t) => e.items.value.map((r, n) => t(l(r), n)),
161
+ forEach: (t) => e.items.value.forEach((r, n) => t(l(r), n)),
162
+ toArray: () => e.peek(),
163
+ [Symbol.iterator]: function* () {
164
+ const t = e.items.value;
165
+ for (let r = 0; r < t.length; r++) yield l(t[r]);
166
+ }
167
+ };
168
+ return new Proxy(i, {
169
+ get: (t, r, n) => r === "__path" ? e.path : typeof r == "string" && p(r) ? l(e.items.value[Number(r)]) : Reflect.get(t, r, n),
170
+ has: (t, r) => typeof r == "string" && p(r) ? Number(r) < e.items.value.length : Reflect.has(t, r)
171
+ });
172
+ }
173
+ function d(e) {
174
+ if (e.kind === "leaf") return e.signal;
175
+ if (e.kind === "group")
176
+ return new Proxy(
177
+ {},
178
+ {
179
+ get: (t, r) => {
180
+ if (r === "__path") return e.path;
181
+ if (typeof r != "string") return;
182
+ const n = e.children.get(r);
183
+ return n ? d(n) : void 0;
184
+ },
185
+ has: (t, r) => typeof r == "string" && e.children.has(r),
186
+ ownKeys: () => [...e.children.keys()],
187
+ getOwnPropertyDescriptor: (t, r) => typeof r == "string" && e.children.has(r) ? { enumerable: !0, configurable: !0 } : void 0
188
+ }
189
+ );
190
+ const i = e;
191
+ return new Proxy(
192
+ {
193
+ get length() {
194
+ return i.items.value.length;
195
+ }
196
+ },
197
+ {
198
+ get: (t, r, n) => {
199
+ if (r === "__path") return i.path;
200
+ if (typeof r == "string" && p(r)) {
201
+ const s = i.items.value[Number(r)];
202
+ return s ? d(s) : void 0;
203
+ }
204
+ return Reflect.get(t, r, n);
205
+ }
206
+ }
207
+ );
208
+ }
209
+ function j(e, i) {
210
+ if (!i) return;
211
+ let t = e;
212
+ for (const r of i.split(".")) {
213
+ if (!t) return;
214
+ if (t.kind === "group") t = t.children.get(r);
215
+ else if (t.kind === "array") t = t.items.peek()[Number(r)];
216
+ else return;
217
+ }
218
+ return t && t.kind === "leaf" ? t.signal : void 0;
219
+ }
220
+ const y = /* @__PURE__ */ new Set([
221
+ "$",
222
+ "get",
223
+ "set",
224
+ "patch",
225
+ "isDirty",
226
+ "reset",
227
+ "captureInitial",
228
+ "signalAt"
229
+ ]), v = /* @__PURE__ */ new WeakMap(), w = /* @__PURE__ */ new WeakMap();
230
+ function _(e) {
231
+ const i = v.get(e);
232
+ if (i) return i;
233
+ const t = {
234
+ $: d(e),
235
+ get: () => e.peek(),
236
+ set: (n) => e.set(n),
237
+ patch: (n) => e.set(n),
238
+ isDirty: () => e.dirty(),
239
+ reset: () => e.resetToInitial(),
240
+ captureInitial: () => e.captureInitial(),
241
+ signalAt: (n) => j(e, n)
242
+ }, r = new Proxy(
243
+ {},
244
+ {
245
+ get: (n, s) => {
246
+ if (s === "__path") return e.path;
247
+ if (typeof s != "string") return;
248
+ const f = e.children.get(s);
249
+ if (f) return l(f);
250
+ if (y.has(s)) return t[s];
251
+ },
252
+ set: (n, s, f) => {
253
+ if (typeof s != "string") return !1;
254
+ const g = e.children.get(s);
255
+ return g ? (g.set(f), !0) : !1;
256
+ },
257
+ has: (n, s) => typeof s == "string" && (e.children.has(s) || y.has(s)),
258
+ ownKeys: () => [...e.children.keys()],
259
+ getOwnPropertyDescriptor: (n, s) => typeof s == "string" && e.children.has(s) ? { enumerable: !0, configurable: !0 } : void 0
260
+ }
261
+ );
262
+ return v.set(e, r), w.set(r, e), r;
263
+ }
264
+ function m(e, i) {
265
+ if (e.kind === "leaf") {
266
+ i(e.signal);
267
+ return;
268
+ }
269
+ if (e.kind === "group") {
270
+ for (const t of e.children.values()) m(t, i);
271
+ return;
272
+ }
273
+ for (const t of e.items.value) m(t, i);
274
+ }
275
+ function D(e, i) {
276
+ const t = w.get(e);
277
+ t && m(t, i);
278
+ }
279
+ function O(e) {
280
+ const i = new A(e, "");
281
+ return _(i);
282
+ }
283
+ export {
284
+ O as c,
285
+ D as e
286
+ };