attaform 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/dev-key-collision-warnings.cjs +1 -1
- package/dist/chunks/dev-key-collision-warnings.mjs +1 -1
- package/dist/chunks/devtools.cjs +1 -1
- package/dist/chunks/devtools.mjs +1 -1
- package/dist/chunks/fingerprint2.cjs +1 -1
- package/dist/chunks/fingerprint2.mjs +1 -1
- package/dist/chunks/indexeddb.cjs +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/multi-tab-sync.cjs +2 -2
- package/dist/chunks/multi-tab-sync.mjs +2 -2
- package/dist/chunks/session-storage.cjs +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/chunks/wire-persistence.cjs +2 -2
- package/dist/chunks/wire-persistence.mjs +2 -2
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +15 -14
- package/dist/index.d.mts +15 -14
- package/dist/index.d.ts +15 -14
- package/dist/index.mjs +5 -5
- package/dist/nuxt.d.cts +1 -1
- package/dist/nuxt.d.mts +1 -1
- package/dist/nuxt.d.ts +1 -1
- package/dist/runtime/plugins/attaform.cjs +2 -2
- package/dist/runtime/plugins/attaform.mjs +2 -2
- package/dist/shared/{attaform.BzvOdiSI.cjs → attaform.BSkvn43g.cjs} +4 -4
- package/dist/shared/{attaform.BzvOdiSI.cjs.map → attaform.BSkvn43g.cjs.map} +1 -1
- package/dist/shared/{attaform.F8LMHHWV.d.cts → attaform.BWfliRIK.d.cts} +78 -2
- package/dist/shared/{attaform.r3PePkDR.mjs → attaform.Be8NZG9M.mjs} +9 -3
- package/dist/shared/attaform.Be8NZG9M.mjs.map +1 -0
- package/dist/shared/{attaform.CEf6wYfD.cjs → attaform.Bq5sX7TF.cjs} +2 -2
- package/dist/shared/{attaform.CEf6wYfD.cjs.map → attaform.Bq5sX7TF.cjs.map} +1 -1
- package/dist/shared/{attaform.7lzO9pdM.d.mts → attaform.Bv7dRDWK.d.ts} +78 -2
- package/dist/shared/{attaform._rsCZy2j.cjs → attaform.CICFZ1iS.cjs} +9 -3
- package/dist/shared/attaform.CICFZ1iS.cjs.map +1 -0
- package/dist/shared/{attaform.BUszFoKq.cjs → attaform.ClXwitZj.cjs} +366 -63
- package/dist/shared/attaform.ClXwitZj.cjs.map +1 -0
- package/dist/shared/{attaform.B1nyO4ec.d.cts → attaform.D0dWZsJt.d.cts} +269 -49
- package/dist/shared/{attaform.B1nyO4ec.d.mts → attaform.D0dWZsJt.d.mts} +269 -49
- package/dist/shared/{attaform.B1nyO4ec.d.ts → attaform.D0dWZsJt.d.ts} +269 -49
- package/dist/shared/{attaform.BA3vRDos.cjs → attaform.D32WwKk6.cjs} +214 -33
- package/dist/shared/attaform.D32WwKk6.cjs.map +1 -0
- package/dist/shared/{attaform.BnK_bfcb.mjs → attaform.DMEP_ENr.mjs} +4 -4
- package/dist/shared/{attaform.PnqML3xW.cjs.map → attaform.DMEP_ENr.mjs.map} +1 -1
- package/dist/shared/{attaform.DSqO6Db7.mjs → attaform.DR6RmxWZ.mjs} +367 -64
- package/dist/shared/attaform.DR6RmxWZ.mjs.map +1 -0
- package/dist/shared/{attaform.CkjTapyq.mjs → attaform.DozgVlCE.mjs} +4 -4
- package/dist/shared/{attaform.CkjTapyq.mjs.map → attaform.DozgVlCE.mjs.map} +1 -1
- package/dist/shared/{attaform.BK1RE2ha.d.ts → attaform.Duecg2NO.d.mts} +2 -2
- package/dist/shared/{attaform.BDIEq9qP.d.cts → attaform.FudOcHaa.d.cts} +2 -2
- package/dist/shared/{attaform.BQ6drorq.d.mts → attaform.MtrpT6Ki.d.ts} +2 -2
- package/dist/shared/{attaform.CRsXyy-Y.d.ts → attaform.NQ8mybyW.d.mts} +78 -2
- package/dist/shared/{attaform.PnqML3xW.cjs → attaform.S-pYLSo4.cjs} +4 -4
- package/dist/shared/{attaform.BnK_bfcb.mjs.map → attaform.S-pYLSo4.cjs.map} +1 -1
- package/dist/shared/{attaform.ezb5Nh2t.mjs → attaform.Y1ZGhM4k.mjs} +2 -2
- package/dist/shared/{attaform.ezb5Nh2t.mjs.map → attaform.Y1ZGhM4k.mjs.map} +1 -1
- package/dist/shared/{attaform.Y_Mgg0Yp.mjs → attaform.pmtahXKy.mjs} +214 -34
- package/dist/shared/attaform.pmtahXKy.mjs.map +1 -0
- package/dist/zod-v3.cjs +3 -3
- package/dist/zod-v3.d.cts +3 -3
- package/dist/zod-v3.d.mts +3 -3
- package/dist/zod-v3.d.ts +3 -3
- package/dist/zod-v3.mjs +3 -3
- package/dist/zod-v4.cjs +3 -3
- package/dist/zod-v4.d.cts +4 -4
- package/dist/zod-v4.d.mts +4 -4
- package/dist/zod-v4.d.ts +4 -4
- package/dist/zod-v4.mjs +3 -3
- package/dist/zod.cjs +5 -5
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +52 -10
- package/dist/zod.d.mts +52 -10
- package/dist/zod.d.ts +52 -10
- package/dist/zod.mjs +6 -6
- package/dist/zod.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/shared/attaform.BA3vRDos.cjs.map +0 -1
- package/dist/shared/attaform.BUszFoKq.cjs.map +0 -1
- package/dist/shared/attaform.DSqO6Db7.mjs.map +0 -1
- package/dist/shared/attaform.Y_Mgg0Yp.mjs.map +0 -1
- package/dist/shared/attaform._rsCZy2j.cjs.map +0 -1
- package/dist/shared/attaform.r3PePkDR.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { computed, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, readonly,
|
|
2
|
-
import { _ as __DEV__, j as canonicalizePath, G as segmentsForPathKey, t as isPathPrefix, b as FORM_ERRORS_PATH_KEY, S as SubmitErrorHandlerError, A as AnonPersistError, k as captureUserCallSite, I as INTERACTIVE_TAG_NAMES, r as getOrAssignElementId, e as ROOT_PATH_KEY, R as ROOT_PATH, h as allowSensitivePersist, F as FORM_ERRORS_PATH, l as coerceToPathKey, v as isSensitivePath, o as createPersistOptInRegistry, d as InvalidUseFormConfigError, q as ensureAttaformInstalled,
|
|
1
|
+
import { computed, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, readonly, toRaw, reactive, watch, markRaw, shallowRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, effectScope, nextTick } from 'vue';
|
|
2
|
+
import { _ as __DEV__, j as canonicalizePath, G as segmentsForPathKey, t as isPathPrefix, b as FORM_ERRORS_PATH_KEY, S as SubmitErrorHandlerError, H as toError, A as AnonPersistError, k as captureUserCallSite, I as INTERACTIVE_TAG_NAMES, r as getOrAssignElementId, e as ROOT_PATH_KEY, R as ROOT_PATH, h as allowSensitivePersist, F as FORM_ERRORS_PATH, l as coerceToPathKey, v as isSensitivePath, o as createPersistOptInRegistry, d as InvalidUseFormConfigError, q as ensureAttaformInstalled, K as useRegistry, z as kFormContext, B as kFormInstanceId, g as ReservedFormKeyError, n as createIsSensitivePath, y as kAttaformWizardActiveStepResolver, w as kAttaformAncestorWizard } from './attaform.pmtahXKy.mjs';
|
|
3
3
|
|
|
4
4
|
function safeAssign(target, key, value) {
|
|
5
5
|
if (key === "__proto__") {
|
|
@@ -13,10 +13,14 @@ function safeAssign(target, key, value) {
|
|
|
13
13
|
}
|
|
14
14
|
target[key] = value;
|
|
15
15
|
}
|
|
16
|
+
function isShadowedKey(key) {
|
|
17
|
+
return key in Object.prototype;
|
|
18
|
+
}
|
|
16
19
|
function safeOwnRead(target, key) {
|
|
17
|
-
if (key
|
|
18
|
-
const desc = Object.getOwnPropertyDescriptor(target,
|
|
19
|
-
return
|
|
20
|
+
if (isShadowedKey(key)) {
|
|
21
|
+
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
22
|
+
if (desc === void 0) return void 0;
|
|
23
|
+
return "value" in desc ? desc.value : target[key];
|
|
20
24
|
}
|
|
21
25
|
return target[key];
|
|
22
26
|
}
|
|
@@ -35,6 +39,10 @@ function descendStep(value, segment) {
|
|
|
35
39
|
}
|
|
36
40
|
const record = value;
|
|
37
41
|
const key = typeof segment === "number" ? String(segment) : segment;
|
|
42
|
+
if (isShadowedKey(key)) {
|
|
43
|
+
if (!safeOwnHas(record, key)) return NOT_FOUND;
|
|
44
|
+
return safeOwnRead(record, key);
|
|
45
|
+
}
|
|
38
46
|
if (!(key in record)) return NOT_FOUND;
|
|
39
47
|
return record[key];
|
|
40
48
|
}
|
|
@@ -64,6 +72,7 @@ function hasAtPath(root, path) {
|
|
|
64
72
|
return typeof last === "number" && last >= 0 && last < current.length;
|
|
65
73
|
}
|
|
66
74
|
const key = typeof last === "number" ? String(last) : last;
|
|
75
|
+
if (isShadowedKey(key)) return safeOwnHas(current, key);
|
|
67
76
|
return key in current;
|
|
68
77
|
}
|
|
69
78
|
function isPlainRecord(value) {
|
|
@@ -470,7 +479,12 @@ function computeVerdict(field, formMeta) {
|
|
|
470
479
|
if (field.valid === true && field.blank !== true && field.dirty === true) return "success";
|
|
471
480
|
return "idle";
|
|
472
481
|
}
|
|
473
|
-
|
|
482
|
+
function earliestNonNull(a, b) {
|
|
483
|
+
if (a === null) return b;
|
|
484
|
+
if (b === null) return a;
|
|
485
|
+
return a < b ? a : b;
|
|
486
|
+
}
|
|
487
|
+
const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
|
|
474
488
|
const FOCUS_OUT_GRACE = 16;
|
|
475
489
|
const defaultFamily = /* @__PURE__ */ new WeakSet();
|
|
476
490
|
function isDefaultDisplayState(fn) {
|
|
@@ -480,10 +494,11 @@ function makeDefaultDisplayState({
|
|
|
480
494
|
showDelay,
|
|
481
495
|
minVisible
|
|
482
496
|
}) {
|
|
483
|
-
const reducer = (prev, { field, formMeta, validatingSince, now }) => {
|
|
497
|
+
const reducer = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
|
|
484
498
|
const verdict = computeVerdict(field, formMeta);
|
|
485
499
|
if (!isGateOpen(field, formMeta)) return { display: verdict };
|
|
486
|
-
|
|
500
|
+
const inFlightSince = earliestNonNull(validatingSince, transformingSince);
|
|
501
|
+
if (inFlightSince === null) {
|
|
487
502
|
if (prev.display === "pending") {
|
|
488
503
|
const shownAt = prev.pendingShownAt ?? now;
|
|
489
504
|
if (now < shownAt + minVisible)
|
|
@@ -494,8 +509,8 @@ function makeDefaultDisplayState({
|
|
|
494
509
|
if (prev.display === "pending")
|
|
495
510
|
return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
|
|
496
511
|
const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
|
|
497
|
-
if (now -
|
|
498
|
-
return { display: prev.display, reviewAt:
|
|
512
|
+
if (now - inFlightSince < window) {
|
|
513
|
+
return { display: prev.display, reviewAt: inFlightSince + window };
|
|
499
514
|
}
|
|
500
515
|
return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
|
|
501
516
|
};
|
|
@@ -621,6 +636,8 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
621
636
|
if (blankForKey !== void 0) errors.push(...blankForKey);
|
|
622
637
|
if (userForKey !== void 0) errors.push(...userForKey);
|
|
623
638
|
const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
|
|
639
|
+
const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
|
|
640
|
+
const transformError = state.transformErrors.get(key) ?? null;
|
|
624
641
|
const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
|
|
625
642
|
const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
|
|
626
643
|
const valid = !gated && errors.length === 0 && !validating && !isOrphan;
|
|
@@ -647,6 +664,9 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
647
664
|
errors,
|
|
648
665
|
validating,
|
|
649
666
|
valid,
|
|
667
|
+
transforming,
|
|
668
|
+
busy: transforming || validating,
|
|
669
|
+
transformError,
|
|
650
670
|
path: segments,
|
|
651
671
|
...computeFieldIdentity(formInstanceId, state.formKey, key),
|
|
652
672
|
key: state.arrayElementKey(segments),
|
|
@@ -660,12 +680,14 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
660
680
|
function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
|
|
661
681
|
const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
|
|
662
682
|
const validatingSince = state.fieldValidatingSince.get(key) ?? null;
|
|
683
|
+
const transformingSince = state.fieldTransformingSince.get(key) ?? null;
|
|
663
684
|
return decorateWithDerivedProps(
|
|
664
685
|
base,
|
|
665
686
|
state,
|
|
666
687
|
getFormMetaBase,
|
|
667
688
|
key,
|
|
668
689
|
validatingSince,
|
|
690
|
+
transformingSince,
|
|
669
691
|
false,
|
|
670
692
|
// revealedDescendantError: leaves have no descendants
|
|
671
693
|
false,
|
|
@@ -688,6 +710,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
688
710
|
let connected = false;
|
|
689
711
|
let validating = false;
|
|
690
712
|
let validatingSince = null;
|
|
713
|
+
let transforming = false;
|
|
714
|
+
let transformingSince = null;
|
|
691
715
|
let updatedAt = null;
|
|
692
716
|
let asyncPending = false;
|
|
693
717
|
const submissionAttempts = state.submissionAttempts.value;
|
|
@@ -718,6 +742,13 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
718
742
|
if (leafGateOpen && since !== void 0 && (validatingSince === null || since < validatingSince))
|
|
719
743
|
validatingSince = since;
|
|
720
744
|
}
|
|
745
|
+
if ((state.fieldTransformCounts.get(leafKey) ?? 0) > 0) {
|
|
746
|
+
transforming = true;
|
|
747
|
+
const leafGateOpen = submissionAttempts > 0 || leafRecord?.blurredAfterInteraction === true;
|
|
748
|
+
const since = state.fieldTransformingSince.get(leafKey);
|
|
749
|
+
if (leafGateOpen && since !== void 0 && (transformingSince === null || since < transformingSince))
|
|
750
|
+
transformingSince = since;
|
|
751
|
+
}
|
|
721
752
|
if (state.pathHasAsyncValidationByKey(leafKey, entry.segments)) asyncPending = true;
|
|
722
753
|
const ts = leafRecord?.updatedAt;
|
|
723
754
|
if (ts !== void 0 && ts !== null) {
|
|
@@ -737,6 +768,19 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
737
768
|
return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
|
|
738
769
|
});
|
|
739
770
|
if (!asyncPending && state.pathHasAsyncValidation(segments)) asyncPending = true;
|
|
771
|
+
if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
|
|
772
|
+
validating = true;
|
|
773
|
+
const since = state.fieldValidatingSince.get(key);
|
|
774
|
+
if (since !== void 0 && (validatingSince === null || since < validatingSince))
|
|
775
|
+
validatingSince = since;
|
|
776
|
+
}
|
|
777
|
+
if ((state.fieldTransformCounts.get(key) ?? 0) > 0) {
|
|
778
|
+
transforming = true;
|
|
779
|
+
const since = state.fieldTransformingSince.get(key);
|
|
780
|
+
if (since !== void 0 && (transformingSince === null || since < transformingSince))
|
|
781
|
+
transformingSince = since;
|
|
782
|
+
}
|
|
783
|
+
const ownTransformError = state.transformErrors.get(key) ?? null;
|
|
740
784
|
const gated = asyncPending && !state.firstValidationDone.value;
|
|
741
785
|
const valid = !gated && errors.length === 0 && !validating;
|
|
742
786
|
const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
|
|
@@ -760,6 +804,12 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
760
804
|
errors,
|
|
761
805
|
validating,
|
|
762
806
|
valid,
|
|
807
|
+
transforming,
|
|
808
|
+
busy: transforming || validating,
|
|
809
|
+
// A container surfaces its OWN transform failure (a transform registered
|
|
810
|
+
// on the container path, e.g. a file normalizer) but never rolls up a
|
|
811
|
+
// descendant leaf's failure — that stays a per-field channel.
|
|
812
|
+
transformError: ownTransformError,
|
|
763
813
|
path: segments,
|
|
764
814
|
...computeFieldIdentity(formInstanceId, state.formKey, key),
|
|
765
815
|
key: state.arrayElementKey(segments),
|
|
@@ -770,28 +820,25 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
770
820
|
meta: resolved.meta
|
|
771
821
|
},
|
|
772
822
|
validatingSince,
|
|
823
|
+
transformingSince,
|
|
773
824
|
revealedDescendantError
|
|
774
825
|
};
|
|
775
826
|
}
|
|
776
827
|
function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
|
|
777
|
-
const { base, validatingSince, revealedDescendantError } = buildContainerFieldStateBase(
|
|
778
|
-
state,
|
|
779
|
-
segments,
|
|
780
|
-
key,
|
|
781
|
-
formInstanceId
|
|
782
|
-
);
|
|
828
|
+
const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
|
|
783
829
|
return decorateWithDerivedProps(
|
|
784
830
|
base,
|
|
785
831
|
state,
|
|
786
832
|
getFormMetaBase,
|
|
787
833
|
key,
|
|
788
834
|
validatingSince,
|
|
835
|
+
transformingSince,
|
|
789
836
|
revealedDescendantError,
|
|
790
837
|
segments.length === 0,
|
|
791
838
|
getDisplayState
|
|
792
839
|
);
|
|
793
840
|
}
|
|
794
|
-
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, revealedDescendantError, isRoot, getDisplayState) {
|
|
841
|
+
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot, getDisplayState) {
|
|
795
842
|
const firstError = base.errors[0];
|
|
796
843
|
const predicate = getDisplayState ?? state.getDisplayState;
|
|
797
844
|
const formMeta = getFormMetaBase();
|
|
@@ -799,6 +846,7 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
|
|
|
799
846
|
field: base,
|
|
800
847
|
formMeta,
|
|
801
848
|
validatingSince,
|
|
849
|
+
transformingSince,
|
|
802
850
|
// The engine's clock. Frozen to 0 under SSR (no clock, nothing in
|
|
803
851
|
// flight) so the reducer returns the plain verdict and hydration matches.
|
|
804
852
|
now: state.ssr ? 0 : Date.now()
|
|
@@ -865,6 +913,15 @@ function liveKeysAtPath(state, segments) {
|
|
|
865
913
|
if (typeof value === "object") return Object.keys(value);
|
|
866
914
|
return [];
|
|
867
915
|
}
|
|
916
|
+
function liveContainerHasKey(state, segments, key) {
|
|
917
|
+
const value = getAtPath(state.form.value, segments);
|
|
918
|
+
if (value === null || value === void 0 || typeof value !== "object") return false;
|
|
919
|
+
if (Array.isArray(value)) {
|
|
920
|
+
const index = Number(key);
|
|
921
|
+
return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
|
|
922
|
+
}
|
|
923
|
+
return Object.hasOwn(value, key);
|
|
924
|
+
}
|
|
868
925
|
function isArrayPath(state, segments) {
|
|
869
926
|
if (segments.length === 0) return false;
|
|
870
927
|
return Array.isArray(getAtPath(state.form.value, segments));
|
|
@@ -893,6 +950,21 @@ const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
|
|
|
893
950
|
function keyToSegment(key) {
|
|
894
951
|
return INTEGER_SEGMENT.test(key) ? Number(key) : key;
|
|
895
952
|
}
|
|
953
|
+
function callableInvokeShim(method, surface, getDescent) {
|
|
954
|
+
const fnMethod = Reflect.get(Function.prototype, method);
|
|
955
|
+
return new Proxy((() => {
|
|
956
|
+
}), {
|
|
957
|
+
apply: (_target, _thisArg, args) => Reflect.apply(fnMethod, surface, args),
|
|
958
|
+
get: (_target, key) => Reflect.get(getDescent(), key),
|
|
959
|
+
has: (_target, key) => Reflect.has(getDescent(), key),
|
|
960
|
+
ownKeys: () => Reflect.ownKeys(getDescent()),
|
|
961
|
+
getOwnPropertyDescriptor: (_target, key) => {
|
|
962
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(getDescent(), key);
|
|
963
|
+
if (descriptor !== void 0) descriptor.configurable = true;
|
|
964
|
+
return descriptor;
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
}
|
|
896
968
|
function buildSurfaceProxy(opts) {
|
|
897
969
|
const containerCache = /* @__PURE__ */ new Map();
|
|
898
970
|
const leafViewCache = /* @__PURE__ */ new Map();
|
|
@@ -919,6 +991,8 @@ function buildSurfaceProxy(opts) {
|
|
|
919
991
|
const cacheKey = `${JSON.stringify(segments)}+${isArrayLike ? "A" : "O"}`;
|
|
920
992
|
const existing = containerCache.get(cacheKey);
|
|
921
993
|
if (existing !== void 0) return existing;
|
|
994
|
+
const isFixedObject = opts.schema.isFixedObjectAtPath(segments);
|
|
995
|
+
const containerHasKey = (k) => opts.containerHasOwnKey !== void 0 ? opts.containerHasOwnKey(segments, k) : opts.containerOwnKeys?.(segments).includes(k) === true;
|
|
922
996
|
const snapshotContainer = () => opts.materializeContainer === void 0 ? {} : opts.materializeContainer(segments);
|
|
923
997
|
const {
|
|
924
998
|
toString: containerToString,
|
|
@@ -926,8 +1000,9 @@ function buildSurfaceProxy(opts) {
|
|
|
926
1000
|
toJSON: containerToJSON,
|
|
927
1001
|
toPrimitive: containerToPrimitive
|
|
928
1002
|
} = makeReadonlyCoercion(snapshotContainer);
|
|
929
|
-
const
|
|
930
|
-
|
|
1003
|
+
const isRoot = segments.length === 0;
|
|
1004
|
+
const target = isRoot ? (() => {
|
|
1005
|
+
}) : isArrayLike ? [] : {};
|
|
931
1006
|
const proxy = new Proxy(target, {
|
|
932
1007
|
apply(_, __, args) {
|
|
933
1008
|
const arg = args[0];
|
|
@@ -958,7 +1033,16 @@ function buildSurfaceProxy(opts) {
|
|
|
958
1033
|
return key === "toString" ? containerToString : containerValueOf;
|
|
959
1034
|
}
|
|
960
1035
|
}
|
|
961
|
-
|
|
1036
|
+
if (key === "hasOwnProperty" && !schemaHasPath(childSegs)) {
|
|
1037
|
+
return Object.prototype.hasOwnProperty;
|
|
1038
|
+
}
|
|
1039
|
+
if (isRoot && (key === "call" || key === "apply" || key === "bind")) {
|
|
1040
|
+
return callableInvokeShim(key, proxy, () => descendOrTerminate(childSegs));
|
|
1041
|
+
}
|
|
1042
|
+
if (opts.isTerminalAt?.(childSegs) === true || isFixedObject && schemaHasPath(childSegs) || containerHasKey(key)) {
|
|
1043
|
+
return descendOrTerminate(childSegs);
|
|
1044
|
+
}
|
|
1045
|
+
return void 0;
|
|
962
1046
|
},
|
|
963
1047
|
has(_, key) {
|
|
964
1048
|
if (typeof key === "symbol") return Reflect.has(target, key);
|
|
@@ -1043,15 +1127,8 @@ function buildSurfaceProxy(opts) {
|
|
|
1043
1127
|
toJSON: leafToJSONHandler,
|
|
1044
1128
|
toPrimitive: leafToPrimitive
|
|
1045
1129
|
} = makeReadonlyCoercion(snapshotLeaf);
|
|
1046
|
-
const target =
|
|
1047
|
-
});
|
|
1130
|
+
const target = {};
|
|
1048
1131
|
const proxy = new Proxy(target, {
|
|
1049
|
-
apply(_, __, args) {
|
|
1050
|
-
const arg = args[0];
|
|
1051
|
-
if (arg === void 0) return opts.resolveCallTarget(segments);
|
|
1052
|
-
const { segments: argSegs } = canonicalizePath(arg);
|
|
1053
|
-
return opts.resolveCallTarget(argSegs);
|
|
1054
|
-
},
|
|
1055
1132
|
get(_, key) {
|
|
1056
1133
|
if (typeof key === "symbol") {
|
|
1057
1134
|
if (key === Symbol.toPrimitive) return leafToPrimitive;
|
|
@@ -1061,6 +1138,9 @@ function buildSurfaceProxy(opts) {
|
|
|
1061
1138
|
if (key === "toString") return leafToString;
|
|
1062
1139
|
if (key === "valueOf") return leafValueOf;
|
|
1063
1140
|
if (key === "toJSON") return leafToJSONHandler;
|
|
1141
|
+
if (key === "hasOwnProperty" && !schemaHasPath([...segments, keyToSegment(key)])) {
|
|
1142
|
+
return Object.prototype.hasOwnProperty;
|
|
1143
|
+
}
|
|
1064
1144
|
if (leafKeys.has(key)) {
|
|
1065
1145
|
const leaf = opts.resolveLeaf(segments);
|
|
1066
1146
|
return readLeafKey(leaf, key);
|
|
@@ -1073,8 +1153,8 @@ function buildSurfaceProxy(opts) {
|
|
|
1073
1153
|
return true;
|
|
1074
1154
|
},
|
|
1075
1155
|
// Iteration: leaf-views expose the leaf-key set so
|
|
1076
|
-
// `
|
|
1077
|
-
//
|
|
1156
|
+
// `Object.keys(form.fields.email)` / spread enumerate the
|
|
1157
|
+
// FieldState props. (`JSON.stringify` routes through `toJSON` above.)
|
|
1078
1158
|
ownKeys: () => Array.from(leafKeys),
|
|
1079
1159
|
getOwnPropertyDescriptor(_, key) {
|
|
1080
1160
|
if (typeof key !== "string") return void 0;
|
|
@@ -1183,6 +1263,12 @@ function buildErrorsProxy(state) {
|
|
|
1183
1263
|
// library-produced verdicts (schema + derived-blank) at unreachable
|
|
1184
1264
|
// paths stay hidden; user-supplied errors are unconditional.
|
|
1185
1265
|
containerOwnKeys: (segments) => errorAwareContainerKeys(state, segments),
|
|
1266
|
+
// Fast path: a key the live form data holds short-circuits before the
|
|
1267
|
+
// O(n) error-store scan, so iterating `form.errors.<array>` over live
|
|
1268
|
+
// indices stays linear. The scan still runs for a key with no live
|
|
1269
|
+
// home — a server error at a non-schema key (`form.errors.ghost`) —
|
|
1270
|
+
// so it keeps surfacing while a genuinely-absent key reads undefined.
|
|
1271
|
+
containerHasOwnKey: (segments, key) => liveContainerHasKey(state, segments, key) || errorAwareContainerKeys(state, segments).includes(key),
|
|
1186
1272
|
isArrayContainer: (segments) => isArrayPath(state, segments)
|
|
1187
1273
|
});
|
|
1188
1274
|
}
|
|
@@ -1356,6 +1442,9 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1356
1442
|
"errors",
|
|
1357
1443
|
"validating",
|
|
1358
1444
|
"valid",
|
|
1445
|
+
"transforming",
|
|
1446
|
+
"busy",
|
|
1447
|
+
"transformError",
|
|
1359
1448
|
"displayState",
|
|
1360
1449
|
"showErrors",
|
|
1361
1450
|
"showPending",
|
|
@@ -1458,14 +1547,22 @@ function buildFieldStateProxy(state, formInstanceId, getFormMetaBase, options) {
|
|
|
1458
1547
|
terminalCache.set(cacheKey, proxy);
|
|
1459
1548
|
return proxy;
|
|
1460
1549
|
}
|
|
1550
|
+
const surfaceSchema = state.schema;
|
|
1461
1551
|
return buildSurfaceProxy({
|
|
1462
|
-
schema:
|
|
1552
|
+
schema: surfaceSchema,
|
|
1463
1553
|
resolveLeaf: (path) => getFieldStateAt(path),
|
|
1464
1554
|
leafKeys: FIELD_STATE_KEYS,
|
|
1465
1555
|
readLeafKey: (computed, key) => computed.value[key],
|
|
1466
1556
|
materializeContainer: (segments) => materializeFields(state, segments, snapshotFieldStateAt),
|
|
1467
|
-
|
|
1557
|
+
// `form.fields(path)` resolves a FieldState for any path the SCHEMA
|
|
1558
|
+
// declares — a leaf, a container, an inactive discriminated-union
|
|
1559
|
+
// variant key, or an out-of-bounds array index (the element schema
|
|
1560
|
+
// admits any index). A path the schema doesn't have is a typo, not a
|
|
1561
|
+
// field, so it reads `undefined` rather than a phantom stub. The
|
|
1562
|
+
// empty path (`form.fields()`) is the root object, always valid.
|
|
1563
|
+
resolveCallTarget: (path) => surfaceSchema.getSlimPrimitiveTypesAtPath(path).size > 0 ? fieldStateTerminalAt(path) : void 0,
|
|
1468
1564
|
containerOwnKeys: (segments) => liveKeysAtPath(state, segments),
|
|
1565
|
+
containerHasOwnKey: (segments, key) => liveContainerHasKey(state, segments, key),
|
|
1469
1566
|
isArrayContainer: (segments) => isArrayPath(state, segments)
|
|
1470
1567
|
});
|
|
1471
1568
|
}
|
|
@@ -1741,7 +1838,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1741
1838
|
if (!result.ok) return result.error;
|
|
1742
1839
|
return stripData(composeWithDerivedBlank(result.refinement, result.segments));
|
|
1743
1840
|
}
|
|
1744
|
-
async function
|
|
1841
|
+
async function parse(pathInput) {
|
|
1745
1842
|
const result = await runImperativeValidation(pathInput, {
|
|
1746
1843
|
cancelInFlight: false,
|
|
1747
1844
|
commitToSchemaErrors: false
|
|
@@ -1794,6 +1891,8 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1794
1891
|
state.activeSubmissions.value += 1;
|
|
1795
1892
|
state.submitting.value = true;
|
|
1796
1893
|
state.submitError.value = null;
|
|
1894
|
+
state.clearUserErrors();
|
|
1895
|
+
while (state.activeTransforms.value > 0) await state.settleTransforms();
|
|
1797
1896
|
state.cancelFieldValidation();
|
|
1798
1897
|
state.displayEngine.clear();
|
|
1799
1898
|
state.activeValidations.value += 1;
|
|
@@ -1832,9 +1931,8 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1832
1931
|
state.emitSubmitSuccess();
|
|
1833
1932
|
} catch (err) {
|
|
1834
1933
|
if (state.submissionGeneration.value === genAtEntry) {
|
|
1835
|
-
state.submitError.value = err;
|
|
1934
|
+
state.submitError.value = toError(err);
|
|
1836
1935
|
}
|
|
1837
|
-
throw err;
|
|
1838
1936
|
} finally {
|
|
1839
1937
|
if (!validationSettled) {
|
|
1840
1938
|
state.activeValidations.value = Math.max(0, state.activeValidations.value - 1);
|
|
@@ -1848,7 +1946,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1848
1946
|
};
|
|
1849
1947
|
return submitHandler;
|
|
1850
1948
|
};
|
|
1851
|
-
return { validate, validateAsync,
|
|
1949
|
+
return { validate, validateAsync, parse, handleSubmit };
|
|
1852
1950
|
}
|
|
1853
1951
|
function toSegments(pathInput) {
|
|
1854
1952
|
return canonicalizePath(pathInput).segments;
|
|
@@ -2321,6 +2419,23 @@ function buildRegister(state, formInstanceId, instanceConfig) {
|
|
|
2321
2419
|
markConnectedOptimistically: () => {
|
|
2322
2420
|
state.markConnectedOptimistically(segments);
|
|
2323
2421
|
},
|
|
2422
|
+
// --- Async transform lifecycle (internal; the directive's
|
|
2423
|
+
// deferred orchestrator is the only legitimate consumer). Thin
|
|
2424
|
+
// path-bound delegates to the store's per-path token / counter
|
|
2425
|
+
// machinery — same pattern as `markBlank` / `setValueWithInternalPath`,
|
|
2426
|
+
// so the directive (which holds only this RegisterValue, never the
|
|
2427
|
+
// store) can drive the busy/discard/error bookkeeping. ---
|
|
2428
|
+
beginTransform: (holder) => state.beginTransform(pathKey, holder),
|
|
2429
|
+
isCurrentTransform: (token) => state.isCurrentTransform(pathKey, token),
|
|
2430
|
+
endTransform: (token) => state.endTransform(pathKey, token),
|
|
2431
|
+
setTransformError: (err) => state.setTransformError(pathKey, err),
|
|
2432
|
+
// Synchronous read of "is a transform in flight at this path". The
|
|
2433
|
+
// orchestrator's `beginTransform` bumps the count before the
|
|
2434
|
+
// listener's force-sync block runs, so the directive reads this to
|
|
2435
|
+
// skip reverting the DOM to stale storage mid-flight.
|
|
2436
|
+
get transforming() {
|
|
2437
|
+
return (state.fieldTransformCounts.get(pathKey) ?? 0) > 0;
|
|
2438
|
+
},
|
|
2324
2439
|
path: pathKey,
|
|
2325
2440
|
// Frozen so a wrapper component can pass `rv.segments` directly
|
|
2326
2441
|
// to `form.fields(...)` without defensive copying — and so test
|
|
@@ -2519,7 +2634,9 @@ function expandUnsetAt(segments, schema, paths) {
|
|
|
2519
2634
|
function buildCallableReadonlySnapshotProxy(opts) {
|
|
2520
2635
|
const target = (() => {
|
|
2521
2636
|
});
|
|
2522
|
-
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
|
|
2637
|
+
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
|
|
2638
|
+
opts.coercionSnapshot ?? opts.snapshot
|
|
2639
|
+
);
|
|
2523
2640
|
const callResolve = opts.resolveCall ?? ((arg) => opts.resolveKey(String(arg)));
|
|
2524
2641
|
return new Proxy(target, {
|
|
2525
2642
|
apply(_, __, args) {
|
|
@@ -2568,27 +2685,52 @@ function buildCallableReadonlySnapshotProxy(opts) {
|
|
|
2568
2685
|
});
|
|
2569
2686
|
}
|
|
2570
2687
|
|
|
2688
|
+
function materializeFormValue(node) {
|
|
2689
|
+
if (node === null || typeof node !== "object") return node;
|
|
2690
|
+
if (Array.isArray(node)) {
|
|
2691
|
+
const out2 = new Array(node.length);
|
|
2692
|
+
for (let i = 0; i < node.length; i++) out2[i] = materializeFormValue(node[i]);
|
|
2693
|
+
return out2;
|
|
2694
|
+
}
|
|
2695
|
+
if (!isPlainRecord(node)) return toRaw(node);
|
|
2696
|
+
const rec = node;
|
|
2697
|
+
const out = {};
|
|
2698
|
+
for (const key of Object.keys(rec)) {
|
|
2699
|
+
safeAssign(out, key, materializeFormValue(safeOwnRead(rec, key)));
|
|
2700
|
+
}
|
|
2701
|
+
return out;
|
|
2702
|
+
}
|
|
2571
2703
|
function buildValuesProxy(form) {
|
|
2572
2704
|
const inner = computed(() => readonly(form.value));
|
|
2573
2705
|
return buildCallableReadonlySnapshotProxy({
|
|
2574
2706
|
surface: "form.values",
|
|
2575
2707
|
snapshot: () => inner.value,
|
|
2708
|
+
// Faithful, reactivity-preserving serialisation: walk the reactive
|
|
2709
|
+
// proxy with own-safe reads so `JSON.stringify(form.values)` /
|
|
2710
|
+
// `String(form.values)` reflect the stored data — including a field
|
|
2711
|
+
// literally named `hasOwnProperty` that Vue would otherwise shim —
|
|
2712
|
+
// while still tracking the per-key reads that drive re-render.
|
|
2713
|
+
coercionSnapshot: () => materializeFormValue(inner.value),
|
|
2576
2714
|
// Read through the readonly proxy at access time so Vue's
|
|
2577
2715
|
// dependency tracking lands inside the consumer's active effect
|
|
2578
2716
|
// — `inner.value[key]` is what triggers per-key tracking.
|
|
2579
|
-
|
|
2580
|
-
//
|
|
2581
|
-
//
|
|
2582
|
-
//
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2717
|
+
//
|
|
2718
|
+
// Prototype-shadowed names (`hasOwnProperty`, `constructor`, …) read
|
|
2719
|
+
// off the RAW target instead: own-shadows-inherited semantics still
|
|
2720
|
+
// hold (a data field by that name returns its stored value), but
|
|
2721
|
+
// when there's no such field the inherited member resolves — so
|
|
2722
|
+
// `form.values.hasOwnProperty('x')` keeps working as the real
|
|
2723
|
+
// method. The raw read dodges Vue's `hasOwnProperty` proxy shim,
|
|
2724
|
+
// which would otherwise mask a data field of that name. (`toString`
|
|
2725
|
+
// / `valueOf` / `toJSON` never reach here — the base get trap
|
|
2726
|
+
// intercepts them as coercion handlers first.)
|
|
2727
|
+
resolveKey: (key) => isShadowedKey(key) ? toRaw(inner.value)[key] : inner.value[key],
|
|
2728
|
+
// Dynamic path: walk segments through the readonly proxy with the
|
|
2729
|
+
// same own-property-safe descent the rest of the runtime uses
|
|
2730
|
+
// (`getAtPath`), so `form.values('a.hasOwnProperty')` resolves the
|
|
2731
|
+
// stored value. Per-level reads still propagate Vue's tracking for
|
|
2732
|
+
// ordinary keys.
|
|
2733
|
+
resolveCall: (arg) => getAtPath(inner.value, canonicalizePath(arg).segments),
|
|
2592
2734
|
ownKeys: () => Reflect.ownKeys(inner.value),
|
|
2593
2735
|
hasKey: (key) => Reflect.has(inner.value, key),
|
|
2594
2736
|
describeKey: (key) => {
|
|
@@ -2649,12 +2791,12 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2649
2791
|
const {
|
|
2650
2792
|
validate: validateBuilt,
|
|
2651
2793
|
validateAsync: validateAsyncBuilt,
|
|
2652
|
-
|
|
2794
|
+
parse: parseBuilt,
|
|
2653
2795
|
handleSubmit
|
|
2654
2796
|
} = buildProcessForm(state, formInstanceId, processOptions);
|
|
2655
2797
|
const validate = (pathInput) => validateBuilt(pathInput);
|
|
2656
2798
|
const validateAsync = (pathInput) => validateAsyncBuilt(pathInput);
|
|
2657
|
-
const
|
|
2799
|
+
const parse = (pathInput) => parseBuilt(pathInput);
|
|
2658
2800
|
function pathToRef(pathInput) {
|
|
2659
2801
|
const segments = canonicalizePath(pathInput).segments;
|
|
2660
2802
|
return computed(() => getAtPath(state.form.value, segments));
|
|
@@ -2882,6 +3024,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2882
3024
|
// keep the explicit form-level computation for the gate.
|
|
2883
3025
|
valid,
|
|
2884
3026
|
errors: metaErrors,
|
|
3027
|
+
// Whole-form transforming mirrors the global `activeTransforms`
|
|
3028
|
+
// counter ORed with any per-leaf transform in flight (the root
|
|
3029
|
+
// rollup), exactly as `validating` composes its lifecycle and
|
|
3030
|
+
// per-field sources. `busy` is the union of both work signals at
|
|
3031
|
+
// the form level. `transformError` is leaf-only, so the root
|
|
3032
|
+
// rollup reads it as `null` (kept for FieldState-shape parity).
|
|
3033
|
+
transforming: computed(
|
|
3034
|
+
() => state.activeTransforms.value > 0 || rootFieldState.value.transforming
|
|
3035
|
+
),
|
|
3036
|
+
busy: computed(
|
|
3037
|
+
() => state.activeValidations.value > 0 || state.activeTransforms.value > 0 || rootFieldState.value.validating || rootFieldState.value.transforming
|
|
3038
|
+
),
|
|
3039
|
+
get transformError() {
|
|
3040
|
+
return rootFieldState.value.transformError;
|
|
3041
|
+
},
|
|
2885
3042
|
// `displayState` / the `show*` booleans / `firstError` flow
|
|
2886
3043
|
// through the same root field-state computed as the rest of the
|
|
2887
3044
|
// FieldState surface, so `form.meta.displayState` matches
|
|
@@ -3110,7 +3267,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
3110
3267
|
setValue: gated(setValueImpl),
|
|
3111
3268
|
validate: gated(validate),
|
|
3112
3269
|
validateAsync: gated(validateAsync),
|
|
3113
|
-
|
|
3270
|
+
parse: gated(parse),
|
|
3271
|
+
settleTransforms: gated(state.settleTransforms),
|
|
3114
3272
|
register: gated(register),
|
|
3115
3273
|
key: state.formKey,
|
|
3116
3274
|
// Auto-unwrapping views over the per-store async-defaults lifecycle
|
|
@@ -3977,6 +4135,106 @@ function createFormStore(options) {
|
|
|
3977
4135
|
fieldValidationCounts.set(key, next);
|
|
3978
4136
|
}
|
|
3979
4137
|
}
|
|
4138
|
+
const fieldTransformCounts = reactive(/* @__PURE__ */ new Map());
|
|
4139
|
+
const fieldTransformingSince = reactive(/* @__PURE__ */ new Map());
|
|
4140
|
+
const transformErrors = reactive(/* @__PURE__ */ new Map());
|
|
4141
|
+
const activeTransforms = ref(0);
|
|
4142
|
+
const transformRuns = /* @__PURE__ */ new Map();
|
|
4143
|
+
let transformTokenSeq = 0;
|
|
4144
|
+
const transformWaiters = [];
|
|
4145
|
+
function incFieldTransform(key) {
|
|
4146
|
+
fieldTransformingSince.set(key, ssr ? 0 : Date.now());
|
|
4147
|
+
fieldTransformCounts.set(key, (fieldTransformCounts.get(key) ?? 0) + 1);
|
|
4148
|
+
}
|
|
4149
|
+
function decFieldTransform(key) {
|
|
4150
|
+
const next = (fieldTransformCounts.get(key) ?? 0) - 1;
|
|
4151
|
+
if (next <= 0) {
|
|
4152
|
+
fieldTransformCounts.delete(key);
|
|
4153
|
+
fieldTransformingSince.delete(key);
|
|
4154
|
+
} else {
|
|
4155
|
+
fieldTransformCounts.set(key, next);
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
function flushSettledTransformWaiters() {
|
|
4159
|
+
if (transformWaiters.length === 0) return;
|
|
4160
|
+
const globalIdle = activeTransforms.value === 0;
|
|
4161
|
+
for (let i = transformWaiters.length - 1; i >= 0; i--) {
|
|
4162
|
+
const w = transformWaiters[i];
|
|
4163
|
+
if (w === void 0) continue;
|
|
4164
|
+
const idle = w.key === null ? globalIdle : (fieldTransformCounts.get(w.key) ?? 0) === 0;
|
|
4165
|
+
if (idle) {
|
|
4166
|
+
transformWaiters.splice(i, 1);
|
|
4167
|
+
w.resolve();
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
function releaseTransformRun(key, run) {
|
|
4172
|
+
if (run.released) return;
|
|
4173
|
+
run.released = true;
|
|
4174
|
+
run.holder.aborted = true;
|
|
4175
|
+
run.holder.controller?.abort();
|
|
4176
|
+
activeTransforms.value = Math.max(0, activeTransforms.value - 1);
|
|
4177
|
+
decFieldTransform(key);
|
|
4178
|
+
}
|
|
4179
|
+
function beginTransform(key, holder) {
|
|
4180
|
+
const prior = transformRuns.get(key);
|
|
4181
|
+
if (prior !== void 0) releaseTransformRun(key, prior);
|
|
4182
|
+
const token = ++transformTokenSeq;
|
|
4183
|
+
transformRuns.set(key, { token, holder, released: false });
|
|
4184
|
+
incFieldTransform(key);
|
|
4185
|
+
activeTransforms.value += 1;
|
|
4186
|
+
if (transformErrors.has(key)) transformErrors.delete(key);
|
|
4187
|
+
return token;
|
|
4188
|
+
}
|
|
4189
|
+
function isCurrentTransform(key, token) {
|
|
4190
|
+
return transformRuns.get(key)?.token === token;
|
|
4191
|
+
}
|
|
4192
|
+
function endTransform(key, token) {
|
|
4193
|
+
const run = transformRuns.get(key);
|
|
4194
|
+
if (run?.token === token) {
|
|
4195
|
+
if (!run.released) {
|
|
4196
|
+
activeTransforms.value = Math.max(0, activeTransforms.value - 1);
|
|
4197
|
+
decFieldTransform(key);
|
|
4198
|
+
}
|
|
4199
|
+
transformRuns.delete(key);
|
|
4200
|
+
}
|
|
4201
|
+
flushSettledTransformWaiters();
|
|
4202
|
+
}
|
|
4203
|
+
function setTransformError(key, err) {
|
|
4204
|
+
transformErrors.set(key, err);
|
|
4205
|
+
}
|
|
4206
|
+
function cancelTransforms() {
|
|
4207
|
+
for (const [key, run] of [...transformRuns]) {
|
|
4208
|
+
releaseTransformRun(key, run);
|
|
4209
|
+
transformRuns.delete(key);
|
|
4210
|
+
}
|
|
4211
|
+
if (transformErrors.size > 0) transformErrors.clear();
|
|
4212
|
+
flushSettledTransformWaiters();
|
|
4213
|
+
}
|
|
4214
|
+
function cancelTransformsUnder(prefix) {
|
|
4215
|
+
for (const [key, run] of [...transformRuns]) {
|
|
4216
|
+
const segs = segmentsForPathKey(key);
|
|
4217
|
+
if (segs === null) continue;
|
|
4218
|
+
if (!isPathPrefix(prefix, segs)) continue;
|
|
4219
|
+
releaseTransformRun(key, run);
|
|
4220
|
+
transformRuns.delete(key);
|
|
4221
|
+
transformErrors.delete(key);
|
|
4222
|
+
}
|
|
4223
|
+
flushSettledTransformWaiters();
|
|
4224
|
+
}
|
|
4225
|
+
function settleTransforms(path) {
|
|
4226
|
+
if (path === void 0) {
|
|
4227
|
+
if (activeTransforms.value === 0) return Promise.resolve();
|
|
4228
|
+
return new Promise((resolve) => {
|
|
4229
|
+
transformWaiters.push({ key: null, resolve });
|
|
4230
|
+
});
|
|
4231
|
+
}
|
|
4232
|
+
const { key } = canonicalizePath(path);
|
|
4233
|
+
if ((fieldTransformCounts.get(key) ?? 0) === 0) return Promise.resolve();
|
|
4234
|
+
return new Promise((resolve) => {
|
|
4235
|
+
transformWaiters.push({ key, resolve });
|
|
4236
|
+
});
|
|
4237
|
+
}
|
|
3980
4238
|
const initStamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3981
4239
|
diffAndApply({}, schemaInitialData, [], (patch) => {
|
|
3982
4240
|
if (patch.kind !== "added") return;
|
|
@@ -4126,6 +4384,7 @@ function createFormStore(options) {
|
|
|
4126
4384
|
}
|
|
4127
4385
|
}
|
|
4128
4386
|
}
|
|
4387
|
+
if (transformRuns.size !== 0) cancelTransformsUnder(path);
|
|
4129
4388
|
if (meta?.skipDiscriminatorReshape !== true) {
|
|
4130
4389
|
if (path.length > 0) {
|
|
4131
4390
|
const last = path[path.length - 1];
|
|
@@ -4460,6 +4719,7 @@ function createFormStore(options) {
|
|
|
4460
4719
|
drainHooks.length = 0;
|
|
4461
4720
|
modules.clear();
|
|
4462
4721
|
cancelFieldValidation();
|
|
4722
|
+
cancelTransforms();
|
|
4463
4723
|
fieldValidatingSince.clear();
|
|
4464
4724
|
formChangeListeners.clear();
|
|
4465
4725
|
submitSuccessListeners.clear();
|
|
@@ -4596,6 +4856,7 @@ function createFormStore(options) {
|
|
|
4596
4856
|
if (remaining === 0) {
|
|
4597
4857
|
elements.delete(key);
|
|
4598
4858
|
touchFieldRecord(key, path, { connected: false, focused: null, blurred: null });
|
|
4859
|
+
if (transformRuns.size !== 0) cancelTransformsUnder(path);
|
|
4599
4860
|
}
|
|
4600
4861
|
return remaining;
|
|
4601
4862
|
}
|
|
@@ -4817,6 +5078,7 @@ function createFormStore(options) {
|
|
|
4817
5078
|
submitError.value = null;
|
|
4818
5079
|
departAttempts.value = 0;
|
|
4819
5080
|
cancelFieldValidation();
|
|
5081
|
+
cancelTransforms();
|
|
4820
5082
|
displayEngine.clear();
|
|
4821
5083
|
fieldValidatingSince.clear();
|
|
4822
5084
|
pathSnapshots.clear();
|
|
@@ -4835,6 +5097,7 @@ function createFormStore(options) {
|
|
|
4835
5097
|
const { key: targetKey, segments: targetSegments } = canonicalizePath(path);
|
|
4836
5098
|
variantMemory.clearUnderPath(targetSegments);
|
|
4837
5099
|
cancelFieldValidationUnder(targetSegments);
|
|
5100
|
+
cancelTransformsUnder(targetSegments);
|
|
4838
5101
|
for (const [snapKey] of [...pathSnapshots]) {
|
|
4839
5102
|
const segs = segmentsForPathKey(snapKey);
|
|
4840
5103
|
if (segs === null) continue;
|
|
@@ -4970,6 +5233,10 @@ function createFormStore(options) {
|
|
|
4970
5233
|
pathHasAsyncValidationByKey,
|
|
4971
5234
|
fieldValidationCounts,
|
|
4972
5235
|
fieldValidatingSince,
|
|
5236
|
+
fieldTransformCounts,
|
|
5237
|
+
fieldTransformingSince,
|
|
5238
|
+
transformErrors,
|
|
5239
|
+
activeTransforms,
|
|
4973
5240
|
displayEngine,
|
|
4974
5241
|
applyFormReplacement,
|
|
4975
5242
|
setValueAtPath,
|
|
@@ -4999,6 +5266,13 @@ function createFormStore(options) {
|
|
|
4999
5266
|
getOriginalAtPath,
|
|
5000
5267
|
getFirstErrorElement,
|
|
5001
5268
|
cancelFieldValidation,
|
|
5269
|
+
beginTransform,
|
|
5270
|
+
isCurrentTransform,
|
|
5271
|
+
endTransform,
|
|
5272
|
+
setTransformError,
|
|
5273
|
+
cancelTransforms,
|
|
5274
|
+
cancelTransformsUnder,
|
|
5275
|
+
settleTransforms,
|
|
5002
5276
|
scheduleFieldValidation,
|
|
5003
5277
|
onFormChange,
|
|
5004
5278
|
onSubmitSuccess,
|
|
@@ -5641,6 +5915,8 @@ function isLazyMarker(value) {
|
|
|
5641
5915
|
}
|
|
5642
5916
|
|
|
5643
5917
|
const NOOP_WIZARD_HISTORY = {
|
|
5918
|
+
push() {
|
|
5919
|
+
},
|
|
5644
5920
|
replace() {
|
|
5645
5921
|
},
|
|
5646
5922
|
read() {
|
|
@@ -5655,6 +5931,9 @@ function createWizardHistory(param) {
|
|
|
5655
5931
|
if (typeof window === "undefined") return NOOP_WIZARD_HISTORY;
|
|
5656
5932
|
const subscribers = [];
|
|
5657
5933
|
let disposed = false;
|
|
5934
|
+
function currentKey() {
|
|
5935
|
+
return new URL(window.location.href).searchParams.get(param) ?? void 0;
|
|
5936
|
+
}
|
|
5658
5937
|
function buildUrl(key) {
|
|
5659
5938
|
const url = new URL(window.location.href);
|
|
5660
5939
|
url.searchParams.set(param, key);
|
|
@@ -5662,25 +5941,29 @@ function createWizardHistory(param) {
|
|
|
5662
5941
|
}
|
|
5663
5942
|
function handlePopstate() {
|
|
5664
5943
|
if (disposed) return;
|
|
5665
|
-
const
|
|
5666
|
-
const value = url.searchParams.get(param) ?? void 0;
|
|
5944
|
+
const value = currentKey();
|
|
5667
5945
|
for (const subscriber of subscribers) subscriber(value);
|
|
5668
5946
|
}
|
|
5669
5947
|
window.addEventListener("popstate", handlePopstate);
|
|
5670
|
-
function
|
|
5948
|
+
function safeWrite(key, mode) {
|
|
5671
5949
|
try {
|
|
5672
|
-
window.history.
|
|
5950
|
+
if (mode === "push") window.history.pushState({}, "", buildUrl(key));
|
|
5951
|
+
else window.history.replaceState({}, "", buildUrl(key));
|
|
5673
5952
|
} catch {
|
|
5674
5953
|
}
|
|
5675
5954
|
}
|
|
5676
5955
|
return {
|
|
5956
|
+
push(key) {
|
|
5957
|
+
if (disposed) return;
|
|
5958
|
+
if (currentKey() === key) return;
|
|
5959
|
+
safeWrite(key, "push");
|
|
5960
|
+
},
|
|
5677
5961
|
replace(key) {
|
|
5678
5962
|
if (disposed) return;
|
|
5679
|
-
|
|
5963
|
+
safeWrite(key, "replace");
|
|
5680
5964
|
},
|
|
5681
5965
|
read() {
|
|
5682
|
-
|
|
5683
|
-
return url.searchParams.get(param) ?? void 0;
|
|
5966
|
+
return currentKey();
|
|
5684
5967
|
},
|
|
5685
5968
|
subscribe(callback) {
|
|
5686
5969
|
if (disposed) return;
|
|
@@ -5718,6 +6001,7 @@ function buildNoopWizardSchema(formKey) {
|
|
|
5718
6001
|
getEmptyValueAtPath: () => void 0,
|
|
5719
6002
|
isPreprocessOrCoerceLeaf: () => false,
|
|
5720
6003
|
arrayShapeAtPath: () => void 0,
|
|
6004
|
+
isFixedObjectAtPath: (path) => path.length === 0,
|
|
5721
6005
|
getSchemasAtPath: () => [],
|
|
5722
6006
|
validateAtPath: () => success,
|
|
5723
6007
|
getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
|
|
@@ -6171,7 +6455,10 @@ function useWizard(options) {
|
|
|
6171
6455
|
};
|
|
6172
6456
|
const persistCallback = options.persist === false ? void 0 : options.persist !== void 0 ? options.persist : (state) => {
|
|
6173
6457
|
if (state.step === void 0) return;
|
|
6174
|
-
historyHandle.
|
|
6458
|
+
const current = historyHandle.read();
|
|
6459
|
+
const effectiveCurrent = current !== void 0 && isCompiledKey(current) ? current : firstKey();
|
|
6460
|
+
if (state.step === effectiveCurrent) historyHandle.replace(state.step);
|
|
6461
|
+
else historyHandle.push(state.step);
|
|
6175
6462
|
};
|
|
6176
6463
|
function isCompiledKey(key) {
|
|
6177
6464
|
const list = compiledSteps.value;
|
|
@@ -6252,6 +6539,7 @@ function useWizard(options) {
|
|
|
6252
6539
|
}
|
|
6253
6540
|
const submitting = ref(false);
|
|
6254
6541
|
const submissionAttempts = ref(0);
|
|
6542
|
+
const submitError = ref(null);
|
|
6255
6543
|
const done = ref(false);
|
|
6256
6544
|
function activateForm(form) {
|
|
6257
6545
|
const source = asSubmissionSource(form);
|
|
@@ -6379,7 +6667,7 @@ function useWizard(options) {
|
|
|
6379
6667
|
formKey: form.key
|
|
6380
6668
|
};
|
|
6381
6669
|
}
|
|
6382
|
-
return full.
|
|
6670
|
+
return full.parse();
|
|
6383
6671
|
}
|
|
6384
6672
|
function collectErrors(results) {
|
|
6385
6673
|
const out = [];
|
|
@@ -6410,6 +6698,7 @@ function useWizard(options) {
|
|
|
6410
6698
|
return;
|
|
6411
6699
|
}
|
|
6412
6700
|
submitting.value = true;
|
|
6701
|
+
submitError.value = null;
|
|
6413
6702
|
try {
|
|
6414
6703
|
const currentKey = activeKey.value;
|
|
6415
6704
|
const final = isFinalStep.value;
|
|
@@ -6418,12 +6707,14 @@ function useWizard(options) {
|
|
|
6418
6707
|
if (final) {
|
|
6419
6708
|
await Promise.all(
|
|
6420
6709
|
list.map(async (step) => {
|
|
6710
|
+
registry.forms.get(step.key)?.clearUserErrors();
|
|
6421
6711
|
const result = await processOne(step.form);
|
|
6422
6712
|
results.set(step.key, result);
|
|
6423
6713
|
})
|
|
6424
6714
|
);
|
|
6425
6715
|
} else {
|
|
6426
6716
|
const active = activeForm.value;
|
|
6717
|
+
registry.forms.get(active.key)?.clearUserErrors();
|
|
6427
6718
|
const result = await processOne(active);
|
|
6428
6719
|
results.set(active.key, result);
|
|
6429
6720
|
}
|
|
@@ -6458,7 +6749,6 @@ function useWizard(options) {
|
|
|
6458
6749
|
if (target !== void 0) moveTo(target.key);
|
|
6459
6750
|
}
|
|
6460
6751
|
} else {
|
|
6461
|
-
if (onError !== void 0) await onError(errors);
|
|
6462
6752
|
if (options.focusFirstError !== false) {
|
|
6463
6753
|
const firstFailedKey = errors[0]?.formKey;
|
|
6464
6754
|
if (firstFailedKey !== void 0 && isCompiledKey(firstFailedKey)) {
|
|
@@ -6473,7 +6763,16 @@ function useWizard(options) {
|
|
|
6473
6763
|
}
|
|
6474
6764
|
}
|
|
6475
6765
|
}
|
|
6766
|
+
if (onError !== void 0) {
|
|
6767
|
+
try {
|
|
6768
|
+
await onError(errors);
|
|
6769
|
+
} catch (cause) {
|
|
6770
|
+
throw new SubmitErrorHandlerError("User-provided onError threw", { cause });
|
|
6771
|
+
}
|
|
6772
|
+
}
|
|
6476
6773
|
}
|
|
6774
|
+
} catch (err) {
|
|
6775
|
+
submitError.value = toError(err);
|
|
6477
6776
|
} finally {
|
|
6478
6777
|
submitting.value = false;
|
|
6479
6778
|
}
|
|
@@ -6482,6 +6781,7 @@ function useWizard(options) {
|
|
|
6482
6781
|
function reset() {
|
|
6483
6782
|
submissionAttempts.value = 0;
|
|
6484
6783
|
done.value = false;
|
|
6784
|
+
submitError.value = null;
|
|
6485
6785
|
lazyEpoch.value += 1;
|
|
6486
6786
|
for (const step of compiledSteps.value) {
|
|
6487
6787
|
const full = asSubmissionSource(step.form);
|
|
@@ -6557,6 +6857,9 @@ function useWizard(options) {
|
|
|
6557
6857
|
get submissionAttempts() {
|
|
6558
6858
|
return submissionAttempts.value;
|
|
6559
6859
|
},
|
|
6860
|
+
get submitError() {
|
|
6861
|
+
return submitError.value;
|
|
6862
|
+
},
|
|
6560
6863
|
get visited() {
|
|
6561
6864
|
return visited.value;
|
|
6562
6865
|
}
|
|
@@ -6667,4 +6970,4 @@ function warnIfAmbientWizardProviderHadDuplicates() {
|
|
|
6667
6970
|
}
|
|
6668
6971
|
|
|
6669
6972
|
export { AttaformErrorCode as A, useAbstractForm as B, useWizard as C, DEFAULT_PERSISTENCE_DEBOUNCE_MS as D, PERSISTENCE_MODULE_KEY as P, DEFAULT_TIMINGS as a, applyPatchesForward as b, cleanupOrphanKeys as c, defaultCoercionRules as d, defaultDisplayState as e, defineCoercion as f, deleteAtPath as g, diffAndApply as h, getAtPath as i, humanize as j, injectForm as k, injectWizard as l, isPlainRecord as m, isUnset as n, lazy as o, makeDefaultDisplayState as p, mergeSparseHydration as q, normalizeNumericOption as r, normalizePersistConfig as s, resolveStorageKeyBase as t, safeAssign as u, safeOwnRead as v, setAtPath as w, slimKindOf as x, structuralSnapshot as y, unset as z };
|
|
6670
|
-
//# sourceMappingURL=attaform.
|
|
6973
|
+
//# sourceMappingURL=attaform.DR6RmxWZ.mjs.map
|