react-hook-form 8.0.0-beta.3 → 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 (101) hide show
  1. package/README.md +8 -9
  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 +2 -1
  9. package/dist/fieldArray.d.ts.map +1 -1
  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 +2966 -2581
  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/getFieldArrayItemNames.d.ts +4 -0
  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/hasValidation.d.ts +1 -1
  42. package/dist/logic/hasValidation.d.ts.map +1 -1
  43. package/dist/logic/iterateFieldsByAction.d.ts +1 -1
  44. package/dist/logic/iterateFieldsByAction.d.ts.map +1 -1
  45. package/dist/logic/schemaErrorLookup.d.ts.map +1 -1
  46. package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
  47. package/dist/logic/unsetEmptyArray.d.ts +1 -1
  48. package/dist/logic/unsetEmptyArray.d.ts.map +1 -1
  49. package/dist/logic/validateField.d.ts.map +1 -1
  50. package/dist/react-server.esm.mjs +545 -262
  51. package/dist/react-server.esm.mjs.map +1 -1
  52. package/dist/types/errors.d.ts +9 -4
  53. package/dist/types/errors.d.ts.map +1 -1
  54. package/dist/types/fields.d.ts +1 -0
  55. package/dist/types/fields.d.ts.map +1 -1
  56. package/dist/types/form.d.ts +108 -59
  57. package/dist/types/form.d.ts.map +1 -1
  58. package/dist/types/path/common.d.ts +6 -0
  59. package/dist/types/path/common.d.ts.map +1 -1
  60. package/dist/types/path/eager.d.ts +16 -12
  61. package/dist/types/path/eager.d.ts.map +1 -1
  62. package/dist/types/utils.d.ts +30 -5
  63. package/dist/types/utils.d.ts.map +1 -1
  64. package/dist/types/validator.d.ts +1 -1
  65. package/dist/types/validator.d.ts.map +1 -1
  66. package/dist/types/watch.d.ts +1 -1
  67. package/dist/types/watch.d.ts.map +1 -1
  68. package/dist/useController.d.ts +5 -17
  69. package/dist/useController.d.ts.map +1 -1
  70. package/dist/useFieldArray.d.ts +5 -30
  71. package/dist/useFieldArray.d.ts.map +1 -1
  72. package/dist/useForm.d.ts +7 -22
  73. package/dist/useForm.d.ts.map +1 -1
  74. package/dist/useFormContext.d.ts +11 -47
  75. package/dist/useFormContext.d.ts.map +1 -1
  76. package/dist/useFormState.d.ts +4 -23
  77. package/dist/useFormState.d.ts.map +1 -1
  78. package/dist/useResyncOnReconnect.d.ts +5 -0
  79. package/dist/useResyncOnReconnect.d.ts.map +1 -0
  80. package/dist/useWatch.d.ts +7 -140
  81. package/dist/useWatch.d.ts.map +1 -1
  82. package/dist/utils/cloneObject.d.ts.map +1 -1
  83. package/dist/utils/deepEqual.d.ts +1 -1
  84. package/dist/utils/deepEqual.d.ts.map +1 -1
  85. package/dist/utils/flatten.d.ts.map +1 -1
  86. package/dist/utils/formData.d.ts +3 -0
  87. package/dist/utils/formData.d.ts.map +1 -0
  88. package/dist/utils/has.d.ts +3 -0
  89. package/dist/utils/has.d.ts.map +1 -0
  90. package/dist/utils/json.d.ts +9 -0
  91. package/dist/utils/json.d.ts.map +1 -0
  92. package/dist/utils/updateMethodsReference.d.ts.map +1 -1
  93. package/dist/watch.d.ts +4 -16
  94. package/dist/watch.d.ts.map +1 -1
  95. package/package.json +14 -15
  96. package/dist/formStateSubscribe.d.ts +0 -7
  97. package/dist/formStateSubscribe.d.ts.map +0 -1
  98. package/dist/logic/getNodeParentName.d.ts +0 -3
  99. package/dist/logic/getNodeParentName.d.ts.map +0 -1
  100. package/dist/utils/deepMerge.d.ts +0 -2
  101. 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
+ ];
43
+ const FORM_ERROR_TYPE = 'form';
34
44
  const ROOT_ERROR_TYPE = 'root';
35
45
  const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
36
46
 
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
- };
51
-
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,6 +105,21 @@ 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
125
  const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
@@ -163,16 +177,15 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
163
177
  }
164
178
 
