react-hook-form 7.79.0 → 7.81.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/dist/constants.d.ts +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/fieldArray.d.ts +36 -0
- package/dist/fieldArray.d.ts.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.mjs +179 -98
- 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/getNodeParentName.d.ts.map +1 -1
- package/dist/logic/hasPromiseValidation.d.ts.map +1 -1
- package/dist/logic/isWatched.d.ts.map +1 -1
- package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +166 -84
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/fieldArray.d.ts +24 -1
- package/dist/types/fieldArray.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/utils/deepEqual.d.ts.map +1 -1
- package/dist/utils/flatten.d.ts.map +1 -1
- package/dist/utils/isKey.d.ts.map +1 -1
- package/dist/utils/stringToPath.d.ts.map +1 -1
- package/dist/utils/unset.d.ts.map +1 -1
- package/package.json +17 -13
package/dist/index.esm.mjs
CHANGED
|
@@ -76,15 +76,16 @@ const INPUT_VALIDATION_RULES = {
|
|
|
76
76
|
required: 'required',
|
|
77
77
|
validate: 'validate',
|
|
78
78
|
};
|
|
79
|
-
const FORM_ERROR_TYPE = 'form';
|
|
80
79
|
const ROOT_ERROR_TYPE = 'root';
|
|
81
80
|
const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
const IS_KEY_RE = /^\w*$/;
|
|
83
|
+
var isKey = (value) => IS_KEY_RE.test(value);
|
|
84
84
|
|
|
85
85
|
var isUndefined = (val) => val === undefined;
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
const FIELD_PATH_RE = /[.[\]'"]/;
|
|
88
|
+
var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
|
|
88
89
|
|
|
89
90
|
var get = (object, path, defaultValue) => {
|
|
90
91
|
if (!path || !isObject(object)) {
|
|
@@ -268,6 +269,9 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
|
268
269
|
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
269
270
|
return Object.is(object1, object2);
|
|
270
271
|
}
|
|
272
|
+
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
271
275
|
const visitedPairs = visited.get(object1);
|
|
272
276
|
if (visitedPairs && visitedPairs.has(object2)) {
|
|
273
277
|
return true;
|
|
@@ -276,7 +280,9 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
|
276
280
|
visitedPairs.add(object2);
|
|
277
281
|
}
|
|
278
282
|
else {
|
|
279
|
-
|
|
283
|
+
const ws = new WeakSet();
|
|
284
|
+
ws.add(object2);
|
|
285
|
+
visited.set(object1, ws);
|
|
280
286
|
}
|
|
281
287
|
for (const key of keys1) {
|
|
282
288
|
const val1 = object1[key];
|
|
@@ -599,7 +605,9 @@ const Controller = (props) => props.render(useController(props));
|
|
|
599
605
|
const flatten = (obj) => {
|
|
600
606
|
const output = {};
|
|
601
607
|
for (const key of Object.keys(obj)) {
|
|
602
|
-
if (isObjectType(obj[key]) &&
|
|
608
|
+
if (isObjectType(obj[key]) &&
|
|
609
|
+
obj[key] !== null &&
|
|
610
|
+
!isDateObject(obj[key])) {
|
|
603
611
|
const nested = flatten(obj[key]);
|
|
604
612
|
for (const nestedKey of Object.keys(nested)) {
|
|
605
613
|
output[`${key}.${nestedKey}`] = nested[nestedKey];
|
|
@@ -944,6 +952,9 @@ function unset(object, path) {
|
|
|
944
952
|
: isKey(path)
|
|
945
953
|
? [path]
|
|
946
954
|
: stringToPath(path);
|
|
955
|
+
if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
|
|
956
|
+
return object;
|
|
957
|
+
}
|
|
947
958
|
const childObject = paths.length === 1 ? object : baseGet(object, paths);
|
|
948
959
|
const index = paths.length - 1;
|
|
949
960
|
const key = paths[index];
|
|
@@ -1132,12 +1143,22 @@ var getValidationModes = (mode) => ({
|
|
|
1132
1143
|
});
|
|
1133
1144
|
|
|
1134
1145
|
const ASYNC_FUNCTION = 'AsyncFunction';
|
|
1135
|
-
var hasPromiseValidation = (fieldReference) =>
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1146
|
+
var hasPromiseValidation = (fieldReference) => {
|
|
1147
|
+
if (!fieldReference || !fieldReference.validate)
|
|
1148
|
+
return false;
|
|
1149
|
+
if (isFunction(fieldReference.validate)) {
|
|
1150
|
+
return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
|
|
1151
|
+
}
|
|
1152
|
+
if (isObject(fieldReference.validate)) {
|
|
1153
|
+
for (const key in fieldReference.validate) {
|
|
1154
|
+
if (fieldReference.validate[key].constructor
|
|
1155
|
+
.name === ASYNC_FUNCTION) {
|
|
1156
|
+
return true;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
return false;
|
|
1161
|
+
};
|
|
1141
1162
|
|
|
1142
1163
|
var hasValidation = (options) => options.mount &&
|
|
1143
1164
|
(options.required ||
|
|
@@ -1148,10 +1169,17 @@ var hasValidation = (options) => options.mount &&
|
|
|
1148
1169
|
options.pattern ||
|
|
1149
1170
|
options.validate);
|
|
1150
1171
|
|
|
1151
|
-
var isWatched = (name, _names, isBlurEvent) =>
|
|
1152
|
-
(
|
|
1153
|
-
|
|
1154
|
-
|
|
1172
|
+
var isWatched = (name, _names, isBlurEvent) => {
|
|
1173
|
+
if (isBlurEvent)
|
|
1174
|
+
return false;
|
|
1175
|
+
if (_names.watchAll || _names.watch.has(name))
|
|
1176
|
+
return true;
|
|
1177
|
+
for (const watchName of _names.watch) {
|
|
1178
|
+
if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
return false;
|
|
1182
|
+
};
|
|
1155
1183
|
|
|
1156
1184
|
const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
1157
1185
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
@@ -1219,10 +1247,10 @@ function schemaErrorLookup(errors, _fields, name) {
|
|
|
1219
1247
|
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
1220
1248
|
updateFormState(formStateData);
|
|
1221
1249
|
const { name, ...formState } = formStateData;
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1250
|
+
const keys = Object.keys(formState);
|
|
1251
|
+
return (!keys.length ||
|
|
1252
|
+
(isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
|
|
1253
|
+
keys.find((key) => _proxyFormState[key] ===
|
|
1226
1254
|
(!isRoot || VALIDATION_MODE.all)));
|
|
1227
1255
|
};
|
|
1228
1256
|
|
|
@@ -1231,7 +1259,7 @@ var shouldSubscribeByName = (name, signalName, exact) => !name ||
|
|
|
1231
1259
|
name === signalName ||
|
|
1232
1260
|
convertToArrayPayload(name).some((currentName) => currentName &&
|
|
1233
1261
|
(exact
|
|
1234
|
-
? currentName === signalName
|
|
1262
|
+
? currentName === signalName || currentName.startsWith(signalName + '.')
|
|
1235
1263
|
: currentName.startsWith(signalName) ||
|
|
1236
1264
|
signalName.startsWith(currentName)));
|
|
1237
1265
|
|
|
@@ -1470,6 +1498,7 @@ const defaultOptions = {
|
|
|
1470
1498
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
1471
1499
|
shouldFocusError: true,
|
|
1472
1500
|
};
|
|
1501
|
+
const FORM_ERROR_TYPE = 'form';
|
|
1473
1502
|
const DEFAULT_FORM_STATE = {
|
|
1474
1503
|
submitCount: 0,
|
|
1475
1504
|
isDirty: false,
|
|
@@ -1517,6 +1546,9 @@ function createFormControl(props = {}) {
|
|
|
1517
1546
|
};
|
|
1518
1547
|
let delayErrorCallback;
|
|
1519
1548
|
let timer = 0;
|
|
1549
|
+
let _valuesSubscriberCount = 0;
|
|
1550
|
+
let _validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1551
|
+
let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
1520
1552
|
const defaultProxyFormState = {
|
|
1521
1553
|
isDirty: false,
|
|
1522
1554
|
dirtyFields: false,
|
|
@@ -1670,12 +1702,6 @@ function createFormControl(props = {}) {
|
|
|
1670
1702
|
: setFieldValue(name, defaultValue);
|
|
1671
1703
|
if (_state.mount && !_state.action) {
|
|
1672
1704
|
_setValid();
|
|
1673
|
-
// Re-registering a field after a prior unregister puts its key back
|
|
1674
|
-
// into _formValues, which can flip isDirty back to false (#13397).
|
|
1675
|
-
// Only run when we are currently dirty, otherwise an initial register
|
|
1676
|
-
// for a field with no defaultValue would flip isDirty to true. Reset
|
|
1677
|
-
// paths repopulate _formValues before re-register, so the key is
|
|
1678
|
-
// present then and this branch is skipped (preserves keepDirty).
|
|
1679
1705
|
if (wasUnsetInFormValues &&
|
|
1680
1706
|
_formState.isDirty &&
|
|
1681
1707
|
(_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
|
|
@@ -1685,9 +1711,6 @@ function createFormControl(props = {}) {
|
|
|
1685
1711
|
_subjects.state.next({ ..._formState });
|
|
1686
1712
|
}
|
|
1687
1713
|
}
|
|
1688
|
-
// When a watched field is re-registered after being unregistered and
|
|
1689
|
-
// its value is restored, trigger a deferred watch broadcast so that
|
|
1690
|
-
// components using watch() re-render with the new value.
|
|
1691
1714
|
if (props.shouldUnregister &&
|
|
1692
1715
|
wasUnsetInFormValues &&
|
|
1693
1716
|
!isUndefined(get(_formValues, name)) &&
|
|
@@ -1705,12 +1728,13 @@ function createFormControl(props = {}) {
|
|
|
1705
1728
|
};
|
|
1706
1729
|
if (!_options.disabled) {
|
|
1707
1730
|
if (!isBlurEvent || shouldDirty) {
|
|
1731
|
+
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1708
1732
|
if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
|
|
1709
1733
|
isPreviousDirty = _formState.isDirty;
|
|
1710
|
-
_formState.isDirty = output.isDirty =
|
|
1734
|
+
_formState.isDirty = output.isDirty =
|
|
1735
|
+
!isCurrentFieldPristine || _getDirty();
|
|
1711
1736
|
shouldUpdateField = isPreviousDirty !== output.isDirty;
|
|
1712
1737
|
}
|
|
1713
|
-
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1714
1738
|
isPreviousDirty = !!get(_formState.dirtyFields, name);
|
|
1715
1739
|
if (isCurrentFieldPristine !== _formState.isDirty) {
|
|
1716
1740
|
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
@@ -1909,7 +1933,7 @@ function createFormControl(props = {}) {
|
|
|
1909
1933
|
};
|
|
1910
1934
|
const _getDirty = (name, data) => !_options.disabled &&
|
|
1911
1935
|
(name && data && set(_formValues, name, data),
|
|
1912
|
-
!deepEqual(
|
|
1936
|
+
!deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
|
|
1913
1937
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
1914
1938
|
...(_state.mount
|
|
1915
1939
|
? _formValues
|
|
@@ -1920,7 +1944,7 @@ function createFormControl(props = {}) {
|
|
|
1920
1944
|
: defaultValue),
|
|
1921
1945
|
}, isGlobal, defaultValue);
|
|
1922
1946
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
1923
|
-
const setFieldValue = (name, value, options = {}, skipClone = false) => {
|
|
1947
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
|
|
1924
1948
|
const field = get(_fields, name);
|
|
1925
1949
|
let fieldValue = value;
|
|
1926
1950
|
if (field) {
|
|
@@ -1958,7 +1982,7 @@ function createFormControl(props = {}) {
|
|
|
1958
1982
|
}
|
|
1959
1983
|
else {
|
|
1960
1984
|
fieldReference.ref.value = fieldValue;
|
|
1961
|
-
if (!fieldReference.ref.type) {
|
|
1985
|
+
if (!fieldReference.ref.type && !skipRender) {
|
|
1962
1986
|
_subjects.state.next({
|
|
1963
1987
|
name,
|
|
1964
1988
|
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
@@ -1968,10 +1992,10 @@ function createFormControl(props = {}) {
|
|
|
1968
1992
|
}
|
|
1969
1993
|
}
|
|
1970
1994
|
(options.shouldDirty || options.shouldTouch) &&
|
|
1971
|
-
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty,
|
|
1995
|
+
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
|
|
1972
1996
|
options.shouldValidate && trigger(name);
|
|
1973
1997
|
};
|
|
1974
|
-
const setFieldValues = (name, value, options, skipClone = false) => {
|
|
1998
|
+
const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
|
|
1975
1999
|
for (const fieldKey in value) {
|
|
1976
2000
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
1977
2001
|
return;
|
|
@@ -1983,11 +2007,11 @@ function createFormControl(props = {}) {
|
|
|
1983
2007
|
isObject(fieldValue) ||
|
|
1984
2008
|
(field && !field._f)) &&
|
|
1985
2009
|
!isDateObject(fieldValue)
|
|
1986
|
-
? setFieldValues(fieldName, fieldValue, options, skipClone)
|
|
1987
|
-
: setFieldValue(fieldName, fieldValue, options, skipClone);
|
|
2010
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
|
|
2011
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
|
|
1988
2012
|
}
|
|
1989
2013
|
};
|
|
1990
|
-
const _setValue = (name, value, options, skipClone) => {
|
|
2014
|
+
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
1991
2015
|
const field = get(_fields, name);
|
|
1992
2016
|
const isFieldArray = _names.array.has(name);
|
|
1993
2017
|
const cloneValue = skipClone ? value : cloneObject(value);
|
|
@@ -2007,24 +2031,26 @@ function createFormControl(props = {}) {
|
|
|
2007
2031
|
_proxySubscribeFormState.dirtyFields) &&
|
|
2008
2032
|
options.shouldDirty) {
|
|
2009
2033
|
_updateDirtyFields();
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2034
|
+
if (!skipStateEmit) {
|
|
2035
|
+
_subjects.state.next({
|
|
2036
|
+
name,
|
|
2037
|
+
dirtyFields: _formState.dirtyFields,
|
|
2038
|
+
isDirty: _getDirty(name, cloneValue),
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2015
2041
|
}
|
|
2016
2042
|
}
|
|
2017
2043
|
else {
|
|
2018
2044
|
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
2019
2045
|
isEmptyObject(cloneValue);
|
|
2020
2046
|
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
2021
|
-
setFieldValue(name, cloneValue, options, skipClone);
|
|
2047
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2022
2048
|
}
|
|
2023
2049
|
else {
|
|
2024
|
-
setFieldValues(name, cloneValue, options, skipClone);
|
|
2050
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2025
2051
|
}
|
|
2026
2052
|
}
|
|
2027
|
-
if (!isValueUnchanged) {
|
|
2053
|
+
if (!isValueUnchanged && !skipStateEmit) {
|
|
2028
2054
|
const watched = isWatched(name, _names);
|
|
2029
2055
|
const values = skipClone ? _formValues : cloneObject(_formValues);
|
|
2030
2056
|
_subjects.state.next({
|
|
@@ -2044,14 +2070,17 @@ function createFormControl(props = {}) {
|
|
|
2044
2070
|
..._formValues,
|
|
2045
2071
|
...updatedFormValues,
|
|
2046
2072
|
};
|
|
2073
|
+
const flattenedUpdates = flatten(updatedFormValues);
|
|
2047
2074
|
for (const fieldName of _names.mount) {
|
|
2048
|
-
|
|
2075
|
+
if (fieldName in flattenedUpdates) {
|
|
2076
|
+
_setValue(fieldName, flattenedUpdates[fieldName], options, true, true);
|
|
2077
|
+
}
|
|
2049
2078
|
}
|
|
2050
2079
|
_subjects.state.next({
|
|
2051
2080
|
..._formState,
|
|
2052
2081
|
name: undefined,
|
|
2053
2082
|
type: undefined,
|
|
2054
|
-
values: _formValues,
|
|
2083
|
+
...(_valuesSubscriberCount ? { values: _formValues } : {}),
|
|
2055
2084
|
});
|
|
2056
2085
|
if (options.shouldValidate) {
|
|
2057
2086
|
_setValid();
|
|
@@ -2070,8 +2099,6 @@ function createFormControl(props = {}) {
|
|
|
2070
2099
|
(isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
|
|
2071
2100
|
deepEqual(fieldValue, get(_formValues, name, fieldValue));
|
|
2072
2101
|
};
|
|
2073
|
-
const validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
2074
|
-
const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
2075
2102
|
if (field) {
|
|
2076
2103
|
let error;
|
|
2077
2104
|
let isValid;
|
|
@@ -2079,12 +2106,13 @@ function createFormControl(props = {}) {
|
|
|
2079
2106
|
? getFieldValue(field._f)
|
|
2080
2107
|
: getEventValue(event);
|
|
2081
2108
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
2082
|
-
const
|
|
2109
|
+
const hasNoValidationEffect = !hasValidation(field._f) &&
|
|
2083
2110
|
!props.validate &&
|
|
2084
2111
|
!_options.resolver &&
|
|
2085
2112
|
!get(_formState.errors, name) &&
|
|
2086
|
-
!field._f.deps
|
|
2087
|
-
|
|
2113
|
+
!field._f.deps;
|
|
2114
|
+
const shouldSkipValidation = hasNoValidationEffect ||
|
|
2115
|
+
skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
|
|
2088
2116
|
const watched = isWatched(name, _names, isBlurEvent);
|
|
2089
2117
|
set(_formValues, name, fieldValue);
|
|
2090
2118
|
if (isBlurEvent) {
|
|
@@ -2102,10 +2130,13 @@ function createFormControl(props = {}) {
|
|
|
2102
2130
|
_subjects.state.next({
|
|
2103
2131
|
name,
|
|
2104
2132
|
type: event.type,
|
|
2105
|
-
|
|
2133
|
+
...(_valuesSubscriberCount
|
|
2134
|
+
? { values: cloneObject(_formValues) }
|
|
2135
|
+
: {}),
|
|
2106
2136
|
});
|
|
2107
2137
|
if (shouldSkipValidation) {
|
|
2108
|
-
if (
|
|
2138
|
+
if ((!hasNoValidationEffect || !_formState.isValid) &&
|
|
2139
|
+
(_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
|
|
2109
2140
|
if (_options.mode === 'onBlur') {
|
|
2110
2141
|
if (isBlurEvent) {
|
|
2111
2142
|
_setValid();
|
|
@@ -2240,8 +2271,6 @@ function createFormControl(props = {}) {
|
|
|
2240
2271
|
const names = name ? convertToArrayPayload(name) : undefined;
|
|
2241
2272
|
names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
|
|
2242
2273
|
if (names) {
|
|
2243
|
-
// Emit for each cleared field with the field name so that
|
|
2244
|
-
// shouldSubscribeByName can filter and avoid broad re-renders
|
|
2245
2274
|
names.forEach((inputName) => {
|
|
2246
2275
|
_subjects.state.next({
|
|
2247
2276
|
name: inputName,
|
|
@@ -2250,7 +2279,6 @@ function createFormControl(props = {}) {
|
|
|
2250
2279
|
});
|
|
2251
2280
|
}
|
|
2252
2281
|
else {
|
|
2253
|
-
// Clear all errors - emit without name to notify all subscribers
|
|
2254
2282
|
_subjects.state.next({
|
|
2255
2283
|
errors: {},
|
|
2256
2284
|
});
|
|
@@ -2259,7 +2287,6 @@ function createFormControl(props = {}) {
|
|
|
2259
2287
|
const setError = (name, error, options) => {
|
|
2260
2288
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
2261
2289
|
const currentError = get(_formState.errors, name) || {};
|
|
2262
|
-
// Don't override existing error messages elsewhere in the object tree.
|
|
2263
2290
|
const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
|
|
2264
2291
|
set(_formState.errors, name, {
|
|
2265
2292
|
...restOfErrorTree,
|
|
@@ -2273,26 +2300,60 @@ function createFormControl(props = {}) {
|
|
|
2273
2300
|
});
|
|
2274
2301
|
options && options.shouldFocus && ref && ref.focus && ref.focus();
|
|
2275
2302
|
};
|
|
2276
|
-
const watch = (name, defaultValue) =>
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
}
|
|
2303
|
+
const watch = (name, defaultValue) => {
|
|
2304
|
+
if (isFunction(name)) {
|
|
2305
|
+
_valuesSubscriberCount++;
|
|
2306
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
2307
|
+
next: (payload) => 'values' in payload &&
|
|
2308
|
+
name(payload.values || _getWatch(undefined, defaultValue), payload),
|
|
2309
|
+
});
|
|
2310
|
+
let called = false;
|
|
2311
|
+
return {
|
|
2312
|
+
unsubscribe: () => {
|
|
2313
|
+
if (called) {
|
|
2314
|
+
return;
|
|
2315
|
+
}
|
|
2316
|
+
called = true;
|
|
2317
|
+
_valuesSubscriberCount--;
|
|
2318
|
+
unsubscribe();
|
|
2319
|
+
},
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
return _getWatch(name, defaultValue, true);
|
|
2323
|
+
};
|
|
2324
|
+
const _subscribe = (props) => {
|
|
2325
|
+
var _a;
|
|
2326
|
+
const needsValues = !!((_a = props.formState) === null || _a === void 0 ? void 0 : _a.values);
|
|
2327
|
+
if (needsValues) {
|
|
2328
|
+
_valuesSubscriberCount++;
|
|
2329
|
+
}
|
|
2330
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
2331
|
+
next: (formState) => {
|
|
2332
|
+
if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
|
|
2333
|
+
shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
|
|
2334
|
+
const snapshot = { ..._formValues };
|
|
2335
|
+
props.callback({
|
|
2336
|
+
values: snapshot,
|
|
2337
|
+
..._formState,
|
|
2338
|
+
...formState,
|
|
2339
|
+
defaultValues: _defaultValues,
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
},
|
|
2343
|
+
});
|
|
2344
|
+
if (!needsValues) {
|
|
2345
|
+
return unsubscribe;
|
|
2346
|
+
}
|
|
2347
|
+
let called = false;
|
|
2348
|
+
return () => {
|
|
2349
|
+
if (called) {
|
|
2350
|
+
return;
|
|
2293
2351
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2352
|
+
called = true;
|
|
2353
|
+
_valuesSubscriberCount--;
|
|
2354
|
+
unsubscribe();
|
|
2355
|
+
};
|
|
2356
|
+
};
|
|
2296
2357
|
const subscribe = (props) => {
|
|
2297
2358
|
_state.mount = true;
|
|
2298
2359
|
_proxySubscribeFormState = {
|
|
@@ -2605,6 +2666,8 @@ function createFormControl(props = {}) {
|
|
|
2605
2666
|
values: { ...values },
|
|
2606
2667
|
});
|
|
2607
2668
|
_subjects.state.next({
|
|
2669
|
+
name: undefined,
|
|
2670
|
+
type: undefined,
|
|
2608
2671
|
values: { ...values },
|
|
2609
2672
|
});
|
|
2610
2673
|
}
|
|
@@ -2626,9 +2689,6 @@ function createFormControl(props = {}) {
|
|
|
2626
2689
|
_state.watch = !!_options.shouldUnregister;
|
|
2627
2690
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
2628
2691
|
_state.action = false;
|
|
2629
|
-
// Clear errors synchronously to prevent validation errors on subsequent submissions
|
|
2630
|
-
// This fixes the issue where form.reset() causes validation errors on subsequent
|
|
2631
|
-
// submissions in Next.js 16 with Server Actions
|
|
2632
2692
|
if (!keepStateOptions.keepErrors) {
|
|
2633
2693
|
_formState.errors = {};
|
|
2634
2694
|
}
|
|
@@ -2680,8 +2740,6 @@ function createFormControl(props = {}) {
|
|
|
2680
2740
|
? fieldReference.refs[0]
|
|
2681
2741
|
: fieldReference.ref;
|
|
2682
2742
|
if (fieldRef.focus) {
|
|
2683
|
-
// Use setTimeout to ensure focus happens after any pending state updates
|
|
2684
|
-
// This fixes the issue where setFocus doesn't work immediately after setError
|
|
2685
2743
|
setTimeout(() => {
|
|
2686
2744
|
fieldRef.focus();
|
|
2687
2745
|
options.shouldSelect &&
|
|
@@ -2692,9 +2750,15 @@ function createFormControl(props = {}) {
|
|
|
2692
2750
|
}
|
|
2693
2751
|
};
|
|
2694
2752
|
const _setFormState = (updatedFormState) => {
|
|
2753
|
+
// `name`, `type`, and `values` describe the event that produced this
|
|
2754
|
+
// update, not the form's persisted state (they aren't part of
|
|
2755
|
+
// `FormState`). Merging them in would leak a stale `name`/`type` from
|
|
2756
|
+
// one event into a later, unrelated notification that doesn't specify
|
|
2757
|
+
// its own.
|
|
2758
|
+
const { name, type, values, ...formState } = updatedFormState;
|
|
2695
2759
|
_formState = {
|
|
2696
2760
|
..._formState,
|
|
2697
|
-
...
|
|
2761
|
+
...formState,
|
|
2698
2762
|
};
|
|
2699
2763
|
};
|
|
2700
2764
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
@@ -2775,6 +2839,8 @@ function createFormControl(props = {}) {
|
|
|
2775
2839
|
..._options,
|
|
2776
2840
|
...value,
|
|
2777
2841
|
};
|
|
2842
|
+
_validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
2843
|
+
_validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
2778
2844
|
},
|
|
2779
2845
|
},
|
|
2780
2846
|
subscribe,
|
|
@@ -2909,8 +2975,8 @@ var updateAt = (fieldValues, index, value) => {
|
|
|
2909
2975
|
function useFieldArray(props) {
|
|
2910
2976
|
const formControl = useFormControlContext();
|
|
2911
2977
|
const { control = formControl, name, keyName = 'id', disabled, shouldUnregister, rules, } = props;
|
|
2912
|
-
const [fields, setFields] = React.useState(
|
|
2913
|
-
const ids = React.useRef(
|
|
2978
|
+
const [fields, setFields] = React.useState(control._getFieldArray(name));
|
|
2979
|
+
const ids = React.useRef(control._getFieldArray(name).map(generateId));
|
|
2914
2980
|
const _actioned = React.useRef(false);
|
|
2915
2981
|
if (!disabled) {
|
|
2916
2982
|
control._names.array.add(name);
|
|
@@ -3068,18 +3134,28 @@ function useFieldArray(props) {
|
|
|
3068
3134
|
!validationModes.isOnBlur) {
|
|
3069
3135
|
if (control._options.resolver) {
|
|
3070
3136
|
control._runSchema([name]).then((result) => {
|
|
3137
|
+
var _a, _b;
|
|
3071
3138
|
control._updateIsValidating([name]);
|
|
3072
3139
|
const error = get(result.errors, name);
|
|
3073
3140
|
const existingError = get(control._formState.errors, name);
|
|
3141
|
+
const existingErrorType = existingError && (existingError.type || ((_a = existingError.root) === null || _a === void 0 ? void 0 : _a.type));
|
|
3142
|
+
const existingErrorMessage = existingError &&
|
|
3143
|
+
(existingError.message || ((_b = existingError.root) === null || _b === void 0 ? void 0 : _b.message));
|
|
3074
3144
|
if (existingError
|
|
3075
|
-
? (!error &&
|
|
3145
|
+
? (!error && existingErrorType) ||
|
|
3076
3146
|
(error &&
|
|
3077
|
-
(
|
|
3078
|
-
|
|
3147
|
+
(existingErrorType !== error.type ||
|
|
3148
|
+
existingErrorMessage !== error.message))
|
|
3079
3149
|
: error && error.type) {
|
|
3080
|
-
error
|
|
3081
|
-
|
|
3082
|
-
|
|
3150
|
+
if (error) {
|
|
3151
|
+
isObject(error) &&
|
|
3152
|
+
!Object.keys(error).some((key) => !Number.isNaN(+key))
|
|
3153
|
+
? updateFieldArrayRootError(control._formState.errors, { [name]: error }, name)
|
|
3154
|
+
: set(control._formState.errors, name, error);
|
|
3155
|
+
}
|
|
3156
|
+
else {
|
|
3157
|
+
unset(control._formState.errors, name);
|
|
3158
|
+
}
|
|
3083
3159
|
control._subjects.state.next({
|
|
3084
3160
|
errors: control._formState.errors,
|
|
3085
3161
|
});
|
|
@@ -3099,10 +3175,14 @@ function useFieldArray(props) {
|
|
|
3099
3175
|
}
|
|
3100
3176
|
}
|
|
3101
3177
|
}
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3178
|
+
// External updates that change `fields` (e.g. reset() or setValue() on
|
|
3179
|
+
// the array) already notify subscribers with the up-to-date values
|
|
3180
|
+
// themselves, so only re-broadcast here for genuine array method calls.
|
|
3181
|
+
_actioned.current &&
|
|
3182
|
+
control._subjects.state.next({
|
|
3183
|
+
name,
|
|
3184
|
+
values: cloneObject(control._formValues),
|
|
3185
|
+
});
|
|
3106
3186
|
control._names.focus &&
|
|
3107
3187
|
iterateFieldsByAction(control._fields, (ref, key) => {
|
|
3108
3188
|
if (control._names.focus &&
|
|
@@ -3164,8 +3244,9 @@ function useFieldArray(props) {
|
|
|
3164
3244
|
]),
|
|
3165
3245
|
fields: React.useMemo(() => fields.map((field, index) => ({
|
|
3166
3246
|
...field,
|
|
3247
|
+
...(isBoolean(disabled) ? { disabled } : {}),
|
|
3167
3248
|
[keyName]: ids.current[index] || generateId(),
|
|
3168
|
-
})), [fields, keyName]),
|
|
3249
|
+
})), [fields, keyName, disabled]),
|
|
3169
3250
|
};
|
|
3170
3251
|
}
|
|
3171
3252
|
|