react-hook-form 7.76.1 → 7.78.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.
- package/README.md +0 -11
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.mjs +114 -59
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/index.d.ts +2 -3
- package/dist/logic/index.d.ts.map +1 -1
- package/dist/logic/isWatched.d.ts.map +1 -1
- package/dist/logic/skipValidation.d.ts +1 -4
- package/dist/logic/skipValidation.d.ts.map +1 -1
- package/dist/logic/updateFieldArrayRootError.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +58 -19
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/form.d.ts +23 -3
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/utils.d.ts.map +1 -1
- package/dist/useController.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useFormContext.d.ts +1 -1
- package/dist/useFormContext.d.ts.map +1 -1
- package/dist/useIsomorphicLayoutEffect.d.ts.map +1 -1
- package/dist/utils/deepEqual.d.ts.map +1 -1
- package/dist/utils/get.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/set.d.ts.map +1 -1
- package/dist/utils/stringToPath.d.ts.map +1 -1
- package/package.json +17 -17
package/dist/index.esm.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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.
|
|
@@ -244,6 +248,7 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
244
248
|
|
|
245
249
|
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
246
250
|
|
|
251
|
+
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
247
252
|
function deepEqual(object1, object2, visited = new WeakSet()) {
|
|
248
253
|
if (object1 === object2) {
|
|
249
254
|
return true;
|
|
@@ -259,6 +264,10 @@ function deepEqual(object1, object2, visited = new WeakSet()) {
|
|
|
259
264
|
if (keys1.length !== keys2.length) {
|
|
260
265
|
return false;
|
|
261
266
|
}
|
|
267
|
+
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
268
|
+
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
269
|
+
return Object.is(object1, object2);
|
|
270
|
+
}
|
|
262
271
|
if (visited.has(object1) || visited.has(object2)) {
|
|
263
272
|
return true;
|
|
264
273
|
}
|
|
@@ -438,13 +447,22 @@ function useController(props) {
|
|
|
438
447
|
get: () => get(formState.errors, name),
|
|
439
448
|
},
|
|
440
449
|
}), [formState, name]);
|
|
441
|
-
const onChange = React.useCallback((event) =>
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
450
|
+
const onChange = React.useCallback((event) => {
|
|
451
|
+
const value = getEventValue(event);
|
|
452
|
+
if (!get(control._fields, name)) {
|
|
453
|
+
_registerProps.current = control.register(name, {
|
|
454
|
+
..._props.current.rules,
|
|
455
|
+
value,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
_registerProps.current.onChange({
|
|
459
|
+
target: {
|
|
460
|
+
value: getEventValue(event),
|
|
461
|
+
name: name,
|
|
462
|
+
},
|
|
463
|
+
type: EVENTS.CHANGE,
|
|
464
|
+
});
|
|
465
|
+
}, [name, control]);
|
|
448
466
|
const onBlur = React.useCallback(() => _registerProps.current.onBlur({
|
|
449
467
|
target: {
|
|
450
468
|
value: get(control._formValues, name),
|
|
@@ -489,7 +507,9 @@ function useController(props) {
|
|
|
489
507
|
};
|
|
490
508
|
updateMounted(name, true);
|
|
491
509
|
if (_shouldUnregisterField) {
|
|
492
|
-
const value = cloneObject(get(
|
|
510
|
+
const value = cloneObject(get(shouldUnregister
|
|
511
|
+
? control._defaultValues
|
|
512
|
+
: control._options.values || control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
|
|
493
513
|
set(control._defaultValues, name, value);
|
|
494
514
|
if (isUndefined(get(control._formValues, name))) {
|
|
495
515
|
set(control._formValues, name, value);
|
|
@@ -640,8 +660,7 @@ const useFormContext = () => React.useContext(HookFormContext);
|
|
|
640
660
|
* }
|
|
641
661
|
* ```
|
|
642
662
|
*/
|
|
643
|
-
const FormProvider = (
|
|
644
|
-
const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
|
|
663
|
+
const FormProvider = ({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
|
|
645
664
|
const memoizedValue = React.useMemo(() => ({
|
|
646
665
|
watch,
|
|
647
666
|
getValues,
|
|
@@ -806,6 +825,8 @@ var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => va
|
|
|
806
825
|
}
|
|
807
826
|
: {};
|
|
808
827
|
|
|
828
|
+
var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
|
|
829
|
+
|
|
809
830
|
var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
|
|
810
831
|
|
|
811
832
|
var createSubject = () => {
|
|
@@ -1115,8 +1136,7 @@ var hasValidation = (options) => options.mount &&
|
|
|
1115
1136
|
var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
|
|
1116
1137
|
(_names.watchAll ||
|
|
1117
1138
|
_names.watch.has(name) ||
|
|
1118
|
-
[..._names.watch].some((watchName) => name.startsWith(watchName)
|
|
1119
|
-
/^\.\w+/.test(name.slice(watchName.length))));
|
|
1139
|
+
[..._names.watch].some((watchName) => name.startsWith(`${watchName}.`)));
|
|
1120
1140
|
|
|
1121
1141
|
const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
1122
1142
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
@@ -1219,7 +1239,8 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
|
|
|
1219
1239
|
var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
|
|
1220
1240
|
|
|
1221
1241
|
var updateFieldArrayRootError = (errors, error, name) => {
|
|
1222
|
-
const
|
|
1242
|
+
const existingErrors = get(errors, name);
|
|
1243
|
+
const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
|
|
1223
1244
|
set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
|
|
1224
1245
|
set(errors, name, fieldArrayErrors);
|
|
1225
1246
|
return errors;
|
|
@@ -1734,7 +1755,9 @@ function createFormControl(props = {}) {
|
|
|
1734
1755
|
for (const name of names) {
|
|
1735
1756
|
const error = get(errors, name);
|
|
1736
1757
|
error
|
|
1737
|
-
? _names.array.has(name) &&
|
|
1758
|
+
? _names.array.has(name) &&
|
|
1759
|
+
isObject(error) &&
|
|
1760
|
+
!Object.keys(error).some((key) => !Number.isNaN(Number(key)))
|
|
1738
1761
|
? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
|
|
1739
1762
|
: set(_formState.errors, name, error)
|
|
1740
1763
|
: unset(_formState.errors, name);
|
|
@@ -2073,13 +2096,15 @@ function createFormControl(props = {}) {
|
|
|
2073
2096
|
const { errors } = await _runSchema([name]);
|
|
2074
2097
|
_updateIsValidating([name]);
|
|
2075
2098
|
_updateIsFieldValueUpdated(fieldValue);
|
|
2076
|
-
if (isFieldValueUpdated) {
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
error = errorLookupResult.error;
|
|
2080
|
-
name = errorLookupResult.name;
|
|
2081
|
-
isValid = isEmptyObject(errors);
|
|
2099
|
+
if (!isFieldValueUpdated) {
|
|
2100
|
+
!isEmptyObject(fieldState) && _subjects.state.next(fieldState);
|
|
2101
|
+
return;
|
|
2082
2102
|
}
|
|
2103
|
+
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
|
2104
|
+
const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
|
|
2105
|
+
error = errorLookupResult.error;
|
|
2106
|
+
name = errorLookupResult.name;
|
|
2107
|
+
isValid = isEmptyObject(errors);
|
|
2083
2108
|
}
|
|
2084
2109
|
else {
|
|
2085
2110
|
_updateIsValidating([name], true);
|
|
@@ -2481,7 +2506,7 @@ function createFormControl(props = {}) {
|
|
|
2481
2506
|
const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
|
|
2482
2507
|
const cloneUpdatedValues = cloneObject(updatedValues);
|
|
2483
2508
|
const isEmptyResetValues = isEmptyObject(formValues);
|
|
2484
|
-
const values =
|
|
2509
|
+
const values = cloneUpdatedValues;
|
|
2485
2510
|
if (!keepStateOptions.keepDefaultValues) {
|
|
2486
2511
|
_defaultValues = updatedValues;
|
|
2487
2512
|
}
|
|
@@ -2530,11 +2555,19 @@ function createFormControl(props = {}) {
|
|
|
2530
2555
|
_fields = {};
|
|
2531
2556
|
}
|
|
2532
2557
|
}
|
|
2533
|
-
|
|
2534
|
-
|
|
2558
|
+
if (_options.shouldUnregister) {
|
|
2559
|
+
_formValues = keepStateOptions.keepDefaultValues
|
|
2535
2560
|
? cloneObject(_defaultValues)
|
|
2536
|
-
: {}
|
|
2537
|
-
|
|
2561
|
+
: {};
|
|
2562
|
+
if (keepStateOptions.keepFieldsRef) {
|
|
2563
|
+
for (const fieldName of _names.mount) {
|
|
2564
|
+
set(_formValues, fieldName, get(values, fieldName));
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
else {
|
|
2569
|
+
_formValues = cloneObject(values);
|
|
2570
|
+
}
|
|
2538
2571
|
_subjects.array.next({
|
|
2539
2572
|
values: { ...values },
|
|
2540
2573
|
});
|
|
@@ -2574,8 +2607,10 @@ function createFormControl(props = {}) {
|
|
|
2574
2607
|
? false
|
|
2575
2608
|
: keepStateOptions.keepDirty
|
|
2576
2609
|
? _formState.isDirty
|
|
2577
|
-
:
|
|
2578
|
-
|
|
2610
|
+
: keepStateOptions.keepValues
|
|
2611
|
+
? _getDirty()
|
|
2612
|
+
: !!(keepStateOptions.keepDefaultValues &&
|
|
2613
|
+
!deepEqual(formValues, _defaultValues)),
|
|
2579
2614
|
isSubmitted: keepStateOptions.keepIsSubmitted
|
|
2580
2615
|
? _formState.isSubmitted
|
|
2581
2616
|
: false,
|
|
@@ -2636,6 +2671,21 @@ function createFormControl(props = {}) {
|
|
|
2636
2671
|
isLoading: false,
|
|
2637
2672
|
});
|
|
2638
2673
|
});
|
|
2674
|
+
const resetDefaultValues = (values, options = {}) => {
|
|
2675
|
+
_defaultValues = cloneObject(values);
|
|
2676
|
+
if (!options.keepDirty) {
|
|
2677
|
+
const newDirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
2678
|
+
_formState.dirtyFields = newDirtyFields;
|
|
2679
|
+
_formState.isDirty = !isEmptyObject(newDirtyFields);
|
|
2680
|
+
}
|
|
2681
|
+
if (!options.keepIsValid) {
|
|
2682
|
+
_setValid();
|
|
2683
|
+
}
|
|
2684
|
+
_subjects.state.next({
|
|
2685
|
+
..._formState,
|
|
2686
|
+
defaultValues: _defaultValues,
|
|
2687
|
+
});
|
|
2688
|
+
};
|
|
2639
2689
|
const methods = {
|
|
2640
2690
|
control: {
|
|
2641
2691
|
register,
|
|
@@ -2704,6 +2754,7 @@ function createFormControl(props = {}) {
|
|
|
2704
2754
|
getValues,
|
|
2705
2755
|
reset,
|
|
2706
2756
|
resetField,
|
|
2757
|
+
resetDefaultValues,
|
|
2707
2758
|
clearErrors,
|
|
2708
2759
|
unregister,
|
|
2709
2760
|
setError,
|
|
@@ -2840,6 +2891,10 @@ function useFieldArray(props) {
|
|
|
2840
2891
|
setFields(fieldValues);
|
|
2841
2892
|
ids.current = fieldValues.map(generateId);
|
|
2842
2893
|
}
|
|
2894
|
+
else if (!fieldArrayName) {
|
|
2895
|
+
setFields([]);
|
|
2896
|
+
ids.current = [];
|
|
2897
|
+
}
|
|
2843
2898
|
}
|
|
2844
2899
|
},
|
|
2845
2900
|
}).unsubscribe, [control, name]);
|