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,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const vue = require('vue');
|
|
4
|
-
const paths = require('./attaform.
|
|
4
|
+
const paths = require('./attaform.D32WwKk6.cjs');
|
|
5
5
|
|
|
6
6
|
function safeAssign(target, key, value) {
|
|
7
7
|
if (key === "__proto__") {
|
|
@@ -15,10 +15,14 @@ function safeAssign(target, key, value) {
|
|
|
15
15
|
}
|
|
16
16
|
target[key] = value;
|
|
17
17
|
}
|
|
18
|
+
function isShadowedKey(key) {
|
|
19
|
+
return key in Object.prototype;
|
|
20
|
+
}
|
|
18
21
|
function safeOwnRead(target, key) {
|
|
19
|
-
if (key
|
|
20
|
-
const desc = Object.getOwnPropertyDescriptor(target,
|
|
21
|
-
return
|
|
22
|
+
if (isShadowedKey(key)) {
|
|
23
|
+
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
24
|
+
if (desc === void 0) return void 0;
|
|
25
|
+
return "value" in desc ? desc.value : target[key];
|
|
22
26
|
}
|
|
23
27
|
return target[key];
|
|
24
28
|
}
|
|
@@ -37,6 +41,10 @@ function descendStep(value, segment) {
|
|
|
37
41
|
}
|
|
38
42
|
const record = value;
|
|
39
43
|
const key = typeof segment === "number" ? String(segment) : segment;
|
|
44
|
+
if (isShadowedKey(key)) {
|
|
45
|
+
if (!safeOwnHas(record, key)) return NOT_FOUND;
|
|
46
|
+
return safeOwnRead(record, key);
|
|
47
|
+
}
|
|
40
48
|
if (!(key in record)) return NOT_FOUND;
|
|
41
49
|
return record[key];
|
|
42
50
|
}
|
|
@@ -66,6 +74,7 @@ function hasAtPath(root, path) {
|
|
|
66
74
|
return typeof last === "number" && last >= 0 && last < current.length;
|
|
67
75
|
}
|
|
68
76
|
const key = typeof last === "number" ? String(last) : last;
|
|
77
|
+
if (isShadowedKey(key)) return safeOwnHas(current, key);
|
|
69
78
|
return key in current;
|
|
70
79
|
}
|
|
71
80
|
function isPlainRecord(value) {
|
|
@@ -472,7 +481,12 @@ function computeVerdict(field, formMeta) {
|
|
|
472
481
|
if (field.valid === true && field.blank !== true && field.dirty === true) return "success";
|
|
473
482
|
return "idle";
|
|
474
483
|
}
|
|
475
|
-
|
|
484
|
+
function earliestNonNull(a, b) {
|
|
485
|
+
if (a === null) return b;
|
|
486
|
+
if (b === null) return a;
|
|
487
|
+
return a < b ? a : b;
|
|
488
|
+
}
|
|
489
|
+
const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
|
|
476
490
|
const FOCUS_OUT_GRACE = 16;
|
|
477
491
|
const defaultFamily = /* @__PURE__ */ new WeakSet();
|
|
478
492
|
function isDefaultDisplayState(fn) {
|
|
@@ -482,10 +496,11 @@ function makeDefaultDisplayState({
|
|
|
482
496
|
showDelay,
|
|
483
497
|
minVisible
|
|
484
498
|
}) {
|
|
485
|
-
const reducer = (prev, { field, formMeta, validatingSince, now }) => {
|
|
499
|
+
const reducer = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
|
|
486
500
|
const verdict = computeVerdict(field, formMeta);
|
|
487
501
|
if (!isGateOpen(field, formMeta)) return { display: verdict };
|
|
488
|
-
|
|
502
|
+
const inFlightSince = earliestNonNull(validatingSince, transformingSince);
|
|
503
|
+
if (inFlightSince === null) {
|
|
489
504
|
if (prev.display === "pending") {
|
|
490
505
|
const shownAt = prev.pendingShownAt ?? now;
|
|
491
506
|
if (now < shownAt + minVisible)
|
|
@@ -496,8 +511,8 @@ function makeDefaultDisplayState({
|
|
|
496
511
|
if (prev.display === "pending")
|
|
497
512
|
return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
|
|
498
513
|
const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
|
|
499
|
-
if (now -
|
|
500
|
-
return { display: prev.display, reviewAt:
|
|
514
|
+
if (now - inFlightSince < window) {
|
|
515
|
+
return { display: prev.display, reviewAt: inFlightSince + window };
|
|
501
516
|
}
|
|
502
517
|
return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
|
|
503
518
|
};
|
|
@@ -623,6 +638,8 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
623
638
|
if (blankForKey !== void 0) errors.push(...blankForKey);
|
|
624
639
|
if (userForKey !== void 0) errors.push(...userForKey);
|
|
625
640
|
const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
|
|
641
|
+
const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
|
|
642
|
+
const transformError = state.transformErrors.get(key) ?? null;
|
|
626
643
|
const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
|
|
627
644
|
const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
|
|
628
645
|
const valid = !gated && errors.length === 0 && !validating && !isOrphan;
|
|
@@ -649,6 +666,9 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
649
666
|
errors,
|
|
650
667
|
validating,
|
|
651
668
|
valid,
|
|
669
|
+
transforming,
|
|
670
|
+
busy: transforming || validating,
|
|
671
|
+
transformError,
|
|
652
672
|
path: segments,
|
|
653
673
|
...computeFieldIdentity(formInstanceId, state.formKey, key),
|
|
654
674
|
key: state.arrayElementKey(segments),
|
|
@@ -662,12 +682,14 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
662
682
|
function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
|
|
663
683
|
const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
|
|
664
684
|
const validatingSince = state.fieldValidatingSince.get(key) ?? null;
|
|
685
|
+
const transformingSince = state.fieldTransformingSince.get(key) ?? null;
|
|
665
686
|
return decorateWithDerivedProps(
|
|
666
687
|
base,
|
|
667
688
|
state,
|
|
668
689
|
getFormMetaBase,
|
|
669
690
|
key,
|
|
670
691
|
validatingSince,
|
|
692
|
+
transformingSince,
|
|
671
693
|
false,
|
|
672
694
|
// revealedDescendantError: leaves have no descendants
|
|
673
695
|
false,
|
|
@@ -690,6 +712,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
690
712
|
let connected = false;
|
|
691
713
|
let validating = false;
|
|
692
714
|
let validatingSince = null;
|
|
715
|
+
let transforming = false;
|
|
716
|
+
let transformingSince = null;
|
|
693
717
|
let updatedAt = null;
|
|
694
718
|
let asyncPending = false;
|
|
695
719
|
const submissionAttempts = state.submissionAttempts.value;
|
|
@@ -720,6 +744,13 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
720
744
|
if (leafGateOpen && since !== void 0 && (validatingSince === null || since < validatingSince))
|
|
721
745
|
validatingSince = since;
|
|
722
746
|
}
|
|
747
|
+
if ((state.fieldTransformCounts.get(leafKey) ?? 0) > 0) {
|
|
748
|
+
transforming = true;
|
|
749
|
+
const leafGateOpen = submissionAttempts > 0 || leafRecord?.blurredAfterInteraction === true;
|
|
750
|
+
const since = state.fieldTransformingSince.get(leafKey);
|
|
751
|
+
if (leafGateOpen && since !== void 0 && (transformingSince === null || since < transformingSince))
|
|
752
|
+
transformingSince = since;
|
|
753
|
+
}
|
|
723
754
|
if (state.pathHasAsyncValidationByKey(leafKey, entry.segments)) asyncPending = true;
|
|
724
755
|
const ts = leafRecord?.updatedAt;
|
|
725
756
|
if (ts !== void 0 && ts !== null) {
|
|
@@ -739,6 +770,19 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
739
770
|
return blurredLeafSegments.some((s) => paths.isPathPrefix(ePath, s));
|
|
740
771
|
});
|
|
741
772
|
if (!asyncPending && state.pathHasAsyncValidation(segments)) asyncPending = true;
|
|
773
|
+
if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
|
|
774
|
+
validating = true;
|
|
775
|
+
const since = state.fieldValidatingSince.get(key);
|
|
776
|
+
if (since !== void 0 && (validatingSince === null || since < validatingSince))
|
|
777
|
+
validatingSince = since;
|
|
778
|
+
}
|
|
779
|
+
if ((state.fieldTransformCounts.get(key) ?? 0) > 0) {
|
|
780
|
+
transforming = true;
|
|
781
|
+
const since = state.fieldTransformingSince.get(key);
|
|
782
|
+
if (since !== void 0 && (transformingSince === null || since < transformingSince))
|
|
783
|
+
transformingSince = since;
|
|
784
|
+
}
|
|
785
|
+
const ownTransformError = state.transformErrors.get(key) ?? null;
|
|
742
786
|
const gated = asyncPending && !state.firstValidationDone.value;
|
|
743
787
|
const valid = !gated && errors.length === 0 && !validating;
|
|
744
788
|
const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
|
|
@@ -762,6 +806,12 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
762
806
|
errors,
|
|
763
807
|
validating,
|
|
764
808
|
valid,
|
|
809
|
+
transforming,
|
|
810
|
+
busy: transforming || validating,
|
|
811
|
+
// A container surfaces its OWN transform failure (a transform registered
|
|
812
|
+
// on the container path, e.g. a file normalizer) but never rolls up a
|
|
813
|
+
// descendant leaf's failure — that stays a per-field channel.
|
|
814
|
+
transformError: ownTransformError,
|
|
765
815
|
path: segments,
|
|
766
816
|
...computeFieldIdentity(formInstanceId, state.formKey, key),
|
|
767
817
|
key: state.arrayElementKey(segments),
|
|
@@ -772,28 +822,25 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
|
|
|
772
822
|
meta: resolved.meta
|
|
773
823
|
},
|
|
774
824
|
validatingSince,
|
|
825
|
+
transformingSince,
|
|
775
826
|
revealedDescendantError
|
|
776
827
|
};
|
|
777
828
|
}
|
|
778
829
|
function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
|
|
779
|
-
const { base, validatingSince, revealedDescendantError } = buildContainerFieldStateBase(
|
|
780
|
-
state,
|
|
781
|
-
segments,
|
|
782
|
-
key,
|
|
783
|
-
formInstanceId
|
|
784
|
-
);
|
|
830
|
+
const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
|
|
785
831
|
return decorateWithDerivedProps(
|
|
786
832
|
base,
|
|
787
833
|
state,
|
|
788
834
|
getFormMetaBase,
|
|
789
835
|
key,
|
|
790
836
|
validatingSince,
|
|
837
|
+
transformingSince,
|
|
791
838
|
revealedDescendantError,
|
|
792
839
|
segments.length === 0,
|
|
793
840
|
getDisplayState
|
|
794
841
|
);
|
|
795
842
|
}
|
|
796
|
-
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, revealedDescendantError, isRoot, getDisplayState) {
|
|
843
|
+
function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot, getDisplayState) {
|
|
797
844
|
const firstError = base.errors[0];
|
|
798
845
|
const predicate = getDisplayState ?? state.getDisplayState;
|
|
799
846
|
const formMeta = getFormMetaBase();
|
|
@@ -801,6 +848,7 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
|
|
|
801
848
|
field: base,
|
|
802
849
|
formMeta,
|
|
803
850
|
validatingSince,
|
|
851
|
+
transformingSince,
|
|
804
852
|
// The engine's clock. Frozen to 0 under SSR (no clock, nothing in
|
|
805
853
|
// flight) so the reducer returns the plain verdict and hydration matches.
|
|
806
854
|
now: state.ssr ? 0 : Date.now()
|
|
@@ -867,6 +915,15 @@ function liveKeysAtPath(state, segments) {
|
|
|
867
915
|
if (typeof value === "object") return Object.keys(value);
|
|
868
916
|
return [];
|
|
869
917
|
}
|
|
918
|
+
function liveContainerHasKey(state, segments, key) {
|
|
919
|
+
const value = getAtPath(state.form.value, segments);
|
|
920
|
+
if (value === null || value === void 0 || typeof value !== "object") return false;
|
|
921
|
+
if (Array.isArray(value)) {
|
|
922
|
+
const index = Number(key);
|
|
923
|
+
return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
|
|
924
|
+
}
|
|
925
|
+
return Object.hasOwn(value, key);
|
|
926
|
+
}
|
|
870
927
|
function isArrayPath(state, segments) {
|
|
871
928
|
if (segments.length === 0) return false;
|
|
872
929
|
return Array.isArray(getAtPath(state.form.value, segments));
|
|
@@ -895,6 +952,21 @@ const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
|
|
|
895
952
|
function keyToSegment(key) {
|
|
896
953
|
return INTEGER_SEGMENT.test(key) ? Number(key) : key;
|
|
897
954
|
}
|
|
955
|
+
function callableInvokeShim(method, surface, getDescent) {
|
|
956
|
+
const fnMethod = Reflect.get(Function.prototype, method);
|
|
957
|
+
return new Proxy((() => {
|
|
958
|
+
}), {
|
|
959
|
+
apply: (_target, _thisArg, args) => Reflect.apply(fnMethod, surface, args),
|
|
960
|
+
get: (_target, key) => Reflect.get(getDescent(), key),
|
|
961
|
+
has: (_target, key) => Reflect.has(getDescent(), key),
|
|
962
|
+
ownKeys: () => Reflect.ownKeys(getDescent()),
|
|
963
|
+
getOwnPropertyDescriptor: (_target, key) => {
|
|
964
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(getDescent(), key);
|
|
965
|
+
if (descriptor !== void 0) descriptor.configurable = true;
|
|
966
|
+
return descriptor;
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
}
|
|
898
970
|
function buildSurfaceProxy(opts) {
|
|
899
971
|
const containerCache = /* @__PURE__ */ new Map();
|
|
900
972
|
const leafViewCache = /* @__PURE__ */ new Map();
|
|
@@ -921,6 +993,8 @@ function buildSurfaceProxy(opts) {
|
|
|
921
993
|
const cacheKey = `${JSON.stringify(segments)}+${isArrayLike ? "A" : "O"}`;
|
|
922
994
|
const existing = containerCache.get(cacheKey);
|
|
923
995
|
if (existing !== void 0) return existing;
|
|
996
|
+
const isFixedObject = opts.schema.isFixedObjectAtPath(segments);
|
|
997
|
+
const containerHasKey = (k) => opts.containerHasOwnKey !== void 0 ? opts.containerHasOwnKey(segments, k) : opts.containerOwnKeys?.(segments).includes(k) === true;
|
|
924
998
|
const snapshotContainer = () => opts.materializeContainer === void 0 ? {} : opts.materializeContainer(segments);
|
|
925
999
|
const {
|
|
926
1000
|
toString: containerToString,
|
|
@@ -928,8 +1002,9 @@ function buildSurfaceProxy(opts) {
|
|
|
928
1002
|
toJSON: containerToJSON,
|
|
929
1003
|
toPrimitive: containerToPrimitive
|
|
930
1004
|
} = makeReadonlyCoercion(snapshotContainer);
|
|
931
|
-
const
|
|
932
|
-
|
|
1005
|
+
const isRoot = segments.length === 0;
|
|
1006
|
+
const target = isRoot ? (() => {
|
|
1007
|
+
}) : isArrayLike ? [] : {};
|
|
933
1008
|
const proxy = new Proxy(target, {
|
|
934
1009
|
apply(_, __, args) {
|
|
935
1010
|
const arg = args[0];
|
|
@@ -960,7 +1035,16 @@ function buildSurfaceProxy(opts) {
|
|
|
960
1035
|
return key === "toString" ? containerToString : containerValueOf;
|
|
961
1036
|
}
|
|
962
1037
|
}
|
|
963
|
-
|
|
1038
|
+
if (key === "hasOwnProperty" && !schemaHasPath(childSegs)) {
|
|
1039
|
+
return Object.prototype.hasOwnProperty;
|
|
1040
|
+
}
|
|
1041
|
+
if (isRoot && (key === "call" || key === "apply" || key === "bind")) {
|
|
1042
|
+
return callableInvokeShim(key, proxy, () => descendOrTerminate(childSegs));
|
|
1043
|
+
}
|
|
1044
|
+
if (opts.isTerminalAt?.(childSegs) === true || isFixedObject && schemaHasPath(childSegs) || containerHasKey(key)) {
|
|
1045
|
+
return descendOrTerminate(childSegs);
|
|
1046
|
+
}
|
|
1047
|
+
return void 0;
|
|
964
1048
|
},
|
|
965
1049
|
has(_, key) {
|
|
966
1050
|
if (typeof key === "symbol") return Reflect.has(target, key);
|
|
@@ -1045,15 +1129,8 @@ function buildSurfaceProxy(opts) {
|
|
|
1045
1129
|
toJSON: leafToJSONHandler,
|
|
1046
1130
|
toPrimitive: leafToPrimitive
|
|
1047
1131
|
} = makeReadonlyCoercion(snapshotLeaf);
|
|
1048
|
-
const target =
|
|
1049
|
-
});
|
|
1132
|
+
const target = {};
|
|
1050
1133
|
const proxy = new Proxy(target, {
|
|
1051
|
-
apply(_, __, args) {
|
|
1052
|
-
const arg = args[0];
|
|
1053
|
-
if (arg === void 0) return opts.resolveCallTarget(segments);
|
|
1054
|
-
const { segments: argSegs } = paths.canonicalizePath(arg);
|
|
1055
|
-
return opts.resolveCallTarget(argSegs);
|
|
1056
|
-
},
|
|
1057
1134
|
get(_, key) {
|
|
1058
1135
|
if (typeof key === "symbol") {
|
|
1059
1136
|
if (key === Symbol.toPrimitive) return leafToPrimitive;
|
|
@@ -1063,6 +1140,9 @@ function buildSurfaceProxy(opts) {
|
|
|
1063
1140
|
if (key === "toString") return leafToString;
|
|
1064
1141
|
if (key === "valueOf") return leafValueOf;
|
|
1065
1142
|
if (key === "toJSON") return leafToJSONHandler;
|
|
1143
|
+
if (key === "hasOwnProperty" && !schemaHasPath([...segments, keyToSegment(key)])) {
|
|
1144
|
+
return Object.prototype.hasOwnProperty;
|
|
1145
|
+
}
|
|
1066
1146
|
if (leafKeys.has(key)) {
|
|
1067
1147
|
const leaf = opts.resolveLeaf(segments);
|
|
1068
1148
|
return readLeafKey(leaf, key);
|
|
@@ -1075,8 +1155,8 @@ function buildSurfaceProxy(opts) {
|
|
|
1075
1155
|
return true;
|
|
1076
1156
|
},
|
|
1077
1157
|
// Iteration: leaf-views expose the leaf-key set so
|
|
1078
|
-
// `
|
|
1079
|
-
//
|
|
1158
|
+
// `Object.keys(form.fields.email)` / spread enumerate the
|
|
1159
|
+
// FieldState props. (`JSON.stringify` routes through `toJSON` above.)
|
|
1080
1160
|
ownKeys: () => Array.from(leafKeys),
|
|
1081
1161
|
getOwnPropertyDescriptor(_, key) {
|
|
1082
1162
|
if (typeof key !== "string") return void 0;
|
|
@@ -1185,6 +1265,12 @@ function buildErrorsProxy(state) {
|
|
|
1185
1265
|
// library-produced verdicts (schema + derived-blank) at unreachable
|
|
1186
1266
|
// paths stay hidden; user-supplied errors are unconditional.
|
|
1187
1267
|
containerOwnKeys: (segments) => errorAwareContainerKeys(state, segments),
|
|
1268
|
+
// Fast path: a key the live form data holds short-circuits before the
|
|
1269
|
+
// O(n) error-store scan, so iterating `form.errors.<array>` over live
|
|
1270
|
+
// indices stays linear. The scan still runs for a key with no live
|
|
1271
|
+
// home — a server error at a non-schema key (`form.errors.ghost`) —
|
|
1272
|
+
// so it keeps surfacing while a genuinely-absent key reads undefined.
|
|
1273
|
+
containerHasOwnKey: (segments, key) => liveContainerHasKey(state, segments, key) || errorAwareContainerKeys(state, segments).includes(key),
|
|
1188
1274
|
isArrayContainer: (segments) => isArrayPath(state, segments)
|
|
1189
1275
|
});
|
|
1190
1276
|
}
|
|
@@ -1358,6 +1444,9 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1358
1444
|
"errors",
|
|
1359
1445
|
"validating",
|
|
1360
1446
|
"valid",
|
|
1447
|
+
"transforming",
|
|
1448
|
+
"busy",
|
|
1449
|
+
"transformError",
|
|
1361
1450
|
"displayState",
|
|
1362
1451
|
"showErrors",
|
|
1363
1452
|
"showPending",
|
|
@@ -1460,14 +1549,22 @@ function buildFieldStateProxy(state, formInstanceId, getFormMetaBase, options) {
|
|
|
1460
1549
|
terminalCache.set(cacheKey, proxy);
|
|
1461
1550
|
return proxy;
|
|
1462
1551
|
}
|
|
1552
|
+
const surfaceSchema = state.schema;
|
|
1463
1553
|
return buildSurfaceProxy({
|
|
1464
|
-
schema:
|
|
1554
|
+
schema: surfaceSchema,
|
|
1465
1555
|
resolveLeaf: (path) => getFieldStateAt(path),
|
|
1466
1556
|
leafKeys: FIELD_STATE_KEYS,
|
|
1467
1557
|
readLeafKey: (computed, key) => computed.value[key],
|
|
1468
1558
|
materializeContainer: (segments) => materializeFields(state, segments, snapshotFieldStateAt),
|
|
1469
|
-
|
|
1559
|
+
// `form.fields(path)` resolves a FieldState for any path the SCHEMA
|
|
1560
|
+
// declares — a leaf, a container, an inactive discriminated-union
|
|
1561
|
+
// variant key, or an out-of-bounds array index (the element schema
|
|
1562
|
+
// admits any index). A path the schema doesn't have is a typo, not a
|
|
1563
|
+
// field, so it reads `undefined` rather than a phantom stub. The
|
|
1564
|
+
// empty path (`form.fields()`) is the root object, always valid.
|
|
1565
|
+
resolveCallTarget: (path) => surfaceSchema.getSlimPrimitiveTypesAtPath(path).size > 0 ? fieldStateTerminalAt(path) : void 0,
|
|
1470
1566
|
containerOwnKeys: (segments) => liveKeysAtPath(state, segments),
|
|
1567
|
+
containerHasOwnKey: (segments, key) => liveContainerHasKey(state, segments, key),
|
|
1471
1568
|
isArrayContainer: (segments) => isArrayPath(state, segments)
|
|
1472
1569
|
});
|
|
1473
1570
|
}
|
|
@@ -1743,7 +1840,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1743
1840
|
if (!result.ok) return result.error;
|
|
1744
1841
|
return stripData(composeWithDerivedBlank(result.refinement, result.segments));
|
|
1745
1842
|
}
|
|
1746
|
-
async function
|
|
1843
|
+
async function parse(pathInput) {
|
|
1747
1844
|
const result = await runImperativeValidation(pathInput, {
|
|
1748
1845
|
cancelInFlight: false,
|
|
1749
1846
|
commitToSchemaErrors: false
|
|
@@ -1796,6 +1893,8 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1796
1893
|
state.activeSubmissions.value += 1;
|
|
1797
1894
|
state.submitting.value = true;
|
|
1798
1895
|
state.submitError.value = null;
|
|
1896
|
+
state.clearUserErrors();
|
|
1897
|
+
while (state.activeTransforms.value > 0) await state.settleTransforms();
|
|
1799
1898
|
state.cancelFieldValidation();
|
|
1800
1899
|
state.displayEngine.clear();
|
|
1801
1900
|
state.activeValidations.value += 1;
|
|
@@ -1834,9 +1933,8 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1834
1933
|
state.emitSubmitSuccess();
|
|
1835
1934
|
} catch (err) {
|
|
1836
1935
|
if (state.submissionGeneration.value === genAtEntry) {
|
|
1837
|
-
state.submitError.value = err;
|
|
1936
|
+
state.submitError.value = paths.toError(err);
|
|
1838
1937
|
}
|
|
1839
|
-
throw err;
|
|
1840
1938
|
} finally {
|
|
1841
1939
|
if (!validationSettled) {
|
|
1842
1940
|
state.activeValidations.value = Math.max(0, state.activeValidations.value - 1);
|
|
@@ -1850,7 +1948,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
|
|
|
1850
1948
|
};
|
|
1851
1949
|
return submitHandler;
|
|
1852
1950
|
};
|
|
1853
|
-
return { validate, validateAsync,
|
|
1951
|
+
return { validate, validateAsync, parse, handleSubmit };
|
|
1854
1952
|
}
|
|
1855
1953
|
function toSegments(pathInput) {
|
|
1856
1954
|
return paths.canonicalizePath(pathInput).segments;
|
|
@@ -2323,6 +2421,23 @@ function buildRegister(state, formInstanceId, instanceConfig) {
|
|
|
2323
2421
|
markConnectedOptimistically: () => {
|
|
2324
2422
|
state.markConnectedOptimistically(segments);
|
|
2325
2423
|
},
|
|
2424
|
+
// --- Async transform lifecycle (internal; the directive's
|
|
2425
|
+
// deferred orchestrator is the only legitimate consumer). Thin
|
|
2426
|
+
// path-bound delegates to the store's per-path token / counter
|
|
2427
|
+
// machinery — same pattern as `markBlank` / `setValueWithInternalPath`,
|
|
2428
|
+
// so the directive (which holds only this RegisterValue, never the
|
|
2429
|
+
// store) can drive the busy/discard/error bookkeeping. ---
|
|
2430
|
+
beginTransform: (holder) => state.beginTransform(pathKey, holder),
|
|
2431
|
+
isCurrentTransform: (token) => state.isCurrentTransform(pathKey, token),
|
|
2432
|
+
endTransform: (token) => state.endTransform(pathKey, token),
|
|
2433
|
+
setTransformError: (err) => state.setTransformError(pathKey, err),
|
|
2434
|
+
// Synchronous read of "is a transform in flight at this path". The
|
|
2435
|
+
// orchestrator's `beginTransform` bumps the count before the
|
|
2436
|
+
// listener's force-sync block runs, so the directive reads this to
|
|
2437
|
+
// skip reverting the DOM to stale storage mid-flight.
|
|
2438
|
+
get transforming() {
|
|
2439
|
+
return (state.fieldTransformCounts.get(pathKey) ?? 0) > 0;
|
|
2440
|
+
},
|
|
2326
2441
|
path: pathKey,
|
|
2327
2442
|
// Frozen so a wrapper component can pass `rv.segments` directly
|
|
2328
2443
|
// to `form.fields(...)` without defensive copying — and so test
|
|
@@ -2521,7 +2636,9 @@ function expandUnsetAt(segments, schema, paths$1) {
|
|
|
2521
2636
|
function buildCallableReadonlySnapshotProxy(opts) {
|
|
2522
2637
|
const target = (() => {
|
|
2523
2638
|
});
|
|
2524
|
-
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
|
|
2639
|
+
const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
|
|
2640
|
+
opts.coercionSnapshot ?? opts.snapshot
|
|
2641
|
+
);
|
|
2525
2642
|
const callResolve = opts.resolveCall ?? ((arg) => opts.resolveKey(String(arg)));
|
|
2526
2643
|
return new Proxy(target, {
|
|
2527
2644
|
apply(_, __, args) {
|
|
@@ -2570,27 +2687,52 @@ function buildCallableReadonlySnapshotProxy(opts) {
|
|
|
2570
2687
|
});
|
|
2571
2688
|
}
|
|
2572
2689
|
|
|
2690
|
+
function materializeFormValue(node) {
|
|
2691
|
+
if (node === null || typeof node !== "object") return node;
|
|
2692
|
+
if (Array.isArray(node)) {
|
|
2693
|
+
const out2 = new Array(node.length);
|
|
2694
|
+
for (let i = 0; i < node.length; i++) out2[i] = materializeFormValue(node[i]);
|
|
2695
|
+
return out2;
|
|
2696
|
+
}
|
|
2697
|
+
if (!isPlainRecord(node)) return vue.toRaw(node);
|
|
2698
|
+
const rec = node;
|
|
2699
|
+
const out = {};
|
|
2700
|
+
for (const key of Object.keys(rec)) {
|
|
2701
|
+
safeAssign(out, key, materializeFormValue(safeOwnRead(rec, key)));
|
|
2702
|
+
}
|
|
2703
|
+
return out;
|
|
2704
|
+
}
|
|
2573
2705
|
function buildValuesProxy(form) {
|
|
2574
2706
|
const inner = vue.computed(() => vue.readonly(form.value));
|
|
2575
2707
|
return buildCallableReadonlySnapshotProxy({
|
|
2576
2708
|
surface: "form.values",
|
|
2577
2709
|
snapshot: () => inner.value,
|
|
2710
|
+
// Faithful, reactivity-preserving serialisation: walk the reactive
|
|
2711
|
+
// proxy with own-safe reads so `JSON.stringify(form.values)` /
|
|
2712
|
+
// `String(form.values)` reflect the stored data — including a field
|
|
2713
|
+
// literally named `hasOwnProperty` that Vue would otherwise shim —
|
|
2714
|
+
// while still tracking the per-key reads that drive re-render.
|
|
2715
|
+
coercionSnapshot: () => materializeFormValue(inner.value),
|
|
2578
2716
|
// Read through the readonly proxy at access time so Vue's
|
|
2579
2717
|
// dependency tracking lands inside the consumer's active effect
|
|
2580
2718
|
// — `inner.value[key]` is what triggers per-key tracking.
|
|
2581
|
-
|
|
2582
|
-
//
|
|
2583
|
-
//
|
|
2584
|
-
//
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2719
|
+
//
|
|
2720
|
+
// Prototype-shadowed names (`hasOwnProperty`, `constructor`, …) read
|
|
2721
|
+
// off the RAW target instead: own-shadows-inherited semantics still
|
|
2722
|
+
// hold (a data field by that name returns its stored value), but
|
|
2723
|
+
// when there's no such field the inherited member resolves — so
|
|
2724
|
+
// `form.values.hasOwnProperty('x')` keeps working as the real
|
|
2725
|
+
// method. The raw read dodges Vue's `hasOwnProperty` proxy shim,
|
|
2726
|
+
// which would otherwise mask a data field of that name. (`toString`
|
|
2727
|
+
// / `valueOf` / `toJSON` never reach here — the base get trap
|
|
2728
|
+
// intercepts them as coercion handlers first.)
|
|
2729
|
+
resolveKey: (key) => isShadowedKey(key) ? vue.toRaw(inner.value)[key] : inner.value[key],
|
|
2730
|
+
// Dynamic path: walk segments through the readonly proxy with the
|
|
2731
|
+
// same own-property-safe descent the rest of the runtime uses
|
|
2732
|
+
// (`getAtPath`), so `form.values('a.hasOwnProperty')` resolves the
|
|
2733
|
+
// stored value. Per-level reads still propagate Vue's tracking for
|
|
2734
|
+
// ordinary keys.
|
|
2735
|
+
resolveCall: (arg) => getAtPath(inner.value, paths.canonicalizePath(arg).segments),
|
|
2594
2736
|
ownKeys: () => Reflect.ownKeys(inner.value),
|
|
2595
2737
|
hasKey: (key) => Reflect.has(inner.value, key),
|
|
2596
2738
|
describeKey: (key) => {
|
|
@@ -2651,12 +2793,12 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2651
2793
|
const {
|
|
2652
2794
|
validate: validateBuilt,
|
|
2653
2795
|
validateAsync: validateAsyncBuilt,
|
|
2654
|
-
|
|
2796
|
+
parse: parseBuilt,
|
|
2655
2797
|
handleSubmit
|
|
2656
2798
|
} = buildProcessForm(state, formInstanceId, processOptions);
|
|
2657
2799
|
const validate = (pathInput) => validateBuilt(pathInput);
|
|
2658
2800
|
const validateAsync = (pathInput) => validateAsyncBuilt(pathInput);
|
|
2659
|
-
const
|
|
2801
|
+
const parse = (pathInput) => parseBuilt(pathInput);
|
|
2660
2802
|
function pathToRef(pathInput) {
|
|
2661
2803
|
const segments = paths.canonicalizePath(pathInput).segments;
|
|
2662
2804
|
return vue.computed(() => getAtPath(state.form.value, segments));
|
|
@@ -2884,6 +3026,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
2884
3026
|
// keep the explicit form-level computation for the gate.
|
|
2885
3027
|
valid,
|
|
2886
3028
|
errors: metaErrors,
|
|
3029
|
+
// Whole-form transforming mirrors the global `activeTransforms`
|
|
3030
|
+
// counter ORed with any per-leaf transform in flight (the root
|
|
3031
|
+
// rollup), exactly as `validating` composes its lifecycle and
|
|
3032
|
+
// per-field sources. `busy` is the union of both work signals at
|
|
3033
|
+
// the form level. `transformError` is leaf-only, so the root
|
|
3034
|
+
// rollup reads it as `null` (kept for FieldState-shape parity).
|
|
3035
|
+
transforming: vue.computed(
|
|
3036
|
+
() => state.activeTransforms.value > 0 || rootFieldState.value.transforming
|
|
3037
|
+
),
|
|
3038
|
+
busy: vue.computed(
|
|
3039
|
+
() => state.activeValidations.value > 0 || state.activeTransforms.value > 0 || rootFieldState.value.validating || rootFieldState.value.transforming
|
|
3040
|
+
),
|
|
3041
|
+
get transformError() {
|
|
3042
|
+
return rootFieldState.value.transformError;
|
|
3043
|
+
},
|
|
2887
3044
|
// `displayState` / the `show*` booleans / `firstError` flow
|
|
2888
3045
|
// through the same root field-state computed as the rest of the
|
|
2889
3046
|
// FieldState surface, so `form.meta.displayState` matches
|
|
@@ -3112,7 +3269,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
|
|
|
3112
3269
|
setValue: gated(setValueImpl),
|
|
3113
3270
|
validate: gated(validate),
|
|
3114
3271
|
validateAsync: gated(validateAsync),
|
|
3115
|
-
|
|
3272
|
+
parse: gated(parse),
|
|
3273
|
+
settleTransforms: gated(state.settleTransforms),
|
|
3116
3274
|
register: gated(register),
|
|
3117
3275
|
key: state.formKey,
|
|
3118
3276
|
// Auto-unwrapping views over the per-store async-defaults lifecycle
|
|
@@ -3979,6 +4137,106 @@ function createFormStore(options) {
|
|
|
3979
4137
|
fieldValidationCounts.set(key, next);
|
|
3980
4138
|
}
|
|
3981
4139
|
}
|
|
4140
|
+
const fieldTransformCounts = vue.reactive(/* @__PURE__ */ new Map());
|
|
4141
|
+
const fieldTransformingSince = vue.reactive(/* @__PURE__ */ new Map());
|
|
4142
|
+
const transformErrors = vue.reactive(/* @__PURE__ */ new Map());
|
|
4143
|
+
const activeTransforms = vue.ref(0);
|
|
4144
|
+
const transformRuns = /* @__PURE__ */ new Map();
|
|
4145
|
+
let transformTokenSeq = 0;
|
|
4146
|
+
const transformWaiters = [];
|
|
4147
|
+
function incFieldTransform(key) {
|
|
4148
|
+
fieldTransformingSince.set(key, ssr ? 0 : Date.now());
|
|
4149
|
+
fieldTransformCounts.set(key, (fieldTransformCounts.get(key) ?? 0) + 1);
|
|
4150
|
+
}
|
|
4151
|
+
function decFieldTransform(key) {
|
|
4152
|
+
const next = (fieldTransformCounts.get(key) ?? 0) - 1;
|
|
4153
|
+
if (next <= 0) {
|
|
4154
|
+
fieldTransformCounts.delete(key);
|
|
4155
|
+
fieldTransformingSince.delete(key);
|
|
4156
|
+
} else {
|
|
4157
|
+
fieldTransformCounts.set(key, next);
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
function flushSettledTransformWaiters() {
|
|
4161
|
+
if (transformWaiters.length === 0) return;
|
|
4162
|
+
const globalIdle = activeTransforms.value === 0;
|
|
4163
|
+
for (let i = transformWaiters.length - 1; i >= 0; i--) {
|
|
4164
|
+
const w = transformWaiters[i];
|
|
4165
|
+
if (w === void 0) continue;
|
|
4166
|
+
const idle = w.key === null ? globalIdle : (fieldTransformCounts.get(w.key) ?? 0) === 0;
|
|
4167
|
+
if (idle) {
|
|
4168
|
+
transformWaiters.splice(i, 1);
|
|
4169
|
+
w.resolve();
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
function releaseTransformRun(key, run) {
|
|
4174
|
+
if (run.released) return;
|
|
4175
|
+
run.released = true;
|
|
4176
|
+
run.holder.aborted = true;
|
|
4177
|
+
run.holder.controller?.abort();
|
|
4178
|
+
activeTransforms.value = Math.max(0, activeTransforms.value - 1);
|
|
4179
|
+
decFieldTransform(key);
|
|
4180
|
+
}
|
|
4181
|
+
function beginTransform(key, holder) {
|
|
4182
|
+
const prior = transformRuns.get(key);
|
|
4183
|
+
if (prior !== void 0) releaseTransformRun(key, prior);
|
|
4184
|
+
const token = ++transformTokenSeq;
|
|
4185
|
+
transformRuns.set(key, { token, holder, released: false });
|
|
4186
|
+
incFieldTransform(key);
|
|
4187
|
+
activeTransforms.value += 1;
|
|
4188
|
+
if (transformErrors.has(key)) transformErrors.delete(key);
|
|
4189
|
+
return token;
|
|
4190
|
+
}
|
|
4191
|
+
function isCurrentTransform(key, token) {
|
|
4192
|
+
return transformRuns.get(key)?.token === token;
|
|
4193
|
+
}
|
|
4194
|
+
function endTransform(key, token) {
|
|
4195
|
+
const run = transformRuns.get(key);
|
|
4196
|
+
if (run?.token === token) {
|
|
4197
|
+
if (!run.released) {
|
|
4198
|
+
activeTransforms.value = Math.max(0, activeTransforms.value - 1);
|
|
4199
|
+
decFieldTransform(key);
|
|
4200
|
+
}
|
|
4201
|
+
transformRuns.delete(key);
|
|
4202
|
+
}
|
|
4203
|
+
flushSettledTransformWaiters();
|
|
4204
|
+
}
|
|
4205
|
+
function setTransformError(key, err) {
|
|
4206
|
+
transformErrors.set(key, err);
|
|
4207
|
+
}
|
|
4208
|
+
function cancelTransforms() {
|
|
4209
|
+
for (const [key, run] of [...transformRuns]) {
|
|
4210
|
+
releaseTransformRun(key, run);
|
|
4211
|
+
transformRuns.delete(key);
|
|
4212
|
+
}
|
|
4213
|
+
if (transformErrors.size > 0) transformErrors.clear();
|
|
4214
|
+
flushSettledTransformWaiters();
|
|
4215
|
+
}
|
|
4216
|
+
function cancelTransformsUnder(prefix) {
|
|
4217
|
+
for (const [key, run] of [...transformRuns]) {
|
|
4218
|
+
const segs = paths.segmentsForPathKey(key);
|
|
4219
|
+
if (segs === null) continue;
|
|
4220
|
+
if (!paths.isPathPrefix(prefix, segs)) continue;
|
|
4221
|
+
releaseTransformRun(key, run);
|
|
4222
|
+
transformRuns.delete(key);
|
|
4223
|
+
transformErrors.delete(key);
|
|
4224
|
+
}
|
|
4225
|
+
flushSettledTransformWaiters();
|
|
4226
|
+
}
|
|
4227
|
+
function settleTransforms(path) {
|
|
4228
|
+
if (path === void 0) {
|
|
4229
|
+
if (activeTransforms.value === 0) return Promise.resolve();
|
|
4230
|
+
return new Promise((resolve) => {
|
|
4231
|
+
transformWaiters.push({ key: null, resolve });
|
|
4232
|
+
});
|
|
4233
|
+
}
|
|
4234
|
+
const { key } = paths.canonicalizePath(path);
|
|
4235
|
+
if ((fieldTransformCounts.get(key) ?? 0) === 0) return Promise.resolve();
|
|
4236
|
+
return new Promise((resolve) => {
|
|
4237
|
+
transformWaiters.push({ key, resolve });
|
|
4238
|
+
});
|
|
4239
|
+
}
|
|
3982
4240
|
const initStamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3983
4241
|
diffAndApply({}, schemaInitialData, [], (patch) => {
|
|
3984
4242
|
if (patch.kind !== "added") return;
|
|
@@ -4128,6 +4386,7 @@ function createFormStore(options) {
|
|
|
4128
4386
|
}
|
|
4129
4387
|
}
|
|
4130
4388
|
}
|
|
4389
|
+
if (transformRuns.size !== 0) cancelTransformsUnder(path);
|
|
4131
4390
|
if (meta?.skipDiscriminatorReshape !== true) {
|
|
4132
4391
|
if (path.length > 0) {
|
|
4133
4392
|
const last = path[path.length - 1];
|
|
@@ -4462,6 +4721,7 @@ function createFormStore(options) {
|
|
|
4462
4721
|
drainHooks.length = 0;
|
|
4463
4722
|
modules.clear();
|
|
4464
4723
|
cancelFieldValidation();
|
|
4724
|
+
cancelTransforms();
|
|
4465
4725
|
fieldValidatingSince.clear();
|
|
4466
4726
|
formChangeListeners.clear();
|
|
4467
4727
|
submitSuccessListeners.clear();
|
|
@@ -4598,6 +4858,7 @@ function createFormStore(options) {
|
|
|
4598
4858
|
if (remaining === 0) {
|
|
4599
4859
|
elements.delete(key);
|
|
4600
4860
|
touchFieldRecord(key, path, { connected: false, focused: null, blurred: null });
|
|
4861
|
+
if (transformRuns.size !== 0) cancelTransformsUnder(path);
|
|
4601
4862
|
}
|
|
4602
4863
|
return remaining;
|
|
4603
4864
|
}
|
|
@@ -4819,6 +5080,7 @@ function createFormStore(options) {
|
|
|
4819
5080
|
submitError.value = null;
|
|
4820
5081
|
departAttempts.value = 0;
|
|
4821
5082
|
cancelFieldValidation();
|
|
5083
|
+
cancelTransforms();
|
|
4822
5084
|
displayEngine.clear();
|
|
4823
5085
|
fieldValidatingSince.clear();
|
|
4824
5086
|
pathSnapshots.clear();
|
|
@@ -4837,6 +5099,7 @@ function createFormStore(options) {
|
|
|
4837
5099
|
const { key: targetKey, segments: targetSegments } = paths.canonicalizePath(path);
|
|
4838
5100
|
variantMemory.clearUnderPath(targetSegments);
|
|
4839
5101
|
cancelFieldValidationUnder(targetSegments);
|
|
5102
|
+
cancelTransformsUnder(targetSegments);
|
|
4840
5103
|
for (const [snapKey] of [...pathSnapshots]) {
|
|
4841
5104
|
const segs = paths.segmentsForPathKey(snapKey);
|
|
4842
5105
|
if (segs === null) continue;
|
|
@@ -4972,6 +5235,10 @@ function createFormStore(options) {
|
|
|
4972
5235
|
pathHasAsyncValidationByKey,
|
|
4973
5236
|
fieldValidationCounts,
|
|
4974
5237
|
fieldValidatingSince,
|
|
5238
|
+
fieldTransformCounts,
|
|
5239
|
+
fieldTransformingSince,
|
|
5240
|
+
transformErrors,
|
|
5241
|
+
activeTransforms,
|
|
4975
5242
|
displayEngine,
|
|
4976
5243
|
applyFormReplacement,
|
|
4977
5244
|
setValueAtPath,
|
|
@@ -5001,6 +5268,13 @@ function createFormStore(options) {
|
|
|
5001
5268
|
getOriginalAtPath,
|
|
5002
5269
|
getFirstErrorElement,
|
|
5003
5270
|
cancelFieldValidation,
|
|
5271
|
+
beginTransform,
|
|
5272
|
+
isCurrentTransform,
|
|
5273
|
+
endTransform,
|
|
5274
|
+
setTransformError,
|
|
5275
|
+
cancelTransforms,
|
|
5276
|
+
cancelTransformsUnder,
|
|
5277
|
+
settleTransforms,
|
|
5004
5278
|
scheduleFieldValidation,
|
|
5005
5279
|
onFormChange,
|
|
5006
5280
|
onSubmitSuccess,
|
|
@@ -5643,6 +5917,8 @@ function isLazyMarker(value) {
|
|
|
5643
5917
|
}
|
|
5644
5918
|
|
|
5645
5919
|
const NOOP_WIZARD_HISTORY = {
|
|
5920
|
+
push() {
|
|
5921
|
+
},
|
|
5646
5922
|
replace() {
|
|
5647
5923
|
},
|
|
5648
5924
|
read() {
|
|
@@ -5657,6 +5933,9 @@ function createWizardHistory(param) {
|
|
|
5657
5933
|
if (typeof window === "undefined") return NOOP_WIZARD_HISTORY;
|
|
5658
5934
|
const subscribers = [];
|
|
5659
5935
|
let disposed = false;
|
|
5936
|
+
function currentKey() {
|
|
5937
|
+
return new URL(window.location.href).searchParams.get(param) ?? void 0;
|
|
5938
|
+
}
|
|
5660
5939
|
function buildUrl(key) {
|
|
5661
5940
|
const url = new URL(window.location.href);
|
|
5662
5941
|
url.searchParams.set(param, key);
|
|
@@ -5664,25 +5943,29 @@ function createWizardHistory(param) {
|
|
|
5664
5943
|
}
|
|
5665
5944
|
function handlePopstate() {
|
|
5666
5945
|
if (disposed) return;
|
|
5667
|
-
const
|
|
5668
|
-
const value = url.searchParams.get(param) ?? void 0;
|
|
5946
|
+
const value = currentKey();
|
|
5669
5947
|
for (const subscriber of subscribers) subscriber(value);
|
|
5670
5948
|
}
|
|
5671
5949
|
window.addEventListener("popstate", handlePopstate);
|
|
5672
|
-
function
|
|
5950
|
+
function safeWrite(key, mode) {
|
|
5673
5951
|
try {
|
|
5674
|
-
window.history.
|
|
5952
|
+
if (mode === "push") window.history.pushState({}, "", buildUrl(key));
|
|
5953
|
+
else window.history.replaceState({}, "", buildUrl(key));
|
|
5675
5954
|
} catch {
|
|
5676
5955
|
}
|
|
5677
5956
|
}
|
|
5678
5957
|
return {
|
|
5958
|
+
push(key) {
|
|
5959
|
+
if (disposed) return;
|
|
5960
|
+
if (currentKey() === key) return;
|
|
5961
|
+
safeWrite(key, "push");
|
|
5962
|
+
},
|
|
5679
5963
|
replace(key) {
|
|
5680
5964
|
if (disposed) return;
|
|
5681
|
-
|
|
5965
|
+
safeWrite(key, "replace");
|
|
5682
5966
|
},
|
|
5683
5967
|
read() {
|
|
5684
|
-
|
|
5685
|
-
return url.searchParams.get(param) ?? void 0;
|
|
5968
|
+
return currentKey();
|
|
5686
5969
|
},
|
|
5687
5970
|
subscribe(callback) {
|
|
5688
5971
|
if (disposed) return;
|
|
@@ -5720,6 +6003,7 @@ function buildNoopWizardSchema(formKey) {
|
|
|
5720
6003
|
getEmptyValueAtPath: () => void 0,
|
|
5721
6004
|
isPreprocessOrCoerceLeaf: () => false,
|
|
5722
6005
|
arrayShapeAtPath: () => void 0,
|
|
6006
|
+
isFixedObjectAtPath: (path) => path.length === 0,
|
|
5723
6007
|
getSchemasAtPath: () => [],
|
|
5724
6008
|
validateAtPath: () => success,
|
|
5725
6009
|
getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
|
|
@@ -6173,7 +6457,10 @@ function useWizard(options) {
|
|
|
6173
6457
|
};
|
|
6174
6458
|
const persistCallback = options.persist === false ? void 0 : options.persist !== void 0 ? options.persist : (state) => {
|
|
6175
6459
|
if (state.step === void 0) return;
|
|
6176
|
-
historyHandle.
|
|
6460
|
+
const current = historyHandle.read();
|
|
6461
|
+
const effectiveCurrent = current !== void 0 && isCompiledKey(current) ? current : firstKey();
|
|
6462
|
+
if (state.step === effectiveCurrent) historyHandle.replace(state.step);
|
|
6463
|
+
else historyHandle.push(state.step);
|
|
6177
6464
|
};
|
|
6178
6465
|
function isCompiledKey(key) {
|
|
6179
6466
|
const list = compiledSteps.value;
|
|
@@ -6254,6 +6541,7 @@ function useWizard(options) {
|
|
|
6254
6541
|
}
|
|
6255
6542
|
const submitting = vue.ref(false);
|
|
6256
6543
|
const submissionAttempts = vue.ref(0);
|
|
6544
|
+
const submitError = vue.ref(null);
|
|
6257
6545
|
const done = vue.ref(false);
|
|
6258
6546
|
function activateForm(form) {
|
|
6259
6547
|
const source = asSubmissionSource(form);
|
|
@@ -6381,7 +6669,7 @@ function useWizard(options) {
|
|
|
6381
6669
|
formKey: form.key
|
|
6382
6670
|
};
|
|
6383
6671
|
}
|
|
6384
|
-
return full.
|
|
6672
|
+
return full.parse();
|
|
6385
6673
|
}
|
|
6386
6674
|
function collectErrors(results) {
|
|
6387
6675
|
const out = [];
|
|
@@ -6412,6 +6700,7 @@ function useWizard(options) {
|
|
|
6412
6700
|
return;
|
|
6413
6701
|
}
|
|
6414
6702
|
submitting.value = true;
|
|
6703
|
+
submitError.value = null;
|
|
6415
6704
|
try {
|
|
6416
6705
|
const currentKey = activeKey.value;
|
|
6417
6706
|
const final = isFinalStep.value;
|
|
@@ -6420,12 +6709,14 @@ function useWizard(options) {
|
|
|
6420
6709
|
if (final) {
|
|
6421
6710
|
await Promise.all(
|
|
6422
6711
|
list.map(async (step) => {
|
|
6712
|
+
registry.forms.get(step.key)?.clearUserErrors();
|
|
6423
6713
|
const result = await processOne(step.form);
|
|
6424
6714
|
results.set(step.key, result);
|
|
6425
6715
|
})
|
|
6426
6716
|
);
|
|
6427
6717
|
} else {
|
|
6428
6718
|
const active = activeForm.value;
|
|
6719
|
+
registry.forms.get(active.key)?.clearUserErrors();
|
|
6429
6720
|
const result = await processOne(active);
|
|
6430
6721
|
results.set(active.key, result);
|
|
6431
6722
|
}
|
|
@@ -6460,7 +6751,6 @@ function useWizard(options) {
|
|
|
6460
6751
|
if (target !== void 0) moveTo(target.key);
|
|
6461
6752
|
}
|
|
6462
6753
|
} else {
|
|
6463
|
-
if (onError !== void 0) await onError(errors);
|
|
6464
6754
|
if (options.focusFirstError !== false) {
|
|
6465
6755
|
const firstFailedKey = errors[0]?.formKey;
|
|
6466
6756
|
if (firstFailedKey !== void 0 && isCompiledKey(firstFailedKey)) {
|
|
@@ -6475,7 +6765,16 @@ function useWizard(options) {
|
|
|
6475
6765
|
}
|
|
6476
6766
|
}
|
|
6477
6767
|
}
|
|
6768
|
+
if (onError !== void 0) {
|
|
6769
|
+
try {
|
|
6770
|
+
await onError(errors);
|
|
6771
|
+
} catch (cause) {
|
|
6772
|
+
throw new paths.SubmitErrorHandlerError("User-provided onError threw", { cause });
|
|
6773
|
+
}
|
|
6774
|
+
}
|
|
6478
6775
|
}
|
|
6776
|
+
} catch (err) {
|
|
6777
|
+
submitError.value = paths.toError(err);
|
|
6479
6778
|
} finally {
|
|
6480
6779
|
submitting.value = false;
|
|
6481
6780
|
}
|
|
@@ -6484,6 +6783,7 @@ function useWizard(options) {
|
|
|
6484
6783
|
function reset() {
|
|
6485
6784
|
submissionAttempts.value = 0;
|
|
6486
6785
|
done.value = false;
|
|
6786
|
+
submitError.value = null;
|
|
6487
6787
|
lazyEpoch.value += 1;
|
|
6488
6788
|
for (const step of compiledSteps.value) {
|
|
6489
6789
|
const full = asSubmissionSource(step.form);
|
|
@@ -6559,6 +6859,9 @@ function useWizard(options) {
|
|
|
6559
6859
|
get submissionAttempts() {
|
|
6560
6860
|
return submissionAttempts.value;
|
|
6561
6861
|
},
|
|
6862
|
+
get submitError() {
|
|
6863
|
+
return submitError.value;
|
|
6864
|
+
},
|
|
6562
6865
|
get visited() {
|
|
6563
6866
|
return visited.value;
|
|
6564
6867
|
}
|
|
@@ -6699,4 +7002,4 @@ exports.structuralSnapshot = structuralSnapshot;
|
|
|
6699
7002
|
exports.unset = unset;
|
|
6700
7003
|
exports.useAbstractForm = useAbstractForm;
|
|
6701
7004
|
exports.useWizard = useWizard;
|
|
6702
|
-
//# sourceMappingURL=attaform.
|
|
7005
|
+
//# sourceMappingURL=attaform.ClXwitZj.cjs.map
|