attaform 0.14.0 → 0.15.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/dist/chunks/devtools.cjs +3 -3
- package/dist/chunks/devtools.cjs.map +1 -1
- package/dist/chunks/devtools.mjs +3 -3
- 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 +5 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +6 -6
- 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 +1 -1
- package/dist/runtime/plugins/attaform.mjs +1 -1
- package/dist/shared/{attaform.DDXrY-1Q.d.mts → attaform.0Gxd_OOx.d.cts} +558 -174
- package/dist/shared/{attaform.DDXrY-1Q.d.ts → attaform.0Gxd_OOx.d.mts} +558 -174
- package/dist/shared/{attaform.DDXrY-1Q.d.cts → attaform.0Gxd_OOx.d.ts} +558 -174
- package/dist/shared/{attaform.xKWYHMdq.cjs → attaform.BOi138GE.cjs} +10 -2
- package/dist/shared/{attaform.xKWYHMdq.cjs.map → attaform.BOi138GE.cjs.map} +1 -1
- package/dist/shared/{attaform.CRgix6_n.cjs → attaform.BgYBU8gV.cjs} +18 -17
- package/dist/shared/attaform.BgYBU8gV.cjs.map +1 -0
- package/dist/shared/attaform.Bubm_slq.cjs.map +1 -1
- package/dist/shared/{attaform.CNJO3mME.cjs → attaform.CDJVeoJU.cjs} +633 -236
- package/dist/shared/attaform.CDJVeoJU.cjs.map +1 -0
- package/dist/shared/{attaform.CXZgUECn.d.cts → attaform.CPx7zTgS.d.mts} +39 -9
- package/dist/shared/{attaform.DlgKK10S.mjs → attaform.CRk8NhlD.mjs} +18 -17
- package/dist/shared/attaform.CRk8NhlD.mjs.map +1 -0
- package/dist/shared/attaform.CXpzmj38.mjs.map +1 -1
- package/dist/shared/{attaform.DOKOyb3Y.d.mts → attaform.D-eHWfVx.d.cts} +39 -9
- package/dist/shared/{attaform.Cc93zNzD.mjs → attaform.DXye3JKf.mjs} +10 -3
- package/dist/shared/{attaform.Cc93zNzD.mjs.map → attaform.DXye3JKf.mjs.map} +1 -1
- package/dist/shared/{attaform.B5GWYl76.cjs → attaform.RypIkgVy.cjs} +38 -7
- package/dist/shared/attaform.RypIkgVy.cjs.map +1 -0
- package/dist/shared/{attaform.al_rpt7_.mjs → attaform.a99dQV7Q.mjs} +39 -8
- package/dist/shared/attaform.a99dQV7Q.mjs.map +1 -0
- package/dist/shared/{attaform.BRTxpA3q.mjs → attaform.qxyip_aN.mjs} +634 -238
- package/dist/shared/attaform.qxyip_aN.mjs.map +1 -0
- package/dist/shared/{attaform.BYc9kugA.d.ts → attaform.riAENZQM.d.ts} +39 -9
- package/dist/transforms.d.cts +2 -2
- package/dist/transforms.d.mts +2 -2
- package/dist/transforms.d.ts +2 -2
- package/dist/zod-v3.cjs +55 -3
- package/dist/zod-v3.cjs.map +1 -1
- package/dist/zod-v3.d.cts +77 -4
- package/dist/zod-v3.d.mts +77 -4
- package/dist/zod-v3.d.ts +77 -4
- package/dist/zod-v3.mjs +56 -6
- package/dist/zod-v3.mjs.map +1 -1
- package/dist/zod.cjs +372 -5
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +120 -4
- package/dist/zod.d.mts +120 -4
- package/dist/zod.d.ts +120 -4
- package/dist/zod.mjs +371 -8
- package/dist/zod.mjs.map +1 -1
- package/package.json +3 -1
- package/dist/shared/attaform.B5GWYl76.cjs.map +0 -1
- package/dist/shared/attaform.BRTxpA3q.mjs.map +0 -1
- package/dist/shared/attaform.CNJO3mME.cjs.map +0 -1
- package/dist/shared/attaform.CRgix6_n.cjs.map +0 -1
- package/dist/shared/attaform.DlgKK10S.mjs.map +0 -1
- package/dist/shared/attaform.al_rpt7_.mjs.map +0 -1
|
@@ -1,8 +1,175 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const vue = require('vue');
|
|
4
|
-
const paths = require('./attaform.
|
|
5
|
-
const sensitiveNames = require('./attaform.
|
|
4
|
+
const paths = require('./attaform.BOi138GE.cjs');
|
|
5
|
+
const sensitiveNames = require('./attaform.RypIkgVy.cjs');
|
|
6
|
+
|
|
7
|
+
function isDescendable(value) {
|
|
8
|
+
if (value === null || typeof value !== "object") return false;
|
|
9
|
+
if (Array.isArray(value)) return true;
|
|
10
|
+
const proto = Object.getPrototypeOf(value);
|
|
11
|
+
return proto === null || proto === Object.prototype;
|
|
12
|
+
}
|
|
13
|
+
function appendSegment(prefix, segment) {
|
|
14
|
+
const next = new Array(prefix.length + 1);
|
|
15
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
16
|
+
const s = prefix[i];
|
|
17
|
+
next[i] = s;
|
|
18
|
+
}
|
|
19
|
+
next[prefix.length] = segment;
|
|
20
|
+
return next;
|
|
21
|
+
}
|
|
22
|
+
function diffAndApply(oldValue, newValue, prefix, visit) {
|
|
23
|
+
if (Object.is(oldValue, newValue)) return;
|
|
24
|
+
const oldIsDescendable = isDescendable(oldValue);
|
|
25
|
+
const newIsDescendable = isDescendable(newValue);
|
|
26
|
+
if (oldValue === void 0 && newIsDescendable) {
|
|
27
|
+
if (Array.isArray(newValue)) {
|
|
28
|
+
for (let i = 0; i < newValue.length; i++) {
|
|
29
|
+
diffAndApply(void 0, newValue[i], appendSegment(prefix, i), visit);
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
const rec = newValue;
|
|
33
|
+
for (const k of Object.keys(rec)) {
|
|
34
|
+
diffAndApply(void 0, rec[k], appendSegment(prefix, k), visit);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (oldIsDescendable && newValue === void 0) {
|
|
40
|
+
if (Array.isArray(oldValue)) {
|
|
41
|
+
for (let i = 0; i < oldValue.length; i++) {
|
|
42
|
+
diffAndApply(oldValue[i], void 0, appendSegment(prefix, i), visit);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
const rec = oldValue;
|
|
46
|
+
for (const k of Object.keys(rec)) {
|
|
47
|
+
diffAndApply(rec[k], void 0, appendSegment(prefix, k), visit);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (oldIsDescendable && newIsDescendable) {
|
|
53
|
+
const oldIsArray = Array.isArray(oldValue);
|
|
54
|
+
const newIsArray = Array.isArray(newValue);
|
|
55
|
+
if (oldIsArray && newIsArray) {
|
|
56
|
+
const oldArr = oldValue;
|
|
57
|
+
const newArr = newValue;
|
|
58
|
+
const max = Math.max(oldArr.length, newArr.length);
|
|
59
|
+
for (let i = 0; i < max; i++) {
|
|
60
|
+
diffAndApply(oldArr[i], newArr[i], appendSegment(prefix, i), visit);
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!oldIsArray && !newIsArray) {
|
|
65
|
+
const oldRec = oldValue;
|
|
66
|
+
const newRec = newValue;
|
|
67
|
+
const seen = /* @__PURE__ */ new Set();
|
|
68
|
+
for (const k of Object.keys(oldRec)) {
|
|
69
|
+
seen.add(k);
|
|
70
|
+
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
71
|
+
}
|
|
72
|
+
for (const k of Object.keys(newRec)) {
|
|
73
|
+
if (seen.has(k)) continue;
|
|
74
|
+
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (oldIsDescendable && !newIsDescendable) {
|
|
82
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (!oldIsDescendable && newIsDescendable) {
|
|
86
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (oldValue === void 0) {
|
|
90
|
+
visit({ kind: "added", path: prefix, newValue });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (newValue === void 0) {
|
|
94
|
+
visit({ kind: "removed", path: prefix, oldValue });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
98
|
+
}
|
|
99
|
+
function applyChangedKeys(target, source) {
|
|
100
|
+
if (!isDescendable(target) || !isDescendable(source)) return false;
|
|
101
|
+
const targetIsArray = Array.isArray(target);
|
|
102
|
+
const sourceIsArray = Array.isArray(source);
|
|
103
|
+
if (targetIsArray !== sourceIsArray) return false;
|
|
104
|
+
const ROOT_SENTINEL = Symbol.for("attaform.applyChangedKeys.rootMismatch");
|
|
105
|
+
const changedFirstSegments = /* @__PURE__ */ new Set();
|
|
106
|
+
diffAndApply(target, source, [], (patch) => {
|
|
107
|
+
if (patch.path.length === 0) {
|
|
108
|
+
changedFirstSegments.add(ROOT_SENTINEL);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
changedFirstSegments.add(patch.path[0]);
|
|
112
|
+
});
|
|
113
|
+
if (changedFirstSegments.has(ROOT_SENTINEL)) return false;
|
|
114
|
+
if (targetIsArray) {
|
|
115
|
+
const t = target;
|
|
116
|
+
const s = source;
|
|
117
|
+
if (t.length > s.length) t.length = s.length;
|
|
118
|
+
for (const idx of changedFirstSegments) {
|
|
119
|
+
if (typeof idx === "symbol") continue;
|
|
120
|
+
const i = typeof idx === "number" ? idx : Number(idx);
|
|
121
|
+
t[i] = s[i];
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const t = target;
|
|
125
|
+
const s = source;
|
|
126
|
+
const sourceKeys = new Set(Object.keys(s));
|
|
127
|
+
for (const k of Object.keys(t)) {
|
|
128
|
+
if (!sourceKeys.has(k)) delete t[k];
|
|
129
|
+
}
|
|
130
|
+
for (const k of changedFirstSegments) {
|
|
131
|
+
if (typeof k === "symbol") continue;
|
|
132
|
+
t[String(k)] = s[String(k)];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
function structuralSnapshot(value) {
|
|
138
|
+
if (!isDescendable(value)) return value;
|
|
139
|
+
if (Array.isArray(value)) {
|
|
140
|
+
const out2 = new Array(value.length);
|
|
141
|
+
for (let i = 0; i < value.length; i++) {
|
|
142
|
+
out2[i] = structuralSnapshot(value[i]);
|
|
143
|
+
}
|
|
144
|
+
return out2;
|
|
145
|
+
}
|
|
146
|
+
const src = value;
|
|
147
|
+
const out = {};
|
|
148
|
+
for (const k of Object.keys(src)) {
|
|
149
|
+
out[k] = structuralSnapshot(src[k]);
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const EMPTY_RESOLVED_FIELD_META = Object.freeze({
|
|
155
|
+
label: "",
|
|
156
|
+
description: void 0,
|
|
157
|
+
placeholder: void 0,
|
|
158
|
+
meta: Object.freeze({})
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
function humanize(segment) {
|
|
162
|
+
if (typeof segment === "number") return "";
|
|
163
|
+
const str = String(segment);
|
|
164
|
+
if (str.length === 0) return "";
|
|
165
|
+
if (/^\d+$/.test(str)) return "";
|
|
166
|
+
const tokens = str.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().split(" ").filter((part) => part.length > 0);
|
|
167
|
+
if (tokens.length === 0) return "";
|
|
168
|
+
return tokens.map((part) => {
|
|
169
|
+
const head = part[0];
|
|
170
|
+
return head === void 0 ? part : head.toUpperCase() + part.slice(1).toLowerCase();
|
|
171
|
+
}).join(" ");
|
|
172
|
+
}
|
|
6
173
|
|
|
7
174
|
const NOT_FOUND = Symbol("NOT_FOUND");
|
|
8
175
|
function descendStep(value, segment) {
|
|
@@ -248,6 +415,153 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
248
415
|
return rec;
|
|
249
416
|
}
|
|
250
417
|
|
|
418
|
+
function buildFieldStateAccessor(state) {
|
|
419
|
+
const cache = /* @__PURE__ */ new Map();
|
|
420
|
+
return function getFieldState(pathInput) {
|
|
421
|
+
const { segments, key } = paths.canonicalizePath(pathInput);
|
|
422
|
+
const cached = cache.get(key);
|
|
423
|
+
if (cached !== void 0) return cached;
|
|
424
|
+
const c = vue.computed(
|
|
425
|
+
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key) : buildContainerFieldState(state, segments)
|
|
426
|
+
);
|
|
427
|
+
cache.set(key, c);
|
|
428
|
+
return c;
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function buildLeafFieldState(state, segments, key) {
|
|
432
|
+
const record = state.fields.get(key);
|
|
433
|
+
const value = state.getValueAtPath(segments);
|
|
434
|
+
const original = state.originals.get(key)?.value;
|
|
435
|
+
const pristine = state.isPristineAtPath(segments);
|
|
436
|
+
const schemaForKey = state.schemaErrors.get(key);
|
|
437
|
+
const blankForKey = state.derivedBlankErrors.value.get(key);
|
|
438
|
+
const userForKey = state.userErrors.get(key);
|
|
439
|
+
const errors = [];
|
|
440
|
+
if (schemaForKey !== void 0) errors.push(...schemaForKey);
|
|
441
|
+
if (blankForKey !== void 0) errors.push(...blankForKey);
|
|
442
|
+
if (userForKey !== void 0) errors.push(...userForKey);
|
|
443
|
+
const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
|
|
444
|
+
const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
|
|
445
|
+
const valid = !gated && errors.length === 0 && !validating;
|
|
446
|
+
const elementRecord = state.elements.get(key);
|
|
447
|
+
const elementsArr = elementRecord ? Object.freeze([...elementRecord.elements]) : EMPTY_ELEMENTS;
|
|
448
|
+
const firstElement = elementsArr[0] ?? null;
|
|
449
|
+
const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
|
|
450
|
+
const lastSegment = segments.length === 0 ? "" : segments[segments.length - 1] ?? "";
|
|
451
|
+
const label = resolved.label || humanize(lastSegment);
|
|
452
|
+
return {
|
|
453
|
+
value,
|
|
454
|
+
original,
|
|
455
|
+
pristine,
|
|
456
|
+
dirty: !pristine,
|
|
457
|
+
focused: record?.focused ?? null,
|
|
458
|
+
blurred: record?.blurred ?? null,
|
|
459
|
+
touched: record?.touched ?? null,
|
|
460
|
+
connected: record?.connected ?? false,
|
|
461
|
+
element: firstElement,
|
|
462
|
+
elements: elementsArr,
|
|
463
|
+
updatedAt: record?.updatedAt ?? null,
|
|
464
|
+
errors,
|
|
465
|
+
validating,
|
|
466
|
+
valid,
|
|
467
|
+
path: segments,
|
|
468
|
+
blank: state.blankPaths.has(key),
|
|
469
|
+
label,
|
|
470
|
+
description: resolved.description,
|
|
471
|
+
placeholder: resolved.placeholder,
|
|
472
|
+
meta: resolved.meta
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function buildContainerFieldState(state, segments, _key) {
|
|
476
|
+
const formValue = state.form.value;
|
|
477
|
+
const value = state.getValueAtPath(segments);
|
|
478
|
+
const original = state.originals.get(paths.canonicalizePath(segments).key)?.value;
|
|
479
|
+
let pristine = true;
|
|
480
|
+
let blank = true;
|
|
481
|
+
let dirty = false;
|
|
482
|
+
let focused = false;
|
|
483
|
+
let blurred = false;
|
|
484
|
+
let touched = false;
|
|
485
|
+
let connected = false;
|
|
486
|
+
let validating = false;
|
|
487
|
+
let updatedAt = null;
|
|
488
|
+
let asyncPending = false;
|
|
489
|
+
for (const [, entry] of state.originals) {
|
|
490
|
+
if (!paths.isPathPrefix(segments, entry.segments)) continue;
|
|
491
|
+
if (segments.length === entry.segments.length) continue;
|
|
492
|
+
if (!hasAtPath(formValue, entry.segments)) continue;
|
|
493
|
+
const leafKey = paths.canonicalizePath(entry.segments).key;
|
|
494
|
+
const leafRecord = state.fields.get(leafKey);
|
|
495
|
+
if (!state.isPristineAtPath(entry.segments)) {
|
|
496
|
+
pristine = false;
|
|
497
|
+
dirty = true;
|
|
498
|
+
}
|
|
499
|
+
if (!state.blankPaths.has(leafKey)) blank = false;
|
|
500
|
+
if (leafRecord?.focused === true) focused = true;
|
|
501
|
+
if (leafRecord?.blurred === true) blurred = true;
|
|
502
|
+
if (leafRecord?.touched === true) touched = true;
|
|
503
|
+
if (leafRecord?.connected === true) connected = true;
|
|
504
|
+
if ((state.fieldValidationCounts.get(leafKey) ?? 0) > 0) validating = true;
|
|
505
|
+
if (state.pathHasAsyncValidation(entry.segments)) asyncPending = true;
|
|
506
|
+
const ts = leafRecord?.updatedAt;
|
|
507
|
+
if (ts !== void 0 && ts !== null) {
|
|
508
|
+
if (updatedAt === null || ts > updatedAt) updatedAt = ts;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const errors = aggregateErrorsAt(state, segments);
|
|
512
|
+
if (!asyncPending && state.pathHasAsyncValidation(segments)) asyncPending = true;
|
|
513
|
+
const gated = asyncPending && !state.firstValidationDone.value;
|
|
514
|
+
const valid = !gated && errors.length === 0 && !validating;
|
|
515
|
+
const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
|
|
516
|
+
const lastSegment = segments.length === 0 ? "" : segments[segments.length - 1] ?? "";
|
|
517
|
+
const label = resolved.label || humanize(lastSegment);
|
|
518
|
+
return {
|
|
519
|
+
value,
|
|
520
|
+
original,
|
|
521
|
+
pristine,
|
|
522
|
+
dirty,
|
|
523
|
+
focused,
|
|
524
|
+
blurred,
|
|
525
|
+
touched,
|
|
526
|
+
connected,
|
|
527
|
+
element: null,
|
|
528
|
+
elements: EMPTY_ELEMENTS,
|
|
529
|
+
updatedAt,
|
|
530
|
+
errors,
|
|
531
|
+
validating,
|
|
532
|
+
valid,
|
|
533
|
+
path: segments,
|
|
534
|
+
blank,
|
|
535
|
+
label,
|
|
536
|
+
description: resolved.description,
|
|
537
|
+
placeholder: resolved.placeholder,
|
|
538
|
+
meta: resolved.meta
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function aggregateErrorsAt(state, prefix) {
|
|
542
|
+
const formValue = state.form.value;
|
|
543
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
544
|
+
const collect = (errs) => {
|
|
545
|
+
for (const [pathKey, list] of errs) {
|
|
546
|
+
if (list.length === 0) continue;
|
|
547
|
+
const segs = paths.segmentsForPathKey(pathKey);
|
|
548
|
+
if (segs === null) continue;
|
|
549
|
+
if (!paths.isPathPrefix(prefix, segs)) continue;
|
|
550
|
+
if (segs.length > 0 && !hasAtPath(formValue, segs)) continue;
|
|
551
|
+
const ordinal = state.ensurePathOrdinal(pathKey);
|
|
552
|
+
const existing = buckets.get(ordinal);
|
|
553
|
+
if (existing === void 0) buckets.set(ordinal, [...list]);
|
|
554
|
+
else existing.push(...list);
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
collect(state.schemaErrors);
|
|
558
|
+
collect(state.derivedBlankErrors.value);
|
|
559
|
+
collect(state.userErrors);
|
|
560
|
+
if (buckets.size === 0) return [];
|
|
561
|
+
return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
|
|
562
|
+
}
|
|
563
|
+
const EMPTY_ELEMENTS = Object.freeze([]);
|
|
564
|
+
|
|
251
565
|
const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
|
|
252
566
|
function keyToSegment(key) {
|
|
253
567
|
return INTEGER_SEGMENT.test(key) ? Number(key) : key;
|
|
@@ -272,11 +586,6 @@ function buildSurfaceProxy(opts) {
|
|
|
272
586
|
}
|
|
273
587
|
return containerProxyAt(segs);
|
|
274
588
|
}
|
|
275
|
-
function navigateTo(input) {
|
|
276
|
-
if (input === void 0) return rootProxy;
|
|
277
|
-
const { segments } = paths.canonicalizePath(input);
|
|
278
|
-
return descendOrTerminate(segments);
|
|
279
|
-
}
|
|
280
589
|
function containerProxyAt(segments) {
|
|
281
590
|
const cacheKey = JSON.stringify(segments);
|
|
282
591
|
const existing = containerCache.get(cacheKey);
|
|
@@ -293,8 +602,9 @@ function buildSurfaceProxy(opts) {
|
|
|
293
602
|
const proxy = new Proxy(target, {
|
|
294
603
|
apply(_, __, args) {
|
|
295
604
|
const arg = args[0];
|
|
296
|
-
if (arg === void 0) return
|
|
297
|
-
|
|
605
|
+
if (arg === void 0) return opts.resolveCallTarget(segments);
|
|
606
|
+
const { segments: argSegs } = paths.canonicalizePath(arg);
|
|
607
|
+
return opts.resolveCallTarget(argSegs);
|
|
298
608
|
},
|
|
299
609
|
get(_, key) {
|
|
300
610
|
if (typeof key === "symbol") {
|
|
@@ -356,8 +666,9 @@ function buildSurfaceProxy(opts) {
|
|
|
356
666
|
const proxy = new Proxy(target, {
|
|
357
667
|
apply(_, __, args) {
|
|
358
668
|
const arg = args[0];
|
|
359
|
-
if (arg === void 0) return opts.
|
|
360
|
-
|
|
669
|
+
if (arg === void 0) return opts.resolveCallTarget(segments);
|
|
670
|
+
const { segments: argSegs } = paths.canonicalizePath(arg);
|
|
671
|
+
return opts.resolveCallTarget(argSegs);
|
|
361
672
|
},
|
|
362
673
|
get(_, key) {
|
|
363
674
|
if (typeof key === "symbol") {
|
|
@@ -380,9 +691,8 @@ function buildSurfaceProxy(opts) {
|
|
|
380
691
|
return true;
|
|
381
692
|
},
|
|
382
693
|
// Iteration: leaf-views expose the leaf-key set so
|
|
383
|
-
// `JSON.stringify(form.fields.email)` produces
|
|
384
|
-
//
|
|
385
|
-
// `JSON.stringify(form.getFieldState('email').value)` shape).
|
|
694
|
+
// `JSON.stringify(form.fields.email)` produces a FieldState
|
|
695
|
+
// snapshot rather than the function-target placeholder.
|
|
386
696
|
ownKeys: () => Array.from(leafKeys),
|
|
387
697
|
getOwnPropertyDescriptor(_, key) {
|
|
388
698
|
if (typeof key !== "string") return void 0;
|
|
@@ -423,7 +733,20 @@ function buildErrorsProxy(state) {
|
|
|
423
733
|
},
|
|
424
734
|
// No leafKeys — at a leaf, the resolved value (the merged array or
|
|
425
735
|
// undefined) IS the terminal.
|
|
426
|
-
materializeContainer: (segments) => materializeErrors(state, segments)
|
|
736
|
+
materializeContainer: (segments) => materializeErrors(state, segments),
|
|
737
|
+
// Call-form aggregates: `form.errors(path)` returns a single
|
|
738
|
+
// `ValidationError[]` for any depth (leaf or container) — same
|
|
739
|
+
// shared `aggregateErrorsAt` helper that `form.meta.errors` and
|
|
740
|
+
// `form.fields(path).errors` use, so the three surfaces never
|
|
741
|
+
// drift. Empty results return `undefined`, matching the leaf
|
|
742
|
+
// proxy's pre-existing semantic (`form.errors.email === undefined`
|
|
743
|
+
// when valid) so consumer code that branches on truthiness keeps
|
|
744
|
+
// working — the call-form just extends that semantic to
|
|
745
|
+
// containers and dynamic paths.
|
|
746
|
+
resolveCallTarget: (path) => {
|
|
747
|
+
const errs = aggregateErrorsAt(state, path);
|
|
748
|
+
return errs.length === 0 ? void 0 : errs;
|
|
749
|
+
}
|
|
427
750
|
});
|
|
428
751
|
}
|
|
429
752
|
function materializeErrors(state, containerSegments) {
|
|
@@ -530,39 +853,6 @@ function buildFieldArrayApi(state) {
|
|
|
530
853
|
};
|
|
531
854
|
}
|
|
532
855
|
|
|
533
|
-
function buildFieldStateAccessor(state) {
|
|
534
|
-
return function getFieldState(pathInput) {
|
|
535
|
-
const { segments, key } = paths.canonicalizePath(pathInput);
|
|
536
|
-
return vue.computed(() => {
|
|
537
|
-
const record = state.fields.get(key);
|
|
538
|
-
const value = state.getValueAtPath(segments);
|
|
539
|
-
const original = state.originals.get(key)?.value;
|
|
540
|
-
const pristine = state.isPristineAtPath(segments);
|
|
541
|
-
const schemaForKey = state.schemaErrors.get(key);
|
|
542
|
-
const blankForKey = state.derivedBlankErrors.value.get(key);
|
|
543
|
-
const userForKey = state.userErrors.get(key);
|
|
544
|
-
const errors = [];
|
|
545
|
-
if (schemaForKey !== void 0) errors.push(...schemaForKey);
|
|
546
|
-
if (blankForKey !== void 0) errors.push(...blankForKey);
|
|
547
|
-
if (userForKey !== void 0) errors.push(...userForKey);
|
|
548
|
-
return {
|
|
549
|
-
value,
|
|
550
|
-
original,
|
|
551
|
-
pristine,
|
|
552
|
-
dirty: !pristine,
|
|
553
|
-
focused: record?.focused ?? null,
|
|
554
|
-
blurred: record?.blurred ?? null,
|
|
555
|
-
touched: record?.touched ?? null,
|
|
556
|
-
isConnected: record?.isConnected ?? false,
|
|
557
|
-
updatedAt: record?.updatedAt ?? null,
|
|
558
|
-
errors,
|
|
559
|
-
path: segments,
|
|
560
|
-
blank: state.blankPaths.has(key)
|
|
561
|
-
};
|
|
562
|
-
});
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
|
|
566
856
|
const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
567
857
|
"value",
|
|
568
858
|
"original",
|
|
@@ -571,11 +861,19 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
571
861
|
"focused",
|
|
572
862
|
"blurred",
|
|
573
863
|
"touched",
|
|
574
|
-
"
|
|
864
|
+
"connected",
|
|
865
|
+
"element",
|
|
866
|
+
"elements",
|
|
575
867
|
"updatedAt",
|
|
576
868
|
"errors",
|
|
869
|
+
"validating",
|
|
870
|
+
"valid",
|
|
577
871
|
"path",
|
|
578
|
-
"blank"
|
|
872
|
+
"blank",
|
|
873
|
+
"label",
|
|
874
|
+
"description",
|
|
875
|
+
"placeholder",
|
|
876
|
+
"meta"
|
|
579
877
|
]);
|
|
580
878
|
function buildFieldStateProxy(state) {
|
|
581
879
|
const getFieldStateAt = buildFieldStateAccessor(state);
|
|
@@ -585,12 +883,61 @@ function buildFieldStateProxy(state) {
|
|
|
585
883
|
for (const k of FIELD_STATE_KEYS) snapshot[k] = view[k];
|
|
586
884
|
return snapshot;
|
|
587
885
|
};
|
|
886
|
+
const terminalCache = /* @__PURE__ */ new Map();
|
|
887
|
+
function fieldStateTerminalAt(segments) {
|
|
888
|
+
const cacheKey = JSON.stringify(segments);
|
|
889
|
+
const existing = terminalCache.get(cacheKey);
|
|
890
|
+
if (existing !== void 0) return existing;
|
|
891
|
+
const target = (() => {
|
|
892
|
+
});
|
|
893
|
+
const proxy = new Proxy(target, {
|
|
894
|
+
get(_, key) {
|
|
895
|
+
if (typeof key === "symbol") {
|
|
896
|
+
if (key === Symbol.toPrimitive) {
|
|
897
|
+
return (hint) => hint === "number" ? NaN : JSON.stringify(snapshotFieldStateAt(segments));
|
|
898
|
+
}
|
|
899
|
+
return Reflect.get(target, key);
|
|
900
|
+
}
|
|
901
|
+
if (typeof key !== "string") return void 0;
|
|
902
|
+
if (key === "toJSON") return () => snapshotFieldStateAt(segments);
|
|
903
|
+
if (key === "toString") return () => JSON.stringify(snapshotFieldStateAt(segments));
|
|
904
|
+
if (key === "valueOf")
|
|
905
|
+
return function() {
|
|
906
|
+
return this;
|
|
907
|
+
};
|
|
908
|
+
if (FIELD_STATE_KEYS.has(key)) {
|
|
909
|
+
const computed = getFieldStateAt(segments);
|
|
910
|
+
return computed.value[key];
|
|
911
|
+
}
|
|
912
|
+
return void 0;
|
|
913
|
+
},
|
|
914
|
+
has: (_, key) => typeof key === "string" && FIELD_STATE_KEYS.has(key),
|
|
915
|
+
ownKeys: () => Array.from(FIELD_STATE_KEYS),
|
|
916
|
+
getOwnPropertyDescriptor(_, key) {
|
|
917
|
+
if (typeof key !== "string") return void 0;
|
|
918
|
+
if (!FIELD_STATE_KEYS.has(key)) return void 0;
|
|
919
|
+
const computed = getFieldStateAt(segments);
|
|
920
|
+
return {
|
|
921
|
+
configurable: true,
|
|
922
|
+
enumerable: true,
|
|
923
|
+
value: computed.value[key],
|
|
924
|
+
writable: false
|
|
925
|
+
};
|
|
926
|
+
},
|
|
927
|
+
set: () => false,
|
|
928
|
+
deleteProperty: () => false,
|
|
929
|
+
defineProperty: () => false
|
|
930
|
+
});
|
|
931
|
+
terminalCache.set(cacheKey, proxy);
|
|
932
|
+
return proxy;
|
|
933
|
+
}
|
|
588
934
|
return buildSurfaceProxy({
|
|
589
935
|
schema: state.schema,
|
|
590
936
|
resolveLeaf: (path) => getFieldStateAt(path),
|
|
591
937
|
leafKeys: FIELD_STATE_KEYS,
|
|
592
938
|
readLeafKey: (computed, key) => computed.value[key],
|
|
593
|
-
materializeContainer: (segments) => materializeFields(state, segments, snapshotFieldStateAt)
|
|
939
|
+
materializeContainer: (segments) => materializeFields(state, segments, snapshotFieldStateAt),
|
|
940
|
+
resolveCallTarget: (path) => fieldStateTerminalAt(path)
|
|
594
941
|
});
|
|
595
942
|
}
|
|
596
943
|
function materializeFields(state, containerSegments, snapshotFieldStateAt) {
|
|
@@ -922,7 +1269,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
922
1269
|
}
|
|
923
1270
|
const genAtEntry = state.submissionGeneration.value;
|
|
924
1271
|
state.activeSubmissions.value += 1;
|
|
925
|
-
state.
|
|
1272
|
+
state.submitting.value = true;
|
|
926
1273
|
state.submitError.value = null;
|
|
927
1274
|
state.cancelFieldValidation();
|
|
928
1275
|
state.activeValidations.value += 1;
|
|
@@ -969,7 +1316,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
969
1316
|
}
|
|
970
1317
|
state.activeSubmissions.value = Math.max(0, state.activeSubmissions.value - 1);
|
|
971
1318
|
if (state.submissionGeneration.value === genAtEntry) {
|
|
972
|
-
state.
|
|
1319
|
+
state.submitting.value = state.activeSubmissions.value > 0;
|
|
973
1320
|
state.submitCount.value += 1;
|
|
974
1321
|
}
|
|
975
1322
|
}
|
|
@@ -1365,14 +1712,14 @@ function buildRegister(state, formInstanceId) {
|
|
|
1365
1712
|
segments,
|
|
1366
1713
|
state.coerceIndex
|
|
1367
1714
|
);
|
|
1368
|
-
if (persist && !state.
|
|
1715
|
+
if (persist && !state.ssr && !state.modules.has(PERSISTENCE_MODULE_KEY)) {
|
|
1369
1716
|
throw new sensitiveNames.AnonPersistError({
|
|
1370
1717
|
cause: "register-without-config",
|
|
1371
1718
|
schemaFields: extractSchemaFields(state.schema),
|
|
1372
1719
|
callSite: sensitiveNames.captureUserCallSite()
|
|
1373
1720
|
});
|
|
1374
1721
|
}
|
|
1375
|
-
|
|
1722
|
+
const internalRv = {
|
|
1376
1723
|
innerRef,
|
|
1377
1724
|
displayValue,
|
|
1378
1725
|
lastTypedForm,
|
|
@@ -1396,18 +1743,25 @@ function buildRegister(state, formInstanceId) {
|
|
|
1396
1743
|
},
|
|
1397
1744
|
// Called by the `vRegisterHint` compile-time transform's wrapping
|
|
1398
1745
|
// IIFE on every server-side render of `<element v-register="…">`.
|
|
1399
|
-
// Without it, every SSR'd FieldState serialises `
|
|
1746
|
+
// Without it, every SSR'd FieldState serialises `connected: false`
|
|
1400
1747
|
// (because Vue skips directive lifecycle during SSR) and the client
|
|
1401
1748
|
// briefly shows that stale flag until hydration runs the directive's
|
|
1402
|
-
// `created` hook. The mark only takes effect when `state.
|
|
1749
|
+
// `created` hook. The mark only takes effect when `state.ssr` is
|
|
1403
1750
|
// true; on the client this is a no-op so the directive lifecycle
|
|
1404
1751
|
// remains the source of truth.
|
|
1405
1752
|
markConnectedOptimistically: () => {
|
|
1406
1753
|
state.markConnectedOptimistically(segments);
|
|
1407
1754
|
},
|
|
1755
|
+
path: pathKey,
|
|
1756
|
+
// Frozen so a wrapper component can pass `rv.segments` directly
|
|
1757
|
+
// to `form.fields(...)` without defensive copying — and so test
|
|
1758
|
+
// fixtures or downstream code can't mutate the canonical
|
|
1759
|
+
// segment list out from under the directive.
|
|
1760
|
+
segments: Object.freeze(segments.slice()),
|
|
1761
|
+
formKey: state.formKey,
|
|
1762
|
+
formInstanceId,
|
|
1408
1763
|
// --- Persistence opt-in (internal; the directive is the only
|
|
1409
1764
|
// legitimate consumer) ---
|
|
1410
|
-
path: pathKey,
|
|
1411
1765
|
persist,
|
|
1412
1766
|
acknowledgeSensitive,
|
|
1413
1767
|
persistOptIns: state.persistOptIns,
|
|
@@ -1415,6 +1769,7 @@ function buildRegister(state, formInstanceId) {
|
|
|
1415
1769
|
coerce,
|
|
1416
1770
|
...coerceElement !== void 0 ? { coerceElement } : {}
|
|
1417
1771
|
};
|
|
1772
|
+
return vue.shallowReadonly(internalRv);
|
|
1418
1773
|
};
|
|
1419
1774
|
}
|
|
1420
1775
|
|
|
@@ -1453,22 +1808,30 @@ function walk(input, segments, schema, paths$1) {
|
|
|
1453
1808
|
}
|
|
1454
1809
|
if (Array.isArray(input)) {
|
|
1455
1810
|
const out = new Array(input.length);
|
|
1811
|
+
let mutated = false;
|
|
1456
1812
|
for (let i = 0; i < input.length; i++) {
|
|
1457
|
-
|
|
1813
|
+
const walked = walk(input[i], [...segments, i], schema, paths$1);
|
|
1814
|
+
out[i] = walked;
|
|
1815
|
+
if (walked !== input[i]) mutated = true;
|
|
1458
1816
|
}
|
|
1459
|
-
return out;
|
|
1817
|
+
return mutated ? out : input;
|
|
1460
1818
|
}
|
|
1461
1819
|
if (typeof input === "object") {
|
|
1462
1820
|
const slim = schema.getDefaultAtPath(segments);
|
|
1463
|
-
const
|
|
1821
|
+
const inputKeys = Object.keys(input);
|
|
1822
|
+
const allKeys = new Set(inputKeys);
|
|
1464
1823
|
if (slim !== null && slim !== void 0 && typeof slim === "object" && !Array.isArray(slim) && !(slim instanceof Date) && !(slim instanceof RegExp) && !(slim instanceof Map) && !(slim instanceof Set)) {
|
|
1465
1824
|
for (const k of Object.keys(slim)) allKeys.add(k);
|
|
1466
1825
|
}
|
|
1467
1826
|
const out = {};
|
|
1827
|
+
let mutated = allKeys.size !== inputKeys.length;
|
|
1468
1828
|
for (const key of allKeys) {
|
|
1469
|
-
|
|
1829
|
+
const orig = input[key];
|
|
1830
|
+
const walked = walk(orig, [...segments, key], schema, paths$1);
|
|
1831
|
+
out[key] = walked;
|
|
1832
|
+
if (walked !== orig) mutated = true;
|
|
1470
1833
|
}
|
|
1471
|
-
return out;
|
|
1834
|
+
return mutated ? out : input;
|
|
1472
1835
|
}
|
|
1473
1836
|
return input;
|
|
1474
1837
|
}
|
|
@@ -1492,6 +1855,48 @@ function walkUnspecified(slim, segments, paths$1) {
|
|
|
1492
1855
|
}
|
|
1493
1856
|
return slim;
|
|
1494
1857
|
}
|
|
1858
|
+
function substituteUnsetSentinels(value, prefix, schema) {
|
|
1859
|
+
const paths = [];
|
|
1860
|
+
const cleaned = substitute(value, [...prefix], schema, paths);
|
|
1861
|
+
return { cleanedValues: cleaned, paths };
|
|
1862
|
+
}
|
|
1863
|
+
function substitute(input, segments, schema, paths$1) {
|
|
1864
|
+
if (isUnset(input)) {
|
|
1865
|
+
const slim = schema.getDefaultAtPath(segments);
|
|
1866
|
+
if (!isPrimitiveOrEmpty(slim)) {
|
|
1867
|
+
warnNonPrimitiveLeaf(segments, slim);
|
|
1868
|
+
return slim;
|
|
1869
|
+
}
|
|
1870
|
+
paths$1.push(paths.canonicalizePath(segments).key);
|
|
1871
|
+
return slim;
|
|
1872
|
+
}
|
|
1873
|
+
if (input === void 0 || input === null) return input;
|
|
1874
|
+
if (input instanceof Date || input instanceof RegExp || input instanceof Map || input instanceof Set || typeof input === "function") {
|
|
1875
|
+
return input;
|
|
1876
|
+
}
|
|
1877
|
+
if (Array.isArray(input)) {
|
|
1878
|
+
let mutated = false;
|
|
1879
|
+
const out = new Array(input.length);
|
|
1880
|
+
for (let i = 0; i < input.length; i++) {
|
|
1881
|
+
const walked = substitute(input[i], [...segments, i], schema, paths$1);
|
|
1882
|
+
out[i] = walked;
|
|
1883
|
+
if (walked !== input[i]) mutated = true;
|
|
1884
|
+
}
|
|
1885
|
+
return mutated ? out : input;
|
|
1886
|
+
}
|
|
1887
|
+
if (typeof input === "object") {
|
|
1888
|
+
let mutated = false;
|
|
1889
|
+
const out = {};
|
|
1890
|
+
for (const key of Object.keys(input)) {
|
|
1891
|
+
const orig = input[key];
|
|
1892
|
+
const walked = substitute(orig, [...segments, key], schema, paths$1);
|
|
1893
|
+
out[key] = walked;
|
|
1894
|
+
if (walked !== orig) mutated = true;
|
|
1895
|
+
}
|
|
1896
|
+
return mutated ? out : input;
|
|
1897
|
+
}
|
|
1898
|
+
return input;
|
|
1899
|
+
}
|
|
1495
1900
|
function isPrimitiveOrEmpty(value) {
|
|
1496
1901
|
if (value === null || value === void 0) return true;
|
|
1497
1902
|
const t = typeof value;
|
|
@@ -1600,14 +2005,14 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
1600
2005
|
}
|
|
1601
2006
|
function setValueImpl(pathOrValue, maybeValue) {
|
|
1602
2007
|
if (arguments.length === 1) {
|
|
1603
|
-
const next = typeof pathOrValue === "function" ? pathOrValue(state.form.value) : pathOrValue;
|
|
1604
|
-
const
|
|
2008
|
+
const next = typeof pathOrValue === "function" ? pathOrValue(structuralSnapshot(state.form.value)) : pathOrValue;
|
|
2009
|
+
const walked2 = walkUnsetSentinels(
|
|
1605
2010
|
next,
|
|
1606
2011
|
state.schema
|
|
1607
2012
|
);
|
|
1608
|
-
const
|
|
1609
|
-
if (!
|
|
1610
|
-
for (const pathKey of
|
|
2013
|
+
const ok2 = state.setValueAtPath([], walked2.cleanedValues);
|
|
2014
|
+
if (!ok2) return false;
|
|
2015
|
+
for (const pathKey of walked2.paths) {
|
|
1611
2016
|
const segments2 = paths.segmentsForPathKey(pathKey);
|
|
1612
2017
|
if (segments2 === null) continue;
|
|
1613
2018
|
state.setValueAtPath(segments2, state.schema.getDefaultAtPath(segments2), {
|
|
@@ -1635,7 +2040,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
1635
2040
|
} else {
|
|
1636
2041
|
resolvedValue = maybeValue;
|
|
1637
2042
|
}
|
|
1638
|
-
|
|
2043
|
+
const walked = substituteUnsetSentinels(
|
|
2044
|
+
resolvedValue,
|
|
2045
|
+
segments,
|
|
2046
|
+
state.schema
|
|
2047
|
+
);
|
|
2048
|
+
const ok = state.setValueAtPath(segments, walked.cleanedValues);
|
|
2049
|
+
if (!ok) return false;
|
|
2050
|
+
for (const pathKey of walked.paths) {
|
|
2051
|
+
const blankSegments = paths.segmentsForPathKey(pathKey);
|
|
2052
|
+
if (blankSegments === null) continue;
|
|
2053
|
+
state.setValueAtPath(blankSegments, state.schema.getDefaultAtPath(blankSegments), {
|
|
2054
|
+
blank: true
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
return true;
|
|
1639
2058
|
}
|
|
1640
2059
|
const errorsProxy = buildErrorsProxy(state);
|
|
1641
2060
|
function setFieldErrors(errors) {
|
|
@@ -1654,58 +2073,89 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
1654
2073
|
state.clearSchemaErrors(segments);
|
|
1655
2074
|
state.clearUserErrors(segments);
|
|
1656
2075
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
if (state.blankPaths.size !== state.originalBlankPaths.size) return true;
|
|
1662
|
-
for (const key of state.blankPaths) {
|
|
1663
|
-
if (!state.originalBlankPaths.has(key)) return true;
|
|
2076
|
+
function setFormErrors(errors) {
|
|
2077
|
+
if (errors.length === 0) {
|
|
2078
|
+
state.userErrors.delete(paths.ROOT_PATH_KEY);
|
|
2079
|
+
return;
|
|
1664
2080
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
2081
|
+
state.userErrors.set(
|
|
2082
|
+
paths.ROOT_PATH_KEY,
|
|
2083
|
+
errors.map((e) => ({
|
|
2084
|
+
path: [],
|
|
2085
|
+
message: e.message,
|
|
2086
|
+
formKey: state.formKey,
|
|
2087
|
+
code: e.code ?? "atta:form-error"
|
|
2088
|
+
}))
|
|
2089
|
+
);
|
|
2090
|
+
}
|
|
2091
|
+
function clearFormErrors() {
|
|
2092
|
+
state.userErrors.delete(paths.ROOT_PATH_KEY);
|
|
2093
|
+
}
|
|
2094
|
+
const submitting = vue.computed(() => state.submitting.value);
|
|
1671
2095
|
const submitCount = vue.computed(() => state.submitCount.value);
|
|
1672
2096
|
const submitError = vue.computed(() => state.submitError.value);
|
|
1673
|
-
const
|
|
2097
|
+
const validating = vue.computed(() => state.activeValidations.value > 0);
|
|
2098
|
+
const valid = vue.computed(
|
|
2099
|
+
() => state.firstValidationDone.value && state.schemaErrors.size === 0 && state.userErrors.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
|
|
2100
|
+
);
|
|
1674
2101
|
const history = options.history;
|
|
1675
2102
|
const undo = history?.undo ?? (() => false);
|
|
1676
2103
|
const redo = history?.redo ?? (() => false);
|
|
1677
2104
|
const canUndo = history?.canUndo ?? vue.computed(() => false);
|
|
1678
2105
|
const canRedo = history?.canRedo ?? vue.computed(() => false);
|
|
1679
2106
|
const historySize = history?.historySize ?? vue.computed(() => 0);
|
|
1680
|
-
const metaErrors = vue.computed(
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
const ordinal = state.ensurePathOrdinal(pathKey);
|
|
1686
|
-
const existing = buckets.get(ordinal);
|
|
1687
|
-
if (existing === void 0) buckets.set(ordinal, [...list]);
|
|
1688
|
-
else existing.push(...list);
|
|
1689
|
-
}
|
|
1690
|
-
};
|
|
1691
|
-
collect(state.schemaErrors);
|
|
1692
|
-
collect(state.derivedBlankErrors.value);
|
|
1693
|
-
collect(state.userErrors);
|
|
1694
|
-
if (buckets.size === 0) return [];
|
|
1695
|
-
return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
|
|
1696
|
-
});
|
|
2107
|
+
const metaErrors = vue.computed(
|
|
2108
|
+
() => aggregateErrorsAt(state, [])
|
|
2109
|
+
);
|
|
2110
|
+
const getRootFieldStateAt = buildFieldStateAccessor(state);
|
|
2111
|
+
const rootFieldState = getRootFieldStateAt([]);
|
|
1697
2112
|
const formMeta = vue.readonly(
|
|
1698
2113
|
vue.reactive({
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
2114
|
+
// FieldState fields — read through one shared root computed. Each
|
|
2115
|
+
// property accesses `rootFieldState.value[X]`, so any descendant
|
|
2116
|
+
// change re-evaluates the root computed once (Vue's reactive
|
|
2117
|
+
// graph dedupes the dependent re-renders).
|
|
2118
|
+
value: vue.computed(() => rootFieldState.value.value),
|
|
2119
|
+
original: vue.computed(() => rootFieldState.value.original),
|
|
2120
|
+
pristine: vue.computed(() => rootFieldState.value.pristine),
|
|
2121
|
+
dirty: vue.computed(() => rootFieldState.value.dirty),
|
|
2122
|
+
focused: vue.computed(() => rootFieldState.value.focused),
|
|
2123
|
+
blurred: vue.computed(() => rootFieldState.value.blurred),
|
|
2124
|
+
touched: vue.computed(() => rootFieldState.value.touched),
|
|
2125
|
+
connected: vue.computed(() => rootFieldState.value.connected),
|
|
2126
|
+
element: vue.computed(() => rootFieldState.value.element),
|
|
2127
|
+
elements: vue.computed(() => rootFieldState.value.elements),
|
|
2128
|
+
updatedAt: vue.computed(() => rootFieldState.value.updatedAt),
|
|
2129
|
+
// Whole-form validating mirrors the LIFECYCLE counter
|
|
2130
|
+
// (`state.activeValidations`) ORed with any per-leaf validation
|
|
2131
|
+
// in flight (via `rootFieldState.validating`). A submit-time
|
|
2132
|
+
// validate run shows up as activeValidations; per-field
|
|
2133
|
+
// debounced validators show up as fieldValidationCounts. Either
|
|
2134
|
+
// flips the flag.
|
|
2135
|
+
validating: vue.computed(
|
|
2136
|
+
() => state.activeValidations.value > 0 || rootFieldState.value.validating
|
|
2137
|
+
),
|
|
2138
|
+
// Whole-form valid keeps the original `firstValidationDone`
|
|
2139
|
+
// mount gate so the surface doesn't lie about a yet-to-arrive
|
|
2140
|
+
// verdict at construction time. The shared `aggregateErrorsAt`
|
|
2141
|
+
// ensures `form.meta.errors` and `rootFieldState.errors` match,
|
|
2142
|
+
// so `errors.length === 0` here would agree with `valid` —
|
|
2143
|
+
// keep the explicit form-level computation for the gate.
|
|
2144
|
+
valid,
|
|
2145
|
+
errors: metaErrors,
|
|
2146
|
+
path: vue.computed(() => rootFieldState.value.path),
|
|
2147
|
+
blank: vue.computed(() => rootFieldState.value.blank),
|
|
2148
|
+
label: vue.computed(() => rootFieldState.value.label),
|
|
2149
|
+
description: vue.computed(() => rootFieldState.value.description),
|
|
2150
|
+
placeholder: vue.computed(() => rootFieldState.value.placeholder),
|
|
2151
|
+
meta: vue.computed(() => rootFieldState.value.meta),
|
|
2152
|
+
// Lifecycle (form-level only — not on FieldState).
|
|
2153
|
+
submitting,
|
|
1703
2154
|
submitCount,
|
|
1704
2155
|
submitError,
|
|
1705
2156
|
canUndo,
|
|
1706
2157
|
canRedo,
|
|
1707
2158
|
historySize,
|
|
1708
|
-
errors: metaErrors,
|
|
1709
2159
|
// Per-`useForm()`-call identity. Stable for one mount; new on
|
|
1710
2160
|
// re-mount; orthogonal to `form.key` (which is the user-supplied
|
|
1711
2161
|
// shared identifier). Useful for devtools panels disambiguating
|
|
@@ -1796,6 +2246,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
1796
2246
|
setFieldErrors,
|
|
1797
2247
|
addFieldErrors,
|
|
1798
2248
|
clearFieldErrors,
|
|
2249
|
+
setFormErrors,
|
|
2250
|
+
clearFormErrors,
|
|
1799
2251
|
meta: formMeta,
|
|
1800
2252
|
reset,
|
|
1801
2253
|
resetField,
|
|
@@ -1816,103 +2268,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
1816
2268
|
};
|
|
1817
2269
|
}
|
|
1818
2270
|
|
|
1819
|
-
function isDescendable(value) {
|
|
1820
|
-
if (value === null || typeof value !== "object") return false;
|
|
1821
|
-
if (Array.isArray(value)) return true;
|
|
1822
|
-
const proto = Object.getPrototypeOf(value);
|
|
1823
|
-
return proto === null || proto === Object.prototype;
|
|
1824
|
-
}
|
|
1825
|
-
function appendSegment(prefix, segment) {
|
|
1826
|
-
const next = new Array(prefix.length + 1);
|
|
1827
|
-
for (let i = 0; i < prefix.length; i++) {
|
|
1828
|
-
const s = prefix[i];
|
|
1829
|
-
next[i] = s;
|
|
1830
|
-
}
|
|
1831
|
-
next[prefix.length] = segment;
|
|
1832
|
-
return next;
|
|
1833
|
-
}
|
|
1834
|
-
function diffAndApply(oldValue, newValue, prefix, visit) {
|
|
1835
|
-
if (Object.is(oldValue, newValue)) return;
|
|
1836
|
-
const oldIsDescendable = isDescendable(oldValue);
|
|
1837
|
-
const newIsDescendable = isDescendable(newValue);
|
|
1838
|
-
if (oldValue === void 0 && newIsDescendable) {
|
|
1839
|
-
if (Array.isArray(newValue)) {
|
|
1840
|
-
for (let i = 0; i < newValue.length; i++) {
|
|
1841
|
-
diffAndApply(void 0, newValue[i], appendSegment(prefix, i), visit);
|
|
1842
|
-
}
|
|
1843
|
-
} else {
|
|
1844
|
-
const rec = newValue;
|
|
1845
|
-
for (const k of Object.keys(rec)) {
|
|
1846
|
-
diffAndApply(void 0, rec[k], appendSegment(prefix, k), visit);
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
if (oldIsDescendable && newValue === void 0) {
|
|
1852
|
-
if (Array.isArray(oldValue)) {
|
|
1853
|
-
for (let i = 0; i < oldValue.length; i++) {
|
|
1854
|
-
diffAndApply(oldValue[i], void 0, appendSegment(prefix, i), visit);
|
|
1855
|
-
}
|
|
1856
|
-
} else {
|
|
1857
|
-
const rec = oldValue;
|
|
1858
|
-
for (const k of Object.keys(rec)) {
|
|
1859
|
-
diffAndApply(rec[k], void 0, appendSegment(prefix, k), visit);
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
return;
|
|
1863
|
-
}
|
|
1864
|
-
if (oldIsDescendable && newIsDescendable) {
|
|
1865
|
-
const oldIsArray = Array.isArray(oldValue);
|
|
1866
|
-
const newIsArray = Array.isArray(newValue);
|
|
1867
|
-
if (oldIsArray && newIsArray) {
|
|
1868
|
-
const oldArr = oldValue;
|
|
1869
|
-
const newArr = newValue;
|
|
1870
|
-
const max = Math.max(oldArr.length, newArr.length);
|
|
1871
|
-
for (let i = 0; i < max; i++) {
|
|
1872
|
-
diffAndApply(oldArr[i], newArr[i], appendSegment(prefix, i), visit);
|
|
1873
|
-
}
|
|
1874
|
-
return;
|
|
1875
|
-
}
|
|
1876
|
-
if (!oldIsArray && !newIsArray) {
|
|
1877
|
-
const oldRec = oldValue;
|
|
1878
|
-
const newRec = newValue;
|
|
1879
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1880
|
-
for (const k of Object.keys(oldRec)) {
|
|
1881
|
-
seen.add(k);
|
|
1882
|
-
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
1883
|
-
}
|
|
1884
|
-
for (const k of Object.keys(newRec)) {
|
|
1885
|
-
if (seen.has(k)) continue;
|
|
1886
|
-
diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
|
|
1887
|
-
}
|
|
1888
|
-
return;
|
|
1889
|
-
}
|
|
1890
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
1891
|
-
return;
|
|
1892
|
-
}
|
|
1893
|
-
if (oldIsDescendable && !newIsDescendable) {
|
|
1894
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
1895
|
-
return;
|
|
1896
|
-
}
|
|
1897
|
-
if (!oldIsDescendable && newIsDescendable) {
|
|
1898
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
1899
|
-
return;
|
|
1900
|
-
}
|
|
1901
|
-
if (oldValue === void 0) {
|
|
1902
|
-
visit({ kind: "added", path: prefix, newValue });
|
|
1903
|
-
return;
|
|
1904
|
-
}
|
|
1905
|
-
if (newValue === void 0) {
|
|
1906
|
-
visit({ kind: "removed", path: prefix, oldValue });
|
|
1907
|
-
return;
|
|
1908
|
-
}
|
|
1909
|
-
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
1910
|
-
}
|
|
1911
|
-
|
|
1912
2271
|
function isHydratedFieldRecord(value) {
|
|
1913
2272
|
if (typeof value !== "object" || value === null) return false;
|
|
1914
2273
|
const r = value;
|
|
1915
|
-
return Array.isArray(r.path) && (typeof r.updatedAt === "string" || r.updatedAt === null) && typeof r.
|
|
2274
|
+
return Array.isArray(r.path) && (typeof r.updatedAt === "string" || r.updatedAt === null) && typeof r.connected === "boolean" && (typeof r.focused === "boolean" || r.focused === null) && (typeof r.blurred === "boolean" || r.blurred === null) && (typeof r.touched === "boolean" || r.touched === null);
|
|
1916
2275
|
}
|
|
1917
2276
|
function isHydratedValidationErrorArray(value) {
|
|
1918
2277
|
if (!Array.isArray(value)) return false;
|
|
@@ -1943,7 +2302,7 @@ function isPathKeyUnder(existingKey, parentPath) {
|
|
|
1943
2302
|
}
|
|
1944
2303
|
function createFormStore(options) {
|
|
1945
2304
|
const { formKey, schema, defaultValues, strict = true, hydration } = options;
|
|
1946
|
-
const
|
|
2305
|
+
const ssr = options.ssr === true;
|
|
1947
2306
|
const rememberVariants = options.rememberVariants !== false;
|
|
1948
2307
|
const fieldValidationMode = options.validateOn ?? "change";
|
|
1949
2308
|
const fieldValidationDebounceMs = options.debounceMs ?? DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS;
|
|
@@ -1962,7 +2321,7 @@ function createFormStore(options) {
|
|
|
1962
2321
|
strict
|
|
1963
2322
|
});
|
|
1964
2323
|
const schemaInitialData = schemaResponse.data;
|
|
1965
|
-
const initialData = hydration !== void 0 ? hydration.form : schemaInitialData;
|
|
2324
|
+
const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
|
|
1966
2325
|
const form = vue.ref(initialData);
|
|
1967
2326
|
const fields = vue.reactive(/* @__PURE__ */ new Map());
|
|
1968
2327
|
const elements = vue.reactive(/* @__PURE__ */ new Map());
|
|
@@ -1970,7 +2329,7 @@ function createFormStore(options) {
|
|
|
1970
2329
|
let sortedRegistrationsCache = null;
|
|
1971
2330
|
const schemaErrors = vue.reactive(/* @__PURE__ */ new Map());
|
|
1972
2331
|
const userErrors = vue.reactive(/* @__PURE__ */ new Map());
|
|
1973
|
-
const originals = /* @__PURE__ */ new Map();
|
|
2332
|
+
const originals = vue.reactive(/* @__PURE__ */ new Map());
|
|
1974
2333
|
const initialTransientList = hydration?.blankPaths ?? options.initialBlankPaths ?? [];
|
|
1975
2334
|
const blankPaths = vue.reactive(/* @__PURE__ */ new Set());
|
|
1976
2335
|
const originalBlankPaths = /* @__PURE__ */ new Set();
|
|
@@ -2008,12 +2367,37 @@ function createFormStore(options) {
|
|
|
2008
2367
|
}
|
|
2009
2368
|
return result;
|
|
2010
2369
|
});
|
|
2011
|
-
const
|
|
2370
|
+
const submitting = vue.ref(false);
|
|
2012
2371
|
const activeSubmissions = vue.ref(0);
|
|
2013
2372
|
const submitCount = vue.ref(0);
|
|
2014
2373
|
const submitError = vue.ref(null);
|
|
2015
2374
|
const submissionGeneration = vue.ref(0);
|
|
2016
2375
|
const activeValidations = vue.ref(0);
|
|
2376
|
+
const firstValidationDone = vue.ref(!strict || schema.needsAsyncValidation?.() !== true);
|
|
2377
|
+
vue.watch(activeValidations, (now, prev) => {
|
|
2378
|
+
if (prev > 0 && now === 0) {
|
|
2379
|
+
firstValidationDone.value = true;
|
|
2380
|
+
}
|
|
2381
|
+
});
|
|
2382
|
+
const pathAsyncCache = /* @__PURE__ */ new Map();
|
|
2383
|
+
function pathHasAsyncValidation(path) {
|
|
2384
|
+
const { key } = paths.canonicalizePath(path);
|
|
2385
|
+
const cached = pathAsyncCache.get(key);
|
|
2386
|
+
if (cached !== void 0) return cached;
|
|
2387
|
+
const candidates = schema.getSchemasAtPath(path);
|
|
2388
|
+
const hasAsync = candidates.some((sub) => sub.needsAsyncValidation?.() === true);
|
|
2389
|
+
pathAsyncCache.set(key, hasAsync);
|
|
2390
|
+
return hasAsync;
|
|
2391
|
+
}
|
|
2392
|
+
const fieldValidationCounts = vue.reactive(/* @__PURE__ */ new Map());
|
|
2393
|
+
function incFieldValidation(key) {
|
|
2394
|
+
fieldValidationCounts.set(key, (fieldValidationCounts.get(key) ?? 0) + 1);
|
|
2395
|
+
}
|
|
2396
|
+
function decFieldValidation(key) {
|
|
2397
|
+
const next = (fieldValidationCounts.get(key) ?? 0) - 1;
|
|
2398
|
+
if (next <= 0) fieldValidationCounts.delete(key);
|
|
2399
|
+
else fieldValidationCounts.set(key, next);
|
|
2400
|
+
}
|
|
2017
2401
|
const initStamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2018
2402
|
diffAndApply({}, schemaInitialData, [], (patch) => {
|
|
2019
2403
|
if (patch.kind !== "added") return;
|
|
@@ -2050,7 +2434,7 @@ function createFormStore(options) {
|
|
|
2050
2434
|
fields.set(key, {
|
|
2051
2435
|
path: patch.path,
|
|
2052
2436
|
updatedAt: initStamp,
|
|
2053
|
-
|
|
2437
|
+
connected: false,
|
|
2054
2438
|
focused: null,
|
|
2055
2439
|
blurred: null,
|
|
2056
2440
|
touched: null
|
|
@@ -2060,7 +2444,7 @@ function createFormStore(options) {
|
|
|
2060
2444
|
setAllSchemaErrors(schemaResponse.errors);
|
|
2061
2445
|
}
|
|
2062
2446
|
}
|
|
2063
|
-
if (!
|
|
2447
|
+
if (!ssr && strict && schema.needsAsyncValidation?.() === true) {
|
|
2064
2448
|
queueMicrotask(() => scheduleFieldValidation(
|
|
2065
2449
|
[],
|
|
2066
2450
|
true
|
|
@@ -2072,7 +2456,7 @@ function createFormStore(options) {
|
|
|
2072
2456
|
fields.set(pathKey, {
|
|
2073
2457
|
path,
|
|
2074
2458
|
updatedAt: patch.updatedAt ?? current?.updatedAt ?? null,
|
|
2075
|
-
|
|
2459
|
+
connected: patch.connected ?? current?.connected ?? false,
|
|
2076
2460
|
focused: patch.focused ?? current?.focused ?? null,
|
|
2077
2461
|
blurred: patch.blurred ?? current?.blurred ?? null,
|
|
2078
2462
|
touched: patch.touched ?? current?.touched ?? null
|
|
@@ -2081,18 +2465,24 @@ function createFormStore(options) {
|
|
|
2081
2465
|
function applyFormReplacement(next, meta) {
|
|
2082
2466
|
const prev = form.value;
|
|
2083
2467
|
if (Object.is(prev, next)) return;
|
|
2084
|
-
form.value = next;
|
|
2085
2468
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2469
|
+
const patches = [];
|
|
2086
2470
|
diffAndApply(prev, next, [], (patch) => {
|
|
2471
|
+
patches.push(patch);
|
|
2472
|
+
});
|
|
2473
|
+
if (!applyChangedKeys(prev, next)) {
|
|
2474
|
+
form.value = next;
|
|
2475
|
+
}
|
|
2476
|
+
for (const patch of patches) {
|
|
2087
2477
|
const { key } = paths.canonicalizePath(patch.path);
|
|
2088
2478
|
if (patch.kind === "added" && !originals.has(key)) {
|
|
2089
2479
|
originals.set(key, { segments: patch.path, value: void 0 });
|
|
2090
2480
|
}
|
|
2091
2481
|
touchFieldRecord(key, patch.path, { updatedAt: now });
|
|
2092
|
-
}
|
|
2482
|
+
}
|
|
2093
2483
|
for (const listener of formChangeListeners) {
|
|
2094
2484
|
try {
|
|
2095
|
-
listener(
|
|
2485
|
+
listener(form.value, meta);
|
|
2096
2486
|
} catch (err) {
|
|
2097
2487
|
console.error("[attaform] onFormChange threw:", err);
|
|
2098
2488
|
}
|
|
@@ -2266,6 +2656,7 @@ function createFormStore(options) {
|
|
|
2266
2656
|
if (controller.signal.aborted) return;
|
|
2267
2657
|
const data = getAtPath(form.value, path);
|
|
2268
2658
|
activeValidations.value += 1;
|
|
2659
|
+
incFieldValidation(key);
|
|
2269
2660
|
void Promise.resolve().then(() => schema.validateAtPath(data, path)).then((response) => {
|
|
2270
2661
|
if (controller.signal.aborted) return;
|
|
2271
2662
|
const reStamped = response.success ? [] : response.errors.map((err) => ({
|
|
@@ -2276,6 +2667,7 @@ function createFormStore(options) {
|
|
|
2276
2667
|
}).catch(() => {
|
|
2277
2668
|
}).finally(() => {
|
|
2278
2669
|
activeValidations.value = Math.max(0, activeValidations.value - 1);
|
|
2670
|
+
decFieldValidation(key);
|
|
2279
2671
|
});
|
|
2280
2672
|
};
|
|
2281
2673
|
if (immediate || fieldValidationDebounceMs === 0) {
|
|
@@ -2431,15 +2823,16 @@ function createFormStore(options) {
|
|
|
2431
2823
|
function registerElement(path, element, formInstanceId) {
|
|
2432
2824
|
const { key } = paths.canonicalizePath(path);
|
|
2433
2825
|
const record = elements.get(key);
|
|
2826
|
+
const raw = vue.markRaw(element);
|
|
2434
2827
|
if (record === void 0) {
|
|
2435
|
-
elements.set(key, { path, elements: /* @__PURE__ */ new Set([
|
|
2828
|
+
elements.set(key, { path, elements: vue.reactive(/* @__PURE__ */ new Set([raw])) });
|
|
2436
2829
|
} else {
|
|
2437
|
-
if (record.elements.has(
|
|
2438
|
-
record.elements.add(
|
|
2830
|
+
if (record.elements.has(raw)) return false;
|
|
2831
|
+
record.elements.add(raw);
|
|
2439
2832
|
}
|
|
2440
2833
|
elementToFormInstance.set(element, formInstanceId);
|
|
2441
2834
|
sortedRegistrationsCache = null;
|
|
2442
|
-
touchFieldRecord(key, path, {
|
|
2835
|
+
touchFieldRecord(key, path, { connected: true });
|
|
2443
2836
|
return true;
|
|
2444
2837
|
}
|
|
2445
2838
|
function deregisterElement(path, element) {
|
|
@@ -2454,16 +2847,16 @@ function createFormStore(options) {
|
|
|
2454
2847
|
const remaining = record.elements.size;
|
|
2455
2848
|
if (remaining === 0) {
|
|
2456
2849
|
elements.delete(key);
|
|
2457
|
-
touchFieldRecord(key, path, {
|
|
2850
|
+
touchFieldRecord(key, path, { connected: false });
|
|
2458
2851
|
}
|
|
2459
2852
|
return remaining;
|
|
2460
2853
|
}
|
|
2461
2854
|
function markConnectedOptimistically(path) {
|
|
2462
|
-
if (!
|
|
2855
|
+
if (!ssr) return;
|
|
2463
2856
|
const { key } = paths.canonicalizePath(path);
|
|
2464
2857
|
const current = fields.get(key);
|
|
2465
|
-
if (current?.
|
|
2466
|
-
touchFieldRecord(key, path, {
|
|
2858
|
+
if (current?.connected === true) return;
|
|
2859
|
+
touchFieldRecord(key, path, { connected: true });
|
|
2467
2860
|
}
|
|
2468
2861
|
function markFocused(path, focused) {
|
|
2469
2862
|
const { key } = paths.canonicalizePath(path);
|
|
@@ -2515,14 +2908,14 @@ function createFormStore(options) {
|
|
|
2515
2908
|
fields.set(pathKey, {
|
|
2516
2909
|
path: record.path,
|
|
2517
2910
|
updatedAt: now,
|
|
2518
|
-
|
|
2911
|
+
connected: record.connected,
|
|
2519
2912
|
focused: null,
|
|
2520
2913
|
blurred: null,
|
|
2521
2914
|
touched: null
|
|
2522
2915
|
});
|
|
2523
2916
|
}
|
|
2524
2917
|
submissionGeneration.value += 1;
|
|
2525
|
-
|
|
2918
|
+
submitting.value = false;
|
|
2526
2919
|
activeSubmissions.value = 0;
|
|
2527
2920
|
submitCount.value = 0;
|
|
2528
2921
|
submitError.value = null;
|
|
@@ -2599,7 +2992,7 @@ function createFormStore(options) {
|
|
|
2599
2992
|
fields.set(pathKey, {
|
|
2600
2993
|
path: record.path,
|
|
2601
2994
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2602
|
-
|
|
2995
|
+
connected: record.connected,
|
|
2603
2996
|
focused: null,
|
|
2604
2997
|
blurred: null,
|
|
2605
2998
|
touched: null
|
|
@@ -2661,13 +3054,16 @@ function createFormStore(options) {
|
|
|
2661
3054
|
derivedBlankErrors,
|
|
2662
3055
|
originals,
|
|
2663
3056
|
schema,
|
|
2664
|
-
|
|
2665
|
-
|
|
3057
|
+
ssr,
|
|
3058
|
+
submitting,
|
|
2666
3059
|
activeSubmissions,
|
|
2667
3060
|
submitCount,
|
|
2668
3061
|
submitError,
|
|
2669
3062
|
submissionGeneration,
|
|
2670
3063
|
activeValidations,
|
|
3064
|
+
firstValidationDone,
|
|
3065
|
+
pathHasAsyncValidation,
|
|
3066
|
+
fieldValidationCounts,
|
|
2671
3067
|
applyFormReplacement,
|
|
2672
3068
|
setValueAtPath,
|
|
2673
3069
|
getValueAtPath,
|
|
@@ -2720,7 +3116,7 @@ function createHistoryModule(state, config) {
|
|
|
2720
3116
|
let suppressNext = false;
|
|
2721
3117
|
function captureSnapshot() {
|
|
2722
3118
|
return {
|
|
2723
|
-
form: state.form.value,
|
|
3119
|
+
form: structuralSnapshot(state.form.value),
|
|
2724
3120
|
blankPaths: [...state.blankPaths],
|
|
2725
3121
|
schemaErrors: [...state.schemaErrors.entries()].map(([k, v]) => [k, [...v]]),
|
|
2726
3122
|
userErrors: [...state.userErrors.entries()].map(([k, v]) => [k, [...v]])
|
|
@@ -2827,8 +3223,8 @@ function useAbstractForm(configuration) {
|
|
|
2827
3223
|
const releaseConsumer = registry.trackConsumer(key);
|
|
2828
3224
|
vue.onScopeDispose(releaseConsumer);
|
|
2829
3225
|
}
|
|
2830
|
-
const persistDisabledByAnonRule = merged.persist !== void 0 && enforceAnonPersistRule(state.formKey, registry.
|
|
2831
|
-
if (existing === void 0 && !registry.
|
|
3226
|
+
const persistDisabledByAnonRule = merged.persist !== void 0 && enforceAnonPersistRule(state.formKey, registry.ssr);
|
|
3227
|
+
if (existing === void 0 && !registry.ssr) {
|
|
2832
3228
|
if (merged.persist !== void 0 && !persistDisabledByAnonRule) {
|
|
2833
3229
|
const resolvedPersist = normalizePersistConfig(merged.persist);
|
|
2834
3230
|
const persistenceBase = resolveStorageKeyBase(resolvedPersist, state.formKey);
|
|
@@ -2847,7 +3243,7 @@ function useAbstractForm(configuration) {
|
|
|
2847
3243
|
state.registerCleanup(() => historyModule.dispose());
|
|
2848
3244
|
}
|
|
2849
3245
|
if (configuration.key === void 0) {
|
|
2850
|
-
recordAmbientProvide(registry.
|
|
3246
|
+
recordAmbientProvide(registry.ssr);
|
|
2851
3247
|
vue.provide(sensitiveNames.kFormContext, state);
|
|
2852
3248
|
}
|
|
2853
3249
|
const formInstanceId = vue.getCurrentInstance() !== null ? vue.useId() : `atta:form-instance:${formInstanceCounter++}`;
|
|
@@ -2900,7 +3296,7 @@ function buildFreshState(key, schema, configuration, registry) {
|
|
|
2900
3296
|
hydration: pending,
|
|
2901
3297
|
...configuration.validateOn !== void 0 ? { validateOn: configuration.validateOn } : {},
|
|
2902
3298
|
...configuration.debounceMs !== void 0 ? { debounceMs: configuration.debounceMs } : {},
|
|
2903
|
-
|
|
3299
|
+
ssr: registry.ssr,
|
|
2904
3300
|
...configuration.rememberVariants !== void 0 ? { rememberVariants: configuration.rememberVariants } : {},
|
|
2905
3301
|
...configuration.coerce !== void 0 ? { coerce: configuration.coerce } : {},
|
|
2906
3302
|
...initialBlankPaths !== void 0 ? { initialBlankPaths } : {}
|
|
@@ -2915,8 +3311,8 @@ function buildFreshState(key, schema, configuration, registry) {
|
|
|
2915
3311
|
let anonCounter = 0;
|
|
2916
3312
|
let formInstanceCounter = 0;
|
|
2917
3313
|
const ambientProvideHistory = sensitiveNames.__DEV__ ? /* @__PURE__ */ new WeakMap() : null;
|
|
2918
|
-
function recordAmbientProvide(
|
|
2919
|
-
if (!sensitiveNames.__DEV__ ||
|
|
3314
|
+
function recordAmbientProvide(ssr) {
|
|
3315
|
+
if (!sensitiveNames.__DEV__ || ssr || ambientProvideHistory === null) return;
|
|
2920
3316
|
const instance = vue.getCurrentInstance();
|
|
2921
3317
|
if (instance === null) return;
|
|
2922
3318
|
const instanceKey = instance;
|
|
@@ -3178,14 +3574,14 @@ function isEmptyContainer(value) {
|
|
|
3178
3574
|
return false;
|
|
3179
3575
|
}
|
|
3180
3576
|
const warnedAnonPersistKeys = /* @__PURE__ */ new Set();
|
|
3181
|
-
function enforceAnonPersistRule(formKey,
|
|
3577
|
+
function enforceAnonPersistRule(formKey, ssr) {
|
|
3182
3578
|
if (!formKey.startsWith(ANONYMOUS_FORM_KEY_PREFIX)) return false;
|
|
3183
3579
|
if (sensitiveNames.__DEV__)
|
|
3184
3580
|
throw new sensitiveNames.AnonPersistError({
|
|
3185
3581
|
cause: "no-key",
|
|
3186
3582
|
callSite: sensitiveNames.captureUserCallSite()
|
|
3187
3583
|
});
|
|
3188
|
-
if (!
|
|
3584
|
+
if (!ssr && !warnedAnonPersistKeys.has(formKey)) {
|
|
3189
3585
|
warnedAnonPersistKeys.add(formKey);
|
|
3190
3586
|
console.warn(
|
|
3191
3587
|
"[attaform] persist: ignored \u2014 anonymous useForm() can't safely persist (key drift + cross-form collision risk).\n Persistence is disabled for this form; the app keeps working.\n Fix: useForm({ schema, key: 'login', persist: '...' })"
|
|
@@ -3243,21 +3639,21 @@ function resolveState(key, registry) {
|
|
|
3243
3639
|
if (key !== void 0) {
|
|
3244
3640
|
const stored = registry.forms.get(key);
|
|
3245
3641
|
if (stored === void 0) {
|
|
3246
|
-
warnMiss(`no form registered for key '${key}'`, registry.
|
|
3642
|
+
warnMiss(`no form registered for key '${key}'`, registry.ssr);
|
|
3247
3643
|
return null;
|
|
3248
3644
|
}
|
|
3249
3645
|
return stored;
|
|
3250
3646
|
}
|
|
3251
3647
|
const ambient = vue.inject(sensitiveNames.kFormContext, null);
|
|
3252
3648
|
if (ambient === null) {
|
|
3253
|
-
warnMiss("no ambient form context", registry.
|
|
3649
|
+
warnMiss("no ambient form context", registry.ssr);
|
|
3254
3650
|
return null;
|
|
3255
3651
|
}
|
|
3256
3652
|
warnIfAmbientProviderHadDuplicates();
|
|
3257
3653
|
return ambient;
|
|
3258
3654
|
}
|
|
3259
|
-
function warnMiss(detail,
|
|
3260
|
-
if (!sensitiveNames.__DEV__ ||
|
|
3655
|
+
function warnMiss(detail, ssr) {
|
|
3656
|
+
if (!sensitiveNames.__DEV__ || ssr) return;
|
|
3261
3657
|
const frame = sensitiveNames.captureUserCallSite();
|
|
3262
3658
|
console.warn(
|
|
3263
3659
|
`[attaform] injectForm: ${detail}. Returning null.` + (frame !== void 0 ? ` ${frame}` : "")
|
|
@@ -3285,6 +3681,7 @@ exports.AttaformErrorCode = AttaformErrorCode;
|
|
|
3285
3681
|
exports.defaultCoercionRules = defaultCoercionRules;
|
|
3286
3682
|
exports.defineCoercion = defineCoercion;
|
|
3287
3683
|
exports.getAtPath = getAtPath;
|
|
3684
|
+
exports.humanize = humanize;
|
|
3288
3685
|
exports.injectForm = injectForm;
|
|
3289
3686
|
exports.isPlainRecord = isPlainRecord;
|
|
3290
3687
|
exports.isUnset = isUnset;
|
|
@@ -3292,4 +3689,4 @@ exports.setAtPath = setAtPath;
|
|
|
3292
3689
|
exports.slimKindOf = slimKindOf;
|
|
3293
3690
|
exports.unset = unset;
|
|
3294
3691
|
exports.useAbstractForm = useAbstractForm;
|
|
3295
|
-
//# sourceMappingURL=attaform.
|
|
3692
|
+
//# sourceMappingURL=attaform.CDJVeoJU.cjs.map
|