formstand 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +188 -0
- package/README.md +1 -1
- package/dist/chunk-XJ6W5CKB.js +22 -0
- package/dist/chunk-XJ6W5CKB.js.map +1 -0
- package/dist/{createForm-BexUOCjZ.d.cts → createForm-RE6Bjnfv.d.cts} +18 -7
- package/dist/{createForm-BexUOCjZ.d.ts → createForm-RE6Bjnfv.d.ts} +18 -7
- package/dist/devtools/index.cjs +30 -54
- package/dist/devtools/index.cjs.map +1 -1
- package/dist/devtools/index.js +31 -21
- package/dist/devtools/index.js.map +1 -1
- package/dist/index.cjs +330 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -20
- package/dist/index.d.ts +46 -20
- package/dist/index.js +484 -97
- package/dist/index.js.map +1 -1
- package/dist/testing/index.cjs +6 -10
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +4 -4
- package/dist/testing/index.d.ts +4 -4
- package/dist/testing/index.js +6 -10
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EQIS5IVH.js +0 -172
- package/dist/chunk-EQIS5IVH.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -298,6 +298,12 @@ var validateAsync = async (schema, values) => {
|
|
|
298
298
|
return result.success ? { kind: "valid", data: result.data } : { kind: "invalid", errors: flattenIssues(result.error.issues) };
|
|
299
299
|
};
|
|
300
300
|
var isAsyncRequiredError = (e) => e instanceof zod.z.core.$ZodAsyncError || e instanceof Error && /Encountered Promise during synchronous parse/i.test(e.message);
|
|
301
|
+
var reportBackgroundFailure = (error) => {
|
|
302
|
+
console.error(
|
|
303
|
+
"[formstand] a background validation pass threw (an async refinement rejected). Its in-flight flags were released. The error:",
|
|
304
|
+
error
|
|
305
|
+
);
|
|
306
|
+
};
|
|
301
307
|
var isPathOrChild = (key, path) => key === path || key.startsWith(`${path}.`);
|
|
302
308
|
var prefixErrorKeys = (errors, path) => path === "" ? errors : Object.fromEntries(
|
|
303
309
|
Object.entries(errors).map(([k, v]) => [
|
|
@@ -349,6 +355,42 @@ var schemaHasPath = (schema, path) => {
|
|
|
349
355
|
};
|
|
350
356
|
return walk(schema, parsePath(path), SCHEMA_WALK_BUDGET);
|
|
351
357
|
};
|
|
358
|
+
var schemaAllowsKindChangeAt = (schema, path) => {
|
|
359
|
+
const flexible = (s) => s instanceof zod.z.ZodUnion || s instanceof zod.z.ZodDiscriminatedUnion || s instanceof zod.z.ZodPipe || s instanceof zod.z.ZodAny || s instanceof zod.z.ZodUnknown || s instanceof zod.z.ZodLazy || s instanceof zod.z.ZodCatch || s.def.coerce === true;
|
|
360
|
+
const strip = (s) => {
|
|
361
|
+
if (s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodNullable) {
|
|
362
|
+
return strip(s.unwrap());
|
|
363
|
+
}
|
|
364
|
+
if (s instanceof zod.z.ZodDefault || s instanceof zod.z.ZodPrefault || s instanceof zod.z.ZodReadonly || s instanceof zod.z.ZodNonOptional) {
|
|
365
|
+
return strip(s.def.innerType);
|
|
366
|
+
}
|
|
367
|
+
return s;
|
|
368
|
+
};
|
|
369
|
+
const walk = (s, segments, budget) => {
|
|
370
|
+
if (budget <= 0) return true;
|
|
371
|
+
const node = strip(s);
|
|
372
|
+
if (flexible(node)) return true;
|
|
373
|
+
const [head, ...rest] = segments;
|
|
374
|
+
if (head === void 0) return false;
|
|
375
|
+
if (node instanceof zod.z.ZodObject) {
|
|
376
|
+
const shape = node.shape;
|
|
377
|
+
const child = Object.hasOwn(shape, String(head)) ? shape[String(head)] : void 0;
|
|
378
|
+
return child === void 0 ? true : walk(child, rest, budget - 1);
|
|
379
|
+
}
|
|
380
|
+
if (node instanceof zod.z.ZodArray) {
|
|
381
|
+
return typeof head === "number" ? walk(node.element, rest, budget - 1) : true;
|
|
382
|
+
}
|
|
383
|
+
if (node instanceof zod.z.ZodTuple && typeof head === "number") {
|
|
384
|
+
const item = node.def.items[head];
|
|
385
|
+
return item === void 0 ? true : walk(item, rest, budget - 1);
|
|
386
|
+
}
|
|
387
|
+
if (node instanceof zod.z.ZodRecord) {
|
|
388
|
+
return walk(node.valueType, rest, budget - 1);
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
};
|
|
392
|
+
return walk(schema, parsePath(path), SCHEMA_WALK_BUDGET);
|
|
393
|
+
};
|
|
352
394
|
var hasChecks = (s) => {
|
|
353
395
|
const checks = s.def.checks;
|
|
354
396
|
return checks !== void 0 && checks.length > 0;
|
|
@@ -433,7 +475,7 @@ var fieldSchemaAtPath = (schema, path) => parsePath(path).reduce((current, segme
|
|
|
433
475
|
}, schema);
|
|
434
476
|
|
|
435
477
|
// src/core/createForm.ts
|
|
436
|
-
var shallowFieldEqual = (a, b) => Object.is(a.value, b.value) && a.error === b.error && a.touched === b.touched && a.dirty === b.dirty && a.isValidating === b.isValidating;
|
|
478
|
+
var shallowFieldEqual = (a, b) => Object.is(a.value, b.value) && Object.is(a.initialValue, b.initialValue) && a.error === b.error && a.touched === b.touched && a.dirty === b.dirty && a.isValidating === b.isValidating;
|
|
437
479
|
var emptyErrors = {};
|
|
438
480
|
var emptyBools = {};
|
|
439
481
|
var identityMapper = (n) => n;
|
|
@@ -491,7 +533,26 @@ var reuseErrorRefs = (next, prev) => {
|
|
|
491
533
|
const sameShape = entries.length === Object.keys(prev).length && entries.every(([k, v]) => entryAt(prev, k) === v);
|
|
492
534
|
return sameShape ? prev : Object.fromEntries(entries);
|
|
493
535
|
};
|
|
494
|
-
var
|
|
536
|
+
var noScopeErrors = { scoped: emptyErrors, full: null };
|
|
537
|
+
var scopeParse = (result, path, viaSubschema) => {
|
|
538
|
+
const errors = result.kind === "invalid" ? result.errors : emptyErrors;
|
|
539
|
+
return viaSubschema ? { scoped: prefixErrorKeys(errors, path), full: null } : {
|
|
540
|
+
scoped: path === "" ? errors : pickScope(errors, [path]),
|
|
541
|
+
full: errors
|
|
542
|
+
};
|
|
543
|
+
};
|
|
544
|
+
var pruneUnreported = (prev, full) => {
|
|
545
|
+
const entries = Object.entries(prev);
|
|
546
|
+
const kept = entries.filter(([k]) => Object.hasOwn(full, k));
|
|
547
|
+
return kept.length === entries.length ? prev : Object.fromEntries(kept);
|
|
548
|
+
};
|
|
549
|
+
var dropEmptyLists = (map) => {
|
|
550
|
+
const entries = Object.entries(map);
|
|
551
|
+
const kept = entries.filter(
|
|
552
|
+
([, list]) => list !== void 0 && list.length > 0
|
|
553
|
+
);
|
|
554
|
+
return kept.length === entries.length ? map : Object.fromEntries(kept);
|
|
555
|
+
};
|
|
495
556
|
var mergeErrorChannels = (schema, server) => {
|
|
496
557
|
const extra = Object.entries(server).filter(
|
|
497
558
|
([k]) => !Object.hasOwn(schema, k)
|
|
@@ -601,17 +662,17 @@ var createForm = (schema, options) => {
|
|
|
601
662
|
const merged = scopes.reduce(
|
|
602
663
|
(acc, { path, scope }) => scope.kind === "skip" ? acc : {
|
|
603
664
|
...acc,
|
|
604
|
-
...
|
|
665
|
+
...scopeParse(
|
|
605
666
|
validateSyncLatched(path, scope.schema, scope.value),
|
|
606
667
|
path,
|
|
607
668
|
true
|
|
608
|
-
)
|
|
669
|
+
).scoped
|
|
609
670
|
},
|
|
610
671
|
{}
|
|
611
672
|
);
|
|
612
673
|
store.setState((state) => ({
|
|
613
674
|
...state,
|
|
614
|
-
...commitScopedErrors(state, merged, paths)
|
|
675
|
+
...commitScopedErrors(state, merged, paths, null)
|
|
615
676
|
}));
|
|
616
677
|
return settledFields(merged);
|
|
617
678
|
}
|
|
@@ -620,7 +681,7 @@ var createForm = (schema, options) => {
|
|
|
620
681
|
const requestedErrors = pickScope(fullErrors, paths);
|
|
621
682
|
store.setState((state) => ({
|
|
622
683
|
...state,
|
|
623
|
-
...commitScopedErrors(state, requestedErrors, paths)
|
|
684
|
+
...commitScopedErrors(state, requestedErrors, paths, fullErrors)
|
|
624
685
|
}));
|
|
625
686
|
return settledFields(requestedErrors);
|
|
626
687
|
} catch (e) {
|
|
@@ -665,7 +726,7 @@ var createForm = (schema, options) => {
|
|
|
665
726
|
const slot = slotAtPath(values, path);
|
|
666
727
|
return slot.exists ? { kind: "parse", schema: sub, value: slot.value, viaSubschema: true } : { kind: "skip" };
|
|
667
728
|
};
|
|
668
|
-
const parseScopeAsync = async (path, scope) => scope.kind === "skip" ?
|
|
729
|
+
const parseScopeAsync = async (path, scope) => scope.kind === "skip" ? noScopeErrors : scopeParse(
|
|
669
730
|
await validateAsync(scope.schema, scope.value),
|
|
670
731
|
path,
|
|
671
732
|
scope.viaSubschema
|
|
@@ -685,14 +746,18 @@ var createForm = (schema, options) => {
|
|
|
685
746
|
};
|
|
686
747
|
const settledFields = (scoped) => Object.keys(scoped).length === 0 ? { kind: "valid" } : { kind: "invalid", errors: scoped };
|
|
687
748
|
const settledFormResult = (result) => settledFields(result.kind === "invalid" ? result.errors : emptyErrors);
|
|
688
|
-
const commitScopedErrors = (state, scoped, paths) => errorChannels(state, {
|
|
749
|
+
const commitScopedErrors = (state, scoped, paths, full) => errorChannels(state, {
|
|
689
750
|
schemaErrors: reuseErrorRefs(
|
|
690
|
-
mergeScopedErrors(
|
|
751
|
+
mergeScopedErrors(
|
|
752
|
+
full === null ? state.schemaErrors : pruneUnreported(state.schemaErrors, full),
|
|
753
|
+
scoped,
|
|
754
|
+
paths
|
|
755
|
+
),
|
|
691
756
|
state.schemaErrors
|
|
692
757
|
),
|
|
693
758
|
serverErrors: omitScope(state.serverErrors, paths)
|
|
694
759
|
});
|
|
695
|
-
const commitFieldErrors = (state,
|
|
760
|
+
const commitFieldErrors = (state, parse, path) => path === "" ? commitFullPass(state, parse.scoped) : commitScopedErrors(state, parse.scoped, [path], parse.full);
|
|
696
761
|
const validateField = (path) => {
|
|
697
762
|
warnMissingSchemaPath("validateField", path);
|
|
698
763
|
const scope = fieldScopeFor(path, store.getState().values);
|
|
@@ -700,7 +765,7 @@ var createForm = (schema, options) => {
|
|
|
700
765
|
return { kind: "pending", promise: validateFieldAsync(path) };
|
|
701
766
|
}
|
|
702
767
|
try {
|
|
703
|
-
const
|
|
768
|
+
const parse = scope.kind === "skip" ? noScopeErrors : scopeParse(
|
|
704
769
|
validateSyncLatched(
|
|
705
770
|
scope.viaSubschema ? path : "",
|
|
706
771
|
scope.schema,
|
|
@@ -711,9 +776,9 @@ var createForm = (schema, options) => {
|
|
|
711
776
|
);
|
|
712
777
|
store.setState((state) => ({
|
|
713
778
|
...state,
|
|
714
|
-
...commitFieldErrors(state,
|
|
779
|
+
...commitFieldErrors(state, parse, path)
|
|
715
780
|
}));
|
|
716
|
-
return fieldResult(scoped);
|
|
781
|
+
return fieldResult(parse.scoped);
|
|
717
782
|
} catch (e) {
|
|
718
783
|
if (isAsyncRequiredError(e)) {
|
|
719
784
|
return { kind: "pending", promise: validateFieldAsync(path) };
|
|
@@ -723,11 +788,15 @@ var createForm = (schema, options) => {
|
|
|
723
788
|
};
|
|
724
789
|
const snapshotField = (state, path) => {
|
|
725
790
|
const value = getAtPath(state.values, path);
|
|
791
|
+
const initialValue = getAtPath(state.initialValues, path);
|
|
792
|
+
const error = entryAt(state.errors, path);
|
|
726
793
|
return {
|
|
727
794
|
value,
|
|
728
|
-
|
|
795
|
+
initialValue,
|
|
796
|
+
error,
|
|
797
|
+
firstError: error?.[0],
|
|
729
798
|
touched: flagAt(state.touched, path),
|
|
730
|
-
dirty: isFieldDirty(value,
|
|
799
|
+
dirty: isFieldDirty(value, initialValue),
|
|
731
800
|
isValidating: flagAt(state.isValidating, path)
|
|
732
801
|
};
|
|
733
802
|
};
|
|
@@ -741,7 +810,14 @@ var createForm = (schema, options) => {
|
|
|
741
810
|
const pass = claimPass(FORM_SEQ_KEY);
|
|
742
811
|
const valuesAtStart = store.getState().values;
|
|
743
812
|
store.setState((state) => ({ ...state, isValidatingForm: true }));
|
|
744
|
-
const result = await validateAsync(schema, valuesAtStart)
|
|
813
|
+
const result = await validateAsync(schema, valuesAtStart).catch(
|
|
814
|
+
(error) => {
|
|
815
|
+
if (sequences.get(FORM_SEQ_KEY) === pass) {
|
|
816
|
+
store.setState((state) => ({ ...state, isValidatingForm: false }));
|
|
817
|
+
}
|
|
818
|
+
throw error;
|
|
819
|
+
}
|
|
820
|
+
);
|
|
745
821
|
const live = store.getState();
|
|
746
822
|
const stillOwns = sequences.get(FORM_SEQ_KEY) === pass;
|
|
747
823
|
if (!stillOwns || live.values !== valuesAtStart) {
|
|
@@ -781,12 +857,15 @@ var createForm = (schema, options) => {
|
|
|
781
857
|
...Object.fromEntries(paths.map((p) => [p, true]))
|
|
782
858
|
}
|
|
783
859
|
}));
|
|
784
|
-
const
|
|
860
|
+
const parseBatch = async () => allViaSubschema ? {
|
|
785
861
|
kind: "slots",
|
|
786
862
|
byPath: new Map(
|
|
787
863
|
await Promise.all(
|
|
788
864
|
scopes.map(
|
|
789
|
-
async ({ path, scope }) => [
|
|
865
|
+
async ({ path, scope }) => [
|
|
866
|
+
path,
|
|
867
|
+
(await parseScopeAsync(path, scope)).scoped
|
|
868
|
+
]
|
|
790
869
|
)
|
|
791
870
|
)
|
|
792
871
|
)
|
|
@@ -796,6 +875,18 @@ var createForm = (schema, options) => {
|
|
|
796
875
|
(result) => result.kind === "invalid" ? result.errors : emptyErrors
|
|
797
876
|
)
|
|
798
877
|
};
|
|
878
|
+
const parsed = await parseBatch().catch((error) => {
|
|
879
|
+
const stillOwned = new Set(
|
|
880
|
+
paths.filter((p) => sequences.get(p) === passes.get(p))
|
|
881
|
+
);
|
|
882
|
+
if (stillOwned.size > 0) {
|
|
883
|
+
store.setState((state) => ({
|
|
884
|
+
...state,
|
|
885
|
+
isValidating: omitKeys(state.isValidating, stillOwned)
|
|
886
|
+
}));
|
|
887
|
+
}
|
|
888
|
+
throw error;
|
|
889
|
+
});
|
|
799
890
|
const errorsFor = (path) => {
|
|
800
891
|
switch (parsed.kind) {
|
|
801
892
|
case "slots":
|
|
@@ -824,7 +915,8 @@ var createForm = (schema, options) => {
|
|
|
824
915
|
Object.fromEntries(
|
|
825
916
|
fresh.flatMap((path) => Object.entries(errorsFor(path)))
|
|
826
917
|
),
|
|
827
|
-
fresh
|
|
918
|
+
fresh,
|
|
919
|
+
parsed.kind === "full" ? parsed.errors : null
|
|
828
920
|
),
|
|
829
921
|
isValidating: omitKeys(state.isValidating, ownedKeys)
|
|
830
922
|
}));
|
|
@@ -845,24 +937,32 @@ var createForm = (schema, options) => {
|
|
|
845
937
|
...state,
|
|
846
938
|
isValidating: { ...state.isValidating, [path]: true }
|
|
847
939
|
}));
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
const stillOwns = sequences.get(path) === pass;
|
|
851
|
-
if (!stillOwns || scopeStale(scope, path, valuesAtStart, live.values)) {
|
|
852
|
-
if (stillOwns) {
|
|
940
|
+
const releaseOwnFlag = () => {
|
|
941
|
+
if (sequences.get(path) === pass) {
|
|
853
942
|
store.setState((state) => ({
|
|
854
943
|
...state,
|
|
855
944
|
isValidating: omitKey(state.isValidating, path)
|
|
856
945
|
}));
|
|
857
946
|
}
|
|
858
|
-
|
|
947
|
+
};
|
|
948
|
+
const parse = await parseScopeAsync(path, scope).catch(
|
|
949
|
+
(error) => {
|
|
950
|
+
releaseOwnFlag();
|
|
951
|
+
throw error;
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
const live = store.getState();
|
|
955
|
+
const stillOwns = sequences.get(path) === pass;
|
|
956
|
+
if (!stillOwns || scopeStale(scope, path, valuesAtStart, live.values)) {
|
|
957
|
+
releaseOwnFlag();
|
|
958
|
+
return fieldResult(parse.scoped);
|
|
859
959
|
}
|
|
860
960
|
store.setState((state) => ({
|
|
861
961
|
...state,
|
|
862
|
-
...commitFieldErrors(state,
|
|
962
|
+
...commitFieldErrors(state, parse, path),
|
|
863
963
|
isValidating: omitKey(state.isValidating, path)
|
|
864
964
|
}));
|
|
865
|
-
return fieldResult(scoped);
|
|
965
|
+
return fieldResult(parse.scoped);
|
|
866
966
|
};
|
|
867
967
|
const applyArrayOp = (path, nextArray, mapper, indexInBounds) => {
|
|
868
968
|
const current = getAtPath(store.getState().values, path);
|
|
@@ -921,7 +1021,9 @@ var createForm = (schema, options) => {
|
|
|
921
1021
|
count: 0,
|
|
922
1022
|
baseline: false
|
|
923
1023
|
};
|
|
924
|
-
const submit = async (onValid,
|
|
1024
|
+
const submit = async (onValid, onInvalidOrOptions, positionalOptions) => {
|
|
1025
|
+
const submitOptions = typeof onInvalidOrOptions === "object" ? onInvalidOrOptions : positionalOptions;
|
|
1026
|
+
const onInvalid = typeof onInvalidOrOptions === "function" ? onInvalidOrOptions : submitOptions?.onInvalid;
|
|
925
1027
|
if (inFlight.count > 0 && submitOptions?.force !== true) {
|
|
926
1028
|
return { kind: "skipped" };
|
|
927
1029
|
}
|
|
@@ -962,6 +1064,7 @@ var createForm = (schema, options) => {
|
|
|
962
1064
|
try {
|
|
963
1065
|
onInvalid?.(merged);
|
|
964
1066
|
} catch (error) {
|
|
1067
|
+
submitOptions?.onError?.(error);
|
|
965
1068
|
return { kind: "error", error };
|
|
966
1069
|
}
|
|
967
1070
|
return { kind: "invalid", errors: merged };
|
|
@@ -988,7 +1091,10 @@ var createForm = (schema, options) => {
|
|
|
988
1091
|
}
|
|
989
1092
|
};
|
|
990
1093
|
if (options.validateOnMount === true) {
|
|
991
|
-
validate();
|
|
1094
|
+
const result = validate();
|
|
1095
|
+
if (result.kind === "pending") {
|
|
1096
|
+
void result.promise.catch(reportBackgroundFailure);
|
|
1097
|
+
}
|
|
992
1098
|
}
|
|
993
1099
|
return Object.freeze({
|
|
994
1100
|
schema,
|
|
@@ -1081,7 +1187,7 @@ var createForm = (schema, options) => {
|
|
|
1081
1187
|
},
|
|
1082
1188
|
setErrors: (errors) => store.setState((state) => ({
|
|
1083
1189
|
...state,
|
|
1084
|
-
...errorChannels(state, { serverErrors: errors })
|
|
1190
|
+
...errorChannels(state, { serverErrors: dropEmptyLists(errors) })
|
|
1085
1191
|
})),
|
|
1086
1192
|
addErrors: (errors) => store.setState((state) => {
|
|
1087
1193
|
const entries = Object.entries(errors);
|
|
@@ -1124,11 +1230,11 @@ var createForm = (schema, options) => {
|
|
|
1124
1230
|
if (next.values !== state.values) {
|
|
1125
1231
|
clearArrayOpsUnder(store, "");
|
|
1126
1232
|
}
|
|
1127
|
-
const serverErrors = patch.serverErrors !== void 0 ? patch.serverErrors : next.values !== state.values ? releaseChangedSlices(state.serverErrors, state.values, next.values) : state.serverErrors;
|
|
1233
|
+
const serverErrors = patch.serverErrors !== void 0 ? dropEmptyLists(patch.serverErrors) : next.values !== state.values ? releaseChangedSlices(state.serverErrors, state.values, next.values) : state.serverErrors;
|
|
1128
1234
|
store.setState(() => ({
|
|
1129
1235
|
...next,
|
|
1130
1236
|
...errorChannels(state, {
|
|
1131
|
-
schemaErrors:
|
|
1237
|
+
schemaErrors: patch.schemaErrors === void 0 ? state.schemaErrors : dropEmptyLists(patch.schemaErrors),
|
|
1132
1238
|
serverErrors
|
|
1133
1239
|
})
|
|
1134
1240
|
}));
|
|
@@ -1237,9 +1343,14 @@ var createForm = (schema, options) => {
|
|
|
1237
1343
|
swapIndices(a, b),
|
|
1238
1344
|
(len) => Number.isInteger(a) && Number.isInteger(b) && a >= 0 && a < len && b >= 0 && b < len
|
|
1239
1345
|
),
|
|
1240
|
-
handleSubmit: (onValid,
|
|
1346
|
+
handleSubmit: (onValid, onInvalidOrOptions, positionalOptions) => async (event) => {
|
|
1241
1347
|
event?.preventDefault();
|
|
1242
|
-
const
|
|
1348
|
+
const opts = typeof onInvalidOrOptions === "object" ? onInvalidOrOptions : positionalOptions;
|
|
1349
|
+
const result = await submit(
|
|
1350
|
+
onValid,
|
|
1351
|
+
onInvalidOrOptions,
|
|
1352
|
+
positionalOptions
|
|
1353
|
+
);
|
|
1243
1354
|
if (result.kind === "error" && opts?.onError === void 0 && isDevBuild()) {
|
|
1244
1355
|
console.warn(
|
|
1245
1356
|
"[formstand] submit handler threw and nothing observed it \u2014 the form shows no feedback. Pass { onError } to handleSubmit (or setError inside your handler):",
|
|
@@ -1265,8 +1376,8 @@ var createForm = (schema, options) => {
|
|
|
1265
1376
|
restore: (snap) => {
|
|
1266
1377
|
clearArrayOpsUnder(store, "");
|
|
1267
1378
|
store.setState(() => {
|
|
1268
|
-
const schemaErrors = snap.schemaErrors ?? emptyErrors;
|
|
1269
|
-
const serverErrors = snap.serverErrors ?? emptyErrors;
|
|
1379
|
+
const schemaErrors = dropEmptyLists(snap.schemaErrors ?? emptyErrors);
|
|
1380
|
+
const serverErrors = dropEmptyLists(snap.serverErrors ?? emptyErrors);
|
|
1270
1381
|
return {
|
|
1271
1382
|
...snap,
|
|
1272
1383
|
schemaErrors,
|
|
@@ -1313,11 +1424,13 @@ var createDebouncer = (ms) => {
|
|
|
1313
1424
|
const timer = {
|
|
1314
1425
|
current: null
|
|
1315
1426
|
};
|
|
1427
|
+
const scheduled = { current: null };
|
|
1316
1428
|
const cancel = () => {
|
|
1317
1429
|
if (timer.current !== null) {
|
|
1318
1430
|
clearTimeout(timer.current);
|
|
1319
1431
|
timer.current = null;
|
|
1320
1432
|
}
|
|
1433
|
+
scheduled.current = null;
|
|
1321
1434
|
};
|
|
1322
1435
|
const schedule = (run) => {
|
|
1323
1436
|
cancel();
|
|
@@ -1325,37 +1438,50 @@ var createDebouncer = (ms) => {
|
|
|
1325
1438
|
run();
|
|
1326
1439
|
return;
|
|
1327
1440
|
}
|
|
1441
|
+
scheduled.current = run;
|
|
1328
1442
|
timer.current = setTimeout(() => {
|
|
1329
1443
|
timer.current = null;
|
|
1444
|
+
scheduled.current = null;
|
|
1330
1445
|
run();
|
|
1331
1446
|
}, ms);
|
|
1332
1447
|
};
|
|
1448
|
+
const flush = () => {
|
|
1449
|
+
const run = scheduled.current;
|
|
1450
|
+
if (run === null) return;
|
|
1451
|
+
cancel();
|
|
1452
|
+
run();
|
|
1453
|
+
};
|
|
1333
1454
|
return Object.freeze({
|
|
1334
1455
|
schedule,
|
|
1335
1456
|
cancel,
|
|
1457
|
+
flush,
|
|
1336
1458
|
pending: () => timer.current !== null
|
|
1337
1459
|
});
|
|
1338
1460
|
};
|
|
1339
1461
|
|
|
1340
1462
|
// src/core/persist.ts
|
|
1341
1463
|
var kindOf = (value) => value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
1342
|
-
var
|
|
1343
|
-
|
|
1344
|
-
if (
|
|
1464
|
+
var joinPath = (base, key) => base === "" ? String(key) : `${base}.${String(key)}`;
|
|
1465
|
+
var conflictPath = (draft, reference, path, flexibleAt) => {
|
|
1466
|
+
if (draft === void 0 || draft === null) return null;
|
|
1467
|
+
if (reference === void 0 || reference === null) return null;
|
|
1345
1468
|
const draftKind = kindOf(draft);
|
|
1346
1469
|
const referenceKind = kindOf(reference);
|
|
1347
|
-
if (draftKind !== referenceKind) return
|
|
1470
|
+
if (draftKind !== referenceKind) return flexibleAt(path) ? null : path;
|
|
1348
1471
|
if (draftKind === "array") {
|
|
1349
1472
|
const [d] = draft;
|
|
1350
1473
|
const [r] = reference;
|
|
1351
|
-
return
|
|
1474
|
+
return conflictPath(d, r, joinPath(path, 0), flexibleAt);
|
|
1352
1475
|
}
|
|
1353
1476
|
if (draftKind === "object") {
|
|
1354
1477
|
const d = draft;
|
|
1355
1478
|
const r = reference;
|
|
1356
|
-
return Object.keys(d).
|
|
1479
|
+
return Object.keys(d).reduce(
|
|
1480
|
+
(found, key) => found ?? conflictPath(d[key], r[key], joinPath(path, key), flexibleAt),
|
|
1481
|
+
null
|
|
1482
|
+
);
|
|
1357
1483
|
}
|
|
1358
|
-
return
|
|
1484
|
+
return null;
|
|
1359
1485
|
};
|
|
1360
1486
|
var defaultStorage = () => {
|
|
1361
1487
|
try {
|
|
@@ -1368,7 +1494,35 @@ var persistForm = (form, options) => {
|
|
|
1368
1494
|
const storage = options.storage ?? defaultStorage();
|
|
1369
1495
|
const debounceMs = options.debounceMs ?? 300;
|
|
1370
1496
|
const apply = options.apply ?? "adopt";
|
|
1371
|
-
const
|
|
1497
|
+
const schema = form.schema;
|
|
1498
|
+
const fillRequiredGaps = (draft, initial, path) => {
|
|
1499
|
+
if (!isPlainObject(draft) || !isPlainObject(initial)) return draft;
|
|
1500
|
+
return Object.keys(initial).reduce(
|
|
1501
|
+
(acc, key) => {
|
|
1502
|
+
const childPath = joinPath(path, key);
|
|
1503
|
+
if (Object.hasOwn(draft, key)) {
|
|
1504
|
+
const next = fillRequiredGaps(draft[key], initial[key], childPath);
|
|
1505
|
+
return Object.is(next, draft[key]) ? acc : { ...acc, [key]: next };
|
|
1506
|
+
}
|
|
1507
|
+
if (initial[key] === void 0) return acc;
|
|
1508
|
+
const sub = fieldSchemaForIntrospection(schema, childPath);
|
|
1509
|
+
return sub !== null && isClearableSchema(sub) ? acc : { ...acc, [key]: initial[key] };
|
|
1510
|
+
},
|
|
1511
|
+
draft
|
|
1512
|
+
);
|
|
1513
|
+
};
|
|
1514
|
+
const applyDraft = (values) => {
|
|
1515
|
+
const filled = fillRequiredGaps(
|
|
1516
|
+
values,
|
|
1517
|
+
form.getState().initialValues,
|
|
1518
|
+
""
|
|
1519
|
+
);
|
|
1520
|
+
if (apply === "edit" || apply === "restore") {
|
|
1521
|
+
form.setValues(filled);
|
|
1522
|
+
} else {
|
|
1523
|
+
form.adoptValues(filled);
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1372
1526
|
const referenceShape = () => {
|
|
1373
1527
|
try {
|
|
1374
1528
|
return JSON.parse(JSON.stringify(form.getState().initialValues));
|
|
@@ -1376,30 +1530,67 @@ var persistForm = (form, options) => {
|
|
|
1376
1530
|
return void 0;
|
|
1377
1531
|
}
|
|
1378
1532
|
};
|
|
1379
|
-
const
|
|
1533
|
+
const flexibleAt = (path) => schemaAllowsKindChangeAt(schema, path);
|
|
1534
|
+
const inspect = () => {
|
|
1535
|
+
const raw = (() => {
|
|
1536
|
+
try {
|
|
1537
|
+
return storage === null ? null : storage.getItem(options.key);
|
|
1538
|
+
} catch {
|
|
1539
|
+
return null;
|
|
1540
|
+
}
|
|
1541
|
+
})();
|
|
1542
|
+
if (raw === null) return { kind: "absent" };
|
|
1380
1543
|
try {
|
|
1381
|
-
const raw = storage === null ? null : storage.getItem(options.key);
|
|
1382
|
-
if (raw === null) return false;
|
|
1383
1544
|
const parsed = JSON.parse(raw);
|
|
1384
1545
|
const versioned = options.version !== void 0 && typeof parsed === "object" && parsed !== null && "__v" in parsed;
|
|
1385
|
-
if (options.version !== void 0 && !versioned)
|
|
1546
|
+
if (options.version !== void 0 && !versioned) {
|
|
1547
|
+
return {
|
|
1548
|
+
kind: "ignored",
|
|
1549
|
+
reason: `it carries no version and this configuration expects version ${String(options.version)}`
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1386
1552
|
if (options.version === void 0 && typeof parsed === "object" && parsed !== null && Object.hasOwn(parsed, "__v") && Object.hasOwn(parsed, "values")) {
|
|
1387
|
-
return
|
|
1553
|
+
return {
|
|
1554
|
+
kind: "ignored",
|
|
1555
|
+
reason: "it was written with a version and this configuration has none"
|
|
1556
|
+
};
|
|
1388
1557
|
}
|
|
1389
1558
|
const wrapper = parsed;
|
|
1390
|
-
if (versioned && wrapper.__v !== options.version)
|
|
1391
|
-
|
|
1559
|
+
if (versioned && wrapper.__v !== options.version) {
|
|
1560
|
+
return {
|
|
1561
|
+
kind: "ignored",
|
|
1562
|
+
reason: `its version (${String(wrapper.__v)}) is not the configured version (${String(options.version)})`
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1565
|
+
if (versioned && wrapper.values === void 0) {
|
|
1566
|
+
return { kind: "ignored", reason: "its version wrapper holds no values" };
|
|
1567
|
+
}
|
|
1392
1568
|
const values = versioned ? wrapper.values : parsed;
|
|
1393
|
-
if (values === null || values === void 0)
|
|
1569
|
+
if (values === null || values === void 0) {
|
|
1570
|
+
return { kind: "ignored", reason: "it holds no values" };
|
|
1571
|
+
}
|
|
1394
1572
|
const reference = referenceShape();
|
|
1395
|
-
|
|
1396
|
-
|
|
1573
|
+
const conflict = reference === void 0 ? null : conflictPath(values, reference, "", flexibleAt);
|
|
1574
|
+
if (conflict !== null) {
|
|
1575
|
+
return {
|
|
1576
|
+
kind: "ignored",
|
|
1577
|
+
reason: `its shape conflicts with the form's initial values at "${conflict}" (set the version option when the schema changes)`
|
|
1578
|
+
};
|
|
1397
1579
|
}
|
|
1398
1580
|
applyDraft(values);
|
|
1399
|
-
return
|
|
1581
|
+
return { kind: "applied" };
|
|
1400
1582
|
} catch {
|
|
1401
|
-
return
|
|
1583
|
+
return { kind: "ignored", reason: "it is not valid JSON" };
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1586
|
+
const load = () => {
|
|
1587
|
+
const outcome = inspect();
|
|
1588
|
+
if (outcome.kind === "ignored" && isDevBuild()) {
|
|
1589
|
+
console.warn(
|
|
1590
|
+
`[formstand] persistForm: ignored the draft under "${options.key}": ${outcome.reason}. The next edit overwrites it.`
|
|
1591
|
+
);
|
|
1402
1592
|
}
|
|
1593
|
+
return outcome.kind === "applied";
|
|
1403
1594
|
};
|
|
1404
1595
|
const writeDraft = (values) => {
|
|
1405
1596
|
try {
|
|
@@ -1413,24 +1604,28 @@ var persistForm = (form, options) => {
|
|
|
1413
1604
|
}
|
|
1414
1605
|
};
|
|
1415
1606
|
const writes = createDebouncer(debounceMs);
|
|
1416
|
-
const cancelPending = () => writes.cancel();
|
|
1417
1607
|
if (apply !== "manual") {
|
|
1418
1608
|
load();
|
|
1419
1609
|
}
|
|
1610
|
+
const cleared = { current: false };
|
|
1420
1611
|
const unsubscribe = form.watchValues((values) => {
|
|
1612
|
+
if (cleared.current && values === form.getState().initialValues) return;
|
|
1613
|
+
cleared.current = false;
|
|
1421
1614
|
writes.schedule(() => writeDraft(values));
|
|
1422
1615
|
});
|
|
1423
1616
|
return Object.freeze({
|
|
1424
1617
|
load,
|
|
1618
|
+
flush: () => writes.flush(),
|
|
1425
1619
|
clear: () => {
|
|
1426
|
-
|
|
1620
|
+
writes.cancel();
|
|
1621
|
+
cleared.current = true;
|
|
1427
1622
|
try {
|
|
1428
1623
|
storage?.removeItem(options.key);
|
|
1429
1624
|
} catch {
|
|
1430
1625
|
}
|
|
1431
1626
|
},
|
|
1432
1627
|
dispose: () => {
|
|
1433
|
-
|
|
1628
|
+
writes.flush();
|
|
1434
1629
|
unsubscribe();
|
|
1435
1630
|
}
|
|
1436
1631
|
});
|
|
@@ -1442,6 +1637,7 @@ var usePersistForm = (form, options) => {
|
|
|
1442
1637
|
latestOptions.current = options;
|
|
1443
1638
|
});
|
|
1444
1639
|
const key = options.key;
|
|
1640
|
+
const storage = options.storage;
|
|
1445
1641
|
react.useEffect(() => {
|
|
1446
1642
|
const handle = persistForm(form, latestOptions.current);
|
|
1447
1643
|
inner.current = handle;
|
|
@@ -1449,10 +1645,11 @@ var usePersistForm = (form, options) => {
|
|
|
1449
1645
|
inner.current = null;
|
|
1450
1646
|
handle.dispose();
|
|
1451
1647
|
};
|
|
1452
|
-
}, [form, key]);
|
|
1648
|
+
}, [form, key, storage]);
|
|
1453
1649
|
return react.useMemo(
|
|
1454
1650
|
() => ({
|
|
1455
1651
|
load: () => inner.current?.load() ?? false,
|
|
1652
|
+
flush: () => inner.current?.flush(),
|
|
1456
1653
|
clear: () => inner.current?.clear(),
|
|
1457
1654
|
// dispose stops THIS component's watching early; the effect cleanup
|
|
1458
1655
|
// still runs its own dispose harmlessly (persistForm's dispose is
|
|
@@ -1486,9 +1683,12 @@ var useForm = (schema, options) => {
|
|
|
1486
1683
|
var hasFieldError = (error) => error !== void 0 && error.length > 0;
|
|
1487
1684
|
var ariaInvalid = (field) => hasFieldError(field.error) ? true : void 0;
|
|
1488
1685
|
var numberToInputText = (value) => value === void 0 || value === null || Number.isNaN(value) ? "" : String(value);
|
|
1686
|
+
var DECIMAL_TEXT = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
|
|
1489
1687
|
var parseNumberText = (text) => {
|
|
1490
|
-
|
|
1491
|
-
|
|
1688
|
+
const trimmed = text.trim();
|
|
1689
|
+
if (trimmed === "") return { kind: "empty" };
|
|
1690
|
+
if (!DECIMAL_TEXT.test(trimmed)) return { kind: "invalid" };
|
|
1691
|
+
const parsed = Number(trimmed);
|
|
1492
1692
|
return Number.isFinite(parsed) ? { kind: "number", value: parsed } : { kind: "invalid" };
|
|
1493
1693
|
};
|
|
1494
1694
|
var textInputProps = (field) => ({
|
|
@@ -1516,11 +1716,11 @@ var numberInputProps = (field) => ({
|
|
|
1516
1716
|
onBlur: field.onBlur
|
|
1517
1717
|
});
|
|
1518
1718
|
var dateToInputText = (value) => {
|
|
1519
|
-
if (value === void 0 || value === null
|
|
1520
|
-
|
|
1521
|
-
|
|
1719
|
+
if (value === void 0 || value === null) return "";
|
|
1720
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
1721
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
1522
1722
|
const pad = (part) => String(part).padStart(2, "0");
|
|
1523
|
-
return `${String(
|
|
1723
|
+
return `${String(date.getFullYear()).padStart(4, "0")}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
1524
1724
|
};
|
|
1525
1725
|
var parseDateText = (text) => {
|
|
1526
1726
|
if (text.trim() === "") return { kind: "empty" };
|
|
@@ -1600,7 +1800,8 @@ var useMaskedInput = (field, options) => {
|
|
|
1600
1800
|
field.setValue(parsed.value);
|
|
1601
1801
|
return;
|
|
1602
1802
|
case "empty": {
|
|
1603
|
-
const
|
|
1803
|
+
const isStringField = typeof field.initialValue === "string" || typeof field.value === "string";
|
|
1804
|
+
const empty = field.clearable || !isStringField ? field.emptyValue : "";
|
|
1604
1805
|
setEdit({ raw: text, pushed: empty });
|
|
1605
1806
|
field.setValue(empty);
|
|
1606
1807
|
return;
|
|
@@ -1667,7 +1868,8 @@ var useFormSteps = (form, steps) => {
|
|
|
1667
1868
|
const goTo = react.useCallback(
|
|
1668
1869
|
async (target) => {
|
|
1669
1870
|
const count = latest.current.length;
|
|
1670
|
-
|
|
1871
|
+
if (!Number.isFinite(target)) return currentStep.current;
|
|
1872
|
+
const clamped = Math.max(0, Math.min(Math.trunc(target), count - 1));
|
|
1671
1873
|
if (clamped <= step) {
|
|
1672
1874
|
setStep(clamped);
|
|
1673
1875
|
return clamped;
|
|
@@ -1740,8 +1942,7 @@ var useFormAction = (form, onValid, options) => {
|
|
|
1740
1942
|
const { onValid: handler, options: opts } = latest.current;
|
|
1741
1943
|
const result = await form.submit(
|
|
1742
1944
|
(data) => handler(data, formData),
|
|
1743
|
-
opts
|
|
1744
|
-
opts?.onError === void 0 ? void 0 : { onError: opts.onError }
|
|
1945
|
+
opts ?? {}
|
|
1745
1946
|
);
|
|
1746
1947
|
warnUnobserved(result, opts, "useFormAction");
|
|
1747
1948
|
},
|
|
@@ -1757,8 +1958,7 @@ var useFormActionState = (form, action, initialState, options) => {
|
|
|
1757
1958
|
async (data) => {
|
|
1758
1959
|
nextRef.current = await action(prev, data, formData);
|
|
1759
1960
|
},
|
|
1760
|
-
options
|
|
1761
|
-
options?.onError === void 0 ? void 0 : { onError: options.onError }
|
|
1961
|
+
options ?? {}
|
|
1762
1962
|
);
|
|
1763
1963
|
warnUnobserved(result, options, "useFormActionState");
|
|
1764
1964
|
return nextRef.current;
|
|
@@ -1824,6 +2024,12 @@ function useField(form, pathArg, options) {
|
|
|
1824
2024
|
debouncerRef.current = null;
|
|
1825
2025
|
};
|
|
1826
2026
|
}, [form, path, debounceMs]);
|
|
2027
|
+
const validateNow = react.useCallback(() => {
|
|
2028
|
+
const result = form.validateField(path);
|
|
2029
|
+
if (result.kind === "pending") {
|
|
2030
|
+
void result.promise.catch(reportBackgroundFailure);
|
|
2031
|
+
}
|
|
2032
|
+
}, [form, path]);
|
|
1827
2033
|
const triggerValidate = react.useCallback(() => {
|
|
1828
2034
|
if (debounceMs !== void 0 && debounceMs > 0) {
|
|
1829
2035
|
const debouncer = debouncerRef.current ?? createDebouncer(debounceMs);
|
|
@@ -1835,12 +2041,12 @@ function useField(form, pathArg, options) {
|
|
|
1835
2041
|
const rebased = state.values !== scheduledValues && state.values === state.initialValues;
|
|
1836
2042
|
if (rebased) return;
|
|
1837
2043
|
if (!Object.is(getAtPath(state.values, path), scheduled)) return;
|
|
1838
|
-
void form.validateFieldAsync(path);
|
|
2044
|
+
void form.validateFieldAsync(path).catch(reportBackgroundFailure);
|
|
1839
2045
|
});
|
|
1840
2046
|
return;
|
|
1841
2047
|
}
|
|
1842
|
-
|
|
1843
|
-
}, [form, path, debounceMs]);
|
|
2048
|
+
validateNow();
|
|
2049
|
+
}, [form, path, debounceMs, validateNow]);
|
|
1844
2050
|
const setValue = react.useCallback(
|
|
1845
2051
|
(value) => {
|
|
1846
2052
|
const before = form.store.getState();
|
|
@@ -1889,9 +2095,10 @@ function useField(form, pathArg, options) {
|
|
|
1889
2095
|
state.submitCount > 0,
|
|
1890
2096
|
true
|
|
1891
2097
|
)) {
|
|
1892
|
-
|
|
2098
|
+
debouncerRef.current?.cancel();
|
|
2099
|
+
validateNow();
|
|
1893
2100
|
}
|
|
1894
|
-
}, [form, path,
|
|
2101
|
+
}, [form, path, validateNow]);
|
|
1895
2102
|
return react.useMemo(
|
|
1896
2103
|
() => ({
|
|
1897
2104
|
path: slice.path,
|
|
@@ -2243,6 +2450,14 @@ function useFieldArray(form, pathArg) {
|
|
|
2243
2450
|
]
|
|
2244
2451
|
);
|
|
2245
2452
|
}
|
|
2453
|
+
|
|
2454
|
+
// src/react/useVariantFieldArray.ts
|
|
2455
|
+
function useVariantFieldArray(form, unionPath, field) {
|
|
2456
|
+
return useFieldArray(
|
|
2457
|
+
form,
|
|
2458
|
+
`${unionPath}.${field}`
|
|
2459
|
+
);
|
|
2460
|
+
}
|
|
2246
2461
|
var useFormError = (form) => react$1.useStore(
|
|
2247
2462
|
form.store,
|
|
2248
2463
|
shallow.useShallow((state) => state.errors[""])
|
|
@@ -2250,29 +2465,37 @@ var useFormError = (form) => react$1.useStore(
|
|
|
2250
2465
|
function useFormValues(form) {
|
|
2251
2466
|
return react$1.useStore(form.store, (state) => state.values);
|
|
2252
2467
|
}
|
|
2253
|
-
|
|
2254
|
-
// src/react/useFields.ts
|
|
2255
2468
|
function useFields(form, paths) {
|
|
2469
|
+
const [arity] = react.useState(paths.length);
|
|
2470
|
+
if (paths.length !== arity) {
|
|
2471
|
+
throw new Error(
|
|
2472
|
+
`[formstand] useFields: the paths tuple changed length (${String(arity)} to ${String(paths.length)}); its length and order must be stable across renders, so pass a literal or a module-level constant.`
|
|
2473
|
+
);
|
|
2474
|
+
}
|
|
2256
2475
|
const fields = paths.map(
|
|
2257
2476
|
(path) => (
|
|
2258
2477
|
// eslint-disable-next-line react-hooks/rules-of-hooks -- a fixed hook count by the stable-arity contract above; each element must be a REAL UseFieldReturn so it spreads into the prop builders
|
|
2259
2478
|
useField(form, path)
|
|
2260
2479
|
)
|
|
2261
2480
|
);
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
fields.
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2481
|
+
return react.useMemo(() => {
|
|
2482
|
+
const merged = [
|
|
2483
|
+
...new Set(fields.flatMap((field) => field.error ?? []))
|
|
2484
|
+
];
|
|
2485
|
+
return {
|
|
2486
|
+
fields,
|
|
2487
|
+
error: merged.length > 0 ? merged : void 0,
|
|
2488
|
+
firstError: merged[0],
|
|
2489
|
+
touched: fields.some((field) => field.touched),
|
|
2490
|
+
dirty: fields.some((field) => field.dirty),
|
|
2491
|
+
isValidating: fields.some((field) => field.isValidating),
|
|
2492
|
+
onBlur: () => {
|
|
2493
|
+
fields.forEach((field) => {
|
|
2494
|
+
field.onBlur();
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
}, fields);
|
|
2276
2499
|
}
|
|
2277
2500
|
function useIsDirty(form, path) {
|
|
2278
2501
|
return react$1.useStore(
|
|
@@ -2321,6 +2544,11 @@ var createFormHooks = (form, name) => {
|
|
|
2321
2544
|
field
|
|
2322
2545
|
);
|
|
2323
2546
|
const useBoundFieldArray = (path) => useFieldArray(structural, path);
|
|
2547
|
+
const useBoundVariantFieldArray = (unionPath, field) => useVariantFieldArray(
|
|
2548
|
+
structural,
|
|
2549
|
+
unionPath,
|
|
2550
|
+
field
|
|
2551
|
+
);
|
|
2324
2552
|
const useBoundSelector = (selector) => useFormSelector(structural, selector);
|
|
2325
2553
|
const useBoundSelectorShallow = (selector) => useFormSelectorShallow(structural, selector);
|
|
2326
2554
|
const useBoundError = () => useFormError(structural);
|
|
@@ -2335,11 +2563,15 @@ var createFormHooks = (form, name) => {
|
|
|
2335
2563
|
);
|
|
2336
2564
|
const useBoundSubmitCount = () => useSubmitCount(structural);
|
|
2337
2565
|
const useBoundSteps = (steps) => useFormSteps(form, steps);
|
|
2566
|
+
const useBoundAction = (onValid, options) => useFormAction(form, onValid, options);
|
|
2567
|
+
const useBoundActionState = (action, initialState, options) => useFormActionState(form, action, initialState, options);
|
|
2568
|
+
const useBoundPersist = (options) => usePersistForm(form, options);
|
|
2338
2569
|
const prefix = capitalize(name ?? "");
|
|
2339
2570
|
return {
|
|
2340
2571
|
[`use${prefix}Field`]: useBoundField,
|
|
2341
2572
|
[`use${prefix}VariantField`]: useBoundVariantField,
|
|
2342
2573
|
[`use${prefix}FieldArray`]: useBoundFieldArray,
|
|
2574
|
+
[`use${prefix}VariantFieldArray`]: useBoundVariantFieldArray,
|
|
2343
2575
|
[`use${prefix}Selector`]: useBoundSelector,
|
|
2344
2576
|
[`use${prefix}SelectorShallow`]: useBoundSelectorShallow,
|
|
2345
2577
|
[`use${prefix}Error`]: useBoundError,
|
|
@@ -2350,7 +2582,10 @@ var createFormHooks = (form, name) => {
|
|
|
2350
2582
|
[`use${prefix}SubmitCount`]: useBoundSubmitCount,
|
|
2351
2583
|
[`use${prefix}Values`]: useBoundValues,
|
|
2352
2584
|
[`use${prefix}Fields`]: useBoundFields,
|
|
2353
|
-
[`use${prefix}Steps`]: useBoundSteps
|
|
2585
|
+
[`use${prefix}Steps`]: useBoundSteps,
|
|
2586
|
+
[`use${prefix}Action`]: useBoundAction,
|
|
2587
|
+
[`use${prefix}ActionState`]: useBoundActionState,
|
|
2588
|
+
[`use${prefix}Persist`]: useBoundPersist
|
|
2354
2589
|
};
|
|
2355
2590
|
};
|
|
2356
2591
|
var useFieldA11y = (error) => {
|
|
@@ -2694,6 +2929,7 @@ exports.useNumberInput = useNumberInput;
|
|
|
2694
2929
|
exports.usePersistForm = usePersistForm;
|
|
2695
2930
|
exports.useSubmitCount = useSubmitCount;
|
|
2696
2931
|
exports.useVariantField = useVariantField;
|
|
2932
|
+
exports.useVariantFieldArray = useVariantFieldArray;
|
|
2697
2933
|
exports.validateAsync = validateAsync;
|
|
2698
2934
|
exports.validateSync = validateSync;
|
|
2699
2935
|
//# sourceMappingURL=index.cjs.map
|