attaform 0.30.1 → 0.31.1
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/abstract.d.mts +5 -5
- package/dist/abstract.mjs +4 -4
- package/dist/dev/abstract.mjs +4 -4
- package/dist/dev/chunks/devtools.mjs +3 -3
- package/dist/dev/directive.mjs +1 -1
- package/dist/dev/history.mjs +15 -2
- package/dist/dev/index.mjs +5 -5
- package/dist/dev/runtime/plugins/attaform.mjs +1 -1
- package/dist/dev/shared/{attaform-dev.zlvDr0WB.mjs → attaform-dev.04aupFBW.mjs} +3 -2
- package/dist/dev/shared/{attaform-dev.DxHdkkPG.mjs → attaform-dev.3uTCYwy8.mjs} +770 -254
- package/dist/dev/shared/{attaform-dev.BJK1kqHY.mjs → attaform-dev.BpVGFSFa.mjs} +88 -115
- package/dist/dev/shared/{attaform-dev.Chm4D6SJ.mjs → attaform-dev.Bu6wgrA5.mjs} +3 -3
- package/dist/dev/shared/{attaform-dev.BMQ3GcgD.mjs → attaform-dev.Cbx0AiQF.mjs} +476 -337
- package/dist/dev/shared/attaform-dev.CwYTWyPX.mjs +120 -0
- package/dist/dev/shared/{attaform-dev.DuEE4GU1.mjs → attaform-dev.D7lKyM_7.mjs} +4 -4
- package/dist/dev/shared/{attaform-dev.CT7MDjPy.mjs → attaform-dev.OceE0X3v.mjs} +154 -229
- package/dist/{shared/attaform.DRsANMok.mjs → dev/shared/attaform-dev.PTGM9KE1.mjs} +16 -15
- package/dist/{shared/attaform.8mfKZCwH.mjs → dev/shared/attaform-dev.n6n00owJ.mjs} +49 -128
- package/dist/dev/zod-v3.mjs +6 -6
- package/dist/dev/zod-v4.mjs +6 -6
- package/dist/dev/zod.mjs +5 -5
- package/dist/directive.d.mts +2 -2
- package/dist/directive.mjs +1 -1
- package/dist/history.d.mts +1 -1
- package/dist/history.mjs +15 -2
- package/dist/index.d.mts +16 -55
- package/dist/index.mjs +5 -5
- package/dist/runtime/components/AttaformDevtoolsPanel.vue +3 -3
- package/dist/runtime/plugins/attaform.mjs +1 -1
- package/dist/shared/{attaform.CO918TdU.mjs → attaform.B5b-HmhH.mjs} +88 -115
- package/dist/shared/{attaform.2FslhB9R.d.mts → attaform.B9PYKlhB.d.mts} +43 -19
- package/dist/shared/{attaform.D_f1WgYf.mjs → attaform.BPMOl562.mjs} +458 -319
- package/dist/{dev/shared/attaform-dev.CZz4GYZ6.mjs → shared/attaform.BPSqtU7a.mjs} +44 -156
- package/dist/shared/{attaform.CdZIEf7_.mjs → attaform.BhtAZysa.mjs} +3 -2
- package/dist/shared/{attaform.BcQwgWaq.d.mts → attaform.CYlF4P6X.d.mts} +58 -17
- package/dist/shared/{attaform.WiGdIqgx.mjs → attaform.CdA9bfRv.mjs} +3 -3
- package/dist/shared/{attaform.BIWicztt.mjs → attaform.DAf4ehIe.mjs} +765 -251
- package/dist/shared/{attaform.ZYn2ahzJ.mjs → attaform.DBCbxlyk.mjs} +59 -1
- package/dist/shared/{attaform.L0kUn3vL.d.mts → attaform.DZOynI6c.d.mts} +1 -1
- package/dist/shared/{attaform.B2iebkPA.mjs → attaform.KEfNRDot.mjs} +4 -4
- package/dist/shared/attaform._1Zp3mDG.mjs +96 -0
- package/dist/shared/{attaform.Br8EBn5B.d.mts → attaform.i13OEHJF.d.mts} +195 -38
- package/dist/{dev/shared/attaform-dev.BUIFcTYf.mjs → shared/attaform.j9xI_ObC.mjs} +16 -15
- package/dist/shared/{attaform.D_pt1gOj.mjs → attaform.u6jfHoed.mjs} +154 -229
- package/dist/transforms.mjs +1 -1
- package/dist/vite.mjs +1 -1
- package/dist/zod-v3.d.mts +4 -4
- package/dist/zod-v3.mjs +6 -6
- package/dist/zod-v4.d.mts +22 -16
- package/dist/zod-v4.mjs +6 -6
- package/dist/zod.d.mts +4 -4
- package/dist/zod.mjs +5 -5
- package/package.json +2 -1
- package/skills/attaform/SKILL.md +2 -1
- package/skills/attaform/references/custom-components.md +4 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as safeAssign, a as safeOwnRead, r as readConsumerIndex, c as consumerKeys, b as readConsumerProp } from './attaform._1Zp3mDG.mjs';
|
|
2
|
+
import { m as mapSegmentKeys, f as pathsEqual, i as isPathPrefix } from './attaform.BhtAZysa.mjs';
|
|
2
3
|
|
|
3
4
|
const DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS = 0;
|
|
4
5
|
const DEFAULT_HISTORY_MAX_SNAPSHOTS = 128;
|
|
@@ -9,11 +10,6 @@ const DEFAULT_MAX_RECURSION_DEPTH = 64;
|
|
|
9
10
|
function normalizeNumericOption(config) {
|
|
10
11
|
const { value, source, min, defaultValue } = config;
|
|
11
12
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
12
|
-
{
|
|
13
|
-
console.warn(
|
|
14
|
-
`[attaform] ${source} must be a non-negative finite integer; got ${String(value)}. Falling back to ${String(defaultValue)}.`
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
13
|
return defaultValue;
|
|
18
14
|
}
|
|
19
15
|
return Math.max(min, Math.floor(value));
|
|
@@ -26,124 +22,6 @@ function pickDefined(bag) {
|
|
|
26
22
|
return out;
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
const reported = /* @__PURE__ */ new Set() ;
|
|
30
|
-
function reportConsumerThrow(site, detail, err) {
|
|
31
|
-
const key = detail === void 0 ? site : `${site}|${detail}`;
|
|
32
|
-
if (reported === null || reported.has(key)) return;
|
|
33
|
-
reported.add(key);
|
|
34
|
-
const at = detail === void 0 ? "" : ` at \`${detail}\``;
|
|
35
|
-
const advice = {
|
|
36
|
-
"default-factory": "a `.default(() => ...)` factory threw. Attaform used `undefined` for that field's initial value.",
|
|
37
|
-
"catch-factory": "a `.catch(() => ...)` fallback threw. Attaform used `undefined` for that value.",
|
|
38
|
-
"lazy-getter": "a `z.lazy(() => ...)` factory threw. Attaform stopped descending at that node, so paths below it will not resolve.",
|
|
39
|
-
"wizard-slot": `a function step slot threw${at}. Attaform dropped that step from the compiled list; the rest of the flow still navigates.`,
|
|
40
|
-
"wizard-lazy-slot": `a \`lazy()\` step resolver threw${at}. Attaform dropped that step from the compiled list until the resolver's own dependencies change.`,
|
|
41
|
-
"wizard-progress": "a `useWizard({ progress })` override threw. Attaform fell back to its own valid-step ratio.",
|
|
42
|
-
"wizard-restore": "a `useWizard({ restore })` callback threw. Attaform read no step from it, so the wizard stays where it is.",
|
|
43
|
-
"wizard-persist": "a `useWizard({ persist })` callback threw. Attaform navigated anyway, so the step is live but unrecorded.",
|
|
44
|
-
"wizard-default-statuses": "a `useWizard({ defaultStatuses })` factory threw or rejected. Attaform seeded no statuses, the same as omitting the option."
|
|
45
|
-
};
|
|
46
|
-
console.error(
|
|
47
|
-
`[attaform] ${advice[site]} Attaform has nowhere to surface this, so it must not throw; wrap your own try/catch if the failure is recoverable. Original error:`,
|
|
48
|
-
err
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
function callConsumerFn(fn, fallback, site, detail) {
|
|
52
|
-
try {
|
|
53
|
-
return fn();
|
|
54
|
-
} catch (err) {
|
|
55
|
-
reportConsumerThrow(site, detail, err);
|
|
56
|
-
return fallback;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function readConsumerProp(obj, key) {
|
|
60
|
-
try {
|
|
61
|
-
return obj[key];
|
|
62
|
-
} catch {
|
|
63
|
-
return void 0;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function consumerKeys(obj) {
|
|
67
|
-
try {
|
|
68
|
-
return Object.keys(obj);
|
|
69
|
-
} catch {
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function readConsumerIndex(arr, i) {
|
|
74
|
-
try {
|
|
75
|
-
return arr[i];
|
|
76
|
-
} catch {
|
|
77
|
-
return void 0;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function consumerSymbolKeys(obj) {
|
|
81
|
-
try {
|
|
82
|
-
return Object.getOwnPropertySymbols(obj);
|
|
83
|
-
} catch {
|
|
84
|
-
return [];
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function consumerHas(obj, key) {
|
|
88
|
-
try {
|
|
89
|
-
return key in obj;
|
|
90
|
-
} catch {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function safeAssign(target, key, value) {
|
|
96
|
-
if (key === "__proto__") {
|
|
97
|
-
Object.defineProperty(target, key, {
|
|
98
|
-
value,
|
|
99
|
-
writable: true,
|
|
100
|
-
enumerable: true,
|
|
101
|
-
configurable: true
|
|
102
|
-
});
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
target[key] = value;
|
|
106
|
-
}
|
|
107
|
-
const SHADOWED_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));
|
|
108
|
-
function isShadowedKey(key) {
|
|
109
|
-
return SHADOWED_KEYS.has(key);
|
|
110
|
-
}
|
|
111
|
-
function safeOwnRead(target, key) {
|
|
112
|
-
if (isShadowedKey(key)) {
|
|
113
|
-
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
114
|
-
if (desc === void 0) return void 0;
|
|
115
|
-
return "value" in desc ? desc.value : readConsumerProp(target, key);
|
|
116
|
-
}
|
|
117
|
-
return readConsumerProp(target, key);
|
|
118
|
-
}
|
|
119
|
-
function safeOwnHas(target, key) {
|
|
120
|
-
try {
|
|
121
|
-
return Object.prototype.hasOwnProperty.call(target, key);
|
|
122
|
-
} catch {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function spreadConsumerRecord(src) {
|
|
127
|
-
try {
|
|
128
|
-
return { ...src };
|
|
129
|
-
} catch {
|
|
130
|
-
const out = {};
|
|
131
|
-
for (const key of Object.keys(src)) {
|
|
132
|
-
safeAssign(out, key, readConsumerProp(src, key));
|
|
133
|
-
}
|
|
134
|
-
return out;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
function copyConsumerArray(src) {
|
|
138
|
-
try {
|
|
139
|
-
return src.slice();
|
|
140
|
-
} catch {
|
|
141
|
-
const out = new Array(src.length);
|
|
142
|
-
for (let i = 0; i < src.length; i++) out[i] = readConsumerIndex(src, i);
|
|
143
|
-
return out;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
25
|
function isDescendable(value) {
|
|
148
26
|
if (value === null || typeof value !== "object") return false;
|
|
149
27
|
if (Array.isArray(value)) return true;
|
|
@@ -151,6 +29,9 @@ function isDescendable(value) {
|
|
|
151
29
|
const proto = Object.getPrototypeOf(value);
|
|
152
30
|
return proto === null || proto === Object.prototype;
|
|
153
31
|
}
|
|
32
|
+
function isBarePatch(patch) {
|
|
33
|
+
return patch.kind === "added" ? isDescendable(patch.newValue) : patch.kind === "removed" && isDescendable(patch.oldValue);
|
|
34
|
+
}
|
|
154
35
|
function appendSegment(prefix, segment) {
|
|
155
36
|
const next = new Array(prefix.length + 1);
|
|
156
37
|
for (let i = 0; i < prefix.length; i++) {
|
|
@@ -165,11 +46,11 @@ function diffAndApply(oldValue, newValue, prefix, visit) {
|
|
|
165
46
|
const oldIsDescendable = isDescendable(oldValue);
|
|
166
47
|
const newIsDescendable = isDescendable(newValue);
|
|
167
48
|
if (oldValue === void 0 && newIsDescendable) {
|
|
168
|
-
|
|
49
|
+
walkDescendable(newValue, prefix, visit, true);
|
|
169
50
|
return;
|
|
170
51
|
}
|
|
171
52
|
if (oldIsDescendable && newValue === void 0) {
|
|
172
|
-
|
|
53
|
+
walkDescendable(oldValue, prefix, visit, false);
|
|
173
54
|
return;
|
|
174
55
|
}
|
|
175
56
|
if (oldIsDescendable && newIsDescendable) {
|
|
@@ -219,50 +100,51 @@ function diffAndApply(oldValue, newValue, prefix, visit) {
|
|
|
219
100
|
}
|
|
220
101
|
visit({ kind: "changed", path: prefix, oldValue, newValue });
|
|
221
102
|
}
|
|
222
|
-
function
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
103
|
+
function walkDescendable(value, prefix, visit, arrived) {
|
|
104
|
+
let reported = false;
|
|
105
|
+
if (Array.isArray(value)) {
|
|
106
|
+
for (let i = 0; i < value.length; i++) {
|
|
107
|
+
diffSlot(readConsumerIndex(value, i), appendSegment(prefix, i), visit, arrived);
|
|
226
108
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
109
|
+
reported = value.length > 0;
|
|
110
|
+
} else if (value instanceof Map) {
|
|
111
|
+
for (const [key, entry] of value) {
|
|
112
|
+
diffSlot(entry, appendSegment(prefix, key), visit, arrived);
|
|
230
113
|
}
|
|
114
|
+
reported = value.size > 0;
|
|
231
115
|
} else {
|
|
232
|
-
const rec =
|
|
116
|
+
const rec = value;
|
|
233
117
|
for (const k of consumerKeys(rec)) {
|
|
234
|
-
|
|
118
|
+
const entry = readConsumerProp(rec, k);
|
|
119
|
+
if (entry === void 0) continue;
|
|
120
|
+
reported = true;
|
|
121
|
+
if (arrived) diffAndApply(void 0, entry, appendSegment(prefix, k), visit);
|
|
122
|
+
else diffAndApply(entry, void 0, appendSegment(prefix, k), visit);
|
|
235
123
|
}
|
|
236
124
|
}
|
|
125
|
+
if (!reported) visit(presencePatch(arrived, prefix, value));
|
|
237
126
|
}
|
|
238
|
-
function
|
|
239
|
-
if (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
diffAndApply(entry, void 0, appendSegment(prefix, key), visit);
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
const rec = oldValue;
|
|
249
|
-
for (const k of consumerKeys(rec)) {
|
|
250
|
-
diffAndApply(readConsumerProp(rec, k), void 0, appendSegment(prefix, k), visit);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
127
|
+
function diffSlot(entry, path, visit, arrived) {
|
|
128
|
+
if (entry === void 0) visit(presencePatch(arrived, path, entry));
|
|
129
|
+
else if (arrived) diffAndApply(void 0, entry, path, visit);
|
|
130
|
+
else diffAndApply(entry, void 0, path, visit);
|
|
131
|
+
}
|
|
132
|
+
function presencePatch(arrived, path, value) {
|
|
133
|
+
return arrived ? { kind: "added", path, newValue: value } : { kind: "removed", path, oldValue: value };
|
|
253
134
|
}
|
|
254
135
|
function diffMapsLockstep(oldMap, newMap, prefix, visit) {
|
|
255
136
|
for (const [key, entry] of newMap) {
|
|
256
|
-
|
|
137
|
+
const path = appendSegment(prefix, key);
|
|
138
|
+
if (oldMap.has(key)) diffAndApply(oldMap.get(key), entry, path, visit);
|
|
139
|
+
else diffSlot(entry, path, visit, true);
|
|
257
140
|
}
|
|
258
141
|
for (const [key, entry] of oldMap) {
|
|
259
|
-
if (newMap.has(key))
|
|
260
|
-
diffAndApply(entry, void 0, appendSegment(prefix, key), visit);
|
|
142
|
+
if (!newMap.has(key)) diffSlot(entry, appendSegment(prefix, key), visit, false);
|
|
261
143
|
}
|
|
262
144
|
}
|
|
263
145
|
function diffArraysLockstep(oldArr, newArr, prefix, visit) {
|
|
264
|
-
const
|
|
265
|
-
for (let i = 0; i <
|
|
146
|
+
const min = Math.min(oldArr.length, newArr.length);
|
|
147
|
+
for (let i = 0; i < min; i++) {
|
|
266
148
|
diffAndApply(
|
|
267
149
|
readConsumerIndex(oldArr, i),
|
|
268
150
|
readConsumerIndex(newArr, i),
|
|
@@ -270,6 +152,12 @@ function diffArraysLockstep(oldArr, newArr, prefix, visit) {
|
|
|
270
152
|
visit
|
|
271
153
|
);
|
|
272
154
|
}
|
|
155
|
+
for (let i = min; i < newArr.length; i++) {
|
|
156
|
+
diffSlot(readConsumerIndex(newArr, i), appendSegment(prefix, i), visit, true);
|
|
157
|
+
}
|
|
158
|
+
for (let i = min; i < oldArr.length; i++) {
|
|
159
|
+
diffSlot(readConsumerIndex(oldArr, i), appendSegment(prefix, i), visit, false);
|
|
160
|
+
}
|
|
273
161
|
}
|
|
274
162
|
function diffObjectsLockstep(oldRec, newRec, prefix, visit) {
|
|
275
163
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -383,4 +271,4 @@ function structuralSnapshot(value) {
|
|
|
383
271
|
return out;
|
|
384
272
|
}
|
|
385
273
|
|
|
386
|
-
export { ANONYMOUS_FORM_KEY_PREFIX as A, DEFAULT_HISTORY_MAX_SNAPSHOTS as D, RESERVED_KEY_PREFIX as R,
|
|
274
|
+
export { ANONYMOUS_FORM_KEY_PREFIX as A, DEFAULT_HISTORY_MAX_SNAPSHOTS as D, RESERVED_KEY_PREFIX as R, DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS as a, isDescendable as b, applyChangedKeys as c, diffAndApply as d, DEFAULT_MAX_RECURSION_DEPTH as e, ANONYMOUS_WIZARD_KEY_PREFIX as f, isBarePatch as i, normalizeNumericOption as n, pickDefined as p, structuralSnapshot as s };
|
|
@@ -114,7 +114,8 @@ const canonicalStringCache = /* @__PURE__ */ new Map();
|
|
|
114
114
|
const PATHKEY_TO_SEGMENTS_MAX = 4096;
|
|
115
115
|
const pathKeyToSegments = /* @__PURE__ */ new Map();
|
|
116
116
|
function rememberSegmentsForPathKey(key, segments) {
|
|
117
|
-
if (
|
|
117
|
+
if (pathKeyToSegments.has(key)) return;
|
|
118
|
+
if (pathKeyToSegments.size >= PATHKEY_TO_SEGMENTS_MAX) {
|
|
118
119
|
const oldest = pathKeyToSegments.keys().next().value;
|
|
119
120
|
if (oldest !== void 0) pathKeyToSegments.delete(oldest);
|
|
120
121
|
}
|
|
@@ -156,7 +157,7 @@ function canonicalizePath(input) {
|
|
|
156
157
|
return keyForSegments(input);
|
|
157
158
|
}
|
|
158
159
|
function keyForSegments(input) {
|
|
159
|
-
const segments =
|
|
160
|
+
const segments = input.map(normalizeSegment);
|
|
160
161
|
const key = JSON.stringify(segments);
|
|
161
162
|
rememberSegmentsForPathKey(key, segments);
|
|
162
163
|
return { segments, key };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GenericForm, F as FormKey, a as UseFormReturnType, _ as RegisterValue, v as Path, w as PathKey,
|
|
1
|
+
import { G as GenericForm, F as FormKey, a as UseFormReturnType, _ as RegisterValue, v as Path, w as PathKey, aq as DisplayCtx, ar as GetDisplayState, as as DisplayMachine, at as FieldRecord, au as ErrorCell, ac as ValidationError, av as OriginalsRecord, A as AbstractSchema, ag as WriteMeta, d as DeepPartial, ah as WriteShape, aw as StructureSnapshot, ax as AttaformDomBinding, ay as TransformAbortHolder } from './attaform.i13OEHJF.mjs';
|
|
2
2
|
import { Ref, ComputedRef, ShallowRef, App, InjectionKey, Plugin } from 'vue';
|
|
3
3
|
|
|
4
4
|
/** Options accepted by `injectForm` in place of a bare key string. */
|
|
@@ -48,6 +48,10 @@ type InjectFormInput = {
|
|
|
48
48
|
* Pass the `Form` generic explicitly, since Vue's provide/inject erases
|
|
49
49
|
* generics. The form stays alive for this component's lifetime and is
|
|
50
50
|
* cleaned up once every consumer has unmounted.
|
|
51
|
+
*
|
|
52
|
+
* Components whose nearest `useForm`-calling ancestor is the same one get
|
|
53
|
+
* the same form object for the same form: `injectForm('cart')` in two of
|
|
54
|
+
* its descendants returns one form, with one set of field caches.
|
|
51
55
|
*/
|
|
52
56
|
declare function injectForm<Form extends GenericForm, GetValueFormType extends GenericForm = Form>(input?: FormKey | InjectFormInput): UseFormReturnType<Form, GetValueFormType> | null;
|
|
53
57
|
|
|
@@ -135,6 +139,10 @@ type UseRegisterOptions = {
|
|
|
135
139
|
* `.value` unwrap. Reads inside a `computed` or `watchEffect` re-run
|
|
136
140
|
* when the parent rebinds to a different path.
|
|
137
141
|
*
|
|
142
|
+
* Modifiers on the parent's binding apply at the inner control, so
|
|
143
|
+
* `<MyInput v-register.trim="form.register('email')" />` trims there,
|
|
144
|
+
* together with any the wrapper writes on its own `v-register`.
|
|
145
|
+
*
|
|
138
146
|
* When no parent bound, every field reads `undefined`, so reach for
|
|
139
147
|
* `rv?.path`. `v-register="rv"` is still safe. A wrapper that is meant
|
|
140
148
|
* to render both with and without a form declares it with
|
|
@@ -159,9 +167,10 @@ type DynamicPathSweep = {
|
|
|
159
167
|
* `PathKey` of a path the form no longer has, and deletes whatever it
|
|
160
168
|
* files under that path. A cache keying by more than the path (a
|
|
161
169
|
* shape sigil, say) deletes every variant; a key it never held is a
|
|
162
|
-
* no-op.
|
|
170
|
+
* no-op. Returns the release, which a registrant that does not live
|
|
171
|
+
* as long as the form must call.
|
|
163
172
|
*/
|
|
164
|
-
readonly onEvict: (evict: (key: PathKey) => void) => void;
|
|
173
|
+
readonly onEvict: (evict: (key: PathKey) => void) => () => void;
|
|
165
174
|
};
|
|
166
175
|
|
|
167
176
|
/**
|
|
@@ -277,6 +286,13 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
277
286
|
readonly pathSweep: DynamicPathSweep;
|
|
278
287
|
readonly formKey: FormKey;
|
|
279
288
|
readonly form: Ref<F>;
|
|
289
|
+
/**
|
|
290
|
+
* Per-path field records: one per leaf from construction, and one per
|
|
291
|
+
* container, the root (`[]`) included, once a directive binds to it or a
|
|
292
|
+
* write takes leaves away beneath it. A container's own record holds the
|
|
293
|
+
* stamp of that write and the interaction history of the descendants it
|
|
294
|
+
* took; see `stampContainers` and `foldInteractionHistory`.
|
|
295
|
+
*/
|
|
280
296
|
readonly fields: Map<PathKey, FieldRecord>;
|
|
281
297
|
/**
|
|
282
298
|
* The tagged error store: one cell per error-bearing path, each segregating
|
|
@@ -290,8 +306,14 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
290
306
|
* mutated so Vue's per-key Map tracking fires for either side. Derived blank
|
|
291
307
|
* entries are not stored here; they synthesize at read
|
|
292
308
|
* (`derivedBlankErrors`).
|
|
309
|
+
*
|
|
310
|
+
* A method, not a property, because it is also the gate on the
|
|
311
|
+
* construction seed: the first call runs it (see `createErrorCells`). A
|
|
312
|
+
* getter on the store object would gate a property read the same way,
|
|
313
|
+
* but V8 builds an object literal holding an accessor in dictionary mode,
|
|
314
|
+
* and every kernel read of the store would then pay a hash lookup.
|
|
293
315
|
*/
|
|
294
|
-
readonly errorCells: Map<PathKey, ErrorCell>;
|
|
316
|
+
readonly errorCells: () => Map<PathKey, ErrorCell>;
|
|
295
317
|
/**
|
|
296
318
|
* Reactively-derived "No value supplied" errors: a pure function of
|
|
297
319
|
* `(blankPaths, schema.isRequiredAtPath)` with no writers and no clears.
|
|
@@ -492,10 +514,15 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
492
514
|
* side, because no errors at frame 1 means "not checked yet", not "checked
|
|
493
515
|
* and clean".
|
|
494
516
|
*
|
|
495
|
-
* The window it closes:
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
* so
|
|
517
|
+
* The window it closes: a schema with async work gets no verdict from the
|
|
518
|
+
* construction parse (v4 skips it for an async refine or transform; v3 skips
|
|
519
|
+
* it for an async transform and mounts clean when it throws over an async
|
|
520
|
+
* refine), so no construction errors land, and until the queued async pass
|
|
521
|
+
* runs, frame 1 would paint the form valid a tick before the real verdict.
|
|
522
|
+
* A sync-only schema's construction parse seeds its verdict synchronously,
|
|
523
|
+
* before the first read of its errors returns, so its gate starts open. v3
|
|
524
|
+
* reports every `.refine` as async, so a v3 schema with a sync refine
|
|
525
|
+
* starts gated and seeded.
|
|
499
526
|
*
|
|
500
527
|
* `reset()` restores it to the same construction-time seed, so the post-reset
|
|
501
528
|
* window gates exactly like the post-mount one.
|
|
@@ -621,6 +648,19 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
621
648
|
* empty is skipped.
|
|
622
649
|
*/
|
|
623
650
|
restoreErrorCells(entries: ReadonlyArray<readonly [PathKey, ErrorCell]>): void;
|
|
651
|
+
/**
|
|
652
|
+
* The per-element bookkeeping as it stands, for a history position to put
|
|
653
|
+
* back with its value (see `StructureSnapshot`). The entries are copied,
|
|
654
|
+
* and the records they hold are never mutated in place, so the snapshot
|
|
655
|
+
* stays detached from the live store.
|
|
656
|
+
*/
|
|
657
|
+
captureStructure(): StructureSnapshot;
|
|
658
|
+
/**
|
|
659
|
+
* Put a `captureStructure()` back, before the value it was taken with is
|
|
660
|
+
* restored, so the write that restores it compares each row against its
|
|
661
|
+
* own baseline. Every reading it can change is woken.
|
|
662
|
+
*/
|
|
663
|
+
restoreStructure(snapshot: StructureSnapshot): void;
|
|
624
664
|
/**
|
|
625
665
|
* Merged read of the cell at `path`, in schema -> blank -> user order:
|
|
626
666
|
* structural validation first, the synthesized blank entry between, user
|
|
@@ -709,18 +749,19 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
709
749
|
* insert or removal) against its construction / reset baseline. The
|
|
710
750
|
* structural half of `dirty`: per-element baselines travel with their
|
|
711
751
|
* element across a mutation, so a positional value comparison alone cannot
|
|
712
|
-
* see the shape change.
|
|
752
|
+
* see the shape change. `key` is the canonical key of `path`.
|
|
713
753
|
*/
|
|
714
|
-
hasStructuralChangeUnder(path: Path): boolean;
|
|
754
|
+
hasStructuralChangeUnder(path: Path, key: PathKey): boolean;
|
|
715
755
|
/**
|
|
716
|
-
* Whether a
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
756
|
+
* Whether a path under `path` that held a real baseline value was removed
|
|
757
|
+
* and is still absent: a dropped key, an emptied container, a row a
|
|
758
|
+
* wholesale write took away. The other half of removal-driven `dirty`: the
|
|
759
|
+
* present-leaf walk never visits an absent leaf, and the array tracker
|
|
760
|
+
* follows only array lengths and orders. A path a later write brought back
|
|
761
|
+
* stops counting, and the present-leaf walk judges it instead. `key` is the
|
|
762
|
+
* canonical key of `path`.
|
|
722
763
|
*/
|
|
723
|
-
hasRemovedSubtreeUnder(path: Path): boolean;
|
|
764
|
+
hasRemovedSubtreeUnder(path: Path, key: PathKey): boolean;
|
|
724
765
|
getFieldRecord(path: Path): FieldRecord | undefined;
|
|
725
766
|
/**
|
|
726
767
|
* Cancel every in-flight field-level validation run: clear the timers of
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as RegistryNotInstalledError, O as OutsideSetupError, g as pathKeyToDotted } from './attaform.
|
|
1
|
+
import { c as RegistryNotInstalledError, O as OutsideSetupError, g as pathKeyToDotted } from './attaform.BhtAZysa.mjs';
|
|
2
2
|
import { shallowReactive, getCurrentInstance, inject } from 'vue';
|
|
3
3
|
|
|
4
4
|
function detectSSR(options = {}) {
|
|
@@ -168,8 +168,8 @@ function renderAttaformState(app) {
|
|
|
168
168
|
// The wire shape stays two per-source arrays; the tagged store
|
|
169
169
|
// splits at the boundary and the client replays each side into
|
|
170
170
|
// its cell half.
|
|
171
|
-
schemaErrors: [...state.errorCells.entries()].filter(([, cell]) => cell.schema.length > 0).map(([key2, cell]) => [key2, cell.schema]),
|
|
172
|
-
userErrors: [...state.errorCells.entries()].filter(([, cell]) => cell.user.length > 0).map(([key2, cell]) => [key2, cell.user]),
|
|
171
|
+
schemaErrors: [...state.errorCells().entries()].filter(([, cell]) => cell.schema.length > 0).map(([key2, cell]) => [key2, cell.schema]),
|
|
172
|
+
userErrors: [...state.errorCells().entries()].filter(([, cell]) => cell.user.length > 0).map(([key2, cell]) => [key2, cell.user]),
|
|
173
173
|
fields: Array.from(state.fields.entries()),
|
|
174
174
|
...transientList.length > 0 ? { blankPaths: transientList } : {}
|
|
175
175
|
}
|