react-hook-form 7.25.0 → 7.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +384 -310
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/controller.d.ts +42 -0
- package/dist/controller.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 +320 -88
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/getProxyFormState.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/types/controller.d.ts +21 -0
- package/dist/types/controller.d.ts.map +1 -1
- package/dist/types/fieldArray.d.ts +172 -9
- package/dist/types/fieldArray.d.ts.map +1 -1
- package/dist/types/form.d.ts +376 -5
- package/dist/types/form.d.ts.map +1 -1
- package/dist/useController.d.ts +24 -0
- package/dist/useController.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts +39 -2
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useForm.d.ts +29 -0
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormContext.d.ts +60 -0
- package/dist/useFormContext.d.ts.map +1 -1
- package/dist/useFormState.d.ts +30 -0
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useWatch.d.ts +77 -0
- package/dist/useWatch.d.ts.map +1 -1
- package/package.json +16 -16
package/dist/index.esm.mjs
CHANGED
@@ -40,6 +40,7 @@ var get = (obj, path, defaultValue) => {
|
|
40
40
|
|
41
41
|
const EVENTS = {
|
42
42
|
BLUR: 'blur',
|
43
|
+
FOCUS_OUT: 'focusout',
|
43
44
|
CHANGE: 'change',
|
44
45
|
};
|
45
46
|
const VALIDATION_MODE = {
|
@@ -66,26 +67,81 @@ var omit = (source, key) => {
|
|
66
67
|
};
|
67
68
|
|
68
69
|
const HookFormContext = React.createContext(null);
|
70
|
+
/**
|
71
|
+
* 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}.
|
72
|
+
*
|
73
|
+
* @remarks
|
74
|
+
* [API](https://react-hook-form.com/api/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
75
|
+
*
|
76
|
+
* @returns return all useForm methods
|
77
|
+
*
|
78
|
+
* @example
|
79
|
+
* ```tsx
|
80
|
+
* function App() {
|
81
|
+
* const methods = useForm();
|
82
|
+
* const onSubmit = data => console.log(data);
|
83
|
+
*
|
84
|
+
* return (
|
85
|
+
* <FormProvider {...methods} >
|
86
|
+
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
87
|
+
* <NestedInput />
|
88
|
+
* <input type="submit" />
|
89
|
+
* </form>
|
90
|
+
* </FormProvider>
|
91
|
+
* );
|
92
|
+
* }
|
93
|
+
*
|
94
|
+
* function NestedInput() {
|
95
|
+
* const { register } = useFormContext(); // retrieve all hook methods
|
96
|
+
* return <input {...register("test")} />;
|
97
|
+
* }
|
98
|
+
* ```
|
99
|
+
*/
|
69
100
|
const useFormContext = () => React.useContext(HookFormContext);
|
101
|
+
/**
|
102
|
+
* A provider component that propagates the `useForm` methods to all children components via [React Context](https://reactjs.org/docs/context.html) API. To be used with {@link useFormContext}.
|
103
|
+
*
|
104
|
+
* @remarks
|
105
|
+
* [API](https://react-hook-form.com/api/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
106
|
+
*
|
107
|
+
* @param props - all useFrom methods
|
108
|
+
*
|
109
|
+
* @example
|
110
|
+
* ```tsx
|
111
|
+
* function App() {
|
112
|
+
* const methods = useForm();
|
113
|
+
* const onSubmit = data => console.log(data);
|
114
|
+
*
|
115
|
+
* return (
|
116
|
+
* <FormProvider {...methods} >
|
117
|
+
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
118
|
+
* <NestedInput />
|
119
|
+
* <input type="submit" />
|
120
|
+
* </form>
|
121
|
+
* </FormProvider>
|
122
|
+
* );
|
123
|
+
* }
|
124
|
+
*
|
125
|
+
* function NestedInput() {
|
126
|
+
* const { register } = useFormContext(); // retrieve all hook methods
|
127
|
+
* return <input {...register("test")} />;
|
128
|
+
* }
|
129
|
+
* ```
|
130
|
+
*/
|
70
131
|
const FormProvider = (props) => (React.createElement(HookFormContext.Provider, { value: omit(props, 'children') }, props.children));
|
71
132
|
|
72
133
|
var getProxyFormState = (formState, _proxyFormState, localProxyFormState, isRoot = true) => {
|
73
|
-
function createGetter(prop) {
|
74
|
-
return () => {
|
75
|
-
if (prop in formState) {
|
76
|
-
if (_proxyFormState[prop] !== VALIDATION_MODE.all) {
|
77
|
-
_proxyFormState[prop] = !isRoot || VALIDATION_MODE.all;
|
78
|
-
}
|
79
|
-
localProxyFormState && (localProxyFormState[prop] = true);
|
80
|
-
return formState[prop];
|
81
|
-
}
|
82
|
-
return undefined;
|
83
|
-
};
|
84
|
-
}
|
85
134
|
const result = {};
|
86
135
|
for (const key in formState) {
|
87
136
|
Object.defineProperty(result, key, {
|
88
|
-
get:
|
137
|
+
get: () => {
|
138
|
+
const _key = key;
|
139
|
+
if (_proxyFormState[_key] !== VALIDATION_MODE.all) {
|
140
|
+
_proxyFormState[_key] = !isRoot || VALIDATION_MODE.all;
|
141
|
+
}
|
142
|
+
localProxyFormState && (localProxyFormState[_key] = true);
|
143
|
+
return formState[_key];
|
144
|
+
},
|
89
145
|
});
|
90
146
|
}
|
91
147
|
return result;
|
@@ -129,6 +185,36 @@ function useSubscribe(props) {
|
|
129
185
|
}, [props.disabled]);
|
130
186
|
}
|
131
187
|
|
188
|
+
/**
|
189
|
+
* 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.
|
190
|
+
*
|
191
|
+
* @remarks
|
192
|
+
* [API](https://react-hook-form.com/api/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly)
|
193
|
+
*
|
194
|
+
* @param props - include options on specify fields to subscribe. {@link UseFormStateReturn}
|
195
|
+
*
|
196
|
+
* @example
|
197
|
+
* ```tsx
|
198
|
+
* function App() {
|
199
|
+
* const { register, handleSubmit, control } = useForm({
|
200
|
+
* defaultValues: {
|
201
|
+
* firstName: "firstName"
|
202
|
+
* }});
|
203
|
+
* const { dirtyFields } = useFormState({
|
204
|
+
* control
|
205
|
+
* });
|
206
|
+
* const onSubmit = (data) => console.log(data);
|
207
|
+
*
|
208
|
+
* return (
|
209
|
+
* <form onSubmit={handleSubmit(onSubmit)}>
|
210
|
+
* <input {...register("firstName")} placeholder="First Name" />
|
211
|
+
* {dirtyFields.firstName && <p>Field is dirty.</p>}
|
212
|
+
* <input type="submit" />
|
213
|
+
* </form>
|
214
|
+
* );
|
215
|
+
* }
|
216
|
+
* ```
|
217
|
+
*/
|
132
218
|
function useFormState(props) {
|
133
219
|
const methods = useFormContext();
|
134
220
|
const { control = methods.control, disabled, name, exact } = props || {};
|
@@ -186,6 +272,22 @@ var objectHasFunction = (data) => {
|
|
186
272
|
return false;
|
187
273
|
};
|
188
274
|
|
275
|
+
/**
|
276
|
+
* Custom hook to subscribe to field change and isolate re-rendering at the component level.
|
277
|
+
*
|
278
|
+
* @remarks
|
279
|
+
*
|
280
|
+
* [API](https://react-hook-form.com/api/usewatch) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-usewatch-h9i5e)
|
281
|
+
*
|
282
|
+
* @example
|
283
|
+
* ```tsx
|
284
|
+
* const { watch } = useForm();
|
285
|
+
* const values = useWatch({
|
286
|
+
* name: "fieldName"
|
287
|
+
* control,
|
288
|
+
* })
|
289
|
+
* ```
|
290
|
+
*/
|
189
291
|
function useWatch(props) {
|
190
292
|
const methods = useFormContext();
|
191
293
|
const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
|
@@ -217,6 +319,30 @@ function useWatch(props) {
|
|
217
319
|
return value;
|
218
320
|
}
|
219
321
|
|
322
|
+
/**
|
323
|
+
* Custom hook to work with controlled component, this function provide you with both form and field level state. Re-render is isolated at the hook level.
|
324
|
+
*
|
325
|
+
* @remarks
|
326
|
+
* [API](https://react-hook-form.com/api/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px)
|
327
|
+
*
|
328
|
+
* @param props - the path name to the form field value, and validation rules.
|
329
|
+
*
|
330
|
+
* @returns field properties, field and form state. {@link UseControllerReturn}
|
331
|
+
*
|
332
|
+
* @example
|
333
|
+
* ```tsx
|
334
|
+
* function Input(props) {
|
335
|
+
* const { field, fieldState, formState } = useController(props);
|
336
|
+
* return (
|
337
|
+
* <div>
|
338
|
+
* <input {...field} placeholder={props.name} />
|
339
|
+
* <p>{fieldState.isTouched && "Touched"}</p>
|
340
|
+
* <p>{formState.isSubmitted ? "submitted" : ""}</p>
|
341
|
+
* </div>
|
342
|
+
* );
|
343
|
+
* }
|
344
|
+
* ```
|
345
|
+
*/
|
220
346
|
function useController(props) {
|
221
347
|
const methods = useFormContext();
|
222
348
|
const { name, control = methods.control, shouldUnregister } = props;
|
@@ -280,13 +406,55 @@ function useController(props) {
|
|
280
406
|
reportValidity: () => elm.reportValidity(),
|
281
407
|
};
|
282
408
|
}
|
283
|
-
}, [name, control]),
|
409
|
+
}, [name, control._fields]),
|
284
410
|
},
|
285
411
|
formState,
|
286
412
|
fieldState: control.getFieldState(name, formState),
|
287
413
|
};
|
288
414
|
}
|
289
415
|
|
416
|
+
/**
|
417
|
+
* Component based on `useController` hook to work with controlled component.
|
418
|
+
*
|
419
|
+
* @remarks
|
420
|
+
* [API](https://react-hook-form.com/api/usecontroller/controller) • [Demo](https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw) • [Video](https://www.youtube.com/watch?v=N2UNk_UCVyA)
|
421
|
+
*
|
422
|
+
* @param props - the path name to the form field value, and validation rules.
|
423
|
+
*
|
424
|
+
* @returns provide field handler functions, field and form state.
|
425
|
+
*
|
426
|
+
* @example
|
427
|
+
* ```tsx
|
428
|
+
* function App() {
|
429
|
+
* const { control } = useForm<FormValues>({
|
430
|
+
* defaultValues: {
|
431
|
+
* test: ""
|
432
|
+
* }
|
433
|
+
* });
|
434
|
+
*
|
435
|
+
* return (
|
436
|
+
* <form>
|
437
|
+
* <Controller
|
438
|
+
* control={control}
|
439
|
+
* name="test"
|
440
|
+
* render={({ field: { onChange, onBlur, value, ref }, formState, fieldState }) => (
|
441
|
+
* <>
|
442
|
+
* <input
|
443
|
+
* onChange={onChange} // send value to hook form
|
444
|
+
* onBlur={onBlur} // notify when input is touched
|
445
|
+
* value={value} // return updated value
|
446
|
+
* ref={ref} // set ref for focus management
|
447
|
+
* />
|
448
|
+
* <p>{formState.isSubmitted ? "submitted" : ""}</p>
|
449
|
+
* <p>{fieldState.isTouched ? "touched" : ""}</p>
|
450
|
+
* </>
|
451
|
+
* )}
|
452
|
+
* />
|
453
|
+
* </form>
|
454
|
+
* );
|
455
|
+
* }
|
456
|
+
* ```
|
457
|
+
*/
|
290
458
|
const Controller = (props) => props.render(useController(props));
|
291
459
|
|
292
460
|
var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
|
@@ -436,7 +604,44 @@ var updateAt = (fieldValues, index, value) => {
|
|
436
604
|
return fieldValues;
|
437
605
|
};
|
438
606
|
|
439
|
-
|
607
|
+
/**
|
608
|
+
* A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc.
|
609
|
+
*
|
610
|
+
* @remarks
|
611
|
+
* [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
|
612
|
+
*
|
613
|
+
* @param props - useFieldArray props
|
614
|
+
*
|
615
|
+
* @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
|
616
|
+
*
|
617
|
+
* @example
|
618
|
+
* ```tsx
|
619
|
+
* function App() {
|
620
|
+
* const { register, control, handleSubmit, reset, trigger, setError } = useForm({
|
621
|
+
* defaultValues: {
|
622
|
+
* test: []
|
623
|
+
* }
|
624
|
+
* });
|
625
|
+
* const { fields, append } = useFieldArray({
|
626
|
+
* control,
|
627
|
+
* name: "test"
|
628
|
+
* });
|
629
|
+
*
|
630
|
+
* return (
|
631
|
+
* <form onSubmit={handleSubmit(data => console.log(data))}>
|
632
|
+
* {fields.map((item, index) => (
|
633
|
+
* <input key={item.id} {...register(`test.${index}.firstName`)} />
|
634
|
+
* ))}
|
635
|
+
* <button type="button" onClick={() => append({ firstName: "bill" })}>
|
636
|
+
* append
|
637
|
+
* </button>
|
638
|
+
* <input type="submit" />
|
639
|
+
* </form>
|
640
|
+
* );
|
641
|
+
* }
|
642
|
+
* ```
|
643
|
+
*/
|
644
|
+
function useFieldArray(props) {
|
440
645
|
const methods = useFormContext();
|
441
646
|
const { control = methods.control, name, keyName = 'id', shouldUnregister, } = props;
|
442
647
|
const [fields, setFields] = React.useState(control._getFieldArray(name));
|
@@ -460,89 +665,89 @@ const useFieldArray = (props) => {
|
|
460
665
|
});
|
461
666
|
const updateValues = React.useCallback((updatedFieldArrayValues) => {
|
462
667
|
_actioned.current = true;
|
463
|
-
|
668
|
+
control._updateFieldArray(name, updatedFieldArrayValues);
|
464
669
|
}, [control, name]);
|
465
670
|
const append$1 = (value, options) => {
|
466
671
|
const appendValue = convertToArrayPayload(cloneObject(value));
|
467
672
|
const updatedFieldArrayValues = append(control._getFieldArray(name), appendValue);
|
468
673
|
control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
|
469
674
|
ids.current = append(ids.current, appendValue.map(generateId));
|
470
|
-
setFields(updatedFieldArrayValues);
|
471
675
|
updateValues(updatedFieldArrayValues);
|
472
|
-
|
676
|
+
setFields(updatedFieldArrayValues);
|
677
|
+
control._updateFieldArray(name, updatedFieldArrayValues, append, {
|
473
678
|
argA: fillEmptyArray(value),
|
474
|
-
}
|
679
|
+
});
|
475
680
|
};
|
476
681
|
const prepend$1 = (value, options) => {
|
477
682
|
const prependValue = convertToArrayPayload(cloneObject(value));
|
478
683
|
const updatedFieldArrayValues = prepend(control._getFieldArray(name), prependValue);
|
479
684
|
control._names.focus = getFocusFieldName(name, 0, options);
|
480
685
|
ids.current = prepend(ids.current, prependValue.map(generateId));
|
481
|
-
setFields(updatedFieldArrayValues);
|
482
686
|
updateValues(updatedFieldArrayValues);
|
483
|
-
|
687
|
+
setFields(updatedFieldArrayValues);
|
688
|
+
control._updateFieldArray(name, updatedFieldArrayValues, prepend, {
|
484
689
|
argA: fillEmptyArray(value),
|
485
|
-
}
|
690
|
+
});
|
486
691
|
};
|
487
692
|
const remove = (index) => {
|
488
693
|
const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
|
489
694
|
ids.current = removeArrayAt(ids.current, index);
|
490
|
-
setFields(updatedFieldArrayValues);
|
491
695
|
updateValues(updatedFieldArrayValues);
|
492
|
-
|
696
|
+
setFields(updatedFieldArrayValues);
|
697
|
+
control._updateFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
|
493
698
|
argA: index,
|
494
|
-
}
|
699
|
+
});
|
495
700
|
};
|
496
701
|
const insert$1 = (index, value, options) => {
|
497
702
|
const insertValue = convertToArrayPayload(cloneObject(value));
|
498
703
|
const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
|
499
|
-
updateValues(updatedFieldArrayValues);
|
500
704
|
control._names.focus = getFocusFieldName(name, index, options);
|
501
705
|
ids.current = insert(ids.current, index, insertValue.map(generateId));
|
706
|
+
updateValues(updatedFieldArrayValues);
|
502
707
|
setFields(updatedFieldArrayValues);
|
503
|
-
control._updateFieldArray(name, insert, {
|
708
|
+
control._updateFieldArray(name, updatedFieldArrayValues, insert, {
|
504
709
|
argA: index,
|
505
710
|
argB: fillEmptyArray(value),
|
506
|
-
}
|
711
|
+
});
|
507
712
|
};
|
508
713
|
const swap = (indexA, indexB) => {
|
509
714
|
const updatedFieldArrayValues = control._getFieldArray(name);
|
510
715
|
swapArrayAt(updatedFieldArrayValues, indexA, indexB);
|
511
716
|
swapArrayAt(ids.current, indexA, indexB);
|
512
|
-
setFields(updatedFieldArrayValues);
|
513
717
|
updateValues(updatedFieldArrayValues);
|
514
|
-
|
718
|
+
setFields(updatedFieldArrayValues);
|
719
|
+
control._updateFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
|
515
720
|
argA: indexA,
|
516
721
|
argB: indexB,
|
517
|
-
},
|
722
|
+
}, false);
|
518
723
|
};
|
519
724
|
const move = (from, to) => {
|
520
725
|
const updatedFieldArrayValues = control._getFieldArray(name);
|
521
726
|
moveArrayAt(updatedFieldArrayValues, from, to);
|
522
727
|
moveArrayAt(ids.current, from, to);
|
523
|
-
setFields(updatedFieldArrayValues);
|
524
728
|
updateValues(updatedFieldArrayValues);
|
525
|
-
|
729
|
+
setFields(updatedFieldArrayValues);
|
730
|
+
control._updateFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
|
526
731
|
argA: from,
|
527
732
|
argB: to,
|
528
|
-
},
|
733
|
+
}, false);
|
529
734
|
};
|
530
735
|
const update = (index, value) => {
|
531
736
|
const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, value);
|
532
737
|
ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
|
533
|
-
setFields([...updatedFieldArrayValues]);
|
534
738
|
updateValues(updatedFieldArrayValues);
|
535
|
-
|
739
|
+
setFields([...updatedFieldArrayValues]);
|
740
|
+
control._updateFieldArray(name, updatedFieldArrayValues, updateAt, {
|
536
741
|
argA: index,
|
537
742
|
argB: value,
|
538
|
-
},
|
743
|
+
}, true, false);
|
539
744
|
};
|
540
745
|
const replace = (value) => {
|
541
|
-
const updatedFieldArrayValues = convertToArrayPayload(value);
|
746
|
+
const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
|
542
747
|
ids.current = updatedFieldArrayValues.map(generateId);
|
543
748
|
updateValues([...updatedFieldArrayValues]);
|
544
749
|
setFields([...updatedFieldArrayValues]);
|
545
|
-
control._updateFieldArray(name, () =>
|
750
|
+
control._updateFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
|
546
751
|
};
|
547
752
|
React.useEffect(() => {
|
548
753
|
control._stateFlags.action = false;
|
@@ -568,7 +773,7 @@ const useFieldArray = (props) => {
|
|
568
773
|
control._proxyFormState.isValid && control._updateValid();
|
569
774
|
}, [fields, name, control]);
|
570
775
|
React.useEffect(() => {
|
571
|
-
!get(control._formValues, name) &&
|
776
|
+
!get(control._formValues, name) && control._updateFieldArray(name);
|
572
777
|
return () => {
|
573
778
|
(control._options.shouldUnregister || shouldUnregister) &&
|
574
779
|
control.unregister(name);
|
@@ -585,7 +790,7 @@ const useFieldArray = (props) => {
|
|
585
790
|
replace: React.useCallback(replace, [updateValues, name, control]),
|
586
791
|
fields: React.useMemo(() => fields.map((field, index) => (Object.assign(Object.assign({}, field), { [keyName]: ids.current[index] || generateId() }))), [fields, keyName]),
|
587
792
|
};
|
588
|
-
}
|
793
|
+
}
|
589
794
|
|
590
795
|
function createSubject() {
|
591
796
|
let _observers = [];
|
@@ -974,8 +1179,7 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
|
|
974
1179
|
const maxOutput = getValueAndMessage(max);
|
975
1180
|
const minOutput = getValueAndMessage(min);
|
976
1181
|
if (!isNaN(inputValue)) {
|
977
|
-
const valueNumber = ref.valueAsNumber ||
|
978
|
-
parseFloat(inputValue);
|
1182
|
+
const valueNumber = ref.valueAsNumber || +inputValue;
|
979
1183
|
if (!isNullOrUndefined(maxOutput.value)) {
|
980
1184
|
exceedMax = valueNumber > maxOutput.value;
|
981
1185
|
}
|
@@ -1138,33 +1342,38 @@ function createFormControl(props = {}) {
|
|
1138
1342
|
}
|
1139
1343
|
return isValid;
|
1140
1344
|
};
|
1141
|
-
const _updateFieldArray = (name,
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1345
|
+
const _updateFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndErrors = true) => {
|
1346
|
+
if (args && method) {
|
1347
|
+
_stateFlags.action = true;
|
1348
|
+
if (shouldUpdateFieldsAndErrors && Array.isArray(get(_fields, name))) {
|
1349
|
+
const fieldValues = method(get(_fields, name), args.argA, args.argB);
|
1350
|
+
shouldSetValues && set(_fields, name, fieldValues);
|
1351
|
+
}
|
1352
|
+
if (_proxyFormState.errors &&
|
1353
|
+
shouldUpdateFieldsAndErrors &&
|
1354
|
+
Array.isArray(get(_formState.errors, name))) {
|
1355
|
+
const errors = method(get(_formState.errors, name), args.argA, args.argB);
|
1356
|
+
shouldSetValues && set(_formState.errors, name, errors);
|
1357
|
+
unsetEmptyArray(_formState.errors, name);
|
1358
|
+
}
|
1359
|
+
if (_proxyFormState.touchedFields &&
|
1360
|
+
Array.isArray(get(_formState.touchedFields, name))) {
|
1361
|
+
const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
|
1362
|
+
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
1363
|
+
}
|
1364
|
+
if (_proxyFormState.dirtyFields) {
|
1365
|
+
_formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
|
1366
|
+
}
|
1367
|
+
_subjects.state.next({
|
1368
|
+
isDirty: _getDirty(name, values),
|
1369
|
+
dirtyFields: _formState.dirtyFields,
|
1370
|
+
errors: _formState.errors,
|
1371
|
+
isValid: _formState.isValid,
|
1372
|
+
});
|
1158
1373
|
}
|
1159
|
-
|
1160
|
-
|
1374
|
+
else {
|
1375
|
+
set(_formValues, name, values);
|
1161
1376
|
}
|
1162
|
-
_subjects.state.next({
|
1163
|
-
isDirty: _getDirty(name, values),
|
1164
|
-
dirtyFields: _formState.dirtyFields,
|
1165
|
-
errors: _formState.errors,
|
1166
|
-
isValid: _formState.isValid,
|
1167
|
-
});
|
1168
1377
|
};
|
1169
1378
|
const updateErrors = (name, error) => (set(_formState.errors, name, error),
|
1170
1379
|
_subjects.state.next({
|
@@ -1238,7 +1447,8 @@ function createFormControl(props = {}) {
|
|
1238
1447
|
_subjects.state.next(updatedFormState);
|
1239
1448
|
}
|
1240
1449
|
validateFields[name]--;
|
1241
|
-
if (_proxyFormState.isValidating &&
|
1450
|
+
if (_proxyFormState.isValidating &&
|
1451
|
+
!Object.values(validateFields).some((v) => v)) {
|
1242
1452
|
_subjects.state.next({
|
1243
1453
|
isValidating: false,
|
1244
1454
|
});
|
@@ -1343,7 +1553,10 @@ function createFormControl(props = {}) {
|
|
1343
1553
|
fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
|
1344
1554
|
}
|
1345
1555
|
}
|
1346
|
-
else if (
|
1556
|
+
else if (isFileInput(fieldReference.ref)) {
|
1557
|
+
fieldReference.ref.value = '';
|
1558
|
+
}
|
1559
|
+
else {
|
1347
1560
|
fieldReference.ref.value = fieldValue;
|
1348
1561
|
if (!fieldReference.ref.type) {
|
1349
1562
|
_subjects.watch.next({
|
@@ -1410,7 +1623,7 @@ function createFormControl(props = {}) {
|
|
1410
1623
|
const fieldValue = target.type
|
1411
1624
|
? getFieldValue(field._f)
|
1412
1625
|
: getEventValue(event);
|
1413
|
-
const isBlurEvent = event.type === EVENTS.BLUR;
|
1626
|
+
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
1414
1627
|
const shouldSkipValidation = (!hasValidation(field._f) &&
|
1415
1628
|
!_options.resolver &&
|
1416
1629
|
!get(_formState.errors, name) &&
|
@@ -1437,10 +1650,9 @@ function createFormControl(props = {}) {
|
|
1437
1650
|
}
|
1438
1651
|
!isBlurEvent && watched && _subjects.state.next({});
|
1439
1652
|
validateFields[name] = validateFields[name] ? +1 : 1;
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
});
|
1653
|
+
_subjects.state.next({
|
1654
|
+
isValidating: true,
|
1655
|
+
});
|
1444
1656
|
if (_options.resolver) {
|
1445
1657
|
const { errors } = await _executeSchema([name]);
|
1446
1658
|
const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
|
@@ -1614,9 +1826,7 @@ function createFormControl(props = {}) {
|
|
1614
1826
|
e.persist && e.persist();
|
1615
1827
|
}
|
1616
1828
|
let hasNoPromiseError = true;
|
1617
|
-
let fieldValues =
|
1618
|
-
? cloneObject(_formValues)
|
1619
|
-
: Object.assign({}, _formValues);
|
1829
|
+
let fieldValues = cloneObject(_formValues);
|
1620
1830
|
_subjects.state.next({
|
1621
1831
|
isSubmitting: true,
|
1622
1832
|
});
|
@@ -1638,7 +1848,9 @@ function createFormControl(props = {}) {
|
|
1638
1848
|
await onValid(fieldValues, e);
|
1639
1849
|
}
|
1640
1850
|
else {
|
1641
|
-
|
1851
|
+
if (onInvalid) {
|
1852
|
+
await onInvalid(Object.assign({}, _formState.errors), e);
|
1853
|
+
}
|
1642
1854
|
_options.shouldFocusError &&
|
1643
1855
|
focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
|
1644
1856
|
}
|
@@ -1781,15 +1993,9 @@ function createFormControl(props = {}) {
|
|
1781
1993
|
get _fields() {
|
1782
1994
|
return _fields;
|
1783
1995
|
},
|
1784
|
-
set _fields(value) {
|
1785
|
-
_fields = value;
|
1786
|
-
},
|
1787
1996
|
get _formValues() {
|
1788
1997
|
return _formValues;
|
1789
1998
|
},
|
1790
|
-
set _formValues(value) {
|
1791
|
-
_formValues = value;
|
1792
|
-
},
|
1793
1999
|
get _stateFlags() {
|
1794
2000
|
return _stateFlags;
|
1795
2001
|
},
|
@@ -1799,9 +2005,6 @@ function createFormControl(props = {}) {
|
|
1799
2005
|
get _defaultValues() {
|
1800
2006
|
return _defaultValues;
|
1801
2007
|
},
|
1802
|
-
set _defaultValues(value) {
|
1803
|
-
_defaultValues = value;
|
1804
|
-
},
|
1805
2008
|
get _names() {
|
1806
2009
|
return _names;
|
1807
2010
|
},
|
@@ -1837,6 +2040,35 @@ function createFormControl(props = {}) {
|
|
1837
2040
|
};
|
1838
2041
|
}
|
1839
2042
|
|
2043
|
+
/**
|
2044
|
+
* Custom hook to mange the entire form.
|
2045
|
+
*
|
2046
|
+
* @remarks
|
2047
|
+
* [API](https://react-hook-form.com/api/useform) • [Demo](https://codesandbox.io/s/react-hook-form-get-started-ts-5ksmm) • [Video](https://www.youtube.com/watch?v=RkXv4AXXC_4)
|
2048
|
+
*
|
2049
|
+
* @param props - form configuration and validation parameters.
|
2050
|
+
*
|
2051
|
+
* @returns methods - individual functions to manage the form state. {@link UseFormReturn}
|
2052
|
+
*
|
2053
|
+
* @example
|
2054
|
+
* ```tsx
|
2055
|
+
* function App() {
|
2056
|
+
* const { register, handleSubmit, watch, formState: { errors } } = useForm();
|
2057
|
+
* const onSubmit = data => console.log(data);
|
2058
|
+
*
|
2059
|
+
* console.log(watch("example"));
|
2060
|
+
*
|
2061
|
+
* return (
|
2062
|
+
* <form onSubmit={handleSubmit(onSubmit)}>
|
2063
|
+
* <input defaultValue="test" {...register("example")} />
|
2064
|
+
* <input {...register("exampleRequired", { required: true })} />
|
2065
|
+
* {errors.exampleRequired && <span>This field is required</span>}
|
2066
|
+
* <input type="submit" />
|
2067
|
+
* </form>
|
2068
|
+
* );
|
2069
|
+
* }
|
2070
|
+
* ```
|
2071
|
+
*/
|
1840
2072
|
function useForm(props = {}) {
|
1841
2073
|
const _formControl = React.useRef();
|
1842
2074
|
const [formState, updateFormState] = React.useState({
|