react-hook-form 7.25.1 → 7.26.1
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 +383 -311
- 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 +252 -13
- 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/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 +371 -0
- 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 +8 -8
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,7 +67,67 @@ 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) => {
|
@@ -124,6 +185,36 @@ function useSubscribe(props) {
|
|
124
185
|
}, [props.disabled]);
|
125
186
|
}
|
126
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
|
+
*/
|
127
218
|
function useFormState(props) {
|
128
219
|
const methods = useFormContext();
|
129
220
|
const { control = methods.control, disabled, name, exact } = props || {};
|
@@ -181,6 +272,22 @@ var objectHasFunction = (data) => {
|
|
181
272
|
return false;
|
182
273
|
};
|
183
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
|
+
*/
|
184
291
|
function useWatch(props) {
|
185
292
|
const methods = useFormContext();
|
186
293
|
const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
|
@@ -212,6 +319,30 @@ function useWatch(props) {
|
|
212
319
|
return value;
|
213
320
|
}
|
214
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
|
+
*/
|
215
346
|
function useController(props) {
|
216
347
|
const methods = useFormContext();
|
217
348
|
const { name, control = methods.control, shouldUnregister } = props;
|
@@ -220,7 +351,7 @@ function useController(props) {
|
|
220
351
|
control,
|
221
352
|
name,
|
222
353
|
defaultValue: get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)),
|
223
|
-
exact:
|
354
|
+
exact: true,
|
224
355
|
});
|
225
356
|
const formState = useFormState({
|
226
357
|
control,
|
@@ -282,6 +413,48 @@ function useController(props) {
|
|
282
413
|
};
|
283
414
|
}
|
284
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
|
+
*/
|
285
458
|
const Controller = (props) => props.render(useController(props));
|
286
459
|
|
287
460
|
var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
|
@@ -431,7 +604,44 @@ var updateAt = (fieldValues, index, value) => {
|
|
431
604
|
return fieldValues;
|
432
605
|
};
|
433
606
|
|
434
|
-
|
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) {
|
435
645
|
const methods = useFormContext();
|
436
646
|
const { control = methods.control, name, keyName = 'id', shouldUnregister, } = props;
|
437
647
|
const [fields, setFields] = React.useState(control._getFieldArray(name));
|
@@ -533,11 +743,11 @@ const useFieldArray = (props) => {
|
|
533
743
|
}, true, false);
|
534
744
|
};
|
535
745
|
const replace = (value) => {
|
536
|
-
const updatedFieldArrayValues = convertToArrayPayload(value);
|
746
|
+
const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
|
537
747
|
ids.current = updatedFieldArrayValues.map(generateId);
|
538
748
|
updateValues([...updatedFieldArrayValues]);
|
539
749
|
setFields([...updatedFieldArrayValues]);
|
540
|
-
control._updateFieldArray(name, [...updatedFieldArrayValues], () =>
|
750
|
+
control._updateFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
|
541
751
|
};
|
542
752
|
React.useEffect(() => {
|
543
753
|
control._stateFlags.action = false;
|
@@ -580,7 +790,7 @@ const useFieldArray = (props) => {
|
|
580
790
|
replace: React.useCallback(replace, [updateValues, name, control]),
|
581
791
|
fields: React.useMemo(() => fields.map((field, index) => (Object.assign(Object.assign({}, field), { [keyName]: ids.current[index] || generateId() }))), [fields, keyName]),
|
582
792
|
};
|
583
|
-
}
|
793
|
+
}
|
584
794
|
|
585
795
|
function createSubject() {
|
586
796
|
let _observers = [];
|
@@ -969,8 +1179,7 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
|
|
969
1179
|
const maxOutput = getValueAndMessage(max);
|
970
1180
|
const minOutput = getValueAndMessage(min);
|
971
1181
|
if (!isNaN(inputValue)) {
|
972
|
-
const valueNumber = ref.valueAsNumber ||
|
973
|
-
parseFloat(inputValue);
|
1182
|
+
const valueNumber = ref.valueAsNumber || +inputValue;
|
974
1183
|
if (!isNullOrUndefined(maxOutput.value)) {
|
975
1184
|
exceedMax = valueNumber > maxOutput.value;
|
976
1185
|
}
|
@@ -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
|
});
|
@@ -1413,7 +1623,7 @@ function createFormControl(props = {}) {
|
|
1413
1623
|
const fieldValue = target.type
|
1414
1624
|
? getFieldValue(field._f)
|
1415
1625
|
: getEventValue(event);
|
1416
|
-
const isBlurEvent = event.type === EVENTS.BLUR;
|
1626
|
+
const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
|
1417
1627
|
const shouldSkipValidation = (!hasValidation(field._f) &&
|
1418
1628
|
!_options.resolver &&
|
1419
1629
|
!get(_formState.errors, name) &&
|
@@ -1616,9 +1826,7 @@ function createFormControl(props = {}) {
|
|
1616
1826
|
e.persist && e.persist();
|
1617
1827
|
}
|
1618
1828
|
let hasNoPromiseError = true;
|
1619
|
-
let fieldValues =
|
1620
|
-
? cloneObject(_formValues)
|
1621
|
-
: Object.assign({}, _formValues);
|
1829
|
+
let fieldValues = cloneObject(_formValues);
|
1622
1830
|
_subjects.state.next({
|
1623
1831
|
isSubmitting: true,
|
1624
1832
|
});
|
@@ -1640,7 +1848,9 @@ function createFormControl(props = {}) {
|
|
1640
1848
|
await onValid(fieldValues, e);
|
1641
1849
|
}
|
1642
1850
|
else {
|
1643
|
-
|
1851
|
+
if (onInvalid) {
|
1852
|
+
await onInvalid(Object.assign({}, _formState.errors), e);
|
1853
|
+
}
|
1644
1854
|
_options.shouldFocusError &&
|
1645
1855
|
focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
|
1646
1856
|
}
|
@@ -1830,6 +2040,35 @@ function createFormControl(props = {}) {
|
|
1830
2040
|
};
|
1831
2041
|
}
|
1832
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
|
+
*/
|
1833
2072
|
function useForm(props = {}) {
|
1834
2073
|
const _formControl = React.useRef();
|
1835
2074
|
const [formState, updateFormState] = React.useState({
|