react-hook-form 8.0.0-beta.1 → 8.0.0-beta.3
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 +16 -40
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/fieldArray.d.ts +36 -0
- package/dist/fieldArray.d.ts.map +1 -0
- package/dist/form.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 +755 -293
- 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/getNodeParentName.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/hasPromiseValidation.d.ts.map +1 -1
- package/dist/logic/hasValidation.d.ts +1 -1
- package/dist/logic/index.d.ts +2 -3
- package/dist/logic/index.d.ts.map +1 -1
- package/dist/logic/isNameInFieldArray.d.ts.map +1 -1
- package/dist/logic/isWatched.d.ts.map +1 -1
- package/dist/logic/shouldRenderFormState.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/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +522 -144
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/errors.d.ts +1 -0
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/fieldArray.d.ts +25 -1
- package/dist/types/fieldArray.d.ts.map +1 -1
- package/dist/types/form.d.ts +61 -8
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/path/eager.d.ts +1 -1
- package/dist/types/path/eager.d.ts.map +1 -1
- package/dist/types/utils.d.ts +3 -3
- package/dist/types/utils.d.ts.map +1 -1
- package/dist/types/validator.d.ts +13 -1
- package/dist/types/validator.d.ts.map +1 -1
- package/dist/useController.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 +1 -1
- package/dist/useFormContext.d.ts.map +1 -1
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useIsomorphicLayoutEffect.d.ts.map +1 -1
- package/dist/utils/deepEqual.d.ts +1 -1
- package/dist/utils/deepEqual.d.ts.map +1 -1
- package/dist/utils/flatten.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/isKey.d.ts.map +1 -1
- package/dist/utils/set.d.ts.map +1 -1
- package/dist/utils/stringToPath.d.ts.map +1 -1
- package/dist/utils/unset.d.ts.map +1 -1
- package/dist/watch.d.ts +1 -1
- package/dist/watch.d.ts.map +1 -1
- package/package.json +31 -28
- package/dist/__tests__/controller.server.test.d.ts +0 -2
- package/dist/__tests__/controller.server.test.d.ts.map +0 -1
- package/dist/__tests__/controller.test.d.ts +0 -2
- package/dist/__tests__/controller.test.d.ts.map +0 -1
- package/dist/__tests__/form.test.d.ts +0 -2
- package/dist/__tests__/form.test.d.ts.map +0 -1
- package/dist/__tests__/formStateSubscribe.server.test.d.ts +0 -2
- package/dist/__tests__/formStateSubscribe.server.test.d.ts.map +0 -1
- package/dist/__tests__/formStateSubscribe.test.d.ts +0 -2
- package/dist/__tests__/formStateSubscribe.test.d.ts.map +0 -1
- package/dist/__tests__/isPlainObject.test.d.ts +0 -2
- package/dist/__tests__/isPlainObject.test.d.ts.map +0 -1
- package/dist/__tests__/logic/appendErrors.test.d.ts +0 -2
- package/dist/__tests__/logic/appendErrors.test.d.ts.map +0 -1
- package/dist/__tests__/logic/createFormControl.test.d.ts +0 -2
- package/dist/__tests__/logic/createFormControl.test.d.ts.map +0 -1
- package/dist/__tests__/logic/generateId.test.d.ts +0 -2
- package/dist/__tests__/logic/generateId.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getCheckboxValue.test.d.ts +0 -2
- package/dist/__tests__/logic/getCheckboxValue.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getDirtyFields.test.d.ts +0 -2
- package/dist/__tests__/logic/getDirtyFields.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getEventValue.test.d.ts +0 -2
- package/dist/__tests__/logic/getEventValue.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getFieldValue.test.d.ts +0 -2
- package/dist/__tests__/logic/getFieldValue.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getFieldValueAs.test.d.ts +0 -2
- package/dist/__tests__/logic/getFieldValueAs.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getFocusFieldName.test.d.ts +0 -2
- package/dist/__tests__/logic/getFocusFieldName.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getNodeParentName.test.d.ts +0 -2
- package/dist/__tests__/logic/getNodeParentName.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getRadioValue.test.d.ts +0 -2
- package/dist/__tests__/logic/getRadioValue.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getResolverOptions.test.d.ts +0 -2
- package/dist/__tests__/logic/getResolverOptions.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getRuleValue.test.d.ts +0 -2
- package/dist/__tests__/logic/getRuleValue.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getValidateError.test.d.ts +0 -2
- package/dist/__tests__/logic/getValidateError.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getValidationModes.test.d.ts +0 -2
- package/dist/__tests__/logic/getValidationModes.test.d.ts.map +0 -1
- package/dist/__tests__/logic/getValueAndMessage.test.d.ts +0 -2
- package/dist/__tests__/logic/getValueAndMessage.test.d.ts.map +0 -1
- package/dist/__tests__/logic/hasPromiseValidation.test.d.ts +0 -2
- package/dist/__tests__/logic/hasPromiseValidation.test.d.ts.map +0 -1
- package/dist/__tests__/logic/hasValidation.test.d.ts +0 -2
- package/dist/__tests__/logic/hasValidation.test.d.ts.map +0 -1
- package/dist/__tests__/logic/isNameInFieldArray.test.d.ts +0 -2
- package/dist/__tests__/logic/isNameInFieldArray.test.d.ts.map +0 -1
- package/dist/__tests__/logic/isWatched.test.d.ts +0 -2
- package/dist/__tests__/logic/isWatched.test.d.ts.map +0 -1
- package/dist/__tests__/logic/iterateFieldsByAction.test.d.ts +0 -2
- package/dist/__tests__/logic/iterateFieldsByAction.test.d.ts.map +0 -1
- package/dist/__tests__/logic/schemaErrorLookup.test.d.ts +0 -2
- package/dist/__tests__/logic/schemaErrorLookup.test.d.ts.map +0 -1
- package/dist/__tests__/logic/shouldRenderFormState.test.d.ts +0 -2
- package/dist/__tests__/logic/shouldRenderFormState.test.d.ts.map +0 -1
- package/dist/__tests__/logic/shouldSubscribeByName.test.d.ts +0 -2
- package/dist/__tests__/logic/shouldSubscribeByName.test.d.ts.map +0 -1
- package/dist/__tests__/logic/skipValidation.test.d.ts +0 -2
- package/dist/__tests__/logic/skipValidation.test.d.ts.map +0 -1
- package/dist/__tests__/logic/unsetEmptyArray.test.d.ts +0 -2
- package/dist/__tests__/logic/unsetEmptyArray.test.d.ts.map +0 -1
- package/dist/__tests__/logic/validateField.test.d.ts +0 -2
- package/dist/__tests__/logic/validateField.test.d.ts.map +0 -1
- package/dist/__tests__/type.test.d.ts +0 -2
- package/dist/__tests__/type.test.d.ts.map +0 -1
- package/dist/__tests__/useController.test.d.ts +0 -2
- package/dist/__tests__/useController.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/append.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/append.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/focus.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/focus.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/insert.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/insert.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/move.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/move.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/prepend.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/prepend.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/remove.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/remove.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/replace.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/replace.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/swap.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/swap.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray/update.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray/update.test.d.ts.map +0 -1
- package/dist/__tests__/useFieldArray.test.d.ts +0 -2
- package/dist/__tests__/useFieldArray.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/clearErrors.test.d.ts +0 -2
- package/dist/__tests__/useForm/clearErrors.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/formState.test.d.ts +0 -2
- package/dist/__tests__/useForm/formState.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/getFieldState.test.d.ts +0 -2
- package/dist/__tests__/useForm/getFieldState.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/getValues.test.d.ts +0 -2
- package/dist/__tests__/useForm/getValues.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/handleSubmit.test.d.ts +0 -2
- package/dist/__tests__/useForm/handleSubmit.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/register.test.d.ts +0 -2
- package/dist/__tests__/useForm/register.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/reset.test.d.ts +0 -2
- package/dist/__tests__/useForm/reset.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/resetField.test.d.ts +0 -2
- package/dist/__tests__/useForm/resetField.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/resolver.test.d.ts +0 -2
- package/dist/__tests__/useForm/resolver.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/setError.test.d.ts +0 -2
- package/dist/__tests__/useForm/setError.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/setFocus.test.d.ts +0 -2
- package/dist/__tests__/useForm/setFocus.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/setValue.test.d.ts +0 -2
- package/dist/__tests__/useForm/setValue.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/subscribe.test.d.ts +0 -2
- package/dist/__tests__/useForm/subscribe.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/trigger.test.d.ts +0 -2
- package/dist/__tests__/useForm/trigger.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/unregister.test.d.ts +0 -2
- package/dist/__tests__/useForm/unregister.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/useFormWithNullValues.test.d.ts +0 -2
- package/dist/__tests__/useForm/useFormWithNullValues.test.d.ts.map +0 -1
- package/dist/__tests__/useForm/watch.test.d.ts +0 -2
- package/dist/__tests__/useForm/watch.test.d.ts.map +0 -1
- package/dist/__tests__/useForm.server.test.d.ts +0 -2
- package/dist/__tests__/useForm.server.test.d.ts.map +0 -1
- package/dist/__tests__/useForm.test.d.ts +0 -2
- package/dist/__tests__/useForm.test.d.ts.map +0 -1
- package/dist/__tests__/useFormContext.server.test.d.ts +0 -2
- package/dist/__tests__/useFormContext.server.test.d.ts.map +0 -1
- package/dist/__tests__/useFormContext.test.d.ts +0 -2
- package/dist/__tests__/useFormContext.test.d.ts.map +0 -1
- package/dist/__tests__/useFormState.test.d.ts +0 -2
- package/dist/__tests__/useFormState.test.d.ts.map +0 -1
- package/dist/__tests__/useWatch.test.d.ts +0 -2
- package/dist/__tests__/useWatch.test.d.ts.map +0 -1
- package/dist/__tests__/utils/append.test.d.ts +0 -2
- package/dist/__tests__/utils/append.test.d.ts.map +0 -1
- package/dist/__tests__/utils/cloneObject.test.d.ts +0 -2
- package/dist/__tests__/utils/cloneObject.test.d.ts.map +0 -1
- package/dist/__tests__/utils/compact.test.d.ts +0 -2
- package/dist/__tests__/utils/compact.test.d.ts.map +0 -1
- package/dist/__tests__/utils/convertToArrayPayload.test.d.ts +0 -2
- package/dist/__tests__/utils/convertToArrayPayload.test.d.ts.map +0 -1
- package/dist/__tests__/utils/createSubject.test.d.ts +0 -2
- package/dist/__tests__/utils/createSubject.test.d.ts.map +0 -1
- package/dist/__tests__/utils/deepEqual.test.d.ts +0 -2
- package/dist/__tests__/utils/deepEqual.test.d.ts.map +0 -1
- package/dist/__tests__/utils/deepMerge.test.d.ts +0 -2
- package/dist/__tests__/utils/deepMerge.test.d.ts.map +0 -1
- package/dist/__tests__/utils/extractFormValues.test.d.ts +0 -2
- package/dist/__tests__/utils/extractFormValues.test.d.ts.map +0 -1
- package/dist/__tests__/utils/fillEmptyArray.test.d.ts +0 -2
- package/dist/__tests__/utils/fillEmptyArray.test.d.ts.map +0 -1
- package/dist/__tests__/utils/flatten.test.d.ts +0 -2
- package/dist/__tests__/utils/flatten.test.d.ts.map +0 -1
- package/dist/__tests__/utils/get.test.d.ts +0 -2
- package/dist/__tests__/utils/get.test.d.ts.map +0 -1
- package/dist/__tests__/utils/insert.test.d.ts +0 -2
- package/dist/__tests__/utils/insert.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isBoolean.test.d.ts +0 -2
- package/dist/__tests__/utils/isBoolean.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isCheckBoxInput.test.d.ts +0 -2
- package/dist/__tests__/utils/isCheckBoxInput.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isEmptyObject.test.d.ts +0 -2
- package/dist/__tests__/utils/isEmptyObject.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isFileInput.test.d.ts +0 -2
- package/dist/__tests__/utils/isFileInput.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isFunction.test.d.ts +0 -2
- package/dist/__tests__/utils/isFunction.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isHTMLElement.test.d.ts +0 -2
- package/dist/__tests__/utils/isHTMLElement.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isKey.test.d.ts +0 -2
- package/dist/__tests__/utils/isKey.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isMultipleSelect.test.d.ts +0 -2
- package/dist/__tests__/utils/isMultipleSelect.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isNullOrUndefined.test.d.ts +0 -2
- package/dist/__tests__/utils/isNullOrUndefined.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isObject.test.d.ts +0 -2
- package/dist/__tests__/utils/isObject.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isPrimitive.test.d.ts +0 -2
- package/dist/__tests__/utils/isPrimitive.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isRadioInput.test.d.ts +0 -2
- package/dist/__tests__/utils/isRadioInput.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isRadioOrCheckbox.test.d.ts +0 -2
- package/dist/__tests__/utils/isRadioOrCheckbox.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isRegex.test.d.ts +0 -2
- package/dist/__tests__/utils/isRegex.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isString.test.d.ts +0 -2
- package/dist/__tests__/utils/isString.test.d.ts.map +0 -1
- package/dist/__tests__/utils/isUndefined.test.d.ts +0 -2
- package/dist/__tests__/utils/isUndefined.test.d.ts.map +0 -1
- package/dist/__tests__/utils/live.test.d.ts +0 -2
- package/dist/__tests__/utils/live.test.d.ts.map +0 -1
- package/dist/__tests__/utils/move.test.d.ts +0 -2
- package/dist/__tests__/utils/move.test.d.ts.map +0 -1
- package/dist/__tests__/utils/noop.test.d.ts +0 -2
- package/dist/__tests__/utils/noop.test.d.ts.map +0 -1
- package/dist/__tests__/utils/objectHasFunction.test.d.ts +0 -2
- package/dist/__tests__/utils/objectHasFunction.test.d.ts.map +0 -1
- package/dist/__tests__/utils/prepend.test.d.ts +0 -2
- package/dist/__tests__/utils/prepend.test.d.ts.map +0 -1
- package/dist/__tests__/utils/remove.test.d.ts +0 -2
- package/dist/__tests__/utils/remove.test.d.ts.map +0 -1
- package/dist/__tests__/utils/set.test.d.ts +0 -2
- package/dist/__tests__/utils/set.test.d.ts.map +0 -1
- package/dist/__tests__/utils/stringToPath.test.d.ts +0 -2
- package/dist/__tests__/utils/stringToPath.test.d.ts.map +0 -1
- package/dist/__tests__/utils/swap.test.d.ts +0 -2
- package/dist/__tests__/utils/swap.test.d.ts.map +0 -1
- package/dist/__tests__/utils/unset.test.d.ts +0 -2
- package/dist/__tests__/utils/unset.test.d.ts.map +0 -1
- package/dist/__tests__/utils/validationModeChecker.test.d.ts +0 -2
- package/dist/__tests__/utils/validationModeChecker.test.d.ts.map +0 -1
- package/dist/__tests__/watch.server.test.d.ts +0 -2
- package/dist/__tests__/watch.server.test.d.ts.map +0 -1
- package/dist/__tests__/watch.test.d.ts +0 -2
- package/dist/__tests__/watch.test.d.ts.map +0 -1
package/dist/index.esm.mjs
CHANGED
|
@@ -18,9 +18,9 @@ var getEventValue = (event) => isObject(event) && event.target
|
|
|
18
18
|
: event.target.value
|
|
19
19
|
: event;
|
|
20
20
|
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
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;
|
|
@@ -52,19 +52,52 @@ function cloneObject(data) {
|
|
|
52
52
|
return copy;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
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 ROOT_ERROR_TYPE = 'root';
|
|
80
|
+
const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
|
|
81
|
+
|
|
82
|
+
const IS_KEY_RE = /^\w*$/;
|
|
83
|
+
var isKey = (value) => IS_KEY_RE.test(value);
|
|
56
84
|
|
|
57
85
|
var isUndefined = (val) => val === undefined;
|
|
58
86
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
|
|
87
|
+
const FIELD_PATH_RE = /[.[\]'"]/;
|
|
88
|
+
var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
|
|
62
89
|
|
|
63
90
|
var get = (object, path, defaultValue) => {
|
|
64
91
|
if (!path || !isObject(object)) {
|
|
65
92
|
return defaultValue;
|
|
66
93
|
}
|
|
67
|
-
const
|
|
94
|
+
const paths = isKey(path) ? [path] : stringToPath(path);
|
|
95
|
+
if (paths.some((key) => PROTOTYPE_KEYWORDS.includes(key))) {
|
|
96
|
+
return defaultValue;
|
|
97
|
+
}
|
|
98
|
+
const result = paths.reduce((result, key) => {
|
|
99
|
+
return isNullOrUndefined(result) ? undefined : result[key];
|
|
100
|
+
}, object);
|
|
68
101
|
return isUndefined(result) || result === object
|
|
69
102
|
? isUndefined(object[path])
|
|
70
103
|
? defaultValue
|
|
@@ -91,7 +124,7 @@ var set = (object, path, value) => {
|
|
|
91
124
|
? []
|
|
92
125
|
: {};
|
|
93
126
|
}
|
|
94
|
-
if (key
|
|
127
|
+
if (PROTOTYPE_KEYWORDS.includes(key)) {
|
|
95
128
|
return;
|
|
96
129
|
}
|
|
97
130
|
object[key] = newValue;
|
|
@@ -99,28 +132,6 @@ var set = (object, path, value) => {
|
|
|
99
132
|
}
|
|
100
133
|
};
|
|
101
134
|
|
|
102
|
-
const EVENTS = {
|
|
103
|
-
BLUR: 'blur',
|
|
104
|
-
FOCUS_OUT: 'focusout',
|
|
105
|
-
CHANGE: 'change',
|
|
106
|
-
};
|
|
107
|
-
const VALIDATION_MODE = {
|
|
108
|
-
onBlur: 'onBlur',
|
|
109
|
-
onChange: 'onChange',
|
|
110
|
-
onSubmit: 'onSubmit',
|
|
111
|
-
onTouched: 'onTouched',
|
|
112
|
-
all: 'all',
|
|
113
|
-
};
|
|
114
|
-
const INPUT_VALIDATION_RULES = {
|
|
115
|
-
max: 'max',
|
|
116
|
-
min: 'min',
|
|
117
|
-
maxLength: 'maxLength',
|
|
118
|
-
minLength: 'minLength',
|
|
119
|
-
pattern: 'pattern',
|
|
120
|
-
required: 'required',
|
|
121
|
-
validate: 'validate',
|
|
122
|
-
};
|
|
123
|
-
|
|
124
135
|
/**
|
|
125
136
|
* Separate context for `control` to prevent unnecessary rerenders.
|
|
126
137
|
* Internal hooks that only need control use this instead of full form context.
|
|
@@ -133,10 +144,7 @@ HookFormControlContext.displayName = 'HookFormControlContext';
|
|
|
133
144
|
const useFormControlContext = () => React.useContext(HookFormControlContext);
|
|
134
145
|
|
|
135
146
|
var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
|
|
136
|
-
const result = {
|
|
137
|
-
...formState,
|
|
138
|
-
defaultValues: control._defaultValues,
|
|
139
|
-
};
|
|
147
|
+
const result = {};
|
|
140
148
|
for (const key in formState) {
|
|
141
149
|
Object.defineProperty(result, key, {
|
|
142
150
|
get: () => {
|
|
@@ -152,7 +160,9 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
|
|
|
152
160
|
return result;
|
|
153
161
|
};
|
|
154
162
|
|
|
155
|
-
const useIsomorphicLayoutEffect =
|
|
163
|
+
const useIsomorphicLayoutEffect = isWeb
|
|
164
|
+
? React.useLayoutEffect
|
|
165
|
+
: React.useEffect;
|
|
156
166
|
|
|
157
167
|
/**
|
|
158
168
|
* 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.
|
|
@@ -187,7 +197,10 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayou
|
|
|
187
197
|
function useFormState(props) {
|
|
188
198
|
const formControl = useFormControlContext();
|
|
189
199
|
const { control = formControl, disabled, name, exact } = props || {};
|
|
190
|
-
const [formState, updateFormState] = React.useState(
|
|
200
|
+
const [formState, updateFormState] = React.useState(() => ({
|
|
201
|
+
...control._formState,
|
|
202
|
+
defaultValues: control._defaultValues,
|
|
203
|
+
}));
|
|
191
204
|
const _localProxyFormState = React.useRef({
|
|
192
205
|
isDirty: false,
|
|
193
206
|
isLoading: false,
|
|
@@ -207,6 +220,7 @@ function useFormState(props) {
|
|
|
207
220
|
updateFormState({
|
|
208
221
|
...control._formState,
|
|
209
222
|
...formState,
|
|
223
|
+
defaultValues: control._defaultValues,
|
|
210
224
|
});
|
|
211
225
|
},
|
|
212
226
|
}), [name, disabled, exact]);
|
|
@@ -233,7 +247,11 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
233
247
|
|
|
234
248
|
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
235
249
|
|
|
236
|
-
|
|
250
|
+
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
251
|
+
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
252
|
+
if (object1 === object2) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
237
255
|
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
238
256
|
return Object.is(object1, object2);
|
|
239
257
|
}
|
|
@@ -245,22 +263,36 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
|
|
|
245
263
|
if (keys1.length !== keys2.length) {
|
|
246
264
|
return false;
|
|
247
265
|
}
|
|
248
|
-
if (
|
|
266
|
+
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
267
|
+
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
268
|
+
return Object.is(object1, object2);
|
|
269
|
+
}
|
|
270
|
+
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
const visitedPairs = visited.get(object1);
|
|
274
|
+
if (visitedPairs && visitedPairs.has(object2)) {
|
|
249
275
|
return true;
|
|
250
276
|
}
|
|
251
|
-
|
|
252
|
-
|
|
277
|
+
if (visitedPairs) {
|
|
278
|
+
visitedPairs.add(object2);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const ws = new WeakSet();
|
|
282
|
+
ws.add(object2);
|
|
283
|
+
visited.set(object1, ws);
|
|
284
|
+
}
|
|
253
285
|
for (const key of keys1) {
|
|
254
286
|
const val1 = object1[key];
|
|
255
|
-
if (!
|
|
287
|
+
if (!(key in object2)) {
|
|
256
288
|
return false;
|
|
257
289
|
}
|
|
258
290
|
if (key !== 'ref') {
|
|
259
291
|
const val2 = object2[key];
|
|
260
292
|
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
261
|
-
(isObject(val1)
|
|
262
|
-
|
|
263
|
-
? !deepEqual(val1, val2,
|
|
293
|
+
((isObject(val1) || Array.isArray(val1)) &&
|
|
294
|
+
(isObject(val2) || Array.isArray(val2)))
|
|
295
|
+
? !deepEqual(val1, val2, visited)
|
|
264
296
|
: !Object.is(val1, val2)) {
|
|
265
297
|
return false;
|
|
266
298
|
}
|
|
@@ -396,7 +428,7 @@ function useController(props) {
|
|
|
396
428
|
exact,
|
|
397
429
|
});
|
|
398
430
|
const _props = React.useRef(props);
|
|
399
|
-
const
|
|
431
|
+
const _proxyRef = React.useRef(null);
|
|
400
432
|
const _registerProps = React.useRef(control.register(name, {
|
|
401
433
|
...props.rules,
|
|
402
434
|
value,
|
|
@@ -425,13 +457,22 @@ function useController(props) {
|
|
|
425
457
|
get: () => get(formState.errors, name),
|
|
426
458
|
},
|
|
427
459
|
}), [formState, name]);
|
|
428
|
-
const onChange = React.useCallback((event) =>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
460
|
+
const onChange = React.useCallback((event) => {
|
|
461
|
+
const value = getEventValue(event);
|
|
462
|
+
if (!get(control._fields, name)) {
|
|
463
|
+
_registerProps.current = control.register(name, {
|
|
464
|
+
..._props.current.rules,
|
|
465
|
+
value,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
return _registerProps.current.onChange({
|
|
469
|
+
target: {
|
|
470
|
+
value: getEventValue(event),
|
|
471
|
+
name: name,
|
|
472
|
+
},
|
|
473
|
+
type: EVENTS.CHANGE,
|
|
474
|
+
});
|
|
475
|
+
}, [name, control]);
|
|
435
476
|
const onBlur = React.useCallback(() => _registerProps.current.onBlur({
|
|
436
477
|
target: {
|
|
437
478
|
value: get(control._formValues, name),
|
|
@@ -440,9 +481,12 @@ function useController(props) {
|
|
|
440
481
|
type: EVENTS.BLUR,
|
|
441
482
|
}), [name, control._formValues]);
|
|
442
483
|
const ref = React.useCallback((elm) => {
|
|
484
|
+
if (elm) {
|
|
485
|
+
_proxyRef.current = elm;
|
|
486
|
+
}
|
|
443
487
|
const field = get(control._fields, name);
|
|
444
488
|
if (field && field._f && elm) {
|
|
445
|
-
field._f.ref =
|
|
489
|
+
field._f.ref = _proxyRef.current;
|
|
446
490
|
}
|
|
447
491
|
}, [control._fields, name]);
|
|
448
492
|
const field = React.useMemo(() => ({
|
|
@@ -457,10 +501,6 @@ function useController(props) {
|
|
|
457
501
|
}), [name, disabled, formState.disabled, onChange, onBlur, ref, value]);
|
|
458
502
|
React.useEffect(() => {
|
|
459
503
|
const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
|
|
460
|
-
const previousName = _previousNameRef.current;
|
|
461
|
-
if (previousName && previousName !== name && !isArrayField) {
|
|
462
|
-
control.unregister(previousName);
|
|
463
|
-
}
|
|
464
504
|
control.register(name, {
|
|
465
505
|
..._props.current.rules,
|
|
466
506
|
...(isBoolean(_props.current.disabled)
|
|
@@ -475,14 +515,21 @@ function useController(props) {
|
|
|
475
515
|
};
|
|
476
516
|
updateMounted(name, true);
|
|
477
517
|
if (_shouldUnregisterField) {
|
|
478
|
-
const value = cloneObject(get(
|
|
518
|
+
const value = cloneObject(get(shouldUnregister
|
|
519
|
+
? control._defaultValues
|
|
520
|
+
: control._options.values || control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
|
|
479
521
|
set(control._defaultValues, name, value);
|
|
480
522
|
if (isUndefined(get(control._formValues, name))) {
|
|
481
523
|
set(control._formValues, name, value);
|
|
482
524
|
}
|
|
483
525
|
}
|
|
484
526
|
!isArrayField && control.register(name);
|
|
485
|
-
|
|
527
|
+
if (_proxyRef.current) {
|
|
528
|
+
const field = get(control._fields, name);
|
|
529
|
+
if (field && field._f) {
|
|
530
|
+
field._f.ref = _proxyRef.current;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
486
533
|
return () => {
|
|
487
534
|
(isArrayField
|
|
488
535
|
? _shouldUnregisterField && !control._state.action
|
|
@@ -551,7 +598,9 @@ const Controller = (props) => props.render(useController(props));
|
|
|
551
598
|
const flatten = (obj) => {
|
|
552
599
|
const output = {};
|
|
553
600
|
for (const key of Object.keys(obj)) {
|
|
554
|
-
if (isObjectType(obj[key]) &&
|
|
601
|
+
if (isObjectType(obj[key]) &&
|
|
602
|
+
obj[key] !== null &&
|
|
603
|
+
!isDateObject(obj[key])) {
|
|
555
604
|
const nested = flatten(obj[key]);
|
|
556
605
|
for (const nestedKey of Object.keys(nested)) {
|
|
557
606
|
output[`${key}.${nestedKey}`] = nested[nestedKey];
|
|
@@ -627,44 +676,46 @@ const useFormContext = () => React.useContext(HookFormContext);
|
|
|
627
676
|
* }
|
|
628
677
|
* ```
|
|
629
678
|
*/
|
|
630
|
-
const FormProvider = (
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
679
|
+
const FormProvider = ({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
|
|
680
|
+
const memoizedValue = React.useMemo(() => ({
|
|
681
|
+
watch,
|
|
682
|
+
getValues,
|
|
683
|
+
getFieldState,
|
|
684
|
+
setError,
|
|
685
|
+
clearErrors,
|
|
686
|
+
setValue,
|
|
687
|
+
setValues,
|
|
688
|
+
trigger,
|
|
689
|
+
formState,
|
|
690
|
+
resetField,
|
|
691
|
+
reset,
|
|
692
|
+
handleSubmit,
|
|
693
|
+
unregister,
|
|
694
|
+
control,
|
|
695
|
+
register,
|
|
696
|
+
setFocus,
|
|
697
|
+
subscribe,
|
|
698
|
+
}), [
|
|
699
|
+
clearErrors,
|
|
700
|
+
control,
|
|
701
|
+
formState,
|
|
702
|
+
getFieldState,
|
|
703
|
+
getValues,
|
|
704
|
+
handleSubmit,
|
|
705
|
+
register,
|
|
706
|
+
reset,
|
|
707
|
+
resetField,
|
|
708
|
+
setError,
|
|
709
|
+
setFocus,
|
|
710
|
+
setValue,
|
|
711
|
+
setValues,
|
|
712
|
+
subscribe,
|
|
713
|
+
trigger,
|
|
714
|
+
unregister,
|
|
715
|
+
watch,
|
|
716
|
+
]);
|
|
717
|
+
return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
|
|
718
|
+
React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
|
|
668
719
|
};
|
|
669
720
|
|
|
670
721
|
const POST_REQUEST = 'post';
|
|
@@ -694,7 +745,7 @@ function Form(props) {
|
|
|
694
745
|
const methods = useFormContext();
|
|
695
746
|
const [mounted, setMounted] = React.useState(false);
|
|
696
747
|
const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
|
|
697
|
-
const submit = async (event) => {
|
|
748
|
+
const submit = React.useCallback(async (event) => {
|
|
698
749
|
let hasError = false;
|
|
699
750
|
let type = '';
|
|
700
751
|
await control.handleSubmit(async (data) => {
|
|
@@ -703,8 +754,8 @@ function Form(props) {
|
|
|
703
754
|
try {
|
|
704
755
|
formDataJson = JSON.stringify(data);
|
|
705
756
|
}
|
|
706
|
-
catch
|
|
707
|
-
const flattenFormValues = flatten(
|
|
757
|
+
catch { }
|
|
758
|
+
const flattenFormValues = flatten(data);
|
|
708
759
|
for (const key in flattenFormValues) {
|
|
709
760
|
formData.append(key, flattenFormValues[key]);
|
|
710
761
|
}
|
|
@@ -751,15 +802,25 @@ function Form(props) {
|
|
|
751
802
|
}
|
|
752
803
|
}
|
|
753
804
|
})(event);
|
|
754
|
-
if (hasError &&
|
|
755
|
-
|
|
805
|
+
if (hasError && control) {
|
|
806
|
+
control._subjects.state.next({
|
|
756
807
|
isSubmitSuccessful: false,
|
|
757
808
|
});
|
|
758
|
-
|
|
809
|
+
control.setError('root.server', {
|
|
759
810
|
type,
|
|
760
811
|
});
|
|
761
812
|
}
|
|
762
|
-
}
|
|
813
|
+
}, [
|
|
814
|
+
control,
|
|
815
|
+
onSubmit,
|
|
816
|
+
method,
|
|
817
|
+
action,
|
|
818
|
+
headers,
|
|
819
|
+
encType,
|
|
820
|
+
validateStatus,
|
|
821
|
+
onError,
|
|
822
|
+
onSuccess,
|
|
823
|
+
]);
|
|
763
824
|
React.useEffect(() => {
|
|
764
825
|
setMounted(true);
|
|
765
826
|
}, []);
|
|
@@ -780,6 +841,8 @@ var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => va
|
|
|
780
841
|
}
|
|
781
842
|
: {};
|
|
782
843
|
|
|
844
|
+
var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
|
|
845
|
+
|
|
783
846
|
var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
|
|
784
847
|
|
|
785
848
|
var createSubject = () => {
|
|
@@ -857,7 +920,12 @@ function baseGet(object, updatePath) {
|
|
|
857
920
|
const length = updatePath.slice(0, -1).length;
|
|
858
921
|
let index = 0;
|
|
859
922
|
while (index < length) {
|
|
860
|
-
|
|
923
|
+
if (isNullOrUndefined(object)) {
|
|
924
|
+
object = undefined;
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
object = object[updatePath[index]];
|
|
928
|
+
index++;
|
|
861
929
|
}
|
|
862
930
|
return object;
|
|
863
931
|
}
|
|
@@ -870,11 +938,18 @@ function isEmptyArray(obj) {
|
|
|
870
938
|
return true;
|
|
871
939
|
}
|
|
872
940
|
function unset(object, path) {
|
|
941
|
+
if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
|
|
942
|
+
delete object[path];
|
|
943
|
+
return object;
|
|
944
|
+
}
|
|
873
945
|
const paths = Array.isArray(path)
|
|
874
946
|
? path
|
|
875
947
|
: isKey(path)
|
|
876
948
|
? [path]
|
|
877
949
|
: stringToPath(path);
|
|
950
|
+
if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
|
|
951
|
+
return object;
|
|
952
|
+
}
|
|
878
953
|
const childObject = paths.length === 1 ? object : baseGet(object, paths);
|
|
879
954
|
const index = paths.length - 1;
|
|
880
955
|
const key = paths[index];
|
|
@@ -914,6 +989,29 @@ function markFieldsDirty(data, fields = {}) {
|
|
|
914
989
|
}
|
|
915
990
|
return fields;
|
|
916
991
|
}
|
|
992
|
+
function pruneDirtyFields(value) {
|
|
993
|
+
if (value === false) {
|
|
994
|
+
return undefined;
|
|
995
|
+
}
|
|
996
|
+
if (value === true) {
|
|
997
|
+
return true;
|
|
998
|
+
}
|
|
999
|
+
if (Array.isArray(value)) {
|
|
1000
|
+
const result = value.map((value) => pruneDirtyFields(value));
|
|
1001
|
+
return (result.some((value) => value !== undefined) ? result : undefined);
|
|
1002
|
+
}
|
|
1003
|
+
if (isObject(value)) {
|
|
1004
|
+
const result = {};
|
|
1005
|
+
for (const key in value) {
|
|
1006
|
+
const pruned = pruneDirtyFields(value[key]);
|
|
1007
|
+
if (!isUndefined(pruned)) {
|
|
1008
|
+
result[key] = pruned;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return (Object.keys(result).length ? result : undefined);
|
|
1012
|
+
}
|
|
1013
|
+
return undefined;
|
|
1014
|
+
}
|
|
917
1015
|
function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
918
1016
|
if (!dirtyFieldsFromValues) {
|
|
919
1017
|
dirtyFieldsFromValues = markFieldsDirty(formValues);
|
|
@@ -933,7 +1031,7 @@ function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
|
933
1031
|
dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
|
|
934
1032
|
}
|
|
935
1033
|
}
|
|
936
|
-
return dirtyFieldsFromValues;
|
|
1034
|
+
return pruneDirtyFields(dirtyFieldsFromValues) || {};
|
|
937
1035
|
}
|
|
938
1036
|
|
|
939
1037
|
const defaultResult = {
|
|
@@ -1040,12 +1138,22 @@ var getValidationModes = (mode) => ({
|
|
|
1040
1138
|
});
|
|
1041
1139
|
|
|
1042
1140
|
const ASYNC_FUNCTION = 'AsyncFunction';
|
|
1043
|
-
var hasPromiseValidation = (fieldReference) =>
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1141
|
+
var hasPromiseValidation = (fieldReference) => {
|
|
1142
|
+
if (!fieldReference || !fieldReference.validate)
|
|
1143
|
+
return false;
|
|
1144
|
+
if (isFunction(fieldReference.validate)) {
|
|
1145
|
+
return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
|
|
1146
|
+
}
|
|
1147
|
+
if (isObject(fieldReference.validate)) {
|
|
1148
|
+
for (const key in fieldReference.validate) {
|
|
1149
|
+
if (fieldReference.validate[key].constructor
|
|
1150
|
+
.name === ASYNC_FUNCTION) {
|
|
1151
|
+
return true;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return false;
|
|
1156
|
+
};
|
|
1049
1157
|
|
|
1050
1158
|
var hasValidation = (options) => options.mount &&
|
|
1051
1159
|
(options.required ||
|
|
@@ -1056,11 +1164,17 @@ var hasValidation = (options) => options.mount &&
|
|
|
1056
1164
|
options.pattern ||
|
|
1057
1165
|
options.validate);
|
|
1058
1166
|
|
|
1059
|
-
var isWatched = (name, _names, isBlurEvent) =>
|
|
1060
|
-
(
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1167
|
+
var isWatched = (name, _names, isBlurEvent) => {
|
|
1168
|
+
if (isBlurEvent)
|
|
1169
|
+
return false;
|
|
1170
|
+
if (_names.watchAll || _names.watch.has(name))
|
|
1171
|
+
return true;
|
|
1172
|
+
for (const watchName of _names.watch) {
|
|
1173
|
+
if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
|
|
1174
|
+
return true;
|
|
1175
|
+
}
|
|
1176
|
+
return false;
|
|
1177
|
+
};
|
|
1064
1178
|
|
|
1065
1179
|
const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
1066
1180
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
@@ -1128,9 +1242,10 @@ function schemaErrorLookup(errors, _fields, name) {
|
|
|
1128
1242
|
var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
|
|
1129
1243
|
updateFormState(formStateData);
|
|
1130
1244
|
const { name, ...formState } = formStateData;
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
Object.keys(
|
|
1245
|
+
const keys = Object.keys(formState);
|
|
1246
|
+
return (!keys.length ||
|
|
1247
|
+
(isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
|
|
1248
|
+
keys.find((key) => _proxyFormState[key] ===
|
|
1134
1249
|
(!isRoot || VALIDATION_MODE.all)));
|
|
1135
1250
|
};
|
|
1136
1251
|
|
|
@@ -1139,7 +1254,7 @@ var shouldSubscribeByName = (name, signalName, exact) => !name ||
|
|
|
1139
1254
|
name === signalName ||
|
|
1140
1255
|
convertToArrayPayload(name).some((currentName) => currentName &&
|
|
1141
1256
|
(exact
|
|
1142
|
-
? currentName === signalName
|
|
1257
|
+
? currentName === signalName || currentName.startsWith(signalName + '.')
|
|
1143
1258
|
: currentName.startsWith(signalName) ||
|
|
1144
1259
|
signalName.startsWith(currentName)));
|
|
1145
1260
|
|
|
@@ -1162,8 +1277,9 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
|
|
|
1162
1277
|
var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
|
|
1163
1278
|
|
|
1164
1279
|
var updateFieldArrayRootError = (errors, error, name) => {
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1280
|
+
const existingErrors = get(errors, name);
|
|
1281
|
+
const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
|
|
1282
|
+
set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
|
|
1167
1283
|
set(errors, name, fieldArrayErrors);
|
|
1168
1284
|
return errors;
|
|
1169
1285
|
};
|
|
@@ -1196,7 +1312,13 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
1196
1312
|
const inputRef = refs ? refs[0] : ref;
|
|
1197
1313
|
const setCustomValidity = (message) => {
|
|
1198
1314
|
if (shouldUseNativeValidation && inputRef.reportValidity) {
|
|
1199
|
-
|
|
1315
|
+
const validityMessage = isBoolean(message) ? '' : message || '';
|
|
1316
|
+
if (refs) {
|
|
1317
|
+
refs.forEach((ref) => ref.setCustomValidity(validityMessage));
|
|
1318
|
+
}
|
|
1319
|
+
else {
|
|
1320
|
+
inputRef.setCustomValidity(validityMessage);
|
|
1321
|
+
}
|
|
1200
1322
|
inputRef.reportValidity();
|
|
1201
1323
|
}
|
|
1202
1324
|
};
|
|
@@ -1371,24 +1493,28 @@ const defaultOptions = {
|
|
|
1371
1493
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
1372
1494
|
shouldFocusError: true,
|
|
1373
1495
|
};
|
|
1496
|
+
const FORM_ERROR_TYPE = 'form';
|
|
1497
|
+
const DEFAULT_FORM_STATE = {
|
|
1498
|
+
submitCount: 0,
|
|
1499
|
+
isDirty: false,
|
|
1500
|
+
isReady: false,
|
|
1501
|
+
isValidating: false,
|
|
1502
|
+
isSubmitted: false,
|
|
1503
|
+
isSubmitting: false,
|
|
1504
|
+
isSubmitSuccessful: false,
|
|
1505
|
+
isValid: false,
|
|
1506
|
+
touchedFields: {},
|
|
1507
|
+
dirtyFields: {},
|
|
1508
|
+
validatingFields: {},
|
|
1509
|
+
};
|
|
1374
1510
|
function createFormControl(props = {}) {
|
|
1375
1511
|
let _options = {
|
|
1376
1512
|
...defaultOptions,
|
|
1377
1513
|
...props,
|
|
1378
1514
|
};
|
|
1379
1515
|
let _formState = {
|
|
1380
|
-
|
|
1381
|
-
isDirty: false,
|
|
1382
|
-
isReady: false,
|
|
1516
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
1383
1517
|
isLoading: isFunction(_options.defaultValues),
|
|
1384
|
-
isValidating: false,
|
|
1385
|
-
isSubmitted: false,
|
|
1386
|
-
isSubmitting: false,
|
|
1387
|
-
isSubmitSuccessful: false,
|
|
1388
|
-
isValid: false,
|
|
1389
|
-
touchedFields: {},
|
|
1390
|
-
dirtyFields: {},
|
|
1391
|
-
validatingFields: {},
|
|
1392
1518
|
errors: _options.errors || {},
|
|
1393
1519
|
disabled: _options.disabled || false,
|
|
1394
1520
|
};
|
|
@@ -1411,9 +1537,13 @@ function createFormControl(props = {}) {
|
|
|
1411
1537
|
unMount: new Set(),
|
|
1412
1538
|
array: new Set(),
|
|
1413
1539
|
watch: new Set(),
|
|
1540
|
+
registerName: new Set(),
|
|
1414
1541
|
};
|
|
1415
1542
|
let delayErrorCallback;
|
|
1416
1543
|
let timer = 0;
|
|
1544
|
+
let _valuesSubscriberCount = 0;
|
|
1545
|
+
let _validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1546
|
+
let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
1417
1547
|
const defaultProxyFormState = {
|
|
1418
1548
|
isDirty: false,
|
|
1419
1549
|
dirtyFields: false,
|
|
@@ -1452,7 +1582,11 @@ function createFormControl(props = {}) {
|
|
|
1452
1582
|
_updateIsValidating();
|
|
1453
1583
|
}
|
|
1454
1584
|
else {
|
|
1455
|
-
isValid = await executeBuiltInValidation(
|
|
1585
|
+
isValid = await executeBuiltInValidation({
|
|
1586
|
+
fields: _fields,
|
|
1587
|
+
onlyCheckValid: true,
|
|
1588
|
+
eventType: EVENTS.VALID,
|
|
1589
|
+
});
|
|
1456
1590
|
}
|
|
1457
1591
|
if (isValid !== _formState.isValid) {
|
|
1458
1592
|
_subjects.state.next({
|
|
@@ -1480,6 +1614,9 @@ function createFormControl(props = {}) {
|
|
|
1480
1614
|
});
|
|
1481
1615
|
}
|
|
1482
1616
|
};
|
|
1617
|
+
const _updateDirtyFields = () => {
|
|
1618
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1619
|
+
};
|
|
1483
1620
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
1484
1621
|
if (args && method && !_options.disabled) {
|
|
1485
1622
|
_state.action = true;
|
|
@@ -1501,7 +1638,7 @@ function createFormControl(props = {}) {
|
|
|
1501
1638
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
1502
1639
|
}
|
|
1503
1640
|
if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
|
|
1504
|
-
|
|
1641
|
+
_updateDirtyFields();
|
|
1505
1642
|
}
|
|
1506
1643
|
_subjects.state.next({
|
|
1507
1644
|
name,
|
|
@@ -1517,6 +1654,7 @@ function createFormControl(props = {}) {
|
|
|
1517
1654
|
};
|
|
1518
1655
|
const updateErrors = (name, error) => {
|
|
1519
1656
|
set(_formState.errors, name, error);
|
|
1657
|
+
_formState.errors = { ..._formState.errors };
|
|
1520
1658
|
_subjects.state.next({
|
|
1521
1659
|
errors: _formState.errors,
|
|
1522
1660
|
});
|
|
@@ -1528,16 +1666,53 @@ function createFormControl(props = {}) {
|
|
|
1528
1666
|
isValid: false,
|
|
1529
1667
|
});
|
|
1530
1668
|
};
|
|
1669
|
+
const hasExplicitNullIntermediate = (name) => {
|
|
1670
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
1671
|
+
let formValues = _formValues;
|
|
1672
|
+
let defaultValues = _defaultValues;
|
|
1673
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1674
|
+
const key = segments[i];
|
|
1675
|
+
formValues = isNullOrUndefined(formValues) ? formValues : formValues[key];
|
|
1676
|
+
defaultValues = isNullOrUndefined(defaultValues)
|
|
1677
|
+
? defaultValues
|
|
1678
|
+
: defaultValues[key];
|
|
1679
|
+
if (formValues === null && defaultValues !== null) {
|
|
1680
|
+
return true;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
return false;
|
|
1684
|
+
};
|
|
1531
1685
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
1532
1686
|
const field = get(_fields, name);
|
|
1533
1687
|
if (field) {
|
|
1688
|
+
if (hasExplicitNullIntermediate(name)) {
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
1534
1692
|
const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
|
|
1535
1693
|
isUndefined(defaultValue) ||
|
|
1536
1694
|
(ref && ref.defaultChecked) ||
|
|
1537
1695
|
shouldSkipSetValueAs
|
|
1538
1696
|
? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
|
|
1539
1697
|
: setFieldValue(name, defaultValue);
|
|
1540
|
-
_state.mount && !_state.action
|
|
1698
|
+
if (_state.mount && !_state.action) {
|
|
1699
|
+
_setValid();
|
|
1700
|
+
if (wasUnsetInFormValues &&
|
|
1701
|
+
_formState.isDirty &&
|
|
1702
|
+
(_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
|
|
1703
|
+
const isDirty = _getDirty();
|
|
1704
|
+
if (!isDirty) {
|
|
1705
|
+
_formState.isDirty = false;
|
|
1706
|
+
_subjects.state.next({ ..._formState });
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
if (props.shouldUnregister &&
|
|
1710
|
+
wasUnsetInFormValues &&
|
|
1711
|
+
!isUndefined(get(_formValues, name)) &&
|
|
1712
|
+
isWatched(name, _names)) {
|
|
1713
|
+
_state.watch = true;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1541
1716
|
}
|
|
1542
1717
|
};
|
|
1543
1718
|
const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
|
|
@@ -1548,16 +1723,22 @@ function createFormControl(props = {}) {
|
|
|
1548
1723
|
};
|
|
1549
1724
|
if (!_options.disabled) {
|
|
1550
1725
|
if (!isBlurEvent || shouldDirty) {
|
|
1726
|
+
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1551
1727
|
if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
|
|
1552
1728
|
isPreviousDirty = _formState.isDirty;
|
|
1553
|
-
_formState.isDirty = output.isDirty =
|
|
1729
|
+
_formState.isDirty = output.isDirty =
|
|
1730
|
+
!isCurrentFieldPristine || _getDirty();
|
|
1554
1731
|
shouldUpdateField = isPreviousDirty !== output.isDirty;
|
|
1555
1732
|
}
|
|
1556
|
-
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1557
1733
|
isPreviousDirty = !!get(_formState.dirtyFields, name);
|
|
1558
|
-
isCurrentFieldPristine
|
|
1559
|
-
|
|
1560
|
-
|
|
1734
|
+
if (isCurrentFieldPristine !== _formState.isDirty) {
|
|
1735
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1736
|
+
}
|
|
1737
|
+
else {
|
|
1738
|
+
isCurrentFieldPristine
|
|
1739
|
+
? unset(_formState.dirtyFields, name)
|
|
1740
|
+
: set(_formState.dirtyFields, name, true);
|
|
1741
|
+
}
|
|
1561
1742
|
output.dirtyFields = _formState.dirtyFields;
|
|
1562
1743
|
shouldUpdateField =
|
|
1563
1744
|
shouldUpdateField ||
|
|
@@ -1596,6 +1777,7 @@ function createFormControl(props = {}) {
|
|
|
1596
1777
|
error
|
|
1597
1778
|
? set(_formState.errors, name, error)
|
|
1598
1779
|
: unset(_formState.errors, name);
|
|
1780
|
+
_formState.errors = { ..._formState.errors };
|
|
1599
1781
|
}
|
|
1600
1782
|
if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
|
|
1601
1783
|
!isEmptyObject(fieldState) ||
|
|
@@ -1615,8 +1797,7 @@ function createFormControl(props = {}) {
|
|
|
1615
1797
|
};
|
|
1616
1798
|
const _runSchema = async (name) => {
|
|
1617
1799
|
_updateIsValidating(name, true);
|
|
1618
|
-
|
|
1619
|
-
return result;
|
|
1800
|
+
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
1620
1801
|
};
|
|
1621
1802
|
const executeSchemaAndUpdateState = async (names) => {
|
|
1622
1803
|
const { errors } = await _runSchema(names);
|
|
@@ -1625,18 +1806,69 @@ function createFormControl(props = {}) {
|
|
|
1625
1806
|
for (const name of names) {
|
|
1626
1807
|
const error = get(errors, name);
|
|
1627
1808
|
error
|
|
1628
|
-
?
|
|
1809
|
+
? _names.array.has(name) &&
|
|
1810
|
+
isObject(error) &&
|
|
1811
|
+
!Object.keys(error).some((key) => !Number.isNaN(Number(key)))
|
|
1812
|
+
? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
|
|
1813
|
+
: set(_formState.errors, name, error)
|
|
1629
1814
|
: unset(_formState.errors, name);
|
|
1630
1815
|
}
|
|
1816
|
+
_formState.errors = { ..._formState.errors };
|
|
1631
1817
|
}
|
|
1632
1818
|
else {
|
|
1633
1819
|
_formState.errors = errors;
|
|
1634
1820
|
}
|
|
1635
1821
|
return errors;
|
|
1636
1822
|
};
|
|
1637
|
-
const
|
|
1823
|
+
const validateForm = async ({ name, eventType, }) => {
|
|
1824
|
+
if (props.validate) {
|
|
1825
|
+
const result = await props.validate({
|
|
1826
|
+
formValues: _formValues,
|
|
1827
|
+
formState: _formState,
|
|
1828
|
+
name,
|
|
1829
|
+
eventType,
|
|
1830
|
+
});
|
|
1831
|
+
if (isObject(result)) {
|
|
1832
|
+
for (const key in result) {
|
|
1833
|
+
const error = result[key];
|
|
1834
|
+
if (error) {
|
|
1835
|
+
setError(`${FORM_ERROR_TYPE}.${key}`, {
|
|
1836
|
+
message: isString(error.message) ? error.message : '',
|
|
1837
|
+
type: error.type || INPUT_VALIDATION_RULES.validate,
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
else if (isString(result) || !result) {
|
|
1843
|
+
setError(FORM_ERROR_TYPE, {
|
|
1844
|
+
message: result || '',
|
|
1845
|
+
type: INPUT_VALIDATION_RULES.validate,
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
else {
|
|
1849
|
+
clearErrors(FORM_ERROR_TYPE);
|
|
1850
|
+
}
|
|
1851
|
+
return result;
|
|
1852
|
+
}
|
|
1853
|
+
return true;
|
|
1854
|
+
};
|
|
1855
|
+
const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
|
|
1638
1856
|
valid: true,
|
|
1639
|
-
|
|
1857
|
+
runRootValidation: false,
|
|
1858
|
+
}, }) => {
|
|
1859
|
+
if (props.validate) {
|
|
1860
|
+
context.runRootValidation = true;
|
|
1861
|
+
const result = await validateForm({
|
|
1862
|
+
name,
|
|
1863
|
+
eventType,
|
|
1864
|
+
});
|
|
1865
|
+
if (!result) {
|
|
1866
|
+
context.valid = false;
|
|
1867
|
+
if (onlyCheckValid) {
|
|
1868
|
+
return context.valid;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1640
1872
|
for (const name in fields) {
|
|
1641
1873
|
const field = fields[name];
|
|
1642
1874
|
if (field) {
|
|
@@ -1644,28 +1876,41 @@ function createFormControl(props = {}) {
|
|
|
1644
1876
|
if (_f) {
|
|
1645
1877
|
const isFieldArrayRoot = _names.array.has(_f.name);
|
|
1646
1878
|
const isPromiseFunction = field._f && hasPromiseValidation(field._f);
|
|
1647
|
-
|
|
1879
|
+
const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
|
|
1880
|
+
_proxyFormState.isValidating ||
|
|
1881
|
+
_proxySubscribeFormState.validatingFields ||
|
|
1882
|
+
_proxySubscribeFormState.isValidating;
|
|
1883
|
+
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1648
1884
|
_updateIsValidating([_f.name], true);
|
|
1649
1885
|
}
|
|
1650
|
-
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !
|
|
1651
|
-
if (isPromiseFunction &&
|
|
1886
|
+
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
|
|
1887
|
+
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1652
1888
|
_updateIsValidating([_f.name]);
|
|
1653
1889
|
}
|
|
1654
1890
|
if (fieldError[_f.name]) {
|
|
1655
1891
|
context.valid = false;
|
|
1656
|
-
if (
|
|
1892
|
+
if (onlyCheckValid) {
|
|
1657
1893
|
break;
|
|
1658
1894
|
}
|
|
1659
1895
|
}
|
|
1660
|
-
!
|
|
1896
|
+
!onlyCheckValid &&
|
|
1661
1897
|
(get(fieldError, _f.name)
|
|
1662
1898
|
? isFieldArrayRoot
|
|
1663
1899
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
1664
1900
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
1665
1901
|
: unset(_formState.errors, _f.name));
|
|
1902
|
+
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
1903
|
+
break;
|
|
1904
|
+
}
|
|
1666
1905
|
}
|
|
1667
1906
|
!isEmptyObject(fieldValue) &&
|
|
1668
|
-
(await executeBuiltInValidation(
|
|
1907
|
+
(await executeBuiltInValidation({
|
|
1908
|
+
context,
|
|
1909
|
+
onlyCheckValid,
|
|
1910
|
+
fields: fieldValue,
|
|
1911
|
+
name: name,
|
|
1912
|
+
eventType,
|
|
1913
|
+
}));
|
|
1669
1914
|
}
|
|
1670
1915
|
}
|
|
1671
1916
|
return context.valid;
|
|
@@ -1683,7 +1928,7 @@ function createFormControl(props = {}) {
|
|
|
1683
1928
|
};
|
|
1684
1929
|
const _getDirty = (name, data) => !_options.disabled &&
|
|
1685
1930
|
(name && data && set(_formValues, name, data),
|
|
1686
|
-
!deepEqual(
|
|
1931
|
+
!deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
|
|
1687
1932
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
1688
1933
|
...(_state.mount
|
|
1689
1934
|
? _formValues
|
|
@@ -1694,7 +1939,7 @@ function createFormControl(props = {}) {
|
|
|
1694
1939
|
: defaultValue),
|
|
1695
1940
|
}, isGlobal, defaultValue);
|
|
1696
1941
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
1697
|
-
const setFieldValue = (name, value, options = {}) => {
|
|
1942
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
|
|
1698
1943
|
const field = get(_fields, name);
|
|
1699
1944
|
let fieldValue = value;
|
|
1700
1945
|
if (field) {
|
|
@@ -1732,20 +1977,20 @@ function createFormControl(props = {}) {
|
|
|
1732
1977
|
}
|
|
1733
1978
|
else {
|
|
1734
1979
|
fieldReference.ref.value = fieldValue;
|
|
1735
|
-
if (!fieldReference.ref.type) {
|
|
1980
|
+
if (!fieldReference.ref.type && !skipRender) {
|
|
1736
1981
|
_subjects.state.next({
|
|
1737
1982
|
name,
|
|
1738
|
-
values: cloneObject(_formValues),
|
|
1983
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1739
1984
|
});
|
|
1740
1985
|
}
|
|
1741
1986
|
}
|
|
1742
1987
|
}
|
|
1743
1988
|
}
|
|
1744
1989
|
(options.shouldDirty || options.shouldTouch) &&
|
|
1745
|
-
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty,
|
|
1990
|
+
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
|
|
1746
1991
|
options.shouldValidate && trigger(name);
|
|
1747
1992
|
};
|
|
1748
|
-
const
|
|
1993
|
+
const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
|
|
1749
1994
|
for (const fieldKey in value) {
|
|
1750
1995
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
1751
1996
|
return;
|
|
@@ -1757,49 +2002,84 @@ function createFormControl(props = {}) {
|
|
|
1757
2002
|
isObject(fieldValue) ||
|
|
1758
2003
|
(field && !field._f)) &&
|
|
1759
2004
|
!isDateObject(fieldValue)
|
|
1760
|
-
?
|
|
1761
|
-
: setFieldValue(fieldName, fieldValue, options);
|
|
2005
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
|
|
2006
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
|
|
1762
2007
|
}
|
|
1763
2008
|
};
|
|
1764
|
-
const
|
|
2009
|
+
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
1765
2010
|
const field = get(_fields, name);
|
|
1766
2011
|
const isFieldArray = _names.array.has(name);
|
|
1767
|
-
const cloneValue = cloneObject(value);
|
|
1768
|
-
|
|
2012
|
+
const cloneValue = skipClone ? value : cloneObject(value);
|
|
2013
|
+
const previousValue = get(_formValues, name);
|
|
2014
|
+
const isValueUnchanged = deepEqual(previousValue, cloneValue);
|
|
2015
|
+
if (!isValueUnchanged) {
|
|
2016
|
+
set(_formValues, name, cloneValue);
|
|
2017
|
+
}
|
|
1769
2018
|
if (isFieldArray) {
|
|
1770
2019
|
_subjects.array.next({
|
|
1771
2020
|
name,
|
|
1772
|
-
values: cloneObject(_formValues),
|
|
2021
|
+
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
1773
2022
|
});
|
|
1774
2023
|
if ((_proxyFormState.isDirty ||
|
|
1775
2024
|
_proxyFormState.dirtyFields ||
|
|
1776
2025
|
_proxySubscribeFormState.isDirty ||
|
|
1777
2026
|
_proxySubscribeFormState.dirtyFields) &&
|
|
1778
2027
|
options.shouldDirty) {
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
2028
|
+
_updateDirtyFields();
|
|
2029
|
+
if (!skipStateEmit) {
|
|
2030
|
+
_subjects.state.next({
|
|
2031
|
+
name,
|
|
2032
|
+
dirtyFields: _formState.dirtyFields,
|
|
2033
|
+
isDirty: _getDirty(name, cloneValue),
|
|
2034
|
+
});
|
|
2035
|
+
}
|
|
1784
2036
|
}
|
|
1785
2037
|
}
|
|
1786
2038
|
else {
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
2039
|
+
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
2040
|
+
isEmptyObject(cloneValue);
|
|
2041
|
+
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
2042
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2043
|
+
}
|
|
2044
|
+
else {
|
|
2045
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2046
|
+
}
|
|
1790
2047
|
}
|
|
1791
|
-
if (
|
|
2048
|
+
if (!isValueUnchanged && !skipStateEmit) {
|
|
2049
|
+
const watched = isWatched(name, _names);
|
|
2050
|
+
const values = skipClone ? _formValues : cloneObject(_formValues);
|
|
1792
2051
|
_subjects.state.next({
|
|
1793
|
-
..._formState,
|
|
1794
|
-
name,
|
|
1795
|
-
values
|
|
2052
|
+
...(watched && _formState),
|
|
2053
|
+
name: _state.mount || watched ? name : undefined,
|
|
2054
|
+
values,
|
|
1796
2055
|
});
|
|
1797
2056
|
}
|
|
1798
|
-
|
|
2057
|
+
};
|
|
2058
|
+
const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
|
|
2059
|
+
const setValues = (formValues, options = {}) => {
|
|
2060
|
+
const updatedFormValues = isFunction(formValues)
|
|
2061
|
+
? formValues(_formValues)
|
|
2062
|
+
: formValues;
|
|
2063
|
+
if (!deepEqual(_formValues, updatedFormValues)) {
|
|
2064
|
+
_formValues = {
|
|
2065
|
+
..._formValues,
|
|
2066
|
+
...updatedFormValues,
|
|
2067
|
+
};
|
|
2068
|
+
const flattenedUpdates = flatten(updatedFormValues);
|
|
2069
|
+
for (const fieldName of _names.mount) {
|
|
2070
|
+
if (fieldName in flattenedUpdates) {
|
|
2071
|
+
_setValue(fieldName, flattenedUpdates[fieldName], options, true, true);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
1799
2074
|
_subjects.state.next({
|
|
1800
|
-
|
|
1801
|
-
|
|
2075
|
+
..._formState,
|
|
2076
|
+
name: undefined,
|
|
2077
|
+
type: undefined,
|
|
2078
|
+
...(_valuesSubscriberCount ? { values: _formValues } : {}),
|
|
1802
2079
|
});
|
|
2080
|
+
if (options.shouldValidate) {
|
|
2081
|
+
_setValid();
|
|
2082
|
+
}
|
|
1803
2083
|
}
|
|
1804
2084
|
};
|
|
1805
2085
|
const onChange = async (event) => {
|
|
@@ -1814,8 +2094,6 @@ function createFormControl(props = {}) {
|
|
|
1814
2094
|
(isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
|
|
1815
2095
|
deepEqual(fieldValue, get(_formValues, name, fieldValue));
|
|
1816
2096
|
};
|
|
1817
|
-
const validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
1818
|
-
const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
1819
2097
|
if (field) {
|
|
1820
2098
|
let error;
|
|
1821
2099
|
let isValid;
|
|
@@ -1823,11 +2101,13 @@ function createFormControl(props = {}) {
|
|
|
1823
2101
|
? getFieldValue(field._f)
|
|
1824
2102
|
: getEventValue(event);
|
|
1825
2103
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
1826
|
-
const
|
|
2104
|
+
const hasNoValidationEffect = !hasValidation(field._f) &&
|
|
2105
|
+
!props.validate &&
|
|
1827
2106
|
!_options.resolver &&
|
|
1828
2107
|
!get(_formState.errors, name) &&
|
|
1829
|
-
!field._f.deps
|
|
1830
|
-
|
|
2108
|
+
!field._f.deps;
|
|
2109
|
+
const shouldSkipValidation = hasNoValidationEffect ||
|
|
2110
|
+
skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
|
|
1831
2111
|
const watched = isWatched(name, _names, isBlurEvent);
|
|
1832
2112
|
set(_formValues, name, fieldValue);
|
|
1833
2113
|
if (isBlurEvent) {
|
|
@@ -1845,10 +2125,13 @@ function createFormControl(props = {}) {
|
|
|
1845
2125
|
_subjects.state.next({
|
|
1846
2126
|
name,
|
|
1847
2127
|
type: event.type,
|
|
1848
|
-
|
|
2128
|
+
...(_valuesSubscriberCount
|
|
2129
|
+
? { values: cloneObject(_formValues) }
|
|
2130
|
+
: {}),
|
|
1849
2131
|
});
|
|
1850
2132
|
if (shouldSkipValidation) {
|
|
1851
|
-
if (
|
|
2133
|
+
if ((!hasNoValidationEffect || !_formState.isValid) &&
|
|
2134
|
+
(_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
|
|
1852
2135
|
if (_options.mode === 'onBlur') {
|
|
1853
2136
|
if (isBlurEvent) {
|
|
1854
2137
|
_setValid();
|
|
@@ -1861,18 +2144,26 @@ function createFormControl(props = {}) {
|
|
|
1861
2144
|
return (shouldRender &&
|
|
1862
2145
|
_subjects.state.next({ name, ...(watched ? {} : fieldState) }));
|
|
1863
2146
|
}
|
|
2147
|
+
if (!_options.resolver && props.validate) {
|
|
2148
|
+
await validateForm({
|
|
2149
|
+
name: name,
|
|
2150
|
+
eventType: event.type,
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
1864
2153
|
!isBlurEvent && watched && _subjects.state.next({ ..._formState });
|
|
1865
2154
|
if (_options.resolver) {
|
|
1866
2155
|
const { errors } = await _runSchema([name]);
|
|
1867
2156
|
_updateIsValidating([name]);
|
|
1868
2157
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1869
|
-
if (isFieldValueUpdated) {
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
error = errorLookupResult.error;
|
|
1873
|
-
name = errorLookupResult.name;
|
|
1874
|
-
isValid = isEmptyObject(errors);
|
|
2158
|
+
if (!isFieldValueUpdated) {
|
|
2159
|
+
!isEmptyObject(fieldState) && _subjects.state.next(fieldState);
|
|
2160
|
+
return;
|
|
1875
2161
|
}
|
|
2162
|
+
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
|
2163
|
+
const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
|
|
2164
|
+
error = errorLookupResult.error;
|
|
2165
|
+
name = errorLookupResult.name;
|
|
2166
|
+
isValid = isEmptyObject(errors);
|
|
1876
2167
|
}
|
|
1877
2168
|
else {
|
|
1878
2169
|
_updateIsValidating([name], true);
|
|
@@ -1885,7 +2176,12 @@ function createFormControl(props = {}) {
|
|
|
1885
2176
|
}
|
|
1886
2177
|
else if (_proxyFormState.isValid ||
|
|
1887
2178
|
_proxySubscribeFormState.isValid) {
|
|
1888
|
-
isValid = await executeBuiltInValidation(
|
|
2179
|
+
isValid = await executeBuiltInValidation({
|
|
2180
|
+
fields: _fields,
|
|
2181
|
+
onlyCheckValid: true,
|
|
2182
|
+
name: name,
|
|
2183
|
+
eventType: event.type,
|
|
2184
|
+
});
|
|
1889
2185
|
}
|
|
1890
2186
|
}
|
|
1891
2187
|
}
|
|
@@ -1918,12 +2214,19 @@ function createFormControl(props = {}) {
|
|
|
1918
2214
|
else if (name) {
|
|
1919
2215
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
1920
2216
|
const field = get(_fields, fieldName);
|
|
1921
|
-
return await executeBuiltInValidation(
|
|
2217
|
+
return await executeBuiltInValidation({
|
|
2218
|
+
fields: field && field._f ? { [fieldName]: field } : field,
|
|
2219
|
+
eventType: EVENTS.TRIGGER,
|
|
2220
|
+
});
|
|
1922
2221
|
}))).every(Boolean);
|
|
1923
2222
|
!(!validationResult && !_formState.isValid) && _setValid();
|
|
1924
2223
|
}
|
|
1925
2224
|
else {
|
|
1926
|
-
validationResult = isValid = await executeBuiltInValidation(
|
|
2225
|
+
validationResult = isValid = await executeBuiltInValidation({
|
|
2226
|
+
fields: _fields,
|
|
2227
|
+
name,
|
|
2228
|
+
eventType: EVENTS.TRIGGER,
|
|
2229
|
+
});
|
|
1927
2230
|
}
|
|
1928
2231
|
_subjects.state.next({
|
|
1929
2232
|
...(!isString(name) ||
|
|
@@ -1960,16 +2263,25 @@ function createFormControl(props = {}) {
|
|
|
1960
2263
|
isTouched: !!get((formState || _formState).touchedFields, name),
|
|
1961
2264
|
});
|
|
1962
2265
|
const clearErrors = (name) => {
|
|
1963
|
-
name
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2266
|
+
const names = name ? convertToArrayPayload(name) : undefined;
|
|
2267
|
+
names?.forEach((inputName) => unset(_formState.errors, inputName));
|
|
2268
|
+
if (names) {
|
|
2269
|
+
names.forEach((inputName) => {
|
|
2270
|
+
_subjects.state.next({
|
|
2271
|
+
name: inputName,
|
|
2272
|
+
errors: _formState.errors,
|
|
2273
|
+
});
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2276
|
+
else {
|
|
2277
|
+
_subjects.state.next({
|
|
2278
|
+
errors: {},
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
1968
2281
|
};
|
|
1969
2282
|
const setError = (name, error, options) => {
|
|
1970
2283
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
1971
2284
|
const currentError = get(_formState.errors, name) || {};
|
|
1972
|
-
// Don't override existing error messages elsewhere in the object tree.
|
|
1973
2285
|
const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
|
|
1974
2286
|
set(_formState.errors, name, {
|
|
1975
2287
|
...restOfErrorTree,
|
|
@@ -1983,20 +2295,59 @@ function createFormControl(props = {}) {
|
|
|
1983
2295
|
});
|
|
1984
2296
|
options && options.shouldFocus && ref && ref.focus && ref.focus();
|
|
1985
2297
|
};
|
|
1986
|
-
const watch = (name, defaultValue) =>
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2298
|
+
const watch = (name, defaultValue) => {
|
|
2299
|
+
if (isFunction(name)) {
|
|
2300
|
+
_valuesSubscriberCount++;
|
|
2301
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
2302
|
+
next: (payload) => 'values' in payload &&
|
|
2303
|
+
name(payload.values || _getWatch(undefined, defaultValue), payload),
|
|
2304
|
+
});
|
|
2305
|
+
let called = false;
|
|
2306
|
+
return {
|
|
2307
|
+
unsubscribe: () => {
|
|
2308
|
+
if (called) {
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2311
|
+
called = true;
|
|
2312
|
+
_valuesSubscriberCount--;
|
|
2313
|
+
unsubscribe();
|
|
2314
|
+
},
|
|
2315
|
+
};
|
|
2316
|
+
}
|
|
2317
|
+
return _getWatch(name, defaultValue, true);
|
|
2318
|
+
};
|
|
2319
|
+
const _subscribe = (props) => {
|
|
2320
|
+
const needsValues = !!props.formState?.values;
|
|
2321
|
+
if (needsValues) {
|
|
2322
|
+
_valuesSubscriberCount++;
|
|
2323
|
+
}
|
|
2324
|
+
const { unsubscribe } = _subjects.state.subscribe({
|
|
2325
|
+
next: (formState) => {
|
|
2326
|
+
if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
|
|
2327
|
+
shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
|
|
2328
|
+
const snapshot = { ..._formValues };
|
|
2329
|
+
props.callback({
|
|
2330
|
+
values: snapshot,
|
|
2331
|
+
..._formState,
|
|
2332
|
+
...formState,
|
|
2333
|
+
defaultValues: _defaultValues,
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
},
|
|
2337
|
+
});
|
|
2338
|
+
if (!needsValues) {
|
|
2339
|
+
return unsubscribe;
|
|
2340
|
+
}
|
|
2341
|
+
let called = false;
|
|
2342
|
+
return () => {
|
|
2343
|
+
if (called) {
|
|
2344
|
+
return;
|
|
1997
2345
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2346
|
+
called = true;
|
|
2347
|
+
_valuesSubscriberCount--;
|
|
2348
|
+
unsubscribe();
|
|
2349
|
+
};
|
|
2350
|
+
};
|
|
2000
2351
|
const subscribe = (props) => {
|
|
2001
2352
|
_state.mount = true;
|
|
2002
2353
|
_proxySubscribeFormState = {
|
|
@@ -2051,6 +2402,7 @@ function createFormControl(props = {}) {
|
|
|
2051
2402
|
const register = (name, options = {}) => {
|
|
2052
2403
|
let field = get(_fields, name);
|
|
2053
2404
|
const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
|
|
2405
|
+
const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
|
|
2054
2406
|
set(_fields, name, {
|
|
2055
2407
|
...(field || {}),
|
|
2056
2408
|
_f: {
|
|
@@ -2061,7 +2413,7 @@ function createFormControl(props = {}) {
|
|
|
2061
2413
|
},
|
|
2062
2414
|
});
|
|
2063
2415
|
_names.mount.add(name);
|
|
2064
|
-
if (field) {
|
|
2416
|
+
if (field && !shouldRevalidateRemount) {
|
|
2065
2417
|
_setDisabledField({
|
|
2066
2418
|
disabled: isBoolean(options.disabled)
|
|
2067
2419
|
? options.disabled
|
|
@@ -2091,7 +2443,9 @@ function createFormControl(props = {}) {
|
|
|
2091
2443
|
onBlur: onChange,
|
|
2092
2444
|
ref: (ref) => {
|
|
2093
2445
|
if (ref) {
|
|
2446
|
+
_names.registerName.add(name);
|
|
2094
2447
|
register(name, options);
|
|
2448
|
+
_names.registerName.delete(name);
|
|
2095
2449
|
field = get(_fields, name);
|
|
2096
2450
|
const fieldRef = isUndefined(ref.value)
|
|
2097
2451
|
? ref.querySelectorAll
|
|
@@ -2135,6 +2489,7 @@ function createFormControl(props = {}) {
|
|
|
2135
2489
|
};
|
|
2136
2490
|
};
|
|
2137
2491
|
const _focusError = () => _options.shouldFocusError &&
|
|
2492
|
+
!_options.shouldUseNativeValidation &&
|
|
2138
2493
|
iterateFieldsByAction(_fields, _focusInput, _names.mount);
|
|
2139
2494
|
const _disableForm = (disabled) => {
|
|
2140
2495
|
if (isBoolean(disabled)) {
|
|
@@ -2170,14 +2525,17 @@ function createFormControl(props = {}) {
|
|
|
2170
2525
|
fieldValues = cloneObject(values);
|
|
2171
2526
|
}
|
|
2172
2527
|
else {
|
|
2173
|
-
await executeBuiltInValidation(
|
|
2528
|
+
await executeBuiltInValidation({
|
|
2529
|
+
fields: _fields,
|
|
2530
|
+
eventType: EVENTS.SUBMIT,
|
|
2531
|
+
});
|
|
2174
2532
|
}
|
|
2175
2533
|
if (_names.disabled.size) {
|
|
2176
2534
|
for (const name of _names.disabled) {
|
|
2177
2535
|
unset(fieldValues, name);
|
|
2178
2536
|
}
|
|
2179
2537
|
}
|
|
2180
|
-
unset(_formState.errors,
|
|
2538
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
2181
2539
|
if (isEmptyObject(_formState.errors)) {
|
|
2182
2540
|
_subjects.state.next({
|
|
2183
2541
|
errors: {},
|
|
@@ -2236,7 +2594,7 @@ function createFormControl(props = {}) {
|
|
|
2236
2594
|
const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
|
|
2237
2595
|
const cloneUpdatedValues = cloneObject(updatedValues);
|
|
2238
2596
|
const isEmptyResetValues = isEmptyObject(formValues);
|
|
2239
|
-
const values =
|
|
2597
|
+
const values = cloneUpdatedValues;
|
|
2240
2598
|
if (!keepStateOptions.keepDefaultValues) {
|
|
2241
2599
|
_defaultValues = updatedValues;
|
|
2242
2600
|
}
|
|
@@ -2285,15 +2643,25 @@ function createFormControl(props = {}) {
|
|
|
2285
2643
|
_fields = {};
|
|
2286
2644
|
}
|
|
2287
2645
|
}
|
|
2288
|
-
|
|
2289
|
-
|
|
2646
|
+
if (_options.shouldUnregister) {
|
|
2647
|
+
_formValues = keepStateOptions.keepDefaultValues
|
|
2290
2648
|
? cloneObject(_defaultValues)
|
|
2291
|
-
: {}
|
|
2292
|
-
|
|
2649
|
+
: {};
|
|
2650
|
+
if (keepStateOptions.keepFieldsRef) {
|
|
2651
|
+
for (const fieldName of _names.mount) {
|
|
2652
|
+
set(_formValues, fieldName, get(values, fieldName));
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
else {
|
|
2657
|
+
_formValues = cloneObject(values);
|
|
2658
|
+
}
|
|
2293
2659
|
_subjects.array.next({
|
|
2294
2660
|
values: { ...values },
|
|
2295
2661
|
});
|
|
2296
2662
|
_subjects.state.next({
|
|
2663
|
+
name: undefined,
|
|
2664
|
+
type: undefined,
|
|
2297
2665
|
values: { ...values },
|
|
2298
2666
|
});
|
|
2299
2667
|
}
|
|
@@ -2301,6 +2669,7 @@ function createFormControl(props = {}) {
|
|
|
2301
2669
|
mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
|
|
2302
2670
|
unMount: new Set(),
|
|
2303
2671
|
array: new Set(),
|
|
2672
|
+
registerName: new Set(),
|
|
2304
2673
|
disabled: new Set(),
|
|
2305
2674
|
watch: new Set(),
|
|
2306
2675
|
watchAll: false,
|
|
@@ -2314,9 +2683,6 @@ function createFormControl(props = {}) {
|
|
|
2314
2683
|
_state.watch = !!_options.shouldUnregister;
|
|
2315
2684
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
2316
2685
|
_state.action = false;
|
|
2317
|
-
// Clear errors synchronously to prevent validation errors on subsequent submissions
|
|
2318
|
-
// This fixes the issue where form.reset() causes validation errors on subsequent
|
|
2319
|
-
// submissions in Next.js 16 with Server Actions
|
|
2320
2686
|
if (!keepStateOptions.keepErrors) {
|
|
2321
2687
|
_formState.errors = {};
|
|
2322
2688
|
}
|
|
@@ -2328,8 +2694,10 @@ function createFormControl(props = {}) {
|
|
|
2328
2694
|
? false
|
|
2329
2695
|
: keepStateOptions.keepDirty
|
|
2330
2696
|
? _formState.isDirty
|
|
2331
|
-
:
|
|
2332
|
-
|
|
2697
|
+
: keepStateOptions.keepValues
|
|
2698
|
+
? _getDirty()
|
|
2699
|
+
: !!(keepStateOptions.keepDefaultValues &&
|
|
2700
|
+
!deepEqual(formValues, _defaultValues)),
|
|
2333
2701
|
isSubmitted: keepStateOptions.keepIsSubmitted
|
|
2334
2702
|
? _formState.isSubmitted
|
|
2335
2703
|
: false,
|
|
@@ -2366,8 +2734,6 @@ function createFormControl(props = {}) {
|
|
|
2366
2734
|
? fieldReference.refs[0]
|
|
2367
2735
|
: fieldReference.ref;
|
|
2368
2736
|
if (fieldRef.focus) {
|
|
2369
|
-
// Use setTimeout to ensure focus happens after any pending state updates
|
|
2370
|
-
// This fixes the issue where setFocus doesn't work immediately after setError
|
|
2371
2737
|
setTimeout(() => {
|
|
2372
2738
|
fieldRef.focus();
|
|
2373
2739
|
options.shouldSelect &&
|
|
@@ -2378,9 +2744,15 @@ function createFormControl(props = {}) {
|
|
|
2378
2744
|
}
|
|
2379
2745
|
};
|
|
2380
2746
|
const _setFormState = (updatedFormState) => {
|
|
2747
|
+
// `name`, `type`, and `values` describe the event that produced this
|
|
2748
|
+
// update, not the form's persisted state (they aren't part of
|
|
2749
|
+
// `FormState`). Merging them in would leak a stale `name`/`type` from
|
|
2750
|
+
// one event into a later, unrelated notification that doesn't specify
|
|
2751
|
+
// its own.
|
|
2752
|
+
const { name, type, values, ...formState } = updatedFormState;
|
|
2381
2753
|
_formState = {
|
|
2382
2754
|
..._formState,
|
|
2383
|
-
...
|
|
2755
|
+
...formState,
|
|
2384
2756
|
};
|
|
2385
2757
|
};
|
|
2386
2758
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
@@ -2390,6 +2762,21 @@ function createFormControl(props = {}) {
|
|
|
2390
2762
|
isLoading: false,
|
|
2391
2763
|
});
|
|
2392
2764
|
});
|
|
2765
|
+
const resetDefaultValues = (values, options = {}) => {
|
|
2766
|
+
_defaultValues = cloneObject(values);
|
|
2767
|
+
if (!options.keepDirty) {
|
|
2768
|
+
const newDirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
2769
|
+
_formState.dirtyFields = newDirtyFields;
|
|
2770
|
+
_formState.isDirty = !isEmptyObject(newDirtyFields);
|
|
2771
|
+
}
|
|
2772
|
+
if (!options.keepIsValid) {
|
|
2773
|
+
_setValid();
|
|
2774
|
+
}
|
|
2775
|
+
_subjects.state.next({
|
|
2776
|
+
..._formState,
|
|
2777
|
+
defaultValues: _defaultValues,
|
|
2778
|
+
});
|
|
2779
|
+
};
|
|
2393
2780
|
const methods = {
|
|
2394
2781
|
control: {
|
|
2395
2782
|
register,
|
|
@@ -2446,6 +2833,8 @@ function createFormControl(props = {}) {
|
|
|
2446
2833
|
..._options,
|
|
2447
2834
|
...value,
|
|
2448
2835
|
};
|
|
2836
|
+
_validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
2837
|
+
_validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
2449
2838
|
},
|
|
2450
2839
|
},
|
|
2451
2840
|
subscribe,
|
|
@@ -2454,9 +2843,11 @@ function createFormControl(props = {}) {
|
|
|
2454
2843
|
handleSubmit,
|
|
2455
2844
|
watch,
|
|
2456
2845
|
setValue,
|
|
2846
|
+
setValues,
|
|
2457
2847
|
getValues,
|
|
2458
2848
|
reset,
|
|
2459
2849
|
resetField,
|
|
2850
|
+
resetDefaultValues,
|
|
2460
2851
|
clearErrors,
|
|
2461
2852
|
unregister,
|
|
2462
2853
|
setError,
|
|
@@ -2577,30 +2968,45 @@ var updateAt = (fieldValues, index, value) => {
|
|
|
2577
2968
|
*/
|
|
2578
2969
|
function useFieldArray(props) {
|
|
2579
2970
|
const formControl = useFormControlContext();
|
|
2580
|
-
const { control = formControl, name, shouldUnregister, rules } = props;
|
|
2971
|
+
const { control = formControl, name, shouldUnregister, rules, disabled, } = props;
|
|
2581
2972
|
const [fields, setFields] = React.useState(control._getFieldArray(name));
|
|
2582
2973
|
const ids = React.useRef(control._getFieldArray(name).map(generateId));
|
|
2583
2974
|
const _actioned = React.useRef(false);
|
|
2584
|
-
|
|
2585
|
-
|
|
2975
|
+
if (!disabled) {
|
|
2976
|
+
control._names.array.add(name);
|
|
2977
|
+
}
|
|
2978
|
+
React.useMemo(() => !disabled &&
|
|
2979
|
+
rules &&
|
|
2586
2980
|
fields.length >= 0 &&
|
|
2587
|
-
control.register(name, rules), [control, name, fields.length, rules]);
|
|
2588
|
-
useIsomorphicLayoutEffect(() =>
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2981
|
+
control.register(name, rules), [control, name, fields.length, rules, disabled]);
|
|
2982
|
+
useIsomorphicLayoutEffect(() => {
|
|
2983
|
+
if (disabled) {
|
|
2984
|
+
return;
|
|
2985
|
+
}
|
|
2986
|
+
return control._subjects.array.subscribe({
|
|
2987
|
+
next: ({ values, name: fieldArrayName, }) => {
|
|
2988
|
+
if (fieldArrayName === name || !fieldArrayName) {
|
|
2989
|
+
const fieldValues = get(values, name);
|
|
2990
|
+
if (Array.isArray(fieldValues)) {
|
|
2991
|
+
setFields(fieldValues);
|
|
2992
|
+
ids.current = fieldValues.map(generateId);
|
|
2993
|
+
}
|
|
2994
|
+
else if (!fieldArrayName) {
|
|
2995
|
+
setFields([]);
|
|
2996
|
+
ids.current = [];
|
|
2997
|
+
}
|
|
2595
2998
|
}
|
|
2596
|
-
}
|
|
2597
|
-
}
|
|
2598
|
-
}
|
|
2999
|
+
},
|
|
3000
|
+
}).unsubscribe;
|
|
3001
|
+
}, [control, name, disabled]);
|
|
2599
3002
|
const updateValues = React.useCallback((updatedFieldArrayValues) => {
|
|
2600
3003
|
_actioned.current = true;
|
|
2601
3004
|
control._setFieldArray(name, updatedFieldArrayValues);
|
|
2602
3005
|
}, [control, name]);
|
|
2603
3006
|
const append = (value, options) => {
|
|
3007
|
+
if (disabled) {
|
|
3008
|
+
return;
|
|
3009
|
+
}
|
|
2604
3010
|
const appendValue = convertToArrayPayload(cloneObject(value));
|
|
2605
3011
|
const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
|
|
2606
3012
|
control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
|
|
@@ -2612,6 +3018,9 @@ function useFieldArray(props) {
|
|
|
2612
3018
|
});
|
|
2613
3019
|
};
|
|
2614
3020
|
const prepend = (value, options) => {
|
|
3021
|
+
if (disabled) {
|
|
3022
|
+
return;
|
|
3023
|
+
}
|
|
2615
3024
|
const prependValue = convertToArrayPayload(cloneObject(value));
|
|
2616
3025
|
const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
|
|
2617
3026
|
control._names.focus = getFocusFieldName(name, 0, options);
|
|
@@ -2623,6 +3032,9 @@ function useFieldArray(props) {
|
|
|
2623
3032
|
});
|
|
2624
3033
|
};
|
|
2625
3034
|
const remove = (index) => {
|
|
3035
|
+
if (disabled) {
|
|
3036
|
+
return;
|
|
3037
|
+
}
|
|
2626
3038
|
const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
|
|
2627
3039
|
ids.current = removeArrayAt(ids.current, index);
|
|
2628
3040
|
updateValues(updatedFieldArrayValues);
|
|
@@ -2634,6 +3046,9 @@ function useFieldArray(props) {
|
|
|
2634
3046
|
});
|
|
2635
3047
|
};
|
|
2636
3048
|
const insert$1 = (index, value, options) => {
|
|
3049
|
+
if (disabled) {
|
|
3050
|
+
return;
|
|
3051
|
+
}
|
|
2637
3052
|
const insertValue = convertToArrayPayload(cloneObject(value));
|
|
2638
3053
|
const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
|
|
2639
3054
|
control._names.focus = getFocusFieldName(name, index, options);
|
|
@@ -2646,6 +3061,9 @@ function useFieldArray(props) {
|
|
|
2646
3061
|
});
|
|
2647
3062
|
};
|
|
2648
3063
|
const swap = (indexA, indexB) => {
|
|
3064
|
+
if (disabled) {
|
|
3065
|
+
return;
|
|
3066
|
+
}
|
|
2649
3067
|
const updatedFieldArrayValues = control._getFieldArray(name);
|
|
2650
3068
|
swapArrayAt(updatedFieldArrayValues, indexA, indexB);
|
|
2651
3069
|
swapArrayAt(ids.current, indexA, indexB);
|
|
@@ -2657,6 +3075,9 @@ function useFieldArray(props) {
|
|
|
2657
3075
|
}, false);
|
|
2658
3076
|
};
|
|
2659
3077
|
const move = (from, to) => {
|
|
3078
|
+
if (disabled) {
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
2660
3081
|
const updatedFieldArrayValues = control._getFieldArray(name);
|
|
2661
3082
|
moveArrayAt(updatedFieldArrayValues, from, to);
|
|
2662
3083
|
moveArrayAt(ids.current, from, to);
|
|
@@ -2668,6 +3089,9 @@ function useFieldArray(props) {
|
|
|
2668
3089
|
}, false);
|
|
2669
3090
|
};
|
|
2670
3091
|
const update = (index, value) => {
|
|
3092
|
+
if (disabled) {
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
2671
3095
|
const updateValue = cloneObject(value);
|
|
2672
3096
|
const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
|
|
2673
3097
|
ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
|
|
@@ -2679,6 +3103,9 @@ function useFieldArray(props) {
|
|
|
2679
3103
|
}, true, false);
|
|
2680
3104
|
};
|
|
2681
3105
|
const replace = (value) => {
|
|
3106
|
+
if (disabled) {
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
2682
3109
|
const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
|
|
2683
3110
|
ids.current = updatedFieldArrayValues.map(generateId);
|
|
2684
3111
|
updateValues([...updatedFieldArrayValues]);
|
|
@@ -2686,29 +3113,42 @@ function useFieldArray(props) {
|
|
|
2686
3113
|
control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
|
|
2687
3114
|
};
|
|
2688
3115
|
React.useEffect(() => {
|
|
3116
|
+
if (disabled) {
|
|
3117
|
+
return;
|
|
3118
|
+
}
|
|
2689
3119
|
control._state.action = false;
|
|
2690
3120
|
isWatched(name, control._names) &&
|
|
2691
3121
|
control._subjects.state.next({
|
|
2692
3122
|
...control._formState,
|
|
2693
3123
|
});
|
|
3124
|
+
const validationModes = getValidationModes(control._options.mode);
|
|
2694
3125
|
if (_actioned.current &&
|
|
2695
|
-
(!
|
|
2696
|
-
|
|
2697
|
-
!
|
|
3126
|
+
(!validationModes.isOnSubmit || control._formState.isSubmitted) &&
|
|
3127
|
+
!getValidationModes(control._options.reValidateMode).isOnSubmit &&
|
|
3128
|
+
!validationModes.isOnBlur) {
|
|
2698
3129
|
if (control._options.resolver) {
|
|
2699
3130
|
control._runSchema([name]).then((result) => {
|
|
2700
3131
|
control._updateIsValidating([name]);
|
|
2701
3132
|
const error = get(result.errors, name);
|
|
2702
3133
|
const existingError = get(control._formState.errors, name);
|
|
3134
|
+
const existingErrorType = existingError && (existingError.type || existingError.root?.type);
|
|
3135
|
+
const existingErrorMessage = existingError &&
|
|
3136
|
+
(existingError.message || existingError.root?.message);
|
|
2703
3137
|
if (existingError
|
|
2704
|
-
? (!error &&
|
|
3138
|
+
? (!error && existingErrorType) ||
|
|
2705
3139
|
(error &&
|
|
2706
|
-
(
|
|
2707
|
-
|
|
3140
|
+
(existingErrorType !== error.type ||
|
|
3141
|
+
existingErrorMessage !== error.message))
|
|
2708
3142
|
: error && error.type) {
|
|
2709
|
-
error
|
|
2710
|
-
|
|
2711
|
-
|
|
3143
|
+
if (error) {
|
|
3144
|
+
isObject(error) &&
|
|
3145
|
+
!Object.keys(error).some((key) => !Number.isNaN(+key))
|
|
3146
|
+
? updateFieldArrayRootError(control._formState.errors, { [name]: error }, name)
|
|
3147
|
+
: set(control._formState.errors, name, error);
|
|
3148
|
+
}
|
|
3149
|
+
else {
|
|
3150
|
+
unset(control._formState.errors, name);
|
|
3151
|
+
}
|
|
2712
3152
|
control._subjects.state.next({
|
|
2713
3153
|
errors: control._formState.errors,
|
|
2714
3154
|
});
|
|
@@ -2728,10 +3168,14 @@ function useFieldArray(props) {
|
|
|
2728
3168
|
}
|
|
2729
3169
|
}
|
|
2730
3170
|
}
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
3171
|
+
// External updates that change `fields` (e.g. reset() or setValue() on
|
|
3172
|
+
// the array) already notify subscribers with the up-to-date values
|
|
3173
|
+
// themselves, so only re-broadcast here for genuine array method calls.
|
|
3174
|
+
_actioned.current &&
|
|
3175
|
+
control._subjects.state.next({
|
|
3176
|
+
name,
|
|
3177
|
+
values: cloneObject(control._formValues),
|
|
3178
|
+
});
|
|
2735
3179
|
control._names.focus &&
|
|
2736
3180
|
iterateFieldsByAction(control._fields, (ref, key) => {
|
|
2737
3181
|
if (control._names.focus &&
|
|
@@ -2745,34 +3189,57 @@ function useFieldArray(props) {
|
|
|
2745
3189
|
control._names.focus = '';
|
|
2746
3190
|
control._setValid();
|
|
2747
3191
|
_actioned.current = false;
|
|
2748
|
-
}, [fields, name, control]);
|
|
3192
|
+
}, [fields, name, control, disabled]);
|
|
2749
3193
|
React.useEffect(() => {
|
|
2750
|
-
!
|
|
3194
|
+
if (!disabled) {
|
|
3195
|
+
!get(control._formValues, name) && control._setFieldArray(name);
|
|
3196
|
+
}
|
|
2751
3197
|
return () => {
|
|
3198
|
+
if (disabled) {
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
|
|
2752
3202
|
const updateMounted = (name, value) => {
|
|
2753
3203
|
const field = get(control._fields, name);
|
|
2754
3204
|
if (field && field._f) {
|
|
2755
3205
|
field._f.mount = value;
|
|
2756
3206
|
}
|
|
2757
3207
|
};
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
3208
|
+
if (_actioned.current && shouldKeepFieldArrayValues) {
|
|
3209
|
+
control._subjects.state.next({
|
|
3210
|
+
name,
|
|
3211
|
+
values: cloneObject(control._formValues),
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
3214
|
+
shouldKeepFieldArrayValues
|
|
3215
|
+
? updateMounted(name, false)
|
|
3216
|
+
: control.unregister(name);
|
|
2761
3217
|
};
|
|
2762
|
-
}, [name, control, shouldUnregister]);
|
|
3218
|
+
}, [name, control, shouldUnregister, disabled]);
|
|
2763
3219
|
return {
|
|
2764
|
-
swap: React.useCallback(swap, [updateValues, name, control]),
|
|
2765
|
-
move: React.useCallback(move, [updateValues, name, control]),
|
|
2766
|
-
prepend: React.useCallback(prepend, [
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
3220
|
+
swap: React.useCallback(swap, [updateValues, name, control, disabled]),
|
|
3221
|
+
move: React.useCallback(move, [updateValues, name, control, disabled]),
|
|
3222
|
+
prepend: React.useCallback(prepend, [
|
|
3223
|
+
updateValues,
|
|
3224
|
+
name,
|
|
3225
|
+
control,
|
|
3226
|
+
disabled,
|
|
3227
|
+
]),
|
|
3228
|
+
append: React.useCallback(append, [updateValues, name, control, disabled]),
|
|
3229
|
+
remove: React.useCallback(remove, [updateValues, name, control, disabled]),
|
|
3230
|
+
insert: React.useCallback(insert$1, [updateValues, name, control, disabled]),
|
|
3231
|
+
update: React.useCallback(update, [updateValues, name, control, disabled]),
|
|
3232
|
+
replace: React.useCallback(replace, [
|
|
3233
|
+
updateValues,
|
|
3234
|
+
name,
|
|
3235
|
+
control,
|
|
3236
|
+
disabled,
|
|
3237
|
+
]),
|
|
2772
3238
|
fields: React.useMemo(() => fields.map((field, index) => ({
|
|
2773
3239
|
...field,
|
|
3240
|
+
...(isBoolean(disabled) ? { disabled } : {}),
|
|
2774
3241
|
key: ids.current[index] || generateId(),
|
|
2775
|
-
})), [fields]),
|
|
3242
|
+
})), [fields, disabled]),
|
|
2776
3243
|
};
|
|
2777
3244
|
}
|
|
2778
3245
|
|
|
@@ -2819,26 +3286,19 @@ function updateMethodsReference(_formControl) {
|
|
|
2819
3286
|
function useForm(props = {}) {
|
|
2820
3287
|
const _formControl = React.useRef(undefined);
|
|
2821
3288
|
const _values = React.useRef(undefined);
|
|
2822
|
-
const
|
|
2823
|
-
|
|
2824
|
-
|
|
3289
|
+
const _formControlProp = React.useRef(props.formControl);
|
|
3290
|
+
const [formState, updateFormState] = React.useState(() => ({
|
|
3291
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
2825
3292
|
isLoading: isFunction(props.defaultValues),
|
|
2826
|
-
isSubmitted: false,
|
|
2827
|
-
isSubmitting: false,
|
|
2828
|
-
isSubmitSuccessful: false,
|
|
2829
|
-
isValid: false,
|
|
2830
|
-
submitCount: 0,
|
|
2831
|
-
dirtyFields: {},
|
|
2832
|
-
touchedFields: {},
|
|
2833
|
-
validatingFields: {},
|
|
2834
3293
|
errors: props.errors || {},
|
|
2835
3294
|
disabled: props.disabled || false,
|
|
2836
|
-
isReady: false,
|
|
2837
3295
|
defaultValues: isFunction(props.defaultValues)
|
|
2838
3296
|
? undefined
|
|
2839
3297
|
: props.defaultValues,
|
|
2840
|
-
});
|
|
2841
|
-
if (!_formControl.current
|
|
3298
|
+
}));
|
|
3299
|
+
if (!_formControl.current ||
|
|
3300
|
+
(props.formControl && _formControlProp.current !== props.formControl)) {
|
|
3301
|
+
_formControlProp.current = props.formControl;
|
|
2842
3302
|
if (props.formControl) {
|
|
2843
3303
|
_formControl.current = {
|
|
2844
3304
|
...props.formControl,
|
|
@@ -2861,7 +3321,10 @@ function useForm(props = {}) {
|
|
|
2861
3321
|
useIsomorphicLayoutEffect(() => {
|
|
2862
3322
|
const sub = control._subscribe({
|
|
2863
3323
|
formState: control._proxyFormState,
|
|
2864
|
-
callback: () => updateFormState({
|
|
3324
|
+
callback: () => updateFormState({
|
|
3325
|
+
...control._formState,
|
|
3326
|
+
defaultValues: control._defaultValues,
|
|
3327
|
+
}),
|
|
2865
3328
|
reRenderRoot: true,
|
|
2866
3329
|
});
|
|
2867
3330
|
updateFormState((data) => ({
|
|
@@ -2903,14 +3366,13 @@ function useForm(props = {}) {
|
|
|
2903
3366
|
}
|
|
2904
3367
|
}, [control, formState.isDirty]);
|
|
2905
3368
|
React.useEffect(() => {
|
|
2906
|
-
var _a;
|
|
2907
3369
|
if (props.values && !deepEqual(props.values, _values.current)) {
|
|
2908
3370
|
updateMethodsReference(_formControl);
|
|
2909
3371
|
control._reset(props.values, {
|
|
2910
3372
|
keepFieldsRef: true,
|
|
2911
3373
|
...control._options.resetOptions,
|
|
2912
3374
|
});
|
|
2913
|
-
if (!
|
|
3375
|
+
if (!control._options.resetOptions?.keepIsValid) {
|
|
2914
3376
|
control._setValid();
|
|
2915
3377
|
}
|
|
2916
3378
|
_values.current = props.values;
|