react-hook-form 7.77.0 → 7.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -248,7 +248,8 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
248
248
 
249
249
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
250
250
 
251
- function deepEqual(object1, object2, visited = new WeakSet()) {
251
+ const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
252
+ function deepEqual(object1, object2, visited = new WeakMap()) {
252
253
  if (object1 === object2) {
253
254
  return true;
254
255
  }
@@ -263,11 +264,20 @@ function deepEqual(object1, object2, visited = new WeakSet()) {
263
264
  if (keys1.length !== keys2.length) {
264
265
  return false;
265
266
  }
266
- if (visited.has(object1) || visited.has(object2)) {
267
+ if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
268
+ isEmptyObjectWithCustomPrototype(object2, keys2)) {
269
+ return Object.is(object1, object2);
270
+ }
271
+ const visitedPairs = visited.get(object1);
272
+ if (visitedPairs && visitedPairs.has(object2)) {
267
273
  return true;
268
274
  }
269
- visited.add(object1);
270
- visited.add(object2);
275
+ if (visitedPairs) {
276
+ visitedPairs.add(object2);
277
+ }
278
+ else {
279
+ visited.set(object1, new WeakSet([object2]));
280
+ }
271
281
  for (const key of keys1) {
272
282
  const val1 = object1[key];
273
283
  if (!(key in object2)) {
@@ -414,6 +424,7 @@ function useController(props) {
414
424
  exact,
415
425
  });
416
426
  const _props = React.useRef(props);
427
+ const _proxyRef = React.useRef(null);
417
428
  const _registerProps = React.useRef(control.register(name, {
418
429
  ...props.rules,
419
430
  value,
@@ -442,13 +453,22 @@ function useController(props) {
442
453
  get: () => get(formState.errors, name),
443
454
  },
444
455
  }), [formState, name]);
445
- const onChange = React.useCallback((event) => _registerProps.current.onChange({
446
- target: {
447
- value: getEventValue(event),
448
- name: name,
449
- },
450
- type: EVENTS.CHANGE,
451
- }), [name]);
456
+ const onChange = React.useCallback((event) => {
457
+ const value = getEventValue(event);
458
+ if (!get(control._fields, name)) {
459
+ _registerProps.current = control.register(name, {
460
+ ..._props.current.rules,
461
+ value,
462
+ });
463
+ }
464
+ return _registerProps.current.onChange({
465
+ target: {
466
+ value: getEventValue(event),
467
+ name: name,
468
+ },
469
+ type: EVENTS.CHANGE,
470
+ });
471
+ }, [name, control]);
452
472
  const onBlur = React.useCallback(() => _registerProps.current.onBlur({
453
473
  target: {
454
474
  value: get(control._formValues, name),
@@ -457,15 +477,18 @@ function useController(props) {
457
477
  type: EVENTS.BLUR,
458
478
  }), [name, control._formValues]);
459
479
  const ref = React.useCallback((elm) => {
460
- const field = get(control._fields, name);
461
- if (field && field._f && elm) {
462
- field._f.ref = {
480
+ if (elm) {
481
+ _proxyRef.current = {
463
482
  focus: () => isFunction(elm.focus) && elm.focus(),
464
483
  select: () => isFunction(elm.select) && elm.select(),
465
484
  setCustomValidity: (message) => isFunction(elm.setCustomValidity) && elm.setCustomValidity(message),
466
485
  reportValidity: () => isFunction(elm.reportValidity) && elm.reportValidity(),
467
486
  };
468
487
  }
488
+ const field = get(control._fields, name);
489
+ if (field && field._f && elm) {
490
+ field._f.ref = _proxyRef.current;
491
+ }
469
492
  }, [control._fields, name]);
470
493
  const field = React.useMemo(() => ({
471
494
  name,
@@ -493,13 +516,21 @@ function useController(props) {
493
516
  };
494
517
  updateMounted(name, true);
495
518
  if (_shouldUnregisterField) {
496
- const value = cloneObject(get(control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
519
+ const value = cloneObject(get(shouldUnregister
520
+ ? control._defaultValues
521
+ : control._options.values || control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
497
522
  set(control._defaultValues, name, value);
498
523
  if (isUndefined(get(control._formValues, name))) {
499
524
  set(control._formValues, name, value);
500
525
  }
501
526
  }
502
527
  !isArrayField && control.register(name);
528
+ if (_proxyRef.current) {
529
+ const field = get(control._fields, name);
530
+ if (field && field._f) {
531
+ field._f.ref = _proxyRef.current;
532
+ }
533
+ }
503
534
  return () => {
504
535
  (isArrayField
505
536
  ? _shouldUnregisterField && !control._state.action
@@ -1258,7 +1289,13 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
1258
1289
  const inputRef = refs ? refs[0] : ref;
1259
1290
  const setCustomValidity = (message) => {
1260
1291
  if (shouldUseNativeValidation && inputRef.reportValidity) {
1261
- inputRef.setCustomValidity(isBoolean(message) ? '' : message || '');
1292
+ const validityMessage = isBoolean(message) ? '' : message || '';
1293
+ if (refs) {
1294
+ refs.forEach((ref) => ref.setCustomValidity(validityMessage));
1295
+ }
1296
+ else {
1297
+ inputRef.setCustomValidity(validityMessage);
1298
+ }
1262
1299
  inputRef.reportValidity();
1263
1300
  }
1264
1301
  };
@@ -1590,6 +1627,7 @@ function createFormControl(props = {}) {
1590
1627
  };
1591
1628
  const updateErrors = (name, error) => {
1592
1629
  set(_formState.errors, name, error);
1630
+ _formState.errors = { ..._formState.errors };
1593
1631
  _subjects.state.next({
1594
1632
  errors: _formState.errors,
1595
1633
  });
@@ -1647,6 +1685,15 @@ function createFormControl(props = {}) {
1647
1685
  _subjects.state.next({ ..._formState });
1648
1686
  }
1649
1687
  }
1688
+ // When a watched field is re-registered after being unregistered and
1689
+ // its value is restored, trigger a deferred watch broadcast so that
1690
+ // components using watch() re-render with the new value.
1691
+ if (props.shouldUnregister &&
1692
+ wasUnsetInFormValues &&
1693
+ !isUndefined(get(_formValues, name)) &&
1694
+ isWatched(name, _names)) {
1695
+ _state.watch = true;
1696
+ }
1650
1697
  }
1651
1698
  }
1652
1699
  };
@@ -1711,6 +1758,7 @@ function createFormControl(props = {}) {
1711
1758
  error
1712
1759
  ? set(_formState.errors, name, error)
1713
1760
  : unset(_formState.errors, name);
1761
+ _formState.errors = { ..._formState.errors };
1714
1762
  }
1715
1763
  if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1716
1764
  !isEmptyObject(fieldState) ||
@@ -1746,6 +1794,7 @@ function createFormControl(props = {}) {
1746
1794
  : set(_formState.errors, name, error)
1747
1795
  : unset(_formState.errors, name);
1748
1796
  }
1797
+ _formState.errors = { ..._formState.errors };
1749
1798
  }
1750
1799
  else {
1751
1800
  _formState.errors = errors;
@@ -2080,13 +2129,15 @@ function createFormControl(props = {}) {
2080
2129
  const { errors } = await _runSchema([name]);
2081
2130
  _updateIsValidating([name]);
2082
2131
  _updateIsFieldValueUpdated(fieldValue);
2083
- if (isFieldValueUpdated) {
2084
- const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
2085
- const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
2086
- error = errorLookupResult.error;
2087
- name = errorLookupResult.name;
2088
- isValid = isEmptyObject(errors);
2132
+ if (!isFieldValueUpdated) {
2133
+ !isEmptyObject(fieldState) && _subjects.state.next(fieldState);
2134
+ return;
2089
2135
  }
2136
+ const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
2137
+ const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
2138
+ error = errorLookupResult.error;
2139
+ name = errorLookupResult.name;
2140
+ isValid = isEmptyObject(errors);
2090
2141
  }
2091
2142
  else {
2092
2143
  _updateIsValidating([name], true);
@@ -2857,34 +2908,45 @@ var updateAt = (fieldValues, index, value) => {
2857
2908
  */
2858
2909
  function useFieldArray(props) {
2859
2910
  const formControl = useFormControlContext();
2860
- const { control = formControl, name, keyName = 'id', shouldUnregister, rules, } = props;
2861
- const [fields, setFields] = React.useState(control._getFieldArray(name));
2862
- const ids = React.useRef(control._getFieldArray(name).map(generateId));
2911
+ const { control = formControl, name, keyName = 'id', disabled, shouldUnregister, rules, } = props;
2912
+ const [fields, setFields] = React.useState(disabled ? [] : control._getFieldArray(name));
2913
+ const ids = React.useRef(disabled ? [] : control._getFieldArray(name).map(generateId));
2863
2914
  const _actioned = React.useRef(false);
2864
- control._names.array.add(name);
2865
- React.useMemo(() => rules &&
2915
+ if (!disabled) {
2916
+ control._names.array.add(name);
2917
+ }
2918
+ React.useMemo(() => !disabled &&
2919
+ rules &&
2866
2920
  fields.length >= 0 &&
2867
- control.register(name, rules), [control, name, fields.length, rules]);
2868
- useIsomorphicLayoutEffect(() => control._subjects.array.subscribe({
2869
- next: ({ values, name: fieldArrayName, }) => {
2870
- if (fieldArrayName === name || !fieldArrayName) {
2871
- const fieldValues = get(values, name);
2872
- if (Array.isArray(fieldValues)) {
2873
- setFields(fieldValues);
2874
- ids.current = fieldValues.map(generateId);
2875
- }
2876
- else if (!fieldArrayName) {
2877
- setFields([]);
2878
- ids.current = [];
2921
+ control.register(name, rules), [control, name, fields.length, rules, disabled]);
2922
+ useIsomorphicLayoutEffect(() => {
2923
+ if (disabled) {
2924
+ return;
2925
+ }
2926
+ return control._subjects.array.subscribe({
2927
+ next: ({ values, name: fieldArrayName, }) => {
2928
+ if (fieldArrayName === name || !fieldArrayName) {
2929
+ const fieldValues = get(values, name);
2930
+ if (Array.isArray(fieldValues)) {
2931
+ setFields(fieldValues);
2932
+ ids.current = fieldValues.map(generateId);
2933
+ }
2934
+ else if (!fieldArrayName) {
2935
+ setFields([]);
2936
+ ids.current = [];
2937
+ }
2879
2938
  }
2880
- }
2881
- },
2882
- }).unsubscribe, [control, name]);
2939
+ },
2940
+ }).unsubscribe;
2941
+ }, [control, name, disabled]);
2883
2942
  const updateValues = React.useCallback((updatedFieldArrayValues) => {
2884
2943
  _actioned.current = true;
2885
2944
  control._setFieldArray(name, updatedFieldArrayValues);
2886
2945
  }, [control, name]);
2887
2946
  const append = (value, options) => {
2947
+ if (disabled) {
2948
+ return;
2949
+ }
2888
2950
  const appendValue = convertToArrayPayload(cloneObject(value));
2889
2951
  const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
2890
2952
  control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
@@ -2896,6 +2958,9 @@ function useFieldArray(props) {
2896
2958
  });
2897
2959
  };
2898
2960
  const prepend = (value, options) => {
2961
+ if (disabled) {
2962
+ return;
2963
+ }
2899
2964
  const prependValue = convertToArrayPayload(cloneObject(value));
2900
2965
  const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
2901
2966
  control._names.focus = getFocusFieldName(name, 0, options);
@@ -2907,6 +2972,9 @@ function useFieldArray(props) {
2907
2972
  });
2908
2973
  };
2909
2974
  const remove = (index) => {
2975
+ if (disabled) {
2976
+ return;
2977
+ }
2910
2978
  const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
2911
2979
  ids.current = removeArrayAt(ids.current, index);
2912
2980
  updateValues(updatedFieldArrayValues);
@@ -2918,6 +2986,9 @@ function useFieldArray(props) {
2918
2986
  });
2919
2987
  };
2920
2988
  const insert$1 = (index, value, options) => {
2989
+ if (disabled) {
2990
+ return;
2991
+ }
2921
2992
  const insertValue = convertToArrayPayload(cloneObject(value));
2922
2993
  const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
2923
2994
  control._names.focus = getFocusFieldName(name, index, options);
@@ -2930,6 +3001,9 @@ function useFieldArray(props) {
2930
3001
  });
2931
3002
  };
2932
3003
  const swap = (indexA, indexB) => {
3004
+ if (disabled) {
3005
+ return;
3006
+ }
2933
3007
  const updatedFieldArrayValues = control._getFieldArray(name);
2934
3008
  swapArrayAt(updatedFieldArrayValues, indexA, indexB);
2935
3009
  swapArrayAt(ids.current, indexA, indexB);
@@ -2941,6 +3015,9 @@ function useFieldArray(props) {
2941
3015
  }, false);
2942
3016
  };
2943
3017
  const move = (from, to) => {
3018
+ if (disabled) {
3019
+ return;
3020
+ }
2944
3021
  const updatedFieldArrayValues = control._getFieldArray(name);
2945
3022
  moveArrayAt(updatedFieldArrayValues, from, to);
2946
3023
  moveArrayAt(ids.current, from, to);
@@ -2952,6 +3029,9 @@ function useFieldArray(props) {
2952
3029
  }, false);
2953
3030
  };
2954
3031
  const update = (index, value) => {
3032
+ if (disabled) {
3033
+ return;
3034
+ }
2955
3035
  const updateValue = cloneObject(value);
2956
3036
  const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
2957
3037
  ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
@@ -2963,6 +3043,9 @@ function useFieldArray(props) {
2963
3043
  }, true, false);
2964
3044
  };
2965
3045
  const replace = (value) => {
3046
+ if (disabled) {
3047
+ return;
3048
+ }
2966
3049
  const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
2967
3050
  ids.current = updatedFieldArrayValues.map(generateId);
2968
3051
  updateValues([...updatedFieldArrayValues]);
@@ -2970,6 +3053,9 @@ function useFieldArray(props) {
2970
3053
  control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
2971
3054
  };
2972
3055
  React.useEffect(() => {
3056
+ if (disabled) {
3057
+ return;
3058
+ }
2973
3059
  control._state.action = false;
2974
3060
  isWatched(name, control._names) &&
2975
3061
  control._subjects.state.next({
@@ -3030,10 +3116,15 @@ function useFieldArray(props) {
3030
3116
  control._names.focus = '';
3031
3117
  control._setValid();
3032
3118
  _actioned.current = false;
3033
- }, [fields, name, control]);
3119
+ }, [fields, name, control, disabled]);
3034
3120
  React.useEffect(() => {
3035
- !get(control._formValues, name) && control._setFieldArray(name);
3121
+ if (!disabled) {
3122
+ !get(control._formValues, name) && control._setFieldArray(name);
3123
+ }
3036
3124
  return () => {
3125
+ if (disabled) {
3126
+ return;
3127
+ }
3037
3128
  const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
3038
3129
  const updateMounted = (name, value) => {
3039
3130
  const field = get(control._fields, name);
@@ -3051,16 +3142,26 @@ function useFieldArray(props) {
3051
3142
  ? updateMounted(name, false)
3052
3143
  : control.unregister(name);
3053
3144
  };
3054
- }, [name, control, keyName, shouldUnregister]);
3145
+ }, [name, control, keyName, shouldUnregister, disabled]);
3055
3146
  return {
3056
- swap: React.useCallback(swap, [updateValues, name, control]),
3057
- move: React.useCallback(move, [updateValues, name, control]),
3058
- prepend: React.useCallback(prepend, [updateValues, name, control]),
3059
- append: React.useCallback(append, [updateValues, name, control]),
3060
- remove: React.useCallback(remove, [updateValues, name, control]),
3061
- insert: React.useCallback(insert$1, [updateValues, name, control]),
3062
- update: React.useCallback(update, [updateValues, name, control]),
3063
- replace: React.useCallback(replace, [updateValues, name, control]),
3147
+ swap: React.useCallback(swap, [updateValues, name, control, disabled]),
3148
+ move: React.useCallback(move, [updateValues, name, control, disabled]),
3149
+ prepend: React.useCallback(prepend, [
3150
+ updateValues,
3151
+ name,
3152
+ control,
3153
+ disabled,
3154
+ ]),
3155
+ append: React.useCallback(append, [updateValues, name, control, disabled]),
3156
+ remove: React.useCallback(remove, [updateValues, name, control, disabled]),
3157
+ insert: React.useCallback(insert$1, [updateValues, name, control, disabled]),
3158
+ update: React.useCallback(update, [updateValues, name, control, disabled]),
3159
+ replace: React.useCallback(replace, [
3160
+ updateValues,
3161
+ name,
3162
+ control,
3163
+ disabled,
3164
+ ]),
3064
3165
  fields: React.useMemo(() => fields.map((field, index) => ({
3065
3166
  ...field,
3066
3167
  [keyName]: ids.current[index] || generateId(),
@@ -3100,6 +3201,7 @@ function useFieldArray(props) {
3100
3201
  function useForm(props = {}) {
3101
3202
  const _formControl = React.useRef(undefined);
3102
3203
  const _values = React.useRef(undefined);
3204
+ const _formControlProp = React.useRef(props.formControl);
3103
3205
  const [formState, updateFormState] = React.useState(() => ({
3104
3206
  ...cloneObject(DEFAULT_FORM_STATE),
3105
3207
  isLoading: isFunction(props.defaultValues),
@@ -3109,7 +3211,9 @@ function useForm(props = {}) {
3109
3211
  ? undefined
3110
3212
  : props.defaultValues,
3111
3213
  }));
3112
- if (!_formControl.current) {
3214
+ if (!_formControl.current ||
3215
+ (props.formControl && _formControlProp.current !== props.formControl)) {
3216
+ _formControlProp.current = props.formControl;
3113
3217
  if (props.formControl) {
3114
3218
  _formControl.current = {
3115
3219
  ...props.formControl,