react-hook-form 7.71.2 → 7.72.1
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/dist/__tests__/useFieldArray/dirtyFields.test.d.ts +2 -0
- package/dist/__tests__/useFieldArray/dirtyFields.test.d.ts.map +1 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.mjs +158 -59
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/isNameInFieldArray.d.ts.map +1 -1
- package/dist/logic/updateFieldArrayRootError.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +123 -24
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/errors.d.ts +1 -0
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/form.d.ts +7 -3
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/validator.d.ts +13 -1
- package/dist/types/validator.d.ts.map +1 -1
- package/dist/useFormContext.d.ts.map +1 -1
- package/package.json +21 -21
package/dist/index.esm.mjs
CHANGED
|
@@ -18,9 +18,9 @@ var getEventValue = (event) => isObject(event) && event.target
|
|
|
18
18
|
: event.target.value
|
|
19
19
|
: event;
|
|
20
20
|
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
var isNameInFieldArray = (names, name) => name
|
|
22
|
+
.split('.')
|
|
23
|
+
.some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
|
|
24
24
|
|
|
25
25
|
var isPlainObject = (tempObject) => {
|
|
26
26
|
const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
|
|
@@ -105,6 +105,9 @@ const EVENTS = {
|
|
|
105
105
|
BLUR: 'blur',
|
|
106
106
|
FOCUS_OUT: 'focusout',
|
|
107
107
|
CHANGE: 'change',
|
|
108
|
+
SUBMIT: 'submit',
|
|
109
|
+
TRIGGER: 'trigger',
|
|
110
|
+
VALID: 'valid',
|
|
108
111
|
};
|
|
109
112
|
const VALIDATION_MODE = {
|
|
110
113
|
onBlur: 'onBlur',
|
|
@@ -122,6 +125,8 @@ const INPUT_VALIDATION_RULES = {
|
|
|
122
125
|
required: 'required',
|
|
123
126
|
validate: 'validate',
|
|
124
127
|
};
|
|
128
|
+
const FORM_ERROR_TYPE = 'form';
|
|
129
|
+
const ROOT_ERROR_TYPE = 'root';
|
|
125
130
|
|
|
126
131
|
/**
|
|
127
132
|
* Separate context for `control` to prevent unnecessary rerenders.
|
|
@@ -259,8 +264,8 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
|
|
|
259
264
|
if (key !== 'ref') {
|
|
260
265
|
const val2 = object2[key];
|
|
261
266
|
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
262
|
-
(isObject(val1)
|
|
263
|
-
|
|
267
|
+
((isObject(val1) || Array.isArray(val1)) &&
|
|
268
|
+
(isObject(val2) || Array.isArray(val2)))
|
|
264
269
|
? !deepEqual(val1, val2, _internal_visited)
|
|
265
270
|
: !Object.is(val1, val2)) {
|
|
266
271
|
return false;
|
|
@@ -635,42 +640,43 @@ const useFormContext = () => React.useContext(HookFormContext);
|
|
|
635
640
|
*/
|
|
636
641
|
const FormProvider = (props) => {
|
|
637
642
|
const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
643
|
+
const memoizedValue = React.useMemo(() => ({
|
|
644
|
+
watch,
|
|
645
|
+
getValues,
|
|
646
|
+
getFieldState,
|
|
647
|
+
setError,
|
|
648
|
+
clearErrors,
|
|
649
|
+
setValue,
|
|
650
|
+
trigger,
|
|
651
|
+
formState,
|
|
652
|
+
resetField,
|
|
653
|
+
reset,
|
|
654
|
+
handleSubmit,
|
|
655
|
+
unregister,
|
|
656
|
+
control,
|
|
657
|
+
register,
|
|
658
|
+
setFocus,
|
|
659
|
+
subscribe,
|
|
660
|
+
}), [
|
|
661
|
+
clearErrors,
|
|
662
|
+
control,
|
|
663
|
+
formState,
|
|
664
|
+
getFieldState,
|
|
665
|
+
getValues,
|
|
666
|
+
handleSubmit,
|
|
667
|
+
register,
|
|
668
|
+
reset,
|
|
669
|
+
resetField,
|
|
670
|
+
setError,
|
|
671
|
+
setFocus,
|
|
672
|
+
setValue,
|
|
673
|
+
subscribe,
|
|
674
|
+
trigger,
|
|
675
|
+
unregister,
|
|
676
|
+
watch,
|
|
677
|
+
]);
|
|
678
|
+
return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
|
|
679
|
+
React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
|
|
674
680
|
};
|
|
675
681
|
|
|
676
682
|
const POST_REQUEST = 'post';
|
|
@@ -1009,6 +1015,8 @@ function getFieldValue(_f) {
|
|
|
1009
1015
|
return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
|
|
1010
1016
|
}
|
|
1011
1017
|
|
|
1018
|
+
var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name;
|
|
1019
|
+
|
|
1012
1020
|
var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
|
|
1013
1021
|
const fields = {};
|
|
1014
1022
|
for (const name of fieldsNames) {
|
|
@@ -1167,7 +1175,7 @@ var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(re
|
|
|
1167
1175
|
|
|
1168
1176
|
var updateFieldArrayRootError = (errors, error, name) => {
|
|
1169
1177
|
const fieldArrayErrors = convertToArrayPayload(get(errors, name));
|
|
1170
|
-
set(fieldArrayErrors,
|
|
1178
|
+
set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
|
|
1171
1179
|
set(errors, name, fieldArrayErrors);
|
|
1172
1180
|
return errors;
|
|
1173
1181
|
};
|
|
@@ -1415,6 +1423,7 @@ function createFormControl(props = {}) {
|
|
|
1415
1423
|
unMount: new Set(),
|
|
1416
1424
|
array: new Set(),
|
|
1417
1425
|
watch: new Set(),
|
|
1426
|
+
registerName: new Set(),
|
|
1418
1427
|
};
|
|
1419
1428
|
let delayErrorCallback;
|
|
1420
1429
|
let timer = 0;
|
|
@@ -1456,7 +1465,11 @@ function createFormControl(props = {}) {
|
|
|
1456
1465
|
_updateIsValidating();
|
|
1457
1466
|
}
|
|
1458
1467
|
else {
|
|
1459
|
-
isValid = await executeBuiltInValidation(
|
|
1468
|
+
isValid = await executeBuiltInValidation({
|
|
1469
|
+
fields: _fields,
|
|
1470
|
+
onlyCheckValid: true,
|
|
1471
|
+
eventType: EVENTS.VALID,
|
|
1472
|
+
});
|
|
1460
1473
|
}
|
|
1461
1474
|
if (isValid !== _formState.isValid) {
|
|
1462
1475
|
_subjects.state.next({
|
|
@@ -1484,6 +1497,11 @@ function createFormControl(props = {}) {
|
|
|
1484
1497
|
});
|
|
1485
1498
|
}
|
|
1486
1499
|
};
|
|
1500
|
+
const _updateDirtyFields = (name) => {
|
|
1501
|
+
const fullDirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1502
|
+
const rootName = getNodeParentName(name);
|
|
1503
|
+
set(_formState.dirtyFields, rootName, get(fullDirtyFields, rootName));
|
|
1504
|
+
};
|
|
1487
1505
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
1488
1506
|
if (args && method && !_options.disabled) {
|
|
1489
1507
|
_state.action = true;
|
|
@@ -1505,7 +1523,7 @@ function createFormControl(props = {}) {
|
|
|
1505
1523
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
1506
1524
|
}
|
|
1507
1525
|
if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
|
|
1508
|
-
|
|
1526
|
+
_updateDirtyFields(name);
|
|
1509
1527
|
}
|
|
1510
1528
|
_subjects.state.next({
|
|
1511
1529
|
name,
|
|
@@ -1619,8 +1637,7 @@ function createFormControl(props = {}) {
|
|
|
1619
1637
|
};
|
|
1620
1638
|
const _runSchema = async (name) => {
|
|
1621
1639
|
_updateIsValidating(name, true);
|
|
1622
|
-
|
|
1623
|
-
return result;
|
|
1640
|
+
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
1624
1641
|
};
|
|
1625
1642
|
const executeSchemaAndUpdateState = async (names) => {
|
|
1626
1643
|
const { errors } = await _runSchema(names);
|
|
@@ -1638,9 +1655,55 @@ function createFormControl(props = {}) {
|
|
|
1638
1655
|
}
|
|
1639
1656
|
return errors;
|
|
1640
1657
|
};
|
|
1641
|
-
const
|
|
1658
|
+
const validateForm = async ({ name, eventType, }) => {
|
|
1659
|
+
if (props.validate) {
|
|
1660
|
+
const result = await props.validate({
|
|
1661
|
+
formValues: _formValues,
|
|
1662
|
+
formState: _formState,
|
|
1663
|
+
name,
|
|
1664
|
+
eventType,
|
|
1665
|
+
});
|
|
1666
|
+
if (isObject(result)) {
|
|
1667
|
+
for (const key in result) {
|
|
1668
|
+
const error = result[key];
|
|
1669
|
+
if (error) {
|
|
1670
|
+
setError(`${FORM_ERROR_TYPE}.${key}`, {
|
|
1671
|
+
message: isString(result.message) ? result.message : '',
|
|
1672
|
+
type: INPUT_VALIDATION_RULES.validate,
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
else if (isString(result) || !result) {
|
|
1678
|
+
setError(FORM_ERROR_TYPE, {
|
|
1679
|
+
message: result || '',
|
|
1680
|
+
type: INPUT_VALIDATION_RULES.validate,
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
else {
|
|
1684
|
+
clearErrors(FORM_ERROR_TYPE);
|
|
1685
|
+
}
|
|
1686
|
+
return result;
|
|
1687
|
+
}
|
|
1688
|
+
return true;
|
|
1689
|
+
};
|
|
1690
|
+
const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
|
|
1642
1691
|
valid: true,
|
|
1643
|
-
|
|
1692
|
+
runRootValidation: false,
|
|
1693
|
+
}, }) => {
|
|
1694
|
+
if (props.validate) {
|
|
1695
|
+
context.runRootValidation = true;
|
|
1696
|
+
const result = await validateForm({
|
|
1697
|
+
name,
|
|
1698
|
+
eventType,
|
|
1699
|
+
});
|
|
1700
|
+
if (!result) {
|
|
1701
|
+
context.valid = false;
|
|
1702
|
+
if (onlyCheckValid) {
|
|
1703
|
+
return context.valid;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1644
1707
|
for (const name in fields) {
|
|
1645
1708
|
const field = fields[name];
|
|
1646
1709
|
if (field) {
|
|
@@ -1651,25 +1714,34 @@ function createFormControl(props = {}) {
|
|
|
1651
1714
|
if (isPromiseFunction && _proxyFormState.validatingFields) {
|
|
1652
1715
|
_updateIsValidating([_f.name], true);
|
|
1653
1716
|
}
|
|
1654
|
-
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !
|
|
1717
|
+
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
|
|
1655
1718
|
if (isPromiseFunction && _proxyFormState.validatingFields) {
|
|
1656
1719
|
_updateIsValidating([_f.name]);
|
|
1657
1720
|
}
|
|
1658
1721
|
if (fieldError[_f.name]) {
|
|
1659
1722
|
context.valid = false;
|
|
1660
|
-
if (
|
|
1723
|
+
if (onlyCheckValid) {
|
|
1661
1724
|
break;
|
|
1662
1725
|
}
|
|
1663
1726
|
}
|
|
1664
|
-
!
|
|
1727
|
+
!onlyCheckValid &&
|
|
1665
1728
|
(get(fieldError, _f.name)
|
|
1666
1729
|
? isFieldArrayRoot
|
|
1667
1730
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
1668
1731
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
1669
1732
|
: unset(_formState.errors, _f.name));
|
|
1733
|
+
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
1734
|
+
break;
|
|
1735
|
+
}
|
|
1670
1736
|
}
|
|
1671
1737
|
!isEmptyObject(fieldValue) &&
|
|
1672
|
-
(await executeBuiltInValidation(
|
|
1738
|
+
(await executeBuiltInValidation({
|
|
1739
|
+
context,
|
|
1740
|
+
onlyCheckValid,
|
|
1741
|
+
fields: fieldValue,
|
|
1742
|
+
name: name,
|
|
1743
|
+
eventType,
|
|
1744
|
+
}));
|
|
1673
1745
|
}
|
|
1674
1746
|
}
|
|
1675
1747
|
return context.valid;
|
|
@@ -1780,9 +1852,10 @@ function createFormControl(props = {}) {
|
|
|
1780
1852
|
_proxySubscribeFormState.isDirty ||
|
|
1781
1853
|
_proxySubscribeFormState.dirtyFields) &&
|
|
1782
1854
|
options.shouldDirty) {
|
|
1855
|
+
_updateDirtyFields(name);
|
|
1783
1856
|
_subjects.state.next({
|
|
1784
1857
|
name,
|
|
1785
|
-
dirtyFields:
|
|
1858
|
+
dirtyFields: _formState.dirtyFields,
|
|
1786
1859
|
isDirty: _getDirty(name, cloneValue),
|
|
1787
1860
|
});
|
|
1788
1861
|
}
|
|
@@ -1828,6 +1901,7 @@ function createFormControl(props = {}) {
|
|
|
1828
1901
|
: getEventValue(event);
|
|
1829
1902
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
1830
1903
|
const shouldSkipValidation = (!hasValidation(field._f) &&
|
|
1904
|
+
!props.validate &&
|
|
1831
1905
|
!_options.resolver &&
|
|
1832
1906
|
!get(_formState.errors, name) &&
|
|
1833
1907
|
!field._f.deps) ||
|
|
@@ -1865,6 +1939,12 @@ function createFormControl(props = {}) {
|
|
|
1865
1939
|
return (shouldRender &&
|
|
1866
1940
|
_subjects.state.next({ name, ...(watched ? {} : fieldState) }));
|
|
1867
1941
|
}
|
|
1942
|
+
if (!_options.resolver && props.validate) {
|
|
1943
|
+
await validateForm({
|
|
1944
|
+
name: name,
|
|
1945
|
+
eventType: event.type,
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1868
1948
|
!isBlurEvent && watched && _subjects.state.next({ ..._formState });
|
|
1869
1949
|
if (_options.resolver) {
|
|
1870
1950
|
const { errors } = await _runSchema([name]);
|
|
@@ -1889,7 +1969,12 @@ function createFormControl(props = {}) {
|
|
|
1889
1969
|
}
|
|
1890
1970
|
else if (_proxyFormState.isValid ||
|
|
1891
1971
|
_proxySubscribeFormState.isValid) {
|
|
1892
|
-
isValid = await executeBuiltInValidation(
|
|
1972
|
+
isValid = await executeBuiltInValidation({
|
|
1973
|
+
fields: _fields,
|
|
1974
|
+
onlyCheckValid: true,
|
|
1975
|
+
name: name,
|
|
1976
|
+
eventType: event.type,
|
|
1977
|
+
});
|
|
1893
1978
|
}
|
|
1894
1979
|
}
|
|
1895
1980
|
}
|
|
@@ -1922,12 +2007,19 @@ function createFormControl(props = {}) {
|
|
|
1922
2007
|
else if (name) {
|
|
1923
2008
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
1924
2009
|
const field = get(_fields, fieldName);
|
|
1925
|
-
return await executeBuiltInValidation(
|
|
2010
|
+
return await executeBuiltInValidation({
|
|
2011
|
+
fields: field && field._f ? { [fieldName]: field } : field,
|
|
2012
|
+
eventType: EVENTS.TRIGGER,
|
|
2013
|
+
});
|
|
1926
2014
|
}))).every(Boolean);
|
|
1927
2015
|
!(!validationResult && !_formState.isValid) && _setValid();
|
|
1928
2016
|
}
|
|
1929
2017
|
else {
|
|
1930
|
-
validationResult = isValid = await executeBuiltInValidation(
|
|
2018
|
+
validationResult = isValid = await executeBuiltInValidation({
|
|
2019
|
+
fields: _fields,
|
|
2020
|
+
name,
|
|
2021
|
+
eventType: EVENTS.TRIGGER,
|
|
2022
|
+
});
|
|
1931
2023
|
}
|
|
1932
2024
|
_subjects.state.next({
|
|
1933
2025
|
...(!isString(name) ||
|
|
@@ -2073,6 +2165,7 @@ function createFormControl(props = {}) {
|
|
|
2073
2165
|
const register = (name, options = {}) => {
|
|
2074
2166
|
let field = get(_fields, name);
|
|
2075
2167
|
const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
|
|
2168
|
+
const shouldRevalidateRemount = !_names.registerName.has(name) && field && !field._f.mount;
|
|
2076
2169
|
set(_fields, name, {
|
|
2077
2170
|
...(field || {}),
|
|
2078
2171
|
_f: {
|
|
@@ -2083,7 +2176,7 @@ function createFormControl(props = {}) {
|
|
|
2083
2176
|
},
|
|
2084
2177
|
});
|
|
2085
2178
|
_names.mount.add(name);
|
|
2086
|
-
if (field) {
|
|
2179
|
+
if (field && !shouldRevalidateRemount) {
|
|
2087
2180
|
_setDisabledField({
|
|
2088
2181
|
disabled: isBoolean(options.disabled)
|
|
2089
2182
|
? options.disabled
|
|
@@ -2113,7 +2206,9 @@ function createFormControl(props = {}) {
|
|
|
2113
2206
|
onBlur: onChange,
|
|
2114
2207
|
ref: (ref) => {
|
|
2115
2208
|
if (ref) {
|
|
2209
|
+
_names.registerName.add(name);
|
|
2116
2210
|
register(name, options);
|
|
2211
|
+
_names.registerName.delete(name);
|
|
2117
2212
|
field = get(_fields, name);
|
|
2118
2213
|
const fieldRef = isUndefined(ref.value)
|
|
2119
2214
|
? ref.querySelectorAll
|
|
@@ -2192,14 +2287,17 @@ function createFormControl(props = {}) {
|
|
|
2192
2287
|
fieldValues = cloneObject(values);
|
|
2193
2288
|
}
|
|
2194
2289
|
else {
|
|
2195
|
-
await executeBuiltInValidation(
|
|
2290
|
+
await executeBuiltInValidation({
|
|
2291
|
+
fields: _fields,
|
|
2292
|
+
eventType: EVENTS.SUBMIT,
|
|
2293
|
+
});
|
|
2196
2294
|
}
|
|
2197
2295
|
if (_names.disabled.size) {
|
|
2198
2296
|
for (const name of _names.disabled) {
|
|
2199
2297
|
unset(fieldValues, name);
|
|
2200
2298
|
}
|
|
2201
2299
|
}
|
|
2202
|
-
unset(_formState.errors,
|
|
2300
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
2203
2301
|
if (isEmptyObject(_formState.errors)) {
|
|
2204
2302
|
_subjects.state.next({
|
|
2205
2303
|
errors: {},
|
|
@@ -2323,6 +2421,7 @@ function createFormControl(props = {}) {
|
|
|
2323
2421
|
mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
|
|
2324
2422
|
unMount: new Set(),
|
|
2325
2423
|
array: new Set(),
|
|
2424
|
+
registerName: new Set(),
|
|
2326
2425
|
disabled: new Set(),
|
|
2327
2426
|
watch: new Set(),
|
|
2328
2427
|
watchAll: false,
|