attaform 0.16.3 → 0.17.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 +4 -2
- package/dist/chunks/devtools.cjs +19 -12
- package/dist/chunks/devtools.cjs.map +1 -1
- package/dist/chunks/devtools.mjs +19 -12
- package/dist/chunks/devtools.mjs.map +1 -1
- package/dist/chunks/indexeddb.cjs +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/session-storage.cjs +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/index.cjs +27 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -8
- package/dist/index.d.mts +80 -8
- package/dist/index.d.ts +80 -8
- package/dist/index.mjs +28 -9
- package/dist/index.mjs.map +1 -1
- package/dist/nuxt.d.cts +1 -1
- package/dist/nuxt.d.mts +1 -1
- package/dist/nuxt.d.ts +1 -1
- package/dist/runtime/plugins/attaform.cjs +3 -3
- package/dist/runtime/plugins/attaform.cjs.map +1 -1
- package/dist/runtime/plugins/attaform.mjs +3 -3
- package/dist/runtime/plugins/attaform.mjs.map +1 -1
- package/dist/shared/{attaform.KrNw10aW.cjs → attaform.0Wg7UEeX.cjs} +60 -20
- package/dist/shared/attaform.0Wg7UEeX.cjs.map +1 -0
- package/dist/shared/attaform.AOgGyRoI.d.cts +65 -0
- package/dist/shared/{attaform.lFNwBcA3.d.ts → attaform.B0zue7zt.d.ts} +1 -1
- package/dist/shared/{attaform.c_NzdRyc.cjs → attaform.BBM2muQ9.cjs} +7 -3
- package/dist/shared/attaform.BBM2muQ9.cjs.map +1 -0
- package/dist/shared/{attaform.C9Ph2SMx.cjs → attaform.BFumZXY2.cjs} +1514 -391
- package/dist/shared/attaform.BFumZXY2.cjs.map +1 -0
- package/dist/shared/attaform.BQ-iGGWd.d.mts +65 -0
- package/dist/shared/{attaform.DILbdvfo.mjs → attaform.BT55rDNN.mjs} +1514 -393
- package/dist/shared/attaform.BT55rDNN.mjs.map +1 -0
- package/dist/shared/{attaform._EqYNPYF.d.mts → attaform.BYbsV2Wv.d.cts} +738 -138
- package/dist/shared/{attaform._EqYNPYF.d.ts → attaform.BYbsV2Wv.d.mts} +738 -138
- package/dist/shared/{attaform._EqYNPYF.d.cts → attaform.BYbsV2Wv.d.ts} +738 -138
- package/dist/shared/{attaform.DGuGGNg9.cjs → attaform.C6_zOf8x.cjs} +232 -113
- package/dist/shared/attaform.C6_zOf8x.cjs.map +1 -0
- package/dist/shared/{attaform.CJttVxRj.cjs → attaform.C8LVFVVe.cjs} +2 -2
- package/dist/shared/{attaform.CJttVxRj.cjs.map → attaform.C8LVFVVe.cjs.map} +1 -1
- package/dist/shared/{attaform.BfMxsfmE.mjs → attaform.CIEQgJnM.mjs} +143 -78
- package/dist/shared/attaform.CIEQgJnM.mjs.map +1 -0
- package/dist/shared/attaform.CX9v2M8k.d.ts +65 -0
- package/dist/shared/{attaform.XYOMTvuO.mjs → attaform.Cj0pCNVn.mjs} +232 -113
- package/dist/shared/attaform.Cj0pCNVn.mjs.map +1 -0
- package/dist/shared/{attaform.DLnKT7wk.d.cts → attaform.ClfCi1i2.d.mts} +1 -1
- package/dist/shared/{attaform.CFA6y0KF.mjs → attaform.D6Q5ZP8L.mjs} +60 -20
- package/dist/shared/attaform.D6Q5ZP8L.mjs.map +1 -0
- package/dist/shared/{attaform.Bls_kFR6.d.mts → attaform.D7lomopc.d.cts} +1 -1
- package/dist/shared/{attaform.rIRYSUI1.cjs → attaform.Dee2rU1P.cjs} +145 -77
- package/dist/shared/attaform.Dee2rU1P.cjs.map +1 -0
- package/dist/shared/{attaform.CINUMjPq.mjs → attaform.Vo-Kft0t.mjs} +2 -2
- package/dist/shared/{attaform.CINUMjPq.mjs.map → attaform.Vo-Kft0t.mjs.map} +1 -1
- package/dist/shared/{attaform.jrxE_xZw.mjs → attaform.h1sq3BFu.mjs} +6 -4
- package/dist/shared/attaform.h1sq3BFu.mjs.map +1 -0
- package/dist/zod-v3.cjs +3 -3
- package/dist/zod-v3.d.cts +5 -5
- package/dist/zod-v3.d.mts +5 -5
- package/dist/zod-v3.d.ts +5 -5
- package/dist/zod-v3.mjs +3 -3
- package/dist/zod-v4.cjs +3 -3
- package/dist/zod-v4.d.cts +16 -42
- package/dist/zod-v4.d.mts +16 -42
- package/dist/zod-v4.d.ts +16 -42
- package/dist/zod-v4.mjs +3 -3
- package/dist/zod.cjs +4 -4
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +6 -5
- package/dist/zod.d.mts +6 -5
- package/dist/zod.d.ts +6 -5
- package/dist/zod.mjs +5 -5
- package/dist/zod.mjs.map +1 -1
- package/package.json +3 -8
- package/dist/shared/attaform.BfMxsfmE.mjs.map +0 -1
- package/dist/shared/attaform.C9Ph2SMx.cjs.map +0 -1
- package/dist/shared/attaform.CFA6y0KF.mjs.map +0 -1
- package/dist/shared/attaform.DGuGGNg9.cjs.map +0 -1
- package/dist/shared/attaform.DILbdvfo.mjs.map +0 -1
- package/dist/shared/attaform.KrNw10aW.cjs.map +0 -1
- package/dist/shared/attaform.XYOMTvuO.mjs.map +0 -1
- package/dist/shared/attaform.c_NzdRyc.cjs.map +0 -1
- package/dist/shared/attaform.jrxE_xZw.mjs.map +0 -1
- package/dist/shared/attaform.rIRYSUI1.cjs.map +0 -1
|
@@ -1,173 +1,6 @@
|
|
|
1
|
-
import { computed, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, readonly, reactive, watch, markRaw, shallowRef, getCurrentInstance, provide, useId,
|
|
2
|
-
import { s as
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
function isDescendable(value) {
|
|
6
|
-
if (value === null || typeof value !== "object") return false;
|
|
7
|
-
if (Array.isArray(value)) return true;
|
|
8
|
-
const proto = Object.getPrototypeOf(value);
|
|
9
|
-
return proto === null || proto === Object.prototype;
|
|
10
|
-
}
|
|
11
|
-
function appendSegment(prefix, segment) {
|
|
12
|
-
const next = new Array(prefix.length + 1);
|
|
13
|
-
for (let i = 0; i < prefix.length; i++) {
|
|
14
|
-
const s = prefix[i];
|
|
15
|
-
next[i] = s;
|
|
16
|
-
}
|
|
17
|
-
next[prefix.length] = segment;
|
|
18
|
-
return next;
|
|
19
|
-
}
|
|
20
|
-
function diffAndApply(oldValue, newValue, prefix, visit) {
|
|
21
|
-
if (Object.is(oldValue, newValue)) return;
|
|
22
|
-
const oldIsDescendable = isDescendable(oldValue);
|
|
23
|
-
const newIsDescendable = isDescendable(newValue);
|
|
24
|
-
if (oldValue === void 0 && newIsDescendable) {
|
|
25
|
-
if (Array.isArray(newValue)) {
|
|
26
|
-
for (let i = 0; i < newValue.length; i++) {
|
|
27
|
-
diffAndApply(void 0, newValue[i], appendSegment(prefix, i), visit);
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
const rec = newValue;
|
|
31
|
-
for (const k of Object.keys(rec)) {
|
|
32
|
-
diffAndApply(void 0, rec[k], appendSegment(prefix, k), visit);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (oldIsDescendable && newValue === void 0) {
|
|
38
|
-
if (Array.isArray(oldValue)) {
|
|
39
|
-
for (let i = 0; i < oldValue.length; i++) {
|
|
40
|
-
diffAndApply(oldValue[i], void 0, appendSegment(prefix, i), visit);
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
const rec = oldValue;
|
|
44
|
-
for (const k of Object.keys(rec)) {
|
|
45
|
-
diffAndApply(rec[k], void 0, appendSegment(prefix, k), visit);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (oldIsDescendable && newIsDescendable) {
|
|
51
|
-
const oldIsArray = Array.isArray(oldValue);
|
|
52
|
-
const newIsArray = Array.isArray(newValue);
|
|
53
|
-
if (oldIsArray && newIsArray) {
|
|
54
|
-
const oldArr = oldValue;
|
|
55
|
-
const newArr = newValue;
|
|
56
|
-
const max = Math.max(oldArr.length, newArr.length);
|
|
57
|
-
for (let i = 0; i < max; i++) {
|
|
58
|
-
diffAndApply(oldArr[i], newArr[i], appendSegment(prefix, i), visit);
|
|
59
|
-
}
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (!oldIsArray && !newIsArray) {
|
|
63
|
-
const oldRec = oldValue;
|
|
64
|
-
const newRec = newValue;
|
|
65
|
-
const seen = /* @__PURE__ */ new Set();
|
|
66
|
-
for (const k of Object.keys(oldRec)) {
|
|
67
|
-
seen.add(k);
|
|
68
|
-
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
69
|
-
}
|
|
70
|
-
for (const k of Object.keys(newRec)) {
|
|
71
|
-
if (seen.has(k)) continue;
|
|
72
|
-
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
73
|
-
}
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (oldIsDescendable && !newIsDescendable) {
|
|
80
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (!oldIsDescendable && newIsDescendable) {
|
|
84
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (oldValue === void 0) {
|
|
88
|
-
visit({ kind: "added", path: prefix, newValue });
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (newValue === void 0) {
|
|
92
|
-
visit({ kind: "removed", path: prefix, oldValue });
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
96
|
-
}
|
|
97
|
-
function applyChangedKeys(target, source) {
|
|
98
|
-
if (!isDescendable(target) || !isDescendable(source)) return false;
|
|
99
|
-
const targetIsArray = Array.isArray(target);
|
|
100
|
-
const sourceIsArray = Array.isArray(source);
|
|
101
|
-
if (targetIsArray !== sourceIsArray) return false;
|
|
102
|
-
const ROOT_SENTINEL = Symbol.for("attaform.applyChangedKeys.rootMismatch");
|
|
103
|
-
const changedFirstSegments = /* @__PURE__ */ new Set();
|
|
104
|
-
diffAndApply(target, source, [], (patch) => {
|
|
105
|
-
if (patch.path.length === 0) {
|
|
106
|
-
changedFirstSegments.add(ROOT_SENTINEL);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
changedFirstSegments.add(patch.path[0]);
|
|
110
|
-
});
|
|
111
|
-
if (changedFirstSegments.has(ROOT_SENTINEL)) return false;
|
|
112
|
-
if (targetIsArray) {
|
|
113
|
-
const t = target;
|
|
114
|
-
const s = source;
|
|
115
|
-
if (t.length > s.length) t.length = s.length;
|
|
116
|
-
for (const idx of changedFirstSegments) {
|
|
117
|
-
if (typeof idx === "symbol") continue;
|
|
118
|
-
const i = typeof idx === "number" ? idx : Number(idx);
|
|
119
|
-
t[i] = s[i];
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
const t = target;
|
|
123
|
-
const s = source;
|
|
124
|
-
const sourceKeys = new Set(Object.keys(s));
|
|
125
|
-
for (const k of Object.keys(t)) {
|
|
126
|
-
if (!sourceKeys.has(k)) delete t[k];
|
|
127
|
-
}
|
|
128
|
-
for (const k of changedFirstSegments) {
|
|
129
|
-
if (typeof k === "symbol") continue;
|
|
130
|
-
t[String(k)] = s[String(k)];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
function structuralSnapshot(value) {
|
|
136
|
-
if (!isDescendable(value)) return value;
|
|
137
|
-
if (Array.isArray(value)) {
|
|
138
|
-
const out2 = new Array(value.length);
|
|
139
|
-
for (let i = 0; i < value.length; i++) {
|
|
140
|
-
out2[i] = structuralSnapshot(value[i]);
|
|
141
|
-
}
|
|
142
|
-
return out2;
|
|
143
|
-
}
|
|
144
|
-
const src = value;
|
|
145
|
-
const out = {};
|
|
146
|
-
for (const k of Object.keys(src)) {
|
|
147
|
-
out[k] = structuralSnapshot(src[k]);
|
|
148
|
-
}
|
|
149
|
-
return out;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const EMPTY_RESOLVED_FIELD_META = Object.freeze({
|
|
153
|
-
label: "",
|
|
154
|
-
description: void 0,
|
|
155
|
-
placeholder: void 0,
|
|
156
|
-
meta: Object.freeze({})
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
function humanize(segment) {
|
|
160
|
-
if (typeof segment === "number") return "";
|
|
161
|
-
const str = String(segment);
|
|
162
|
-
if (str.length === 0) return "";
|
|
163
|
-
if (/^\d+$/.test(str)) return "";
|
|
164
|
-
const tokens = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().split(" ").filter((part) => part.length > 0);
|
|
165
|
-
if (tokens.length === 0) return "";
|
|
166
|
-
return tokens.map((part) => {
|
|
167
|
-
const head = part[0];
|
|
168
|
-
return head === void 0 ? part : head.toUpperCase() + part.slice(1).toLowerCase();
|
|
169
|
-
}).join(" ");
|
|
170
|
-
}
|
|
1
|
+
import { computed, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, readonly, reactive, watch, markRaw, toRaw, shallowRef, getCurrentInstance, provide, useId, inject } from 'vue';
|
|
2
|
+
import { _ as __DEV__, e as SubmitErrorHandlerError, A as AnonPersistError, l as captureUserCallSite, m as enforceSensitiveCheck, s as segmentMatchesSensitive, n as isSensitivePath, o as createPersistOptInRegistry, b as InvalidUseFormConfigError, p as ensureAttaformInstalled, j as useRegistry, q as kFormContext, r as kFormInstanceId, d as ReservedFormKeyError, t as createIsSensitivePath, w as createSegmentMatchesSensitive } from './attaform.CIEQgJnM.mjs';
|
|
3
|
+
import { c as canonicalizePath, s as segmentsForPathKey, i as isPathPrefix, F as FORM_ERRORS_PATH_KEY, R as ROOT_PATH, b as FORM_ERRORS_PATH } from './attaform.h1sq3BFu.mjs';
|
|
171
4
|
|
|
172
5
|
const NOT_FOUND = Symbol("NOT_FOUND");
|
|
173
6
|
function descendStep(value, segment) {
|
|
@@ -413,20 +246,236 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
413
246
|
return rec;
|
|
414
247
|
}
|
|
415
248
|
|
|
416
|
-
function
|
|
249
|
+
function isDescendable(value) {
|
|
250
|
+
if (value === null || typeof value !== "object") return false;
|
|
251
|
+
if (Array.isArray(value)) return true;
|
|
252
|
+
const proto = Object.getPrototypeOf(value);
|
|
253
|
+
return proto === null || proto === Object.prototype;
|
|
254
|
+
}
|
|
255
|
+
function appendSegment(prefix, segment) {
|
|
256
|
+
const next = new Array(prefix.length + 1);
|
|
257
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
258
|
+
const s = prefix[i];
|
|
259
|
+
next[i] = s;
|
|
260
|
+
}
|
|
261
|
+
next[prefix.length] = segment;
|
|
262
|
+
return next;
|
|
263
|
+
}
|
|
264
|
+
function diffAndApply(oldValue, newValue, prefix, visit) {
|
|
265
|
+
if (Object.is(oldValue, newValue)) return;
|
|
266
|
+
const oldIsDescendable = isDescendable(oldValue);
|
|
267
|
+
const newIsDescendable = isDescendable(newValue);
|
|
268
|
+
if (oldValue === void 0 && newIsDescendable) {
|
|
269
|
+
if (Array.isArray(newValue)) {
|
|
270
|
+
for (let i = 0; i < newValue.length; i++) {
|
|
271
|
+
diffAndApply(void 0, newValue[i], appendSegment(prefix, i), visit);
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
const rec = newValue;
|
|
275
|
+
for (const k of Object.keys(rec)) {
|
|
276
|
+
diffAndApply(void 0, rec[k], appendSegment(prefix, k), visit);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (oldIsDescendable && newValue === void 0) {
|
|
282
|
+
if (Array.isArray(oldValue)) {
|
|
283
|
+
for (let i = 0; i < oldValue.length; i++) {
|
|
284
|
+
diffAndApply(oldValue[i], void 0, appendSegment(prefix, i), visit);
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
const rec = oldValue;
|
|
288
|
+
for (const k of Object.keys(rec)) {
|
|
289
|
+
diffAndApply(rec[k], void 0, appendSegment(prefix, k), visit);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (oldIsDescendable && newIsDescendable) {
|
|
295
|
+
const oldIsArray = Array.isArray(oldValue);
|
|
296
|
+
const newIsArray = Array.isArray(newValue);
|
|
297
|
+
if (oldIsArray && newIsArray) {
|
|
298
|
+
const oldArr = oldValue;
|
|
299
|
+
const newArr = newValue;
|
|
300
|
+
const max = Math.max(oldArr.length, newArr.length);
|
|
301
|
+
for (let i = 0; i < max; i++) {
|
|
302
|
+
diffAndApply(oldArr[i], newArr[i], appendSegment(prefix, i), visit);
|
|
303
|
+
}
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (!oldIsArray && !newIsArray) {
|
|
307
|
+
const oldRec = oldValue;
|
|
308
|
+
const newRec = newValue;
|
|
309
|
+
const seen = /* @__PURE__ */ new Set();
|
|
310
|
+
for (const k of Object.keys(oldRec)) {
|
|
311
|
+
seen.add(k);
|
|
312
|
+
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
313
|
+
}
|
|
314
|
+
for (const k of Object.keys(newRec)) {
|
|
315
|
+
if (seen.has(k)) continue;
|
|
316
|
+
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (oldIsDescendable && !newIsDescendable) {
|
|
324
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (!oldIsDescendable && newIsDescendable) {
|
|
328
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (oldValue === void 0) {
|
|
332
|
+
visit({ kind: "added", path: prefix, newValue });
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (newValue === void 0) {
|
|
336
|
+
visit({ kind: "removed", path: prefix, oldValue });
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
340
|
+
}
|
|
341
|
+
function applyChangedKeys(target, source) {
|
|
342
|
+
if (!isDescendable(target) || !isDescendable(source)) return false;
|
|
343
|
+
const targetIsArray = Array.isArray(target);
|
|
344
|
+
const sourceIsArray = Array.isArray(source);
|
|
345
|
+
if (targetIsArray !== sourceIsArray) return false;
|
|
346
|
+
const ROOT_SENTINEL = Symbol.for("attaform.applyChangedKeys.rootMismatch");
|
|
347
|
+
const changedFirstSegments = /* @__PURE__ */ new Set();
|
|
348
|
+
diffAndApply(target, source, [], (patch) => {
|
|
349
|
+
if (patch.path.length === 0) {
|
|
350
|
+
changedFirstSegments.add(ROOT_SENTINEL);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
changedFirstSegments.add(patch.path[0]);
|
|
354
|
+
});
|
|
355
|
+
if (changedFirstSegments.has(ROOT_SENTINEL)) return false;
|
|
356
|
+
if (targetIsArray) {
|
|
357
|
+
const t = target;
|
|
358
|
+
const s = source;
|
|
359
|
+
if (t.length > s.length) t.length = s.length;
|
|
360
|
+
for (const idx of changedFirstSegments) {
|
|
361
|
+
if (typeof idx === "symbol") continue;
|
|
362
|
+
const i = typeof idx === "number" ? idx : Number(idx);
|
|
363
|
+
t[i] = s[i];
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
const t = target;
|
|
367
|
+
const s = source;
|
|
368
|
+
const sourceKeys = new Set(Object.keys(s));
|
|
369
|
+
for (const k of Object.keys(t)) {
|
|
370
|
+
if (!sourceKeys.has(k)) delete t[k];
|
|
371
|
+
}
|
|
372
|
+
for (const k of changedFirstSegments) {
|
|
373
|
+
if (typeof k === "symbol") continue;
|
|
374
|
+
t[String(k)] = s[String(k)];
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
function applyPatchesForward(root, patches) {
|
|
380
|
+
let current = root;
|
|
381
|
+
for (const patch of patches) {
|
|
382
|
+
if (patch.path.length === 0) {
|
|
383
|
+
current = patch.kind === "removed" ? void 0 : patch.newValue;
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (patch.kind === "removed") {
|
|
387
|
+
current = deleteAtPath(current, patch.path);
|
|
388
|
+
} else {
|
|
389
|
+
current = setAtPath(current, patch.path, patch.newValue);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return current;
|
|
393
|
+
}
|
|
394
|
+
function applyPatchesInverse(root, patches) {
|
|
395
|
+
let current = root;
|
|
396
|
+
for (let i = patches.length - 1; i >= 0; i--) {
|
|
397
|
+
const patch = patches[i];
|
|
398
|
+
if (patch.path.length === 0) {
|
|
399
|
+
if (patch.kind === "added") {
|
|
400
|
+
current = void 0;
|
|
401
|
+
} else {
|
|
402
|
+
current = patch.oldValue;
|
|
403
|
+
}
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (patch.kind === "added") {
|
|
407
|
+
current = deleteAtPath(current, patch.path);
|
|
408
|
+
} else {
|
|
409
|
+
current = setAtPath(current, patch.path, patch.oldValue);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return current;
|
|
413
|
+
}
|
|
414
|
+
function structuralSnapshot(value) {
|
|
415
|
+
if (!isDescendable(value)) return value;
|
|
416
|
+
if (Array.isArray(value)) {
|
|
417
|
+
const out2 = new Array(value.length);
|
|
418
|
+
for (let i = 0; i < value.length; i++) {
|
|
419
|
+
out2[i] = structuralSnapshot(value[i]);
|
|
420
|
+
}
|
|
421
|
+
return out2;
|
|
422
|
+
}
|
|
423
|
+
const src = value;
|
|
424
|
+
const out = {};
|
|
425
|
+
for (const k of Object.keys(src)) {
|
|
426
|
+
out[k] = structuralSnapshot(src[k]);
|
|
427
|
+
}
|
|
428
|
+
return out;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const EMPTY_RESOLVED_FIELD_META = Object.freeze({
|
|
432
|
+
label: "",
|
|
433
|
+
description: void 0,
|
|
434
|
+
placeholder: void 0,
|
|
435
|
+
meta: Object.freeze({})
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
function humanize(segment) {
|
|
439
|
+
if (typeof segment === "number") return "";
|
|
440
|
+
const str = String(segment);
|
|
441
|
+
if (str.length === 0) return "";
|
|
442
|
+
if (/^\d+$/.test(str)) return "";
|
|
443
|
+
const tokens = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().split(" ").filter((part) => part.length > 0);
|
|
444
|
+
if (tokens.length === 0) return "";
|
|
445
|
+
return tokens.map((part) => {
|
|
446
|
+
const head = part[0];
|
|
447
|
+
return head === void 0 ? part : head.toUpperCase() + part.slice(1).toLowerCase();
|
|
448
|
+
}).join(" ");
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function isUnderStubAncestor(state, segments) {
|
|
452
|
+
for (let i = 0; i < segments.length; i++) {
|
|
453
|
+
const ancestorPath = segments.slice(0, i);
|
|
454
|
+
const du = state.schema.getUnionDiscriminatorAtPath(ancestorPath);
|
|
455
|
+
if (du === void 0) continue;
|
|
456
|
+
const ancestorValue = getAtPath(state.form.value, ancestorPath);
|
|
457
|
+
if (ancestorValue === null || typeof ancestorValue !== "object") continue;
|
|
458
|
+
const discValue = ancestorValue[du.discriminatorKey];
|
|
459
|
+
if (discValue === void 0) return true;
|
|
460
|
+
if (!du.isVariantSelected(discValue)) return true;
|
|
461
|
+
}
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
function buildFieldStateAccessor(state, getFormMetaBase, options) {
|
|
417
465
|
const cache = /* @__PURE__ */ new Map();
|
|
466
|
+
const predicate = options?.shouldShowErrors;
|
|
418
467
|
return function getFieldState(pathInput) {
|
|
419
468
|
const { segments, key } = canonicalizePath(pathInput);
|
|
420
469
|
const cached = cache.get(key);
|
|
421
470
|
if (cached !== void 0) return cached;
|
|
422
471
|
const c = computed(
|
|
423
|
-
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key) : buildContainerFieldState(state, segments)
|
|
472
|
+
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, getFormMetaBase, predicate) : buildContainerFieldState(state, segments, key, getFormMetaBase, predicate)
|
|
424
473
|
);
|
|
425
474
|
cache.set(key, c);
|
|
426
475
|
return c;
|
|
427
476
|
};
|
|
428
477
|
}
|
|
429
|
-
function
|
|
478
|
+
function buildLeafFieldStateBase(state, segments, key) {
|
|
430
479
|
const record = state.fields.get(key);
|
|
431
480
|
const value = state.getValueAtPath(segments);
|
|
432
481
|
const original = state.originals.get(key)?.value;
|
|
@@ -440,7 +489,8 @@ function buildLeafFieldState(state, segments, key) {
|
|
|
440
489
|
if (userForKey !== void 0) errors.push(...userForKey);
|
|
441
490
|
const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
|
|
442
491
|
const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
|
|
443
|
-
const
|
|
492
|
+
const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
|
|
493
|
+
const valid = !gated && errors.length === 0 && !validating && !isOrphan;
|
|
444
494
|
const elementRecord = state.elements.get(key);
|
|
445
495
|
const elementsArr = elementRecord ? Object.freeze([...elementRecord.elements]) : EMPTY_ELEMENTS;
|
|
446
496
|
const firstElement = elementsArr[0] ?? null;
|
|
@@ -470,7 +520,11 @@ function buildLeafFieldState(state, segments, key) {
|
|
|
470
520
|
meta: resolved.meta
|
|
471
521
|
};
|
|
472
522
|
}
|
|
473
|
-
function
|
|
523
|
+
function buildLeafFieldState(state, segments, key, getFormMetaBase, shouldShowErrors) {
|
|
524
|
+
const base = buildLeafFieldStateBase(state, segments, key);
|
|
525
|
+
return decorateWithDerivedProps(base, state, getFormMetaBase, shouldShowErrors);
|
|
526
|
+
}
|
|
527
|
+
function buildContainerFieldStateBase(state, segments, _key) {
|
|
474
528
|
const formValue = state.form.value;
|
|
475
529
|
const value = state.getValueAtPath(segments);
|
|
476
530
|
const original = state.originals.get(canonicalizePath(segments).key)?.value;
|
|
@@ -536,6 +590,16 @@ function buildContainerFieldState(state, segments, _key) {
|
|
|
536
590
|
meta: resolved.meta
|
|
537
591
|
};
|
|
538
592
|
}
|
|
593
|
+
function buildContainerFieldState(state, segments, key, getFormMetaBase, shouldShowErrors) {
|
|
594
|
+
const base = buildContainerFieldStateBase(state, segments);
|
|
595
|
+
return decorateWithDerivedProps(base, state, getFormMetaBase, shouldShowErrors);
|
|
596
|
+
}
|
|
597
|
+
function decorateWithDerivedProps(base, state, getFormMetaBase, shouldShowErrors) {
|
|
598
|
+
const firstError = base.errors[0];
|
|
599
|
+
const predicate = shouldShowErrors ?? state.shouldShowErrors;
|
|
600
|
+
const showErrors = base.errors.length > 0 && predicate(base, getFormMetaBase());
|
|
601
|
+
return { ...base, showErrors, firstError };
|
|
602
|
+
}
|
|
539
603
|
function aggregateErrorsAt(state, prefix) {
|
|
540
604
|
const formValue = state.form.value;
|
|
541
605
|
const buckets = /* @__PURE__ */ new Map();
|
|
@@ -545,7 +609,7 @@ function aggregateErrorsAt(state, prefix) {
|
|
|
545
609
|
const segs = segmentsForPathKey(pathKey);
|
|
546
610
|
if (segs === null) continue;
|
|
547
611
|
if (!isPathPrefix(prefix, segs)) continue;
|
|
548
|
-
if (segs.length > 0 && !hasAtPath(formValue, segs)) continue;
|
|
612
|
+
if (pathKey === FORM_ERRORS_PATH_KEY) ; else if (segs.length > 0 && !hasAtPath(formValue, segs)) continue;
|
|
549
613
|
const ordinal = state.ensurePathOrdinal(pathKey);
|
|
550
614
|
const existing = buckets.get(ordinal);
|
|
551
615
|
if (existing === void 0) buckets.set(ordinal, [...list]);
|
|
@@ -718,14 +782,16 @@ function buildErrorsProxy(state) {
|
|
|
718
782
|
return buildSurfaceProxy({
|
|
719
783
|
schema: state.schema,
|
|
720
784
|
resolveLeaf: (path) => {
|
|
721
|
-
if (!hasAtPath(state.form.value, path)) return void 0;
|
|
722
785
|
const { key } = canonicalizePath(path);
|
|
723
|
-
const schemaForKey = state.schemaErrors.get(key);
|
|
724
|
-
const blankForKey = state.derivedBlankErrors.value.get(key);
|
|
725
786
|
const userForKey = state.userErrors.get(key);
|
|
787
|
+
const isActive = hasAtPath(state.form.value, path);
|
|
726
788
|
const merged = [];
|
|
727
|
-
if (
|
|
728
|
-
|
|
789
|
+
if (isActive) {
|
|
790
|
+
const schemaForKey = state.schemaErrors.get(key);
|
|
791
|
+
const blankForKey = state.derivedBlankErrors.value.get(key);
|
|
792
|
+
if (schemaForKey !== void 0) merged.push(...schemaForKey);
|
|
793
|
+
if (blankForKey !== void 0) merged.push(...blankForKey);
|
|
794
|
+
}
|
|
729
795
|
if (userForKey !== void 0) merged.push(...userForKey);
|
|
730
796
|
return merged.length === 0 ? void 0 : merged;
|
|
731
797
|
},
|
|
@@ -750,7 +816,7 @@ function buildErrorsProxy(state) {
|
|
|
750
816
|
function materializeErrors(state, containerSegments) {
|
|
751
817
|
const liveContainer = getAtPath(state.form.value, containerSegments);
|
|
752
818
|
const tree = Array.isArray(liveContainer) ? [] : {};
|
|
753
|
-
const collect = (store) => {
|
|
819
|
+
const collect = (store, applyActivePathFilter) => {
|
|
754
820
|
entries: for (const [pathKey, errors] of store) {
|
|
755
821
|
if (errors.length === 0) continue;
|
|
756
822
|
const fullPath = segmentsForPathKey(pathKey);
|
|
@@ -759,13 +825,13 @@ function materializeErrors(state, containerSegments) {
|
|
|
759
825
|
for (let i = 0; i < containerSegments.length; i++) {
|
|
760
826
|
if (fullPath[i] !== containerSegments[i]) continue entries;
|
|
761
827
|
}
|
|
762
|
-
if (!hasAtPath(state.form.value, fullPath)) continue;
|
|
828
|
+
if (applyActivePathFilter && !hasAtPath(state.form.value, fullPath)) continue;
|
|
763
829
|
placeAt(tree, fullPath.slice(containerSegments.length), errors);
|
|
764
830
|
}
|
|
765
831
|
};
|
|
766
|
-
collect(state.schemaErrors);
|
|
767
|
-
collect(state.derivedBlankErrors.value);
|
|
768
|
-
collect(state.userErrors);
|
|
832
|
+
collect(state.schemaErrors, true);
|
|
833
|
+
collect(state.derivedBlankErrors.value, true);
|
|
834
|
+
collect(state.userErrors, false);
|
|
769
835
|
return tree;
|
|
770
836
|
}
|
|
771
837
|
function placeAt(tree, path, errors) {
|
|
@@ -796,11 +862,13 @@ function buildFieldArrayApi(state) {
|
|
|
796
862
|
const current = state.getValueAtPath(segments);
|
|
797
863
|
return Array.isArray(current) ? current.slice() : [];
|
|
798
864
|
}
|
|
799
|
-
function writeArray(path, next) {
|
|
865
|
+
function writeArray(path, next, arrayOp) {
|
|
800
866
|
const { segments, key } = canonicalizePath(path);
|
|
801
|
-
|
|
802
|
-
persist: state.persistOptIns.hasAnyOptInForPath(key)
|
|
803
|
-
|
|
867
|
+
const meta = {
|
|
868
|
+
persist: state.persistOptIns.hasAnyOptInForPath(key),
|
|
869
|
+
...arrayOp !== void 0 ? { arrayOp } : {}
|
|
870
|
+
};
|
|
871
|
+
return state.setValueAtPath(segments, next, meta);
|
|
804
872
|
}
|
|
805
873
|
return {
|
|
806
874
|
append(path, value) {
|
|
@@ -811,18 +879,19 @@ function buildFieldArrayApi(state) {
|
|
|
811
879
|
prepend(path, value) {
|
|
812
880
|
const next = readArray(path);
|
|
813
881
|
next.unshift(value);
|
|
814
|
-
return writeArray(path, next);
|
|
882
|
+
return writeArray(path, next, { kind: "shift-from", index: 0 });
|
|
815
883
|
},
|
|
816
884
|
insert(path, index, value) {
|
|
817
885
|
const next = readArray(path);
|
|
818
886
|
next.splice(index, 0, value);
|
|
819
|
-
|
|
887
|
+
const clampedIndex = Math.max(0, Math.min(index, next.length));
|
|
888
|
+
return writeArray(path, next, { kind: "shift-from", index: clampedIndex });
|
|
820
889
|
},
|
|
821
890
|
remove(path, index) {
|
|
822
891
|
const next = readArray(path);
|
|
823
892
|
if (index < 0 || index >= next.length) return false;
|
|
824
893
|
next.splice(index, 1);
|
|
825
|
-
return writeArray(path, next);
|
|
894
|
+
return writeArray(path, next, { kind: "shift-from", index });
|
|
826
895
|
},
|
|
827
896
|
swap(path, a, b) {
|
|
828
897
|
const next = readArray(path);
|
|
@@ -832,7 +901,7 @@ function buildFieldArrayApi(state) {
|
|
|
832
901
|
const tmp = next[a];
|
|
833
902
|
next[a] = next[b];
|
|
834
903
|
next[b] = tmp;
|
|
835
|
-
return writeArray(path, next);
|
|
904
|
+
return writeArray(path, next, { kind: "swap", a, b });
|
|
836
905
|
},
|
|
837
906
|
move(path, from, to) {
|
|
838
907
|
const next = readArray(path);
|
|
@@ -840,13 +909,17 @@ function buildFieldArrayApi(state) {
|
|
|
840
909
|
const [item] = next.splice(from, 1);
|
|
841
910
|
const clampedTo = Math.max(0, Math.min(to, next.length));
|
|
842
911
|
next.splice(clampedTo, 0, item);
|
|
843
|
-
return writeArray(path, next
|
|
912
|
+
return writeArray(path, next, {
|
|
913
|
+
kind: "shift-range",
|
|
914
|
+
fromIndex: Math.min(from, clampedTo),
|
|
915
|
+
toIndex: Math.max(from, clampedTo)
|
|
916
|
+
});
|
|
844
917
|
},
|
|
845
918
|
replace(path, index, value) {
|
|
846
919
|
const next = readArray(path);
|
|
847
920
|
if (index < 0 || index >= next.length) return false;
|
|
848
921
|
next[index] = value;
|
|
849
|
-
return writeArray(path, next);
|
|
922
|
+
return writeArray(path, next, { kind: "replace-at", index });
|
|
850
923
|
}
|
|
851
924
|
};
|
|
852
925
|
}
|
|
@@ -866,6 +939,8 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
866
939
|
"errors",
|
|
867
940
|
"validating",
|
|
868
941
|
"valid",
|
|
942
|
+
"showErrors",
|
|
943
|
+
"firstError",
|
|
869
944
|
"path",
|
|
870
945
|
"blank",
|
|
871
946
|
"label",
|
|
@@ -873,8 +948,12 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
873
948
|
"placeholder",
|
|
874
949
|
"meta"
|
|
875
950
|
]);
|
|
876
|
-
function buildFieldStateProxy(state) {
|
|
877
|
-
const getFieldStateAt = buildFieldStateAccessor(
|
|
951
|
+
function buildFieldStateProxy(state, getFormMetaBase, options) {
|
|
952
|
+
const getFieldStateAt = buildFieldStateAccessor(
|
|
953
|
+
state,
|
|
954
|
+
getFormMetaBase,
|
|
955
|
+
options?.shouldShowErrors !== void 0 ? { shouldShowErrors: options.shouldShowErrors } : void 0
|
|
956
|
+
);
|
|
878
957
|
const snapshotFieldStateAt = (path) => {
|
|
879
958
|
const view = getFieldStateAt(path).value;
|
|
880
959
|
const snapshot = {};
|
|
@@ -965,10 +1044,25 @@ function walk$2(value, basePath, schema, snapshotFieldStateAt) {
|
|
|
965
1044
|
|
|
966
1045
|
const DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS = 0;
|
|
967
1046
|
const DEFAULT_PERSISTENCE_DEBOUNCE_MS = 300;
|
|
968
|
-
const DEFAULT_HISTORY_MAX_SNAPSHOTS =
|
|
1047
|
+
const DEFAULT_HISTORY_MAX_SNAPSHOTS = 128;
|
|
969
1048
|
const PERSISTENCE_KEY_PREFIX = "attaform:";
|
|
970
1049
|
const RESERVED_KEY_PREFIX = "__atta:";
|
|
971
1050
|
const ANONYMOUS_FORM_KEY_PREFIX = `${RESERVED_KEY_PREFIX}anon:`;
|
|
1051
|
+
const DEFAULT_MAX_RECURSION_DEPTH = 64;
|
|
1052
|
+
function normalizeNumericOption(config) {
|
|
1053
|
+
const { value, source, allowInfinity, min, defaultValue } = config;
|
|
1054
|
+
if (allowInfinity && value === Infinity) return Infinity;
|
|
1055
|
+
if (typeof value !== "number" || Number.isNaN(value) || value === Infinity || value === -Infinity) {
|
|
1056
|
+
if (__DEV__) {
|
|
1057
|
+
const acceptedDescription = allowInfinity ? "a non-negative integer or Infinity" : "a non-negative finite integer";
|
|
1058
|
+
console.warn(
|
|
1059
|
+
`[attaform] ${source} must be ${acceptedDescription}; got ${String(value)}. Falling back to ${String(defaultValue)}.`
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
return defaultValue;
|
|
1063
|
+
}
|
|
1064
|
+
return Math.max(min, Math.floor(value));
|
|
1065
|
+
}
|
|
972
1066
|
|
|
973
1067
|
const PERSISTENCE_MODULE_KEY = "persistence";
|
|
974
1068
|
async function getStorageAdapter(storage) {
|
|
@@ -1143,20 +1237,29 @@ function mergeDeep(target, source, path, schema) {
|
|
|
1143
1237
|
if (source === null || typeof source !== "object") return source;
|
|
1144
1238
|
if (Array.isArray(source)) return source;
|
|
1145
1239
|
if (!isPlainRecord(source)) return source;
|
|
1146
|
-
let mergeTarget = target;
|
|
1147
1240
|
if (schema !== void 0) {
|
|
1148
1241
|
const du = schema.getUnionDiscriminatorAtPath(path);
|
|
1149
1242
|
if (du !== void 0) {
|
|
1150
|
-
const
|
|
1151
|
-
const
|
|
1152
|
-
if (sourceDisc !== void 0 && !
|
|
1243
|
+
const sourceRecord = source;
|
|
1244
|
+
const sourceDisc = sourceRecord[du.discriminatorKey];
|
|
1245
|
+
if (sourceDisc !== void 0 && !du.isVariantSelected(sourceDisc)) {
|
|
1246
|
+
return { [du.discriminatorKey]: sourceDisc };
|
|
1247
|
+
}
|
|
1248
|
+
if (sourceDisc !== void 0) {
|
|
1153
1249
|
const variantDefault = du.getVariantDefault(sourceDisc);
|
|
1154
1250
|
if (isPlainRecord(variantDefault)) {
|
|
1155
|
-
|
|
1251
|
+
const out2 = { ...variantDefault };
|
|
1252
|
+
for (const key of Object.keys(sourceRecord)) {
|
|
1253
|
+
if (!(key in variantDefault) && key !== du.discriminatorKey) continue;
|
|
1254
|
+
out2[key] = mergeDeep(out2[key], sourceRecord[key], [...path, key], schema);
|
|
1255
|
+
}
|
|
1256
|
+
return out2;
|
|
1156
1257
|
}
|
|
1157
1258
|
}
|
|
1259
|
+
return {};
|
|
1158
1260
|
}
|
|
1159
1261
|
}
|
|
1262
|
+
const mergeTarget = target;
|
|
1160
1263
|
const out = isPlainRecord(mergeTarget) ? { ...mergeTarget } : {};
|
|
1161
1264
|
for (const key of Object.keys(source)) {
|
|
1162
1265
|
out[key] = mergeDeep(out[key], source[key], [...path, key], schema);
|
|
@@ -1185,14 +1288,14 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1185
1288
|
});
|
|
1186
1289
|
let gen = 0;
|
|
1187
1290
|
async function kickoff(data, path, captured) {
|
|
1188
|
-
state.activeValidations.value += 1;
|
|
1189
|
-
result.value = {
|
|
1190
|
-
pending: true,
|
|
1191
|
-
errors: void 0,
|
|
1192
|
-
success: false,
|
|
1193
|
-
formKey: state.formKey
|
|
1194
|
-
};
|
|
1195
1291
|
try {
|
|
1292
|
+
state.activeValidations.value += 1;
|
|
1293
|
+
result.value = {
|
|
1294
|
+
pending: true,
|
|
1295
|
+
errors: void 0,
|
|
1296
|
+
success: false,
|
|
1297
|
+
formKey: state.formKey
|
|
1298
|
+
};
|
|
1196
1299
|
const refinement = await runRefinementValidation(data, path);
|
|
1197
1300
|
if (captured !== gen) return;
|
|
1198
1301
|
result.value = settled(composeWithDerivedBlank(refinement, path));
|
|
@@ -1236,14 +1339,44 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1236
1339
|
async function validateAsync(pathInput) {
|
|
1237
1340
|
const segments = pathInput === void 0 ? void 0 : toSegments(pathInput);
|
|
1238
1341
|
const dataAtPath = segments === void 0 ? state.form.value : state.getValueAtPath(segments);
|
|
1239
|
-
state.activeValidations.value += 1;
|
|
1240
1342
|
try {
|
|
1343
|
+
state.activeValidations.value += 1;
|
|
1241
1344
|
const refinement = await runRefinementValidation(dataAtPath, segments);
|
|
1242
1345
|
return stripData(composeWithDerivedBlank(refinement, segments));
|
|
1346
|
+
} catch (err) {
|
|
1347
|
+
return adapterThrowResponse(err);
|
|
1348
|
+
} finally {
|
|
1349
|
+
state.activeValidations.value = Math.max(0, state.activeValidations.value - 1);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
async function process(pathInput) {
|
|
1353
|
+
const segments = pathInput === void 0 ? void 0 : toSegments(pathInput);
|
|
1354
|
+
const dataAtPath = segments === void 0 ? state.form.value : state.getValueAtPath(segments);
|
|
1355
|
+
try {
|
|
1356
|
+
state.activeValidations.value += 1;
|
|
1357
|
+
const refinement = await runRefinementValidation(dataAtPath, segments);
|
|
1358
|
+
return composeWithDerivedBlank(refinement, segments);
|
|
1359
|
+
} catch (err) {
|
|
1360
|
+
return adapterThrowResponse(err);
|
|
1243
1361
|
} finally {
|
|
1244
1362
|
state.activeValidations.value = Math.max(0, state.activeValidations.value - 1);
|
|
1245
1363
|
}
|
|
1246
1364
|
}
|
|
1365
|
+
function adapterThrowResponse(err) {
|
|
1366
|
+
return {
|
|
1367
|
+
success: false,
|
|
1368
|
+
data: void 0,
|
|
1369
|
+
errors: [
|
|
1370
|
+
{
|
|
1371
|
+
message: adapterThrowMessage(err),
|
|
1372
|
+
path: [],
|
|
1373
|
+
formKey: state.formKey,
|
|
1374
|
+
code: AttaformErrorCode.AdapterThrew
|
|
1375
|
+
}
|
|
1376
|
+
],
|
|
1377
|
+
formKey: state.formKey
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1247
1380
|
async function runRefinementValidation(data, path) {
|
|
1248
1381
|
return await state.schema.validateAtPath(data, path);
|
|
1249
1382
|
}
|
|
@@ -1265,14 +1398,17 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1265
1398
|
if (event !== void 0 && "preventDefault" in event && typeof event.preventDefault === "function") {
|
|
1266
1399
|
event.preventDefault();
|
|
1267
1400
|
}
|
|
1401
|
+
if (state.activeSubmissions.value > 0) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1268
1404
|
const genAtEntry = state.submissionGeneration.value;
|
|
1269
|
-
state.activeSubmissions.value += 1;
|
|
1270
|
-
state.submitting.value = true;
|
|
1271
|
-
state.submitError.value = null;
|
|
1272
|
-
state.cancelFieldValidation();
|
|
1273
|
-
state.activeValidations.value += 1;
|
|
1274
1405
|
let validationSettled = false;
|
|
1275
1406
|
try {
|
|
1407
|
+
state.activeSubmissions.value += 1;
|
|
1408
|
+
state.submitting.value = true;
|
|
1409
|
+
state.submitError.value = null;
|
|
1410
|
+
state.cancelFieldValidation();
|
|
1411
|
+
state.activeValidations.value += 1;
|
|
1276
1412
|
const refinement = await runRefinementValidation(state.form.value, void 0);
|
|
1277
1413
|
const merged = composeWithDerivedBlank(refinement, void 0);
|
|
1278
1414
|
state.activeValidations.value = Math.max(0, state.activeValidations.value - 1);
|
|
@@ -1321,7 +1457,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1321
1457
|
};
|
|
1322
1458
|
return submitHandler;
|
|
1323
1459
|
};
|
|
1324
|
-
return { validate, validateAsync, handleSubmit };
|
|
1460
|
+
return { validate, validateAsync, process, handleSubmit };
|
|
1325
1461
|
}
|
|
1326
1462
|
function toSegments(pathInput) {
|
|
1327
1463
|
return canonicalizePath(pathInput).segments;
|
|
@@ -1659,11 +1795,12 @@ function coerceValue(value, accepted, elementAccepted, index) {
|
|
|
1659
1795
|
const EMPTY_TRANSFORMS = Object.freeze([]);
|
|
1660
1796
|
const INTERACTIVE_TAG_NAMES = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA"]);
|
|
1661
1797
|
const attaformListenersSymbol = Symbol.for("attaform:focus-listeners");
|
|
1662
|
-
function attachFocusListeners(state, segments, element) {
|
|
1798
|
+
function attachFocusListeners(state, segments, element, instanceMeta) {
|
|
1663
1799
|
const target = element;
|
|
1664
1800
|
if (target[attaformListenersSymbol] !== void 0) return;
|
|
1665
|
-
const
|
|
1666
|
-
const
|
|
1801
|
+
const focusMeta = instanceMeta !== void 0 ? { instance: instanceMeta } : void 0;
|
|
1802
|
+
const handleFocus = () => state.markFocused(segments, true, focusMeta);
|
|
1803
|
+
const handleBlur = () => state.markFocused(segments, false, focusMeta);
|
|
1667
1804
|
element.addEventListener("focus", handleFocus);
|
|
1668
1805
|
element.addEventListener("blur", handleBlur);
|
|
1669
1806
|
target[attaformListenersSymbol] = { handleFocus, handleBlur };
|
|
@@ -1676,7 +1813,13 @@ function detachFocusListeners(element) {
|
|
|
1676
1813
|
element.removeEventListener("blur", listeners.handleBlur);
|
|
1677
1814
|
delete target[attaformListenersSymbol];
|
|
1678
1815
|
}
|
|
1679
|
-
function buildRegister(state, formInstanceId) {
|
|
1816
|
+
function buildRegister(state, formInstanceId, instanceConfig) {
|
|
1817
|
+
const coerceIndex = instanceConfig?.coerce !== void 0 ? resolveCoercionIndex(instanceConfig.coerce) : state.coerceIndex;
|
|
1818
|
+
const instanceMeta = instanceConfig?.instanceMeta;
|
|
1819
|
+
const withInstanceMeta = (meta) => {
|
|
1820
|
+
if (instanceMeta === void 0) return meta;
|
|
1821
|
+
return meta === void 0 ? { instance: instanceMeta } : { ...meta, instance: instanceMeta };
|
|
1822
|
+
};
|
|
1680
1823
|
const lastTypedFormByPath = /* @__PURE__ */ new Map();
|
|
1681
1824
|
return function register(pathInput, options) {
|
|
1682
1825
|
const { segments, key: pathKey } = canonicalizePath(pathInput);
|
|
@@ -1699,16 +1842,23 @@ function buildRegister(state, formInstanceId) {
|
|
|
1699
1842
|
const slimDefault = state.schema.getDefaultAtPath(segments);
|
|
1700
1843
|
const persist = options?.persist === true;
|
|
1701
1844
|
const acknowledgeSensitive = options?.acknowledgeSensitive === true;
|
|
1845
|
+
const multiTab = options?.multiTab !== false;
|
|
1702
1846
|
const transforms = options?.transforms ?? EMPTY_TRANSFORMS;
|
|
1847
|
+
const markNoSync = !multiTab ? () => {
|
|
1848
|
+
state.incrementNoSyncOptOut(pathKey);
|
|
1849
|
+
} : void 0;
|
|
1850
|
+
const unmarkNoSync = !multiTab ? () => {
|
|
1851
|
+
state.decrementNoSyncOptOut(pathKey);
|
|
1852
|
+
} : void 0;
|
|
1703
1853
|
const coerce = buildCoerceFn(
|
|
1704
1854
|
state.schema,
|
|
1705
1855
|
segments,
|
|
1706
|
-
|
|
1856
|
+
coerceIndex
|
|
1707
1857
|
);
|
|
1708
1858
|
const coerceElement = buildElementCoerceFn(
|
|
1709
1859
|
state.schema,
|
|
1710
1860
|
segments,
|
|
1711
|
-
|
|
1861
|
+
coerceIndex
|
|
1712
1862
|
);
|
|
1713
1863
|
if (persist && !state.ssr && !state.modules.has(PERSISTENCE_MODULE_KEY)) {
|
|
1714
1864
|
throw new AnonPersistError({
|
|
@@ -1722,22 +1872,26 @@ function buildRegister(state, formInstanceId) {
|
|
|
1722
1872
|
displayValue,
|
|
1723
1873
|
lastTypedForm,
|
|
1724
1874
|
markBlank: () => {
|
|
1725
|
-
return state.setValueAtPath(
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1875
|
+
return state.setValueAtPath(
|
|
1876
|
+
segments,
|
|
1877
|
+
slimDefault,
|
|
1878
|
+
withInstanceMeta({
|
|
1879
|
+
blank: true,
|
|
1880
|
+
persist
|
|
1881
|
+
})
|
|
1882
|
+
);
|
|
1729
1883
|
},
|
|
1730
1884
|
registerElement: (element) => {
|
|
1731
1885
|
if (!INTERACTIVE_TAG_NAMES.has(element.tagName)) return;
|
|
1732
1886
|
const added = state.registerElement(segments, element, formInstanceId);
|
|
1733
|
-
if (added) attachFocusListeners(state, segments, element);
|
|
1887
|
+
if (added) attachFocusListeners(state, segments, element, instanceMeta);
|
|
1734
1888
|
},
|
|
1735
1889
|
deregisterElement: (element) => {
|
|
1736
1890
|
detachFocusListeners(element);
|
|
1737
1891
|
state.deregisterElement(segments, element);
|
|
1738
1892
|
},
|
|
1739
1893
|
setValueWithInternalPath: (value, meta) => {
|
|
1740
|
-
return state.setValueAtPath(segments, value, meta);
|
|
1894
|
+
return state.setValueAtPath(segments, value, withInstanceMeta(meta));
|
|
1741
1895
|
},
|
|
1742
1896
|
// Called by the `vRegisterHint` compile-time transform's wrapping
|
|
1743
1897
|
// IIFE on every server-side render of `<element v-register="…">`.
|
|
@@ -1763,6 +1917,10 @@ function buildRegister(state, formInstanceId) {
|
|
|
1763
1917
|
persist,
|
|
1764
1918
|
acknowledgeSensitive,
|
|
1765
1919
|
persistOptIns: state.persistOptIns,
|
|
1920
|
+
isSensitivePath: state.isSensitivePath,
|
|
1921
|
+
multiTab,
|
|
1922
|
+
...markNoSync !== void 0 ? { markNoSync } : {},
|
|
1923
|
+
...unmarkNoSync !== void 0 ? { unmarkNoSync } : {},
|
|
1766
1924
|
transforms,
|
|
1767
1925
|
coerce,
|
|
1768
1926
|
...coerceElement !== void 0 ? { coerceElement } : {}
|
|
@@ -1920,6 +2078,8 @@ function buildValuesProxy(form) {
|
|
|
1920
2078
|
const inner = computed(() => readonly(form.value));
|
|
1921
2079
|
const target = (() => {
|
|
1922
2080
|
});
|
|
2081
|
+
const valuesToString = () => JSON.stringify(inner.value);
|
|
2082
|
+
const valuesToPrimitive = (hint) => hint === "number" ? NaN : valuesToString();
|
|
1923
2083
|
return new Proxy(target, {
|
|
1924
2084
|
apply(_, __, args) {
|
|
1925
2085
|
const arg = args[0];
|
|
@@ -1933,8 +2093,16 @@ function buildValuesProxy(form) {
|
|
|
1933
2093
|
return cursor;
|
|
1934
2094
|
},
|
|
1935
2095
|
get(_, key) {
|
|
1936
|
-
if (typeof key === "symbol")
|
|
2096
|
+
if (typeof key === "symbol") {
|
|
2097
|
+
if (key === Symbol.toPrimitive) return valuesToPrimitive;
|
|
2098
|
+
return Reflect.get(target, key);
|
|
2099
|
+
}
|
|
1937
2100
|
if (key === "toJSON") return () => inner.value;
|
|
2101
|
+
if (key === "toString") return valuesToString;
|
|
2102
|
+
if (key === "valueOf")
|
|
2103
|
+
return function() {
|
|
2104
|
+
return this;
|
|
2105
|
+
};
|
|
1938
2106
|
return inner.value[key];
|
|
1939
2107
|
},
|
|
1940
2108
|
has(_, key) {
|
|
@@ -1973,6 +2141,14 @@ function buildValuesProxy(form) {
|
|
|
1973
2141
|
});
|
|
1974
2142
|
}
|
|
1975
2143
|
|
|
2144
|
+
function blankForKind(slimDefault) {
|
|
2145
|
+
if (typeof slimDefault === "string") return "";
|
|
2146
|
+
if (typeof slimDefault === "number") return 0;
|
|
2147
|
+
if (typeof slimDefault === "bigint") return 0n;
|
|
2148
|
+
if (typeof slimDefault === "boolean") return false;
|
|
2149
|
+
if (slimDefault === null) return null;
|
|
2150
|
+
return void 0;
|
|
2151
|
+
}
|
|
1976
2152
|
function readonlySetSnapshot(source) {
|
|
1977
2153
|
const snapshot = new Set(source);
|
|
1978
2154
|
return new Proxy(snapshot, {
|
|
@@ -1988,15 +2164,36 @@ function readonlySetSnapshot(source) {
|
|
|
1988
2164
|
});
|
|
1989
2165
|
}
|
|
1990
2166
|
function buildFormApi(state, formInstanceId, options = {}) {
|
|
1991
|
-
const
|
|
2167
|
+
const instanceMeta = (() => {
|
|
2168
|
+
const bag = {};
|
|
2169
|
+
if (options.validateOn !== void 0) bag.validateOn = options.validateOn;
|
|
2170
|
+
if (options.debounceMs !== void 0) bag.debounceMs = options.debounceMs;
|
|
2171
|
+
if (options.rememberVariants !== void 0) bag.rememberVariants = options.rememberVariants;
|
|
2172
|
+
return Object.keys(bag).length > 0 ? bag : void 0;
|
|
2173
|
+
})();
|
|
2174
|
+
const withInstanceMeta = (meta) => {
|
|
2175
|
+
if (instanceMeta === void 0) return meta;
|
|
2176
|
+
return meta === void 0 ? { instance: instanceMeta } : { ...meta, instance: instanceMeta };
|
|
2177
|
+
};
|
|
2178
|
+
const registerConfig = {
|
|
2179
|
+
...instanceMeta !== void 0 ? { instanceMeta } : {},
|
|
2180
|
+
...options.coerce !== void 0 ? { coerce: options.coerce } : {}
|
|
2181
|
+
};
|
|
2182
|
+
const register = buildRegister(
|
|
2183
|
+
state,
|
|
2184
|
+
formInstanceId,
|
|
2185
|
+
Object.keys(registerConfig).length > 0 ? registerConfig : void 0
|
|
2186
|
+
);
|
|
1992
2187
|
const processOptions = options.onInvalidSubmit !== void 0 ? { onInvalidSubmit: options.onInvalidSubmit } : {};
|
|
1993
2188
|
const {
|
|
1994
2189
|
validate: validateBuilt,
|
|
1995
2190
|
validateAsync: validateAsyncBuilt,
|
|
2191
|
+
process: processBuilt,
|
|
1996
2192
|
handleSubmit
|
|
1997
2193
|
} = buildProcessForm(state, formInstanceId, processOptions);
|
|
1998
2194
|
const validate = (pathInput) => validateBuilt(pathInput);
|
|
1999
2195
|
const validateAsync = (pathInput) => validateAsyncBuilt(pathInput);
|
|
2196
|
+
const process = (pathInput) => processBuilt(pathInput);
|
|
2000
2197
|
function pathToRef(pathInput) {
|
|
2001
2198
|
const segments = canonicalizePath(pathInput).segments;
|
|
2002
2199
|
return computed(() => getAtPath(state.form.value, segments));
|
|
@@ -2008,22 +2205,36 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2008
2205
|
next,
|
|
2009
2206
|
state.schema
|
|
2010
2207
|
);
|
|
2011
|
-
const ok2 = state.setValueAtPath([], walked2.cleanedValues);
|
|
2208
|
+
const ok2 = state.setValueAtPath([], walked2.cleanedValues, withInstanceMeta());
|
|
2012
2209
|
if (!ok2) return false;
|
|
2013
2210
|
for (const pathKey of walked2.paths) {
|
|
2014
2211
|
const segments2 = segmentsForPathKey(pathKey);
|
|
2015
2212
|
if (segments2 === null) continue;
|
|
2016
|
-
state.setValueAtPath(
|
|
2017
|
-
|
|
2018
|
-
|
|
2213
|
+
state.setValueAtPath(
|
|
2214
|
+
segments2,
|
|
2215
|
+
state.schema.getDefaultAtPath(segments2),
|
|
2216
|
+
withInstanceMeta({ blank: true })
|
|
2217
|
+
);
|
|
2019
2218
|
}
|
|
2020
2219
|
return true;
|
|
2021
2220
|
}
|
|
2022
2221
|
const segments = canonicalizePath(pathOrValue).segments;
|
|
2023
2222
|
if (isUnset(maybeValue)) {
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2223
|
+
const last = segments.length > 0 ? segments[segments.length - 1] : void 0;
|
|
2224
|
+
if (typeof last === "string") {
|
|
2225
|
+
const parent = segments.slice(0, -1);
|
|
2226
|
+
const parentDU = state.schema.getUnionDiscriminatorAtPath(parent);
|
|
2227
|
+
if (parentDU?.discriminatorKey === last) {
|
|
2228
|
+
const slimDefault = state.schema.getDefaultAtPath(segments);
|
|
2229
|
+
const blank = blankForKind(slimDefault);
|
|
2230
|
+
return state.setValueAtPath(segments, blank, withInstanceMeta({ blank: true }));
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
return state.setValueAtPath(
|
|
2234
|
+
segments,
|
|
2235
|
+
state.schema.getDefaultAtPath(segments),
|
|
2236
|
+
withInstanceMeta({ blank: true })
|
|
2237
|
+
);
|
|
2027
2238
|
}
|
|
2028
2239
|
let resolvedValue;
|
|
2029
2240
|
if (typeof maybeValue === "function") {
|
|
@@ -2031,9 +2242,11 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2031
2242
|
const prev = current === void 0 ? state.schema.getDefaultAtPath(segments) : current;
|
|
2032
2243
|
resolvedValue = maybeValue(prev);
|
|
2033
2244
|
if (isUnset(resolvedValue)) {
|
|
2034
|
-
return state.setValueAtPath(
|
|
2035
|
-
|
|
2036
|
-
|
|
2245
|
+
return state.setValueAtPath(
|
|
2246
|
+
segments,
|
|
2247
|
+
state.schema.getDefaultAtPath(segments),
|
|
2248
|
+
withInstanceMeta({ blank: true })
|
|
2249
|
+
);
|
|
2037
2250
|
}
|
|
2038
2251
|
} else {
|
|
2039
2252
|
resolvedValue = maybeValue;
|
|
@@ -2043,28 +2256,52 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2043
2256
|
segments,
|
|
2044
2257
|
state.schema
|
|
2045
2258
|
);
|
|
2046
|
-
const ok = state.setValueAtPath(segments, walked.cleanedValues);
|
|
2259
|
+
const ok = state.setValueAtPath(segments, walked.cleanedValues, withInstanceMeta());
|
|
2047
2260
|
if (!ok) return false;
|
|
2048
2261
|
for (const pathKey of walked.paths) {
|
|
2049
2262
|
const blankSegments = segmentsForPathKey(pathKey);
|
|
2050
2263
|
if (blankSegments === null) continue;
|
|
2051
|
-
state.setValueAtPath(
|
|
2052
|
-
|
|
2053
|
-
|
|
2264
|
+
state.setValueAtPath(
|
|
2265
|
+
blankSegments,
|
|
2266
|
+
state.schema.getDefaultAtPath(blankSegments),
|
|
2267
|
+
withInstanceMeta({ blank: true })
|
|
2268
|
+
);
|
|
2054
2269
|
}
|
|
2055
2270
|
return true;
|
|
2056
2271
|
}
|
|
2057
2272
|
const errorsProxy = buildErrorsProxy(state);
|
|
2273
|
+
function filterToOwnFormKey(errors, op) {
|
|
2274
|
+
const own = [];
|
|
2275
|
+
let dropped = 0;
|
|
2276
|
+
for (const e of errors) {
|
|
2277
|
+
if (e.formKey === state.formKey) own.push(e);
|
|
2278
|
+
else dropped++;
|
|
2279
|
+
}
|
|
2280
|
+
if (__DEV__ && dropped > 0) {
|
|
2281
|
+
console.warn(
|
|
2282
|
+
`[attaform] ${op}: dropped ${dropped} error(s) with non-matching formKey (this form's key is "${String(state.formKey)}"). Errors are scoped to the form that produced them \u2014 pass them to the matching form instance.`
|
|
2283
|
+
);
|
|
2284
|
+
}
|
|
2285
|
+
return own;
|
|
2286
|
+
}
|
|
2058
2287
|
function setFieldErrors(errors) {
|
|
2059
|
-
state.
|
|
2288
|
+
const preserved = state.userErrors.get(FORM_ERRORS_PATH_KEY);
|
|
2289
|
+
state.setAllUserErrors(filterToOwnFormKey(errors, "setFieldErrors"));
|
|
2290
|
+
if (preserved !== void 0 && preserved.length > 0) {
|
|
2291
|
+
state.userErrors.set(FORM_ERRORS_PATH_KEY, preserved);
|
|
2292
|
+
}
|
|
2060
2293
|
}
|
|
2061
2294
|
function addFieldErrors(errors) {
|
|
2062
|
-
state.addUserErrors(errors);
|
|
2295
|
+
state.addUserErrors(filterToOwnFormKey(errors, "addFieldErrors"));
|
|
2063
2296
|
}
|
|
2064
2297
|
function clearFieldErrors(path) {
|
|
2065
2298
|
if (path === void 0) {
|
|
2299
|
+
const preserved = state.userErrors.get(FORM_ERRORS_PATH_KEY);
|
|
2066
2300
|
state.clearSchemaErrors();
|
|
2067
2301
|
state.clearUserErrors();
|
|
2302
|
+
if (preserved !== void 0 && preserved.length > 0) {
|
|
2303
|
+
state.userErrors.set(FORM_ERRORS_PATH_KEY, preserved);
|
|
2304
|
+
}
|
|
2068
2305
|
return;
|
|
2069
2306
|
}
|
|
2070
2307
|
const segments = canonicalizePath(path).segments;
|
|
@@ -2073,13 +2310,13 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2073
2310
|
}
|
|
2074
2311
|
function setFormErrors(errors) {
|
|
2075
2312
|
if (errors.length === 0) {
|
|
2076
|
-
state.userErrors.delete(
|
|
2313
|
+
state.userErrors.delete(FORM_ERRORS_PATH_KEY);
|
|
2077
2314
|
return;
|
|
2078
2315
|
}
|
|
2079
2316
|
state.userErrors.set(
|
|
2080
|
-
|
|
2317
|
+
FORM_ERRORS_PATH_KEY,
|
|
2081
2318
|
errors.map((e) => ({
|
|
2082
|
-
path: [],
|
|
2319
|
+
path: [...FORM_ERRORS_PATH],
|
|
2083
2320
|
message: e.message,
|
|
2084
2321
|
formKey: state.formKey,
|
|
2085
2322
|
code: e.code ?? "atta:form-error"
|
|
@@ -2087,7 +2324,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2087
2324
|
);
|
|
2088
2325
|
}
|
|
2089
2326
|
function clearFormErrors() {
|
|
2090
|
-
state.userErrors.delete(
|
|
2327
|
+
state.userErrors.delete(FORM_ERRORS_PATH_KEY);
|
|
2091
2328
|
}
|
|
2092
2329
|
const submitting = computed(() => state.submitting.value);
|
|
2093
2330
|
const submitCount = computed(() => state.submitCount.value);
|
|
@@ -2097,15 +2334,36 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2097
2334
|
() => state.firstValidationDone.value && state.schemaErrors.size === 0 && state.userErrors.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
|
|
2098
2335
|
);
|
|
2099
2336
|
const history = options.history;
|
|
2100
|
-
const
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2337
|
+
const formHistory = readonly(
|
|
2338
|
+
reactive({
|
|
2339
|
+
undo: history?.undo ?? (() => false),
|
|
2340
|
+
redo: history?.redo ?? (() => false),
|
|
2341
|
+
clear: history?.clear ?? (() => {
|
|
2342
|
+
}),
|
|
2343
|
+
canUndo: history?.canUndo ?? computed(() => false),
|
|
2344
|
+
canRedo: history?.canRedo ?? computed(() => false),
|
|
2345
|
+
size: history?.historySize ?? computed(() => 0)
|
|
2346
|
+
})
|
|
2347
|
+
);
|
|
2105
2348
|
const metaErrors = computed(
|
|
2106
2349
|
() => aggregateErrorsAt(state, [])
|
|
2107
2350
|
);
|
|
2108
|
-
const
|
|
2351
|
+
const getFormMetaBase = () => {
|
|
2352
|
+
const rootBase = buildContainerFieldStateBase(state, ROOT_PATH);
|
|
2353
|
+
return {
|
|
2354
|
+
...rootBase,
|
|
2355
|
+
submitting: state.submitting.value,
|
|
2356
|
+
submitCount: state.submitCount.value,
|
|
2357
|
+
submitError: state.submitError.value,
|
|
2358
|
+
instanceId: formInstanceId
|
|
2359
|
+
};
|
|
2360
|
+
};
|
|
2361
|
+
const fieldStateAccessorOptions = options.shouldShowErrors !== void 0 ? { shouldShowErrors: options.shouldShowErrors } : void 0;
|
|
2362
|
+
const getRootFieldStateAt = buildFieldStateAccessor(
|
|
2363
|
+
state,
|
|
2364
|
+
getFormMetaBase,
|
|
2365
|
+
fieldStateAccessorOptions
|
|
2366
|
+
);
|
|
2109
2367
|
const rootFieldState = getRootFieldStateAt([]);
|
|
2110
2368
|
const formMeta = readonly(
|
|
2111
2369
|
reactive({
|
|
@@ -2141,6 +2399,13 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2141
2399
|
// keep the explicit form-level computation for the gate.
|
|
2142
2400
|
valid,
|
|
2143
2401
|
errors: metaErrors,
|
|
2402
|
+
// `showErrors` / `firstError` flow through the same root
|
|
2403
|
+
// field-state computed as the rest of the FieldState surface,
|
|
2404
|
+
// so `form.meta.showErrors` matches `form.fields().showErrors`
|
|
2405
|
+
// exactly — the predicate runs once at the root and the result
|
|
2406
|
+
// is shared.
|
|
2407
|
+
showErrors: computed(() => rootFieldState.value.showErrors),
|
|
2408
|
+
firstError: computed(() => rootFieldState.value.firstError),
|
|
2144
2409
|
path: computed(() => rootFieldState.value.path),
|
|
2145
2410
|
blank: computed(() => rootFieldState.value.blank),
|
|
2146
2411
|
label: computed(() => rootFieldState.value.label),
|
|
@@ -2151,9 +2416,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2151
2416
|
submitting,
|
|
2152
2417
|
submitCount,
|
|
2153
2418
|
submitError,
|
|
2154
|
-
canUndo,
|
|
2155
|
-
canRedo,
|
|
2156
|
-
historySize,
|
|
2157
2419
|
// Per-`useForm()`-call identity. Stable for one mount; new on
|
|
2158
2420
|
// re-mount; orthogonal to `form.key` (which is the user-supplied
|
|
2159
2421
|
// shared identifier). Useful for devtools panels disambiguating
|
|
@@ -2175,9 +2437,11 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2175
2437
|
for (const pathKey of walked.paths) {
|
|
2176
2438
|
const segments = segmentsForPathKey(pathKey);
|
|
2177
2439
|
if (segments === null) continue;
|
|
2178
|
-
state.setValueAtPath(
|
|
2179
|
-
|
|
2180
|
-
|
|
2440
|
+
state.setValueAtPath(
|
|
2441
|
+
segments,
|
|
2442
|
+
state.schema.getDefaultAtPath(segments),
|
|
2443
|
+
withInstanceMeta({ blank: true })
|
|
2444
|
+
);
|
|
2181
2445
|
state.originalBlankPaths.add(pathKey);
|
|
2182
2446
|
}
|
|
2183
2447
|
}
|
|
@@ -2194,7 +2458,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2194
2458
|
};
|
|
2195
2459
|
const persist = async (pathInput, options2) => {
|
|
2196
2460
|
const segments = canonicalizePath(pathInput).segments;
|
|
2197
|
-
enforceSensitiveCheck(segments, options2?.acknowledgeSensitive === true);
|
|
2461
|
+
enforceSensitiveCheck(segments, options2?.acknowledgeSensitive === true, state.isSensitivePath);
|
|
2198
2462
|
if (persistence === void 0) return;
|
|
2199
2463
|
await persistence.writePathImmediately(segments);
|
|
2200
2464
|
};
|
|
@@ -2207,6 +2471,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2207
2471
|
const segments = canonicalizePath(pathInput).segments;
|
|
2208
2472
|
await persistence.clearPersistedDraft(segments);
|
|
2209
2473
|
};
|
|
2474
|
+
function touch(pathInput) {
|
|
2475
|
+
const segments = pathInput === void 0 ? ROOT_PATH : canonicalizePath(pathInput).segments;
|
|
2476
|
+
state.touchAtPath(segments);
|
|
2477
|
+
}
|
|
2210
2478
|
const focusFirstError = (options2) => {
|
|
2211
2479
|
const target = state.getFirstErrorElement(formInstanceId);
|
|
2212
2480
|
if (target === null) return false;
|
|
@@ -2224,7 +2492,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2224
2492
|
return readonlySetSnapshot(state.blankPaths);
|
|
2225
2493
|
});
|
|
2226
2494
|
const valuesProxy = buildValuesProxy(state.form);
|
|
2227
|
-
const fieldStateProxy = buildFieldStateProxy(state);
|
|
2495
|
+
const fieldStateProxy = buildFieldStateProxy(state, getFormMetaBase, fieldStateAccessorOptions);
|
|
2228
2496
|
return {
|
|
2229
2497
|
handleSubmit,
|
|
2230
2498
|
// `values` is the callable readonly Proxy. Each `get` trap reads
|
|
@@ -2237,6 +2505,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2237
2505
|
setValue: setValueImpl,
|
|
2238
2506
|
validate,
|
|
2239
2507
|
validateAsync,
|
|
2508
|
+
process,
|
|
2240
2509
|
register,
|
|
2241
2510
|
key: state.formKey,
|
|
2242
2511
|
errors: errorsProxy,
|
|
@@ -2253,8 +2522,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2253
2522
|
clearPersistedDraft,
|
|
2254
2523
|
focusFirstError,
|
|
2255
2524
|
scrollToFirstError,
|
|
2256
|
-
|
|
2257
|
-
|
|
2525
|
+
touch,
|
|
2526
|
+
history: formHistory,
|
|
2258
2527
|
append: fieldArrays.append,
|
|
2259
2528
|
prepend: fieldArrays.prepend,
|
|
2260
2529
|
insert: fieldArrays.insert,
|
|
@@ -2266,6 +2535,16 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2266
2535
|
};
|
|
2267
2536
|
}
|
|
2268
2537
|
|
|
2538
|
+
const defaultShouldShowErrors = (field, formMeta) => formMeta.submitCount > 0 || field.touched === true && field.dirty;
|
|
2539
|
+
const SHOW_ALWAYS = () => true;
|
|
2540
|
+
const SHOW_NEVER = () => false;
|
|
2541
|
+
function resolveShouldShowErrors(config) {
|
|
2542
|
+
if (config === void 0) return defaultShouldShowErrors;
|
|
2543
|
+
if (config === true) return SHOW_ALWAYS;
|
|
2544
|
+
if (config === false) return SHOW_NEVER;
|
|
2545
|
+
return config;
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2269
2548
|
function isHydratedFieldRecord(value) {
|
|
2270
2549
|
if (typeof value !== "object" || value === null) return false;
|
|
2271
2550
|
const r = value;
|
|
@@ -2289,6 +2568,42 @@ function warnMalformedHydration(formKey, kind, rawKey) {
|
|
|
2289
2568
|
`[attaform] hydration: skipping malformed ${kind} entry at key '${rawKey}' on form '${formKey}'. This usually means the SSR bundle is on a different version than the client (rolling deploy / stale cache).`
|
|
2290
2569
|
);
|
|
2291
2570
|
}
|
|
2571
|
+
function applyDuStubs(schema, data, options = {}) {
|
|
2572
|
+
const warned = options.warn === true ? /* @__PURE__ */ new Set() : void 0;
|
|
2573
|
+
return walkDuStubs(schema, data, options.basePath ?? [], warned);
|
|
2574
|
+
}
|
|
2575
|
+
function walkDuStubs(schema, value, path, warned) {
|
|
2576
|
+
if (value === null || value === void 0 || typeof value !== "object") return value;
|
|
2577
|
+
if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function") {
|
|
2578
|
+
return value;
|
|
2579
|
+
}
|
|
2580
|
+
if (Array.isArray(value)) {
|
|
2581
|
+
return value.map((item, i) => walkDuStubs(schema, item, [...path, i], warned));
|
|
2582
|
+
}
|
|
2583
|
+
const rec = value;
|
|
2584
|
+
const du = schema.getUnionDiscriminatorAtPath(path);
|
|
2585
|
+
if (du !== void 0) {
|
|
2586
|
+
const discValue = rec[du.discriminatorKey];
|
|
2587
|
+
if (discValue !== void 0 && !du.isVariantSelected(discValue)) {
|
|
2588
|
+
if (warned !== void 0 && __DEV__) {
|
|
2589
|
+
const dotted = path.map((s) => String(s)).join(".") || "(root)";
|
|
2590
|
+
const key = `${dotted}::${String(discValue)}`;
|
|
2591
|
+
if (!warned.has(key)) {
|
|
2592
|
+
warned.add(key);
|
|
2593
|
+
console.warn(
|
|
2594
|
+
`[attaform] defaultValues at '${dotted}' carries discriminator '${du.discriminatorKey}=${JSON.stringify(discValue)}' which isn't a known variant. Form mounts in a stub holding only the discriminator key. Validation will surface the mismatch.`
|
|
2595
|
+
);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
return { [du.discriminatorKey]: discValue };
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
const out = {};
|
|
2602
|
+
for (const k of Object.keys(rec)) {
|
|
2603
|
+
out[k] = walkDuStubs(schema, rec[k], [...path, k], warned);
|
|
2604
|
+
}
|
|
2605
|
+
return out;
|
|
2606
|
+
}
|
|
2292
2607
|
function isPathKeyUnder(existingKey, parentPath) {
|
|
2293
2608
|
const parsed = segmentsForPathKey(existingKey);
|
|
2294
2609
|
if (parsed === null) return false;
|
|
@@ -2298,18 +2613,96 @@ function isPathKeyUnder(existingKey, parentPath) {
|
|
|
2298
2613
|
}
|
|
2299
2614
|
return true;
|
|
2300
2615
|
}
|
|
2616
|
+
function stripSymbolsDeep(value) {
|
|
2617
|
+
if (value === null || typeof value !== "object") return value;
|
|
2618
|
+
if (Array.isArray(value)) {
|
|
2619
|
+
let mutated2 = false;
|
|
2620
|
+
const out2 = new Array(value.length);
|
|
2621
|
+
for (let i = 0; i < value.length; i++) {
|
|
2622
|
+
const cleaned = stripSymbolsDeep(value[i]);
|
|
2623
|
+
out2[i] = cleaned;
|
|
2624
|
+
if (cleaned !== value[i]) mutated2 = true;
|
|
2625
|
+
}
|
|
2626
|
+
return mutated2 ? out2 : value;
|
|
2627
|
+
}
|
|
2628
|
+
const proto = Object.getPrototypeOf(value);
|
|
2629
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
2630
|
+
const symKeys = Object.getOwnPropertySymbols(value);
|
|
2631
|
+
const stringKeys = Object.keys(value);
|
|
2632
|
+
let mutated = symKeys.length > 0;
|
|
2633
|
+
const out = {};
|
|
2634
|
+
const src = value;
|
|
2635
|
+
for (const k of stringKeys) {
|
|
2636
|
+
const cleaned = stripSymbolsDeep(src[k]);
|
|
2637
|
+
out[k] = cleaned;
|
|
2638
|
+
if (cleaned !== src[k]) mutated = true;
|
|
2639
|
+
}
|
|
2640
|
+
return mutated ? out : value;
|
|
2641
|
+
}
|
|
2642
|
+
function cloneVariantSnapshot(value) {
|
|
2643
|
+
if (value === null || typeof value !== "object") return value;
|
|
2644
|
+
const raw = toRaw(value);
|
|
2645
|
+
if (raw instanceof Date) return new Date(raw.getTime());
|
|
2646
|
+
if (raw instanceof Map) {
|
|
2647
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
2648
|
+
for (const [k, v] of raw.entries()) out2.set(cloneVariantSnapshot(k), cloneVariantSnapshot(v));
|
|
2649
|
+
return out2;
|
|
2650
|
+
}
|
|
2651
|
+
if (raw instanceof Set) {
|
|
2652
|
+
const out2 = /* @__PURE__ */ new Set();
|
|
2653
|
+
for (const v of raw) out2.add(cloneVariantSnapshot(v));
|
|
2654
|
+
return out2;
|
|
2655
|
+
}
|
|
2656
|
+
if (raw instanceof RegExp) return new RegExp(raw.source, raw.flags);
|
|
2657
|
+
if (Array.isArray(raw)) {
|
|
2658
|
+
const out2 = new Array(raw.length);
|
|
2659
|
+
for (let i = 0; i < raw.length; i++) out2[i] = cloneVariantSnapshot(raw[i]);
|
|
2660
|
+
return out2;
|
|
2661
|
+
}
|
|
2662
|
+
const src = raw;
|
|
2663
|
+
const out = {};
|
|
2664
|
+
for (const k of Object.keys(src)) out[k] = cloneVariantSnapshot(src[k]);
|
|
2665
|
+
return out;
|
|
2666
|
+
}
|
|
2301
2667
|
function createFormStore(options) {
|
|
2302
2668
|
const { formKey, schema, defaultValues, strict = true, hydration } = options;
|
|
2303
2669
|
const ssr = options.ssr === true;
|
|
2304
2670
|
const rememberVariants = options.rememberVariants !== false;
|
|
2305
2671
|
const fieldValidationMode = options.validateOn ?? "change";
|
|
2306
|
-
const fieldValidationDebounceMs =
|
|
2672
|
+
const fieldValidationDebounceMs = normalizeNumericOption({
|
|
2673
|
+
value: options.debounceMs ?? DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS,
|
|
2674
|
+
source: "useForm.debounceMs",
|
|
2675
|
+
allowInfinity: false,
|
|
2676
|
+
min: 0,
|
|
2677
|
+
defaultValue: DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS
|
|
2678
|
+
});
|
|
2307
2679
|
const fieldValidationState = /* @__PURE__ */ new Map();
|
|
2308
2680
|
const formChangeListeners = /* @__PURE__ */ new Set();
|
|
2309
2681
|
const submitSuccessListeners = /* @__PURE__ */ new Set();
|
|
2310
2682
|
const resetListeners = /* @__PURE__ */ new Set();
|
|
2311
2683
|
const persistOptIns = createPersistOptInRegistry();
|
|
2684
|
+
const noSyncPaths = /* @__PURE__ */ new Set();
|
|
2685
|
+
const noSyncPathCounts = /* @__PURE__ */ new Map();
|
|
2686
|
+
function incrementNoSyncOptOut(path) {
|
|
2687
|
+
const next = (noSyncPathCounts.get(path) ?? 0) + 1;
|
|
2688
|
+
noSyncPathCounts.set(path, next);
|
|
2689
|
+
if (next === 1) noSyncPaths.add(path);
|
|
2690
|
+
}
|
|
2691
|
+
function decrementNoSyncOptOut(path) {
|
|
2692
|
+
const current = noSyncPathCounts.get(path) ?? 0;
|
|
2693
|
+
if (current <= 1) {
|
|
2694
|
+
noSyncPathCounts.delete(path);
|
|
2695
|
+
noSyncPaths.delete(path);
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
noSyncPathCounts.set(path, current - 1);
|
|
2699
|
+
}
|
|
2312
2700
|
const coerceIndex = resolveCoercionIndex(options.coerce);
|
|
2701
|
+
const resolvedShouldShowErrors = resolveShouldShowErrors(
|
|
2702
|
+
options.shouldShowErrors
|
|
2703
|
+
);
|
|
2704
|
+
const resolvedIsSensitivePath = options.isSensitivePath ?? isSensitivePath;
|
|
2705
|
+
const resolvedSegmentMatchesSensitive = options.segmentMatchesSensitive ?? segmentMatchesSensitive;
|
|
2313
2706
|
const cleanupHooks = [];
|
|
2314
2707
|
const modules = /* @__PURE__ */ new Map();
|
|
2315
2708
|
const completedConstraints = defaultValues === void 0 ? void 0 : mergeStructural(schema, [], defaultValues);
|
|
@@ -2320,7 +2713,10 @@ function createFormStore(options) {
|
|
|
2320
2713
|
});
|
|
2321
2714
|
const schemaInitialData = schemaResponse.data;
|
|
2322
2715
|
const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
|
|
2323
|
-
const
|
|
2716
|
+
const stubbedInitialData = applyDuStubs(schema, initialData, {
|
|
2717
|
+
warn: true
|
|
2718
|
+
});
|
|
2719
|
+
const form = ref(stubbedInitialData);
|
|
2324
2720
|
const fields = reactive(/* @__PURE__ */ new Map());
|
|
2325
2721
|
const elements = reactive(/* @__PURE__ */ new Map());
|
|
2326
2722
|
const elementToFormInstance = /* @__PURE__ */ new WeakMap();
|
|
@@ -2336,6 +2732,40 @@ function createFormStore(options) {
|
|
|
2336
2732
|
originalBlankPaths.add(raw);
|
|
2337
2733
|
}
|
|
2338
2734
|
const variantMemory = /* @__PURE__ */ new Map();
|
|
2735
|
+
function clearVariantMemoryUnderPath(arrayPath) {
|
|
2736
|
+
for (const memKey of [...variantMemory.keys()]) {
|
|
2737
|
+
const segs = segmentsForPathKey(memKey);
|
|
2738
|
+
if (segs === null) continue;
|
|
2739
|
+
if (isPathPrefix(arrayPath, segs)) variantMemory.delete(memKey);
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
function clearVariantMemoryAtArrayIndices(arrayPath, indexFilter) {
|
|
2743
|
+
for (const memKey of [...variantMemory.keys()]) {
|
|
2744
|
+
const segs = segmentsForPathKey(memKey);
|
|
2745
|
+
if (segs === null) continue;
|
|
2746
|
+
if (!isPathPrefix(arrayPath, segs)) continue;
|
|
2747
|
+
if (segs.length <= arrayPath.length) continue;
|
|
2748
|
+
const idxSeg = segs[arrayPath.length];
|
|
2749
|
+
if (typeof idxSeg !== "number") continue;
|
|
2750
|
+
if (indexFilter(idxSeg)) variantMemory.delete(memKey);
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
function applyArrayOpToMemory(arrayPath, op) {
|
|
2754
|
+
switch (op.kind) {
|
|
2755
|
+
case "shift-from":
|
|
2756
|
+
clearVariantMemoryAtArrayIndices(arrayPath, (i) => i >= op.index);
|
|
2757
|
+
return;
|
|
2758
|
+
case "shift-range":
|
|
2759
|
+
clearVariantMemoryAtArrayIndices(arrayPath, (i) => i >= op.fromIndex && i <= op.toIndex);
|
|
2760
|
+
return;
|
|
2761
|
+
case "swap":
|
|
2762
|
+
clearVariantMemoryAtArrayIndices(arrayPath, (i) => i === op.a || i === op.b);
|
|
2763
|
+
return;
|
|
2764
|
+
case "replace-at":
|
|
2765
|
+
clearVariantMemoryAtArrayIndices(arrayPath, (i) => i === op.index);
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2339
2769
|
const pathOrdinals = /* @__PURE__ */ new Map();
|
|
2340
2770
|
let nextOrdinal = 0;
|
|
2341
2771
|
function ensurePathOrdinal(key) {
|
|
@@ -2487,9 +2917,35 @@ function createFormStore(options) {
|
|
|
2487
2917
|
}
|
|
2488
2918
|
}
|
|
2489
2919
|
function setValueAtPath(path, value, meta) {
|
|
2920
|
+
value = stripSymbolsDeep(value);
|
|
2921
|
+
value = schema.normalizeWriteValueAtPath(value, path);
|
|
2490
2922
|
if (!isSlimPrimitiveValid(schema, form, path, value)) {
|
|
2491
2923
|
return false;
|
|
2492
2924
|
}
|
|
2925
|
+
if (path.length >= 2) {
|
|
2926
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
2927
|
+
const ancestorPath = path.slice(0, i + 1);
|
|
2928
|
+
const du = schema.getUnionDiscriminatorAtPath(ancestorPath);
|
|
2929
|
+
if (du === void 0) continue;
|
|
2930
|
+
const nextSeg = path[i + 1];
|
|
2931
|
+
if (nextSeg === du.discriminatorKey) continue;
|
|
2932
|
+
const ancestorValue = getAtPath(form.value, ancestorPath);
|
|
2933
|
+
if (!isPlainRecord(ancestorValue)) continue;
|
|
2934
|
+
const discValue = ancestorValue[du.discriminatorKey];
|
|
2935
|
+
if (discValue === void 0) {
|
|
2936
|
+
return false;
|
|
2937
|
+
}
|
|
2938
|
+
if (!du.isVariantSelected(discValue)) {
|
|
2939
|
+
return false;
|
|
2940
|
+
}
|
|
2941
|
+
const variantDefault = du.getVariantDefault(discValue);
|
|
2942
|
+
if (!isPlainRecord(variantDefault)) continue;
|
|
2943
|
+
if (typeof nextSeg !== "string") continue;
|
|
2944
|
+
if (!(nextSeg in variantDefault)) {
|
|
2945
|
+
return false;
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2493
2949
|
if (meta?.skipDiscriminatorReshape !== true) {
|
|
2494
2950
|
if (path.length > 0) {
|
|
2495
2951
|
const last = path[path.length - 1];
|
|
@@ -2510,6 +2966,14 @@ function createFormStore(options) {
|
|
|
2510
2966
|
meta
|
|
2511
2967
|
);
|
|
2512
2968
|
}
|
|
2969
|
+
return reshapeUnionVariant(
|
|
2970
|
+
parentPath,
|
|
2971
|
+
oldValue,
|
|
2972
|
+
value,
|
|
2973
|
+
{ [last]: value },
|
|
2974
|
+
void 0,
|
|
2975
|
+
meta
|
|
2976
|
+
);
|
|
2513
2977
|
}
|
|
2514
2978
|
}
|
|
2515
2979
|
}
|
|
@@ -2518,12 +2982,13 @@ function createFormStore(options) {
|
|
|
2518
2982
|
const selfDU = schema.getUnionDiscriminatorAtPath(path);
|
|
2519
2983
|
if (selfDU !== void 0) {
|
|
2520
2984
|
const valueRecord = value;
|
|
2521
|
-
const
|
|
2985
|
+
const discKey = selfDU.discriminatorKey;
|
|
2986
|
+
const discValue = valueRecord[discKey];
|
|
2987
|
+
const currentUnionValue = getAtPath(form.value, path);
|
|
2988
|
+
const oldDiscValue = isPlainRecord(currentUnionValue) ? currentUnionValue[discKey] : void 0;
|
|
2522
2989
|
if (discValue !== void 0) {
|
|
2523
2990
|
const variantDefault = selfDU.getVariantDefault(discValue);
|
|
2524
2991
|
if (variantDefault !== void 0 && isPlainRecord(variantDefault)) {
|
|
2525
|
-
const currentUnionValue = getAtPath(form.value, path);
|
|
2526
|
-
const oldDiscValue = isPlainRecord(currentUnionValue) ? currentUnionValue[selfDU.discriminatorKey] : void 0;
|
|
2527
2992
|
return reshapeUnionVariant(
|
|
2528
2993
|
path,
|
|
2529
2994
|
oldDiscValue,
|
|
@@ -2533,7 +2998,16 @@ function createFormStore(options) {
|
|
|
2533
2998
|
meta
|
|
2534
2999
|
);
|
|
2535
3000
|
}
|
|
3001
|
+
return reshapeUnionVariant(
|
|
3002
|
+
path,
|
|
3003
|
+
oldDiscValue,
|
|
3004
|
+
discValue,
|
|
3005
|
+
{ [discKey]: discValue },
|
|
3006
|
+
void 0,
|
|
3007
|
+
meta
|
|
3008
|
+
);
|
|
2536
3009
|
}
|
|
3010
|
+
return reshapeUnionVariant(path, oldDiscValue, void 0, {}, void 0, meta);
|
|
2537
3011
|
}
|
|
2538
3012
|
}
|
|
2539
3013
|
}
|
|
@@ -2550,12 +3024,17 @@ function createFormStore(options) {
|
|
|
2550
3024
|
}
|
|
2551
3025
|
const nextForm = setAtPathWithSchemaFill(form.value, schema, path, completedValue);
|
|
2552
3026
|
applyFormReplacement(nextForm, meta);
|
|
2553
|
-
if (
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
3027
|
+
if (meta?.arrayOp !== void 0) {
|
|
3028
|
+
applyArrayOpToMemory(path, meta.arrayOp);
|
|
3029
|
+
} else if (Array.isArray(value) && Array.isArray(currentValue)) {
|
|
3030
|
+
clearVariantMemoryUnderPath(path);
|
|
3031
|
+
}
|
|
3032
|
+
const effectiveModeAfterWrite = meta?.instance?.validateOn ?? fieldValidationMode;
|
|
3033
|
+
if (effectiveModeAfterWrite === "change") {
|
|
3034
|
+
scheduleFieldValidation(path, false, {
|
|
3035
|
+
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3036
|
+
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3037
|
+
});
|
|
2559
3038
|
}
|
|
2560
3039
|
return true;
|
|
2561
3040
|
}
|
|
@@ -2564,9 +3043,10 @@ function createFormStore(options) {
|
|
|
2564
3043
|
const parentKey = canonicalizePath(parentPath).key;
|
|
2565
3044
|
let baseline = variantDefault;
|
|
2566
3045
|
let restoredBlanks;
|
|
2567
|
-
|
|
3046
|
+
const effectiveRemember = meta?.instance?.rememberVariants ?? rememberVariants;
|
|
3047
|
+
if (effectiveRemember && !sameDisc) {
|
|
2568
3048
|
if (oldDiscValue !== void 0) {
|
|
2569
|
-
const currentValue2 =
|
|
3049
|
+
const currentValue2 = cloneVariantSnapshot(getAtPath(form.value, parentPath));
|
|
2570
3050
|
const outgoingBlanks = [];
|
|
2571
3051
|
for (const k of blankPaths) {
|
|
2572
3052
|
if (isPathKeyUnder(k, parentPath)) outgoingBlanks.push(k);
|
|
@@ -2588,7 +3068,10 @@ function createFormStore(options) {
|
|
|
2588
3068
|
restoredBlanks = [...restored.blankPaths];
|
|
2589
3069
|
}
|
|
2590
3070
|
}
|
|
2591
|
-
const
|
|
3071
|
+
const layered = consumerOverrides !== void 0 ? { ...baseline, ...consumerOverrides } : baseline;
|
|
3072
|
+
const finalValue = applyDuStubs(schema, layered, {
|
|
3073
|
+
basePath: parentPath
|
|
3074
|
+
});
|
|
2592
3075
|
let newBlankPaths;
|
|
2593
3076
|
if (restoredBlanks !== void 0) {
|
|
2594
3077
|
newBlankPaths = restoredBlanks;
|
|
@@ -2607,9 +3090,10 @@ function createFormStore(options) {
|
|
|
2607
3090
|
for (const k of newBlankPaths) blankPaths.add(k);
|
|
2608
3091
|
return true;
|
|
2609
3092
|
}
|
|
2610
|
-
const nextForm = parentPath.length === 0 ? finalValue :
|
|
3093
|
+
const nextForm = parentPath.length === 0 ? finalValue : setAtPathWithSchemaFill(form.value, schema, parentPath, finalValue);
|
|
2611
3094
|
let appliedSync = false;
|
|
2612
|
-
|
|
3095
|
+
const reshapeMode = meta?.instance?.validateOn ?? fieldValidationMode;
|
|
3096
|
+
if (reshapeMode === "change") {
|
|
2613
3097
|
const syncOrPromise = schema.validateAtPath(finalValue, parentPath, { sync: true });
|
|
2614
3098
|
if (!(syncOrPromise instanceof Promise)) {
|
|
2615
3099
|
const reStamped = syncOrPromise.success ? [] : syncOrPromise.errors.map((err) => ({
|
|
@@ -2629,17 +3113,18 @@ function createFormStore(options) {
|
|
|
2629
3113
|
}
|
|
2630
3114
|
applyFormReplacement(nextForm, meta);
|
|
2631
3115
|
for (const k of newBlankPaths) blankPaths.add(k);
|
|
2632
|
-
if (
|
|
2633
|
-
scheduleFieldValidation(
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
);
|
|
3116
|
+
if (reshapeMode === "change" && !appliedSync) {
|
|
3117
|
+
scheduleFieldValidation(parentPath, false, {
|
|
3118
|
+
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3119
|
+
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3120
|
+
});
|
|
2638
3121
|
}
|
|
2639
3122
|
return true;
|
|
2640
3123
|
}
|
|
2641
|
-
function scheduleFieldValidation(path, immediate) {
|
|
2642
|
-
|
|
3124
|
+
function scheduleFieldValidation(path, immediate, override) {
|
|
3125
|
+
const effectiveMode = override?.mode ?? fieldValidationMode;
|
|
3126
|
+
if (effectiveMode === "submit") return;
|
|
3127
|
+
const effectiveDebounce = override?.debounceMs ?? fieldValidationDebounceMs;
|
|
2643
3128
|
const { key } = canonicalizePath(path);
|
|
2644
3129
|
const prev = fieldValidationState.get(key);
|
|
2645
3130
|
if (prev !== void 0) {
|
|
@@ -2653,8 +3138,17 @@ function createFormStore(options) {
|
|
|
2653
3138
|
fresh.timer = null;
|
|
2654
3139
|
if (controller.signal.aborted) return;
|
|
2655
3140
|
const data = getAtPath(form.value, path);
|
|
2656
|
-
|
|
2657
|
-
|
|
3141
|
+
let activeIncremented = false;
|
|
3142
|
+
try {
|
|
3143
|
+
activeValidations.value += 1;
|
|
3144
|
+
activeIncremented = true;
|
|
3145
|
+
incFieldValidation(key);
|
|
3146
|
+
} catch (err) {
|
|
3147
|
+
if (activeIncremented) {
|
|
3148
|
+
activeValidations.value = Math.max(0, activeValidations.value - 1);
|
|
3149
|
+
}
|
|
3150
|
+
throw err;
|
|
3151
|
+
}
|
|
2658
3152
|
void Promise.resolve().then(() => schema.validateAtPath(data, path)).then((response) => {
|
|
2659
3153
|
if (controller.signal.aborted) return;
|
|
2660
3154
|
const reStamped = response.success ? [] : response.errors.map((err) => ({
|
|
@@ -2668,10 +3162,10 @@ function createFormStore(options) {
|
|
|
2668
3162
|
decFieldValidation(key);
|
|
2669
3163
|
});
|
|
2670
3164
|
};
|
|
2671
|
-
if (immediate ||
|
|
3165
|
+
if (immediate || effectiveDebounce === 0) {
|
|
2672
3166
|
run();
|
|
2673
3167
|
} else {
|
|
2674
|
-
fresh.timer = setTimeout(run,
|
|
3168
|
+
fresh.timer = setTimeout(run, effectiveDebounce);
|
|
2675
3169
|
}
|
|
2676
3170
|
}
|
|
2677
3171
|
function cancelFieldValidation() {
|
|
@@ -2735,13 +3229,26 @@ function createFormStore(options) {
|
|
|
2735
3229
|
submitSuccessListeners.clear();
|
|
2736
3230
|
resetListeners.clear();
|
|
2737
3231
|
persistOptIns.clear();
|
|
3232
|
+
noSyncPaths.clear();
|
|
3233
|
+
noSyncPathCounts.clear();
|
|
2738
3234
|
}
|
|
2739
3235
|
function getValueAtPath(path) {
|
|
2740
3236
|
return getAtPath(form.value, path);
|
|
2741
3237
|
}
|
|
3238
|
+
function rerouteFormLevelEntry(err) {
|
|
3239
|
+
if (err.path.length === 0) {
|
|
3240
|
+
return { ...err, path: [...FORM_ERRORS_PATH] };
|
|
3241
|
+
}
|
|
3242
|
+
return err;
|
|
3243
|
+
}
|
|
3244
|
+
function pathKeyForEntry(err) {
|
|
3245
|
+
if (err.path.length === 0) return FORM_ERRORS_PATH_KEY;
|
|
3246
|
+
return canonicalizePath(err.path).key;
|
|
3247
|
+
}
|
|
2742
3248
|
function appendErrorsTo(map, entries) {
|
|
2743
|
-
for (const
|
|
2744
|
-
const
|
|
3249
|
+
for (const raw of entries) {
|
|
3250
|
+
const err = rerouteFormLevelEntry(raw);
|
|
3251
|
+
const key = pathKeyForEntry(err);
|
|
2745
3252
|
const current = map.get(key);
|
|
2746
3253
|
if (current === void 0) {
|
|
2747
3254
|
map.set(key, [err]);
|
|
@@ -2771,16 +3278,18 @@ function createFormStore(options) {
|
|
|
2771
3278
|
schemaErrors.set(key, [...entries]);
|
|
2772
3279
|
}
|
|
2773
3280
|
function applySchemaErrorsForSubtree(path, entries) {
|
|
2774
|
-
const
|
|
3281
|
+
const parentKey = path.length === 0 ? FORM_ERRORS_PATH_KEY : canonicalizePath(path).key;
|
|
2775
3282
|
const grouped = /* @__PURE__ */ new Map();
|
|
2776
|
-
for (const
|
|
2777
|
-
const
|
|
3283
|
+
for (const raw of entries) {
|
|
3284
|
+
const err = rerouteFormLevelEntry(raw);
|
|
3285
|
+
const key = pathKeyForEntry(err);
|
|
2778
3286
|
const list = grouped.get(key);
|
|
2779
3287
|
if (list === void 0) grouped.set(key, [err]);
|
|
2780
3288
|
else list.push(err);
|
|
2781
3289
|
}
|
|
2782
3290
|
if (!grouped.has(parentKey)) schemaErrors.delete(parentKey);
|
|
2783
3291
|
for (const existingKey of [...schemaErrors.keys()]) {
|
|
3292
|
+
if (existingKey === parentKey) continue;
|
|
2784
3293
|
if (isPathKeyUnder(existingKey, path) && !grouped.has(existingKey)) {
|
|
2785
3294
|
schemaErrors.delete(existingKey);
|
|
2786
3295
|
}
|
|
@@ -2856,7 +3365,7 @@ function createFormStore(options) {
|
|
|
2856
3365
|
if (current?.connected === true) return;
|
|
2857
3366
|
touchFieldRecord(key, path, { connected: true });
|
|
2858
3367
|
}
|
|
2859
|
-
function markFocused(path, focused) {
|
|
3368
|
+
function markFocused(path, focused, meta) {
|
|
2860
3369
|
const { key } = canonicalizePath(path);
|
|
2861
3370
|
touchFieldRecord(key, path, {
|
|
2862
3371
|
focused,
|
|
@@ -2865,24 +3374,45 @@ function createFormStore(options) {
|
|
|
2865
3374
|
// a field is currently focused we keep whatever value it held.
|
|
2866
3375
|
touched: focused ? fields.get(key)?.touched ?? null : true
|
|
2867
3376
|
});
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
);
|
|
3377
|
+
const focusMode = meta?.instance?.validateOn ?? fieldValidationMode;
|
|
3378
|
+
if (!focused && focusMode === "blur") {
|
|
3379
|
+
scheduleFieldValidation(path, true, {
|
|
3380
|
+
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3381
|
+
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3382
|
+
});
|
|
2874
3383
|
}
|
|
2875
3384
|
}
|
|
2876
3385
|
function markTouched(path) {
|
|
2877
3386
|
const { key } = canonicalizePath(path);
|
|
2878
3387
|
touchFieldRecord(key, path, { touched: true });
|
|
2879
3388
|
}
|
|
3389
|
+
function touchAtPath(segments) {
|
|
3390
|
+
const formValue = form.value;
|
|
3391
|
+
let touchedAny = false;
|
|
3392
|
+
for (const [, entry] of originals) {
|
|
3393
|
+
if (!isPathPrefix(segments, entry.segments)) continue;
|
|
3394
|
+
if (!hasAtPath(formValue, entry.segments)) continue;
|
|
3395
|
+
touchedAny = true;
|
|
3396
|
+
const leafKey = canonicalizePath(entry.segments).key;
|
|
3397
|
+
const current = fields.get(leafKey);
|
|
3398
|
+
if (current?.touched === true) continue;
|
|
3399
|
+
touchFieldRecord(leafKey, entry.segments, { touched: true });
|
|
3400
|
+
}
|
|
3401
|
+
if (!touchedAny && __DEV__) {
|
|
3402
|
+
console.warn(
|
|
3403
|
+
`[attaform] form.touch(): no fields resolved at path ${JSON.stringify(segments)}. Check the path matches an existing field or container.`
|
|
3404
|
+
);
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
2880
3407
|
function reset(nextDefaultValues) {
|
|
2881
|
-
const
|
|
3408
|
+
const resetSource = nextDefaultValues ?? defaultValues;
|
|
3409
|
+
const completedResetConstraints = resetSource === void 0 ? void 0 : mergeStructural(schema, [], resetSource);
|
|
3410
|
+
const resetResponse = schema.getDefaultValues({
|
|
2882
3411
|
useDefaultSchemaValues: true,
|
|
2883
|
-
constraints:
|
|
3412
|
+
constraints: completedResetConstraints,
|
|
2884
3413
|
strict
|
|
2885
|
-
})
|
|
3414
|
+
});
|
|
3415
|
+
const next = resetResponse.data;
|
|
2886
3416
|
applyFormReplacement(next);
|
|
2887
3417
|
originals.clear();
|
|
2888
3418
|
diffAndApply({}, next, [], (patch) => {
|
|
@@ -2901,6 +3431,24 @@ function createFormStore(options) {
|
|
|
2901
3431
|
}
|
|
2902
3432
|
schemaErrors.clear();
|
|
2903
3433
|
userErrors.clear();
|
|
3434
|
+
if (strict && !resetResponse.success) {
|
|
3435
|
+
setAllSchemaErrors(resetResponse.errors);
|
|
3436
|
+
}
|
|
3437
|
+
if (strict) {
|
|
3438
|
+
const syncResult = schema.validateAtPath(form.value, void 0, { sync: true });
|
|
3439
|
+
if (!(syncResult instanceof Promise) && !syncResult.success) {
|
|
3440
|
+
applySchemaErrorsForSubtree([], syncResult.errors);
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
firstValidationDone.value = !strict || schema.needsAsyncValidation?.() !== true;
|
|
3444
|
+
const needsAsync = !ssr && strict && schema.needsAsyncValidation?.() === true;
|
|
3445
|
+
if (needsAsync) {
|
|
3446
|
+
queueMicrotask(() => scheduleFieldValidation(
|
|
3447
|
+
[],
|
|
3448
|
+
true
|
|
3449
|
+
/* immediate */
|
|
3450
|
+
));
|
|
3451
|
+
}
|
|
2904
3452
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2905
3453
|
for (const [pathKey, record] of fields) {
|
|
2906
3454
|
fields.set(pathKey, {
|
|
@@ -2944,30 +3492,28 @@ function createFormStore(options) {
|
|
|
2944
3492
|
`[attaform] resetField: leaf write rejected for path '${targetKey}' \u2014 originals contain a value that doesn't satisfy the slim primitive shape. This is a bug in the construction pipeline.`
|
|
2945
3493
|
);
|
|
2946
3494
|
}
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
`[attaform] resetField: subtree write rejected at path '${targetKey}' \u2014 originals contain values that don't satisfy the slim primitive shape. This is a bug in the construction pipeline.`
|
|
2970
|
-
);
|
|
3495
|
+
} else {
|
|
3496
|
+
let subtree = void 0;
|
|
3497
|
+
let anyMatch = false;
|
|
3498
|
+
for (const [, entry] of originals) {
|
|
3499
|
+
const leafSegments = entry.segments;
|
|
3500
|
+
if (!isPathPrefix(targetSegments, leafSegments)) continue;
|
|
3501
|
+
if (leafSegments.length === targetSegments.length) continue;
|
|
3502
|
+
anyMatch = true;
|
|
3503
|
+
const relative = leafSegments.slice(targetSegments.length);
|
|
3504
|
+
if (subtree === void 0) {
|
|
3505
|
+
subtree = typeof relative[0] === "number" ? [] : {};
|
|
3506
|
+
}
|
|
3507
|
+
subtree = setAtPath(subtree, relative, entry.value);
|
|
3508
|
+
}
|
|
3509
|
+
if (anyMatch) {
|
|
3510
|
+
const wroteSubtree = setValueAtPath(targetSegments, subtree);
|
|
3511
|
+
if (!wroteSubtree) {
|
|
3512
|
+
console.error(
|
|
3513
|
+
`[attaform] resetField: subtree write rejected at path '${targetKey}' \u2014 originals contain values that don't satisfy the slim primitive shape. This is a bug in the construction pipeline.`
|
|
3514
|
+
);
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
2971
3517
|
}
|
|
2972
3518
|
deleteErrorsUnderPrefix(schemaErrors, targetSegments);
|
|
2973
3519
|
deleteErrorsUnderPrefix(userErrors, targetSegments);
|
|
@@ -3053,6 +3599,7 @@ function createFormStore(options) {
|
|
|
3053
3599
|
originals,
|
|
3054
3600
|
schema,
|
|
3055
3601
|
ssr,
|
|
3602
|
+
shouldShowErrors: resolvedShouldShowErrors,
|
|
3056
3603
|
submitting,
|
|
3057
3604
|
activeSubmissions,
|
|
3058
3605
|
submitCount,
|
|
@@ -3079,6 +3626,7 @@ function createFormStore(options) {
|
|
|
3079
3626
|
deregisterElement,
|
|
3080
3627
|
markFocused,
|
|
3081
3628
|
markTouched,
|
|
3629
|
+
touchAtPath,
|
|
3082
3630
|
markConnectedOptimistically,
|
|
3083
3631
|
isPristineAtPath,
|
|
3084
3632
|
getFieldRecord,
|
|
@@ -3095,6 +3643,11 @@ function createFormStore(options) {
|
|
|
3095
3643
|
awaitPendingWrites,
|
|
3096
3644
|
modules,
|
|
3097
3645
|
persistOptIns,
|
|
3646
|
+
isSensitivePath: resolvedIsSensitivePath,
|
|
3647
|
+
segmentMatchesSensitive: resolvedSegmentMatchesSensitive,
|
|
3648
|
+
noSyncPaths,
|
|
3649
|
+
incrementNoSyncOptOut,
|
|
3650
|
+
decrementNoSyncOptOut,
|
|
3098
3651
|
coerceIndex,
|
|
3099
3652
|
blankPaths,
|
|
3100
3653
|
originalBlankPaths,
|
|
@@ -3102,43 +3655,140 @@ function createFormStore(options) {
|
|
|
3102
3655
|
};
|
|
3103
3656
|
}
|
|
3104
3657
|
|
|
3105
|
-
function getComputedSchema(formKey, schemaOrCallback) {
|
|
3106
|
-
if (typeof schemaOrCallback === "function") return schemaOrCallback(formKey);
|
|
3658
|
+
function getComputedSchema(formKey, schemaOrCallback, options) {
|
|
3659
|
+
if (typeof schemaOrCallback === "function") return schemaOrCallback(formKey, options);
|
|
3107
3660
|
return schemaOrCallback;
|
|
3108
3661
|
}
|
|
3109
3662
|
|
|
3663
|
+
function captureErrorEntries(map) {
|
|
3664
|
+
const out = [];
|
|
3665
|
+
for (const [k, v] of map) out.push([k, [...v]]);
|
|
3666
|
+
return out;
|
|
3667
|
+
}
|
|
3668
|
+
function errorsEqual(a, b) {
|
|
3669
|
+
if (a.length !== b.length) return false;
|
|
3670
|
+
const bMap = /* @__PURE__ */ new Map();
|
|
3671
|
+
for (const [k, v] of b) bMap.set(k, v);
|
|
3672
|
+
for (const [k, v] of a) {
|
|
3673
|
+
const bv = bMap.get(k);
|
|
3674
|
+
if (bv === void 0) return false;
|
|
3675
|
+
if (v.length !== bv.length) return false;
|
|
3676
|
+
for (let i = 0; i < v.length; i++) {
|
|
3677
|
+
const av = v[i];
|
|
3678
|
+
const bvi = bv[i];
|
|
3679
|
+
if (av === bvi) continue;
|
|
3680
|
+
if (av.message !== bvi.message) return false;
|
|
3681
|
+
if (av.code !== bvi.code) return false;
|
|
3682
|
+
if (av.formKey !== bvi.formKey) return false;
|
|
3683
|
+
if (av.path !== bvi.path) {
|
|
3684
|
+
if (av.path.length !== bvi.path.length) return false;
|
|
3685
|
+
for (let j = 0; j < av.path.length; j++) {
|
|
3686
|
+
if (av.path[j] !== bvi.path[j]) return false;
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
return true;
|
|
3692
|
+
}
|
|
3693
|
+
function diffBlankPaths$1(prev, curr) {
|
|
3694
|
+
const added = [];
|
|
3695
|
+
const removed = [];
|
|
3696
|
+
for (const k of curr) if (!prev.has(k)) added.push(k);
|
|
3697
|
+
for (const k of prev) if (!curr.has(k)) removed.push(k);
|
|
3698
|
+
return { added, removed };
|
|
3699
|
+
}
|
|
3700
|
+
function applyDeltaForward(snap, d) {
|
|
3701
|
+
const nextForm = applyPatchesForward(snap.form, d.formPatches);
|
|
3702
|
+
const nextBlank = new Set(snap.blankPaths);
|
|
3703
|
+
for (const k of d.blankPathsRemoved) nextBlank.delete(k);
|
|
3704
|
+
for (const k of d.blankPathsAdded) nextBlank.add(k);
|
|
3705
|
+
return {
|
|
3706
|
+
form: nextForm,
|
|
3707
|
+
blankPaths: [...nextBlank],
|
|
3708
|
+
schemaErrors: d.schemaErrors !== void 0 ? d.schemaErrors.after : snap.schemaErrors,
|
|
3709
|
+
userErrors: d.userErrors !== void 0 ? d.userErrors.after : snap.userErrors
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3712
|
+
function applyDeltaInverse(snap, d) {
|
|
3713
|
+
const prevForm = applyPatchesInverse(snap.form, d.formPatches);
|
|
3714
|
+
const prevBlank = new Set(snap.blankPaths);
|
|
3715
|
+
for (const k of d.blankPathsAdded) prevBlank.delete(k);
|
|
3716
|
+
for (const k of d.blankPathsRemoved) prevBlank.add(k);
|
|
3717
|
+
return {
|
|
3718
|
+
form: prevForm,
|
|
3719
|
+
blankPaths: [...prevBlank],
|
|
3720
|
+
schemaErrors: d.schemaErrors !== void 0 ? d.schemaErrors.before : snap.schemaErrors,
|
|
3721
|
+
userErrors: d.userErrors !== void 0 ? d.userErrors.before : snap.userErrors
|
|
3722
|
+
};
|
|
3723
|
+
}
|
|
3110
3724
|
function createHistoryModule(state, config) {
|
|
3111
|
-
const max =
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3725
|
+
const max = normalizeNumericOption({
|
|
3726
|
+
value: typeof config === "object" ? config.max ?? DEFAULT_HISTORY_MAX_SNAPSHOTS : DEFAULT_HISTORY_MAX_SNAPSHOTS,
|
|
3727
|
+
source: "useForm.history.max",
|
|
3728
|
+
allowInfinity: false,
|
|
3729
|
+
min: 0,
|
|
3730
|
+
defaultValue: DEFAULT_HISTORY_MAX_SNAPSHOTS
|
|
3731
|
+
});
|
|
3115
3732
|
function captureSnapshot() {
|
|
3116
3733
|
return {
|
|
3117
3734
|
form: structuralSnapshot(state.form.value),
|
|
3118
3735
|
blankPaths: [...state.blankPaths],
|
|
3119
|
-
schemaErrors:
|
|
3120
|
-
userErrors:
|
|
3736
|
+
schemaErrors: captureErrorEntries(state.schemaErrors),
|
|
3737
|
+
userErrors: captureErrorEntries(state.userErrors)
|
|
3121
3738
|
};
|
|
3122
3739
|
}
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3740
|
+
const initial = captureSnapshot();
|
|
3741
|
+
const base = shallowRef(initial);
|
|
3742
|
+
const currentSnapshot = shallowRef(initial);
|
|
3743
|
+
const undoDeltas = shallowRef([]);
|
|
3744
|
+
const redoDeltas = shallowRef([]);
|
|
3745
|
+
let suppressNext = false;
|
|
3746
|
+
function appendDelta(delta, newCurrent) {
|
|
3747
|
+
if (max === 0) {
|
|
3748
|
+
base.value = newCurrent;
|
|
3749
|
+
currentSnapshot.value = newCurrent;
|
|
3750
|
+
redoDeltas.value = [];
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
undoDeltas.value = [...undoDeltas.value, delta];
|
|
3754
|
+
redoDeltas.value = [];
|
|
3755
|
+
currentSnapshot.value = newCurrent;
|
|
3756
|
+
while (1 + undoDeltas.value.length > max && undoDeltas.value.length > 0) {
|
|
3757
|
+
const oldest = undoDeltas.value[0];
|
|
3758
|
+
base.value = applyDeltaForward(base.value, oldest);
|
|
3759
|
+
undoDeltas.value = undoDeltas.value.slice(1);
|
|
3760
|
+
}
|
|
3127
3761
|
}
|
|
3128
|
-
|
|
3129
|
-
const unsubscribeChange = state.onFormChange(() => {
|
|
3762
|
+
const unsubscribeChange = state.onFormChange((_next, meta) => {
|
|
3130
3763
|
if (suppressNext) {
|
|
3131
3764
|
suppressNext = false;
|
|
3132
3765
|
return;
|
|
3133
3766
|
}
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3767
|
+
if (meta?.hydration === true) {
|
|
3768
|
+
clear();
|
|
3769
|
+
return;
|
|
3770
|
+
}
|
|
3771
|
+
if (meta?.crossTab === true) {
|
|
3772
|
+
currentSnapshot.value = captureSnapshot();
|
|
3773
|
+
return;
|
|
3774
|
+
}
|
|
3775
|
+
const newSnap = captureSnapshot();
|
|
3776
|
+
const prevSnap = currentSnapshot.value;
|
|
3777
|
+
const formPatches = [];
|
|
3778
|
+
diffAndApply(prevSnap.form, newSnap.form, [], (p) => formPatches.push(p));
|
|
3779
|
+
const prevBlankSet = new Set(prevSnap.blankPaths);
|
|
3780
|
+
const currBlankSet = new Set(newSnap.blankPaths);
|
|
3781
|
+
const blankDiff = diffBlankPaths$1(prevBlankSet, currBlankSet);
|
|
3782
|
+
const delta = {
|
|
3783
|
+
formPatches,
|
|
3784
|
+
blankPathsAdded: blankDiff.added,
|
|
3785
|
+
blankPathsRemoved: blankDiff.removed,
|
|
3786
|
+
...errorsEqual(prevSnap.schemaErrors, newSnap.schemaErrors) ? {} : { schemaErrors: { before: prevSnap.schemaErrors, after: newSnap.schemaErrors } },
|
|
3787
|
+
...errorsEqual(prevSnap.userErrors, newSnap.userErrors) ? {} : { userErrors: { before: prevSnap.userErrors, after: newSnap.userErrors } }
|
|
3788
|
+
};
|
|
3789
|
+
appendDelta(delta, newSnap);
|
|
3140
3790
|
});
|
|
3141
|
-
function
|
|
3791
|
+
function restoreCurrent(snap) {
|
|
3142
3792
|
suppressNext = true;
|
|
3143
3793
|
state.blankPaths.clear();
|
|
3144
3794
|
for (const key of snap.blankPaths) state.blankPaths.add(key);
|
|
@@ -3151,38 +3801,46 @@ function createHistoryModule(state, config) {
|
|
|
3151
3801
|
state.setAllUserErrors(userFlat);
|
|
3152
3802
|
}
|
|
3153
3803
|
function undo() {
|
|
3154
|
-
if (
|
|
3155
|
-
const
|
|
3156
|
-
const
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3804
|
+
if (undoDeltas.value.length === 0) return false;
|
|
3805
|
+
const d = undoDeltas.value[undoDeltas.value.length - 1];
|
|
3806
|
+
const restored = applyDeltaInverse(currentSnapshot.value, d);
|
|
3807
|
+
redoDeltas.value = [...redoDeltas.value, d];
|
|
3808
|
+
undoDeltas.value = undoDeltas.value.slice(0, -1);
|
|
3809
|
+
currentSnapshot.value = restored;
|
|
3810
|
+
restoreCurrent(restored);
|
|
3161
3811
|
return true;
|
|
3162
3812
|
}
|
|
3163
3813
|
function redo() {
|
|
3164
|
-
if (
|
|
3165
|
-
const
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3814
|
+
if (redoDeltas.value.length === 0) return false;
|
|
3815
|
+
const d = redoDeltas.value[redoDeltas.value.length - 1];
|
|
3816
|
+
const next = applyDeltaForward(currentSnapshot.value, d);
|
|
3817
|
+
undoDeltas.value = [...undoDeltas.value, d];
|
|
3818
|
+
redoDeltas.value = redoDeltas.value.slice(0, -1);
|
|
3819
|
+
currentSnapshot.value = next;
|
|
3820
|
+
restoreCurrent(next);
|
|
3170
3821
|
return true;
|
|
3171
3822
|
}
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3823
|
+
function clear() {
|
|
3824
|
+
const fresh = captureSnapshot();
|
|
3825
|
+
base.value = fresh;
|
|
3826
|
+
currentSnapshot.value = fresh;
|
|
3827
|
+
undoDeltas.value = [];
|
|
3828
|
+
redoDeltas.value = [];
|
|
3829
|
+
}
|
|
3830
|
+
const canUndo = computed(() => undoDeltas.value.length > 0);
|
|
3831
|
+
const canRedo = computed(() => redoDeltas.value.length > 0);
|
|
3832
|
+
const historySize = computed(() => 1 + undoDeltas.value.length + redoDeltas.value.length);
|
|
3175
3833
|
return {
|
|
3176
3834
|
undo,
|
|
3177
3835
|
redo,
|
|
3836
|
+
clear,
|
|
3178
3837
|
canUndo,
|
|
3179
3838
|
canRedo,
|
|
3180
3839
|
historySize,
|
|
3181
3840
|
dispose() {
|
|
3182
3841
|
unsubscribeChange();
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
redoStack.value = [];
|
|
3842
|
+
undoDeltas.value = [];
|
|
3843
|
+
redoDeltas.value = [];
|
|
3186
3844
|
}
|
|
3187
3845
|
};
|
|
3188
3846
|
}
|
|
@@ -3200,12 +3858,368 @@ function hashStableString(input, seed = 0) {
|
|
|
3200
3858
|
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36).padStart(11, "0");
|
|
3201
3859
|
}
|
|
3202
3860
|
|
|
3861
|
+
const PROTOCOL_VERSION = 1;
|
|
3862
|
+
const JOIN_COLLECTION_WINDOW_MS = 50;
|
|
3863
|
+
const SNAPSHOT_TIMEOUT_MS = 200;
|
|
3864
|
+
const MAX_LEADER_ATTEMPTS = 3;
|
|
3865
|
+
function isDangerousSegment(s) {
|
|
3866
|
+
return s === "__proto__" || s === "constructor" || s === "prototype";
|
|
3867
|
+
}
|
|
3868
|
+
function pathContainsDangerousSegment(path) {
|
|
3869
|
+
for (let i = 0; i < path.length; i++) {
|
|
3870
|
+
if (isDangerousSegment(path[i])) return true;
|
|
3871
|
+
}
|
|
3872
|
+
return false;
|
|
3873
|
+
}
|
|
3874
|
+
function diffBlankPaths(prev, curr) {
|
|
3875
|
+
const added = [];
|
|
3876
|
+
const removed = [];
|
|
3877
|
+
const prevSet = new Set(prev);
|
|
3878
|
+
for (const k of curr) if (!prevSet.has(k)) added.push(k);
|
|
3879
|
+
for (const k of prev) if (!curr.has(k)) removed.push(k);
|
|
3880
|
+
return { added, removed };
|
|
3881
|
+
}
|
|
3882
|
+
function snapshotForm(form) {
|
|
3883
|
+
return structuralSnapshot(form);
|
|
3884
|
+
}
|
|
3885
|
+
function stripSensitivePathsDeep(value, pathSoFar, isSensitivePath) {
|
|
3886
|
+
if (value === null || typeof value !== "object") return value;
|
|
3887
|
+
if (Array.isArray(value)) {
|
|
3888
|
+
return value.map((item, i) => stripSensitivePathsDeep(item, [...pathSoFar, i], isSensitivePath));
|
|
3889
|
+
}
|
|
3890
|
+
const proto = Object.getPrototypeOf(value);
|
|
3891
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
3892
|
+
const out = {};
|
|
3893
|
+
const src = value;
|
|
3894
|
+
for (const key of Object.keys(src)) {
|
|
3895
|
+
const childPath = [...pathSoFar, key];
|
|
3896
|
+
if (isSensitivePath(childPath)) {
|
|
3897
|
+
out[key] = void 0;
|
|
3898
|
+
continue;
|
|
3899
|
+
}
|
|
3900
|
+
out[key] = stripSensitivePathsDeep(src[key], childPath, isSensitivePath);
|
|
3901
|
+
}
|
|
3902
|
+
return out;
|
|
3903
|
+
}
|
|
3904
|
+
function isValidSyncMessage(data) {
|
|
3905
|
+
if (data === null || typeof data !== "object") return false;
|
|
3906
|
+
const m = data;
|
|
3907
|
+
if (m["v"] !== PROTOCOL_VERSION) return false;
|
|
3908
|
+
if (typeof m["senderId"] !== "string") return false;
|
|
3909
|
+
if (typeof m["kind"] !== "string") return false;
|
|
3910
|
+
switch (m["kind"]) {
|
|
3911
|
+
case "hello":
|
|
3912
|
+
case "announce":
|
|
3913
|
+
return true;
|
|
3914
|
+
case "requestSnapshot":
|
|
3915
|
+
return typeof m["targetId"] === "string";
|
|
3916
|
+
case "snapshot":
|
|
3917
|
+
return Array.isArray(m["blankPaths"]) && "form" in m;
|
|
3918
|
+
case "patches":
|
|
3919
|
+
return Array.isArray(m["formPatches"]) && Array.isArray(m["blankPathsAdded"]) && Array.isArray(m["blankPathsRemoved"]);
|
|
3920
|
+
default:
|
|
3921
|
+
return false;
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
function generateSenderId() {
|
|
3925
|
+
try {
|
|
3926
|
+
return globalThis.crypto.randomUUID();
|
|
3927
|
+
} catch {
|
|
3928
|
+
return `atta-${Math.random().toString(36).slice(2)}-${Date.now().toString(36)}`;
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
function createMultiTabSyncModule(state, channelName, options) {
|
|
3932
|
+
if (typeof BroadcastChannel === "undefined") {
|
|
3933
|
+
return {
|
|
3934
|
+
dispose: () => void 0,
|
|
3935
|
+
lifecycle: () => "established",
|
|
3936
|
+
senderId: "",
|
|
3937
|
+
channelName
|
|
3938
|
+
};
|
|
3939
|
+
}
|
|
3940
|
+
let channel;
|
|
3941
|
+
try {
|
|
3942
|
+
channel = new BroadcastChannel(channelName);
|
|
3943
|
+
} catch {
|
|
3944
|
+
return {
|
|
3945
|
+
dispose: () => void 0,
|
|
3946
|
+
lifecycle: () => "established",
|
|
3947
|
+
senderId: "",
|
|
3948
|
+
channelName
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3951
|
+
const senderId = generateSenderId();
|
|
3952
|
+
let lifecycle = "joining";
|
|
3953
|
+
let disposed = false;
|
|
3954
|
+
const peerIds = /* @__PURE__ */ new Set();
|
|
3955
|
+
let joinCollectionTimer = null;
|
|
3956
|
+
let snapshotTimeoutTimer = null;
|
|
3957
|
+
let leaderAttempts = 0;
|
|
3958
|
+
let prior = {
|
|
3959
|
+
form: snapshotForm(state.form.value),
|
|
3960
|
+
blankPathsSnapshot: [...state.blankPaths]
|
|
3961
|
+
};
|
|
3962
|
+
function safePost(msg) {
|
|
3963
|
+
if (disposed) return;
|
|
3964
|
+
try {
|
|
3965
|
+
channel.postMessage(msg);
|
|
3966
|
+
} catch {
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
function refreshPrior() {
|
|
3970
|
+
prior = {
|
|
3971
|
+
form: snapshotForm(state.form.value),
|
|
3972
|
+
blankPathsSnapshot: [...state.blankPaths]
|
|
3973
|
+
};
|
|
3974
|
+
}
|
|
3975
|
+
function isPathLocallySuppressed(path) {
|
|
3976
|
+
if (pathContainsDangerousSegment(path)) return true;
|
|
3977
|
+
if (options.isSensitivePath(path)) return true;
|
|
3978
|
+
const { key } = canonicalizePath([...path]);
|
|
3979
|
+
if (options.noSyncPaths.has(key)) return true;
|
|
3980
|
+
return false;
|
|
3981
|
+
}
|
|
3982
|
+
function postPatches() {
|
|
3983
|
+
if (lifecycle !== "established") return;
|
|
3984
|
+
const next = snapshotForm(state.form.value);
|
|
3985
|
+
const rawPatches = [];
|
|
3986
|
+
diffAndApply(prior.form, next, [], (p) => rawPatches.push(p));
|
|
3987
|
+
const safePatches = [];
|
|
3988
|
+
for (const p of rawPatches) {
|
|
3989
|
+
if (isPathLocallySuppressed(p.path)) continue;
|
|
3990
|
+
safePatches.push(p);
|
|
3991
|
+
}
|
|
3992
|
+
const { added, removed } = diffBlankPaths(prior.blankPathsSnapshot, state.blankPaths);
|
|
3993
|
+
if (safePatches.length === 0 && added.length === 0 && removed.length === 0) {
|
|
3994
|
+
prior = { form: next, blankPathsSnapshot: [...state.blankPaths] };
|
|
3995
|
+
return;
|
|
3996
|
+
}
|
|
3997
|
+
safePost({
|
|
3998
|
+
v: PROTOCOL_VERSION,
|
|
3999
|
+
kind: "patches",
|
|
4000
|
+
senderId,
|
|
4001
|
+
formPatches: safePatches,
|
|
4002
|
+
blankPathsAdded: added,
|
|
4003
|
+
blankPathsRemoved: removed
|
|
4004
|
+
});
|
|
4005
|
+
prior = { form: next, blankPathsSnapshot: [...state.blankPaths] };
|
|
4006
|
+
}
|
|
4007
|
+
const unsubscribeChange = state.onFormChange((_next, meta) => {
|
|
4008
|
+
if (disposed) return;
|
|
4009
|
+
if (lifecycle !== "established") return;
|
|
4010
|
+
if (meta?.crossTab === true) return;
|
|
4011
|
+
if (meta?.hydration === true) {
|
|
4012
|
+
refreshPrior();
|
|
4013
|
+
return;
|
|
4014
|
+
}
|
|
4015
|
+
postPatches();
|
|
4016
|
+
});
|
|
4017
|
+
function applyIncomingForm(form, blankPaths) {
|
|
4018
|
+
state.blankPaths.clear();
|
|
4019
|
+
for (const k of blankPaths) state.blankPaths.add(k);
|
|
4020
|
+
state.applyFormReplacement(form, { crossTab: true, persist: false });
|
|
4021
|
+
refreshPrior();
|
|
4022
|
+
}
|
|
4023
|
+
function handlePatches(msg) {
|
|
4024
|
+
if (lifecycle !== "established") return;
|
|
4025
|
+
const safePatches = [];
|
|
4026
|
+
for (const p of msg.formPatches) {
|
|
4027
|
+
if (!Array.isArray(p.path)) continue;
|
|
4028
|
+
if (isPathLocallySuppressed(p.path)) continue;
|
|
4029
|
+
safePatches.push(p);
|
|
4030
|
+
}
|
|
4031
|
+
const safeBlankAdded = [];
|
|
4032
|
+
for (const k of msg.blankPathsAdded) {
|
|
4033
|
+
const segs = canonicalizePath(k).segments;
|
|
4034
|
+
if (isPathLocallySuppressed(segs)) continue;
|
|
4035
|
+
safeBlankAdded.push(k);
|
|
4036
|
+
}
|
|
4037
|
+
const safeBlankRemoved = [];
|
|
4038
|
+
for (const k of msg.blankPathsRemoved) {
|
|
4039
|
+
const segs = canonicalizePath(k).segments;
|
|
4040
|
+
if (isPathLocallySuppressed(segs)) continue;
|
|
4041
|
+
safeBlankRemoved.push(k);
|
|
4042
|
+
}
|
|
4043
|
+
if (safePatches.length === 0 && safeBlankAdded.length === 0 && safeBlankRemoved.length === 0) {
|
|
4044
|
+
return;
|
|
4045
|
+
}
|
|
4046
|
+
const candidate = applyPatchesForward(state.form.value, safePatches);
|
|
4047
|
+
try {
|
|
4048
|
+
options.validateForm(state.form.value);
|
|
4049
|
+
try {
|
|
4050
|
+
options.validateForm(candidate);
|
|
4051
|
+
} catch {
|
|
4052
|
+
return;
|
|
4053
|
+
}
|
|
4054
|
+
} catch {
|
|
4055
|
+
}
|
|
4056
|
+
const nextBlankPaths = new Set(state.blankPaths);
|
|
4057
|
+
for (const k of safeBlankRemoved) nextBlankPaths.delete(k);
|
|
4058
|
+
for (const k of safeBlankAdded) nextBlankPaths.add(k);
|
|
4059
|
+
applyIncomingForm(candidate, [...nextBlankPaths]);
|
|
4060
|
+
}
|
|
4061
|
+
function handleSnapshot(msg) {
|
|
4062
|
+
if (lifecycle !== "joining") return;
|
|
4063
|
+
try {
|
|
4064
|
+
options.validateForm(msg.form);
|
|
4065
|
+
} catch {
|
|
4066
|
+
return;
|
|
4067
|
+
}
|
|
4068
|
+
if (snapshotTimeoutTimer !== null) {
|
|
4069
|
+
clearTimeout(snapshotTimeoutTimer);
|
|
4070
|
+
snapshotTimeoutTimer = null;
|
|
4071
|
+
}
|
|
4072
|
+
if (joinCollectionTimer !== null) {
|
|
4073
|
+
clearTimeout(joinCollectionTimer);
|
|
4074
|
+
joinCollectionTimer = null;
|
|
4075
|
+
}
|
|
4076
|
+
applyIncomingForm(msg.form, msg.blankPaths);
|
|
4077
|
+
lifecycle = "established";
|
|
4078
|
+
peerIds.clear();
|
|
4079
|
+
}
|
|
4080
|
+
function respondToHello() {
|
|
4081
|
+
safePost({ v: PROTOCOL_VERSION, kind: "announce", senderId });
|
|
4082
|
+
}
|
|
4083
|
+
function respondToSnapshotRequest() {
|
|
4084
|
+
const scrubbedForm = stripSensitivePathsDeep(state.form.value, [], options.isSensitivePath);
|
|
4085
|
+
safePost({
|
|
4086
|
+
v: PROTOCOL_VERSION,
|
|
4087
|
+
kind: "snapshot",
|
|
4088
|
+
senderId,
|
|
4089
|
+
form: scrubbedForm,
|
|
4090
|
+
blankPaths: [...state.blankPaths]
|
|
4091
|
+
});
|
|
4092
|
+
}
|
|
4093
|
+
channel.onmessage = (event) => {
|
|
4094
|
+
if (disposed) return;
|
|
4095
|
+
const data = event.data;
|
|
4096
|
+
if (!isValidSyncMessage(data)) return;
|
|
4097
|
+
const msg = data;
|
|
4098
|
+
if (msg.senderId === senderId) return;
|
|
4099
|
+
switch (msg.kind) {
|
|
4100
|
+
case "hello":
|
|
4101
|
+
if (lifecycle !== "established") return;
|
|
4102
|
+
respondToHello();
|
|
4103
|
+
break;
|
|
4104
|
+
case "announce":
|
|
4105
|
+
if (lifecycle === "joining") peerIds.add(msg.senderId);
|
|
4106
|
+
break;
|
|
4107
|
+
case "requestSnapshot":
|
|
4108
|
+
if (lifecycle !== "established") return;
|
|
4109
|
+
if (msg.targetId !== senderId) return;
|
|
4110
|
+
respondToSnapshotRequest();
|
|
4111
|
+
break;
|
|
4112
|
+
case "snapshot":
|
|
4113
|
+
handleSnapshot(msg);
|
|
4114
|
+
break;
|
|
4115
|
+
case "patches":
|
|
4116
|
+
handlePatches(msg);
|
|
4117
|
+
break;
|
|
4118
|
+
}
|
|
4119
|
+
};
|
|
4120
|
+
function electLeaderAndRequest() {
|
|
4121
|
+
if (disposed) return;
|
|
4122
|
+
if (peerIds.size === 0) {
|
|
4123
|
+
lifecycle = "established";
|
|
4124
|
+
refreshPrior();
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
const sorted = [...peerIds].sort();
|
|
4128
|
+
const leaderId = sorted[0];
|
|
4129
|
+
peerIds.delete(leaderId);
|
|
4130
|
+
leaderAttempts++;
|
|
4131
|
+
safePost({
|
|
4132
|
+
v: PROTOCOL_VERSION,
|
|
4133
|
+
kind: "requestSnapshot",
|
|
4134
|
+
senderId,
|
|
4135
|
+
targetId: leaderId
|
|
4136
|
+
});
|
|
4137
|
+
snapshotTimeoutTimer = setTimeout(() => {
|
|
4138
|
+
snapshotTimeoutTimer = null;
|
|
4139
|
+
if (disposed) return;
|
|
4140
|
+
if (lifecycle === "established") return;
|
|
4141
|
+
if (leaderAttempts >= MAX_LEADER_ATTEMPTS || peerIds.size === 0) {
|
|
4142
|
+
lifecycle = "established";
|
|
4143
|
+
refreshPrior();
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
electLeaderAndRequest();
|
|
4147
|
+
}, SNAPSHOT_TIMEOUT_MS);
|
|
4148
|
+
}
|
|
4149
|
+
function joinFlow() {
|
|
4150
|
+
safePost({ v: PROTOCOL_VERSION, kind: "hello", senderId });
|
|
4151
|
+
joinCollectionTimer = setTimeout(() => {
|
|
4152
|
+
joinCollectionTimer = null;
|
|
4153
|
+
if (disposed) return;
|
|
4154
|
+
if (lifecycle === "established") return;
|
|
4155
|
+
electLeaderAndRequest();
|
|
4156
|
+
}, JOIN_COLLECTION_WINDOW_MS);
|
|
4157
|
+
}
|
|
4158
|
+
joinFlow();
|
|
4159
|
+
return {
|
|
4160
|
+
dispose: () => {
|
|
4161
|
+
if (disposed) return;
|
|
4162
|
+
disposed = true;
|
|
4163
|
+
if (joinCollectionTimer !== null) {
|
|
4164
|
+
clearTimeout(joinCollectionTimer);
|
|
4165
|
+
joinCollectionTimer = null;
|
|
4166
|
+
}
|
|
4167
|
+
if (snapshotTimeoutTimer !== null) {
|
|
4168
|
+
clearTimeout(snapshotTimeoutTimer);
|
|
4169
|
+
snapshotTimeoutTimer = null;
|
|
4170
|
+
}
|
|
4171
|
+
unsubscribeChange();
|
|
4172
|
+
try {
|
|
4173
|
+
channel.close();
|
|
4174
|
+
} catch {
|
|
4175
|
+
}
|
|
4176
|
+
},
|
|
4177
|
+
lifecycle: () => lifecycle,
|
|
4178
|
+
senderId,
|
|
4179
|
+
channelName
|
|
4180
|
+
};
|
|
4181
|
+
}
|
|
4182
|
+
const MULTI_TAB_SYNC_MODULE_KEY = "multiTabSync";
|
|
4183
|
+
|
|
4184
|
+
const warned = /* @__PURE__ */ new Set();
|
|
4185
|
+
function warnOnceInsecureContext(feature) {
|
|
4186
|
+
if (!__DEV__) return;
|
|
4187
|
+
if (warned.has(feature)) return;
|
|
4188
|
+
warned.add(feature);
|
|
4189
|
+
const message = featureMessage(feature);
|
|
4190
|
+
console.warn(`[attaform] ${message}`);
|
|
4191
|
+
}
|
|
4192
|
+
function featureMessage(feature) {
|
|
4193
|
+
switch (feature) {
|
|
4194
|
+
case "multiTab":
|
|
4195
|
+
return "Multi-tab sync requires a secure context (HTTPS or localhost). Plain HTTP on a real hostname is interceptable by network observers, so the sync module is disabled. Serve over HTTPS in production (or develop on `localhost`) to enable cross-tab synchronisation. Use `multiTab: false` on `useForm` to silence this warning.";
|
|
4196
|
+
case "persist:local":
|
|
4197
|
+
return "Built-in `persist: 'local'` storage requires a secure context (HTTPS or localhost). Plain HTTP on a real hostname is MITM-interceptable, so the persistence layer is disabled. Serve over HTTPS to enable localStorage persistence, or pass a custom storage adapter to opt out of the secure-context gate.";
|
|
4198
|
+
case "persist:session":
|
|
4199
|
+
return "Built-in `persist: 'session'` storage requires a secure context (HTTPS or localhost). Plain HTTP on a real hostname is MITM-interceptable, so the persistence layer is disabled. Serve over HTTPS to enable sessionStorage persistence, or pass a custom storage adapter to opt out of the secure-context gate.";
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
function isSecureContext() {
|
|
4203
|
+
return typeof window !== "undefined" && window.isSecureContext === true;
|
|
4204
|
+
}
|
|
4205
|
+
|
|
3203
4206
|
function useAbstractForm(configuration) {
|
|
3204
4207
|
if (configuration === void 0 || configuration === null || configuration.schema === void 0) {
|
|
3205
4208
|
throw new InvalidUseFormConfigError();
|
|
3206
4209
|
}
|
|
3207
4210
|
const key = resolveFormKey(configuration.key);
|
|
3208
|
-
const
|
|
4211
|
+
const instance = getCurrentInstance();
|
|
4212
|
+
if (instance !== null) ensureAttaformInstalled(instance.appContext.app);
|
|
4213
|
+
const registry = useRegistry();
|
|
4214
|
+
const merged = mergeWithDefaults(registry.defaults, configuration);
|
|
4215
|
+
const maxRecursionDepth = normalizeNumericOption({
|
|
4216
|
+
value: merged.maxRecursionDepth ?? DEFAULT_MAX_RECURSION_DEPTH,
|
|
4217
|
+
source: "useForm.maxRecursionDepth",
|
|
4218
|
+
allowInfinity: true,
|
|
4219
|
+
min: 0,
|
|
4220
|
+
defaultValue: DEFAULT_MAX_RECURSION_DEPTH
|
|
4221
|
+
});
|
|
4222
|
+
const resolvedSchema = getComputedSchema(key, configuration.schema, { maxRecursionDepth });
|
|
3209
4223
|
if (configuration.persist !== void 0 && configuration.key === void 0) {
|
|
3210
4224
|
throw new AnonPersistError({
|
|
3211
4225
|
cause: "no-key",
|
|
@@ -3213,13 +4227,10 @@ function useAbstractForm(configuration) {
|
|
|
3213
4227
|
callSite: captureUserCallSite()
|
|
3214
4228
|
});
|
|
3215
4229
|
}
|
|
3216
|
-
const instance = getCurrentInstance();
|
|
3217
|
-
if (instance !== null) ensureAttaformInstalled(instance.appContext.app);
|
|
3218
|
-
const registry = useRegistry();
|
|
3219
|
-
const merged = mergeWithDefaults(registry.defaults, configuration);
|
|
3220
4230
|
const existing = registry.forms.get(key);
|
|
3221
4231
|
if (__DEV__ && existing !== void 0) {
|
|
3222
4232
|
warnOnSchemaFingerprintMismatch(key, existing.schema, resolvedSchema);
|
|
4233
|
+
warnOnPersistDivergence(key, existing, configuration.persist);
|
|
3223
4234
|
}
|
|
3224
4235
|
const state = existing ?? buildFreshState(key, resolvedSchema, merged, registry);
|
|
3225
4236
|
if (getCurrentScope() !== void 0) {
|
|
@@ -3230,16 +4241,54 @@ function useAbstractForm(configuration) {
|
|
|
3230
4241
|
if (existing === void 0 && !registry.ssr) {
|
|
3231
4242
|
if (merged.persist !== void 0 && !persistDisabledByAnonRule) {
|
|
3232
4243
|
const resolvedPersist = normalizePersistConfig(merged.persist);
|
|
3233
|
-
const
|
|
3234
|
-
|
|
3235
|
-
const
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
4244
|
+
const storageKind = resolvedPersist.storage;
|
|
4245
|
+
const isBuiltinStorage = typeof storageKind === "string";
|
|
4246
|
+
const secureContextOk = !isBuiltinStorage || isSecureContext();
|
|
4247
|
+
if (!secureContextOk) {
|
|
4248
|
+
const feature = storageKind === "session" ? "persist:session" : "persist:local";
|
|
4249
|
+
warnOnceInsecureContext(feature);
|
|
4250
|
+
void sweepAllOrphansAcrossStandardStores(`${PERSISTENCE_KEY_PREFIX}${state.formKey}`);
|
|
4251
|
+
} else {
|
|
4252
|
+
const persistenceBase = resolveStorageKeyBase(resolvedPersist, state.formKey);
|
|
4253
|
+
void sweepNonConfiguredStandardStoresForOrphans(resolvedPersist.storage, persistenceBase);
|
|
4254
|
+
const persistenceModule = wirePersistence(state, resolvedPersist);
|
|
4255
|
+
state.modules.set(PERSISTENCE_MODULE_KEY, persistenceModule);
|
|
4256
|
+
state.registerDrain(() => persistenceModule.awaitPendingWrites());
|
|
4257
|
+
state.registerCleanup(() => persistenceModule.dispose());
|
|
4258
|
+
}
|
|
3239
4259
|
} else {
|
|
3240
4260
|
void sweepAllOrphansAcrossStandardStores(`${PERSISTENCE_KEY_PREFIX}${state.formKey}`);
|
|
3241
4261
|
}
|
|
3242
4262
|
}
|
|
4263
|
+
if (existing === void 0 && merged.multiTab !== false && configuration.key !== void 0 && !registry.ssr) {
|
|
4264
|
+
const hasBroadcastChannel = typeof BroadcastChannel !== "undefined";
|
|
4265
|
+
const secureContext = isSecureContext();
|
|
4266
|
+
if (hasBroadcastChannel && secureContext) {
|
|
4267
|
+
let channelName;
|
|
4268
|
+
try {
|
|
4269
|
+
channelName = `attaform:sync:${state.formKey}:${hashStableString(state.schema.fingerprint())}`;
|
|
4270
|
+
} catch {
|
|
4271
|
+
channelName = null;
|
|
4272
|
+
}
|
|
4273
|
+
if (channelName !== null) {
|
|
4274
|
+
const syncModule = createMultiTabSyncModule(state, channelName, {
|
|
4275
|
+
isSensitivePath: state.isSensitivePath,
|
|
4276
|
+
noSyncPaths: state.noSyncPaths,
|
|
4277
|
+
validateForm: (form) => {
|
|
4278
|
+
const result = state.schema.validateAtPath(form, void 0, { sync: true });
|
|
4279
|
+
if (result instanceof Promise) return;
|
|
4280
|
+
if (!result.success) {
|
|
4281
|
+
throw new Error("attaform multi-tab sync: post-apply schema validation failed");
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
});
|
|
4285
|
+
state.modules.set(MULTI_TAB_SYNC_MODULE_KEY, syncModule);
|
|
4286
|
+
state.registerCleanup(() => syncModule.dispose());
|
|
4287
|
+
}
|
|
4288
|
+
} else if (hasBroadcastChannel && !secureContext) {
|
|
4289
|
+
warnOnceInsecureContext("multiTab");
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
3243
4292
|
if (existing === void 0 && merged.history !== void 0) {
|
|
3244
4293
|
const historyModule = createHistoryModule(state, merged.history);
|
|
3245
4294
|
state.modules.set(HISTORY_MODULE_KEY, historyModule);
|
|
@@ -3261,6 +4310,22 @@ function useAbstractForm(configuration) {
|
|
|
3261
4310
|
if (history !== void 0) {
|
|
3262
4311
|
apiOptions.history = history;
|
|
3263
4312
|
}
|
|
4313
|
+
if (merged.validateOn !== void 0) {
|
|
4314
|
+
apiOptions.validateOn = merged.validateOn;
|
|
4315
|
+
}
|
|
4316
|
+
const mergedDebounceMs = merged.debounceMs;
|
|
4317
|
+
if (mergedDebounceMs !== void 0) {
|
|
4318
|
+
apiOptions.debounceMs = mergedDebounceMs;
|
|
4319
|
+
}
|
|
4320
|
+
if (merged.shouldShowErrors !== void 0) {
|
|
4321
|
+
apiOptions.shouldShowErrors = resolveShouldShowErrors(merged.shouldShowErrors);
|
|
4322
|
+
}
|
|
4323
|
+
if (merged.coerce !== void 0) {
|
|
4324
|
+
apiOptions.coerce = merged.coerce;
|
|
4325
|
+
}
|
|
4326
|
+
if (merged.rememberVariants !== void 0) {
|
|
4327
|
+
apiOptions.rememberVariants = merged.rememberVariants;
|
|
4328
|
+
}
|
|
3264
4329
|
return buildFormApi(state, formInstanceId, apiOptions);
|
|
3265
4330
|
}
|
|
3266
4331
|
function mergeWithDefaults(defaults, configuration) {
|
|
@@ -3271,6 +4336,10 @@ function mergeWithDefaults(defaults, configuration) {
|
|
|
3271
4336
|
const coerce = configuration.coerce ?? defaults.coerce;
|
|
3272
4337
|
const validateOn = configuration.validateOn ?? defaults.validateOn;
|
|
3273
4338
|
const debounceMs = configuration.debounceMs ?? defaults.debounceMs;
|
|
4339
|
+
const shouldShowErrors = configuration.shouldShowErrors ?? defaults.shouldShowErrors;
|
|
4340
|
+
const maxRecursionDepth = configuration.maxRecursionDepth ?? defaults.maxRecursionDepth;
|
|
4341
|
+
const sensitiveNames = configuration.sensitiveNames ?? defaults.sensitiveNames;
|
|
4342
|
+
const multiTab = configuration.multiTab ?? defaults.multiTab;
|
|
3274
4343
|
return {
|
|
3275
4344
|
...configuration,
|
|
3276
4345
|
...strict === void 0 ? {} : { strict },
|
|
@@ -3279,7 +4348,11 @@ function mergeWithDefaults(defaults, configuration) {
|
|
|
3279
4348
|
...rememberVariants === void 0 ? {} : { rememberVariants },
|
|
3280
4349
|
...coerce === void 0 ? {} : { coerce },
|
|
3281
4350
|
...validateOn === void 0 ? {} : { validateOn },
|
|
3282
|
-
...debounceMs === void 0 ? {} : { debounceMs }
|
|
4351
|
+
...debounceMs === void 0 ? {} : { debounceMs },
|
|
4352
|
+
...shouldShowErrors === void 0 ? {} : { shouldShowErrors },
|
|
4353
|
+
...maxRecursionDepth === void 0 ? {} : { maxRecursionDepth },
|
|
4354
|
+
...sensitiveNames === void 0 ? {} : { sensitiveNames },
|
|
4355
|
+
...multiTab === void 0 ? {} : { multiTab }
|
|
3283
4356
|
};
|
|
3284
4357
|
}
|
|
3285
4358
|
const HISTORY_MODULE_KEY = "history";
|
|
@@ -3291,6 +4364,9 @@ function buildFreshState(key, schema, configuration, registry) {
|
|
|
3291
4364
|
schema
|
|
3292
4365
|
);
|
|
3293
4366
|
const initialBlankPaths = pending === void 0 ? walked.paths : void 0;
|
|
4367
|
+
const resolvedSensitiveNames = configuration.sensitiveNames;
|
|
4368
|
+
const resolvedIsSensitivePath = resolvedSensitiveNames === void 0 ? void 0 : createIsSensitivePath(resolvedSensitiveNames);
|
|
4369
|
+
const resolvedSegmentMatchesSensitive = resolvedSensitiveNames === void 0 ? void 0 : createSegmentMatchesSensitive(resolvedSensitiveNames);
|
|
3294
4370
|
const createOptions = {
|
|
3295
4371
|
formKey: key,
|
|
3296
4372
|
schema,
|
|
@@ -3302,7 +4378,10 @@ function buildFreshState(key, schema, configuration, registry) {
|
|
|
3302
4378
|
ssr: registry.ssr,
|
|
3303
4379
|
...configuration.rememberVariants !== void 0 ? { rememberVariants: configuration.rememberVariants } : {},
|
|
3304
4380
|
...configuration.coerce !== void 0 ? { coerce: configuration.coerce } : {},
|
|
3305
|
-
...
|
|
4381
|
+
...configuration.shouldShowErrors !== void 0 ? { shouldShowErrors: configuration.shouldShowErrors } : {},
|
|
4382
|
+
...initialBlankPaths !== void 0 ? { initialBlankPaths } : {},
|
|
4383
|
+
...resolvedIsSensitivePath !== void 0 ? { isSensitivePath: resolvedIsSensitivePath } : {},
|
|
4384
|
+
...resolvedSegmentMatchesSensitive !== void 0 ? { segmentMatchesSensitive: resolvedSegmentMatchesSensitive } : {}
|
|
3306
4385
|
};
|
|
3307
4386
|
const state = createFormStore(createOptions);
|
|
3308
4387
|
registry.forms.set(
|
|
@@ -3361,11 +4440,47 @@ function warnOnSchemaFingerprintMismatch(key, existing, incoming) {
|
|
|
3361
4440
|
incoming: ${incomingFp}`
|
|
3362
4441
|
);
|
|
3363
4442
|
}
|
|
4443
|
+
function warnOnPersistDivergence(key, existing, incomingPersist) {
|
|
4444
|
+
if (incomingPersist === void 0) return;
|
|
4445
|
+
const wired = existing.modules.get(PERSISTENCE_MODULE_KEY);
|
|
4446
|
+
const incomingNormalized = normalizePersistConfig(incomingPersist);
|
|
4447
|
+
if (wired === void 0) {
|
|
4448
|
+
console.warn(
|
|
4449
|
+
`[attaform] useForm({ key: "${key}" }) passed a persist config but the first useForm({ key }) call didn't wire persistence; the new config is silently dropped. Pass persist on the first call, or remove persist here to make the inheritance explicit.`
|
|
4450
|
+
);
|
|
4451
|
+
return;
|
|
4452
|
+
}
|
|
4453
|
+
if (persistConfigsEquivalent(wired.wiredConfig, incomingNormalized)) return;
|
|
4454
|
+
console.warn(
|
|
4455
|
+
`[attaform] useForm({ key: "${key}" }) passed a persist config that differs from the first useForm({ key }) call's; first wins, this one is ignored.
|
|
4456
|
+
wired: ${describePersist(wired.wiredConfig)}
|
|
4457
|
+
incoming: ${describePersist(incomingNormalized)}`
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
function persistConfigsEquivalent(a, b) {
|
|
4461
|
+
if (a.storage !== b.storage) return false;
|
|
4462
|
+
if ((a.key ?? void 0) !== (b.key ?? void 0)) return false;
|
|
4463
|
+
if ((a.debounceMs ?? void 0) !== (b.debounceMs ?? void 0)) return false;
|
|
4464
|
+
return true;
|
|
4465
|
+
}
|
|
4466
|
+
function describePersist(config) {
|
|
4467
|
+
const storage = typeof config.storage === "string" ? config.storage : "custom-adapter";
|
|
4468
|
+
const parts = [`storage=${storage}`];
|
|
4469
|
+
if (config.key !== void 0) parts.push(`key=${config.key}`);
|
|
4470
|
+
if (config.debounceMs !== void 0) parts.push(`debounceMs=${config.debounceMs}`);
|
|
4471
|
+
return `{ ${parts.join(", ")} }`;
|
|
4472
|
+
}
|
|
3364
4473
|
function wirePersistence(state, config) {
|
|
3365
4474
|
const fingerprint = hashStableString(state.schema.fingerprint());
|
|
3366
4475
|
const base = resolveStorageKeyBase(config, state.formKey);
|
|
3367
4476
|
const key = `${base}:${fingerprint}`;
|
|
3368
|
-
const debounceMs =
|
|
4477
|
+
const debounceMs = normalizeNumericOption({
|
|
4478
|
+
value: config.debounceMs ?? DEFAULT_PERSISTENCE_DEBOUNCE_MS,
|
|
4479
|
+
source: "useForm.persist.debounceMs",
|
|
4480
|
+
allowInfinity: false,
|
|
4481
|
+
min: 0,
|
|
4482
|
+
defaultValue: DEFAULT_PERSISTENCE_DEBOUNCE_MS
|
|
4483
|
+
});
|
|
3369
4484
|
const include = config.include ?? "form";
|
|
3370
4485
|
const clearOnSubmitSuccess = config.clearOnSubmitSuccess ?? true;
|
|
3371
4486
|
const adapterPromise = getStorageAdapter(config.storage);
|
|
@@ -3400,6 +4515,7 @@ function wirePersistence(state, config) {
|
|
|
3400
4515
|
}, debounceMs);
|
|
3401
4516
|
const unsubscribeChange = state.onFormChange((_next, meta) => {
|
|
3402
4517
|
if (disposed || inFlightFinalFlush !== null) return;
|
|
4518
|
+
if (meta?.crossTab === true) return;
|
|
3403
4519
|
if (meta?.persist !== true) return;
|
|
3404
4520
|
pendingOptedInPaths = new Set(state.persistOptIns.optedInPaths());
|
|
3405
4521
|
writer.schedule();
|
|
@@ -3433,7 +4549,7 @@ function wirePersistence(state, config) {
|
|
|
3433
4549
|
payload.data.form,
|
|
3434
4550
|
state.schema
|
|
3435
4551
|
);
|
|
3436
|
-
state.applyFormReplacement(merged);
|
|
4552
|
+
state.applyFormReplacement(merged, { hydration: true });
|
|
3437
4553
|
const persistedLeafPaths = collectPersistedLeafPaths(payload.data.form);
|
|
3438
4554
|
for (const k of persistedLeafPaths) {
|
|
3439
4555
|
state.blankPaths.delete(k);
|
|
@@ -3564,6 +4680,7 @@ function wirePersistence(state, config) {
|
|
|
3564
4680
|
});
|
|
3565
4681
|
}
|
|
3566
4682
|
return {
|
|
4683
|
+
wiredConfig: config,
|
|
3567
4684
|
writePathImmediately,
|
|
3568
4685
|
clearPersistedDraft,
|
|
3569
4686
|
awaitPendingWrites,
|
|
@@ -3638,7 +4755,11 @@ function injectForm(key) {
|
|
|
3638
4755
|
}
|
|
3639
4756
|
const ambientInstanceId = getCurrentInstance() !== null ? inject(kFormInstanceId, null) : null;
|
|
3640
4757
|
const formInstanceId = ambientInstanceId ?? (getCurrentInstance() !== null ? useId() : `atta:form-instance-injected:${injectedInstanceCounter++}`);
|
|
3641
|
-
return buildFormApi(
|
|
4758
|
+
return buildFormApi(
|
|
4759
|
+
state,
|
|
4760
|
+
formInstanceId,
|
|
4761
|
+
apiOptions
|
|
4762
|
+
);
|
|
3642
4763
|
}
|
|
3643
4764
|
function resolveState(key, registry) {
|
|
3644
4765
|
if (key !== void 0) {
|
|
@@ -3682,5 +4803,5 @@ function warnIfAmbientProviderHadDuplicates() {
|
|
|
3682
4803
|
}
|
|
3683
4804
|
}
|
|
3684
4805
|
|
|
3685
|
-
export { AttaformErrorCode as A, isUnset as a,
|
|
3686
|
-
//# sourceMappingURL=attaform.
|
|
4806
|
+
export { AttaformErrorCode as A, isUnset as a, defaultShouldShowErrors as b, defineCoercion as c, defaultCoercionRules as d, useAbstractForm as e, setAtPath as f, getAtPath as g, humanize as h, injectForm as i, isPlainRecord as j, normalizeNumericOption as n, slimKindOf as s, unset as u };
|
|
4807
|
+
//# sourceMappingURL=attaform.BT55rDNN.mjs.map
|