react-hook-form 7.25.2 → 7.27.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 +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 +253 -14
- 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 +173 -10
- package/dist/types/fieldArray.d.ts.map +1 -1
- package/dist/types/form.d.ts +376 -1
- 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 +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));
|
@@ -534,11 +743,11 @@ const useFieldArray = (props) => {
|
|
534
743
|
}, true, false);
|
535
744
|
};
|
536
745
|
const replace = (value) => {
|
537
|
-
const updatedFieldArrayValues = convertToArrayPayload(value);
|
746
|
+
const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
|
538
747
|
ids.current = updatedFieldArrayValues.map(generateId);
|
539
748
|
updateValues([...updatedFieldArrayValues]);
|
540
749
|
setFields([...updatedFieldArrayValues]);
|
541
|
-
control._updateFieldArray(name, [...updatedFieldArrayValues], () =>
|
750
|
+
control._updateFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
|
542
751
|
};
|
543
752
|
React.useEffect(() => {
|
544
753
|
control._stateFlags.action = false;
|
@@ -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 = [];
|
@@ -970,8 +1179,7 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
|
|
970
1179
|
const maxOutput = getValueAndMessage(max);
|
971
1180
|
const minOutput = getValueAndMessage(min);
|
972
1181
|
if (!isNaN(inputValue)) {
|
973
|
-
const valueNumber = ref.valueAsNumber ||
|
974
|
-
parseFloat(inputValue);
|
1182
|
+
const valueNumber = ref.valueAsNumber || +inputValue;
|
975
1183
|
if (!isNullOrUndefined(maxOutput.value)) {
|
976
1184
|
exceedMax = valueNumber > maxOutput.value;
|
977
1185
|
}
|
@@ -1239,7 +1447,8 @@ function createFormControl(props = {}) {
|
|
1239
1447
|
_subjects.state.next(updatedFormState);
|
1240
1448
|
}
|
1241
1449
|
validateFields[name]--;
|
1242
|
-
if (_proxyFormState.isValidating &&
|
1450
|
+
if (_proxyFormState.isValidating &&
|
1451
|
+
!Object.values(validateFields).some((v) => v)) {
|
1243
1452
|
_subjects.state.next({
|
1244
1453
|
isValidating: false,
|
1245
1454
|
});
|
@@ -1617,9 +1826,7 @@ function createFormControl(props = {}) {
|
|
1617
1826
|
e.persist && e.persist();
|
1618
1827
|
}
|
1619
1828
|
let hasNoPromiseError = true;
|
1620
|
-
let fieldValues =
|
1621
|
-
? cloneObject(_formValues)
|
1622
|
-
: Object.assign({}, _formValues);
|
1829
|
+
let fieldValues = cloneObject(_formValues);
|
1623
1830
|
_subjects.state.next({
|
1624
1831
|
isSubmitting: true,
|
1625
1832
|
});
|
@@ -1641,7 +1848,9 @@ function createFormControl(props = {}) {
|
|
1641
1848
|
await onValid(fieldValues, e);
|
1642
1849
|
}
|
1643
1850
|
else {
|
1644
|
-
|
1851
|
+
if (onInvalid) {
|
1852
|
+
await onInvalid(Object.assign({}, _formState.errors), e);
|
1853
|
+
}
|
1645
1854
|
_options.shouldFocusError &&
|
1646
1855
|
focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
|
1647
1856
|
}
|
@@ -1763,9 +1972,10 @@ function createFormControl(props = {}) {
|
|
1763
1972
|
isSubmitSuccessful: false,
|
1764
1973
|
});
|
1765
1974
|
};
|
1766
|
-
const setFocus = (name) => {
|
1975
|
+
const setFocus = (name, options = {}) => {
|
1767
1976
|
const field = get(_fields, name)._f;
|
1768
|
-
|
1977
|
+
const fieldRef = field.refs ? field.refs[0] : field.ref;
|
1978
|
+
options.shouldSelect ? fieldRef.select() : fieldRef.focus();
|
1769
1979
|
};
|
1770
1980
|
return {
|
1771
1981
|
control: {
|
@@ -1831,6 +2041,35 @@ function createFormControl(props = {}) {
|
|
1831
2041
|
};
|
1832
2042
|
}
|
1833
2043
|
|
2044
|
+
/**
|
2045
|
+
* Custom hook to mange the entire form.
|
2046
|
+
*
|
2047
|
+
* @remarks
|
2048
|
+
* [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)
|
2049
|
+
*
|
2050
|
+
* @param props - form configuration and validation parameters.
|
2051
|
+
*
|
2052
|
+
* @returns methods - individual functions to manage the form state. {@link UseFormReturn}
|
2053
|
+
*
|
2054
|
+
* @example
|
2055
|
+
* ```tsx
|
2056
|
+
* function App() {
|
2057
|
+
* const { register, handleSubmit, watch, formState: { errors } } = useForm();
|
2058
|
+
* const onSubmit = data => console.log(data);
|
2059
|
+
*
|
2060
|
+
* console.log(watch("example"));
|
2061
|
+
*
|
2062
|
+
* return (
|
2063
|
+
* <form onSubmit={handleSubmit(onSubmit)}>
|
2064
|
+
* <input defaultValue="test" {...register("example")} />
|
2065
|
+
* <input {...register("exampleRequired", { required: true })} />
|
2066
|
+
* {errors.exampleRequired && <span>This field is required</span>}
|
2067
|
+
* <input type="submit" />
|
2068
|
+
* </form>
|
2069
|
+
* );
|
2070
|
+
* }
|
2071
|
+
* ```
|
2072
|
+
*/
|
1834
2073
|
function useForm(props = {}) {
|
1835
2074
|
const _formControl = React.useRef();
|
1836
2075
|
const [formState, updateFormState] = React.useState({
|