react-hook-form 7.17.3 → 7.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1185 -0
- package/dist/controller.d.ts +2 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +130 -76
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/schemaErrorLookup.d.ts +5 -0
- package/dist/types/controller.d.ts +10 -10
- package/dist/types/fieldArray.d.ts +1 -1
- package/dist/types/form.d.ts +11 -8
- package/dist/types/utils.d.ts +9 -3
- package/dist/useController.d.ts +2 -2
- package/dist/useSubscribe.d.ts +2 -2
- package/dist/useWatch.d.ts +4 -4
- package/dist/utils/cloneObject.d.ts +1 -1
- package/dist/utils/convertToArrayPayload.d.ts +1 -1
- package/dist/utils/createSubject.d.ts +18 -0
- package/dist/utils/get.d.ts +1 -1
- package/package.json +21 -21
- package/dist/utils/Subject.d.ts +0 -24
package/dist/index.esm.js
CHANGED
@@ -101,7 +101,7 @@ var shouldRenderFormState = (formStateData, _proxyFormState, isRoot) => {
|
|
101
101
|
(!isRoot || VALIDATION_MODE.all)));
|
102
102
|
};
|
103
103
|
|
104
|
-
var convertToArrayPayload = (value) => Array.isArray(value) ? value : [value];
|
104
|
+
var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
|
105
105
|
|
106
106
|
var shouldSubscribeByName = (name, signalName) => !name ||
|
107
107
|
!signalName ||
|
@@ -159,6 +159,7 @@ function useFormState(props) {
|
|
159
159
|
shouldRenderFormState(formState, _localProxyFormState.current) &&
|
160
160
|
updateFormState(Object.assign(Object.assign({}, control._formState), formState)),
|
161
161
|
subject: control._subjects.state,
|
162
|
+
skipEarlySubscription: true,
|
162
163
|
});
|
163
164
|
return getProxyFormState(formState, control._proxyFormState, _localProxyFormState.current, false);
|
164
165
|
}
|
@@ -177,6 +178,7 @@ function useController(props) {
|
|
177
178
|
subject: control._subjects.control,
|
178
179
|
callback: (data) => (!data.name || _name.current === data.name) &&
|
179
180
|
setInputStateValue(get(data.values, _name.current)),
|
181
|
+
skipEarlySubscription: true,
|
180
182
|
});
|
181
183
|
const registerProps = control.register(name, Object.assign(Object.assign({}, props.rules), { value }));
|
182
184
|
const updateMounted = React.useCallback((name, value) => {
|
@@ -466,6 +468,15 @@ const useFieldArray = (props) => {
|
|
466
468
|
}
|
467
469
|
}
|
468
470
|
}
|
471
|
+
control._executeSchema([name]).then((result) => {
|
472
|
+
const error = get(result.errors, name);
|
473
|
+
if (error && error.type && !get(control._formState.errors, name)) {
|
474
|
+
set(control._formState.errors, name, error);
|
475
|
+
control._subjects.state.next({
|
476
|
+
errors: control._formState.errors,
|
477
|
+
});
|
478
|
+
}
|
479
|
+
});
|
469
480
|
control._subjects.watch.next({
|
470
481
|
name,
|
471
482
|
values: control._formValues,
|
@@ -523,6 +534,60 @@ function cloneObject(data) {
|
|
523
534
|
return copy;
|
524
535
|
}
|
525
536
|
|
537
|
+
function createSubscription() {
|
538
|
+
let tearDowns = [];
|
539
|
+
const add = (tearDown) => {
|
540
|
+
tearDowns.push(tearDown);
|
541
|
+
};
|
542
|
+
const unsubscribe = () => {
|
543
|
+
for (const teardown of tearDowns) {
|
544
|
+
teardown();
|
545
|
+
}
|
546
|
+
tearDowns = [];
|
547
|
+
};
|
548
|
+
return {
|
549
|
+
add,
|
550
|
+
unsubscribe,
|
551
|
+
};
|
552
|
+
}
|
553
|
+
function createSubscriber(observer, subscription) {
|
554
|
+
let closed = false;
|
555
|
+
subscription.add(() => (closed = true));
|
556
|
+
const next = (value) => {
|
557
|
+
if (!closed) {
|
558
|
+
observer.next(value);
|
559
|
+
}
|
560
|
+
};
|
561
|
+
return {
|
562
|
+
next,
|
563
|
+
};
|
564
|
+
}
|
565
|
+
function createSubject() {
|
566
|
+
let _observers = [];
|
567
|
+
const next = (value) => {
|
568
|
+
for (const observer of _observers) {
|
569
|
+
observer.next(value);
|
570
|
+
}
|
571
|
+
};
|
572
|
+
const subscribe = (observer) => {
|
573
|
+
const subscription = createSubscription();
|
574
|
+
const subscriber = createSubscriber(observer, subscription);
|
575
|
+
_observers.push(subscriber);
|
576
|
+
return subscription;
|
577
|
+
};
|
578
|
+
const unsubscribe = () => {
|
579
|
+
_observers = [];
|
580
|
+
};
|
581
|
+
return {
|
582
|
+
get observers() {
|
583
|
+
return _observers;
|
584
|
+
},
|
585
|
+
next,
|
586
|
+
subscribe,
|
587
|
+
unsubscribe,
|
588
|
+
};
|
589
|
+
}
|
590
|
+
|
526
591
|
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
527
592
|
|
528
593
|
function deepEqual(object1, object2) {
|
@@ -566,6 +631,8 @@ var getValidationModes = (mode) => ({
|
|
566
631
|
|
567
632
|
var isBoolean = (value) => typeof value === 'boolean';
|
568
633
|
|
634
|
+
var isFileInput = (element) => element.type === 'file';
|
635
|
+
|
569
636
|
var isHTMLElement = (value) => value instanceof HTMLElement;
|
570
637
|
|
571
638
|
var isMultipleSelect = (element) => element.type === `select-multiple`;
|
@@ -582,52 +649,6 @@ var isWeb = typeof window !== 'undefined' &&
|
|
582
649
|
|
583
650
|
var live = (ref) => isHTMLElement(ref) && document.contains(ref);
|
584
651
|
|
585
|
-
class Subscription {
|
586
|
-
constructor() {
|
587
|
-
this.tearDowns = [];
|
588
|
-
}
|
589
|
-
add(tearDown) {
|
590
|
-
this.tearDowns.push(tearDown);
|
591
|
-
}
|
592
|
-
unsubscribe() {
|
593
|
-
for (const teardown of this.tearDowns) {
|
594
|
-
teardown();
|
595
|
-
}
|
596
|
-
this.tearDowns = [];
|
597
|
-
}
|
598
|
-
}
|
599
|
-
class Subscriber {
|
600
|
-
constructor(observer, subscription) {
|
601
|
-
this.observer = observer;
|
602
|
-
this.closed = false;
|
603
|
-
subscription.add(() => (this.closed = true));
|
604
|
-
}
|
605
|
-
next(value) {
|
606
|
-
if (!this.closed) {
|
607
|
-
this.observer.next(value);
|
608
|
-
}
|
609
|
-
}
|
610
|
-
}
|
611
|
-
class Subject {
|
612
|
-
constructor() {
|
613
|
-
this.observers = [];
|
614
|
-
}
|
615
|
-
next(value) {
|
616
|
-
for (const observer of this.observers) {
|
617
|
-
observer.next(value);
|
618
|
-
}
|
619
|
-
}
|
620
|
-
subscribe(observer) {
|
621
|
-
const subscription = new Subscription();
|
622
|
-
const subscriber = new Subscriber(observer, subscription);
|
623
|
-
this.observers.push(subscriber);
|
624
|
-
return subscription;
|
625
|
-
}
|
626
|
-
unsubscribe() {
|
627
|
-
this.observers = [];
|
628
|
-
}
|
629
|
-
}
|
630
|
-
|
631
652
|
function baseGet(object, updatePath) {
|
632
653
|
const length = updatePath.slice(0, -1).length;
|
633
654
|
let index = 0;
|
@@ -667,8 +688,6 @@ function unset(object, path) {
|
|
667
688
|
return object;
|
668
689
|
}
|
669
690
|
|
670
|
-
var isFileInput = (element) => element.type === 'file';
|
671
|
-
|
672
691
|
const defaultResult = {
|
673
692
|
value: false,
|
674
693
|
isValid: false,
|
@@ -762,6 +781,35 @@ var hasValidation = (options) => options.mount &&
|
|
762
781
|
options.pattern ||
|
763
782
|
options.validate);
|
764
783
|
|
784
|
+
function schemaErrorLookup(errors, _fields, name) {
|
785
|
+
const error = get(errors, name);
|
786
|
+
if (error || isKey(name)) {
|
787
|
+
return {
|
788
|
+
error,
|
789
|
+
name,
|
790
|
+
};
|
791
|
+
}
|
792
|
+
const names = name.split('.');
|
793
|
+
while (names.length) {
|
794
|
+
const fieldName = names.join('.');
|
795
|
+
const field = get(_fields, fieldName);
|
796
|
+
const foundError = get(errors, fieldName);
|
797
|
+
if (field && !Array.isArray(field) && name !== fieldName) {
|
798
|
+
return { name };
|
799
|
+
}
|
800
|
+
if (foundError && foundError.type) {
|
801
|
+
return {
|
802
|
+
name: fieldName,
|
803
|
+
error: foundError,
|
804
|
+
};
|
805
|
+
}
|
806
|
+
names.pop();
|
807
|
+
}
|
808
|
+
return {
|
809
|
+
name,
|
810
|
+
};
|
811
|
+
}
|
812
|
+
|
765
813
|
function deepMerge(target, source) {
|
766
814
|
if (isPrimitive(target) || isPrimitive(source)) {
|
767
815
|
return source;
|
@@ -1031,10 +1079,10 @@ function createFormControl(props = {}) {
|
|
1031
1079
|
errors: false,
|
1032
1080
|
};
|
1033
1081
|
const _subjects = {
|
1034
|
-
watch:
|
1035
|
-
control:
|
1036
|
-
array:
|
1037
|
-
state:
|
1082
|
+
watch: createSubject(),
|
1083
|
+
control: createSubject(),
|
1084
|
+
array: createSubject(),
|
1085
|
+
state: createSubject(),
|
1038
1086
|
};
|
1039
1087
|
const validationModeBeforeSubmit = getValidationModes(_options.mode);
|
1040
1088
|
const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
@@ -1051,7 +1099,7 @@ function createFormControl(props = {}) {
|
|
1051
1099
|
let isValid = false;
|
1052
1100
|
if (_proxyFormState.isValid) {
|
1053
1101
|
isValid = _options.resolver
|
1054
|
-
? isEmptyObject((await
|
1102
|
+
? isEmptyObject((await _executeSchema()).errors)
|
1055
1103
|
: await executeBuildInValidation(_fields, true);
|
1056
1104
|
if (!shouldSkipRender && isValid !== _formState.isValid) {
|
1057
1105
|
_formState.isValid = isValid;
|
@@ -1170,11 +1218,11 @@ function createFormControl(props = {}) {
|
|
1170
1218
|
validateFields = {};
|
1171
1219
|
}
|
1172
1220
|
};
|
1173
|
-
const
|
1221
|
+
const _executeSchema = async (name) => _options.resolver
|
1174
1222
|
? await _options.resolver(Object.assign({}, _formValues), _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation))
|
1175
1223
|
: {};
|
1176
|
-
const
|
1177
|
-
const { errors } = await
|
1224
|
+
const executeSchemaAndUpdateState = async (names) => {
|
1225
|
+
const { errors } = await _executeSchema();
|
1178
1226
|
if (names) {
|
1179
1227
|
for (const name of names) {
|
1180
1228
|
const error = get(errors, name);
|
@@ -1257,7 +1305,10 @@ function createFormControl(props = {}) {
|
|
1257
1305
|
isWeb && isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
|
1258
1306
|
? ''
|
1259
1307
|
: value;
|
1260
|
-
if (
|
1308
|
+
if (isFileInput(fieldReference.ref) && !isString(fieldValue)) {
|
1309
|
+
fieldReference.ref.files = fieldValue;
|
1310
|
+
}
|
1311
|
+
else if (isMultipleSelect(fieldReference.ref)) {
|
1261
1312
|
[...fieldReference.ref.options].forEach((selectRef) => (selectRef.selected = fieldValue.includes(selectRef.value)));
|
1262
1313
|
}
|
1263
1314
|
else if (fieldReference.refs) {
|
@@ -1368,18 +1419,11 @@ function createFormControl(props = {}) {
|
|
1368
1419
|
isValidating: true,
|
1369
1420
|
});
|
1370
1421
|
if (_options.resolver) {
|
1371
|
-
const { errors } = await
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
if (Array.isArray(parentField) &&
|
1377
|
-
parentField.every((field) => field._f && isCheckBoxInput(field._f.ref))) {
|
1378
|
-
const parentError = get(errors, parentNodeName, {});
|
1379
|
-
parentError.type && (error = parentError);
|
1380
|
-
name = parentNodeName;
|
1381
|
-
}
|
1382
|
-
}
|
1422
|
+
const { errors } = await _executeSchema([name]);
|
1423
|
+
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
1424
|
+
const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
|
1425
|
+
error = errorLookupResult.error;
|
1426
|
+
name = errorLookupResult.name;
|
1383
1427
|
isValid = isEmptyObject(errors);
|
1384
1428
|
}
|
1385
1429
|
else {
|
@@ -1398,7 +1442,7 @@ function createFormControl(props = {}) {
|
|
1398
1442
|
isValidating: true,
|
1399
1443
|
});
|
1400
1444
|
if (_options.resolver) {
|
1401
|
-
const errors = await
|
1445
|
+
const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
|
1402
1446
|
isValid = isEmptyObject(errors);
|
1403
1447
|
validationResult = name
|
1404
1448
|
? !fieldNames.some((name) => get(errors, name))
|
@@ -1414,7 +1458,10 @@ function createFormControl(props = {}) {
|
|
1414
1458
|
else {
|
1415
1459
|
validationResult = isValid = await executeBuildInValidation(_fields);
|
1416
1460
|
}
|
1417
|
-
_subjects.state.next(Object.assign(Object.assign({}, (!isString(name) ||
|
1461
|
+
_subjects.state.next(Object.assign(Object.assign(Object.assign({}, (!isString(name) ||
|
1462
|
+
(_proxyFormState.isValid && isValid !== _formState.isValid)
|
1463
|
+
? {}
|
1464
|
+
: { name })), (_options.resolver ? { isValid } : {})), { errors: _formState.errors, isValidating: false }));
|
1418
1465
|
options.shouldFocus &&
|
1419
1466
|
!validationResult &&
|
1420
1467
|
focusFieldBy(_fields, (key) => get(_formState.errors, key), name ? fieldNames : _names.mount);
|
@@ -1434,6 +1481,7 @@ function createFormControl(props = {}) {
|
|
1434
1481
|
: (_formState.errors = {});
|
1435
1482
|
_subjects.state.next({
|
1436
1483
|
errors: _formState.errors,
|
1484
|
+
isValid: true,
|
1437
1485
|
});
|
1438
1486
|
};
|
1439
1487
|
const setError = (name, error, options) => {
|
@@ -1540,7 +1588,7 @@ function createFormControl(props = {}) {
|
|
1540
1588
|
});
|
1541
1589
|
try {
|
1542
1590
|
if (_options.resolver) {
|
1543
|
-
const { errors, values } = await
|
1591
|
+
const { errors, values } = await _executeSchema();
|
1544
1592
|
_formState.errors = errors;
|
1545
1593
|
fieldValues = values;
|
1546
1594
|
}
|
@@ -1600,7 +1648,11 @@ function createFormControl(props = {}) {
|
|
1600
1648
|
}
|
1601
1649
|
}
|
1602
1650
|
}
|
1603
|
-
_formValues = props.shouldUnregister
|
1651
|
+
_formValues = props.shouldUnregister
|
1652
|
+
? keepStateOptions.keepDefaultValues
|
1653
|
+
? cloneObject(_defaultValues)
|
1654
|
+
: {}
|
1655
|
+
: cloneUpdatedValues;
|
1604
1656
|
_fields = {};
|
1605
1657
|
_subjects.control.next({
|
1606
1658
|
values: hasUpdatedFormValues ? cloneUpdatedValues : _defaultValues,
|
@@ -1649,13 +1701,14 @@ function createFormControl(props = {}) {
|
|
1649
1701
|
_stateFlags.watch = !!props.shouldUnregister;
|
1650
1702
|
};
|
1651
1703
|
const setFocus = (name) => {
|
1652
|
-
const
|
1653
|
-
(ref.focus
|
1704
|
+
const field = get(_fields, name)._f;
|
1705
|
+
(field.ref.focus ? field.ref : field.refs[0]).focus();
|
1654
1706
|
};
|
1655
1707
|
return {
|
1656
1708
|
control: {
|
1657
1709
|
register,
|
1658
1710
|
unregister,
|
1711
|
+
_executeSchema,
|
1659
1712
|
_getWatch,
|
1660
1713
|
_getDirty,
|
1661
1714
|
_updateValid,
|
@@ -1762,6 +1815,7 @@ function useForm(props = {}) {
|
|
1762
1815
|
}
|
1763
1816
|
control._removeUnmounted();
|
1764
1817
|
});
|
1818
|
+
React.useEffect(() => () => Object.values(control._subjects).forEach((subject) => subject.unsubscribe()), [control]);
|
1765
1819
|
_formControl.current.formState = getProxyFormState(formState, control._proxyFormState);
|
1766
1820
|
return _formControl.current;
|
1767
1821
|
}
|