react-f0rm 1.2.0 → 1.3.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 +107 -24
- package/dist/devtools/index.cjs.js +1 -1
- package/dist/devtools/index.cjs.js.map +1 -1
- package/dist/devtools/index.mjs +1 -1
- package/dist/devtools/index.mjs.map +1 -1
- package/dist/errors-BKrUdpfI.cjs.js +2 -0
- package/dist/errors-BKrUdpfI.cjs.js.map +1 -0
- package/dist/errors-CrQBddrJ.mjs +2 -0
- package/dist/errors-CrQBddrJ.mjs.map +1 -0
- package/dist/{form-CvmWHUrd.d.ts → form-CeKSBs31.d.ts} +68 -5
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +344 -49
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +379 -283
- 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.mjs +1 -1
- package/dist/persist.mjs.map +1 -1
- package/dist/resolvers/standard-schema.cjs.js +1 -1
- package/dist/resolvers/standard-schema.mjs +1 -1
- package/dist/resolvers/yup.cjs.js +1 -1
- package/dist/resolvers/yup.d.ts +1 -1
- package/dist/resolvers/yup.mjs +1 -1
- package/dist/resolvers/zod.cjs.js +1 -1
- package/dist/resolvers/zod.d.ts +1 -1
- package/dist/resolvers/zod.mjs +1 -1
- package/dist/server/index.cjs.js +1 -1
- package/dist/server/index.cjs.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/{validate-B1Gdjeaq.mjs → validate-CNtuUhmk.mjs} +2 -2
- package/dist/validate-CNtuUhmk.mjs.map +1 -0
- package/dist/{validate-DAfz8Nbb.cjs.js → validate-Cl4ksNFu.cjs.js} +2 -2
- package/dist/validate-Cl4ksNFu.cjs.js.map +1 -0
- package/dist/{validate-CUmNZqg6.d.ts → validate-nksgv1pR.d.ts} +37 -3
- package/dist/values-Cu6awQOJ.cjs.js +2 -0
- package/dist/values-Cu6awQOJ.cjs.js.map +1 -0
- package/dist/values-DRY-a32G.mjs +2 -0
- package/dist/values-DRY-a32G.mjs.map +1 -0
- package/package.json +20 -9
- package/dist/errors-CxSjrWJO.cjs.js +0 -2
- package/dist/errors-CxSjrWJO.cjs.js.map +0 -1
- package/dist/errors-CzWtwjO0.mjs +0 -2
- package/dist/errors-CzWtwjO0.mjs.map +0 -1
- package/dist/validate-B1Gdjeaq.mjs.map +0 -1
- package/dist/validate-DAfz8Nbb.cjs.js.map +0 -1
- package/dist/values-B1IV-6V4.mjs +0 -2
- package/dist/values-B1IV-6V4.mjs.map +0 -1
- package/dist/values-CDNAYEOB.cjs.js +0 -2
- package/dist/values-CDNAYEOB.cjs.js.map +0 -1
package/dist/index.umd.js
CHANGED
|
@@ -433,14 +433,16 @@
|
|
|
433
433
|
function getFirstError({ errors }) {
|
|
434
434
|
return errors.values().next().value?.[0]?.message;
|
|
435
435
|
}
|
|
436
|
-
function setError(form, name, error) {
|
|
437
|
-
setErrorByPath(form, create$1(name), error);
|
|
436
|
+
function setError(form, name, error, options) {
|
|
437
|
+
setErrorByPath(form, create$1(name), error, options);
|
|
438
438
|
}
|
|
439
|
-
function setErrorByPath(
|
|
439
|
+
function setErrorByPath(form, path, error, options) {
|
|
440
|
+
const { emitter, errors } = form;
|
|
440
441
|
const list = normalizeErrors(error);
|
|
441
442
|
if (list) errors.set(path.key, list);
|
|
442
443
|
else errors.delete(path.key);
|
|
443
444
|
emit(emitter, "errors", path);
|
|
445
|
+
if (options?.shouldFocus) emit(emitter, "focusError", path.key);
|
|
444
446
|
}
|
|
445
447
|
function normalizeErrors(error) {
|
|
446
448
|
if (typeof error === "string") {
|
|
@@ -486,6 +488,48 @@
|
|
|
486
488
|
return errors.size > 0;
|
|
487
489
|
}
|
|
488
490
|
|
|
491
|
+
function isFieldDirtyByPath(form, path) {
|
|
492
|
+
const live = form.values.get(path.key);
|
|
493
|
+
return form.values.has(path.key) && getDirtyBaseline(form, path.key, path.value) !== live;
|
|
494
|
+
}
|
|
495
|
+
function isDirty(form) {
|
|
496
|
+
let dirty = false;
|
|
497
|
+
forEachDirtyField(form, () => {
|
|
498
|
+
dirty = true;
|
|
499
|
+
});
|
|
500
|
+
return dirty;
|
|
501
|
+
}
|
|
502
|
+
function forEachDirtyField(form, fn) {
|
|
503
|
+
for (const [key, value] of form.values) {
|
|
504
|
+
const path = JSON.parse(key);
|
|
505
|
+
if (getDirtyBaseline(form, key, path) !== value) fn(path.join("."));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function computeDirtyFields(form) {
|
|
509
|
+
const dirtyFields = {};
|
|
510
|
+
forEachDirtyField(form, (key) => {
|
|
511
|
+
dirtyFields[key] = true;
|
|
512
|
+
});
|
|
513
|
+
return dirtyFields;
|
|
514
|
+
}
|
|
515
|
+
function sameDirtyKeys(a, b) {
|
|
516
|
+
const aKeys = Object.keys(a);
|
|
517
|
+
if (aKeys.length !== Object.keys(b).length) return false;
|
|
518
|
+
return aKeys.every((key) => b[key] === true);
|
|
519
|
+
}
|
|
520
|
+
function getDirtyFields(form) {
|
|
521
|
+
let cache = dirtyFieldsCaches.get(form);
|
|
522
|
+
if (!cache) {
|
|
523
|
+
cache = { version: 0, result: computeDirtyFields(form) };
|
|
524
|
+
dirtyFieldsCaches.set(form, cache);
|
|
525
|
+
} else if (cache.version > 0) {
|
|
526
|
+
const result = computeDirtyFields(form);
|
|
527
|
+
if (!sameDirtyKeys(cache.result, result)) cache.result = result;
|
|
528
|
+
cache.version = 0;
|
|
529
|
+
}
|
|
530
|
+
return cache.result;
|
|
531
|
+
}
|
|
532
|
+
|
|
489
533
|
function setTouched(form, name) {
|
|
490
534
|
setTouchedByPath(form, create$1(name));
|
|
491
535
|
}
|
|
@@ -553,11 +597,12 @@
|
|
|
553
597
|
}
|
|
554
598
|
function setValueByPath(form, path, value, options) {
|
|
555
599
|
const { emitter, values, deleted } = form;
|
|
556
|
-
|
|
600
|
+
const next = typeof value === "function" ? value(getValueByPath(form, path)) : value;
|
|
601
|
+
values.set(path.key, next);
|
|
557
602
|
pruneDescendantKeys(values, path);
|
|
558
603
|
reviveBranch(deleted, path);
|
|
559
604
|
pruneDirtyBaselines(form, path);
|
|
560
|
-
if (options?.shouldDirty === false) setDirtyBaseline(form, path,
|
|
605
|
+
if (options?.shouldDirty === false) setDirtyBaseline(form, path, next);
|
|
561
606
|
bumpDirtyVersion(form);
|
|
562
607
|
bumpValuesVersion(form);
|
|
563
608
|
if (options?.shouldTouch) setTouchedByPath(form, path);
|
|
@@ -578,15 +623,14 @@
|
|
|
578
623
|
}
|
|
579
624
|
function getFieldState(form, name) {
|
|
580
625
|
const path = create$1(name);
|
|
581
|
-
const {
|
|
582
|
-
const live = values.get(path.key);
|
|
626
|
+
const { touched, validating } = form;
|
|
583
627
|
return {
|
|
584
628
|
value: getValueByPath(form, path),
|
|
585
629
|
error: getErrorByPath(form, path),
|
|
586
630
|
errors: getFieldErrorsByPath(form, path),
|
|
587
|
-
//
|
|
631
|
+
// The shared per-field rule (committed baselines included): the field
|
|
588
632
|
// is dirty while its live value differs from its effective baseline.
|
|
589
|
-
isDirty:
|
|
633
|
+
isDirty: isFieldDirtyByPath(form, path),
|
|
590
634
|
isTouched: touched.has(path.key),
|
|
591
635
|
isValidating: validating.has(path.key)
|
|
592
636
|
};
|
|
@@ -691,7 +735,8 @@
|
|
|
691
735
|
validating.clear();
|
|
692
736
|
if (!options?.keepIsSubmitting) form.isSubmitting = false;
|
|
693
737
|
if (!options?.keepSubmitCount) form.submitCount = 0;
|
|
694
|
-
if (!options?.keepIsSubmitted) form.
|
|
738
|
+
if (!options?.keepIsSubmitted) form.isSubmitted = false;
|
|
739
|
+
if (!options?.keepIsSubmitSuccessful) form.isSubmitSuccessful = void 0;
|
|
695
740
|
bumpDirtyVersion(form);
|
|
696
741
|
bumpValuesVersion(form);
|
|
697
742
|
for (const { segments, value } of keptValues) {
|
|
@@ -730,44 +775,6 @@
|
|
|
730
775
|
bumpValuesVersion(form);
|
|
731
776
|
}
|
|
732
777
|
|
|
733
|
-
function isDirty(form) {
|
|
734
|
-
let dirty = false;
|
|
735
|
-
forEachDirtyField(form, () => {
|
|
736
|
-
dirty = true;
|
|
737
|
-
});
|
|
738
|
-
return dirty;
|
|
739
|
-
}
|
|
740
|
-
function forEachDirtyField(form, fn) {
|
|
741
|
-
for (const [key, value] of form.values) {
|
|
742
|
-
const path = JSON.parse(key);
|
|
743
|
-
if (getDirtyBaseline(form, key, path) !== value) fn(path.join("."));
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
function computeDirtyFields(form) {
|
|
747
|
-
const dirtyFields = {};
|
|
748
|
-
forEachDirtyField(form, (key) => {
|
|
749
|
-
dirtyFields[key] = true;
|
|
750
|
-
});
|
|
751
|
-
return dirtyFields;
|
|
752
|
-
}
|
|
753
|
-
function sameDirtyKeys(a, b) {
|
|
754
|
-
const aKeys = Object.keys(a);
|
|
755
|
-
if (aKeys.length !== Object.keys(b).length) return false;
|
|
756
|
-
return aKeys.every((key) => b[key] === true);
|
|
757
|
-
}
|
|
758
|
-
function getDirtyFields(form) {
|
|
759
|
-
let cache = dirtyFieldsCaches.get(form);
|
|
760
|
-
if (!cache) {
|
|
761
|
-
cache = { version: 0, result: computeDirtyFields(form) };
|
|
762
|
-
dirtyFieldsCaches.set(form, cache);
|
|
763
|
-
} else if (cache.version > 0) {
|
|
764
|
-
const result = computeDirtyFields(form);
|
|
765
|
-
if (!sameDirtyKeys(cache.result, result)) cache.result = result;
|
|
766
|
-
cache.version = 0;
|
|
767
|
-
}
|
|
768
|
-
return cache.result;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
778
|
function unsetValidatingByPath({ emitter, validating }, path) {
|
|
772
779
|
validating.delete(path.key);
|
|
773
780
|
emit(emitter, "validating", path);
|
|
@@ -808,6 +815,25 @@
|
|
|
808
815
|
errorSource = "sync";
|
|
809
816
|
return true;
|
|
810
817
|
};
|
|
818
|
+
const collectSyncErrors = () => {
|
|
819
|
+
const sync = registration.sync();
|
|
820
|
+
if (!sync) return null;
|
|
821
|
+
const errors = sync(getValueByPath(form, path), { form, path });
|
|
822
|
+
if (errors === void 0) return null;
|
|
823
|
+
const list = Array.isArray(errors) ? errors : [errors];
|
|
824
|
+
return list.length ? list : null;
|
|
825
|
+
};
|
|
826
|
+
const land = (result) => {
|
|
827
|
+
if (registration.asyncAlways?.()) {
|
|
828
|
+
const gate = collectSyncErrors();
|
|
829
|
+
const own = result === void 0 ? [] : Array.isArray(result) ? result : [result];
|
|
830
|
+
setErrorByPath(form, path, [...gate ?? [], ...own]);
|
|
831
|
+
errorSource = hasErrors2(result) ? "validator" : gate ? "sync" : null;
|
|
832
|
+
} else {
|
|
833
|
+
setErrorByPath(form, path, result);
|
|
834
|
+
errorSource = hasErrors2(result) ? "validator" : null;
|
|
835
|
+
}
|
|
836
|
+
};
|
|
811
837
|
const supersede = () => {
|
|
812
838
|
if (timer !== null) {
|
|
813
839
|
clearTimeout(timer);
|
|
@@ -837,8 +863,7 @@
|
|
|
837
863
|
throw e;
|
|
838
864
|
}
|
|
839
865
|
if (!isPromise(result)) {
|
|
840
|
-
|
|
841
|
-
errorSource = hasErrors2(result) ? "validator" : null;
|
|
866
|
+
land(result);
|
|
842
867
|
unmark();
|
|
843
868
|
return;
|
|
844
869
|
}
|
|
@@ -846,8 +871,7 @@
|
|
|
846
871
|
result.then(
|
|
847
872
|
(error) => {
|
|
848
873
|
if (lock === round) {
|
|
849
|
-
|
|
850
|
-
errorSource = hasErrors2(error) ? "validator" : null;
|
|
874
|
+
land(error);
|
|
851
875
|
}
|
|
852
876
|
}
|
|
853
877
|
).catch(() => {
|
|
@@ -860,7 +884,7 @@
|
|
|
860
884
|
};
|
|
861
885
|
const run = () => {
|
|
862
886
|
timer = null;
|
|
863
|
-
if (runSync()) {
|
|
887
|
+
if (runSync() && !registration.asyncAlways?.()) {
|
|
864
888
|
supersede();
|
|
865
889
|
unmark();
|
|
866
890
|
return;
|
|
@@ -868,7 +892,7 @@
|
|
|
868
892
|
runValidator();
|
|
869
893
|
};
|
|
870
894
|
const kick = () => {
|
|
871
|
-
if (runSync()) {
|
|
895
|
+
if (runSync() && !registration.asyncAlways?.()) {
|
|
872
896
|
supersede();
|
|
873
897
|
unmark();
|
|
874
898
|
return;
|
|
@@ -1215,6 +1239,10 @@
|
|
|
1215
1239
|
form.disabled = value;
|
|
1216
1240
|
emit(form.emitter, "disabled");
|
|
1217
1241
|
}
|
|
1242
|
+
function setStatus(form, value) {
|
|
1243
|
+
form.status = value;
|
|
1244
|
+
emit(form.emitter, "status");
|
|
1245
|
+
}
|
|
1218
1246
|
function nameToPath(name) {
|
|
1219
1247
|
if (name.startsWith("[")) {
|
|
1220
1248
|
try {
|
|
@@ -1253,6 +1281,7 @@
|
|
|
1253
1281
|
e.preventDefault();
|
|
1254
1282
|
}
|
|
1255
1283
|
const formEl = e?.currentTarget;
|
|
1284
|
+
form.isSubmitted = true;
|
|
1256
1285
|
setIsSubmitting(form, true);
|
|
1257
1286
|
incrementSubmitCount(form);
|
|
1258
1287
|
const values = getValues(form);
|
|
@@ -1309,6 +1338,8 @@
|
|
|
1309
1338
|
mode: options?.mode ?? "onSubmit",
|
|
1310
1339
|
reValidateMode: options?.reValidateMode ?? "onChange",
|
|
1311
1340
|
disabled: options?.disabled ?? false,
|
|
1341
|
+
validateOnMount: options?.validateOnMount ?? false,
|
|
1342
|
+
asyncAlways: options?.asyncAlways ?? false,
|
|
1312
1343
|
validateDeps: options?.validateDeps ? new Set(options.validateDeps.map((dep) => create$1(dep).key)) : void 0,
|
|
1313
1344
|
initialValues: {},
|
|
1314
1345
|
values: /* @__PURE__ */ new Map(),
|
|
@@ -1319,18 +1350,20 @@
|
|
|
1319
1350
|
validating: /* @__PURE__ */ new Set(),
|
|
1320
1351
|
parsedValues: void 0,
|
|
1321
1352
|
isSubmitting: false,
|
|
1353
|
+
isSubmitted: false,
|
|
1322
1354
|
submitCount: 0,
|
|
1323
1355
|
isSubmitSuccessful: void 0,
|
|
1324
|
-
isLoading: false
|
|
1356
|
+
isLoading: false,
|
|
1357
|
+
status: void 0
|
|
1325
1358
|
};
|
|
1326
1359
|
if (isPromise(source)) {
|
|
1327
1360
|
form.isLoading = true;
|
|
1328
1361
|
emit(emitter, "loading");
|
|
1329
1362
|
Promise.resolve(source).then(
|
|
1330
1363
|
(resolved) => {
|
|
1364
|
+
setInitialValues(form, resolved ?? {});
|
|
1331
1365
|
form.isLoading = false;
|
|
1332
1366
|
emit(emitter, "loading");
|
|
1333
|
-
setInitialValues(form, resolved ?? {});
|
|
1334
1367
|
},
|
|
1335
1368
|
(error) => {
|
|
1336
1369
|
form.isLoading = false;
|
|
@@ -1362,9 +1395,9 @@
|
|
|
1362
1395
|
}
|
|
1363
1396
|
}
|
|
1364
1397
|
function rulesToValidator(rules) {
|
|
1365
|
-
return (value) => {
|
|
1398
|
+
return (value, meta) => {
|
|
1366
1399
|
if (rules.required) {
|
|
1367
|
-
if (value === "" || value === void 0 || value === null) {
|
|
1400
|
+
if (value === "" || value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
|
|
1368
1401
|
return [
|
|
1369
1402
|
{
|
|
1370
1403
|
type: "required",
|
|
@@ -1387,13 +1420,14 @@
|
|
|
1387
1420
|
errors.push({ type: "max", message: message("max", rules.max) });
|
|
1388
1421
|
}
|
|
1389
1422
|
}
|
|
1390
|
-
|
|
1423
|
+
const isSized = typeof value === "string" || Array.isArray(value);
|
|
1424
|
+
if (rules.minLength !== void 0 && isSized && value.length < rules.minLength) {
|
|
1391
1425
|
errors.push({
|
|
1392
1426
|
type: "minLength",
|
|
1393
1427
|
message: message("minLength", rules.minLength)
|
|
1394
1428
|
});
|
|
1395
1429
|
}
|
|
1396
|
-
if (rules.maxLength !== void 0 &&
|
|
1430
|
+
if (rules.maxLength !== void 0 && isSized && value.length > rules.maxLength) {
|
|
1397
1431
|
errors.push({
|
|
1398
1432
|
type: "maxLength",
|
|
1399
1433
|
message: message("maxLength", rules.maxLength)
|
|
@@ -1406,207 +1440,32 @@
|
|
|
1406
1440
|
message: rules.messages?.pattern ?? rules.pattern.message ?? defaultMessage("pattern")
|
|
1407
1441
|
});
|
|
1408
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
|
+
}
|
|
1409
1455
|
return errors.length ? errors : void 0;
|
|
1410
1456
|
};
|
|
1411
1457
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1422
|
-
*
|
|
1423
|
-
* This source code is licensed under the MIT license found in the
|
|
1424
|
-
* LICENSE file in the root directory of this source tree.
|
|
1425
|
-
*/
|
|
1426
|
-
|
|
1427
|
-
var hasRequiredUseSyncExternalStoreShim_production;
|
|
1428
|
-
|
|
1429
|
-
function requireUseSyncExternalStoreShim_production () {
|
|
1430
|
-
if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
|
|
1431
|
-
hasRequiredUseSyncExternalStoreShim_production = 1;
|
|
1432
|
-
var React$1 = React;
|
|
1433
|
-
function is(x, y) {
|
|
1434
|
-
return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
|
|
1435
|
-
}
|
|
1436
|
-
var objectIs = "function" === typeof Object.is ? Object.is : is,
|
|
1437
|
-
useState = React$1.useState,
|
|
1438
|
-
useEffect = React$1.useEffect,
|
|
1439
|
-
useLayoutEffect = React$1.useLayoutEffect,
|
|
1440
|
-
useDebugValue = React$1.useDebugValue;
|
|
1441
|
-
function useSyncExternalStore$2(subscribe, getSnapshot) {
|
|
1442
|
-
var value = getSnapshot(),
|
|
1443
|
-
_useState = useState({ inst: { value: value, getSnapshot: getSnapshot } }),
|
|
1444
|
-
inst = _useState[0].inst,
|
|
1445
|
-
forceUpdate = _useState[1];
|
|
1446
|
-
useLayoutEffect(
|
|
1447
|
-
function () {
|
|
1448
|
-
inst.value = value;
|
|
1449
|
-
inst.getSnapshot = getSnapshot;
|
|
1450
|
-
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
1451
|
-
},
|
|
1452
|
-
[subscribe, value, getSnapshot]
|
|
1453
|
-
);
|
|
1454
|
-
useEffect(
|
|
1455
|
-
function () {
|
|
1456
|
-
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
1457
|
-
return subscribe(function () {
|
|
1458
|
-
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
1459
|
-
});
|
|
1460
|
-
},
|
|
1461
|
-
[subscribe]
|
|
1462
|
-
);
|
|
1463
|
-
useDebugValue(value);
|
|
1464
|
-
return value;
|
|
1465
|
-
}
|
|
1466
|
-
function checkIfSnapshotChanged(inst) {
|
|
1467
|
-
var latestGetSnapshot = inst.getSnapshot;
|
|
1468
|
-
inst = inst.value;
|
|
1469
|
-
try {
|
|
1470
|
-
var nextValue = latestGetSnapshot();
|
|
1471
|
-
return !objectIs(inst, nextValue);
|
|
1472
|
-
} catch (error) {
|
|
1473
|
-
return true;
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
function useSyncExternalStore$1(subscribe, getSnapshot) {
|
|
1477
|
-
return getSnapshot();
|
|
1478
|
-
}
|
|
1479
|
-
var shim =
|
|
1480
|
-
"undefined" === typeof window ||
|
|
1481
|
-
"undefined" === typeof window.document ||
|
|
1482
|
-
"undefined" === typeof window.document.createElement
|
|
1483
|
-
? useSyncExternalStore$1
|
|
1484
|
-
: useSyncExternalStore$2;
|
|
1485
|
-
useSyncExternalStoreShim_production.useSyncExternalStore =
|
|
1486
|
-
void 0 !== React$1.useSyncExternalStore ? React$1.useSyncExternalStore : shim;
|
|
1487
|
-
return useSyncExternalStoreShim_production;
|
|
1458
|
+
function rulesToConstraintAttrs(rules) {
|
|
1459
|
+
const attrs = {};
|
|
1460
|
+
if (rules.required) attrs.required = true;
|
|
1461
|
+
if (rules.min !== void 0) attrs.min = rules.min;
|
|
1462
|
+
if (rules.max !== void 0) attrs.max = rules.max;
|
|
1463
|
+
if (rules.minLength !== void 0) attrs.minLength = rules.minLength;
|
|
1464
|
+
if (rules.maxLength !== void 0) attrs.maxLength = rules.maxLength;
|
|
1465
|
+
if (rules.pattern) attrs.pattern = rules.pattern.value.source;
|
|
1466
|
+
return attrs;
|
|
1488
1467
|
}
|
|
1489
1468
|
|
|
1490
|
-
var useSyncExternalStoreShim_development = {};
|
|
1491
|
-
|
|
1492
|
-
/**
|
|
1493
|
-
* @license React
|
|
1494
|
-
* use-sync-external-store-shim.development.js
|
|
1495
|
-
*
|
|
1496
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
1497
|
-
*
|
|
1498
|
-
* This source code is licensed under the MIT license found in the
|
|
1499
|
-
* LICENSE file in the root directory of this source tree.
|
|
1500
|
-
*/
|
|
1501
|
-
|
|
1502
|
-
var hasRequiredUseSyncExternalStoreShim_development;
|
|
1503
|
-
|
|
1504
|
-
function requireUseSyncExternalStoreShim_development () {
|
|
1505
|
-
if (hasRequiredUseSyncExternalStoreShim_development) return useSyncExternalStoreShim_development;
|
|
1506
|
-
hasRequiredUseSyncExternalStoreShim_development = 1;
|
|
1507
|
-
"production" !== process.env.NODE_ENV &&
|
|
1508
|
-
(function () {
|
|
1509
|
-
function is(x, y) {
|
|
1510
|
-
return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
|
|
1511
|
-
}
|
|
1512
|
-
function useSyncExternalStore$2(subscribe, getSnapshot) {
|
|
1513
|
-
didWarnOld18Alpha ||
|
|
1514
|
-
void 0 === React$1.startTransition ||
|
|
1515
|
-
((didWarnOld18Alpha = true),
|
|
1516
|
-
console.error(
|
|
1517
|
-
"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
|
|
1518
|
-
));
|
|
1519
|
-
var value = getSnapshot();
|
|
1520
|
-
if (!didWarnUncachedGetSnapshot) {
|
|
1521
|
-
var cachedValue = getSnapshot();
|
|
1522
|
-
objectIs(value, cachedValue) ||
|
|
1523
|
-
(console.error(
|
|
1524
|
-
"The result of getSnapshot should be cached to avoid an infinite loop"
|
|
1525
|
-
),
|
|
1526
|
-
(didWarnUncachedGetSnapshot = true));
|
|
1527
|
-
}
|
|
1528
|
-
cachedValue = useState({
|
|
1529
|
-
inst: { value: value, getSnapshot: getSnapshot }
|
|
1530
|
-
});
|
|
1531
|
-
var inst = cachedValue[0].inst,
|
|
1532
|
-
forceUpdate = cachedValue[1];
|
|
1533
|
-
useLayoutEffect(
|
|
1534
|
-
function () {
|
|
1535
|
-
inst.value = value;
|
|
1536
|
-
inst.getSnapshot = getSnapshot;
|
|
1537
|
-
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
1538
|
-
},
|
|
1539
|
-
[subscribe, value, getSnapshot]
|
|
1540
|
-
);
|
|
1541
|
-
useEffect(
|
|
1542
|
-
function () {
|
|
1543
|
-
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
1544
|
-
return subscribe(function () {
|
|
1545
|
-
checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
|
|
1546
|
-
});
|
|
1547
|
-
},
|
|
1548
|
-
[subscribe]
|
|
1549
|
-
);
|
|
1550
|
-
useDebugValue(value);
|
|
1551
|
-
return value;
|
|
1552
|
-
}
|
|
1553
|
-
function checkIfSnapshotChanged(inst) {
|
|
1554
|
-
var latestGetSnapshot = inst.getSnapshot;
|
|
1555
|
-
inst = inst.value;
|
|
1556
|
-
try {
|
|
1557
|
-
var nextValue = latestGetSnapshot();
|
|
1558
|
-
return !objectIs(inst, nextValue);
|
|
1559
|
-
} catch (error) {
|
|
1560
|
-
return true;
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
function useSyncExternalStore$1(subscribe, getSnapshot) {
|
|
1564
|
-
return getSnapshot();
|
|
1565
|
-
}
|
|
1566
|
-
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
|
|
1567
|
-
"function" ===
|
|
1568
|
-
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
|
|
1569
|
-
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
1570
|
-
var React$1 = React,
|
|
1571
|
-
objectIs = "function" === typeof Object.is ? Object.is : is,
|
|
1572
|
-
useState = React$1.useState,
|
|
1573
|
-
useEffect = React$1.useEffect,
|
|
1574
|
-
useLayoutEffect = React$1.useLayoutEffect,
|
|
1575
|
-
useDebugValue = React$1.useDebugValue,
|
|
1576
|
-
didWarnOld18Alpha = false,
|
|
1577
|
-
didWarnUncachedGetSnapshot = false,
|
|
1578
|
-
shim =
|
|
1579
|
-
"undefined" === typeof window ||
|
|
1580
|
-
"undefined" === typeof window.document ||
|
|
1581
|
-
"undefined" === typeof window.document.createElement
|
|
1582
|
-
? useSyncExternalStore$1
|
|
1583
|
-
: useSyncExternalStore$2;
|
|
1584
|
-
useSyncExternalStoreShim_development.useSyncExternalStore =
|
|
1585
|
-
void 0 !== React$1.useSyncExternalStore ? React$1.useSyncExternalStore : shim;
|
|
1586
|
-
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
|
|
1587
|
-
"function" ===
|
|
1588
|
-
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
|
|
1589
|
-
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
1590
|
-
})();
|
|
1591
|
-
return useSyncExternalStoreShim_development;
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
var hasRequiredShim;
|
|
1595
|
-
|
|
1596
|
-
function requireShim () {
|
|
1597
|
-
if (hasRequiredShim) return shim.exports;
|
|
1598
|
-
hasRequiredShim = 1;
|
|
1599
|
-
|
|
1600
|
-
if (process.env.NODE_ENV === 'production') {
|
|
1601
|
-
shim.exports = requireUseSyncExternalStoreShim_production();
|
|
1602
|
-
} else {
|
|
1603
|
-
shim.exports = requireUseSyncExternalStoreShim_development();
|
|
1604
|
-
}
|
|
1605
|
-
return shim.exports;
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
var shimExports = requireShim();
|
|
1609
|
-
|
|
1610
1469
|
function isDescendant(key, ancestorKey) {
|
|
1611
1470
|
return key.startsWith(`${ancestorKey.slice(0, -1)},`);
|
|
1612
1471
|
}
|
|
@@ -1677,6 +1536,19 @@
|
|
|
1677
1536
|
seeded.source = values;
|
|
1678
1537
|
setInitialValues(form, values);
|
|
1679
1538
|
}, [form, values]);
|
|
1539
|
+
React.useEffect(() => {
|
|
1540
|
+
if (!form.validateOnMount || !form.validate) return;
|
|
1541
|
+
const run = () => {
|
|
1542
|
+
void runFormValidate(form).catch(() => void 0);
|
|
1543
|
+
};
|
|
1544
|
+
if (!form.isLoading) {
|
|
1545
|
+
run();
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
return on(form.emitter, "loading", () => {
|
|
1549
|
+
run();
|
|
1550
|
+
});
|
|
1551
|
+
}, [form]);
|
|
1680
1552
|
return form;
|
|
1681
1553
|
}
|
|
1682
1554
|
function useWatchCore(subscribeFactory, getter, isEqual2) {
|
|
@@ -1713,7 +1585,7 @@
|
|
|
1713
1585
|
},
|
|
1714
1586
|
[subscribeFactory, cache]
|
|
1715
1587
|
);
|
|
1716
|
-
return
|
|
1588
|
+
return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1717
1589
|
}
|
|
1718
1590
|
function useWatch(formOrEmitter, event, getter, isEqual2) {
|
|
1719
1591
|
const emitter = "emitter" in formOrEmitter ? formOrEmitter.emitter : formOrEmitter;
|
|
@@ -1723,18 +1595,25 @@
|
|
|
1723
1595
|
);
|
|
1724
1596
|
return useWatchCore(subscribeFactory, getter, isEqual2);
|
|
1725
1597
|
}
|
|
1726
|
-
function useValue(form, name) {
|
|
1727
|
-
return useValueByPath(form, create$1(name));
|
|
1598
|
+
function useValue(form, name, options) {
|
|
1599
|
+
return useValueByPath(form, create$1(name), options);
|
|
1728
1600
|
}
|
|
1729
|
-
function useValueByPath(form, path) {
|
|
1601
|
+
function useValueByPath(form, path, options) {
|
|
1730
1602
|
const { emitter } = form;
|
|
1731
1603
|
const { key } = path;
|
|
1604
|
+
const scope = options?.exact === false ? "branch" : "leaf";
|
|
1732
1605
|
const subscribeFactory = React.useCallback(
|
|
1733
|
-
(invalidate) => onPathEvent(emitter, "change", path,
|
|
1606
|
+
(invalidate) => onPathEvent(emitter, "change", path, scope, invalidate),
|
|
1734
1607
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- deps are `key` on purpose: useValue creates a fresh Path per render, so the object must stay out of the deps while the key string pins the subscription
|
|
1735
|
-
[emitter, key]
|
|
1608
|
+
[emitter, key, scope]
|
|
1736
1609
|
);
|
|
1737
|
-
return useWatchCore(subscribeFactory,
|
|
1610
|
+
return useWatchCore(subscribeFactory, () => {
|
|
1611
|
+
if (options?.exact === false) {
|
|
1612
|
+
return get(getValues(form), path.value);
|
|
1613
|
+
}
|
|
1614
|
+
const value = getValueByPath(form, path);
|
|
1615
|
+
return value === void 0 ? options?.defaultValue : value;
|
|
1616
|
+
});
|
|
1738
1617
|
}
|
|
1739
1618
|
function useTouched(form, name) {
|
|
1740
1619
|
return useTouchedByPath(form, create$1(name));
|
|
@@ -1781,6 +1660,19 @@
|
|
|
1781
1660
|
function useIsDirty(form) {
|
|
1782
1661
|
return useWatch(form, "change", isDirty.bind(null, form));
|
|
1783
1662
|
}
|
|
1663
|
+
function useIsFieldDirty(form, name) {
|
|
1664
|
+
return useIsFieldDirtyByPath(form, create$1(name));
|
|
1665
|
+
}
|
|
1666
|
+
function useIsFieldDirtyByPath(form, path) {
|
|
1667
|
+
const { emitter } = form;
|
|
1668
|
+
const { key } = path;
|
|
1669
|
+
const subscribeFactory = React.useCallback(
|
|
1670
|
+
(invalidate) => onPathEvent(emitter, "change", path, "leaf", invalidate),
|
|
1671
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- same key-pinning convention as useValueByPath
|
|
1672
|
+
[emitter, key]
|
|
1673
|
+
);
|
|
1674
|
+
return useWatchCore(subscribeFactory, () => isFieldDirtyByPath(form, path));
|
|
1675
|
+
}
|
|
1784
1676
|
function useDirtyFields(form) {
|
|
1785
1677
|
return useWatch(form, "change", getDirtyFields.bind(null, form));
|
|
1786
1678
|
}
|
|
@@ -1807,6 +1699,7 @@
|
|
|
1807
1699
|
hasErrors: hasErrors(form),
|
|
1808
1700
|
isValid: !hasErrors(form),
|
|
1809
1701
|
isSubmitting: form.isSubmitting,
|
|
1702
|
+
isSubmitted: form.isSubmitted,
|
|
1810
1703
|
isValidating: form.validating.size > 0,
|
|
1811
1704
|
isSubmitSuccessful: form.isSubmitSuccessful,
|
|
1812
1705
|
submitCount: form.submitCount,
|
|
@@ -1816,7 +1709,7 @@
|
|
|
1816
1709
|
}
|
|
1817
1710
|
function isSameFormState(a, b) {
|
|
1818
1711
|
const sameTouched = a.touchedFields.length === b.touchedFields.length && a.touchedFields.every((path, i) => path === b.touchedFields[i]);
|
|
1819
|
-
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.isValidating === b.isValidating && a.isSubmitSuccessful === b.isSubmitSuccessful && a.submitCount === b.submitCount && a.isLoading === b.isLoading && a.disabled === b.disabled;
|
|
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;
|
|
1820
1713
|
}
|
|
1821
1714
|
function useFormState(form) {
|
|
1822
1715
|
const getter = React.useCallback(() => getFormState(form), [form]);
|
|
@@ -1845,6 +1738,9 @@
|
|
|
1845
1738
|
function useIsLoading(form) {
|
|
1846
1739
|
return useWatch(form, "loading", () => form.isLoading);
|
|
1847
1740
|
}
|
|
1741
|
+
function useStatus(form) {
|
|
1742
|
+
return useWatch(form, "status", () => form.status);
|
|
1743
|
+
}
|
|
1848
1744
|
function useCanSubmit(form) {
|
|
1849
1745
|
const { emitter } = form;
|
|
1850
1746
|
const subscribeFactory = React.useCallback(
|
|
@@ -1900,6 +1796,19 @@
|
|
|
1900
1796
|
[ref]
|
|
1901
1797
|
);
|
|
1902
1798
|
}
|
|
1799
|
+
function useUnmountRestore(teardown, restore) {
|
|
1800
|
+
const removedRef = React.useRef(false);
|
|
1801
|
+
React.useEffect(() => {
|
|
1802
|
+
if (removedRef.current) {
|
|
1803
|
+
removedRef.current = false;
|
|
1804
|
+
restore();
|
|
1805
|
+
}
|
|
1806
|
+
return () => {
|
|
1807
|
+
removedRef.current = true;
|
|
1808
|
+
teardown();
|
|
1809
|
+
};
|
|
1810
|
+
}, []);
|
|
1811
|
+
}
|
|
1903
1812
|
|
|
1904
1813
|
function useValidate(validate, path, formProp, options) {
|
|
1905
1814
|
const contextForm = React.useContext(FormContext);
|
|
@@ -1911,20 +1820,67 @@
|
|
|
1911
1820
|
debounceRef.current = options?.debounce ?? 0;
|
|
1912
1821
|
const syncRef = React.useRef(options?.sync);
|
|
1913
1822
|
syncRef.current = options?.sync;
|
|
1914
|
-
React.
|
|
1915
|
-
|
|
1823
|
+
const asyncAlwaysRef = React.useRef(options?.asyncAlways ?? false);
|
|
1824
|
+
asyncAlwaysRef.current = options?.asyncAlways ?? false;
|
|
1825
|
+
React.useEffect(() => {
|
|
1826
|
+
const dispose = registerValidatorByPath(form, path, {
|
|
1916
1827
|
validate: () => validateRef.current,
|
|
1917
1828
|
debounce: () => debounceRef.current,
|
|
1918
|
-
sync: () => syncRef.current
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1829
|
+
sync: () => syncRef.current,
|
|
1830
|
+
asyncAlways: () => asyncAlwaysRef.current
|
|
1831
|
+
});
|
|
1832
|
+
const validateOnMount = options?.validateOnMount ?? form.validateOnMount;
|
|
1833
|
+
if (!validateOnMount || !validateRef.current && !syncRef.current) {
|
|
1834
|
+
return dispose;
|
|
1835
|
+
}
|
|
1836
|
+
let disposed = false;
|
|
1837
|
+
const kick = () => {
|
|
1838
|
+
if (disposed) return;
|
|
1839
|
+
form.validators.get(path.key)?.();
|
|
1840
|
+
};
|
|
1841
|
+
if (!form.isLoading) {
|
|
1842
|
+
kick();
|
|
1843
|
+
} else {
|
|
1844
|
+
const off = on(form.emitter, "loading", () => {
|
|
1845
|
+
off();
|
|
1846
|
+
kick();
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
return () => {
|
|
1850
|
+
disposed = true;
|
|
1851
|
+
dispose();
|
|
1852
|
+
};
|
|
1853
|
+
}, [form, path.key]);
|
|
1923
1854
|
return useStageFn(() => form.validators.get(path.key)?.());
|
|
1924
1855
|
}
|
|
1925
1856
|
|
|
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
|
+
const uncontrolledSyncRegistry = /* @__PURE__ */ new WeakMap();
|
|
1926
1882
|
function hasRuleConstraints(rules) {
|
|
1927
|
-
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;
|
|
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;
|
|
1928
1884
|
}
|
|
1929
1885
|
function combineRulesAndValidate(rules, validate) {
|
|
1930
1886
|
if (!rules || !hasRuleConstraints(rules)) return validate;
|
|
@@ -1987,9 +1943,11 @@
|
|
|
1987
1943
|
rules,
|
|
1988
1944
|
validateDebounce,
|
|
1989
1945
|
validateDeps,
|
|
1946
|
+
validateOnMount,
|
|
1990
1947
|
delayError,
|
|
1991
1948
|
disabled,
|
|
1992
1949
|
uncontrolled,
|
|
1950
|
+
asyncAlways,
|
|
1993
1951
|
mode: modeOption
|
|
1994
1952
|
}, Context) {
|
|
1995
1953
|
const contextForm = React.useContext(Context);
|
|
@@ -2010,6 +1968,8 @@
|
|
|
2010
1968
|
const restRules = rules ? { ...rules, required: void 0 } : void 0;
|
|
2011
1969
|
useValidate(combineRulesAndValidate(restRules, validate), path, form, {
|
|
2012
1970
|
debounce: validateDebounce,
|
|
1971
|
+
validateOnMount,
|
|
1972
|
+
asyncAlways: asyncAlways ?? form.asyncAlways,
|
|
2013
1973
|
sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0
|
|
2014
1974
|
});
|
|
2015
1975
|
const liveErrors = useFieldErrorsByPath(form, path);
|
|
@@ -2017,6 +1977,22 @@
|
|
|
2017
1977
|
const errorObject = errors[0];
|
|
2018
1978
|
const error = errorObject?.message;
|
|
2019
1979
|
const value = useFieldValue(form, path, !!uncontrolled);
|
|
1980
|
+
const isDirty = useWatchCore(
|
|
1981
|
+
React.useCallback(
|
|
1982
|
+
(invalidate) => uncontrolled ? () => {
|
|
1983
|
+
} : onPathEvent(form.emitter, "change", path, "leaf", invalidate),
|
|
1984
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- usePath memoizes the Path per key, so key pins the subscription like every path-scoped hook
|
|
1985
|
+
[form.emitter, path.key, uncontrolled]
|
|
1986
|
+
),
|
|
1987
|
+
() => isFieldDirtyByPath(form, path)
|
|
1988
|
+
);
|
|
1989
|
+
const validating = useWatchCore(
|
|
1990
|
+
React.useCallback(
|
|
1991
|
+
(invalidate) => onKeyEvent(form.emitter, "validating", path.key, invalidate),
|
|
1992
|
+
[form.emitter, path.key]
|
|
1993
|
+
),
|
|
1994
|
+
() => form.validating.has(path.key)
|
|
1995
|
+
);
|
|
2020
1996
|
const formDisabled = useWatch(form, "disabled", () => form.disabled);
|
|
2021
1997
|
const onChange = useStageFn((v) => userChangeByPath(form, path, v));
|
|
2022
1998
|
const onBlur = useStageFn(() => userBlur(form, path));
|
|
@@ -2051,20 +2027,52 @@
|
|
|
2051
2027
|
),
|
|
2052
2028
|
[form, path.key]
|
|
2053
2029
|
);
|
|
2054
|
-
React.useEffect(
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2030
|
+
React.useEffect(() => {
|
|
2031
|
+
if (!uncontrolled) return;
|
|
2032
|
+
let entry = uncontrolledSyncRegistry.get(form);
|
|
2033
|
+
if (!entry) {
|
|
2034
|
+
const cells = /* @__PURE__ */ new Map();
|
|
2035
|
+
const off = on(form.emitter, "change", (changed) => {
|
|
2036
|
+
if (changed) return;
|
|
2037
|
+
for (const read of cells.values()) {
|
|
2038
|
+
const { el, path: path2 } = read();
|
|
2039
|
+
if (!el || el.type === "file") continue;
|
|
2040
|
+
const next = getValueByPath(form, path2);
|
|
2041
|
+
const asString = next == null ? "" : String(next);
|
|
2042
|
+
if (el.value !== asString) el.value = asString;
|
|
2043
|
+
}
|
|
2044
|
+
});
|
|
2045
|
+
entry = { cells, off };
|
|
2046
|
+
uncontrolledSyncRegistry.set(form, entry);
|
|
2047
|
+
}
|
|
2048
|
+
entry.cells.set(path.key, () => ({ el: elementRef.current, path }));
|
|
2049
|
+
return () => {
|
|
2050
|
+
entry.cells.delete(path.key);
|
|
2051
|
+
if (entry.cells.size === 0) {
|
|
2052
|
+
entry.off();
|
|
2053
|
+
uncontrolledSyncRegistry.delete(form);
|
|
2058
2054
|
}
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
);
|
|
2055
|
+
};
|
|
2056
|
+
}, [form, path.key, uncontrolled]);
|
|
2057
|
+
const removalSnapshotRef = React.useRef(null);
|
|
2058
|
+
const teardownOnUnmount = useStageFn(() => {
|
|
2059
|
+
if ((shouldUnregister ?? form.shouldUnregister) === false) return;
|
|
2060
|
+
removalSnapshotRef.current = removeFieldForUnmount(form, path);
|
|
2061
|
+
});
|
|
2062
|
+
const restoreAfterStrictMode = useStageFn(() => {
|
|
2063
|
+
const snapshot = removalSnapshotRef.current;
|
|
2064
|
+
removalSnapshotRef.current = null;
|
|
2065
|
+
if (snapshot) restoreRemovedField(form, path, snapshot);
|
|
2066
|
+
});
|
|
2067
|
+
useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
|
|
2062
2068
|
return {
|
|
2063
2069
|
form,
|
|
2064
2070
|
value,
|
|
2065
2071
|
error,
|
|
2066
2072
|
errorObject,
|
|
2067
2073
|
errors,
|
|
2074
|
+
isDirty,
|
|
2075
|
+
validating,
|
|
2068
2076
|
onChange,
|
|
2069
2077
|
onBlur,
|
|
2070
2078
|
name: path.key,
|
|
@@ -2101,6 +2109,8 @@
|
|
|
2101
2109
|
const contextForm = React.useContext(Context);
|
|
2102
2110
|
const form = options.form || contextForm;
|
|
2103
2111
|
if (!form) throw new Error("no form provided");
|
|
2112
|
+
const keyName = options.keyName ?? "id";
|
|
2113
|
+
const { rules, shouldUnregister } = options;
|
|
2104
2114
|
const path = usePath(options.name);
|
|
2105
2115
|
const idsRef = React.useRef([]);
|
|
2106
2116
|
const getArray = React.useCallback(
|
|
@@ -2121,8 +2131,12 @@
|
|
|
2121
2131
|
while (idsRef.current.length > arr.length) {
|
|
2122
2132
|
idsRef.current.pop();
|
|
2123
2133
|
}
|
|
2124
|
-
return idsRef.current.map((id, index) => ({
|
|
2125
|
-
|
|
2134
|
+
return idsRef.current.map((id, index) => ({
|
|
2135
|
+
id,
|
|
2136
|
+
index,
|
|
2137
|
+
[keyName]: id
|
|
2138
|
+
}));
|
|
2139
|
+
}, [getArray, form, keyName]);
|
|
2126
2140
|
const [fields, syncFields] = React.useReducer(
|
|
2127
2141
|
computeFields,
|
|
2128
2142
|
void 0,
|
|
@@ -2140,6 +2154,25 @@
|
|
|
2140
2154
|
if (registry?.get(path.key) === idsRef.current) registry.delete(path.key);
|
|
2141
2155
|
};
|
|
2142
2156
|
}, [form, path.key]);
|
|
2157
|
+
const removalSnapshotRef = React.useRef(null);
|
|
2158
|
+
const teardownOnUnmount = useStageFn(() => {
|
|
2159
|
+
if ((shouldUnregister ?? form.shouldUnregister) === false) return;
|
|
2160
|
+
removalSnapshotRef.current = removeFieldForUnmount(form, path);
|
|
2161
|
+
});
|
|
2162
|
+
const restoreAfterStrictMode = useStageFn(() => {
|
|
2163
|
+
const snapshot = removalSnapshotRef.current;
|
|
2164
|
+
removalSnapshotRef.current = null;
|
|
2165
|
+
if (snapshot) restoreRemovedField(form, path, snapshot);
|
|
2166
|
+
});
|
|
2167
|
+
useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
|
|
2168
|
+
useValidate(
|
|
2169
|
+
rules ? rulesToValidator({ ...rules, required: void 0 }) : void 0,
|
|
2170
|
+
path,
|
|
2171
|
+
form,
|
|
2172
|
+
{
|
|
2173
|
+
sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0
|
|
2174
|
+
}
|
|
2175
|
+
);
|
|
2143
2176
|
const append = useStageFn((value) => {
|
|
2144
2177
|
const arr = getArray();
|
|
2145
2178
|
idsRef.current.push(generateId(form));
|
|
@@ -2298,6 +2331,29 @@
|
|
|
2298
2331
|
return group;
|
|
2299
2332
|
}
|
|
2300
2333
|
|
|
2334
|
+
function useTransform(form, name, options = {}) {
|
|
2335
|
+
const path = usePath(name);
|
|
2336
|
+
const { toDisplay, fromDisplay } = options;
|
|
2337
|
+
const subscribeFactory = React.useCallback(
|
|
2338
|
+
(invalidate) => onPathEvent(form.emitter, "change", path, "leaf", invalidate),
|
|
2339
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- usePath memoizes the Path per key, so key pins the subscription like every path-scoped hook
|
|
2340
|
+
[form.emitter, path.key]
|
|
2341
|
+
);
|
|
2342
|
+
const raw = useWatchCore(subscribeFactory, () => getValueByPath(form, path));
|
|
2343
|
+
const value = toDisplay ? toDisplay(raw) : raw;
|
|
2344
|
+
const onChange = React.useCallback(
|
|
2345
|
+
(display) => {
|
|
2346
|
+
userChangeByPath(
|
|
2347
|
+
form,
|
|
2348
|
+
path,
|
|
2349
|
+
fromDisplay ? fromDisplay(display) : display
|
|
2350
|
+
);
|
|
2351
|
+
},
|
|
2352
|
+
[form, path, fromDisplay]
|
|
2353
|
+
);
|
|
2354
|
+
return { value, onChange };
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2301
2357
|
function appendFormDataValue(fd, key, value) {
|
|
2302
2358
|
if (value == null) return;
|
|
2303
2359
|
if (Array.isArray(value)) {
|
|
@@ -2339,6 +2395,9 @@
|
|
|
2339
2395
|
initialValues,
|
|
2340
2396
|
values,
|
|
2341
2397
|
shouldUnregister,
|
|
2398
|
+
validateOnMount,
|
|
2399
|
+
disabled,
|
|
2400
|
+
asyncAlways,
|
|
2342
2401
|
onSubmit,
|
|
2343
2402
|
onValidSubmit,
|
|
2344
2403
|
onInvalidSubmit,
|
|
@@ -2346,8 +2405,18 @@
|
|
|
2346
2405
|
shouldFocusError,
|
|
2347
2406
|
...props
|
|
2348
2407
|
}) {
|
|
2349
|
-
const f2 = useForm({
|
|
2408
|
+
const f2 = useForm({
|
|
2409
|
+
initialValues,
|
|
2410
|
+
values,
|
|
2411
|
+
shouldUnregister,
|
|
2412
|
+
validateOnMount,
|
|
2413
|
+
disabled,
|
|
2414
|
+
asyncAlways
|
|
2415
|
+
});
|
|
2350
2416
|
const form = f1 || f2;
|
|
2417
|
+
React__namespace.useEffect(() => {
|
|
2418
|
+
if (disabled !== void 0) setDisabled(form, disabled);
|
|
2419
|
+
}, [form, disabled]);
|
|
2351
2420
|
const submit = handleSubmit(form, {
|
|
2352
2421
|
onSubmit,
|
|
2353
2422
|
onValidSubmit,
|
|
@@ -2398,6 +2467,10 @@
|
|
|
2398
2467
|
shouldUnregister,
|
|
2399
2468
|
rules,
|
|
2400
2469
|
validateDebounce,
|
|
2470
|
+
validateOnMount,
|
|
2471
|
+
valueAsNumber,
|
|
2472
|
+
valueAsDate,
|
|
2473
|
+
asyncAlways,
|
|
2401
2474
|
disabled,
|
|
2402
2475
|
delayError,
|
|
2403
2476
|
mode,
|
|
@@ -2421,8 +2494,10 @@
|
|
|
2421
2494
|
shouldUnregister,
|
|
2422
2495
|
rules,
|
|
2423
2496
|
validateDebounce,
|
|
2497
|
+
validateOnMount,
|
|
2424
2498
|
delayError,
|
|
2425
2499
|
disabled,
|
|
2500
|
+
asyncAlways,
|
|
2426
2501
|
mode,
|
|
2427
2502
|
// File inputs cannot be value-controlled at all — force the
|
|
2428
2503
|
// uncontrolled path so no `value` prop ever reaches the element.
|
|
@@ -2462,12 +2537,14 @@
|
|
|
2462
2537
|
if (nativeInvalidCount > 0) innerRef.current?.reportValidity();
|
|
2463
2538
|
}, [nativeInvalidCount]);
|
|
2464
2539
|
const isFile = props.type === "file";
|
|
2465
|
-
const toValue = eventToValue ?? (isFile ? (e) => e.target.files : (e) => e.target.value);
|
|
2540
|
+
const toValue = eventToValue ?? (isFile ? (e) => e.target.files : valueAsNumber ? (e) => e.target.valueAsNumber : valueAsDate ? (e) => e.target.valueAsDate : (e) => e.target.value);
|
|
2466
2541
|
const valueProps = valueToProps ? valueToProps(value) : isFile ? {} : uncontrolled ? { defaultValue: value } : { value };
|
|
2467
2542
|
const errorId = errorIdFromKey(fieldKey);
|
|
2543
|
+
const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
|
|
2468
2544
|
return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, /* @__PURE__ */ React__namespace.createElement(
|
|
2469
2545
|
Component,
|
|
2470
2546
|
{
|
|
2547
|
+
...constraintAttrs,
|
|
2471
2548
|
...props,
|
|
2472
2549
|
name: fieldKey,
|
|
2473
2550
|
onBlur,
|
|
@@ -2490,6 +2567,8 @@
|
|
|
2490
2567
|
validate,
|
|
2491
2568
|
rules,
|
|
2492
2569
|
validateDebounce,
|
|
2570
|
+
validateOnMount,
|
|
2571
|
+
asyncAlways,
|
|
2493
2572
|
disabled,
|
|
2494
2573
|
delayError,
|
|
2495
2574
|
mode,
|
|
@@ -2510,13 +2589,17 @@
|
|
|
2510
2589
|
validate,
|
|
2511
2590
|
rules,
|
|
2512
2591
|
validateDebounce,
|
|
2592
|
+
validateOnMount,
|
|
2593
|
+
asyncAlways,
|
|
2513
2594
|
delayError,
|
|
2514
2595
|
disabled,
|
|
2515
2596
|
mode
|
|
2516
2597
|
});
|
|
2598
|
+
const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
|
|
2517
2599
|
return /* @__PURE__ */ React__namespace.createElement(
|
|
2518
2600
|
"input",
|
|
2519
2601
|
{
|
|
2602
|
+
...constraintAttrs,
|
|
2520
2603
|
...props,
|
|
2521
2604
|
name: fieldKey,
|
|
2522
2605
|
onBlur,
|
|
@@ -2545,6 +2628,8 @@
|
|
|
2545
2628
|
validate,
|
|
2546
2629
|
rules,
|
|
2547
2630
|
validateDebounce,
|
|
2631
|
+
validateOnMount,
|
|
2632
|
+
asyncAlways,
|
|
2548
2633
|
disabled,
|
|
2549
2634
|
delayError,
|
|
2550
2635
|
mode,
|
|
@@ -2565,13 +2650,17 @@
|
|
|
2565
2650
|
validate,
|
|
2566
2651
|
rules,
|
|
2567
2652
|
validateDebounce,
|
|
2653
|
+
validateOnMount,
|
|
2654
|
+
asyncAlways,
|
|
2568
2655
|
delayError,
|
|
2569
2656
|
disabled,
|
|
2570
2657
|
mode
|
|
2571
2658
|
});
|
|
2659
|
+
const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
|
|
2572
2660
|
return /* @__PURE__ */ React__namespace.createElement(
|
|
2573
2661
|
"select",
|
|
2574
2662
|
{
|
|
2663
|
+
...constraintAttrs,
|
|
2575
2664
|
...props,
|
|
2576
2665
|
name: fieldKey,
|
|
2577
2666
|
onBlur,
|
|
@@ -2626,6 +2715,7 @@
|
|
|
2626
2715
|
exports.hasTouchedByPath = hasTouchedByPath;
|
|
2627
2716
|
exports.incrementSubmitCount = incrementSubmitCount;
|
|
2628
2717
|
exports.isDirty = isDirty;
|
|
2718
|
+
exports.isFieldDirtyByPath = isFieldDirtyByPath;
|
|
2629
2719
|
exports.isTouched = isTouched;
|
|
2630
2720
|
exports.registerFieldMode = registerFieldMode;
|
|
2631
2721
|
exports.registerFieldValidateDeps = registerFieldValidateDeps;
|
|
@@ -2636,6 +2726,7 @@
|
|
|
2636
2726
|
exports.resetField = resetField;
|
|
2637
2727
|
exports.revalidateDependentsOnChange = revalidateDependentsOnChange;
|
|
2638
2728
|
exports.revalidateFormOnChange = revalidateFormOnChange;
|
|
2729
|
+
exports.runFormValidate = runFormValidate;
|
|
2639
2730
|
exports.seedValueByPath = seedValueByPath;
|
|
2640
2731
|
exports.setDisabled = setDisabled;
|
|
2641
2732
|
exports.setError = setError;
|
|
@@ -2644,6 +2735,7 @@
|
|
|
2644
2735
|
exports.setInitialValues = setInitialValues;
|
|
2645
2736
|
exports.setIsSubmitting = setIsSubmitting;
|
|
2646
2737
|
exports.setServerErrors = setServerErrors;
|
|
2738
|
+
exports.setStatus = setStatus;
|
|
2647
2739
|
exports.setSubmitSuccessful = setSubmitSuccessful;
|
|
2648
2740
|
exports.setTouched = setTouched;
|
|
2649
2741
|
exports.setTouchedByPath = setTouchedByPath;
|
|
@@ -2672,15 +2764,19 @@
|
|
|
2672
2764
|
exports.useFormState = useFormState;
|
|
2673
2765
|
exports.useHasErrors = useHasErrors;
|
|
2674
2766
|
exports.useIsDirty = useIsDirty;
|
|
2767
|
+
exports.useIsFieldDirty = useIsFieldDirty;
|
|
2768
|
+
exports.useIsFieldDirtyByPath = useIsFieldDirtyByPath;
|
|
2675
2769
|
exports.useIsLoading = useIsLoading;
|
|
2676
2770
|
exports.useIsSubmitSuccessful = useIsSubmitSuccessful;
|
|
2677
2771
|
exports.useIsSubmitting = useIsSubmitting;
|
|
2678
2772
|
exports.useIsValid = useIsValid;
|
|
2679
2773
|
exports.useIsValidating = useIsValidating;
|
|
2774
|
+
exports.useStatus = useStatus;
|
|
2680
2775
|
exports.useSubmitCount = useSubmitCount;
|
|
2681
2776
|
exports.useTouched = useTouched;
|
|
2682
2777
|
exports.useTouchedByPath = useTouchedByPath;
|
|
2683
2778
|
exports.useTouchedFields = useTouchedFields;
|
|
2779
|
+
exports.useTransform = useTransform;
|
|
2684
2780
|
exports.useValue = useValue;
|
|
2685
2781
|
exports.useValueByPath = useValueByPath;
|
|
2686
2782
|
exports.useWatch = useWatch;
|