formstand 0.17.0 → 0.19.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 +81 -0
- package/dist/{createForm-D0xLZH-Q.d.cts → createForm-B73p1TgL.d.cts} +2 -1
- package/dist/{createForm-D0xLZH-Q.d.ts → createForm-B73p1TgL.d.ts} +2 -1
- package/dist/devtools/index.d.cts +1 -1
- package/dist/devtools/index.d.ts +1 -1
- package/dist/index.cjs +66 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +65 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,86 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.19.0 — 2026-09-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **The React 19 form-actions bridge.** `useFormAction(form, onValid,
|
|
8
|
+
options?)` returns an action for `<form action={...}>` that validates
|
|
9
|
+
first and hands the handler parsed `z.output` data (plus the raw
|
|
10
|
+
`FormData` last, for file pickers and uncontrolled co-inputs) under
|
|
11
|
+
the full submit lifecycle — isSubmitting/submitCount, errors written
|
|
12
|
+
and marked touched on failure, `onInvalid`/`onError` mirroring
|
|
13
|
+
`handleSubmit`, the same dev warning when a failure resolves
|
|
14
|
+
unobserved, and a reference-stable identity. `useFormActionState(form,
|
|
15
|
+
action, initialState, options?)` is `useActionState` with
|
|
16
|
+
schema-validated data: the handler's `(prevState, data, formData)`
|
|
17
|
+
shape lets a `"use server"` function slot straight in, and invalid,
|
|
18
|
+
skipped, or throwing submissions keep the previous state, because
|
|
19
|
+
field errors already live in the form store. Client-side integration
|
|
20
|
+
by design: no-JS progressive enhancement bypasses any client wrapper,
|
|
21
|
+
so that path validates server-side with the same zod schema.
|
|
22
|
+
|
|
23
|
+
## 0.18.0 — 2026-09-17
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`PersistHandle.restore()` is now `load()`** (breaking). The method's
|
|
28
|
+
DEFAULT application is `adoptValues` — a rebase that reads clean — and
|
|
29
|
+
the old name promised the setValues semantics it only has under
|
|
30
|
+
`apply: "restore"`. The name now describes what it does; the `apply`
|
|
31
|
+
mode names are unchanged. `usePersistForm`'s handle follows.
|
|
32
|
+
- **Cleared inputs write `emptyValue` whenever the schema accepts it.**
|
|
33
|
+
`textInputProps`/`selectProps` (and the bound `TextField`/`SelectField`)
|
|
34
|
+
used to write the empty value only for nullable fields, so clearing
|
|
35
|
+
`z.string().optional()` left `""` behind — a documented asymmetry that
|
|
36
|
+
kept the field dirty against an `undefined` initial and made an optional
|
|
37
|
+
enum select unclearable. Clearing now writes `undefined` for optional
|
|
38
|
+
and defaulted fields and `null` for nullable ones; a REQUIRED string
|
|
39
|
+
cleared to `""` still stays `""`, so the schema judges a visible value
|
|
40
|
+
instead of a hole it rejects. `SelectField`'s empty option is
|
|
41
|
+
accordingly selectable for every clearable field, not just nullable
|
|
42
|
+
ones.
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **`field.clearable`** on `UseFieldReturn`: whether the schema accepts
|
|
47
|
+
the field's `emptyValue` (optional, nullable, or defaulted),
|
|
48
|
+
introspected from the zod schema with the same shallow walk as
|
|
49
|
+
`emptyValue` so the pair can never disagree. Schema-less forms fall
|
|
50
|
+
back to the null-initial heuristic. **`isClearableSchema(schema)`** is
|
|
51
|
+
the exported rule behind it, next to `emptyValueForSchema`.
|
|
52
|
+
|
|
53
|
+
## formstand-cli 0.18.0 — 2026-09-17
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- **Generated kit adapters clear through `field.clearable`.** The
|
|
58
|
+
emitted text and select bindings wrote the empty value only for
|
|
59
|
+
nullable fields, mirroring the library's old rule; they now write
|
|
60
|
+
`field.emptyValue` whenever `field.clearable` says the schema accepts
|
|
61
|
+
it, so generated optional fields clear to `undefined` instead of
|
|
62
|
+
holding `""`. Kit output therefore needs formstand 0.18; regenerate
|
|
63
|
+
to pick the rule up, or keep the old adapter — both compile.
|
|
64
|
+
|
|
65
|
+
## formstand-cli 0.17.0 — 2026-09-17
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- **Containers inside array rows generate.** The remaining row-shape
|
|
70
|
+
TODO matrix is gone (formstand 0.17 types the paths): a tuple as the
|
|
71
|
+
row item or as a row-object field binds its positions inline at static
|
|
72
|
+
sub-indices (`points.${index}.0`, `segments.${index}.span.1`); a
|
|
73
|
+
discriminated union as a row-object FIELD binds on the holed template
|
|
74
|
+
(`invoices.${p0}.pay`), optional/nullable ones keeping the clearable
|
|
75
|
+
select; an array-of-arrays item extracts an inner Rows component; and
|
|
76
|
+
the same shapes under nested arrays work at any depth, union items
|
|
77
|
+
included (`teams.${p0}.methods.${index}`). Single-file extracts a
|
|
78
|
+
child component per site that needs hooks (rows render inside
|
|
79
|
+
rows.map); the module layout binds in the Row component, which already
|
|
80
|
+
is one. The one shape that still degrades to a TODO is a container
|
|
81
|
+
inside a union variant — binding it needs variant sub-paths the
|
|
82
|
+
library does not type.
|
|
83
|
+
|
|
3
84
|
## 0.17.0 — 2026-09-17
|
|
4
85
|
|
|
5
86
|
### Added
|
|
@@ -108,6 +108,7 @@ declare const validateSync: <TSchema extends z.ZodType>(schema: TSchema, values:
|
|
|
108
108
|
declare const validateAsync: <TSchema extends z.ZodType>(schema: TSchema, values: z.input<TSchema>) => Promise<SettledValidationResult<z.output<TSchema>>>;
|
|
109
109
|
declare const isAsyncRequiredError: (e: unknown) => boolean;
|
|
110
110
|
declare const emptyValueForSchema: (schema: z.ZodType) => null | undefined;
|
|
111
|
+
declare const isClearableSchema: (schema: z.ZodType) => boolean;
|
|
111
112
|
|
|
112
113
|
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, "getState" | "getInitialState" | "subscribe">;
|
|
113
114
|
type CreateFormOptions<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = Readonly<{
|
|
@@ -197,4 +198,4 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
|
|
|
197
198
|
}>;
|
|
198
199
|
declare const createForm: <TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth>(schema: TSchema, options: CreateFormOptions<TSchema, D>) => Form<TSchema, D>;
|
|
199
200
|
|
|
200
|
-
export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r,
|
|
201
|
+
export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r, isClearableSchema as s, shouldValidateOn as t, validateSync as u, validateAsync as v };
|
|
@@ -108,6 +108,7 @@ declare const validateSync: <TSchema extends z.ZodType>(schema: TSchema, values:
|
|
|
108
108
|
declare const validateAsync: <TSchema extends z.ZodType>(schema: TSchema, values: z.input<TSchema>) => Promise<SettledValidationResult<z.output<TSchema>>>;
|
|
109
109
|
declare const isAsyncRequiredError: (e: unknown) => boolean;
|
|
110
110
|
declare const emptyValueForSchema: (schema: z.ZodType) => null | undefined;
|
|
111
|
+
declare const isClearableSchema: (schema: z.ZodType) => boolean;
|
|
111
112
|
|
|
112
113
|
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, "getState" | "getInitialState" | "subscribe">;
|
|
113
114
|
type CreateFormOptions<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = Readonly<{
|
|
@@ -197,4 +198,4 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
|
|
|
197
198
|
}>;
|
|
198
199
|
declare const createForm: <TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth>(schema: TSchema, options: CreateFormOptions<TSchema, D>) => Form<TSchema, D>;
|
|
199
200
|
|
|
200
|
-
export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r,
|
|
201
|
+
export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r, isClearableSchema as s, shouldValidateOn as t, validateSync as u, validateAsync as v };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { F as Form } from '../createForm-
|
|
3
|
+
import { F as Form } from '../createForm-B73p1TgL.cjs';
|
|
4
4
|
import 'zustand/vanilla';
|
|
5
5
|
|
|
6
6
|
type DevtoolsPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
package/dist/devtools/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { F as Form } from '../createForm-
|
|
3
|
+
import { F as Form } from '../createForm-B73p1TgL.js';
|
|
4
4
|
import 'zustand/vanilla';
|
|
5
5
|
|
|
6
6
|
type DevtoolsPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
package/dist/index.cjs
CHANGED
|
@@ -276,6 +276,7 @@ var emptyValueForSchema = (schema) => {
|
|
|
276
276
|
};
|
|
277
277
|
return walk(schema, false);
|
|
278
278
|
};
|
|
279
|
+
var isClearableSchema = (schema) => schema instanceof zod.z.ZodOptional || schema instanceof zod.z.ZodNullable || schema instanceof zod.z.ZodDefault || schema instanceof zod.z.ZodPrefault;
|
|
279
280
|
var unwrapForWalk = (s) => {
|
|
280
281
|
if (s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodNullable) {
|
|
281
282
|
return s.unwrap();
|
|
@@ -1197,7 +1198,7 @@ var persistForm = (form, options) => {
|
|
|
1197
1198
|
return void 0;
|
|
1198
1199
|
}
|
|
1199
1200
|
};
|
|
1200
|
-
const
|
|
1201
|
+
const load = () => {
|
|
1201
1202
|
try {
|
|
1202
1203
|
const raw = storage === null ? null : storage.getItem(options.key);
|
|
1203
1204
|
if (raw === null) return false;
|
|
@@ -1242,7 +1243,7 @@ var persistForm = (form, options) => {
|
|
|
1242
1243
|
}
|
|
1243
1244
|
};
|
|
1244
1245
|
if (apply !== "manual") {
|
|
1245
|
-
|
|
1246
|
+
load();
|
|
1246
1247
|
}
|
|
1247
1248
|
const unsubscribe = form.watchValues((values) => {
|
|
1248
1249
|
cancelPending();
|
|
@@ -1256,7 +1257,7 @@ var persistForm = (form, options) => {
|
|
|
1256
1257
|
}
|
|
1257
1258
|
});
|
|
1258
1259
|
return Object.freeze({
|
|
1259
|
-
|
|
1260
|
+
load,
|
|
1260
1261
|
clear: () => {
|
|
1261
1262
|
cancelPending();
|
|
1262
1263
|
try {
|
|
@@ -1287,7 +1288,7 @@ var usePersistForm = (form, options) => {
|
|
|
1287
1288
|
}, [form, key]);
|
|
1288
1289
|
return react.useMemo(
|
|
1289
1290
|
() => ({
|
|
1290
|
-
|
|
1291
|
+
load: () => inner.current?.load() ?? false,
|
|
1291
1292
|
clear: () => inner.current?.clear(),
|
|
1292
1293
|
// dispose stops THIS component's watching early; the effect cleanup
|
|
1293
1294
|
// still runs its own dispose harmlessly (persistForm's dispose is
|
|
@@ -1316,6 +1317,51 @@ var useForm = (schema, options) => {
|
|
|
1316
1317
|
}, [form, schema, options.initialValues]);
|
|
1317
1318
|
return form;
|
|
1318
1319
|
};
|
|
1320
|
+
var warnUnobserved = (result, options, site) => {
|
|
1321
|
+
if (result.kind === "error" && options?.onError === void 0 && process.env.NODE_ENV !== "production") {
|
|
1322
|
+
console.warn(
|
|
1323
|
+
`[formstand] action handler threw and nothing observed it \u2014 the form shows no feedback. Pass { onError } to ${site} (or setError inside your handler):`,
|
|
1324
|
+
result.error
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
var useFormAction = (form, onValid, options) => {
|
|
1329
|
+
const latest = react.useRef({ onValid, options });
|
|
1330
|
+
react.useEffect(() => {
|
|
1331
|
+
latest.current = { onValid, options };
|
|
1332
|
+
});
|
|
1333
|
+
return react.useCallback(
|
|
1334
|
+
async (formData) => {
|
|
1335
|
+
const { onValid: handler, options: opts } = latest.current;
|
|
1336
|
+
const result = await form.submit(
|
|
1337
|
+
(data) => handler(data, formData),
|
|
1338
|
+
opts?.onInvalid,
|
|
1339
|
+
opts?.onError === void 0 ? void 0 : { onError: opts.onError }
|
|
1340
|
+
);
|
|
1341
|
+
warnUnobserved(result, opts, "useFormAction");
|
|
1342
|
+
},
|
|
1343
|
+
[form]
|
|
1344
|
+
);
|
|
1345
|
+
};
|
|
1346
|
+
var useFormActionState = (form, action, initialState, options) => {
|
|
1347
|
+
const [state, formAction, isPending] = react.useActionState(
|
|
1348
|
+
async (prevState, formData) => {
|
|
1349
|
+
const prev = prevState;
|
|
1350
|
+
const nextRef = { current: prev };
|
|
1351
|
+
const result = await form.submit(
|
|
1352
|
+
async (data) => {
|
|
1353
|
+
nextRef.current = await action(prev, data, formData);
|
|
1354
|
+
},
|
|
1355
|
+
options?.onInvalid,
|
|
1356
|
+
options?.onError === void 0 ? void 0 : { onError: options.onError }
|
|
1357
|
+
);
|
|
1358
|
+
warnUnobserved(result, options, "useFormActionState");
|
|
1359
|
+
return nextRef.current;
|
|
1360
|
+
},
|
|
1361
|
+
initialState
|
|
1362
|
+
);
|
|
1363
|
+
return [state, formAction, isPending];
|
|
1364
|
+
};
|
|
1319
1365
|
var createFormContext = () => {
|
|
1320
1366
|
const Context = react.createContext(null);
|
|
1321
1367
|
const Provider = ({ form, children }) => /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value: form, children });
|
|
@@ -1351,12 +1397,17 @@ function useField(form, pathArg, options) {
|
|
|
1351
1397
|
const path = slice.path;
|
|
1352
1398
|
const formSchema = form.schema;
|
|
1353
1399
|
const initialValue = slice.initialValue;
|
|
1354
|
-
const emptyValue = react.useMemo(() => {
|
|
1400
|
+
const { emptyValue, clearable } = react.useMemo(() => {
|
|
1355
1401
|
if (formSchema !== void 0) {
|
|
1356
1402
|
const sub = fieldSchemaAtPath(formSchema, path);
|
|
1357
|
-
if (sub !== null)
|
|
1403
|
+
if (sub !== null) {
|
|
1404
|
+
return {
|
|
1405
|
+
emptyValue: emptyValueForSchema(sub),
|
|
1406
|
+
clearable: isClearableSchema(sub)
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1358
1409
|
}
|
|
1359
|
-
return initialValue === null ? null : void 0;
|
|
1410
|
+
return initialValue === null ? { emptyValue: null, clearable: true } : { emptyValue: void 0, clearable: false };
|
|
1360
1411
|
}, [formSchema, path, initialValue]);
|
|
1361
1412
|
const debounceMs = options?.debounceMs;
|
|
1362
1413
|
const debounceTimerRef = react.useRef(null);
|
|
@@ -1442,6 +1493,7 @@ function useField(form, pathArg, options) {
|
|
|
1442
1493
|
value: slice.value,
|
|
1443
1494
|
initialValue: slice.initialValue,
|
|
1444
1495
|
emptyValue,
|
|
1496
|
+
clearable,
|
|
1445
1497
|
error: slice.error,
|
|
1446
1498
|
// `?.[0]` covers both the undefined channel and an empty array.
|
|
1447
1499
|
firstError: slice.error?.[0],
|
|
@@ -1456,7 +1508,7 @@ function useField(form, pathArg, options) {
|
|
|
1456
1508
|
validateAsync: validateAsync2,
|
|
1457
1509
|
onBlur
|
|
1458
1510
|
}),
|
|
1459
|
-
[slice, emptyValue, setValue, setTouched, setError, clearError, validate, validateAsync2, onBlur]
|
|
1511
|
+
[slice, emptyValue, clearable, setValue, setTouched, setError, clearError, validate, validateAsync2, onBlur]
|
|
1460
1512
|
);
|
|
1461
1513
|
}
|
|
1462
1514
|
|
|
@@ -1797,9 +1849,7 @@ var textInputProps = (field) => ({
|
|
|
1797
1849
|
"aria-invalid": ariaInvalid(field),
|
|
1798
1850
|
onChange: (e) => {
|
|
1799
1851
|
const text = e.target.value;
|
|
1800
|
-
field.setValue(
|
|
1801
|
-
text === "" && field.emptyValue === null ? null : text
|
|
1802
|
-
);
|
|
1852
|
+
field.setValue(text === "" && field.clearable ? field.emptyValue : text);
|
|
1803
1853
|
},
|
|
1804
1854
|
onBlur: field.onBlur
|
|
1805
1855
|
});
|
|
@@ -1873,9 +1923,7 @@ var selectProps = (field) => ({
|
|
|
1873
1923
|
"aria-invalid": ariaInvalid(field),
|
|
1874
1924
|
onChange: (e) => {
|
|
1875
1925
|
const v = e.target.value;
|
|
1876
|
-
field.setValue(
|
|
1877
|
-
v === "" && field.emptyValue === null ? null : v
|
|
1878
|
-
);
|
|
1926
|
+
field.setValue(v === "" && field.clearable ? field.emptyValue : v);
|
|
1879
1927
|
},
|
|
1880
1928
|
onBlur: field.onBlur
|
|
1881
1929
|
});
|
|
@@ -2082,7 +2130,7 @@ var SelectField = ({
|
|
|
2082
2130
|
const field = useField(form, path);
|
|
2083
2131
|
const a11y = useFieldA11y(field.error);
|
|
2084
2132
|
const select = selectProps(field);
|
|
2085
|
-
const clearable = field.
|
|
2133
|
+
const clearable = field.clearable;
|
|
2086
2134
|
const hasExplicitEmptyOption = options.some((opt) => opt.value === "");
|
|
2087
2135
|
const showEmptyOption = !hasExplicitEmptyOption && (clearable || select.value === "" || placeholder !== void 0);
|
|
2088
2136
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2189,6 +2237,7 @@ exports.focusFirstError = focusFirstError;
|
|
|
2189
2237
|
exports.getAtPath = getAtPath;
|
|
2190
2238
|
exports.hasFieldError = hasFieldError;
|
|
2191
2239
|
exports.isAsyncRequiredError = isAsyncRequiredError;
|
|
2240
|
+
exports.isClearableSchema = isClearableSchema;
|
|
2192
2241
|
exports.numberInputProps = numberInputProps;
|
|
2193
2242
|
exports.numberToInputText = numberToInputText;
|
|
2194
2243
|
exports.parseDateText = parseDateText;
|
|
@@ -2203,6 +2252,8 @@ exports.useField = useField;
|
|
|
2203
2252
|
exports.useFieldArray = useFieldArray;
|
|
2204
2253
|
exports.useFields = useFields;
|
|
2205
2254
|
exports.useForm = useForm;
|
|
2255
|
+
exports.useFormAction = useFormAction;
|
|
2256
|
+
exports.useFormActionState = useFormActionState;
|
|
2206
2257
|
exports.useFormError = useFormError;
|
|
2207
2258
|
exports.useFormSelector = useFormSelector;
|
|
2208
2259
|
exports.useFormSelectorShallow = useFormSelectorShallow;
|