react-hook-form 7.25.3 → 7.27.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 +377 -311
- 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 +254 -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 +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 -10
- package/dist/types/fieldArray.d.ts.map +1 -1
- package/dist/types/form.d.ts +380 -5
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/resolvers.d.ts +1 -1
- package/dist/types/resolvers.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 +30 -1
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormContext.d.ts +62 -2
- 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/dist/utils/unset.d.ts.map +1 -1
- package/package.json +9 -9
package/dist/index.esm.mjs
CHANGED
@@ -67,7 +67,67 @@ var omit = (source, key) => {
|
|
67
67
|
};
|
68
68
|
|
69
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
|
+
*/
|
70
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
|
+
*/
|
71
131
|
const FormProvider = (props) => (React.createElement(HookFormContext.Provider, { value: omit(props, 'children') }, props.children));
|
72
132
|
|
73
133
|
var getProxyFormState = (formState, _proxyFormState, localProxyFormState, isRoot = true) => {
|
@@ -125,6 +185,36 @@ function useSubscribe(props) {
|
|
125
185
|
}, [props.disabled]);
|
126
186
|
}
|
127
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
|
+
*/
|
128
218
|
function useFormState(props) {
|
129
219
|
const methods = useFormContext();
|
130
220
|
const { control = methods.control, disabled, name, exact } = props || {};
|
@@ -182,6 +272,22 @@ var objectHasFunction = (data) => {
|
|
182
272
|
return false;
|
183
273
|
};
|
184
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
|
+
*/
|
185
291
|
function useWatch(props) {
|
186
292
|
const methods = useFormContext();
|
187
293
|
const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
|
@@ -213,6 +319,30 @@ function useWatch(props) {
|
|
213
319
|
return value;
|
214
320
|
}
|
215
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
|
+
*/
|
216
346
|
function useController(props) {
|
217
347
|
const methods = useFormContext();
|
218
348
|
const { name, control = methods.control, shouldUnregister } = props;
|
@@ -221,7 +351,7 @@ function useController(props) {
|
|
221
351
|
control,
|
222
352
|
name,
|
223
353
|
defaultValue: get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)),
|
224
|
-
exact:
|
354
|
+
exact: true,
|
225
355
|
});
|
226
356
|
const formState = useFormState({
|
227
357
|
control,
|
@@ -283,6 +413,48 @@ function useController(props) {
|
|
283
413
|
};
|
284
414
|
}
|
285
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
|
+
*/
|
286
458
|
const Controller = (props) => props.render(useController(props));
|
287
459
|
|
288
460
|
var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
|
@@ -432,7 +604,44 @@ var updateAt = (fieldValues, index, value) => {
|
|
432
604
|
return fieldValues;
|
433
605
|
};
|
434
606
|
|
435
|
-
|
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) {
|
436
645
|
const methods = useFormContext();
|
437
646
|
const { control = methods.control, name, keyName = 'id', shouldUnregister, } = props;
|
438
647
|
const [fields, setFields] = React.useState(control._getFieldArray(name));
|
@@ -581,7 +790,7 @@ const useFieldArray = (props) => {
|
|
581
790
|
replace: React.useCallback(replace, [updateValues, name, control]),
|
582
791
|
fields: React.useMemo(() => fields.map((field, index) => (Object.assign(Object.assign({}, field), { [keyName]: ids.current[index] || generateId() }))), [fields, keyName]),
|
583
792
|
};
|
584
|
-
}
|
793
|
+
}
|
585
794
|
|
586
795
|
function createSubject() {
|
587
796
|
let _observers = [];
|
@@ -700,7 +909,9 @@ function unset(object, path) {
|
|
700
909
|
if (currentPathsLength === index &&
|
701
910
|
((isObject(objectRef) && isEmptyObject(objectRef)) ||
|
702
911
|
(Array.isArray(objectRef) &&
|
703
|
-
!objectRef.filter((data) => (isObject(data) && !isEmptyObject(data)) ||
|
912
|
+
!objectRef.filter((data) => (isObject(data) && !isEmptyObject(data)) ||
|
913
|
+
isBoolean(data) ||
|
914
|
+
(Array.isArray(data) && data.length)).length))) {
|
704
915
|
previousObjRef ? delete previousObjRef[item] : delete object[item];
|
705
916
|
}
|
706
917
|
previousObjRef = objectRef;
|
@@ -970,8 +1181,7 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
|
|
970
1181
|
const maxOutput = getValueAndMessage(max);
|
971
1182
|
const minOutput = getValueAndMessage(min);
|
972
1183
|
if (!isNaN(inputValue)) {
|
973
|
-
const valueNumber = ref.valueAsNumber ||
|
974
|
-
parseFloat(inputValue);
|
1184
|
+
const valueNumber = ref.valueAsNumber || +inputValue;
|
975
1185
|
if (!isNullOrUndefined(maxOutput.value)) {
|
976
1186
|
exceedMax = valueNumber > maxOutput.value;
|
977
1187
|
}
|
@@ -1239,7 +1449,8 @@ function createFormControl(props = {}) {
|
|
1239
1449
|
_subjects.state.next(updatedFormState);
|
1240
1450
|
}
|
1241
1451
|
validateFields[name]--;
|
1242
|
-
if (_proxyFormState.isValidating &&
|
1452
|
+
if (_proxyFormState.isValidating &&
|
1453
|
+
!Object.values(validateFields).some((v) => v)) {
|
1243
1454
|
_subjects.state.next({
|
1244
1455
|
isValidating: false,
|
1245
1456
|
});
|
@@ -1617,9 +1828,7 @@ function createFormControl(props = {}) {
|
|
1617
1828
|
e.persist && e.persist();
|
1618
1829
|
}
|
1619
1830
|
let hasNoPromiseError = true;
|
1620
|
-
let fieldValues =
|
1621
|
-
? cloneObject(_formValues)
|
1622
|
-
: Object.assign({}, _formValues);
|
1831
|
+
let fieldValues = cloneObject(_formValues);
|
1623
1832
|
_subjects.state.next({
|
1624
1833
|
isSubmitting: true,
|
1625
1834
|
});
|
@@ -1641,7 +1850,9 @@ function createFormControl(props = {}) {
|
|
1641
1850
|
await onValid(fieldValues, e);
|
1642
1851
|
}
|
1643
1852
|
else {
|
1644
|
-
|
1853
|
+
if (onInvalid) {
|
1854
|
+
await onInvalid(Object.assign({}, _formState.errors), e);
|
1855
|
+
}
|
1645
1856
|
_options.shouldFocusError &&
|
1646
1857
|
focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
|
1647
1858
|
}
|
@@ -1763,9 +1974,10 @@ function createFormControl(props = {}) {
|
|
1763
1974
|
isSubmitSuccessful: false,
|
1764
1975
|
});
|
1765
1976
|
};
|
1766
|
-
const setFocus = (name) => {
|
1977
|
+
const setFocus = (name, options = {}) => {
|
1767
1978
|
const field = get(_fields, name)._f;
|
1768
|
-
|
1979
|
+
const fieldRef = field.refs ? field.refs[0] : field.ref;
|
1980
|
+
options.shouldSelect ? fieldRef.select() : fieldRef.focus();
|
1769
1981
|
};
|
1770
1982
|
return {
|
1771
1983
|
control: {
|
@@ -1831,6 +2043,35 @@ function createFormControl(props = {}) {
|
|
1831
2043
|
};
|
1832
2044
|
}
|
1833
2045
|
|
2046
|
+
/**
|
2047
|
+
* Custom hook to mange the entire form.
|
2048
|
+
*
|
2049
|
+
* @remarks
|
2050
|
+
* [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)
|
2051
|
+
*
|
2052
|
+
* @param props - form configuration and validation parameters.
|
2053
|
+
*
|
2054
|
+
* @returns methods - individual functions to manage the form state. {@link UseFormReturn}
|
2055
|
+
*
|
2056
|
+
* @example
|
2057
|
+
* ```tsx
|
2058
|
+
* function App() {
|
2059
|
+
* const { register, handleSubmit, watch, formState: { errors } } = useForm();
|
2060
|
+
* const onSubmit = data => console.log(data);
|
2061
|
+
*
|
2062
|
+
* console.log(watch("example"));
|
2063
|
+
*
|
2064
|
+
* return (
|
2065
|
+
* <form onSubmit={handleSubmit(onSubmit)}>
|
2066
|
+
* <input defaultValue="test" {...register("example")} />
|
2067
|
+
* <input {...register("exampleRequired", { required: true })} />
|
2068
|
+
* {errors.exampleRequired && <span>This field is required</span>}
|
2069
|
+
* <input type="submit" />
|
2070
|
+
* </form>
|
2071
|
+
* );
|
2072
|
+
* }
|
2073
|
+
* ```
|
2074
|
+
*/
|
1834
2075
|
function useForm(props = {}) {
|
1835
2076
|
const _formControl = React.useRef();
|
1836
2077
|
const [formState, updateFormState] = React.useState({
|