react-f0rm 1.3.0 → 1.4.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/README.md +88 -1143
- package/devtools.d.ts +1 -0
- package/devtools.js +1 -0
- package/dist/array-3hAjl6Bz.d.ts +160 -0
- package/dist/devtools/index.cjs.js +1 -1
- package/dist/devtools/index.cjs.js.map +1 -1
- package/dist/devtools/index.d.cts +34 -0
- package/dist/devtools/index.d.mts +34 -0
- package/dist/devtools/index.d.ts +3 -2
- package/dist/devtools/index.mjs +1 -1
- package/dist/devtools/index.mjs.map +1 -1
- package/dist/errors-8oPux7GR.cjs.js +2 -0
- package/dist/errors-8oPux7GR.cjs.js.map +1 -0
- package/dist/errors-ClH3eV1R.mjs +2 -0
- package/dist/errors-ClH3eV1R.mjs.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.cts +1833 -0
- package/dist/index.d.mts +1833 -0
- package/dist/index.d.ts +372 -117
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +859 -225
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +2 -2
- package/dist/index.umd.min.js.map +1 -1
- package/dist/persist.cjs.js +1 -1
- package/dist/persist.cjs.js.map +1 -1
- package/dist/persist.d.cts +49 -0
- package/dist/persist.d.mts +49 -0
- package/dist/persist.mjs +1 -1
- package/dist/persist.mjs.map +1 -1
- package/dist/resolvers/standard-schema.cjs.js +1 -1
- package/dist/resolvers/standard-schema.cjs.js.map +1 -1
- package/dist/resolvers/standard-schema.d.cts +2 -0
- package/dist/resolvers/standard-schema.d.mts +2 -0
- package/dist/resolvers/standard-schema.d.ts +1 -67
- package/dist/resolvers/standard-schema.mjs +1 -1
- package/dist/resolvers/standard-schema.mjs.map +1 -1
- package/dist/resolvers/yup.cjs.js +1 -1
- package/dist/resolvers/yup.cjs.js.map +1 -1
- package/dist/resolvers/yup.d.cts +6 -0
- package/dist/resolvers/yup.d.mts +6 -0
- package/dist/resolvers/yup.d.ts +0 -1
- package/dist/resolvers/yup.mjs +1 -1
- package/dist/resolvers/yup.mjs.map +1 -1
- package/dist/resolvers/zod.cjs.js +1 -1
- package/dist/resolvers/zod.cjs.js.map +1 -1
- package/dist/resolvers/zod.d.cts +6 -0
- package/dist/resolvers/zod.d.mts +6 -0
- package/dist/resolvers/zod.d.ts +0 -1
- package/dist/resolvers/zod.mjs +1 -1
- package/dist/resolvers/zod.mjs.map +1 -1
- package/dist/server/index.cjs.js +1 -1
- package/dist/server/index.cjs.js.map +1 -1
- package/dist/server/index.d.cts +106 -0
- package/dist/server/index.d.mts +106 -0
- package/dist/server/index.d.ts +31 -2
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/standard-schema-CYbnugL7.d.ts +1184 -0
- package/dist/standardSchema-BpZvg0tZ.mjs +2 -0
- package/dist/standardSchema-BpZvg0tZ.mjs.map +1 -0
- package/dist/standardSchema-CxV_DhBO.cjs.js +2 -0
- package/dist/standardSchema-CxV_DhBO.cjs.js.map +1 -0
- package/dist/validate-BEjNsNvd.mjs +2 -0
- package/dist/validate-BEjNsNvd.mjs.map +1 -0
- package/dist/validate-BvN6hiEG.cjs.js +2 -0
- package/dist/validate-BvN6hiEG.cjs.js.map +1 -0
- package/dist/values-Bod74Kzu.mjs +2 -0
- package/dist/values-Bod74Kzu.mjs.map +1 -0
- package/dist/values-DKpOCD5J.cjs.js +2 -0
- package/dist/values-DKpOCD5J.cjs.js.map +1 -0
- package/package.json +72 -27
- package/persist.d.ts +1 -0
- package/persist.js +1 -0
- package/resolvers/standard-schema.d.ts +1 -0
- package/resolvers/standard-schema.js +1 -0
- package/resolvers/yup.d.ts +1 -0
- package/resolvers/yup.js +1 -0
- package/resolvers/zod.d.ts +1 -0
- package/resolvers/zod.js +1 -0
- package/server.d.ts +1 -0
- package/server.js +1 -0
- package/dist/errors-BKrUdpfI.cjs.js +0 -2
- package/dist/errors-BKrUdpfI.cjs.js.map +0 -1
- package/dist/errors-CrQBddrJ.mjs +0 -2
- package/dist/errors-CrQBddrJ.mjs.map +0 -1
- package/dist/form-CeKSBs31.d.ts +0 -486
- package/dist/validate-CNtuUhmk.mjs +0 -2
- package/dist/validate-CNtuUhmk.mjs.map +0 -1
- package/dist/validate-Cl4ksNFu.cjs.js +0 -2
- package/dist/validate-Cl4ksNFu.cjs.js.map +0 -1
- package/dist/validate-nksgv1pR.d.ts +0 -272
- package/dist/values-Cu6awQOJ.cjs.js +0 -2
- package/dist/values-Cu6awQOJ.cjs.js.map +0 -1
- package/dist/values-DRY-a32G.mjs +0 -2
- package/dist/values-DRY-a32G.mjs.map +0 -1
package/dist/index.umd.js
CHANGED
|
@@ -309,6 +309,15 @@
|
|
|
309
309
|
function isPromise(value) {
|
|
310
310
|
return value && typeof value.then === "function";
|
|
311
311
|
}
|
|
312
|
+
function extractEventValue(e, options) {
|
|
313
|
+
const target = e?.target;
|
|
314
|
+
if (!target) return e;
|
|
315
|
+
if (target.type === "file") return target.files;
|
|
316
|
+
if (target.type === "checkbox") return target.checked;
|
|
317
|
+
if (options?.valueAsNumber) return target.valueAsNumber;
|
|
318
|
+
if (options?.valueAsDate) return target.valueAsDate;
|
|
319
|
+
return target.value;
|
|
320
|
+
}
|
|
312
321
|
function isEqual(a, b) {
|
|
313
322
|
if (Object.is(a, b)) return true;
|
|
314
323
|
if (a instanceof Date && b instanceof Date)
|
|
@@ -361,6 +370,11 @@
|
|
|
361
370
|
const cache = valuesCaches.get(form);
|
|
362
371
|
if (cache) cache.version++;
|
|
363
372
|
}
|
|
373
|
+
const errorsCaches = /* @__PURE__ */ new WeakMap();
|
|
374
|
+
function bumpErrorsVersion(form) {
|
|
375
|
+
const cache = errorsCaches.get(form);
|
|
376
|
+
if (cache) cache.version++;
|
|
377
|
+
}
|
|
364
378
|
const dirtyBaselines = /* @__PURE__ */ new WeakMap();
|
|
365
379
|
function getDirtyBaseline(form, key, segments) {
|
|
366
380
|
const baselines = dirtyBaselines.get(form);
|
|
@@ -430,6 +444,50 @@
|
|
|
430
444
|
}
|
|
431
445
|
return entries;
|
|
432
446
|
}
|
|
447
|
+
function computeErrorsViews(form) {
|
|
448
|
+
const cached = errorsCaches.get(form);
|
|
449
|
+
if (cached && cached.version === 0) return;
|
|
450
|
+
const result = {};
|
|
451
|
+
const tree = {};
|
|
452
|
+
for (const [key, list] of form.errors) {
|
|
453
|
+
const segments = JSON.parse(key);
|
|
454
|
+
result[segments.join(".")] = list;
|
|
455
|
+
let node = tree;
|
|
456
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
457
|
+
const segment = segments[i];
|
|
458
|
+
const slot = node[segment];
|
|
459
|
+
const container = slot && !(Array.isArray(slot) && slot.length > 0 && isFieldError(slot[0])) ? slot : typeof segments[i + 1] === "number" ? [] : {};
|
|
460
|
+
node[segment] = container;
|
|
461
|
+
node = container;
|
|
462
|
+
}
|
|
463
|
+
node[segments[segments.length - 1]] = list;
|
|
464
|
+
}
|
|
465
|
+
if (cached) {
|
|
466
|
+
cached.result = result;
|
|
467
|
+
cached.tree = tree;
|
|
468
|
+
cached.version = 0;
|
|
469
|
+
} else {
|
|
470
|
+
errorsCaches.set(form, { version: 0, result, tree });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function getErrorsRecord(form) {
|
|
474
|
+
computeErrorsViews(form);
|
|
475
|
+
return errorsCaches.get(form).result;
|
|
476
|
+
}
|
|
477
|
+
function getErrorsTree(form) {
|
|
478
|
+
computeErrorsViews(form);
|
|
479
|
+
return errorsCaches.get(form).tree;
|
|
480
|
+
}
|
|
481
|
+
function fieldPathToDottedKey(name) {
|
|
482
|
+
return create$1(name).value.join(".");
|
|
483
|
+
}
|
|
484
|
+
function dottedKeyToFieldPath(key) {
|
|
485
|
+
const segments = key.split(".");
|
|
486
|
+
const numeric = (segment) => /^(0|[1-9]\d*)$/.test(segment);
|
|
487
|
+
return segments.map(
|
|
488
|
+
(segment, i) => i > 0 && numeric(segment) ? `[${segment}]` : `${i > 0 ? "." : ""}${segment}`
|
|
489
|
+
).join("");
|
|
490
|
+
}
|
|
433
491
|
function getFirstError({ errors }) {
|
|
434
492
|
return errors.values().next().value?.[0]?.message;
|
|
435
493
|
}
|
|
@@ -441,6 +499,7 @@
|
|
|
441
499
|
const list = normalizeErrors(error);
|
|
442
500
|
if (list) errors.set(path.key, list);
|
|
443
501
|
else errors.delete(path.key);
|
|
502
|
+
bumpErrorsVersion(form);
|
|
444
503
|
emit(emitter, "errors", path);
|
|
445
504
|
if (options?.shouldFocus) emit(emitter, "focusError", path.key);
|
|
446
505
|
}
|
|
@@ -464,11 +523,13 @@
|
|
|
464
523
|
const { emitter, errors } = form;
|
|
465
524
|
if (name === void 0) {
|
|
466
525
|
errors.clear();
|
|
526
|
+
bumpErrorsVersion(form);
|
|
467
527
|
emit(emitter, "errors");
|
|
468
528
|
return;
|
|
469
529
|
}
|
|
470
530
|
const paths = typeof name === "string" || isSegmentsPath(name) ? [create$1(name)] : name.map((one) => create$1(one));
|
|
471
531
|
for (const { key } of paths) errors.delete(key);
|
|
532
|
+
bumpErrorsVersion(form);
|
|
472
533
|
for (const path of paths) emit(emitter, "errors", path);
|
|
473
534
|
}
|
|
474
535
|
function setServerErrors(form, errors, options) {
|
|
@@ -484,10 +545,109 @@
|
|
|
484
545
|
);
|
|
485
546
|
}
|
|
486
547
|
}
|
|
548
|
+
function clearServerErrors(form) {
|
|
549
|
+
let changed = false;
|
|
550
|
+
for (const [key, errors] of form.errors) {
|
|
551
|
+
const kept = errors.filter((error) => error.type !== "server");
|
|
552
|
+
if (kept.length === 0) {
|
|
553
|
+
form.errors.delete(key);
|
|
554
|
+
changed = true;
|
|
555
|
+
} else if (kept.length !== errors.length) {
|
|
556
|
+
form.errors.set(key, kept);
|
|
557
|
+
changed = true;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
if (changed) {
|
|
561
|
+
bumpErrorsVersion(form);
|
|
562
|
+
emit(form.emitter, "errors");
|
|
563
|
+
}
|
|
564
|
+
}
|
|
487
565
|
function hasErrors({ errors }) {
|
|
488
566
|
return errors.size > 0;
|
|
489
567
|
}
|
|
490
568
|
|
|
569
|
+
function hasStandardProps(schema) {
|
|
570
|
+
return !!schema && typeof schema === "object" && typeof schema["~standard"]?.validate === "function";
|
|
571
|
+
}
|
|
572
|
+
function toFieldError(issue) {
|
|
573
|
+
return { type: "standard", message: issue?.message || "Validation failed" };
|
|
574
|
+
}
|
|
575
|
+
function schemaToFieldValidator(schema) {
|
|
576
|
+
return async (value) => {
|
|
577
|
+
const result = await schema["~standard"].validate(value);
|
|
578
|
+
if (!result.issues?.length) return void 0;
|
|
579
|
+
return result.issues.map(toFieldError);
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function schemaToFormValidator(schema) {
|
|
583
|
+
return async (values) => {
|
|
584
|
+
const result = await schema["~standard"].validate(values);
|
|
585
|
+
const { issues } = result;
|
|
586
|
+
if (!issues?.length) {
|
|
587
|
+
return {
|
|
588
|
+
[VALIDATION_OUTCOME]: true,
|
|
589
|
+
values: "value" in result ? result.value : void 0
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
const errors = {};
|
|
593
|
+
for (const issue of issues) {
|
|
594
|
+
const segments = toPathSegments(issue);
|
|
595
|
+
if (segments.length) {
|
|
596
|
+
assignAtPath(errors, segments, toFieldError(issue));
|
|
597
|
+
} else {
|
|
598
|
+
const slot = errors[FORM_ERROR] ??= [];
|
|
599
|
+
if (Array.isArray(slot)) slot.push(toFieldError(issue));
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return { [VALIDATION_OUTCOME]: true, errors: pruneEmpty(errors) || {} };
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function toPathSegments(issue) {
|
|
606
|
+
const path = issue.path || [];
|
|
607
|
+
const segments = [];
|
|
608
|
+
for (const segment of path) {
|
|
609
|
+
const key = typeof segment === "object" && segment !== null ? segment.key : segment;
|
|
610
|
+
segments.push(String(key));
|
|
611
|
+
}
|
|
612
|
+
return segments;
|
|
613
|
+
}
|
|
614
|
+
function assignAtPath(root, segments, error) {
|
|
615
|
+
let node = root;
|
|
616
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
617
|
+
const segment = segments[i];
|
|
618
|
+
let next = node[segment];
|
|
619
|
+
if (next === void 0) {
|
|
620
|
+
next = node[segment] = {};
|
|
621
|
+
}
|
|
622
|
+
if (!isBranch(next)) return;
|
|
623
|
+
node = next;
|
|
624
|
+
}
|
|
625
|
+
const leaf = segments[segments.length - 1];
|
|
626
|
+
const slot = node[leaf];
|
|
627
|
+
if (slot === void 0) node[leaf] = [error];
|
|
628
|
+
else if (Array.isArray(slot)) slot.push(error);
|
|
629
|
+
}
|
|
630
|
+
function isBranch(value) {
|
|
631
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
632
|
+
}
|
|
633
|
+
function pruneEmpty(node) {
|
|
634
|
+
let hasLeaf = false;
|
|
635
|
+
const result = {};
|
|
636
|
+
Object.entries(node).forEach(([key, value]) => {
|
|
637
|
+
if (isBranch(value)) {
|
|
638
|
+
const pruned = pruneEmpty(value);
|
|
639
|
+
if (pruned) {
|
|
640
|
+
result[key] = pruned;
|
|
641
|
+
hasLeaf = true;
|
|
642
|
+
}
|
|
643
|
+
} else {
|
|
644
|
+
result[key] = value;
|
|
645
|
+
hasLeaf = true;
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
return hasLeaf ? result : void 0;
|
|
649
|
+
}
|
|
650
|
+
|
|
491
651
|
function isFieldDirtyByPath(form, path) {
|
|
492
652
|
const live = form.values.get(path.key);
|
|
493
653
|
return form.values.has(path.key) && getDirtyBaseline(form, path.key, path.value) !== live;
|
|
@@ -647,7 +807,7 @@
|
|
|
647
807
|
if (!hasLiveBranch(values, segments)) deleted.add(key);
|
|
648
808
|
}
|
|
649
809
|
if (!options?.keepTouched) touched.delete(key);
|
|
650
|
-
if (!options?.keepError
|
|
810
|
+
if (!options?.keepError && errors.delete(key)) bumpErrorsVersion(form);
|
|
651
811
|
validating.delete(key);
|
|
652
812
|
bumpDirtyVersion(form);
|
|
653
813
|
bumpValuesVersion(form);
|
|
@@ -769,6 +929,7 @@
|
|
|
769
929
|
emit(emitter, "touched", path);
|
|
770
930
|
}
|
|
771
931
|
if (!options?.keepErrors && errors.delete(path.key)) {
|
|
932
|
+
bumpErrorsVersion(form);
|
|
772
933
|
emit(emitter, "errors", path);
|
|
773
934
|
}
|
|
774
935
|
bumpDirtyVersion(form);
|
|
@@ -978,7 +1139,7 @@
|
|
|
978
1139
|
if (stored) footprint.set(path.key, stored);
|
|
979
1140
|
}
|
|
980
1141
|
function applyValidateResult(form, result) {
|
|
981
|
-
const footprint = form.validateDeps ? getFormErrorFootprint(form) : void 0;
|
|
1142
|
+
const footprint = form.validateDeps || form.validateMode !== "onSubmit" ? getFormErrorFootprint(form) : void 0;
|
|
982
1143
|
if (footprint) {
|
|
983
1144
|
clearFormValidateErrors(form, footprint);
|
|
984
1145
|
footprint.clear();
|
|
@@ -1014,6 +1175,7 @@
|
|
|
1014
1175
|
const stored = form.errors.get(key);
|
|
1015
1176
|
if (stored !== written) continue;
|
|
1016
1177
|
form.errors.delete(key);
|
|
1178
|
+
bumpErrorsVersion(form);
|
|
1017
1179
|
emit(form.emitter, "errors", create$1(JSON.parse(key)));
|
|
1018
1180
|
}
|
|
1019
1181
|
}
|
|
@@ -1207,6 +1369,10 @@
|
|
|
1207
1369
|
if (mode === "onChange" || mode === "all" || mode === "onTouched" && hasTouchedByPath(form, path) || getFieldErrorsByPath(form, path).length > 0 && form.reValidateMode === "onChange")
|
|
1208
1370
|
form.validators.get(path.key)?.();
|
|
1209
1371
|
revalidateFormOnChange(form, path, mode);
|
|
1372
|
+
if (form.validateMode === "onChange" && form.validate) {
|
|
1373
|
+
runFormValidate(form).catch(() => {
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1210
1376
|
revalidateDependentsOnChange(form, path, mode);
|
|
1211
1377
|
}
|
|
1212
1378
|
function userChangeByPath(form, path, value) {
|
|
@@ -1221,6 +1387,327 @@
|
|
|
1221
1387
|
const mode = entry.mode ?? form.mode;
|
|
1222
1388
|
if (mode === "onBlur" || mode === "onTouched" || mode === "all" || getFieldErrorsByPath(form, path).length > 0 && form.reValidateMode === "onBlur")
|
|
1223
1389
|
form.validators.get(path.key)?.();
|
|
1390
|
+
if (form.validateMode === "onBlur" && form.validate) {
|
|
1391
|
+
runFormValidate(form).catch(() => {
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
function removeFieldForUnmount(form, path) {
|
|
1397
|
+
const { key } = path;
|
|
1398
|
+
const snapshot = {
|
|
1399
|
+
present: form.values.has(key),
|
|
1400
|
+
value: form.values.get(key),
|
|
1401
|
+
touched: form.touched.has(key),
|
|
1402
|
+
errors: form.errors.get(key)
|
|
1403
|
+
};
|
|
1404
|
+
removeFieldByPath(form, path);
|
|
1405
|
+
return snapshot;
|
|
1406
|
+
}
|
|
1407
|
+
function restoreRemovedField(form, path, snapshot) {
|
|
1408
|
+
const { key } = path;
|
|
1409
|
+
if (snapshot.present) {
|
|
1410
|
+
setValueByPath(form, path, snapshot.value, { shouldDirty: false });
|
|
1411
|
+
} else {
|
|
1412
|
+
form.deleted.delete(key);
|
|
1413
|
+
bumpValuesVersion(form);
|
|
1414
|
+
emit(form.emitter, "change", path);
|
|
1415
|
+
}
|
|
1416
|
+
if (snapshot.touched) setTouchedByPath(form, path);
|
|
1417
|
+
if (snapshot.errors) setErrorByPath(form, path, snapshot.errors);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
function hasRuleConstraints(rules) {
|
|
1421
|
+
return rules.required !== void 0 || rules.min !== void 0 || rules.max !== void 0 || rules.minLength !== void 0 || rules.maxLength !== void 0 || rules.pattern !== void 0 || rules.validate !== void 0;
|
|
1422
|
+
}
|
|
1423
|
+
function defaultMessage(type, bound) {
|
|
1424
|
+
switch (type) {
|
|
1425
|
+
case "required":
|
|
1426
|
+
return "This field is required";
|
|
1427
|
+
case "min":
|
|
1428
|
+
return `Must be at least ${bound}`;
|
|
1429
|
+
case "max":
|
|
1430
|
+
return `Must be at most ${bound}`;
|
|
1431
|
+
case "minLength":
|
|
1432
|
+
return `Must be at least ${bound} characters`;
|
|
1433
|
+
case "maxLength":
|
|
1434
|
+
return `Must be at most ${bound} characters`;
|
|
1435
|
+
case "pattern":
|
|
1436
|
+
return "Invalid format";
|
|
1437
|
+
default:
|
|
1438
|
+
return "Invalid value";
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
function rulesToValidator(rules) {
|
|
1442
|
+
return (value, meta) => {
|
|
1443
|
+
if (rules.required) {
|
|
1444
|
+
if (value === "" || value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
|
|
1445
|
+
return [
|
|
1446
|
+
{
|
|
1447
|
+
type: "required",
|
|
1448
|
+
message: typeof rules.required === "string" ? rules.required : defaultMessage("required")
|
|
1449
|
+
}
|
|
1450
|
+
];
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
const errors = [];
|
|
1454
|
+
const message = (type, bound) => rules.messages?.[type] ?? defaultMessage(type, bound);
|
|
1455
|
+
if (rules.min !== void 0) {
|
|
1456
|
+
const n = Number(value);
|
|
1457
|
+
if (!Number.isNaN(n) && n < rules.min) {
|
|
1458
|
+
errors.push({ type: "min", message: message("min", rules.min) });
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
if (rules.max !== void 0) {
|
|
1462
|
+
const n = Number(value);
|
|
1463
|
+
if (!Number.isNaN(n) && n > rules.max) {
|
|
1464
|
+
errors.push({ type: "max", message: message("max", rules.max) });
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
const isSized = typeof value === "string" || Array.isArray(value);
|
|
1468
|
+
if (rules.minLength !== void 0 && isSized && value.length < rules.minLength) {
|
|
1469
|
+
errors.push({
|
|
1470
|
+
type: "minLength",
|
|
1471
|
+
message: message("minLength", rules.minLength)
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
if (rules.maxLength !== void 0 && isSized && value.length > rules.maxLength) {
|
|
1475
|
+
errors.push({
|
|
1476
|
+
type: "maxLength",
|
|
1477
|
+
message: message("maxLength", rules.maxLength)
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
if (rules.pattern && !rules.pattern.value.test(value)) {
|
|
1481
|
+
errors.push({
|
|
1482
|
+
type: "pattern",
|
|
1483
|
+
// pattern.message is type-required but JS consumers may omit it.
|
|
1484
|
+
message: rules.messages?.pattern ?? rules.pattern.message ?? defaultMessage("pattern")
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
if (rules.validate !== void 0) {
|
|
1488
|
+
const fns = typeof rules.validate === "function" ? { validate: rules.validate } : rules.validate;
|
|
1489
|
+
for (const [type, fn] of Object.entries(fns)) {
|
|
1490
|
+
const result = fn(value, meta);
|
|
1491
|
+
if (result === void 0) continue;
|
|
1492
|
+
for (const entry of Array.isArray(result) ? result : [result]) {
|
|
1493
|
+
errors.push(
|
|
1494
|
+
typeof entry === "string" ? { type, message: entry } : { ...entry, type }
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
return errors.length ? errors : void 0;
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
function rulesToConstraintAttrs(rules) {
|
|
1503
|
+
const attrs = {};
|
|
1504
|
+
if (rules.required) attrs.required = true;
|
|
1505
|
+
if (rules.min !== void 0) attrs.min = rules.min;
|
|
1506
|
+
if (rules.max !== void 0) attrs.max = rules.max;
|
|
1507
|
+
if (rules.minLength !== void 0) attrs.minLength = rules.minLength;
|
|
1508
|
+
if (rules.maxLength !== void 0) attrs.maxLength = rules.maxLength;
|
|
1509
|
+
if (rules.pattern) attrs.pattern = rules.pattern.value.source;
|
|
1510
|
+
return attrs;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
function registerField(form, name, options) {
|
|
1514
|
+
const path = create$1(name);
|
|
1515
|
+
const {
|
|
1516
|
+
mode,
|
|
1517
|
+
shouldUnregister,
|
|
1518
|
+
eventToValue,
|
|
1519
|
+
valueAsNumber,
|
|
1520
|
+
valueAsDate,
|
|
1521
|
+
rules
|
|
1522
|
+
} = options ?? {};
|
|
1523
|
+
const toValue = eventToValue ?? ((e) => {
|
|
1524
|
+
const target = e?.target;
|
|
1525
|
+
if (!target) return e;
|
|
1526
|
+
if (target.type === "file") return target.files;
|
|
1527
|
+
if (target.type === "checkbox") return target.checked;
|
|
1528
|
+
if (valueAsNumber) return target.valueAsNumber;
|
|
1529
|
+
if (valueAsDate) return target.valueAsDate;
|
|
1530
|
+
return target.value;
|
|
1531
|
+
});
|
|
1532
|
+
let el = null;
|
|
1533
|
+
let modeToken = null;
|
|
1534
|
+
let disposeValidator = null;
|
|
1535
|
+
let snapshot = null;
|
|
1536
|
+
let offFocus = null;
|
|
1537
|
+
let offBulkSync = null;
|
|
1538
|
+
const syncDom = () => {
|
|
1539
|
+
if (!el || el.type === "file") return;
|
|
1540
|
+
const next = getValueByPath(form, path);
|
|
1541
|
+
const asString = next == null ? "" : String(next);
|
|
1542
|
+
if (el.value !== asString) el.value = asString;
|
|
1543
|
+
};
|
|
1544
|
+
const attach = (node) => {
|
|
1545
|
+
if (snapshot) {
|
|
1546
|
+
restoreRemovedField(form, path, snapshot);
|
|
1547
|
+
snapshot = null;
|
|
1548
|
+
}
|
|
1549
|
+
el = node;
|
|
1550
|
+
if (node.type !== "file" && getValueByPath(form, path) === void 0) {
|
|
1551
|
+
seedValueByPath(
|
|
1552
|
+
form,
|
|
1553
|
+
path,
|
|
1554
|
+
node.type === "checkbox" ? node.checked : node.value
|
|
1555
|
+
);
|
|
1556
|
+
emitChangeByPath(form, path);
|
|
1557
|
+
}
|
|
1558
|
+
modeToken = registerFieldMode(form, path, mode).token;
|
|
1559
|
+
if (rules && hasRuleConstraints(rules)) {
|
|
1560
|
+
const sync = rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0;
|
|
1561
|
+
const rest = rules.required !== void 0 ? { ...rules, required: void 0 } : rules;
|
|
1562
|
+
disposeValidator = registerValidatorByPath(form, path, {
|
|
1563
|
+
validate: () => hasRuleConstraints(rest) ? rulesToValidator(rest) : void 0,
|
|
1564
|
+
debounce: () => 0,
|
|
1565
|
+
sync: () => sync
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
offFocus = on(
|
|
1569
|
+
form.emitter,
|
|
1570
|
+
"focusError",
|
|
1571
|
+
(key, options2) => {
|
|
1572
|
+
if (key !== path.key || !el || typeof el.focus !== "function") return;
|
|
1573
|
+
el.focus();
|
|
1574
|
+
if (options2?.shouldSelect && typeof el.select === "function") {
|
|
1575
|
+
el.select();
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
);
|
|
1579
|
+
offBulkSync = on(form.emitter, "change", (changed) => {
|
|
1580
|
+
if (changed) return;
|
|
1581
|
+
syncDom();
|
|
1582
|
+
});
|
|
1583
|
+
};
|
|
1584
|
+
const detach = () => {
|
|
1585
|
+
if (modeToken) {
|
|
1586
|
+
unregisterFieldMode(form, path, modeToken);
|
|
1587
|
+
modeToken = null;
|
|
1588
|
+
}
|
|
1589
|
+
if (disposeValidator) {
|
|
1590
|
+
disposeValidator();
|
|
1591
|
+
disposeValidator = null;
|
|
1592
|
+
}
|
|
1593
|
+
if (offFocus) {
|
|
1594
|
+
offFocus();
|
|
1595
|
+
offFocus = null;
|
|
1596
|
+
}
|
|
1597
|
+
if (offBulkSync) {
|
|
1598
|
+
offBulkSync();
|
|
1599
|
+
offBulkSync = null;
|
|
1600
|
+
}
|
|
1601
|
+
el = null;
|
|
1602
|
+
if ((shouldUnregister ?? form.shouldUnregister) !== false) {
|
|
1603
|
+
snapshot = removeFieldForUnmount(form, path);
|
|
1604
|
+
}
|
|
1605
|
+
};
|
|
1606
|
+
return {
|
|
1607
|
+
name: path.key,
|
|
1608
|
+
onChange: (e) => changeValueByPath(form, path, toValue(e)),
|
|
1609
|
+
onBlur: () => userBlur(form, path),
|
|
1610
|
+
ref: (node) => {
|
|
1611
|
+
if (node) attach(node);
|
|
1612
|
+
else detach();
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
function readArray(form, path) {
|
|
1618
|
+
const value = getValueByPath(form, path);
|
|
1619
|
+
return Array.isArray(value) ? value : [];
|
|
1620
|
+
}
|
|
1621
|
+
function appendValueByPath(form, path, value) {
|
|
1622
|
+
const arr = readArray(form, path);
|
|
1623
|
+
setValueByPath(form, path, [...arr, value]);
|
|
1624
|
+
}
|
|
1625
|
+
function prependValueByPath(form, path, value) {
|
|
1626
|
+
const arr = readArray(form, path);
|
|
1627
|
+
setValueByPath(form, path, [value, ...arr]);
|
|
1628
|
+
}
|
|
1629
|
+
function insertValueByPath(form, path, index, value) {
|
|
1630
|
+
const arr = readArray(form, path);
|
|
1631
|
+
if (index < 0 || index > arr.length) return false;
|
|
1632
|
+
setValueByPath(form, path, [
|
|
1633
|
+
...arr.slice(0, index),
|
|
1634
|
+
value,
|
|
1635
|
+
...arr.slice(index)
|
|
1636
|
+
]);
|
|
1637
|
+
return true;
|
|
1638
|
+
}
|
|
1639
|
+
function removeValueByPath(form, path, indices) {
|
|
1640
|
+
const arr = readArray(form, path);
|
|
1641
|
+
const drop = /* @__PURE__ */ new Set();
|
|
1642
|
+
for (const index of Array.isArray(indices) ? indices : [indices]) {
|
|
1643
|
+
if (index >= 0 && index < arr.length) drop.add(index);
|
|
1644
|
+
}
|
|
1645
|
+
if (drop.size === 0) return [];
|
|
1646
|
+
const dropped = [...drop].sort((a, b) => b - a);
|
|
1647
|
+
setValueByPath(
|
|
1648
|
+
form,
|
|
1649
|
+
path,
|
|
1650
|
+
arr.filter((_, i) => !drop.has(i))
|
|
1651
|
+
);
|
|
1652
|
+
return dropped;
|
|
1653
|
+
}
|
|
1654
|
+
function moveValueByPath(form, path, from, to) {
|
|
1655
|
+
const arr = readArray(form, path);
|
|
1656
|
+
if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) {
|
|
1657
|
+
return false;
|
|
1658
|
+
}
|
|
1659
|
+
if (from === to) return false;
|
|
1660
|
+
const next = [...arr];
|
|
1661
|
+
const [item] = next.splice(from, 1);
|
|
1662
|
+
next.splice(to, 0, item);
|
|
1663
|
+
setValueByPath(form, path, next);
|
|
1664
|
+
return true;
|
|
1665
|
+
}
|
|
1666
|
+
function swapValuesByPath(form, path, from, to) {
|
|
1667
|
+
const arr = readArray(form, path);
|
|
1668
|
+
if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) {
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
if (from === to) return false;
|
|
1672
|
+
const next = [...arr];
|
|
1673
|
+
[next[from], next[to]] = [next[to], next[from]];
|
|
1674
|
+
setValueByPath(form, path, next);
|
|
1675
|
+
return true;
|
|
1676
|
+
}
|
|
1677
|
+
function replaceValuesByPath(form, path, values) {
|
|
1678
|
+
setValueByPath(form, path, [...values]);
|
|
1679
|
+
}
|
|
1680
|
+
function updateValueByPath(form, path, index, value) {
|
|
1681
|
+
const arr = readArray(form, path);
|
|
1682
|
+
if (index < 0 || index >= arr.length) return false;
|
|
1683
|
+
const next = [...arr];
|
|
1684
|
+
next[index] = value;
|
|
1685
|
+
setValueByPath(form, path, next);
|
|
1686
|
+
return true;
|
|
1687
|
+
}
|
|
1688
|
+
function appendValue(form, name, value) {
|
|
1689
|
+
appendValueByPath(form, create$1(name), value);
|
|
1690
|
+
}
|
|
1691
|
+
function prependValue(form, name, value) {
|
|
1692
|
+
prependValueByPath(form, create$1(name), value);
|
|
1693
|
+
}
|
|
1694
|
+
function insertValue(form, name, index, value) {
|
|
1695
|
+
return insertValueByPath(form, create$1(name), index, value);
|
|
1696
|
+
}
|
|
1697
|
+
function removeValue(form, name, indices) {
|
|
1698
|
+
return removeValueByPath(form, create$1(name), indices);
|
|
1699
|
+
}
|
|
1700
|
+
function moveValue(form, name, from, to) {
|
|
1701
|
+
return moveValueByPath(form, create$1(name), from, to);
|
|
1702
|
+
}
|
|
1703
|
+
function swapValues(form, name, from, to) {
|
|
1704
|
+
return swapValuesByPath(form, create$1(name), from, to);
|
|
1705
|
+
}
|
|
1706
|
+
function replaceValues(form, name, values) {
|
|
1707
|
+
replaceValuesByPath(form, create$1(name), values);
|
|
1708
|
+
}
|
|
1709
|
+
function updateValue(form, name, index, value) {
|
|
1710
|
+
return updateValueByPath(form, create$1(name), index, value);
|
|
1224
1711
|
}
|
|
1225
1712
|
|
|
1226
1713
|
function setIsSubmitting(form, value) {
|
|
@@ -1274,18 +1761,20 @@
|
|
|
1274
1761
|
onValidSubmit,
|
|
1275
1762
|
onInvalidSubmit,
|
|
1276
1763
|
onAction,
|
|
1277
|
-
shouldFocusError = true
|
|
1764
|
+
shouldFocusError = true,
|
|
1765
|
+
shouldUseNativeValidation = form.shouldUseNativeValidation
|
|
1278
1766
|
} = options ?? {};
|
|
1279
1767
|
return async (e) => {
|
|
1280
1768
|
if (e && typeof e.preventDefault === "function") {
|
|
1281
1769
|
e.preventDefault();
|
|
1282
1770
|
}
|
|
1283
1771
|
const formEl = e?.currentTarget;
|
|
1772
|
+
clearServerErrors(form);
|
|
1284
1773
|
form.isSubmitted = true;
|
|
1285
1774
|
setIsSubmitting(form, true);
|
|
1286
1775
|
incrementSubmitCount(form);
|
|
1287
1776
|
const values = getValues(form);
|
|
1288
|
-
if (formEl && typeof formEl.checkValidity === "function" && formEl.checkValidity() === false) {
|
|
1777
|
+
if (shouldUseNativeValidation && formEl && typeof formEl.checkValidity === "function" && formEl.checkValidity() === false) {
|
|
1289
1778
|
formEl.reportValidity();
|
|
1290
1779
|
if (shouldFocusError && typeof formEl.querySelector === "function") {
|
|
1291
1780
|
const invalid = formEl.querySelector(":invalid");
|
|
@@ -1311,7 +1800,14 @@
|
|
|
1311
1800
|
const submitted = getValues(form);
|
|
1312
1801
|
if (onSubmit) await onSubmit(submitted, e);
|
|
1313
1802
|
if (onValidSubmit) await onValidSubmit(submitted, e);
|
|
1314
|
-
if (onAction)
|
|
1803
|
+
if (onAction) {
|
|
1804
|
+
const result = await onAction(submitted, e);
|
|
1805
|
+
if (result && typeof result === "object" && result.errors !== void 0 && typeof result.errors === "object") {
|
|
1806
|
+
setServerErrors(form, result.errors);
|
|
1807
|
+
setSubmitSuccessful(form, false);
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1315
1811
|
setSubmitSuccessful(form, true);
|
|
1316
1812
|
} catch {
|
|
1317
1813
|
setSubmitSuccessful(form, false);
|
|
@@ -1332,14 +1828,21 @@
|
|
|
1332
1828
|
_setMaxListeners(emitter, 0);
|
|
1333
1829
|
let source = options?.initialValues ?? {};
|
|
1334
1830
|
if (typeof source === "function") source = source();
|
|
1831
|
+
const validateOption = options?.validate;
|
|
1832
|
+
const wrappedValidate = validateOption && hasStandardProps(validateOption) ? schemaToFormValidator(
|
|
1833
|
+
validateOption
|
|
1834
|
+
) : validateOption;
|
|
1335
1835
|
const form = {
|
|
1336
1836
|
emitter,
|
|
1337
1837
|
...options,
|
|
1838
|
+
validate: wrappedValidate,
|
|
1338
1839
|
mode: options?.mode ?? "onSubmit",
|
|
1339
1840
|
reValidateMode: options?.reValidateMode ?? "onChange",
|
|
1841
|
+
validateMode: options?.validateMode ?? "onSubmit",
|
|
1340
1842
|
disabled: options?.disabled ?? false,
|
|
1341
1843
|
validateOnMount: options?.validateOnMount ?? false,
|
|
1342
1844
|
asyncAlways: options?.asyncAlways ?? false,
|
|
1845
|
+
shouldUseNativeValidation: options?.shouldUseNativeValidation ?? true,
|
|
1343
1846
|
validateDeps: options?.validateDeps ? new Set(options.validateDeps.map((dep) => create$1(dep).key)) : void 0,
|
|
1344
1847
|
initialValues: {},
|
|
1345
1848
|
values: /* @__PURE__ */ new Map(),
|
|
@@ -1354,7 +1857,8 @@
|
|
|
1354
1857
|
submitCount: 0,
|
|
1355
1858
|
isSubmitSuccessful: void 0,
|
|
1356
1859
|
isLoading: false,
|
|
1357
|
-
status: void 0
|
|
1860
|
+
status: void 0,
|
|
1861
|
+
register: (name, registerOptions) => registerField(form, name, registerOptions)
|
|
1358
1862
|
};
|
|
1359
1863
|
if (isPromise(source)) {
|
|
1360
1864
|
form.isLoading = true;
|
|
@@ -1376,94 +1880,44 @@
|
|
|
1376
1880
|
return form;
|
|
1377
1881
|
}
|
|
1378
1882
|
|
|
1379
|
-
function
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
return "This field is required";
|
|
1383
|
-
case "min":
|
|
1384
|
-
return `Must be at least ${bound}`;
|
|
1385
|
-
case "max":
|
|
1386
|
-
return `Must be at most ${bound}`;
|
|
1387
|
-
case "minLength":
|
|
1388
|
-
return `Must be at least ${bound} characters`;
|
|
1389
|
-
case "maxLength":
|
|
1390
|
-
return `Must be at most ${bound} characters`;
|
|
1391
|
-
case "pattern":
|
|
1392
|
-
return "Invalid format";
|
|
1393
|
-
default:
|
|
1394
|
-
return "Invalid value";
|
|
1395
|
-
}
|
|
1883
|
+
function errorIdFromKey(key) {
|
|
1884
|
+
const id = key.replace(/["'[\],\s]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1885
|
+
return id || "field";
|
|
1396
1886
|
}
|
|
1397
|
-
function
|
|
1398
|
-
return (
|
|
1399
|
-
if (rules.required) {
|
|
1400
|
-
if (value === "" || value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
|
|
1401
|
-
return [
|
|
1402
|
-
{
|
|
1403
|
-
type: "required",
|
|
1404
|
-
message: typeof rules.required === "string" ? rules.required : defaultMessage("required")
|
|
1405
|
-
}
|
|
1406
|
-
];
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
const errors = [];
|
|
1410
|
-
const message = (type, bound) => rules.messages?.[type] ?? defaultMessage(type, bound);
|
|
1411
|
-
if (rules.min !== void 0) {
|
|
1412
|
-
const n = Number(value);
|
|
1413
|
-
if (!Number.isNaN(n) && n < rules.min) {
|
|
1414
|
-
errors.push({ type: "min", message: message("min", rules.min) });
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
if (rules.max !== void 0) {
|
|
1418
|
-
const n = Number(value);
|
|
1419
|
-
if (!Number.isNaN(n) && n > rules.max) {
|
|
1420
|
-
errors.push({ type: "max", message: message("max", rules.max) });
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
const isSized = typeof value === "string" || Array.isArray(value);
|
|
1424
|
-
if (rules.minLength !== void 0 && isSized && value.length < rules.minLength) {
|
|
1425
|
-
errors.push({
|
|
1426
|
-
type: "minLength",
|
|
1427
|
-
message: message("minLength", rules.minLength)
|
|
1428
|
-
});
|
|
1429
|
-
}
|
|
1430
|
-
if (rules.maxLength !== void 0 && isSized && value.length > rules.maxLength) {
|
|
1431
|
-
errors.push({
|
|
1432
|
-
type: "maxLength",
|
|
1433
|
-
message: message("maxLength", rules.maxLength)
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
if (rules.pattern && !rules.pattern.value.test(value)) {
|
|
1437
|
-
errors.push({
|
|
1438
|
-
type: "pattern",
|
|
1439
|
-
// pattern.message is type-required but JS consumers may omit it.
|
|
1440
|
-
message: rules.messages?.pattern ?? rules.pattern.message ?? defaultMessage("pattern")
|
|
1441
|
-
});
|
|
1442
|
-
}
|
|
1443
|
-
if (rules.validate !== void 0) {
|
|
1444
|
-
const fns = typeof rules.validate === "function" ? { validate: rules.validate } : rules.validate;
|
|
1445
|
-
for (const [type, fn] of Object.entries(fns)) {
|
|
1446
|
-
const result = fn(value, meta);
|
|
1447
|
-
if (result === void 0) continue;
|
|
1448
|
-
for (const entry of Array.isArray(result) ? result : [result]) {
|
|
1449
|
-
errors.push(
|
|
1450
|
-
typeof entry === "string" ? { type, message: entry } : { ...entry, type }
|
|
1451
|
-
);
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
return errors.length ? errors : void 0;
|
|
1456
|
-
};
|
|
1887
|
+
function fieldErrorId(name) {
|
|
1888
|
+
return errorIdFromKey(create$1(name).key);
|
|
1457
1889
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
if (
|
|
1462
|
-
|
|
1463
|
-
if (
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1890
|
+
|
|
1891
|
+
const fieldDisabledRegistry = /* @__PURE__ */ new WeakMap();
|
|
1892
|
+
function registerFieldDisabled(form, path, disabled) {
|
|
1893
|
+
if (disabled === void 0) return null;
|
|
1894
|
+
let registry = fieldDisabledRegistry.get(form);
|
|
1895
|
+
if (!registry) {
|
|
1896
|
+
registry = /* @__PURE__ */ new Map();
|
|
1897
|
+
fieldDisabledRegistry.set(form, registry);
|
|
1898
|
+
}
|
|
1899
|
+
const token = {};
|
|
1900
|
+
registry.set(path.key, { disabled, token });
|
|
1901
|
+
emit(form.emitter, "disabled", path);
|
|
1902
|
+
return { token };
|
|
1903
|
+
}
|
|
1904
|
+
function unregisterFieldDisabled(form, path, token) {
|
|
1905
|
+
const registry = fieldDisabledRegistry.get(form);
|
|
1906
|
+
const entry = registry?.get(path.key);
|
|
1907
|
+
if (registry && entry && entry.token === token) {
|
|
1908
|
+
registry.delete(path.key);
|
|
1909
|
+
emit(form.emitter, "disabled", path);
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
function hasDisabledAncestor(form, path) {
|
|
1913
|
+
const registry = fieldDisabledRegistry.get(form);
|
|
1914
|
+
if (!registry?.size) return false;
|
|
1915
|
+
const segments = path.value;
|
|
1916
|
+
for (let i = 1; i < segments.length; i++) {
|
|
1917
|
+
const prefix = JSON.stringify(segments.slice(0, i));
|
|
1918
|
+
if (registry.get(prefix)?.disabled) return true;
|
|
1919
|
+
}
|
|
1920
|
+
return false;
|
|
1467
1921
|
}
|
|
1468
1922
|
|
|
1469
1923
|
function isDescendant(key, ancestorKey) {
|
|
@@ -1495,6 +1949,41 @@
|
|
|
1495
1949
|
});
|
|
1496
1950
|
return unsubscribes.length === 1 ? unsubscribes[0] : () => unsubscribes.forEach((unsubscribe) => unsubscribe());
|
|
1497
1951
|
}
|
|
1952
|
+
function watch(form, event, getter, isEqual) {
|
|
1953
|
+
const cache = { hasValue: false };
|
|
1954
|
+
const consumers = /* @__PURE__ */ new Set();
|
|
1955
|
+
const wake = () => {
|
|
1956
|
+
if (isEqual && cache.hasValue) {
|
|
1957
|
+
const next = getter();
|
|
1958
|
+
if (isEqual(cache.value, next)) return;
|
|
1959
|
+
cache.value = next;
|
|
1960
|
+
} else {
|
|
1961
|
+
cache.value = getter();
|
|
1962
|
+
cache.hasValue = true;
|
|
1963
|
+
}
|
|
1964
|
+
consumers.forEach((invalidate) => invalidate());
|
|
1965
|
+
};
|
|
1966
|
+
const off = on(form.emitter, event, wake);
|
|
1967
|
+
return {
|
|
1968
|
+
getSnapshot: () => {
|
|
1969
|
+
if (!cache.hasValue) {
|
|
1970
|
+
cache.value = getter();
|
|
1971
|
+
cache.hasValue = true;
|
|
1972
|
+
}
|
|
1973
|
+
return cache.value;
|
|
1974
|
+
},
|
|
1975
|
+
subscribe: (invalidate) => {
|
|
1976
|
+
consumers.add(invalidate);
|
|
1977
|
+
return () => {
|
|
1978
|
+
consumers.delete(invalidate);
|
|
1979
|
+
};
|
|
1980
|
+
},
|
|
1981
|
+
dispose: () => {
|
|
1982
|
+
off();
|
|
1983
|
+
consumers.clear();
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1498
1987
|
|
|
1499
1988
|
function useForm(options) {
|
|
1500
1989
|
const [form] = React.useState(() => {
|
|
@@ -1603,8 +2092,13 @@
|
|
|
1603
2092
|
const { key } = path;
|
|
1604
2093
|
const scope = options?.exact === false ? "branch" : "leaf";
|
|
1605
2094
|
const subscribeFactory = React.useCallback(
|
|
1606
|
-
(invalidate) => onPathEvent(
|
|
1607
|
-
|
|
2095
|
+
(invalidate) => onPathEvent(
|
|
2096
|
+
emitter,
|
|
2097
|
+
"change",
|
|
2098
|
+
create$1(JSON.parse(key)),
|
|
2099
|
+
scope,
|
|
2100
|
+
invalidate
|
|
2101
|
+
),
|
|
1608
2102
|
[emitter, key, scope]
|
|
1609
2103
|
);
|
|
1610
2104
|
return useWatchCore(subscribeFactory, () => {
|
|
@@ -1615,6 +2109,9 @@
|
|
|
1615
2109
|
return value === void 0 ? options?.defaultValue : value;
|
|
1616
2110
|
});
|
|
1617
2111
|
}
|
|
2112
|
+
function useValues(form) {
|
|
2113
|
+
return useWatch(form, "change", () => getValues(form));
|
|
2114
|
+
}
|
|
1618
2115
|
function useTouched(form, name) {
|
|
1619
2116
|
return useTouchedByPath(form, create$1(name));
|
|
1620
2117
|
}
|
|
@@ -1667,8 +2164,13 @@
|
|
|
1667
2164
|
const { emitter } = form;
|
|
1668
2165
|
const { key } = path;
|
|
1669
2166
|
const subscribeFactory = React.useCallback(
|
|
1670
|
-
(invalidate) => onPathEvent(
|
|
1671
|
-
|
|
2167
|
+
(invalidate) => onPathEvent(
|
|
2168
|
+
emitter,
|
|
2169
|
+
"change",
|
|
2170
|
+
create$1(JSON.parse(key)),
|
|
2171
|
+
"leaf",
|
|
2172
|
+
invalidate
|
|
2173
|
+
),
|
|
1672
2174
|
[emitter, key]
|
|
1673
2175
|
);
|
|
1674
2176
|
return useWatchCore(subscribeFactory, () => isFieldDirtyByPath(form, path));
|
|
@@ -1698,6 +2200,7 @@
|
|
|
1698
2200
|
touchedFields: getTouchedFields(form),
|
|
1699
2201
|
hasErrors: hasErrors(form),
|
|
1700
2202
|
isValid: !hasErrors(form),
|
|
2203
|
+
errors: getErrorsRecord(form),
|
|
1701
2204
|
isSubmitting: form.isSubmitting,
|
|
1702
2205
|
isSubmitted: form.isSubmitted,
|
|
1703
2206
|
isValidating: form.validating.size > 0,
|
|
@@ -1709,7 +2212,7 @@
|
|
|
1709
2212
|
}
|
|
1710
2213
|
function isSameFormState(a, b) {
|
|
1711
2214
|
const sameTouched = a.touchedFields.length === b.touchedFields.length && a.touchedFields.every((path, i) => path === b.touchedFields[i]);
|
|
1712
|
-
return a.isDirty === b.isDirty && a.dirtyFields === b.dirtyFields && a.isTouched === b.isTouched && sameTouched && a.hasErrors === b.hasErrors && a.isValid === b.isValid && a.isSubmitting === b.isSubmitting && a.isSubmitted === b.isSubmitted && a.isValidating === b.isValidating && a.isSubmitSuccessful === b.isSubmitSuccessful && a.submitCount === b.submitCount && a.isLoading === b.isLoading && a.disabled === b.disabled;
|
|
2215
|
+
return a.isDirty === b.isDirty && a.dirtyFields === b.dirtyFields && a.isTouched === b.isTouched && sameTouched && a.hasErrors === b.hasErrors && a.isValid === b.isValid && a.errors === b.errors && a.isSubmitting === b.isSubmitting && a.isSubmitted === b.isSubmitted && a.isValidating === b.isValidating && a.isSubmitSuccessful === b.isSubmitSuccessful && a.submitCount === b.submitCount && a.isLoading === b.isLoading && a.disabled === b.disabled;
|
|
1713
2216
|
}
|
|
1714
2217
|
function useFormState(form) {
|
|
1715
2218
|
const getter = React.useCallback(() => getFormState(form), [form]);
|
|
@@ -1726,9 +2229,29 @@
|
|
|
1726
2229
|
);
|
|
1727
2230
|
return useWatchCore(subscribeFactory, getter, isSameFormState);
|
|
1728
2231
|
}
|
|
2232
|
+
function useStore(form, selector, isEqual2) {
|
|
2233
|
+
const subscribeFactory = React.useCallback(
|
|
2234
|
+
(invalidate) => {
|
|
2235
|
+
const offs = FORM_STATE_EVENTS.map(
|
|
2236
|
+
(event) => on(form.emitter, event, invalidate)
|
|
2237
|
+
);
|
|
2238
|
+
return () => {
|
|
2239
|
+
for (const off of offs) off();
|
|
2240
|
+
};
|
|
2241
|
+
},
|
|
2242
|
+
[form.emitter]
|
|
2243
|
+
);
|
|
2244
|
+
return useWatchCore(subscribeFactory, selector, isEqual2);
|
|
2245
|
+
}
|
|
1729
2246
|
function useHasErrors(form) {
|
|
1730
2247
|
return useWatch(form, "errors", hasErrors.bind(null, form));
|
|
1731
2248
|
}
|
|
2249
|
+
function useErrors(form) {
|
|
2250
|
+
return useWatch(form, "errors", () => getErrorsRecord(form));
|
|
2251
|
+
}
|
|
2252
|
+
function useErrorsTree(form) {
|
|
2253
|
+
return useWatch(form, "errors", () => getErrorsTree(form));
|
|
2254
|
+
}
|
|
1732
2255
|
function useIsValid(form) {
|
|
1733
2256
|
return useWatch(form, "errors", () => !hasErrors(form));
|
|
1734
2257
|
}
|
|
@@ -1780,8 +2303,8 @@
|
|
|
1780
2303
|
}
|
|
1781
2304
|
|
|
1782
2305
|
function usePath(name) {
|
|
1783
|
-
const
|
|
1784
|
-
return React.useMemo(() =>
|
|
2306
|
+
const key = React.useMemo(() => create$1(normalizePath(name)).key, [name]);
|
|
2307
|
+
return React.useMemo(() => create$1(JSON.parse(key)), [key]);
|
|
1785
2308
|
}
|
|
1786
2309
|
|
|
1787
2310
|
function useStage(value) {
|
|
@@ -1798,38 +2321,46 @@
|
|
|
1798
2321
|
}
|
|
1799
2322
|
function useUnmountRestore(teardown, restore) {
|
|
1800
2323
|
const removedRef = React.useRef(false);
|
|
2324
|
+
const teardownRef = useStage(teardown);
|
|
2325
|
+
const restoreRef = useStage(restore);
|
|
1801
2326
|
React.useEffect(() => {
|
|
2327
|
+
const teardownOnce = teardownRef.current;
|
|
2328
|
+
const restoreOnce = restoreRef.current;
|
|
1802
2329
|
if (removedRef.current) {
|
|
1803
2330
|
removedRef.current = false;
|
|
1804
|
-
|
|
2331
|
+
restoreOnce();
|
|
1805
2332
|
}
|
|
1806
2333
|
return () => {
|
|
1807
2334
|
removedRef.current = true;
|
|
1808
|
-
|
|
2335
|
+
teardownOnce();
|
|
1809
2336
|
};
|
|
1810
|
-
}, []);
|
|
2337
|
+
}, [removedRef, teardownRef, restoreRef]);
|
|
1811
2338
|
}
|
|
1812
2339
|
|
|
1813
2340
|
function useValidate(validate, path, formProp, options) {
|
|
1814
2341
|
const contextForm = React.useContext(FormContext);
|
|
1815
2342
|
const form = formProp || contextForm;
|
|
1816
2343
|
if (!form) throw new Error("no form provided");
|
|
1817
|
-
const
|
|
1818
|
-
validateRef
|
|
2344
|
+
const validateOption = validate;
|
|
2345
|
+
const validateRef = React.useRef(void 0);
|
|
2346
|
+
validateRef.current = validateOption && hasStandardProps(validateOption) ? schemaToFieldValidator(validateOption) : validateOption;
|
|
1819
2347
|
const debounceRef = React.useRef(options?.debounce ?? 0);
|
|
1820
2348
|
debounceRef.current = options?.debounce ?? 0;
|
|
1821
2349
|
const syncRef = React.useRef(options?.sync);
|
|
1822
2350
|
syncRef.current = options?.sync;
|
|
1823
2351
|
const asyncAlwaysRef = React.useRef(options?.asyncAlways ?? false);
|
|
1824
2352
|
asyncAlwaysRef.current = options?.asyncAlways ?? false;
|
|
2353
|
+
const validateOnMountRef = React.useRef(options?.validateOnMount);
|
|
2354
|
+
validateOnMountRef.current = options?.validateOnMount;
|
|
1825
2355
|
React.useEffect(() => {
|
|
1826
|
-
const
|
|
2356
|
+
const spath = create$1(JSON.parse(path.key));
|
|
2357
|
+
const dispose = registerValidatorByPath(form, spath, {
|
|
1827
2358
|
validate: () => validateRef.current,
|
|
1828
2359
|
debounce: () => debounceRef.current,
|
|
1829
2360
|
sync: () => syncRef.current,
|
|
1830
2361
|
asyncAlways: () => asyncAlwaysRef.current
|
|
1831
2362
|
});
|
|
1832
|
-
const validateOnMount =
|
|
2363
|
+
const validateOnMount = validateOnMountRef.current ?? form.validateOnMount;
|
|
1833
2364
|
if (!validateOnMount || !validateRef.current && !syncRef.current) {
|
|
1834
2365
|
return dispose;
|
|
1835
2366
|
}
|
|
@@ -1854,34 +2385,7 @@
|
|
|
1854
2385
|
return useStageFn(() => form.validators.get(path.key)?.());
|
|
1855
2386
|
}
|
|
1856
2387
|
|
|
1857
|
-
function removeFieldForUnmount(form, path) {
|
|
1858
|
-
const { key } = path;
|
|
1859
|
-
const snapshot = {
|
|
1860
|
-
present: form.values.has(key),
|
|
1861
|
-
value: form.values.get(key),
|
|
1862
|
-
touched: form.touched.has(key),
|
|
1863
|
-
errors: form.errors.get(key)
|
|
1864
|
-
};
|
|
1865
|
-
removeFieldByPath(form, path);
|
|
1866
|
-
return snapshot;
|
|
1867
|
-
}
|
|
1868
|
-
function restoreRemovedField(form, path, snapshot) {
|
|
1869
|
-
const { key } = path;
|
|
1870
|
-
if (snapshot.present) {
|
|
1871
|
-
setValueByPath(form, path, snapshot.value, { shouldDirty: false });
|
|
1872
|
-
} else {
|
|
1873
|
-
form.deleted.delete(key);
|
|
1874
|
-
bumpValuesVersion(form);
|
|
1875
|
-
emit(form.emitter, "change", path);
|
|
1876
|
-
}
|
|
1877
|
-
if (snapshot.touched) setTouchedByPath(form, path);
|
|
1878
|
-
if (snapshot.errors) setErrorByPath(form, path, snapshot.errors);
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1881
2388
|
const uncontrolledSyncRegistry = /* @__PURE__ */ new WeakMap();
|
|
1882
|
-
function hasRuleConstraints(rules) {
|
|
1883
|
-
return rules.required !== void 0 || rules.min !== void 0 || rules.max !== void 0 || rules.minLength !== void 0 || rules.maxLength !== void 0 || rules.pattern !== void 0 || rules.validate !== void 0;
|
|
1884
|
-
}
|
|
1885
2389
|
function combineRulesAndValidate(rules, validate) {
|
|
1886
2390
|
if (!rules || !hasRuleConstraints(rules)) return validate;
|
|
1887
2391
|
const ruleValidator = rulesToValidator(rules);
|
|
@@ -1898,22 +2402,59 @@
|
|
|
1898
2402
|
return isPromise(result) ? result.then(merge) : merge(result);
|
|
1899
2403
|
};
|
|
1900
2404
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
React.
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
2405
|
+
const NO_DELAYED_ERRORS = [];
|
|
2406
|
+
function useDelayedErrors(form, path, delay) {
|
|
2407
|
+
const pendingRef = React.useRef(false);
|
|
2408
|
+
const prevRef = React.useRef(false);
|
|
2409
|
+
const timerRef = React.useRef(null);
|
|
2410
|
+
const subscribeFactory = React.useCallback(
|
|
2411
|
+
(invalidate) => {
|
|
2412
|
+
const spath = create$1(JSON.parse(path.key));
|
|
2413
|
+
const clearTimer = () => {
|
|
2414
|
+
if (timerRef.current !== null) {
|
|
2415
|
+
clearTimeout(timerRef.current);
|
|
2416
|
+
timerRef.current = null;
|
|
2417
|
+
}
|
|
2418
|
+
};
|
|
2419
|
+
pendingRef.current = false;
|
|
2420
|
+
prevRef.current = false;
|
|
2421
|
+
clearTimer();
|
|
2422
|
+
const startWindow = () => {
|
|
2423
|
+
clearTimer();
|
|
2424
|
+
pendingRef.current = true;
|
|
2425
|
+
timerRef.current = setTimeout(() => {
|
|
2426
|
+
timerRef.current = null;
|
|
2427
|
+
pendingRef.current = false;
|
|
2428
|
+
invalidate();
|
|
2429
|
+
}, delay);
|
|
2430
|
+
};
|
|
2431
|
+
const off = onKeyEvent(form.emitter, "errors", spath.key, () => {
|
|
2432
|
+
const has = getFieldErrorsByPath(form, spath).length > 0;
|
|
2433
|
+
const was = prevRef.current;
|
|
2434
|
+
prevRef.current = has;
|
|
2435
|
+
if (delay !== void 0) {
|
|
2436
|
+
if (!has) {
|
|
2437
|
+
if (pendingRef.current) {
|
|
2438
|
+
clearTimer();
|
|
2439
|
+
pendingRef.current = false;
|
|
2440
|
+
}
|
|
2441
|
+
} else if (!was || pendingRef.current) {
|
|
2442
|
+
startWindow();
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
invalidate();
|
|
2446
|
+
});
|
|
2447
|
+
return () => {
|
|
2448
|
+
off();
|
|
2449
|
+
clearTimer();
|
|
2450
|
+
};
|
|
2451
|
+
},
|
|
2452
|
+
[form, path.key, delay]
|
|
2453
|
+
);
|
|
2454
|
+
return useWatchCore(
|
|
2455
|
+
subscribeFactory,
|
|
2456
|
+
() => delay === void 0 || !pendingRef.current ? getFieldErrorsByPath(form, path) : NO_DELAYED_ERRORS
|
|
2457
|
+
);
|
|
1917
2458
|
}
|
|
1918
2459
|
function useFieldValue(form, path, uncontrolled) {
|
|
1919
2460
|
const snapshotRef = React.useRef({
|
|
@@ -1948,7 +2489,11 @@
|
|
|
1948
2489
|
disabled,
|
|
1949
2490
|
uncontrolled,
|
|
1950
2491
|
asyncAlways,
|
|
1951
|
-
mode: modeOption
|
|
2492
|
+
mode: modeOption,
|
|
2493
|
+
eventToValue,
|
|
2494
|
+
valueAsNumber,
|
|
2495
|
+
valueAsDate,
|
|
2496
|
+
type
|
|
1952
2497
|
}, Context) {
|
|
1953
2498
|
const contextForm = React.useContext(Context);
|
|
1954
2499
|
const form = f1 || contextForm;
|
|
@@ -1966,22 +2511,28 @@
|
|
|
1966
2511
|
emitChangeByPath(form, path);
|
|
1967
2512
|
});
|
|
1968
2513
|
const restRules = rules ? { ...rules, required: void 0 } : void 0;
|
|
1969
|
-
|
|
2514
|
+
const validateOption = validate;
|
|
2515
|
+
const validateWrapped = validateOption && hasStandardProps(validateOption) ? schemaToFieldValidator(validateOption) : validateOption;
|
|
2516
|
+
useValidate(combineRulesAndValidate(restRules, validateWrapped), path, form, {
|
|
1970
2517
|
debounce: validateDebounce,
|
|
1971
2518
|
validateOnMount,
|
|
1972
2519
|
asyncAlways: asyncAlways ?? form.asyncAlways,
|
|
1973
2520
|
sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0
|
|
1974
2521
|
});
|
|
1975
|
-
const
|
|
1976
|
-
const errors = useDelayedErrors(liveErrors, delayError);
|
|
2522
|
+
const errors = useDelayedErrors(form, path, delayError);
|
|
1977
2523
|
const errorObject = errors[0];
|
|
1978
2524
|
const error = errorObject?.message;
|
|
1979
2525
|
const value = useFieldValue(form, path, !!uncontrolled);
|
|
1980
2526
|
const isDirty = useWatchCore(
|
|
1981
2527
|
React.useCallback(
|
|
1982
2528
|
(invalidate) => uncontrolled ? () => {
|
|
1983
|
-
} : onPathEvent(
|
|
1984
|
-
|
|
2529
|
+
} : onPathEvent(
|
|
2530
|
+
form.emitter,
|
|
2531
|
+
"change",
|
|
2532
|
+
create$1(JSON.parse(path.key)),
|
|
2533
|
+
"leaf",
|
|
2534
|
+
invalidate
|
|
2535
|
+
),
|
|
1985
2536
|
[form.emitter, path.key, uncontrolled]
|
|
1986
2537
|
),
|
|
1987
2538
|
() => isFieldDirtyByPath(form, path)
|
|
@@ -1993,20 +2544,46 @@
|
|
|
1993
2544
|
),
|
|
1994
2545
|
() => form.validating.has(path.key)
|
|
1995
2546
|
);
|
|
1996
|
-
const
|
|
2547
|
+
const mergedDisabled = useWatchCore(
|
|
2548
|
+
React.useCallback(
|
|
2549
|
+
(invalidate) => onPathEvent(
|
|
2550
|
+
form.emitter,
|
|
2551
|
+
"disabled",
|
|
2552
|
+
create$1(JSON.parse(path.key)),
|
|
2553
|
+
"branch",
|
|
2554
|
+
invalidate
|
|
2555
|
+
),
|
|
2556
|
+
[form.emitter, path.key]
|
|
2557
|
+
),
|
|
2558
|
+
() => form.disabled || disabled === true || disabled !== false && hasDisabledAncestor(form, path)
|
|
2559
|
+
);
|
|
2560
|
+
const disabledTokenRef = React.useRef(null);
|
|
2561
|
+
React.useEffect(() => {
|
|
2562
|
+
const spath = create$1(JSON.parse(path.key));
|
|
2563
|
+
const registration = registerFieldDisabled(form, spath, disabled);
|
|
2564
|
+
if (registration) disabledTokenRef.current = registration.token;
|
|
2565
|
+
return () => {
|
|
2566
|
+
if (disabledTokenRef.current !== null) {
|
|
2567
|
+
unregisterFieldDisabled(form, spath, disabledTokenRef.current);
|
|
2568
|
+
disabledTokenRef.current = null;
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
}, [form, path.key, disabled]);
|
|
1997
2572
|
const onChange = useStageFn((v) => userChangeByPath(form, path, v));
|
|
1998
2573
|
const onBlur = useStageFn(() => userBlur(form, path));
|
|
1999
2574
|
React.useEffect(() => {
|
|
2000
|
-
const
|
|
2001
|
-
|
|
2575
|
+
const spath = create$1(JSON.parse(path.key));
|
|
2576
|
+
const { token, displaced } = registerFieldMode(form, spath, modeOption);
|
|
2577
|
+
return () => unregisterFieldMode(form, spath, token);
|
|
2002
2578
|
}, [form, path.key, modeOption]);
|
|
2003
2579
|
const depsKey = validateDeps?.length ? validateDeps.join("\n") : void 0;
|
|
2580
|
+
const validateDepsRef = useStage(validateDeps);
|
|
2004
2581
|
React.useEffect(() => {
|
|
2005
2582
|
if (!depsKey) return;
|
|
2006
|
-
const depKeys =
|
|
2583
|
+
const depKeys = validateDepsRef.current.map((dep) => create$1(dep).key);
|
|
2007
2584
|
registerFieldValidateDeps(form, path.key, depKeys);
|
|
2008
2585
|
return () => unregisterFieldValidateDeps(form, path.key, depKeys);
|
|
2009
|
-
}, [form, path.key, depsKey]);
|
|
2586
|
+
}, [form, path.key, depsKey, validateDepsRef]);
|
|
2010
2587
|
const elementRef = React.useRef(null);
|
|
2011
2588
|
const focusRef = React.useCallback((el) => {
|
|
2012
2589
|
elementRef.current = el;
|
|
@@ -2028,7 +2605,7 @@
|
|
|
2028
2605
|
[form, path.key]
|
|
2029
2606
|
);
|
|
2030
2607
|
React.useEffect(() => {
|
|
2031
|
-
|
|
2608
|
+
const spath = create$1(JSON.parse(path.key));
|
|
2032
2609
|
let entry = uncontrolledSyncRegistry.get(form);
|
|
2033
2610
|
if (!entry) {
|
|
2034
2611
|
const cells = /* @__PURE__ */ new Map();
|
|
@@ -2045,7 +2622,7 @@
|
|
|
2045
2622
|
entry = { cells, off };
|
|
2046
2623
|
uncontrolledSyncRegistry.set(form, entry);
|
|
2047
2624
|
}
|
|
2048
|
-
entry.cells.set(path.key, () => ({ el: elementRef.current, path }));
|
|
2625
|
+
entry.cells.set(path.key, () => ({ el: elementRef.current, path: spath }));
|
|
2049
2626
|
return () => {
|
|
2050
2627
|
entry.cells.delete(path.key);
|
|
2051
2628
|
if (entry.cells.size === 0) {
|
|
@@ -2065,6 +2642,16 @@
|
|
|
2065
2642
|
if (snapshot) restoreRemovedField(form, path, snapshot);
|
|
2066
2643
|
});
|
|
2067
2644
|
useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
|
|
2645
|
+
const extract = eventToValue ?? ((e) => extractEventValue(e, { valueAsNumber, valueAsDate }));
|
|
2646
|
+
const inputProps = {
|
|
2647
|
+
name: path.key,
|
|
2648
|
+
ref: focusRef,
|
|
2649
|
+
onChange: (e) => onChange(extract(e)),
|
|
2650
|
+
onBlur,
|
|
2651
|
+
disabled: mergedDisabled,
|
|
2652
|
+
...type === "checkbox" ? { checked: !!value } : type === "file" ? {} : uncontrolled ? { defaultValue: value } : { value: value ?? "" },
|
|
2653
|
+
...error ? { "aria-invalid": true, "aria-describedby": errorIdFromKey(path.key) } : {}
|
|
2654
|
+
};
|
|
2068
2655
|
return {
|
|
2069
2656
|
form,
|
|
2070
2657
|
value,
|
|
@@ -2076,8 +2663,9 @@
|
|
|
2076
2663
|
onChange,
|
|
2077
2664
|
onBlur,
|
|
2078
2665
|
name: path.key,
|
|
2079
|
-
disabled:
|
|
2080
|
-
focusRef
|
|
2666
|
+
disabled: mergedDisabled,
|
|
2667
|
+
focusRef,
|
|
2668
|
+
inputProps
|
|
2081
2669
|
};
|
|
2082
2670
|
}
|
|
2083
2671
|
function useField(options) {
|
|
@@ -2117,12 +2705,6 @@
|
|
|
2117
2705
|
() => getValueByPath(form, path) || [],
|
|
2118
2706
|
[form, path]
|
|
2119
2707
|
);
|
|
2120
|
-
const setArray = React.useCallback(
|
|
2121
|
-
(arr) => {
|
|
2122
|
-
setValueByPath(form, path, arr);
|
|
2123
|
-
},
|
|
2124
|
-
[form, path]
|
|
2125
|
-
);
|
|
2126
2708
|
const computeFields = React.useCallback(() => {
|
|
2127
2709
|
const arr = getArray();
|
|
2128
2710
|
while (idsRef.current.length < arr.length) {
|
|
@@ -2174,56 +2756,39 @@
|
|
|
2174
2756
|
}
|
|
2175
2757
|
);
|
|
2176
2758
|
const append = useStageFn((value) => {
|
|
2177
|
-
const arr = getArray();
|
|
2178
2759
|
idsRef.current.push(generateId(form));
|
|
2179
|
-
|
|
2760
|
+
appendValueByPath(form, path, value);
|
|
2180
2761
|
});
|
|
2181
2762
|
const prepend = useStageFn((value) => {
|
|
2182
|
-
const arr = getArray();
|
|
2183
2763
|
idsRef.current.unshift(generateId(form));
|
|
2184
|
-
|
|
2764
|
+
prependValueByPath(form, path, value);
|
|
2185
2765
|
});
|
|
2186
2766
|
const insert = useStageFn((index, value) => {
|
|
2187
|
-
|
|
2767
|
+
if (!insertValueByPath(form, path, index, value)) return;
|
|
2188
2768
|
idsRef.current.splice(index, 0, generateId(form));
|
|
2189
|
-
const newArr = [...arr.slice(0, index), value, ...arr.slice(index)];
|
|
2190
|
-
setArray(newArr);
|
|
2191
2769
|
});
|
|
2192
|
-
const remove = useStageFn((
|
|
2193
|
-
const
|
|
2194
|
-
idsRef.current.splice(index, 1);
|
|
2195
|
-
const newArr = arr.filter((_, i) => i !== index);
|
|
2196
|
-
setArray(newArr);
|
|
2770
|
+
const remove = useStageFn((indices) => {
|
|
2771
|
+
const dropped = removeValueByPath(form, path, indices);
|
|
2772
|
+
for (const index of dropped) idsRef.current.splice(index, 1);
|
|
2197
2773
|
});
|
|
2198
2774
|
const swap = useStageFn((from, to) => {
|
|
2199
|
-
|
|
2775
|
+
if (!swapValuesByPath(form, path, from, to)) return;
|
|
2200
2776
|
[idsRef.current[from], idsRef.current[to]] = [
|
|
2201
2777
|
idsRef.current[to],
|
|
2202
2778
|
idsRef.current[from]
|
|
2203
2779
|
];
|
|
2204
|
-
const newArr = [...arr];
|
|
2205
|
-
[newArr[from], newArr[to]] = [newArr[to], newArr[from]];
|
|
2206
|
-
setArray(newArr);
|
|
2207
2780
|
});
|
|
2208
2781
|
const move = useStageFn((from, to) => {
|
|
2209
|
-
|
|
2782
|
+
if (!moveValueByPath(form, path, from, to)) return;
|
|
2210
2783
|
const [id] = idsRef.current.splice(from, 1);
|
|
2211
2784
|
idsRef.current.splice(to, 0, id);
|
|
2212
|
-
const newArr = [...arr];
|
|
2213
|
-
const [item] = newArr.splice(from, 1);
|
|
2214
|
-
newArr.splice(to, 0, item);
|
|
2215
|
-
setArray(newArr);
|
|
2216
2785
|
});
|
|
2217
2786
|
const replace = useStageFn((values) => {
|
|
2218
2787
|
idsRef.current = values.map(() => generateId(form));
|
|
2219
|
-
|
|
2788
|
+
replaceValuesByPath(form, path, values);
|
|
2220
2789
|
});
|
|
2221
2790
|
const update = useStageFn((index, value) => {
|
|
2222
|
-
|
|
2223
|
-
if (index < 0 || index >= arr.length) return;
|
|
2224
|
-
const newArr = [...arr];
|
|
2225
|
-
newArr[index] = value;
|
|
2226
|
-
setArray(newArr);
|
|
2791
|
+
updateValueByPath(form, path, index, value);
|
|
2227
2792
|
});
|
|
2228
2793
|
return { fields, append, prepend, insert, remove, swap, move, replace, update };
|
|
2229
2794
|
}
|
|
@@ -2309,7 +2874,10 @@
|
|
|
2309
2874
|
return useFieldCore(options, Context);
|
|
2310
2875
|
}
|
|
2311
2876
|
function useFieldArray(options) {
|
|
2312
|
-
return useFieldArrayCore(
|
|
2877
|
+
return useFieldArrayCore(
|
|
2878
|
+
options,
|
|
2879
|
+
Context
|
|
2880
|
+
);
|
|
2313
2881
|
}
|
|
2314
2882
|
function useFieldArrayItem(options) {
|
|
2315
2883
|
return useFieldArrayItemCore(options, Context);
|
|
@@ -2333,23 +2901,59 @@
|
|
|
2333
2901
|
|
|
2334
2902
|
function useTransform(form, name, options = {}) {
|
|
2335
2903
|
const path = usePath(name);
|
|
2336
|
-
const { toDisplay, fromDisplay } = options;
|
|
2904
|
+
const { toDisplay, fromDisplay, asyncDebounceMs } = options;
|
|
2337
2905
|
const subscribeFactory = React.useCallback(
|
|
2338
|
-
(invalidate) => onPathEvent(
|
|
2339
|
-
|
|
2906
|
+
(invalidate) => onPathEvent(
|
|
2907
|
+
form.emitter,
|
|
2908
|
+
"change",
|
|
2909
|
+
create$1(JSON.parse(path.key)),
|
|
2910
|
+
"leaf",
|
|
2911
|
+
invalidate
|
|
2912
|
+
),
|
|
2340
2913
|
[form.emitter, path.key]
|
|
2341
2914
|
);
|
|
2342
2915
|
const raw = useWatchCore(subscribeFactory, () => getValueByPath(form, path));
|
|
2343
2916
|
const value = toDisplay ? toDisplay(raw) : raw;
|
|
2917
|
+
const timerRef = React.useRef(null);
|
|
2918
|
+
const seqRef = React.useRef(0);
|
|
2919
|
+
const fromDisplayRef = React.useRef(fromDisplay);
|
|
2920
|
+
fromDisplayRef.current = fromDisplay;
|
|
2921
|
+
const debounceRef = React.useRef(asyncDebounceMs ?? 0);
|
|
2922
|
+
debounceRef.current = asyncDebounceMs ?? 0;
|
|
2923
|
+
React.useEffect(
|
|
2924
|
+
() => () => {
|
|
2925
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2926
|
+
},
|
|
2927
|
+
[]
|
|
2928
|
+
);
|
|
2344
2929
|
const onChange = React.useCallback(
|
|
2345
2930
|
(display) => {
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2931
|
+
const run = () => {
|
|
2932
|
+
const seq = ++seqRef.current;
|
|
2933
|
+
const transform = fromDisplayRef.current;
|
|
2934
|
+
const commit = (next) => userChangeByPath(form, path, next);
|
|
2935
|
+
if (!transform) {
|
|
2936
|
+
commit(display);
|
|
2937
|
+
return;
|
|
2938
|
+
}
|
|
2939
|
+
const result = transform(display);
|
|
2940
|
+
if (isPromise(result)) {
|
|
2941
|
+
result.then((next) => {
|
|
2942
|
+
if (seqRef.current === seq) commit(next);
|
|
2943
|
+
});
|
|
2944
|
+
} else if (seqRef.current === seq) {
|
|
2945
|
+
commit(result);
|
|
2946
|
+
}
|
|
2947
|
+
};
|
|
2948
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2949
|
+
timerRef.current = null;
|
|
2950
|
+
if (debounceRef.current > 0) {
|
|
2951
|
+
timerRef.current = setTimeout(run, debounceRef.current);
|
|
2952
|
+
} else {
|
|
2953
|
+
run();
|
|
2954
|
+
}
|
|
2351
2955
|
},
|
|
2352
|
-
[form, path
|
|
2956
|
+
[form, path]
|
|
2353
2957
|
);
|
|
2354
2958
|
return { value, onChange };
|
|
2355
2959
|
}
|
|
@@ -2403,6 +3007,7 @@
|
|
|
2403
3007
|
onInvalidSubmit,
|
|
2404
3008
|
action,
|
|
2405
3009
|
shouldFocusError,
|
|
3010
|
+
shouldUseNativeValidation,
|
|
2406
3011
|
...props
|
|
2407
3012
|
}) {
|
|
2408
3013
|
const f2 = useForm({
|
|
@@ -2411,7 +3016,8 @@
|
|
|
2411
3016
|
shouldUnregister,
|
|
2412
3017
|
validateOnMount,
|
|
2413
3018
|
disabled,
|
|
2414
|
-
asyncAlways
|
|
3019
|
+
asyncAlways,
|
|
3020
|
+
shouldUseNativeValidation
|
|
2415
3021
|
});
|
|
2416
3022
|
const form = f1 || f2;
|
|
2417
3023
|
React__namespace.useEffect(() => {
|
|
@@ -2422,10 +3028,12 @@
|
|
|
2422
3028
|
onValidSubmit,
|
|
2423
3029
|
onInvalidSubmit,
|
|
2424
3030
|
shouldFocusError,
|
|
2425
|
-
|
|
3031
|
+
shouldUseNativeValidation,
|
|
3032
|
+
onAction: typeof action === "function" ? (values2) => action(formDataFromValues(values2)) : void 0
|
|
2426
3033
|
});
|
|
2427
3034
|
const { Provider } = context ?? FormContext;
|
|
2428
|
-
|
|
3035
|
+
const nativeAction = typeof action === "string" ? action : void 0;
|
|
3036
|
+
return /* @__PURE__ */ React__namespace.createElement(Provider, { value: form }, /* @__PURE__ */ React__namespace.createElement("form", { ...props, action: nativeAction, noValidate: true, onSubmit: submit }));
|
|
2429
3037
|
}
|
|
2430
3038
|
|
|
2431
3039
|
function FormField({ children, ...options }) {
|
|
@@ -2440,19 +3048,12 @@
|
|
|
2440
3048
|
ref.current = value;
|
|
2441
3049
|
}
|
|
2442
3050
|
}
|
|
2443
|
-
function errorIdFromKey(key) {
|
|
2444
|
-
const id = key.replace(/["'[\],\s]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2445
|
-
return id || "field";
|
|
2446
|
-
}
|
|
2447
3051
|
function ariaProps(error, fieldKey, props) {
|
|
2448
3052
|
return {
|
|
2449
3053
|
"aria-invalid": error ? true : props["aria-invalid"],
|
|
2450
3054
|
"aria-describedby": error ? [props["aria-describedby"], errorIdFromKey(fieldKey)].filter(Boolean).join(" ") : props["aria-describedby"]
|
|
2451
3055
|
};
|
|
2452
3056
|
}
|
|
2453
|
-
function fieldErrorId(name) {
|
|
2454
|
-
return errorIdFromKey(create$1(name).key);
|
|
2455
|
-
}
|
|
2456
3057
|
const Field = React__namespace.forwardRef(
|
|
2457
3058
|
({
|
|
2458
3059
|
validate,
|
|
@@ -2479,6 +3080,10 @@
|
|
|
2479
3080
|
}, ref) => {
|
|
2480
3081
|
const innerRef = React__namespace.useRef(null);
|
|
2481
3082
|
const [nativeInvalidCount, setNativeInvalidCount] = React__namespace.useState(0);
|
|
3083
|
+
const contextForm = React__namespace.useContext(FormContext);
|
|
3084
|
+
const resolvedForm = formProp ?? contextForm;
|
|
3085
|
+
const validateOption = validate;
|
|
3086
|
+
const validateWrapped = validateOption && hasStandardProps(validateOption) ? schemaToFieldValidator(validateOption) : validateOption;
|
|
2482
3087
|
const {
|
|
2483
3088
|
value,
|
|
2484
3089
|
onChange,
|
|
@@ -2503,15 +3108,17 @@
|
|
|
2503
3108
|
// uncontrolled path so no `value` prop ever reaches the element.
|
|
2504
3109
|
uncontrolled: uncontrolled || props.type === "file",
|
|
2505
3110
|
validate: (...params) => {
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
el.
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
3111
|
+
if (resolvedForm?.shouldUseNativeValidation !== false) {
|
|
3112
|
+
const el = innerRef.current;
|
|
3113
|
+
if (el && typeof el.checkValidity === "function") {
|
|
3114
|
+
el.setCustomValidity("");
|
|
3115
|
+
if (el.checkValidity() === false) {
|
|
3116
|
+
setNativeInvalidCount((count) => count + 1);
|
|
3117
|
+
return void 0;
|
|
3118
|
+
}
|
|
2512
3119
|
}
|
|
2513
3120
|
}
|
|
2514
|
-
if (
|
|
3121
|
+
if (validateWrapped) return validateWrapped(...params);
|
|
2515
3122
|
}
|
|
2516
3123
|
});
|
|
2517
3124
|
const mergedRef = React__namespace.useCallback(
|
|
@@ -2537,7 +3144,7 @@
|
|
|
2537
3144
|
if (nativeInvalidCount > 0) innerRef.current?.reportValidity();
|
|
2538
3145
|
}, [nativeInvalidCount]);
|
|
2539
3146
|
const isFile = props.type === "file";
|
|
2540
|
-
const toValue = eventToValue ?? (
|
|
3147
|
+
const toValue = eventToValue ?? ((e) => extractEventValue(e, { valueAsNumber, valueAsDate }));
|
|
2541
3148
|
const valueProps = valueToProps ? valueToProps(value) : isFile ? {} : uncontrolled ? { defaultValue: value } : { value };
|
|
2542
3149
|
const errorId = errorIdFromKey(fieldKey);
|
|
2543
3150
|
const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
|
|
@@ -2689,18 +3296,25 @@
|
|
|
2689
3296
|
exports.FormProvider = FormProvider;
|
|
2690
3297
|
exports.Select = Select;
|
|
2691
3298
|
exports.VALIDATION_OUTCOME = VALIDATION_OUTCOME;
|
|
3299
|
+
exports.appendValue = appendValue;
|
|
3300
|
+
exports.appendValueByPath = appendValueByPath;
|
|
2692
3301
|
exports.changeValue = changeValue;
|
|
2693
3302
|
exports.changeValueByPath = changeValueByPath;
|
|
2694
3303
|
exports.clearErrors = clearErrors;
|
|
3304
|
+
exports.clearServerErrors = clearServerErrors;
|
|
2695
3305
|
exports.createForm = create;
|
|
2696
3306
|
exports.createFormContext = createFormContext;
|
|
3307
|
+
exports.dottedKeyToFieldPath = dottedKeyToFieldPath;
|
|
2697
3308
|
exports.emitChangeByPath = emitChangeByPath;
|
|
2698
3309
|
exports.ensureValidate = ensureValidate;
|
|
2699
3310
|
exports.fieldErrorId = fieldErrorId;
|
|
3311
|
+
exports.fieldPathToDottedKey = fieldPathToDottedKey;
|
|
2700
3312
|
exports.getDirtyFields = getDirtyFields;
|
|
2701
3313
|
exports.getError = getError;
|
|
2702
3314
|
exports.getErrorByPath = getErrorByPath;
|
|
2703
3315
|
exports.getErrors = getErrors;
|
|
3316
|
+
exports.getErrorsRecord = getErrorsRecord;
|
|
3317
|
+
exports.getErrorsTree = getErrorsTree;
|
|
2704
3318
|
exports.getFieldErrors = getFieldErrors;
|
|
2705
3319
|
exports.getFieldErrorsByPath = getFieldErrorsByPath;
|
|
2706
3320
|
exports.getFieldState = getFieldState;
|
|
@@ -2714,14 +3328,25 @@
|
|
|
2714
3328
|
exports.hasTouched = hasTouched;
|
|
2715
3329
|
exports.hasTouchedByPath = hasTouchedByPath;
|
|
2716
3330
|
exports.incrementSubmitCount = incrementSubmitCount;
|
|
3331
|
+
exports.insertValue = insertValue;
|
|
3332
|
+
exports.insertValueByPath = insertValueByPath;
|
|
2717
3333
|
exports.isDirty = isDirty;
|
|
2718
3334
|
exports.isFieldDirtyByPath = isFieldDirtyByPath;
|
|
2719
3335
|
exports.isTouched = isTouched;
|
|
3336
|
+
exports.moveValue = moveValue;
|
|
3337
|
+
exports.moveValueByPath = moveValueByPath;
|
|
3338
|
+
exports.prependValue = prependValue;
|
|
3339
|
+
exports.prependValueByPath = prependValueByPath;
|
|
3340
|
+
exports.registerField = registerField;
|
|
2720
3341
|
exports.registerFieldMode = registerFieldMode;
|
|
2721
3342
|
exports.registerFieldValidateDeps = registerFieldValidateDeps;
|
|
2722
3343
|
exports.registerValidatorByPath = registerValidatorByPath;
|
|
2723
3344
|
exports.removeField = removeField;
|
|
2724
3345
|
exports.removeFieldByPath = removeFieldByPath;
|
|
3346
|
+
exports.removeValue = removeValue;
|
|
3347
|
+
exports.removeValueByPath = removeValueByPath;
|
|
3348
|
+
exports.replaceValues = replaceValues;
|
|
3349
|
+
exports.replaceValuesByPath = replaceValuesByPath;
|
|
2725
3350
|
exports.reset = reset;
|
|
2726
3351
|
exports.resetField = resetField;
|
|
2727
3352
|
exports.revalidateDependentsOnChange = revalidateDependentsOnChange;
|
|
@@ -2743,15 +3368,21 @@
|
|
|
2743
3368
|
exports.setValue = setValue;
|
|
2744
3369
|
exports.setValueByPath = setValueByPath;
|
|
2745
3370
|
exports.subscribe = subscribe;
|
|
3371
|
+
exports.swapValues = swapValues;
|
|
3372
|
+
exports.swapValuesByPath = swapValuesByPath;
|
|
2746
3373
|
exports.trigger = trigger;
|
|
2747
3374
|
exports.unregisterFieldMode = unregisterFieldMode;
|
|
2748
3375
|
exports.unregisterFieldValidateDeps = unregisterFieldValidateDeps;
|
|
2749
3376
|
exports.unsetValidatingByPath = unsetValidatingByPath;
|
|
3377
|
+
exports.updateValue = updateValue;
|
|
3378
|
+
exports.updateValueByPath = updateValueByPath;
|
|
2750
3379
|
exports.useCanSubmit = useCanSubmit;
|
|
2751
3380
|
exports.useCheckboxGroupContext = useCheckboxGroupContext;
|
|
2752
3381
|
exports.useDirtyFields = useDirtyFields;
|
|
2753
3382
|
exports.useError = useError;
|
|
2754
3383
|
exports.useErrorByPath = useErrorByPath;
|
|
3384
|
+
exports.useErrors = useErrors;
|
|
3385
|
+
exports.useErrorsTree = useErrorsTree;
|
|
2755
3386
|
exports.useField = useField;
|
|
2756
3387
|
exports.useFieldArray = useFieldArray;
|
|
2757
3388
|
exports.useFieldArrayItem = useFieldArrayItem;
|
|
@@ -2772,6 +3403,7 @@
|
|
|
2772
3403
|
exports.useIsValid = useIsValid;
|
|
2773
3404
|
exports.useIsValidating = useIsValidating;
|
|
2774
3405
|
exports.useStatus = useStatus;
|
|
3406
|
+
exports.useStore = useStore;
|
|
2775
3407
|
exports.useSubmitCount = useSubmitCount;
|
|
2776
3408
|
exports.useTouched = useTouched;
|
|
2777
3409
|
exports.useTouchedByPath = useTouchedByPath;
|
|
@@ -2779,11 +3411,13 @@
|
|
|
2779
3411
|
exports.useTransform = useTransform;
|
|
2780
3412
|
exports.useValue = useValue;
|
|
2781
3413
|
exports.useValueByPath = useValueByPath;
|
|
3414
|
+
exports.useValues = useValues;
|
|
2782
3415
|
exports.useWatch = useWatch;
|
|
2783
3416
|
exports.useWatchCore = useWatchCore;
|
|
2784
3417
|
exports.userBlur = userBlur;
|
|
2785
3418
|
exports.userChangeByPath = userChangeByPath;
|
|
2786
3419
|
exports.validate = validate;
|
|
3420
|
+
exports.watch = watch;
|
|
2787
3421
|
|
|
2788
3422
|
}));
|
|
2789
3423
|
//# sourceMappingURL=index.umd.js.map
|