attaform 0.28.0 → 0.30.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/abstract.d.mts +5 -5
- package/dist/abstract.mjs +4 -4
- package/dist/dev/abstract.mjs +4 -4
- package/dist/dev/chunks/dev-key-collision-warnings.mjs +47 -8
- package/dist/dev/chunks/devtools.mjs +1 -1
- package/dist/dev/directive.mjs +1 -1
- package/dist/dev/history.mjs +1 -2
- package/dist/dev/index.mjs +5 -5
- package/dist/dev/runtime/plugins/attaform.mjs +3 -3
- package/dist/dev/shared/{attaform-dev.oYrkP9dj.mjs → attaform-dev.BK6Ge2qR.mjs} +80 -341
- package/dist/dev/shared/{attaform-dev.Dr2YzS5B.mjs → attaform-dev.BQc5QV3Y.mjs} +11 -19
- package/dist/dev/shared/{attaform-dev.BR8u0YOZ.mjs → attaform-dev.BcNtyOmf.mjs} +4 -4
- package/dist/{shared/attaform.h0i6LijT.mjs → dev/shared/attaform-dev.BcYT6tFh.mjs} +152 -20
- package/dist/dev/shared/{attaform-dev.6qxD-Yqo.mjs → attaform-dev.BisFstxh.mjs} +227 -88
- package/dist/dev/shared/{attaform-dev.WmuhD_CZ.mjs → attaform-dev.CQ2rJiAX.mjs} +833 -656
- package/dist/dev/shared/{attaform-dev.P7cseiEG.mjs → attaform-dev.D6CLvaQT.mjs} +20 -11
- package/dist/dev/shared/{attaform-dev.D2I8e_Mm.mjs → attaform-dev.DTrHonpc.mjs} +225 -238
- package/dist/dev/shared/{attaform-dev.BXE2cr0L.mjs → attaform-dev.DUZckyV8.mjs} +1 -3
- 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 +1 -2
- package/dist/index.d.mts +9 -7
- package/dist/index.mjs +5 -5
- package/dist/nuxt.d.mts +11 -20
- package/dist/nuxt.mjs +0 -1
- package/dist/runtime/plugins/attaform.mjs +3 -3
- package/dist/shared/{attaform.uLbun31C.mjs → attaform.B3resMQ1.mjs} +19 -11
- package/dist/shared/{attaform.Cs2Rbdlo.mjs → attaform.BK0cgu2K.mjs} +123 -139
- package/dist/{dev/shared/attaform-dev.By4PRjt0.mjs → shared/attaform.BRDDQeHV.mjs} +136 -26
- package/dist/shared/{attaform.NLmerepI.mjs → attaform.BXneBxEj.mjs} +71 -334
- package/dist/shared/{attaform.D6DCnnQu.mjs → attaform.ByWP6kSx.mjs} +4 -4
- package/dist/shared/{attaform.CJP3RkGa.mjs → attaform.CJ8DpRGj.mjs} +223 -238
- package/dist/shared/{attaform.C09fpdLS.mjs → attaform.CUfrMK7t.mjs} +227 -88
- package/dist/shared/{attaform.wfY8XFvm.mjs → attaform.CdZIEf7_.mjs} +11 -19
- package/dist/shared/{attaform.JfSWdEcb.d.mts → attaform.Clz0ArIi.d.mts} +1 -1
- package/dist/shared/{attaform.B8k8JrmK.mjs → attaform.DNJOWjQw.mjs} +826 -612
- package/dist/shared/{attaform.B4VkS43-.d.mts → attaform.Rc9u4Vfw.d.mts} +1 -1
- package/dist/shared/{attaform.D5V4tZWq.d.mts → attaform.UGyOK83T.d.mts} +200 -218
- package/dist/shared/{attaform.Dq4vWxuG.mjs → attaform.WiGdIqgx.mjs} +1 -3
- package/dist/shared/{attaform.Cgu-hdSb.d.mts → attaform.bKLzMU0o.d.mts} +321 -523
- package/dist/transforms.d.mts +0 -22
- package/dist/transforms.mjs +1 -1
- package/dist/vite.d.mts +13 -4
- package/dist/vite.mjs +8 -2
- package/dist/zod-v3.d.mts +6 -4
- package/dist/zod-v3.mjs +6 -6
- package/dist/zod-v4.d.mts +18 -31
- package/dist/zod-v4.mjs +6 -6
- package/dist/zod.d.mts +4 -4
- package/dist/zod.mjs +5 -5
- package/package.json +19 -15
- package/skills/attaform/SKILL.md +6 -3
- package/skills/attaform/references/custom-components.md +8 -3
- package/skills/attaform/references/errors.md +8 -3
- package/skills/attaform/references/saving.md +77 -0
- package/skills/attaform/references/wizards.md +10 -8
- package/dist/chunks/fingerprint.mjs +0 -183
- package/dist/chunks/fingerprint2.mjs +0 -159
- package/dist/dev/chunks/fingerprint.mjs +0 -183
- package/dist/dev/chunks/fingerprint2.mjs +0 -159
- package/dist/dev/shared/attaform-dev.BJGA_UOS.mjs +0 -36
- package/dist/shared/attaform.BJGA_UOS.mjs +0 -36
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, nextTick, warn, reactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope } from 'vue';
|
|
2
|
-
import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey,
|
|
3
|
-
import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform-dev.
|
|
4
|
-
import { R as REGISTER_OWNER_MARKER, d as armDomBinding, V as V_REGISTER_MARKER } from './attaform-dev.
|
|
5
|
-
import { i as isPathPrefix, e as canonicalizePath,
|
|
1
|
+
import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, nextTick, warn, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope } from 'vue';
|
|
2
|
+
import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey, d as safeOwnHas, a as safeOwnRead, e as consumerHas, f as spreadConsumerRecord, g as copyConsumerArray, r as readConsumerIndex, b as safeAssign, h as consumerKeys, j as readConsumerProp, k as diffAndApply, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, l as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, m as consumerSymbolKeys, o as applyChangedKeys, R as RESERVED_KEY_PREFIX, q as DEFAULT_MAX_RECURSION_DEPTH, t as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform-dev.BcYT6tFh.mjs';
|
|
3
|
+
import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform-dev.DUZckyV8.mjs';
|
|
4
|
+
import { R as REGISTER_OWNER_MARKER, d as armDomBinding, V as V_REGISTER_MARKER } from './attaform-dev.D6CLvaQT.mjs';
|
|
5
|
+
import { i as isPathPrefix, e as canonicalizePath, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, s as segmentsForPathKey, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, l as normalizeErrorInputs, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform-dev.BQc5QV3Y.mjs';
|
|
6
6
|
|
|
7
7
|
const AttaformErrorCode = {
|
|
8
8
|
/** A required field is in the blank set — user hasn't supplied a value. */
|
|
@@ -98,42 +98,32 @@ function earliestNonNull(a, b) {
|
|
|
98
98
|
return a < b ? a : b;
|
|
99
99
|
}
|
|
100
100
|
const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
|
|
101
|
+
const { showDelay, minVisible } = DEFAULT_TIMINGS;
|
|
101
102
|
const FOCUS_OUT_GRACE = 16;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (prev.display === "pending") {
|
|
116
|
-
const shownAt = prev.pendingShownAt ?? now;
|
|
117
|
-
if (now < shownAt + minVisible)
|
|
118
|
-
return { display: "pending", pendingShownAt: shownAt, reviewAt: shownAt + minVisible };
|
|
119
|
-
}
|
|
120
|
-
return { display: verdict };
|
|
121
|
-
}
|
|
122
|
-
if (prev.display === "pending")
|
|
123
|
-
return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
|
|
124
|
-
const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
|
|
125
|
-
if (now - inFlightSince < window) {
|
|
126
|
-
return { display: prev.display, reviewAt: inFlightSince + window };
|
|
103
|
+
const defaultDisplayState = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
|
|
104
|
+
const verdict = computeVerdict(field, formMeta);
|
|
105
|
+
if (!isGateOpen(field, formMeta)) return { display: verdict };
|
|
106
|
+
const inFlightSince = earliestNonNull(validatingSince, transformingSince);
|
|
107
|
+
if (inFlightSince === null) {
|
|
108
|
+
if (prev.display === "pending") {
|
|
109
|
+
const shownAt = prev.pendingShownAt ?? now;
|
|
110
|
+
if (now < shownAt + minVisible)
|
|
111
|
+
return {
|
|
112
|
+
display: "pending",
|
|
113
|
+
pendingShownAt: shownAt,
|
|
114
|
+
reviewAt: shownAt + minVisible
|
|
115
|
+
};
|
|
127
116
|
}
|
|
128
|
-
return { display:
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
117
|
+
return { display: verdict };
|
|
118
|
+
}
|
|
119
|
+
if (prev.display === "pending")
|
|
120
|
+
return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
|
|
121
|
+
const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
|
|
122
|
+
if (now - inFlightSince < window) {
|
|
123
|
+
return { display: prev.display, reviewAt: inFlightSince + window };
|
|
124
|
+
}
|
|
125
|
+
return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
|
|
126
|
+
};
|
|
137
127
|
|
|
138
128
|
function hashStableString(input, seed = 0) {
|
|
139
129
|
let h1 = 3735928559 ^ seed;
|
|
@@ -186,6 +176,17 @@ function humanize(segment) {
|
|
|
186
176
|
}
|
|
187
177
|
|
|
188
178
|
const NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
|
|
179
|
+
function mapKeyForSegment(map, segment, declared) {
|
|
180
|
+
if (map.has(segment)) return segment;
|
|
181
|
+
if (typeof segment !== "number") return segment;
|
|
182
|
+
const asString = String(segment);
|
|
183
|
+
if (map.has(asString)) return asString;
|
|
184
|
+
return declared === "string" ? asString : segment;
|
|
185
|
+
}
|
|
186
|
+
function isRebuildableContainer(root, segment) {
|
|
187
|
+
if (root === null || root === void 0 || typeof root !== "object") return true;
|
|
188
|
+
return typeof segment === "number" ? Array.isArray(root) : isPlainRecord(root);
|
|
189
|
+
}
|
|
189
190
|
function descendStep(value, segment) {
|
|
190
191
|
if (value === null || value === void 0) return NOT_FOUND;
|
|
191
192
|
if (typeof value !== "object") return NOT_FOUND;
|
|
@@ -194,6 +195,11 @@ function descendStep(value, segment) {
|
|
|
194
195
|
if (!(segment in value)) return NOT_FOUND;
|
|
195
196
|
return value[segment];
|
|
196
197
|
}
|
|
198
|
+
if (value instanceof Map) {
|
|
199
|
+
const key2 = mapKeyForSegment(value, segment);
|
|
200
|
+
if (!value.has(key2)) return NOT_FOUND;
|
|
201
|
+
return value.get(key2);
|
|
202
|
+
}
|
|
197
203
|
const record = value;
|
|
198
204
|
const key = typeof segment === "number" ? String(segment) : segment;
|
|
199
205
|
if (isShadowedKey(key)) {
|
|
@@ -205,16 +211,27 @@ function descendStep(value, segment) {
|
|
|
205
211
|
}
|
|
206
212
|
function getAtPath(root, path) {
|
|
207
213
|
if (path.length === 0) return root;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
try {
|
|
215
|
+
let current = root;
|
|
216
|
+
for (const segment of path) {
|
|
217
|
+
const next = descendStep(current, segment);
|
|
218
|
+
if (next === NOT_FOUND) return void 0;
|
|
219
|
+
current = next;
|
|
220
|
+
}
|
|
221
|
+
return current;
|
|
222
|
+
} catch {
|
|
223
|
+
return void 0;
|
|
213
224
|
}
|
|
214
|
-
return current;
|
|
215
225
|
}
|
|
216
226
|
function hasAtPath(root, path) {
|
|
217
227
|
if (path.length === 0) return true;
|
|
228
|
+
try {
|
|
229
|
+
return hasAtPathUnguarded(root, path);
|
|
230
|
+
} catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function hasAtPathUnguarded(root, path) {
|
|
218
235
|
let current = root;
|
|
219
236
|
for (let i = 0; i < path.length - 1; i++) {
|
|
220
237
|
const segment = path[i];
|
|
@@ -226,11 +243,14 @@ function hasAtPath(root, path) {
|
|
|
226
243
|
if (current === null || current === void 0) return false;
|
|
227
244
|
if (typeof current !== "object") return false;
|
|
228
245
|
if (Array.isArray(current)) {
|
|
229
|
-
return typeof last === "number" && last
|
|
246
|
+
return typeof last === "number" && consumerHas(current, last);
|
|
247
|
+
}
|
|
248
|
+
if (current instanceof Map) {
|
|
249
|
+
return current.has(mapKeyForSegment(current, last));
|
|
230
250
|
}
|
|
231
251
|
const key = typeof last === "number" ? String(last) : last;
|
|
232
252
|
if (isShadowedKey(key)) return safeOwnHas(current, key);
|
|
233
|
-
return key
|
|
253
|
+
return consumerHas(current, key);
|
|
234
254
|
}
|
|
235
255
|
function isPlainRecord(value) {
|
|
236
256
|
if (value === null || typeof value !== "object") return false;
|
|
@@ -238,29 +258,30 @@ function isPlainRecord(value) {
|
|
|
238
258
|
const proto = Object.getPrototypeOf(value);
|
|
239
259
|
return proto === null || proto === Object.prototype;
|
|
240
260
|
}
|
|
261
|
+
const NO_SCHEMA_DEFAULTS = /* @__PURE__ */ new Set();
|
|
262
|
+
const NO_SCHEMA_FILL = {
|
|
263
|
+
getDefaultAtPath: () => void 0,
|
|
264
|
+
arrayShapeAtPath: () => null,
|
|
265
|
+
getSlimPrimitiveTypesAtPath: () => NO_SCHEMA_DEFAULTS,
|
|
266
|
+
entryKeyKindAtPath: () => void 0
|
|
267
|
+
};
|
|
241
268
|
function setAtPath(root, path, value) {
|
|
242
|
-
return
|
|
243
|
-
}
|
|
244
|
-
function setAtPathOffset(root, path, value, offset) {
|
|
245
|
-
if (offset >= path.length) return value;
|
|
246
|
-
const head = path[offset];
|
|
247
|
-
const nextOffset = offset + 1;
|
|
248
|
-
if (typeof head === "number") {
|
|
249
|
-
const arr = Array.isArray(root) ? [...root] : [];
|
|
250
|
-
while (arr.length <= head) arr.push(void 0);
|
|
251
|
-
arr[head] = setAtPathOffset(arr[head], path, value, nextOffset);
|
|
252
|
-
return arr;
|
|
253
|
-
}
|
|
254
|
-
const rec = isPlainRecord(root) ? { ...root } : {};
|
|
255
|
-
safeAssign(rec, head, setAtPathOffset(safeOwnRead(rec, head), path, value, nextOffset));
|
|
256
|
-
return rec;
|
|
269
|
+
return setAtPathWithSchemaFill(root, NO_SCHEMA_FILL, path, value);
|
|
257
270
|
}
|
|
258
271
|
const NO_IN_PLACE = { applied: false };
|
|
259
272
|
function tryInPlaceLeafWrite(root, path, value) {
|
|
260
273
|
if (path.length === 0) return NO_IN_PLACE;
|
|
274
|
+
try {
|
|
275
|
+
return descendAndWrite(root, path, value);
|
|
276
|
+
} catch {
|
|
277
|
+
return NO_IN_PLACE;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function descendAndWrite(root, path, value) {
|
|
261
281
|
let node = root;
|
|
262
282
|
for (let i = 0; i < path.length; i++) {
|
|
263
283
|
const seg = path[i];
|
|
284
|
+
if (node instanceof Map) return NO_IN_PLACE;
|
|
264
285
|
if (Array.isArray(node)) {
|
|
265
286
|
if (typeof seg !== "number" || seg < 0 || seg >= node.length) return NO_IN_PLACE;
|
|
266
287
|
} else if (isPlainRecord(node)) {
|
|
@@ -295,17 +316,40 @@ function mergeStructuralImpl(schema, scratch, consumer, defaultValue) {
|
|
|
295
316
|
if (Array.isArray(consumer)) {
|
|
296
317
|
return mergeStructuralArray(schema, scratch, consumer);
|
|
297
318
|
}
|
|
319
|
+
if (consumer instanceof Map) {
|
|
320
|
+
return mergeStructuralMap(schema, scratch, consumer);
|
|
321
|
+
}
|
|
298
322
|
if (isPlainRecord(consumer)) {
|
|
299
323
|
if (!isPlainRecord(defaultValue)) {
|
|
300
324
|
return consumer;
|
|
301
325
|
}
|
|
302
|
-
const out =
|
|
326
|
+
const out = spreadConsumerRecord(consumer);
|
|
303
327
|
const filledAny = fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out);
|
|
304
328
|
const recursedAny = recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out);
|
|
305
329
|
return filledAny || recursedAny ? out : consumer;
|
|
306
330
|
}
|
|
307
331
|
return consumer;
|
|
308
332
|
}
|
|
333
|
+
function mergeStructuralMap(schema, scratch, consumer) {
|
|
334
|
+
if (consumer.size === 0) return consumer;
|
|
335
|
+
let entryDefault;
|
|
336
|
+
let entryDefaultRead = false;
|
|
337
|
+
let out = null;
|
|
338
|
+
for (const [key, entry] of consumer) {
|
|
339
|
+
if (typeof key !== "string" && typeof key !== "number") continue;
|
|
340
|
+
scratch.push(key);
|
|
341
|
+
if (!entryDefaultRead) {
|
|
342
|
+
entryDefault = schema.getDefaultAtPath(scratch);
|
|
343
|
+
entryDefaultRead = true;
|
|
344
|
+
}
|
|
345
|
+
const merged = mergeStructuralImpl(schema, scratch, entry, entryDefault);
|
|
346
|
+
scratch.pop();
|
|
347
|
+
if (merged === entry) continue;
|
|
348
|
+
out ?? (out = new Map(consumer));
|
|
349
|
+
out.set(key, merged);
|
|
350
|
+
}
|
|
351
|
+
return out ?? consumer;
|
|
352
|
+
}
|
|
309
353
|
function mergeStructuralArray(schema, scratch, consumer) {
|
|
310
354
|
const shape = schema.arrayShapeAtPath(scratch);
|
|
311
355
|
const isTuple = typeof shape === "number";
|
|
@@ -313,7 +357,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
|
|
|
313
357
|
let cachedElementDefault;
|
|
314
358
|
let cachedElementDefaultRead = false;
|
|
315
359
|
let mutated = targetLen > consumer.length;
|
|
316
|
-
const out = consumer
|
|
360
|
+
const out = copyConsumerArray(consumer);
|
|
317
361
|
while (out.length < targetLen) out.push(void 0);
|
|
318
362
|
for (let i = 0; i < targetLen; i++) {
|
|
319
363
|
scratch.push(i);
|
|
@@ -327,7 +371,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
|
|
|
327
371
|
}
|
|
328
372
|
elemDefault = cachedElementDefault;
|
|
329
373
|
}
|
|
330
|
-
const consumerElem = i < consumer.length ? consumer
|
|
374
|
+
const consumerElem = i < consumer.length ? readConsumerIndex(consumer, i) : void 0;
|
|
331
375
|
const merged = mergeStructuralImpl(schema, scratch, consumerElem, elemDefault);
|
|
332
376
|
scratch.pop();
|
|
333
377
|
if (merged !== consumerElem) {
|
|
@@ -355,7 +399,7 @@ function fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out
|
|
|
355
399
|
}
|
|
356
400
|
function recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out) {
|
|
357
401
|
let mutated = false;
|
|
358
|
-
for (const key of
|
|
402
|
+
for (const key of consumerKeys(consumer)) {
|
|
359
403
|
const cVal = safeOwnRead(consumer, key);
|
|
360
404
|
if (cVal === void 0) continue;
|
|
361
405
|
scratch.push(key);
|
|
@@ -376,6 +420,21 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
376
420
|
if (startIdx >= fullPath.length) return value;
|
|
377
421
|
const head = fullPath[startIdx];
|
|
378
422
|
const isLeafStep = startIdx === fullPath.length - 1;
|
|
423
|
+
if (root instanceof Map) {
|
|
424
|
+
const next = new Map(root);
|
|
425
|
+
const key = mapKeyForSegment(root, head, schema.entryKeyKindAtPath(fullPath.slice(0, startIdx)));
|
|
426
|
+
if (isLeafStep) {
|
|
427
|
+
next.set(key, value);
|
|
428
|
+
return next;
|
|
429
|
+
}
|
|
430
|
+
let childRoot2 = next.get(key);
|
|
431
|
+
if (childRoot2 === void 0 || childRoot2 !== null && typeof childRoot2 !== "object") {
|
|
432
|
+
childRoot2 = schema.getDefaultAtPath(fullPath.slice(0, startIdx + 1));
|
|
433
|
+
}
|
|
434
|
+
next.set(key, setAtPathWithSchemaFillImpl(childRoot2, schema, fullPath, value, startIdx + 1));
|
|
435
|
+
return next;
|
|
436
|
+
}
|
|
437
|
+
if (!isRebuildableContainer(root, head)) return root;
|
|
379
438
|
if (typeof head === "number") {
|
|
380
439
|
const arr = Array.isArray(root) ? [...root] : [];
|
|
381
440
|
const prefix = fullPath.slice(0, startIdx);
|
|
@@ -413,10 +472,10 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
413
472
|
}
|
|
414
473
|
const rec = isPlainRecord(root) ? { ...root } : {};
|
|
415
474
|
if (isLeafStep) {
|
|
416
|
-
rec
|
|
475
|
+
safeAssign(rec, head, value);
|
|
417
476
|
return rec;
|
|
418
477
|
}
|
|
419
|
-
const existing = rec
|
|
478
|
+
const existing = safeOwnRead(rec, head);
|
|
420
479
|
let childRoot;
|
|
421
480
|
if (existing === void 0 || existing !== null && typeof existing !== "object") {
|
|
422
481
|
const intermPath = [...fullPath.slice(0, startIdx + 1)];
|
|
@@ -425,11 +484,14 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
425
484
|
} else {
|
|
426
485
|
childRoot = existing;
|
|
427
486
|
}
|
|
428
|
-
|
|
487
|
+
safeAssign(
|
|
488
|
+
rec,
|
|
489
|
+
head,
|
|
490
|
+
setAtPathWithSchemaFillImpl(childRoot, schema, fullPath, value, startIdx + 1)
|
|
491
|
+
);
|
|
429
492
|
return rec;
|
|
430
493
|
}
|
|
431
494
|
|
|
432
|
-
const warnedDisplayStatePredicates = /* @__PURE__ */ new WeakSet();
|
|
433
495
|
function isUnderStubAncestor(state, segments) {
|
|
434
496
|
for (let i = 0; i < segments.length; i++) {
|
|
435
497
|
const ancestorPath = segments.slice(0, i);
|
|
@@ -443,17 +505,18 @@ function isUnderStubAncestor(state, segments) {
|
|
|
443
505
|
}
|
|
444
506
|
return false;
|
|
445
507
|
}
|
|
446
|
-
function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase,
|
|
508
|
+
function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, sweep) {
|
|
447
509
|
const cache = /* @__PURE__ */ new Map();
|
|
448
|
-
|
|
510
|
+
sweep.onEvict((key) => cache.delete(key));
|
|
449
511
|
return function getFieldState(pathInput) {
|
|
450
512
|
const { segments, key } = canonicalizePath(pathInput);
|
|
451
513
|
const cached = cache.get(key);
|
|
452
514
|
if (cached !== void 0) return cached;
|
|
453
515
|
const c = computed(
|
|
454
|
-
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase
|
|
516
|
+
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) : buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase)
|
|
455
517
|
);
|
|
456
518
|
cache.set(key, c);
|
|
519
|
+
sweep.track(segments, key);
|
|
457
520
|
return c;
|
|
458
521
|
};
|
|
459
522
|
}
|
|
@@ -467,7 +530,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
467
530
|
const record = state.fields.get(key);
|
|
468
531
|
const value = state.getValueAtPath(segments);
|
|
469
532
|
const original = state.originals.get(key)?.value;
|
|
470
|
-
const pristine = state.
|
|
533
|
+
const pristine = state.isPristineAtPathByKey(key, segments);
|
|
471
534
|
const cell = state.errorCells.get(key);
|
|
472
535
|
const schemaForKey = cell !== void 0 && cell.schema.length > 0 ? cell.schema : void 0;
|
|
473
536
|
const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
|
|
@@ -479,7 +542,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
479
542
|
const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
|
|
480
543
|
const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
|
|
481
544
|
const transformError = state.transformErrors.get(key) ?? null;
|
|
482
|
-
const gated = state.
|
|
545
|
+
const gated = state.pathHasAsyncValidationByKey(key, segments) && !state.firstValidationDone.value;
|
|
483
546
|
const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
|
|
484
547
|
const valid = !gated && errors.length === 0 && !validating && !isOrphan;
|
|
485
548
|
const elementRecord = state.domBinding.value?.elements.get(key);
|
|
@@ -522,7 +585,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
522
585
|
meta: resolved.meta
|
|
523
586
|
};
|
|
524
587
|
}
|
|
525
|
-
function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase
|
|
588
|
+
function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
|
|
526
589
|
const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
|
|
527
590
|
const validatingSince = state.fieldValidatingSince.get(key) ?? null;
|
|
528
591
|
const transformingSince = state.fieldTransformingSince.get(key) ?? null;
|
|
@@ -535,15 +598,14 @@ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBa
|
|
|
535
598
|
transformingSince,
|
|
536
599
|
false,
|
|
537
600
|
// revealedDescendantError: leaves have no descendants
|
|
538
|
-
false
|
|
601
|
+
false
|
|
539
602
|
// isRoot: a leaf is never the form root
|
|
540
|
-
getDisplayState
|
|
541
603
|
);
|
|
542
604
|
}
|
|
543
605
|
function visitActiveLeafPaths(value, base, visit) {
|
|
544
606
|
if (Array.isArray(value)) {
|
|
545
607
|
for (let i = 0; i < value.length; i++) {
|
|
546
|
-
const child = value
|
|
608
|
+
const child = readConsumerIndex(value, i);
|
|
547
609
|
if (Array.isArray(child) || isPlainRecord(child)) {
|
|
548
610
|
visitActiveLeafPaths(child, [...base, i], visit);
|
|
549
611
|
} else {
|
|
@@ -553,8 +615,8 @@ function visitActiveLeafPaths(value, base, visit) {
|
|
|
553
615
|
return;
|
|
554
616
|
}
|
|
555
617
|
if (isPlainRecord(value)) {
|
|
556
|
-
for (const k of
|
|
557
|
-
const child = value
|
|
618
|
+
for (const k of consumerKeys(value)) {
|
|
619
|
+
const child = readConsumerProp(value, k);
|
|
558
620
|
if (Array.isArray(child) || isPlainRecord(child)) {
|
|
559
621
|
visitActiveLeafPaths(child, [...base, k], visit);
|
|
560
622
|
} else {
|
|
@@ -635,7 +697,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
635
697
|
pristine = false;
|
|
636
698
|
dirty = true;
|
|
637
699
|
}
|
|
638
|
-
const errors = aggregateErrorsAt(state, segments);
|
|
700
|
+
const errors = aggregateErrorsAt(state, segments, key);
|
|
639
701
|
const revealedDescendantError = errors.length > 0 && errors.some((e) => {
|
|
640
702
|
const ePath = e.path;
|
|
641
703
|
if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
|
|
@@ -643,7 +705,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
643
705
|
if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
|
|
644
706
|
return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
|
|
645
707
|
});
|
|
646
|
-
if (!asyncPending && state.
|
|
708
|
+
if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
|
|
647
709
|
if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
|
|
648
710
|
validating = true;
|
|
649
711
|
const since = state.fieldValidatingSince.get(key);
|
|
@@ -714,7 +776,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
714
776
|
revealedDescendantError
|
|
715
777
|
};
|
|
716
778
|
}
|
|
717
|
-
function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase
|
|
779
|
+
function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
|
|
718
780
|
const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
|
|
719
781
|
return decorateWithDerivedProps(
|
|
720
782
|
base,
|
|
@@ -724,14 +786,12 @@ function buildContainerFieldState(state, segments, key, formInstanceId, getFormM
|
|
|
724
786
|
validatingSince,
|
|
725
787
|
transformingSince,
|
|
726
788
|
revealedDescendantError,
|
|
727
|
-
segments.length === 0
|
|
728
|
-
getDisplayState
|
|
789
|
+
segments.length === 0
|
|
729
790
|
);
|
|
730
791
|
}
|
|
731
|
-
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot
|
|
792
|
+
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot) {
|
|
732
793
|
const firstError = base.errors[0];
|
|
733
794
|
const firstOwnError = base.ownErrors[0];
|
|
734
|
-
const predicate = getDisplayState ?? state.getDisplayState;
|
|
735
795
|
const formMeta = getFormMetaBase();
|
|
736
796
|
const ctx = {
|
|
737
797
|
field: base,
|
|
@@ -742,23 +802,9 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
|
|
|
742
802
|
// flight) so the reducer returns the plain verdict and hydration matches.
|
|
743
803
|
now: state.ssr ? 0 : Date.now()
|
|
744
804
|
};
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
machine = state.displayEngine.resolve(key, ctx, predicate);
|
|
749
|
-
} catch (err) {
|
|
750
|
-
if (!warnedDisplayStatePredicates.has(predicate)) {
|
|
751
|
-
warnedDisplayStatePredicates.add(predicate);
|
|
752
|
-
console.warn(
|
|
753
|
-
"[attaform] custom getDisplayState threw \u2014 falling back to defaultDisplayState. Subsequent throws from the same predicate will not warn again.",
|
|
754
|
-
err
|
|
755
|
-
);
|
|
756
|
-
}
|
|
757
|
-
machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
|
|
758
|
-
rollupApplies = true;
|
|
759
|
-
}
|
|
760
|
-
const submitValidating = rollupApplies && isRoot && state.submitting.value && state.activeValidations.value > 0;
|
|
761
|
-
const resolvedDisplayState = machine.display === "pending" || submitValidating ? "pending" : rollupApplies && revealedDescendantError ? "error" : machine.display;
|
|
805
|
+
const machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
|
|
806
|
+
const submitValidating = isRoot && state.submitting.value && state.activeValidations.value > 0;
|
|
807
|
+
const resolvedDisplayState = machine.display === "pending" || submitValidating ? "pending" : revealedDescendantError ? "error" : machine.display;
|
|
762
808
|
const displayState = base.disabled === true ? "idle" : resolvedDisplayState;
|
|
763
809
|
return {
|
|
764
810
|
...base,
|
|
@@ -771,26 +817,33 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
|
|
|
771
817
|
firstOwnError
|
|
772
818
|
};
|
|
773
819
|
}
|
|
774
|
-
function aggregateErrorsAt(state, prefix) {
|
|
820
|
+
function aggregateErrorsAt(state, prefix, prefixKey) {
|
|
821
|
+
const candidates = state.errorWindowAt(prefix, prefixKey);
|
|
822
|
+
if (candidates.length === 0) return [];
|
|
775
823
|
const formValue = state.form.value;
|
|
824
|
+
const cells = state.errorCells;
|
|
776
825
|
const buckets = /* @__PURE__ */ new Map();
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
826
|
+
for (const { key, segments } of candidates) {
|
|
827
|
+
if (!isPathPrefix(prefix, segments)) continue;
|
|
828
|
+
if (segments.length > 0 && !hasAtPath(formValue, segments)) continue;
|
|
829
|
+
const cell = cells.get(key);
|
|
830
|
+
const blankList = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
|
|
831
|
+
const schemaList = cell?.schema;
|
|
832
|
+
const userList = cell?.user;
|
|
833
|
+
const total = (schemaList?.length ?? 0) + (blankList?.length ?? 0) + (userList?.length ?? 0);
|
|
834
|
+
if (total === 0) continue;
|
|
835
|
+
const ordinal = state.ensurePathOrdinal(key);
|
|
836
|
+
let bucket = buckets.get(ordinal);
|
|
837
|
+
if (bucket === void 0) {
|
|
838
|
+
bucket = [];
|
|
839
|
+
buckets.set(ordinal, bucket);
|
|
840
|
+
}
|
|
841
|
+
if (schemaList !== void 0) bucket.push(...schemaList);
|
|
842
|
+
if (blankList !== void 0) bucket.push(...blankList);
|
|
843
|
+
if (userList !== void 0) bucket.push(...userList);
|
|
844
|
+
}
|
|
793
845
|
if (buckets.size === 0) return [];
|
|
846
|
+
if (buckets.size === 1) return [...buckets.values()][0];
|
|
794
847
|
return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
|
|
795
848
|
}
|
|
796
849
|
const EMPTY_ELEMENTS = Object.freeze([]);
|
|
@@ -803,6 +856,10 @@ function liveKeysAtPath(state, segments) {
|
|
|
803
856
|
for (let i = 0; i < value.length; i += 1) keys[i] = String(i);
|
|
804
857
|
return keys;
|
|
805
858
|
}
|
|
859
|
+
if (value instanceof Map) {
|
|
860
|
+
return mapSegmentKeys(value)?.map(String) ?? [];
|
|
861
|
+
}
|
|
862
|
+
if (value instanceof Set) return [];
|
|
806
863
|
if (typeof value === "object") return Object.keys(value);
|
|
807
864
|
return [];
|
|
808
865
|
}
|
|
@@ -813,6 +870,12 @@ function liveContainerHasKey(state, segments, key) {
|
|
|
813
870
|
const index = Number(key);
|
|
814
871
|
return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
|
|
815
872
|
}
|
|
873
|
+
if (value instanceof Map) {
|
|
874
|
+
if (value.has(key)) return true;
|
|
875
|
+
const index = Number(key);
|
|
876
|
+
return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
|
|
877
|
+
}
|
|
878
|
+
if (value instanceof Set) return false;
|
|
816
879
|
return Object.hasOwn(value, key);
|
|
817
880
|
}
|
|
818
881
|
function isArrayPath(state, segments) {
|
|
@@ -839,6 +902,7 @@ function makeReadonlyCoercion(snapshot) {
|
|
|
839
902
|
}
|
|
840
903
|
|
|
841
904
|
const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
|
|
905
|
+
const RELEASED = /* @__PURE__ */ Symbol();
|
|
842
906
|
const EMPTY_DESCENT = Object.freeze({});
|
|
843
907
|
function keyToSegment(key) {
|
|
844
908
|
return INTEGER_SEGMENT.test(key) ? Number(key) : key;
|
|
@@ -868,12 +932,18 @@ function callableInvokeShim(method, surface, getDescent) {
|
|
|
868
932
|
function buildTree(spec) {
|
|
869
933
|
const containerCache = /* @__PURE__ */ new Map();
|
|
870
934
|
const existsCache = /* @__PURE__ */ new Map();
|
|
935
|
+
spec.sweep.onEvict((key) => {
|
|
936
|
+
containerCache.delete(`${key}+A`);
|
|
937
|
+
containerCache.delete(`${key}+O`);
|
|
938
|
+
existsCache.delete(key);
|
|
939
|
+
});
|
|
871
940
|
function schemaHasPath(segs) {
|
|
872
|
-
const cacheKey =
|
|
941
|
+
const cacheKey = keyForSegments(segs).key;
|
|
873
942
|
const cached = existsCache.get(cacheKey);
|
|
874
943
|
if (cached !== void 0) return cached;
|
|
875
944
|
const result = spec.schema.getSlimPrimitiveTypesAtPath(segs).size > 0;
|
|
876
945
|
existsCache.set(cacheKey, result);
|
|
946
|
+
spec.sweep.track(segs, cacheKey);
|
|
877
947
|
return result;
|
|
878
948
|
}
|
|
879
949
|
function descend(segs) {
|
|
@@ -883,7 +953,8 @@ function buildTree(spec) {
|
|
|
883
953
|
}
|
|
884
954
|
function containerAt(segments) {
|
|
885
955
|
const isArrayLike = spec.isArrayAt(segments);
|
|
886
|
-
const
|
|
956
|
+
const pathKey = keyForSegments(segments).key;
|
|
957
|
+
const cacheKey = `${pathKey}+${isArrayLike ? "A" : "O"}`;
|
|
887
958
|
const existing = containerCache.get(cacheKey);
|
|
888
959
|
if (existing !== void 0) return existing;
|
|
889
960
|
const isFixedObject = spec.schema.isFixedObjectAtPath(segments);
|
|
@@ -973,46 +1044,42 @@ function buildTree(spec) {
|
|
|
973
1044
|
}
|
|
974
1045
|
});
|
|
975
1046
|
containerCache.set(cacheKey, proxy);
|
|
1047
|
+
spec.sweep.track(segments, pathKey);
|
|
976
1048
|
return proxy;
|
|
977
1049
|
}
|
|
978
1050
|
return containerAt([]);
|
|
979
1051
|
}
|
|
980
|
-
function buildErrorsSurface(state) {
|
|
1052
|
+
function buildErrorsSurface(state, sweep) {
|
|
981
1053
|
const treeCache = /* @__PURE__ */ new Map();
|
|
1054
|
+
sweep.onEvict((key) => treeCache.delete(key));
|
|
982
1055
|
const materialize = (segments) => {
|
|
983
|
-
const cacheKey =
|
|
1056
|
+
const cacheKey = keyForSegments(segments).key;
|
|
984
1057
|
let tree = treeCache.get(cacheKey);
|
|
985
1058
|
if (tree === void 0) {
|
|
986
1059
|
const frozen = [...segments];
|
|
987
1060
|
tree = computed(() => materializeErrors(state, frozen));
|
|
988
1061
|
treeCache.set(cacheKey, tree);
|
|
1062
|
+
sweep.track(segments, cacheKey);
|
|
989
1063
|
}
|
|
990
1064
|
return tree.value;
|
|
991
1065
|
};
|
|
992
1066
|
const resolveLeaf = (path) => {
|
|
993
1067
|
const isContainerSelfAccess = path.length > 1 && path[path.length - 1] === "";
|
|
994
|
-
const collectAtKey = (key2, active2, into) => {
|
|
995
|
-
const cell = state.errorCells.get(key2);
|
|
996
|
-
if (active2) {
|
|
997
|
-
const b = state.derivedBlankErrors.value.get(key2);
|
|
998
|
-
if (cell !== void 0) into.push(...cell.schema);
|
|
999
|
-
if (b !== void 0) into.push(...b);
|
|
1000
|
-
}
|
|
1001
|
-
if (cell !== void 0) into.push(...cell.user);
|
|
1002
|
-
};
|
|
1003
1068
|
const merged = [];
|
|
1004
1069
|
if (isContainerSelfAccess) {
|
|
1005
1070
|
const containerPath = path.slice(0, -1);
|
|
1006
|
-
const
|
|
1007
|
-
const
|
|
1071
|
+
const container = canonicalizePath(containerPath);
|
|
1072
|
+
const literal = canonicalizePath(path);
|
|
1008
1073
|
const active2 = hasAtPath(state.form.value, containerPath);
|
|
1009
|
-
|
|
1010
|
-
if (
|
|
1074
|
+
collectErrorsAt(state, container.key, container.segments, active2, merged);
|
|
1075
|
+
if (literal.key !== container.key) {
|
|
1076
|
+
collectErrorsAt(state, literal.key, literal.segments, active2, merged);
|
|
1077
|
+
}
|
|
1011
1078
|
return merged;
|
|
1012
1079
|
}
|
|
1013
|
-
const { key } = canonicalizePath(path);
|
|
1080
|
+
const { key, segments } = canonicalizePath(path);
|
|
1014
1081
|
const active = hasAtPath(state.form.value, path);
|
|
1015
|
-
|
|
1082
|
+
collectErrorsAt(state, key, segments, active, merged);
|
|
1016
1083
|
return merged;
|
|
1017
1084
|
};
|
|
1018
1085
|
return buildTree({
|
|
@@ -1030,64 +1097,80 @@ function buildErrorsSurface(state) {
|
|
|
1030
1097
|
// `errors()` / `errors([])` / `errors(path)` are all the subtree
|
|
1031
1098
|
// aggregate — the same helper `meta.errors` reads, so the surfaces
|
|
1032
1099
|
// never drift.
|
|
1033
|
-
call: (path) => aggregateErrorsAt(state, path),
|
|
1034
|
-
surface: "form.errors"
|
|
1100
|
+
call: (path) => aggregateErrorsAt(state, path, keyForSegments(path).key),
|
|
1101
|
+
surface: "form.errors",
|
|
1102
|
+
sweep
|
|
1035
1103
|
});
|
|
1036
1104
|
}
|
|
1105
|
+
function collectErrorsAt(state, key, segments, active, into) {
|
|
1106
|
+
const cell = state.errorCells.get(key);
|
|
1107
|
+
if (active) {
|
|
1108
|
+
if (cell !== void 0) into.push(...cell.schema);
|
|
1109
|
+
if (state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments)) {
|
|
1110
|
+
into.push(makeBlankRequiredError(segments));
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
if (cell !== void 0) into.push(...cell.user);
|
|
1114
|
+
}
|
|
1037
1115
|
function errorAwareContainerKeys(state, segments) {
|
|
1038
1116
|
const keys = new Set(liveKeysAtPath(state, segments));
|
|
1039
1117
|
const formValue = state.form.value;
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1118
|
+
const errors = [];
|
|
1119
|
+
const found = [];
|
|
1120
|
+
for (const { key, segments: decoded } of state.errorWindowAt(
|
|
1121
|
+
segments,
|
|
1122
|
+
keyForSegments(segments).key
|
|
1123
|
+
)) {
|
|
1124
|
+
if (decoded.length <= segments.length) continue;
|
|
1125
|
+
if (!isPathPrefix(segments, decoded)) continue;
|
|
1126
|
+
errors.length = 0;
|
|
1127
|
+
collectErrorsAt(state, key, decoded, hasAtPath(formValue, decoded), errors);
|
|
1128
|
+
if (errors.length === 0) continue;
|
|
1129
|
+
const nextSeg = decoded[segments.length];
|
|
1130
|
+
found.push({
|
|
1131
|
+
childKey: typeof nextSeg === "number" ? String(nextSeg) : nextSeg,
|
|
1132
|
+
ordinal: state.ensurePathOrdinal(key)
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
found.sort((a, b) => a.ordinal - b.ordinal);
|
|
1136
|
+
for (const { childKey } of found) keys.add(childKey);
|
|
1055
1137
|
return [...keys];
|
|
1056
1138
|
}
|
|
1057
1139
|
function materializeErrors(state, containerSegments) {
|
|
1058
|
-
const
|
|
1140
|
+
const formValue = state.form.value;
|
|
1141
|
+
const liveContainer = getAtPath(formValue, containerSegments);
|
|
1059
1142
|
const tree = Array.isArray(liveContainer) ? [] : {};
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
for (let i = 0; i < containerSegments.length; i++) {
|
|
1071
|
-
if (fullPath[i] !== containerSegments[i]) continue entries;
|
|
1072
|
-
}
|
|
1073
|
-
if (applyActivePathFilter && !hasAtPath(state.form.value, fullPath)) continue;
|
|
1074
|
-
const relativePath = fullPath.slice(containerSegments.length);
|
|
1075
|
-
let placePath;
|
|
1076
|
-
if (relativePath.length === 0) {
|
|
1077
|
-
placePath = [""];
|
|
1078
|
-
} else if (state.schema.isLeafAtPath(fullPath)) {
|
|
1079
|
-
placePath = relativePath;
|
|
1080
|
-
} else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
|
|
1081
|
-
placePath = [...relativePath, ""];
|
|
1082
|
-
} else {
|
|
1083
|
-
placePath = relativePath;
|
|
1084
|
-
}
|
|
1085
|
-
placeAt(tree, placePath, errors);
|
|
1143
|
+
const placements = [];
|
|
1144
|
+
for (const { key, segments: fullPath } of state.errorWindowAt(
|
|
1145
|
+
containerSegments,
|
|
1146
|
+
keyForSegments(containerSegments).key
|
|
1147
|
+
)) {
|
|
1148
|
+
const isRoot = fullPath.length === 0;
|
|
1149
|
+
if (isRoot) {
|
|
1150
|
+
if (containerSegments.length !== 0) continue;
|
|
1151
|
+
} else if (!isPathPrefix(containerSegments, fullPath)) {
|
|
1152
|
+
continue;
|
|
1086
1153
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1154
|
+
const errors = [];
|
|
1155
|
+
collectErrorsAt(state, key, fullPath, isRoot || hasAtPath(formValue, fullPath), errors);
|
|
1156
|
+
if (errors.length === 0) continue;
|
|
1157
|
+
const relativePath = fullPath.slice(containerSegments.length);
|
|
1158
|
+
let placePath;
|
|
1159
|
+
if (isRoot) {
|
|
1160
|
+
placePath = [ROOT_PATH_KEY];
|
|
1161
|
+
} else if (relativePath.length === 0) {
|
|
1162
|
+
placePath = [""];
|
|
1163
|
+
} else if (state.schema.isLeafAtPath(fullPath)) {
|
|
1164
|
+
placePath = relativePath;
|
|
1165
|
+
} else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
|
|
1166
|
+
placePath = [...relativePath, ""];
|
|
1167
|
+
} else {
|
|
1168
|
+
placePath = relativePath;
|
|
1169
|
+
}
|
|
1170
|
+
placements.push({ placePath, errors, ordinal: state.ensurePathOrdinal(key) });
|
|
1171
|
+
}
|
|
1172
|
+
placements.sort((a, b) => a.ordinal - b.ordinal);
|
|
1173
|
+
for (const { placePath, errors } of placements) placeAt(tree, placePath, errors);
|
|
1091
1174
|
return tree;
|
|
1092
1175
|
}
|
|
1093
1176
|
function placeAt(tree, path, errors) {
|
|
@@ -1150,7 +1233,7 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1150
1233
|
"placeholder",
|
|
1151
1234
|
"meta"
|
|
1152
1235
|
]);
|
|
1153
|
-
function buildFieldsSurface(state, getFieldStateAt) {
|
|
1236
|
+
function buildFieldsSurface(state, getFieldStateAt, sweep) {
|
|
1154
1237
|
const snapshotAt = (segments) => {
|
|
1155
1238
|
const view = getFieldStateAt(segments).value;
|
|
1156
1239
|
const snapshot = {};
|
|
@@ -1158,8 +1241,9 @@ function buildFieldsSurface(state, getFieldStateAt) {
|
|
|
1158
1241
|
return snapshot;
|
|
1159
1242
|
};
|
|
1160
1243
|
const viewCache = /* @__PURE__ */ new Map();
|
|
1244
|
+
sweep.onEvict((key) => viewCache.delete(key));
|
|
1161
1245
|
function viewAt(segments) {
|
|
1162
|
-
const cacheKey =
|
|
1246
|
+
const cacheKey = keyForSegments(segments).key;
|
|
1163
1247
|
const existing = viewCache.get(cacheKey);
|
|
1164
1248
|
if (existing !== void 0) return existing;
|
|
1165
1249
|
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
|
|
@@ -1212,6 +1296,7 @@ function buildFieldsSurface(state, getFieldStateAt) {
|
|
|
1212
1296
|
}
|
|
1213
1297
|
});
|
|
1214
1298
|
viewCache.set(cacheKey, proxy);
|
|
1299
|
+
sweep.track(segments, cacheKey);
|
|
1215
1300
|
return proxy;
|
|
1216
1301
|
}
|
|
1217
1302
|
return buildTree({
|
|
@@ -1226,7 +1311,8 @@ function buildFieldsSurface(state, getFieldStateAt) {
|
|
|
1226
1311
|
// container's rollup); a path the schema doesn't have is a typo and
|
|
1227
1312
|
// reads `undefined`. The root (`fields()`) is always declared.
|
|
1228
1313
|
call: (path) => state.schema.getSlimPrimitiveTypesAtPath(path).size > 0 ? viewAt(path) : void 0,
|
|
1229
|
-
surface: "form.fields"
|
|
1314
|
+
surface: "form.fields",
|
|
1315
|
+
sweep
|
|
1230
1316
|
});
|
|
1231
1317
|
}
|
|
1232
1318
|
function materializeFields(state, containerSegments, snapshotAt) {
|
|
@@ -1260,18 +1346,34 @@ function materializeFormValue(node) {
|
|
|
1260
1346
|
}
|
|
1261
1347
|
return out;
|
|
1262
1348
|
}
|
|
1263
|
-
function buildValuesSurface(form) {
|
|
1349
|
+
function buildValuesSurface(form, onFormChange) {
|
|
1264
1350
|
const inner = computed(() => readonly(form.value));
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1351
|
+
let held = null;
|
|
1352
|
+
const snapshot = computed(() => {
|
|
1353
|
+
const box = { value: materializeFormValue(inner.value) };
|
|
1354
|
+
held = box;
|
|
1355
|
+
return box;
|
|
1356
|
+
});
|
|
1357
|
+
onFormChange(() => {
|
|
1358
|
+
if (held === null) return;
|
|
1359
|
+
held.value = RELEASED;
|
|
1360
|
+
held = null;
|
|
1361
|
+
});
|
|
1362
|
+
const readSnapshot = () => {
|
|
1363
|
+
const box = snapshot.value;
|
|
1364
|
+
return box.value === RELEASED ? materializeFormValue(inner.value) : box.value;
|
|
1365
|
+
};
|
|
1366
|
+
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(() => readSnapshot());
|
|
1268
1367
|
const target = (() => {
|
|
1269
1368
|
});
|
|
1270
1369
|
return new Proxy(target, {
|
|
1271
1370
|
apply(_, __, args) {
|
|
1272
1371
|
const arg = args[0];
|
|
1273
|
-
if (arg === void 0) return
|
|
1274
|
-
|
|
1372
|
+
if (arg === void 0) return readSnapshot();
|
|
1373
|
+
const segments = canonicalizePath(arg).segments;
|
|
1374
|
+
const node = getAtPath(inner.value, segments);
|
|
1375
|
+
if (node === null || typeof node !== "object") return node;
|
|
1376
|
+
return getAtPath(readSnapshot(), segments);
|
|
1275
1377
|
},
|
|
1276
1378
|
get(_, key) {
|
|
1277
1379
|
if (typeof key === "symbol") {
|
|
@@ -1556,9 +1658,12 @@ function cloneVariantSnapshot(value) {
|
|
|
1556
1658
|
for (let i = 0; i < raw.length; i++) out2[i] = cloneVariantSnapshot(raw[i]);
|
|
1557
1659
|
return out2;
|
|
1558
1660
|
}
|
|
1661
|
+
if (!isPlainRecord(raw)) return raw;
|
|
1559
1662
|
const src = raw;
|
|
1560
1663
|
const out = {};
|
|
1561
|
-
for (const k of
|
|
1664
|
+
for (const k of consumerKeys(src)) {
|
|
1665
|
+
safeAssign(out, k, cloneVariantSnapshot(readConsumerProp(src, k)));
|
|
1666
|
+
}
|
|
1562
1667
|
return out;
|
|
1563
1668
|
}
|
|
1564
1669
|
function createArrayBookkeeping(deps) {
|
|
@@ -1733,8 +1838,8 @@ function deriveSubmitErrors(err) {
|
|
|
1733
1838
|
messageless: true
|
|
1734
1839
|
};
|
|
1735
1840
|
}
|
|
1736
|
-
function buildProcessForm(state,
|
|
1737
|
-
const
|
|
1841
|
+
function buildProcessForm(state, options = {}) {
|
|
1842
|
+
const applyInvalidSubmit = options.applyInvalidSubmit;
|
|
1738
1843
|
function validate(pathInput) {
|
|
1739
1844
|
const result = ref({
|
|
1740
1845
|
pending: true,
|
|
@@ -1832,7 +1937,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1832
1937
|
};
|
|
1833
1938
|
}
|
|
1834
1939
|
async function runRefinementValidation(data, path) {
|
|
1835
|
-
return await state.schema.validateAtPath(data, path);
|
|
1940
|
+
return stampFormKey(await state.schema.validateAtPath(data, path), state.formKey);
|
|
1836
1941
|
}
|
|
1837
1942
|
function composeWithDerivedBlank(refinement, scope) {
|
|
1838
1943
|
const blankErrors = collectScopedBlankErrors(state, scope);
|
|
@@ -1853,6 +1958,11 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1853
1958
|
event.preventDefault();
|
|
1854
1959
|
}
|
|
1855
1960
|
if (state.activeSubmissions.value > 0) {
|
|
1961
|
+
if (event === void 0) {
|
|
1962
|
+
console.warn(
|
|
1963
|
+
`[attaform] handleSubmit: a submit is already in flight on form "${String(state.formKey)}", so this call was ignored; its callback never ran. Await the first submit before starting another, or move the work into that submit's callback.`
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1856
1966
|
return;
|
|
1857
1967
|
}
|
|
1858
1968
|
const genAtEntry = state.submissionGeneration.value;
|
|
@@ -1878,7 +1988,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1878
1988
|
}
|
|
1879
1989
|
}
|
|
1880
1990
|
if (generationStillValid) {
|
|
1881
|
-
|
|
1991
|
+
applyInvalidSubmit?.();
|
|
1882
1992
|
}
|
|
1883
1993
|
if (onError !== void 0) {
|
|
1884
1994
|
try {
|
|
@@ -1895,7 +2005,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1895
2005
|
await onSubmit(merged.data);
|
|
1896
2006
|
if (hasUserErrorEntries(state)) {
|
|
1897
2007
|
if (state.submissionGeneration.value === genAtEntry) {
|
|
1898
|
-
|
|
2008
|
+
applyInvalidSubmit?.();
|
|
1899
2009
|
}
|
|
1900
2010
|
return;
|
|
1901
2011
|
}
|
|
@@ -1913,7 +2023,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1913
2023
|
if (segments === null) continue;
|
|
1914
2024
|
state.setUserErrorsForPath([...segments], bucket);
|
|
1915
2025
|
}
|
|
1916
|
-
|
|
2026
|
+
applyInvalidSubmit?.();
|
|
1917
2027
|
if (messageless) {
|
|
1918
2028
|
console.warn(
|
|
1919
2029
|
"[attaform] handleSubmit callback threw a non-Error value; throw an Error or a ValidationError ({ message, path? }) so the failure surfaces with a usable message."
|
|
@@ -1933,6 +2043,10 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1933
2043
|
};
|
|
1934
2044
|
return { validate, parse, handleSubmit };
|
|
1935
2045
|
}
|
|
2046
|
+
function stampFormKey(verdict, formKey) {
|
|
2047
|
+
if (verdict.success) return { ...verdict, formKey };
|
|
2048
|
+
return verdict.data === void 0 ? { data: void 0, errors: verdict.errors, success: false, formKey } : { data: verdict.data, errors: verdict.errors, success: false, formKey };
|
|
2049
|
+
}
|
|
1936
2050
|
function toSegments(pathInput) {
|
|
1937
2051
|
return canonicalizePath(pathInput).segments;
|
|
1938
2052
|
}
|
|
@@ -1966,24 +2080,9 @@ function collectScopedBlankErrors(state, scope) {
|
|
|
1966
2080
|
}
|
|
1967
2081
|
return errors;
|
|
1968
2082
|
}
|
|
1969
|
-
function applyInvalidSubmitPolicy(state, formInstanceId, policy) {
|
|
1970
|
-
if (policy === "none") return;
|
|
1971
|
-
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
1972
|
-
if (target === null) return;
|
|
1973
|
-
if (policy === "scroll-to-first-error") {
|
|
1974
|
-
target.element.scrollIntoView();
|
|
1975
|
-
return;
|
|
1976
|
-
}
|
|
1977
|
-
if (policy === "focus-first-error") {
|
|
1978
|
-
target.element.focus({ focusVisible: true });
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
target.element.scrollIntoView();
|
|
1982
|
-
target.element.focus({ preventScroll: true, focusVisible: true });
|
|
1983
|
-
}
|
|
1984
2083
|
|
|
1985
2084
|
const warnedRejections = /* @__PURE__ */ new WeakMap() ;
|
|
1986
|
-
function shouldWarnOnce
|
|
2085
|
+
function shouldWarnOnce(store, key) {
|
|
1987
2086
|
if (warnedRejections === null) return false;
|
|
1988
2087
|
let set = warnedRejections.get(store);
|
|
1989
2088
|
if (set === void 0) {
|
|
@@ -2039,15 +2138,16 @@ function walk(schema, store, path, value) {
|
|
|
2039
2138
|
reportRejection(store, path, kind, accepted);
|
|
2040
2139
|
return false;
|
|
2041
2140
|
}
|
|
2141
|
+
if (schema.isOpaqueLeafAtPath(path)) return true;
|
|
2042
2142
|
if (Array.isArray(value)) {
|
|
2043
2143
|
for (let i = 0; i < value.length; i++) {
|
|
2044
|
-
if (!walk(schema, store, [...path, i], value
|
|
2144
|
+
if (!walk(schema, store, [...path, i], readConsumerIndex(value, i))) return false;
|
|
2045
2145
|
}
|
|
2046
2146
|
return true;
|
|
2047
2147
|
}
|
|
2048
2148
|
if (isPlainRecord(value)) {
|
|
2049
|
-
for (const key of
|
|
2050
|
-
if (!walk(schema, store, [...path, key], value
|
|
2149
|
+
for (const key of consumerKeys(value)) {
|
|
2150
|
+
if (!walk(schema, store, [...path, key], readConsumerProp(value, key))) {
|
|
2051
2151
|
return false;
|
|
2052
2152
|
}
|
|
2053
2153
|
}
|
|
@@ -2058,7 +2158,7 @@ function walk(schema, store, path, value) {
|
|
|
2058
2158
|
function reportRejection(store, path, kind, accepted) {
|
|
2059
2159
|
const dotted = path.map((s) => String(s)).join(".") || "(root)";
|
|
2060
2160
|
const key = `${dotted}::${kind}`;
|
|
2061
|
-
if (!shouldWarnOnce
|
|
2161
|
+
if (!shouldWarnOnce(store, key)) return;
|
|
2062
2162
|
if (accepted.size === 0) {
|
|
2063
2163
|
console.warn(
|
|
2064
2164
|
`[attaform] Cannot write to '${dotted}' \u2014 this path is not in your schema.
|
|
@@ -2091,170 +2191,95 @@ function formatExpectedKinds(accepted) {
|
|
|
2091
2191
|
return `one of: ${list.join(", ")}`;
|
|
2092
2192
|
}
|
|
2093
2193
|
|
|
2094
|
-
function defineCoercion(entry) {
|
|
2095
|
-
return entry;
|
|
2096
|
-
}
|
|
2097
2194
|
const IDENTITY = (v) => v;
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
if (trimmed === "") return { coerced: false };
|
|
2106
|
-
const n = Number(trimmed);
|
|
2107
|
-
if (!Number.isFinite(n)) return { coerced: false };
|
|
2108
|
-
return { coerced: true, value: n };
|
|
2109
|
-
}
|
|
2110
|
-
}),
|
|
2111
|
-
defineCoercion({
|
|
2112
|
-
input: "string",
|
|
2113
|
-
output: "boolean",
|
|
2114
|
-
transform: (s) => {
|
|
2115
|
-
const normalized = s.trim().toLowerCase();
|
|
2116
|
-
if (normalized === "true") return { coerced: true, value: true };
|
|
2117
|
-
if (normalized === "false") return { coerced: true, value: false };
|
|
2118
|
-
return { coerced: false };
|
|
2119
|
-
}
|
|
2120
|
-
})
|
|
2121
|
-
];
|
|
2122
|
-
function resolveCoercionIndex(config) {
|
|
2123
|
-
if (config === false) return EMPTY_INDEX;
|
|
2124
|
-
const rules = config === void 0 || config === true ? defaultCoercionRules : config;
|
|
2125
|
-
return indexRules(rules);
|
|
2126
|
-
}
|
|
2127
|
-
function indexRules(rules) {
|
|
2128
|
-
const idx = /* @__PURE__ */ new Map();
|
|
2129
|
-
for (const entry of rules) {
|
|
2130
|
-
const candidate = entry;
|
|
2131
|
-
if (candidate === null || typeof candidate !== "object" || typeof candidate.transform !== "function") {
|
|
2132
|
-
{
|
|
2133
|
-
console.warn("[attaform] coercion entry missing or invalid `transform` \u2014 skipped.");
|
|
2134
|
-
}
|
|
2135
|
-
continue;
|
|
2136
|
-
}
|
|
2137
|
-
const key = `${entry.input}->${entry.output}`;
|
|
2138
|
-
if (idx.has(key) && true) {
|
|
2139
|
-
console.warn(`[attaform] duplicate coercion rule for '${key}' \u2014 last entry wins.`);
|
|
2140
|
-
}
|
|
2141
|
-
idx.set(key, entry);
|
|
2195
|
+
function resolveCoerceEnabled(config) {
|
|
2196
|
+
return config !== false;
|
|
2197
|
+
}
|
|
2198
|
+
function memberSlimTypes(schema, segments, accepted) {
|
|
2199
|
+
if (accepted.has("array")) return schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
|
|
2200
|
+
if (accepted.has("set")) {
|
|
2201
|
+
return schema.getSlimPrimitiveTypesAtPath([...segments, SET_MEMBER_SEGMENT]);
|
|
2142
2202
|
}
|
|
2143
|
-
return
|
|
2203
|
+
return void 0;
|
|
2144
2204
|
}
|
|
2145
|
-
function buildCoerceFn(schema, segments,
|
|
2146
|
-
if (
|
|
2147
|
-
if (index.size === 0) return IDENTITY;
|
|
2205
|
+
function buildCoerceFn(schema, segments, enabled) {
|
|
2206
|
+
if (!enabled) return IDENTITY;
|
|
2148
2207
|
const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
|
|
2149
|
-
const elementAccepted =
|
|
2150
|
-
return (value) => coerceValue(value, accepted, elementAccepted
|
|
2208
|
+
const elementAccepted = memberSlimTypes(schema, segments, accepted);
|
|
2209
|
+
return (value) => coerceValue(value, accepted, elementAccepted);
|
|
2151
2210
|
}
|
|
2152
|
-
function buildElementCoerceFn(schema, segments,
|
|
2153
|
-
if (
|
|
2154
|
-
if (index.size === 0) return void 0;
|
|
2211
|
+
function buildElementCoerceFn(schema, segments, enabled) {
|
|
2212
|
+
if (!enabled) return void 0;
|
|
2155
2213
|
const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
return (value) => coerceScalar(value, elementAccepted
|
|
2214
|
+
const elementAccepted = memberSlimTypes(schema, segments, accepted);
|
|
2215
|
+
if (elementAccepted === void 0) return void 0;
|
|
2216
|
+
return (value) => coerceScalar(value, elementAccepted);
|
|
2159
2217
|
}
|
|
2160
2218
|
function pickScalarTarget(accepted) {
|
|
2161
2219
|
if (accepted.has("string")) return null;
|
|
2162
2220
|
if (accepted.has("number")) return "number";
|
|
2163
2221
|
if (accepted.has("boolean")) return "boolean";
|
|
2164
|
-
if (accepted.has("bigint")) return "bigint";
|
|
2165
2222
|
return null;
|
|
2166
2223
|
}
|
|
2167
|
-
|
|
2168
|
-
const
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
if (set === void 0) {
|
|
2173
|
-
set = /* @__PURE__ */ new Set();
|
|
2174
|
-
warnedCoerce.set(sharedWarnStore, set);
|
|
2175
|
-
}
|
|
2176
|
-
if (set.has(key)) return false;
|
|
2177
|
-
set.add(key);
|
|
2178
|
-
return true;
|
|
2224
|
+
function toNumber(source) {
|
|
2225
|
+
const trimmed = source.trim();
|
|
2226
|
+
if (trimmed === "") return source;
|
|
2227
|
+
const n = Number(trimmed);
|
|
2228
|
+
return Number.isFinite(n) ? n : source;
|
|
2179
2229
|
}
|
|
2180
|
-
function
|
|
2230
|
+
function toBoolean(source) {
|
|
2231
|
+
const normalized = source.trim().toLowerCase();
|
|
2232
|
+
if (normalized === "true") return true;
|
|
2233
|
+
if (normalized === "false") return false;
|
|
2234
|
+
return source;
|
|
2235
|
+
}
|
|
2236
|
+
function coerceScalar(value, accepted) {
|
|
2181
2237
|
if (accepted.size === 0) return value;
|
|
2182
2238
|
const sourceKind = slimKindOf(value);
|
|
2183
2239
|
if (accepted.has(sourceKind)) return value;
|
|
2240
|
+
if (sourceKind !== "string") return value;
|
|
2184
2241
|
const target = pickScalarTarget(accepted);
|
|
2185
|
-
if (target ===
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
let result;
|
|
2189
|
-
try {
|
|
2190
|
-
result = entry.transform(value);
|
|
2191
|
-
} catch (err) {
|
|
2192
|
-
if (shouldWarnOnce(`${entry.input}->${entry.output}::throw`)) {
|
|
2193
|
-
console.warn(
|
|
2194
|
-
`[attaform] coercion '${entry.input}->${entry.output}' threw \u2014 write passes through.`,
|
|
2195
|
-
err
|
|
2196
|
-
);
|
|
2197
|
-
}
|
|
2198
|
-
return value;
|
|
2199
|
-
}
|
|
2200
|
-
if (!result.coerced) return value;
|
|
2201
|
-
const returnedKind = slimKindOf(result.value);
|
|
2202
|
-
if (returnedKind !== entry.output) {
|
|
2203
|
-
if (shouldWarnOnce(`${entry.input}->${entry.output}::wrong-kind:${returnedKind}`)) {
|
|
2204
|
-
console.warn(
|
|
2205
|
-
`[attaform] coercion '${entry.input}->${entry.output}' produced a ${returnedKind} \u2014 write passes through.`
|
|
2206
|
-
);
|
|
2207
|
-
}
|
|
2208
|
-
return value;
|
|
2209
|
-
}
|
|
2210
|
-
if (entry.output === "number" && !Number.isFinite(result.value)) {
|
|
2211
|
-
if (shouldWarnOnce(`${entry.input}->${entry.output}::nan`)) {
|
|
2212
|
-
console.warn(
|
|
2213
|
-
`[attaform] coercion '${entry.input}->${entry.output}' produced a non-finite number \u2014 write passes through.`
|
|
2214
|
-
);
|
|
2215
|
-
}
|
|
2216
|
-
return value;
|
|
2217
|
-
}
|
|
2218
|
-
return result.value;
|
|
2242
|
+
if (target === "number") return toNumber(value);
|
|
2243
|
+
if (target === "boolean") return toBoolean(value);
|
|
2244
|
+
return value;
|
|
2219
2245
|
}
|
|
2220
|
-
function coerceArrayMembers(arr, elementAccepted
|
|
2246
|
+
function coerceArrayMembers(arr, elementAccepted) {
|
|
2221
2247
|
let changed = false;
|
|
2222
2248
|
const out = [];
|
|
2223
2249
|
for (const el of arr) {
|
|
2224
|
-
const next = coerceScalar(el, elementAccepted
|
|
2250
|
+
const next = coerceScalar(el, elementAccepted);
|
|
2225
2251
|
if (next !== el) changed = true;
|
|
2226
2252
|
out.push(next);
|
|
2227
2253
|
}
|
|
2228
2254
|
return changed ? out : arr;
|
|
2229
2255
|
}
|
|
2230
|
-
function coerceSetMembers(set, elementAccepted
|
|
2256
|
+
function coerceSetMembers(set, elementAccepted) {
|
|
2231
2257
|
let changed = false;
|
|
2232
2258
|
const out = [];
|
|
2233
2259
|
for (const el of set) {
|
|
2234
|
-
const next = coerceScalar(el, elementAccepted
|
|
2260
|
+
const next = coerceScalar(el, elementAccepted);
|
|
2235
2261
|
if (next !== el) changed = true;
|
|
2236
2262
|
out.push(next);
|
|
2237
2263
|
}
|
|
2238
2264
|
return changed ? new Set(out) : set;
|
|
2239
2265
|
}
|
|
2240
|
-
function coerceValue(value, accepted, elementAccepted
|
|
2266
|
+
function coerceValue(value, accepted, elementAccepted) {
|
|
2241
2267
|
if (Array.isArray(value)) {
|
|
2242
2268
|
if (!accepted.has("array") || elementAccepted === void 0) return value;
|
|
2243
|
-
return coerceArrayMembers(value, elementAccepted
|
|
2269
|
+
return coerceArrayMembers(value, elementAccepted);
|
|
2244
2270
|
}
|
|
2245
2271
|
if (value instanceof Set) {
|
|
2246
2272
|
if (!accepted.has("set") || elementAccepted === void 0) return value;
|
|
2247
|
-
return coerceSetMembers(value, elementAccepted
|
|
2273
|
+
return coerceSetMembers(value, elementAccepted);
|
|
2248
2274
|
}
|
|
2249
|
-
return coerceScalar(value, accepted
|
|
2275
|
+
return coerceScalar(value, accepted);
|
|
2250
2276
|
}
|
|
2251
2277
|
|
|
2252
2278
|
const warnedMultiRootHosts = /* @__PURE__ */ new Set();
|
|
2253
2279
|
const EMPTY_TRANSFORMS = Object.freeze([]);
|
|
2254
2280
|
function buildRegister(state, formInstanceId, instanceConfig) {
|
|
2255
|
-
const
|
|
2281
|
+
const coerceEnabled = instanceConfig?.coerce !== void 0 ? resolveCoerceEnabled(instanceConfig.coerce) : state.coerceEnabled;
|
|
2256
2282
|
const instanceMeta = instanceConfig?.instanceMeta;
|
|
2257
|
-
const formAutoAria = instanceConfig?.autoAria ?? true;
|
|
2258
2283
|
const getDisplayStateAt = instanceConfig?.getDisplayStateAt;
|
|
2259
2284
|
const withInstanceMeta = (meta) => {
|
|
2260
2285
|
if (instanceMeta === void 0) return meta;
|
|
@@ -2294,16 +2319,15 @@ function buildRegister(state, formInstanceId, instanceConfig) {
|
|
|
2294
2319
|
const coerce = buildCoerceFn(
|
|
2295
2320
|
state.schema,
|
|
2296
2321
|
segments,
|
|
2297
|
-
|
|
2322
|
+
coerceEnabled
|
|
2298
2323
|
);
|
|
2299
2324
|
const coerceElement = buildElementCoerceFn(
|
|
2300
2325
|
state.schema,
|
|
2301
2326
|
segments,
|
|
2302
|
-
|
|
2327
|
+
coerceEnabled
|
|
2303
2328
|
);
|
|
2304
2329
|
const { aria } = computeFieldIdentity(formInstanceId, state.formKey, pathKey);
|
|
2305
2330
|
const isRequired = state.schema.isRequiredAtPath(segments);
|
|
2306
|
-
const ariaEnabled = options?.autoAria ?? formAutoAria;
|
|
2307
2331
|
const ariaDisplayState = getDisplayStateAt !== void 0 ? computed(() => getDisplayStateAt(segments)) : void 0;
|
|
2308
2332
|
const markBlank = () => state.setValueAtPath(segments, slimDefault, withInstanceMeta({ blank: true }));
|
|
2309
2333
|
const internalRv = {
|
|
@@ -2423,7 +2447,6 @@ function buildRegister(state, formInstanceId, instanceConfig) {
|
|
|
2423
2447
|
// --- Aria (internal; consumed by the directive) ---
|
|
2424
2448
|
aria,
|
|
2425
2449
|
isRequired,
|
|
2426
|
-
ariaEnabled,
|
|
2427
2450
|
...ariaDisplayState !== void 0 ? { ariaDisplayState } : {}
|
|
2428
2451
|
};
|
|
2429
2452
|
return shallowReadonly(internalRv);
|
|
@@ -2445,8 +2468,8 @@ function walkUnsetSentinels(values, schema) {
|
|
|
2445
2468
|
const cleaned = walkCore(values, [], schema, paths, true);
|
|
2446
2469
|
return { cleanedValues: cleaned, paths };
|
|
2447
2470
|
}
|
|
2448
|
-
function
|
|
2449
|
-
return value
|
|
2471
|
+
function isRecursable(value) {
|
|
2472
|
+
return Array.isArray(value) || isPlainRecord(value);
|
|
2450
2473
|
}
|
|
2451
2474
|
function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
2452
2475
|
if (isUnset(input)) {
|
|
@@ -2460,20 +2483,21 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
|
2460
2483
|
return input;
|
|
2461
2484
|
}
|
|
2462
2485
|
if (input === null) return null;
|
|
2463
|
-
if (
|
|
2486
|
+
if (!isRecursable(input)) return input;
|
|
2464
2487
|
if (Array.isArray(input)) {
|
|
2465
2488
|
const out = new Array(input.length);
|
|
2466
2489
|
let mutated = false;
|
|
2467
2490
|
for (let i = 0; i < input.length; i++) {
|
|
2468
|
-
const
|
|
2491
|
+
const original = readConsumerIndex(input, i);
|
|
2492
|
+
const walked = walkCore(original, [...segments, i], schema, paths, synthesizeSchemaKeys);
|
|
2469
2493
|
out[i] = walked;
|
|
2470
|
-
if (walked !==
|
|
2494
|
+
if (walked !== original) mutated = true;
|
|
2471
2495
|
}
|
|
2472
2496
|
return mutated ? out : input;
|
|
2473
2497
|
}
|
|
2474
2498
|
if (typeof input === "object") {
|
|
2475
2499
|
const obj = input;
|
|
2476
|
-
const inputKeys =
|
|
2500
|
+
const inputKeys = consumerKeys(obj);
|
|
2477
2501
|
let keys = inputKeys;
|
|
2478
2502
|
let mutated = false;
|
|
2479
2503
|
let inputKeysSet = null;
|
|
@@ -2481,7 +2505,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
|
2481
2505
|
inputKeysSet = new Set(inputKeys);
|
|
2482
2506
|
const allKeys = new Set(inputKeys);
|
|
2483
2507
|
const slim = schema.getDefaultAtPath(segments);
|
|
2484
|
-
if (
|
|
2508
|
+
if (isPlainRecord(slim)) {
|
|
2485
2509
|
for (const k of Object.keys(slim)) allKeys.add(k);
|
|
2486
2510
|
}
|
|
2487
2511
|
keys = allKeys;
|
|
@@ -2489,7 +2513,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
|
2489
2513
|
}
|
|
2490
2514
|
const out = {};
|
|
2491
2515
|
for (const key of keys) {
|
|
2492
|
-
const orig = obj
|
|
2516
|
+
const orig = readConsumerProp(obj, key);
|
|
2493
2517
|
if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
|
|
2494
2518
|
safeAssign(out, key, void 0);
|
|
2495
2519
|
mutated = true;
|
|
@@ -2510,22 +2534,12 @@ function walkUnspecified(slim, segments, paths) {
|
|
|
2510
2534
|
}
|
|
2511
2535
|
return slim;
|
|
2512
2536
|
}
|
|
2513
|
-
if (
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
if (slim !== null && typeof slim === "object") {
|
|
2518
|
-
const out = {};
|
|
2519
|
-
for (const key of Object.keys(slim)) {
|
|
2520
|
-
safeAssign(
|
|
2521
|
-
out,
|
|
2522
|
-
key,
|
|
2523
|
-
walkUnspecified(slim[key], [...segments, key], paths)
|
|
2524
|
-
);
|
|
2525
|
-
}
|
|
2526
|
-
return out;
|
|
2537
|
+
if (!isPlainRecord(slim)) return slim;
|
|
2538
|
+
const out = {};
|
|
2539
|
+
for (const key of Object.keys(slim)) {
|
|
2540
|
+
safeAssign(out, key, walkUnspecified(slim[key], [...segments, key], paths));
|
|
2527
2541
|
}
|
|
2528
|
-
return
|
|
2542
|
+
return out;
|
|
2529
2543
|
}
|
|
2530
2544
|
function substituteUnsetSentinels(value, prefix, schema) {
|
|
2531
2545
|
const paths = [];
|
|
@@ -2561,11 +2575,11 @@ function expandUnsetAt(segments, schema, paths) {
|
|
|
2561
2575
|
paths.push(canonicalizePath(segments).key);
|
|
2562
2576
|
return slim;
|
|
2563
2577
|
}
|
|
2564
|
-
if (
|
|
2578
|
+
if (Array.isArray(slim)) return slim;
|
|
2579
|
+
if (!isPlainRecord(slim)) {
|
|
2565
2580
|
paths.push(canonicalizePath(segments).key);
|
|
2566
2581
|
return slim;
|
|
2567
2582
|
}
|
|
2568
|
-
if (Array.isArray(slim)) return slim;
|
|
2569
2583
|
const result = {};
|
|
2570
2584
|
for (const key of Object.keys(slim)) {
|
|
2571
2585
|
result[key] = expandUnsetAt([...segments, key], schema, paths);
|
|
@@ -2575,14 +2589,14 @@ function expandUnsetAt(segments, schema, paths) {
|
|
|
2575
2589
|
function walkAuthoredFromConstraints(value, prefix, out) {
|
|
2576
2590
|
if (prefix.length > 0) out.add(canonicalizePath(prefix).key);
|
|
2577
2591
|
if (isPlainRecord(value)) {
|
|
2578
|
-
for (const k of
|
|
2579
|
-
walkAuthoredFromConstraints(value
|
|
2592
|
+
for (const k of consumerKeys(value)) {
|
|
2593
|
+
walkAuthoredFromConstraints(readConsumerProp(value, k), [...prefix, k], out);
|
|
2580
2594
|
}
|
|
2581
2595
|
return;
|
|
2582
2596
|
}
|
|
2583
2597
|
if (Array.isArray(value)) {
|
|
2584
2598
|
for (let i = 0; i < value.length; i++) {
|
|
2585
|
-
walkAuthoredFromConstraints(value
|
|
2599
|
+
walkAuthoredFromConstraints(readConsumerIndex(value, i), [...prefix, i], out);
|
|
2586
2600
|
}
|
|
2587
2601
|
}
|
|
2588
2602
|
}
|
|
@@ -2596,11 +2610,50 @@ const DERIVED_DISPLAY_KEYS = /* @__PURE__ */ new Set([
|
|
|
2596
2610
|
"firstError",
|
|
2597
2611
|
"firstOwnError"
|
|
2598
2612
|
]);
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2613
|
+
const META_KEYS = [
|
|
2614
|
+
...FIELD_STATE_KEYS,
|
|
2615
|
+
"submitting",
|
|
2616
|
+
"submissionAttempts",
|
|
2617
|
+
"departAttempts",
|
|
2618
|
+
"submitError",
|
|
2619
|
+
"submitted",
|
|
2620
|
+
"instanceId",
|
|
2621
|
+
"errorCount"
|
|
2622
|
+
];
|
|
2623
|
+
const BASE_META_KEYS = META_KEYS.filter((k) => !DERIVED_DISPLAY_KEYS.has(k));
|
|
2624
|
+
let INERT_HISTORY;
|
|
2625
|
+
function inertHistory() {
|
|
2626
|
+
INERT_HISTORY ?? (INERT_HISTORY = readonly({
|
|
2627
|
+
undo: () => false,
|
|
2628
|
+
redo: () => false,
|
|
2629
|
+
clear: () => {
|
|
2630
|
+
},
|
|
2631
|
+
canUndo: false,
|
|
2632
|
+
canRedo: false,
|
|
2633
|
+
size: 0
|
|
2634
|
+
}));
|
|
2635
|
+
return INERT_HISTORY;
|
|
2636
|
+
}
|
|
2637
|
+
const denyWrite = () => false;
|
|
2638
|
+
function buildMetaProxy(keys, read) {
|
|
2639
|
+
const target = {};
|
|
2640
|
+
const owns = new Set(keys);
|
|
2641
|
+
return new Proxy(target, {
|
|
2642
|
+
get: (_, key) => owns.has(key) ? read(key) : Reflect.get(target, key),
|
|
2643
|
+
has: (_, key) => owns.has(key) || Reflect.has(target, key),
|
|
2644
|
+
// Safe to hand back the same array every time: the spec copies a
|
|
2645
|
+
// trap's key list before using it.
|
|
2646
|
+
ownKeys: () => keys,
|
|
2647
|
+
getOwnPropertyDescriptor(_, key) {
|
|
2648
|
+
if (!owns.has(key)) return Reflect.getOwnPropertyDescriptor(target, key);
|
|
2649
|
+
return { configurable: true, enumerable: true, value: read(key), writable: false };
|
|
2650
|
+
},
|
|
2651
|
+
// A getter with no setter throws on assignment under strict mode,
|
|
2652
|
+
// which every module here is. `false` keeps that.
|
|
2653
|
+
set: denyWrite,
|
|
2654
|
+
deleteProperty: denyWrite,
|
|
2655
|
+
defineProperty: denyWrite
|
|
2656
|
+
});
|
|
2604
2657
|
}
|
|
2605
2658
|
function buildFormApi(state, formInstanceId, options = {}) {
|
|
2606
2659
|
const instanceBag = pickDefined({
|
|
@@ -2627,32 +2680,26 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2627
2680
|
const rootBaseComputed = computed(
|
|
2628
2681
|
() => buildContainerFieldStateBase(state, ROOT_PATH, ROOT_PATH_KEY, formInstanceId).base
|
|
2629
2682
|
);
|
|
2630
|
-
const metaBase = {
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2683
|
+
const metaBase = buildMetaProxy(BASE_META_KEYS, (key) => {
|
|
2684
|
+
switch (key) {
|
|
2685
|
+
case "instanceId":
|
|
2686
|
+
return formInstanceId;
|
|
2687
|
+
case "errorCount":
|
|
2688
|
+
return rootBaseComputed.value.errors.length;
|
|
2689
|
+
case "submitting":
|
|
2690
|
+
return state.submitting.value;
|
|
2691
|
+
case "submissionAttempts":
|
|
2692
|
+
return state.submissionAttempts.value;
|
|
2693
|
+
case "departAttempts":
|
|
2694
|
+
return state.departAttempts.value;
|
|
2695
|
+
case "submitError":
|
|
2696
|
+
return state.submitError.value;
|
|
2697
|
+
case "submitted":
|
|
2698
|
+
return state.submitted.value;
|
|
2699
|
+
default:
|
|
2700
|
+
return rootBaseComputed.value[key];
|
|
2646
2701
|
}
|
|
2647
|
-
};
|
|
2648
|
-
for (const k of BASE_MIRROR_KEYS) {
|
|
2649
|
-
defineGetter(
|
|
2650
|
-
metaBase,
|
|
2651
|
-
k,
|
|
2652
|
-
() => rootBaseComputed.value[k]
|
|
2653
|
-
);
|
|
2654
|
-
}
|
|
2655
|
-
defineGetter(metaBase, "errorCount", () => rootBaseComputed.value.errors.length);
|
|
2702
|
+
});
|
|
2656
2703
|
const getFormMetaBase = () => {
|
|
2657
2704
|
void state.submitting.value;
|
|
2658
2705
|
void state.submissionAttempts.value;
|
|
@@ -2661,26 +2708,41 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2661
2708
|
void state.submitted.value;
|
|
2662
2709
|
return metaBase;
|
|
2663
2710
|
};
|
|
2664
|
-
const
|
|
2711
|
+
const pathSweep = state.pathSweep;
|
|
2665
2712
|
const getRootFieldStateAt = buildFieldStateAccessor(
|
|
2666
2713
|
state,
|
|
2667
2714
|
formInstanceId,
|
|
2668
2715
|
getFormMetaBase,
|
|
2669
|
-
|
|
2716
|
+
pathSweep
|
|
2670
2717
|
);
|
|
2671
2718
|
const getDisplayStateAt = (segments) => getRootFieldStateAt(segments).value.displayState;
|
|
2672
2719
|
const registerConfig = {
|
|
2673
|
-
...pickDefined({ instanceMeta, coerce: options.coerce
|
|
2720
|
+
...pickDefined({ instanceMeta, coerce: options.coerce }),
|
|
2674
2721
|
getDisplayStateAt
|
|
2675
2722
|
};
|
|
2676
2723
|
const register = buildRegister(state, formInstanceId, registerConfig);
|
|
2677
|
-
const
|
|
2678
|
-
|
|
2724
|
+
const focusFirstError = (options2) => {
|
|
2725
|
+
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2726
|
+
if (target === null) return false;
|
|
2727
|
+
target.element.focus({ focusVisible: true, ...options2 });
|
|
2728
|
+
return true;
|
|
2729
|
+
};
|
|
2730
|
+
const scrollToFirstError = (options2) => {
|
|
2731
|
+
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2732
|
+
if (target === null) return false;
|
|
2733
|
+
target.element.scrollIntoView(options2);
|
|
2734
|
+
return true;
|
|
2735
|
+
};
|
|
2736
|
+
const applyInvalidSubmitPolicyPublic = () => {
|
|
2737
|
+
if (options.focusOnInvalidSubmit !== false) focusFirstError();
|
|
2738
|
+
};
|
|
2679
2739
|
const {
|
|
2680
2740
|
validate: validateBuilt,
|
|
2681
2741
|
parse: parseBuilt,
|
|
2682
2742
|
handleSubmit
|
|
2683
|
-
} = buildProcessForm(state,
|
|
2743
|
+
} = buildProcessForm(state, {
|
|
2744
|
+
applyInvalidSubmit: applyInvalidSubmitPolicyPublic
|
|
2745
|
+
});
|
|
2684
2746
|
const validate = (pathInput) => validateBuilt(pathInput);
|
|
2685
2747
|
const parse = (arg1, arg2) => {
|
|
2686
2748
|
const isPathArg = typeof arg1 === "string" || Array.isArray(arg1);
|
|
@@ -2692,6 +2754,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2692
2754
|
const segments = canonicalizePath(pathInput).segments;
|
|
2693
2755
|
return computed(() => getAtPath(state.form.value, segments));
|
|
2694
2756
|
}
|
|
2757
|
+
function pathStoresFunctions(segments) {
|
|
2758
|
+
if (state.schema.isOpaqueLeafAtPath(segments)) return false;
|
|
2759
|
+
return state.schema.getSlimPrimitiveTypesAtPath(segments).has("function");
|
|
2760
|
+
}
|
|
2695
2761
|
function setValueImpl(pathOrValue, maybeValue) {
|
|
2696
2762
|
const argc = arguments.length;
|
|
2697
2763
|
const isPathForm = argc >= 2 && (typeof pathOrValue === "string" || Array.isArray(pathOrValue));
|
|
@@ -2744,7 +2810,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2744
2810
|
};
|
|
2745
2811
|
if (isUnset(maybeValue)) return writeUnsetAt();
|
|
2746
2812
|
let resolvedValue;
|
|
2747
|
-
if (typeof maybeValue === "function") {
|
|
2813
|
+
if (typeof maybeValue === "function" && !pathStoresFunctions(segments)) {
|
|
2748
2814
|
const current = state.getValueAtPath(segments);
|
|
2749
2815
|
const prev = current === void 0 ? state.schema.getDefaultAtPath(segments) : current;
|
|
2750
2816
|
resolvedValue = maybeValue(prev);
|
|
@@ -2762,7 +2828,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2762
2828
|
reMarkBlanksAfterSubstitution(walked.paths);
|
|
2763
2829
|
return true;
|
|
2764
2830
|
}
|
|
2765
|
-
const errorsProxy = buildErrorsSurface(state);
|
|
2831
|
+
const errorsProxy = buildErrorsSurface(state, pathSweep);
|
|
2766
2832
|
function flattenUserErrors() {
|
|
2767
2833
|
const all = [];
|
|
2768
2834
|
for (const cell of state.errorCells.values()) all.push(...cell.user);
|
|
@@ -2804,22 +2870,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2804
2870
|
() => state.firstValidationDone.value && state.errorCells.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
|
|
2805
2871
|
);
|
|
2806
2872
|
const history = options.history;
|
|
2807
|
-
const formHistory = readonly(
|
|
2873
|
+
const formHistory = history === void 0 ? inertHistory() : readonly(
|
|
2808
2874
|
reactive({
|
|
2809
|
-
undo: history
|
|
2810
|
-
redo: history
|
|
2811
|
-
clear: history
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
size: history?.historySize ?? computed(() => 0)
|
|
2875
|
+
undo: history.undo,
|
|
2876
|
+
redo: history.redo,
|
|
2877
|
+
clear: history.clear,
|
|
2878
|
+
canUndo: history.canUndo,
|
|
2879
|
+
canRedo: history.canRedo,
|
|
2880
|
+
size: history.historySize
|
|
2816
2881
|
})
|
|
2817
2882
|
);
|
|
2818
2883
|
const metaErrors = computed(
|
|
2819
|
-
() => aggregateErrorsAt(state, [])
|
|
2884
|
+
() => aggregateErrorsAt(state, [], ROOT_PATH_KEY)
|
|
2820
2885
|
);
|
|
2821
2886
|
const rootFieldState = getRootFieldStateAt([]);
|
|
2822
|
-
const
|
|
2887
|
+
const metaOwn = {
|
|
2823
2888
|
// Whole-form work signals compose the LIFECYCLE counters with the
|
|
2824
2889
|
// per-leaf rollup: a submit-time validate shows up as
|
|
2825
2890
|
// activeValidations, per-field debounced validators as
|
|
@@ -2848,21 +2913,19 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2848
2913
|
// identifier).
|
|
2849
2914
|
instanceId: formInstanceId
|
|
2850
2915
|
};
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
);
|
|
2857
|
-
}
|
|
2858
|
-
defineGetter(metaTarget, "errorCount", () => metaErrors.value.length);
|
|
2916
|
+
const metaTarget = buildMetaProxy(META_KEYS, (key) => {
|
|
2917
|
+
if (key === "errorCount") return metaErrors.value.length;
|
|
2918
|
+
if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
|
|
2919
|
+
return rootFieldState.value[key];
|
|
2920
|
+
});
|
|
2859
2921
|
const formMeta = readonly(reactive(metaTarget));
|
|
2860
2922
|
const reset = (nextDefaultValues) => {
|
|
2861
2923
|
if (nextDefaultValues === void 0) {
|
|
2862
2924
|
state.reset();
|
|
2863
2925
|
} else {
|
|
2864
|
-
const walked =
|
|
2926
|
+
const walked = substituteUnsetSentinels(
|
|
2865
2927
|
nextDefaultValues,
|
|
2928
|
+
[],
|
|
2866
2929
|
state.schema
|
|
2867
2930
|
);
|
|
2868
2931
|
state.reset(walked.cleanedValues);
|
|
@@ -2894,21 +2957,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2894
2957
|
} catch {
|
|
2895
2958
|
}
|
|
2896
2959
|
}
|
|
2897
|
-
const focusFirstError = (options2) => {
|
|
2898
|
-
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2899
|
-
if (target === null) return false;
|
|
2900
|
-
target.element.focus({ focusVisible: true, ...options2 });
|
|
2901
|
-
return true;
|
|
2902
|
-
};
|
|
2903
|
-
const scrollToFirstError = (options2) => {
|
|
2904
|
-
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2905
|
-
if (target === null) return false;
|
|
2906
|
-
target.element.scrollIntoView(options2);
|
|
2907
|
-
return true;
|
|
2908
|
-
};
|
|
2909
|
-
const applyInvalidSubmitPolicyPublic = (policy) => {
|
|
2910
|
-
applyInvalidSubmitPolicy(state, formInstanceId, policy ?? defaultInvalidSubmitPolicy);
|
|
2911
|
-
};
|
|
2912
2960
|
const fieldArrays = buildFieldArrayApi(state);
|
|
2913
2961
|
const blankPathsView = computed(() => {
|
|
2914
2962
|
const keys = /* @__PURE__ */ new Set();
|
|
@@ -2936,8 +2984,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2936
2984
|
};
|
|
2937
2985
|
return Object.freeze(view);
|
|
2938
2986
|
});
|
|
2939
|
-
const valuesProxy = buildValuesSurface(state.form);
|
|
2940
|
-
const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt);
|
|
2987
|
+
const valuesProxy = buildValuesSurface(state.form, state.onFormChange);
|
|
2988
|
+
const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt, pathSweep);
|
|
2941
2989
|
const needsLazyGate = state.defaultValuesFactory.value !== void 0 || state.hasSsrPrefetch;
|
|
2942
2990
|
function gated(fn) {
|
|
2943
2991
|
if (!needsLazyGate) return fn;
|
|
@@ -3083,8 +3131,53 @@ function shortenSourceFrame(frame) {
|
|
|
3083
3131
|
return `(${path}:${line})`;
|
|
3084
3132
|
}
|
|
3085
3133
|
|
|
3134
|
+
const SWEEP_SLICE = 8;
|
|
3135
|
+
function createDynamicPathSweep(deps) {
|
|
3136
|
+
const dynamicKeys = /* @__PURE__ */ new Set();
|
|
3137
|
+
const evictors = [];
|
|
3138
|
+
const isDynamicPath = (segments) => {
|
|
3139
|
+
for (let i = 0; i < segments.length; i++) {
|
|
3140
|
+
if (typeof segments[i] === "number") return true;
|
|
3141
|
+
if (!deps.isFixedObjectAtPath(segments.slice(0, i))) return true;
|
|
3142
|
+
}
|
|
3143
|
+
return false;
|
|
3144
|
+
};
|
|
3145
|
+
let sweepCursor = null;
|
|
3146
|
+
deps.onFormChange((next) => {
|
|
3147
|
+
if (dynamicKeys.size === 0) return;
|
|
3148
|
+
const raw = toRaw(next);
|
|
3149
|
+
for (let i = 0; i < SWEEP_SLICE; i++) {
|
|
3150
|
+
sweepCursor ?? (sweepCursor = dynamicKeys.values());
|
|
3151
|
+
const step = sweepCursor.next();
|
|
3152
|
+
if (step.done === true) {
|
|
3153
|
+
sweepCursor = null;
|
|
3154
|
+
break;
|
|
3155
|
+
}
|
|
3156
|
+
const segments = segmentsForPathKey(step.value);
|
|
3157
|
+
if (segments !== null && hasAtPath(raw, segments)) continue;
|
|
3158
|
+
dynamicKeys.delete(step.value);
|
|
3159
|
+
for (const evict of evictors) evict(step.value);
|
|
3160
|
+
}
|
|
3161
|
+
});
|
|
3162
|
+
return {
|
|
3163
|
+
track(segments, key) {
|
|
3164
|
+
if (dynamicKeys.has(key)) return;
|
|
3165
|
+
if (isDynamicPath(segments)) dynamicKeys.add(key);
|
|
3166
|
+
},
|
|
3167
|
+
onEvict(evict) {
|
|
3168
|
+
evictors.push(evict);
|
|
3169
|
+
}
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3086
3173
|
const IDLE = Object.freeze({ display: "idle" });
|
|
3087
3174
|
const MAX_DELAY = 2147483647;
|
|
3175
|
+
const PENDING_LIVENESS_MS = 250;
|
|
3176
|
+
function withLiveness(machine, now) {
|
|
3177
|
+
if (machine.display !== "pending") return machine;
|
|
3178
|
+
if (machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt)) return machine;
|
|
3179
|
+
return { ...machine, reviewAt: now + PENDING_LIVENESS_MS };
|
|
3180
|
+
}
|
|
3088
3181
|
function createDisplayEngine(ssr) {
|
|
3089
3182
|
const machines = /* @__PURE__ */ new Map();
|
|
3090
3183
|
const tick = ref(0);
|
|
@@ -3113,7 +3206,7 @@ function createDisplayEngine(ssr) {
|
|
|
3113
3206
|
return;
|
|
3114
3207
|
}
|
|
3115
3208
|
if (timer !== null && timerTarget === target) return;
|
|
3116
|
-
if (target === lastFiredTarget) {
|
|
3209
|
+
if (target === lastFiredTarget && target <= now) {
|
|
3117
3210
|
clearTimer();
|
|
3118
3211
|
return;
|
|
3119
3212
|
}
|
|
@@ -3132,8 +3225,9 @@ function createDisplayEngine(ssr) {
|
|
|
3132
3225
|
function resolve(key, ctx, reducer) {
|
|
3133
3226
|
void tick.value;
|
|
3134
3227
|
const prev = machines.get(key) ?? IDLE;
|
|
3135
|
-
const
|
|
3136
|
-
if (ssr) return
|
|
3228
|
+
const reduced = reducer(prev, ctx);
|
|
3229
|
+
if (ssr) return reduced;
|
|
3230
|
+
const machine = withLiveness(reduced, ctx.now);
|
|
3137
3231
|
const active = machine.display !== "idle" || machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt);
|
|
3138
3232
|
if (active) machines.set(key, machine);
|
|
3139
3233
|
else machines.delete(key);
|
|
@@ -3169,6 +3263,58 @@ function createDisplayEngine(ssr) {
|
|
|
3169
3263
|
return engine;
|
|
3170
3264
|
}
|
|
3171
3265
|
|
|
3266
|
+
function buildErrorPathIndex(cells, blank) {
|
|
3267
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3268
|
+
for (const [key, cell] of cells) {
|
|
3269
|
+
if (cell.schema.length > 0 || cell.user.length > 0) keys.add(key);
|
|
3270
|
+
}
|
|
3271
|
+
for (const [key, list] of blank) {
|
|
3272
|
+
if (list.length > 0) keys.add(key);
|
|
3273
|
+
}
|
|
3274
|
+
if (keys.size === 0) return EMPTY_INDEX;
|
|
3275
|
+
const entries = [];
|
|
3276
|
+
for (const key of keys) {
|
|
3277
|
+
const segments = segmentsForPathKey(key);
|
|
3278
|
+
if (segments !== null) entries.push({ key, segments });
|
|
3279
|
+
}
|
|
3280
|
+
entries.sort(compareByKey);
|
|
3281
|
+
return entries;
|
|
3282
|
+
}
|
|
3283
|
+
const EMPTY_INDEX = Object.freeze([]);
|
|
3284
|
+
function compareByKey(a, b) {
|
|
3285
|
+
return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
|
|
3286
|
+
}
|
|
3287
|
+
function windowUnder(index, prefix) {
|
|
3288
|
+
if (prefix.length === 0 || index.length === 0) return index;
|
|
3289
|
+
const prefixKey = keyForSegments(prefix).key;
|
|
3290
|
+
const marker = `${prefixKey.slice(0, -1)},`;
|
|
3291
|
+
const start = lowerBound(index, marker);
|
|
3292
|
+
if (start >= index.length) return EMPTY_INDEX;
|
|
3293
|
+
let end = start;
|
|
3294
|
+
for (; end < index.length; end += 1) {
|
|
3295
|
+
const entry = index[end];
|
|
3296
|
+
if (entry === void 0 || entry.key > prefixKey) break;
|
|
3297
|
+
}
|
|
3298
|
+
return start === 0 && end === index.length ? index : index.slice(start, end);
|
|
3299
|
+
}
|
|
3300
|
+
function isSameWindow(a, b) {
|
|
3301
|
+
if (a.length !== b.length) return false;
|
|
3302
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
3303
|
+
if (a[i]?.key !== b[i]?.key) return false;
|
|
3304
|
+
}
|
|
3305
|
+
return true;
|
|
3306
|
+
}
|
|
3307
|
+
function lowerBound(index, target) {
|
|
3308
|
+
let lo = 0;
|
|
3309
|
+
let hi = index.length;
|
|
3310
|
+
while (lo < hi) {
|
|
3311
|
+
const mid = lo + hi >>> 1;
|
|
3312
|
+
if ((index[mid]?.key ?? target) < target) lo = mid + 1;
|
|
3313
|
+
else hi = mid;
|
|
3314
|
+
}
|
|
3315
|
+
return lo;
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3172
3318
|
function mergeSparseHydration(schemaDefaults, sparse, schema) {
|
|
3173
3319
|
return mergeDeep(schemaDefaults, sparse, [], schema);
|
|
3174
3320
|
}
|
|
@@ -3230,6 +3376,7 @@ async function runFactoryAndApply(st, factory) {
|
|
|
3230
3376
|
st.schema
|
|
3231
3377
|
);
|
|
3232
3378
|
st.applyFormReplacement(full, { hydration: true });
|
|
3379
|
+
st.adoptResolvedDefaults(value);
|
|
3233
3380
|
st.scheduleFieldValidation(
|
|
3234
3381
|
[],
|
|
3235
3382
|
true
|
|
@@ -3314,12 +3461,10 @@ function applyDuStubs(schema, data, options = {}) {
|
|
|
3314
3461
|
}
|
|
3315
3462
|
function walkDuStubs(schema, value, path, warned) {
|
|
3316
3463
|
if (value === null || value === void 0 || typeof value !== "object") return value;
|
|
3317
|
-
if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function") {
|
|
3318
|
-
return value;
|
|
3319
|
-
}
|
|
3320
3464
|
if (Array.isArray(value)) {
|
|
3321
3465
|
return value.map((item, i) => walkDuStubs(schema, item, [...path, i], warned));
|
|
3322
3466
|
}
|
|
3467
|
+
if (!isPlainRecord(value)) return value;
|
|
3323
3468
|
const rec = value;
|
|
3324
3469
|
const du = schema.getUnionDiscriminatorAtPath(path);
|
|
3325
3470
|
if (du !== void 0) {
|
|
@@ -3342,8 +3487,8 @@ function walkDuStubs(schema, value, path, warned) {
|
|
|
3342
3487
|
}
|
|
3343
3488
|
}
|
|
3344
3489
|
const out = {};
|
|
3345
|
-
for (const k of
|
|
3346
|
-
safeAssign(out, k, walkDuStubs(schema, rec
|
|
3490
|
+
for (const k of consumerKeys(rec)) {
|
|
3491
|
+
safeAssign(out, k, walkDuStubs(schema, readConsumerProp(rec, k), [...path, k], warned));
|
|
3347
3492
|
}
|
|
3348
3493
|
return out;
|
|
3349
3494
|
}
|
|
@@ -3353,23 +3498,25 @@ function stripSymbolsDeep(value) {
|
|
|
3353
3498
|
let mutated2 = false;
|
|
3354
3499
|
const out2 = new Array(value.length);
|
|
3355
3500
|
for (let i = 0; i < value.length; i++) {
|
|
3356
|
-
const
|
|
3501
|
+
const original = readConsumerIndex(value, i);
|
|
3502
|
+
const cleaned = stripSymbolsDeep(original);
|
|
3357
3503
|
out2[i] = cleaned;
|
|
3358
|
-
if (cleaned !==
|
|
3504
|
+
if (cleaned !== original) mutated2 = true;
|
|
3359
3505
|
}
|
|
3360
3506
|
return mutated2 ? out2 : value;
|
|
3361
3507
|
}
|
|
3362
3508
|
const proto = Object.getPrototypeOf(value);
|
|
3363
3509
|
if (proto !== Object.prototype && proto !== null) return value;
|
|
3364
|
-
const symKeys =
|
|
3365
|
-
const stringKeys =
|
|
3510
|
+
const symKeys = consumerSymbolKeys(value);
|
|
3511
|
+
const stringKeys = consumerKeys(value);
|
|
3366
3512
|
let mutated = symKeys.length > 0;
|
|
3367
3513
|
const out = {};
|
|
3368
3514
|
const src = value;
|
|
3369
3515
|
for (const k of stringKeys) {
|
|
3370
|
-
const
|
|
3516
|
+
const original = readConsumerProp(src, k);
|
|
3517
|
+
const cleaned = stripSymbolsDeep(original);
|
|
3371
3518
|
out[k] = cleaned;
|
|
3372
|
-
if (cleaned !==
|
|
3519
|
+
if (cleaned !== original) mutated = true;
|
|
3373
3520
|
}
|
|
3374
3521
|
return mutated ? out : value;
|
|
3375
3522
|
}
|
|
@@ -3394,16 +3541,15 @@ function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out)
|
|
|
3394
3541
|
out.add(canonicalizePath(prefix).key);
|
|
3395
3542
|
}
|
|
3396
3543
|
}
|
|
3397
|
-
function computeBaselineResponse(schema,
|
|
3544
|
+
function computeBaselineResponse(schema, source) {
|
|
3398
3545
|
const completed = source === void 0 ? void 0 : mergeStructural(schema, [], source);
|
|
3399
3546
|
return schema.getDefaultValues({
|
|
3400
3547
|
useDefaultSchemaValues: true,
|
|
3401
|
-
constraints: completed
|
|
3402
|
-
strict
|
|
3548
|
+
constraints: completed
|
|
3403
3549
|
});
|
|
3404
3550
|
}
|
|
3405
|
-
function initialFirstValidationGate(schema
|
|
3406
|
-
return
|
|
3551
|
+
function initialFirstValidationGate(schema) {
|
|
3552
|
+
return schema.needsAsyncValidation?.() !== true;
|
|
3407
3553
|
}
|
|
3408
3554
|
function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
|
|
3409
3555
|
st.originals.clear();
|
|
@@ -3415,7 +3561,7 @@ function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
|
|
|
3415
3561
|
});
|
|
3416
3562
|
}
|
|
3417
3563
|
function queueInitialAsyncValidation(st) {
|
|
3418
|
-
if (!st.ssr && st.
|
|
3564
|
+
if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
|
|
3419
3565
|
queueMicrotask(() => scheduleFieldValidation(
|
|
3420
3566
|
st,
|
|
3421
3567
|
[],
|
|
@@ -3457,10 +3603,6 @@ function ensurePathOrdinal(st, key) {
|
|
|
3457
3603
|
}
|
|
3458
3604
|
return ordinal;
|
|
3459
3605
|
}
|
|
3460
|
-
function pathHasAsyncValidation(st, path) {
|
|
3461
|
-
const { key } = canonicalizePath(path);
|
|
3462
|
-
return pathHasAsyncValidationByKey(st, key, path);
|
|
3463
|
-
}
|
|
3464
3606
|
function pathHasAsyncValidationByKey(st, key, segments) {
|
|
3465
3607
|
const cached = st.pathAsyncCache.get(key);
|
|
3466
3608
|
if (cached !== void 0) return cached;
|
|
@@ -3603,10 +3745,15 @@ function commitWritePatches(st, patches, meta) {
|
|
|
3603
3745
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3604
3746
|
for (const patch of patches) {
|
|
3605
3747
|
const { key } = canonicalizePath(patch.path);
|
|
3606
|
-
if (
|
|
3748
|
+
if (!st.originals.has(key)) {
|
|
3607
3749
|
st.originals.set(key, { segments: patch.path, value: void 0 });
|
|
3608
3750
|
}
|
|
3609
3751
|
touchFieldRecord(st, key, patch.path, { updatedAt: now });
|
|
3752
|
+
st.pathSweep.track(patch.path, key);
|
|
3753
|
+
for (let i = 1; i < patch.path.length; i++) {
|
|
3754
|
+
const ancestor = patch.path.slice(0, i);
|
|
3755
|
+
st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
|
|
3756
|
+
}
|
|
3610
3757
|
}
|
|
3611
3758
|
for (const listener of st.formChangeListeners) {
|
|
3612
3759
|
try {
|
|
@@ -3817,10 +3964,7 @@ function setValueAtPath(st, path, value, meta) {
|
|
|
3817
3964
|
if (newlyAuthored && st.schema.isPreprocessOrCoerceLeaf(path)) {
|
|
3818
3965
|
const modeForAuthoringTransition = meta?.instance?.validateOn ?? st.fieldValidationMode;
|
|
3819
3966
|
if (modeForAuthoringTransition === "change") {
|
|
3820
|
-
scheduleFieldValidation(st, path, false,
|
|
3821
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3822
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3823
|
-
});
|
|
3967
|
+
scheduleFieldValidation(st, path, false, meta?.instance);
|
|
3824
3968
|
}
|
|
3825
3969
|
}
|
|
3826
3970
|
return true;
|
|
@@ -3836,15 +3980,12 @@ function setValueAtPath(st, path, value, meta) {
|
|
|
3836
3980
|
st.arrayIdentity.realign(path);
|
|
3837
3981
|
} else if (isContainer(currentValue) && !isContainer(value)) {
|
|
3838
3982
|
if (subtreeHadRealBaseline(st, path, currentValue)) {
|
|
3839
|
-
st.removedSubtrees.add(
|
|
3983
|
+
st.removedSubtrees.add(pathKey);
|
|
3840
3984
|
}
|
|
3841
3985
|
}
|
|
3842
3986
|
const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
|
|
3843
3987
|
if (effectiveModeAfterWrite === "change") {
|
|
3844
|
-
scheduleFieldValidation(st, path, false,
|
|
3845
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3846
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3847
|
-
});
|
|
3988
|
+
scheduleFieldValidation(st, path, false, meta?.instance);
|
|
3848
3989
|
}
|
|
3849
3990
|
return true;
|
|
3850
3991
|
}
|
|
@@ -3905,12 +4046,11 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
|
|
|
3905
4046
|
path: [...parentPath, ...err.path]
|
|
3906
4047
|
}));
|
|
3907
4048
|
applySchemaErrorsForSubtree(st, parentPath, reStamped);
|
|
3908
|
-
const
|
|
3909
|
-
const prevValidation = st.fieldValidationState.get(parentKey2);
|
|
4049
|
+
const prevValidation = st.fieldValidationState.get(parentKey);
|
|
3910
4050
|
if (prevValidation !== void 0) {
|
|
3911
4051
|
if (prevValidation.timer !== null) clearTimeout(prevValidation.timer);
|
|
3912
4052
|
prevValidation.aborted = true;
|
|
3913
|
-
st.fieldValidationState.delete(
|
|
4053
|
+
st.fieldValidationState.delete(parentKey);
|
|
3914
4054
|
}
|
|
3915
4055
|
appliedSync = true;
|
|
3916
4056
|
}
|
|
@@ -3918,17 +4058,14 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
|
|
|
3918
4058
|
applyFormReplacement(st, nextForm, meta);
|
|
3919
4059
|
for (const k of newBlankPaths) st.blankPaths.add(k);
|
|
3920
4060
|
if (reshapeMode === "change" && !appliedSync) {
|
|
3921
|
-
scheduleFieldValidation(st, parentPath, false,
|
|
3922
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3923
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3924
|
-
});
|
|
4061
|
+
scheduleFieldValidation(st, parentPath, false, meta?.instance);
|
|
3925
4062
|
}
|
|
3926
4063
|
return true;
|
|
3927
4064
|
}
|
|
3928
|
-
function scheduleFieldValidation(st, path, immediate,
|
|
3929
|
-
const effectiveMode =
|
|
4065
|
+
function scheduleFieldValidation(st, path, immediate, instance) {
|
|
4066
|
+
const effectiveMode = instance?.validateOn ?? st.fieldValidationMode;
|
|
3930
4067
|
if (effectiveMode === "submit") return;
|
|
3931
|
-
const effectiveDebounce =
|
|
4068
|
+
const effectiveDebounce = instance?.debounceMs ?? st.fieldValidationDebounceMs;
|
|
3932
4069
|
const { key } = canonicalizePath(path);
|
|
3933
4070
|
const prev = st.fieldValidationState.get(key);
|
|
3934
4071
|
if (prev !== void 0) {
|
|
@@ -4202,10 +4339,7 @@ function markFocused(st, path, focused, meta) {
|
|
|
4202
4339
|
});
|
|
4203
4340
|
}
|
|
4204
4341
|
if (changed) {
|
|
4205
|
-
scheduleFieldValidation(st, path, true,
|
|
4206
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
4207
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
4208
|
-
});
|
|
4342
|
+
scheduleFieldValidation(st, path, true, meta?.instance);
|
|
4209
4343
|
}
|
|
4210
4344
|
}
|
|
4211
4345
|
}
|
|
@@ -4218,11 +4352,10 @@ function markInteracted(st, path) {
|
|
|
4218
4352
|
function touchAtPath(st, segments) {
|
|
4219
4353
|
const formValue = st.form.value;
|
|
4220
4354
|
let touchedAny = false;
|
|
4221
|
-
for (const [, entry] of st.originals) {
|
|
4355
|
+
for (const [leafKey, entry] of st.originals) {
|
|
4222
4356
|
if (!isPathPrefix(segments, entry.segments)) continue;
|
|
4223
4357
|
if (!hasAtPath(formValue, entry.segments)) continue;
|
|
4224
4358
|
touchedAny = true;
|
|
4225
|
-
const leafKey = canonicalizePath(entry.segments).key;
|
|
4226
4359
|
const current = st.fields.get(leafKey);
|
|
4227
4360
|
if (current?.touched === true) continue;
|
|
4228
4361
|
touchFieldRecord(st, leafKey, entry.segments, { touched: true });
|
|
@@ -4237,11 +4370,10 @@ function interactAtPath(st, segments) {
|
|
|
4237
4370
|
if (st.effectiveDisabled.value) return false;
|
|
4238
4371
|
const formValue = st.form.value;
|
|
4239
4372
|
let interactedAny = false;
|
|
4240
|
-
for (const [, entry] of st.originals) {
|
|
4373
|
+
for (const [leafKey, entry] of st.originals) {
|
|
4241
4374
|
if (!isPathPrefix(segments, entry.segments)) continue;
|
|
4242
4375
|
if (!hasAtPath(formValue, entry.segments)) continue;
|
|
4243
4376
|
interactedAny = true;
|
|
4244
|
-
const leafKey = canonicalizePath(entry.segments).key;
|
|
4245
4377
|
const current = st.fields.get(leafKey);
|
|
4246
4378
|
if (current?.touched === true && current.interacted === true && current.blurredAfterInteraction === true) {
|
|
4247
4379
|
continue;
|
|
@@ -4290,9 +4422,24 @@ function activate(st) {
|
|
|
4290
4422
|
if (factory === void 0) return Promise.resolve();
|
|
4291
4423
|
return fireFactory(st, factory);
|
|
4292
4424
|
}
|
|
4425
|
+
function adoptResolvedDefaults(st, value) {
|
|
4426
|
+
st.defaultValues = structuralSnapshot(
|
|
4427
|
+
mergeSparseHydration(
|
|
4428
|
+
st.defaultValues,
|
|
4429
|
+
value,
|
|
4430
|
+
st.schema
|
|
4431
|
+
)
|
|
4432
|
+
);
|
|
4433
|
+
seedOriginalsFromBaseline(st, computeBaselineResponse(st.schema, st.defaultValues).data, false);
|
|
4434
|
+
}
|
|
4293
4435
|
function reset(st, nextDefaultValues) {
|
|
4294
|
-
const resetSource = nextDefaultValues
|
|
4295
|
-
|
|
4436
|
+
const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
|
|
4437
|
+
st.defaultValues,
|
|
4438
|
+
nextDefaultValues,
|
|
4439
|
+
st.schema
|
|
4440
|
+
);
|
|
4441
|
+
st.defaultValues = structuralSnapshot(resetSource);
|
|
4442
|
+
const resetResponse = computeBaselineResponse(st.schema, resetSource);
|
|
4296
4443
|
const next = resetResponse.data;
|
|
4297
4444
|
rebuildAuthoredPaths(st, resetSource, next);
|
|
4298
4445
|
applyFormReplacement(st, next);
|
|
@@ -4300,25 +4447,23 @@ function reset(st, nextDefaultValues) {
|
|
|
4300
4447
|
st.removedSubtrees.clear();
|
|
4301
4448
|
seedOriginalsFromBaseline(st, next, false);
|
|
4302
4449
|
if (nextDefaultValues !== void 0) {
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4450
|
+
const mentioned = /* @__PURE__ */ new Set();
|
|
4451
|
+
walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
|
|
4452
|
+
for (const key of mentioned) st.originalBlankPaths.delete(key);
|
|
4453
|
+
}
|
|
4454
|
+
st.blankPaths.clear();
|
|
4455
|
+
for (const key of st.originalBlankPaths) {
|
|
4456
|
+
st.blankPaths.add(key);
|
|
4310
4457
|
}
|
|
4311
4458
|
st.errorCells.clear();
|
|
4312
|
-
if (
|
|
4459
|
+
if (!resetResponse.success) {
|
|
4313
4460
|
replaceErrorChannel(st, "schema", resetResponse.errors);
|
|
4314
4461
|
}
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
applySchemaErrorsForSubtree(st, [], syncResult.errors);
|
|
4319
|
-
}
|
|
4462
|
+
const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
|
|
4463
|
+
if (!(syncResult instanceof Promise) && !syncResult.success) {
|
|
4464
|
+
applySchemaErrorsForSubtree(st, [], syncResult.errors);
|
|
4320
4465
|
}
|
|
4321
|
-
st.firstValidationDone.value = initialFirstValidationGate(st.schema
|
|
4466
|
+
st.firstValidationDone.value = initialFirstValidationGate(st.schema);
|
|
4322
4467
|
queueInitialAsyncValidation(st);
|
|
4323
4468
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4324
4469
|
for (const [pathKey, record] of st.fields) {
|
|
@@ -4408,10 +4553,6 @@ function clearFieldRecordFlags(st, pathKey) {
|
|
|
4408
4553
|
if (record === void 0) return;
|
|
4409
4554
|
st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
|
|
4410
4555
|
}
|
|
4411
|
-
function isPristineAtPath(st, path) {
|
|
4412
|
-
const { key, segments } = canonicalizePath(path);
|
|
4413
|
-
return isPristineAtPathByKey(st, key, segments);
|
|
4414
|
-
}
|
|
4415
4556
|
function isPristineAtPathByKey(st, key, segments) {
|
|
4416
4557
|
if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
|
|
4417
4558
|
const entry = st.originals.get(key);
|
|
@@ -4445,12 +4586,8 @@ function getFieldRecord(st, path) {
|
|
|
4445
4586
|
const { key } = canonicalizePath(path);
|
|
4446
4587
|
return st.fields.get(key);
|
|
4447
4588
|
}
|
|
4448
|
-
function getOriginalAtPath(st, path) {
|
|
4449
|
-
const { key } = canonicalizePath(path);
|
|
4450
|
-
return st.originals.get(key)?.value;
|
|
4451
|
-
}
|
|
4452
4589
|
function createFormStore(options) {
|
|
4453
|
-
const { formKey, schema, defaultValues,
|
|
4590
|
+
const { formKey, schema, defaultValues, hydration } = options;
|
|
4454
4591
|
const ssr = options.ssr === true;
|
|
4455
4592
|
const ssrPrefetch = options.ssrPrefetch;
|
|
4456
4593
|
const rememberVariants = options.rememberVariants !== false;
|
|
@@ -4458,22 +4595,16 @@ function createFormStore(options) {
|
|
|
4458
4595
|
const fieldValidationDebounceMs = normalizeNumericOption({
|
|
4459
4596
|
value: options.debounceMs ?? DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS,
|
|
4460
4597
|
source: "useForm.debounceMs",
|
|
4461
|
-
allowInfinity: false,
|
|
4462
4598
|
min: 0,
|
|
4463
4599
|
defaultValue: DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS
|
|
4464
4600
|
});
|
|
4465
|
-
const
|
|
4466
|
-
const resolvedGetDisplayState = resolveGetDisplayState(options.getDisplayState);
|
|
4601
|
+
const coerceEnabled = resolveCoerceEnabled(options.coerce);
|
|
4467
4602
|
const cleanupHooks = [];
|
|
4468
4603
|
const modules = /* @__PURE__ */ new Map();
|
|
4469
4604
|
const fieldValidatingSince = reactive(/* @__PURE__ */ new Map());
|
|
4470
4605
|
const displayEngine = createDisplayEngine(ssr);
|
|
4471
4606
|
cleanupHooks.push(() => displayEngine.dispose());
|
|
4472
|
-
const schemaResponse = computeBaselineResponse(
|
|
4473
|
-
schema,
|
|
4474
|
-
strict,
|
|
4475
|
-
defaultValues
|
|
4476
|
-
);
|
|
4607
|
+
const schemaResponse = computeBaselineResponse(schema, defaultValues);
|
|
4477
4608
|
const schemaInitialData = schemaResponse.data;
|
|
4478
4609
|
const authoredPaths = /* @__PURE__ */ new Set();
|
|
4479
4610
|
const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
|
|
@@ -4486,16 +4617,15 @@ function createFormStore(options) {
|
|
|
4486
4617
|
const v = getAtPath(toRaw(form.value), arraySegs);
|
|
4487
4618
|
return Array.isArray(v) ? v.length : 0;
|
|
4488
4619
|
});
|
|
4489
|
-
const fields =
|
|
4620
|
+
const fields = shallowReactive(/* @__PURE__ */ new Map());
|
|
4490
4621
|
const domBinding = shallowRef(null);
|
|
4491
|
-
const errorCells =
|
|
4492
|
-
const originals =
|
|
4622
|
+
const errorCells = shallowReactive(/* @__PURE__ */ new Map());
|
|
4623
|
+
const originals = shallowReactive(/* @__PURE__ */ new Map());
|
|
4493
4624
|
const removedSubtrees = /* @__PURE__ */ new Set();
|
|
4494
|
-
const initialTransientList = hydration?.blankPaths ?? options.initialBlankPaths ?? [];
|
|
4495
4625
|
const blankPaths = reactive(/* @__PURE__ */ new Set());
|
|
4496
4626
|
const originalBlankPaths = /* @__PURE__ */ new Set();
|
|
4497
|
-
|
|
4498
|
-
|
|
4627
|
+
const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
|
|
4628
|
+
for (const key of seededBlankPaths) {
|
|
4499
4629
|
blankPaths.add(key);
|
|
4500
4630
|
originalBlankPaths.add(key);
|
|
4501
4631
|
}
|
|
@@ -4512,6 +4642,9 @@ function createFormStore(options) {
|
|
|
4512
4642
|
}
|
|
4513
4643
|
return result;
|
|
4514
4644
|
});
|
|
4645
|
+
const errorPathIndex = computed(
|
|
4646
|
+
() => buildErrorPathIndex(errorCells, derivedBlankErrors.value)
|
|
4647
|
+
);
|
|
4515
4648
|
const submitting = ref(false);
|
|
4516
4649
|
const activeSubmissions = ref(0);
|
|
4517
4650
|
const submissionAttempts = ref(0);
|
|
@@ -4544,7 +4677,7 @@ function createFormStore(options) {
|
|
|
4544
4677
|
const defaultsResolved = ref(false);
|
|
4545
4678
|
const activated = ref(false);
|
|
4546
4679
|
const activationPromise = ref(void 0);
|
|
4547
|
-
const firstValidationDone = ref(initialFirstValidationGate(schema
|
|
4680
|
+
const firstValidationDone = ref(initialFirstValidationGate(schema));
|
|
4548
4681
|
watch(activeValidations, (now, prev) => {
|
|
4549
4682
|
if (prev > 0 && now === 0) {
|
|
4550
4683
|
firstValidationDone.value = true;
|
|
@@ -4562,6 +4695,33 @@ function createFormStore(options) {
|
|
|
4562
4695
|
const activeTransforms = ref(0);
|
|
4563
4696
|
const transformRuns = /* @__PURE__ */ new Map();
|
|
4564
4697
|
const transformWaiters = [];
|
|
4698
|
+
const errorWindows = /* @__PURE__ */ new Map();
|
|
4699
|
+
const pathSweep = createDynamicPathSweep({
|
|
4700
|
+
onFormChange: (listener) => {
|
|
4701
|
+
formChangeListeners.add(listener);
|
|
4702
|
+
},
|
|
4703
|
+
isFixedObjectAtPath: (path) => schema.isFixedObjectAtPath(path)
|
|
4704
|
+
});
|
|
4705
|
+
pathSweep.onEvict((key) => {
|
|
4706
|
+
fields.delete(key);
|
|
4707
|
+
fieldValidationState.delete(key);
|
|
4708
|
+
authoredPaths.delete(key);
|
|
4709
|
+
if (originals.get(key)?.value === void 0) originals.delete(key);
|
|
4710
|
+
errorWindows.delete(key);
|
|
4711
|
+
});
|
|
4712
|
+
const errorWindowAt = (prefix, prefixKey) => {
|
|
4713
|
+
let cached = errorWindows.get(prefixKey);
|
|
4714
|
+
if (cached === void 0) {
|
|
4715
|
+
const frozen = [...prefix];
|
|
4716
|
+
cached = computed((prev) => {
|
|
4717
|
+
const next = windowUnder(errorPathIndex.value, frozen);
|
|
4718
|
+
return prev !== void 0 && isSameWindow(prev, next) ? prev : next;
|
|
4719
|
+
});
|
|
4720
|
+
errorWindows.set(prefixKey, cached);
|
|
4721
|
+
pathSweep.track(frozen, prefixKey);
|
|
4722
|
+
}
|
|
4723
|
+
return cached.value;
|
|
4724
|
+
};
|
|
4565
4725
|
const arrayBookkeeping = createArrayBookkeeping({
|
|
4566
4726
|
form,
|
|
4567
4727
|
fields,
|
|
@@ -4579,6 +4739,7 @@ function createFormStore(options) {
|
|
|
4579
4739
|
touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
|
|
4580
4740
|
decFieldValidation: (key) => decFieldValidation(st, key)
|
|
4581
4741
|
});
|
|
4742
|
+
const bind = (fn) => (...args) => fn(st, ...args);
|
|
4582
4743
|
const st = {
|
|
4583
4744
|
// --- public data (the FormStore contract's state members) ---
|
|
4584
4745
|
formKey,
|
|
@@ -4586,10 +4747,11 @@ function createFormStore(options) {
|
|
|
4586
4747
|
fields,
|
|
4587
4748
|
errorCells,
|
|
4588
4749
|
derivedBlankErrors,
|
|
4750
|
+
errorWindowAt,
|
|
4589
4751
|
originals,
|
|
4752
|
+
pathSweep,
|
|
4590
4753
|
schema,
|
|
4591
4754
|
ssr,
|
|
4592
|
-
getDisplayState: resolvedGetDisplayState,
|
|
4593
4755
|
submitting,
|
|
4594
4756
|
activeSubmissions,
|
|
4595
4757
|
submissionAttempts,
|
|
@@ -4617,12 +4779,20 @@ function createFormStore(options) {
|
|
|
4617
4779
|
displayEngine,
|
|
4618
4780
|
domBinding,
|
|
4619
4781
|
modules,
|
|
4620
|
-
|
|
4782
|
+
coerceEnabled,
|
|
4621
4783
|
blankPaths,
|
|
4622
4784
|
originalBlankPaths,
|
|
4623
4785
|
// --- kernel-internal state ---
|
|
4624
|
-
|
|
4625
|
-
|
|
4786
|
+
// Defensive copy, not a fix for an observed alias: today
|
|
4787
|
+
// `getDefaultValues` happens to build a fresh tree, so form storage
|
|
4788
|
+
// does not currently share structure with the consumer's object.
|
|
4789
|
+
// That is an adapter implementation detail rather than a contract,
|
|
4790
|
+
// and this field is now durable state that every `reset()` reads, so
|
|
4791
|
+
// it should not depend on it. The copy also means a consumer who
|
|
4792
|
+
// keeps a reference to the literal they passed cannot mutate the
|
|
4793
|
+
// form's defaults from outside. `reset()` snapshots for a harder
|
|
4794
|
+
// reason (see there) where an alias IS reachable.
|
|
4795
|
+
defaultValues: structuralSnapshot(defaultValues),
|
|
4626
4796
|
ssrPrefetch,
|
|
4627
4797
|
rememberVariants,
|
|
4628
4798
|
fieldValidationMode,
|
|
@@ -4649,16 +4819,20 @@ function createFormStore(options) {
|
|
|
4649
4819
|
transformTokenSeq: 0,
|
|
4650
4820
|
warnedDisabledWrite: false,
|
|
4651
4821
|
// --- methods: thin per-instance skins over the module kernel ---
|
|
4652
|
-
rehydrate: (
|
|
4653
|
-
activate: (
|
|
4654
|
-
|
|
4655
|
-
pathHasAsyncValidationByKey: (
|
|
4656
|
-
applyFormReplacement: (
|
|
4657
|
-
setValueAtPath: (
|
|
4658
|
-
getValueAtPath: (
|
|
4659
|
-
arrayElementKey: (
|
|
4660
|
-
reset: (
|
|
4661
|
-
resetField: (
|
|
4822
|
+
rehydrate: bind(rehydrate),
|
|
4823
|
+
activate: bind(activate),
|
|
4824
|
+
adoptResolvedDefaults: bind(adoptResolvedDefaults),
|
|
4825
|
+
pathHasAsyncValidationByKey: bind(pathHasAsyncValidationByKey),
|
|
4826
|
+
applyFormReplacement: bind(applyFormReplacement),
|
|
4827
|
+
setValueAtPath: bind(setValueAtPath),
|
|
4828
|
+
getValueAtPath: bind(getValueAtPath),
|
|
4829
|
+
arrayElementKey: bind(arrayElementKey),
|
|
4830
|
+
reset: bind(reset),
|
|
4831
|
+
resetField: bind(resetField),
|
|
4832
|
+
// The schema/user pair below reads as a fold waiting to happen. It was
|
|
4833
|
+
// tried: a `setErrorsForPathIn(channel)` factory measured 10 B LARGER,
|
|
4834
|
+
// because gzip had already collected the rent on two adjacent copies
|
|
4835
|
+
// and the helper added a name the original did not need.
|
|
4662
4836
|
setSchemaErrorsForPath: (path, entries) => setErrorChannelForKey(
|
|
4663
4837
|
st,
|
|
4664
4838
|
canonicalizePath(path).key,
|
|
@@ -4667,7 +4841,7 @@ function createFormStore(options) {
|
|
|
4667
4841
|
),
|
|
4668
4842
|
setAllSchemaErrors: (entries) => replaceErrorChannel(st, "schema", entries),
|
|
4669
4843
|
clearSchemaErrors: (path) => clearErrorChannel(st, "schema", path),
|
|
4670
|
-
applySchemaErrorsForSubtree: (
|
|
4844
|
+
applySchemaErrorsForSubtree: bind(applySchemaErrorsForSubtree),
|
|
4671
4845
|
setAllUserErrors: (entries) => replaceErrorChannel(st, "user", entries),
|
|
4672
4846
|
setUserErrorsForPath: (path, entries) => setErrorChannelForKey(
|
|
4673
4847
|
st,
|
|
@@ -4676,37 +4850,34 @@ function createFormStore(options) {
|
|
|
4676
4850
|
entries.length === 0 ? NO_ERRORS : [...entries]
|
|
4677
4851
|
),
|
|
4678
4852
|
clearUserErrors: (path) => clearErrorChannel(st, "user", path),
|
|
4679
|
-
restoreErrorCells: (
|
|
4680
|
-
getErrorsForPath: (
|
|
4681
|
-
ensurePathOrdinal: (
|
|
4682
|
-
noteDomConnected: (
|
|
4683
|
-
noteDomDisconnected: (
|
|
4684
|
-
markFocused: (
|
|
4685
|
-
markInteracted: (
|
|
4686
|
-
touchAtPath: (
|
|
4687
|
-
interactAtPath: (
|
|
4688
|
-
markConnectedOptimistically: (
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
emitSubmitSuccess: () => emitSubmitSuccess(st),
|
|
4708
|
-
registerCleanup: (fn) => registerCleanup(st, fn),
|
|
4709
|
-
dispose: () => dispose(st)
|
|
4853
|
+
restoreErrorCells: bind(restoreErrorCells),
|
|
4854
|
+
getErrorsForPath: bind(getErrorsForPath),
|
|
4855
|
+
ensurePathOrdinal: bind(ensurePathOrdinal),
|
|
4856
|
+
noteDomConnected: bind(noteDomConnected),
|
|
4857
|
+
noteDomDisconnected: bind(noteDomDisconnected),
|
|
4858
|
+
markFocused: bind(markFocused),
|
|
4859
|
+
markInteracted: bind(markInteracted),
|
|
4860
|
+
touchAtPath: bind(touchAtPath),
|
|
4861
|
+
interactAtPath: bind(interactAtPath),
|
|
4862
|
+
markConnectedOptimistically: bind(markConnectedOptimistically),
|
|
4863
|
+
isPristineAtPathByKey: bind(isPristineAtPathByKey),
|
|
4864
|
+
hasStructuralChangeUnder: bind(hasStructuralChangeUnder),
|
|
4865
|
+
hasRemovedSubtreeUnder: bind(hasRemovedSubtreeUnder),
|
|
4866
|
+
getFieldRecord: bind(getFieldRecord),
|
|
4867
|
+
cancelFieldValidation: bind(cancelFieldValidation),
|
|
4868
|
+
beginTransform: bind(beginTransform),
|
|
4869
|
+
isCurrentTransform: bind(isCurrentTransform),
|
|
4870
|
+
endTransform: bind(endTransform),
|
|
4871
|
+
setTransformError: bind(setTransformError),
|
|
4872
|
+
cancelTransformsUnder: bind(cancelTransformsUnder),
|
|
4873
|
+
settleTransforms: bind(settleTransforms),
|
|
4874
|
+
scheduleFieldValidation: bind(scheduleFieldValidation),
|
|
4875
|
+
onFormChange: bind(onFormChange),
|
|
4876
|
+
onSubmitSuccess: bind(onSubmitSuccess),
|
|
4877
|
+
onReset: bind(onReset),
|
|
4878
|
+
emitSubmitSuccess: bind(emitSubmitSuccess),
|
|
4879
|
+
registerCleanup: bind(registerCleanup),
|
|
4880
|
+
dispose: bind(dispose)
|
|
4710
4881
|
};
|
|
4711
4882
|
rebuildAuthoredPaths(st, defaultValues, schemaInitialData);
|
|
4712
4883
|
seedOriginalsFromBaseline(st, schemaInitialData, true);
|
|
@@ -4748,7 +4919,7 @@ function createFormStore(options) {
|
|
|
4748
4919
|
blurredAfterInteraction: false
|
|
4749
4920
|
});
|
|
4750
4921
|
});
|
|
4751
|
-
if (
|
|
4922
|
+
if (!schemaResponse.success) {
|
|
4752
4923
|
replaceErrorChannel(st, "schema", schemaResponse.errors);
|
|
4753
4924
|
}
|
|
4754
4925
|
}
|
|
@@ -4779,24 +4950,23 @@ function useAbstractForm(configuration, options) {
|
|
|
4779
4950
|
const resolvedDefaults = resolveTrichotomy(configuration.defaultValues);
|
|
4780
4951
|
const materialisedDefaults = resolvedDefaults.kind === "sync" ? resolvedDefaults.value : void 0;
|
|
4781
4952
|
const { defaultValues: _droppedDefaults, ...configWithoutDefaults } = configuration;
|
|
4782
|
-
const
|
|
4783
|
-
const merged = mergeWithDefaults(registry.defaults, trichotomyOverride);
|
|
4784
|
-
const maxRecursionDepth = normalizeNumericOption({
|
|
4785
|
-
value: merged.maxRecursionDepth ?? DEFAULT_MAX_RECURSION_DEPTH,
|
|
4786
|
-
source: "useForm.maxRecursionDepth",
|
|
4787
|
-
allowInfinity: true,
|
|
4788
|
-
min: 0,
|
|
4789
|
-
defaultValue: DEFAULT_MAX_RECURSION_DEPTH
|
|
4790
|
-
});
|
|
4791
|
-
const resolvedSchema = getComputedSchema(key, configuration.schema, { maxRecursionDepth });
|
|
4953
|
+
const materialisedConfiguration = materialisedDefaults === void 0 ? configWithoutDefaults : { ...configWithoutDefaults, defaultValues: materialisedDefaults };
|
|
4792
4954
|
const existing = registry.forms.get(key);
|
|
4955
|
+
const resolvedSchema = getComputedSchema(key, configuration.schema, {
|
|
4956
|
+
maxRecursionDepth: DEFAULT_MAX_RECURSION_DEPTH
|
|
4957
|
+
}) ;
|
|
4793
4958
|
if (existing !== void 0) {
|
|
4794
4959
|
void import('../chunks/dev-key-collision-warnings.mjs').then((m) => {
|
|
4795
4960
|
void m.warnOnSchemaFingerprintMismatch(key, existing.schema, resolvedSchema);
|
|
4796
4961
|
});
|
|
4797
4962
|
}
|
|
4798
4963
|
const hadPendingHydration = registry.pendingHydration.has(key);
|
|
4799
|
-
const state = existing ?? buildFreshState(
|
|
4964
|
+
const state = existing ?? buildFreshState(
|
|
4965
|
+
key,
|
|
4966
|
+
resolvedSchema,
|
|
4967
|
+
materialisedConfiguration,
|
|
4968
|
+
registry
|
|
4969
|
+
);
|
|
4800
4970
|
if (existing !== void 0) ; else if (resolvedDefaults.kind === "sync") {
|
|
4801
4971
|
state.defaultsResolved.value = true;
|
|
4802
4972
|
}
|
|
@@ -4804,6 +4974,7 @@ function useAbstractForm(configuration, options) {
|
|
|
4804
4974
|
const factory = resolvedDefaults.factory;
|
|
4805
4975
|
state.defaultValuesFactory.value = factory;
|
|
4806
4976
|
if (hadPendingHydration) {
|
|
4977
|
+
state.adoptResolvedDefaults(toRaw(state.form.value));
|
|
4807
4978
|
state.hydrating.value = false;
|
|
4808
4979
|
state.defaultsResolved.value = true;
|
|
4809
4980
|
} else if (registry.ssr) {
|
|
@@ -4820,8 +4991,8 @@ function useAbstractForm(configuration, options) {
|
|
|
4820
4991
|
const releaseConsumer = registry.trackConsumer(key);
|
|
4821
4992
|
onScopeDispose(releaseConsumer);
|
|
4822
4993
|
}
|
|
4823
|
-
if (existing === void 0 &&
|
|
4824
|
-
const historyModule =
|
|
4994
|
+
if (existing === void 0 && materialisedConfiguration.history !== void 0) {
|
|
4995
|
+
const historyModule = materialisedConfiguration.history.attach(state);
|
|
4825
4996
|
state.modules.set(HISTORY_MODULE_KEY, historyModule);
|
|
4826
4997
|
state.registerCleanup(() => historyModule.dispose());
|
|
4827
4998
|
}
|
|
@@ -4834,36 +5005,16 @@ function useAbstractForm(configuration, options) {
|
|
|
4834
5005
|
provide(kFormInstanceId, formInstanceId);
|
|
4835
5006
|
}
|
|
4836
5007
|
const apiOptions = pickDefined({
|
|
4837
|
-
|
|
5008
|
+
focusOnInvalidSubmit: materialisedConfiguration.focusOnInvalidSubmit,
|
|
4838
5009
|
history: state.modules.get(HISTORY_MODULE_KEY),
|
|
4839
|
-
validateOn:
|
|
4840
|
-
debounceMs:
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
rememberVariants: merged.rememberVariants,
|
|
4844
|
-
autoAria: merged.autoAria
|
|
5010
|
+
validateOn: materialisedConfiguration.validateOn,
|
|
5011
|
+
debounceMs: materialisedConfiguration.debounceMs,
|
|
5012
|
+
coerce: materialisedConfiguration.coerce,
|
|
5013
|
+
rememberVariants: materialisedConfiguration.rememberVariants
|
|
4845
5014
|
});
|
|
4846
5015
|
const api = buildFormApi(state, formInstanceId, apiOptions);
|
|
4847
5016
|
return api;
|
|
4848
5017
|
}
|
|
4849
|
-
function mergeWithDefaults(defaults, configuration) {
|
|
4850
|
-
return {
|
|
4851
|
-
...configuration,
|
|
4852
|
-
...pickDefined({
|
|
4853
|
-
strict: configuration.strict ?? defaults.strict,
|
|
4854
|
-
onInvalidSubmit: configuration.onInvalidSubmit ?? defaults.onInvalidSubmit,
|
|
4855
|
-
history: configuration.history ?? defaults.history,
|
|
4856
|
-
rememberVariants: configuration.rememberVariants ?? defaults.rememberVariants,
|
|
4857
|
-
disabled: configuration.disabled ?? defaults.disabled,
|
|
4858
|
-
coerce: configuration.coerce ?? defaults.coerce,
|
|
4859
|
-
validateOn: configuration.validateOn ?? defaults.validateOn,
|
|
4860
|
-
debounceMs: configuration.debounceMs ?? defaults.debounceMs,
|
|
4861
|
-
getDisplayState: configuration.getDisplayState ?? defaults.getDisplayState,
|
|
4862
|
-
maxRecursionDepth: configuration.maxRecursionDepth ?? defaults.maxRecursionDepth,
|
|
4863
|
-
autoAria: configuration.autoAria ?? defaults.autoAria
|
|
4864
|
-
})
|
|
4865
|
-
};
|
|
4866
|
-
}
|
|
4867
5018
|
const HISTORY_MODULE_KEY = "history";
|
|
4868
5019
|
function buildFreshState(key, schema, configuration, registry) {
|
|
4869
5020
|
const pending = registry.pendingHydration.get(key);
|
|
@@ -4883,13 +5034,11 @@ function buildFreshState(key, schema, configuration, registry) {
|
|
|
4883
5034
|
hydration: pending,
|
|
4884
5035
|
ssr: registry.ssr,
|
|
4885
5036
|
...pickDefined({
|
|
4886
|
-
strict: configuration.strict,
|
|
4887
5037
|
validateOn: configuration.validateOn,
|
|
4888
5038
|
debounceMs: configuration.debounceMs,
|
|
4889
5039
|
rememberVariants: configuration.rememberVariants,
|
|
4890
5040
|
disabled: configuration.disabled,
|
|
4891
5041
|
coerce: configuration.coerce,
|
|
4892
|
-
getDisplayState: configuration.getDisplayState,
|
|
4893
5042
|
initialBlankPaths
|
|
4894
5043
|
}),
|
|
4895
5044
|
// Server-only: bind the SSR prefetch coordination handles. `enqueue`
|
|
@@ -5032,12 +5181,13 @@ function makeRegisterValueProxy(capturedRegisterValue) {
|
|
|
5032
5181
|
get(_target, prop) {
|
|
5033
5182
|
if (prop === "__v_isRef") return true;
|
|
5034
5183
|
if (prop === "value") return capturedRegisterValue.value;
|
|
5184
|
+
if (prop === "isBound") return capturedRegisterValue.value !== void 0;
|
|
5035
5185
|
const v = capturedRegisterValue.value;
|
|
5036
5186
|
if (v === void 0) return void 0;
|
|
5037
5187
|
return Reflect.get(v, prop);
|
|
5038
5188
|
},
|
|
5039
5189
|
has(_target, prop) {
|
|
5040
|
-
if (prop === "__v_isRef" || prop === "value") return true;
|
|
5190
|
+
if (prop === "__v_isRef" || prop === "value" || prop === "isBound") return true;
|
|
5041
5191
|
const v = capturedRegisterValue.value;
|
|
5042
5192
|
if (v === void 0) return false;
|
|
5043
5193
|
return Reflect.has(v, prop);
|
|
@@ -5058,7 +5208,7 @@ function makeRegisterValueProxy(capturedRegisterValue) {
|
|
|
5058
5208
|
}
|
|
5059
5209
|
});
|
|
5060
5210
|
}
|
|
5061
|
-
function useRegister() {
|
|
5211
|
+
function useRegister(options) {
|
|
5062
5212
|
const instance = getCurrentInstance();
|
|
5063
5213
|
if (instance === null) {
|
|
5064
5214
|
warnOutsideSetup();
|
|
@@ -5098,7 +5248,7 @@ function useRegister() {
|
|
|
5098
5248
|
if (el !== null && el !== void 0 && typeof el === "object") {
|
|
5099
5249
|
el[REGISTER_OWNER_MARKER] = true;
|
|
5100
5250
|
}
|
|
5101
|
-
if (capturedRegisterValue.value === void 0) {
|
|
5251
|
+
if (capturedRegisterValue.value === void 0 && options?.optional !== true) {
|
|
5102
5252
|
warnNoParentRV(instance);
|
|
5103
5253
|
}
|
|
5104
5254
|
});
|
|
@@ -5118,7 +5268,7 @@ function warnNoParentRV(instance) {
|
|
|
5118
5268
|
warnedNoParentRV.add(instance);
|
|
5119
5269
|
const frame = captureUserCallSite();
|
|
5120
5270
|
console.warn(
|
|
5121
|
-
`[attaform] useRegister: no parent registerValue prop; RegisterValue fields will read as undefined. Pass v-register on the parent: \`<YourComponent v-register="form.register('field')"
|
|
5271
|
+
`[attaform] useRegister: no parent registerValue prop; RegisterValue fields will read as undefined. Pass v-register on the parent: \`<YourComponent v-register="form.register('field')" />\`. If this component is meant to work without a form too, say so with \`useRegister({ optional: true })\` and branch on \`rv?.isBound\`.` + (frame !== void 0 ? ` ${frame}` : "")
|
|
5122
5272
|
);
|
|
5123
5273
|
}
|
|
5124
5274
|
|
|
@@ -5202,38 +5352,36 @@ function createWizardHistory(param) {
|
|
|
5202
5352
|
};
|
|
5203
5353
|
}
|
|
5204
5354
|
|
|
5205
|
-
const NOOP_FINGERPRINT = "attaform:wizard-noop";
|
|
5206
5355
|
const EMPTY_SLIM_KINDS = /* @__PURE__ */ new Set();
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
errors: void 0,
|
|
5219
|
-
formKey
|
|
5220
|
-
};
|
|
5221
|
-
return {
|
|
5222
|
-
fingerprint: () => Promise.resolve(NOOP_FINGERPRINT),
|
|
5223
|
-
getDefaultValues: () => defaultsResponse,
|
|
5356
|
+
const EMPTY_VALUE = {};
|
|
5357
|
+
const NOOP_SUCCESS = {
|
|
5358
|
+
success: true,
|
|
5359
|
+
data: EMPTY_VALUE,
|
|
5360
|
+
errors: void 0
|
|
5361
|
+
};
|
|
5362
|
+
const NOOP_DEFAULTS = NOOP_SUCCESS;
|
|
5363
|
+
let NOOP_SCHEMA;
|
|
5364
|
+
function buildNoopWizardSchema() {
|
|
5365
|
+
NOOP_SCHEMA ?? (NOOP_SCHEMA = {
|
|
5366
|
+
getDefaultValues: () => NOOP_DEFAULTS,
|
|
5224
5367
|
getDefaultAtPath: () => void 0,
|
|
5225
5368
|
getEmptyValueAtPath: () => void 0,
|
|
5226
5369
|
isPreprocessOrCoerceLeaf: () => false,
|
|
5370
|
+
isOpaqueLeafAtPath: () => false,
|
|
5227
5371
|
arrayShapeAtPath: () => null,
|
|
5228
5372
|
isFixedObjectAtPath: (path) => path.length === 0,
|
|
5373
|
+
// The noop schema declares no shape at all, so nothing under it is
|
|
5374
|
+
// addressable, root included.
|
|
5375
|
+
entryKeyKindAtPath: () => void 0,
|
|
5229
5376
|
getSchemasAtPath: () => [],
|
|
5230
|
-
validateAtPath: () =>
|
|
5377
|
+
validateAtPath: () => NOOP_SUCCESS,
|
|
5231
5378
|
getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
|
|
5232
5379
|
isLeafAtPath: () => false,
|
|
5233
5380
|
isRequiredAtPath: () => false,
|
|
5234
5381
|
getUnionDiscriminatorAtPath: () => void 0,
|
|
5235
5382
|
hasDiscriminatedUnions: () => false
|
|
5236
|
-
};
|
|
5383
|
+
});
|
|
5384
|
+
return NOOP_SCHEMA;
|
|
5237
5385
|
}
|
|
5238
5386
|
|
|
5239
5387
|
function buildCallableReadonlySnapshotProxy(opts) {
|
|
@@ -5352,7 +5500,7 @@ function useWizard(options) {
|
|
|
5352
5500
|
if (typeof slot !== "string") continue;
|
|
5353
5501
|
if (noopForms.has(slot)) continue;
|
|
5354
5502
|
const noop = useAbstractForm({
|
|
5355
|
-
schema: buildNoopWizardSchema(
|
|
5503
|
+
schema: buildNoopWizardSchema(),
|
|
5356
5504
|
key: slot
|
|
5357
5505
|
});
|
|
5358
5506
|
noopForms.set(slot, noop);
|
|
@@ -5363,7 +5511,7 @@ function useWizard(options) {
|
|
|
5363
5511
|
const noop = lazyNoopScope.run(
|
|
5364
5512
|
() => useAbstractForm(
|
|
5365
5513
|
{
|
|
5366
|
-
schema: buildNoopWizardSchema(
|
|
5514
|
+
schema: buildNoopWizardSchema(),
|
|
5367
5515
|
key
|
|
5368
5516
|
},
|
|
5369
5517
|
{ registry }
|
|
@@ -6024,6 +6172,24 @@ function useWizard(options) {
|
|
|
6024
6172
|
const target = list[idx + 1];
|
|
6025
6173
|
moveTo(target.key);
|
|
6026
6174
|
}
|
|
6175
|
+
let cancelDeferredAdvance = null;
|
|
6176
|
+
function advanceWhenInFlightSubmitLands(store, key) {
|
|
6177
|
+
cancelDeferredAdvance?.();
|
|
6178
|
+
const attemptsAtRequest = store.submissionAttempts.value;
|
|
6179
|
+
const off = store.onSubmitSuccess(() => {
|
|
6180
|
+
off();
|
|
6181
|
+
cancelDeferredAdvance = null;
|
|
6182
|
+
if (store.submissionAttempts.value !== attemptsAtRequest) return;
|
|
6183
|
+
if (activeKey.value !== key) return;
|
|
6184
|
+
advanceOne();
|
|
6185
|
+
});
|
|
6186
|
+
cancelDeferredAdvance = off;
|
|
6187
|
+
}
|
|
6188
|
+
function inFlightActiveStore() {
|
|
6189
|
+
const store = registry.forms.get(activeKey.value);
|
|
6190
|
+
if (store === void 0 || store.activeSubmissions.value === 0) return void 0;
|
|
6191
|
+
return store;
|
|
6192
|
+
}
|
|
6027
6193
|
async function next() {
|
|
6028
6194
|
if (submitting.value) {
|
|
6029
6195
|
{
|
|
@@ -6050,7 +6216,12 @@ function useWizard(options) {
|
|
|
6050
6216
|
return;
|
|
6051
6217
|
}
|
|
6052
6218
|
const active = list[idx];
|
|
6053
|
-
if (active !== void 0 && active.isGate) {
|
|
6219
|
+
if (active !== void 0 && active.isGate && !clearedGates.has(active.key)) {
|
|
6220
|
+
const inFlight = inFlightActiveStore();
|
|
6221
|
+
if (inFlight !== void 0) {
|
|
6222
|
+
advanceWhenInFlightSubmitLands(inFlight, activeKey.value);
|
|
6223
|
+
return;
|
|
6224
|
+
}
|
|
6054
6225
|
await tryNext();
|
|
6055
6226
|
return;
|
|
6056
6227
|
}
|
|
@@ -6082,11 +6253,16 @@ function useWizard(options) {
|
|
|
6082
6253
|
const form = activeForm.value;
|
|
6083
6254
|
if (form === void 0) return false;
|
|
6084
6255
|
const before = activeKey.value;
|
|
6256
|
+
const inFlight = inFlightActiveStore();
|
|
6257
|
+
if (inFlight !== void 0) {
|
|
6258
|
+
advanceWhenInFlightSubmitLands(inFlight, before);
|
|
6259
|
+
return false;
|
|
6260
|
+
}
|
|
6085
6261
|
let ranClean = false;
|
|
6086
6262
|
await asHandleSubmitSource(form).handleSubmit(() => {
|
|
6087
6263
|
ranClean = true;
|
|
6088
6264
|
})();
|
|
6089
|
-
if (ranClean) advanceOne();
|
|
6265
|
+
if (ranClean && activeKey.value === before) advanceOne();
|
|
6090
6266
|
return activeKey.value !== before;
|
|
6091
6267
|
}
|
|
6092
6268
|
function back() {
|
|
@@ -6366,6 +6542,7 @@ function useWizard(options) {
|
|
|
6366
6542
|
onScopeDispose(() => {
|
|
6367
6543
|
historyHandle.dispose();
|
|
6368
6544
|
lazyNoopScope.stop();
|
|
6545
|
+
cancelDeferredAdvance?.();
|
|
6369
6546
|
});
|
|
6370
6547
|
}
|
|
6371
6548
|
const explicitKey = options.key;
|
|
@@ -6558,4 +6735,4 @@ function escapeForInlineScript(json) {
|
|
|
6558
6735
|
});
|
|
6559
6736
|
}
|
|
6560
6737
|
|
|
6561
|
-
export { AttaformErrorCode as A,
|
|
6738
|
+
export { AttaformErrorCode as A, injectWizard as a, isUnset as b, useAbstractForm as c, useRegister as d, escapeForInlineScript as e, useWizard as f, gate as g, getAtPath as h, injectForm as i, humanize as j, isPlainRecord as k, lazy as l, slimKindOf as s, unset as u };
|