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.
@@ -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
- var isKey = (value) => /^\w*$/.test(value);
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
- var stringToPath = (input) => input.split(/[.[\]'"]/g).filter(Boolean);
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
- visited.set(object1, new WeakSet([object2]));
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]) && obj[key] !== null) {
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) => !!fieldReference &&
1136
- !!fieldReference.validate &&
1137
- !!((isFunction(fieldReference.validate) &&
1138
- fieldReference.validate.constructor.name === ASYNC_FUNCTION) ||
1139
- (isObject(fieldReference.validate) &&
1140
- Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION)));
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) => !isBlurEvent &&
1152
- (_names.watchAll ||
1153
- _names.watch.has(name) ||
1154
- [..._names.watch].some((watchName) => name.startsWith(`${watchName}.`)));
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
- return (isEmptyObject(formState) ||
1223
- (isRoot &&
1224
- Object.keys(formState).length >= Object.keys(_proxyFormState).length) ||
1225
- Object.keys(formState).find((key) => _proxyFormState[key] ===
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 = _getDirty();
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(getValues(), _defaultValues));
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, true);
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
- _subjects.state.next({
2011
- name,
2012
- dirtyFields: _formState.dirtyFields,
2013
- isDirty: _getDirty(name, cloneValue),
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
- _setValue(fieldName, get(updatedFormValues, fieldName), options, true);
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 shouldSkipValidation = (!hasValidation(field._f) &&
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
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
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
- values: cloneObject(_formValues),
2133
+ ...(_valuesSubscriberCount
2134
+ ? { values: cloneObject(_formValues) }
2135
+ : {}),
2106
2136
  });
2107
2137
  if (shouldSkipValidation) {
2108
- if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) {
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) => isFunction(name)
2277
- ? _subjects.state.subscribe({
2278
- next: (payload) => 'values' in payload &&
2279
- name(payload.values || _getWatch(undefined, defaultValue), payload),
2280
- })
2281
- : _getWatch(name, defaultValue, true);
2282
- const _subscribe = (props) => _subjects.state.subscribe({
2283
- next: (formState) => {
2284
- if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
2285
- shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
2286
- const snapshot = { ..._formValues };
2287
- props.callback({
2288
- values: snapshot,
2289
- ..._formState,
2290
- ...formState,
2291
- defaultValues: _defaultValues,
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
- }).unsubscribe;
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
- ...updatedFormState,
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(disabled ? [] : control._getFieldArray(name));
2913
- const ids = React.useRef(disabled ? [] : control._getFieldArray(name).map(generateId));
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 && existingError.type) ||
3145
+ ? (!error && existingErrorType) ||
3076
3146
  (error &&
3077
- (existingError.type !== error.type ||
3078
- existingError.message !== error.message))
3147
+ (existingErrorType !== error.type ||
3148
+ existingErrorMessage !== error.message))
3079
3149
  : error && error.type) {
3080
- error
3081
- ? set(control._formState.errors, name, error)
3082
- : unset(control._formState.errors, name);
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
- control._subjects.state.next({
3103
- name,
3104
- values: cloneObject(control._formValues),
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