react-hook-form 8.0.0-alpha.0 → 8.0.0-alpha.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,19 @@ 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
+ * // can skip passing down the control into useWatch if the form is wrapped with the FormProvider
285
+ * const values = useWatch()
286
+ * ```
287
+ */
185
288
  function useWatch(props) {
186
289
  const methods = useFormContext();
187
290
  const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
@@ -213,6 +316,30 @@ function useWatch(props) {
213
316
  return value;
214
317
  }
215
318
 
319
+ /**
320
+ * 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.
321
+ *
322
+ * @remarks
323
+ * [API](https://react-hook-form.com/api/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px)
324
+ *
325
+ * @param props - the path name to the form field value, and validation rules.
326
+ *
327
+ * @returns field properties, field and form state. {@link UseControllerReturn}
328
+ *
329
+ * @example
330
+ * ```tsx
331
+ * function Input(props) {
332
+ * const { field, fieldState, formState } = useController(props);
333
+ * return (
334
+ * <div>
335
+ * <input {...field} placeholder={props.name} />
336
+ * <p>{fieldState.isTouched && "Touched"}</p>
337
+ * <p>{formState.isSubmitted ? "submitted" : ""}</p>
338
+ * </div>
339
+ * );
340
+ * }
341
+ * ```
342
+ */
216
343
  function useController(props) {
217
344
  const methods = useFormContext();
218
345
  const { name, control = methods.control, shouldUnregister } = props;
@@ -221,7 +348,7 @@ function useController(props) {
221
348
  control,
222
349
  name,
223
350
  defaultValue: get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)),
224
- exact: !isArrayField,
351
+ exact: true,
225
352
  });
226
353
  const formState = useFormState({
227
354
  control,
@@ -283,6 +410,48 @@ function useController(props) {
283
410
  };
284
411
  }
285
412
 
413
+ /**
414
+ * Component based on `useController` hook to work with controlled component.
415
+ *
416
+ * @remarks
417
+ * [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)
418
+ *
419
+ * @param props - the path name to the form field value, and validation rules.
420
+ *
421
+ * @returns provide field handler functions, field and form state.
422
+ *
423
+ * @example
424
+ * ```tsx
425
+ * function App() {
426
+ * const { control } = useForm<FormValues>({
427
+ * defaultValues: {
428
+ * test: ""
429
+ * }
430
+ * });
431
+ *
432
+ * return (
433
+ * <form>
434
+ * <Controller
435
+ * control={control}
436
+ * name="test"
437
+ * render={({ field: { onChange, onBlur, value, ref }, formState, fieldState }) => (
438
+ * <>
439
+ * <input
440
+ * onChange={onChange} // send value to hook form
441
+ * onBlur={onBlur} // notify when input is touched
442
+ * value={value} // return updated value
443
+ * ref={ref} // set ref for focus management
444
+ * />
445
+ * <p>{formState.isSubmitted ? "submitted" : ""}</p>
446
+ * <p>{fieldState.isTouched ? "touched" : ""}</p>
447
+ * </>
448
+ * )}
449
+ * />
450
+ * </form>
451
+ * );
452
+ * }
453
+ * ```
454
+ */
286
455
  const Controller = (props) => props.render(useController(props));
287
456
 
288
457
  var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
@@ -463,7 +632,44 @@ var updateAt = (fieldValues, index, value) => {
463
632
  return fieldValues;
464
633
  };
465
634
 
466
- const useFieldArray = (props) => {
635
+ /**
636
+ * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc.
637
+ *
638
+ * @remarks
639
+ * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
640
+ *
641
+ * @param props - useFieldArray props
642
+ *
643
+ * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
644
+ *
645
+ * @example
646
+ * ```tsx
647
+ * function App() {
648
+ * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
649
+ * defaultValues: {
650
+ * test: []
651
+ * }
652
+ * });
653
+ * const { fields, append } = useFieldArray({
654
+ * control,
655
+ * name: "test"
656
+ * });
657
+ *
658
+ * return (
659
+ * <form onSubmit={handleSubmit(data => console.log(data))}>
660
+ * {fields.map((item, index) => (
661
+ * <input key={item.id} {...register(`test.${index}.firstName`)} />
662
+ * ))}
663
+ * <button type="button" onClick={() => append({ firstName: "bill" })}>
664
+ * append
665
+ * </button>
666
+ * <input type="submit" />
667
+ * </form>
668
+ * );
669
+ * }
670
+ * ```
671
+ */
672
+ function useFieldArray(props) {
467
673
  const methods = useFormContext();
468
674
  const { control = methods.control, name, shouldUnregister } = props;
469
675
  const [fields, setFields] = React.useState(control._getFieldArray(name));
@@ -612,7 +818,7 @@ const useFieldArray = (props) => {
612
818
  replace: React.useCallback(replace, [updateValues, name, control]),
613
819
  fields: React.useMemo(() => fields.map((field, index) => (Object.assign(Object.assign({}, field), { id: ids.current[index] || generateId() }))), [fields]),
614
820
  };
615
- };
821
+ }
616
822
 
617
823
  function createSubject() {
618
824
  let _observers = [];
@@ -731,7 +937,9 @@ function unset(object, path) {
731
937
  if (currentPathsLength === index &&
732
938
  ((isObject(objectRef) && isEmptyObject(objectRef)) ||
733
939
  (Array.isArray(objectRef) &&
734
- !objectRef.filter((data) => (isObject(data) && !isEmptyObject(data)) || isBoolean(data)).length))) {
940
+ !objectRef.filter((data) => (isObject(data) && !isEmptyObject(data)) ||
941
+ isBoolean(data) ||
942
+ (Array.isArray(data) && data.length)).length))) {
735
943
  previousObjRef ? delete previousObjRef[item] : delete object[item];
736
944
  }
737
945
  previousObjRef = objectRef;
@@ -1269,7 +1477,8 @@ function createFormControl(props = {}) {
1269
1477
  _subjects.state.next(updatedFormState);
1270
1478
  }
1271
1479
  validateFields[name]--;
1272
- if (_proxyFormState.isValidating && !validateFields[name]) {
1480
+ if (_proxyFormState.isValidating &&
1481
+ !Object.values(validateFields).some((v) => v)) {
1273
1482
  _subjects.state.next({
1274
1483
  isValidating: false,
1275
1484
  });
@@ -1647,9 +1856,7 @@ function createFormControl(props = {}) {
1647
1856
  e.persist && e.persist();
1648
1857
  }
1649
1858
  let hasNoPromiseError = true;
1650
- let fieldValues = _options.shouldUnregister
1651
- ? cloneObject(_formValues)
1652
- : Object.assign({}, _formValues);
1859
+ let fieldValues = cloneObject(_formValues);
1653
1860
  _subjects.state.next({
1654
1861
  isSubmitting: true,
1655
1862
  });
@@ -1671,7 +1878,9 @@ function createFormControl(props = {}) {
1671
1878
  await onValid(fieldValues, e);
1672
1879
  }
1673
1880
  else {
1674
- onInvalid && (await onInvalid(_formState.errors, e));
1881
+ if (onInvalid) {
1882
+ await onInvalid(Object.assign({}, _formState.errors), e);
1883
+ }
1675
1884
  _options.shouldFocusError &&
1676
1885
  focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
1677
1886
  }
@@ -1726,22 +1935,6 @@ function createFormControl(props = {}) {
1726
1935
  _defaultValues = updatedValues;
1727
1936
  }
1728
1937
  if (!keepStateOptions.keepValues) {
1729
- if (isWeb && isUndefined(formValues)) {
1730
- for (const name of _names.mount) {
1731
- const field = get(_fields, name);
1732
- if (field && field._f) {
1733
- const fieldReference = Array.isArray(field._f.refs)
1734
- ? field._f.refs[0]
1735
- : field._f.ref;
1736
- try {
1737
- isHTMLElement(fieldReference) &&
1738
- fieldReference.closest('form').reset();
1739
- break;
1740
- }
1741
- catch (_a) { }
1742
- }
1743
- }
1744
- }
1745
1938
  _formValues = props.shouldUnregister
1746
1939
  ? keepStateOptions.keepDefaultValues
1747
1940
  ? cloneObject(_defaultValues)
@@ -1792,9 +1985,10 @@ function createFormControl(props = {}) {
1792
1985
  isSubmitSuccessful: false,
1793
1986
  });
1794
1987
  };
1795
- const setFocus = (name) => {
1988
+ const setFocus = (name, options = {}) => {
1796
1989
  const field = get(_fields, name)._f;
1797
- (field.ref.focus ? field.ref : field.refs[0]).focus();
1990
+ const fieldRef = field.refs ? field.refs[0] : field.ref;
1991
+ options.shouldSelect ? fieldRef.select() : fieldRef.focus();
1798
1992
  };
1799
1993
  return {
1800
1994
  control: {
@@ -1860,6 +2054,35 @@ function createFormControl(props = {}) {
1860
2054
  };
1861
2055
  }
1862
2056
 
2057
+ /**
2058
+ * Custom hook to mange the entire form.
2059
+ *
2060
+ * @remarks
2061
+ * [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)
2062
+ *
2063
+ * @param props - form configuration and validation parameters.
2064
+ *
2065
+ * @returns methods - individual functions to manage the form state. {@link UseFormReturn}
2066
+ *
2067
+ * @example
2068
+ * ```tsx
2069
+ * function App() {
2070
+ * const { register, handleSubmit, watch, formState: { errors } } = useForm();
2071
+ * const onSubmit = data => console.log(data);
2072
+ *
2073
+ * console.log(watch("example"));
2074
+ *
2075
+ * return (
2076
+ * <form onSubmit={handleSubmit(onSubmit)}>
2077
+ * <input defaultValue="test" {...register("example")} />
2078
+ * <input {...register("exampleRequired", { required: true })} />
2079
+ * {errors.exampleRequired && <span>This field is required</span>}
2080
+ * <input type="submit" />
2081
+ * </form>
2082
+ * );
2083
+ * }
2084
+ * ```
2085
+ */
1863
2086
  function useForm(props = {}) {
1864
2087
  const _formControl = React.useRef();
1865
2088
  const [formState, updateFormState] = React.useState({