react-hook-form 7.76.1 → 7.77.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.
@@ -52,19 +52,48 @@ function cloneObject(data) {
52
52
  return copy;
53
53
  }
54
54
 
55
+ const EVENTS = {
56
+ BLUR: 'blur',
57
+ FOCUS_OUT: 'focusout',
58
+ CHANGE: 'change',
59
+ SUBMIT: 'submit',
60
+ TRIGGER: 'trigger',
61
+ VALID: 'valid',
62
+ };
63
+ const VALIDATION_MODE = {
64
+ onBlur: 'onBlur',
65
+ onChange: 'onChange',
66
+ onSubmit: 'onSubmit',
67
+ onTouched: 'onTouched',
68
+ all: 'all',
69
+ };
70
+ const INPUT_VALIDATION_RULES = {
71
+ max: 'max',
72
+ min: 'min',
73
+ maxLength: 'maxLength',
74
+ minLength: 'minLength',
75
+ pattern: 'pattern',
76
+ required: 'required',
77
+ validate: 'validate',
78
+ };
79
+ const FORM_ERROR_TYPE = 'form';
80
+ const ROOT_ERROR_TYPE = 'root';
81
+ const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
82
+
55
83
  var isKey = (value) => /^\w*$/.test(value);
56
84
 
57
85
  var isUndefined = (val) => val === undefined;
58
86
 