165
179
  function extractFormValues(fieldsState, formValues) {
166
- const values = {};
180
+ const values = (Array.isArray(fieldsState) ? [] : {});
167
181
  for (const key in fieldsState) {
168
182
  if (fieldsState.hasOwnProperty(key)) {
169
183
  const fieldState = fieldsState[key];
170
184
  const fieldValue = formValues[key];
171
- if (fieldState && isObject(fieldState) && fieldValue) {
172
- const nestedFieldsState = extractFormValues(fieldState, fieldValue);
173
- if (isObject(nestedFieldsState)) {
174
- values[key] = nestedFieldsState;
175
- }
185
+ if (fieldState &&
186
+ (isObject(fieldState) || Array.isArray(fieldState)) &&
187
+ fieldValue) {
188
+ values[key] = extractFormValues(fieldState, fieldValue);
176
189
  }
177
190
  else if (fieldsState[key]) {
178
191
  values[key] = fieldValue;
@@ -182,24 +195,6 @@ function extractFormValues(fieldsState, formValues) {
182
195
  return values;
183
196
  }
184
197
 
185
- const flatten = (obj) => {
186
- const output = {};
187
- for (const key of Object.keys(obj)) {
188
- if (isObjectType(obj[key]) &&
189
- obj[key] !== null &&
190
- !isDateObject(obj[key])) {
191
- const nested = flatten(obj[key]);
192
- for (const nestedKey of Object.keys(nested)) {
193
- output[`${key}.${nestedKey}`] = nested[nestedKey];
194
- }
195
- }
196
- else {
197
- output[key] = obj[key];
198
- }
199
- }
200
- return output;
201
- };
202
-
203
198
  const IS_KEY_RE = /^\w*$/;
204
199
  var isKey = (value) => IS_KEY_RE.test(value);
205
200
 
@@ -226,6 +221,24 @@ var get = (object, path, defaultValue) => {
226
221
  : result;
227
222
  };
228
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
+
229
242
  var isBoolean = (value) => typeof value === 'boolean';
230
243
 
231
244
  var isCheckBoxInput = (element) => element.type === 'checkbox';
@@ -281,7 +294,7 @@ var set = (object, path, value) => {
281
294
  };
282
295
 
283
296
  function baseGet(object, updatePath) {
284
- const length = updatePath.slice(0, -1).length;
297
+ const length = updatePath.length - 1;
285
298
  let index = 0;
286
299
  while (index < length) {
287
300
  if (isNullOrUndefined(object)) {
@@ -328,6 +341,24 @@ function unset(object, path) {
328
341
  return object;
329
342
  }
330
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
+
331
362
  var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) => {
332
363
  if (isString(names)) {
333
364
  isGlobal && _names.watch.add(names);
@@ -335,7 +366,7 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
335
366
  }
336
367
  if (Array.isArray(names)) {
337
368
  return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
338
- get(formValues, fieldName)));
369
+ get(formValues, fieldName, get(defaultValue, fieldName))));
339
370
  }
340
371
  isGlobal && (_names.watchAll = true);
341
372
  return formValues;
@@ -353,12 +384,33 @@ var objectHasFunction = (data) => {
353
384
  function isTraversable(value) {
354
385
  return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
355
386
  }
356
- 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) {
357
404
  for (const key in data) {
358
405
  const value = data[key];
359
- if (isTraversable(value)) {
406
+ const fieldRef = fieldRefs && fieldRefs[key];
407
+ if (isTraversable(value) &&
408
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
360
409
  fields[key] = Array.isArray(value) ? [] : {};
361
- markFieldsDirty(value, fields[key]);
410
+ markFieldsDirty(value, fields[key], fieldRef);
411
+ if (isEmptyDirtyContainer(fields[key])) {
412
+ clearDirtyField(fields, key);
413
+ }
362
414
  }
363
415
  else if (!isUndefined(value)) {
364
416
  fields[key] = true;
@@ -366,80 +418,80 @@ function markFieldsDirty(data, fields = {}) {
366
418
  }
367
419
  return fields;
368
420
  }
369
- function pruneDirtyFields(value) {
370
- if (value === false) {
371
- return undefined;
372
- }
373
- if (value === true) {
374
- return true;
375
- }
376
- if (Array.isArray(value)) {
377
- const result = value.map((value) => pruneDirtyFields(value));
378
- return (result.some((value) => value !== undefined) ? result : undefined);
379
- }
380
- if (isObject(value)) {
381
- const result = {};
382
- for (const key in value) {
383
- const pruned = pruneDirtyFields(value[key]);
384
- if (!isUndefined(pruned)) {
385
- result[key] = pruned;
386
- }
387
- }
388
- return (Object.keys(result).length ? result : undefined);
389
- }
390
- return undefined;
391
- }
392
- function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
421
+ function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
393
422
  if (!dirtyFieldsFromValues) {
394
- dirtyFieldsFromValues = markFieldsDirty(formValues);
423
+ dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
395
424
  }
396
425
  for (const key in data) {
397
426
  const value = data[key];
398
- if (isTraversable(value)) {
427
+ const fieldRef = fieldRefs && fieldRefs[key];
428
+ if (isTraversable(value) &&
429
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
399
430
  if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
400
- dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
431
+ dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
401
432
  }
402
433
  else {
403
- getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
434
+ getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
435
+ }
436
+ if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
437
+ clearDirtyField(dirtyFieldsFromValues, key);
404
438
  }
405
439
  }
440
+ else if (deepEqual(value, formValues[key])) {
441
+ clearDirtyField(dirtyFieldsFromValues, key);
442
+ }
406
443
  else {
407
- const formValue = formValues[key];
408
- dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
444
+ dirtyFieldsFromValues[key] = true;
409
445
  }
410
446
  }
411
- return pruneDirtyFields(dirtyFieldsFromValues) || {};
447
+ return dirtyFieldsFromValues;
412
448
  }
413
449
 
414
450
  var getEventValue = (event) => isObject(event) && event.target
415
451
  ? isCheckBoxInput(event.target)
416
452
  ? event.target.checked
417
- : event.target.value
453
+ : isFileInput(event.target)
454
+ ? event.target.files
455
+ : event.target.value
418
456
  : event;
419
457
 
458
+ var getFieldArrayItemNames = (names, name) => {
459
+ const segments = name.split('.');
460
+ const matches = [];
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
+ }
466
+ }
467
+ return matches;
468
+ };
469
+
420
470
  const defaultResult = {
421
471
  value: false,
422
472
  isValid: false,
423
473
  };
424
474
  const validResult = { value: true, isValid: true };
425
475
  var getCheckboxValue = (options) => {
426
- if (Array.isArray(options)) {
427
- if (options.length > 1) {
428
- const values = options
429
- .filter((option) => option && option.checked && !option.disabled)
430
- .map((option) => option.value);
431
- return { value: values, isValid: !!values.length };
432
- }
433
- return options[0].checked && !options[0].disabled
434
- ? // @ts-expect-error expected to work in the browser
435
- options[0].attributes && !isUndefined(options[0].attributes.value)
436
- ? isUndefined(options[0].value) || options[0].value === ''
437
- ? validResult
438
- : { value: options[0].value, isValid: true }
439
- : validResult
440
- : defaultResult;
441
- }
442
- 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 };
443
495
  };
444
496
 
445
497
  var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
@@ -483,7 +535,7 @@ function getFieldValue(_f) {
483
535
  if (isCheckBoxInput(ref)) {
484
536
  return getCheckboxValue(_f.refs).value;
485
537
  }
486
- return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
538
+ return getFieldValueAs(ref.value, _f);
487
539
  }
488
540
 
489
541
  var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
@@ -540,10 +592,11 @@ var hasPromiseValidation = (fieldReference) => {
540
592
 
541
593
  var hasValidation = (options) => options.mount &&
542
594
  (options.required ||
543
- options.min ||
544
- options.max ||
545
- options.maxLength ||
546
- 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) ||
547
600
  options.pattern ||
548
601
  options.validate);
549
602
 
@@ -563,27 +616,30 @@ var isWatched = (name, _names, isBlurEvent) => {
563
616
  return false;
564
617
  };
565
618
 
566
- const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
619
+ const iterateFieldsByAction = (fields, action, fieldsNames) => {
567
620
  for (const key of fieldsNames || Object.keys(fields)) {
568
- const field = get(fields, key);
621
+ if (key === '_f') {
622
+ continue;
623
+ }
624
+ const field = fieldsNames ? get(fields, key) : fields[key];
569
625
  if (field) {
570
- const { _f, ...currentField } = field;
626
+ const { _f } = field;
571
627
  if (_f) {
572
- 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)) {
573
629
  return true;
574
630
  }
575
- else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
631
+ else if (_f.ref && action(_f.ref, _f.name)) {
576
632
  return true;
577
633
  }
578
634
  else {
579
- if (iterateFieldsByAction(currentField, action)) {
580
- break;
635
+ if (iterateFieldsByAction(field, action)) {
636
+ return true;
581
637
  }
582
638
  }
583
639
  }
584
- else if (isObject(currentField)) {
585
- if (iterateFieldsByAction(currentField, action)) {
586
- break;
640
+ else if (isObject(field) || Array.isArray(field)) {
641
+ if (iterateFieldsByAction(field, action)) {
642
+ return true;
587
643
  }
588
644
  }
589
645
  }
@@ -593,7 +649,7 @@ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
593
649
 
594
650
  function schemaErrorLookup(errors, _fields, name) {
595
651
  const error = get(errors, name);
596
- if (error || isKey(name)) {
652
+ if (error?.type || error?.message || Array.isArray(error)) {
597
653
  return {
598
654
  error,
599
655
  name,
@@ -628,8 +684,7 @@ function schemaErrorLookup(errors, _fields, name) {
628
684
 
629
685
  var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
630
686
  updateFormState(formStateData);
631
- const { name, ...formState } = formStateData;
632
- const keys = Object.keys(formState);
687
+ const keys = Object.keys(formStateData).filter((key) => key !== 'name');
633
688
  return (!keys.length ||
634
689
  (isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
635
690
  keys.find((key) => _proxyFormState[key] ===
@@ -661,7 +716,12 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
661
716
  return true;
662
717
  };
663
718
 
664
- 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
+ };
665
725
 
666
726
  var updateFieldArrayRootError = (errors, error, name) => {
667
727
  const existingErrors = get(errors, name);
@@ -691,7 +751,7 @@ var getValueAndMessage = (validationData) => isObject(validationData) && !isRege
691
751
  };
692
752
 
693
753
  var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
694
- 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;
695
755
  const inputValue = get(formValues, name);
696
756
  if (!mount || disabledFieldNames.has(name)) {
697
757
  return {};
@@ -701,7 +761,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
701
761
  if (shouldUseNativeValidation && inputRef.reportValidity) {
702
762
  const validityMessage = isBoolean(message) ? '' : message || '';
703
763
  if (refs) {
704
- refs.forEach((ref) => ref.setCustomValidity(validityMessage));
764
+ refs.forEach((ref) => isFunction(ref.setCustomValidity) &&
765
+ ref.setCustomValidity(validityMessage));
705
766
  }
706
767
  else {
707
768
  inputRef.setCustomValidity(validityMessage);
@@ -716,7 +777,7 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
716
777
  const isEmpty = ((valueAsNumber || isFileInput(ref)) &&
717
778
  isUndefined(ref.value) &&
718
779
  isUndefined(inputValue)) ||
719
- (isHTMLElement(ref) && ref.value === '') ||
780
+ (isHTMLElement(ref) && ref.value === '' && !_c) ||
720
781
  inputValue === '' ||
721
782
  (Array.isArray(inputValue) && !inputValue.length);
722
783
  const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
@@ -757,7 +818,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
757
818
  let exceedMin;
758
819
  const maxOutput = getValueAndMessage(max);
759
820
  const minOutput = getValueAndMessage(min);
760
- if (!isNullOrUndefined(inputValue) && !isNaN(inputValue)) {
821
+ if (!isNullOrUndefined(inputValue) &&
822
+ !isDateObject(inputValue) &&
823
+ !isNaN(inputValue)) {
761
824
  const valueNumber = ref.valueAsNumber ||
762
825
  (inputValue ? +inputValue : inputValue);
763
826
  if (!isNullOrUndefined(maxOutput.value)) {
@@ -854,7 +917,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
854
917
  ...validateError,
855
918
  ...appendErrorsCurry(key, validateError.message),
856
919
  };
857
- setCustomValidity(validateError.message);
920
+ if (!validateAllFieldCriteria) {
921
+ setCustomValidity(validateError.message);
922
+ }
858
923
  if (validateAllFieldCriteria) {
859
924
  error[name] = validationResult;
860
925
  }
@@ -871,7 +936,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
871
936
  }
872
937
  }
873
938
  }
874
- setCustomValidity(true);
939
+ const fieldError = error[name];
940
+ setCustomValidity(fieldError ? fieldError.message : true);
875
941
  return error;
876
942
  };
877
943
 
@@ -880,7 +946,14 @@ const defaultOptions = {
880
946
  reValidateMode: VALIDATION_MODE.onChange,
881
947
  shouldFocusError: true,
882
948
  };
883
- const FORM_ERROR_TYPE = 'form';
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
+ };
884
957
  const DEFAULT_FORM_STATE = {
885
958
  submitCount: 0,
886
959
  isDirty: false,
@@ -914,6 +987,7 @@ function createFormControl(props = {}) {
914
987
  : cloneObject(_defaultValues);
915
988
  let _state = {
916
989
  action: false,
990
+ actionArrayLengths: new Map(),
917
991
  mount: false,
918
992
  watch: false,
919
993
  keepIsValid: false,
@@ -926,8 +1000,8 @@ function createFormControl(props = {}) {
926
1000
  watch: new Set(),
927
1001
  registerName: new Set(),
928
1002
  };
929
- let delayErrorCallback;
930
- let timer = 0;
1003
+ const delayErrorCallbacks = {};
1004
+ const timers = {};
931
1005
  let _valuesSubscriberCount = 0;
932
1006
  let _validationModeBeforeSubmit = getValidationModes(_options.mode);
933
1007
  let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
@@ -946,27 +1020,40 @@ function createFormControl(props = {}) {
946
1020
  let _proxySubscribeFormState = {
947
1021
  ..._proxyFormState,
948
1022
  };
1023
+ const _isTracked = (...keys) => keys.some((key) => _proxyFormState[key] || _proxySubscribeFormState[key]);
949
1024
  const _subjects = {
950
1025
  array: createSubject(),
951
1026
  state: createSubject(),
952
1027
  };
953
- const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
954
- const debounce = (callback) => (wait) => {
955
- clearTimeout(timer);
956
- 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
+ }
957
1046
  };
958
1047
  const _setValid = async (shouldUpdateValid) => {
959
1048
  if (_state.keepIsValid) {
960
1049
  return;
961
1050
  }
962
- if (!_options.disabled &&
963
- (_proxyFormState.isValid ||
964
- _proxySubscribeFormState.isValid ||
965
- shouldUpdateValid)) {
1051
+ if (!_options.disabled && (_isTracked('isValid') || shouldUpdateValid)) {
1052
+ const callId = ++_setValidCallId;
966
1053
  let isValid;
967
1054
  if (_options.resolver) {
968
1055
  isValid = isEmptyObject((await _runSchema()).errors);
969
- _updateIsValidating();
1056
+ callId === _setValidCallId && _updateIsValidating();
970
1057
  }
971
1058
  else {
972
1059
  isValid = await executeBuiltInValidation({
@@ -975,7 +1062,7 @@ function createFormControl(props = {}) {
975
1062
  eventType: EVENTS.VALID,
976
1063
  });
977
1064
  }
978
- if (isValid !== _formState.isValid) {
1065
+ if (callId === _setValidCallId && isValid !== _formState.isValid) {
979
1066
  _subjects.state.next({
980
1067
  isValid,
981
1068
  });
@@ -983,12 +1070,8 @@ function createFormControl(props = {}) {
983
1070
  }
984
1071
  };
985
1072
  const _updateIsValidating = (names, isValidating) => {
986
- if (!_options.disabled &&
987
- (_proxyFormState.isValidating ||
988
- _proxyFormState.validatingFields ||
989
- _proxySubscribeFormState.isValidating ||
990
- _proxySubscribeFormState.validatingFields)) {
991
- (names || Array.from(_names.mount)).forEach((name) => {
1073
+ if (!_options.disabled && _isTracked('isValidating', 'validatingFields')) {
1074
+ (names || _names.mount).forEach((name) => {
992
1075
  if (name) {
993
1076
  isValidating
994
1077
  ? set(_formState.validatingFields, name, isValidating)
@@ -1002,35 +1085,50 @@ function createFormControl(props = {}) {
1002
1085
  }
1003
1086
  };
1004
1087
  const _updateDirtyFields = () => {
1005
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1088
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
1006
1089
  };
1007
1090
  const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
1008
1091
  if (args && method && !_options.disabled) {
1009
1092
  _state.action = true;
1010
- if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
1011
- 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);
1012
1099
  shouldSetValues && set(_fields, name, fieldValues);
1013
1100
  }
1014
- if (shouldUpdateFieldsAndState &&
1015
- Array.isArray(get(_formState.errors, name))) {
1016
- 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
+ }
1017
1108
  shouldSetValues && set(_formState.errors, name, errors);
1018
1109
  unsetEmptyArray(_formState.errors, name);
1019
1110
  }
1020
- if ((_proxyFormState.touchedFields ||
1021
- _proxySubscribeFormState.touchedFields) &&
1022
- shouldUpdateFieldsAndState &&
1023
- Array.isArray(get(_formState.touchedFields, name))) {
1024
- 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);
1025
1115
  shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1026
1116
  }
1027
- 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')) {
1028
1123
  _updateDirtyFields();
1029
1124
  }
1030
1125
  _subjects.state.next({
1031
1126
  name,
1032
1127
  isDirty: _getDirty(name, values),
1033
1128
  dirtyFields: _formState.dirtyFields,
1129
+ ...(shouldUpdateTouchedFields && {
1130
+ touchedFields: _formState.touchedFields,
1131
+ }),
1034
1132
  errors: _formState.errors,
1035
1133
  isValid: _formState.isValid,
1036
1134
  });
@@ -1047,11 +1145,14 @@ function createFormControl(props = {}) {
1047
1145
  });
1048
1146
  };
1049
1147
  const _setErrors = (errors) => {
1148
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1149
+ const hasErrors = !isEmptyObject(errors);
1050
1150
  _formState.errors = errors;
1051
1151
  _subjects.state.next({
1052
1152
  errors: _formState.errors,
1053
- isValid: false,
1153
+ ...(hasErrors ? { isValid: false } : {}),
1054
1154
  });
1155
+ !hasErrors && _state.mount && _setValid();
1055
1156
  };
1056
1157
  const hasExplicitNullIntermediate = (name) => {
1057
1158
  const segments = isKey(name) ? [name] : stringToPath(name);
@@ -1069,10 +1170,46 @@ function createFormControl(props = {}) {
1069
1170
  }
1070
1171
  return false;
1071
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
+ };
1072
1209
  const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1073
1210
  const field = get(_fields, name);
1074
1211
  if (field) {
1075
- if (hasExplicitNullIntermediate(name)) {
1212
+ if (hasExplicitNullIntermediate(name) || isStaleArrayField(name)) {
1076
1213
  return;
1077
1214
  }
1078
1215
  const wasUnsetInFormValues = isUndefined(get(_formValues, name));
@@ -1083,10 +1220,16 @@ function createFormControl(props = {}) {
1083
1220
  ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1084
1221
  : setFieldValue(name, defaultValue);
1085
1222
  if (_state.mount && !_state.action) {
1086
- _setValid();
1223
+ if (_options.resolver &&
1224
+ _isTracked('isValidating', 'validatingFields')) {
1225
+ Promise.resolve().then(() => _setValid());
1226
+ }
1227
+ else {
1228
+ _setValid();
1229
+ }
1087
1230
  if (wasUnsetInFormValues &&
1088
1231
  _formState.isDirty &&
1089
- (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
1232
+ _isTracked('isDirty')) {
1090
1233
  const isDirty = _getDirty();
1091
1234
  if (!isDirty) {
1092
1235
  _formState.isDirty = false;
@@ -1108,10 +1251,12 @@ function createFormControl(props = {}) {
1108
1251
  const output = {
1109
1252
  name,
1110
1253
  };
1111
- 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) {
1112
1257
  if (!isBlurEvent || shouldDirty) {
1113
1258
  const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1114
- if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
1259
+ if (_isTracked('isDirty')) {
1115
1260
  isPreviousDirty = _formState.isDirty;
1116
1261
  _formState.isDirty = output.isDirty =
1117
1262
  !isCurrentFieldPristine || _getDirty();
@@ -1119,7 +1264,7 @@ function createFormControl(props = {}) {
1119
1264
  }
1120
1265
  isPreviousDirty = !!get(_formState.dirtyFields, name);
1121
1266
  if (isCurrentFieldPristine !== _formState.isDirty) {
1122
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1267
+ updateDirtyFields(_formState.dirtyFields, getDirtyFields(_defaultValues, _formValues, undefined, _fields));
1123
1268
  }
1124
1269
  else {
1125
1270
  isCurrentFieldPristine
@@ -1129,8 +1274,7 @@ function createFormControl(props = {}) {
1129
1274
  output.dirtyFields = _formState.dirtyFields;
1130
1275
  shouldUpdateField =
1131
1276
  shouldUpdateField ||
1132
- ((_proxyFormState.dirtyFields ||
1133
- _proxySubscribeFormState.dirtyFields) &&
1277
+ (_isTracked('dirtyFields') &&
1134
1278
  isPreviousDirty !== !isCurrentFieldPristine);
1135
1279
  }
1136
1280
  if (isBlurEvent) {
@@ -1140,8 +1284,7 @@ function createFormControl(props = {}) {
1140
1284
  output.touchedFields = _formState.touchedFields;
1141
1285
  shouldUpdateField =
1142
1286
  shouldUpdateField ||
1143
- ((_proxyFormState.touchedFields ||
1144
- _proxySubscribeFormState.touchedFields) &&
1287
+ (_isTracked('touchedFields') &&
1145
1288
  isPreviousFieldTouched !== isBlurEvent);
1146
1289
  }
1147
1290
  }
@@ -1151,16 +1294,15 @@ function createFormControl(props = {}) {
1151
1294
  };
1152
1295
  const shouldRenderByError = (name, isValid, error, fieldState) => {
1153
1296
  const previousFieldError = get(_formState.errors, name);
1154
- const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1297
+ const shouldUpdateValid = _isTracked('isValid') &&
1155
1298
  isBoolean(isValid) &&
1156
1299
  _formState.isValid !== isValid;
1157
1300
  if (_options.delayError && error) {
1158
- delayErrorCallback = debounce(() => updateErrors(name, error));
1159
- delayErrorCallback(_options.delayError);
1301
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
1302
+ delayErrorCallbacks[name](_options.delayError);
1160
1303
  }
1161
1304
  else {
1162
- clearTimeout(timer);
1163
- delayErrorCallback = null;
1305
+ cancelDelayedError(name);
1164
1306
  error
1165
1307
  ? set(_formState.errors, name, error)
1166
1308
  : unset(_formState.errors, name);
@@ -1175,10 +1317,6 @@ function createFormControl(props = {}) {
1175
1317
  errors: _formState.errors,
1176
1318
  name,
1177
1319
  };
1178
- _formState = {
1179
- ..._formState,
1180
- ...updatedFormState,
1181
- };
1182
1320
  _subjects.state.next(updatedFormState);
1183
1321
  }
1184
1322
  };
@@ -1187,55 +1325,76 @@ function createFormControl(props = {}) {
1187
1325
  return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1188
1326
  };
1189
1327
  const executeSchemaAndUpdateState = async (names) => {
1328
+ const resetCallId = _resetCallId;
1190
1329
  const { errors } = await _runSchema(names);
1330
+ if (resetCallId !== _resetCallId) {
1331
+ return errors;
1332
+ }
1191
1333
  _updateIsValidating(names);
1192
1334
  if (names) {
1193
1335
  for (const name of names) {
1194
1336
  const error = get(errors, name);
1195
- error
1196
- ? _names.array.has(name) &&
1197
- isObject(error) &&
1198
- !Object.keys(error).some((key) => !Number.isNaN(Number(key)))
1199
- ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
1200
- : set(_formState.errors, name, error)
1201
- : unset(_formState.errors, name);
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);
1202
1351
  }
1203
1352
  _formState.errors = { ..._formState.errors };
1204
1353
  }
1205
1354
  else {
1355
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1206
1356
  _formState.errors = errors;
1207
1357
  }
1208
1358
  return errors;
1209
1359
  };
1210
1360
  const validateForm = async ({ name, eventType, }) => {
1211
- if (props.validate) {
1212
- const result = await props.validate({
1361
+ if (_options.validate) {
1362
+ const resetCallId = _resetCallId;
1363
+ const result = await _options.validate({
1213
1364
  formValues: _formValues,
1214
1365
  formState: _formState,
1215
1366
  name,
1216
1367
  eventType,
1217
1368
  });
1369
+ if (resetCallId !== _resetCallId) {
1370
+ return true;
1371
+ }
1218
1372
  if (isObject(result)) {
1373
+ let isValid = true;
1374
+ clearErrors(FORM_ERROR_TYPE);
1219
1375
  for (const key in result) {
1220
1376
  const error = result[key];
1221
1377
  if (error) {
1378
+ isValid = false;
1222
1379
  setError(`${FORM_ERROR_TYPE}.${key}`, {
1223
1380
  message: isString(error.message) ? error.message : '',
1224
1381
  type: error.type || INPUT_VALIDATION_RULES.validate,
1225
1382
  });
1226
1383
  }
1227
1384
  }
1385
+ return isValid;
1228
1386
  }
1229
1387
  else if (isString(result) || !result) {
1230
1388
  setError(FORM_ERROR_TYPE, {
1231
1389
  message: result || '',
1232
1390
  type: INPUT_VALIDATION_RULES.validate,
1233
1391
  });
1392
+ return false;
1234
1393
  }
1235
1394
  else {
1236
1395
  clearErrors(FORM_ERROR_TYPE);
1396
+ return true;
1237
1397
  }
1238
- return result;
1239
1398
  }
1240
1399
  return true;
1241
1400
  };
@@ -1243,7 +1402,8 @@ function createFormControl(props = {}) {
1243
1402
  valid: true,
1244
1403
  runRootValidation: false,
1245
1404
  }, }) => {
1246
- if (props.validate) {
1405
+ const resetCallId = _resetCallId;
1406
+ if (_options.validate && !context.runRootValidation) {
1247
1407
  context.runRootValidation = true;
1248
1408
  const result = await validateForm({
1249
1409
  name,
@@ -1263,14 +1423,14 @@ function createFormControl(props = {}) {
1263
1423
  if (_f) {
1264
1424
  const isFieldArrayRoot = _names.array.has(_f.name);
1265
1425
  const isPromiseFunction = field._f && hasPromiseValidation(field._f);
1266
- const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
1267
- _proxyFormState.isValidating ||
1268
- _proxySubscribeFormState.validatingFields ||
1269
- _proxySubscribeFormState.isValidating;
1426
+ const shouldTrackIsValidatingState = _isTracked('isValidating', 'validatingFields');
1270
1427
  if (isPromiseFunction && shouldTrackIsValidatingState) {
1271
1428
  _updateIsValidating([_f.name], true);
1272
1429
  }
1273
1430
  const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
1431
+ if (resetCallId !== _resetCallId) {
1432
+ return context.valid;
1433
+ }
1274
1434
  if (isPromiseFunction && shouldTrackIsValidatingState) {
1275
1435
  _updateIsValidating([_f.name]);
1276
1436
  }
@@ -1280,12 +1440,14 @@ function createFormControl(props = {}) {
1280
1440
  break;
1281
1441
  }
1282
1442
  }
1283
- !onlyCheckValid &&
1284
- (get(fieldError, _f.name)
1443
+ if (!onlyCheckValid) {
1444
+ cancelDelayedError(_f.name);
1445
+ get(fieldError, _f.name)
1285
1446
  ? isFieldArrayRoot
1286
1447
  ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1287
1448
  : set(_formState.errors, _f.name, fieldError[_f.name])
1288
- : unset(_formState.errors, _f.name));
1449
+ : unset(_formState.errors, _f.name);
1450
+ }
1289
1451
  if (props.shouldUseNativeValidation && fieldError[_f.name]) {
1290
1452
  break;
1291
1453
  }
@@ -1313,20 +1475,17 @@ function createFormControl(props = {}) {
1313
1475
  }
1314
1476
  _names.unMount = new Set();
1315
1477
  };
1316
- const _getDirty = (name, data) => !_options.disabled &&
1317
- (name && data && set(_formValues, name, data),
1318
- !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
1478
+ const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
1479
+ !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
1319
1480
  const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
1320
1481
  ...(_state.mount
1321
1482
  ? _formValues
1322
- : isUndefined(defaultValue)
1483
+ : isUndefined(defaultValue) || isString(names)
1323
1484
  ? _defaultValues
1324
- : isString(names)
1325
- ? { [names]: defaultValue }
1326
- : defaultValue),
1485
+ : defaultValue),
1327
1486
  }, isGlobal, defaultValue);
1328
1487
  const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
1329
- const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
1488
+ const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
1330
1489
  const field = get(_fields, name);
1331
1490
  let fieldValue = value;
1332
1491
  if (field) {
@@ -1364,7 +1523,7 @@ function createFormControl(props = {}) {
1364
1523
  }
1365
1524
  else {
1366
1525
  fieldReference.ref.value = fieldValue;
1367
- if (!fieldReference.ref.type && !skipRender) {
1526
+ if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
1368
1527
  _subjects.state.next({
1369
1528
  name,
1370
1529
  values: skipClone ? _formValues : cloneObject(_formValues),
@@ -1374,13 +1533,36 @@ function createFormControl(props = {}) {
1374
1533
  }
1375
1534
  }
1376
1535
  (options.shouldDirty || options.shouldTouch) &&
1377
- updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
1378
- 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
+ }
1379
1555
  };
1380
- const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
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
+ }
1381
1563
  for (const fieldKey in value) {
1382
1564
  if (!value.hasOwnProperty(fieldKey)) {
1383
- return;
1565
+ continue;
1384
1566
  }
1385
1567
  const fieldValue = value[fieldKey];
1386
1568
  const fieldName = name + '.' + fieldKey;
@@ -1389,8 +1571,8 @@ function createFormControl(props = {}) {
1389
1571
  isObject(fieldValue) ||
1390
1572
  (field && !field._f)) &&
1391
1573
  !isDateObject(fieldValue)
1392
- ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
1393
- : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
1574
+ ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
1575
+ : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
1394
1576
  }
1395
1577
  };
1396
1578
  const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
@@ -1407,11 +1589,7 @@ function createFormControl(props = {}) {
1407
1589
  name,
1408
1590
  values: skipClone ? _formValues : cloneObject(_formValues),
1409
1591
  });
1410
- if ((_proxyFormState.isDirty ||
1411
- _proxyFormState.dirtyFields ||
1412
- _proxySubscribeFormState.isDirty ||
1413
- _proxySubscribeFormState.dirtyFields) &&
1414
- options.shouldDirty) {
1592
+ if (_isTracked('isDirty', 'dirtyFields') && options.shouldDirty) {
1415
1593
  _updateDirtyFields();
1416
1594
  if (!skipStateEmit) {
1417
1595
  _subjects.state.next({
@@ -1421,15 +1599,20 @@ function createFormControl(props = {}) {
1421
1599
  });
1422
1600
  }
1423
1601
  }
1602
+ options.shouldValidate &&
1603
+ trigger(name, {
1604
+ delayError: options.delayError,
1605
+ });
1424
1606
  }
1425
1607
  else {
1426
1608
  const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
1427
1609
  isEmptyObject(cloneValue);
1610
+ const skipValueRender = !isValueUnchanged && !skipStateEmit;
1428
1611
  if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
1429
- setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
1612
+ setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
1430
1613
  }
1431
1614
  else {
1432
- setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
1615
+ setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
1433
1616
  }
1434
1617
  }
1435
1618
  if (!isValueUnchanged && !skipStateEmit) {
@@ -1440,6 +1623,11 @@ function createFormControl(props = {}) {
1440
1623
  name: _state.mount || watched ? name : undefined,
1441
1624
  values,
1442
1625
  });
1626
+ if (!isFieldArray) {
1627
+ for (const itemName of getFieldArrayItemNames(_names.array, name)) {
1628
+ _subjects.state.next({ name: itemName, values });
1629
+ }
1630
+ }
1443
1631
  }
1444
1632
  };
1445
1633
  const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
@@ -1452,10 +1640,9 @@ function createFormControl(props = {}) {
1452
1640
  ..._formValues,
1453
1641
  ...updatedFormValues,
1454
1642
  };
1455
- const flattenedUpdates = flatten(updatedFormValues);
1456
1643
  for (const fieldName of _names.mount) {
1457
- if (fieldName in flattenedUpdates) {
1458
- _setValue(fieldName, flattenedUpdates[fieldName], options, true, true);
1644
+ if (has(updatedFormValues, fieldName)) {
1645
+ _setValue(fieldName, get(updatedFormValues, fieldName), options, true, true);
1459
1646
  }
1460
1647
  }
1461
1648
  _subjects.state.next({
@@ -1489,18 +1676,19 @@ function createFormControl(props = {}) {
1489
1676
  : getEventValue(event);
1490
1677
  const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1491
1678
  const hasNoValidationEffect = !hasValidation(field._f) &&
1492
- !props.validate &&
1679
+ !_options.validate &&
1493
1680
  !_options.resolver &&
1494
1681
  !get(_formState.errors, name) &&
1495
1682
  !field._f.deps;
1496
1683
  const shouldSkipValidation = hasNoValidationEffect ||
1497
1684
  skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
1498
1685
  const watched = isWatched(name, _names, isBlurEvent);
1499
- set(_formValues, name, fieldValue);
1686
+ set(_formValues, name, cloneObject(fieldValue));
1500
1687
  if (isBlurEvent) {
1501
1688
  if (!target || !target.readOnly) {
1502
1689
  field._f.onBlur && field._f.onBlur(event);
1503
- delayErrorCallback && delayErrorCallback(0);
1690
+ const pendingDelayError = delayErrorCallbacks[name];
1691
+ pendingDelayError && pendingDelayError(0);
1504
1692
  }
1505
1693
  }
1506
1694
  else if (field._f.onChange) {
@@ -1518,7 +1706,7 @@ function createFormControl(props = {}) {
1518
1706
  });
1519
1707
  if (shouldSkipValidation) {
1520
1708
  if ((!hasNoValidationEffect || !_formState.isValid) &&
1521
- (_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
1709
+ _isTracked('isValid')) {
1522
1710
  if (_options.mode === 'onBlur') {
1523
1711
  if (isBlurEvent) {
1524
1712
  _setValid();
@@ -1531,7 +1719,7 @@ function createFormControl(props = {}) {
1531
1719
  return (shouldRender &&
1532
1720
  _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
1533
1721
  }
1534
- if (!_options.resolver && props.validate) {
1722
+ if (!_options.resolver && _options.validate) {
1535
1723
  await validateForm({
1536
1724
  name: name,
1537
1725
  eventType: event.type,
@@ -1539,7 +1727,11 @@ function createFormControl(props = {}) {
1539
1727
  }
1540
1728
  !isBlurEvent && watched && _subjects.state.next({ ..._formState });
1541
1729
  if (_options.resolver) {
1730
+ const resetCallId = _resetCallId;
1542
1731
  const { errors } = await _runSchema([name]);
1732
+ if (resetCallId !== _resetCallId) {
1733
+ return;
1734
+ }
1543
1735
  _updateIsValidating([name]);
1544
1736
  _updateIsFieldValueUpdated(fieldValue);
1545
1737
  if (!isFieldValueUpdated) {
@@ -1553,22 +1745,28 @@ function createFormControl(props = {}) {
1553
1745
  isValid = isEmptyObject(errors);
1554
1746
  }
1555
1747
  else {
1748
+ const resetCallId = _resetCallId;
1556
1749
  _updateIsValidating([name], true);
1557
1750
  error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
1751
+ if (resetCallId !== _resetCallId) {
1752
+ return;
1753
+ }
1558
1754
  _updateIsValidating([name]);
1559
1755
  _updateIsFieldValueUpdated(fieldValue);
1560
1756
  if (isFieldValueUpdated) {
1561
1757
  if (error) {
1562
1758
  isValid = false;
1563
1759
  }
1564
- else if (_proxyFormState.isValid ||
1565
- _proxySubscribeFormState.isValid) {
1760
+ else if (_isTracked('isValid')) {
1566
1761
  isValid = await executeBuiltInValidation({
1567
1762
  fields: _fields,
1568
1763
  onlyCheckValid: true,
1569
1764
  name: name,
1570
1765
  eventType: event.type,
1571
1766
  });
1767
+ if (resetCallId !== _resetCallId) {
1768
+ return;
1769
+ }
1572
1770
  }
1573
1771
  }
1574
1772
  }
@@ -1592,11 +1790,15 @@ function createFormControl(props = {}) {
1592
1790
  let validationResult;
1593
1791
  const fieldNames = convertToArrayPayload(name);
1594
1792
  if (_options.resolver) {
1793
+ const resetCallId = _resetCallId;
1595
1794
  const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
1596
1795
  isValid = isEmptyObject(errors);
1597
1796
  validationResult = name
1598
1797
  ? !fieldNames.some((name) => get(errors, name))
1599
1798
  : isValid;
1799
+ if (resetCallId !== _resetCallId) {
1800
+ return validationResult;
1801
+ }
1600
1802
  }
1601
1803
  else if (name) {
1602
1804
  validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
@@ -1615,13 +1817,32 @@ function createFormControl(props = {}) {
1615
1817
  eventType: EVENTS.TRIGGER,
1616
1818
  });
1617
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
+ }
1618
1837
  _subjects.state.next({
1619
1838
  ...(!isString(name) ||
1620
- ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1621
- isValid !== _formState.isValid)
1839
+ (_isTracked('isValid') && isValid !== _formState.isValid)
1622
1840
  ? {}
1623
1841
  : { name }),
1624
1842
  ...(_options.resolver || !name ? { isValid } : {}),
1843
+ ...(options.shouldTouch && _isTracked('touchedFields')
1844
+ ? { touchedFields: _formState.touchedFields }
1845
+ : {}),
1625
1846
  errors: _formState.errors,
1626
1847
  });
1627
1848
  options.shouldFocus &&
@@ -1642,18 +1863,28 @@ function createFormControl(props = {}) {
1642
1863
  ? get(values, fieldNames)
1643
1864
  : fieldNames.map((name) => get(values, name));
1644
1865
  };
1645
- const getFieldState = (name, formState) => ({
1646
- invalid: !!get((formState || _formState).errors, name),
1647
- isDirty: !!get((formState || _formState).dirtyFields, name),
1648
- error: get((formState || _formState).errors, name),
1649
- isValidating: !!get(_formState.validatingFields, name),
1650
- isTouched: !!get((formState || _formState).touchedFields, name),
1651
- });
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
+ };
1652
1882
  const clearErrors = (name) => {
1653
1883
  const names = name ? convertToArrayPayload(name) : undefined;
1654
- names?.forEach((inputName) => unset(_formState.errors, inputName));
1655
1884
  if (names) {
1656
1885
  names.forEach((inputName) => {
1886
+ cancelDelayedErrorTree(inputName);
1887
+ unset(_formState.errors, inputName);
1657
1888
  _subjects.state.next({
1658
1889
  name: inputName,
1659
1890
  errors: _formState.errors,
@@ -1661,15 +1892,18 @@ function createFormControl(props = {}) {
1661
1892
  });
1662
1893
  }
1663
1894
  else {
1895
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1896
+ _formState.errors = {};
1664
1897
  _subjects.state.next({
1665
- errors: {},
1898
+ errors: _formState.errors,
1666
1899
  });
1667
1900
  }
1668
1901
  };
1669
1902
  const setError = (name, error, options) => {
1903
+ cancelDelayedErrorTree(name);
1670
1904
  const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
1671
1905
  const currentError = get(_formState.errors, name) || {};
1672
- const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
1906
+ const { ref: currentRef, message, type, types, ...restOfErrorTree } = currentError;
1673
1907
  set(_formState.errors, name, {
1674
1908
  ...restOfErrorTree,
1675
1909
  ...error,
@@ -1753,11 +1987,15 @@ function createFormControl(props = {}) {
1753
1987
  for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
1754
1988
  _names.mount.delete(fieldName);
1755
1989
  _names.array.delete(fieldName);
1990
+ _names.disabled.delete(fieldName);
1756
1991
  if (!options.keepValue) {
1757
1992
  unset(_fields, fieldName);
1758
1993
  unset(_formValues, fieldName);
1759
1994
  }
1760
- !options.keepError && unset(_formState.errors, fieldName);
1995
+ if (!options.keepError) {
1996
+ cancelDelayedErrorTree(fieldName);
1997
+ unset(_formState.errors, fieldName);
1998
+ }
1761
1999
  !options.keepDirty && unset(_formState.dirtyFields, fieldName);
1762
2000
  !options.keepTouched && unset(_formState.touchedFields, fieldName);
1763
2001
  !options.keepIsValidating &&
@@ -1766,12 +2004,16 @@ function createFormControl(props = {}) {
1766
2004
  !options.keepDefaultValue &&
1767
2005
  unset(_defaultValues, fieldName);
1768
2006
  }
1769
- _subjects.state.next({
1770
- values: cloneObject(_formValues),
1771
- });
2007
+ _valuesSubscriberCount &&
2008
+ _subjects.state.next({
2009
+ values: cloneObject(_formValues),
2010
+ });
1772
2011
  _subjects.state.next({
1773
2012
  ..._formState,
1774
- ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2013
+ ...(options.keepDirty ? {} : { isDirty: _getDirty() }),
2014
+ ...(options.keepIsValidating
2015
+ ? {}
2016
+ : { isValidating: !isEmptyObject(_formState.validatingFields) }),
1775
2017
  });
1776
2018
  !options.keepIsValid && _setValid();
1777
2019
  };
@@ -1800,6 +2042,14 @@ function createFormControl(props = {}) {
1800
2042
  },
1801
2043
  });
1802
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
+ }
1803
2053
  if (field && !shouldRevalidateRemount) {
1804
2054
  _setDisabledField({
1805
2055
  disabled: isBoolean(options.disabled)
@@ -1846,20 +2096,23 @@ function createFormControl(props = {}) {
1846
2096
  : fieldRef === field._f.ref) {
1847
2097
  return;
1848
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
+ }
1849
2114
  set(_fields, name, {
1850
- _f: {
1851
- ...field._f,
1852
- ...(radioOrCheckbox
1853
- ? {
1854
- refs: [
1855
- ...refs.filter(live),
1856
- fieldRef,
1857
- ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
1858
- ],
1859
- ref: { type: fieldRef.type, name },
1860
- }
1861
- : { ref: fieldRef }),
1862
- },
2115
+ _f: newField,
1863
2116
  });
1864
2117
  updateValidAndValue(name, false, undefined, fieldRef);
1865
2118
  }
@@ -1891,10 +2144,11 @@ function createFormControl(props = {}) {
1891
2144
  });
1892
2145
  }
1893
2146
  }
1894
- }, 0, false);
2147
+ }, 0);
1895
2148
  }
1896
2149
  };
1897
2150
  const handleSubmit = (onValid, onInvalid) => async (e) => {
2151
+ let result = undefined;
1898
2152
  let onValidError = undefined;
1899
2153
  if (e) {
1900
2154
  e.preventDefault && e.preventDefault();
@@ -1906,29 +2160,38 @@ function createFormControl(props = {}) {
1906
2160
  isSubmitting: true,
1907
2161
  });
1908
2162
  if (_options.resolver) {
2163
+ const resetCallId = _resetCallId;
1909
2164
  const { errors, values } = await _runSchema();
2165
+ if (resetCallId !== _resetCallId) {
2166
+ return;
2167
+ }
1910
2168
  _updateIsValidating();
2169
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1911
2170
  _formState.errors = errors;
1912
2171
  fieldValues = cloneObject(values);
1913
2172
  }
1914
2173
  else {
2174
+ const resetCallId = _resetCallId;
1915
2175
  await executeBuiltInValidation({
1916
2176
  fields: _fields,
1917
2177
  eventType: EVENTS.SUBMIT,
1918
2178
  });
2179
+ if (resetCallId !== _resetCallId) {
2180
+ return;
2181
+ }
2182
+ unset(_formState.errors, ROOT_ERROR_TYPE);
1919
2183
  }
1920
2184
  if (_names.disabled.size) {
1921
2185
  for (const name of _names.disabled) {
1922
2186
  unset(fieldValues, name);
1923
2187
  }
1924
2188
  }
1925
- unset(_formState.errors, ROOT_ERROR_TYPE);
1926
2189
  if (isEmptyObject(_formState.errors)) {
1927
2190
  _subjects.state.next({
1928
2191
  errors: {},
1929
2192
  });
1930
2193
  try {
1931
- await onValid(fieldValues, e);
2194
+ result = await onValid(fieldValues, e);
1932
2195
  }
1933
2196
  catch (error) {
1934
2197
  onValidError = error;
@@ -1951,9 +2214,11 @@ function createFormControl(props = {}) {
1951
2214
  if (onValidError) {
1952
2215
  throw onValidError;
1953
2216
  }
2217
+ return result;
1954
2218
  };
1955
2219
  const resetField = (name, options = {}) => {
1956
2220
  if (get(_fields, name)) {
2221
+ unset(_formState.validatingFields, name);
1957
2222
  if (isUndefined(options.defaultValue)) {
1958
2223
  setValue(name, cloneObject(get(_defaultValues, name)));
1959
2224
  }
@@ -1971,17 +2236,24 @@ function createFormControl(props = {}) {
1971
2236
  : _getDirty();
1972
2237
  }
1973
2238
  if (!options.keepError) {
2239
+ cancelDelayedErrorTree(name);
1974
2240
  unset(_formState.errors, name);
1975
- _proxyFormState.isValid && _setValid();
2241
+ _setValid();
1976
2242
  }
1977
- _subjects.state.next({ ..._formState });
2243
+ _subjects.state.next({
2244
+ ..._formState,
2245
+ isValidating: !isEmptyObject(_formState.validatingFields),
2246
+ });
1978
2247
  }
1979
2248
  };
1980
2249
  const _reset = (formValues, keepStateOptions = {}) => {
2250
+ _resetCallId++;
1981
2251
  const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
1982
2252
  const cloneUpdatedValues = cloneObject(updatedValues);
1983
2253
  const isEmptyResetValues = isEmptyObject(formValues);
1984
2254
  const values = cloneUpdatedValues;
2255
+ const fieldRefs = _fields;
2256
+ Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
1985
2257
  if (!keepStateOptions.keepDefaultValues) {
1986
2258
  _defaultValues = updatedValues;
1987
2259
  }
@@ -1989,9 +2261,9 @@ function createFormControl(props = {}) {
1989
2261
  if (keepStateOptions.keepDirtyValues) {
1990
2262
  const fieldsToCheck = new Set([
1991
2263
  ..._names.mount,
1992
- ...Object.keys(getDirtyFields(_defaultValues, _formValues)),
2264
+ ...collectDirtyFieldNames(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs), _formState.dirtyFields),
1993
2265
  ]);
1994
- for (const fieldName of Array.from(fieldsToCheck)) {
2266
+ for (const fieldName of fieldsToCheck) {
1995
2267
  const isDirty = get(_formState.dirtyFields, fieldName);
1996
2268
  const existingValue = get(_formValues, fieldName);
1997
2269
  const newValue = get(values, fieldName);
@@ -2070,6 +2342,7 @@ function createFormControl(props = {}) {
2070
2342
  _state.watch = !!_options.shouldUnregister;
2071
2343
  _state.keepIsValid = !!keepStateOptions.keepIsValid;
2072
2344
  _state.action = false;
2345
+ _state.actionArrayLengths.clear();
2073
2346
  if (!keepStateOptions.keepErrors) {
2074
2347
  _formState.errors = {};
2075
2348
  }
@@ -2092,16 +2365,22 @@ function createFormControl(props = {}) {
2092
2365
  ? {}
2093
2366
  : keepStateOptions.keepDirtyValues
2094
2367
  ? keepStateOptions.keepDefaultValues && _formValues
2095
- ? getDirtyFields(_defaultValues, _formValues)
2368
+ ? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
2096
2369
  : _formState.dirtyFields
2097
2370
  : keepStateOptions.keepDefaultValues && formValues
2098
- ? getDirtyFields(_defaultValues, formValues)
2371
+ ? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
2099
2372
  : keepStateOptions.keepDirty
2100
2373
  ? _formState.dirtyFields
2101
- : {},
2374
+ : keepStateOptions.keepValues
2375
+ ? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
2376
+ : {},
2102
2377
  touchedFields: keepStateOptions.keepTouched
2103
2378
  ? _formState.touchedFields
2104
2379
  : {},
2380
+ ...(!keepStateOptions.keepIsValidating &&
2381
+ (_formState.isValidating || !isEmptyObject(_formState.validatingFields))
2382
+ ? { validatingFields: {}, isValidating: false }
2383
+ : null),
2105
2384
  errors: keepStateOptions.keepErrors ? _formState.errors : {},
2106
2385
  isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
2107
2386
  ? _formState.isSubmitSuccessful
@@ -2142,6 +2421,7 @@ function createFormControl(props = {}) {
2142
2421
  ...formState,
2143
2422
  };
2144
2423
  };
2424
+ _subjects.state.subscribe({ next: _setFormState });
2145
2425
  const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
2146
2426
  _options.defaultValues().then((values) => {
2147
2427
  reset(values, _options.resetOptions);
@@ -2152,7 +2432,7 @@ function createFormControl(props = {}) {
2152
2432
  const resetDefaultValues = (values, options = {}) => {
2153
2433
  _defaultValues = cloneObject(values);
2154
2434
  if (!options.keepDirty) {
2155
- const newDirtyFields = getDirtyFields(_defaultValues, _formValues);
2435
+ const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
2156
2436
  _formState.dirtyFields = newDirtyFields;
2157
2437
  _formState.isDirty = !isEmptyObject(newDirtyFields);
2158
2438
  }
@@ -2222,6 +2502,8 @@ function createFormControl(props = {}) {
2222
2502
  };
2223
2503
  _validationModeBeforeSubmit = getValidationModes(_options.mode);
2224
2504
  _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
2505
+ shouldDisplayAllAssociatedErrors =
2506
+ _options.criteriaMode === VALIDATION_MODE.all;
2225
2507
  },
2226
2508
  },
2227
2509
  subscribe,
@@ -2232,6 +2514,7 @@ function createFormControl(props = {}) {
2232
2514
  setValue,
2233
2515
  setValues,
2234
2516
  getValues,
2517
+ getErrors,
2235
2518
  reset,
2236
2519
  resetField,
2237
2520
  resetDefaultValues,