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.
@@ -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));
@@ -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)) || isBoolean(data)).length))) {
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 && !validateFields[name]) {
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 = _options.shouldUnregister
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
- onInvalid && (await onInvalid(_formState.errors, e));
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
- (field.ref.focus ? field.ref : field.refs[0]).focus();
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({