react-hook-form 7.39.3 → 7.40.0-next.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.
Files changed (49) hide show
  1. package/dist/__typetest__/__fixtures__/pathString.d.ts +2 -2
  2. package/dist/__typetest__/__fixtures__/pathString.d.ts.map +1 -1
  3. package/dist/__typetest__/__fixtures__/traversable.d.ts +3 -3
  4. package/dist/__typetest__/__fixtures__/traversable.d.ts.map +1 -1
  5. package/dist/__typetest__/__fixtures__/tuple.d.ts +2 -2
  6. package/dist/__typetest__/__fixtures__/tuple.d.ts.map +1 -1
  7. package/dist/index.cjs.js +1 -1
  8. package/dist/index.cjs.js.map +1 -1
  9. package/dist/index.esm.mjs +112 -92
  10. package/dist/index.esm.mjs.map +1 -1
  11. package/dist/index.umd.js +1 -1
  12. package/dist/index.umd.js.map +1 -1
  13. package/dist/logic/createFormControl.d.ts.map +1 -1
  14. package/dist/logic/getCheckboxValue.d.ts +1 -1
  15. package/dist/logic/getCheckboxValue.d.ts.map +1 -1
  16. package/dist/logic/getRadioValue.d.ts +1 -1
  17. package/dist/logic/getRadioValue.d.ts.map +1 -1
  18. package/dist/types/controller.d.ts +5 -5
  19. package/dist/types/controller.d.ts.map +1 -1
  20. package/dist/types/errors.d.ts +8 -8
  21. package/dist/types/errors.d.ts.map +1 -1
  22. package/dist/types/events.d.ts +1 -1
  23. package/dist/types/events.d.ts.map +1 -1
  24. package/dist/types/fieldArray.d.ts +13 -13
  25. package/dist/types/fieldArray.d.ts.map +1 -1
  26. package/dist/types/fields.d.ts +10 -10
  27. package/dist/types/fields.d.ts.map +1 -1
  28. package/dist/types/form.d.ts +56 -52
  29. package/dist/types/form.d.ts.map +1 -1
  30. package/dist/types/path/common.d.ts +32 -32
  31. package/dist/types/path/common.d.ts.map +1 -1
  32. package/dist/types/path/eager.d.ts +11 -11
  33. package/dist/types/path/eager.d.ts.map +1 -1
  34. package/dist/types/resolvers.d.ts +4 -4
  35. package/dist/types/resolvers.d.ts.map +1 -1
  36. package/dist/types/utils.d.ts +13 -13
  37. package/dist/types/utils.d.ts.map +1 -1
  38. package/dist/types/validator.d.ts +6 -6
  39. package/dist/types/validator.d.ts.map +1 -1
  40. package/dist/useFieldArray.d.ts.map +1 -1
  41. package/dist/useForm.d.ts.map +1 -1
  42. package/dist/useFormState.d.ts.map +1 -1
  43. package/dist/useSubscribe.d.ts +2 -2
  44. package/dist/useSubscribe.d.ts.map +1 -1
  45. package/dist/useWatch.d.ts.map +1 -1
  46. package/dist/utils/createSubject.d.ts +3 -3
  47. package/dist/utils/createSubject.d.ts.map +1 -1
  48. package/dist/utils/isHTMLElement.d.ts.map +1 -1
  49. package/package.json +3 -3
@@ -173,7 +173,7 @@ function useSubscribe(props) {
173
173
  React.useEffect(() => {
174
174
  const subscription = !props.disabled &&
175
175
  _props.current.subject.subscribe({
176
- next: _props.current.callback,
176
+ next: _props.current.next,
177
177
  });
178
178
  return () => {
179
179
  subscription && subscription.unsubscribe();
@@ -228,21 +228,28 @@ function useFormState(props) {
228
228
  _name.current = name;
229
229
  useSubscribe({
230
230
  disabled,
231
- callback: React.useCallback((value) => _mounted.current &&
231
+ next: (value) => _mounted.current &&
232
232
  shouldSubscribeByName(_name.current, value.name, exact) &&
233
233
  shouldRenderFormState(value, _localProxyFormState.current) &&
234
234
  updateFormState({
235
235
  ...control._formState,
236
236
  ...value,
237
- }), [control, exact]),
237
+ }),
238
238
  subject: control._subjects.state,
239
239
  });
240
240
  React.useEffect(() => {
241
241
  _mounted.current = true;
242
+ const isDirty = control._proxyFormState.isDirty && control._getDirty();
243
+ if (isDirty !== control._formState.isDirty) {
244
+ control._subjects.state.next({
245
+ isDirty,
246
+ });
247
+ }
248
+ control._updateValid();
242
249
  return () => {
243
250
  _mounted.current = false;
244
251
  };
245
- }, []);
252
+ }, [control]);
246
253
  return getProxyFormState(formState, control, _localProxyFormState.current, false);
247
254
  }
