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,9 +1,9 @@
|
|
|
1
|
-
import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope, nextTick } from 'vue';
|
|
2
|
-
import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.
|
|
3
|
-
import { c as armDomBinding } from './attaform.
|
|
1
|
+
import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope, nextTick } from 'vue';
|
|
2
|
+
import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.WiGdIqgx.mjs';
|
|
3
|
+
import { c as armDomBinding } from './attaform.B3resMQ1.mjs';
|
|
4
4
|
import { R as REGISTER_OWNER_MARKER, b as V_REGISTER_MARKER } from './attaform.KvlEedlF.mjs';
|
|
5
|
-
import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey,
|
|
6
|
-
import { i as isPathPrefix, e as canonicalizePath,
|
|
5
|
+
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.BRDDQeHV.mjs';
|
|
6
|
+
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.CdZIEf7_.mjs';
|
|
7
7
|
|
|
8
8
|
const AttaformErrorCode = {
|
|
9
9
|
/** A required field is in the blank set — user hasn't supplied a value. */
|
|
@@ -99,42 +99,32 @@ function earliestNonNull(a, b) {
|
|
|
99
99
|
return a < b ? a : b;
|
|
100
100
|
}
|
|
101
101
|
const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
|
|
102
|
+
const { showDelay, minVisible } = DEFAULT_TIMINGS;
|
|
102
103
|
const FOCUS_OUT_GRACE = 16;
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (prev.display === "pending") {
|
|
117
|
-
const shownAt = prev.pendingShownAt ?? now;
|
|
118
|
-
if (now < shownAt + minVisible)
|
|
119
|
-
return { display: "pending", pendingShownAt: shownAt, reviewAt: shownAt + minVisible };
|
|
120
|
-
}
|
|
121
|
-
return { display: verdict };
|
|
122
|
-
}
|
|
123
|
-
if (prev.display === "pending")
|
|
124
|
-
return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
|
|
125
|
-
const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
|
|
126
|
-
if (now - inFlightSince < window) {
|
|
127
|
-
return { display: prev.display, reviewAt: inFlightSince + window };
|
|
104
|
+
const defaultDisplayState = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
|
|
105
|
+
const verdict = computeVerdict(field, formMeta);
|
|
106
|
+
if (!isGateOpen(field, formMeta)) return { display: verdict };
|
|
107
|
+
const inFlightSince = earliestNonNull(validatingSince, transformingSince);
|
|
108
|
+
if (inFlightSince === null) {
|
|
109
|
+
if (prev.display === "pending") {
|
|
110
|
+
const shownAt = prev.pendingShownAt ?? now;
|
|
111
|
+
if (now < shownAt + minVisible)
|
|
112
|
+
return {
|
|
113
|
+
display: "pending",
|
|
114
|
+
pendingShownAt: shownAt,
|
|
115
|
+
reviewAt: shownAt + minVisible
|
|
116
|
+
};
|
|
128
117
|
}
|
|
129
|
-
return { display:
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
118
|
+
return { display: verdict };
|
|
119
|
+
}
|
|
120
|
+
if (prev.display === "pending")
|
|
121
|
+
return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
|
|
122
|
+
const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
|
|
123
|
+
if (now - inFlightSince < window) {
|
|
124
|
+
return { display: prev.display, reviewAt: inFlightSince + window };
|
|
125
|
+
}
|
|
126
|
+
return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
|
|
127
|
+
};
|
|
138
128
|
|
|
139
129
|
function hashStableString(input, seed = 0) {
|
|
140
130
|
let h1 = 3735928559 ^ seed;
|
|
@@ -187,6 +177,17 @@ function humanize(segment) {
|
|
|
187
177
|
}
|
|
188
178
|
|
|
189
179
|
const NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
|
|
180
|
+
function mapKeyForSegment(map, segment, declared) {
|
|
181
|
+
if (map.has(segment)) return segment;
|
|
182
|
+
if (typeof segment !== "number") return segment;
|
|
183
|
+
const asString = String(segment);
|
|
184
|
+
if (map.has(asString)) return asString;
|
|
185
|
+
return declared === "string" ? asString : segment;
|
|
186
|
+
}
|
|
187
|
+
function isRebuildableContainer(root, segment) {
|
|
188
|
+
if (root === null || root === void 0 || typeof root !== "object") return true;
|
|
189
|
+
return typeof segment === "number" ? Array.isArray(root) : isPlainRecord(root);
|
|
190
|
+
}
|
|
190
191
|
function descendStep(value, segment) {
|
|
191
192
|
if (value === null || value === void 0) return NOT_FOUND;
|
|
192
193
|
if (typeof value !== "object") return NOT_FOUND;
|
|
@@ -195,6 +196,11 @@ function descendStep(value, segment) {
|
|
|
195
196
|
if (!(segment in value)) return NOT_FOUND;
|
|
196
197
|
return value[segment];
|
|
197
198
|
}
|
|
199
|
+
if (value instanceof Map) {
|
|
200
|
+
const key2 = mapKeyForSegment(value, segment);
|
|
201
|
+
if (!value.has(key2)) return NOT_FOUND;
|
|
202
|
+
return value.get(key2);
|
|
203
|
+
}
|
|
198
204
|
const record = value;
|
|
199
205
|
const key = typeof segment === "number" ? String(segment) : segment;
|
|
200
206
|
if (isShadowedKey(key)) {
|
|
@@ -206,16 +212,27 @@ function descendStep(value, segment) {
|
|
|
206
212
|
}
|
|
207
213
|
function getAtPath(root, path) {
|
|
208
214
|
if (path.length === 0) return root;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
215
|
+
try {
|
|
216
|
+
let current = root;
|
|
217
|
+
for (const segment of path) {
|
|
218
|
+
const next = descendStep(current, segment);
|
|
219
|
+
if (next === NOT_FOUND) return void 0;
|
|
220
|
+
current = next;
|
|
221
|
+
}
|
|
222
|
+
return current;
|
|
223
|
+
} catch {
|
|
224
|
+
return void 0;
|
|
214
225
|
}
|
|
215
|
-
return current;
|
|
216
226
|
}
|
|
217
227
|
function hasAtPath(root, path) {
|
|
218
228
|
if (path.length === 0) return true;
|
|
229
|
+
try {
|
|
230
|
+
return hasAtPathUnguarded(root, path);
|
|
231
|
+
} catch {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function hasAtPathUnguarded(root, path) {
|
|
219
236
|
let current = root;
|
|
220
237
|
for (let i = 0; i < path.length - 1; i++) {
|
|
221
238
|
const segment = path[i];
|
|
@@ -227,11 +244,14 @@ function hasAtPath(root, path) {
|
|
|
227
244
|
if (current === null || current === void 0) return false;
|
|
228
245
|
if (typeof current !== "object") return false;
|
|
229
246
|
if (Array.isArray(current)) {
|
|
230
|
-
return typeof last === "number" && last
|
|
247
|
+
return typeof last === "number" && consumerHas(current, last);
|
|
248
|
+
}
|
|
249
|
+
if (current instanceof Map) {
|
|
250
|
+
return current.has(mapKeyForSegment(current, last));
|
|
231
251
|
}
|
|
232
252
|
const key = typeof last === "number" ? String(last) : last;
|
|
233
253
|
if (isShadowedKey(key)) return safeOwnHas(current, key);
|
|
234
|
-
return key
|
|
254
|
+
return consumerHas(current, key);
|
|
235
255
|
}
|
|
236
256
|
function isPlainRecord(value) {
|
|
237
257
|
if (value === null || typeof value !== "object") return false;
|
|
@@ -239,29 +259,30 @@ function isPlainRecord(value) {
|
|
|
239
259
|
const proto = Object.getPrototypeOf(value);
|
|
240
260
|
return proto === null || proto === Object.prototype;
|
|
241
261
|
}
|
|
262
|
+
const NO_SCHEMA_DEFAULTS = /* @__PURE__ */ new Set();
|
|
263
|
+
const NO_SCHEMA_FILL = {
|
|
264
|
+
getDefaultAtPath: () => void 0,
|
|
265
|
+
arrayShapeAtPath: () => null,
|
|
266
|
+
getSlimPrimitiveTypesAtPath: () => NO_SCHEMA_DEFAULTS,
|
|
267
|
+
entryKeyKindAtPath: () => void 0
|
|
268
|
+
};
|
|
242
269
|
function setAtPath(root, path, value) {
|
|
243
|
-
return
|
|
244
|
-
}
|
|
245
|
-
function setAtPathOffset(root, path, value, offset) {
|
|
246
|
-
if (offset >= path.length) return value;
|
|
247
|
-
const head = path[offset];
|
|
248
|
-
const nextOffset = offset + 1;
|
|
249
|
-
if (typeof head === "number") {
|
|
250
|
-
const arr = Array.isArray(root) ? [...root] : [];
|
|
251
|
-
while (arr.length <= head) arr.push(void 0);
|
|
252
|
-
arr[head] = setAtPathOffset(arr[head], path, value, nextOffset);
|
|
253
|
-
return arr;
|
|
254
|
-
}
|
|
255
|
-
const rec = isPlainRecord(root) ? { ...root } : {};
|
|
256
|
-
safeAssign(rec, head, setAtPathOffset(safeOwnRead(rec, head), path, value, nextOffset));
|
|
257
|
-
return rec;
|
|
270
|
+
return setAtPathWithSchemaFill(root, NO_SCHEMA_FILL, path, value);
|
|
258
271
|
}
|
|
259
272
|
const NO_IN_PLACE = { applied: false };
|
|
260
273
|
function tryInPlaceLeafWrite(root, path, value) {
|
|
261
274
|
if (path.length === 0) return NO_IN_PLACE;
|
|
275
|
+
try {
|
|
276
|
+
return descendAndWrite(root, path, value);
|
|
277
|
+
} catch {
|
|
278
|
+
return NO_IN_PLACE;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function descendAndWrite(root, path, value) {
|
|
262
282
|
let node = root;
|
|
263
283
|
for (let i = 0; i < path.length; i++) {
|
|
264
284
|
const seg = path[i];
|
|
285
|
+
if (node instanceof Map) return NO_IN_PLACE;
|
|
265
286
|
if (Array.isArray(node)) {
|
|
266
287
|
if (typeof seg !== "number" || seg < 0 || seg >= node.length) return NO_IN_PLACE;
|
|
267
288
|
} else if (isPlainRecord(node)) {
|
|
@@ -296,17 +317,40 @@ function mergeStructuralImpl(schema, scratch, consumer, defaultValue) {
|
|
|
296
317
|
if (Array.isArray(consumer)) {
|
|
297
318
|
return mergeStructuralArray(schema, scratch, consumer);
|
|
298
319
|
}
|
|
320
|
+
if (consumer instanceof Map) {
|
|
321
|
+
return mergeStructuralMap(schema, scratch, consumer);
|
|
322
|
+
}
|
|
299
323
|
if (isPlainRecord(consumer)) {
|
|
300
324
|
if (!isPlainRecord(defaultValue)) {
|
|
301
325
|
return consumer;
|
|
302
326
|
}
|
|
303
|
-
const out =
|
|
327
|
+
const out = spreadConsumerRecord(consumer);
|
|
304
328
|
const filledAny = fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out);
|
|
305
329
|
const recursedAny = recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out);
|
|
306
330
|
return filledAny || recursedAny ? out : consumer;
|
|
307
331
|
}
|
|
308
332
|
return consumer;
|
|
309
333
|
}
|
|
334
|
+
function mergeStructuralMap(schema, scratch, consumer) {
|
|
335
|
+
if (consumer.size === 0) return consumer;
|
|
336
|
+
let entryDefault;
|
|
337
|
+
let entryDefaultRead = false;
|
|
338
|
+
let out = null;
|
|
339
|
+
for (const [key, entry] of consumer) {
|
|
340
|
+
if (typeof key !== "string" && typeof key !== "number") continue;
|
|
341
|
+
scratch.push(key);
|
|
342
|
+
if (!entryDefaultRead) {
|
|
343
|
+
entryDefault = schema.getDefaultAtPath(scratch);
|
|
344
|
+
entryDefaultRead = true;
|
|
345
|
+
}
|
|
346
|
+
const merged = mergeStructuralImpl(schema, scratch, entry, entryDefault);
|
|
347
|
+
scratch.pop();
|
|
348
|
+
if (merged === entry) continue;
|
|
349
|
+
out ?? (out = new Map(consumer));
|
|
350
|
+
out.set(key, merged);
|
|
351
|
+
}
|
|
352
|
+
return out ?? consumer;
|
|
353
|
+
}
|
|
310
354
|
function mergeStructuralArray(schema, scratch, consumer) {
|
|
311
355
|
const shape = schema.arrayShapeAtPath(scratch);
|
|
312
356
|
const isTuple = typeof shape === "number";
|
|
@@ -314,7 +358,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
|
|
|
314
358
|
let cachedElementDefault;
|
|
315
359
|
let cachedElementDefaultRead = false;
|
|
316
360
|
let mutated = targetLen > consumer.length;
|
|
317
|
-
const out = consumer
|
|
361
|
+
const out = copyConsumerArray(consumer);
|
|
318
362
|
while (out.length < targetLen) out.push(void 0);
|
|
319
363
|
for (let i = 0; i < targetLen; i++) {
|
|
320
364
|
scratch.push(i);
|
|
@@ -328,7 +372,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
|
|
|
328
372
|
}
|
|
329
373
|
elemDefault = cachedElementDefault;
|
|
330
374
|
}
|
|
331
|
-
const consumerElem = i < consumer.length ? consumer
|
|
375
|
+
const consumerElem = i < consumer.length ? readConsumerIndex(consumer, i) : void 0;
|
|
332
376
|
const merged = mergeStructuralImpl(schema, scratch, consumerElem, elemDefault);
|
|
333
377
|
scratch.pop();
|
|
334
378
|
if (merged !== consumerElem) {
|
|
@@ -356,7 +400,7 @@ function fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out
|
|
|
356
400
|
}
|
|
357
401
|
function recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out) {
|
|
358
402
|
let mutated = false;
|
|
359
|
-
for (const key of
|
|
403
|
+
for (const key of consumerKeys(consumer)) {
|
|
360
404
|
const cVal = safeOwnRead(consumer, key);
|
|
361
405
|
if (cVal === void 0) continue;
|
|
362
406
|
scratch.push(key);
|
|
@@ -377,6 +421,21 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
377
421
|
if (startIdx >= fullPath.length) return value;
|
|
378
422
|
const head = fullPath[startIdx];
|
|
379
423
|
const isLeafStep = startIdx === fullPath.length - 1;
|
|
424
|
+
if (root instanceof Map) {
|
|
425
|
+
const next = new Map(root);
|
|
426
|
+
const key = mapKeyForSegment(root, head, schema.entryKeyKindAtPath(fullPath.slice(0, startIdx)));
|
|
427
|
+
if (isLeafStep) {
|
|
428
|
+
next.set(key, value);
|
|
429
|
+
return next;
|
|
430
|
+
}
|
|
431
|
+
let childRoot2 = next.get(key);
|
|
432
|
+
if (childRoot2 === void 0 || childRoot2 !== null && typeof childRoot2 !== "object") {
|
|
433
|
+
childRoot2 = schema.getDefaultAtPath(fullPath.slice(0, startIdx + 1));
|
|
434
|
+
}
|
|
435
|
+
next.set(key, setAtPathWithSchemaFillImpl(childRoot2, schema, fullPath, value, startIdx + 1));
|
|
436
|
+
return next;
|
|
437
|
+
}
|
|
438
|
+
if (!isRebuildableContainer(root, head)) return root;
|
|
380
439
|
if (typeof head === "number") {
|
|
381
440
|
const arr = Array.isArray(root) ? [...root] : [];
|
|
382
441
|
const prefix = fullPath.slice(0, startIdx);
|
|
@@ -414,10 +473,10 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
414
473
|
}
|
|
415
474
|
const rec = isPlainRecord(root) ? { ...root } : {};
|
|
416
475
|
if (isLeafStep) {
|
|
417
|
-
rec
|
|
476
|
+
safeAssign(rec, head, value);
|
|
418
477
|
return rec;
|
|
419
478
|
}
|
|
420
|
-
const existing = rec
|
|
479
|
+
const existing = safeOwnRead(rec, head);
|
|
421
480
|
let childRoot;
|
|
422
481
|
if (existing === void 0 || existing !== null && typeof existing !== "object") {
|
|
423
482
|
const intermPath = [...fullPath.slice(0, startIdx + 1)];
|
|
@@ -426,7 +485,11 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
|
|
|
426
485
|
} else {
|
|
427
486
|
childRoot = existing;
|
|
428
487
|
}
|
|
429
|
-
|
|
488
|
+
safeAssign(
|
|
489
|
+
rec,
|
|
490
|
+
head,
|
|
491
|
+
setAtPathWithSchemaFillImpl(childRoot, schema, fullPath, value, startIdx + 1)
|
|
492
|
+
);
|
|
430
493
|
return rec;
|
|
431
494
|
}
|
|
432
495
|
|
|
@@ -443,17 +506,18 @@ function isUnderStubAncestor(state, segments) {
|
|
|
443
506
|
}
|
|
444
507
|
return false;
|
|
445
508
|
}
|
|
446
|
-
function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase,
|
|
509
|
+
function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, sweep) {
|
|
447
510
|
const cache = /* @__PURE__ */ new Map();
|
|
448
|
-
|
|
511
|
+
sweep.onEvict((key) => cache.delete(key));
|
|
449
512
|
return function getFieldState(pathInput) {
|
|
450
513
|
const { segments, key } = canonicalizePath(pathInput);
|
|
451
514
|
const cached = cache.get(key);
|
|
452
515
|
if (cached !== void 0) return cached;
|
|
453
516
|
const c = computed(
|
|
454
|
-
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase
|
|
517
|
+
() => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) : buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase)
|
|
455
518
|
);
|
|
456
519
|
cache.set(key, c);
|
|
520
|
+
sweep.track(segments, key);
|
|
457
521
|
return c;
|
|
458
522
|
};
|
|
459
523
|
}
|
|
@@ -467,7 +531,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
467
531
|
const record = state.fields.get(key);
|
|
468
532
|
const value = state.getValueAtPath(segments);
|
|
469
533
|
const original = state.originals.get(key)?.value;
|
|
470
|
-
const pristine = state.
|
|
534
|
+
const pristine = state.isPristineAtPathByKey(key, segments);
|
|
471
535
|
const cell = state.errorCells.get(key);
|
|
472
536
|
const schemaForKey = cell !== void 0 && cell.schema.length > 0 ? cell.schema : void 0;
|
|
473
537
|
const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
|
|
@@ -479,7 +543,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
479
543
|
const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
|
|
480
544
|
const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
|
|
481
545
|
const transformError = state.transformErrors.get(key) ?? null;
|
|
482
|
-
const gated = state.
|
|
546
|
+
const gated = state.pathHasAsyncValidationByKey(key, segments) && !state.firstValidationDone.value;
|
|
483
547
|
const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
|
|
484
548
|
const valid = !gated && errors.length === 0 && !validating && !isOrphan;
|
|
485
549
|
const elementRecord = state.domBinding.value?.elements.get(key);
|
|
@@ -522,7 +586,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
522
586
|
meta: resolved.meta
|
|
523
587
|
};
|
|
524
588
|
}
|
|
525
|
-
function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase
|
|
589
|
+
function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
|
|
526
590
|
const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
|
|
527
591
|
const validatingSince = state.fieldValidatingSince.get(key) ?? null;
|
|
528
592
|
const transformingSince = state.fieldTransformingSince.get(key) ?? null;
|
|
@@ -535,15 +599,14 @@ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBa
|
|
|
535
599
|
transformingSince,
|
|
536
600
|
false,
|
|
537
601
|
// revealedDescendantError: leaves have no descendants
|
|
538
|
-
false
|
|
602
|
+
false
|
|
539
603
|
// isRoot: a leaf is never the form root
|
|
540
|
-
getDisplayState
|
|
541
604
|
);
|
|
542
605
|
}
|
|
543
606
|
function visitActiveLeafPaths(value, base, visit) {
|
|
544
607
|
if (Array.isArray(value)) {
|
|
545
608
|
for (let i = 0; i < value.length; i++) {
|
|
546
|
-
const child = value
|
|
609
|
+
const child = readConsumerIndex(value, i);
|
|
547
610
|
if (Array.isArray(child) || isPlainRecord(child)) {
|
|
548
611
|
visitActiveLeafPaths(child, [...base, i], visit);
|
|
549
612
|
} else {
|
|
@@ -553,8 +616,8 @@ function visitActiveLeafPaths(value, base, visit) {
|
|
|
553
616
|
return;
|
|
554
617
|
}
|
|
555
618
|
if (isPlainRecord(value)) {
|
|
556
|
-
for (const k of
|
|
557
|
-
const child = value
|
|
619
|
+
for (const k of consumerKeys(value)) {
|
|
620
|
+
const child = readConsumerProp(value, k);
|
|
558
621
|
if (Array.isArray(child) || isPlainRecord(child)) {
|
|
559
622
|
visitActiveLeafPaths(child, [...base, k], visit);
|
|
560
623
|
} else {
|
|
@@ -635,7 +698,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
635
698
|
pristine = false;
|
|
636
699
|
dirty = true;
|
|
637
700
|
}
|
|
638
|
-
const errors = aggregateErrorsAt(state, segments);
|
|
701
|
+
const errors = aggregateErrorsAt(state, segments, key);
|
|
639
702
|
const revealedDescendantError = errors.length > 0 && errors.some((e) => {
|
|
640
703
|
const ePath = e.path;
|
|
641
704
|
if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
|
|
@@ -643,7 +706,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
643
706
|
if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
|
|
644
707
|
return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
|
|
645
708
|
});
|
|
646
|
-
if (!asyncPending && state.
|
|
709
|
+
if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
|
|
647
710
|
if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
|
|
648
711
|
validating = true;
|
|
649
712
|
const since = state.fieldValidatingSince.get(key);
|
|
@@ -714,7 +777,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
714
777
|
revealedDescendantError
|
|
715
778
|
};
|
|
716
779
|
}
|
|
717
|
-
function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase
|
|
780
|
+
function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
|
|
718
781
|
const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
|
|
719
782
|
return decorateWithDerivedProps(
|
|
720
783
|
base,
|
|
@@ -724,14 +787,12 @@ function buildContainerFieldState(state, segments, key, formInstanceId, getFormM
|
|
|
724
787
|
validatingSince,
|
|
725
788
|
transformingSince,
|
|
726
789
|
revealedDescendantError,
|
|
727
|
-
segments.length === 0
|
|
728
|
-
getDisplayState
|
|
790
|
+
segments.length === 0
|
|
729
791
|
);
|
|
730
792
|
}
|
|
731
|
-
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot
|
|
793
|
+
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot) {
|
|
732
794
|
const firstError = base.errors[0];
|
|
733
795
|
const firstOwnError = base.ownErrors[0];
|
|
734
|
-
const predicate = getDisplayState ?? state.getDisplayState;
|
|
735
796
|
const formMeta = getFormMetaBase();
|
|
736
797
|
const ctx = {
|
|
737
798
|
field: base,
|
|
@@ -742,16 +803,9 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
|
|
|
742
803
|
// flight) so the reducer returns the plain verdict and hydration matches.
|
|
743
804
|
now: state.ssr ? 0 : Date.now()
|
|
744
805
|
};
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
machine = state.displayEngine.resolve(key, ctx, predicate);
|
|
749
|
-
} catch (err) {
|
|
750
|
-
machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
|
|
751
|
-
rollupApplies = true;
|
|
752
|
-
}
|
|
753
|
-
const submitValidating = rollupApplies && isRoot && state.submitting.value && state.activeValidations.value > 0;
|
|
754
|
-
const resolvedDisplayState = machine.display === "pending" || submitValidating ? "pending" : rollupApplies && revealedDescendantError ? "error" : machine.display;
|
|
806
|
+
const machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
|
|
807
|
+
const submitValidating = isRoot && state.submitting.value && state.activeValidations.value > 0;
|
|
808
|
+
const resolvedDisplayState = machine.display === "pending" || submitValidating ? "pending" : revealedDescendantError ? "error" : machine.display;
|
|
755
809
|
const displayState = base.disabled === true ? "idle" : resolvedDisplayState;
|
|
756
810
|
return {
|
|
757
811
|
...base,
|
|
@@ -764,26 +818,33 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
|
|
|
764
818
|
firstOwnError
|
|
765
819
|
};
|
|
766
820
|
}
|
|
767
|
-
function aggregateErrorsAt(state, prefix) {
|
|
821
|
+
function aggregateErrorsAt(state, prefix, prefixKey) {
|
|
822
|
+
const candidates = state.errorWindowAt(prefix, prefixKey);
|
|
823
|
+
if (candidates.length === 0) return [];
|
|
768
824
|
const formValue = state.form.value;
|
|
825
|
+
const cells = state.errorCells;
|
|
769
826
|
const buckets = /* @__PURE__ */ new Map();
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
827
|
+
for (const { key, segments } of candidates) {
|
|
828
|
+
if (!isPathPrefix(prefix, segments)) continue;
|
|
829
|
+
if (segments.length > 0 && !hasAtPath(formValue, segments)) continue;
|
|
830
|
+
const cell = cells.get(key);
|
|
831
|
+
const blankList = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
|
|
832
|
+
const schemaList = cell?.schema;
|
|
833
|
+
const userList = cell?.user;
|
|
834
|
+
const total = (schemaList?.length ?? 0) + (blankList?.length ?? 0) + (userList?.length ?? 0);
|
|
835
|
+
if (total === 0) continue;
|
|
836
|
+
const ordinal = state.ensurePathOrdinal(key);
|
|
837
|
+
let bucket = buckets.get(ordinal);
|
|
838
|
+
if (bucket === void 0) {
|
|
839
|
+
bucket = [];
|
|
840
|
+
buckets.set(ordinal, bucket);
|
|
841
|
+
}
|
|
842
|
+
if (schemaList !== void 0) bucket.push(...schemaList);
|
|
843
|
+
if (blankList !== void 0) bucket.push(...blankList);
|
|
844
|
+
if (userList !== void 0) bucket.push(...userList);
|
|
845
|
+
}
|
|
786
846
|
if (buckets.size === 0) return [];
|
|
847
|
+
if (buckets.size === 1) return [...buckets.values()][0];
|
|
787
848
|
return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
|
|
788
849
|
}
|
|
789
850
|
const EMPTY_ELEMENTS = Object.freeze([]);
|
|
@@ -796,6 +857,10 @@ function liveKeysAtPath(state, segments) {
|
|
|
796
857
|
for (let i = 0; i < value.length; i += 1) keys[i] = String(i);
|
|
797
858
|
return keys;
|
|
798
859
|
}
|
|
860
|
+
if (value instanceof Map) {
|
|
861
|
+
return mapSegmentKeys(value)?.map(String) ?? [];
|
|
862
|
+
}
|
|
863
|
+
if (value instanceof Set) return [];
|
|
799
864
|
if (typeof value === "object") return Object.keys(value);
|
|
800
865
|
return [];
|
|
801
866
|
}
|
|
@@ -806,6 +871,12 @@ function liveContainerHasKey(state, segments, key) {
|
|
|
806
871
|
const index = Number(key);
|
|
807
872
|
return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
|
|
808
873
|
}
|
|
874
|
+
if (value instanceof Map) {
|
|
875
|
+
if (value.has(key)) return true;
|
|
876
|
+
const index = Number(key);
|
|
877
|
+
return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
|
|
878
|
+
}
|
|
879
|
+
if (value instanceof Set) return false;
|
|
809
880
|
return Object.hasOwn(value, key);
|
|
810
881
|
}
|
|
811
882
|
function isArrayPath(state, segments) {
|
|
@@ -829,6 +900,7 @@ function makeReadonlyCoercion(snapshot) {
|
|
|
829
900
|
}
|
|
830
901
|
|
|
831
902
|
const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
|
|
903
|
+
const RELEASED = /* @__PURE__ */ Symbol();
|
|
832
904
|
const EMPTY_DESCENT = Object.freeze({});
|
|
833
905
|
function keyToSegment(key) {
|
|
834
906
|
return INTEGER_SEGMENT.test(key) ? Number(key) : key;
|
|
@@ -858,12 +930,18 @@ function callableInvokeShim(method, surface, getDescent) {
|
|
|
858
930
|
function buildTree(spec) {
|
|
859
931
|
const containerCache = /* @__PURE__ */ new Map();
|
|
860
932
|
const existsCache = /* @__PURE__ */ new Map();
|
|
933
|
+
spec.sweep.onEvict((key) => {
|
|
934
|
+
containerCache.delete(`${key}+A`);
|
|
935
|
+
containerCache.delete(`${key}+O`);
|
|
936
|
+
existsCache.delete(key);
|
|
937
|
+
});
|
|
861
938
|
function schemaHasPath(segs) {
|
|
862
|
-
const cacheKey =
|
|
939
|
+
const cacheKey = keyForSegments(segs).key;
|
|
863
940
|
const cached = existsCache.get(cacheKey);
|
|
864
941
|
if (cached !== void 0) return cached;
|
|
865
942
|
const result = spec.schema.getSlimPrimitiveTypesAtPath(segs).size > 0;
|
|
866
943
|
existsCache.set(cacheKey, result);
|
|
944
|
+
spec.sweep.track(segs, cacheKey);
|
|
867
945
|
return result;
|
|
868
946
|
}
|
|
869
947
|
function descend(segs) {
|
|
@@ -873,7 +951,8 @@ function buildTree(spec) {
|
|
|
873
951
|
}
|
|
874
952
|
function containerAt(segments) {
|
|
875
953
|
const isArrayLike = spec.isArrayAt(segments);
|
|
876
|
-
const
|
|
954
|
+
const pathKey = keyForSegments(segments).key;
|
|
955
|
+
const cacheKey = `${pathKey}+${isArrayLike ? "A" : "O"}`;
|
|
877
956
|
const existing = containerCache.get(cacheKey);
|
|
878
957
|
if (existing !== void 0) return existing;
|
|
879
958
|
const isFixedObject = spec.schema.isFixedObjectAtPath(segments);
|
|
@@ -963,46 +1042,42 @@ function buildTree(spec) {
|
|
|
963
1042
|
}
|
|
964
1043
|
});
|
|
965
1044
|
containerCache.set(cacheKey, proxy);
|
|
1045
|
+
spec.sweep.track(segments, pathKey);
|
|
966
1046
|
return proxy;
|
|
967
1047
|
}
|
|
968
1048
|
return containerAt([]);
|
|
969
1049
|
}
|
|
970
|
-
function buildErrorsSurface(state) {
|
|
1050
|
+
function buildErrorsSurface(state, sweep) {
|
|
971
1051
|
const treeCache = /* @__PURE__ */ new Map();
|
|
1052
|
+
sweep.onEvict((key) => treeCache.delete(key));
|
|
972
1053
|
const materialize = (segments) => {
|
|
973
|
-
const cacheKey =
|
|
1054
|
+
const cacheKey = keyForSegments(segments).key;
|
|
974
1055
|
let tree = treeCache.get(cacheKey);
|
|
975
1056
|
if (tree === void 0) {
|
|
976
1057
|
const frozen = [...segments];
|
|
977
1058
|
tree = computed(() => materializeErrors(state, frozen));
|
|
978
1059
|
treeCache.set(cacheKey, tree);
|
|
1060
|
+
sweep.track(segments, cacheKey);
|
|
979
1061
|
}
|
|
980
1062
|
return tree.value;
|
|
981
1063
|
};
|
|
982
1064
|
const resolveLeaf = (path) => {
|
|
983
1065
|
const isContainerSelfAccess = path.length > 1 && path[path.length - 1] === "";
|
|
984
|
-
const collectAtKey = (key2, active2, into) => {
|
|
985
|
-
const cell = state.errorCells.get(key2);
|
|
986
|
-
if (active2) {
|
|
987
|
-
const b = state.derivedBlankErrors.value.get(key2);
|
|
988
|
-
if (cell !== void 0) into.push(...cell.schema);
|
|
989
|
-
if (b !== void 0) into.push(...b);
|
|
990
|
-
}
|
|
991
|
-
if (cell !== void 0) into.push(...cell.user);
|
|
992
|
-
};
|
|
993
1066
|
const merged = [];
|
|
994
1067
|
if (isContainerSelfAccess) {
|
|
995
1068
|
const containerPath = path.slice(0, -1);
|
|
996
|
-
const
|
|
997
|
-
const
|
|
1069
|
+
const container = canonicalizePath(containerPath);
|
|
1070
|
+
const literal = canonicalizePath(path);
|
|
998
1071
|
const active2 = hasAtPath(state.form.value, containerPath);
|
|
999
|
-
|
|
1000
|
-
if (
|
|
1072
|
+
collectErrorsAt(state, container.key, container.segments, active2, merged);
|
|
1073
|
+
if (literal.key !== container.key) {
|
|
1074
|
+
collectErrorsAt(state, literal.key, literal.segments, active2, merged);
|
|
1075
|
+
}
|
|
1001
1076
|
return merged;
|
|
1002
1077
|
}
|
|
1003
|
-
const { key } = canonicalizePath(path);
|
|
1078
|
+
const { key, segments } = canonicalizePath(path);
|
|
1004
1079
|
const active = hasAtPath(state.form.value, path);
|
|
1005
|
-
|
|
1080
|
+
collectErrorsAt(state, key, segments, active, merged);
|
|
1006
1081
|
return merged;
|
|
1007
1082
|
};
|
|
1008
1083
|
return buildTree({
|
|
@@ -1020,64 +1095,80 @@ function buildErrorsSurface(state) {
|
|
|
1020
1095
|
// `errors()` / `errors([])` / `errors(path)` are all the subtree
|
|
1021
1096
|
// aggregate — the same helper `meta.errors` reads, so the surfaces
|
|
1022
1097
|
// never drift.
|
|
1023
|
-
call: (path) => aggregateErrorsAt(state, path),
|
|
1024
|
-
surface: "form.errors"
|
|
1098
|
+
call: (path) => aggregateErrorsAt(state, path, keyForSegments(path).key),
|
|
1099
|
+
surface: "form.errors",
|
|
1100
|
+
sweep
|
|
1025
1101
|
});
|
|
1026
1102
|
}
|
|
1103
|
+
function collectErrorsAt(state, key, segments, active, into) {
|
|
1104
|
+
const cell = state.errorCells.get(key);
|
|
1105
|
+
if (active) {
|
|
1106
|
+
if (cell !== void 0) into.push(...cell.schema);
|
|
1107
|
+
if (state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments)) {
|
|
1108
|
+
into.push(makeBlankRequiredError(segments));
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (cell !== void 0) into.push(...cell.user);
|
|
1112
|
+
}
|
|
1027
1113
|
function errorAwareContainerKeys(state, segments) {
|
|
1028
1114
|
const keys = new Set(liveKeysAtPath(state, segments));
|
|
1029
1115
|
const formValue = state.form.value;
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1116
|
+
const errors = [];
|
|
1117
|
+
const found = [];
|
|
1118
|
+
for (const { key, segments: decoded } of state.errorWindowAt(
|
|
1119
|
+
segments,
|
|
1120
|
+
keyForSegments(segments).key
|
|
1121
|
+
)) {
|
|
1122
|
+
if (decoded.length <= segments.length) continue;
|
|
1123
|
+
if (!isPathPrefix(segments, decoded)) continue;
|
|
1124
|
+
errors.length = 0;
|
|
1125
|
+
collectErrorsAt(state, key, decoded, hasAtPath(formValue, decoded), errors);
|
|
1126
|
+
if (errors.length === 0) continue;
|
|
1127
|
+
const nextSeg = decoded[segments.length];
|
|
1128
|
+
found.push({
|
|
1129
|
+
childKey: typeof nextSeg === "number" ? String(nextSeg) : nextSeg,
|
|
1130
|
+
ordinal: state.ensurePathOrdinal(key)
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
found.sort((a, b) => a.ordinal - b.ordinal);
|
|
1134
|
+
for (const { childKey } of found) keys.add(childKey);
|
|
1045
1135
|
return [...keys];
|
|
1046
1136
|
}
|
|
1047
1137
|
function materializeErrors(state, containerSegments) {
|
|
1048
|
-
const
|
|
1138
|
+
const formValue = state.form.value;
|
|
1139
|
+
const liveContainer = getAtPath(formValue, containerSegments);
|
|
1049
1140
|
const tree = Array.isArray(liveContainer) ? [] : {};
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
for (let i = 0; i < containerSegments.length; i++) {
|
|
1061
|
-
if (fullPath[i] !== containerSegments[i]) continue entries;
|
|
1062
|
-
}
|
|
1063
|
-
if (applyActivePathFilter && !hasAtPath(state.form.value, fullPath)) continue;
|
|
1064
|
-
const relativePath = fullPath.slice(containerSegments.length);
|
|
1065
|
-
let placePath;
|
|
1066
|
-
if (relativePath.length === 0) {
|
|
1067
|
-
placePath = [""];
|
|
1068
|
-
} else if (state.schema.isLeafAtPath(fullPath)) {
|
|
1069
|
-
placePath = relativePath;
|
|
1070
|
-
} else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
|
|
1071
|
-
placePath = [...relativePath, ""];
|
|
1072
|
-
} else {
|
|
1073
|
-
placePath = relativePath;
|
|
1074
|
-
}
|
|
1075
|
-
placeAt(tree, placePath, errors);
|
|
1141
|
+
const placements = [];
|
|
1142
|
+
for (const { key, segments: fullPath } of state.errorWindowAt(
|
|
1143
|
+
containerSegments,
|
|
1144
|
+
keyForSegments(containerSegments).key
|
|
1145
|
+
)) {
|
|
1146
|
+
const isRoot = fullPath.length === 0;
|
|
1147
|
+
if (isRoot) {
|
|
1148
|
+
if (containerSegments.length !== 0) continue;
|
|
1149
|
+
} else if (!isPathPrefix(containerSegments, fullPath)) {
|
|
1150
|
+
continue;
|
|
1076
1151
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1152
|
+
const errors = [];
|
|
1153
|
+
collectErrorsAt(state, key, fullPath, isRoot || hasAtPath(formValue, fullPath), errors);
|
|
1154
|
+
if (errors.length === 0) continue;
|
|
1155
|
+
const relativePath = fullPath.slice(containerSegments.length);
|
|
1156
|
+
let placePath;
|
|
1157
|
+
if (isRoot) {
|
|
1158
|
+
placePath = [ROOT_PATH_KEY];
|
|
1159
|
+
} else if (relativePath.length === 0) {
|
|
1160
|
+
placePath = [""];
|
|
1161
|
+
} else if (state.schema.isLeafAtPath(fullPath)) {
|
|
1162
|
+
placePath = relativePath;
|
|
1163
|
+
} else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
|
|
1164
|
+
placePath = [...relativePath, ""];
|
|
1165
|
+
} else {
|
|
1166
|
+
placePath = relativePath;
|
|
1167
|
+
}
|
|
1168
|
+
placements.push({ placePath, errors, ordinal: state.ensurePathOrdinal(key) });
|
|
1169
|
+
}
|
|
1170
|
+
placements.sort((a, b) => a.ordinal - b.ordinal);
|
|
1171
|
+
for (const { placePath, errors } of placements) placeAt(tree, placePath, errors);
|
|
1081
1172
|
return tree;
|
|
1082
1173
|
}
|
|
1083
1174
|
function placeAt(tree, path, errors) {
|
|
@@ -1140,7 +1231,7 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1140
1231
|
"placeholder",
|
|
1141
1232
|
"meta"
|
|
1142
1233
|
]);
|
|
1143
|
-
function buildFieldsSurface(state, getFieldStateAt) {
|
|
1234
|
+
function buildFieldsSurface(state, getFieldStateAt, sweep) {
|
|
1144
1235
|
const snapshotAt = (segments) => {
|
|
1145
1236
|
const view = getFieldStateAt(segments).value;
|
|
1146
1237
|
const snapshot = {};
|
|
@@ -1148,8 +1239,9 @@ function buildFieldsSurface(state, getFieldStateAt) {
|
|
|
1148
1239
|
return snapshot;
|
|
1149
1240
|
};
|
|
1150
1241
|
const viewCache = /* @__PURE__ */ new Map();
|
|
1242
|
+
sweep.onEvict((key) => viewCache.delete(key));
|
|
1151
1243
|
function viewAt(segments) {
|
|
1152
|
-
const cacheKey =
|
|
1244
|
+
const cacheKey = keyForSegments(segments).key;
|
|
1153
1245
|
const existing = viewCache.get(cacheKey);
|
|
1154
1246
|
if (existing !== void 0) return existing;
|
|
1155
1247
|
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
|
|
@@ -1199,6 +1291,7 @@ function buildFieldsSurface(state, getFieldStateAt) {
|
|
|
1199
1291
|
}
|
|
1200
1292
|
});
|
|
1201
1293
|
viewCache.set(cacheKey, proxy);
|
|
1294
|
+
sweep.track(segments, cacheKey);
|
|
1202
1295
|
return proxy;
|
|
1203
1296
|
}
|
|
1204
1297
|
return buildTree({
|
|
@@ -1213,7 +1306,8 @@ function buildFieldsSurface(state, getFieldStateAt) {
|
|
|
1213
1306
|
// container's rollup); a path the schema doesn't have is a typo and
|
|
1214
1307
|
// reads `undefined`. The root (`fields()`) is always declared.
|
|
1215
1308
|
call: (path) => state.schema.getSlimPrimitiveTypesAtPath(path).size > 0 ? viewAt(path) : void 0,
|
|
1216
|
-
surface: "form.fields"
|
|
1309
|
+
surface: "form.fields",
|
|
1310
|
+
sweep
|
|
1217
1311
|
});
|
|
1218
1312
|
}
|
|
1219
1313
|
function materializeFields(state, containerSegments, snapshotAt) {
|
|
@@ -1247,18 +1341,34 @@ function materializeFormValue(node) {
|
|
|
1247
1341
|
}
|
|
1248
1342
|
return out;
|
|
1249
1343
|
}
|
|
1250
|
-
function buildValuesSurface(form) {
|
|
1344
|
+
function buildValuesSurface(form, onFormChange) {
|
|
1251
1345
|
const inner = computed(() => readonly(form.value));
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1346
|
+
let held = null;
|
|
1347
|
+
const snapshot = computed(() => {
|
|
1348
|
+
const box = { value: materializeFormValue(inner.value) };
|
|
1349
|
+
held = box;
|
|
1350
|
+
return box;
|
|
1351
|
+
});
|
|
1352
|
+
onFormChange(() => {
|
|
1353
|
+
if (held === null) return;
|
|
1354
|
+
held.value = RELEASED;
|
|
1355
|
+
held = null;
|
|
1356
|
+
});
|
|
1357
|
+
const readSnapshot = () => {
|
|
1358
|
+
const box = snapshot.value;
|
|
1359
|
+
return box.value === RELEASED ? materializeFormValue(inner.value) : box.value;
|
|
1360
|
+
};
|
|
1361
|
+
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(() => readSnapshot());
|
|
1255
1362
|
const target = (() => {
|
|
1256
1363
|
});
|
|
1257
1364
|
return new Proxy(target, {
|
|
1258
1365
|
apply(_, __, args) {
|
|
1259
1366
|
const arg = args[0];
|
|
1260
|
-
if (arg === void 0) return
|
|
1261
|
-
|
|
1367
|
+
if (arg === void 0) return readSnapshot();
|
|
1368
|
+
const segments = canonicalizePath(arg).segments;
|
|
1369
|
+
const node = getAtPath(inner.value, segments);
|
|
1370
|
+
if (node === null || typeof node !== "object") return node;
|
|
1371
|
+
return getAtPath(readSnapshot(), segments);
|
|
1262
1372
|
},
|
|
1263
1373
|
get(_, key) {
|
|
1264
1374
|
if (typeof key === "symbol") {
|
|
@@ -1540,9 +1650,12 @@ function cloneVariantSnapshot(value) {
|
|
|
1540
1650
|
for (let i = 0; i < raw.length; i++) out2[i] = cloneVariantSnapshot(raw[i]);
|
|
1541
1651
|
return out2;
|
|
1542
1652
|
}
|
|
1653
|
+
if (!isPlainRecord(raw)) return raw;
|
|
1543
1654
|
const src = raw;
|
|
1544
1655
|
const out = {};
|
|
1545
|
-
for (const k of
|
|
1656
|
+
for (const k of consumerKeys(src)) {
|
|
1657
|
+
safeAssign(out, k, cloneVariantSnapshot(readConsumerProp(src, k)));
|
|
1658
|
+
}
|
|
1546
1659
|
return out;
|
|
1547
1660
|
}
|
|
1548
1661
|
function createArrayBookkeeping(deps) {
|
|
@@ -1716,8 +1829,8 @@ function deriveSubmitErrors(err) {
|
|
|
1716
1829
|
messageless: true
|
|
1717
1830
|
};
|
|
1718
1831
|
}
|
|
1719
|
-
function buildProcessForm(state,
|
|
1720
|
-
const
|
|
1832
|
+
function buildProcessForm(state, options = {}) {
|
|
1833
|
+
const applyInvalidSubmit = options.applyInvalidSubmit;
|
|
1721
1834
|
function validate(pathInput) {
|
|
1722
1835
|
const result = ref({
|
|
1723
1836
|
pending: true,
|
|
@@ -1810,7 +1923,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1810
1923
|
};
|
|
1811
1924
|
}
|
|
1812
1925
|
async function runRefinementValidation(data, path) {
|
|
1813
|
-
return await state.schema.validateAtPath(data, path);
|
|
1926
|
+
return stampFormKey(await state.schema.validateAtPath(data, path), state.formKey);
|
|
1814
1927
|
}
|
|
1815
1928
|
function composeWithDerivedBlank(refinement, scope) {
|
|
1816
1929
|
const blankErrors = collectScopedBlankErrors(state, scope);
|
|
@@ -1856,7 +1969,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1856
1969
|
}
|
|
1857
1970
|
}
|
|
1858
1971
|
if (generationStillValid) {
|
|
1859
|
-
|
|
1972
|
+
applyInvalidSubmit?.();
|
|
1860
1973
|
}
|
|
1861
1974
|
if (onError !== void 0) {
|
|
1862
1975
|
try {
|
|
@@ -1873,7 +1986,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1873
1986
|
await onSubmit(merged.data);
|
|
1874
1987
|
if (hasUserErrorEntries(state)) {
|
|
1875
1988
|
if (state.submissionGeneration.value === genAtEntry) {
|
|
1876
|
-
|
|
1989
|
+
applyInvalidSubmit?.();
|
|
1877
1990
|
}
|
|
1878
1991
|
return;
|
|
1879
1992
|
}
|
|
@@ -1891,7 +2004,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1891
2004
|
if (segments === null) continue;
|
|
1892
2005
|
state.setUserErrorsForPath([...segments], bucket);
|
|
1893
2006
|
}
|
|
1894
|
-
|
|
2007
|
+
applyInvalidSubmit?.();
|
|
1895
2008
|
}
|
|
1896
2009
|
}
|
|
1897
2010
|
} finally {
|
|
@@ -1906,6 +2019,10 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1906
2019
|
};
|
|
1907
2020
|
return { validate, parse, handleSubmit };
|
|
1908
2021
|
}
|
|
2022
|
+
function stampFormKey(verdict, formKey) {
|
|
2023
|
+
if (verdict.success) return { ...verdict, formKey };
|
|
2024
|
+
return verdict.data === void 0 ? { data: void 0, errors: verdict.errors, success: false, formKey } : { data: verdict.data, errors: verdict.errors, success: false, formKey };
|
|
2025
|
+
}
|
|
1909
2026
|
function toSegments(pathInput) {
|
|
1910
2027
|
return canonicalizePath(pathInput).segments;
|
|
1911
2028
|
}
|
|
@@ -1939,21 +2056,6 @@ function collectScopedBlankErrors(state, scope) {
|
|
|
1939
2056
|
}
|
|
1940
2057
|
return errors;
|
|
1941
2058
|
}
|
|
1942
|
-
function applyInvalidSubmitPolicy(state, formInstanceId, policy) {
|
|
1943
|
-
if (policy === "none") return;
|
|
1944
|
-
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
1945
|
-
if (target === null) return;
|
|
1946
|
-
if (policy === "scroll-to-first-error") {
|
|
1947
|
-
target.element.scrollIntoView();
|
|
1948
|
-
return;
|
|
1949
|
-
}
|
|
1950
|
-
if (policy === "focus-first-error") {
|
|
1951
|
-
target.element.focus({ focusVisible: true });
|
|
1952
|
-
return;
|
|
1953
|
-
}
|
|
1954
|
-
target.element.scrollIntoView();
|
|
1955
|
-
target.element.focus({ preventScroll: true, focusVisible: true });
|
|
1956
|
-
}
|
|
1957
2059
|
|
|
1958
2060
|
function slimKindOf(value) {
|
|
1959
2061
|
if (value === null) return "null";
|
|
@@ -1999,15 +2101,16 @@ function walk(schema, store, path, value) {
|
|
|
1999
2101
|
if (!accepted.has(kind)) {
|
|
2000
2102
|
return false;
|
|
2001
2103
|
}
|
|
2104
|
+
if (schema.isOpaqueLeafAtPath(path)) return true;
|
|
2002
2105
|
if (Array.isArray(value)) {
|
|
2003
2106
|
for (let i = 0; i < value.length; i++) {
|
|
2004
|
-
if (!walk(schema, store, [...path, i], value
|
|
2107
|
+
if (!walk(schema, store, [...path, i], readConsumerIndex(value, i))) return false;
|
|
2005
2108
|
}
|
|
2006
2109
|
return true;
|
|
2007
2110
|
}
|
|
2008
2111
|
if (isPlainRecord(value)) {
|
|
2009
|
-
for (const key of
|
|
2010
|
-
if (!walk(schema, store, [...path, key], value
|
|
2112
|
+
for (const key of consumerKeys(value)) {
|
|
2113
|
+
if (!walk(schema, store, [...path, key], readConsumerProp(value, key))) {
|
|
2011
2114
|
return false;
|
|
2012
2115
|
}
|
|
2013
2116
|
}
|
|
@@ -2016,135 +2119,94 @@ function walk(schema, store, path, value) {
|
|
|
2016
2119
|
return true;
|
|
2017
2120
|
}
|
|
2018
2121
|
|
|
2019
|
-
function defineCoercion(entry) {
|
|
2020
|
-
return entry;
|
|
2021
|
-
}
|
|
2022
2122
|
const IDENTITY = (v) => v;
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
if (trimmed === "") return { coerced: false };
|
|
2031
|
-
const n = Number(trimmed);
|
|
2032
|
-
if (!Number.isFinite(n)) return { coerced: false };
|
|
2033
|
-
return { coerced: true, value: n };
|
|
2034
|
-
}
|
|
2035
|
-
}),
|
|
2036
|
-
defineCoercion({
|
|
2037
|
-
input: "string",
|
|
2038
|
-
output: "boolean",
|
|
2039
|
-
transform: (s) => {
|
|
2040
|
-
const normalized = s.trim().toLowerCase();
|
|
2041
|
-
if (normalized === "true") return { coerced: true, value: true };
|
|
2042
|
-
if (normalized === "false") return { coerced: true, value: false };
|
|
2043
|
-
return { coerced: false };
|
|
2044
|
-
}
|
|
2045
|
-
})
|
|
2046
|
-
];
|
|
2047
|
-
function resolveCoercionIndex(config) {
|
|
2048
|
-
if (config === false) return EMPTY_INDEX;
|
|
2049
|
-
const rules = config === void 0 || config === true ? defaultCoercionRules : config;
|
|
2050
|
-
return indexRules(rules);
|
|
2051
|
-
}
|
|
2052
|
-
function indexRules(rules) {
|
|
2053
|
-
const idx = /* @__PURE__ */ new Map();
|
|
2054
|
-
for (const entry of rules) {
|
|
2055
|
-
const candidate = entry;
|
|
2056
|
-
if (candidate === null || typeof candidate !== "object" || typeof candidate.transform !== "function") {
|
|
2057
|
-
continue;
|
|
2058
|
-
}
|
|
2059
|
-
const key = `${entry.input}->${entry.output}`;
|
|
2060
|
-
if (idx.has(key) && false) ;
|
|
2061
|
-
idx.set(key, entry);
|
|
2123
|
+
function resolveCoerceEnabled(config) {
|
|
2124
|
+
return config !== false;
|
|
2125
|
+
}
|
|
2126
|
+
function memberSlimTypes(schema, segments, accepted) {
|
|
2127
|
+
if (accepted.has("array")) return schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
|
|
2128
|
+
if (accepted.has("set")) {
|
|
2129
|
+
return schema.getSlimPrimitiveTypesAtPath([...segments, SET_MEMBER_SEGMENT]);
|
|
2062
2130
|
}
|
|
2063
|
-
return
|
|
2131
|
+
return void 0;
|
|
2064
2132
|
}
|
|
2065
|
-
function buildCoerceFn(schema, segments,
|
|
2066
|
-
if (
|
|
2067
|
-
if (index.size === 0) return IDENTITY;
|
|
2133
|
+
function buildCoerceFn(schema, segments, enabled) {
|
|
2134
|
+
if (!enabled) return IDENTITY;
|
|
2068
2135
|
const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
|
|
2069
|
-
const elementAccepted =
|
|
2070
|
-
return (value) => coerceValue(value, accepted, elementAccepted
|
|
2136
|
+
const elementAccepted = memberSlimTypes(schema, segments, accepted);
|
|
2137
|
+
return (value) => coerceValue(value, accepted, elementAccepted);
|
|
2071
2138
|
}
|
|
2072
|
-
function buildElementCoerceFn(schema, segments,
|
|
2073
|
-
if (
|
|
2074
|
-
if (index.size === 0) return void 0;
|
|
2139
|
+
function buildElementCoerceFn(schema, segments, enabled) {
|
|
2140
|
+
if (!enabled) return void 0;
|
|
2075
2141
|
const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
return (value) => coerceScalar(value, elementAccepted
|
|
2142
|
+
const elementAccepted = memberSlimTypes(schema, segments, accepted);
|
|
2143
|
+
if (elementAccepted === void 0) return void 0;
|
|
2144
|
+
return (value) => coerceScalar(value, elementAccepted);
|
|
2079
2145
|
}
|
|
2080
2146
|
function pickScalarTarget(accepted) {
|
|
2081
2147
|
if (accepted.has("string")) return null;
|
|
2082
2148
|
if (accepted.has("number")) return "number";
|
|
2083
2149
|
if (accepted.has("boolean")) return "boolean";
|
|
2084
|
-
if (accepted.has("bigint")) return "bigint";
|
|
2085
2150
|
return null;
|
|
2086
2151
|
}
|
|
2087
|
-
function
|
|
2152
|
+
function toNumber(source) {
|
|
2153
|
+
const trimmed = source.trim();
|
|
2154
|
+
if (trimmed === "") return source;
|
|
2155
|
+
const n = Number(trimmed);
|
|
2156
|
+
return Number.isFinite(n) ? n : source;
|
|
2157
|
+
}
|
|
2158
|
+
function toBoolean(source) {
|
|
2159
|
+
const normalized = source.trim().toLowerCase();
|
|
2160
|
+
if (normalized === "true") return true;
|
|
2161
|
+
if (normalized === "false") return false;
|
|
2162
|
+
return source;
|
|
2163
|
+
}
|
|
2164
|
+
function coerceScalar(value, accepted) {
|
|
2088
2165
|
if (accepted.size === 0) return value;
|
|
2089
2166
|
const sourceKind = slimKindOf(value);
|
|
2090
2167
|
if (accepted.has(sourceKind)) return value;
|
|
2168
|
+
if (sourceKind !== "string") return value;
|
|
2091
2169
|
const target = pickScalarTarget(accepted);
|
|
2092
|
-
if (target ===
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
let result;
|
|
2096
|
-
try {
|
|
2097
|
-
result = entry.transform(value);
|
|
2098
|
-
} catch (err) {
|
|
2099
|
-
return value;
|
|
2100
|
-
}
|
|
2101
|
-
if (!result.coerced) return value;
|
|
2102
|
-
const returnedKind = slimKindOf(result.value);
|
|
2103
|
-
if (returnedKind !== entry.output) {
|
|
2104
|
-
return value;
|
|
2105
|
-
}
|
|
2106
|
-
if (entry.output === "number" && !Number.isFinite(result.value)) {
|
|
2107
|
-
return value;
|
|
2108
|
-
}
|
|
2109
|
-
return result.value;
|
|
2170
|
+
if (target === "number") return toNumber(value);
|
|
2171
|
+
if (target === "boolean") return toBoolean(value);
|
|
2172
|
+
return value;
|
|
2110
2173
|
}
|
|
2111
|
-
function coerceArrayMembers(arr, elementAccepted
|
|
2174
|
+
function coerceArrayMembers(arr, elementAccepted) {
|
|
2112
2175
|
let changed = false;
|
|
2113
2176
|
const out = [];
|
|
2114
2177
|
for (const el of arr) {
|
|
2115
|
-
const next = coerceScalar(el, elementAccepted
|
|
2178
|
+
const next = coerceScalar(el, elementAccepted);
|
|
2116
2179
|
if (next !== el) changed = true;
|
|
2117
2180
|
out.push(next);
|
|
2118
2181
|
}
|
|
2119
2182
|
return changed ? out : arr;
|
|
2120
2183
|
}
|
|
2121
|
-
function coerceSetMembers(set, elementAccepted
|
|
2184
|
+
function coerceSetMembers(set, elementAccepted) {
|
|
2122
2185
|
let changed = false;
|
|
2123
2186
|
const out = [];
|
|
2124
2187
|
for (const el of set) {
|
|
2125
|
-
const next = coerceScalar(el, elementAccepted
|
|
2188
|
+
const next = coerceScalar(el, elementAccepted);
|
|
2126
2189
|
if (next !== el) changed = true;
|
|
2127
2190
|
out.push(next);
|
|
2128
2191
|
}
|
|
2129
2192
|
return changed ? new Set(out) : set;
|
|
2130
2193
|
}
|
|
2131
|
-
function coerceValue(value, accepted, elementAccepted
|
|
2194
|
+
function coerceValue(value, accepted, elementAccepted) {
|
|
2132
2195
|
if (Array.isArray(value)) {
|
|
2133
2196
|
if (!accepted.has("array") || elementAccepted === void 0) return value;
|
|
2134
|
-
return coerceArrayMembers(value, elementAccepted
|
|
2197
|
+
return coerceArrayMembers(value, elementAccepted);
|
|
2135
2198
|
}
|
|
2136
2199
|
if (value instanceof Set) {
|
|
2137
2200
|
if (!accepted.has("set") || elementAccepted === void 0) return value;
|
|
2138
|
-
return coerceSetMembers(value, elementAccepted
|
|
2201
|
+
return coerceSetMembers(value, elementAccepted);
|
|
2139
2202
|
}
|
|
2140
|
-
return coerceScalar(value, accepted
|
|
2203
|
+
return coerceScalar(value, accepted);
|
|
2141
2204
|
}
|
|
2142
2205
|
|
|
2143
2206
|
const EMPTY_TRANSFORMS = Object.freeze([]);
|
|
2144
2207
|
function buildRegister(state, formInstanceId, instanceConfig) {
|
|
2145
|
-
const
|
|
2208
|
+
const coerceEnabled = instanceConfig?.coerce !== void 0 ? resolveCoerceEnabled(instanceConfig.coerce) : state.coerceEnabled;
|
|
2146
2209
|
const instanceMeta = instanceConfig?.instanceMeta;
|
|
2147
|
-
const formAutoAria = instanceConfig?.autoAria ?? true;
|
|
2148
2210
|
const getDisplayStateAt = instanceConfig?.getDisplayStateAt;
|
|
2149
2211
|
const withInstanceMeta = (meta) => {
|
|
2150
2212
|
if (instanceMeta === void 0) return meta;
|
|
@@ -2184,16 +2246,15 @@ function buildRegister(state, formInstanceId, instanceConfig) {
|
|
|
2184
2246
|
const coerce = buildCoerceFn(
|
|
2185
2247
|
state.schema,
|
|
2186
2248
|
segments,
|
|
2187
|
-
|
|
2249
|
+
coerceEnabled
|
|
2188
2250
|
);
|
|
2189
2251
|
const coerceElement = buildElementCoerceFn(
|
|
2190
2252
|
state.schema,
|
|
2191
2253
|
segments,
|
|
2192
|
-
|
|
2254
|
+
coerceEnabled
|
|
2193
2255
|
);
|
|
2194
2256
|
const { aria } = computeFieldIdentity(formInstanceId, state.formKey, pathKey);
|
|
2195
2257
|
const isRequired = state.schema.isRequiredAtPath(segments);
|
|
2196
|
-
const ariaEnabled = options?.autoAria ?? formAutoAria;
|
|
2197
2258
|
const ariaDisplayState = getDisplayStateAt !== void 0 ? computed(() => getDisplayStateAt(segments)) : void 0;
|
|
2198
2259
|
const markBlank = () => state.setValueAtPath(segments, slimDefault, withInstanceMeta({ blank: true }));
|
|
2199
2260
|
const internalRv = {
|
|
@@ -2295,7 +2356,6 @@ function buildRegister(state, formInstanceId, instanceConfig) {
|
|
|
2295
2356
|
// --- Aria (internal; consumed by the directive) ---
|
|
2296
2357
|
aria,
|
|
2297
2358
|
isRequired,
|
|
2298
|
-
ariaEnabled,
|
|
2299
2359
|
...ariaDisplayState !== void 0 ? { ariaDisplayState } : {}
|
|
2300
2360
|
};
|
|
2301
2361
|
return shallowReadonly(internalRv);
|
|
@@ -2317,8 +2377,8 @@ function walkUnsetSentinels(values, schema) {
|
|
|
2317
2377
|
const cleaned = walkCore(values, [], schema, paths, true);
|
|
2318
2378
|
return { cleanedValues: cleaned, paths };
|
|
2319
2379
|
}
|
|
2320
|
-
function
|
|
2321
|
-
return value
|
|
2380
|
+
function isRecursable(value) {
|
|
2381
|
+
return Array.isArray(value) || isPlainRecord(value);
|
|
2322
2382
|
}
|
|
2323
2383
|
function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
2324
2384
|
if (isUnset(input)) {
|
|
@@ -2332,20 +2392,21 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
|
2332
2392
|
return input;
|
|
2333
2393
|
}
|
|
2334
2394
|
if (input === null) return null;
|
|
2335
|
-
if (
|
|
2395
|
+
if (!isRecursable(input)) return input;
|
|
2336
2396
|
if (Array.isArray(input)) {
|
|
2337
2397
|
const out = new Array(input.length);
|
|
2338
2398
|
let mutated = false;
|
|
2339
2399
|
for (let i = 0; i < input.length; i++) {
|
|
2340
|
-
const
|
|
2400
|
+
const original = readConsumerIndex(input, i);
|
|
2401
|
+
const walked = walkCore(original, [...segments, i], schema, paths, synthesizeSchemaKeys);
|
|
2341
2402
|
out[i] = walked;
|
|
2342
|
-
if (walked !==
|
|
2403
|
+
if (walked !== original) mutated = true;
|
|
2343
2404
|
}
|
|
2344
2405
|
return mutated ? out : input;
|
|
2345
2406
|
}
|
|
2346
2407
|
if (typeof input === "object") {
|
|
2347
2408
|
const obj = input;
|
|
2348
|
-
const inputKeys =
|
|
2409
|
+
const inputKeys = consumerKeys(obj);
|
|
2349
2410
|
let keys = inputKeys;
|
|
2350
2411
|
let mutated = false;
|
|
2351
2412
|
let inputKeysSet = null;
|
|
@@ -2353,7 +2414,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
|
2353
2414
|
inputKeysSet = new Set(inputKeys);
|
|
2354
2415
|
const allKeys = new Set(inputKeys);
|
|
2355
2416
|
const slim = schema.getDefaultAtPath(segments);
|
|
2356
|
-
if (
|
|
2417
|
+
if (isPlainRecord(slim)) {
|
|
2357
2418
|
for (const k of Object.keys(slim)) allKeys.add(k);
|
|
2358
2419
|
}
|
|
2359
2420
|
keys = allKeys;
|
|
@@ -2361,7 +2422,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
|
|
|
2361
2422
|
}
|
|
2362
2423
|
const out = {};
|
|
2363
2424
|
for (const key of keys) {
|
|
2364
|
-
const orig = obj
|
|
2425
|
+
const orig = readConsumerProp(obj, key);
|
|
2365
2426
|
if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
|
|
2366
2427
|
safeAssign(out, key, void 0);
|
|
2367
2428
|
mutated = true;
|
|
@@ -2382,22 +2443,12 @@ function walkUnspecified(slim, segments, paths) {
|
|
|
2382
2443
|
}
|
|
2383
2444
|
return slim;
|
|
2384
2445
|
}
|
|
2385
|
-
if (
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
if (slim !== null && typeof slim === "object") {
|
|
2390
|
-
const out = {};
|
|
2391
|
-
for (const key of Object.keys(slim)) {
|
|
2392
|
-
safeAssign(
|
|
2393
|
-
out,
|
|
2394
|
-
key,
|
|
2395
|
-
walkUnspecified(slim[key], [...segments, key], paths)
|
|
2396
|
-
);
|
|
2397
|
-
}
|
|
2398
|
-
return out;
|
|
2446
|
+
if (!isPlainRecord(slim)) return slim;
|
|
2447
|
+
const out = {};
|
|
2448
|
+
for (const key of Object.keys(slim)) {
|
|
2449
|
+
safeAssign(out, key, walkUnspecified(slim[key], [...segments, key], paths));
|
|
2399
2450
|
}
|
|
2400
|
-
return
|
|
2451
|
+
return out;
|
|
2401
2452
|
}
|
|
2402
2453
|
function substituteUnsetSentinels(value, prefix, schema) {
|
|
2403
2454
|
const paths = [];
|
|
@@ -2433,11 +2484,11 @@ function expandUnsetAt(segments, schema, paths) {
|
|
|
2433
2484
|
paths.push(canonicalizePath(segments).key);
|
|
2434
2485
|
return slim;
|
|
2435
2486
|
}
|
|
2436
|
-
if (
|
|
2487
|
+
if (Array.isArray(slim)) return slim;
|
|
2488
|
+
if (!isPlainRecord(slim)) {
|
|
2437
2489
|
paths.push(canonicalizePath(segments).key);
|
|
2438
2490
|
return slim;
|
|
2439
2491
|
}
|
|
2440
|
-
if (Array.isArray(slim)) return slim;
|
|
2441
2492
|
const result = {};
|
|
2442
2493
|
for (const key of Object.keys(slim)) {
|
|
2443
2494
|
result[key] = expandUnsetAt([...segments, key], schema, paths);
|
|
@@ -2447,14 +2498,14 @@ function expandUnsetAt(segments, schema, paths) {
|
|
|
2447
2498
|
function walkAuthoredFromConstraints(value, prefix, out) {
|
|
2448
2499
|
if (prefix.length > 0) out.add(canonicalizePath(prefix).key);
|
|
2449
2500
|
if (isPlainRecord(value)) {
|
|
2450
|
-
for (const k of
|
|
2451
|
-
walkAuthoredFromConstraints(value
|
|
2501
|
+
for (const k of consumerKeys(value)) {
|
|
2502
|
+
walkAuthoredFromConstraints(readConsumerProp(value, k), [...prefix, k], out);
|
|
2452
2503
|
}
|
|
2453
2504
|
return;
|
|
2454
2505
|
}
|
|
2455
2506
|
if (Array.isArray(value)) {
|
|
2456
2507
|
for (let i = 0; i < value.length; i++) {
|
|
2457
|
-
walkAuthoredFromConstraints(value
|
|
2508
|
+
walkAuthoredFromConstraints(readConsumerIndex(value, i), [...prefix, i], out);
|
|
2458
2509
|
}
|
|
2459
2510
|
}
|
|
2460
2511
|
}
|
|
@@ -2468,11 +2519,50 @@ const DERIVED_DISPLAY_KEYS = /* @__PURE__ */ new Set([
|
|
|
2468
2519
|
"firstError",
|
|
2469
2520
|
"firstOwnError"
|
|
2470
2521
|
]);
|
|
2471
|
-
const
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2522
|
+
const META_KEYS = [
|
|
2523
|
+
...FIELD_STATE_KEYS,
|
|
2524
|
+
"submitting",
|
|
2525
|
+
"submissionAttempts",
|
|
2526
|
+
"departAttempts",
|
|
2527
|
+
"submitError",
|
|
2528
|
+
"submitted",
|
|
2529
|
+
"instanceId",
|
|
2530
|
+
"errorCount"
|
|
2531
|
+
];
|
|
2532
|
+
const BASE_META_KEYS = META_KEYS.filter((k) => !DERIVED_DISPLAY_KEYS.has(k));
|
|
2533
|
+
let INERT_HISTORY;
|
|
2534
|
+
function inertHistory() {
|
|
2535
|
+
INERT_HISTORY ?? (INERT_HISTORY = readonly({
|
|
2536
|
+
undo: () => false,
|
|
2537
|
+
redo: () => false,
|
|
2538
|
+
clear: () => {
|
|
2539
|
+
},
|
|
2540
|
+
canUndo: false,
|
|
2541
|
+
canRedo: false,
|
|
2542
|
+
size: 0
|
|
2543
|
+
}));
|
|
2544
|
+
return INERT_HISTORY;
|
|
2545
|
+
}
|
|
2546
|
+
const denyWrite = () => false;
|
|
2547
|
+
function buildMetaProxy(keys, read) {
|
|
2548
|
+
const target = {};
|
|
2549
|
+
const owns = new Set(keys);
|
|
2550
|
+
return new Proxy(target, {
|
|
2551
|
+
get: (_, key) => owns.has(key) ? read(key) : Reflect.get(target, key),
|
|
2552
|
+
has: (_, key) => owns.has(key) || Reflect.has(target, key),
|
|
2553
|
+
// Safe to hand back the same array every time: the spec copies a
|
|
2554
|
+
// trap's key list before using it.
|
|
2555
|
+
ownKeys: () => keys,
|
|
2556
|
+
getOwnPropertyDescriptor(_, key) {
|
|
2557
|
+
if (!owns.has(key)) return Reflect.getOwnPropertyDescriptor(target, key);
|
|
2558
|
+
return { configurable: true, enumerable: true, value: read(key), writable: false };
|
|
2559
|
+
},
|
|
2560
|
+
// A getter with no setter throws on assignment under strict mode,
|
|
2561
|
+
// which every module here is. `false` keeps that.
|
|
2562
|
+
set: denyWrite,
|
|
2563
|
+
deleteProperty: denyWrite,
|
|
2564
|
+
defineProperty: denyWrite
|
|
2565
|
+
});
|
|
2476
2566
|
}
|
|
2477
2567
|
function buildFormApi(state, formInstanceId, options = {}) {
|
|
2478
2568
|
const instanceBag = pickDefined({
|
|
@@ -2499,32 +2589,26 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2499
2589
|
const rootBaseComputed = computed(
|
|
2500
2590
|
() => buildContainerFieldStateBase(state, ROOT_PATH, ROOT_PATH_KEY, formInstanceId).base
|
|
2501
2591
|
);
|
|
2502
|
-
const metaBase = {
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2592
|
+
const metaBase = buildMetaProxy(BASE_META_KEYS, (key) => {
|
|
2593
|
+
switch (key) {
|
|
2594
|
+
case "instanceId":
|
|
2595
|
+
return formInstanceId;
|
|
2596
|
+
case "errorCount":
|
|
2597
|
+
return rootBaseComputed.value.errors.length;
|
|
2598
|
+
case "submitting":
|
|
2599
|
+
return state.submitting.value;
|
|
2600
|
+
case "submissionAttempts":
|
|
2601
|
+
return state.submissionAttempts.value;
|
|
2602
|
+
case "departAttempts":
|
|
2603
|
+
return state.departAttempts.value;
|
|
2604
|
+
case "submitError":
|
|
2605
|
+
return state.submitError.value;
|
|
2606
|
+
case "submitted":
|
|
2607
|
+
return state.submitted.value;
|
|
2608
|
+
default:
|
|
2609
|
+
return rootBaseComputed.value[key];
|
|
2518
2610
|
}
|
|
2519
|
-
};
|
|
2520
|
-
for (const k of BASE_MIRROR_KEYS) {
|
|
2521
|
-
defineGetter(
|
|
2522
|
-
metaBase,
|
|
2523
|
-
k,
|
|
2524
|
-
() => rootBaseComputed.value[k]
|
|
2525
|
-
);
|
|
2526
|
-
}
|
|
2527
|
-
defineGetter(metaBase, "errorCount", () => rootBaseComputed.value.errors.length);
|
|
2611
|
+
});
|
|
2528
2612
|
const getFormMetaBase = () => {
|
|
2529
2613
|
void state.submitting.value;
|
|
2530
2614
|
void state.submissionAttempts.value;
|
|
@@ -2533,26 +2617,41 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2533
2617
|
void state.submitted.value;
|
|
2534
2618
|
return metaBase;
|
|
2535
2619
|
};
|
|
2536
|
-
const
|
|
2620
|
+
const pathSweep = state.pathSweep;
|
|
2537
2621
|
const getRootFieldStateAt = buildFieldStateAccessor(
|
|
2538
2622
|
state,
|
|
2539
2623
|
formInstanceId,
|
|
2540
2624
|
getFormMetaBase,
|
|
2541
|
-
|
|
2625
|
+
pathSweep
|
|
2542
2626
|
);
|
|
2543
2627
|
const getDisplayStateAt = (segments) => getRootFieldStateAt(segments).value.displayState;
|
|
2544
2628
|
const registerConfig = {
|
|
2545
|
-
...pickDefined({ instanceMeta, coerce: options.coerce
|
|
2629
|
+
...pickDefined({ instanceMeta, coerce: options.coerce }),
|
|
2546
2630
|
getDisplayStateAt
|
|
2547
2631
|
};
|
|
2548
2632
|
const register = buildRegister(state, formInstanceId, registerConfig);
|
|
2549
|
-
const
|
|
2550
|
-
|
|
2633
|
+
const focusFirstError = (options2) => {
|
|
2634
|
+
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2635
|
+
if (target === null) return false;
|
|
2636
|
+
target.element.focus({ focusVisible: true, ...options2 });
|
|
2637
|
+
return true;
|
|
2638
|
+
};
|
|
2639
|
+
const scrollToFirstError = (options2) => {
|
|
2640
|
+
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2641
|
+
if (target === null) return false;
|
|
2642
|
+
target.element.scrollIntoView(options2);
|
|
2643
|
+
return true;
|
|
2644
|
+
};
|
|
2645
|
+
const applyInvalidSubmitPolicyPublic = () => {
|
|
2646
|
+
if (options.focusOnInvalidSubmit !== false) focusFirstError();
|
|
2647
|
+
};
|
|
2551
2648
|
const {
|
|
2552
2649
|
validate: validateBuilt,
|
|
2553
2650
|
parse: parseBuilt,
|
|
2554
2651
|
handleSubmit
|
|
2555
|
-
} = buildProcessForm(state,
|
|
2652
|
+
} = buildProcessForm(state, {
|
|
2653
|
+
applyInvalidSubmit: applyInvalidSubmitPolicyPublic
|
|
2654
|
+
});
|
|
2556
2655
|
const validate = (pathInput) => validateBuilt(pathInput);
|
|
2557
2656
|
const parse = (arg1, arg2) => {
|
|
2558
2657
|
const isPathArg = typeof arg1 === "string" || Array.isArray(arg1);
|
|
@@ -2564,6 +2663,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2564
2663
|
const segments = canonicalizePath(pathInput).segments;
|
|
2565
2664
|
return computed(() => getAtPath(state.form.value, segments));
|
|
2566
2665
|
}
|
|
2666
|
+
function pathStoresFunctions(segments) {
|
|
2667
|
+
if (state.schema.isOpaqueLeafAtPath(segments)) return false;
|
|
2668
|
+
return state.schema.getSlimPrimitiveTypesAtPath(segments).has("function");
|
|
2669
|
+
}
|
|
2567
2670
|
function setValueImpl(pathOrValue, maybeValue) {
|
|
2568
2671
|
const argc = arguments.length;
|
|
2569
2672
|
const isPathForm = argc >= 2 && (typeof pathOrValue === "string" || Array.isArray(pathOrValue));
|
|
@@ -2616,7 +2719,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2616
2719
|
};
|
|
2617
2720
|
if (isUnset(maybeValue)) return writeUnsetAt();
|
|
2618
2721
|
let resolvedValue;
|
|
2619
|
-
if (typeof maybeValue === "function") {
|
|
2722
|
+
if (typeof maybeValue === "function" && !pathStoresFunctions(segments)) {
|
|
2620
2723
|
const current = state.getValueAtPath(segments);
|
|
2621
2724
|
const prev = current === void 0 ? state.schema.getDefaultAtPath(segments) : current;
|
|
2622
2725
|
resolvedValue = maybeValue(prev);
|
|
@@ -2634,7 +2737,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2634
2737
|
reMarkBlanksAfterSubstitution(walked.paths);
|
|
2635
2738
|
return true;
|
|
2636
2739
|
}
|
|
2637
|
-
const errorsProxy = buildErrorsSurface(state);
|
|
2740
|
+
const errorsProxy = buildErrorsSurface(state, pathSweep);
|
|
2638
2741
|
function flattenUserErrors() {
|
|
2639
2742
|
const all = [];
|
|
2640
2743
|
for (const cell of state.errorCells.values()) all.push(...cell.user);
|
|
@@ -2676,22 +2779,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2676
2779
|
() => state.firstValidationDone.value && state.errorCells.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
|
|
2677
2780
|
);
|
|
2678
2781
|
const history = options.history;
|
|
2679
|
-
const formHistory = readonly(
|
|
2782
|
+
const formHistory = history === void 0 ? inertHistory() : readonly(
|
|
2680
2783
|
reactive({
|
|
2681
|
-
undo: history
|
|
2682
|
-
redo: history
|
|
2683
|
-
clear: history
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
size: history?.historySize ?? computed(() => 0)
|
|
2784
|
+
undo: history.undo,
|
|
2785
|
+
redo: history.redo,
|
|
2786
|
+
clear: history.clear,
|
|
2787
|
+
canUndo: history.canUndo,
|
|
2788
|
+
canRedo: history.canRedo,
|
|
2789
|
+
size: history.historySize
|
|
2688
2790
|
})
|
|
2689
2791
|
);
|
|
2690
2792
|
const metaErrors = computed(
|
|
2691
|
-
() => aggregateErrorsAt(state, [])
|
|
2793
|
+
() => aggregateErrorsAt(state, [], ROOT_PATH_KEY)
|
|
2692
2794
|
);
|
|
2693
2795
|
const rootFieldState = getRootFieldStateAt([]);
|
|
2694
|
-
const
|
|
2796
|
+
const metaOwn = {
|
|
2695
2797
|
// Whole-form work signals compose the LIFECYCLE counters with the
|
|
2696
2798
|
// per-leaf rollup: a submit-time validate shows up as
|
|
2697
2799
|
// activeValidations, per-field debounced validators as
|
|
@@ -2720,21 +2822,19 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2720
2822
|
// identifier).
|
|
2721
2823
|
instanceId: formInstanceId
|
|
2722
2824
|
};
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
);
|
|
2729
|
-
}
|
|
2730
|
-
defineGetter(metaTarget, "errorCount", () => metaErrors.value.length);
|
|
2825
|
+
const metaTarget = buildMetaProxy(META_KEYS, (key) => {
|
|
2826
|
+
if (key === "errorCount") return metaErrors.value.length;
|
|
2827
|
+
if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
|
|
2828
|
+
return rootFieldState.value[key];
|
|
2829
|
+
});
|
|
2731
2830
|
const formMeta = readonly(reactive(metaTarget));
|
|
2732
2831
|
const reset = (nextDefaultValues) => {
|
|
2733
2832
|
if (nextDefaultValues === void 0) {
|
|
2734
2833
|
state.reset();
|
|
2735
2834
|
} else {
|
|
2736
|
-
const walked =
|
|
2835
|
+
const walked = substituteUnsetSentinels(
|
|
2737
2836
|
nextDefaultValues,
|
|
2837
|
+
[],
|
|
2738
2838
|
state.schema
|
|
2739
2839
|
);
|
|
2740
2840
|
state.reset(walked.cleanedValues);
|
|
@@ -2766,21 +2866,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2766
2866
|
} catch {
|
|
2767
2867
|
}
|
|
2768
2868
|
}
|
|
2769
|
-
const focusFirstError = (options2) => {
|
|
2770
|
-
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2771
|
-
if (target === null) return false;
|
|
2772
|
-
target.element.focus({ focusVisible: true, ...options2 });
|
|
2773
|
-
return true;
|
|
2774
|
-
};
|
|
2775
|
-
const scrollToFirstError = (options2) => {
|
|
2776
|
-
const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
|
|
2777
|
-
if (target === null) return false;
|
|
2778
|
-
target.element.scrollIntoView(options2);
|
|
2779
|
-
return true;
|
|
2780
|
-
};
|
|
2781
|
-
const applyInvalidSubmitPolicyPublic = (policy) => {
|
|
2782
|
-
applyInvalidSubmitPolicy(state, formInstanceId, policy ?? defaultInvalidSubmitPolicy);
|
|
2783
|
-
};
|
|
2784
2869
|
const fieldArrays = buildFieldArrayApi(state);
|
|
2785
2870
|
const blankPathsView = computed(() => {
|
|
2786
2871
|
const keys = /* @__PURE__ */ new Set();
|
|
@@ -2808,8 +2893,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2808
2893
|
};
|
|
2809
2894
|
return Object.freeze(view);
|
|
2810
2895
|
});
|
|
2811
|
-
const valuesProxy = buildValuesSurface(state.form);
|
|
2812
|
-
const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt);
|
|
2896
|
+
const valuesProxy = buildValuesSurface(state.form, state.onFormChange);
|
|
2897
|
+
const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt, pathSweep);
|
|
2813
2898
|
const needsLazyGate = state.defaultValuesFactory.value !== void 0 || state.hasSsrPrefetch;
|
|
2814
2899
|
function gated(fn) {
|
|
2815
2900
|
if (!needsLazyGate) return fn;
|
|
@@ -2928,8 +3013,53 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2928
3013
|
return api;
|
|
2929
3014
|
}
|
|
2930
3015
|
|
|
3016
|
+
const SWEEP_SLICE = 8;
|
|
3017
|
+
function createDynamicPathSweep(deps) {
|
|
3018
|
+
const dynamicKeys = /* @__PURE__ */ new Set();
|
|
3019
|
+
const evictors = [];
|
|
3020
|
+
const isDynamicPath = (segments) => {
|
|
3021
|
+
for (let i = 0; i < segments.length; i++) {
|
|
3022
|
+
if (typeof segments[i] === "number") return true;
|
|
3023
|
+
if (!deps.isFixedObjectAtPath(segments.slice(0, i))) return true;
|
|
3024
|
+
}
|
|
3025
|
+
return false;
|
|
3026
|
+
};
|
|
3027
|
+
let sweepCursor = null;
|
|
3028
|
+
deps.onFormChange((next) => {
|
|
3029
|
+
if (dynamicKeys.size === 0) return;
|
|
3030
|
+
const raw = toRaw(next);
|
|
3031
|
+
for (let i = 0; i < SWEEP_SLICE; i++) {
|
|
3032
|
+
sweepCursor ?? (sweepCursor = dynamicKeys.values());
|
|
3033
|
+
const step = sweepCursor.next();
|
|
3034
|
+
if (step.done === true) {
|
|
3035
|
+
sweepCursor = null;
|
|
3036
|
+
break;
|
|
3037
|
+
}
|
|
3038
|
+
const segments = segmentsForPathKey(step.value);
|
|
3039
|
+
if (segments !== null && hasAtPath(raw, segments)) continue;
|
|
3040
|
+
dynamicKeys.delete(step.value);
|
|
3041
|
+
for (const evict of evictors) evict(step.value);
|
|
3042
|
+
}
|
|
3043
|
+
});
|
|
3044
|
+
return {
|
|
3045
|
+
track(segments, key) {
|
|
3046
|
+
if (dynamicKeys.has(key)) return;
|
|
3047
|
+
if (isDynamicPath(segments)) dynamicKeys.add(key);
|
|
3048
|
+
},
|
|
3049
|
+
onEvict(evict) {
|
|
3050
|
+
evictors.push(evict);
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
|
|
2931
3055
|
const IDLE = Object.freeze({ display: "idle" });
|
|
2932
3056
|
const MAX_DELAY = 2147483647;
|
|
3057
|
+
const PENDING_LIVENESS_MS = 250;
|
|
3058
|
+
function withLiveness(machine, now) {
|
|
3059
|
+
if (machine.display !== "pending") return machine;
|
|
3060
|
+
if (machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt)) return machine;
|
|
3061
|
+
return { ...machine, reviewAt: now + PENDING_LIVENESS_MS };
|
|
3062
|
+
}
|
|
2933
3063
|
function createDisplayEngine(ssr) {
|
|
2934
3064
|
const machines = /* @__PURE__ */ new Map();
|
|
2935
3065
|
const tick = ref(0);
|
|
@@ -2958,7 +3088,7 @@ function createDisplayEngine(ssr) {
|
|
|
2958
3088
|
return;
|
|
2959
3089
|
}
|
|
2960
3090
|
if (timer !== null && timerTarget === target) return;
|
|
2961
|
-
if (target === lastFiredTarget) {
|
|
3091
|
+
if (target === lastFiredTarget && target <= now) {
|
|
2962
3092
|
clearTimer();
|
|
2963
3093
|
return;
|
|
2964
3094
|
}
|
|
@@ -2977,8 +3107,9 @@ function createDisplayEngine(ssr) {
|
|
|
2977
3107
|
function resolve(key, ctx, reducer) {
|
|
2978
3108
|
void tick.value;
|
|
2979
3109
|
const prev = machines.get(key) ?? IDLE;
|
|
2980
|
-
const
|
|
2981
|
-
if (ssr) return
|
|
3110
|
+
const reduced = reducer(prev, ctx);
|
|
3111
|
+
if (ssr) return reduced;
|
|
3112
|
+
const machine = withLiveness(reduced, ctx.now);
|
|
2982
3113
|
const active = machine.display !== "idle" || machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt);
|
|
2983
3114
|
if (active) machines.set(key, machine);
|
|
2984
3115
|
else machines.delete(key);
|
|
@@ -3009,6 +3140,58 @@ function createDisplayEngine(ssr) {
|
|
|
3009
3140
|
return engine;
|
|
3010
3141
|
}
|
|
3011
3142
|
|
|
3143
|
+
function buildErrorPathIndex(cells, blank) {
|
|
3144
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3145
|
+
for (const [key, cell] of cells) {
|
|
3146
|
+
if (cell.schema.length > 0 || cell.user.length > 0) keys.add(key);
|
|
3147
|
+
}
|
|
3148
|
+
for (const [key, list] of blank) {
|
|
3149
|
+
if (list.length > 0) keys.add(key);
|
|
3150
|
+
}
|
|
3151
|
+
if (keys.size === 0) return EMPTY_INDEX;
|
|
3152
|
+
const entries = [];
|
|
3153
|
+
for (const key of keys) {
|
|
3154
|
+
const segments = segmentsForPathKey(key);
|
|
3155
|
+
if (segments !== null) entries.push({ key, segments });
|
|
3156
|
+
}
|
|
3157
|
+
entries.sort(compareByKey);
|
|
3158
|
+
return entries;
|
|
3159
|
+
}
|
|
3160
|
+
const EMPTY_INDEX = Object.freeze([]);
|
|
3161
|
+
function compareByKey(a, b) {
|
|
3162
|
+
return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
|
|
3163
|
+
}
|
|
3164
|
+
function windowUnder(index, prefix) {
|
|
3165
|
+
if (prefix.length === 0 || index.length === 0) return index;
|
|
3166
|
+
const prefixKey = keyForSegments(prefix).key;
|
|
3167
|
+
const marker = `${prefixKey.slice(0, -1)},`;
|
|
3168
|
+
const start = lowerBound(index, marker);
|
|
3169
|
+
if (start >= index.length) return EMPTY_INDEX;
|
|
3170
|
+
let end = start;
|
|
3171
|
+
for (; end < index.length; end += 1) {
|
|
3172
|
+
const entry = index[end];
|
|
3173
|
+
if (entry === void 0 || entry.key > prefixKey) break;
|
|
3174
|
+
}
|
|
3175
|
+
return start === 0 && end === index.length ? index : index.slice(start, end);
|
|
3176
|
+
}
|
|
3177
|
+
function isSameWindow(a, b) {
|
|
3178
|
+
if (a.length !== b.length) return false;
|
|
3179
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
3180
|
+
if (a[i]?.key !== b[i]?.key) return false;
|
|
3181
|
+
}
|
|
3182
|
+
return true;
|
|
3183
|
+
}
|
|
3184
|
+
function lowerBound(index, target) {
|
|
3185
|
+
let lo = 0;
|
|
3186
|
+
let hi = index.length;
|
|
3187
|
+
while (lo < hi) {
|
|
3188
|
+
const mid = lo + hi >>> 1;
|
|
3189
|
+
if ((index[mid]?.key ?? target) < target) lo = mid + 1;
|
|
3190
|
+
else hi = mid;
|
|
3191
|
+
}
|
|
3192
|
+
return lo;
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3012
3195
|
function mergeSparseHydration(schemaDefaults, sparse, schema) {
|
|
3013
3196
|
return mergeDeep(schemaDefaults, sparse, [], schema);
|
|
3014
3197
|
}
|
|
@@ -3070,6 +3253,7 @@ async function runFactoryAndApply(st, factory) {
|
|
|
3070
3253
|
st.schema
|
|
3071
3254
|
);
|
|
3072
3255
|
st.applyFormReplacement(full, { hydration: true });
|
|
3256
|
+
st.adoptResolvedDefaults(value);
|
|
3073
3257
|
st.scheduleFieldValidation(
|
|
3074
3258
|
[],
|
|
3075
3259
|
true
|
|
@@ -3149,12 +3333,10 @@ function applyDuStubs(schema, data, options = {}) {
|
|
|
3149
3333
|
}
|
|
3150
3334
|
function walkDuStubs(schema, value, path, warned) {
|
|
3151
3335
|
if (value === null || value === void 0 || typeof value !== "object") return value;
|
|
3152
|
-
if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function") {
|
|
3153
|
-
return value;
|
|
3154
|
-
}
|
|
3155
3336
|
if (Array.isArray(value)) {
|
|
3156
3337
|
return value.map((item, i) => walkDuStubs(schema, item, [...path, i]));
|
|
3157
3338
|
}
|
|
3339
|
+
if (!isPlainRecord(value)) return value;
|
|
3158
3340
|
const rec = value;
|
|
3159
3341
|
const du = schema.getUnionDiscriminatorAtPath(path);
|
|
3160
3342
|
if (du !== void 0) {
|
|
@@ -3166,8 +3348,8 @@ function walkDuStubs(schema, value, path, warned) {
|
|
|
3166
3348
|
}
|
|
3167
3349
|
}
|
|
3168
3350
|
const out = {};
|
|
3169
|
-
for (const k of
|
|
3170
|
-
safeAssign(out, k, walkDuStubs(schema, rec
|
|
3351
|
+
for (const k of consumerKeys(rec)) {
|
|
3352
|
+
safeAssign(out, k, walkDuStubs(schema, readConsumerProp(rec, k), [...path, k]));
|
|
3171
3353
|
}
|
|
3172
3354
|
return out;
|
|
3173
3355
|
}
|
|
@@ -3177,23 +3359,25 @@ function stripSymbolsDeep(value) {
|
|
|
3177
3359
|
let mutated2 = false;
|
|
3178
3360
|
const out2 = new Array(value.length);
|
|
3179
3361
|
for (let i = 0; i < value.length; i++) {
|
|
3180
|
-
const
|
|
3362
|
+
const original = readConsumerIndex(value, i);
|
|
3363
|
+
const cleaned = stripSymbolsDeep(original);
|
|
3181
3364
|
out2[i] = cleaned;
|
|
3182
|
-
if (cleaned !==
|
|
3365
|
+
if (cleaned !== original) mutated2 = true;
|
|
3183
3366
|
}
|
|
3184
3367
|
return mutated2 ? out2 : value;
|
|
3185
3368
|
}
|
|
3186
3369
|
const proto = Object.getPrototypeOf(value);
|
|
3187
3370
|
if (proto !== Object.prototype && proto !== null) return value;
|
|
3188
|
-
const symKeys =
|
|
3189
|
-
const stringKeys =
|
|
3371
|
+
const symKeys = consumerSymbolKeys(value);
|
|
3372
|
+
const stringKeys = consumerKeys(value);
|
|
3190
3373
|
let mutated = symKeys.length > 0;
|
|
3191
3374
|
const out = {};
|
|
3192
3375
|
const src = value;
|
|
3193
3376
|
for (const k of stringKeys) {
|
|
3194
|
-
const
|
|
3377
|
+
const original = readConsumerProp(src, k);
|
|
3378
|
+
const cleaned = stripSymbolsDeep(original);
|
|
3195
3379
|
out[k] = cleaned;
|
|
3196
|
-
if (cleaned !==
|
|
3380
|
+
if (cleaned !== original) mutated = true;
|
|
3197
3381
|
}
|
|
3198
3382
|
return mutated ? out : value;
|
|
3199
3383
|
}
|
|
@@ -3218,16 +3402,15 @@ function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out)
|
|
|
3218
3402
|
out.add(canonicalizePath(prefix).key);
|
|
3219
3403
|
}
|
|
3220
3404
|
}
|
|
3221
|
-
function computeBaselineResponse(schema,
|
|
3405
|
+
function computeBaselineResponse(schema, source) {
|
|
3222
3406
|
const completed = source === void 0 ? void 0 : mergeStructural(schema, [], source);
|
|
3223
3407
|
return schema.getDefaultValues({
|
|
3224
3408
|
useDefaultSchemaValues: true,
|
|
3225
|
-
constraints: completed
|
|
3226
|
-
strict
|
|
3409
|
+
constraints: completed
|
|
3227
3410
|
});
|
|
3228
3411
|
}
|
|
3229
|
-
function initialFirstValidationGate(schema
|
|
3230
|
-
return
|
|
3412
|
+
function initialFirstValidationGate(schema) {
|
|
3413
|
+
return schema.needsAsyncValidation?.() !== true;
|
|
3231
3414
|
}
|
|
3232
3415
|
function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
|
|
3233
3416
|
st.originals.clear();
|
|
@@ -3239,7 +3422,7 @@ function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
|
|
|
3239
3422
|
});
|
|
3240
3423
|
}
|
|
3241
3424
|
function queueInitialAsyncValidation(st) {
|
|
3242
|
-
if (!st.ssr && st.
|
|
3425
|
+
if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
|
|
3243
3426
|
queueMicrotask(() => scheduleFieldValidation(
|
|
3244
3427
|
st,
|
|
3245
3428
|
[],
|
|
@@ -3281,10 +3464,6 @@ function ensurePathOrdinal(st, key) {
|
|
|
3281
3464
|
}
|
|
3282
3465
|
return ordinal;
|
|
3283
3466
|
}
|
|
3284
|
-
function pathHasAsyncValidation(st, path) {
|
|
3285
|
-
const { key } = canonicalizePath(path);
|
|
3286
|
-
return pathHasAsyncValidationByKey(st, key, path);
|
|
3287
|
-
}
|
|
3288
3467
|
function pathHasAsyncValidationByKey(st, key, segments) {
|
|
3289
3468
|
const cached = st.pathAsyncCache.get(key);
|
|
3290
3469
|
if (cached !== void 0) return cached;
|
|
@@ -3427,10 +3606,15 @@ function commitWritePatches(st, patches, meta) {
|
|
|
3427
3606
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3428
3607
|
for (const patch of patches) {
|
|
3429
3608
|
const { key } = canonicalizePath(patch.path);
|
|
3430
|
-
if (
|
|
3609
|
+
if (!st.originals.has(key)) {
|
|
3431
3610
|
st.originals.set(key, { segments: patch.path, value: void 0 });
|
|
3432
3611
|
}
|
|
3433
3612
|
touchFieldRecord(st, key, patch.path, { updatedAt: now });
|
|
3613
|
+
st.pathSweep.track(patch.path, key);
|
|
3614
|
+
for (let i = 1; i < patch.path.length; i++) {
|
|
3615
|
+
const ancestor = patch.path.slice(0, i);
|
|
3616
|
+
st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
|
|
3617
|
+
}
|
|
3434
3618
|
}
|
|
3435
3619
|
for (const listener of st.formChangeListeners) {
|
|
3436
3620
|
try {
|
|
@@ -3635,10 +3819,7 @@ function setValueAtPath(st, path, value, meta) {
|
|
|
3635
3819
|
if (newlyAuthored && st.schema.isPreprocessOrCoerceLeaf(path)) {
|
|
3636
3820
|
const modeForAuthoringTransition = meta?.instance?.validateOn ?? st.fieldValidationMode;
|
|
3637
3821
|
if (modeForAuthoringTransition === "change") {
|
|
3638
|
-
scheduleFieldValidation(st, path, false,
|
|
3639
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3640
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3641
|
-
});
|
|
3822
|
+
scheduleFieldValidation(st, path, false, meta?.instance);
|
|
3642
3823
|
}
|
|
3643
3824
|
}
|
|
3644
3825
|
return true;
|
|
@@ -3654,15 +3835,12 @@ function setValueAtPath(st, path, value, meta) {
|
|
|
3654
3835
|
st.arrayIdentity.realign(path);
|
|
3655
3836
|
} else if (isContainer(currentValue) && !isContainer(value)) {
|
|
3656
3837
|
if (subtreeHadRealBaseline(st, path, currentValue)) {
|
|
3657
|
-
st.removedSubtrees.add(
|
|
3838
|
+
st.removedSubtrees.add(pathKey);
|
|
3658
3839
|
}
|
|
3659
3840
|
}
|
|
3660
3841
|
const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
|
|
3661
3842
|
if (effectiveModeAfterWrite === "change") {
|
|
3662
|
-
scheduleFieldValidation(st, path, false,
|
|
3663
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3664
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3665
|
-
});
|
|
3843
|
+
scheduleFieldValidation(st, path, false, meta?.instance);
|
|
3666
3844
|
}
|
|
3667
3845
|
return true;
|
|
3668
3846
|
}
|
|
@@ -3723,12 +3901,11 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
|
|
|
3723
3901
|
path: [...parentPath, ...err.path]
|
|
3724
3902
|
}));
|
|
3725
3903
|
applySchemaErrorsForSubtree(st, parentPath, reStamped);
|
|
3726
|
-
const
|
|
3727
|
-
const prevValidation = st.fieldValidationState.get(parentKey2);
|
|
3904
|
+
const prevValidation = st.fieldValidationState.get(parentKey);
|
|
3728
3905
|
if (prevValidation !== void 0) {
|
|
3729
3906
|
if (prevValidation.timer !== null) clearTimeout(prevValidation.timer);
|
|
3730
3907
|
prevValidation.aborted = true;
|
|
3731
|
-
st.fieldValidationState.delete(
|
|
3908
|
+
st.fieldValidationState.delete(parentKey);
|
|
3732
3909
|
}
|
|
3733
3910
|
appliedSync = true;
|
|
3734
3911
|
}
|
|
@@ -3736,17 +3913,14 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
|
|
|
3736
3913
|
applyFormReplacement(st, nextForm, meta);
|
|
3737
3914
|
for (const k of newBlankPaths) st.blankPaths.add(k);
|
|
3738
3915
|
if (reshapeMode === "change" && !appliedSync) {
|
|
3739
|
-
scheduleFieldValidation(st, parentPath, false,
|
|
3740
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
3741
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
3742
|
-
});
|
|
3916
|
+
scheduleFieldValidation(st, parentPath, false, meta?.instance);
|
|
3743
3917
|
}
|
|
3744
3918
|
return true;
|
|
3745
3919
|
}
|
|
3746
|
-
function scheduleFieldValidation(st, path, immediate,
|
|
3747
|
-
const effectiveMode =
|
|
3920
|
+
function scheduleFieldValidation(st, path, immediate, instance) {
|
|
3921
|
+
const effectiveMode = instance?.validateOn ?? st.fieldValidationMode;
|
|
3748
3922
|
if (effectiveMode === "submit") return;
|
|
3749
|
-
const effectiveDebounce =
|
|
3923
|
+
const effectiveDebounce = instance?.debounceMs ?? st.fieldValidationDebounceMs;
|
|
3750
3924
|
const { key } = canonicalizePath(path);
|
|
3751
3925
|
const prev = st.fieldValidationState.get(key);
|
|
3752
3926
|
if (prev !== void 0) {
|
|
@@ -4020,10 +4194,7 @@ function markFocused(st, path, focused, meta) {
|
|
|
4020
4194
|
});
|
|
4021
4195
|
}
|
|
4022
4196
|
if (changed) {
|
|
4023
|
-
scheduleFieldValidation(st, path, true,
|
|
4024
|
-
...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
|
|
4025
|
-
...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
|
|
4026
|
-
});
|
|
4197
|
+
scheduleFieldValidation(st, path, true, meta?.instance);
|
|
4027
4198
|
}
|
|
4028
4199
|
}
|
|
4029
4200
|
}
|
|
@@ -4035,10 +4206,9 @@ function markInteracted(st, path) {
|
|
|
4035
4206
|
}
|
|
4036
4207
|
function touchAtPath(st, segments) {
|
|
4037
4208
|
const formValue = st.form.value;
|
|
4038
|
-
for (const [, entry] of st.originals) {
|
|
4209
|
+
for (const [leafKey, entry] of st.originals) {
|
|
4039
4210
|
if (!isPathPrefix(segments, entry.segments)) continue;
|
|
4040
4211
|
if (!hasAtPath(formValue, entry.segments)) continue;
|
|
4041
|
-
const leafKey = canonicalizePath(entry.segments).key;
|
|
4042
4212
|
const current = st.fields.get(leafKey);
|
|
4043
4213
|
if (current?.touched === true) continue;
|
|
4044
4214
|
touchFieldRecord(st, leafKey, entry.segments, { touched: true });
|
|
@@ -4048,11 +4218,10 @@ function interactAtPath(st, segments) {
|
|
|
4048
4218
|
if (st.effectiveDisabled.value) return false;
|
|
4049
4219
|
const formValue = st.form.value;
|
|
4050
4220
|
let interactedAny = false;
|
|
4051
|
-
for (const [, entry] of st.originals) {
|
|
4221
|
+
for (const [leafKey, entry] of st.originals) {
|
|
4052
4222
|
if (!isPathPrefix(segments, entry.segments)) continue;
|
|
4053
4223
|
if (!hasAtPath(formValue, entry.segments)) continue;
|
|
4054
4224
|
interactedAny = true;
|
|
4055
|
-
const leafKey = canonicalizePath(entry.segments).key;
|
|
4056
4225
|
const current = st.fields.get(leafKey);
|
|
4057
4226
|
if (current?.touched === true && current.interacted === true && current.blurredAfterInteraction === true) {
|
|
4058
4227
|
continue;
|
|
@@ -4096,9 +4265,24 @@ function activate(st) {
|
|
|
4096
4265
|
if (factory === void 0) return Promise.resolve();
|
|
4097
4266
|
return fireFactory(st, factory);
|
|
4098
4267
|
}
|
|
4268
|
+
function adoptResolvedDefaults(st, value) {
|
|
4269
|
+
st.defaultValues = structuralSnapshot(
|
|
4270
|
+
mergeSparseHydration(
|
|
4271
|
+
st.defaultValues,
|
|
4272
|
+
value,
|
|
4273
|
+
st.schema
|
|
4274
|
+
)
|
|
4275
|
+
);
|
|
4276
|
+
seedOriginalsFromBaseline(st, computeBaselineResponse(st.schema, st.defaultValues).data, false);
|
|
4277
|
+
}
|
|
4099
4278
|
function reset(st, nextDefaultValues) {
|
|
4100
|
-
const resetSource = nextDefaultValues
|
|
4101
|
-
|
|
4279
|
+
const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
|
|
4280
|
+
st.defaultValues,
|
|
4281
|
+
nextDefaultValues,
|
|
4282
|
+
st.schema
|
|
4283
|
+
);
|
|
4284
|
+
st.defaultValues = structuralSnapshot(resetSource);
|
|
4285
|
+
const resetResponse = computeBaselineResponse(st.schema, resetSource);
|
|
4102
4286
|
const next = resetResponse.data;
|
|
4103
4287
|
rebuildAuthoredPaths(st, resetSource, next);
|
|
4104
4288
|
applyFormReplacement(st, next);
|
|
@@ -4106,25 +4290,23 @@ function reset(st, nextDefaultValues) {
|
|
|
4106
4290
|
st.removedSubtrees.clear();
|
|
4107
4291
|
seedOriginalsFromBaseline(st, next, false);
|
|
4108
4292
|
if (nextDefaultValues !== void 0) {
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4293
|
+
const mentioned = /* @__PURE__ */ new Set();
|
|
4294
|
+
walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
|
|
4295
|
+
for (const key of mentioned) st.originalBlankPaths.delete(key);
|
|
4296
|
+
}
|
|
4297
|
+
st.blankPaths.clear();
|
|
4298
|
+
for (const key of st.originalBlankPaths) {
|
|
4299
|
+
st.blankPaths.add(key);
|
|
4116
4300
|
}
|
|
4117
4301
|
st.errorCells.clear();
|
|
4118
|
-
if (
|
|
4302
|
+
if (!resetResponse.success) {
|
|
4119
4303
|
replaceErrorChannel(st, "schema", resetResponse.errors);
|
|
4120
4304
|
}
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
applySchemaErrorsForSubtree(st, [], syncResult.errors);
|
|
4125
|
-
}
|
|
4305
|
+
const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
|
|
4306
|
+
if (!(syncResult instanceof Promise) && !syncResult.success) {
|
|
4307
|
+
applySchemaErrorsForSubtree(st, [], syncResult.errors);
|
|
4126
4308
|
}
|
|
4127
|
-
st.firstValidationDone.value = initialFirstValidationGate(st.schema
|
|
4309
|
+
st.firstValidationDone.value = initialFirstValidationGate(st.schema);
|
|
4128
4310
|
queueInitialAsyncValidation(st);
|
|
4129
4311
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4130
4312
|
for (const [pathKey, record] of st.fields) {
|
|
@@ -4214,10 +4396,6 @@ function clearFieldRecordFlags(st, pathKey) {
|
|
|
4214
4396
|
if (record === void 0) return;
|
|
4215
4397
|
st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
|
|
4216
4398
|
}
|
|
4217
|
-
function isPristineAtPath(st, path) {
|
|
4218
|
-
const { key, segments } = canonicalizePath(path);
|
|
4219
|
-
return isPristineAtPathByKey(st, key, segments);
|
|
4220
|
-
}
|
|
4221
4399
|
function isPristineAtPathByKey(st, key, segments) {
|
|
4222
4400
|
if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
|
|
4223
4401
|
const entry = st.originals.get(key);
|
|
@@ -4251,12 +4429,8 @@ function getFieldRecord(st, path) {
|
|
|
4251
4429
|
const { key } = canonicalizePath(path);
|
|
4252
4430
|
return st.fields.get(key);
|
|
4253
4431
|
}
|
|
4254
|
-
function getOriginalAtPath(st, path) {
|
|
4255
|
-
const { key } = canonicalizePath(path);
|
|
4256
|
-
return st.originals.get(key)?.value;
|
|
4257
|
-
}
|
|
4258
4432
|
function createFormStore(options) {
|
|
4259
|
-
const { formKey, schema, defaultValues,
|
|
4433
|
+
const { formKey, schema, defaultValues, hydration } = options;
|
|
4260
4434
|
const ssr = options.ssr === true;
|
|
4261
4435
|
const ssrPrefetch = options.ssrPrefetch;
|
|
4262
4436
|
const rememberVariants = options.rememberVariants !== false;
|
|
@@ -4264,22 +4438,16 @@ function createFormStore(options) {
|
|
|
4264
4438
|
const fieldValidationDebounceMs = normalizeNumericOption({
|
|
4265
4439
|
value: options.debounceMs ?? DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS,
|
|
4266
4440
|
source: "useForm.debounceMs",
|
|
4267
|
-
allowInfinity: false,
|
|
4268
4441
|
min: 0,
|
|
4269
4442
|
defaultValue: DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS
|
|
4270
4443
|
});
|
|
4271
|
-
const
|
|
4272
|
-
const resolvedGetDisplayState = resolveGetDisplayState(options.getDisplayState);
|
|
4444
|
+
const coerceEnabled = resolveCoerceEnabled(options.coerce);
|
|
4273
4445
|
const cleanupHooks = [];
|
|
4274
4446
|
const modules = /* @__PURE__ */ new Map();
|
|
4275
4447
|
const fieldValidatingSince = reactive(/* @__PURE__ */ new Map());
|
|
4276
4448
|
const displayEngine = createDisplayEngine(ssr);
|
|
4277
4449
|
cleanupHooks.push(() => displayEngine.dispose());
|
|
4278
|
-
const schemaResponse = computeBaselineResponse(
|
|
4279
|
-
schema,
|
|
4280
|
-
strict,
|
|
4281
|
-
defaultValues
|
|
4282
|
-
);
|
|
4450
|
+
const schemaResponse = computeBaselineResponse(schema, defaultValues);
|
|
4283
4451
|
const schemaInitialData = schemaResponse.data;
|
|
4284
4452
|
const authoredPaths = /* @__PURE__ */ new Set();
|
|
4285
4453
|
const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
|
|
@@ -4292,16 +4460,15 @@ function createFormStore(options) {
|
|
|
4292
4460
|
const v = getAtPath(toRaw(form.value), arraySegs);
|
|
4293
4461
|
return Array.isArray(v) ? v.length : 0;
|
|
4294
4462
|
});
|
|
4295
|
-
const fields =
|
|
4463
|
+
const fields = shallowReactive(/* @__PURE__ */ new Map());
|
|
4296
4464
|
const domBinding = shallowRef(null);
|
|
4297
|
-
const errorCells =
|
|
4298
|
-
const originals =
|
|
4465
|
+
const errorCells = shallowReactive(/* @__PURE__ */ new Map());
|
|
4466
|
+
const originals = shallowReactive(/* @__PURE__ */ new Map());
|
|
4299
4467
|
const removedSubtrees = /* @__PURE__ */ new Set();
|
|
4300
|
-
const initialTransientList = hydration?.blankPaths ?? options.initialBlankPaths ?? [];
|
|
4301
4468
|
const blankPaths = reactive(/* @__PURE__ */ new Set());
|
|
4302
4469
|
const originalBlankPaths = /* @__PURE__ */ new Set();
|
|
4303
|
-
|
|
4304
|
-
|
|
4470
|
+
const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
|
|
4471
|
+
for (const key of seededBlankPaths) {
|
|
4305
4472
|
blankPaths.add(key);
|
|
4306
4473
|
originalBlankPaths.add(key);
|
|
4307
4474
|
}
|
|
@@ -4318,6 +4485,9 @@ function createFormStore(options) {
|
|
|
4318
4485
|
}
|
|
4319
4486
|
return result;
|
|
4320
4487
|
});
|
|
4488
|
+
const errorPathIndex = computed(
|
|
4489
|
+
() => buildErrorPathIndex(errorCells, derivedBlankErrors.value)
|
|
4490
|
+
);
|
|
4321
4491
|
const submitting = ref(false);
|
|
4322
4492
|
const activeSubmissions = ref(0);
|
|
4323
4493
|
const submissionAttempts = ref(0);
|
|
@@ -4342,7 +4512,7 @@ function createFormStore(options) {
|
|
|
4342
4512
|
const defaultsResolved = ref(false);
|
|
4343
4513
|
const activated = ref(false);
|
|
4344
4514
|
const activationPromise = ref(void 0);
|
|
4345
|
-
const firstValidationDone = ref(initialFirstValidationGate(schema
|
|
4515
|
+
const firstValidationDone = ref(initialFirstValidationGate(schema));
|
|
4346
4516
|
watch(activeValidations, (now, prev) => {
|
|
4347
4517
|
if (prev > 0 && now === 0) {
|
|
4348
4518
|
firstValidationDone.value = true;
|
|
@@ -4360,6 +4530,33 @@ function createFormStore(options) {
|
|
|
4360
4530
|
const activeTransforms = ref(0);
|
|
4361
4531
|
const transformRuns = /* @__PURE__ */ new Map();
|
|
4362
4532
|
const transformWaiters = [];
|
|
4533
|
+
const errorWindows = /* @__PURE__ */ new Map();
|
|
4534
|
+
const pathSweep = createDynamicPathSweep({
|
|
4535
|
+
onFormChange: (listener) => {
|
|
4536
|
+
formChangeListeners.add(listener);
|
|
4537
|
+
},
|
|
4538
|
+
isFixedObjectAtPath: (path) => schema.isFixedObjectAtPath(path)
|
|
4539
|
+
});
|
|
4540
|
+
pathSweep.onEvict((key) => {
|
|
4541
|
+
fields.delete(key);
|
|
4542
|
+
fieldValidationState.delete(key);
|
|
4543
|
+
authoredPaths.delete(key);
|
|
4544
|
+
if (originals.get(key)?.value === void 0) originals.delete(key);
|
|
4545
|
+
errorWindows.delete(key);
|
|
4546
|
+
});
|
|
4547
|
+
const errorWindowAt = (prefix, prefixKey) => {
|
|
4548
|
+
let cached = errorWindows.get(prefixKey);
|
|
4549
|
+
if (cached === void 0) {
|
|
4550
|
+
const frozen = [...prefix];
|
|
4551
|
+
cached = computed((prev) => {
|
|
4552
|
+
const next = windowUnder(errorPathIndex.value, frozen);
|
|
4553
|
+
return prev !== void 0 && isSameWindow(prev, next) ? prev : next;
|
|
4554
|
+
});
|
|
4555
|
+
errorWindows.set(prefixKey, cached);
|
|
4556
|
+
pathSweep.track(frozen, prefixKey);
|
|
4557
|
+
}
|
|
4558
|
+
return cached.value;
|
|
4559
|
+
};
|
|
4363
4560
|
const arrayBookkeeping = createArrayBookkeeping({
|
|
4364
4561
|
form,
|
|
4365
4562
|
fields,
|
|
@@ -4377,6 +4574,7 @@ function createFormStore(options) {
|
|
|
4377
4574
|
touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
|
|
4378
4575
|
decFieldValidation: (key) => decFieldValidation(st, key)
|
|
4379
4576
|
});
|
|
4577
|
+
const bind = (fn) => (...args) => fn(st, ...args);
|
|
4380
4578
|
const st = {
|
|
4381
4579
|
// --- public data (the FormStore contract's state members) ---
|
|
4382
4580
|
formKey,
|
|
@@ -4384,10 +4582,11 @@ function createFormStore(options) {
|
|
|
4384
4582
|
fields,
|
|
4385
4583
|
errorCells,
|
|
4386
4584
|
derivedBlankErrors,
|
|
4585
|
+
errorWindowAt,
|
|
4387
4586
|
originals,
|
|
4587
|
+
pathSweep,
|
|
4388
4588
|
schema,
|
|
4389
4589
|
ssr,
|
|
4390
|
-
getDisplayState: resolvedGetDisplayState,
|
|
4391
4590
|
submitting,
|
|
4392
4591
|
activeSubmissions,
|
|
4393
4592
|
submissionAttempts,
|
|
@@ -4415,12 +4614,20 @@ function createFormStore(options) {
|
|
|
4415
4614
|
displayEngine,
|
|
4416
4615
|
domBinding,
|
|
4417
4616
|
modules,
|
|
4418
|
-
|
|
4617
|
+
coerceEnabled,
|
|
4419
4618
|
blankPaths,
|
|
4420
4619
|
originalBlankPaths,
|
|
4421
4620
|
// --- kernel-internal state ---
|
|
4422
|
-
|
|
4423
|
-
|
|
4621
|
+
// Defensive copy, not a fix for an observed alias: today
|
|
4622
|
+
// `getDefaultValues` happens to build a fresh tree, so form storage
|
|
4623
|
+
// does not currently share structure with the consumer's object.
|
|
4624
|
+
// That is an adapter implementation detail rather than a contract,
|
|
4625
|
+
// and this field is now durable state that every `reset()` reads, so
|
|
4626
|
+
// it should not depend on it. The copy also means a consumer who
|
|
4627
|
+
// keeps a reference to the literal they passed cannot mutate the
|
|
4628
|
+
// form's defaults from outside. `reset()` snapshots for a harder
|
|
4629
|
+
// reason (see there) where an alias IS reachable.
|
|
4630
|
+
defaultValues: structuralSnapshot(defaultValues),
|
|
4424
4631
|
ssrPrefetch,
|
|
4425
4632
|
rememberVariants,
|
|
4426
4633
|
fieldValidationMode,
|
|
@@ -4447,16 +4654,20 @@ function createFormStore(options) {
|
|
|
4447
4654
|
transformTokenSeq: 0,
|
|
4448
4655
|
warnedDisabledWrite: false,
|
|
4449
4656
|
// --- methods: thin per-instance skins over the module kernel ---
|
|
4450
|
-
rehydrate: (
|
|
4451
|
-
activate: (
|
|
4452
|
-
|
|
4453
|
-
pathHasAsyncValidationByKey: (
|
|
4454
|
-
applyFormReplacement: (
|
|
4455
|
-
setValueAtPath: (
|
|
4456
|
-
getValueAtPath: (
|
|
4457
|
-
arrayElementKey: (
|
|
4458
|
-
reset: (
|
|
4459
|
-
resetField: (
|
|
4657
|
+
rehydrate: bind(rehydrate),
|
|
4658
|
+
activate: bind(activate),
|
|
4659
|
+
adoptResolvedDefaults: bind(adoptResolvedDefaults),
|
|
4660
|
+
pathHasAsyncValidationByKey: bind(pathHasAsyncValidationByKey),
|
|
4661
|
+
applyFormReplacement: bind(applyFormReplacement),
|
|
4662
|
+
setValueAtPath: bind(setValueAtPath),
|
|
4663
|
+
getValueAtPath: bind(getValueAtPath),
|
|
4664
|
+
arrayElementKey: bind(arrayElementKey),
|
|
4665
|
+
reset: bind(reset),
|
|
4666
|
+
resetField: bind(resetField),
|
|
4667
|
+
// The schema/user pair below reads as a fold waiting to happen. It was
|
|
4668
|
+
// tried: a `setErrorsForPathIn(channel)` factory measured 10 B LARGER,
|
|
4669
|
+
// because gzip had already collected the rent on two adjacent copies
|
|
4670
|
+
// and the helper added a name the original did not need.
|
|
4460
4671
|
setSchemaErrorsForPath: (path, entries) => setErrorChannelForKey(
|
|
4461
4672
|
st,
|
|
4462
4673
|
canonicalizePath(path).key,
|
|
@@ -4465,7 +4676,7 @@ function createFormStore(options) {
|
|
|
4465
4676
|
),
|
|
4466
4677
|
setAllSchemaErrors: (entries) => replaceErrorChannel(st, "schema", entries),
|
|
4467
4678
|
clearSchemaErrors: (path) => clearErrorChannel(st, "schema", path),
|
|
4468
|
-
applySchemaErrorsForSubtree: (
|
|
4679
|
+
applySchemaErrorsForSubtree: bind(applySchemaErrorsForSubtree),
|
|
4469
4680
|
setAllUserErrors: (entries) => replaceErrorChannel(st, "user", entries),
|
|
4470
4681
|
setUserErrorsForPath: (path, entries) => setErrorChannelForKey(
|
|
4471
4682
|
st,
|
|
@@ -4474,37 +4685,34 @@ function createFormStore(options) {
|
|
|
4474
4685
|
entries.length === 0 ? NO_ERRORS : [...entries]
|
|
4475
4686
|
),
|
|
4476
4687
|
clearUserErrors: (path) => clearErrorChannel(st, "user", path),
|
|
4477
|
-
restoreErrorCells: (
|
|
4478
|
-
getErrorsForPath: (
|
|
4479
|
-
ensurePathOrdinal: (
|
|
4480
|
-
noteDomConnected: (
|
|
4481
|
-
noteDomDisconnected: (
|
|
4482
|
-
markFocused: (
|
|
4483
|
-
markInteracted: (
|
|
4484
|
-
touchAtPath: (
|
|
4485
|
-
interactAtPath: (
|
|
4486
|
-
markConnectedOptimistically: (
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
emitSubmitSuccess: () => emitSubmitSuccess(st),
|
|
4506
|
-
registerCleanup: (fn) => registerCleanup(st, fn),
|
|
4507
|
-
dispose: () => dispose(st)
|
|
4688
|
+
restoreErrorCells: bind(restoreErrorCells),
|
|
4689
|
+
getErrorsForPath: bind(getErrorsForPath),
|
|
4690
|
+
ensurePathOrdinal: bind(ensurePathOrdinal),
|
|
4691
|
+
noteDomConnected: bind(noteDomConnected),
|
|
4692
|
+
noteDomDisconnected: bind(noteDomDisconnected),
|
|
4693
|
+
markFocused: bind(markFocused),
|
|
4694
|
+
markInteracted: bind(markInteracted),
|
|
4695
|
+
touchAtPath: bind(touchAtPath),
|
|
4696
|
+
interactAtPath: bind(interactAtPath),
|
|
4697
|
+
markConnectedOptimistically: bind(markConnectedOptimistically),
|
|
4698
|
+
isPristineAtPathByKey: bind(isPristineAtPathByKey),
|
|
4699
|
+
hasStructuralChangeUnder: bind(hasStructuralChangeUnder),
|
|
4700
|
+
hasRemovedSubtreeUnder: bind(hasRemovedSubtreeUnder),
|
|
4701
|
+
getFieldRecord: bind(getFieldRecord),
|
|
4702
|
+
cancelFieldValidation: bind(cancelFieldValidation),
|
|
4703
|
+
beginTransform: bind(beginTransform),
|
|
4704
|
+
isCurrentTransform: bind(isCurrentTransform),
|
|
4705
|
+
endTransform: bind(endTransform),
|
|
4706
|
+
setTransformError: bind(setTransformError),
|
|
4707
|
+
cancelTransformsUnder: bind(cancelTransformsUnder),
|
|
4708
|
+
settleTransforms: bind(settleTransforms),
|
|
4709
|
+
scheduleFieldValidation: bind(scheduleFieldValidation),
|
|
4710
|
+
onFormChange: bind(onFormChange),
|
|
4711
|
+
onSubmitSuccess: bind(onSubmitSuccess),
|
|
4712
|
+
onReset: bind(onReset),
|
|
4713
|
+
emitSubmitSuccess: bind(emitSubmitSuccess),
|
|
4714
|
+
registerCleanup: bind(registerCleanup),
|
|
4715
|
+
dispose: bind(dispose)
|
|
4508
4716
|
};
|
|
4509
4717
|
rebuildAuthoredPaths(st, defaultValues, schemaInitialData);
|
|
4510
4718
|
seedOriginalsFromBaseline(st, schemaInitialData, true);
|
|
@@ -4543,7 +4751,7 @@ function createFormStore(options) {
|
|
|
4543
4751
|
blurredAfterInteraction: false
|
|
4544
4752
|
});
|
|
4545
4753
|
});
|
|
4546
|
-
if (
|
|
4754
|
+
if (!schemaResponse.success) {
|
|
4547
4755
|
replaceErrorChannel(st, "schema", schemaResponse.errors);
|
|
4548
4756
|
}
|
|
4549
4757
|
}
|
|
@@ -4574,19 +4782,18 @@ function useAbstractForm(configuration, options) {
|
|
|
4574
4782
|
const resolvedDefaults = resolveTrichotomy(configuration.defaultValues);
|
|
4575
4783
|
const materialisedDefaults = resolvedDefaults.kind === "sync" ? resolvedDefaults.value : void 0;
|
|
4576
4784
|
const { defaultValues: _droppedDefaults, ...configWithoutDefaults } = configuration;
|
|
4577
|
-
const
|
|
4578
|
-
const merged = mergeWithDefaults(registry.defaults, trichotomyOverride);
|
|
4579
|
-
const maxRecursionDepth = normalizeNumericOption({
|
|
4580
|
-
value: merged.maxRecursionDepth ?? DEFAULT_MAX_RECURSION_DEPTH,
|
|
4581
|
-
source: "useForm.maxRecursionDepth",
|
|
4582
|
-
allowInfinity: true,
|
|
4583
|
-
min: 0,
|
|
4584
|
-
defaultValue: DEFAULT_MAX_RECURSION_DEPTH
|
|
4585
|
-
});
|
|
4586
|
-
const resolvedSchema = getComputedSchema(key, configuration.schema, { maxRecursionDepth });
|
|
4785
|
+
const materialisedConfiguration = materialisedDefaults === void 0 ? configWithoutDefaults : { ...configWithoutDefaults, defaultValues: materialisedDefaults };
|
|
4587
4786
|
const existing = registry.forms.get(key);
|
|
4787
|
+
const resolvedSchema = existing === void 0 || false ? getComputedSchema(key, configuration.schema, {
|
|
4788
|
+
maxRecursionDepth: DEFAULT_MAX_RECURSION_DEPTH
|
|
4789
|
+
}) : existing.schema;
|
|
4588
4790
|
const hadPendingHydration = registry.pendingHydration.has(key);
|
|
4589
|
-
const state = existing ?? buildFreshState(
|
|
4791
|
+
const state = existing ?? buildFreshState(
|
|
4792
|
+
key,
|
|
4793
|
+
resolvedSchema,
|
|
4794
|
+
materialisedConfiguration,
|
|
4795
|
+
registry
|
|
4796
|
+
);
|
|
4590
4797
|
if (existing !== void 0) ; else if (resolvedDefaults.kind === "sync") {
|
|
4591
4798
|
state.defaultsResolved.value = true;
|
|
4592
4799
|
}
|
|
@@ -4594,6 +4801,7 @@ function useAbstractForm(configuration, options) {
|
|
|
4594
4801
|
const factory = resolvedDefaults.factory;
|
|
4595
4802
|
state.defaultValuesFactory.value = factory;
|
|
4596
4803
|
if (hadPendingHydration) {
|
|
4804
|
+
state.adoptResolvedDefaults(toRaw(state.form.value));
|
|
4597
4805
|
state.hydrating.value = false;
|
|
4598
4806
|
state.defaultsResolved.value = true;
|
|
4599
4807
|
} else if (registry.ssr) {
|
|
@@ -4610,8 +4818,8 @@ function useAbstractForm(configuration, options) {
|
|
|
4610
4818
|
const releaseConsumer = registry.trackConsumer(key);
|
|
4611
4819
|
onScopeDispose(releaseConsumer);
|
|
4612
4820
|
}
|
|
4613
|
-
if (existing === void 0 &&
|
|
4614
|
-
const historyModule =
|
|
4821
|
+
if (existing === void 0 && materialisedConfiguration.history !== void 0) {
|
|
4822
|
+
const historyModule = materialisedConfiguration.history.attach(state);
|
|
4615
4823
|
state.modules.set(HISTORY_MODULE_KEY, historyModule);
|
|
4616
4824
|
state.registerCleanup(() => historyModule.dispose());
|
|
4617
4825
|
}
|
|
@@ -4624,36 +4832,16 @@ function useAbstractForm(configuration, options) {
|
|
|
4624
4832
|
provide(kFormInstanceId, formInstanceId);
|
|
4625
4833
|
}
|
|
4626
4834
|
const apiOptions = pickDefined({
|
|
4627
|
-
|
|
4835
|
+
focusOnInvalidSubmit: materialisedConfiguration.focusOnInvalidSubmit,
|
|
4628
4836
|
history: state.modules.get(HISTORY_MODULE_KEY),
|
|
4629
|
-
validateOn:
|
|
4630
|
-
debounceMs:
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
rememberVariants: merged.rememberVariants,
|
|
4634
|
-
autoAria: merged.autoAria
|
|
4837
|
+
validateOn: materialisedConfiguration.validateOn,
|
|
4838
|
+
debounceMs: materialisedConfiguration.debounceMs,
|
|
4839
|
+
coerce: materialisedConfiguration.coerce,
|
|
4840
|
+
rememberVariants: materialisedConfiguration.rememberVariants
|
|
4635
4841
|
});
|
|
4636
4842
|
const api = buildFormApi(state, formInstanceId, apiOptions);
|
|
4637
4843
|
return api;
|
|
4638
4844
|
}
|
|
4639
|
-
function mergeWithDefaults(defaults, configuration) {
|
|
4640
|
-
return {
|
|
4641
|
-
...configuration,
|
|
4642
|
-
...pickDefined({
|
|
4643
|
-
strict: configuration.strict ?? defaults.strict,
|
|
4644
|
-
onInvalidSubmit: configuration.onInvalidSubmit ?? defaults.onInvalidSubmit,
|
|
4645
|
-
history: configuration.history ?? defaults.history,
|
|
4646
|
-
rememberVariants: configuration.rememberVariants ?? defaults.rememberVariants,
|
|
4647
|
-
disabled: configuration.disabled ?? defaults.disabled,
|
|
4648
|
-
coerce: configuration.coerce ?? defaults.coerce,
|
|
4649
|
-
validateOn: configuration.validateOn ?? defaults.validateOn,
|
|
4650
|
-
debounceMs: configuration.debounceMs ?? defaults.debounceMs,
|
|
4651
|
-
getDisplayState: configuration.getDisplayState ?? defaults.getDisplayState,
|
|
4652
|
-
maxRecursionDepth: configuration.maxRecursionDepth ?? defaults.maxRecursionDepth,
|
|
4653
|
-
autoAria: configuration.autoAria ?? defaults.autoAria
|
|
4654
|
-
})
|
|
4655
|
-
};
|
|
4656
|
-
}
|
|
4657
4845
|
const HISTORY_MODULE_KEY = "history";
|
|
4658
4846
|
function buildFreshState(key, schema, configuration, registry) {
|
|
4659
4847
|
const pending = registry.pendingHydration.get(key);
|
|
@@ -4673,13 +4861,11 @@ function buildFreshState(key, schema, configuration, registry) {
|
|
|
4673
4861
|
hydration: pending,
|
|
4674
4862
|
ssr: registry.ssr,
|
|
4675
4863
|
...pickDefined({
|
|
4676
|
-
strict: configuration.strict,
|
|
4677
4864
|
validateOn: configuration.validateOn,
|
|
4678
4865
|
debounceMs: configuration.debounceMs,
|
|
4679
4866
|
rememberVariants: configuration.rememberVariants,
|
|
4680
4867
|
disabled: configuration.disabled,
|
|
4681
4868
|
coerce: configuration.coerce,
|
|
4682
|
-
getDisplayState: configuration.getDisplayState,
|
|
4683
4869
|
initialBlankPaths
|
|
4684
4870
|
}),
|
|
4685
4871
|
// Server-only: bind the SSR prefetch coordination handles. `enqueue`
|
|
@@ -4775,12 +4961,13 @@ function makeRegisterValueProxy(capturedRegisterValue) {
|
|
|
4775
4961
|
get(_target, prop) {
|
|
4776
4962
|
if (prop === "__v_isRef") return true;
|
|
4777
4963
|
if (prop === "value") return capturedRegisterValue.value;
|
|
4964
|
+
if (prop === "isBound") return capturedRegisterValue.value !== void 0;
|
|
4778
4965
|
const v = capturedRegisterValue.value;
|
|
4779
4966
|
if (v === void 0) return void 0;
|
|
4780
4967
|
return Reflect.get(v, prop);
|
|
4781
4968
|
},
|
|
4782
4969
|
has(_target, prop) {
|
|
4783
|
-
if (prop === "__v_isRef" || prop === "value") return true;
|
|
4970
|
+
if (prop === "__v_isRef" || prop === "value" || prop === "isBound") return true;
|
|
4784
4971
|
const v = capturedRegisterValue.value;
|
|
4785
4972
|
if (v === void 0) return false;
|
|
4786
4973
|
return Reflect.has(v, prop);
|
|
@@ -4801,7 +4988,7 @@ function makeRegisterValueProxy(capturedRegisterValue) {
|
|
|
4801
4988
|
}
|
|
4802
4989
|
});
|
|
4803
4990
|
}
|
|
4804
|
-
function useRegister() {
|
|
4991
|
+
function useRegister(options) {
|
|
4805
4992
|
const instance = getCurrentInstance();
|
|
4806
4993
|
if (instance === null) {
|
|
4807
4994
|
return makeRegisterValueProxy(shallowRef(void 0));
|
|
@@ -4840,7 +5027,7 @@ function useRegister() {
|
|
|
4840
5027
|
if (el !== null && el !== void 0 && typeof el === "object") {
|
|
4841
5028
|
el[REGISTER_OWNER_MARKER] = true;
|
|
4842
5029
|
}
|
|
4843
|
-
if (capturedRegisterValue.value === void 0) ;
|
|
5030
|
+
if (capturedRegisterValue.value === void 0 && options?.optional !== true) ;
|
|
4844
5031
|
});
|
|
4845
5032
|
return makeRegisterValueProxy(capturedRegisterValue);
|
|
4846
5033
|
}
|
|
@@ -4925,38 +5112,36 @@ function createWizardHistory(param) {
|
|
|
4925
5112
|
};
|
|
4926
5113
|
}
|
|
4927
5114
|
|
|
4928
|
-
const NOOP_FINGERPRINT = "attaform:wizard-noop";
|
|
4929
5115
|
const EMPTY_SLIM_KINDS = /* @__PURE__ */ new Set();
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
errors: void 0,
|
|
4942
|
-
formKey
|
|
4943
|
-
};
|
|
4944
|
-
return {
|
|
4945
|
-
fingerprint: () => Promise.resolve(NOOP_FINGERPRINT),
|
|
4946
|
-
getDefaultValues: () => defaultsResponse,
|
|
5116
|
+
const EMPTY_VALUE = {};
|
|
5117
|
+
const NOOP_SUCCESS = {
|
|
5118
|
+
success: true,
|
|
5119
|
+
data: EMPTY_VALUE,
|
|
5120
|
+
errors: void 0
|
|
5121
|
+
};
|
|
5122
|
+
const NOOP_DEFAULTS = NOOP_SUCCESS;
|
|
5123
|
+
let NOOP_SCHEMA;
|
|
5124
|
+
function buildNoopWizardSchema() {
|
|
5125
|
+
NOOP_SCHEMA ?? (NOOP_SCHEMA = {
|
|
5126
|
+
getDefaultValues: () => NOOP_DEFAULTS,
|
|
4947
5127
|
getDefaultAtPath: () => void 0,
|
|
4948
5128
|
getEmptyValueAtPath: () => void 0,
|
|
4949
5129
|
isPreprocessOrCoerceLeaf: () => false,
|
|
5130
|
+
isOpaqueLeafAtPath: () => false,
|
|
4950
5131
|
arrayShapeAtPath: () => null,
|
|
4951
5132
|
isFixedObjectAtPath: (path) => path.length === 0,
|
|
5133
|
+
// The noop schema declares no shape at all, so nothing under it is
|
|
5134
|
+
// addressable, root included.
|
|
5135
|
+
entryKeyKindAtPath: () => void 0,
|
|
4952
5136
|
getSchemasAtPath: () => [],
|
|
4953
|
-
validateAtPath: () =>
|
|
5137
|
+
validateAtPath: () => NOOP_SUCCESS,
|
|
4954
5138
|
getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
|
|
4955
5139
|
isLeafAtPath: () => false,
|
|
4956
5140
|
isRequiredAtPath: () => false,
|
|
4957
5141
|
getUnionDiscriminatorAtPath: () => void 0,
|
|
4958
5142
|
hasDiscriminatedUnions: () => false
|
|
4959
|
-
};
|
|
5143
|
+
});
|
|
5144
|
+
return NOOP_SCHEMA;
|
|
4960
5145
|
}
|
|
4961
5146
|
|
|
4962
5147
|
function buildCallableReadonlySnapshotProxy(opts) {
|
|
@@ -5071,7 +5256,7 @@ function useWizard(options) {
|
|
|
5071
5256
|
if (typeof slot !== "string") continue;
|
|
5072
5257
|
if (noopForms.has(slot)) continue;
|
|
5073
5258
|
const noop = useAbstractForm({
|
|
5074
|
-
schema: buildNoopWizardSchema(
|
|
5259
|
+
schema: buildNoopWizardSchema(),
|
|
5075
5260
|
key: slot
|
|
5076
5261
|
});
|
|
5077
5262
|
noopForms.set(slot, noop);
|
|
@@ -5082,7 +5267,7 @@ function useWizard(options) {
|
|
|
5082
5267
|
const noop = lazyNoopScope.run(
|
|
5083
5268
|
() => useAbstractForm(
|
|
5084
5269
|
{
|
|
5085
|
-
schema: buildNoopWizardSchema(
|
|
5270
|
+
schema: buildNoopWizardSchema(),
|
|
5086
5271
|
key
|
|
5087
5272
|
},
|
|
5088
5273
|
{ registry }
|
|
@@ -5710,6 +5895,24 @@ function useWizard(options) {
|
|
|
5710
5895
|
const target = list[idx + 1];
|
|
5711
5896
|
moveTo(target.key);
|
|
5712
5897
|
}
|
|
5898
|
+
let cancelDeferredAdvance = null;
|
|
5899
|
+
function advanceWhenInFlightSubmitLands(store, key) {
|
|
5900
|
+
cancelDeferredAdvance?.();
|
|
5901
|
+
const attemptsAtRequest = store.submissionAttempts.value;
|
|
5902
|
+
const off = store.onSubmitSuccess(() => {
|
|
5903
|
+
off();
|
|
5904
|
+
cancelDeferredAdvance = null;
|
|
5905
|
+
if (store.submissionAttempts.value !== attemptsAtRequest) return;
|
|
5906
|
+
if (activeKey.value !== key) return;
|
|
5907
|
+
advanceOne();
|
|
5908
|
+
});
|
|
5909
|
+
cancelDeferredAdvance = off;
|
|
5910
|
+
}
|
|
5911
|
+
function inFlightActiveStore() {
|
|
5912
|
+
const store = registry.forms.get(activeKey.value);
|
|
5913
|
+
if (store === void 0 || store.activeSubmissions.value === 0) return void 0;
|
|
5914
|
+
return store;
|
|
5915
|
+
}
|
|
5713
5916
|
async function next() {
|
|
5714
5917
|
if (submitting.value) {
|
|
5715
5918
|
return;
|
|
@@ -5723,7 +5926,12 @@ function useWizard(options) {
|
|
|
5723
5926
|
return;
|
|
5724
5927
|
}
|
|
5725
5928
|
const active = list[idx];
|
|
5726
|
-
if (active !== void 0 && active.isGate) {
|
|
5929
|
+
if (active !== void 0 && active.isGate && !clearedGates.has(active.key)) {
|
|
5930
|
+
const inFlight = inFlightActiveStore();
|
|
5931
|
+
if (inFlight !== void 0) {
|
|
5932
|
+
advanceWhenInFlightSubmitLands(inFlight, activeKey.value);
|
|
5933
|
+
return;
|
|
5934
|
+
}
|
|
5727
5935
|
await tryNext();
|
|
5728
5936
|
return;
|
|
5729
5937
|
}
|
|
@@ -5744,11 +5952,16 @@ function useWizard(options) {
|
|
|
5744
5952
|
const form = activeForm.value;
|
|
5745
5953
|
if (form === void 0) return false;
|
|
5746
5954
|
const before = activeKey.value;
|
|
5955
|
+
const inFlight = inFlightActiveStore();
|
|
5956
|
+
if (inFlight !== void 0) {
|
|
5957
|
+
advanceWhenInFlightSubmitLands(inFlight, before);
|
|
5958
|
+
return false;
|
|
5959
|
+
}
|
|
5747
5960
|
let ranClean = false;
|
|
5748
5961
|
await asHandleSubmitSource(form).handleSubmit(() => {
|
|
5749
5962
|
ranClean = true;
|
|
5750
5963
|
})();
|
|
5751
|
-
if (ranClean) advanceOne();
|
|
5964
|
+
if (ranClean && activeKey.value === before) advanceOne();
|
|
5752
5965
|
return activeKey.value !== before;
|
|
5753
5966
|
}
|
|
5754
5967
|
function back() {
|
|
@@ -5988,6 +6201,7 @@ function useWizard(options) {
|
|
|
5988
6201
|
onScopeDispose(() => {
|
|
5989
6202
|
historyHandle.dispose();
|
|
5990
6203
|
lazyNoopScope.stop();
|
|
6204
|
+
cancelDeferredAdvance?.();
|
|
5991
6205
|
});
|
|
5992
6206
|
}
|
|
5993
6207
|
const explicitKey = options.key;
|
|
@@ -6137,4 +6351,4 @@ function escapeForInlineScript(json) {
|
|
|
6137
6351
|
});
|
|
6138
6352
|
}
|
|
6139
6353
|
|
|
6140
|
-
export { AttaformErrorCode as A,
|
|
6354
|
+
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 };
|