formstand 0.19.0 → 0.21.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 +177 -0
- package/README.md +11 -3
- package/dist/chunk-MQ6262S3.js +20 -0
- package/dist/chunk-MQ6262S3.js.map +1 -0
- package/dist/{chunk-N7WPXYCU.js → chunk-OB23TUKY.js} +11 -4
- package/dist/chunk-OB23TUKY.js.map +1 -0
- package/dist/devtools/index.cjs +9 -2
- package/dist/devtools/index.cjs.map +1 -1
- package/dist/devtools/index.js +1 -1
- package/dist/index.cjs +306 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -25
- package/dist/index.d.ts +71 -25
- package/dist/index.js +290 -162
- package/dist/index.js.map +1 -1
- package/dist/testing/index.cjs +70 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +11 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.js +49 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +11 -1
- package/dist/chunk-N7WPXYCU.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { getAtPath, slotAtPath, setAtPath, isPlainObject, hasOwnSlot, valuesEqual, isFieldDirty, useFormSelector,
|
|
2
|
-
export { getAtPath, parsePath, setAtPath, useFormSelector, useFormSelectorShallow } from './chunk-
|
|
1
|
+
import { getAtPath, slotAtPath, setAtPath, isPlainObject, hasOwnSlot, valuesEqual, useFormSelectorShallow, isFieldDirty, useFormSelector, parsePath } from './chunk-OB23TUKY.js';
|
|
2
|
+
export { getAtPath, parsePath, setAtPath, useFormSelector, useFormSelectorShallow } from './chunk-OB23TUKY.js';
|
|
3
|
+
import { shouldValidateOn } from './chunk-MQ6262S3.js';
|
|
4
|
+
export { shouldValidateOn } from './chunk-MQ6262S3.js';
|
|
3
5
|
import { createStore } from 'zustand/vanilla';
|
|
4
6
|
import { devtools } from 'zustand/middleware';
|
|
5
7
|
import { z } from 'zod';
|
|
6
|
-
import { useRef, useEffect, useMemo, useCallback, useActionState, createContext,
|
|
8
|
+
import { useRef, useEffect, useMemo, useState, useCallback, useActionState, createContext, useContext, useId } from 'react';
|
|
7
9
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
10
|
import { useStore } from 'zustand/react';
|
|
9
11
|
import { useShallow } from 'zustand/react/shallow';
|
|
@@ -828,27 +830,25 @@ var createForm = (schema, options) => {
|
|
|
828
830
|
};
|
|
829
831
|
}),
|
|
830
832
|
updateState: (updater) => {
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
return {
|
|
842
|
-
...next,
|
|
843
|
-
...errorChannels(state, {
|
|
844
|
-
schemaErrors: next.schemaErrors,
|
|
845
|
-
serverErrors: next.serverErrors
|
|
846
|
-
})
|
|
847
|
-
};
|
|
848
|
-
});
|
|
849
|
-
if (store.getState().values !== valuesBefore) {
|
|
833
|
+
const state = store.getState();
|
|
834
|
+
const patch = updater(state);
|
|
835
|
+
if (Object.keys(patch).length === 0) return;
|
|
836
|
+
if (patch.errors !== void 0 && patch.errors !== state.errors) {
|
|
837
|
+
console.warn(
|
|
838
|
+
"[formstand] `errors` is derived from schemaErrors/serverErrors \u2014 patch those channels instead; the direct `errors` patch is ignored."
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
const next = { ...state, ...patch };
|
|
842
|
+
if (next.values !== state.values) {
|
|
850
843
|
clearArrayOpsUnder(store, "");
|
|
851
844
|
}
|
|
845
|
+
store.setState(() => ({
|
|
846
|
+
...next,
|
|
847
|
+
...errorChannels(state, {
|
|
848
|
+
schemaErrors: next.schemaErrors,
|
|
849
|
+
serverErrors: next.serverErrors
|
|
850
|
+
})
|
|
851
|
+
}));
|
|
852
852
|
},
|
|
853
853
|
adoptValues: (values) => {
|
|
854
854
|
sequences.clear();
|
|
@@ -1008,21 +1008,33 @@ var createForm = (schema, options) => {
|
|
|
1008
1008
|
});
|
|
1009
1009
|
};
|
|
1010
1010
|
|
|
1011
|
-
// src/core/
|
|
1012
|
-
var
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1011
|
+
// src/core/debounce.ts
|
|
1012
|
+
var createDebouncer = (ms) => {
|
|
1013
|
+
const timer = {
|
|
1014
|
+
current: null
|
|
1015
|
+
};
|
|
1016
|
+
const cancel = () => {
|
|
1017
|
+
if (timer.current !== null) {
|
|
1018
|
+
clearTimeout(timer.current);
|
|
1019
|
+
timer.current = null;
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
const schedule = (run) => {
|
|
1023
|
+
cancel();
|
|
1024
|
+
if (ms === 0) {
|
|
1025
|
+
run();
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
timer.current = setTimeout(() => {
|
|
1029
|
+
timer.current = null;
|
|
1030
|
+
run();
|
|
1031
|
+
}, ms);
|
|
1032
|
+
};
|
|
1033
|
+
return Object.freeze({
|
|
1034
|
+
schedule,
|
|
1035
|
+
cancel,
|
|
1036
|
+
pending: () => timer.current !== null
|
|
1037
|
+
});
|
|
1026
1038
|
};
|
|
1027
1039
|
|
|
1028
1040
|
// src/core/persist.ts
|
|
@@ -1099,28 +1111,13 @@ var persistForm = (form, options) => {
|
|
|
1099
1111
|
} catch {
|
|
1100
1112
|
}
|
|
1101
1113
|
};
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
};
|
|
1105
|
-
const cancelPending = () => {
|
|
1106
|
-
if (timerRef.current !== null) {
|
|
1107
|
-
clearTimeout(timerRef.current);
|
|
1108
|
-
timerRef.current = null;
|
|
1109
|
-
}
|
|
1110
|
-
};
|
|
1114
|
+
const writes = createDebouncer(debounceMs);
|
|
1115
|
+
const cancelPending = () => writes.cancel();
|
|
1111
1116
|
if (apply !== "manual") {
|
|
1112
1117
|
load();
|
|
1113
1118
|
}
|
|
1114
1119
|
const unsubscribe = form.watchValues((values) => {
|
|
1115
|
-
|
|
1116
|
-
if (debounceMs === 0) {
|
|
1117
|
-
writeDraft(values);
|
|
1118
|
-
} else {
|
|
1119
|
-
timerRef.current = setTimeout(() => {
|
|
1120
|
-
timerRef.current = null;
|
|
1121
|
-
writeDraft(values);
|
|
1122
|
-
}, debounceMs);
|
|
1123
|
-
}
|
|
1120
|
+
writes.schedule(() => writeDraft(values));
|
|
1124
1121
|
});
|
|
1125
1122
|
return Object.freeze({
|
|
1126
1123
|
load,
|
|
@@ -1183,6 +1180,233 @@ var useForm = (schema, options) => {
|
|
|
1183
1180
|
}, [form, schema, options.initialValues]);
|
|
1184
1181
|
return form;
|
|
1185
1182
|
};
|
|
1183
|
+
|
|
1184
|
+
// src/react/inputProps.ts
|
|
1185
|
+
var hasFieldError = (error) => error !== void 0 && error.length > 0;
|
|
1186
|
+
var ariaInvalid = (field) => hasFieldError(field.error) ? true : void 0;
|
|
1187
|
+
var numberToInputText = (value) => value === void 0 || value === null || Number.isNaN(value) ? "" : String(value);
|
|
1188
|
+
var parseNumberText = (text) => {
|
|
1189
|
+
if (text.trim() === "") return { kind: "empty" };
|
|
1190
|
+
const parsed = Number(text);
|
|
1191
|
+
return Number.isFinite(parsed) ? { kind: "number", value: parsed } : { kind: "invalid" };
|
|
1192
|
+
};
|
|
1193
|
+
var textInputProps = (field) => ({
|
|
1194
|
+
name: field.path,
|
|
1195
|
+
value: field.value ?? "",
|
|
1196
|
+
"aria-invalid": ariaInvalid(field),
|
|
1197
|
+
onChange: (e) => {
|
|
1198
|
+
const text = e.target.value;
|
|
1199
|
+
field.setValue(text === "" && field.clearable ? field.emptyValue : text);
|
|
1200
|
+
},
|
|
1201
|
+
onBlur: field.onBlur
|
|
1202
|
+
});
|
|
1203
|
+
var numberInputProps = (field) => ({
|
|
1204
|
+
type: "number",
|
|
1205
|
+
name: field.path,
|
|
1206
|
+
value: numberToInputText(field.value),
|
|
1207
|
+
"aria-invalid": ariaInvalid(field),
|
|
1208
|
+
onChange: (e) => {
|
|
1209
|
+
const parsed = parseNumberText(e.target.value);
|
|
1210
|
+
if (parsed.kind === "invalid") return;
|
|
1211
|
+
field.setValue(
|
|
1212
|
+
parsed.kind === "number" ? parsed.value : field.emptyValue
|
|
1213
|
+
);
|
|
1214
|
+
},
|
|
1215
|
+
onBlur: field.onBlur
|
|
1216
|
+
});
|
|
1217
|
+
var dateToInputText = (value) => {
|
|
1218
|
+
if (value === void 0 || value === null || Number.isNaN(value.getTime())) {
|
|
1219
|
+
return "";
|
|
1220
|
+
}
|
|
1221
|
+
const pad = (part) => String(part).padStart(2, "0");
|
|
1222
|
+
return `${String(value.getFullYear()).padStart(4, "0")}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
|
|
1223
|
+
};
|
|
1224
|
+
var parseDateText = (text) => {
|
|
1225
|
+
if (text.trim() === "") return { kind: "empty" };
|
|
1226
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
|
|
1227
|
+
if (match === null) return { kind: "invalid" };
|
|
1228
|
+
const [, year, month, day] = match;
|
|
1229
|
+
const y = Number(year);
|
|
1230
|
+
const date = new Date(y, Number(month) - 1, Number(day));
|
|
1231
|
+
if (y < 100) date.setFullYear(y);
|
|
1232
|
+
return date.getFullYear() === y && date.getMonth() === Number(month) - 1 && date.getDate() === Number(day) ? { kind: "date", value: date } : { kind: "invalid" };
|
|
1233
|
+
};
|
|
1234
|
+
var dateInputProps = (field) => ({
|
|
1235
|
+
type: "date",
|
|
1236
|
+
name: field.path,
|
|
1237
|
+
value: dateToInputText(field.value),
|
|
1238
|
+
"aria-invalid": ariaInvalid(field),
|
|
1239
|
+
onChange: (e) => {
|
|
1240
|
+
const parsed = parseDateText(e.target.value);
|
|
1241
|
+
if (parsed.kind !== "date") {
|
|
1242
|
+
field.setValue(field.emptyValue);
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
const current = field.value;
|
|
1246
|
+
const next = current instanceof Date && !Number.isNaN(current.getTime()) ? new Date(
|
|
1247
|
+
parsed.value.getFullYear(),
|
|
1248
|
+
parsed.value.getMonth(),
|
|
1249
|
+
parsed.value.getDate(),
|
|
1250
|
+
current.getHours(),
|
|
1251
|
+
current.getMinutes(),
|
|
1252
|
+
current.getSeconds(),
|
|
1253
|
+
current.getMilliseconds()
|
|
1254
|
+
) : parsed.value;
|
|
1255
|
+
field.setValue(next);
|
|
1256
|
+
},
|
|
1257
|
+
onBlur: field.onBlur
|
|
1258
|
+
});
|
|
1259
|
+
var checkboxProps = (field) => ({
|
|
1260
|
+
type: "checkbox",
|
|
1261
|
+
name: field.path,
|
|
1262
|
+
checked: field.value ?? false,
|
|
1263
|
+
"aria-invalid": ariaInvalid(field),
|
|
1264
|
+
onChange: (e) => field.setValue(e.target.checked),
|
|
1265
|
+
onBlur: field.onBlur
|
|
1266
|
+
});
|
|
1267
|
+
var selectProps = (field) => ({
|
|
1268
|
+
name: field.path,
|
|
1269
|
+
value: field.value ?? "",
|
|
1270
|
+
"aria-invalid": ariaInvalid(field),
|
|
1271
|
+
onChange: (e) => {
|
|
1272
|
+
const v = e.target.value;
|
|
1273
|
+
field.setValue(v === "" && field.clearable ? field.emptyValue : v);
|
|
1274
|
+
},
|
|
1275
|
+
onBlur: field.onBlur
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
// src/react/useMaskedInput.ts
|
|
1279
|
+
var useMaskedInput = (field, options) => {
|
|
1280
|
+
const [edit, setEdit] = useState({
|
|
1281
|
+
raw: null,
|
|
1282
|
+
pushed: void 0
|
|
1283
|
+
});
|
|
1284
|
+
const externallyChanged = edit.raw !== null && !Object.is(field.value, edit.pushed);
|
|
1285
|
+
if (externallyChanged) {
|
|
1286
|
+
setEdit({ raw: null, pushed: void 0 });
|
|
1287
|
+
}
|
|
1288
|
+
const raw = externallyChanged ? null : edit.raw;
|
|
1289
|
+
return {
|
|
1290
|
+
name: field.path,
|
|
1291
|
+
value: raw ?? (field.value === void 0 || field.value === null ? "" : options.format(field.value)),
|
|
1292
|
+
"aria-invalid": hasFieldError(field.error) ? true : void 0,
|
|
1293
|
+
onChange: (e) => {
|
|
1294
|
+
const text = e.target.value;
|
|
1295
|
+
const parsed = options.parse(text);
|
|
1296
|
+
switch (parsed.kind) {
|
|
1297
|
+
case "value":
|
|
1298
|
+
setEdit({ raw: text, pushed: parsed.value });
|
|
1299
|
+
field.setValue(parsed.value);
|
|
1300
|
+
return;
|
|
1301
|
+
case "empty": {
|
|
1302
|
+
const empty = field.emptyValue;
|
|
1303
|
+
setEdit({ raw: text, pushed: empty });
|
|
1304
|
+
field.setValue(empty);
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
case "invalid":
|
|
1308
|
+
setEdit({ raw: text, pushed: field.value });
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
},
|
|
1312
|
+
onBlur: () => {
|
|
1313
|
+
setEdit({ raw: null, pushed: void 0 });
|
|
1314
|
+
field.onBlur();
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
};
|
|
1318
|
+
var useFormSteps = (form, steps) => {
|
|
1319
|
+
const [step, setStep] = useState(0);
|
|
1320
|
+
const [visited, setVisited] = useState(
|
|
1321
|
+
() => /* @__PURE__ */ new Set([0])
|
|
1322
|
+
);
|
|
1323
|
+
const latest = useRef(steps);
|
|
1324
|
+
useEffect(() => {
|
|
1325
|
+
latest.current = steps;
|
|
1326
|
+
});
|
|
1327
|
+
const validateStep = useCallback(
|
|
1328
|
+
async (index) => {
|
|
1329
|
+
const definition = latest.current[index];
|
|
1330
|
+
if (definition === void 0) return true;
|
|
1331
|
+
const result = await form.validateFieldsAsync(definition.fields);
|
|
1332
|
+
if (result.kind === "invalid") {
|
|
1333
|
+
Object.keys(result.errors).forEach((key) => {
|
|
1334
|
+
form.setTouched(key, true);
|
|
1335
|
+
});
|
|
1336
|
+
return false;
|
|
1337
|
+
}
|
|
1338
|
+
return true;
|
|
1339
|
+
},
|
|
1340
|
+
[form]
|
|
1341
|
+
);
|
|
1342
|
+
const next = useCallback(async () => {
|
|
1343
|
+
const ok = await validateStep(step);
|
|
1344
|
+
if (!ok) return false;
|
|
1345
|
+
const target = Math.min(step + 1, latest.current.length - 1);
|
|
1346
|
+
setStep(target);
|
|
1347
|
+
setVisited((prev) => /* @__PURE__ */ new Set([...prev, target]));
|
|
1348
|
+
return true;
|
|
1349
|
+
}, [validateStep, step]);
|
|
1350
|
+
const back = useCallback(() => {
|
|
1351
|
+
setStep((prev) => Math.max(prev - 1, 0));
|
|
1352
|
+
}, []);
|
|
1353
|
+
const goTo = useCallback(
|
|
1354
|
+
async (target) => {
|
|
1355
|
+
const count = latest.current.length;
|
|
1356
|
+
const clamped = Math.max(0, Math.min(target, count - 1));
|
|
1357
|
+
if (clamped <= step) {
|
|
1358
|
+
setStep(clamped);
|
|
1359
|
+
return clamped;
|
|
1360
|
+
}
|
|
1361
|
+
const walk = async (from) => {
|
|
1362
|
+
if (from >= clamped) return clamped;
|
|
1363
|
+
return await validateStep(from) ? walk(from + 1) : from;
|
|
1364
|
+
};
|
|
1365
|
+
const landed = await walk(step);
|
|
1366
|
+
setStep(landed);
|
|
1367
|
+
setVisited(
|
|
1368
|
+
(prev) => /* @__PURE__ */ new Set([
|
|
1369
|
+
...prev,
|
|
1370
|
+
...Array.from({ length: landed - step + 1 }, (_, i) => step + i)
|
|
1371
|
+
])
|
|
1372
|
+
);
|
|
1373
|
+
return landed;
|
|
1374
|
+
},
|
|
1375
|
+
[validateStep, step]
|
|
1376
|
+
);
|
|
1377
|
+
const errorFlags = useFormSelectorShallow(
|
|
1378
|
+
form,
|
|
1379
|
+
(state) => steps.map(
|
|
1380
|
+
(definition) => definition.fields.some(
|
|
1381
|
+
(path) => Object.keys(state.errors).some((key) => isPathOrChild(key, path))
|
|
1382
|
+
)
|
|
1383
|
+
)
|
|
1384
|
+
);
|
|
1385
|
+
const statuses = useMemo(
|
|
1386
|
+
() => steps.map(
|
|
1387
|
+
(definition, index) => ({
|
|
1388
|
+
name: definition.name,
|
|
1389
|
+
visited: visited.has(index),
|
|
1390
|
+
hasErrors: errorFlags[index] ?? false
|
|
1391
|
+
})
|
|
1392
|
+
),
|
|
1393
|
+
[steps, visited, errorFlags]
|
|
1394
|
+
);
|
|
1395
|
+
return useMemo(
|
|
1396
|
+
() => ({
|
|
1397
|
+
step,
|
|
1398
|
+
name: steps[step]?.name,
|
|
1399
|
+
count: steps.length,
|
|
1400
|
+
isFirst: step === 0,
|
|
1401
|
+
isLast: step === steps.length - 1,
|
|
1402
|
+
next,
|
|
1403
|
+
back,
|
|
1404
|
+
goTo,
|
|
1405
|
+
steps: statuses
|
|
1406
|
+
}),
|
|
1407
|
+
[step, steps, next, back, goTo, statuses]
|
|
1408
|
+
);
|
|
1409
|
+
};
|
|
1186
1410
|
var warnUnobserved = (result, options, site) => {
|
|
1187
1411
|
if (result.kind === "error" && options?.onError === void 0 && process.env.NODE_ENV !== "production") {
|
|
1188
1412
|
console.warn(
|
|
@@ -1276,28 +1500,24 @@ function useField(form, pathArg, options) {
|
|
|
1276
1500
|
return initialValue === null ? { emptyValue: null, clearable: true } : { emptyValue: void 0, clearable: false };
|
|
1277
1501
|
}, [formSchema, path, initialValue]);
|
|
1278
1502
|
const debounceMs = options?.debounceMs;
|
|
1279
|
-
const
|
|
1503
|
+
const debouncerRef = useRef(null);
|
|
1280
1504
|
useEffect(() => {
|
|
1281
1505
|
return () => {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
debounceTimerRef.current = null;
|
|
1285
|
-
}
|
|
1506
|
+
debouncerRef.current?.cancel();
|
|
1507
|
+
debouncerRef.current = null;
|
|
1286
1508
|
};
|
|
1287
1509
|
}, [form, path, debounceMs]);
|
|
1288
1510
|
const triggerValidate = useCallback(() => {
|
|
1289
1511
|
if (debounceMs !== void 0 && debounceMs > 0) {
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
}
|
|
1512
|
+
const debouncer = debouncerRef.current ?? createDebouncer(debounceMs);
|
|
1513
|
+
debouncerRef.current = debouncer;
|
|
1293
1514
|
const scheduled = getAtPath(form.store.getState().values, path);
|
|
1294
|
-
|
|
1295
|
-
debounceTimerRef.current = null;
|
|
1515
|
+
debouncer.schedule(() => {
|
|
1296
1516
|
const state = form.store.getState();
|
|
1297
1517
|
if (state.values === state.initialValues) return;
|
|
1298
1518
|
if (!Object.is(getAtPath(state.values, path), scheduled)) return;
|
|
1299
1519
|
void form.validateFieldAsync(path);
|
|
1300
|
-
}
|
|
1520
|
+
});
|
|
1301
1521
|
return;
|
|
1302
1522
|
}
|
|
1303
1523
|
form.validateField(path);
|
|
@@ -1676,6 +1896,7 @@ var createFormHooks = (form, name) => {
|
|
|
1676
1896
|
paths
|
|
1677
1897
|
);
|
|
1678
1898
|
const useBoundSubmitCount = () => useSubmitCount(structural);
|
|
1899
|
+
const useBoundSteps = (steps) => useFormSteps(form, steps);
|
|
1679
1900
|
const prefix = capitalize(name ?? "");
|
|
1680
1901
|
return {
|
|
1681
1902
|
[`use${prefix}Field`]: useBoundField,
|
|
@@ -1690,103 +1911,10 @@ var createFormHooks = (form, name) => {
|
|
|
1690
1911
|
[`use${prefix}IsSubmitting`]: useBoundIsSubmitting,
|
|
1691
1912
|
[`use${prefix}SubmitCount`]: useBoundSubmitCount,
|
|
1692
1913
|
[`use${prefix}Values`]: useBoundValues,
|
|
1693
|
-
[`use${prefix}Fields`]: useBoundFields
|
|
1914
|
+
[`use${prefix}Fields`]: useBoundFields,
|
|
1915
|
+
[`use${prefix}Steps`]: useBoundSteps
|
|
1694
1916
|
};
|
|
1695
1917
|
};
|
|
1696
|
-
|
|
1697
|
-
// src/react/inputProps.ts
|
|
1698
|
-
var hasFieldError = (error) => error !== void 0 && error.length > 0;
|
|
1699
|
-
var ariaInvalid = (field) => hasFieldError(field.error) ? true : void 0;
|
|
1700
|
-
var numberToInputText = (value) => value === void 0 || value === null || Number.isNaN(value) ? "" : String(value);
|
|
1701
|
-
var parseNumberText = (text) => {
|
|
1702
|
-
if (text.trim() === "") return { kind: "empty" };
|
|
1703
|
-
const parsed = Number(text);
|
|
1704
|
-
return Number.isFinite(parsed) ? { kind: "number", value: parsed } : { kind: "invalid" };
|
|
1705
|
-
};
|
|
1706
|
-
var textInputProps = (field) => ({
|
|
1707
|
-
name: field.path,
|
|
1708
|
-
value: field.value ?? "",
|
|
1709
|
-
"aria-invalid": ariaInvalid(field),
|
|
1710
|
-
onChange: (e) => {
|
|
1711
|
-
const text = e.target.value;
|
|
1712
|
-
field.setValue(text === "" && field.clearable ? field.emptyValue : text);
|
|
1713
|
-
},
|
|
1714
|
-
onBlur: field.onBlur
|
|
1715
|
-
});
|
|
1716
|
-
var numberInputProps = (field) => ({
|
|
1717
|
-
type: "number",
|
|
1718
|
-
name: field.path,
|
|
1719
|
-
value: numberToInputText(field.value),
|
|
1720
|
-
"aria-invalid": ariaInvalid(field),
|
|
1721
|
-
onChange: (e) => {
|
|
1722
|
-
const parsed = parseNumberText(e.target.value);
|
|
1723
|
-
if (parsed.kind === "invalid") return;
|
|
1724
|
-
field.setValue(
|
|
1725
|
-
parsed.kind === "number" ? parsed.value : field.emptyValue
|
|
1726
|
-
);
|
|
1727
|
-
},
|
|
1728
|
-
onBlur: field.onBlur
|
|
1729
|
-
});
|
|
1730
|
-
var dateToInputText = (value) => {
|
|
1731
|
-
if (value === void 0 || value === null || Number.isNaN(value.getTime())) {
|
|
1732
|
-
return "";
|
|
1733
|
-
}
|
|
1734
|
-
const pad = (part) => String(part).padStart(2, "0");
|
|
1735
|
-
return `${String(value.getFullYear()).padStart(4, "0")}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
|
|
1736
|
-
};
|
|
1737
|
-
var parseDateText = (text) => {
|
|
1738
|
-
if (text.trim() === "") return { kind: "empty" };
|
|
1739
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
|
|
1740
|
-
if (match === null) return { kind: "invalid" };
|
|
1741
|
-
const [, year, month, day] = match;
|
|
1742
|
-
const y = Number(year);
|
|
1743
|
-
const date = new Date(y, Number(month) - 1, Number(day));
|
|
1744
|
-
if (y < 100) date.setFullYear(y);
|
|
1745
|
-
return date.getFullYear() === y && date.getMonth() === Number(month) - 1 && date.getDate() === Number(day) ? { kind: "date", value: date } : { kind: "invalid" };
|
|
1746
|
-
};
|
|
1747
|
-
var dateInputProps = (field) => ({
|
|
1748
|
-
type: "date",
|
|
1749
|
-
name: field.path,
|
|
1750
|
-
value: dateToInputText(field.value),
|
|
1751
|
-
"aria-invalid": ariaInvalid(field),
|
|
1752
|
-
onChange: (e) => {
|
|
1753
|
-
const parsed = parseDateText(e.target.value);
|
|
1754
|
-
if (parsed.kind !== "date") {
|
|
1755
|
-
field.setValue(field.emptyValue);
|
|
1756
|
-
return;
|
|
1757
|
-
}
|
|
1758
|
-
const current = field.value;
|
|
1759
|
-
const next = current instanceof Date && !Number.isNaN(current.getTime()) ? new Date(
|
|
1760
|
-
parsed.value.getFullYear(),
|
|
1761
|
-
parsed.value.getMonth(),
|
|
1762
|
-
parsed.value.getDate(),
|
|
1763
|
-
current.getHours(),
|
|
1764
|
-
current.getMinutes(),
|
|
1765
|
-
current.getSeconds(),
|
|
1766
|
-
current.getMilliseconds()
|
|
1767
|
-
) : parsed.value;
|
|
1768
|
-
field.setValue(next);
|
|
1769
|
-
},
|
|
1770
|
-
onBlur: field.onBlur
|
|
1771
|
-
});
|
|
1772
|
-
var checkboxProps = (field) => ({
|
|
1773
|
-
type: "checkbox",
|
|
1774
|
-
name: field.path,
|
|
1775
|
-
checked: field.value ?? false,
|
|
1776
|
-
"aria-invalid": ariaInvalid(field),
|
|
1777
|
-
onChange: (e) => field.setValue(e.target.checked),
|
|
1778
|
-
onBlur: field.onBlur
|
|
1779
|
-
});
|
|
1780
|
-
var selectProps = (field) => ({
|
|
1781
|
-
name: field.path,
|
|
1782
|
-
value: field.value ?? "",
|
|
1783
|
-
"aria-invalid": ariaInvalid(field),
|
|
1784
|
-
onChange: (e) => {
|
|
1785
|
-
const v = e.target.value;
|
|
1786
|
-
field.setValue(v === "" && field.clearable ? field.emptyValue : v);
|
|
1787
|
-
},
|
|
1788
|
-
onBlur: field.onBlur
|
|
1789
|
-
});
|
|
1790
1918
|
var useFieldA11y = (error) => {
|
|
1791
1919
|
const id = useId();
|
|
1792
1920
|
const errorId = `${id}-error`;
|
|
@@ -2079,6 +2207,6 @@ var focusField = (path, root) => {
|
|
|
2079
2207
|
return path === "" ? (root !== void 0 || document.querySelectorAll("form").length <= 1) && focusFirstOf(namedControls(scope).filter(isFocusCandidate)) : focusFirstOf(pathCandidates(scope, [path]).filter(isFocusCandidate));
|
|
2080
2208
|
};
|
|
2081
2209
|
|
|
2082
|
-
export { CheckboxField, DateField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, hasFieldError, isAsyncRequiredError, isClearableSchema, numberInputProps, numberToInputText, parseDateText, parseNumberText, persistForm, selectProps,
|
|
2210
|
+
export { CheckboxField, DateField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, hasFieldError, isAsyncRequiredError, isClearableSchema, numberInputProps, numberToInputText, parseDateText, parseNumberText, persistForm, selectProps, textInputProps, useField, useFieldArray, useFields, useForm, useFormAction, useFormActionState, useFormError, useFormSteps, useFormValues, useIsDirty, useIsSubmitting, useIsValid, useIsValidating, useMaskedInput, useNumberInput, usePersistForm, useSubmitCount, useVariantField, validateAsync, validateSync };
|
|
2083
2211
|
//# sourceMappingURL=index.js.map
|
|
2084
2212
|
//# sourceMappingURL=index.js.map
|