react-hook-form 8.0.0-beta.0 → 8.0.0-beta.2
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 -29
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -1
- 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 +541 -217
- 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/{isNameInFieldArray.d.ts → getFieldArrayParentNames.d.ts} +2 -2
- package/dist/logic/getFieldArrayParentNames.d.ts.map +1 -0
- 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/logic/updateFieldArrayRootError.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +362 -92
- 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 +1 -2
- package/dist/types/fieldArray.d.ts.map +1 -1
- package/dist/types/form.d.ts +14 -41
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.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 +5 -4
- 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/types/watch.d.ts +32 -0
- package/dist/types/watch.d.ts.map +1 -0
- package/dist/useController.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts +2 -2
- 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/useFormControlContext.d.ts +12 -0
- package/dist/useFormControlContext.d.ts.map +1 -0
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useWatch.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/unset.d.ts.map +1 -1
- package/dist/watch.d.ts +7 -17
- package/dist/watch.d.ts.map +1 -1
- package/package.json +29 -29
- package/dist/logic/isNameInFieldArray.d.ts.map +0 -1
package/dist/index.esm.mjs
CHANGED
|
@@ -18,9 +18,15 @@ var getEventValue = (event) => isObject(event) && event.target
|
|
|
18
18
|
: event.target.value
|
|
19
19
|
: event;
|
|
20
20
|
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
var getFieldArrayParentNames = (names, name) => {
|
|
22
|
+
const parts = name.split('.');
|
|
23
|
+
const matches = [];
|
|
24
|
+
let prefix = parts[0];
|
|
25
|
+
for (let i = 1; i < parts.length; prefix += '.' + parts[i++]) {
|
|
26
|
+
!isNaN(+parts[i]) && names.has(prefix) && matches.push(prefix);
|
|
27
|
+
}
|
|
28
|
+
return matches;
|
|
29
|
+
};
|
|
24
30
|
|
|
25
31
|
var isPlainObject = (tempObject) => {
|
|
26
32
|
const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
|
|
@@ -64,7 +70,10 @@ var get = (object, path, defaultValue) => {
|
|
|
64
70
|
if (!path || !isObject(object)) {
|
|
65
71
|
return defaultValue;
|
|
66
72
|
}
|
|
67
|
-
const
|
|
73
|
+
const paths = isKey(path) ? [path] : stringToPath(path);
|
|
74
|
+
const result = paths.reduce((result, key) => {
|
|
75
|
+
return isNullOrUndefined(result) ? undefined : result[key];
|
|
76
|
+
}, object);
|
|
68
77
|
return isUndefined(result) || result === object
|
|
69
78
|
? isUndefined(object[path])
|
|
70
79
|
? defaultValue
|
|
@@ -103,6 +112,9 @@ const EVENTS = {
|
|
|
103
112
|
BLUR: 'blur',
|
|
104
113
|
FOCUS_OUT: 'focusout',
|
|
105
114
|
CHANGE: 'change',
|
|
115
|
+
SUBMIT: 'submit',
|
|
116
|
+
TRIGGER: 'trigger',
|
|
117
|
+
VALID: 'valid',
|
|
106
118
|
};
|
|
107
119
|
const VALIDATION_MODE = {
|
|
108
120
|
onBlur: 'onBlur',
|
|
@@ -120,80 +132,22 @@ const INPUT_VALIDATION_RULES = {
|
|
|
120
132
|
required: 'required',
|
|
121
133
|
validate: 'validate',
|
|
122
134
|
};
|
|
135
|
+
const FORM_ERROR_TYPE = 'form';
|
|
136
|
+
const ROOT_ERROR_TYPE = 'root';
|
|
123
137
|
|
|
124
|
-
const HookFormContext = React.createContext(null);
|
|
125
|
-
HookFormContext.displayName = 'HookFormContext';
|
|
126
138
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* @remarks
|
|
130
|
-
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
131
|
-
*
|
|
132
|
-
* @returns return all useForm methods
|
|
133
|
-
*
|
|
134
|
-
* @example
|
|
135
|
-
* ```tsx
|
|
136
|
-
* function App() {
|
|
137
|
-
* const methods = useForm();
|
|
138
|
-
* const onSubmit = data => console.log(data);
|
|
139
|
-
*
|
|
140
|
-
* return (
|
|
141
|
-
* <FormProvider {...methods} >
|
|
142
|
-
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
143
|
-
* <NestedInput />
|
|
144
|
-
* <input type="submit" />
|
|
145
|
-
* </form>
|
|
146
|
-
* </FormProvider>
|
|
147
|
-
* );
|
|
148
|
-
* }
|
|
149
|
-
*
|
|
150
|
-
* function NestedInput() {
|
|
151
|
-
* const { register } = useFormContext(); // retrieve all hook methods
|
|
152
|
-
* return <input {...register("test")} />;
|
|
153
|
-
* }
|
|
154
|
-
* ```
|
|
139
|
+
* Separate context for `control` to prevent unnecessary rerenders.
|
|
140
|
+
* Internal hooks that only need control use this instead of full form context.
|
|
155
141
|
*/
|
|
156
|
-
const
|
|
142
|
+
const HookFormControlContext = React.createContext(null);
|
|
143
|
+
HookFormControlContext.displayName = 'HookFormControlContext';
|
|
157
144
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* @remarks
|
|
161
|
-
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
162
|
-
*
|
|
163
|
-
* @param props - all useForm methods
|
|
164
|
-
*
|
|
165
|
-
* @example
|
|
166
|
-
* ```tsx
|
|
167
|
-
* function App() {
|
|
168
|
-
* const methods = useForm();
|
|
169
|
-
* const onSubmit = data => console.log(data);
|
|
170
|
-
*
|
|
171
|
-
* return (
|
|
172
|
-
* <FormProvider {...methods} >
|
|
173
|
-
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
174
|
-
* <NestedInput />
|
|
175
|
-
* <input type="submit" />
|
|
176
|
-
* </form>
|
|
177
|
-
* </FormProvider>
|
|
178
|
-
* );
|
|
179
|
-
* }
|
|
180
|
-
*
|
|
181
|
-
* function NestedInput() {
|
|
182
|
-
* const { register } = useFormContext(); // retrieve all hook methods
|
|
183
|
-
* return <input {...register("test")} />;
|
|
184
|
-
* }
|
|
185
|
-
* ```
|
|
145
|
+
* @internal Internal hook to access only control from context.
|
|
186
146
|
*/
|
|
187
|
-
const
|
|
188
|
-
const { children, ...data } = props;
|
|
189
|
-
return (React.createElement(HookFormContext.Provider, { value: data }, children));
|
|
190
|
-
};
|
|
147
|
+
const useFormControlContext = () => React.useContext(HookFormControlContext);
|
|
191
148
|
|
|
192
149
|
var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
|
|
193
|
-
const result = {
|
|
194
|
-
...formState,
|
|
195
|
-
defaultValues: control._defaultValues,
|
|
196
|
-
};
|
|
150
|
+
const result = {};
|
|
197
151
|
for (const key in formState) {
|
|
198
152
|
Object.defineProperty(result, key, {
|
|
199
153
|
get: () => {
|
|
@@ -242,9 +196,12 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayou
|
|
|
242
196
|
* ```
|
|
243
197
|
*/
|
|
244
198
|
function useFormState(props) {
|
|
245
|
-
const
|
|
246
|
-
const { control =
|
|
247
|
-
const [formState, updateFormState] = React.useState(
|
|
199
|
+
const formControl = useFormControlContext();
|
|
200
|
+
const { control = formControl, disabled, name, exact } = props || {};
|
|
201
|
+
const [formState, updateFormState] = React.useState(() => ({
|
|
202
|
+
...control._formState,
|
|
203
|
+
defaultValues: control._defaultValues,
|
|
204
|
+
}));
|
|
248
205
|
const _localProxyFormState = React.useRef({
|
|
249
206
|
isDirty: false,
|
|
250
207
|
isLoading: false,
|
|
@@ -264,6 +221,7 @@ function useFormState(props) {
|
|
|
264
221
|
updateFormState({
|
|
265
222
|
...control._formState,
|
|
266
223
|
...formState,
|
|
224
|
+
defaultValues: control._defaultValues,
|
|
267
225
|
});
|
|
268
226
|
},
|
|
269
227
|
}), [name, disabled, exact]);
|
|
@@ -290,34 +248,37 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
290
248
|
|
|
291
249
|
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
292
250
|
|
|
293
|
-
function deepEqual(object1, object2,
|
|
251
|
+
function deepEqual(object1, object2, visited = new WeakSet()) {
|
|
252
|
+
if (object1 === object2) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
294
255
|
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
295
256
|
return Object.is(object1, object2);
|
|
296
257
|
}
|
|
297
258
|
if (isDateObject(object1) && isDateObject(object2)) {
|
|
298
|
-
return object1.getTime()
|
|
259
|
+
return Object.is(object1.getTime(), object2.getTime());
|
|
299
260
|
}
|
|
300
261
|
const keys1 = Object.keys(object1);
|
|
301
262
|
const keys2 = Object.keys(object2);
|
|
302
263
|
if (keys1.length !== keys2.length) {
|
|
303
264
|
return false;
|
|
304
265
|
}
|
|
305
|
-
if (
|
|
266
|
+
if (visited.has(object1) || visited.has(object2)) {
|
|
306
267
|
return true;
|
|
307
268
|
}
|
|
308
|
-
|
|
309
|
-
|
|
269
|
+
visited.add(object1);
|
|
270
|
+
visited.add(object2);
|
|
310
271
|
for (const key of keys1) {
|
|
311
272
|
const val1 = object1[key];
|
|
312
|
-
if (!
|
|
273
|
+
if (!(key in object2)) {
|
|
313
274
|
return false;
|
|
314
275
|
}
|
|
315
276
|
if (key !== 'ref') {
|
|
316
277
|
const val2 = object2[key];
|
|
317
278
|
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
318
|
-
(isObject(val1)
|
|
319
|
-
|
|
320
|
-
? !deepEqual(val1, val2,
|
|
279
|
+
((isObject(val1) || Array.isArray(val1)) &&
|
|
280
|
+
(isObject(val2) || Array.isArray(val2)))
|
|
281
|
+
? !deepEqual(val1, val2, visited)
|
|
321
282
|
: !Object.is(val1, val2)) {
|
|
322
283
|
return false;
|
|
323
284
|
}
|
|
@@ -343,8 +304,8 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
|
|
|
343
304
|
* ```
|
|
344
305
|
*/
|
|
345
306
|
function useWatch(props) {
|
|
346
|
-
const
|
|
347
|
-
const { control =
|
|
307
|
+
const formControl = useFormControlContext();
|
|
308
|
+
const { control = formControl, name, defaultValue, disabled, exact, compute, } = props || {};
|
|
348
309
|
const _defaultValue = React.useRef(defaultValue);
|
|
349
310
|
const _compute = React.useRef(compute);
|
|
350
311
|
const _computeFormValues = React.useRef(undefined);
|
|
@@ -437,9 +398,10 @@ function useWatch(props) {
|
|
|
437
398
|
* ```
|
|
438
399
|
*/
|
|
439
400
|
function useController(props) {
|
|
440
|
-
const
|
|
441
|
-
const { name, disabled, control =
|
|
442
|
-
const isArrayField =
|
|
401
|
+
const formControl = useFormControlContext();
|
|
402
|
+
const { name, disabled, control = formControl, shouldUnregister, defaultValue, exact = true, } = props;
|
|
403
|
+
const isArrayField = !!getFieldArrayParentNames(control._names.array, name)
|
|
404
|
+
.length;
|
|
443
405
|
const defaultValueMemo = React.useMemo(() => get(control._formValues, name, get(control._defaultValues, name, defaultValue)), [control, name, defaultValue]);
|
|
444
406
|
const value = useWatch({
|
|
445
407
|
control,
|
|
@@ -453,7 +415,6 @@ function useController(props) {
|
|
|
453
415
|
exact,
|
|
454
416
|
});
|
|
455
417
|
const _props = React.useRef(props);
|
|
456
|
-
const _previousNameRef = React.useRef(undefined);
|
|
457
418
|
const _registerProps = React.useRef(control.register(name, {
|
|
458
419
|
...props.rules,
|
|
459
420
|
value,
|
|
@@ -498,13 +459,8 @@ function useController(props) {
|
|
|
498
459
|
}), [name, control._formValues]);
|
|
499
460
|
const ref = React.useCallback((elm) => {
|
|
500
461
|
const field = get(control._fields, name);
|
|
501
|
-
if (field && elm) {
|
|
502
|
-
field._f.ref =
|
|
503
|
-
focus: () => elm.focus && elm.focus(),
|
|
504
|
-
select: () => elm.select && elm.select(),
|
|
505
|
-
setCustomValidity: (message) => elm.setCustomValidity(message),
|
|
506
|
-
reportValidity: () => elm.reportValidity(),
|
|
507
|
-
};
|
|
462
|
+
if (field && field._f && elm) {
|
|
463
|
+
field._f.ref = elm;
|
|
508
464
|
}
|
|
509
465
|
}, [control._fields, name]);
|
|
510
466
|
const field = React.useMemo(() => ({
|
|
@@ -519,10 +475,6 @@ function useController(props) {
|
|
|
519
475
|
}), [name, disabled, formState.disabled, onChange, onBlur, ref, value]);
|
|
520
476
|
React.useEffect(() => {
|
|
521
477
|
const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
|
|
522
|
-
const previousName = _previousNameRef.current;
|
|
523
|
-
if (previousName && previousName !== name && !isArrayField) {
|
|
524
|
-
control.unregister(previousName);
|
|
525
|
-
}
|
|
526
478
|
control.register(name, {
|
|
527
479
|
..._props.current.rules,
|
|
528
480
|
...(isBoolean(_props.current.disabled)
|
|
@@ -537,14 +489,13 @@ function useController(props) {
|
|
|
537
489
|
};
|
|
538
490
|
updateMounted(name, true);
|
|
539
491
|
if (_shouldUnregisterField) {
|
|
540
|
-
const value = cloneObject(get(control._options.defaultValues, name, _props.current.defaultValue));
|
|
492
|
+
const value = cloneObject(get(control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
|
|
541
493
|
set(control._defaultValues, name, value);
|
|
542
494
|
if (isUndefined(get(control._formValues, name))) {
|
|
543
495
|
set(control._formValues, name, value);
|
|
544
496
|
}
|
|
545
497
|
}
|
|
546
498
|
!isArrayField && control.register(name);
|
|
547
|
-
_previousNameRef.current = name;
|
|
548
499
|
return () => {
|
|
549
500
|
(isArrayField
|
|
550
501
|
? _shouldUnregisterField && !control._state.action
|
|
@@ -626,6 +577,112 @@ const flatten = (obj) => {
|
|
|
626
577
|
return output;
|
|
627
578
|
};
|
|
628
579
|
|
|
580
|
+
const HookFormContext = React.createContext(null);
|
|
581
|
+
HookFormContext.displayName = 'HookFormContext';
|
|
582
|
+
/**
|
|
583
|
+
* This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
|
|
584
|
+
*
|
|
585
|
+
* @remarks
|
|
586
|
+
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
587
|
+
*
|
|
588
|
+
* @returns return all useForm methods
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```tsx
|
|
592
|
+
* function App() {
|
|
593
|
+
* const methods = useForm();
|
|
594
|
+
* const onSubmit = data => console.log(data);
|
|
595
|
+
*
|
|
596
|
+
* return (
|
|
597
|
+
* <FormProvider {...methods} >
|
|
598
|
+
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
599
|
+
* <NestedInput />
|
|
600
|
+
* <input type="submit" />
|
|
601
|
+
* </form>
|
|
602
|
+
* </FormProvider>
|
|
603
|
+
* );
|
|
604
|
+
* }
|
|
605
|
+
*
|
|
606
|
+
* function NestedInput() {
|
|
607
|
+
* const { register } = useFormContext(); // retrieve all hook methods
|
|
608
|
+
* return <input {...register("test")} />;
|
|
609
|
+
* }
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
const useFormContext = () => React.useContext(HookFormContext);
|
|
613
|
+
/**
|
|
614
|
+
* A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
|
|
615
|
+
*
|
|
616
|
+
* @remarks
|
|
617
|
+
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
618
|
+
*
|
|
619
|
+
* @param props - all useForm methods
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```tsx
|
|
623
|
+
* function App() {
|
|
624
|
+
* const methods = useForm();
|
|
625
|
+
* const onSubmit = data => console.log(data);
|
|
626
|
+
*
|
|
627
|
+
* return (
|
|
628
|
+
* <FormProvider {...methods} >
|
|
629
|
+
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
630
|
+
* <NestedInput />
|
|
631
|
+
* <input type="submit" />
|
|
632
|
+
* </form>
|
|
633
|
+
* </FormProvider>
|
|
634
|
+
* );
|
|
635
|
+
* }
|
|
636
|
+
*
|
|
637
|
+
* function NestedInput() {
|
|
638
|
+
* const { register } = useFormContext(); // retrieve all hook methods
|
|
639
|
+
* return <input {...register("test")} />;
|
|
640
|
+
* }
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
const FormProvider = (props) => {
|
|
644
|
+
const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
|
|
645
|
+
const memoizedValue = React.useMemo(() => ({
|
|
646
|
+
watch,
|
|
647
|
+
getValues,
|
|
648
|
+
getFieldState,
|
|
649
|
+
setError,
|
|
650
|
+
clearErrors,
|
|
651
|
+
setValue,
|
|
652
|
+
setValues,
|
|
653
|
+
trigger,
|
|
654
|
+
formState,
|
|
655
|
+
resetField,
|
|
656
|
+
reset,
|
|
657
|
+
handleSubmit,
|
|
658
|
+
unregister,
|
|
659
|
+
control,
|
|
660
|
+
register,
|
|
661
|
+
setFocus,
|
|
662
|
+
subscribe,
|
|
663
|
+
}), [
|
|
664
|
+
clearErrors,
|
|
665
|
+
control,
|
|
666
|
+
formState,
|
|
667
|
+
getFieldState,
|
|
668
|
+
getValues,
|
|
669
|
+
handleSubmit,
|
|
670
|
+
register,
|
|
671
|
+
reset,
|
|
672
|
+
resetField,
|
|
673
|
+
setError,
|
|
674
|
+
setFocus,
|
|
675
|
+
setValue,
|
|
676
|
+
setValues,
|
|
677
|
+
subscribe,
|
|
678
|
+
trigger,
|
|
679
|
+
unregister,
|
|
680
|
+
watch,
|
|
681
|
+
]);
|
|
682
|
+
return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
|
|
683
|
+
React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
|
|
684
|
+
};
|
|
685
|
+
|
|
629
686
|
const POST_REQUEST = 'post';
|
|
630
687
|
/**
|
|
631
688
|
* Form component to manage submission.
|
|
@@ -653,7 +710,7 @@ function Form(props) {
|
|
|
653
710
|
const methods = useFormContext();
|
|
654
711
|
const [mounted, setMounted] = React.useState(false);
|
|
655
712
|
const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
|
|
656
|
-
const submit = async (event) => {
|
|
713
|
+
const submit = React.useCallback(async (event) => {
|
|
657
714
|
let hasError = false;
|
|
658
715
|
let type = '';
|
|
659
716
|
await control.handleSubmit(async (data) => {
|
|
@@ -662,8 +719,8 @@ function Form(props) {
|
|
|
662
719
|
try {
|
|
663
720
|
formDataJson = JSON.stringify(data);
|
|
664
721
|
}
|
|
665
|
-
catch
|
|
666
|
-
const flattenFormValues = flatten(
|
|
722
|
+
catch { }
|
|
723
|
+
const flattenFormValues = flatten(data);
|
|
667
724
|
for (const key in flattenFormValues) {
|
|
668
725
|
formData.append(key, flattenFormValues[key]);
|
|
669
726
|
}
|
|
@@ -710,15 +767,25 @@ function Form(props) {
|
|
|
710
767
|
}
|
|
711
768
|
}
|
|
712
769
|
})(event);
|
|
713
|
-
if (hasError &&
|
|
714
|
-
|
|
770
|
+
if (hasError && control) {
|
|
771
|
+
control._subjects.state.next({
|
|
715
772
|
isSubmitSuccessful: false,
|
|
716
773
|
});
|
|
717
|
-
|
|
774
|
+
control.setError('root.server', {
|
|
718
775
|
type,
|
|
719
776
|
});
|
|
720
777
|
}
|
|
721
|
-
}
|
|
778
|
+
}, [
|
|
779
|
+
control,
|
|
780
|
+
onSubmit,
|
|
781
|
+
method,
|
|
782
|
+
action,
|
|
783
|
+
headers,
|
|
784
|
+
encType,
|
|
785
|
+
validateStatus,
|
|
786
|
+
onError,
|
|
787
|
+
onSuccess,
|
|
788
|
+
]);
|
|
722
789
|
React.useEffect(() => {
|
|
723
790
|
setMounted(true);
|
|
724
791
|
}, []);
|
|
@@ -816,7 +883,12 @@ function baseGet(object, updatePath) {
|
|
|
816
883
|
const length = updatePath.slice(0, -1).length;
|
|
817
884
|
let index = 0;
|
|
818
885
|
while (index < length) {
|
|
819
|
-
|
|
886
|
+
if (isNullOrUndefined(object)) {
|
|
887
|
+
object = undefined;
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
object = object[updatePath[index]];
|
|
891
|
+
index++;
|
|
820
892
|
}
|
|
821
893
|
return object;
|
|
822
894
|
}
|
|
@@ -829,6 +901,10 @@ function isEmptyArray(obj) {
|
|
|
829
901
|
return true;
|
|
830
902
|
}
|
|
831
903
|
function unset(object, path) {
|
|
904
|
+
if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
|
|
905
|
+
delete object[path];
|
|
906
|
+
return object;
|
|
907
|
+
}
|
|
832
908
|
const paths = Array.isArray(path)
|
|
833
909
|
? path
|
|
834
910
|
: isKey(path)
|
|
@@ -873,6 +949,29 @@ function markFieldsDirty(data, fields = {}) {
|
|
|
873
949
|
}
|
|
874
950
|
return fields;
|
|
875
951
|
}
|
|
952
|
+
function pruneDirtyFields(value) {
|
|
953
|
+
if (value === false) {
|
|
954
|
+
return undefined;
|
|
955
|
+
}
|
|
956
|
+
if (value === true) {
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
if (Array.isArray(value)) {
|
|
960
|
+
const result = value.map((value) => pruneDirtyFields(value));
|
|
961
|
+
return (result.some((value) => value !== undefined) ? result : undefined);
|
|
962
|
+
}
|
|
963
|
+
if (isObject(value)) {
|
|
964
|
+
const result = {};
|
|
965
|
+
for (const key in value) {
|
|
966
|
+
const pruned = pruneDirtyFields(value[key]);
|
|
967
|
+
if (!isUndefined(pruned)) {
|
|
968
|
+
result[key] = pruned;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
return (Object.keys(result).length ? result : undefined);
|
|
972
|
+
}
|
|
973
|
+
return undefined;
|
|
974
|
+
}
|
|
876
975
|
function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
877
976
|
if (!dirtyFieldsFromValues) {
|
|
878
977
|
dirtyFieldsFromValues = markFieldsDirty(formValues);
|
|
@@ -892,7 +991,7 @@ function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
|
|
|
892
991
|
dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
|
|
893
992
|
}
|
|
894
993
|
}
|
|
895
|
-
return dirtyFieldsFromValues;
|
|
994
|
+
return pruneDirtyFields(dirtyFieldsFromValues) || {};
|
|
896
995
|
}
|
|
897
996
|
|
|
898
997
|
const defaultResult = {
|
|
@@ -1088,7 +1187,8 @@ var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, is
|
|
|
1088
1187
|
updateFormState(formStateData);
|
|
1089
1188
|
const { name, ...formState } = formStateData;
|
|
1090
1189
|
return (isEmptyObject(formState) ||
|
|
1091
|
-
|
|
1190
|
+
(isRoot &&
|
|
1191
|
+
Object.keys(formState).length >= Object.keys(_proxyFormState).length) ||
|
|
1092
1192
|
Object.keys(formState).find((key) => _proxyFormState[key] ===
|
|
1093
1193
|
(!isRoot || VALIDATION_MODE.all)));
|
|
1094
1194
|
};
|
|
@@ -1122,7 +1222,7 @@ var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(re
|
|
|
1122
1222
|
|
|
1123
1223
|
var updateFieldArrayRootError = (errors, error, name) => {
|
|
1124
1224
|
const fieldArrayErrors = convertToArrayPayload(get(errors, name));
|
|
1125
|
-
set(fieldArrayErrors,
|
|
1225
|
+
set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
|
|
1126
1226
|
set(errors, name, fieldArrayErrors);
|
|
1127
1227
|
return errors;
|
|
1128
1228
|
};
|
|
@@ -1168,7 +1268,8 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
1168
1268
|
isUndefined(inputValue)) ||
|
|
1169
1269
|
(isHTMLElement(ref) && ref.value === '') ||
|
|
1170
1270
|
inputValue === '' ||
|
|
1171
|
-
(Array.isArray(inputValue) && !inputValue.length)
|
|
1271
|
+
(Array.isArray(inputValue) && !inputValue.length) ||
|
|
1272
|
+
(valueAsNumber && typeof inputValue === 'number' && isNaN(inputValue));
|
|
1172
1273
|
const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
|
|
1173
1274
|
const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => {
|
|
1174
1275
|
const message = exceedMax ? maxLengthMessage : minLengthMessage;
|
|
@@ -1330,24 +1431,27 @@ const defaultOptions = {
|
|
|
1330
1431
|
reValidateMode: VALIDATION_MODE.onChange,
|
|
1331
1432
|
shouldFocusError: true,
|
|
1332
1433
|
};
|
|
1434
|
+
const DEFAULT_FORM_STATE = {
|
|
1435
|
+
submitCount: 0,
|
|
1436
|
+
isDirty: false,
|
|
1437
|
+
isReady: false,
|
|
1438
|
+
isValidating: false,
|
|
1439
|
+
isSubmitted: false,
|
|
1440
|
+
isSubmitting: false,
|
|
1441
|
+
isSubmitSuccessful: false,
|
|
1442
|
+
isValid: false,
|
|
1443
|
+
touchedFields: {},
|
|
1444
|
+
dirtyFields: {},
|
|
1445
|
+
validatingFields: {},
|
|
1446
|
+
};
|
|
1333
1447
|
function createFormControl(props = {}) {
|
|
1334
1448
|
let _options = {
|
|
1335
1449
|
...defaultOptions,
|
|
1336
1450
|
...props,
|
|
1337
1451
|
};
|
|
1338
1452
|
let _formState = {
|
|
1339
|
-
|
|
1340
|
-
isDirty: false,
|
|
1341
|
-
isReady: false,
|
|
1453
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
1342
1454
|
isLoading: isFunction(_options.defaultValues),
|
|
1343
|
-
isValidating: false,
|
|
1344
|
-
isSubmitted: false,
|
|
1345
|
-
isSubmitting: false,
|
|
1346
|
-
isSubmitSuccessful: false,
|
|
1347
|
-
isValid: false,
|
|
1348
|
-
touchedFields: {},
|
|
1349
|
-
dirtyFields: {},
|
|
1350
|
-
validatingFields: {},
|
|
1351
1455
|
errors: _options.errors || {},
|
|
1352
1456
|
disabled: _options.disabled || false,
|
|
1353
1457
|
};
|
|
@@ -1362,6 +1466,7 @@ function createFormControl(props = {}) {
|
|
|
1362
1466
|
action: false,
|
|
1363
1467
|
mount: false,
|
|
1364
1468
|
watch: false,
|
|
1469
|
+
keepIsValid: false,
|
|
1365
1470
|
};
|
|
1366
1471
|
let _names = {
|
|
1367
1472
|
mount: new Set(),
|
|
@@ -1369,10 +1474,11 @@ function createFormControl(props = {}) {
|
|
|
1369
1474
|
unMount: new Set(),
|
|
1370
1475
|
array: new Set(),
|
|
1371
1476
|
watch: new Set(),
|
|
1477
|
+
registerName: new Set(),
|
|
1372
1478
|
};
|
|
1373
1479
|
let delayErrorCallback;
|
|
1374
1480
|
let timer = 0;
|
|
1375
|
-
const
|
|
1481
|
+
const defaultProxyFormState = {
|
|
1376
1482
|
isDirty: false,
|
|
1377
1483
|
dirtyFields: false,
|
|
1378
1484
|
validatingFields: false,
|
|
@@ -1381,6 +1487,9 @@ function createFormControl(props = {}) {
|
|
|
1381
1487
|
isValid: false,
|
|
1382
1488
|
errors: false,
|
|
1383
1489
|
};
|
|
1490
|
+
const _proxyFormState = {
|
|
1491
|
+
...defaultProxyFormState,
|
|
1492
|
+
};
|
|
1384
1493
|
let _proxySubscribeFormState = {
|
|
1385
1494
|
..._proxyFormState,
|
|
1386
1495
|
};
|
|
@@ -1394,13 +1503,25 @@ function createFormControl(props = {}) {
|
|
|
1394
1503
|
timer = setTimeout(callback, wait);
|
|
1395
1504
|
};
|
|
1396
1505
|
const _setValid = async (shouldUpdateValid) => {
|
|
1506
|
+
if (_state.keepIsValid) {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1397
1509
|
if (!_options.disabled &&
|
|
1398
1510
|
(_proxyFormState.isValid ||
|
|
1399
1511
|
_proxySubscribeFormState.isValid ||
|
|
1400
1512
|
shouldUpdateValid)) {
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1513
|
+
let isValid;
|
|
1514
|
+
if (_options.resolver) {
|
|
1515
|
+
isValid = isEmptyObject((await _runSchema()).errors);
|
|
1516
|
+
_updateIsValidating();
|
|
1517
|
+
}
|
|
1518
|
+
else {
|
|
1519
|
+
isValid = await executeBuiltInValidation({
|
|
1520
|
+
fields: _fields,
|
|
1521
|
+
onlyCheckValid: true,
|
|
1522
|
+
eventType: EVENTS.VALID,
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1404
1525
|
if (isValid !== _formState.isValid) {
|
|
1405
1526
|
_subjects.state.next({
|
|
1406
1527
|
isValid,
|
|
@@ -1427,6 +1548,9 @@ function createFormControl(props = {}) {
|
|
|
1427
1548
|
});
|
|
1428
1549
|
}
|
|
1429
1550
|
};
|
|
1551
|
+
const _updateDirtyFields = () => {
|
|
1552
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1553
|
+
};
|
|
1430
1554
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
1431
1555
|
if (args && method && !_options.disabled) {
|
|
1432
1556
|
_state.action = true;
|
|
@@ -1448,7 +1572,7 @@ function createFormControl(props = {}) {
|
|
|
1448
1572
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
1449
1573
|
}
|
|
1450
1574
|
if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
|
|
1451
|
-
|
|
1575
|
+
_updateDirtyFields();
|
|
1452
1576
|
}
|
|
1453
1577
|
_subjects.state.next({
|
|
1454
1578
|
name,
|
|
@@ -1475,16 +1599,53 @@ function createFormControl(props = {}) {
|
|
|
1475
1599
|
isValid: false,
|
|
1476
1600
|
});
|
|
1477
1601
|
};
|
|
1602
|
+
const hasExplicitNullIntermediate = (name) => {
|
|
1603
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
1604
|
+
let formValues = _formValues;
|
|
1605
|
+
let defaultValues = _defaultValues;
|
|
1606
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1607
|
+
const key = segments[i];
|
|
1608
|
+
formValues = isNullOrUndefined(formValues) ? formValues : formValues[key];
|
|
1609
|
+
defaultValues = isNullOrUndefined(defaultValues)
|
|
1610
|
+
? defaultValues
|
|
1611
|
+
: defaultValues[key];
|
|
1612
|
+
if (formValues === null && defaultValues !== null) {
|
|
1613
|
+
return true;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
return false;
|
|
1617
|
+
};
|
|
1478
1618
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
1479
1619
|
const field = get(_fields, name);
|
|
1480
1620
|
if (field) {
|
|
1621
|
+
if (hasExplicitNullIntermediate(name)) {
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
1481
1625
|
const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
|
|
1482
1626
|
isUndefined(defaultValue) ||
|
|
1483
1627
|
(ref && ref.defaultChecked) ||
|
|
1484
1628
|
shouldSkipSetValueAs
|
|
1485
1629
|
? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
|
|
1486
1630
|
: setFieldValue(name, defaultValue);
|
|
1487
|
-
_state.mount && !_state.action
|
|
1631
|
+
if (_state.mount && !_state.action) {
|
|
1632
|
+
_setValid();
|
|
1633
|
+
// Re-registering a field after a prior unregister puts its key back
|
|
1634
|
+
// into _formValues, which can flip isDirty back to false (#13397).
|
|
1635
|
+
// Only run when we are currently dirty, otherwise an initial register
|
|
1636
|
+
// for a field with no defaultValue would flip isDirty to true. Reset
|
|
1637
|
+
// paths repopulate _formValues before re-register, so the key is
|
|
1638
|
+
// present then and this branch is skipped (preserves keepDirty).
|
|
1639
|
+
if (wasUnsetInFormValues &&
|
|
1640
|
+
_formState.isDirty &&
|
|
1641
|
+
(_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
|
|
1642
|
+
const isDirty = _getDirty();
|
|
1643
|
+
if (!isDirty) {
|
|
1644
|
+
_formState.isDirty = false;
|
|
1645
|
+
_subjects.state.next({ ..._formState });
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1488
1649
|
}
|
|
1489
1650
|
};
|
|
1490
1651
|
const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
|
|
@@ -1502,9 +1663,14 @@ function createFormControl(props = {}) {
|
|
|
1502
1663
|
}
|
|
1503
1664
|
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
1504
1665
|
isPreviousDirty = !!get(_formState.dirtyFields, name);
|
|
1505
|
-
isCurrentFieldPristine
|
|
1506
|
-
|
|
1507
|
-
|
|
1666
|
+
if (isCurrentFieldPristine !== _formState.isDirty) {
|
|
1667
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
|
1668
|
+
}
|
|
1669
|
+
else {
|
|
1670
|
+
isCurrentFieldPristine
|
|
1671
|
+
? unset(_formState.dirtyFields, name)
|
|
1672
|
+
: set(_formState.dirtyFields, name, true);
|
|
1673
|
+
}
|
|
1508
1674
|
output.dirtyFields = _formState.dirtyFields;
|
|
1509
1675
|
shouldUpdateField =
|
|
1510
1676
|
shouldUpdateField ||
|
|
@@ -1562,17 +1728,18 @@ function createFormControl(props = {}) {
|
|
|
1562
1728
|
};
|
|
1563
1729
|
const _runSchema = async (name) => {
|
|
1564
1730
|
_updateIsValidating(name, true);
|
|
1565
|
-
|
|
1566
|
-
_updateIsValidating(name);
|
|
1567
|
-
return result;
|
|
1731
|
+
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
1568
1732
|
};
|
|
1569
1733
|
const executeSchemaAndUpdateState = async (names) => {
|
|
1570
1734
|
const { errors } = await _runSchema(names);
|
|
1735
|
+
_updateIsValidating(names);
|
|
1571
1736
|
if (names) {
|
|
1572
1737
|
for (const name of names) {
|
|
1573
1738
|
const error = get(errors, name);
|
|
1574
1739
|
error
|
|
1575
|
-
?
|
|
1740
|
+
? _names.array.has(name) && isObject(error)
|
|
1741
|
+
? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
|
|
1742
|
+
: set(_formState.errors, name, error)
|
|
1576
1743
|
: unset(_formState.errors, name);
|
|
1577
1744
|
}
|
|
1578
1745
|
}
|
|
@@ -1581,9 +1748,55 @@ function createFormControl(props = {}) {
|
|
|
1581
1748
|
}
|
|
1582
1749
|
return errors;
|
|
1583
1750
|
};
|
|
1584
|
-
const
|
|
1751
|
+
const validateForm = async ({ name, eventType, }) => {
|
|
1752
|
+
if (props.validate) {
|
|
1753
|
+
const result = await props.validate({
|
|
1754
|
+
formValues: _formValues,
|
|
1755
|
+
formState: _formState,
|
|
1756
|
+
name,
|
|
1757
|
+
eventType,
|
|
1758
|
+
});
|
|
1759
|
+
if (isObject(result)) {
|
|
1760
|
+
for (const key in result) {
|
|
1761
|
+
const error = result[key];
|
|
1762
|
+
if (error) {
|
|
1763
|
+
setError(`${FORM_ERROR_TYPE}.${key}`, {
|
|
1764
|
+
message: isString(error.message) ? error.message : '',
|
|
1765
|
+
type: error.type || INPUT_VALIDATION_RULES.validate,
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
else if (isString(result) || !result) {
|
|
1771
|
+
setError(FORM_ERROR_TYPE, {
|
|
1772
|
+
message: result || '',
|
|
1773
|
+
type: INPUT_VALIDATION_RULES.validate,
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
else {
|
|
1777
|
+
clearErrors(FORM_ERROR_TYPE);
|
|
1778
|
+
}
|
|
1779
|
+
return result;
|
|
1780
|
+
}
|
|
1781
|
+
return true;
|
|
1782
|
+
};
|
|
1783
|
+
const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
|
|
1585
1784
|
valid: true,
|
|
1586
|
-
|
|
1785
|
+
runRootValidation: false,
|
|
1786
|
+
}, }) => {
|
|
1787
|
+
if (props.validate) {
|
|
1788
|
+
context.runRootValidation = true;
|
|
1789
|
+
const result = await validateForm({
|
|
1790
|
+
name,
|
|
1791
|
+
eventType,
|
|
1792
|
+
});
|
|
1793
|
+
if (!result) {
|
|
1794
|
+
context.valid = false;
|
|
1795
|
+
if (onlyCheckValid) {
|
|
1796
|
+
return context.valid;
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1587
1800
|
for (const name in fields) {
|
|
1588
1801
|
const field = fields[name];
|
|
1589
1802
|
if (field) {
|
|
@@ -1591,28 +1804,41 @@ function createFormControl(props = {}) {
|
|
|
1591
1804
|
if (_f) {
|
|
1592
1805
|
const isFieldArrayRoot = _names.array.has(_f.name);
|
|
1593
1806
|
const isPromiseFunction = field._f && hasPromiseValidation(field._f);
|
|
1594
|
-
|
|
1807
|
+
const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
|
|
1808
|
+
_proxyFormState.isValidating ||
|
|
1809
|
+
_proxySubscribeFormState.validatingFields ||
|
|
1810
|
+
_proxySubscribeFormState.isValidating;
|
|
1811
|
+
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1595
1812
|
_updateIsValidating([_f.name], true);
|
|
1596
1813
|
}
|
|
1597
|
-
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !
|
|
1598
|
-
if (isPromiseFunction &&
|
|
1814
|
+
const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
|
|
1815
|
+
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
1599
1816
|
_updateIsValidating([_f.name]);
|
|
1600
1817
|
}
|
|
1601
1818
|
if (fieldError[_f.name]) {
|
|
1602
1819
|
context.valid = false;
|
|
1603
|
-
if (
|
|
1820
|
+
if (onlyCheckValid) {
|
|
1604
1821
|
break;
|
|
1605
1822
|
}
|
|
1606
1823
|
}
|
|
1607
|
-
!
|
|
1824
|
+
!onlyCheckValid &&
|
|
1608
1825
|
(get(fieldError, _f.name)
|
|
1609
1826
|
? isFieldArrayRoot
|
|
1610
1827
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
1611
1828
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
1612
1829
|
: unset(_formState.errors, _f.name));
|
|
1830
|
+
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
1831
|
+
break;
|
|
1832
|
+
}
|
|
1613
1833
|
}
|
|
1614
1834
|
!isEmptyObject(fieldValue) &&
|
|
1615
|
-
(await executeBuiltInValidation(
|
|
1835
|
+
(await executeBuiltInValidation({
|
|
1836
|
+
context,
|
|
1837
|
+
onlyCheckValid,
|
|
1838
|
+
fields: fieldValue,
|
|
1839
|
+
name: name,
|
|
1840
|
+
eventType,
|
|
1841
|
+
}));
|
|
1616
1842
|
}
|
|
1617
1843
|
}
|
|
1618
1844
|
return context.valid;
|
|
@@ -1692,7 +1918,7 @@ function createFormControl(props = {}) {
|
|
|
1692
1918
|
updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, true);
|
|
1693
1919
|
options.shouldValidate && trigger(name);
|
|
1694
1920
|
};
|
|
1695
|
-
const
|
|
1921
|
+
const setFieldValues = (name, value, options) => {
|
|
1696
1922
|
for (const fieldKey in value) {
|
|
1697
1923
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
1698
1924
|
return;
|
|
@@ -1704,7 +1930,7 @@ function createFormControl(props = {}) {
|
|
|
1704
1930
|
isObject(fieldValue) ||
|
|
1705
1931
|
(field && !field._f)) &&
|
|
1706
1932
|
!isDateObject(fieldValue)
|
|
1707
|
-
?
|
|
1933
|
+
? setFieldValues(fieldName, fieldValue, options)
|
|
1708
1934
|
: setFieldValue(fieldName, fieldValue, options);
|
|
1709
1935
|
}
|
|
1710
1936
|
};
|
|
@@ -1712,7 +1938,11 @@ function createFormControl(props = {}) {
|
|
|
1712
1938
|
const field = get(_fields, name);
|
|
1713
1939
|
const isFieldArray = _names.array.has(name);
|
|
1714
1940
|
const cloneValue = cloneObject(value);
|
|
1715
|
-
|
|
1941
|
+
const previousValue = get(_formValues, name);
|
|
1942
|
+
const isValueUnchanged = deepEqual(previousValue, cloneValue);
|
|
1943
|
+
if (!isValueUnchanged) {
|
|
1944
|
+
set(_formValues, name, cloneValue);
|
|
1945
|
+
}
|
|
1716
1946
|
if (isFieldArray) {
|
|
1717
1947
|
_subjects.array.next({
|
|
1718
1948
|
name,
|
|
@@ -1723,23 +1953,53 @@ function createFormControl(props = {}) {
|
|
|
1723
1953
|
_proxySubscribeFormState.isDirty ||
|
|
1724
1954
|
_proxySubscribeFormState.dirtyFields) &&
|
|
1725
1955
|
options.shouldDirty) {
|
|
1956
|
+
_updateDirtyFields();
|
|
1726
1957
|
_subjects.state.next({
|
|
1727
1958
|
name,
|
|
1728
|
-
dirtyFields:
|
|
1959
|
+
dirtyFields: _formState.dirtyFields,
|
|
1729
1960
|
isDirty: _getDirty(name, cloneValue),
|
|
1730
1961
|
});
|
|
1731
1962
|
}
|
|
1732
1963
|
}
|
|
1733
1964
|
else {
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1965
|
+
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
1966
|
+
isEmptyObject(cloneValue);
|
|
1967
|
+
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
1968
|
+
setFieldValue(name, cloneValue, options);
|
|
1969
|
+
}
|
|
1970
|
+
else {
|
|
1971
|
+
setFieldValues(name, cloneValue, options);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
if (!isValueUnchanged) {
|
|
1975
|
+
const watched = isWatched(name, _names);
|
|
1976
|
+
const values = cloneObject(_formValues);
|
|
1977
|
+
if (!isFieldArray) {
|
|
1978
|
+
for (const arrayName of getFieldArrayParentNames(_names.array, name)) {
|
|
1979
|
+
_subjects.array.next({ name: arrayName, values });
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
_subjects.state.next({
|
|
1983
|
+
...(watched && _formState),
|
|
1984
|
+
name: _state.mount || watched ? name : undefined,
|
|
1985
|
+
values,
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
const setValues = (formValues) => {
|
|
1990
|
+
const updatedFormValues = isFunction(formValues)
|
|
1991
|
+
? formValues(_formValues)
|
|
1992
|
+
: formValues;
|
|
1993
|
+
if (!deepEqual(_formValues, updatedFormValues)) {
|
|
1994
|
+
_formValues = {
|
|
1995
|
+
..._formValues,
|
|
1996
|
+
...updatedFormValues,
|
|
1997
|
+
};
|
|
1998
|
+
for (const fieldName of _names.mount) {
|
|
1999
|
+
setValue(fieldName, get(updatedFormValues, fieldName));
|
|
2000
|
+
}
|
|
2001
|
+
_subjects.state.next({ ..._formState, values: _formValues });
|
|
1737
2002
|
}
|
|
1738
|
-
isWatched(name, _names) && _subjects.state.next({ ..._formState, name });
|
|
1739
|
-
_subjects.state.next({
|
|
1740
|
-
name: _state.mount ? name : undefined,
|
|
1741
|
-
values: cloneObject(_formValues),
|
|
1742
|
-
});
|
|
1743
2003
|
};
|
|
1744
2004
|
const onChange = async (event) => {
|
|
1745
2005
|
_state.mount = true;
|
|
@@ -1763,6 +2023,7 @@ function createFormControl(props = {}) {
|
|
|
1763
2023
|
: getEventValue(event);
|
|
1764
2024
|
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
|
1765
2025
|
const shouldSkipValidation = (!hasValidation(field._f) &&
|
|
2026
|
+
!props.validate &&
|
|
1766
2027
|
!_options.resolver &&
|
|
1767
2028
|
!get(_formState.errors, name) &&
|
|
1768
2029
|
!field._f.deps) ||
|
|
@@ -1800,9 +2061,16 @@ function createFormControl(props = {}) {
|
|
|
1800
2061
|
return (shouldRender &&
|
|
1801
2062
|
_subjects.state.next({ name, ...(watched ? {} : fieldState) }));
|
|
1802
2063
|
}
|
|
2064
|
+
if (!_options.resolver && props.validate) {
|
|
2065
|
+
await validateForm({
|
|
2066
|
+
name: name,
|
|
2067
|
+
eventType: event.type,
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
1803
2070
|
!isBlurEvent && watched && _subjects.state.next({ ..._formState });
|
|
1804
2071
|
if (_options.resolver) {
|
|
1805
2072
|
const { errors } = await _runSchema([name]);
|
|
2073
|
+
_updateIsValidating([name]);
|
|
1806
2074
|
_updateIsFieldValueUpdated(fieldValue);
|
|
1807
2075
|
if (isFieldValueUpdated) {
|
|
1808
2076
|
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
|
@@ -1823,7 +2091,12 @@ function createFormControl(props = {}) {
|
|
|
1823
2091
|
}
|
|
1824
2092
|
else if (_proxyFormState.isValid ||
|
|
1825
2093
|
_proxySubscribeFormState.isValid) {
|
|
1826
|
-
isValid = await executeBuiltInValidation(
|
|
2094
|
+
isValid = await executeBuiltInValidation({
|
|
2095
|
+
fields: _fields,
|
|
2096
|
+
onlyCheckValid: true,
|
|
2097
|
+
name: name,
|
|
2098
|
+
eventType: event.type,
|
|
2099
|
+
});
|
|
1827
2100
|
}
|
|
1828
2101
|
}
|
|
1829
2102
|
}
|
|
@@ -1856,12 +2129,19 @@ function createFormControl(props = {}) {
|
|
|
1856
2129
|
else if (name) {
|
|
1857
2130
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
1858
2131
|
const field = get(_fields, fieldName);
|
|
1859
|
-
return await executeBuiltInValidation(
|
|
2132
|
+
return await executeBuiltInValidation({
|
|
2133
|
+
fields: field && field._f ? { [fieldName]: field } : field,
|
|
2134
|
+
eventType: EVENTS.TRIGGER,
|
|
2135
|
+
});
|
|
1860
2136
|
}))).every(Boolean);
|
|
1861
2137
|
!(!validationResult && !_formState.isValid) && _setValid();
|
|
1862
2138
|
}
|
|
1863
2139
|
else {
|
|
1864
|
-
validationResult = isValid = await executeBuiltInValidation(
|
|
2140
|
+
validationResult = isValid = await executeBuiltInValidation({
|
|
2141
|
+
fields: _fields,
|
|
2142
|
+
name,
|
|
2143
|
+
eventType: EVENTS.TRIGGER,
|
|
2144
|
+
});
|
|
1865
2145
|
}
|
|
1866
2146
|
_subjects.state.next({
|
|
1867
2147
|
...(!isString(name) ||
|
|
@@ -1898,11 +2178,24 @@ function createFormControl(props = {}) {
|
|
|
1898
2178
|
isTouched: !!get((formState || _formState).touchedFields, name),
|
|
1899
2179
|
});
|
|
1900
2180
|
const clearErrors = (name) => {
|
|
1901
|
-
name
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2181
|
+
const names = name ? convertToArrayPayload(name) : undefined;
|
|
2182
|
+
names?.forEach((inputName) => unset(_formState.errors, inputName));
|
|
2183
|
+
if (names) {
|
|
2184
|
+
// Emit for each cleared field with the field name so that
|
|
2185
|
+
// shouldSubscribeByName can filter and avoid broad re-renders
|
|
2186
|
+
names.forEach((inputName) => {
|
|
2187
|
+
_subjects.state.next({
|
|
2188
|
+
name: inputName,
|
|
2189
|
+
errors: _formState.errors,
|
|
2190
|
+
});
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
else {
|
|
2194
|
+
// Clear all errors - emit without name to notify all subscribers
|
|
2195
|
+
_subjects.state.next({
|
|
2196
|
+
errors: {},
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
1906
2199
|
};
|
|
1907
2200
|
const setError = (name, error, options) => {
|
|
1908
2201
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
@@ -1921,18 +2214,14 @@ function createFormControl(props = {}) {
|
|
|
1921
2214
|
});
|
|
1922
2215
|
options && options.shouldFocus && ref && ref.focus && ref.focus();
|
|
1923
2216
|
};
|
|
1924
|
-
const watch = (name, defaultValue) =>
|
|
1925
|
-
? _subjects.state.subscribe({
|
|
1926
|
-
next: (payload) => 'values' in payload &&
|
|
1927
|
-
name(_getWatch(undefined, defaultValue), payload),
|
|
1928
|
-
})
|
|
1929
|
-
: _getWatch(name, defaultValue, true);
|
|
2217
|
+
const watch = (name, defaultValue) => _getWatch(name, defaultValue, true);
|
|
1930
2218
|
const _subscribe = (props) => _subjects.state.subscribe({
|
|
1931
2219
|
next: (formState) => {
|
|
1932
2220
|
if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
|
|
1933
2221
|
shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
|
|
2222
|
+
const snapshot = { ..._formValues };
|
|
1934
2223
|
props.callback({
|
|
1935
|
-
values:
|
|
2224
|
+
values: snapshot,
|
|
1936
2225
|
..._formState,
|
|
1937
2226
|
...formState,
|
|
1938
2227
|
defaultValues: _defaultValues,
|
|
@@ -1948,7 +2237,10 @@ function createFormControl(props = {}) {
|
|
|
1948
2237
|
};
|
|
1949
2238
|
return _subscribe({
|
|
1950
2239
|
...props,
|
|
1951
|
-
formState:
|
|
2240
|
+
formState: {
|
|
2241
|
+
...defaultProxyFormState,
|
|
2242
|
+
...props.formState,
|
|
2243
|
+
},
|
|
1952
2244
|
});
|
|
1953
2245
|
};
|
|
1954
2246
|
const unregister = (name, options = {}) => {
|
|
@@ -1981,12 +2273,17 @@ function createFormControl(props = {}) {
|
|
|
1981
2273
|
if ((isBoolean(disabled) && _state.mount) ||
|
|
1982
2274
|
!!disabled ||
|
|
1983
2275
|
_names.disabled.has(name)) {
|
|
2276
|
+
const wasDisabled = _names.disabled.has(name);
|
|
2277
|
+
const isDisabled = !!disabled;
|
|
2278
|
+
const disabledStateChanged = wasDisabled !== isDisabled;
|
|
1984
2279
|
disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
|
|
2280
|
+
disabledStateChanged && _state.mount && !_state.action && _setValid();
|
|
1985
2281
|
}
|
|
1986
2282
|
};
|
|
1987
2283
|
const register = (name, options = {}) => {
|
|
1988
2284
|
let field = get(_fields, name);
|
|
1989
2285
|
const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
|
|
2286
|
+
const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
|
|
1990
2287
|
set(_fields, name, {
|
|
1991
2288
|
...(field || {}),
|
|
1992
2289
|
_f: {
|
|
@@ -1997,7 +2294,7 @@ function createFormControl(props = {}) {
|
|
|
1997
2294
|
},
|
|
1998
2295
|
});
|
|
1999
2296
|
_names.mount.add(name);
|
|
2000
|
-
if (field) {
|
|
2297
|
+
if (field && !shouldRevalidateRemount) {
|
|
2001
2298
|
_setDisabledField({
|
|
2002
2299
|
disabled: isBoolean(options.disabled)
|
|
2003
2300
|
? options.disabled
|
|
@@ -2027,7 +2324,9 @@ function createFormControl(props = {}) {
|
|
|
2027
2324
|
onBlur: onChange,
|
|
2028
2325
|
ref: (ref) => {
|
|
2029
2326
|
if (ref) {
|
|
2327
|
+
_names.registerName.add(name);
|
|
2030
2328
|
register(name, options);
|
|
2329
|
+
_names.registerName.delete(name);
|
|
2031
2330
|
field = get(_fields, name);
|
|
2032
2331
|
const fieldRef = isUndefined(ref.value)
|
|
2033
2332
|
? ref.querySelectorAll
|
|
@@ -2064,13 +2363,15 @@ function createFormControl(props = {}) {
|
|
|
2064
2363
|
field._f.mount = false;
|
|
2065
2364
|
}
|
|
2066
2365
|
(_options.shouldUnregister || options.shouldUnregister) &&
|
|
2067
|
-
!(
|
|
2366
|
+
!(getFieldArrayParentNames(_names.array, name).length &&
|
|
2367
|
+
_state.action) &&
|
|
2068
2368
|
_names.unMount.add(name);
|
|
2069
2369
|
}
|
|
2070
2370
|
},
|
|
2071
2371
|
};
|
|
2072
2372
|
};
|
|
2073
2373
|
const _focusError = () => _options.shouldFocusError &&
|
|
2374
|
+
!_options.shouldUseNativeValidation &&
|
|
2074
2375
|
iterateFieldsByAction(_fields, _focusInput, _names.mount);
|
|
2075
2376
|
const _disableForm = (disabled) => {
|
|
2076
2377
|
if (isBoolean(disabled)) {
|
|
@@ -2101,18 +2402,22 @@ function createFormControl(props = {}) {
|
|
|
2101
2402
|
});
|
|
2102
2403
|
if (_options.resolver) {
|
|
2103
2404
|
const { errors, values } = await _runSchema();
|
|
2405
|
+
_updateIsValidating();
|
|
2104
2406
|
_formState.errors = errors;
|
|
2105
2407
|
fieldValues = cloneObject(values);
|
|
2106
2408
|
}
|
|
2107
2409
|
else {
|
|
2108
|
-
await executeBuiltInValidation(
|
|
2410
|
+
await executeBuiltInValidation({
|
|
2411
|
+
fields: _fields,
|
|
2412
|
+
eventType: EVENTS.SUBMIT,
|
|
2413
|
+
});
|
|
2109
2414
|
}
|
|
2110
2415
|
if (_names.disabled.size) {
|
|
2111
2416
|
for (const name of _names.disabled) {
|
|
2112
2417
|
unset(fieldValues, name);
|
|
2113
2418
|
}
|
|
2114
2419
|
}
|
|
2115
|
-
unset(_formState.errors,
|
|
2420
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
2116
2421
|
if (isEmptyObject(_formState.errors)) {
|
|
2117
2422
|
_subjects.state.next({
|
|
2118
2423
|
errors: {},
|
|
@@ -2182,9 +2487,15 @@ function createFormControl(props = {}) {
|
|
|
2182
2487
|
...Object.keys(getDirtyFields(_defaultValues, _formValues)),
|
|
2183
2488
|
]);
|
|
2184
2489
|
for (const fieldName of Array.from(fieldsToCheck)) {
|
|
2185
|
-
get(_formState.dirtyFields, fieldName)
|
|
2186
|
-
|
|
2187
|
-
|
|
2490
|
+
const isDirty = get(_formState.dirtyFields, fieldName);
|
|
2491
|
+
const existingValue = get(_formValues, fieldName);
|
|
2492
|
+
const newValue = get(values, fieldName);
|
|
2493
|
+
if (isDirty && !isUndefined(existingValue)) {
|
|
2494
|
+
set(values, fieldName, existingValue);
|
|
2495
|
+
}
|
|
2496
|
+
else if (!isDirty && !isUndefined(newValue)) {
|
|
2497
|
+
setValue(fieldName, newValue);
|
|
2498
|
+
}
|
|
2188
2499
|
}
|
|
2189
2500
|
}
|
|
2190
2501
|
else {
|
|
@@ -2230,6 +2541,7 @@ function createFormControl(props = {}) {
|
|
|
2230
2541
|
mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
|
|
2231
2542
|
unMount: new Set(),
|
|
2232
2543
|
array: new Set(),
|
|
2544
|
+
registerName: new Set(),
|
|
2233
2545
|
disabled: new Set(),
|
|
2234
2546
|
watch: new Set(),
|
|
2235
2547
|
watchAll: false,
|
|
@@ -2241,6 +2553,7 @@ function createFormControl(props = {}) {
|
|
|
2241
2553
|
!!keepStateOptions.keepDirtyValues ||
|
|
2242
2554
|
(!_options.shouldUnregister && !isEmptyObject(values));
|
|
2243
2555
|
_state.watch = !!_options.shouldUnregister;
|
|
2556
|
+
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
2244
2557
|
_state.action = false;
|
|
2245
2558
|
// Clear errors synchronously to prevent validation errors on subsequent submissions
|
|
2246
2559
|
// This fixes the issue where form.reset() causes validation errors on subsequent
|
|
@@ -2285,7 +2598,7 @@ function createFormControl(props = {}) {
|
|
|
2285
2598
|
};
|
|
2286
2599
|
const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
|
|
2287
2600
|
? formValues(_formValues)
|
|
2288
|
-
: formValues, keepStateOptions);
|
|
2601
|
+
: formValues, { ..._options.resetOptions, ...keepStateOptions });
|
|
2289
2602
|
const setFocus = (name, options = {}) => {
|
|
2290
2603
|
const field = get(_fields, name);
|
|
2291
2604
|
const fieldReference = field && field._f;
|
|
@@ -2294,10 +2607,14 @@ function createFormControl(props = {}) {
|
|
|
2294
2607
|
? fieldReference.refs[0]
|
|
2295
2608
|
: fieldReference.ref;
|
|
2296
2609
|
if (fieldRef.focus) {
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
fieldRef.
|
|
2610
|
+
// Use setTimeout to ensure focus happens after any pending state updates
|
|
2611
|
+
// This fixes the issue where setFocus doesn't work immediately after setError
|
|
2612
|
+
setTimeout(() => {
|
|
2613
|
+
fieldRef.focus();
|
|
2614
|
+
options.shouldSelect &&
|
|
2615
|
+
isFunction(fieldRef.select) &&
|
|
2616
|
+
fieldRef.select();
|
|
2617
|
+
});
|
|
2301
2618
|
}
|
|
2302
2619
|
}
|
|
2303
2620
|
};
|
|
@@ -2323,6 +2640,7 @@ function createFormControl(props = {}) {
|
|
|
2323
2640
|
setError,
|
|
2324
2641
|
_subscribe,
|
|
2325
2642
|
_runSchema,
|
|
2643
|
+
_updateIsValidating,
|
|
2326
2644
|
_focusError,
|
|
2327
2645
|
_getWatch,
|
|
2328
2646
|
_getDirty,
|
|
@@ -2377,6 +2695,7 @@ function createFormControl(props = {}) {
|
|
|
2377
2695
|
handleSubmit,
|
|
2378
2696
|
watch,
|
|
2379
2697
|
setValue,
|
|
2698
|
+
setValues,
|
|
2380
2699
|
getValues,
|
|
2381
2700
|
reset,
|
|
2382
2701
|
resetField,
|
|
@@ -2398,7 +2717,7 @@ var generateId = () => {
|
|
|
2398
2717
|
}
|
|
2399
2718
|
const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
|
|
2400
2719
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
2401
|
-
const r = (Math.random() * 16 + d) % 16 | 0;
|
|
2720
|
+
const r = ((Math.random() * 16 + d) % 16) | 0;
|
|
2402
2721
|
return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
|
2403
2722
|
});
|
|
2404
2723
|
};
|
|
@@ -2487,7 +2806,7 @@ var updateAt = (fieldValues, index, value) => {
|
|
|
2487
2806
|
* return (
|
|
2488
2807
|
* <form onSubmit={handleSubmit(data => console.log(data))}>
|
|
2489
2808
|
* {fields.map((item, index) => (
|
|
2490
|
-
* <input key={item.
|
|
2809
|
+
* <input key={item.key} {...register(`test.${index}.firstName`)} />
|
|
2491
2810
|
* ))}
|
|
2492
2811
|
* <button type="button" onClick={() => append({ firstName: "bill" })}>
|
|
2493
2812
|
* append
|
|
@@ -2499,8 +2818,8 @@ var updateAt = (fieldValues, index, value) => {
|
|
|
2499
2818
|
* ```
|
|
2500
2819
|
*/
|
|
2501
2820
|
function useFieldArray(props) {
|
|
2502
|
-
const
|
|
2503
|
-
const { control =
|
|
2821
|
+
const formControl = useFormControlContext();
|
|
2822
|
+
const { control = formControl, name, shouldUnregister, rules } = props;
|
|
2504
2823
|
const [fields, setFields] = React.useState(control._getFieldArray(name));
|
|
2505
2824
|
const ids = React.useRef(control._getFieldArray(name).map(generateId));
|
|
2506
2825
|
const _actioned = React.useRef(false);
|
|
@@ -2614,12 +2933,14 @@ function useFieldArray(props) {
|
|
|
2614
2933
|
control._subjects.state.next({
|
|
2615
2934
|
...control._formState,
|
|
2616
2935
|
});
|
|
2936
|
+
const validationModes = getValidationModes(control._options.mode);
|
|
2617
2937
|
if (_actioned.current &&
|
|
2618
|
-
(!
|
|
2619
|
-
|
|
2620
|
-
!
|
|
2938
|
+
(!validationModes.isOnSubmit || control._formState.isSubmitted) &&
|
|
2939
|
+
!getValidationModes(control._options.reValidateMode).isOnSubmit &&
|
|
2940
|
+
!validationModes.isOnBlur) {
|
|
2621
2941
|
if (control._options.resolver) {
|
|
2622
2942
|
control._runSchema([name]).then((result) => {
|
|
2943
|
+
control._updateIsValidating([name]);
|
|
2623
2944
|
const error = get(result.errors, name);
|
|
2624
2945
|
const existingError = get(control._formState.errors, name);
|
|
2625
2946
|
if (existingError
|
|
@@ -2671,17 +2992,24 @@ function useFieldArray(props) {
|
|
|
2671
2992
|
React.useEffect(() => {
|
|
2672
2993
|
!get(control._formValues, name) && control._setFieldArray(name);
|
|
2673
2994
|
return () => {
|
|
2995
|
+
const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
|
|
2674
2996
|
const updateMounted = (name, value) => {
|
|
2675
2997
|
const field = get(control._fields, name);
|
|
2676
2998
|
if (field && field._f) {
|
|
2677
2999
|
field._f.mount = value;
|
|
2678
3000
|
}
|
|
2679
3001
|
};
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
3002
|
+
if (_actioned.current && shouldKeepFieldArrayValues) {
|
|
3003
|
+
control._subjects.state.next({
|
|
3004
|
+
name,
|
|
3005
|
+
values: cloneObject(control._formValues),
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
shouldKeepFieldArrayValues
|
|
3009
|
+
? updateMounted(name, false)
|
|
3010
|
+
: control.unregister(name);
|
|
2683
3011
|
};
|
|
2684
|
-
}, [name, control,
|
|
3012
|
+
}, [name, control, shouldUnregister]);
|
|
2685
3013
|
return {
|
|
2686
3014
|
swap: React.useCallback(swap, [updateValues, name, control]),
|
|
2687
3015
|
move: React.useCallback(move, [updateValues, name, control]),
|
|
@@ -2693,8 +3021,8 @@ function useFieldArray(props) {
|
|
|
2693
3021
|
replace: React.useCallback(replace, [updateValues, name, control]),
|
|
2694
3022
|
fields: React.useMemo(() => fields.map((field, index) => ({
|
|
2695
3023
|
...field,
|
|
2696
|
-
|
|
2697
|
-
})), [fields
|
|
3024
|
+
key: ids.current[index] || generateId(),
|
|
3025
|
+
})), [fields]),
|
|
2698
3026
|
};
|
|
2699
3027
|
}
|
|
2700
3028
|
|
|
@@ -2741,25 +3069,15 @@ function updateMethodsReference(_formControl) {
|
|
|
2741
3069
|
function useForm(props = {}) {
|
|
2742
3070
|
const _formControl = React.useRef(undefined);
|
|
2743
3071
|
const _values = React.useRef(undefined);
|
|
2744
|
-
const [formState, updateFormState] = React.useState({
|
|
2745
|
-
|
|
2746
|
-
isValidating: false,
|
|
3072
|
+
const [formState, updateFormState] = React.useState(() => ({
|
|
3073
|
+
...cloneObject(DEFAULT_FORM_STATE),
|
|
2747
3074
|
isLoading: isFunction(props.defaultValues),
|
|
2748
|
-
isSubmitted: false,
|
|
2749
|
-
isSubmitting: false,
|
|
2750
|
-
isSubmitSuccessful: false,
|
|
2751
|
-
isValid: false,
|
|
2752
|
-
submitCount: 0,
|
|
2753
|
-
dirtyFields: {},
|
|
2754
|
-
touchedFields: {},
|
|
2755
|
-
validatingFields: {},
|
|
2756
3075
|
errors: props.errors || {},
|
|
2757
3076
|
disabled: props.disabled || false,
|
|
2758
|
-
isReady: false,
|
|
2759
3077
|
defaultValues: isFunction(props.defaultValues)
|
|
2760
3078
|
? undefined
|
|
2761
3079
|
: props.defaultValues,
|
|
2762
|
-
});
|
|
3080
|
+
}));
|
|
2763
3081
|
if (!_formControl.current) {
|
|
2764
3082
|
if (props.formControl) {
|
|
2765
3083
|
_formControl.current = {
|
|
@@ -2783,7 +3101,10 @@ function useForm(props = {}) {
|
|
|
2783
3101
|
useIsomorphicLayoutEffect(() => {
|
|
2784
3102
|
const sub = control._subscribe({
|
|
2785
3103
|
formState: control._proxyFormState,
|
|
2786
|
-
callback: () => updateFormState({
|
|
3104
|
+
callback: () => updateFormState({
|
|
3105
|
+
...control._formState,
|
|
3106
|
+
defaultValues: control._defaultValues,
|
|
3107
|
+
}),
|
|
2787
3108
|
reRenderRoot: true,
|
|
2788
3109
|
});
|
|
2789
3110
|
updateFormState((data) => ({
|
|
@@ -2825,14 +3146,13 @@ function useForm(props = {}) {
|
|
|
2825
3146
|
}
|
|
2826
3147
|
}, [control, formState.isDirty]);
|
|
2827
3148
|
React.useEffect(() => {
|
|
2828
|
-
var _a;
|
|
2829
3149
|
if (props.values && !deepEqual(props.values, _values.current)) {
|
|
2830
3150
|
updateMethodsReference(_formControl);
|
|
2831
3151
|
control._reset(props.values, {
|
|
2832
3152
|
keepFieldsRef: true,
|
|
2833
3153
|
...control._options.resetOptions,
|
|
2834
3154
|
});
|
|
2835
|
-
if (!
|
|
3155
|
+
if (!control._options.resetOptions?.keepIsValid) {
|
|
2836
3156
|
control._setValid();
|
|
2837
3157
|
}
|
|
2838
3158
|
_values.current = props.values;
|
|
@@ -2872,7 +3192,11 @@ function useForm(props = {}) {
|
|
|
2872
3192
|
* Watch component that subscribes to form field changes and re-renders when watched fields update.
|
|
2873
3193
|
*
|
|
2874
3194
|
* @param control - The form control object from useForm
|
|
2875
|
-
* @param
|
|
3195
|
+
* @param name - Can be field name, array of field names, or undefined to watch the entire form
|
|
3196
|
+
* @param disabled - Disable subscription
|
|
3197
|
+
* @param exact - Whether to watch exact field names or not
|
|
3198
|
+
* @param defaultValue - The default value to use if the field is not yet set
|
|
3199
|
+
* @param compute - Function to compute derived values from watched fields
|
|
2876
3200
|
* @param render - The function that receives watched values and returns ReactNode
|
|
2877
3201
|
* @returns The result of calling render function with watched values
|
|
2878
3202
|
*
|
|
@@ -2890,7 +3214,7 @@ function useForm(props = {}) {
|
|
|
2890
3214
|
* />
|
|
2891
3215
|
* ```
|
|
2892
3216
|
*/
|
|
2893
|
-
const Watch = (
|
|
3217
|
+
const Watch = (props) => props.render(useWatch(props));
|
|
2894
3218
|
|
|
2895
3219
|
export { Controller, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
|
|
2896
3220
|
//# sourceMappingURL=index.esm.mjs.map
|