248
255
 
@@ -262,16 +269,41 @@ var generateWatchOutput = (names, _names, formValues, isGlobal) => {
262
269
  return formValues;
263
270
  };
264
271
 
265
- var isFunction = (value) => typeof value === 'function';
272
+ var isPlainObject = (tempObject) => {
273
+ const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
274
+ return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
275
+ };
266
276
 
267
- var objectHasFunction = (data) => {
268
- for (const key in data) {
269
- if (isFunction(data[key])) {
270
- return true;
277
+ var isWeb = typeof window !== 'undefined' &&
278
+ typeof window.HTMLElement !== 'undefined' &&
279
+ typeof document !== 'undefined';
280
+
281
+ function cloneObject(data) {
282
+ let copy;
283
+ const isArray = Array.isArray(data);
284
+ if (data instanceof Date) {
285
+ copy = new Date(data);
286
+ }
287
+ else if (data instanceof Set) {
288
+ copy = new Set(data);
289
+ }
290
+ else if (!(isWeb && (data instanceof Blob || data instanceof FileList)) &&
291
+ (isArray || isObject(data))) {
292
+ copy = isArray ? [] : {};
293
+ if (!Array.isArray(data) && !isPlainObject(data)) {
294
+ copy = data;
295
+ }
296
+ else {
297
+ for (const key in data) {
298
+ copy[key] = cloneObject(data[key]);
299
+ }
271
300
  }
272
301
  }
273
- return false;
274
- };
302
+ else {
303
+ return data;
304
+ }
305
+ return copy;
306
+ }
275
307
 
276
308
  /**
277
309
  * Custom hook to subscribe to field change and isolate re-rendering at the component level.
@@ -297,19 +329,16 @@ function useWatch(props) {
297
329
  useSubscribe({
298
330
  disabled,
299
331
  subject: control._subjects.watch,
300
- callback: React.useCallback((formState) => {
332
+ next: (formState) => {
301
333
  if (shouldSubscribeByName(_name.current, formState.name, exact)) {
302
334
  const fieldValues = generateWatchOutput(_name.current, control._names, formState.values || control._formValues);
303
- updateValue(isUndefined(_name.current) ||
304
- (isObject(fieldValues) && !objectHasFunction(fieldValues))
305
- ? { ...fieldValues }
306
- : Array.isArray(fieldValues)
307
- ? [...fieldValues]
308
- : isUndefined(fieldValues)
309
- ? defaultValue
310
- : fieldValues);
335
+ updateValue(isUndefined(_name.current) || !isUndefined(fieldValues)
336
+ ? cloneObject(fieldValues)
337
+ : isUndefined(fieldValues)
338
+ ? defaultValue
339
+ : fieldValues);
311
340
  }
312
- }, [control, exact, defaultValue]),
341
+ },
313
342
  });
314
343
  const [value, updateValue] = React.useState(isUndefined(defaultValue)
315
344
  ? control._getWatch(name)
@@ -562,6 +591,8 @@ var isBoolean = (value) => typeof value === 'boolean';
562
591
 
563
592
  var isFileInput = (element) => element.type === 'file';
564
593
 
594
+ var isFunction = (value) => typeof value === 'function';
595
+
565
596
  var isMessage = (value) => isString(value) || React.isValidElement(value);
566
597
 
567
598
  var isRadioInput = (element) => element.type === 'radio';
@@ -632,8 +663,8 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
632
663
  }
633
664
  const inputRef = refs ? refs[0] : ref;
634
665
  const setCustomValidity = (message) => {
635
- if (shouldUseNativeValidation && isString(message)) {
636
- inputRef.setCustomValidity(message);
666
+ if (shouldUseNativeValidation && inputRef.reportValidity) {
667
+ inputRef.setCustomValidity(isBoolean(message) ? '' : message || '');
637
668
  inputRef.reportValidity();
638
669
  }
639
670
  };
@@ -804,42 +835,6 @@ function append(data, value) {
804
835
  return [...data, ...convertToArrayPayload(value)];
805
836
  }
806
837
 
807
- var isPlainObject = (tempObject) => {
808
- const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
809
- return (isObject(prototypeCopy) && prototypeCopy.hasOwnProperty('isPrototypeOf'));
810
- };
811
-
812
- var isWeb = typeof window !== 'undefined' &&
813
- typeof window.HTMLElement !== 'undefined' &&
814
- typeof document !== 'undefined';
815
-
816
- function cloneObject(data) {
817
- let copy;
818
- const isArray = Array.isArray(data);
819
- if (data instanceof Date) {
820
- copy = new Date(data);
821
- }
822
- else if (data instanceof Set) {
823
- copy = new Set(data);
824
- }
825
- else if (!(isWeb && (data instanceof Blob || data instanceof FileList)) &&
826
- (isArray || isObject(data))) {
827
- copy = isArray ? [] : {};
828
- if (!Array.isArray(data) && !isPlainObject(data)) {
829
- copy = data;
830
- }
831
- else {
832
- for (const key in data) {
833
- copy[key] = cloneObject(data[key]);
834
- }
835
- }
836
- }
837
- else {
838
- return data;
839
- }
840
- return copy;
841
- }
842
-
843
838
  var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
844
839
 
845
840
  var getValidationModes = (mode) => ({
@@ -991,17 +986,16 @@ function useFieldArray(props) {
991
986
  control._names.array.add(name);
992
987
  props.rules &&
993
988
  control.register(name, props.rules);
994
- const callback = React.useCallback(({ values, name: fieldArrayName, }) => {
995
- if (fieldArrayName === _name.current || !fieldArrayName) {
996
- const fieldValues = get(values, _name.current);
997
- if (Array.isArray(fieldValues)) {
998
- setFields(fieldValues);
999
- ids.current = fieldValues.map(generateId);
1000
- }
1001
- }
1002
- }, []);
1003
989
  useSubscribe({
1004
- callback,
990
+ next: ({ values, name: fieldArrayName, }) => {
991
+ if (fieldArrayName === _name.current || !fieldArrayName) {
992
+ const fieldValues = get(values, _name.current);
993
+ if (Array.isArray(fieldValues)) {
994
+ setFields(fieldValues);
995
+ ids.current = fieldValues.map(generateId);
996
+ }
997
+ }
998
+ },
1005
999
  subject: control._subjects.array,
1006
1000
  });
1007
1001
  const updateValues = React.useCallback((updatedFieldArrayValues) => {
@@ -1216,8 +1210,8 @@ function deepEqual(object1, object2) {
1216
1210
 
1217
1211
  var isHTMLElement = (value) => {
1218
1212
  const owner = value ? value.ownerDocument : 0;
1219
- const ElementClass = owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement;
1220
- return value instanceof ElementClass;
1213
+ return (value instanceof
1214
+ (owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement));
1221
1215
  };
1222
1216
 
1223
1217
  var isMultipleSelect = (element) => element.type === `select-multiple`;
@@ -1226,6 +1220,15 @@ var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
1226
1220
 
1227
1221
  var live = (ref) => isHTMLElement(ref) && ref.isConnected;
1228
1222
 
1223
+ var objectHasFunction = (data) => {
1224
+ for (const key in data) {
1225
+ if (isFunction(data[key])) {
1226
+ return true;
1227
+ }
1228
+ }
1229
+ return false;
1230
+ };
1231
+
1229
1232
  function markFieldsDirty(data, fields = {}) {
1230
1233
  const isParentNodeArray = Array.isArray(data);
1231
1234
  if (isObject(data) || isParentNodeArray) {
@@ -1406,7 +1409,9 @@ function createFormControl(props = {}) {
1406
1409
  errors: {},
1407
1410
  };
1408
1411
  let _fields = {};
1409
- let _defaultValues = cloneObject(_options.defaultValues) || {};
1412
+ let _defaultValues = isObject(_options.defaultValues)
1413
+ ? cloneObject(_options.defaultValues) || {}
1414
+ : {};
1410
1415
  let _formValues = _options.shouldUnregister
1411
1416
  ? {}
1412
1417
  : cloneObject(_defaultValues);
@@ -1512,37 +1517,39 @@ function createFormControl(props = {}) {
1512
1517
  }
1513
1518
  };
1514
1519
  const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
1515
- let isFieldDirty = false;
1520
+ let shouldUpdateField = false;
1521
+ let isPreviousDirty = false;
1516
1522
  const output = {
1517
1523
  name,
1518
1524
  };
1519
- const isPreviousFieldTouched = get(_formState.touchedFields, name);
1520
1525
  if (_proxyFormState.isDirty) {
1521
- const isPreviousFormDirty = _formState.isDirty;
1526
+ isPreviousDirty = _formState.isDirty;
1522
1527
  _formState.isDirty = output.isDirty = _getDirty();
1523
- isFieldDirty = isPreviousFormDirty !== output.isDirty;
1528
+ shouldUpdateField = isPreviousDirty !== output.isDirty;
1524
1529
  }
1525
1530
  if (_proxyFormState.dirtyFields && (!isBlurEvent || shouldDirty)) {
1526
- const isPreviousFieldDirty = get(_formState.dirtyFields, name);
1531
+ isPreviousDirty = get(_formState.dirtyFields, name);
1527
1532
  const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1528
1533
  isCurrentFieldPristine
1529
1534
  ? unset(_formState.dirtyFields, name)
1530
1535
  : set(_formState.dirtyFields, name, true);
1531
1536
  output.dirtyFields = _formState.dirtyFields;
1532
- isFieldDirty =
1533
- isFieldDirty ||
1534
- isPreviousFieldDirty !== get(_formState.dirtyFields, name);
1537
+ shouldUpdateField =
1538
+ shouldUpdateField || isPreviousDirty !== !isCurrentFieldPristine;
1535
1539
  }
1536
- if (isBlurEvent && !isPreviousFieldTouched) {
1537
- set(_formState.touchedFields, name, isBlurEvent);
1538
- output.touchedFields = _formState.touchedFields;
1539
- isFieldDirty =
1540
- isFieldDirty ||
1541
- (_proxyFormState.touchedFields &&
1542
- isPreviousFieldTouched !== isBlurEvent);
1540
+ if (isBlurEvent) {
1541
+ const isPreviousFieldTouched = get(_formState.touchedFields, name);
1542
+ if (!isPreviousFieldTouched) {
1543
+ set(_formState.touchedFields, name, isBlurEvent);
1544
+ output.touchedFields = _formState.touchedFields;
1545
+ shouldUpdateField =
1546
+ shouldUpdateField ||
1547
+ (_proxyFormState.touchedFields &&
1548
+ isPreviousFieldTouched !== isBlurEvent);
1549
+ }
1543
1550
  }
1544
- isFieldDirty && shouldRender && _subjects.state.next(output);
1545
- return isFieldDirty ? output : {};
1551
+ shouldUpdateField && shouldRender && _subjects.state.next(output);
1552
+ return shouldUpdateField ? output : {};
1546
1553
  };
1547
1554
  const shouldRenderByError = (name, isValid, error, fieldState) => {
1548
1555
  const previousFieldError = get(_formState.errors, name);
@@ -2168,6 +2175,11 @@ function createFormControl(props = {}) {
2168
2175
  }
2169
2176
  }
2170
2177
  };
2178
+ if (isFunction(_options.defaultValues)) {
2179
+ _options.defaultValues().then((values) => {
2180
+ reset(values, _options.resetOptions);
2181
+ });
2182
+ }
2171
2183
  return {
2172
2184
  control: {
2173
2185
  register,
@@ -2181,6 +2193,7 @@ function createFormControl(props = {}) {
2181
2193
  _removeUnmounted,
2182
2194
  _updateFieldArray,
2183
2195
  _getFieldArray,
2196
+ _reset,
2184
2197
  _subjects,
2185
2198
  _proxyFormState,
2186
2199
  get _fields() {
@@ -2278,7 +2291,9 @@ function useForm(props = {}) {
2278
2291
  dirtyFields: {},
2279
2292
  touchedFields: {},
2280
2293
  errors: {},
2281
- defaultValues: props.defaultValues,
2294
+ defaultValues: isFunction(props.defaultValues)
2295
+ ? undefined
2296
+ : props.defaultValues,
2282
2297
  });
2283
2298
  if (!_formControl.current) {
2284
2299
  _formControl.current = {
@@ -2290,7 +2305,7 @@ function useForm(props = {}) {
2290
2305
  control._options = props;
2291
2306
  useSubscribe({
2292
2307
  subject: control._subjects.state,
2293
- callback: React.useCallback((value) => {
2308
+ next: (value) => {
2294
2309
  if (shouldRenderFormState(value, control._proxyFormState, true)) {
2295
2310
  control._formState = {
2296
2311
  ...control._formState,
@@ -2298,7 +2313,7 @@ function useForm(props = {}) {
2298
2313
  };
2299
2314
  updateFormState({ ...control._formState });
2300
2315
  }
2301
- }, [control]),
2316
+ },
2302
2317
  });
2303
2318
  React.useEffect(() => {
2304
2319
  if (!control._stateFlags.mount) {
@@ -2311,6 +2326,11 @@ function useForm(props = {}) {
2311
2326
  }
2312
2327
  control._removeUnmounted();
2313
2328
  });
2329
+ React.useEffect(() => {
2330
+ if (props.values && !deepEqual(props.values, control._defaultValues)) {
2331
+ control._reset(props.values, control._options.resetOptions);
2332
+ }
2333
+ }, [props.values, control]);
2314
2334
  React.useEffect(() => {
2315
2335
  formState.submitCount && control._focusError();
2316
2336
  }, [control, formState.submitCount]);