react-hook-form 7.68.0 → 7.69.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.
@@ -32,29 +32,23 @@ var isWeb = typeof window !== 'undefined' &&
32
32
  typeof document !== 'undefined';
33
33
 
34
34
  function cloneObject(data) {
35
- let copy;
36
- const isArray = Array.isArray(data);
37
- const isFileListInstance = typeof FileList !== 'undefined' ? data instanceof FileList : false;
38
35
  if (data instanceof Date) {
39
- copy = new Date(data);
36
+ return new Date(data);
40
37
  }
41
- else if (!(isWeb && (data instanceof Blob || isFileListInstance)) &&
42
- (isArray || isObject(data))) {
43
- copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
44
- if (!isArray && !isPlainObject(data)) {
45
- copy = data;
46
- }
47
- else {
48
- for (const key in data) {
49
- if (data.hasOwnProperty(key)) {
50
- copy[key] = cloneObject(data[key]);
51
- }
52
- }
53
- }
38
+ const isFileListInstance = typeof FileList !== 'undefined' && data instanceof FileList;
39
+ if (isWeb && (data instanceof Blob || isFileListInstance)) {
40
+ return data;
54
41
  }
55
- else {
42
+ const isArray = Array.isArray(data);
43
+ if (!isArray && !(isObject(data) && isPlainObject(data))) {
56
44
  return data;
57
45
  }
46
+ const copy = isArray ? [] : Object.create(Object.getPrototypeOf(data));
47
+ for (const key in data) {
48
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
49
+ copy[key] = cloneObject(data[key]);
50
+ }
51
+ }
58
52
  return copy;
59
53
  }
60
54
 
@@ -80,6 +74,8 @@ var get = (object, path, defaultValue) => {
80
74
 
81
75
  var isBoolean = (value) => typeof value === 'boolean';
82
76
 
77
+ var isFunction = (value) => typeof value === 'function';
78
+
83
79
  var set = (object, path, value) => {
84
80
  let index = -1;
85
81
  const tempPath = isKey(path) ? [path] : stringToPath(path);
@@ -503,12 +499,12 @@ function useController(props) {
503
499
  }), [name, control._formValues]);
504
500
  const ref = React.useCallback((elm) => {
505
501
  const field = get(control._fields, name);
506
- if (field && elm) {
502
+ if (field && field._f && elm) {
507
503
  field._f.ref = {
508
- focus: () => elm.focus && elm.focus(),
509
- select: () => elm.select && elm.select(),
510
- setCustomValidity: (message) => elm.setCustomValidity(message),
511
- reportValidity: () => elm.reportValidity(),
504
+ focus: () => isFunction(elm.focus) && elm.focus(),
505
+ select: () => isFunction(elm.select) && elm.select(),
506
+ setCustomValidity: (message) => isFunction(elm.setCustomValidity) && elm.setCustomValidity(message),
507
+ reportValidity: () => isFunction(elm.reportValidity) && elm.reportValidity(),
512
508
  };
513
509
  }
514
510
  }, [control._fields, name]);
@@ -798,8 +794,6 @@ var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
798
794
 
799
795
  var isFileInput = (element) => element.type === 'file';
800
796
 
801
- var isFunction = (value) => typeof value === 'function';
802
-
803
797
  var isHTMLElement = (value) => {
804
798
  if (!isWeb) {
805
799
  return false;
@@ -1367,6 +1361,7 @@ function createFormControl(props = {}) {
1367
1361
  action: false,
1368
1362
  mount: false,
1369
1363
  watch: false,
1364
+ keepIsValid: false,
1370
1365
  };
1371
1366
  let _names = {
1372
1367
  mount: new Set(),
@@ -1377,7 +1372,7 @@ function createFormControl(props = {}) {
1377
1372
  };
1378
1373
  let delayErrorCallback;
1379
1374
  let timer = 0;
1380
- const _proxyFormState = {
1375
+ const defaultProxyFormState = {
1381
1376
  isDirty: false,
1382
1377
  dirtyFields: false,
1383
1378
  validatingFields: false,
@@ -1386,6 +1381,9 @@ function createFormControl(props = {}) {
1386
1381
  isValid: false,
1387
1382
  errors: false,
1388
1383
  };
1384
+ const _proxyFormState = {
1385
+ ...defaultProxyFormState,
1386
+ };
1389
1387
  let _proxySubscribeFormState = {
1390
1388
  ..._proxyFormState,
1391
1389
  };
@@ -1399,13 +1397,21 @@ function createFormControl(props = {}) {
1399
1397
  timer = setTimeout(callback, wait);
1400
1398
  };
1401
1399
  const _setValid = async (shouldUpdateValid) => {
1400
+ if (_state.keepIsValid) {
1401
+ return;
1402
+ }
1402
1403
  if (!_options.disabled &&
1403
1404
  (_proxyFormState.isValid ||
1404
1405
  _proxySubscribeFormState.isValid ||
1405
1406
  shouldUpdateValid)) {
1406
- const isValid = _options.resolver
1407
- ? isEmptyObject((await _runSchema()).errors)
1408
- : await executeBuiltInValidation(_fields, true);
1407
+ let isValid;
1408
+ if (_options.resolver) {
1409
+ isValid = isEmptyObject((await _runSchema()).errors);
1410
+ _updateIsValidating();
1411
+ }
1412
+ else {
1413
+ isValid = await executeBuiltInValidation(_fields, true);
1414
+ }
1409
1415
  if (isValid !== _formState.isValid) {
1410
1416
  _subjects.state.next({
1411
1417
  isValid,
@@ -1568,11 +1574,11 @@ function createFormControl(props = {}) {
1568
1574
  const _runSchema = async (name) => {
1569
1575
  _updateIsValidating(name, true);
1570
1576
  const result = await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1571
- _updateIsValidating(name);
1572
1577
  return result;
1573
1578
  };
1574
1579
  const executeSchemaAndUpdateState = async (names) => {
1575
1580
  const { errors } = await _runSchema(names);
1581
+ _updateIsValidating(names);
1576
1582
  if (names) {
1577
1583
  for (const name of names) {
1578
1584
  const error = get(errors, name);
@@ -1808,6 +1814,7 @@ function createFormControl(props = {}) {
1808
1814
  !isBlurEvent && watched && _subjects.state.next({ ..._formState });
1809
1815
  if (_options.resolver) {
1810
1816
  const { errors } = await _runSchema([name]);
1817
+ _updateIsValidating([name]);
1811
1818
  _updateIsFieldValueUpdated(fieldValue);
1812
1819
  if (isFieldValueUpdated) {
1813
1820
  const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
@@ -1953,7 +1960,10 @@ function createFormControl(props = {}) {
1953
1960
  };
1954
1961
  return _subscribe({
1955
1962
  ...props,
1956
- formState: _proxySubscribeFormState,
1963
+ formState: {
1964
+ ...defaultProxyFormState,
1965
+ ...props.formState,
1966
+ },
1957
1967
  });
1958
1968
  };
1959
1969
  const unregister = (name, options = {}) => {
@@ -2106,6 +2116,7 @@ function createFormControl(props = {}) {
2106
2116
  });
2107
2117
  if (_options.resolver) {
2108
2118
  const { errors, values } = await _runSchema();
2119
+ _updateIsValidating();
2109
2120
  _formState.errors = errors;
2110
2121
  fieldValues = cloneObject(values);
2111
2122
  }
@@ -2246,6 +2257,7 @@ function createFormControl(props = {}) {
2246
2257
  !!keepStateOptions.keepDirtyValues ||
2247
2258
  (!_options.shouldUnregister && !isEmptyObject(values));
2248
2259
  _state.watch = !!_options.shouldUnregister;
2260
+ _state.keepIsValid = !!keepStateOptions.keepIsValid;
2249
2261
  _state.action = false;
2250
2262
  // Clear errors synchronously to prevent validation errors on subsequent submissions
2251
2263
  // This fixes the issue where form.reset() causes validation errors on subsequent
@@ -2290,7 +2302,7 @@ function createFormControl(props = {}) {
2290
2302
  };
2291
2303
  const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
2292
2304
  ? formValues(_formValues)
2293
- : formValues, keepStateOptions);
2305
+ : formValues, { ..._options.resetOptions, ...keepStateOptions });
2294
2306
  const setFocus = (name, options = {}) => {
2295
2307
  const field = get(_fields, name);
2296
2308
  const fieldReference = field && field._f;
@@ -2299,10 +2311,14 @@ function createFormControl(props = {}) {
2299
2311
  ? fieldReference.refs[0]
2300
2312
  : fieldReference.ref;
2301
2313
  if (fieldRef.focus) {
2302
- fieldRef.focus();
2303
- options.shouldSelect &&
2304
- isFunction(fieldRef.select) &&
2305
- fieldRef.select();
2314
+ // Use setTimeout to ensure focus happens after any pending state updates
2315
+ // This fixes the issue where setFocus doesn't work immediately after setError
2316
+ setTimeout(() => {
2317
+ fieldRef.focus();
2318
+ options.shouldSelect &&
2319
+ isFunction(fieldRef.select) &&
2320
+ fieldRef.select();
2321
+ });
2306
2322
  }
2307
2323
  }
2308
2324
  };
@@ -2328,6 +2344,7 @@ function createFormControl(props = {}) {
2328
2344
  setError,
2329
2345
  _subscribe,
2330
2346
  _runSchema,
2347
+ _updateIsValidating,
2331
2348
  _focusError,
2332
2349
  _getWatch,
2333
2350
  _getDirty,
@@ -2403,7 +2420,7 @@ var generateId = () => {
2403
2420
  }
2404
2421
  const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
2405
2422
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
2406
- const r = (Math.random() * 16 + d) % 16 | 0;
2423
+ const r = ((Math.random() * 16 + d) % 16) | 0;
2407
2424
  return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
2408
2425
  });
2409
2426
  };
@@ -2625,6 +2642,7 @@ function useFieldArray(props) {
2625
2642
  !getValidationModes(control._options.reValidateMode).isOnSubmit) {
2626
2643
  if (control._options.resolver) {
2627
2644
  control._runSchema([name]).then((result) => {
2645
+ control._updateIsValidating([name]);
2628
2646
  const error = get(result.errors, name);
2629
2647
  const existingError = get(control._formState.errors, name);
2630
2648
  if (existingError
@@ -2854,7 +2872,11 @@ function useForm(props = {}) {
2854
2872
  * Watch component that subscribes to form field changes and re-renders when watched fields update.
2855
2873
  *
2856
2874
  * @param control - The form control object from useForm
2857
- * @param names - Array of field names to watch for changes
2875
+ * @param name - Can be field name, array of field names, or undefined to watch the entire form
2876
+ * @param disabled - Disable subscription
2877
+ * @param exact - Whether to watch exact field names or not
2878
+ * @param defaultValue - The default value to use if the field is not yet set
2879
+ * @param compute - Function to compute derived values from watched fields
2858
2880
  * @param render - The function that receives watched values and returns ReactNode
2859
2881
  * @returns The result of calling render function with watched values
2860
2882
  *
@@ -2872,7 +2894,7 @@ function useForm(props = {}) {
2872
2894
  * />
2873
2895
  * ```
2874
2896
  */
2875
- const Watch = ({ control, names, render, }) => render(useWatch({ control, name: names }));
2897
+ const Watch = ({ render, names, ...props }) => render(useWatch({ ...props, name: names }));
2876
2898
 
2877
2899
  export { Controller, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
2878
2900
  //# sourceMappingURL=index.esm.mjs.map