react-hook-form 7.74.0 → 7.75.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/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.mjs +96 -57
- 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 +13 -0
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/getDirtyFields.d.ts.map +1 -1
- package/dist/logic/getProxyFormState.d.ts.map +1 -1
- package/dist/logic/getResolverOptions.d.ts +2 -2
- package/dist/logic/hasValidation.d.ts +1 -1
- package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +74 -36
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/form.d.ts +1 -0
- package/dist/types/form.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormContext.d.ts.map +1 -1
- package/dist/useFormState.d.ts.map +1 -1
- package/package.json +4 -5
package/dist/index.esm.mjs
CHANGED
|
@@ -143,9 +143,7 @@ HookFormControlContext.displayName = 'HookFormControlContext';
|
|
|
143
143
|
const useFormControlContext = () => React.useContext(HookFormControlContext);
|
|
144
144
|
|
|
145
145
|
var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
|
|
146
|
-
const result = {
|
|
147
|
-
defaultValues: control._defaultValues,
|
|
148
|
-
};
|
|
146
|
+
const result = {};
|
|
149
147
|
for (const key in formState) {
|
|
150
148
|
Object.defineProperty(result, key, {
|
|
151
149
|
get: () => {
|
|
@@ -196,7 +194,10 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayou
|
|
|
196
194
|
function useFormState(props) {
|
|
197
195
|
const formControl = useFormControlContext();
|
|
198
196
|
const { control = formControl, disabled, name, exact } = props || {};
|
|
199
|
-
const [formState, updateFormState] = React.useState(
|
|
197
|
+
const [formState, updateFormState] = React.useState(() => ({
|
|
198
|
+
...control._formState,
|
|
199
|
+
defaultValues: control._defaultValues,
|
|
200
|
+
}));
|
|
200
201
|
const _localProxyFormState = React.useRef({
|
|
201
202
|
isDirty: false,
|
|
202
203
|
isLoading: false,
|
|
@@ -216,6 +217,7 @@ function useFormState(props) {
|
|
|
216
217
|
updateFormState({
|
|
217
218
|
...control._formState,
|
|
218
219
|
...formState,
|
|
220
|
+
defaultValues: control._defaultValues,
|
|
219
221
|
});
|
|
220
222
|
},
|
|
221
223
|
}), [name, disabled, exact]);
|
|
@@ -639,7 +641,7 @@ const useFormContext = () => React.useContext(HookFormContext);
|
|
|
639
641
|
* ```
|
|
640
642
|
*/
|
|
641
643
|
const FormProvider = (props) => {
|
|
642
|
-
const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
|
|
644
|
+
const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
|
|
643
645
|
const memoizedValue = React.useMemo(() => ({
|
|
644
646
|
watch,
|
|
645
647
|
getValues,
|
|
@@ -647,6 +649,7 @@ const FormProvider = (props) => {
|
|
|
647
649
|
setError,
|
|
648
650
|
clearErrors,
|
|
649
651
|
setValue,
|
|
652
|
+
setValues,
|
|
650
653
|
trigger,
|
|
651
654
|
formState,
|
|
652
655
|
resetField,
|
|
@@ -670,6 +673,7 @@ const FormProvider = (props) => {
|
|
|
670
673
|
setError,
|
|
671
674
|
setFocus,
|
|
672
675
|
setValue,
|
|
676
|
+
setValues,
|
|
673
677
|
subscribe,
|
|
674
678
|
trigger,
|
|
675
679
|
unregister,
|
|
@@ -943,6 +947,29 @@ function markFieldsDirty(data, fields = {}) {
|
|
|
943
947
|
}
|
|
944
948
|
return fields;
|
|
945
949
|
}
|
|
950
|
+
function pruneDirtyFields(value) {
|
|
951
|
+
if (value === false) {
|
|
952
|
+
return undefined;
|
|
953
|
+
}
|
|
954
|
+
if (value === true) {
|
|
955
|
+
return true;
|
|
956
|
+
}
|
|
957
|
+
if (Array.isArray(value)) {
|
|
958
|
+
const result = value.map((value) => pruneDirtyFields(value));
|
|
959
|
+
return (result.some((value) => value !== undefined) ? result : undefined);
|
|
960
|
+
}
|
|
961
|
+
if (isObject(value)) {
|
|
962
|
+
const result = {};
|
|
963
|
+
for (const key in value) {
|
|
964
|
+
const pruned = pruneDirtyFields(value[key]);
|
|
965
|
+
if (!isUndefined(pruned)) {
|
|
966
|
+
result[key] = pruned;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return (Object.keys(result).length ? result : undefined);
|
|
970
|
+
}
|
|
971
|
+
return undefined;
|
|
972
|
+
}
|
|
946
973
|
function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
947
974
|
if (!dirtyFieldsFromValues) {
|
|
948
975
|
dirtyFieldsFromValues = markFieldsDirty(formValues);
|
|
@@ -962,7 +989,7 @@ function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
|
962
989
|
dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
|
|
963
990
|
}
|
|
964
991
|
}
|
|
965
|
-
return dirtyFieldsFromValues;
|
|
992
|
+
return pruneDirtyFields(dirtyFieldsFromValues) || {};
|
|
966
993
|
}
|
|
967
994
|
|
|
968
995
|
const defaultResult = {
|
|
@@ -1034,8 +1061,6 @@ function getFieldValue(_f) {
|
|
|
1034
1061
|
return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
|
|
1035
1062
|
}
|
|
1036
1063
|
|
|
1037
|
-
var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name;
|
|
1038
|
-
|
|
1039
1064
|
var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
|
|
1040
1065
|
const fields = {};
|
|
1041
1066
|
for (const name of fieldsNames) {
|
|
@@ -1160,7 +1185,8 @@ var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, is
|
|
|
1160
1185
|
updateFormState(formStateData);
|
|
1161
1186
|
const { name, ...formState } = formStateData;
|
|
1162
1187
|
return (isEmptyObject(formState) ||
|
|
1163
|
-
|
|
1188
|
+
(isRoot &&
|
|
1189
|
+
Object.keys(formState).length >= Object.keys(_proxyFormState).length) ||
|
|
1164
1190
|
Object.keys(formState).find((key) => _proxyFormState[key] ===
|
|
1165
1191
|
(!isRoot || VALIDATION_MODE.all)));
|
|
1166
1192
|
};
|
|
@@ -1403,24 +1429,27 @@ const defaultOptions = {
|
|
|
1403
1429
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
1404
1430
|
shouldFocusError: true,
|
|
1405
1431
|
};
|
|
1432
|
+
const DEFAULT_FORM_STATE = {
|
|
1433
|
+
submitCount: 0,
|
|
1434
|
+
isDirty: false,
|
|
1435
|
+
isReady: false,
|
|
1436
|
+
isValidating: false,
|
|
1437
|
+
isSubmitted: false,
|
|
1438
|
+
isSubmitting: false,
|
|
1439
|
+
isSubmitSuccessful: false,
|
|
1440
|
+
isValid: false,
|
|
1441
|
+
touchedFields: {},
|
|
1442
|
+
dirtyFields: {},
|
|
1443
|
+
validatingFields: {},
|
|
1444
|
+
};
|
|
1406
1445
|
function createFormControl(props = {}) {
|
|
1407
1446
|
let _options = {
|
|
1408
1447
|
...defaultOptions,
|
|
1409
1448
|
...props,
|
|
1410
1449
|
};
|
|
1411
1450
|
let _formState = {
|
|
1412
|
-
|
|
1413
|
-
isDirty: false,
|
|
1414
|
-
isReady: false,
|
|
1451
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
1415
1452
|
isLoading: isFunction(_options.defaultValues),
|
|
1416
|
-
isValidating: false,
|
|
1417
|
-
isSubmitted: false,
|
|
1418
|
-
isSubmitting: false,
|
|
1419
|
-
isSubmitSuccessful: false,
|
|
1420
|
-
isValid: false,
|
|
1421
|
-
touchedFields: {},
|
|
1422
|
-
dirtyFields: {},
|
|
1423
|
-
validatingFields: {},
|
|
1424
1453
|
errors: _options.errors || {},
|
|
1425
1454
|
disabled: _options.disabled || false,
|
|
1426
1455
|
};
|
|
@@ -1517,10 +1546,8 @@ function createFormControl(props = {}) {
|
|
|
1517
1546
|
});
|
|
1518
1547
|
}
|
|
1519
1548
|
};
|
|
1520
|
-
const _updateDirtyFields = (
|
|
1521
|
-
|
|
1522
|
-
const rootName = getNodeParentName(name);
|
|
1523
|
-
set(_formState.dirtyFields, rootName, get(fullDirtyFields, rootName));
|
|
1549
|
+
const _updateDirtyFields = () => {
|
|
1550
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1524
1551
|
};
|
|
1525
1552
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
1526
1553
|
if (args && method && !_options.disabled) {
|
|
@@ -1543,7 +1570,7 @@ function createFormControl(props = {}) {
|
|
|
1543
1570
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
1544
1571
|
}
|
|
1545
1572
|
if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
|
|
1546
|
-
_updateDirtyFields(
|
|
1573
|
+
_updateDirtyFields();
|
|
1547
1574
|
}
|
|
1548
1575
|
_subjects.state.next({
|
|
1549
1576
|
name,
|
|
@@ -1573,13 +1600,31 @@ function createFormControl(props = {}) {
|
|
|
1573
1600
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
1574
1601
|
const field = get(_fields, name);
|
|
1575
1602
|
if (field) {
|
|
1603
|
+
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
1576
1604
|
const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
|
|
1577
1605
|
isUndefined(defaultValue) ||
|
|
1578
1606
|
(ref && ref.defaultChecked) ||
|
|
1579
1607
|
shouldSkipSetValueAs
|
|
1580
1608
|
? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
|
|
1581
1609
|
: setFieldValue(name, defaultValue);
|
|
1582
|
-
_state.mount && !_state.action
|
|
1610
|
+
if (_state.mount && !_state.action) {
|
|
1611
|
+
_setValid();
|
|
1612
|
+
// Re-registering a field after a prior unregister puts its key back
|
|
1613
|
+
// into _formValues, which can flip isDirty back to false (#13397).
|
|
1614
|
+
// Only run when we are currently dirty, otherwise an initial register
|
|
1615
|
+
// for a field with no defaultValue would flip isDirty to true. Reset
|
|
1616
|
+
// paths repopulate _formValues before re-register, so the key is
|
|
1617
|
+
// present then and this branch is skipped (preserves keepDirty).
|
|
1618
|
+
if (wasUnsetInFormValues &&
|
|
1619
|
+
_formState.isDirty &&
|
|
1620
|
+
(_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
|
|
1621
|
+
const isDirty = _getDirty();
|
|
1622
|
+
if (!isDirty) {
|
|
1623
|
+
_formState.isDirty = false;
|
|
1624
|
+
_subjects.state.next({ ..._formState });
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1583
1628
|
}
|
|
1584
1629
|
};
|
|
1585
1630
|
const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
|
|
@@ -1869,8 +1914,12 @@ function createFormControl(props = {}) {
|
|
|
1869
1914
|
name,
|
|
1870
1915
|
values: cloneObject(_formValues),
|
|
1871
1916
|
});
|
|
1872
|
-
if (
|
|
1873
|
-
|
|
1917
|
+
if ((_proxyFormState.isDirty ||
|
|
1918
|
+
_proxyFormState.dirtyFields ||
|
|
1919
|
+
_proxySubscribeFormState.isDirty ||
|
|
1920
|
+
_proxySubscribeFormState.dirtyFields) &&
|
|
1921
|
+
options.shouldDirty) {
|
|
1922
|
+
_updateDirtyFields();
|
|
1874
1923
|
_subjects.state.next({
|
|
1875
1924
|
name,
|
|
1876
1925
|
dirtyFields: _formState.dirtyFields,
|
|
@@ -1889,19 +1938,12 @@ function createFormControl(props = {}) {
|
|
|
1889
1938
|
}
|
|
1890
1939
|
}
|
|
1891
1940
|
if (!isValueUnchanged) {
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
}
|
|
1899
|
-
else {
|
|
1900
|
-
_subjects.state.next({
|
|
1901
|
-
name: _state.mount ? name : undefined,
|
|
1902
|
-
values: cloneObject(_formValues),
|
|
1903
|
-
});
|
|
1904
|
-
}
|
|
1941
|
+
const watched = isWatched(name, _names);
|
|
1942
|
+
_subjects.state.next({
|
|
1943
|
+
...(watched && _formState),
|
|
1944
|
+
name: _state.mount || watched ? name : undefined,
|
|
1945
|
+
values: cloneObject(_formValues),
|
|
1946
|
+
});
|
|
1905
1947
|
}
|
|
1906
1948
|
};
|
|
1907
1949
|
const setValues = (formValues) => {
|
|
@@ -2910,15 +2952,22 @@ function useFieldArray(props) {
|
|
|
2910
2952
|
React.useEffect(() => {
|
|
2911
2953
|
!get(control._formValues, name) && control._setFieldArray(name);
|
|
2912
2954
|
return () => {
|
|
2955
|
+
const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
|
|
2913
2956
|
const updateMounted = (name, value) => {
|
|
2914
2957
|
const field = get(control._fields, name);
|
|
2915
2958
|
if (field && field._f) {
|
|
2916
2959
|
field._f.mount = value;
|
|
2917
2960
|
}
|
|
2918
2961
|
};
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2962
|
+
if (_actioned.current && shouldKeepFieldArrayValues) {
|
|
2963
|
+
control._subjects.state.next({
|
|
2964
|
+
name,
|
|
2965
|
+
values: cloneObject(control._formValues),
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2968
|
+
shouldKeepFieldArrayValues
|
|
2969
|
+
? updateMounted(name, false)
|
|
2970
|
+
: control.unregister(name);
|
|
2922
2971
|
};
|
|
2923
2972
|
}, [name, control, keyName, shouldUnregister]);
|
|
2924
2973
|
return {
|
|
@@ -2969,25 +3018,15 @@ function useFieldArray(props) {
|
|
|
2969
3018
|
function useForm(props = {}) {
|
|
2970
3019
|
const _formControl = React.useRef(undefined);
|
|
2971
3020
|
const _values = React.useRef(undefined);
|
|
2972
|
-
const [formState, updateFormState] = React.useState({
|
|
2973
|
-
|
|
2974
|
-
isValidating: false,
|
|
3021
|
+
const [formState, updateFormState] = React.useState(() => ({
|
|
3022
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
2975
3023
|
isLoading: isFunction(props.defaultValues),
|
|
2976
|
-
isSubmitted: false,
|
|
2977
|
-
isSubmitting: false,
|
|
2978
|
-
isSubmitSuccessful: false,
|
|
2979
|
-
isValid: false,
|
|
2980
|
-
submitCount: 0,
|
|
2981
|
-
dirtyFields: {},
|
|
2982
|
-
touchedFields: {},
|
|
2983
|
-
validatingFields: {},
|
|
2984
3024
|
errors: props.errors || {},
|
|
2985
3025
|
disabled: props.disabled || false,
|
|
2986
|
-
isReady: false,
|
|
2987
3026
|
defaultValues: isFunction(props.defaultValues)
|
|
2988
3027
|
? undefined
|
|
2989
3028
|
: props.defaultValues,
|
|
2990
|
-
});
|
|
3029
|
+
}));
|
|
2991
3030
|
if (!_formControl.current) {
|
|
2992
3031
|
if (props.formControl) {
|
|
2993
3032
|
_formControl.current = {
|