formstand 0.6.0 → 0.7.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 +27 -0
- package/dist/index.cjs +164 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -59
- package/dist/index.d.ts +90 -59
- package/dist/index.js +165 -138
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createStore } from 'zustand/vanilla';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { useRef, useEffect, createContext, useMemo, useCallback,
|
|
3
|
+
import { useRef, useEffect, createContext, useMemo, useCallback, useState, useId, useContext } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
import { useStore } from 'zustand/react';
|
|
6
6
|
import { useShallow } from 'zustand/react/shallow';
|
|
@@ -983,38 +983,6 @@ var createFormContext = () => {
|
|
|
983
983
|
};
|
|
984
984
|
return { Provider, useFormContext };
|
|
985
985
|
};
|
|
986
|
-
function useFormSelector(form, selector) {
|
|
987
|
-
return useStore(form.store, selector);
|
|
988
|
-
}
|
|
989
|
-
function useFormSelectorShallow(form, selector) {
|
|
990
|
-
return useStore(form.store, useShallow(selector));
|
|
991
|
-
}
|
|
992
|
-
var useFormError = (form) => useStore(
|
|
993
|
-
form.store,
|
|
994
|
-
useShallow((state) => state.errors[""])
|
|
995
|
-
);
|
|
996
|
-
function useIsDirty(form, path) {
|
|
997
|
-
return useStore(
|
|
998
|
-
form.store,
|
|
999
|
-
(state) => path === void 0 || path === "" ? isFieldDirty(state.values, state.initialValues) : isFieldDirty(
|
|
1000
|
-
getAtPath(state.values, path),
|
|
1001
|
-
getAtPath(state.initialValues, path)
|
|
1002
|
-
)
|
|
1003
|
-
);
|
|
1004
|
-
}
|
|
1005
|
-
function useIsValid(form, path) {
|
|
1006
|
-
return useStore(form.store, (state) => {
|
|
1007
|
-
for (const k in state.errors) {
|
|
1008
|
-
const errs = state.errors[k];
|
|
1009
|
-
if (errs !== void 0 && errs.length > 0 && (path === void 0 || path === "" || isPathOrChild(k, path))) {
|
|
1010
|
-
return false;
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
return true;
|
|
1014
|
-
});
|
|
1015
|
-
}
|
|
1016
|
-
var useIsSubmitting = (form) => useStore(form.store, (state) => state.isSubmitting);
|
|
1017
|
-
var useSubmitCount = (form) => useStore(form.store, (state) => state.submitCount);
|
|
1018
986
|
function useField(form, pathArg, options) {
|
|
1019
987
|
const slice = useStore(
|
|
1020
988
|
form.store,
|
|
@@ -1144,6 +1112,169 @@ function useField(form, pathArg, options) {
|
|
|
1144
1112
|
[slice, emptyValue, setValue, setTouched, setError, clearError, validate, validateAsync2, onBlur]
|
|
1145
1113
|
);
|
|
1146
1114
|
}
|
|
1115
|
+
var EMPTY_ID_STATE = { items: [], ids: [], counter: 0 };
|
|
1116
|
+
var EMPTY_ITEMS = [];
|
|
1117
|
+
var reconcileIds = (prev, nextItems) => {
|
|
1118
|
+
if (prev.items === nextItems) return prev;
|
|
1119
|
+
if (prev.items.length === nextItems.length && prev.items.every((item, i) => Object.is(item, nextItems[i]))) {
|
|
1120
|
+
return prev;
|
|
1121
|
+
}
|
|
1122
|
+
const buckets = prev.items.reduce((acc, item, i) => {
|
|
1123
|
+
const bucket = acc.get(item);
|
|
1124
|
+
if (bucket === void 0) {
|
|
1125
|
+
acc.set(item, [i]);
|
|
1126
|
+
} else {
|
|
1127
|
+
bucket.push(i);
|
|
1128
|
+
}
|
|
1129
|
+
return acc;
|
|
1130
|
+
}, /* @__PURE__ */ new Map());
|
|
1131
|
+
const matchedIds = nextItems.map((item) => {
|
|
1132
|
+
const prevIndex = buckets.get(item)?.shift();
|
|
1133
|
+
return prevIndex === void 0 ? null : prev.ids[prevIndex] ?? null;
|
|
1134
|
+
});
|
|
1135
|
+
const leftover = [...buckets.values()].flat().sort((a, b) => a - b).map((i) => prev.ids[i]).filter((id) => id !== void 0);
|
|
1136
|
+
const ordinals = matchedIds.reduce((acc, id) => {
|
|
1137
|
+
const count = acc.length === 0 ? 0 : acc[acc.length - 1] ?? 0;
|
|
1138
|
+
acc.push(id === null ? count + 1 : count);
|
|
1139
|
+
return acc;
|
|
1140
|
+
}, []);
|
|
1141
|
+
const unmatched = ordinals.length === 0 ? 0 : ordinals[ordinals.length - 1] ?? 0;
|
|
1142
|
+
const ids = matchedIds.map((id, i) => {
|
|
1143
|
+
if (id !== null) return id;
|
|
1144
|
+
const ordinal = ordinals[i] ?? 0;
|
|
1145
|
+
return leftover[ordinal - 1] ?? `__zfa_${prev.counter + (ordinal - leftover.length)}`;
|
|
1146
|
+
});
|
|
1147
|
+
return {
|
|
1148
|
+
items: nextItems,
|
|
1149
|
+
ids,
|
|
1150
|
+
counter: prev.counter + Math.max(0, unmatched - leftover.length)
|
|
1151
|
+
};
|
|
1152
|
+
};
|
|
1153
|
+
function useFieldArray(form, pathArg) {
|
|
1154
|
+
const path = useStore(
|
|
1155
|
+
form.store,
|
|
1156
|
+
(state) => typeof pathArg === "function" ? pathArg(state) : pathArg
|
|
1157
|
+
);
|
|
1158
|
+
const slice = useStore(
|
|
1159
|
+
form.store,
|
|
1160
|
+
useShallow((state) => {
|
|
1161
|
+
const value = getAtPath(state.values, path);
|
|
1162
|
+
return {
|
|
1163
|
+
items: Array.isArray(value) ? value : EMPTY_ITEMS,
|
|
1164
|
+
error: state.errors[path]
|
|
1165
|
+
};
|
|
1166
|
+
})
|
|
1167
|
+
);
|
|
1168
|
+
const items = slice.items;
|
|
1169
|
+
const error = slice.error;
|
|
1170
|
+
const [idEntry, setIdEntry] = useState({ form, path, state: EMPTY_ID_STATE });
|
|
1171
|
+
const base = idEntry.form === form && idEntry.path === path ? idEntry.state : { ...EMPTY_ID_STATE, counter: idEntry.state.counter };
|
|
1172
|
+
const nextIdState = reconcileIds(base, items);
|
|
1173
|
+
if (idEntry.form !== form || idEntry.path !== path || idEntry.state !== nextIdState) {
|
|
1174
|
+
setIdEntry({ form, path, state: nextIdState });
|
|
1175
|
+
}
|
|
1176
|
+
const ids = nextIdState.ids;
|
|
1177
|
+
const push = useCallback(
|
|
1178
|
+
(item) => form.arrayPush(path, item),
|
|
1179
|
+
[form, path]
|
|
1180
|
+
);
|
|
1181
|
+
const remove = useCallback(
|
|
1182
|
+
(index) => form.arrayRemove(path, index),
|
|
1183
|
+
[form, path]
|
|
1184
|
+
);
|
|
1185
|
+
const insert = useCallback(
|
|
1186
|
+
(index, item) => form.arrayInsert(path, index, item),
|
|
1187
|
+
[form, path]
|
|
1188
|
+
);
|
|
1189
|
+
const move = useCallback(
|
|
1190
|
+
(from, to) => form.arrayMove(path, from, to),
|
|
1191
|
+
[form, path]
|
|
1192
|
+
);
|
|
1193
|
+
const swap = useCallback(
|
|
1194
|
+
(a, b) => form.arraySwap(path, a, b),
|
|
1195
|
+
[form, path]
|
|
1196
|
+
);
|
|
1197
|
+
const fields = useMemo(
|
|
1198
|
+
() => items.map((value, index) => ({
|
|
1199
|
+
id: ids[index] ?? `__zfa_fallback_${index}`,
|
|
1200
|
+
value
|
|
1201
|
+
})),
|
|
1202
|
+
[items, ids]
|
|
1203
|
+
);
|
|
1204
|
+
return useMemo(
|
|
1205
|
+
() => ({
|
|
1206
|
+
fields,
|
|
1207
|
+
items,
|
|
1208
|
+
length: items.length,
|
|
1209
|
+
error,
|
|
1210
|
+
push,
|
|
1211
|
+
remove,
|
|
1212
|
+
insert,
|
|
1213
|
+
move,
|
|
1214
|
+
swap
|
|
1215
|
+
}),
|
|
1216
|
+
[fields, items, error, push, remove, insert, move, swap]
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
var useFormError = (form) => useStore(
|
|
1220
|
+
form.store,
|
|
1221
|
+
useShallow((state) => state.errors[""])
|
|
1222
|
+
);
|
|
1223
|
+
function useIsDirty(form, path) {
|
|
1224
|
+
return useStore(
|
|
1225
|
+
form.store,
|
|
1226
|
+
(state) => path === void 0 || path === "" ? isFieldDirty(state.values, state.initialValues) : isFieldDirty(
|
|
1227
|
+
getAtPath(state.values, path),
|
|
1228
|
+
getAtPath(state.initialValues, path)
|
|
1229
|
+
)
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
function useIsValid(form, path) {
|
|
1233
|
+
return useStore(form.store, (state) => {
|
|
1234
|
+
for (const k in state.errors) {
|
|
1235
|
+
const errs = state.errors[k];
|
|
1236
|
+
if (errs !== void 0 && errs.length > 0 && (path === void 0 || path === "" || isPathOrChild(k, path))) {
|
|
1237
|
+
return false;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
return true;
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
var useIsSubmitting = (form) => useStore(form.store, (state) => state.isSubmitting);
|
|
1244
|
+
var useSubmitCount = (form) => useStore(form.store, (state) => state.submitCount);
|
|
1245
|
+
function useFormSelector(form, selector) {
|
|
1246
|
+
return useStore(form.store, selector);
|
|
1247
|
+
}
|
|
1248
|
+
function useFormSelectorShallow(form, selector) {
|
|
1249
|
+
return useStore(form.store, useShallow(selector));
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// src/react/createFormHooks.ts
|
|
1253
|
+
var capitalize = (name) => name.length === 0 ? name : name.charAt(0).toUpperCase() + name.slice(1);
|
|
1254
|
+
var createFormHooks = (form, name) => {
|
|
1255
|
+
const structural = form;
|
|
1256
|
+
const useBoundField = (path, options) => useField(structural, path, options);
|
|
1257
|
+
const useBoundFieldArray = (path) => useFieldArray(structural, path);
|
|
1258
|
+
const useBoundSelector = (selector) => useFormSelector(structural, selector);
|
|
1259
|
+
const useBoundSelectorShallow = (selector) => useFormSelectorShallow(structural, selector);
|
|
1260
|
+
const useBoundError = () => useFormError(structural);
|
|
1261
|
+
const useBoundIsDirty = (path) => useIsDirty(structural, path);
|
|
1262
|
+
const useBoundIsValid = (path) => useIsValid(structural, path);
|
|
1263
|
+
const useBoundIsSubmitting = () => useIsSubmitting(structural);
|
|
1264
|
+
const useBoundSubmitCount = () => useSubmitCount(structural);
|
|
1265
|
+
const prefix = capitalize(name ?? "");
|
|
1266
|
+
return {
|
|
1267
|
+
[`use${prefix}Field`]: useBoundField,
|
|
1268
|
+
[`use${prefix}FieldArray`]: useBoundFieldArray,
|
|
1269
|
+
[`use${prefix}Selector`]: useBoundSelector,
|
|
1270
|
+
[`use${prefix}SelectorShallow`]: useBoundSelectorShallow,
|
|
1271
|
+
[`use${prefix}Error`]: useBoundError,
|
|
1272
|
+
[`use${prefix}IsDirty`]: useBoundIsDirty,
|
|
1273
|
+
[`use${prefix}IsValid`]: useBoundIsValid,
|
|
1274
|
+
[`use${prefix}IsSubmitting`]: useBoundIsSubmitting,
|
|
1275
|
+
[`use${prefix}SubmitCount`]: useBoundSubmitCount
|
|
1276
|
+
};
|
|
1277
|
+
};
|
|
1147
1278
|
|
|
1148
1279
|
// src/react/inputProps.ts
|
|
1149
1280
|
var ariaInvalid = (field) => field.error !== void 0 && field.error.length > 0 ? true : void 0;
|
|
@@ -1398,111 +1529,7 @@ var focusField = (path, root) => {
|
|
|
1398
1529
|
const controls = focusableControls(root ?? document);
|
|
1399
1530
|
return path === "" ? (root !== void 0 || document.querySelectorAll("form").length <= 1) && focusFirstOf(controls) : focusFirstOf(controls.filter((el) => nameMatchesAny(el, [path])));
|
|
1400
1531
|
};
|
|
1401
|
-
var EMPTY_ID_STATE = { items: [], ids: [], counter: 0 };
|
|
1402
|
-
var EMPTY_ITEMS = [];
|
|
1403
|
-
var reconcileIds = (prev, nextItems) => {
|
|
1404
|
-
if (prev.items === nextItems) return prev;
|
|
1405
|
-
if (prev.items.length === nextItems.length && prev.items.every((item, i) => Object.is(item, nextItems[i]))) {
|
|
1406
|
-
return prev;
|
|
1407
|
-
}
|
|
1408
|
-
const buckets = prev.items.reduce((acc, item, i) => {
|
|
1409
|
-
const bucket = acc.get(item);
|
|
1410
|
-
if (bucket === void 0) {
|
|
1411
|
-
acc.set(item, [i]);
|
|
1412
|
-
} else {
|
|
1413
|
-
bucket.push(i);
|
|
1414
|
-
}
|
|
1415
|
-
return acc;
|
|
1416
|
-
}, /* @__PURE__ */ new Map());
|
|
1417
|
-
const matchedIds = nextItems.map((item) => {
|
|
1418
|
-
const prevIndex = buckets.get(item)?.shift();
|
|
1419
|
-
return prevIndex === void 0 ? null : prev.ids[prevIndex] ?? null;
|
|
1420
|
-
});
|
|
1421
|
-
const leftover = [...buckets.values()].flat().sort((a, b) => a - b).map((i) => prev.ids[i]).filter((id) => id !== void 0);
|
|
1422
|
-
const ordinals = matchedIds.reduce((acc, id) => {
|
|
1423
|
-
const count = acc.length === 0 ? 0 : acc[acc.length - 1] ?? 0;
|
|
1424
|
-
acc.push(id === null ? count + 1 : count);
|
|
1425
|
-
return acc;
|
|
1426
|
-
}, []);
|
|
1427
|
-
const unmatched = ordinals.length === 0 ? 0 : ordinals[ordinals.length - 1] ?? 0;
|
|
1428
|
-
const ids = matchedIds.map((id, i) => {
|
|
1429
|
-
if (id !== null) return id;
|
|
1430
|
-
const ordinal = ordinals[i] ?? 0;
|
|
1431
|
-
return leftover[ordinal - 1] ?? `__zfa_${prev.counter + (ordinal - leftover.length)}`;
|
|
1432
|
-
});
|
|
1433
|
-
return {
|
|
1434
|
-
items: nextItems,
|
|
1435
|
-
ids,
|
|
1436
|
-
counter: prev.counter + Math.max(0, unmatched - leftover.length)
|
|
1437
|
-
};
|
|
1438
|
-
};
|
|
1439
|
-
function useFieldArray(form, pathArg) {
|
|
1440
|
-
const path = useStore(
|
|
1441
|
-
form.store,
|
|
1442
|
-
(state) => typeof pathArg === "function" ? pathArg(state) : pathArg
|
|
1443
|
-
);
|
|
1444
|
-
const slice = useStore(
|
|
1445
|
-
form.store,
|
|
1446
|
-
useShallow((state) => {
|
|
1447
|
-
const value = getAtPath(state.values, path);
|
|
1448
|
-
return {
|
|
1449
|
-
items: Array.isArray(value) ? value : EMPTY_ITEMS,
|
|
1450
|
-
error: state.errors[path]
|
|
1451
|
-
};
|
|
1452
|
-
})
|
|
1453
|
-
);
|
|
1454
|
-
const items = slice.items;
|
|
1455
|
-
const error = slice.error;
|
|
1456
|
-
const [idEntry, setIdEntry] = useState({ form, path, state: EMPTY_ID_STATE });
|
|
1457
|
-
const base = idEntry.form === form && idEntry.path === path ? idEntry.state : { ...EMPTY_ID_STATE, counter: idEntry.state.counter };
|
|
1458
|
-
const nextIdState = reconcileIds(base, items);
|
|
1459
|
-
if (idEntry.form !== form || idEntry.path !== path || idEntry.state !== nextIdState) {
|
|
1460
|
-
setIdEntry({ form, path, state: nextIdState });
|
|
1461
|
-
}
|
|
1462
|
-
const ids = nextIdState.ids;
|
|
1463
|
-
const push = useCallback(
|
|
1464
|
-
(item) => form.arrayPush(path, item),
|
|
1465
|
-
[form, path]
|
|
1466
|
-
);
|
|
1467
|
-
const remove = useCallback(
|
|
1468
|
-
(index) => form.arrayRemove(path, index),
|
|
1469
|
-
[form, path]
|
|
1470
|
-
);
|
|
1471
|
-
const insert = useCallback(
|
|
1472
|
-
(index, item) => form.arrayInsert(path, index, item),
|
|
1473
|
-
[form, path]
|
|
1474
|
-
);
|
|
1475
|
-
const move = useCallback(
|
|
1476
|
-
(from, to) => form.arrayMove(path, from, to),
|
|
1477
|
-
[form, path]
|
|
1478
|
-
);
|
|
1479
|
-
const swap = useCallback(
|
|
1480
|
-
(a, b) => form.arraySwap(path, a, b),
|
|
1481
|
-
[form, path]
|
|
1482
|
-
);
|
|
1483
|
-
const fields = useMemo(
|
|
1484
|
-
() => items.map((value, index) => ({
|
|
1485
|
-
id: ids[index] ?? `__zfa_fallback_${index}`,
|
|
1486
|
-
value
|
|
1487
|
-
})),
|
|
1488
|
-
[items, ids]
|
|
1489
|
-
);
|
|
1490
|
-
return useMemo(
|
|
1491
|
-
() => ({
|
|
1492
|
-
fields,
|
|
1493
|
-
items,
|
|
1494
|
-
length: items.length,
|
|
1495
|
-
error,
|
|
1496
|
-
push,
|
|
1497
|
-
remove,
|
|
1498
|
-
insert,
|
|
1499
|
-
move,
|
|
1500
|
-
swap
|
|
1501
|
-
}),
|
|
1502
|
-
[fields, items, error, push, remove, insert, move, swap]
|
|
1503
|
-
);
|
|
1504
|
-
}
|
|
1505
1532
|
|
|
1506
|
-
export { CheckboxField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, isAsyncRequiredError, numberInputProps, numberToInputText, parseNumberText, parsePath, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useSubmitCount, validateAsync, validateSync };
|
|
1533
|
+
export { CheckboxField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, isAsyncRequiredError, numberInputProps, numberToInputText, parseNumberText, parsePath, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useSubmitCount, validateAsync, validateSync };
|
|
1507
1534
|
//# sourceMappingURL=index.js.map
|
|
1508
1535
|
//# sourceMappingURL=index.js.map
|