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.
@@ -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: !isArrayField,
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
- const useFieldArray = (props) => {
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], () => updatedFieldArrayValues, {}, true, false);
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 && !validateFields[name]) {
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 = _options.shouldUnregister
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
- onInvalid && (await onInvalid(_formState.errors, e));
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
- (field.ref.focus ? field.ref : field.refs[0]).focus();
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({