react-hook-form 7.72.0 → 7.73.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.
@@ -18,9 +18,9 @@ var getEventValue = (event) => isObject(event) && event.target
18
18
  : event.target.value
19
19
  : event;
20
20
 
21
- var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name;
22
-
23
- var isNameInFieldArray = (names, name) => names.has(getNodeParentName(name));
21
+ var isNameInFieldArray = (names, name) => name
22
+ .split('.')
23
+ .some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
24
24
 
25
25
  var isPlainObject = (tempObject) => {
26
26
  const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
@@ -64,7 +64,10 @@ var get = (object, path, defaultValue) => {
64
64
  if (!path || !isObject(object)) {
65
65
  return defaultValue;
66
66
  }
67
- const result = (isKey(path) ? [path] : stringToPath(path)).reduce((result, key) => isNullOrUndefined(result) ? result : result[key], object);
67
+ const paths = isKey(path) ? [path] : stringToPath(path);
68
+ const result = paths.reduce((result, key) => {
69
+ return isNullOrUndefined(result) ? undefined : result[key];
70
+ }, object);
68
71
  return isUndefined(result) || result === object
69
72
  ? isUndefined(object[path])
70
73
  ? defaultValue
@@ -239,7 +242,10 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
239
242
 
240
243
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
241
244
 
242
- function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
245
+ function deepEqual(object1, object2, visited = new WeakSet()) {
246
+ if (object1 === object2) {
247
+ return true;
248
+ }
243
249
  if (isPrimitive(object1) || isPrimitive(object2)) {
244
250
  return Object.is(object1, object2);
245
251
  }
@@ -251,22 +257,22 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
251
257
  if (keys1.length !== keys2.length) {
252
258
  return false;
253
259
  }
254
- if (_internal_visited.has(object1) || _internal_visited.has(object2)) {
260
+ if (visited.has(object1) || visited.has(object2)) {
255
261
  return true;
256
262
  }
257
- _internal_visited.add(object1);
258
- _internal_visited.add(object2);
263
+ visited.add(object1);
264
+ visited.add(object2);
259
265
  for (const key of keys1) {
260
266
  const val1 = object1[key];
261
- if (!keys2.includes(key)) {
267
+ if (!(key in object2)) {
262
268
  return false;
263
269
  }
264
270
  if (key !== 'ref') {
265
271
  const val2 = object2[key];
266
272
  if ((isDateObject(val1) && isDateObject(val2)) ||
267
- (isObject(val1) && isObject(val2)) ||
268
- (Array.isArray(val1) && Array.isArray(val2))
269
- ? !deepEqual(val1, val2, _internal_visited)
273
+ ((isObject(val1) || Array.isArray(val1)) &&
274
+ (isObject(val2) || Array.isArray(val2)))
275
+ ? !deepEqual(val1, val2, visited)
270
276
  : !Object.is(val1, val2)) {
271
277
  return false;
272
278
  }
@@ -640,42 +646,43 @@ const useFormContext = () => React.useContext(HookFormContext);
640
646
  */
641
647
  const FormProvider = (props) => {
642
648
  const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
643
- return (React.createElement(HookFormContext.Provider, { value: React.useMemo(() => ({
644
- watch,
645
- getValues,
646
- getFieldState,
647
- setError,
648
- clearErrors,
649
- setValue,
650
- trigger,
651
- formState,
652
- resetField,
653
- reset,
654
- handleSubmit,
655
- unregister,
656
- control,
657
- register,
658
- setFocus,
659
- subscribe,
660
- }), [
661
- clearErrors,
662
- control,
663
- formState,
664
- getFieldState,
665
- getValues,
666
- handleSubmit,
667
- register,
668
- reset,
669
- resetField,
670
- setError,
671
- setFocus,
672
- setValue,
673
- subscribe,
674
- trigger,
675
- unregister,
676
- watch,
677
- ]) },
678
- React.createElement(HookFormControlContext.Provider, { value: control }, children)));
649
+ const memoizedValue = React.useMemo(() => ({
650
+ watch,
651
+ getValues,
652
+ getFieldState,
653
+ setError,
654
+ clearErrors,
655
+ setValue,
656
+ trigger,
657
+ formState,
658
+ resetField,
659
+ reset,
660
+ handleSubmit,
661
+ unregister,
662
+ control,
663
+ register,
664
+ setFocus,
665
+ subscribe,
666
+ }), [
667
+ clearErrors,
668
+ control,
669
+ formState,
670
+ getFieldState,
671
+ getValues,
672
+ handleSubmit,
673
+ register,
674
+ reset,
675
+ resetField,
676
+ setError,
677
+ setFocus,
678
+ setValue,
679
+ subscribe,
680
+ trigger,
681
+ unregister,
682
+ watch,
683
+ ]);
684
+ return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
685
+ React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
679
686
  };
680
687
 
681
688
  const POST_REQUEST = 'post';
@@ -705,7 +712,7 @@ function Form(props) {
705
712
  const methods = useFormContext();
706
713
  const [mounted, setMounted] = React.useState(false);
707
714
  const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
708
- const submit = async (event) => {
715
+ const submit = React.useCallback(async (event) => {
709
716
  let hasError = false;
710
717
  let type = '';
711
718
  await control.handleSubmit(async (data) => {
@@ -715,7 +722,7 @@ function Form(props) {
715
722
  formDataJson = JSON.stringify(data);
716
723
  }
717
724
  catch (_a) { }
718
- const flattenFormValues = flatten(control._formValues);
725
+ const flattenFormValues = flatten(data);
719
726
  for (const key in flattenFormValues) {
720
727
  formData.append(key, flattenFormValues[key]);
721
728
  }
@@ -762,15 +769,25 @@ function Form(props) {
762
769
  }
763
770
  }
764
771
  })(event);
765
- if (hasError && props.control) {
766
- props.control._subjects.state.next({
772
+ if (hasError && control) {
773
+ control._subjects.state.next({
767
774
  isSubmitSuccessful: false,
768
775
  });
769
- props.control.setError('root.server', {
776
+ control.setError('root.server', {
770
777
  type,
771
778
  });
772
779
  }
773
- };
780
+ }, [
781
+ control,
782
+ onSubmit,
783
+ method,
784
+ action,
785
+ headers,
786
+ encType,
787
+ validateStatus,
788
+ onError,
789
+ onSuccess,
790
+ ]);
774
791
  React.useEffect(() => {
775
792
  setMounted(true);
776
793
  }, []);
@@ -879,6 +896,10 @@ function isEmptyArray(obj) {
879
896
  return true;
880
897
  }
881
898
  function unset(object, path) {
899
+ if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
900
+ delete object[path];
901
+ return object;
902
+ }
882
903
  const paths = Array.isArray(path)
883
904
  ? path
884
905
  : isKey(path)
@@ -1014,6 +1035,8 @@ function getFieldValue(_f) {
1014
1035
  return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
1015
1036
  }
1016
1037
 
1038
+ var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name;
1039
+
1017
1040
  var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
1018
1041
  const fields = {};
1019
1042
  for (const name of fieldsNames) {
@@ -1420,6 +1443,7 @@ function createFormControl(props = {}) {
1420
1443
  unMount: new Set(),
1421
1444
  array: new Set(),
1422
1445
  watch: new Set(),
1446
+ registerName: new Set(),
1423
1447
  };
1424
1448
  let delayErrorCallback;
1425
1449
  let timer = 0;
@@ -1493,6 +1517,11 @@ function createFormControl(props = {}) {
1493
1517
  });
1494
1518
  }
1495
1519
  };
1520
+ const _updateDirtyFields = (name) => {
1521
+ const fullDirtyFields = getDirtyFields(_defaultValues, _formValues);
1522
+ const rootName = getNodeParentName(name);
1523
+ set(_formState.dirtyFields, rootName, get(fullDirtyFields, rootName));
1524
+ };
1496
1525
  const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
1497
1526
  if (args && method && !_options.disabled) {
1498
1527
  _state.action = true;
@@ -1514,9 +1543,7 @@ function createFormControl(props = {}) {
1514
1543
  shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1515
1544
  }
1516
1545
  if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
1517
- const fullDirtyFields = getDirtyFields(_defaultValues, _formValues);
1518
- const rootName = getNodeParentName(name);
1519
- set(_formState.dirtyFields, rootName, get(fullDirtyFields, rootName));
1546
+ _updateDirtyFields(name);
1520
1547
  }
1521
1548
  _subjects.state.next({
1522
1549
  name,
@@ -1834,41 +1861,47 @@ function createFormControl(props = {}) {
1834
1861
  const field = get(_fields, name);
1835
1862
  const isFieldArray = _names.array.has(name);
1836
1863
  const cloneValue = cloneObject(value);
1864
+ const previousValue = get(_formValues, name);
1865
+ const isValueUnchanged = deepEqual(previousValue, cloneValue);
1837
1866
  set(_formValues, name, cloneValue);
1838
1867
  if (isFieldArray) {
1839
1868
  _subjects.array.next({
1840
1869
  name,
1841
1870
  values: cloneObject(_formValues),
1842
1871
  });
1843
- if ((_proxyFormState.isDirty ||
1844
- _proxyFormState.dirtyFields ||
1845
- _proxySubscribeFormState.isDirty ||
1846
- _proxySubscribeFormState.dirtyFields) &&
1847
- options.shouldDirty) {
1872
+ if (options.shouldDirty) {
1873
+ _updateDirtyFields(name);
1848
1874
  _subjects.state.next({
1849
1875
  name,
1850
- dirtyFields: getDirtyFields(_defaultValues, _formValues),
1876
+ dirtyFields: _formState.dirtyFields,
1851
1877
  isDirty: _getDirty(name, cloneValue),
1852
1878
  });
1853
1879
  }
1854
1880
  }
1855
1881
  else {
1856
- field && !field._f && !isNullOrUndefined(cloneValue)
1857
- ? setValues(name, cloneValue, options)
1858
- : setFieldValue(name, cloneValue, options);
1859
- }
1860
- if (isWatched(name, _names)) {
1861
- _subjects.state.next({
1862
- ..._formState,
1863
- name,
1864
- values: cloneObject(_formValues),
1865
- });
1882
+ const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
1883
+ isEmptyObject(cloneValue);
1884
+ if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
1885
+ setFieldValue(name, cloneValue, options);
1886
+ }
1887
+ else {
1888
+ setValues(name, cloneValue, options);
1889
+ }
1866
1890
  }
1867
- else {
1868
- _subjects.state.next({
1869
- name: _state.mount ? name : undefined,
1870
- values: cloneObject(_formValues),
1871
- });
1891
+ if (!isValueUnchanged) {
1892
+ if (isWatched(name, _names)) {
1893
+ _subjects.state.next({
1894
+ ..._formState,
1895
+ name,
1896
+ values: cloneObject(_formValues),
1897
+ });
1898
+ }
1899
+ else {
1900
+ _subjects.state.next({
1901
+ name: _state.mount ? name : undefined,
1902
+ values: cloneObject(_formValues),
1903
+ });
1904
+ }
1872
1905
  }
1873
1906
  };
1874
1907
  const onChange = async (event) => {
@@ -2087,15 +2120,16 @@ function createFormControl(props = {}) {
2087
2120
  const watch = (name, defaultValue) => isFunction(name)
2088
2121
  ? _subjects.state.subscribe({
2089
2122
  next: (payload) => 'values' in payload &&
2090
- name(_getWatch(undefined, defaultValue), payload),
2123
+ name(payload.values || _getWatch(undefined, defaultValue), payload),
2091
2124
  })
2092
2125
  : _getWatch(name, defaultValue, true);
2093
2126
  const _subscribe = (props) => _subjects.state.subscribe({
2094
2127
  next: (formState) => {
2095
2128
  if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
2096
2129
  shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
2130
+ const snapshot = { ..._formValues };
2097
2131
  props.callback({
2098
- values: { ..._formValues },
2132
+ values: snapshot,
2099
2133
  ..._formState,
2100
2134
  ...formState,
2101
2135
  defaultValues: _defaultValues,
@@ -2157,6 +2191,7 @@ function createFormControl(props = {}) {
2157
2191
  const register = (name, options = {}) => {
2158
2192
  let field = get(_fields, name);
2159
2193
  const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
2194
+ const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
2160
2195
  set(_fields, name, {
2161
2196
  ...(field || {}),
2162
2197
  _f: {
@@ -2167,7 +2202,7 @@ function createFormControl(props = {}) {
2167
2202
  },
2168
2203
  });
2169
2204
  _names.mount.add(name);
2170
- if (field) {
2205
+ if (field && !shouldRevalidateRemount) {
2171
2206
  _setDisabledField({
2172
2207
  disabled: isBoolean(options.disabled)
2173
2208
  ? options.disabled
@@ -2197,7 +2232,9 @@ function createFormControl(props = {}) {
2197
2232
  onBlur: onChange,
2198
2233
  ref: (ref) => {
2199
2234
  if (ref) {
2235
+ _names.registerName.add(name);
2200
2236
  register(name, options);
2237
+ _names.registerName.delete(name);
2201
2238
  field = get(_fields, name);
2202
2239
  const fieldRef = isUndefined(ref.value)
2203
2240
  ? ref.querySelectorAll
@@ -2410,6 +2447,7 @@ function createFormControl(props = {}) {
2410
2447
  mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
2411
2448
  unMount: new Set(),
2412
2449
  array: new Set(),
2450
+ registerName: new Set(),
2413
2451
  disabled: new Set(),
2414
2452
  watch: new Set(),
2415
2453
  watchAll: false,
@@ -2800,10 +2838,11 @@ function useFieldArray(props) {
2800
2838
  control._subjects.state.next({
2801
2839
  ...control._formState,
2802
2840
  });
2841
+ const validationModes = getValidationModes(control._options.mode);
2803
2842
  if (_actioned.current &&
2804
- (!getValidationModes(control._options.mode).isOnSubmit ||
2805
- control._formState.isSubmitted) &&
2806
- !getValidationModes(control._options.reValidateMode).isOnSubmit) {
2843
+ (!validationModes.isOnSubmit || control._formState.isSubmitted) &&
2844
+ !getValidationModes(control._options.reValidateMode).isOnSubmit &&
2845
+ !validationModes.isOnBlur) {
2807
2846
  if (control._options.resolver) {
2808
2847
  control._runSchema([name]).then((result) => {
2809
2848
  control._updateIsValidating([name]);