59
- var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
60
-
61
- var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
87
+ var stringToPath = (input) => input.split(/[.[\]'"]/g).filter(Boolean);
62
88
 
63
89
  var get = (object, path, defaultValue) => {
64
90
  if (!path || !isObject(object)) {
65
91
  return defaultValue;
66
92
  }
67
93
  const paths = isKey(path) ? [path] : stringToPath(path);
94
+ if (paths.some((key) => PROTOTYPE_KEYWORDS.includes(key))) {
95
+ return defaultValue;
96
+ }
68
97
  const result = paths.reduce((result, key) => {
69
98
  return isNullOrUndefined(result) ? undefined : result[key];
70
99
  }, object);
@@ -96,7 +125,7 @@ var set = (object, path, value) => {
96
125
  ? []
97
126
  : {};
98
127
  }
99
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
128
+ if (PROTOTYPE_KEYWORDS.includes(key)) {
100
129
  return;
101
130
  }
102
131
  object[key] = newValue;
@@ -104,33 +133,6 @@ var set = (object, path, value) => {
104
133
  }
105
134
  };
106
135
 
107
- const EVENTS = {
108
- BLUR: 'blur',
109
- FOCUS_OUT: 'focusout',
110
- CHANGE: 'change',
111
- SUBMIT: 'submit',
112
- TRIGGER: 'trigger',
113
- VALID: 'valid',
114
- };
115
- const VALIDATION_MODE = {
116
- onBlur: 'onBlur',
117
- onChange: 'onChange',
118
- onSubmit: 'onSubmit',
119
- onTouched: 'onTouched',
120
- all: 'all',
121
- };
122
- const INPUT_VALIDATION_RULES = {
123
- max: 'max',
124
- min: 'min',
125
- maxLength: 'maxLength',
126
- minLength: 'minLength',
127
- pattern: 'pattern',
128
- required: 'required',
129
- validate: 'validate',
130
- };
131
- const FORM_ERROR_TYPE = 'form';
132
- const ROOT_ERROR_TYPE = 'root';
133
-
134
136
  /**
135
137
  * Separate context for `control` to prevent unnecessary rerenders.
136
138
  * Internal hooks that only need control use this instead of full form context.
@@ -159,7 +161,9 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
159
161
  return result;
160
162
  };
161
163
 
162
- const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
164
+ const useIsomorphicLayoutEffect = isWeb
165
+ ? React.useLayoutEffect
166
+ : React.useEffect;
163
167
 
164
168
  /**
165
169
  * This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
@@ -640,8 +644,7 @@ const useFormContext = () => React.useContext(HookFormContext);
640
644
  * }
641
645
  * ```
642
646
  */
643
- const FormProvider = (props) => {
644
- const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
647
+ const FormProvider = ({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
645
648
  const memoizedValue = React.useMemo(() => ({
646
649
  watch,
647
650
  getValues,
@@ -806,6 +809,8 @@ var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => va
806
809
  }
807
810
  : {};
808
811
 
812
+ var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
813
+
809
814
  var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
810
815
 
811
816
  var createSubject = () => {
@@ -1115,8 +1120,7 @@ var hasValidation = (options) => options.mount &&
1115
1120
  var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
1116
1121
  (_names.watchAll ||
1117
1122
  _names.watch.has(name) ||
1118
- [..._names.watch].some((watchName) => name.startsWith(watchName) &&
1119
- /^\.\w+/.test(name.slice(watchName.length))));
1123
+ [..._names.watch].some((watchName) => name.startsWith(`${watchName}.`)));
1120
1124
 
1121
1125
  const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
1122
1126
  for (const key of fieldsNames || Object.keys(fields)) {
@@ -1219,7 +1223,8 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
1219
1223
  var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1220
1224
 
1221
1225
  var updateFieldArrayRootError = (errors, error, name) => {
1222
- const fieldArrayErrors = convertToArrayPayload(get(errors, name));
1226
+ const existingErrors = get(errors, name);
1227
+ const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
1223
1228
  set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
1224
1229
  set(errors, name, fieldArrayErrors);
1225
1230
  return errors;
@@ -1734,7 +1739,9 @@ function createFormControl(props = {}) {
1734
1739
  for (const name of names) {
1735
1740
  const error = get(errors, name);
1736
1741
  error
1737
- ? _names.array.has(name) && isObject(error)
1742
+ ? _names.array.has(name) &&
1743
+ isObject(error) &&
1744
+ !Object.keys(error).some((key) => !Number.isNaN(Number(key)))
1738
1745
  ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
1739
1746
  : set(_formState.errors, name, error)
1740
1747
  : unset(_formState.errors, name);
@@ -2481,7 +2488,7 @@ function createFormControl(props = {}) {
2481
2488
  const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
2482
2489
  const cloneUpdatedValues = cloneObject(updatedValues);
2483
2490
  const isEmptyResetValues = isEmptyObject(formValues);
2484
- const values = isEmptyResetValues ? _defaultValues : cloneUpdatedValues;
2491
+ const values = cloneUpdatedValues;
2485
2492
  if (!keepStateOptions.keepDefaultValues) {
2486
2493
  _defaultValues = updatedValues;
2487
2494
  }
@@ -2530,11 +2537,19 @@ function createFormControl(props = {}) {
2530
2537
  _fields = {};
2531
2538
  }
2532
2539
  }
2533
- _formValues = _options.shouldUnregister
2534
- ? keepStateOptions.keepDefaultValues
2540
+ if (_options.shouldUnregister) {
2541
+ _formValues = keepStateOptions.keepDefaultValues
2535
2542
  ? cloneObject(_defaultValues)
2536
- : {}
2537
- : cloneObject(values);
2543
+ : {};
2544
+ if (keepStateOptions.keepFieldsRef) {
2545
+ for (const fieldName of _names.mount) {
2546
+ set(_formValues, fieldName, get(values, fieldName));
2547
+ }
2548
+ }
2549
+ }
2550
+ else {
2551
+ _formValues = cloneObject(values);
2552
+ }
2538
2553
  _subjects.array.next({
2539
2554
  values: { ...values },
2540
2555
  });
@@ -2574,8 +2589,10 @@ function createFormControl(props = {}) {
2574
2589
  ? false
2575
2590
  : keepStateOptions.keepDirty
2576
2591
  ? _formState.isDirty
2577
- : !!(keepStateOptions.keepDefaultValues &&
2578
- !deepEqual(formValues, _defaultValues)),
2592
+ : keepStateOptions.keepValues
2593
+ ? _getDirty()
2594
+ : !!(keepStateOptions.keepDefaultValues &&
2595
+ !deepEqual(formValues, _defaultValues)),
2579
2596
  isSubmitted: keepStateOptions.keepIsSubmitted
2580
2597
  ? _formState.isSubmitted
2581
2598
  : false,
@@ -2636,6 +2653,21 @@ function createFormControl(props = {}) {
2636
2653
  isLoading: false,
2637
2654
  });
2638
2655
  });
2656
+ const resetDefaultValues = (values, options = {}) => {
2657
+ _defaultValues = cloneObject(values);
2658
+ if (!options.keepDirty) {
2659
+ const newDirtyFields = getDirtyFields(_defaultValues, _formValues);
2660
+ _formState.dirtyFields = newDirtyFields;
2661
+ _formState.isDirty = !isEmptyObject(newDirtyFields);
2662
+ }
2663
+ if (!options.keepIsValid) {
2664
+ _setValid();
2665
+ }
2666
+ _subjects.state.next({
2667
+ ..._formState,
2668
+ defaultValues: _defaultValues,
2669
+ });
2670
+ };
2639
2671
  const methods = {
2640
2672
  control: {
2641
2673
  register,
@@ -2704,6 +2736,7 @@ function createFormControl(props = {}) {
2704
2736
  getValues,
2705
2737
  reset,
2706
2738
  resetField,
2739
+ resetDefaultValues,
2707
2740
  clearErrors,
2708
2741
  unregister,
2709
2742
  setError,
@@ -2840,6 +2873,10 @@ function useFieldArray(props) {
2840
2873
  setFields(fieldValues);
2841
2874
  ids.current = fieldValues.map(generateId);
2842
2875
  }
2876
+ else if (!fieldArrayName) {
2877
+ setFields([]);
2878
+ ids.current = [];
2879
+ }
2843
2880
  }
2844
2881
  },
2845
2882
  }).unsubscribe, [control, name]);