react-hook-form 7.17.1 → 7.17.5

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.
package/dist/index.esm.js CHANGED
@@ -101,29 +101,41 @@ var shouldRenderFormState = (formStateData, _proxyFormState, isRoot) => {
101
101
  (!isRoot || VALIDATION_MODE.all)));
102
102
  };
103
103
 
104
- var convertToArrayPayload = (value) => Array.isArray(value) ? value : [value];
105
-
106
- function useSubscribe({ disabled, subject, callback }) {
107
- const _subscription = React.useRef(subject);
108
- const _unSubscribe = React.useRef();
109
- if (disabled) {
110
- if (_subscription.current) {
111
- _unSubscribe.current && _unSubscribe.current.unsubscribe();
112
- _subscription.current = _unSubscribe.current = undefined;
113
- }
104
+ var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
105
+
106
+ var shouldSubscribeByName = (name, signalName) => !name ||
107
+ !signalName ||
108
+ convertToArrayPayload(name).some((currentName) => currentName &&
109
+ (currentName.startsWith(signalName) ||
110
+ signalName.startsWith(currentName)));
111
+
112
+ const tearDown = (_unsubscribe) => {
113
+ if (_unsubscribe.current) {
114
+ _unsubscribe.current.unsubscribe();
115
+ _unsubscribe.current = undefined;
114
116
  }
115
- else {
116
- if (!_subscription.current) {
117
- _subscription.current = subject;
118
- }
119
- if (!_unSubscribe.current && _subscription.current) {
120
- _unSubscribe.current = _subscription.current.subscribe({
121
- next: callback,
122
- });
123
- }
117
+ };
118
+ const updateSubscriptionProps = ({ _unsubscribe, props }) => () => {
119
+ if (props.disabled) {
120
+ tearDown(_unsubscribe);
121
+ }
122
+ else if (!_unsubscribe.current) {
123
+ _unsubscribe.current = props.subject.subscribe({
124
+ next: props.callback,
125
+ });
124
126
  }
125
- React.useEffect(() => () => {
126
- _unSubscribe.current && _unSubscribe.current.unsubscribe();
127
+ };
128
+ function useSubscribe(props) {
129
+ const _unsubscribe = React.useRef();
130
+ const _updateSubscription = React.useRef(() => { });
131
+ _updateSubscription.current = updateSubscriptionProps({
132
+ _unsubscribe,
133
+ props,
134
+ });
135
+ !props.skipEarlySubscription && _updateSubscription.current();
136
+ React.useEffect(() => {
137
+ _updateSubscription.current();
138
+ return () => tearDown(_unsubscribe);
127
139
  }, []);
128
140
  }
129
141
 
@@ -143,12 +155,11 @@ function useFormState(props) {
143
155
  _name.current = name;
144
156
  useSubscribe({
145
157
  disabled,
146
- callback: (formState) => (!_name.current ||
147
- !formState.name ||
148
- convertToArrayPayload(_name.current).includes(formState.name)) &&
158
+ callback: (formState) => shouldSubscribeByName(_name.current, formState.name) &&
149
159
  shouldRenderFormState(formState, _localProxyFormState.current) &&
150
160
  updateFormState(Object.assign(Object.assign({}, control._formState), formState)),
151
161
  subject: control._subjects.state,
162
+ skipEarlySubscription: true,
152
163
  });
153
164
  return getProxyFormState(formState, control._proxyFormState, _localProxyFormState.current, false);
154
165
  }
@@ -166,7 +177,7 @@ function useController(props) {
166
177
  useSubscribe({
167
178
  subject: control._subjects.control,
168
179
  callback: (data) => (!data.name || _name.current === data.name) &&
169
- setInputStateValue(get(data.values, name)),
180
+ setInputStateValue(get(data.values, _name.current)),
170
181
  });
171
182
  const registerProps = control.register(name, Object.assign(Object.assign({}, props.rules), { value }));
172
183
  const updateMounted = React.useCallback((name, value) => {
@@ -366,15 +377,18 @@ const useFieldArray = (props) => {
366
377
  const { control = methods.control, name, keyName = 'id', shouldUnregister, } = props;
367
378
  const [fields, setFields] = React.useState(mapIds(control._getFieldArray(name), keyName));
368
379
  const _fieldIds = React.useRef(fields);
380
+ const _name = React.useRef(name);
381
+ _name.current = name;
369
382
  _fieldIds.current = fields;
370
383
  control._names.array.add(name);
371
384
  useSubscribe({
372
385
  callback: ({ values, name: fieldArrayName }) => {
373
- if (fieldArrayName === name || !fieldArrayName) {
374
- setFields(mapIds(get(values, name), keyName));
386
+ if (fieldArrayName === _name.current || !fieldArrayName) {
387
+ setFields(mapIds(get(values, _name.current), keyName));
375
388
  }
376
389
  },
377
390
  subject: control._subjects.array,
391
+ skipEarlySubscription: true,
378
392
  });
379
393
  const updateValues = React.useCallback((updatedFieldArrayValuesWithKey) => {
380
394
  const updatedFieldArrayValues = omitKeys(updatedFieldArrayValuesWithKey, keyName);
@@ -483,6 +497,8 @@ const useFieldArray = (props) => {
483
497
  };
484
498
  };
485
499
 
500
+ var isFunction = (value) => typeof value === 'function';
501
+
486
502
  function cloneObject(data) {
487
503
  let copy;
488
504
  const isArray = Array.isArray(data);
@@ -495,6 +511,10 @@ function cloneObject(data) {
495
511
  else if (isArray || isObject(data)) {
496
512
  copy = isArray ? [] : {};
497
513
  for (const key in data) {
514
+ if (isFunction(data[key])) {
515
+ copy = data;
516
+ break;
517
+ }
498
518
  copy[key] = cloneObject(data[key]);
499
519
  }
500
520
  }
@@ -547,8 +567,6 @@ var getValidationModes = (mode) => ({
547
567
 
548
568
  var isBoolean = (value) => typeof value === 'boolean';
549
569
 
550
- var isFunction = (value) => typeof value === 'function';
551
-
552
570
  var isHTMLElement = (value) => value instanceof HTMLElement;
553
571
 
554
572
  var isMultipleSelect = (element) => element.type === `select-multiple`;
@@ -563,7 +581,7 @@ var isWeb = typeof window !== 'undefined' &&
563
581
  typeof window.HTMLElement !== 'undefined' &&
564
582
  typeof document !== 'undefined';
565
583
 
566
- var live = (ref) => !isHTMLElement(ref) || !document.contains(ref);
584
+ var live = (ref) => isHTMLElement(ref) && document.contains(ref);
567
585
 
568
586
  class Subscription {
569
587
  constructor() {
@@ -1203,7 +1221,9 @@ function createFormControl(props = {}) {
1203
1221
  for (const name of _names.unMount) {
1204
1222
  const field = get(_fields, name);
1205
1223
  field &&
1206
- (field._f.refs ? field._f.refs.every(live) : live(field._f.ref)) &&
1224
+ (field._f.refs
1225
+ ? field._f.refs.every((ref) => !live(ref))
1226
+ : !live(field._f.ref)) &&
1207
1227
  unregister(name);
1208
1228
  }
1209
1229
  _names.unMount = new Set();
@@ -1226,7 +1246,7 @@ function createFormControl(props = {}) {
1226
1246
  isGlobal && (_names.watchAll = true);
1227
1247
  return fieldValues;
1228
1248
  };
1229
- const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, []);
1249
+ const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, props.shouldUnregister ? get(_defaultValues, name, []) : []);
1230
1250
  const setFieldValue = (name, value, options = {}, shouldRender) => {
1231
1251
  const field = get(_fields, name);
1232
1252
  let fieldValue = value;
@@ -1324,8 +1344,8 @@ function createFormControl(props = {}) {
1324
1344
  !field._f.deps) ||
1325
1345
  skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
1326
1346
  const isWatched = isFieldWatched(name, isBlurEvent);
1327
- if (isBlurEvent && field._f.onBlur) {
1328
- field._f.onBlur(event);
1347
+ if (isBlurEvent) {
1348
+ field._f.onBlur && field._f.onBlur(event);
1329
1349
  }
1330
1350
  else if (field._f.onChange) {
1331
1351
  field._f.onChange(event);
@@ -1415,6 +1435,7 @@ function createFormControl(props = {}) {
1415
1435
  : (_formState.errors = {});
1416
1436
  _subjects.state.next({
1417
1437
  errors: _formState.errors,
1438
+ isValid: true,
1418
1439
  });
1419
1440
  };
1420
1441
  const setError = (name, error, options) => {
@@ -1489,7 +1510,7 @@ function createFormControl(props = {}) {
1489
1510
  field = {
1490
1511
  _f: isRadioOrCheckbox
1491
1512
  ? Object.assign(Object.assign({}, field._f), { refs: [
1492
- ...compact(field._f.refs || []).filter((ref) => isHTMLElement(ref) && document.contains(ref)),
1513
+ ...compact(field._f.refs || []).filter(live),
1493
1514
  fieldRef,
1494
1515
  ], ref: { type: fieldRef.type, name } }) : Object.assign(Object.assign({}, field._f), { ref: fieldRef }),
1495
1516
  };
@@ -1558,10 +1579,13 @@ function createFormControl(props = {}) {
1558
1579
  }
1559
1580
  };
1560
1581
  const reset = (formValues, keepStateOptions = {}) => {
1582
+ const hasUpdatedFormValues = !isEmptyObject(formValues);
1561
1583
  const updatedValues = formValues || _defaultValues;
1562
1584
  const cloneUpdatedValues = cloneObject(updatedValues);
1585
+ if (!keepStateOptions.keepDefaultValues) {
1586
+ _defaultValues = updatedValues;
1587
+ }
1563
1588
  if (!keepStateOptions.keepValues) {
1564
- _formValues = props.shouldUnregister ? {} : cloneUpdatedValues;
1565
1589
  if (isWeb) {
1566
1590
  for (const name of _names.mount) {
1567
1591
  const field = get(_fields, name);
@@ -1578,16 +1602,14 @@ function createFormControl(props = {}) {
1578
1602
  }
1579
1603
  }
1580
1604
  }
1581
- }
1582
- if (!keepStateOptions.keepDefaultValues) {
1583
- _defaultValues = Object.assign({}, updatedValues);
1584
- }
1585
- if (!keepStateOptions.keepValues) {
1605
+ _formValues = props.shouldUnregister
1606
+ ? keepStateOptions.keepDefaultValues
1607
+ ? _defaultValues
1608
+ : {}
1609
+ : cloneUpdatedValues;
1586
1610
  _fields = {};
1587
1611
  _subjects.control.next({
1588
- values: keepStateOptions.keepDefaultValues
1589
- ? _defaultValues
1590
- : Object.assign({}, updatedValues),
1612
+ values: hasUpdatedFormValues ? cloneUpdatedValues : _defaultValues,
1591
1613
  });
1592
1614
  _subjects.watch.next({});
1593
1615
  _subjects.array.next({
@@ -1609,14 +1631,16 @@ function createFormControl(props = {}) {
1609
1631
  isDirty: keepStateOptions.keepDirty
1610
1632
  ? _formState.isDirty
1611
1633
  : keepStateOptions.keepDefaultValues
1612
- ? deepEqual(formValues, _defaultValues)
1634
+ ? !deepEqual(formValues, _defaultValues)
1613
1635
  : false,
1614
1636
  isSubmitted: keepStateOptions.keepIsSubmitted
1615
1637
  ? _formState.isSubmitted
1616
1638
  : false,
1617
1639
  dirtyFields: keepStateOptions.keepDirty
1618
1640
  ? _formState.dirtyFields
1619
- : {},
1641
+ : (keepStateOptions.keepDefaultValues && formValues
1642
+ ? Object.entries(formValues).reduce((previous, [key, value]) => (Object.assign(Object.assign({}, previous), { [key]: value !== get(_defaultValues, key) })), {})
1643
+ : {}),
1620
1644
  touchedFields: keepStateOptions.keepTouched
1621
1645
  ? _formState.touchedFields
1622
1646
  : {},
@@ -1630,7 +1654,10 @@ function createFormControl(props = {}) {
1630
1654
  !_proxyFormState.isValid || !!keepStateOptions.keepIsValid;
1631
1655
  _stateFlags.watch = !!props.shouldUnregister;
1632
1656
  };
1633
- const setFocus = (name) => get(_fields, name)._f.ref.focus();
1657
+ const setFocus = (name) => {
1658
+ const field = get(_fields, name)._f;
1659
+ (field.ref.focus ? field.ref : field.refs[0]).focus();
1660
+ };
1634
1661
  return {
1635
1662
  control: {
1636
1663
  register,
@@ -1753,13 +1780,8 @@ function useWatch(props) {
1753
1780
  useSubscribe({
1754
1781
  disabled,
1755
1782
  subject: control._subjects.watch,
1756
- callback: ({ name }) => {
1757
- if (!_name.current ||
1758
- !name ||
1759
- convertToArrayPayload(_name.current).some((currentName) => name &&
1760
- currentName &&
1761
- (name.startsWith(currentName) ||
1762
- currentName.startsWith(name)))) {
1783
+ callback: (formState) => {
1784
+ if (shouldSubscribeByName(_name.current, formState.name)) {
1763
1785
  control._stateFlags.mount = true;
1764
1786
  const fieldValues = control._getWatch(_name.current, defaultValue);
1765
1787
  updateValue(isObject(fieldValues)