react-hook-form 7.16.0 → 7.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -65,10 +65,9 @@ var omit = (source, key) => {
65
65
  return copy;
66
66
  };
67
67
 
68
- const FormContext = React.createContext(null);
69
- FormContext.displayName = 'RHFContext';
70
- const useFormContext = () => React.useContext(FormContext);
71
- const FormProvider = (props) => (React.createElement(FormContext.Provider, { value: omit(props, 'children') }, props.children));
68
+ const HookFormContext = React.createContext(null);
69
+ const useFormContext = () => React.useContext(HookFormContext);
70
+ const FormProvider = (props) => (React.createElement(HookFormContext.Provider, { value: omit(props, 'children') }, props.children));
72
71
 
73
72
  var getProxyFormState = (formState, _proxyFormState, localProxyFormState, isRoot = true) => {
74
73
  function createGetter(prop) {
@@ -104,10 +103,33 @@ var shouldRenderFormState = (formStateData, _proxyFormState, isRoot) => {
104
103
 
105
104
  var convertToArrayPayload = (value) => Array.isArray(value) ? value : [value];
106
105
 
106
+ function useSubscribe({ disabled, subject, callback }) {
107
+ const _subscription = React.useRef(subject);
108
+ const _unSubscribe = React.useRef();
109
+ if (disabled) {
110
+ if (_subscription.current) {
111
+ _unSubscribe.current && _unSubscribe.current.unsubscribe();
112
+ _subscription.current = _unSubscribe.current = undefined;
113
+ }
114
+ }
115
+ else {
116
+ if (!_subscription.current) {
117
+ _subscription.current = subject;
118
+ }
119
+ if (!_unSubscribe.current && _subscription.current) {
120
+ _unSubscribe.current = _subscription.current.subscribe({
121
+ next: callback,
122
+ });
123
+ }
124
+ }
125
+ React.useEffect(() => () => {
126
+ _unSubscribe.current && _unSubscribe.current.unsubscribe();
127
+ }, []);
128
+ }
129
+
107
130
  function useFormState(props) {
108
131
  const methods = useFormContext();
109
132
  const { control = methods.control, disabled, name } = props || {};
110
- const nameRef = React.useRef(name);
111
133
  const [formState, updateFormState] = React.useState(control._formState);
112
134
  const _localProxyFormState = React.useRef({
113
135
  isDirty: false,
@@ -117,18 +139,17 @@ function useFormState(props) {
117
139
  isValid: false,
118
140
  errors: false,
119
141
  });
120
- nameRef.current = name;
121
- React.useEffect(() => {
122
- const formStateSubscription = control._subjects.state.subscribe({
123
- next: (formState) => (!nameRef.current ||
124
- !formState.name ||
125
- convertToArrayPayload(nameRef.current).includes(formState.name)) &&
126
- shouldRenderFormState(formState, _localProxyFormState.current) &&
127
- updateFormState(Object.assign(Object.assign({}, control._formState), formState)),
128
- });
129
- disabled && formStateSubscription.unsubscribe();
130
- return () => formStateSubscription.unsubscribe();
131
- }, [disabled, control]);
142
+ const _name = React.useRef(name);
143
+ _name.current = name;
144
+ useSubscribe({
145
+ disabled,
146
+ callback: (formState) => (!_name.current ||
147
+ !formState.name ||
148
+ convertToArrayPayload(_name.current).includes(formState.name)) &&
149
+ shouldRenderFormState(formState, _localProxyFormState.current) &&
150
+ updateFormState(Object.assign(Object.assign({}, control._formState), formState)),
151
+ subject: control._subjects.state,
152
+ });
132
153
  return getProxyFormState(formState, control._proxyFormState, _localProxyFormState.current, false);
133
154
  }
134
155
 
@@ -140,6 +161,13 @@ function useController(props) {
140
161
  control: control || methods.control,
141
162
  name,
142
163
  });
164
+ const _name = React.useRef(name);
165
+ _name.current = name;
166
+ useSubscribe({
167
+ subject: control._subjects.control,
168
+ callback: (data) => (!data.name || _name.current === data.name) &&
169
+ setInputStateValue(get(data.values, name)),
170
+ });
143
171
  const registerProps = control.register(name, Object.assign(Object.assign({}, props.rules), { value }));
144
172
  const updateMounted = React.useCallback((name, value) => {
145
173
  const field = get(control._fields, name);
@@ -148,14 +176,9 @@ function useController(props) {
148
176
  }
149
177
  }, [control]);
150
178
  React.useEffect(() => {
151
- const controllerSubscription = control._subjects.control.subscribe({
152
- next: (data) => (!data.name || name === data.name) &&
153
- setInputStateValue(get(data.values, name)),
154
- });
155
179
  updateMounted(name, true);
156
180
  return () => {
157
- controllerSubscription.unsubscribe();
158
- const _shouldUnregisterField = control._shouldUnregister || shouldUnregister;
181
+ const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
159
182
  if (isNameInFieldArray(control._names.array, name)
160
183
  ? _shouldUnregisterField && !control._stateFlags.action
161
184
  : _shouldUnregisterField) {
@@ -265,9 +288,10 @@ const focusFieldBy = (fields, callback, fieldsNames) => {
265
288
  }
266
289
  };
267
290
 
268
- var getFocusFieldName = (name, index, options) => options && !options.shouldFocus
269
- ? options.focusName || `${name}.${options.focusIndex}.`
270
- : `${name}.${index}.`;
291
+ var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
292
+ ? options.focusName ||
293
+ `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
294
+ : '';
271
295
 
272
296
  var mapCurrentIds = (values, _fieldIds, keyName) => values.map((value, index) => {
273
297
  const output = _fieldIds.current[index];
@@ -309,7 +333,7 @@ var moveArrayAt = (data, from, to) => {
309
333
  return [];
310
334
  };
311
335
 
312
- var omitKey = (fields, keyName) => fields.map((field = {}) => omit(field, keyName));
336
+ var omitKeys = (fields, keyName) => fields.map((field = {}) => omit(field, keyName));
313
337
 
314
338
  function prepend(data, value) {
315
339
  return [...convertToArrayPayload(value), ...convertToArrayPayload(data)];
@@ -340,73 +364,81 @@ var updateAt = (fieldValues, index, value) => {
340
364
  const useFieldArray = (props) => {
341
365
  const methods = useFormContext();
342
366
  const { control = methods.control, name, keyName = 'id', shouldUnregister, } = props;
343
- const [fields, setFields] = React.useState(mapIds(control._getFieldArrayValue(name), keyName));
367
+ const [fields, setFields] = React.useState(mapIds(control._getFieldArray(name), keyName));
344
368
  const _fieldIds = React.useRef(fields);
345
369
  _fieldIds.current = fields;
346
370
  control._names.array.add(name);
371
+ useSubscribe({
372
+ callback: ({ values, name: fieldArrayName }) => {
373
+ if (fieldArrayName === name || !fieldArrayName) {
374
+ setFields(mapIds(get(values, name), keyName));
375
+ }
376
+ },
377
+ subject: control._subjects.array,
378
+ });
347
379
  const updateValues = React.useCallback((updatedFieldArrayValuesWithKey) => {
348
- const updatedFieldArrayValues = omitKey(updatedFieldArrayValuesWithKey, keyName);
380
+ const updatedFieldArrayValues = omitKeys(updatedFieldArrayValuesWithKey, keyName);
349
381
  set(control._formValues, name, updatedFieldArrayValues);
350
382
  setFields(updatedFieldArrayValuesWithKey);
351
383
  return updatedFieldArrayValues;
352
384
  }, [control, name, keyName]);
353
385
  const append$1 = (value, options) => {
354
386
  const appendValue = convertToArrayPayload(value);
355
- const updatedFieldArrayValuesWithKey = append(mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName), mapIds(appendValue, keyName));
356
- control._updateFieldArray(keyName, name, append, {
387
+ const updatedFieldArrayValuesWithKey = append(mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName), mapIds(appendValue, keyName));
388
+ control._updateFieldArray(name, append, {
357
389
  argA: fillEmptyArray(value),
358
390
  }, updateValues(updatedFieldArrayValuesWithKey));
359
391
  control._names.focus = getFocusFieldName(name, updatedFieldArrayValuesWithKey.length - appendValue.length, options);
360
392
  };
361
393
  const prepend$1 = (value, options) => {
362
- const updatedFieldArrayValuesWithKey = prepend(mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName), mapIds(convertToArrayPayload(value), keyName));
363
- control._updateFieldArray(keyName, name, prepend, {
394
+ const updatedFieldArrayValuesWithKey = prepend(mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName), mapIds(convertToArrayPayload(value), keyName));
395
+ control._updateFieldArray(name, prepend, {
364
396
  argA: fillEmptyArray(value),
365
397
  }, updateValues(updatedFieldArrayValuesWithKey));
366
398
  control._names.focus = getFocusFieldName(name, 0, options);
367
399
  };
368
400
  const remove = (index) => {
369
- const updatedFieldArrayValuesWithKey = removeArrayAt(mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName), index);
370
- control._updateFieldArray(keyName, name, removeArrayAt, {
401
+ const updatedFieldArrayValuesWithKey = removeArrayAt(mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName), index);
402
+ control._updateFieldArray(name, removeArrayAt, {
371
403
  argA: index,
372
404
  }, updateValues(updatedFieldArrayValuesWithKey));
373
405
  };
374
406
  const insert$1 = (index, value, options) => {
375
- const updatedFieldArrayValuesWithKey = insert(mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName), index, mapIds(convertToArrayPayload(value), keyName));
376
- control._updateFieldArray(keyName, name, insert, {
407
+ const updatedFieldArrayValuesWithKey = insert(mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName), index, mapIds(convertToArrayPayload(value), keyName));
408
+ control._updateFieldArray(name, insert, {
377
409
  argA: index,
378
410
  argB: fillEmptyArray(value),
379
411
  }, updateValues(updatedFieldArrayValuesWithKey));
380
412
  control._names.focus = getFocusFieldName(name, index, options);
381
413
  };
382
414
  const swap = (indexA, indexB) => {
383
- const updatedFieldArrayValuesWithKey = mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName);
415
+ const updatedFieldArrayValuesWithKey = mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName);
384
416
  swapArrayAt(updatedFieldArrayValuesWithKey, indexA, indexB);
385
- control._updateFieldArray(keyName, name, swapArrayAt, {
417
+ control._updateFieldArray(name, swapArrayAt, {
386
418
  argA: indexA,
387
419
  argB: indexB,
388
420
  }, updateValues(updatedFieldArrayValuesWithKey), false);
389
421
  };
390
422
  const move = (from, to) => {
391
- const updatedFieldArrayValuesWithKey = mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName);
423
+ const updatedFieldArrayValuesWithKey = mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName);
392
424
  moveArrayAt(updatedFieldArrayValuesWithKey, from, to);
393
- control._updateFieldArray(keyName, name, moveArrayAt, {
425
+ control._updateFieldArray(name, moveArrayAt, {
394
426
  argA: from,
395
427
  argB: to,
396
428
  }, updateValues(updatedFieldArrayValuesWithKey), false);
397
429
  };
398
430
  const update = (index, value) => {
399
- const updatedFieldArrayValuesWithKey = mapCurrentIds(control._getFieldArrayValue(name), _fieldIds, keyName);
431
+ const updatedFieldArrayValuesWithKey = mapCurrentIds(control._getFieldArray(name), _fieldIds, keyName);
400
432
  const updatedFieldArrayValues = updateAt(updatedFieldArrayValuesWithKey, index, value);
401
433
  _fieldIds.current = mapIds(updatedFieldArrayValues, keyName);
402
- control._updateFieldArray(keyName, name, updateAt, {
434
+ control._updateFieldArray(name, updateAt, {
403
435
  argA: index,
404
436
  argB: value,
405
437
  }, updateValues(_fieldIds.current), true, false);
406
438
  };
407
439
  const replace = (value) => {
408
440
  const updatedFieldArrayValuesWithKey = mapIds(convertToArrayPayload(value), keyName);
409
- control._updateFieldArray(keyName, name, () => updatedFieldArrayValuesWithKey, {}, updateValues(updatedFieldArrayValuesWithKey), true, false);
441
+ control._updateFieldArray(name, () => updatedFieldArrayValuesWithKey, {}, updateValues(updatedFieldArrayValuesWithKey), true, false);
410
442
  };
411
443
  React.useEffect(() => {
412
444
  control._stateFlags.action = false;
@@ -431,17 +463,9 @@ const useFieldArray = (props) => {
431
463
  control._proxyFormState.isValid && control._updateValid();
432
464
  }, [fields, name, control, keyName]);
433
465
  React.useEffect(() => {
434
- const fieldArraySubscription = control._subjects.array.subscribe({
435
- next({ values, name: fieldArrayName }) {
436
- if (fieldArrayName === name || !fieldArrayName) {
437
- setFields(mapIds(get(values, name), keyName));
438
- }
439
- },
440
- });
441
466
  !get(control._formValues, name) && set(control._formValues, name, []);
442
467
  return () => {
443
- fieldArraySubscription.unsubscribe();
444
- if (control._shouldUnregister || shouldUnregister) {
468
+ if (control._options.shouldUnregister || shouldUnregister) {
445
469
  control.unregister(name);
446
470
  }
447
471
  };
@@ -483,12 +507,12 @@ function cloneObject(data) {
483
507
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
484
508
 
485
509
  function deepEqual(object1, object2) {
486
- if (isPrimitive(object1) ||
487
- isPrimitive(object2) ||
488
- isDateObject(object1) ||
489
- isDateObject(object2)) {
510
+ if (isPrimitive(object1) || isPrimitive(object2)) {
490
511
  return object1 === object2;
491
512
  }
513
+ if (isDateObject(object1) && isDateObject(object2)) {
514
+ return object1.getTime() === object2.getTime();
515
+ }
492
516
  const keys1 = Object.keys(object1);
493
517
  const keys2 = Object.keys(object2);
494
518
  if (keys1.length !== keys2.length) {
@@ -501,8 +525,9 @@ function deepEqual(object1, object2) {
501
525
  }
502
526
  if (key !== 'ref') {
503
527
  const val2 = object2[key];
504
- if ((isObject(val1) || Array.isArray(val1)) &&
505
- (isObject(val2) || Array.isArray(val2))
528
+ if ((isDateObject(val1) && isDateObject(val2)) ||
529
+ (isObject(val1) && isObject(val2)) ||
530
+ (Array.isArray(val1) && Array.isArray(val2))
506
531
  ? !deepEqual(val1, val2)
507
532
  : val1 !== val2) {
508
533
  return false;
@@ -522,8 +547,6 @@ var getValidationModes = (mode) => ({
522
547
 
523
548
  var isBoolean = (value) => typeof value === 'boolean';
524
549
 
525
- var isFileInput = (element) => element.type === 'file';
526
-
527
550
  var isFunction = (value) => typeof value === 'function';
528
551
 
529
552
  var isHTMLElement = (value) => value instanceof HTMLElement;
@@ -627,6 +650,8 @@ function unset(object, path) {
627
650
  return object;
628
651
  }
629
652
 
653
+ var isFileInput = (element) => element.type === 'file';
654
+
630
655
  const defaultResult = {
631
656
  value: false,
632
657
  isValid: false,
@@ -664,10 +689,6 @@ var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isU
664
689
  ? setValueAs(value)
665
690
  : value;
666
691
 
667
- var getMultipleSelectValue = (options) => [...options]
668
- .filter(({ selected }) => selected)
669
- .map(({ value }) => value);
670
-
671
692
  const defaultReturn = {
672
693
  isValid: false,
673
694
  value: null,
@@ -693,7 +714,7 @@ function getFieldValue(_f) {
693
714
  return getRadioValue(_f.refs).value;
694
715
  }
695
716
  if (isMultipleSelect(ref)) {
696
- return getMultipleSelectValue(ref.options);
717
+ return [...ref.selectedOptions].map(({ value }) => value);
697
718
  }
698
719
  if (isCheckBoxInput(ref)) {
699
720
  return getCheckboxValue(_f.refs).value;
@@ -952,8 +973,7 @@ const defaultOptions = {
952
973
  };
953
974
  const isWindowUndefined = typeof window === 'undefined';
954
975
  function createFormControl(props = {}) {
955
- let formOptions = Object.assign(Object.assign({}, defaultOptions), props);
956
- let _delayCallback;
976
+ let _options = Object.assign(Object.assign({}, defaultOptions), props);
957
977
  let _formState = {
958
978
  isDirty: false,
959
979
  isValidating: false,
@@ -967,8 +987,8 @@ function createFormControl(props = {}) {
967
987
  errors: {},
968
988
  };
969
989
  let _fields = {};
970
- let _defaultValues = formOptions.defaultValues || {};
971
- let _formValues = formOptions.shouldUnregister
990
+ let _defaultValues = _options.defaultValues || {};
991
+ let _formValues = _options.shouldUnregister
972
992
  ? {}
973
993
  : cloneObject(_defaultValues);
974
994
  let _stateFlags = {
@@ -976,14 +996,15 @@ function createFormControl(props = {}) {
976
996
  mount: false,
977
997
  watch: false,
978
998
  };
979
- let _timer = 0;
980
999
  let _names = {
981
1000
  mount: new Set(),
982
1001
  unMount: new Set(),
983
1002
  array: new Set(),
984
1003
  watch: new Set(),
985
1004
  };
986
- let _validateCount = {};
1005
+ let delayErrorCallback;
1006
+ let timer = 0;
1007
+ let validateFields = {};
987
1008
  const _proxyFormState = {
988
1009
  isDirty: false,
989
1010
  dirtyFields: false,
@@ -998,37 +1019,125 @@ function createFormControl(props = {}) {
998
1019
  array: new Subject(),
999
1020
  state: new Subject(),
1000
1021
  };
1001
- const validationMode = getValidationModes(formOptions.mode);
1002
- const reValidateMode = getValidationModes(formOptions.reValidateMode);
1003
- const isValidateAllFieldCriteria = formOptions.criteriaMode === VALIDATION_MODE.all;
1022
+ const validationModeBeforeSubmit = getValidationModes(_options.mode);
1023
+ const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1024
+ const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1004
1025
  const debounce = (callback, wait) => (...args) => {
1005
- clearTimeout(_timer);
1006
- _timer = window.setTimeout(() => callback(...args), wait);
1026
+ clearTimeout(timer);
1027
+ timer = window.setTimeout(() => callback(...args), wait);
1007
1028
  };
1008
- const isFieldWatched = (name) => _names.watchAll ||
1009
- _names.watch.has(name) ||
1010
- _names.watch.has((name.match(/\w+/) || [])[0]);
1011
- const updateErrorState = (name, error) => {
1012
- set(_formState.errors, name, error);
1029
+ const isFieldWatched = (name, isBlurEvent) => !isBlurEvent &&
1030
+ (_names.watchAll ||
1031
+ _names.watch.has(name) ||
1032
+ _names.watch.has((name.match(/\w+/) || [])[0]));
1033
+ const _updateValid = async (shouldSkipRender) => {
1034
+ let isValid = false;
1035
+ if (_proxyFormState.isValid) {
1036
+ isValid = _options.resolver
1037
+ ? isEmptyObject((await executeResolver()).errors)
1038
+ : await executeBuildInValidation(_fields, true);
1039
+ if (!shouldSkipRender && isValid !== _formState.isValid) {
1040
+ _formState.isValid = isValid;
1041
+ _subjects.state.next({
1042
+ isValid,
1043
+ });
1044
+ }
1045
+ }
1046
+ return isValid;
1047
+ };
1048
+ const _updateFieldArray = (name, method, args, values = [], shouldSetValues = true, shouldSetFields = true) => {
1049
+ _stateFlags.action = true;
1050
+ if (shouldSetFields && get(_fields, name)) {
1051
+ const fieldValues = method(get(_fields, name), args.argA, args.argB);
1052
+ shouldSetValues && set(_fields, name, fieldValues);
1053
+ }
1054
+ if (Array.isArray(get(_formState.errors, name))) {
1055
+ const errors = method(get(_formState.errors, name), args.argA, args.argB);
1056
+ shouldSetValues && set(_formState.errors, name, errors);
1057
+ unsetEmptyArray(_formState.errors, name);
1058
+ }
1059
+ if (_proxyFormState.touchedFields && get(_formState.touchedFields, name)) {
1060
+ const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1061
+ shouldSetValues &&
1062
+ set(_formState.touchedFields, name, touchedFields);
1063
+ unsetEmptyArray(_formState.touchedFields, name);
1064
+ }
1065
+ if (_proxyFormState.dirtyFields || _proxyFormState.isDirty) {
1066
+ updateFieldArrayDirty(name, values);
1067
+ }
1013
1068
  _subjects.state.next({
1069
+ isDirty: _getDirty(name, values),
1070
+ dirtyFields: _formState.dirtyFields,
1014
1071
  errors: _formState.errors,
1072
+ isValid: _formState.isValid,
1015
1073
  });
1016
1074
  };
1017
- const shouldRenderBaseOnError = async (shouldSkipRender, name, isValid, error, fieldState) => {
1018
- const previousError = get(_formState.errors, name);
1075
+ const updateErrors = (name, error) => (set(_formState.errors, name, error),
1076
+ _subjects.state.next({
1077
+ errors: _formState.errors,
1078
+ }));
1079
+ const updateValidAndValue = (name, shouldSkipSetValueAs, ref) => {
1080
+ const field = get(_fields, name);
1081
+ if (field) {
1082
+ const defaultValue = get(_formValues, name, get(_defaultValues, name));
1083
+ isUndefined(defaultValue) ||
1084
+ (ref && ref.defaultChecked) ||
1085
+ shouldSkipSetValueAs
1086
+ ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1087
+ : setFieldValue(name, defaultValue);
1088
+ }
1089
+ _stateFlags.mount && _updateValid();
1090
+ };
1091
+ const updateTouchAndDirty = (name, fieldValue, isCurrentTouched, shouldRender = true) => {
1092
+ let isFieldDirty = false;
1093
+ const output = {
1094
+ name,
1095
+ };
1096
+ const isPreviousFieldTouched = get(_formState.touchedFields, name);
1097
+ if (_proxyFormState.isDirty) {
1098
+ const isPreviousFormDirty = _formState.isDirty;
1099
+ _formState.isDirty = output.isDirty = _getDirty();
1100
+ isFieldDirty = isPreviousFormDirty !== output.isDirty;
1101
+ }
1102
+ if (_proxyFormState.dirtyFields && !isCurrentTouched) {
1103
+ const isPreviousFieldDirty = get(_formState.dirtyFields, name);
1104
+ const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1105
+ isCurrentFieldPristine
1106
+ ? unset(_formState.dirtyFields, name)
1107
+ : set(_formState.dirtyFields, name, true);
1108
+ output.dirtyFields = _formState.dirtyFields;
1109
+ isFieldDirty =
1110
+ isFieldDirty ||
1111
+ isPreviousFieldDirty !== get(_formState.dirtyFields, name);
1112
+ }
1113
+ if (isCurrentTouched && !isPreviousFieldTouched) {
1114
+ set(_formState.touchedFields, name, isCurrentTouched);
1115
+ output.touchedFields = _formState.touchedFields;
1116
+ isFieldDirty =
1117
+ isFieldDirty ||
1118
+ (_proxyFormState.touchedFields &&
1119
+ isPreviousFieldTouched !== isCurrentTouched);
1120
+ }
1121
+ isFieldDirty && shouldRender && _subjects.state.next(output);
1122
+ return isFieldDirty ? output : {};
1123
+ };
1124
+ const updateFieldArrayDirty = (name, value) => (set(_formState.dirtyFields, name, setFieldArrayDirtyFields(value, get(_defaultValues, name, []), get(_formState.dirtyFields, name, []))),
1125
+ unsetEmptyArray(_formState.dirtyFields, name));
1126
+ const shouldRenderByError = async (shouldSkipRender, name, isValid, error, fieldState) => {
1127
+ const previousFieldError = get(_formState.errors, name);
1019
1128
  const shouldUpdateValid = _proxyFormState.isValid && _formState.isValid !== isValid;
1020
1129
  if (props.delayError && error) {
1021
- _delayCallback =
1022
- _delayCallback || debounce(updateErrorState, props.delayError);
1023
- _delayCallback(name, error);
1130
+ delayErrorCallback =
1131
+ delayErrorCallback || debounce(updateErrors, props.delayError);
1132
+ delayErrorCallback(name, error);
1024
1133
  }
1025
1134
  else {
1026
- clearTimeout(_timer);
1135
+ clearTimeout(timer);
1027
1136
  error
1028
1137
  ? set(_formState.errors, name, error)
1029
1138
  : unset(_formState.errors, name);
1030
1139
  }
1031
- if (((error ? !deepEqual(previousError, error) : previousError) ||
1140
+ if (((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1032
1141
  !isEmptyObject(fieldState) ||
1033
1142
  shouldUpdateValid) &&
1034
1143
  !shouldSkipRender) {
@@ -1036,138 +1145,169 @@ function createFormControl(props = {}) {
1036
1145
  _formState = Object.assign(Object.assign({}, _formState), updatedFormState);
1037
1146
  _subjects.state.next(updatedFormState);
1038
1147
  }
1039
- _validateCount[name]--;
1040
- if (_proxyFormState.isValidating && !_validateCount[name]) {
1148
+ validateFields[name]--;
1149
+ if (_proxyFormState.isValidating && !validateFields[name]) {
1041
1150
  _subjects.state.next({
1042
1151
  isValidating: false,
1043
1152
  });
1044
- _validateCount = {};
1153
+ validateFields = {};
1045
1154
  }
1046
1155
  };
1156
+ const executeResolver = async (name) => _options.resolver
1157
+ ? await _options.resolver(Object.assign({}, _formValues), _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation))
1158
+ : {};
1159
+ const executeResolverValidation = async (names) => {
1160
+ const { errors } = await executeResolver();
1161
+ if (names) {
1162
+ for (const name of names) {
1163
+ const error = get(errors, name);
1164
+ error
1165
+ ? set(_formState.errors, name, error)
1166
+ : unset(_formState.errors, name);
1167
+ }
1168
+ }
1169
+ else {
1170
+ _formState.errors = errors;
1171
+ }
1172
+ return errors;
1173
+ };
1174
+ const executeBuildInValidation = async (fields, shouldOnlyCheckValid, context = {
1175
+ valid: true,
1176
+ }) => {
1177
+ for (const name in fields) {
1178
+ const field = fields[name];
1179
+ if (field) {
1180
+ const fieldReference = field._f;
1181
+ const fieldValue = omit(field, '_f');
1182
+ if (fieldReference) {
1183
+ const fieldError = await validateField(field, get(_formValues, fieldReference.name), shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation);
1184
+ if (fieldError[fieldReference.name]) {
1185
+ context.valid = false;
1186
+ if (shouldOnlyCheckValid) {
1187
+ break;
1188
+ }
1189
+ }
1190
+ if (!shouldOnlyCheckValid) {
1191
+ fieldError[fieldReference.name]
1192
+ ? set(_formState.errors, fieldReference.name, fieldError[fieldReference.name])
1193
+ : unset(_formState.errors, fieldReference.name);
1194
+ }
1195
+ }
1196
+ fieldValue &&
1197
+ (await executeBuildInValidation(fieldValue, shouldOnlyCheckValid, context));
1198
+ }
1199
+ }
1200
+ return context.valid;
1201
+ };
1202
+ const _removeUnmounted = () => {
1203
+ for (const name of _names.unMount) {
1204
+ const field = get(_fields, name);
1205
+ field &&
1206
+ (field._f.refs ? field._f.refs.every(live) : live(field._f.ref)) &&
1207
+ unregister(name);
1208
+ }
1209
+ _names.unMount = new Set();
1210
+ };
1211
+ const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
1212
+ !deepEqual(getValues(), _defaultValues));
1213
+ const _getWatch = (names, defaultValue, isGlobal) => {
1214
+ const fieldValues = Object.assign({}, (_stateFlags.mount
1215
+ ? _formValues
1216
+ : isUndefined(defaultValue)
1217
+ ? _defaultValues
1218
+ : isString(names)
1219
+ ? { [names]: defaultValue }
1220
+ : defaultValue));
1221
+ if (names) {
1222
+ const result = convertToArrayPayload(names).map((fieldName) => (isGlobal && _names.watch.add(fieldName),
1223
+ get(fieldValues, fieldName)));
1224
+ return Array.isArray(names) ? result : result[0];
1225
+ }
1226
+ isGlobal && (_names.watchAll = true);
1227
+ return fieldValues;
1228
+ };
1229
+ const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, []);
1047
1230
  const setFieldValue = (name, value, options = {}, shouldRender) => {
1048
1231
  const field = get(_fields, name);
1049
1232
  let fieldValue = value;
1050
1233
  if (field) {
1051
- const _f = field._f;
1052
- if (_f) {
1053
- set(_formValues, name, getFieldValueAs(value, _f));
1234
+ const fieldReference = field._f;
1235
+ if (fieldReference) {
1236
+ set(_formValues, name, getFieldValueAs(value, fieldReference));
1054
1237
  fieldValue =
1055
- isWeb && isHTMLElement(_f.ref) && isNullOrUndefined(value)
1238
+ isWeb && isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
1056
1239
  ? ''
1057
1240
  : value;
1058
- if (isFileInput(_f.ref) && !isString(fieldValue)) {
1059
- _f.ref.files = fieldValue;
1060
- }
1061
- else if (isMultipleSelect(_f.ref)) {
1062
- [..._f.ref.options].forEach((selectRef) => (selectRef.selected = fieldValue.includes(selectRef.value)));
1241
+ if (isMultipleSelect(fieldReference.ref)) {
1242
+ [...fieldReference.ref.options].forEach((selectRef) => (selectRef.selected = fieldValue.includes(selectRef.value)));
1063
1243
  }
1064
- else if (_f.refs) {
1065
- if (isCheckBoxInput(_f.ref)) {
1066
- _f.refs.length > 1
1067
- ? _f.refs.forEach((checkboxRef) => (checkboxRef.checked = Array.isArray(fieldValue)
1244
+ else if (fieldReference.refs) {
1245
+ if (isCheckBoxInput(fieldReference.ref)) {
1246
+ fieldReference.refs.length > 1
1247
+ ? fieldReference.refs.forEach((checkboxRef) => (checkboxRef.checked = Array.isArray(fieldValue)
1068
1248
  ? !!fieldValue.find((data) => data === checkboxRef.value)
1069
1249
  : fieldValue === checkboxRef.value))
1070
- : (_f.refs[0].checked = !!fieldValue);
1250
+ : (fieldReference.refs[0].checked = !!fieldValue);
1071
1251
  }
1072
1252
  else {
1073
- _f.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
1253
+ fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
1074
1254
  }
1075
1255
  }
1076
1256
  else {
1077
- _f.ref.value = fieldValue;
1257
+ fieldReference.ref.value = fieldValue;
1078
1258
  }
1079
- if (shouldRender) {
1259
+ shouldRender &&
1080
1260
  _subjects.control.next({
1081
1261
  values: _formValues,
1082
1262
  name,
1083
1263
  });
1084
- }
1085
1264
  }
1086
1265
  }
1087
1266
  (options.shouldDirty || options.shouldTouch) &&
1088
- updateTouchAndDirtyState(name, fieldValue, options.shouldTouch);
1267
+ updateTouchAndDirty(name, fieldValue, options.shouldTouch);
1089
1268
  options.shouldValidate && trigger(name);
1090
1269
  };
1091
- const updateTouchAndDirtyState = (name, inputValue, isCurrentTouched, shouldRender = true) => {
1092
- const state = {
1093
- name,
1094
- };
1095
- let isChanged = false;
1096
- if (_proxyFormState.isDirty) {
1097
- const previousIsDirty = _formState.isDirty;
1098
- _formState.isDirty = _getIsDirty();
1099
- state.isDirty = _formState.isDirty;
1100
- isChanged = previousIsDirty !== state.isDirty;
1101
- }
1102
- if (_proxyFormState.dirtyFields && !isCurrentTouched) {
1103
- const isPreviousFieldDirty = get(_formState.dirtyFields, name);
1104
- const isCurrentFieldDirty = !deepEqual(get(_defaultValues, name), inputValue);
1105
- isCurrentFieldDirty
1106
- ? set(_formState.dirtyFields, name, true)
1107
- : unset(_formState.dirtyFields, name);
1108
- state.dirtyFields = _formState.dirtyFields;
1109
- isChanged =
1110
- isChanged || isPreviousFieldDirty !== get(_formState.dirtyFields, name);
1111
- }
1112
- const isPreviousFieldTouched = get(_formState.touchedFields, name);
1113
- if (isCurrentTouched && !isPreviousFieldTouched) {
1114
- set(_formState.touchedFields, name, isCurrentTouched);
1115
- state.touchedFields = _formState.touchedFields;
1116
- isChanged =
1117
- isChanged ||
1118
- (_proxyFormState.touchedFields &&
1119
- isPreviousFieldTouched !== isCurrentTouched);
1270
+ const setValues = (name, value, options) => {
1271
+ for (const fieldKey in value) {
1272
+ const fieldValue = value[fieldKey];
1273
+ const fieldName = `${name}.${fieldKey}`;
1274
+ const field = get(_fields, fieldName);
1275
+ (_names.array.has(name) ||
1276
+ !isPrimitive(fieldValue) ||
1277
+ (field && !field._f)) &&
1278
+ !isDateObject(fieldValue)
1279
+ ? setValues(fieldName, fieldValue, options)
1280
+ : setFieldValue(fieldName, fieldValue, options, true);
1120
1281
  }
1121
- isChanged && shouldRender && _subjects.state.next(state);
1122
- return isChanged ? state : {};
1123
1282
  };
1124
- const executeResolver = async (name) => {
1125
- return formOptions.resolver
1126
- ? await formOptions.resolver(Object.assign({}, _formValues), formOptions.context, getResolverOptions(name || _names.mount, _fields, formOptions.criteriaMode, formOptions.shouldUseNativeValidation))
1127
- : {};
1128
- };
1129
- const executeResolverValidation = async (names) => {
1130
- const { errors } = await executeResolver();
1131
- if (names) {
1132
- for (const name of names) {
1133
- const error = get(errors, name);
1134
- error
1135
- ? set(_formState.errors, name, error)
1136
- : unset(_formState.errors, name);
1283
+ const setValue = (name, value, options = {}) => {
1284
+ const field = get(_fields, name);
1285
+ const isFieldArray = _names.array.has(name);
1286
+ set(_formValues, name, value);
1287
+ if (isFieldArray) {
1288
+ _subjects.array.next({
1289
+ name,
1290
+ values: _formValues,
1291
+ });
1292
+ if ((_proxyFormState.isDirty || _proxyFormState.dirtyFields) &&
1293
+ options.shouldDirty) {
1294
+ updateFieldArrayDirty(name, value);
1295
+ _subjects.state.next({
1296
+ name,
1297
+ dirtyFields: _formState.dirtyFields,
1298
+ isDirty: _getDirty(name, value),
1299
+ });
1137
1300
  }
1138
1301
  }
1139
1302
  else {
1140
- _formState.errors = errors;
1141
- }
1142
- return errors;
1143
- };
1144
- const validateForm = async (_fields, shouldCheckValid, context = {
1145
- valid: true,
1146
- }) => {
1147
- for (const name in _fields) {
1148
- const field = _fields[name];
1149
- if (field) {
1150
- const _f = field._f;
1151
- const fieldValue = omit(field, '_f');
1152
- if (_f) {
1153
- const fieldError = await validateField(field, get(_formValues, _f.name), isValidateAllFieldCriteria, formOptions.shouldUseNativeValidation);
1154
- if (fieldError[_f.name]) {
1155
- context.valid = false;
1156
- if (shouldCheckValid) {
1157
- break;
1158
- }
1159
- }
1160
- if (!shouldCheckValid) {
1161
- fieldError[_f.name]
1162
- ? set(_formState.errors, _f.name, fieldError[_f.name])
1163
- : unset(_formState.errors, _f.name);
1164
- }
1165
- }
1166
- fieldValue &&
1167
- (await validateForm(fieldValue, shouldCheckValid, context));
1168
- }
1303
+ field && !field._f && !isNullOrUndefined(value)
1304
+ ? setValues(name, value, options)
1305
+ : setFieldValue(name, value, options, true);
1169
1306
  }
1170
- return context.valid;
1307
+ isFieldWatched(name) && _subjects.state.next({});
1308
+ _subjects.watch.next({
1309
+ name,
1310
+ });
1171
1311
  };
1172
1312
  const handleChange = async (event) => {
1173
1313
  const target = event.target;
@@ -1176,22 +1316,22 @@ function createFormControl(props = {}) {
1176
1316
  if (field) {
1177
1317
  let error;
1178
1318
  let isValid;
1179
- const inputValue = target.type ? getFieldValue(field._f) : target.value;
1319
+ const fieldValue = target.type ? getFieldValue(field._f) : target.value;
1180
1320
  const isBlurEvent = event.type === EVENTS.BLUR;
1321
+ const shouldSkipValidation = (!hasValidation(field._f) &&
1322
+ !_options.resolver &&
1323
+ !get(_formState.errors, name) &&
1324
+ !field._f.deps) ||
1325
+ skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
1326
+ const isWatched = isFieldWatched(name, isBlurEvent);
1181
1327
  if (isBlurEvent && field._f.onBlur) {
1182
1328
  field._f.onBlur(event);
1183
1329
  }
1184
1330
  else if (field._f.onChange) {
1185
1331
  field._f.onChange(event);
1186
1332
  }
1187
- const shouldSkipValidation = (!hasValidation(field._f) &&
1188
- !formOptions.resolver &&
1189
- !get(_formState.errors, name) &&
1190
- !field._f.deps) ||
1191
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, reValidateMode, validationMode);
1192
- const isWatched = !isBlurEvent && isFieldWatched(name);
1193
- set(_formValues, name, inputValue);
1194
- const fieldState = updateTouchAndDirtyState(name, inputValue, isBlurEvent, false);
1333
+ set(_formValues, name, fieldValue);
1334
+ const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent, false);
1195
1335
  const shouldRender = !isEmptyObject(fieldState) || isWatched;
1196
1336
  !isBlurEvent &&
1197
1337
  _subjects.watch.next({
@@ -1203,12 +1343,12 @@ function createFormControl(props = {}) {
1203
1343
  _subjects.state.next(Object.assign({ name }, (isWatched ? {} : fieldState))));
1204
1344
  }
1205
1345
  !isBlurEvent && isWatched && _subjects.state.next({});
1206
- _validateCount[name] = _validateCount[name] ? +1 : 1;
1346
+ validateFields[name] = validateFields[name] ? +1 : 1;
1207
1347
  _proxyFormState.isValidating &&
1208
1348
  _subjects.state.next({
1209
1349
  isValidating: true,
1210
1350
  });
1211
- if (formOptions.resolver) {
1351
+ if (_options.resolver) {
1212
1352
  const { errors } = await executeResolver([name]);
1213
1353
  error = get(errors, name);
1214
1354
  if (isCheckBoxInput(target) && !error) {
@@ -1224,170 +1364,42 @@ function createFormControl(props = {}) {
1224
1364
  isValid = isEmptyObject(errors);
1225
1365
  }
1226
1366
  else {
1227
- error = (await validateField(field, get(_formValues, name), isValidateAllFieldCriteria, formOptions.shouldUseNativeValidation))[name];
1367
+ error = (await validateField(field, get(_formValues, name), shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
1228
1368
  isValid = await _updateValid(true);
1229
1369
  }
1230
- if (field._f.deps) {
1231
- trigger(field._f.deps);
1232
- }
1233
- shouldRenderBaseOnError(false, name, isValid, error, fieldState);
1234
- }
1235
- };
1236
- const _updateValidAndInputValue = (name, shouldSkipValueAs, ref) => {
1237
- const field = get(_fields, name);
1238
- if (field) {
1239
- const fieldValue = get(_formValues, name);
1240
- const defaultValue = isUndefined(fieldValue)
1241
- ? get(_defaultValues, name)
1242
- : fieldValue;
1243
- if (isUndefined(defaultValue) ||
1244
- (ref && ref.defaultChecked) ||
1245
- shouldSkipValueAs) {
1246
- set(_formValues, name, shouldSkipValueAs ? defaultValue : getFieldValue(field._f));
1247
- }
1248
- else {
1249
- setFieldValue(name, defaultValue);
1250
- }
1251
- }
1252
- _stateFlags.mount && _updateValid();
1253
- };
1254
- const _getIsDirty = (name, data) => {
1255
- name && data && set(_formValues, name, data);
1256
- return !deepEqual(Object.assign({}, getValues()), _defaultValues);
1257
- };
1258
- const _updateValid = async (skipRender) => {
1259
- let isValid = false;
1260
- if (_proxyFormState.isValid) {
1261
- isValid = formOptions.resolver
1262
- ? isEmptyObject((await executeResolver()).errors)
1263
- : await validateForm(_fields, true);
1264
- if (!skipRender && isValid !== _formState.isValid) {
1265
- _formState.isValid = isValid;
1266
- _subjects.state.next({
1267
- isValid,
1268
- });
1269
- }
1270
- }
1271
- return isValid;
1272
- };
1273
- const setValues = (name, value, options) => Object.entries(value).forEach(([fieldKey, fieldValue]) => {
1274
- const fieldName = `${name}.${fieldKey}`;
1275
- const field = get(_fields, fieldName);
1276
- (_names.array.has(name) ||
1277
- !isPrimitive(fieldValue) ||
1278
- (field && !field._f)) &&
1279
- !isDateObject(fieldValue)
1280
- ? setValues(fieldName, fieldValue, options)
1281
- : setFieldValue(fieldName, fieldValue, options, true);
1282
- });
1283
- const _getWatch = (fieldNames, defaultValue, isMounted, isGlobal) => {
1284
- const fieldValues = Object.assign({}, (isMounted || _stateFlags.mount
1285
- ? _formValues
1286
- : isUndefined(defaultValue)
1287
- ? _defaultValues
1288
- : isString(fieldNames)
1289
- ? { [fieldNames]: defaultValue }
1290
- : defaultValue));
1291
- if (!fieldNames) {
1292
- isGlobal && (_names.watchAll = true);
1293
- return fieldValues;
1294
- }
1295
- const result = [];
1296
- for (const fieldName of convertToArrayPayload(fieldNames)) {
1297
- isGlobal && _names.watch.add(fieldName);
1298
- result.push(get(fieldValues, fieldName));
1299
- }
1300
- return Array.isArray(fieldNames) ? result : result[0];
1301
- };
1302
- const _updateFieldArray = (keyName, name, method, args, values = [], shouldSet = true, shouldSetFields = true) => {
1303
- let output;
1304
- _stateFlags.action = true;
1305
- if (shouldSetFields && get(_fields, name)) {
1306
- output = method(get(_fields, name), args.argA, args.argB);
1307
- shouldSet && set(_fields, name, output);
1308
- }
1309
- if (Array.isArray(get(_formState.errors, name))) {
1310
- const output = method(get(_formState.errors, name), args.argA, args.argB);
1311
- shouldSet && set(_formState.errors, name, output);
1312
- unsetEmptyArray(_formState.errors, name);
1313
- }
1314
- if (_proxyFormState.touchedFields && get(_formState.touchedFields, name)) {
1315
- const output = method(get(_formState.touchedFields, name), args.argA, args.argB);
1316
- shouldSet && set(_formState.touchedFields, name, output);
1317
- unsetEmptyArray(_formState.touchedFields, name);
1318
- }
1319
- if (_proxyFormState.dirtyFields || _proxyFormState.isDirty) {
1320
- set(_formState.dirtyFields, name, setFieldArrayDirtyFields(omitKey(values, keyName), get(_defaultValues, name, []), get(_formState.dirtyFields, name, [])));
1321
- values &&
1322
- set(_formState.dirtyFields, name, setFieldArrayDirtyFields(omitKey(values, keyName), get(_defaultValues, name, []), get(_formState.dirtyFields, name, [])));
1323
- unsetEmptyArray(_formState.dirtyFields, name);
1324
- }
1325
- _subjects.state.next({
1326
- isDirty: _getIsDirty(name, omitKey(values, keyName)),
1327
- dirtyFields: _formState.dirtyFields,
1328
- errors: _formState.errors,
1329
- isValid: _formState.isValid,
1330
- });
1331
- };
1332
- const _getFieldArrayValue = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, []);
1333
- const setValue = (name, value, options = {}) => {
1334
- const field = get(_fields, name);
1335
- const isFieldArray = _names.array.has(name);
1336
- set(_formValues, name, value);
1337
- if (isFieldArray) {
1338
- _subjects.array.next({
1339
- name,
1340
- values: _formValues,
1341
- });
1342
- if ((_proxyFormState.isDirty || _proxyFormState.dirtyFields) &&
1343
- options.shouldDirty) {
1344
- set(_formState.dirtyFields, name, setFieldArrayDirtyFields(value, get(_defaultValues, name, []), get(_formState.dirtyFields, name, [])));
1345
- _subjects.state.next({
1346
- name,
1347
- dirtyFields: _formState.dirtyFields,
1348
- isDirty: _getIsDirty(name, value),
1349
- });
1350
- }
1370
+ field._f.deps && trigger(field._f.deps);
1371
+ shouldRenderByError(false, name, isValid, error, fieldState);
1351
1372
  }
1352
- else {
1353
- field && !field._f && !isNullOrUndefined(value)
1354
- ? setValues(name, value, options)
1355
- : setFieldValue(name, value, options, true);
1356
- }
1357
- isFieldWatched(name) && _subjects.state.next({});
1358
- _subjects.watch.next({
1359
- name,
1360
- });
1361
1373
  };
1362
1374
  const trigger = async (name, options = {}) => {
1363
- const fieldNames = convertToArrayPayload(name);
1364
1375
  let isValid;
1376
+ let validationResult;
1377
+ const fieldNames = convertToArrayPayload(name);
1365
1378
  _subjects.state.next({
1366
1379
  isValidating: true,
1367
1380
  });
1368
- if (formOptions.resolver) {
1369
- const schemaResult = await executeResolverValidation(isUndefined(name) ? name : fieldNames);
1370
- isValid = name
1371
- ? fieldNames.every((name) => !get(schemaResult, name))
1372
- : isEmptyObject(schemaResult);
1381
+ if (_options.resolver) {
1382
+ const errors = await executeResolverValidation(isUndefined(name) ? name : fieldNames);
1383
+ isValid = isEmptyObject(errors);
1384
+ validationResult = name
1385
+ ? !fieldNames.some((name) => get(errors, name))
1386
+ : isValid;
1387
+ }
1388
+ else if (name) {
1389
+ validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
1390
+ const field = get(_fields, fieldName);
1391
+ return await executeBuildInValidation(field && field._f ? { [fieldName]: field } : field);
1392
+ }))).every(Boolean);
1393
+ _updateValid();
1373
1394
  }
1374
1395
  else {
1375
- if (name) {
1376
- isValid = (await Promise.all(fieldNames.map(async (fieldName) => {
1377
- const field = get(_fields, fieldName);
1378
- return await validateForm(field && field._f ? { [fieldName]: field } : field);
1379
- }))).every(Boolean);
1380
- _updateValid();
1381
- }
1382
- else {
1383
- isValid = await validateForm(_fields);
1384
- }
1396
+ validationResult = isValid = await executeBuildInValidation(_fields);
1385
1397
  }
1386
- _subjects.state.next(Object.assign(Object.assign({}, (isString(name) ? { name } : {})), { errors: _formState.errors, isValid, isValidating: false }));
1387
- if (options.shouldFocus && !isValid) {
1398
+ _subjects.state.next(Object.assign(Object.assign({}, (!isString(name) || isValid !== _formState.isValid ? {} : { name })), { errors: _formState.errors, isValid, isValidating: false }));
1399
+ options.shouldFocus &&
1400
+ !validationResult &&
1388
1401
  focusFieldBy(_fields, (key) => get(_formState.errors, key), name ? fieldNames : _names.mount);
1389
- }
1390
- return isValid;
1402
+ return validationResult;
1391
1403
  };
1392
1404
  const getValues = (fieldNames) => {
1393
1405
  const values = Object.assign(Object.assign({}, _defaultValues), (_stateFlags.mount ? _formValues : {}));
@@ -1415,88 +1427,83 @@ function createFormControl(props = {}) {
1415
1427
  });
1416
1428
  options && options.shouldFocus && ref && ref.focus && ref.focus();
1417
1429
  };
1418
- const watch = (fieldName, defaultValue) => isFunction(fieldName)
1430
+ const watch = (name, defaultValue) => isFunction(name)
1419
1431
  ? _subjects.watch.subscribe({
1420
- next: (info) => fieldName(_getWatch(undefined, defaultValue), info),
1432
+ next: (info) => name(_getWatch(undefined, defaultValue), info),
1421
1433
  })
1422
- : _getWatch(fieldName, defaultValue, false, true);
1434
+ : _getWatch(name, defaultValue, true);
1423
1435
  const unregister = (name, options = {}) => {
1424
- for (const inputName of name ? convertToArrayPayload(name) : _names.mount) {
1425
- _names.mount.delete(inputName);
1426
- _names.array.delete(inputName);
1427
- if (get(_fields, inputName)) {
1436
+ for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
1437
+ _names.mount.delete(fieldName);
1438
+ _names.array.delete(fieldName);
1439
+ if (get(_fields, fieldName)) {
1428
1440
  if (!options.keepValue) {
1429
- unset(_fields, inputName);
1430
- unset(_formValues, inputName);
1441
+ unset(_fields, fieldName);
1442
+ unset(_formValues, fieldName);
1431
1443
  }
1432
- !options.keepError && unset(_formState.errors, inputName);
1433
- !options.keepDirty && unset(_formState.dirtyFields, inputName);
1434
- !options.keepTouched && unset(_formState.touchedFields, inputName);
1435
- !formOptions.shouldUnregister &&
1444
+ !options.keepError && unset(_formState.errors, fieldName);
1445
+ !options.keepDirty && unset(_formState.dirtyFields, fieldName);
1446
+ !options.keepTouched && unset(_formState.touchedFields, fieldName);
1447
+ !_options.shouldUnregister &&
1436
1448
  !options.keepDefaultValue &&
1437
- unset(_defaultValues, inputName);
1449
+ unset(_defaultValues, fieldName);
1438
1450
  }
1439
1451
  }
1440
1452
  _subjects.watch.next({});
1441
- _subjects.state.next(Object.assign(Object.assign({}, _formState), (!options.keepDirty ? {} : { isDirty: _getIsDirty() })));
1453
+ _subjects.state.next(Object.assign(Object.assign({}, _formState), (!options.keepDirty ? {} : { isDirty: _getDirty() })));
1442
1454
  !options.keepIsValid && _updateValid();
1443
1455
  };
1444
- const registerFieldRef = (name, fieldRef, options) => {
1445
- register(name, options);
1446
- let field = get(_fields, name);
1447
- const ref = isUndefined(fieldRef.value)
1448
- ? fieldRef.querySelectorAll
1449
- ? fieldRef.querySelectorAll('input,select,textarea')[0] ||
1450
- fieldRef
1451
- : fieldRef
1452
- : fieldRef;
1453
- const isRadioOrCheckbox = isRadioOrCheckboxFunction(ref);
1454
- if (ref === field._f.ref ||
1455
- (isRadioOrCheckbox &&
1456
- compact(field._f.refs || []).find((option) => option === ref))) {
1457
- return;
1458
- }
1459
- field = {
1460
- _f: isRadioOrCheckbox
1461
- ? Object.assign(Object.assign({}, field._f), { refs: [
1462
- ...compact(field._f.refs || []).filter((ref) => isHTMLElement(ref) && document.contains(ref)),
1463
- ref,
1464
- ], ref: { type: ref.type, name } }) : Object.assign(Object.assign({}, field._f), { ref }),
1465
- };
1466
- set(_fields, name, field);
1467
- (!options || !options.disabled) &&
1468
- _updateValidAndInputValue(name, false, ref);
1469
- };
1470
1456
  const register = (name, options = {}) => {
1471
1457
  const field = get(_fields, name);
1472
1458
  set(_fields, name, {
1473
1459
  _f: Object.assign(Object.assign(Object.assign({}, (field && field._f ? field._f : { ref: { name } })), { name, mount: true }), options),
1474
1460
  });
1475
1461
  _names.mount.add(name);
1476
- if (!isUndefined(options.value)) {
1477
- set(_formValues, name, options.value);
1478
- }
1479
- if (field && isBoolean(options.disabled)) {
1480
- set(_formValues, name, options.disabled
1481
- ? undefined
1482
- : get(_formValues, name, getFieldValue(field._f)));
1483
- }
1484
- !field && _updateValidAndInputValue(name, true);
1462
+ !isUndefined(options.value) && set(_formValues, name, options.value);
1463
+ field
1464
+ ? isBoolean(options.disabled) &&
1465
+ set(_formValues, name, options.disabled
1466
+ ? undefined
1467
+ : get(_formValues, name, getFieldValue(field._f)))
1468
+ : updateValidAndValue(name, true);
1485
1469
  return isWindowUndefined
1486
1470
  ? { name: name }
1487
1471
  : Object.assign(Object.assign({ name }, (isBoolean(options.disabled)
1488
1472
  ? { disabled: options.disabled }
1489
1473
  : {})), { onChange: handleChange, onBlur: handleChange, ref: (ref) => {
1490
1474
  if (ref) {
1491
- registerFieldRef(name, ref, options);
1475
+ register(name, options);
1476
+ let field = get(_fields, name);
1477
+ const fieldRef = isUndefined(ref.value)
1478
+ ? ref.querySelectorAll
1479
+ ? ref.querySelectorAll('input,select,textarea')[0] ||
1480
+ ref
1481
+ : ref
1482
+ : ref;
1483
+ const isRadioOrCheckbox = isRadioOrCheckboxFunction(fieldRef);
1484
+ if (fieldRef === field._f.ref ||
1485
+ (isRadioOrCheckbox &&
1486
+ compact(field._f.refs || []).find((option) => option === fieldRef))) {
1487
+ return;
1488
+ }
1489
+ field = {
1490
+ _f: isRadioOrCheckbox
1491
+ ? Object.assign(Object.assign({}, field._f), { refs: [
1492
+ ...compact(field._f.refs || []).filter((ref) => isHTMLElement(ref) && document.contains(ref)),
1493
+ fieldRef,
1494
+ ], ref: { type: fieldRef.type, name } }) : Object.assign(Object.assign({}, field._f), { ref: fieldRef }),
1495
+ };
1496
+ set(_fields, name, field);
1497
+ (!options || !options.disabled) &&
1498
+ updateValidAndValue(name, false, fieldRef);
1492
1499
  }
1493
1500
  else {
1494
1501
  const field = get(_fields, name, {});
1495
- const _shouldUnregister = formOptions.shouldUnregister || options.shouldUnregister;
1502
+ const shouldUnregister = _options.shouldUnregister || options.shouldUnregister;
1496
1503
  if (field._f) {
1497
1504
  field._f.mount = false;
1498
1505
  }
1499
- _shouldUnregister &&
1506
+ shouldUnregister &&
1500
1507
  !(isNameInFieldArray(_names.array, name) && _stateFlags.action) &&
1501
1508
  _names.unMount.add(name);
1502
1509
  }
@@ -1513,13 +1520,13 @@ function createFormControl(props = {}) {
1513
1520
  isSubmitting: true,
1514
1521
  });
1515
1522
  try {
1516
- if (formOptions.resolver) {
1523
+ if (_options.resolver) {
1517
1524
  const { errors, values } = await executeResolver();
1518
1525
  _formState.errors = errors;
1519
1526
  fieldValues = values;
1520
1527
  }
1521
1528
  else {
1522
- await validateForm(_fields);
1529
+ await executeBuildInValidation(_fields);
1523
1530
  }
1524
1531
  if (isEmptyObject(_formState.errors) &&
1525
1532
  Object.keys(_formState.errors).every((name) => get(fieldValues, name))) {
@@ -1531,7 +1538,7 @@ function createFormControl(props = {}) {
1531
1538
  }
1532
1539
  else {
1533
1540
  onInvalid && (await onInvalid(_formState.errors, e));
1534
- formOptions.shouldFocusError &&
1541
+ _options.shouldFocusError &&
1535
1542
  focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
1536
1543
  }
1537
1544
  }
@@ -1552,22 +1559,23 @@ function createFormControl(props = {}) {
1552
1559
  };
1553
1560
  const reset = (formValues, keepStateOptions = {}) => {
1554
1561
  const updatedValues = formValues || _defaultValues;
1555
- const values = cloneObject(updatedValues);
1562
+ const cloneUpdatedValues = cloneObject(updatedValues);
1556
1563
  if (!keepStateOptions.keepValues) {
1557
- _formValues = props.shouldUnregister ? {} : values;
1558
- }
1559
- if (isWeb && !keepStateOptions.keepValues) {
1560
- for (const name of _names.mount) {
1561
- const field = get(_fields, name);
1562
- if (field && field._f) {
1563
- const inputRef = Array.isArray(field._f.refs)
1564
- ? field._f.refs[0]
1565
- : field._f.ref;
1566
- try {
1567
- isHTMLElement(inputRef) && inputRef.closest('form').reset();
1568
- break;
1564
+ _formValues = props.shouldUnregister ? {} : cloneUpdatedValues;
1565
+ if (isWeb) {
1566
+ for (const name of _names.mount) {
1567
+ const field = get(_fields, name);
1568
+ if (field && field._f) {
1569
+ const fieldReference = Array.isArray(field._f.refs)
1570
+ ? field._f.refs[0]
1571
+ : field._f.ref;
1572
+ try {
1573
+ isHTMLElement(fieldReference) &&
1574
+ fieldReference.closest('form').reset();
1575
+ break;
1576
+ }
1577
+ catch (_a) { }
1569
1578
  }
1570
- catch (_a) { }
1571
1579
  }
1572
1580
  }
1573
1581
  }
@@ -1583,7 +1591,7 @@ function createFormControl(props = {}) {
1583
1591
  });
1584
1592
  _subjects.watch.next({});
1585
1593
  _subjects.array.next({
1586
- values,
1594
+ values: cloneUpdatedValues,
1587
1595
  });
1588
1596
  }
1589
1597
  _names = {
@@ -1623,27 +1631,17 @@ function createFormControl(props = {}) {
1623
1631
  _stateFlags.watch = !!props.shouldUnregister;
1624
1632
  };
1625
1633
  const setFocus = (name) => get(_fields, name)._f.ref.focus();
1626
- const _removeFields = () => {
1627
- for (const name of _names.unMount) {
1628
- const field = get(_fields, name);
1629
- field &&
1630
- (field._f.refs ? field._f.refs.every(live) : live(field._f.ref)) &&
1631
- unregister(name);
1632
- }
1633
- _names.unMount = new Set();
1634
- };
1635
1634
  return {
1636
1635
  control: {
1637
1636
  register,
1638
1637
  unregister,
1639
1638
  _getWatch,
1640
- _getIsDirty,
1639
+ _getDirty,
1641
1640
  _updateValid,
1642
- _removeFields,
1641
+ _removeUnmounted,
1643
1642
  _updateFieldArray,
1644
- _getFieldArrayValue,
1643
+ _getFieldArray,
1645
1644
  _subjects,
1646
- _shouldUnregister: formOptions.shouldUnregister,
1647
1645
  _proxyFormState,
1648
1646
  get _fields() {
1649
1647
  return _fields;
@@ -1681,8 +1679,11 @@ function createFormControl(props = {}) {
1681
1679
  set _formState(value) {
1682
1680
  _formState = value;
1683
1681
  },
1684
- _updateProps: (options) => {
1685
- formOptions = Object.assign(Object.assign({}, defaultOptions), options);
1682
+ get _options() {
1683
+ return _options;
1684
+ },
1685
+ set _options(value) {
1686
+ _options = Object.assign(Object.assign({}, _options), value);
1686
1687
  },
1687
1688
  },
1688
1689
  trigger,
@@ -1714,25 +1715,21 @@ function useForm(props = {}) {
1714
1715
  errors: {},
1715
1716
  });
1716
1717
  if (_formControl.current) {
1717
- _formControl.current.control._updateProps(props);
1718
+ _formControl.current.control._options = props;
1718
1719
  }
1719
1720
  else {
1720
1721
  _formControl.current = Object.assign(Object.assign({}, createFormControl(props)), { formState });
1721
1722
  }
1722
1723
  const control = _formControl.current.control;
1723
- React.useEffect(() => {
1724
- const formStateSubscription = control._subjects.state.subscribe({
1725
- next(formState) {
1726
- if (shouldRenderFormState(formState, control._proxyFormState, true)) {
1727
- control._formState = Object.assign(Object.assign({}, control._formState), formState);
1728
- updateFormState(Object.assign({}, control._formState));
1729
- }
1730
- },
1731
- });
1732
- return () => {
1733
- formStateSubscription.unsubscribe();
1734
- };
1735
- }, [control]);
1724
+ useSubscribe({
1725
+ subject: control._subjects.state,
1726
+ callback: (formState) => {
1727
+ if (shouldRenderFormState(formState, control._proxyFormState, true)) {
1728
+ control._formState = Object.assign(Object.assign({}, control._formState), formState);
1729
+ updateFormState(Object.assign({}, control._formState));
1730
+ }
1731
+ },
1732
+ });
1736
1733
  React.useEffect(() => {
1737
1734
  if (!control._stateFlags.mount) {
1738
1735
  control._proxyFormState.isValid && control._updateValid();
@@ -1742,7 +1739,7 @@ function useForm(props = {}) {
1742
1739
  control._stateFlags.watch = false;
1743
1740
  control._subjects.state.next({});
1744
1741
  }
1745
- control._removeFields();
1742
+ control._removeUnmounted();
1746
1743
  });
1747
1744
  _formControl.current.formState = getProxyFormState(formState, control._proxyFormState);
1748
1745
  return _formControl.current;
@@ -1753,31 +1750,30 @@ function useWatch(props) {
1753
1750
  const { control = methods.control, name, defaultValue, disabled, } = props || {};
1754
1751
  const _name = React.useRef(name);
1755
1752
  _name.current = name;
1753
+ useSubscribe({
1754
+ disabled,
1755
+ subject: control._subjects.watch,
1756
+ callback: ({ name }) => {
1757
+ if (!_name.current ||
1758
+ !name ||
1759
+ convertToArrayPayload(_name.current).some((currentName) => name &&
1760
+ currentName &&
1761
+ (name.startsWith(currentName) ||
1762
+ currentName.startsWith(name)))) {
1763
+ control._stateFlags.mount = true;
1764
+ const fieldValues = control._getWatch(_name.current, defaultValue);
1765
+ updateValue(isObject(fieldValues)
1766
+ ? Object.assign({}, fieldValues) : Array.isArray(fieldValues)
1767
+ ? [...fieldValues]
1768
+ : fieldValues);
1769
+ }
1770
+ },
1771
+ });
1756
1772
  const [value, updateValue] = React.useState(isUndefined(defaultValue)
1757
1773
  ? control._getWatch(name)
1758
1774
  : defaultValue);
1759
1775
  React.useEffect(() => {
1760
- const watchSubscription = control._subjects.watch.subscribe({
1761
- next: ({ name }) => {
1762
- if (!_name.current ||
1763
- !name ||
1764
- convertToArrayPayload(_name.current).some((fieldName) => name &&
1765
- fieldName &&
1766
- (fieldName.startsWith(name) ||
1767
- name.startsWith(fieldName)))) {
1768
- const result = control._getWatch(_name.current, defaultValue, true);
1769
- updateValue(isObject(result)
1770
- ? Object.assign({}, result) : Array.isArray(result)
1771
- ? [...result]
1772
- : result);
1773
- }
1774
- },
1775
- });
1776
- disabled && watchSubscription.unsubscribe();
1777
- return () => watchSubscription.unsubscribe();
1778
- }, [disabled, control, defaultValue]);
1779
- React.useEffect(() => {
1780
- control._removeFields();
1776
+ control._removeUnmounted();
1781
1777
  });
1782
1778
  return value;
1783
1779
  }