react-hook-form 8.0.0-beta.2 → 8.0.0-beta.4

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.
Files changed (121) hide show
  1. package/README.md +8 -20
  2. package/dist/constants.d.ts +2 -0
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/controller.d.ts +8 -37
  5. package/dist/controller.d.ts.map +1 -1
  6. package/dist/errorMessage.d.ts +27 -0
  7. package/dist/errorMessage.d.ts.map +1 -0
  8. package/dist/fieldArray.d.ts +37 -0
  9. package/dist/fieldArray.d.ts.map +1 -0
  10. package/dist/form.d.ts +8 -17
  11. package/dist/form.d.ts.map +1 -1
  12. package/dist/formState.d.ts +12 -0
  13. package/dist/formState.d.ts.map +1 -0
  14. package/dist/index.cjs.js +1 -1
  15. package/dist/index.cjs.js.map +1 -1
  16. package/dist/index.d.ts +4 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.esm.mjs +2952 -2347
  19. package/dist/index.esm.mjs.map +1 -1
  20. package/dist/index.umd.js +1 -1
  21. package/dist/index.umd.js.map +1 -1
  22. package/dist/logic/collectDirtyFieldNames.d.ts +3 -0
  23. package/dist/logic/collectDirtyFieldNames.d.ts.map +1 -0
  24. package/dist/logic/createFormControl.d.ts.map +1 -1
  25. package/dist/logic/generateId.d.ts.map +1 -1
  26. package/dist/logic/getCheckboxValue.d.ts.map +1 -1
  27. package/dist/logic/getDirtyFields.d.ts +3 -2
  28. package/dist/logic/getDirtyFields.d.ts.map +1 -1
  29. package/dist/logic/getEventValue.d.ts.map +1 -1
  30. package/dist/logic/{getFieldArrayParentNames.d.ts → getFieldArrayItemNames.d.ts} +1 -1
  31. package/dist/logic/getFieldArrayItemNames.d.ts.map +1 -0
  32. package/dist/logic/getFieldValue.d.ts.map +1 -1
  33. package/dist/logic/getNullAncestorValue.d.ts +5 -0
  34. package/dist/logic/getNullAncestorValue.d.ts.map +1 -0
  35. package/dist/logic/getProxyFormState.d.ts +1 -1
  36. package/dist/logic/getProxyFormState.d.ts.map +1 -1
  37. package/dist/logic/getResolverOptions.d.ts +1 -0
  38. package/dist/logic/getResolverOptions.d.ts.map +1 -1
  39. package/dist/logic/getValueAndMessage.d.ts +1 -4
  40. package/dist/logic/getValueAndMessage.d.ts.map +1 -1
  41. package/dist/logic/hasPromiseValidation.d.ts.map +1 -1
  42. package/dist/logic/hasValidation.d.ts +1 -1
  43. package/dist/logic/hasValidation.d.ts.map +1 -1
  44. package/dist/logic/index.d.ts +2 -3
  45. package/dist/logic/index.d.ts.map +1 -1
  46. package/dist/logic/isNameInFieldArray.d.ts +4 -0
  47. package/dist/logic/isNameInFieldArray.d.ts.map +1 -0
  48. package/dist/logic/isWatched.d.ts.map +1 -1
  49. package/dist/logic/iterateFieldsByAction.d.ts +1 -1
  50. package/dist/logic/iterateFieldsByAction.d.ts.map +1 -1
  51. package/dist/logic/schemaErrorLookup.d.ts.map +1 -1
  52. package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
  53. package/dist/logic/skipValidation.d.ts +1 -4
  54. package/dist/logic/skipValidation.d.ts.map +1 -1
  55. package/dist/logic/unsetEmptyArray.d.ts +1 -1
  56. package/dist/logic/unsetEmptyArray.d.ts.map +1 -1
  57. package/dist/logic/updateFieldArrayRootError.d.ts.map +1 -1
  58. package/dist/logic/validateField.d.ts.map +1 -1
  59. package/dist/react-server.esm.mjs +767 -340
  60. package/dist/react-server.esm.mjs.map +1 -1
  61. package/dist/types/errors.d.ts +9 -4
  62. package/dist/types/errors.d.ts.map +1 -1
  63. package/dist/types/fieldArray.d.ts +25 -1
  64. package/dist/types/fieldArray.d.ts.map +1 -1
  65. package/dist/types/fields.d.ts +1 -0
  66. package/dist/types/fields.d.ts.map +1 -1
  67. package/dist/types/form.d.ts +152 -57
  68. package/dist/types/form.d.ts.map +1 -1
  69. package/dist/types/path/common.d.ts +6 -0
  70. package/dist/types/path/common.d.ts.map +1 -1
  71. package/dist/types/path/eager.d.ts +16 -12
  72. package/dist/types/path/eager.d.ts.map +1 -1
  73. package/dist/types/utils.d.ts +30 -5
  74. package/dist/types/utils.d.ts.map +1 -1
  75. package/dist/types/validator.d.ts +1 -1
  76. package/dist/types/validator.d.ts.map +1 -1
  77. package/dist/types/watch.d.ts +1 -1
  78. package/dist/types/watch.d.ts.map +1 -1
  79. package/dist/useController.d.ts +5 -17
  80. package/dist/useController.d.ts.map +1 -1
  81. package/dist/useFieldArray.d.ts +5 -30
  82. package/dist/useFieldArray.d.ts.map +1 -1
  83. package/dist/useForm.d.ts +7 -22
  84. package/dist/useForm.d.ts.map +1 -1
  85. package/dist/useFormContext.d.ts +11 -47
  86. package/dist/useFormContext.d.ts.map +1 -1
  87. package/dist/useFormState.d.ts +4 -23
  88. package/dist/useFormState.d.ts.map +1 -1
  89. package/dist/useIsomorphicLayoutEffect.d.ts.map +1 -1
  90. package/dist/useResyncOnReconnect.d.ts +5 -0
  91. package/dist/useResyncOnReconnect.d.ts.map +1 -0
  92. package/dist/useWatch.d.ts +7 -140
  93. package/dist/useWatch.d.ts.map +1 -1
  94. package/dist/utils/cloneObject.d.ts.map +1 -1
  95. package/dist/utils/deepEqual.d.ts +1 -1
  96. package/dist/utils/deepEqual.d.ts.map +1 -1
  97. package/dist/utils/flatten.d.ts.map +1 -1
  98. package/dist/utils/formData.d.ts +3 -0
  99. package/dist/utils/formData.d.ts.map +1 -0
  100. package/dist/utils/get.d.ts.map +1 -1
  101. package/dist/utils/has.d.ts +3 -0
  102. package/dist/utils/has.d.ts.map +1 -0
  103. package/dist/utils/index.d.ts +2 -3
  104. package/dist/utils/index.d.ts.map +1 -1
  105. package/dist/utils/isKey.d.ts.map +1 -1
  106. package/dist/utils/json.d.ts +9 -0
  107. package/dist/utils/json.d.ts.map +1 -0
  108. package/dist/utils/set.d.ts.map +1 -1
  109. package/dist/utils/stringToPath.d.ts.map +1 -1
  110. package/dist/utils/unset.d.ts.map +1 -1
  111. package/dist/utils/updateMethodsReference.d.ts.map +1 -1
  112. package/dist/watch.d.ts +4 -16
  113. package/dist/watch.d.ts.map +1 -1
  114. package/package.json +30 -27
  115. package/dist/formStateSubscribe.d.ts +0 -7
  116. package/dist/formStateSubscribe.d.ts.map +0 -1
  117. package/dist/logic/getFieldArrayParentNames.d.ts.map +0 -1
  118. package/dist/logic/getNodeParentName.d.ts +0 -3
  119. package/dist/logic/getNodeParentName.d.ts.map +0 -1
  120. package/dist/utils/deepMerge.d.ts +0 -2
  121. package/dist/utils/deepMerge.d.ts.map +0 -1
@@ -31,38 +31,37 @@ const INPUT_VALIDATION_RULES = {
31
31
  required: 'required',
32
32
  validate: 'validate',
33
33
  };
34
+ const REGISTER_VALIDATION_RULES = [
35
+ INPUT_VALIDATION_RULES.required,
36
+ INPUT_VALIDATION_RULES.min,
37
+ INPUT_VALIDATION_RULES.max,
38
+ INPUT_VALIDATION_RULES.minLength,
39
+ INPUT_VALIDATION_RULES.maxLength,
40
+ INPUT_VALIDATION_RULES.pattern,
41
+ INPUT_VALIDATION_RULES.validate,
42
+ ];
34
43
  const FORM_ERROR_TYPE = 'form';
35
44
  const ROOT_ERROR_TYPE = 'root';
36
-
37
- var isDateObject = (value) => value instanceof Date;
38
-
39
- var isNullOrUndefined = (value) => value == null;
40
-
41
- const isObjectType = (value) => typeof value === 'object';
42
- var isObject = (value) => !isNullOrUndefined(value) &&
43
- !Array.isArray(value) &&
44
- isObjectType(value) &&
45
- !isDateObject(value);
46
-
47
- var isPlainObject = (tempObject) => {
48
- const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
49
- return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
50
- };
45
+ const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
51
46
 
52
47
  var isWeb = typeof window !== 'undefined' &&
53
48
  typeof window.HTMLElement !== 'undefined' &&
54
49
  typeof document !== 'undefined';
55
50
 
