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.cjs
CHANGED
|
@@ -4,9 +4,9 @@ var vanilla = require('zustand/vanilla');
|
|
|
4
4
|
var middleware = require('zustand/middleware');
|
|
5
5
|
var zod = require('zod');
|
|
6
6
|
var react = require('react');
|
|
7
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
8
7
|
var react$1 = require('zustand/react');
|
|
9
8
|
var shallow = require('zustand/react/shallow');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
10
|
|
|
11
11
|
// src/core/createForm.ts
|
|
12
12
|
|
|
@@ -153,11 +153,18 @@ var PARSE_CACHE_MAX = 4096;
|
|
|
153
153
|
var parseCache = /* @__PURE__ */ new Map();
|
|
154
154
|
var parsePath = (path) => {
|
|
155
155
|
const cached = parseCache.get(path);
|
|
156
|
-
if (cached !== void 0)
|
|
156
|
+
if (cached !== void 0) {
|
|
157
|
+
parseCache.delete(path);
|
|
158
|
+
parseCache.set(path, cached);
|
|
159
|
+
return cached;
|
|
160
|
+
}
|
|
157
161
|
const segments = Object.freeze(
|
|
158
162
|
path === "" ? [] : path.split(".").map((s) => isIndexSegment(s) ? Number(s) : s)
|
|
159
163
|
);
|
|
160
|
-
if (parseCache.size >= PARSE_CACHE_MAX)
|
|
164
|
+
if (parseCache.size >= PARSE_CACHE_MAX) {
|
|
165
|
+
const oldest = parseCache.keys().next().value;
|
|
166
|
+
if (oldest !== void 0) parseCache.delete(oldest);
|
|
167
|
+
}
|
|
161
168
|
parseCache.set(path, segments);
|
|
162
169
|
return segments;
|
|
163
170
|
};
|
|
@@ -962,27 +969,25 @@ var createForm = (schema, options) => {
|
|
|
962
969
|
};
|
|
963
970
|
}),
|
|
964
971
|
updateState: (updater) => {
|
|
965
|
-
const
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
return {
|
|
976
|
-
...next,
|
|
977
|
-
...errorChannels(state, {
|
|
978
|
-
schemaErrors: next.schemaErrors,
|
|
979
|
-
serverErrors: next.serverErrors
|
|
980
|
-
})
|
|
981
|
-
};
|
|
982
|
-
});
|
|
983
|
-
if (store.getState().values !== valuesBefore) {
|
|
972
|
+
const state = store.getState();
|
|
973
|
+
const patch = updater(state);
|
|
974
|
+
if (Object.keys(patch).length === 0) return;
|
|
975
|
+
if (patch.errors !== void 0 && patch.errors !== state.errors) {
|
|
976
|
+
console.warn(
|
|
977
|
+
"[formstand] `errors` is derived from schemaErrors/serverErrors \u2014 patch those channels instead; the direct `errors` patch is ignored."
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
const next = { ...state, ...patch };
|
|
981
|
+
if (next.values !== state.values) {
|
|
984
982
|
clearArrayOpsUnder(store, "");
|
|
985
983
|
}
|
|
984
|
+
store.setState(() => ({
|
|
985
|
+
...next,
|
|
986
|
+
...errorChannels(state, {
|
|
987
|
+
schemaErrors: next.schemaErrors,
|
|
988
|
+
serverErrors: next.serverErrors
|
|
989
|
+
})
|
|
990
|
+
}));
|
|
986
991
|
},
|
|
987
992
|
adoptValues: (values) => {
|
|
988
993
|
sequences.clear();
|
|
@@ -1159,6 +1164,35 @@ var shouldValidateOn = (trigger, mode, reValidateMode, submitAttempted, touched
|
|
|
1159
1164
|
}
|
|
1160
1165
|
};
|
|
1161
1166
|
|
|
1167
|
+
// src/core/debounce.ts
|
|
1168
|
+
var createDebouncer = (ms) => {
|
|
1169
|
+
const timer = {
|
|
1170
|
+
current: null
|
|
1171
|
+
};
|
|
1172
|
+
const cancel = () => {
|
|
1173
|
+
if (timer.current !== null) {
|
|
1174
|
+
clearTimeout(timer.current);
|
|
1175
|
+
timer.current = null;
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
const schedule = (run) => {
|
|
1179
|
+
cancel();
|
|
1180
|
+
if (ms === 0) {
|
|
1181
|
+
run();
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
timer.current = setTimeout(() => {
|
|
1185
|
+
timer.current = null;
|
|
1186
|
+
run();
|
|
1187
|
+
}, ms);
|
|
1188
|
+
};
|
|
1189
|
+
return Object.freeze({
|
|
1190
|
+
schedule,
|
|
1191
|
+
cancel,
|
|
1192
|
+
pending: () => timer.current !== null
|
|
1193
|
+
});
|
|
1194
|
+
};
|
|
1195
|
+
|
|
1162
1196
|
// src/core/persist.ts
|
|
1163
1197
|
var kindOf = (value) => value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
1164
1198
|
var conflictsWith = (draft, reference) => {
|
|
@@ -1233,28 +1267,13 @@ var persistForm = (form, options) => {
|
|
|
1233
1267
|
} catch {
|
|
1234
1268
|
}
|
|
1235
1269
|
};
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
};
|
|
1239
|
-
const cancelPending = () => {
|
|
1240
|
-
if (timerRef.current !== null) {
|
|
1241
|
-
clearTimeout(timerRef.current);
|
|
1242
|
-
timerRef.current = null;
|
|
1243
|
-
}
|
|
1244
|
-
};
|
|
1270
|
+
const writes = createDebouncer(debounceMs);
|
|
1271
|
+
const cancelPending = () => writes.cancel();
|
|
1245
1272
|
if (apply !== "manual") {
|
|
1246
1273
|
load();
|
|
1247
1274
|
}
|
|
1248
1275
|
const unsubscribe = form.watchValues((values) => {
|
|
1249
|
-
|
|
1250
|
-
if (debounceMs === 0) {
|
|
1251
|
-
writeDraft(values);
|
|
1252
|
-
} else {
|
|
1253
|
-
timerRef.current = setTimeout(() => {
|
|
1254
|
-
timerRef.current = null;
|
|
1255
|
-
writeDraft(values);
|
|
1256
|
-
}, debounceMs);
|
|
1257
|
-
}
|
|
1276
|
+
writes.schedule(() => writeDraft(values));
|
|
1258
1277
|
});
|
|
1259
1278
|
return Object.freeze({
|
|
1260
1279
|
load,
|
|
@@ -1317,6 +1336,241 @@ var useForm = (schema, options) => {
|
|
|
1317
1336
|
}, [form, schema, options.initialValues]);
|
|
1318
1337
|
return form;
|
|
1319
1338
|
};
|
|
1339
|
+
|
|
1340
|
+
// src/react/inputProps.ts
|
|
1341
|
+
var hasFieldError = (error) => error !== void 0 && error.length > 0;
|
|
1342
|
+
var ariaInvalid = (field) => hasFieldError(field.error) ? true : void 0;
|
|
1343
|
+
var numberToInputText = (value) => value === void 0 || value === null || Number.isNaN(value) ? "" : String(value);
|
|
1344
|
+
var parseNumberText = (text) => {
|
|
1345
|
+
if (text.trim() === "") return { kind: "empty" };
|
|
1346
|
+
const parsed = Number(text);
|
|
1347
|
+
return Number.isFinite(parsed) ? { kind: "number", value: parsed } : { kind: "invalid" };
|
|
1348
|
+
};
|
|
1349
|
+
var textInputProps = (field) => ({
|
|
1350
|
+
name: field.path,
|
|
1351
|
+
value: field.value ?? "",
|
|
1352
|
+
"aria-invalid": ariaInvalid(field),
|
|
1353
|
+
onChange: (e) => {
|
|
1354
|
+
const text = e.target.value;
|
|
1355
|
+
field.setValue(text === "" && field.clearable ? field.emptyValue : text);
|
|
1356
|
+
},
|
|
1357
|
+
onBlur: field.onBlur
|
|
1358
|
+
});
|
|
1359
|
+
var numberInputProps = (field) => ({
|
|
1360
|
+
type: "number",
|
|
1361
|
+
name: field.path,
|
|
1362
|
+
value: numberToInputText(field.value),
|
|
1363
|
+
"aria-invalid": ariaInvalid(field),
|
|
1364
|
+
onChange: (e) => {
|
|
1365
|
+
const parsed = parseNumberText(e.target.value);
|
|
1366
|
+
if (parsed.kind === "invalid") return;
|
|
1367
|
+
field.setValue(
|
|
1368
|
+
parsed.kind === "number" ? parsed.value : field.emptyValue
|
|
1369
|
+
);
|
|
1370
|
+
},
|
|
1371
|
+
onBlur: field.onBlur
|
|
1372
|
+
});
|
|
1373
|
+
var dateToInputText = (value) => {
|
|
1374
|
+
if (value === void 0 || value === null || Number.isNaN(value.getTime())) {
|
|
1375
|
+
return "";
|
|
1376
|
+
}
|
|
1377
|
+
const pad = (part) => String(part).padStart(2, "0");
|
|
1378
|
+
return `${String(value.getFullYear()).padStart(4, "0")}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
|
|
1379
|
+
};
|
|
1380
|
+
var parseDateText = (text) => {
|
|
1381
|
+
if (text.trim() === "") return { kind: "empty" };
|
|
1382
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
|
|
1383
|
+
if (match === null) return { kind: "invalid" };
|
|
1384
|
+
const [, year, month, day] = match;
|
|
1385
|
+
const y = Number(year);
|
|
1386
|
+
const date = new Date(y, Number(month) - 1, Number(day));
|
|
1387
|
+
if (y < 100) date.setFullYear(y);
|
|
1388
|
+
return date.getFullYear() === y && date.getMonth() === Number(month) - 1 && date.getDate() === Number(day) ? { kind: "date", value: date } : { kind: "invalid" };
|
|
1389
|
+
};
|
|
1390
|
+
var dateInputProps = (field) => ({
|
|
1391
|
+
type: "date",
|
|
1392
|
+
name: field.path,
|
|
1393
|
+
value: dateToInputText(field.value),
|
|
1394
|
+
"aria-invalid": ariaInvalid(field),
|
|
1395
|
+
onChange: (e) => {
|
|
1396
|
+
const parsed = parseDateText(e.target.value);
|
|
1397
|
+
if (parsed.kind !== "date") {
|
|
1398
|
+
field.setValue(field.emptyValue);
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
const current = field.value;
|
|
1402
|
+
const next = current instanceof Date && !Number.isNaN(current.getTime()) ? new Date(
|
|
1403
|
+
parsed.value.getFullYear(),
|
|
1404
|
+
parsed.value.getMonth(),
|
|
1405
|
+
parsed.value.getDate(),
|
|
1406
|
+
current.getHours(),
|
|
1407
|
+
current.getMinutes(),
|
|
1408
|
+
current.getSeconds(),
|
|
1409
|
+
current.getMilliseconds()
|
|
1410
|
+
) : parsed.value;
|
|
1411
|
+
field.setValue(next);
|
|
1412
|
+
},
|
|
1413
|
+
onBlur: field.onBlur
|
|
1414
|
+
});
|
|
1415
|
+
var checkboxProps = (field) => ({
|
|
1416
|
+
type: "checkbox",
|
|
1417
|
+
name: field.path,
|
|
1418
|
+
checked: field.value ?? false,
|
|
1419
|
+
"aria-invalid": ariaInvalid(field),
|
|
1420
|
+
onChange: (e) => field.setValue(e.target.checked),
|
|
1421
|
+
onBlur: field.onBlur
|
|
1422
|
+
});
|
|
1423
|
+
var selectProps = (field) => ({
|
|
1424
|
+
name: field.path,
|
|
1425
|
+
value: field.value ?? "",
|
|
1426
|
+
"aria-invalid": ariaInvalid(field),
|
|
1427
|
+
onChange: (e) => {
|
|
1428
|
+
const v = e.target.value;
|
|
1429
|
+
field.setValue(v === "" && field.clearable ? field.emptyValue : v);
|
|
1430
|
+
},
|
|
1431
|
+
onBlur: field.onBlur
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
// src/react/useMaskedInput.ts
|
|
1435
|
+
var useMaskedInput = (field, options) => {
|
|
1436
|
+
const [edit, setEdit] = react.useState({
|
|
1437
|
+
raw: null,
|
|
1438
|
+
pushed: void 0
|
|
1439
|
+
});
|
|
1440
|
+
const externallyChanged = edit.raw !== null && !Object.is(field.value, edit.pushed);
|
|
1441
|
+
if (externallyChanged) {
|
|
1442
|
+
setEdit({ raw: null, pushed: void 0 });
|
|
1443
|
+
}
|
|
1444
|
+
const raw = externallyChanged ? null : edit.raw;
|
|
1445
|
+
return {
|
|
1446
|
+
name: field.path,
|
|
1447
|
+
value: raw ?? (field.value === void 0 || field.value === null ? "" : options.format(field.value)),
|
|
1448
|
+
"aria-invalid": hasFieldError(field.error) ? true : void 0,
|
|
1449
|
+
onChange: (e) => {
|
|
1450
|
+
const text = e.target.value;
|
|
1451
|
+
const parsed = options.parse(text);
|
|
1452
|
+
switch (parsed.kind) {
|
|
1453
|
+
case "value":
|
|
1454
|
+
setEdit({ raw: text, pushed: parsed.value });
|
|
1455
|
+
field.setValue(parsed.value);
|
|
1456
|
+
return;
|
|
1457
|
+
case "empty": {
|
|
1458
|
+
const empty = field.emptyValue;
|
|
1459
|
+
setEdit({ raw: text, pushed: empty });
|
|
1460
|
+
field.setValue(empty);
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
case "invalid":
|
|
1464
|
+
setEdit({ raw: text, pushed: field.value });
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
},
|
|
1468
|
+
onBlur: () => {
|
|
1469
|
+
setEdit({ raw: null, pushed: void 0 });
|
|
1470
|
+
field.onBlur();
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
};
|
|
1474
|
+
function useFormSelector(form, selector) {
|
|
1475
|
+
return react$1.useStore(form.store, selector);
|
|
1476
|
+
}
|
|
1477
|
+
function useFormSelectorShallow(form, selector) {
|
|
1478
|
+
return react$1.useStore(form.store, shallow.useShallow(selector));
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// src/react/useFormSteps.ts
|
|
1482
|
+
var useFormSteps = (form, steps) => {
|
|
1483
|
+
const [step, setStep] = react.useState(0);
|
|
1484
|
+
const [visited, setVisited] = react.useState(
|
|
1485
|
+
() => /* @__PURE__ */ new Set([0])
|
|
1486
|
+
);
|
|
1487
|
+
const latest = react.useRef(steps);
|
|
1488
|
+
react.useEffect(() => {
|
|
1489
|
+
latest.current = steps;
|
|
1490
|
+
});
|
|
1491
|
+
const validateStep = react.useCallback(
|
|
1492
|
+
async (index) => {
|
|
1493
|
+
const definition = latest.current[index];
|
|
1494
|
+
if (definition === void 0) return true;
|
|
1495
|
+
const result = await form.validateFieldsAsync(definition.fields);
|
|
1496
|
+
if (result.kind === "invalid") {
|
|
1497
|
+
Object.keys(result.errors).forEach((key) => {
|
|
1498
|
+
form.setTouched(key, true);
|
|
1499
|
+
});
|
|
1500
|
+
return false;
|
|
1501
|
+
}
|
|
1502
|
+
return true;
|
|
1503
|
+
},
|
|
1504
|
+
[form]
|
|
1505
|
+
);
|
|
1506
|
+
const next = react.useCallback(async () => {
|
|
1507
|
+
const ok = await validateStep(step);
|
|
1508
|
+
if (!ok) return false;
|
|
1509
|
+
const target = Math.min(step + 1, latest.current.length - 1);
|
|
1510
|
+
setStep(target);
|
|
1511
|
+
setVisited((prev) => /* @__PURE__ */ new Set([...prev, target]));
|
|
1512
|
+
return true;
|
|
1513
|
+
}, [validateStep, step]);
|
|
1514
|
+
const back = react.useCallback(() => {
|
|
1515
|
+
setStep((prev) => Math.max(prev - 1, 0));
|
|
1516
|
+
}, []);
|
|
1517
|
+
const goTo = react.useCallback(
|
|
1518
|
+
async (target) => {
|
|
1519
|
+
const count = latest.current.length;
|
|
1520
|
+
const clamped = Math.max(0, Math.min(target, count - 1));
|
|
1521
|
+
if (clamped <= step) {
|
|
1522
|
+
setStep(clamped);
|
|
1523
|
+
return clamped;
|
|
1524
|
+
}
|
|
1525
|
+
const walk = async (from) => {
|
|
1526
|
+
if (from >= clamped) return clamped;
|
|
1527
|
+
return await validateStep(from) ? walk(from + 1) : from;
|
|
1528
|
+
};
|
|
1529
|
+
const landed = await walk(step);
|
|
1530
|
+
setStep(landed);
|
|
1531
|
+
setVisited(
|
|
1532
|
+
(prev) => /* @__PURE__ */ new Set([
|
|
1533
|
+
...prev,
|
|
1534
|
+
...Array.from({ length: landed - step + 1 }, (_, i) => step + i)
|
|
1535
|
+
])
|
|
1536
|
+
);
|
|
1537
|
+
return landed;
|
|
1538
|
+
},
|
|
1539
|
+
[validateStep, step]
|
|
1540
|
+
);
|
|
1541
|
+
const errorFlags = useFormSelectorShallow(
|
|
1542
|
+
form,
|
|
1543
|
+
(state) => steps.map(
|
|
1544
|
+
(definition) => definition.fields.some(
|
|
1545
|
+
(path) => Object.keys(state.errors).some((key) => isPathOrChild(key, path))
|
|
1546
|
+
)
|
|
1547
|
+
)
|
|
1548
|
+
);
|
|
1549
|
+
const statuses = react.useMemo(
|
|
1550
|
+
() => steps.map(
|
|
1551
|
+
(definition, index) => ({
|
|
1552
|
+
name: definition.name,
|
|
1553
|
+
visited: visited.has(index),
|
|
1554
|
+
hasErrors: errorFlags[index] ?? false
|
|
1555
|
+
})
|
|
1556
|
+
),
|
|
1557
|
+
[steps, visited, errorFlags]
|
|
1558
|
+
);
|
|
1559
|
+
return react.useMemo(
|
|
1560
|
+
() => ({
|
|
1561
|
+
step,
|
|
1562
|
+
name: steps[step]?.name,
|
|
1563
|
+
count: steps.length,
|
|
1564
|
+
isFirst: step === 0,
|
|
1565
|
+
isLast: step === steps.length - 1,
|
|
1566
|
+
next,
|
|
1567
|
+
back,
|
|
1568
|
+
goTo,
|
|
1569
|
+
steps: statuses
|
|
1570
|
+
}),
|
|
1571
|
+
[step, steps, next, back, goTo, statuses]
|
|
1572
|
+
);
|
|
1573
|
+
};
|
|
1320
1574
|
var warnUnobserved = (result, options, site) => {
|
|
1321
1575
|
if (result.kind === "error" && options?.onError === void 0 && process.env.NODE_ENV !== "production") {
|
|
1322
1576
|
console.warn(
|
|
@@ -1410,28 +1664,24 @@ function useField(form, pathArg, options) {
|
|
|
1410
1664
|
return initialValue === null ? { emptyValue: null, clearable: true } : { emptyValue: void 0, clearable: false };
|
|
1411
1665
|
}, [formSchema, path, initialValue]);
|
|
1412
1666
|
const debounceMs = options?.debounceMs;
|
|
1413
|
-
const
|
|
1667
|
+
const debouncerRef = react.useRef(null);
|
|
1414
1668
|
react.useEffect(() => {
|
|
1415
1669
|
return () => {
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
debounceTimerRef.current = null;
|
|
1419
|
-
}
|
|
1670
|
+
debouncerRef.current?.cancel();
|
|
1671
|
+
debouncerRef.current = null;
|
|
1420
1672
|
};
|
|
1421
1673
|
}, [form, path, debounceMs]);
|
|
1422
1674
|
const triggerValidate = react.useCallback(() => {
|
|
1423
1675
|
if (debounceMs !== void 0 && debounceMs > 0) {
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1676
|
+
const debouncer = debouncerRef.current ?? createDebouncer(debounceMs);
|
|
1677
|
+
debouncerRef.current = debouncer;
|
|
1427
1678
|
const scheduled = getAtPath(form.store.getState().values, path);
|
|
1428
|
-
|
|
1429
|
-
debounceTimerRef.current = null;
|
|
1679
|
+
debouncer.schedule(() => {
|
|
1430
1680
|
const state = form.store.getState();
|
|
1431
1681
|
if (state.values === state.initialValues) return;
|
|
1432
1682
|
if (!Object.is(getAtPath(state.values, path), scheduled)) return;
|
|
1433
1683
|
void form.validateFieldAsync(path);
|
|
1434
|
-
}
|
|
1684
|
+
});
|
|
1435
1685
|
return;
|
|
1436
1686
|
}
|
|
1437
1687
|
form.validateField(path);
|
|
@@ -1785,12 +2035,6 @@ function useIsValidating(form, path) {
|
|
|
1785
2035
|
}
|
|
1786
2036
|
var useIsSubmitting = (form) => react$1.useStore(form.store, (state) => state.isSubmitting);
|
|
1787
2037
|
var useSubmitCount = (form) => react$1.useStore(form.store, (state) => state.submitCount);
|
|
1788
|
-
function useFormSelector(form, selector) {
|
|
1789
|
-
return react$1.useStore(form.store, selector);
|
|
1790
|
-
}
|
|
1791
|
-
function useFormSelectorShallow(form, selector) {
|
|
1792
|
-
return react$1.useStore(form.store, shallow.useShallow(selector));
|
|
1793
|
-
}
|
|
1794
2038
|
|
|
1795
2039
|
// src/react/createFormHooks.ts
|
|
1796
2040
|
var capitalize = (name) => name.length === 0 ? name : name.charAt(0).toUpperCase() + name.slice(1);
|
|
@@ -1816,6 +2060,7 @@ var createFormHooks = (form, name) => {
|
|
|
1816
2060
|
paths
|
|
1817
2061
|
);
|
|
1818
2062
|
const useBoundSubmitCount = () => useSubmitCount(structural);
|
|
2063
|
+
const useBoundSteps = (steps) => useFormSteps(form, steps);
|
|
1819
2064
|
const prefix = capitalize(name ?? "");
|
|
1820
2065
|
return {
|
|
1821
2066
|
[`use${prefix}Field`]: useBoundField,
|
|
@@ -1830,103 +2075,10 @@ var createFormHooks = (form, name) => {
|
|
|
1830
2075
|
[`use${prefix}IsSubmitting`]: useBoundIsSubmitting,
|
|
1831
2076
|
[`use${prefix}SubmitCount`]: useBoundSubmitCount,
|
|
1832
2077
|
[`use${prefix}Values`]: useBoundValues,
|
|
1833
|
-
[`use${prefix}Fields`]: useBoundFields
|
|
2078
|
+
[`use${prefix}Fields`]: useBoundFields,
|
|
2079
|
+
[`use${prefix}Steps`]: useBoundSteps
|
|
1834
2080
|
};
|
|
1835
2081
|
};
|
|
1836
|
-
|
|
1837
|
-
// src/react/inputProps.ts
|
|
1838
|
-
var hasFieldError = (error) => error !== void 0 && error.length > 0;
|
|
1839
|
-
var ariaInvalid = (field) => hasFieldError(field.error) ? true : void 0;
|
|
1840
|
-
var numberToInputText = (value) => value === void 0 || value === null || Number.isNaN(value) ? "" : String(value);
|
|
1841
|
-
var parseNumberText = (text) => {
|
|
1842
|
-
if (text.trim() === "") return { kind: "empty" };
|
|
1843
|
-
const parsed = Number(text);
|
|
1844
|
-
return Number.isFinite(parsed) ? { kind: "number", value: parsed } : { kind: "invalid" };
|
|
1845
|
-
};
|
|
1846
|
-
var textInputProps = (field) => ({
|
|
1847
|
-
name: field.path,
|
|
1848
|
-
value: field.value ?? "",
|
|
1849
|
-
"aria-invalid": ariaInvalid(field),
|
|
1850
|
-
onChange: (e) => {
|
|
1851
|
-
const text = e.target.value;
|
|
1852
|
-
field.setValue(text === "" && field.clearable ? field.emptyValue : text);
|
|
1853
|
-
},
|
|
1854
|
-
onBlur: field.onBlur
|
|
1855
|
-
});
|
|
1856
|
-
var numberInputProps = (field) => ({
|
|
1857
|
-
type: "number",
|
|
1858
|
-
name: field.path,
|
|
1859
|
-
value: numberToInputText(field.value),
|
|
1860
|
-
"aria-invalid": ariaInvalid(field),
|
|
1861
|
-
onChange: (e) => {
|
|
1862
|
-
const parsed = parseNumberText(e.target.value);
|
|
1863
|
-
if (parsed.kind === "invalid") return;
|
|
1864
|
-
field.setValue(
|
|
1865
|
-
parsed.kind === "number" ? parsed.value : field.emptyValue
|
|
1866
|
-
);
|
|
1867
|
-
},
|
|
1868
|
-
onBlur: field.onBlur
|
|
1869
|
-
});
|
|
1870
|
-
var dateToInputText = (value) => {
|
|
1871
|
-
if (value === void 0 || value === null || Number.isNaN(value.getTime())) {
|
|
1872
|
-
return "";
|
|
1873
|
-
}
|
|
1874
|
-
const pad = (part) => String(part).padStart(2, "0");
|
|
1875
|
-
return `${String(value.getFullYear()).padStart(4, "0")}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
|
|
1876
|
-
};
|
|
1877
|
-
var parseDateText = (text) => {
|
|
1878
|
-
if (text.trim() === "") return { kind: "empty" };
|
|
1879
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
|
|
1880
|
-
if (match === null) return { kind: "invalid" };
|
|
1881
|
-
const [, year, month, day] = match;
|
|
1882
|
-
const y = Number(year);
|
|
1883
|
-
const date = new Date(y, Number(month) - 1, Number(day));
|
|
1884
|
-
if (y < 100) date.setFullYear(y);
|
|
1885
|
-
return date.getFullYear() === y && date.getMonth() === Number(month) - 1 && date.getDate() === Number(day) ? { kind: "date", value: date } : { kind: "invalid" };
|
|
1886
|
-
};
|
|
1887
|
-
var dateInputProps = (field) => ({
|
|
1888
|
-
type: "date",
|
|
1889
|
-
name: field.path,
|
|
1890
|
-
value: dateToInputText(field.value),
|
|
1891
|
-
"aria-invalid": ariaInvalid(field),
|
|
1892
|
-
onChange: (e) => {
|
|
1893
|
-
const parsed = parseDateText(e.target.value);
|
|
1894
|
-
if (parsed.kind !== "date") {
|
|
1895
|
-
field.setValue(field.emptyValue);
|
|
1896
|
-
return;
|
|
1897
|
-
}
|
|
1898
|
-
const current = field.value;
|
|
1899
|
-
const next = current instanceof Date && !Number.isNaN(current.getTime()) ? new Date(
|
|
1900
|
-
parsed.value.getFullYear(),
|
|
1901
|
-
parsed.value.getMonth(),
|
|
1902
|
-
parsed.value.getDate(),
|
|
1903
|
-
current.getHours(),
|
|
1904
|
-
current.getMinutes(),
|
|
1905
|
-
current.getSeconds(),
|
|
1906
|
-
current.getMilliseconds()
|
|
1907
|
-
) : parsed.value;
|
|
1908
|
-
field.setValue(next);
|
|
1909
|
-
},
|
|
1910
|
-
onBlur: field.onBlur
|
|
1911
|
-
});
|
|
1912
|
-
var checkboxProps = (field) => ({
|
|
1913
|
-
type: "checkbox",
|
|
1914
|
-
name: field.path,
|
|
1915
|
-
checked: field.value ?? false,
|
|
1916
|
-
"aria-invalid": ariaInvalid(field),
|
|
1917
|
-
onChange: (e) => field.setValue(e.target.checked),
|
|
1918
|
-
onBlur: field.onBlur
|
|
1919
|
-
});
|
|
1920
|
-
var selectProps = (field) => ({
|
|
1921
|
-
name: field.path,
|
|
1922
|
-
value: field.value ?? "",
|
|
1923
|
-
"aria-invalid": ariaInvalid(field),
|
|
1924
|
-
onChange: (e) => {
|
|
1925
|
-
const v = e.target.value;
|
|
1926
|
-
field.setValue(v === "" && field.clearable ? field.emptyValue : v);
|
|
1927
|
-
},
|
|
1928
|
-
onBlur: field.onBlur
|
|
1929
|
-
});
|
|
1930
2082
|
var useFieldA11y = (error) => {
|
|
1931
2083
|
const id = react.useId();
|
|
1932
2084
|
const errorId = `${id}-error`;
|
|
@@ -2257,11 +2409,13 @@ exports.useFormActionState = useFormActionState;
|
|
|
2257
2409
|
exports.useFormError = useFormError;
|
|
2258
2410
|
exports.useFormSelector = useFormSelector;
|
|
2259
2411
|
exports.useFormSelectorShallow = useFormSelectorShallow;
|
|
2412
|
+
exports.useFormSteps = useFormSteps;
|
|
2260
2413
|
exports.useFormValues = useFormValues;
|
|
2261
2414
|
exports.useIsDirty = useIsDirty;
|
|
2262
2415
|
exports.useIsSubmitting = useIsSubmitting;
|
|
2263
2416
|
exports.useIsValid = useIsValid;
|
|
2264
2417
|
exports.useIsValidating = useIsValidating;
|
|
2418
|
+
exports.useMaskedInput = useMaskedInput;
|
|
2265
2419
|
exports.useNumberInput = useNumberInput;
|
|
2266
2420
|
exports.usePersistForm = usePersistForm;
|
|
2267
2421
|
exports.useSubmitCount = useSubmitCount;
|