56
51
  function cloneObject(data) {
52
+ if (data === null || typeof data !== 'object') {
53
+ return data;
54
+ }
57
55
  if (data instanceof Date) {
58
56
  return new Date(data);
59
57
  }
58
+ const isBlobInstance = typeof Blob !== 'undefined' && data instanceof Blob;
60
59
  const isFileListInstance = typeof FileList !== 'undefined' && data instanceof FileList;
61
- if (isWeb && (data instanceof Blob || isFileListInstance)) {
60
+ if (isWeb && (isBlobInstance || isFileListInstance)) {
62
61
  return data;
63
62
  }
64
63
  const isArray = Array.isArray(data);
65
- if (!isArray && !(isObject(data) && isPlainObject(data))) {
64
+ if (!isArray && data.constructor !== Object) {
66
65
  return data;
67
66
  }
68
67
  const copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
@@ -106,9 +105,25 @@ var createSubject = () => {
106
105
  };
107
106
  };
108
107
 
108
+ var isDateObject = (value) => value instanceof Date;
109
+
110
+ var isNullOrUndefined = (value) => value == null;
111
+
112
+ const isObjectType = (value) => typeof value === 'object';
113
+ var isObject = (value) => !isNullOrUndefined(value) &&
114
+ !Array.isArray(value) &&
115
+ isObjectType(value) &&
116
+ !isDateObject(value);
117
+
118
+ var isPlainObject = (tempObject) => {
119
+ const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
120
+ return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
121
+ };
122
+
109
123
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
110
124
 
111
- function deepEqual(object1, object2, visited = new WeakSet()) {
125
+ const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
126
+ function deepEqual(object1, object2, visited = new WeakMap()) {
112
127
  if (object1 === object2) {
113
128
  return true;
114
129
  }
@@ -123,11 +138,25 @@ function deepEqual(object1, object2, visited = new WeakSet()) {
123
138
  if (keys1.length !== keys2.length) {
124
139
  return false;
125
140
  }
126
- if (visited.has(object1) || visited.has(object2)) {
141
+ if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
142
+ isEmptyObjectWithCustomPrototype(object2, keys2)) {
143
+ return Object.is(object1, object2);
144
+ }
145
+ if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
146
+ return false;
147
+ }
148
+ const visitedPairs = visited.get(object1);
149
+ if (visitedPairs && visitedPairs.has(object2)) {
127
150
  return true;
128
151
  }
129
- visited.add(object1);
130
- visited.add(object2);
152
+ if (visitedPairs) {
153
+ visitedPairs.add(object2);
154
+ }
155
+ else {
156
+ const ws = new WeakSet();
157
+ ws.add(object2);
158
+ visited.set(object1, ws);
159
+ }
131
160
  for (const key of keys1) {
132
161
  const val1 = object1[key];
133
162
  if (!(key in object2)) {
@@ -148,16 +177,15 @@ function deepEqual(object1, object2, visited = new WeakSet()) {
148
177
  }
149
178
 
150
179
  function extractFormValues(fieldsState, formValues) {
151
- const values = {};
180
+ const values = (Array.isArray(fieldsState) ? [] : {});
152
181
  for (const key in fieldsState) {
153
182
  if (fieldsState.hasOwnProperty(key)) {
154
183
  const fieldState = fieldsState[key];
155
184
  const fieldValue = formValues[key];
156
- if (fieldState && isObject(fieldState) && fieldValue) {
157
- const nestedFieldsState = extractFormValues(fieldState, fieldValue);
158
- if (isObject(nestedFieldsState)) {
159
- values[key] = nestedFieldsState;
160
- }
185
+ if (fieldState &&
186
+ (isObject(fieldState) || Array.isArray(fieldState)) &&
187
+ fieldValue) {
188
+ values[key] = extractFormValues(fieldState, fieldValue);
161
189
  }
162
190
  else if (fieldsState[key]) {
163
191
  values[key] = fieldValue;
@@ -167,17 +195,22 @@ function extractFormValues(fieldsState, formValues) {
167
195
  return values;
168
196
  }
169
197
 
170
- var isKey = (value) => /^\w*$/.test(value);
198
+ const IS_KEY_RE = /^\w*$/;
199
+ var isKey = (value) => IS_KEY_RE.test(value);
171
200
 
172
201
  var isUndefined = (val) => val === undefined;
173
202
 
174
- var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
203
+ const FIELD_PATH_RE = /[.[\]'"]/;
204
+ var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
175
205
 
176
206
  var get = (object, path, defaultValue) => {
177
207
  if (!path || !isObject(object)) {
178
208
  return defaultValue;
179
209
  }
180
210
  const paths = isKey(path) ? [path] : stringToPath(path);
211
+ if (paths.some((key) => PROTOTYPE_KEYWORDS.includes(key))) {
212
+ return defaultValue;
213
+ }
181
214
  const result = paths.reduce((result, key) => {
182
215
  return isNullOrUndefined(result) ? undefined : result[key];
183
216
  }, object);
@@ -188,6 +221,24 @@ var get = (object, path, defaultValue) => {
188
221
  : result;
189
222
  };
190
223
 
224
+ const hasOwn = (value, key) => value !== null &&
225
+ isObjectType(value) &&
226
+ Object.prototype.hasOwnProperty.call(value, key);
227
+ var has = (object, path) => {
228
+ if (!path) {
229
+ return false;
230
+ }
231
+ let result = object;
232
+ for (const key of isKey(path) ? [path] : stringToPath(path)) {
233
+ if (!hasOwn(result, key)) {
234
+ // `get` also resolves a path held as a single literal key, eg `{ 'a.b': 1 }`
235
+ return hasOwn(object, path);
236
+ }
237
+ result = result[key];
238
+ }
239
+ return true;
240
+ };
241
+
191
242
  var isBoolean = (value) => typeof value === 'boolean';
192
243
 
193
244
  var isCheckBoxInput = (element) => element.type === 'checkbox';
@@ -234,7 +285,7 @@ var set = (object, path, value) => {
234
285
  ? []
235
286
  : {};
236
287
  }
237
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
288
+ if (PROTOTYPE_KEYWORDS.includes(key)) {
238
289
  return;
239
290
  }
240
291
  object[key] = newValue;
@@ -243,7 +294,7 @@ var set = (object, path, value) => {
243
294
  };
244
295
 
245
296
  function baseGet(object, updatePath) {
246
- const length = updatePath.slice(0, -1).length;
297
+ const length = updatePath.length - 1;
247
298
  let index = 0;
248
299
  while (index < length) {
249
300
  if (isNullOrUndefined(object)) {
@@ -273,6 +324,9 @@ function unset(object, path) {
273
324
  : isKey(path)
274
325
  ? [path]
275
326
  : stringToPath(path);
327
+ if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
328
+ return object;
329
+ }
276
330
  const childObject = paths.length === 1 ? object : baseGet(object, paths);
277
331
  const index = paths.length - 1;
278
332
  const key = paths[index];
@@ -287,6 +341,24 @@ function unset(object, path) {
287
341
  return object;
288
342
  }
289
343
 
344
+ function isDirtyContainer(value) {
345
+ return Array.isArray(value) || isObject(value);
346
+ }
347
+ function collectDirtyFieldNames(dirtyTree, cachedDirtyFields, prefix = '', names = []) {
348
+ for (const key in dirtyTree) {
349
+ const path = prefix ? `${prefix}.${key}` : key;
350
+ const value = dirtyTree[key];
351
+ if (isDirtyContainer(value) &&
352
+ isDirtyContainer(get(cachedDirtyFields, path))) {
353
+ collectDirtyFieldNames(value, cachedDirtyFields, path, names);
354
+ }
355
+ else {
356
+ names.push(path);
357
+ }
358
+ }
359
+ return names;
360
+ }
361
+
290
362
  var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => {
291
363
  if (isString(names)) {
292
364
  isGlobal && _names.watch.add(names);
@@ -294,7 +366,7 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
294
366
  }
295
367
  if (Array.isArray(names)) {
296
368
  return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
297
- get(formValues, fieldName)));
369
+ get(formValues, fieldName, get(defaultValue, fieldName))));
298
370
  }
299
371
  isGlobal && (_names.watchAll = true);
300
372
  return formValues;
@@ -312,12 +384,33 @@ var objectHasFunction = (data) => {
312
384
  function isTraversable(value) {
313
385
  return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
314
386
  }
315
- function markFieldsDirty(data, fields = {}) {
387
+ function isRegisteredLeaf(fieldRef) {
388
+ return !!(fieldRef && '_f' in fieldRef);
389
+ }
390
+ function isEmptyDirtyContainer(value) {
391
+ return Array.isArray(value)
392
+ ? !value.some((item) => !isUndefined(item))
393
+ : !Object.keys(value).length;
394
+ }
395
+ function clearDirtyField(container, key) {
396
+ if (Array.isArray(container)) {
397
+ container[key] = undefined;
398
+ }
399
+ else {
400
+ delete container[key];
401
+ }
402
+ }
403
+ function markFieldsDirty(data, fields = {}, fieldRefs) {
316
404
  for (const key in data) {
317
405
  const value = data[key];
318
- if (isTraversable(value)) {
406
+ const fieldRef = fieldRefs && fieldRefs[key];
407
+ if (isTraversable(value) &&
408
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
319
409
  fields[key] = Array.isArray(value) ? [] : {};
320
- markFieldsDirty(value, fields[key]);
410
+ markFieldsDirty(value, fields[key], fieldRef);
411
+ if (isEmptyDirtyContainer(fields[key])) {
412
+ clearDirtyField(fields, key);
413
+ }
321
414
  }
322
415
  else if (!isUndefined(value)) {
323
416
  fields[key] = true;
@@ -325,63 +418,51 @@ function markFieldsDirty(data, fields = {}) {
325
418
  }
326
419
  return fields;
327
420
  }
328
- function pruneDirtyFields(value) {
329
- if (value === false) {
330
- return undefined;
331
- }
332
- if (value === true) {
333
- return true;
334
- }
335
- if (Array.isArray(value)) {
336
- const result = value.map((value) => pruneDirtyFields(value));
337
- return (result.some((value) => value !== undefined) ? result : undefined);
338
- }
339
- if (isObject(value)) {
340
- const result = {};
341
- for (const key in value) {
342
- const pruned = pruneDirtyFields(value[key]);
343
- if (!isUndefined(pruned)) {
344
- result[key] = pruned;
345
- }
346
- }
347
- return (Object.keys(result).length ? result : undefined);
348
- }
349
- return undefined;
350
- }
351
- function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
421
+ function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
352
422
  if (!dirtyFieldsFromValues) {
353
- dirtyFieldsFromValues = markFieldsDirty(formValues);
423
+ dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
354
424
  }
355
425
  for (const key in data) {
356
426
  const value = data[key];
357
- if (isTraversable(value)) {
427
+ const fieldRef = fieldRefs && fieldRefs[key];
428
+ if (isTraversable(value) &&
429
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
358
430
  if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
359
- dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
431
+ dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
360
432
  }
361
433
  else {
362
- getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
434
+ getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
363
435
  }
436
+ if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
437
+ clearDirtyField(dirtyFieldsFromValues, key);
438
+ }
439
+ }
440
+ else if (deepEqual(value, formValues[key])) {
441
+ clearDirtyField(dirtyFieldsFromValues, key);
364
442
  }
365
443
  else {
366
- const formValue = formValues[key];
367
- dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
444
+ dirtyFieldsFromValues[key] = true;
368
445
  }
369
446
  }
370
- return pruneDirtyFields(dirtyFieldsFromValues) || {};
447
+ return dirtyFieldsFromValues;
371
448
  }
372
449
 
373
450
  var getEventValue = (event) => isObject(event) && event.target
374
451
  ? isCheckBoxInput(event.target)
375
452
  ? event.target.checked
376
- : event.target.value
453
+ : isFileInput(event.target)
454
+ ? event.target.files
455
+ : event.target.value
377
456
  : event;
378
457
 
379
- var getFieldArrayParentNames = (names, name) => {
380
- const parts = name.split('.');
458
+ var getFieldArrayItemNames = (names, name) => {
459
+ const segments = name.split('.');
381
460
  const matches = [];
382
- let prefix = parts[0];
383
- for (let i = 1; i < parts.length; prefix += '.' + parts[i++]) {
384
- !isNaN(+parts[i]) && names.has(prefix) && matches.push(prefix);
461
+ let prefix = segments[0];
462
+ for (let i = 1; i < segments.length; prefix += '.' + segments[i++]) {
463
+ if (!isNaN(+segments[i]) && names.has(prefix)) {
464
+ matches.push(`${prefix}.${segments[i]}`);
465
+ }
385
466
  }
386
467
  return matches;
387
468
  };
@@ -392,23 +473,25 @@ const defaultResult = {
392
473
  };
393
474
  const validResult = { value: true, isValid: true };
394
475
  var getCheckboxValue = (options) => {
395
- if (Array.isArray(options)) {
396
- if (options.length > 1) {
397
- const values = options
398
- .filter((option) => option && option.checked && !option.disabled)
399
- .map((option) => option.value);
400
- return { value: values, isValid: !!values.length };
401
- }
402
- return options[0].checked && !options[0].disabled
403
- ? // @ts-expect-error expected to work in the browser
404
- options[0].attributes && !isUndefined(options[0].attributes.value)
405
- ? isUndefined(options[0].value) || options[0].value === ''
406
- ? validResult
407
- : { value: options[0].value, isValid: true }
408
- : validResult
409
- : defaultResult;
410
- }
411
- return defaultResult;
476
+ if (!Array.isArray(options)) {
477
+ return defaultResult;
478
+ }
479
+ if (options.length > 1) {
480
+ const values = options
481
+ .filter((option) => option && option.checked && !option.disabled)
482
+ .map((option) => option.value);
483
+ return { value: values, isValid: !!values.length };
484
+ }
485
+ const option = options[0];
486
+ if (!option || !option.checked || option.disabled) {
487
+ return defaultResult;
488
+ }
489
+ if (!option.attributes || !('value' in option.attributes)) {
490
+ return validResult;
491
+ }
492
+ return isUndefined(option.value) || option.value === ''
493
+ ? validResult
494
+ : { value: option.value, isValid: true };
412
495
  };
413
496
 
414
497
  var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
@@ -452,7 +535,7 @@ function getFieldValue(_f) {
452
535
  if (isCheckBoxInput(ref)) {
453
536
  return getCheckboxValue(_f.refs).value;
454
537
  }
455
- return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
538
+ return getFieldValueAs(ref.value, _f);
456
539
  }
457
540
 
458
541
  var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
@@ -490,49 +573,73 @@ var getValidationModes = (mode) => ({
490
573
  });
491
574
 
492
575
  const ASYNC_FUNCTION = 'AsyncFunction';
493
- var hasPromiseValidation = (fieldReference) => !!fieldReference &&
494
- !!fieldReference.validate &&
495
- !!((isFunction(fieldReference.validate) &&
496
- fieldReference.validate.constructor.name === ASYNC_FUNCTION) ||
497
- (isObject(fieldReference.validate) &&
498
- Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION)));
576
+ var hasPromiseValidation = (fieldReference) => {
577
+ if (!fieldReference || !fieldReference.validate)
578
+ return false;
579
+ if (isFunction(fieldReference.validate)) {
580
+ return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
581
+ }
582
+ if (isObject(fieldReference.validate)) {
583
+ for (const key in fieldReference.validate) {
584
+ if (fieldReference.validate[key].constructor
585
+ .name === ASYNC_FUNCTION) {
586
+ return true;
587
+ }
588
+ }
589
+ }
590
+ return false;
591
+ };
499
592
 
500
593
  var hasValidation = (options) => options.mount &&
501
594
  (options.required ||
502
- options.min ||
503
- options.max ||
504
- options.maxLength ||
505
- options.minLength ||
595
+ (!isUndefined(options.required) && options.required !== false) ||
596
+ !isUndefined(options.min) ||
597
+ !isUndefined(options.max) ||
598
+ !isUndefined(options.maxLength) ||
599
+ !isUndefined(options.minLength) ||
506
600
  options.pattern ||
507
601
  options.validate);
508
602
 
509
- var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
510
- (_names.watchAll ||
511
- _names.watch.has(name) ||
512
- [..._names.watch].some((watchName) => name.startsWith(watchName) &&
513
- /^\.\w+/.test(name.slice(watchName.length))));
603
+ var isNameInFieldArray = (names, name) => name
604
+ .split('.')
605
+ .some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
606
+
607
+ var isWatched = (name, _names, isBlurEvent) => {
608
+ if (isBlurEvent)
609
+ return false;
610
+ if (_names.watchAll || _names.watch.has(name))
611
+ return true;
612
+ for (const watchName of _names.watch) {
613
+ if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
614
+ return true;
615
+ }
616
+ return false;
617
+ };
514
618
 
515
- const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
619
+ const iterateFieldsByAction = (fields, action, fieldsNames) => {
516
620
  for (const key of fieldsNames || Object.keys(fields)) {
517
- const field = get(fields, key);
621
+ if (key === '_f') {
622
+ continue;
623
+ }
624
+ const field = fieldsNames ? get(fields, key) : fields[key];
518
625
  if (field) {
519
- const { _f, ...currentField } = field;
626
+ const { _f } = field;
520
627
  if (_f) {
521
- if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
628
+ if (_f.refs && _f.refs[0] && action(_f.refs[0], _f.name)) {
522
629
  return true;
523
630
  }
524
- else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
631
+ else if (_f.ref && action(_f.ref, _f.name)) {
525
632
  return true;
526
633
  }
527
634
  else {
528
- if (iterateFieldsByAction(currentField, action)) {
529
- break;
635
+ if (iterateFieldsByAction(field, action)) {
636
+ return true;
530
637
  }
531
638
  }
532
639
  }
533
- else if (isObject(currentField)) {
534
- if (iterateFieldsByAction(currentField, action)) {
535
- break;
640
+ else if (isObject(field) || Array.isArray(field)) {
641
+ if (iterateFieldsByAction(field, action)) {
642
+ return true;
536
643
  }
537
644
  }
538
645
  }
@@ -542,7 +649,7 @@ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
542
649
 
543
650
  function schemaErrorLookup(errors, _fields, name) {
544
651
  const error = get(errors, name);
545
- if (error || isKey(name)) {
652
+ if (error?.type || error?.message || Array.isArray(error)) {
546
653
  return {
547
654
  error,
548
655
  name,
@@ -577,11 +684,10 @@ function schemaErrorLookup(errors, _fields, name) {
577
684
 
578
685
  var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
579
686
  updateFormState(formStateData);
580
- const { name, ...formState } = formStateData;
581
- return (isEmptyObject(formState) ||
582
- (isRoot &&
583
- Object.keys(formState).length >= Object.keys(_proxyFormState).length) ||
584
- Object.keys(formState).find((key) => _proxyFormState[key] ===
687
+ const keys = Object.keys(formStateData).filter((key) => key !== 'name');
688
+ return (!keys.length ||
689
+ (isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
690
+ keys.find((key) => _proxyFormState[key] ===
585
691
  (!isRoot || VALIDATION_MODE.all)));
586
692
  };
587
693
 
@@ -590,7 +696,7 @@ var shouldSubscribeByName = (name, signalName, exact) => !name ||
590
696
  name === signalName ||
591
697
  convertToArrayPayload(name).some((currentName) => currentName &&
592
698
  (exact
593
- ? currentName === signalName
699
+ ? currentName === signalName || currentName.startsWith(signalName + '.')
594
700
  : currentName.startsWith(signalName) ||
595
701
  signalName.startsWith(currentName)));
596
702
 
@@ -610,10 +716,16 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
610
716
  return true;
611
717
  };
612
718
 
613
- var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
719
+ var unsetEmptyArray = (ref, name) => {
720
+ const array = get(ref, name);
721
+ !compact(array).length &&
722
+ !array?.root &&
723
+ unset(ref, name);
724
+ };
614
725
 
615
726
  var updateFieldArrayRootError = (errors, error, name) => {
616
- const fieldArrayErrors = convertToArrayPayload(get(errors, name));
727
+ const existingErrors = get(errors, name);
728
+ const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
617
729
  set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
618
730
  set(errors, name, fieldArrayErrors);
619
731
  return errors;
@@ -639,7 +751,7 @@ var getValueAndMessage = (validationData) => isObject(validationData) && !isRege
639
751
  };
640
752
 
641
753
  var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
642
- const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, } = field._f;
754
+ const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, _c, } = field._f;
643
755
  const inputValue = get(formValues, name);
644
756
  if (!mount || disabledFieldNames.has(name)) {
645
757
  return {};
@@ -647,7 +759,14 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
647
759
  const inputRef = refs ? refs[0] : ref;
648
760
  const setCustomValidity = (message) => {
649
761
  if (shouldUseNativeValidation && inputRef.reportValidity) {
650
- inputRef.setCustomValidity(isBoolean(message) ? '' : message || '');
762
+ const validityMessage = isBoolean(message) ? '' : message || '';
763
+ if (refs) {
764
+ refs.forEach((ref) => isFunction(ref.setCustomValidity) &&
765
+ ref.setCustomValidity(validityMessage));
766
+ }
767
+ else {
768
+ inputRef.setCustomValidity(validityMessage);
769
+ }
651
770
  inputRef.reportValidity();
652
771
  }
653
772
  };
@@ -658,10 +777,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
658
777
  const isEmpty = ((valueAsNumber || isFileInput(ref)) &&
659
778
  isUndefined(ref.value) &&
660
779
  isUndefined(inputValue)) ||
661
- (isHTMLElement(ref) && ref.value === '') ||
780
+ (isHTMLElement(ref) && ref.value === '' && !_c) ||
662
781
  inputValue === '' ||
663
- (Array.isArray(inputValue) && !inputValue.length) ||
664
- (valueAsNumber && typeof inputValue === 'number' && isNaN(inputValue));
782
+ (Array.isArray(inputValue) && !inputValue.length);
665
783
  const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
666
784
  const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => {
667
785
  const message = exceedMax ? maxLengthMessage : minLengthMessage;
@@ -700,7 +818,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
700
818
  let exceedMin;
701
819
  const maxOutput = getValueAndMessage(max);
702
820
  const minOutput = getValueAndMessage(min);
703
- if (!isNullOrUndefined(inputValue) && !isNaN(inputValue)) {
821
+ if (!isNullOrUndefined(inputValue) &&
822
+ !isDateObject(inputValue) &&
823
+ !isNaN(inputValue)) {
704
824
  const valueNumber = ref.valueAsNumber ||
705
825
  (inputValue ? +inputValue : inputValue);
706
826
  if (!isNullOrUndefined(maxOutput.value)) {
@@ -797,7 +917,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
797
917
  ...validateError,
798
918
  ...appendErrorsCurry(key, validateError.message),
799
919
  };
800
- setCustomValidity(validateError.message);
920
+ if (!validateAllFieldCriteria) {
921
+ setCustomValidity(validateError.message);
922
+ }
801
923
  if (validateAllFieldCriteria) {
802
924
  error[name] = validationResult;
803
925
  }
@@ -814,7 +936,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
814
936
  }
815
937
  }
816
938
  }
817
- setCustomValidity(true);
939
+ const fieldError = error[name];
940
+ setCustomValidity(fieldError ? fieldError.message : true);
818
941
  return error;
819
942
  };
820
943
 
@@ -823,6 +946,14 @@ const defaultOptions = {
823
946
  reValidateMode: VALIDATION_MODE.onChange,
824
947
  shouldFocusError: true,
825
948
  };
949
+ const updateDirtyFields = (dirtyFields, nextDirtyFields) => {
950
+ for (const key in dirtyFields) {
951
+ if (!(key in nextDirtyFields)) {
952
+ delete dirtyFields[key];
953
+ }
954
+ }
955
+ Object.assign(dirtyFields, nextDirtyFields);
956
+ };
826
957
  const DEFAULT_FORM_STATE = {
827
958
  submitCount: 0,
828
959
  isDirty: false,
@@ -856,6 +987,7 @@ function createFormControl(props = {}) {
856
987
  : cloneObject(_defaultValues);
857
988
  let _state = {
858
989
  action: false,
990
+ actionArrayLengths: new Map(),
859
991
  mount: false,
860
992
  watch: false,
861
993
  keepIsValid: false,
@@ -868,8 +1000,11 @@ function createFormControl(props = {}) {
868
1000
  watch: new Set(),
869
1001
  registerName: new Set(),
870
1002
  };
871
- let delayErrorCallback;
872
- let timer = 0;
1003
+ const delayErrorCallbacks = {};
1004
+ const timers = {};
1005
+ let _valuesSubscriberCount = 0;
1006
+ let _validationModeBeforeSubmit = getValidationModes(_options.mode);
1007
+ let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
873
1008
  const defaultProxyFormState = {
874
1009
  isDirty: false,
875
1010
  dirtyFields: false,
@@ -885,27 +1020,40 @@ function createFormControl(props = {}) {
885
1020
  let _proxySubscribeFormState = {
886
1021
  ..._proxyFormState,
887
1022
  };
1023
+ const _isTracked = (...keys) => keys.some((key) => _proxyFormState[key] || _proxySubscribeFormState[key]);
888
1024
  const _subjects = {
889
1025
  array: createSubject(),
890
1026
  state: createSubject(),
891
1027
  };
892
- const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
893
- const debounce = (callback) => (wait) => {
894
- clearTimeout(timer);
895
- timer = setTimeout(callback, wait);
1028
+ let _setValidCallId = 0;
1029
+ let _resetCallId = 0;
1030
+ let shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1031
+ const debounce = (name, callback) => (wait) => {
1032
+ clearTimeout(timers[name]);
1033
+ timers[name] = setTimeout(callback, wait);
1034
+ };
1035
+ const cancelDelayedError = (name) => {
1036
+ clearTimeout(timers[name]);
1037
+ delete timers[name];
1038
+ delete delayErrorCallbacks[name];
1039
+ };
1040
+ const cancelDelayedErrorTree = (name) => {
1041
+ cancelDelayedError(name);
1042
+ const prefix = `${name}.`;
1043
+ for (const key of Object.keys(delayErrorCallbacks)) {
1044
+ key.startsWith(prefix) && cancelDelayedError(key);
1045
+ }
896
1046
  };
897
1047
  const _setValid = async (shouldUpdateValid) => {
898
1048
  if (_state.keepIsValid) {
899
1049
  return;
900
1050
  }
901
- if (!_options.disabled &&
902
- (_proxyFormState.isValid ||
903
- _proxySubscribeFormState.isValid ||
904
- shouldUpdateValid)) {
1051
+ if (!_options.disabled && (_isTracked('isValid') || shouldUpdateValid)) {
1052
+ const callId = ++_setValidCallId;
905
1053
  let isValid;
906
1054
  if (_options.resolver) {
907
1055
  isValid = isEmptyObject((await _runSchema()).errors);
908
- _updateIsValidating();
1056
+ callId === _setValidCallId && _updateIsValidating();
909
1057
  }
910
1058
  else {
911
1059
  isValid = await executeBuiltInValidation({
@@ -914,7 +1062,7 @@ function createFormControl(props = {}) {
914
1062
  eventType: EVENTS.VALID,
915
1063
  });
916
1064
  }
917
- if (isValid !== _formState.isValid) {
1065
+ if (callId === _setValidCallId && isValid !== _formState.isValid) {
918
1066
  _subjects.state.next({
919
1067
  isValid,
920
1068
  });
@@ -922,12 +1070,8 @@ function createFormControl(props = {}) {
922
1070
  }
923
1071
  };
924
1072
  const _updateIsValidating = (names, isValidating) => {
925
- if (!_options.disabled &&
926
- (_proxyFormState.isValidating ||
927
- _proxyFormState.validatingFields ||
928
- _proxySubscribeFormState.isValidating ||
929
- _proxySubscribeFormState.validatingFields)) {
930
- (names || Array.from(_names.mount)).forEach((name) => {
1073
+ if (!_options.disabled && _isTracked('isValidating', 'validatingFields')) {
1074
+ (names || _names.mount).forEach((name) => {
931
1075
  if (name) {
932
1076
  isValidating
933
1077
  ? set(_formState.validatingFields, name, isValidating)
@@ -941,35 +1085,50 @@ function createFormControl(props = {}) {
941
1085
  }
942
1086
  };
943
1087
  const _updateDirtyFields = () => {
944
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1088
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
945
1089
  };
946
1090
  const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
947
1091
  if (args && method && !_options.disabled) {
948
1092
  _state.action = true;
949
- if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
950
- const fieldValues = method(get(_fields, name), args.argA, args.argB);
1093
+ const fields = get(_fields, name);
1094
+ if (!_state.actionArrayLengths.has(name)) {
1095
+ _state.actionArrayLengths.set(name, Array.isArray(fields) ? fields.length : 0);
1096
+ }
1097
+ if (shouldUpdateFieldsAndState && Array.isArray(fields)) {
1098
+ const fieldValues = method(fields, args.argA, args.argB);
951
1099
  shouldSetValues && set(_fields, name, fieldValues);
952
1100
  }
953
- if (shouldUpdateFieldsAndState &&
954
- Array.isArray(get(_formState.errors, name))) {
955
- const errors = method(get(_formState.errors, name), args.argA, args.argB);
1101
+ const fieldArrayErrors = get(_formState.errors, name);
1102
+ if (shouldUpdateFieldsAndState && Array.isArray(fieldArrayErrors)) {
1103
+ const rootError = fieldArrayErrors.root;
1104
+ const errors = method(fieldArrayErrors, args.argA, args.argB) || fieldArrayErrors;
1105
+ if (rootError) {
1106
+ errors.root = rootError;
1107
+ }
956
1108
  shouldSetValues && set(_formState.errors, name, errors);
957
1109
  unsetEmptyArray(_formState.errors, name);
958
1110
  }
959
- if ((_proxyFormState.touchedFields ||
960
- _proxySubscribeFormState.touchedFields) &&
961
- shouldUpdateFieldsAndState &&
962
- Array.isArray(get(_formState.touchedFields, name))) {
963
- const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1111
+ const touchedFieldsArray = get(_formState.touchedFields, name);
1112
+ const shouldUpdateTouchedFields = shouldUpdateFieldsAndState && Array.isArray(touchedFieldsArray);
1113
+ if (shouldUpdateTouchedFields) {
1114
+ const touchedFields = method(touchedFieldsArray, args.argA, args.argB);
964
1115
  shouldSetValues && set(_formState.touchedFields, name, touchedFields);
965
1116
  }
966
- if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
1117
+ const dirtyFieldsArray = get(_formState.dirtyFields, name);
1118
+ if (shouldUpdateFieldsAndState && Array.isArray(dirtyFieldsArray)) {
1119
+ const dirtyFields = method(dirtyFieldsArray, args.argA, args.argB) || dirtyFieldsArray;
1120
+ shouldSetValues && set(_formState.dirtyFields, name, dirtyFields);
1121
+ }
1122
+ if (_isTracked('dirtyFields')) {
967
1123
  _updateDirtyFields();
968
1124
  }
969
1125
  _subjects.state.next({
970
1126
  name,
971
1127
  isDirty: _getDirty(name, values),
972
1128
  dirtyFields: _formState.dirtyFields,
1129
+ ...(shouldUpdateTouchedFields && {
1130
+ touchedFields: _formState.touchedFields,
1131
+ }),
973
1132
  errors: _formState.errors,
974
1133
  isValid: _formState.isValid,
975
1134
  });
@@ -980,16 +1139,20 @@ function createFormControl(props = {}) {
980
1139
  };
981
1140
  const updateErrors = (name, error) => {
982
1141
  set(_formState.errors, name, error);
1142
+ _formState.errors = { ..._formState.errors };
983
1143
  _subjects.state.next({
984
1144
  errors: _formState.errors,
985
1145
  });
986
1146
  };
987
1147
  const _setErrors = (errors) => {
1148
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1149
+ const hasErrors = !isEmptyObject(errors);
988
1150
  _formState.errors = errors;
989
1151
  _subjects.state.next({
990
1152
  errors: _formState.errors,
991
- isValid: false,
1153
+ ...(hasErrors ? { isValid: false } : {}),
992
1154
  });
1155
+ !hasErrors && _state.mount && _setValid();
993
1156
  };
994
1157
  const hasExplicitNullIntermediate = (name) => {
995
1158
  const segments = isKey(name) ? [name] : stringToPath(name);
@@ -1007,10 +1170,46 @@ function createFormControl(props = {}) {
1007
1170
  }
1008
1171
  return false;
1009
1172
  };
1173
+ const isStaleArrayField = (name) => {
1174
+ if (!_state.actionArrayLengths.size) {
1175
+ return false;
1176
+ }
1177
+ const segments = isKey(name) ? [name] : stringToPath(name);
1178
+ let node = _formValues;
1179
+ let path = '';
1180
+ let ownerDepth = -1;
1181
+ let ownerPreActionLength = 0;
1182
+ for (let i = 0; i < segments.length; i++) {
1183
+ if (isNullOrUndefined(node)) {
1184
+ return false;
1185
+ }
1186
+ const key = segments[i];
1187
+ path = path ? `${path}.${key}` : key;
1188
+ if (Array.isArray(node) && +key >= node.length) {
1189
+ return ownerDepth === -1
1190
+ ? false
1191
+ : i === ownerDepth
1192
+ ? +key < ownerPreActionLength
1193
+ : true;
1194
+ }
1195
+ if (_state.actionArrayLengths.has(path)) {
1196
+ ownerDepth = i + 1;
1197
+ ownerPreActionLength = _state.actionArrayLengths.get(path);
1198
+ }
1199
+ node = node[key];
1200
+ if (isUndefined(node) &&
1201
+ ownerDepth !== -1 &&
1202
+ i > ownerDepth &&
1203
+ +segments[ownerDepth] < ownerPreActionLength) {
1204
+ return true;
1205
+ }
1206
+ }
1207
+ return false;
1208
+ };
1010
1209
  const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1011
1210
  const field = get(_fields, name);
1012
1211
  if (field) {
1013
- if (hasExplicitNullIntermediate(name)) {
1212
+ if (hasExplicitNullIntermediate(name) || isStaleArrayField(name)) {
1014
1213
  return;
1015
1214
  }
1016
1215
  const wasUnsetInFormValues = isUndefined(get(_formValues, name));
@@ -1021,22 +1220,28 @@ function createFormControl(props = {}) {
1021
1220
  ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1022
1221
  : setFieldValue(name, defaultValue);
1023
1222
  if (_state.mount && !_state.action) {
1024
- _setValid();
1025
- // Re-registering a field after a prior unregister puts its key back
1026
- // into _formValues, which can flip isDirty back to false (#13397).
1027
- // Only run when we are currently dirty, otherwise an initial register
1028
- // for a field with no defaultValue would flip isDirty to true. Reset
1029
- // paths repopulate _formValues before re-register, so the key is
1030
- // present then and this branch is skipped (preserves keepDirty).
1223
+ if (_options.resolver &&
1224
+ _isTracked('isValidating', 'validatingFields')) {
1225
+ Promise.resolve().then(() => _setValid());
1226
+ }
1227
+ else {
1228
+ _setValid();
1229
+ }
1031
1230
  if (wasUnsetInFormValues &&
1032
1231
  _formState.isDirty &&
1033
- (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
1232
+ _isTracked('isDirty')) {
1034
1233
  const isDirty = _getDirty();
1035
1234
  if (!isDirty) {
1036
1235
  _formState.isDirty = false;
1037
1236
  _subjects.state.next({ ..._formState });
1038
1237
  }
1039
1238
  }
1239
+ if (props.shouldUnregister &&
1240
+ wasUnsetInFormValues &&
1241
+ !isUndefined(get(_formValues, name)) &&
1242
+ isWatched(name, _names)) {
1243
+ _state.watch = true;
1244
+ }
1040
1245
  }
1041
1246
  }
1042
1247
  };
@@ -1046,17 +1251,20 @@ function createFormControl(props = {}) {
1046
1251
  const output = {
1047
1252
  name,
1048
1253
  };
1049
- if (!_options.disabled) {
1254
+ // an explicit programmatic update (e.g. setValue with shouldDirty: true)
1255
+ // opts into dirty tracking even when the form is disabled
1256
+ if (!_options.disabled || shouldDirty === true) {
1050
1257
  if (!isBlurEvent || shouldDirty) {
1051
- if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
1258
+ const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1259
+ if (_isTracked('isDirty')) {
1052
1260
  isPreviousDirty = _formState.isDirty;
1053
- _formState.isDirty = output.isDirty = _getDirty();
1261
+ _formState.isDirty = output.isDirty =
1262
+ !isCurrentFieldPristine || _getDirty();
1054
1263
  shouldUpdateField = isPreviousDirty !== output.isDirty;
1055
1264
  }
1056
- const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1057
1265
  isPreviousDirty = !!get(_formState.dirtyFields, name);
1058
1266
  if (isCurrentFieldPristine !== _formState.isDirty) {
1059
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1267
+ updateDirtyFields(_formState.dirtyFields, getDirtyFields(_defaultValues, _formValues, undefined, _fields));
1060
1268
  }
1061
1269
  else {
1062
1270
  isCurrentFieldPristine
@@ -1066,8 +1274,7 @@ function createFormControl(props = {}) {
1066
1274
  output.dirtyFields = _formState.dirtyFields;
1067
1275
  shouldUpdateField =
1068
1276
  shouldUpdateField ||
1069
- ((_proxyFormState.dirtyFields ||
1070
- _proxySubscribeFormState.dirtyFields) &&
1277
+ (_isTracked('dirtyFields') &&
1071
1278
  isPreviousDirty !== !isCurrentFieldPristine);
1072
1279
  }
1073
1280
  if (isBlurEvent) {
@@ -1077,8 +1284,7 @@ function createFormControl(props = {}) {
1077
1284
  output.touchedFields = _formState.touchedFields;
1078
1285
  shouldUpdateField =
1079
1286
  shouldUpdateField ||
1080
- ((_proxyFormState.touchedFields ||
1081
- _proxySubscribeFormState.touchedFields) &&
1287
+ (_isTracked('touchedFields') &&
1082
1288
  isPreviousFieldTouched !== isBlurEvent);
1083
1289
  }
1084
1290
  }
@@ -1088,19 +1294,19 @@ function createFormControl(props = {}) {
1088
1294
  };
1089
1295
  const shouldRenderByError = (name, isValid, error, fieldState) => {
1090
1296
  const previousFieldError = get(_formState.errors, name);
1091
- const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1297
+ const shouldUpdateValid = _isTracked('isValid') &&
1092
1298
  isBoolean(isValid) &&
1093
1299
  _formState.isValid !== isValid;
1094
1300
  if (_options.delayError && error) {
1095
- delayErrorCallback = debounce(() => updateErrors(name, error));
1096
- delayErrorCallback(_options.delayError);
1301
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
1302
+ delayErrorCallbacks[name](_options.delayError);
1097
1303
  }
1098
1304
  else {
1099
- clearTimeout(timer);
1100
- delayErrorCallback = null;
1305
+ cancelDelayedError(name);
1101
1306
  error
1102
1307
  ? set(_formState.errors, name, error)
1103
1308
  : unset(_formState.errors, name);
1309
+ _formState.errors = { ..._formState.errors };
1104
1310
  }
1105
1311
  if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1106
1312
  !isEmptyObject(fieldState) ||
@@ -1111,10 +1317,6 @@ function createFormControl(props = {}) {
1111
1317
  errors: _formState.errors,
1112
1318
  name,
1113
1319
  };
1114
- _formState = {
1115
- ..._formState,
1116
- ...updatedFormState,
1117
- };
1118
1320
  _subjects.state.next(updatedFormState);
1119
1321
  }
1120
1322
  };
@@ -1123,52 +1325,76 @@ function createFormControl(props = {}) {
1123
1325
  return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1124
1326
  };
1125
1327
  const executeSchemaAndUpdateState = async (names) => {
1328
+ const resetCallId = _resetCallId;
1126
1329
  const { errors } = await _runSchema(names);
1330
+ if (resetCallId !== _resetCallId) {
1331
+ return errors;
1332
+ }
1127
1333
  _updateIsValidating(names);
1128
1334
  if (names) {
1129
1335
  for (const name of names) {
1130
1336
  const error = get(errors, name);
1131
- error
1132
- ? _names.array.has(name) && isObject(error)
1133
- ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
1134
- : set(_formState.errors, name, error)
1135
- : unset(_formState.errors, name);
1136
- }
1337
+ cancelDelayedErrorTree(name);
1338
+ const isFieldArrayRootError = _names.array.has(name) &&
1339
+ isObject(error) &&
1340
+ !Object.keys(error).some((key) => !Number.isNaN(Number(key)));
1341
+ const field = get(_fields, name);
1342
+ const hasNestedFields = isObject(field) && Object.keys(field).some((key) => key !== '_f');
1343
+ isFieldArrayRootError
1344
+ ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
1345
+ : error?.type ||
1346
+ error?.message ||
1347
+ Array.isArray(error) ||
1348
+ (isObject(error) && hasNestedFields)
1349
+ ? set(_formState.errors, name, error)
1350
+ : unset(_formState.errors, name);
1351
+ }
1352
+ _formState.errors = { ..._formState.errors };
1137
1353
  }
1138
1354
  else {
1355
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1139
1356
  _formState.errors = errors;
1140
1357
  }
1141
1358
  return errors;
1142
1359
  };
1143
1360
  const validateForm = async ({ name, eventType, }) => {
1144
- if (props.validate) {
1145
- const result = await props.validate({
1361
+ if (_options.validate) {
1362
+ const resetCallId = _resetCallId;
1363
+ const result = await _options.validate({
1146
1364
  formValues: _formValues,
1147
1365
  formState: _formState,
1148
1366
  name,
1149
1367
  eventType,
1150
1368
  });
1369
+ if (resetCallId !== _resetCallId) {
1370
+ return true;
1371
+ }
1151
1372
  if (isObject(result)) {
1373
+ let isValid = true;
1374
+ clearErrors(FORM_ERROR_TYPE);
1152
1375
  for (const key in result) {
1153
1376
  const error = result[key];
1154
1377
  if (error) {
1378
+ isValid = false;
1155
1379
  setError(`${FORM_ERROR_TYPE}.${key}`, {
1156
1380
  message: isString(error.message) ? error.message : '',
1157
1381
  type: error.type || INPUT_VALIDATION_RULES.validate,
1158
1382
  });
1159
1383
  }
1160
1384
  }
1385
+ return isValid;
1161
1386
  }
1162
1387
  else if (isString(result) || !result) {
1163
1388
  setError(FORM_ERROR_TYPE, {
1164
1389
  message: result || '',
1165
1390
  type: INPUT_VALIDATION_RULES.validate,
1166
1391
  });
1392
+ return false;
1167
1393
  }
1168
1394
  else {
1169
1395
  clearErrors(FORM_ERROR_TYPE);
1396
+ return true;
1170
1397
  }
1171
- return result;
1172
1398
  }
1173
1399
  return true;
1174
1400
  };
@@ -1176,7 +1402,8 @@ function createFormControl(props = {}) {
1176
1402
  valid: true,
1177
1403
  runRootValidation: false,
1178
1404
  }, }) => {
1179
- if (props.validate) {
1405
+ const resetCallId = _resetCallId;
1406
+ if (_options.validate && !context.runRootValidation) {
1180
1407
  context.runRootValidation = true;
1181
1408
  const result = await validateForm({
1182
1409
  name,
@@ -1196,14 +1423,14 @@ function createFormControl(props = {}) {
1196
1423
  if (_f) {
1197
1424
  const isFieldArrayRoot = _names.array.has(_f.name);
1198
1425
  const isPromiseFunction = field._f && hasPromiseValidation(field._f);
1199
- const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
1200
- _proxyFormState.isValidating ||
1201
- _proxySubscribeFormState.validatingFields ||
1202
- _proxySubscribeFormState.isValidating;
1426
+ const shouldTrackIsValidatingState = _isTracked('isValidating', 'validatingFields');
1203
1427
  if (isPromiseFunction && shouldTrackIsValidatingState) {
1204
1428
  _updateIsValidating([_f.name], true);
1205
1429
  }
1206
1430
  const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
1431
+ if (resetCallId !== _resetCallId) {
1432
+ return context.valid;
1433
+ }
1207
1434
  if (isPromiseFunction && shouldTrackIsValidatingState) {
1208
1435
  _updateIsValidating([_f.name]);
1209
1436
  }
@@ -1213,12 +1440,14 @@ function createFormControl(props = {}) {
1213
1440
  break;
1214
1441
  }
1215
1442
  }
1216
- !onlyCheckValid &&
1217
- (get(fieldError, _f.name)
1443
+ if (!onlyCheckValid) {
1444
+ cancelDelayedError(_f.name);
1445
+ get(fieldError, _f.name)
1218
1446
  ? isFieldArrayRoot
1219
1447
  ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1220
1448
  : set(_formState.errors, _f.name, fieldError[_f.name])
1221
- : unset(_formState.errors, _f.name));
1449
+ : unset(_formState.errors, _f.name);
1450
+ }
1222
1451
  if (props.shouldUseNativeValidation && fieldError[_f.name]) {
1223
1452
  break;
1224
1453
  }
@@ -1246,20 +1475,17 @@ function createFormControl(props = {}) {
1246
1475
  }
1247
1476
  _names.unMount = new Set();
1248
1477
  };
1249
- const _getDirty = (name, data) => !_options.disabled &&
1250
- (name && data && set(_formValues, name, data),
1251
- !deepEqual(getValues(), _defaultValues));
1478
+ const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
1479
+ !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
1252
1480
  const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
1253
1481
  ...(_state.mount
1254
1482
  ? _formValues
1255
- : isUndefined(defaultValue)
1483
+ : isUndefined(defaultValue) || isString(names)
1256
1484
  ? _defaultValues
1257
- : isString(names)
1258
- ? { [names]: defaultValue }
1259
- : defaultValue),
1485
+ : defaultValue),
1260
1486
  }, isGlobal, defaultValue);
1261
1487
  const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
1262
- const setFieldValue = (name, value, options = {}) => {
1488
+ const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
1263
1489
  const field = get(_fields, name);
1264
1490
  let fieldValue = value;
1265
1491
  if (field) {
@@ -1297,23 +1523,46 @@ function createFormControl(props = {}) {
1297
1523
  }
1298
1524
  else {
1299
1525
  fieldReference.ref.value = fieldValue;
1300
- if (!fieldReference.ref.type) {
1526
+ if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
1301
1527
  _subjects.state.next({
1302
1528
  name,
1303
- values: cloneObject(_formValues),
1529
+ values: skipClone ? _formValues : cloneObject(_formValues),
1304
1530
  });
1305
1531
  }
1306
1532
  }
1307
1533
  }
1308
1534
  }
1309
1535
  (options.shouldDirty || options.shouldTouch) &&
1310
- updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, true);
1311
- options.shouldValidate && trigger(name);
1536
+ updateTouchAndDirty(name, field &&
1537
+ field._f &&
1538
+ !field._f.disabled &&
1539
+ (field._f.valueAsNumber ||
1540
+ field._f.valueAsDate ||
1541
+ field._f.setValueAs)
1542
+ ? getFieldValueAs(value, field._f)
1543
+ : fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
1544
+ options.shouldValidate &&
1545
+ trigger(name, {
1546
+ delayError: options.delayError,
1547
+ });
1548
+ if (options.shouldValidate &&
1549
+ field &&
1550
+ field._f &&
1551
+ field._f.deps &&
1552
+ (!Array.isArray(field._f.deps) || field._f.deps.length > 0)) {
1553
+ trigger(field._f.deps);
1554
+ }
1312
1555
  };
1313
- const setFieldValues = (name, value, options) => {
1556
+ const setFieldValues = (name, value, options, skipClone = false, skipRender = false, skipValueRender = false) => {
1557
+ if (_names.array.has(name)) {
1558
+ _subjects.array.next({
1559
+ name,
1560
+ values: skipClone ? _formValues : cloneObject(_formValues),
1561
+ });
1562
+ }
1314
1563
  for (const fieldKey in value) {
1315
1564
  if (!value.hasOwnProperty(fieldKey)) {
1316
- return;
1565
+ continue;
1317
1566
  }
1318
1567
  const fieldValue = value[fieldKey];
1319
1568
  const fieldName = name + '.' + fieldKey;
@@ -1322,14 +1571,14 @@ function createFormControl(props = {}) {
1322
1571
  isObject(fieldValue) ||
1323
1572
  (field && !field._f)) &&
1324
1573
  !isDateObject(fieldValue)
1325
- ? setFieldValues(fieldName, fieldValue, options)
1326
- : setFieldValue(fieldName, fieldValue, options);
1574
+ ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
1575
+ : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
1327
1576
  }
1328
1577
  };
1329
- const setValue = (name, value, options = {}) => {
1578
+ const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
1330
1579
  const field = get(_fields, name);
1331
1580
  const isFieldArray = _names.array.has(name);
1332
- const cloneValue = cloneObject(value);
1581
+ const cloneValue = skipClone ? value : cloneObject(value);
1333
1582
  const previousValue = get(_formValues, name);
1334
1583
  const isValueUnchanged = deepEqual(previousValue, cloneValue);
1335
1584
  if (!isValueUnchanged) {
@@ -1338,47 +1587,51 @@ function createFormControl(props = {}) {
1338
1587
  if (isFieldArray) {
1339
1588
  _subjects.array.next({
1340
1589
  name,
1341
- values: cloneObject(_formValues),
1590
+ values: skipClone ? _formValues : cloneObject(_formValues),
1342
1591
  });
1343
- if ((_proxyFormState.isDirty ||
1344
- _proxyFormState.dirtyFields ||
1345
- _proxySubscribeFormState.isDirty ||
1346
- _proxySubscribeFormState.dirtyFields) &&
1347
- options.shouldDirty) {
1592
+ if (_isTracked('isDirty', 'dirtyFields') && options.shouldDirty) {
1348
1593
  _updateDirtyFields();
1349
- _subjects.state.next({
1350
- name,
1351
- dirtyFields: _formState.dirtyFields,
1352
- isDirty: _getDirty(name, cloneValue),
1353
- });
1594
+ if (!skipStateEmit) {
1595
+ _subjects.state.next({
1596
+ name,
1597
+ dirtyFields: _formState.dirtyFields,
1598
+ isDirty: _getDirty(name, cloneValue),
1599
+ });
1600
+ }
1354
1601
  }
1602
+ options.shouldValidate &&
1603
+ trigger(name, {
1604
+ delayError: options.delayError,
1605
+ });
1355
1606
  }
1356
1607
  else {
1357
1608
  const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
1358
1609
  isEmptyObject(cloneValue);
1610
+ const skipValueRender = !isValueUnchanged && !skipStateEmit;
1359
1611
  if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
1360
- setFieldValue(name, cloneValue, options);
1612
+ setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
1361
1613
  }
1362
1614
  else {
1363
- setFieldValues(name, cloneValue, options);
1615
+ setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
1364
1616
  }
1365
1617
  }
1366
- if (!isValueUnchanged) {
1618
+ if (!isValueUnchanged && !skipStateEmit) {
1367
1619
  const watched = isWatched(name, _names);
1368
- const values = cloneObject(_formValues);
1369
- if (!isFieldArray) {
1370
- for (const arrayName of getFieldArrayParentNames(_names.array, name)) {
1371
- _subjects.array.next({ name: arrayName, values });
1372
- }
1373
- }
1620
+ const values = skipClone ? _formValues : cloneObject(_formValues);
1374
1621
  _subjects.state.next({
1375
1622
  ...(watched && _formState),
1376
1623
  name: _state.mount || watched ? name : undefined,
1377
1624
  values,
1378
1625
  });
1626
+ if (!isFieldArray) {
1627
+ for (const itemName of getFieldArrayItemNames(_names.array, name)) {
1628
+ _subjects.state.next({ name: itemName, values });
1629
+ }
1630
+ }
1379
1631
  }
1380
1632
  };
1381
- const setValues = (formValues) => {
1633
+ const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
1634
+ const setValues = (formValues, options = {}) => {
1382
1635
  const updatedFormValues = isFunction(formValues)
1383
1636
  ? formValues(_formValues)
1384
1637
  : formValues;
@@ -1388,9 +1641,19 @@ function createFormControl(props = {}) {
1388
1641
  ...updatedFormValues,
1389
1642
  };
1390
1643
  for (const fieldName of _names.mount) {
1391
- setValue(fieldName, get(updatedFormValues, fieldName));
1644
+ if (has(updatedFormValues, fieldName)) {
1645
+ _setValue(fieldName, get(updatedFormValues, fieldName), options, true, true);
1646
+ }
1647
+ }
1648
+ _subjects.state.next({
1649
+ ..._formState,
1650
+ name: undefined,
1651
+ type: undefined,
1652
+ ...(_valuesSubscriberCount ? { values: _formValues } : {}),
1653
+ });
1654
+ if (options.shouldValidate) {
1655
+ _setValid();
1392
1656
  }
1393
- _subjects.state.next({ ..._formState, values: _formValues });
1394
1657
  }
1395
1658
  };
1396
1659
  const onChange = async (event) => {
@@ -1405,8 +1668,6 @@ function createFormControl(props = {}) {
1405
1668
  (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
1406
1669
  deepEqual(fieldValue, get(_formValues, name, fieldValue));
1407
1670
  };
1408
- const validationModeBeforeSubmit = getValidationModes(_options.mode);
1409
- const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1410
1671
  if (field) {
1411
1672
  let error;
1412
1673
  let isValid;
@@ -1414,18 +1675,20 @@ function createFormControl(props = {}) {
1414
1675
  ? getFieldValue(field._f)
1415
1676
  : getEventValue(event);
1416
1677
  const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1417
- const shouldSkipValidation = (!hasValidation(field._f) &&
1418
- !props.validate &&
1678
+ const hasNoValidationEffect = !hasValidation(field._f) &&
1679
+ !_options.validate &&
1419
1680
  !_options.resolver &&
1420
1681
  !get(_formState.errors, name) &&
1421
- !field._f.deps) ||
1422
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
1682
+ !field._f.deps;
1683
+ const shouldSkipValidation = hasNoValidationEffect ||
1684
+ skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
1423
1685
  const watched = isWatched(name, _names, isBlurEvent);
1424
- set(_formValues, name, fieldValue);
1686
+ set(_formValues, name, cloneObject(fieldValue));
1425
1687
  if (isBlurEvent) {
1426
1688
  if (!target || !target.readOnly) {
1427
1689
  field._f.onBlur && field._f.onBlur(event);
1428
- delayErrorCallback && delayErrorCallback(0);
1690
+ const pendingDelayError = delayErrorCallbacks[name];
1691
+ pendingDelayError && pendingDelayError(0);
1429
1692
  }
1430
1693
  }
1431
1694
  else if (field._f.onChange) {
@@ -1437,10 +1700,13 @@ function createFormControl(props = {}) {
1437
1700
  _subjects.state.next({
1438
1701
  name,
1439
1702
  type: event.type,
1440
- values: cloneObject(_formValues),
1703
+ ...(_valuesSubscriberCount
1704
+ ? { values: cloneObject(_formValues) }
1705
+ : {}),
1441
1706
  });
1442
1707
  if (shouldSkipValidation) {
1443
- if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) {
1708
+ if ((!hasNoValidationEffect || !_formState.isValid) &&
1709
+ _isTracked('isValid')) {
1444
1710
  if (_options.mode === 'onBlur') {
1445
1711
  if (isBlurEvent) {
1446
1712
  _setValid();
@@ -1453,7 +1719,7 @@ function createFormControl(props = {}) {
1453
1719
  return (shouldRender &&
1454
1720
  _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
1455
1721
  }
1456
- if (!_options.resolver && props.validate) {
1722
+ if (!_options.resolver && _options.validate) {
1457
1723
  await validateForm({
1458
1724
  name: name,
1459
1725
  eventType: event.type,
@@ -1461,34 +1727,46 @@ function createFormControl(props = {}) {
1461
1727
  }
1462
1728
  !isBlurEvent && watched && _subjects.state.next({ ..._formState });
1463
1729
  if (_options.resolver) {
1730
+ const resetCallId = _resetCallId;
1464
1731
  const { errors } = await _runSchema([name]);
1732
+ if (resetCallId !== _resetCallId) {
1733
+ return;
1734
+ }
1465
1735
  _updateIsValidating([name]);
1466
1736
  _updateIsFieldValueUpdated(fieldValue);
1467
- if (isFieldValueUpdated) {
1468
- const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
1469
- const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
1470
- error = errorLookupResult.error;
1471
- name = errorLookupResult.name;
1472
- isValid = isEmptyObject(errors);
1737
+ if (!isFieldValueUpdated) {
1738
+ !isEmptyObject(fieldState) && _subjects.state.next(fieldState);
1739
+ return;
1473
1740
  }
1741
+ const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
1742
+ const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
1743
+ error = errorLookupResult.error;
1744
+ name = errorLookupResult.name;
1745
+ isValid = isEmptyObject(errors);
1474
1746
  }
1475
1747
  else {
1748
+ const resetCallId = _resetCallId;
1476
1749
  _updateIsValidating([name], true);
1477
1750
  error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
1751
+ if (resetCallId !== _resetCallId) {
1752
+ return;
1753
+ }
1478
1754
  _updateIsValidating([name]);
1479
1755
  _updateIsFieldValueUpdated(fieldValue);
1480
1756
  if (isFieldValueUpdated) {
1481
1757
  if (error) {
1482
1758
  isValid = false;
1483
1759
  }
1484
- else if (_proxyFormState.isValid ||
1485
- _proxySubscribeFormState.isValid) {
1760
+ else if (_isTracked('isValid')) {
1486
1761
  isValid = await executeBuiltInValidation({
1487
1762
  fields: _fields,
1488
1763
  onlyCheckValid: true,
1489
1764
  name: name,
1490
1765
  eventType: event.type,
1491
1766
  });
1767
+ if (resetCallId !== _resetCallId) {
1768
+ return;
1769
+ }
1492
1770
  }
1493
1771
  }
1494
1772
  }
@@ -1512,11 +1790,15 @@ function createFormControl(props = {}) {
1512
1790
  let validationResult;
1513
1791
  const fieldNames = convertToArrayPayload(name);
1514
1792
  if (_options.resolver) {
1793
+ const resetCallId = _resetCallId;
1515
1794
  const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
1516
1795
  isValid = isEmptyObject(errors);
1517
1796
  validationResult = name
1518
1797
  ? !fieldNames.some((name) => get(errors, name))
1519
1798
  : isValid;
1799
+ if (resetCallId !== _resetCallId) {
1800
+ return validationResult;
1801
+ }
1520
1802
  }
1521
1803
  else if (name) {
1522
1804
  validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
@@ -1535,13 +1817,32 @@ function createFormControl(props = {}) {
1535
1817
  eventType: EVENTS.TRIGGER,
1536
1818
  });
1537
1819
  }
1820
+ if (options.delayError && _options.delayError && isString(name)) {
1821
+ const error = get(_formState.errors, name);
1822
+ if (error) {
1823
+ unset(_formState.errors, name);
1824
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
1825
+ delayErrorCallbacks[name](_options.delayError);
1826
+ }
1827
+ else {
1828
+ cancelDelayedError(name);
1829
+ }
1830
+ }
1831
+ if (options.shouldTouch) {
1832
+ for (const fieldName of name ? fieldNames : _names.mount) {
1833
+ !_names.array.has(fieldName) &&
1834
+ set(_formState.touchedFields, fieldName, true);
1835
+ }
1836
+ }
1538
1837
  _subjects.state.next({
1539
1838
  ...(!isString(name) ||
1540
- ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1541
- isValid !== _formState.isValid)
1839
+ (_isTracked('isValid') && isValid !== _formState.isValid)
1542
1840
  ? {}
1543
1841
  : { name }),
1544
1842
  ...(_options.resolver || !name ? { isValid } : {}),
1843
+ ...(options.shouldTouch && _isTracked('touchedFields')
1844
+ ? { touchedFields: _formState.touchedFields }
1845
+ : {}),
1545
1846
  errors: _formState.errors,
1546
1847
  });
1547
1848
  options.shouldFocus &&
@@ -1562,20 +1863,28 @@ function createFormControl(props = {}) {
1562
1863
  ? get(values, fieldNames)
1563
1864
  : fieldNames.map((name) => get(values, name));
1564
1865
  };
1565
- const getFieldState = (name, formState) => ({
1566
- invalid: !!get((formState || _formState).errors, name),
1567
- isDirty: !!get((formState || _formState).dirtyFields, name),
1568
- error: get((formState || _formState).errors, name),
1569
- isValidating: !!get(_formState.validatingFields, name),
1570
- isTouched: !!get((formState || _formState).touchedFields, name),
1571
- });
1866
+ const getErrors = (fieldNames) => isUndefined(fieldNames)
1867
+ ? { ..._formState.errors }
1868
+ : isString(fieldNames)
1869
+ ? get(_formState.errors, fieldNames)
1870
+ : fieldNames.map((name) => get(_formState.errors, name));
1871
+ const getFieldState = (name, formState) => {
1872
+ const targetFormState = formState || _formState;
1873
+ const error = get(targetFormState.errors, name);
1874
+ return {
1875
+ invalid: !!error,
1876
+ isDirty: !!get(targetFormState.dirtyFields, name),
1877
+ error,
1878
+ isValidating: !!get(targetFormState.validatingFields, name),
1879
+ isTouched: !!get(targetFormState.touchedFields, name),
1880
+ };
1881
+ };
1572
1882
  const clearErrors = (name) => {
1573
1883
  const names = name ? convertToArrayPayload(name) : undefined;
1574
- names?.forEach((inputName) => unset(_formState.errors, inputName));
1575
1884
  if (names) {
1576
- // Emit for each cleared field with the field name so that
1577
- // shouldSubscribeByName can filter and avoid broad re-renders
1578
1885
  names.forEach((inputName) => {
1886
+ cancelDelayedErrorTree(inputName);
1887
+ unset(_formState.errors, inputName);
1579
1888
  _subjects.state.next({
1580
1889
  name: inputName,
1581
1890
  errors: _formState.errors,
@@ -1583,17 +1892,18 @@ function createFormControl(props = {}) {
1583
1892
  });
1584
1893
  }
1585
1894
  else {
1586
- // Clear all errors - emit without name to notify all subscribers
1895
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1896
+ _formState.errors = {};
1587
1897
  _subjects.state.next({
1588
- errors: {},
1898
+ errors: _formState.errors,
1589
1899
  });
1590
1900
  }
1591
1901
  };
1592
1902
  const setError = (name, error, options) => {
1903
+ cancelDelayedErrorTree(name);
1593
1904
  const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
1594
1905
  const currentError = get(_formState.errors, name) || {};
1595
- // Don't override existing error messages elsewhere in the object tree.
1596
- const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
1906
+ const { ref: currentRef, message, type, types, ...restOfErrorTree } = currentError;
1597
1907
  set(_formState.errors, name, {
1598
1908
  ...restOfErrorTree,
1599
1909
  ...error,
@@ -1606,21 +1916,59 @@ function createFormControl(props = {}) {
1606
1916
  });
1607
1917
  options && options.shouldFocus && ref && ref.focus && ref.focus();
1608
1918
  };
1609
- const watch = (name, defaultValue) => _getWatch(name, defaultValue, true);
1610
- const _subscribe = (props) => _subjects.state.subscribe({
1611
- next: (formState) => {
1612
- if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
1613
- shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
1614
- const snapshot = { ..._formValues };
1615
- props.callback({
1616
- values: snapshot,
1617
- ..._formState,
1618
- ...formState,
1619
- defaultValues: _defaultValues,
1620
- });
1919
+ const watch = (name, defaultValue) => {
1920
+ if (isFunction(name)) {
1921
+ _valuesSubscriberCount++;
1922
+ const { unsubscribe } = _subjects.state.subscribe({
1923
+ next: (payload) => 'values' in payload &&
1924
+ name(payload.values || _getWatch(undefined, defaultValue), payload),
1925
+ });
1926
+ let called = false;
1927
+ return {
1928
+ unsubscribe: () => {
1929
+ if (called) {
1930
+ return;
1931
+ }
1932
+ called = true;
1933
+ _valuesSubscriberCount--;
1934
+ unsubscribe();
1935
+ },
1936
+ };
1937
+ }
1938
+ return _getWatch(name, defaultValue, true);
1939
+ };
1940
+ const _subscribe = (props) => {
1941
+ const needsValues = !!props.formState?.values;
1942
+ if (needsValues) {
1943
+ _valuesSubscriberCount++;
1944
+ }
1945
+ const { unsubscribe } = _subjects.state.subscribe({
1946
+ next: (formState) => {
1947
+ if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
1948
+ shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
1949
+ const snapshot = { ..._formValues };
1950
+ props.callback({
1951
+ values: snapshot,
1952
+ ..._formState,
1953
+ ...formState,
1954
+ defaultValues: _defaultValues,
1955
+ });
1956
+ }
1957
+ },
1958
+ });
1959
+ if (!needsValues) {
1960
+ return unsubscribe;
1961
+ }
1962
+ let called = false;
1963
+ return () => {
1964
+ if (called) {
1965
+ return;
1621
1966
  }
1622
- },
1623
- }).unsubscribe;
1967
+ called = true;
1968
+ _valuesSubscriberCount--;
1969
+ unsubscribe();
1970
+ };
1971
+ };
1624
1972
  const subscribe = (props) => {
1625
1973
  _state.mount = true;
1626
1974
  _proxySubscribeFormState = {
@@ -1639,11 +1987,15 @@ function createFormControl(props = {}) {
1639
1987
  for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
1640
1988
  _names.mount.delete(fieldName);
1641
1989
  _names.array.delete(fieldName);
1990
+ _names.disabled.delete(fieldName);
1642
1991
  if (!options.keepValue) {
1643
1992
  unset(_fields, fieldName);
1644
1993
  unset(_formValues, fieldName);
1645
1994
  }
1646
- !options.keepError && unset(_formState.errors, fieldName);
1995
+ if (!options.keepError) {
1996
+ cancelDelayedErrorTree(fieldName);
1997
+ unset(_formState.errors, fieldName);
1998
+ }
1647
1999
  !options.keepDirty && unset(_formState.dirtyFields, fieldName);
1648
2000
  !options.keepTouched && unset(_formState.touchedFields, fieldName);
1649
2001
  !options.keepIsValidating &&
@@ -1652,12 +2004,16 @@ function createFormControl(props = {}) {
1652
2004
  !options.keepDefaultValue &&
1653
2005
  unset(_defaultValues, fieldName);
1654
2006
  }
1655
- _subjects.state.next({
1656
- values: cloneObject(_formValues),
1657
- });
2007
+ _valuesSubscriberCount &&
2008
+ _subjects.state.next({
2009
+ values: cloneObject(_formValues),
2010
+ });
1658
2011
  _subjects.state.next({
1659
2012
  ..._formState,
1660
- ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2013
+ ...(options.keepDirty ? {} : { isDirty: _getDirty() }),
2014
+ ...(options.keepIsValidating
2015
+ ? {}
2016
+ : { isValidating: !isEmptyObject(_formState.validatingFields) }),
1661
2017
  });
1662
2018
  !options.keepIsValid && _setValid();
1663
2019
  };
@@ -1686,6 +2042,14 @@ function createFormControl(props = {}) {
1686
2042
  },
1687
2043
  });
1688
2044
  _names.mount.add(name);
2045
+ if (field && field._f) {
2046
+ const nextField = get(_fields, name);
2047
+ for (const rule of REGISTER_VALIDATION_RULES) {
2048
+ if (!(rule in options)) {
2049
+ delete nextField._f[rule];
2050
+ }
2051
+ }
2052
+ }
1689
2053
  if (field && !shouldRevalidateRemount) {
1690
2054
  _setDisabledField({
1691
2055
  disabled: isBoolean(options.disabled)
@@ -1732,20 +2096,23 @@ function createFormControl(props = {}) {
1732
2096
  : fieldRef === field._f.ref) {
1733
2097
  return;
1734
2098
  }
2099
+ const newField = {
2100
+ ...field._f,
2101
+ };
2102
+ if (radioOrCheckbox) {
2103
+ newField.refs = [
2104
+ ...refs.filter(live),
2105
+ fieldRef,
2106
+ ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
2107
+ ];
2108
+ newField.ref = { type: fieldRef.type, name };
2109
+ }
2110
+ else {
2111
+ newField.ref = fieldRef;
2112
+ delete newField.refs;
2113
+ }
1735
2114
  set(_fields, name, {
1736
- _f: {
1737
- ...field._f,
1738
- ...(radioOrCheckbox
1739
- ? {
1740
- refs: [
1741
- ...refs.filter(live),
1742
- fieldRef,
1743
- ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
1744
- ],
1745
- ref: { type: fieldRef.type, name },
1746
- }
1747
- : { ref: fieldRef }),
1748
- },
2115
+ _f: newField,
1749
2116
  });
1750
2117
  updateValidAndValue(name, false, undefined, fieldRef);
1751
2118
  }
@@ -1755,8 +2122,7 @@ function createFormControl(props = {}) {
1755
2122
  field._f.mount = false;
1756
2123
  }
1757
2124
  (_options.shouldUnregister || options.shouldUnregister) &&
1758
- !(getFieldArrayParentNames(_names.array, name).length &&
1759
- _state.action) &&
2125
+ !(isNameInFieldArray(_names.array, name) && _state.action) &&
1760
2126
  _names.unMount.add(name);
1761
2127
  }
1762
2128
  },
@@ -1778,10 +2144,11 @@ function createFormControl(props = {}) {
1778
2144
  });
1779
2145
  }
1780
2146
  }
1781
- }, 0, false);
2147
+ }, 0);
1782
2148
  }
1783
2149
  };
1784
2150
  const handleSubmit = (onValid, onInvalid) => async (e) => {
2151
+ let result = undefined;
1785
2152
  let onValidError = undefined;
1786
2153
  if (e) {
1787
2154
  e.preventDefault && e.preventDefault();
@@ -1793,29 +2160,38 @@ function createFormControl(props = {}) {
1793
2160
  isSubmitting: true,
1794
2161
  });
1795
2162
  if (_options.resolver) {
2163
+ const resetCallId = _resetCallId;
1796
2164
  const { errors, values } = await _runSchema();
2165
+ if (resetCallId !== _resetCallId) {
2166
+ return;
2167
+ }
1797
2168
  _updateIsValidating();
2169
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1798
2170
  _formState.errors = errors;
1799
2171
  fieldValues = cloneObject(values);
1800
2172
  }
1801
2173
  else {
2174
+ const resetCallId = _resetCallId;
1802
2175
  await executeBuiltInValidation({
1803
2176
  fields: _fields,
1804
2177
  eventType: EVENTS.SUBMIT,
1805
2178
  });
2179
+ if (resetCallId !== _resetCallId) {
2180
+ return;
2181
+ }
2182
+ unset(_formState.errors, ROOT_ERROR_TYPE);
1806
2183
  }
1807
2184
  if (_names.disabled.size) {
1808
2185
  for (const name of _names.disabled) {
1809
2186
  unset(fieldValues, name);
1810
2187
  }
1811
2188
  }
1812
- unset(_formState.errors, ROOT_ERROR_TYPE);
1813
2189
  if (isEmptyObject(_formState.errors)) {
1814
2190
  _subjects.state.next({
1815
2191
  errors: {},
1816
2192
  });
1817
2193
  try {
1818
- await onValid(fieldValues, e);
2194
+ result = await onValid(fieldValues, e);
1819
2195
  }
1820
2196
  catch (error) {
1821
2197
  onValidError = error;
@@ -1838,9 +2214,11 @@ function createFormControl(props = {}) {
1838
2214
  if (onValidError) {
1839
2215
  throw onValidError;
1840
2216
  }
2217
+ return result;
1841
2218
  };
1842
2219
  const resetField = (name, options = {}) => {
1843
2220
  if (get(_fields, name)) {
2221
+ unset(_formState.validatingFields, name);
1844
2222
  if (isUndefined(options.defaultValue)) {
1845
2223
  setValue(name, cloneObject(get(_defaultValues, name)));
1846
2224
  }
@@ -1858,17 +2236,24 @@ function createFormControl(props = {}) {
1858
2236
  : _getDirty();
1859
2237
  }
1860
2238
  if (!options.keepError) {
2239
+ cancelDelayedErrorTree(name);
1861
2240
  unset(_formState.errors, name);
1862
- _proxyFormState.isValid && _setValid();
2241
+ _setValid();
1863
2242
  }
1864
- _subjects.state.next({ ..._formState });
2243
+ _subjects.state.next({
2244
+ ..._formState,
2245
+ isValidating: !isEmptyObject(_formState.validatingFields),
2246
+ });
1865
2247
  }
1866
2248
  };
1867
2249
  const _reset = (formValues, keepStateOptions = {}) => {
2250
+ _resetCallId++;
1868
2251
  const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
1869
2252
  const cloneUpdatedValues = cloneObject(updatedValues);
1870
2253
  const isEmptyResetValues = isEmptyObject(formValues);
1871
- const values = isEmptyResetValues ? _defaultValues : cloneUpdatedValues;
2254
+ const values = cloneUpdatedValues;
2255
+ const fieldRefs = _fields;
2256
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1872
2257
  if (!keepStateOptions.keepDefaultValues) {
1873
2258
  _defaultValues = updatedValues;
1874
2259
  }
@@ -1876,9 +2261,9 @@ function createFormControl(props = {}) {
1876
2261
  if (keepStateOptions.keepDirtyValues) {
1877
2262
  const fieldsToCheck = new Set([
1878
2263
  ..._names.mount,
1879
- ...Object.keys(getDirtyFields(_defaultValues, _formValues)),
2264
+ ...collectDirtyFieldNames(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs), _formState.dirtyFields),
1880
2265
  ]);
1881
- for (const fieldName of Array.from(fieldsToCheck)) {
2266
+ for (const fieldName of fieldsToCheck) {
1882
2267
  const isDirty = get(_formState.dirtyFields, fieldName);
1883
2268
  const existingValue = get(_formValues, fieldName);
1884
2269
  const newValue = get(values, fieldName);
@@ -1917,15 +2302,25 @@ function createFormControl(props = {}) {
1917
2302
  _fields = {};
1918
2303
  }
1919
2304
  }
1920
- _formValues = _options.shouldUnregister
1921
- ? keepStateOptions.keepDefaultValues
2305
+ if (_options.shouldUnregister) {
2306
+ _formValues = keepStateOptions.keepDefaultValues
1922
2307
  ? cloneObject(_defaultValues)
1923
- : {}
1924
- : cloneObject(values);
2308
+ : {};
2309
+ if (keepStateOptions.keepFieldsRef) {
2310
+ for (const fieldName of _names.mount) {
2311
+ set(_formValues, fieldName, get(values, fieldName));
2312
+ }
2313
+ }
2314
+ }
2315
+ else {
2316
+ _formValues = cloneObject(values);
2317
+ }
1925
2318
  _subjects.array.next({
1926
2319
  values: { ...values },
1927
2320
  });
1928
2321
  _subjects.state.next({
2322
+ name: undefined,
2323
+ type: undefined,
1929
2324
  values: { ...values },
1930
2325
  });
1931
2326
  }
@@ -1947,9 +2342,7 @@ function createFormControl(props = {}) {
1947
2342
  _state.watch = !!_options.shouldUnregister;
1948
2343
  _state.keepIsValid = !!keepStateOptions.keepIsValid;
1949
2344
  _state.action = false;
1950
- // Clear errors synchronously to prevent validation errors on subsequent submissions
1951
- // This fixes the issue where form.reset() causes validation errors on subsequent
1952
- // submissions in Next.js 16 with Server Actions
2345
+ _state.actionArrayLengths.clear();
1953
2346
  if (!keepStateOptions.keepErrors) {
1954
2347
  _formState.errors = {};
1955
2348
  }
@@ -1961,8 +2354,10 @@ function createFormControl(props = {}) {
1961
2354
  ? false
1962
2355
  : keepStateOptions.keepDirty
1963
2356
  ? _formState.isDirty
1964
- : !!(keepStateOptions.keepDefaultValues &&
1965
- !deepEqual(formValues, _defaultValues)),
2357
+ : keepStateOptions.keepValues
2358
+ ? _getDirty()
2359
+ : !!(keepStateOptions.keepDefaultValues &&
2360
+ !deepEqual(formValues, _defaultValues)),
1966
2361
  isSubmitted: keepStateOptions.keepIsSubmitted
1967
2362
  ? _formState.isSubmitted
1968
2363
  : false,
@@ -1970,16 +2365,22 @@ function createFormControl(props = {}) {
1970
2365
  ? {}
1971
2366
  : keepStateOptions.keepDirtyValues
1972
2367
  ? keepStateOptions.keepDefaultValues && _formValues
1973
- ? getDirtyFields(_defaultValues, _formValues)
2368
+ ? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
1974
2369
  : _formState.dirtyFields
1975
2370
  : keepStateOptions.keepDefaultValues && formValues
1976
- ? getDirtyFields(_defaultValues, formValues)
2371
+ ? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
1977
2372
  : keepStateOptions.keepDirty
1978
2373
  ? _formState.dirtyFields
1979
- : {},
2374
+ : keepStateOptions.keepValues
2375
+ ? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
2376
+ : {},
1980
2377
  touchedFields: keepStateOptions.keepTouched
1981
2378
  ? _formState.touchedFields
1982
2379
  : {},
2380
+ ...(!keepStateOptions.keepIsValidating &&
2381
+ (_formState.isValidating || !isEmptyObject(_formState.validatingFields))
2382
+ ? { validatingFields: {}, isValidating: false }
2383
+ : null),
1983
2384
  errors: keepStateOptions.keepErrors ? _formState.errors : {},
1984
2385
  isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
1985
2386
  ? _formState.isSubmitSuccessful
@@ -1999,8 +2400,6 @@ function createFormControl(props = {}) {
1999
2400
  ? fieldReference.refs[0]
2000
2401
  : fieldReference.ref;
2001
2402
  if (fieldRef.focus) {
2002
- // Use setTimeout to ensure focus happens after any pending state updates
2003
- // This fixes the issue where setFocus doesn't work immediately after setError
2004
2403
  setTimeout(() => {
2005
2404
  fieldRef.focus();
2006
2405
  options.shouldSelect &&
@@ -2011,11 +2410,18 @@ function createFormControl(props = {}) {
2011
2410
  }
2012
2411
  };
2013
2412
  const _setFormState = (updatedFormState) => {
2413
+ // `name`, `type`, and `values` describe the event that produced this
2414
+ // update, not the form's persisted state (they aren't part of
2415
+ // `FormState`). Merging them in would leak a stale `name`/`type` from
2416
+ // one event into a later, unrelated notification that doesn't specify
2417
+ // its own.
2418
+ const { name, type, values, ...formState } = updatedFormState;
2014
2419
  _formState = {
2015
2420
  ..._formState,
2016
- ...updatedFormState,
2421
+ ...formState,
2017
2422
  };
2018
2423
  };
2424
+ _subjects.state.subscribe({ next: _setFormState });
2019
2425
  const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
2020
2426
  _options.defaultValues().then((values) => {
2021
2427
  reset(values, _options.resetOptions);
@@ -2023,6 +2429,21 @@ function createFormControl(props = {}) {
2023
2429
  isLoading: false,
2024
2430
  });
2025
2431
  });
2432
+ const resetDefaultValues = (values, options = {}) => {
2433
+ _defaultValues = cloneObject(values);
2434
+ if (!options.keepDirty) {
2435
+ const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
2436
+ _formState.dirtyFields = newDirtyFields;
2437
+ _formState.isDirty = !isEmptyObject(newDirtyFields);
2438
+ }
2439
+ if (!options.keepIsValid) {
2440
+ _setValid();
2441
+ }
2442
+ _subjects.state.next({
2443
+ ..._formState,
2444
+ defaultValues: _defaultValues,
2445
+ });
2446
+ };
2026
2447
  const methods = {
2027
2448
  control: {
2028
2449
  register,
@@ -2079,6 +2500,10 @@ function createFormControl(props = {}) {
2079
2500
  ..._options,
2080
2501
  ...value,
2081
2502
  };
2503
+ _validationModeBeforeSubmit = getValidationModes(_options.mode);
2504
+ _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
2505
+ shouldDisplayAllAssociatedErrors =
2506
+ _options.criteriaMode === VALIDATION_MODE.all;
2082
2507
  },
2083
2508
  },
2084
2509
  subscribe,
@@ -2089,8 +2514,10 @@ function createFormControl(props = {}) {
2089
2514
  setValue,
2090
2515
  setValues,
2091
2516
  getValues,
2517
+ getErrors,
2092
2518
  reset,
2093
2519
  resetField,
2520
+ resetDefaultValues,
2094
2521
  clearErrors,
2095
2522
  unregister,
2096
2523
  setError,