react-hook-form 7.18.1 → 7.19.2

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
@@ -105,37 +105,35 @@ var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
105
105
 
106
106
  var shouldSubscribeByName = (name, signalName) => !name ||
107
107
  !signalName ||
108
+ name === signalName ||
108
109
  convertToArrayPayload(name).some((currentName) => currentName &&
109
110
  (currentName.startsWith(signalName) ||
110
111
  signalName.startsWith(currentName)));
111
112
 
112
- const tearDown = (_unsubscribe) => {
113
- if (_unsubscribe.current) {
114
- _unsubscribe.current.unsubscribe();
115
- _unsubscribe.current = undefined;
113
+ const tearDown = (_subscription) => {
114
+ if (_subscription.current) {
115
+ _subscription.current.unsubscribe();
116
+ _subscription.current = undefined;
116
117
  }
117
118
  };
118
- const updateSubscriptionProps = ({ _unsubscribe, props }) => () => {
119
+ const updateSubscriptionProps = ({ _subscription, props }) => {
119
120
  if (props.disabled) {
120
- tearDown(_unsubscribe);
121
+ tearDown(_subscription);
121
122
  }
122
- else if (!_unsubscribe.current) {
123
- _unsubscribe.current = props.subject.subscribe({
123
+ else if (!_subscription.current) {
124
+ _subscription.current = props.subject.subscribe({
124
125
  next: props.callback,
125
126
  });
126
127
  }
127
128
  };
128
129
  function useSubscribe(props) {
129
- const _unsubscribe = React.useRef();
130
- const _updateSubscription = React.useRef(() => { });
131
- _updateSubscription.current = updateSubscriptionProps({
132
- _unsubscribe,
130
+ const _subscription = React.useRef();
131
+ updateSubscriptionProps({
132
+ _subscription,
133
133
  props,
134
134
  });
135
- !props.skipEarlySubscription && _updateSubscription.current();
136
135
  React.useEffect(() => {
137
- _updateSubscription.current();
138
- return () => tearDown(_unsubscribe);
136
+ return () => tearDown(_subscription);
139
137
  }, []);
140
138
  }
141
139
 
@@ -159,56 +157,123 @@ function useFormState(props) {
159
157
  shouldRenderFormState(formState, _localProxyFormState.current) &&
160
158
  updateFormState(Object.assign(Object.assign({}, control._formState), formState)),
161
159
  subject: control._subjects.state,
162
- skipEarlySubscription: true,
163
160
  });
164
161
  return getProxyFormState(formState, control._proxyFormState, _localProxyFormState.current, false);
165
162
  }
166
163
 
164
+ var isString = (value) => typeof value === 'string';
165
+
166
+ function generateWatchOutput(names, _names, formValues, isGlobal) {
167
+ const isArray = Array.isArray(names);
168
+ if (isString(names)) {
169
+ isGlobal && _names.watch.add(names);
170
+ return get(formValues, names);
171
+ }
172
+ if (isArray) {
173
+ return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
174
+ get(formValues, fieldName)));
175
+ }
176
+ isGlobal && (_names.watchAll = true);
177
+ return formValues;
178
+ }
179
+
180
+ var isKey = (value) => /^\w*$/.test(value);
181
+
182
+ var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
183
+
184
+ function set(object, path, value) {
185
+ let index = -1;
186
+ const tempPath = isKey(path) ? [path] : stringToPath(path);
187
+ const length = tempPath.length;
188
+ const lastIndex = length - 1;
189
+ while (++index < length) {
190
+ const key = tempPath[index];
191
+ let newValue = value;
192
+ if (index !== lastIndex) {
193
+ const objValue = object[key];
194
+ newValue =
195
+ isObject(objValue) || Array.isArray(objValue)
196
+ ? objValue
197
+ : !isNaN(+tempPath[index + 1])
198
+ ? []
199
+ : {};
200
+ }
201
+ object[key] = newValue;
202
+ object = object[key];
203
+ }
204
+ return object;
205
+ }
206
+
207
+ function useWatch(props) {
208
+ const methods = useFormContext();
209
+ const { control = methods.control, name, defaultValue, disabled, } = props || {};
210
+ const _name = React.useRef(name);
211
+ _name.current = name;
212
+ useSubscribe({
213
+ disabled,
214
+ subject: control._subjects.watch,
215
+ callback: (formState) => {
216
+ if (shouldSubscribeByName(_name.current, formState.name)) {
217
+ const fieldValues = generateWatchOutput(_name.current, control._names, control._formValues);
218
+ updateValue(isObject(fieldValues) &&
219
+ !(isString(_name.current) &&
220
+ get(control._fields, _name.current, {})._f)
221
+ ? Object.assign({}, fieldValues) : Array.isArray(fieldValues)
222
+ ? [...fieldValues]
223
+ : fieldValues);
224
+ }
225
+ },
226
+ });
227
+ const [value, updateValue] = React.useState(isUndefined(defaultValue)
228
+ ? control._getWatch(name)
229
+ : defaultValue);
230
+ React.useEffect(() => {
231
+ control._removeUnmounted();
232
+ });
233
+ return value;
234
+ }
235
+
167
236
  function useController(props) {
168
237
  const methods = useFormContext();
169
238
  const { name, control = methods.control, shouldUnregister } = props;
170
- const [value, setInputStateValue] = React.useState(get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)));
239
+ const value = useWatch({
240
+ control,
241
+ name,
242
+ defaultValue: get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)),
243
+ });
171
244
  const formState = useFormState({
172
- control: control || methods.control,
245
+ control,
173
246
  name,
174
247
  });
175
248
  const _name = React.useRef(name);
176
249
  _name.current = name;
177
- useSubscribe({
178
- subject: control._subjects.control,
179
- callback: (data) => (!data.name || _name.current === data.name) &&
180
- setInputStateValue(get(data.values, _name.current)),
181
- skipEarlySubscription: true,
182
- });
183
250
  const registerProps = control.register(name, Object.assign(Object.assign({}, props.rules), { value }));
184
- const updateMounted = React.useCallback((name, value) => {
185
- const field = get(control._fields, name);
186
- if (field) {
187
- field._f.mount = value;
188
- }
189
- }, [control]);
190
251
  React.useEffect(() => {
252
+ const updateMounted = (name, value) => {
253
+ const field = get(control._fields, name);
254
+ if (field) {
255
+ field._f.mount = value;
256
+ }
257
+ };
191
258
  updateMounted(name, true);
192
259
  return () => {
193
260
  const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
194
261
  if (isNameInFieldArray(control._names.array, name)
195
262
  ? _shouldUnregisterField && !control._stateFlags.action
196
263
  : _shouldUnregisterField) {
197
- control.unregister(name);
264
+ control.unregister(name, { keepDefaultValue: true });
198
265
  }
199
266
  else {
200
267
  updateMounted(name, false);
201
268
  }
202
269
  };
203
- }, [name, control, shouldUnregister, updateMounted]);
270
+ }, [name, control, shouldUnregister]);
204
271
  return {
205
272
  field: {
206
273
  onChange: (event) => {
207
- const value = getControllerValue(event);
208
- setInputStateValue(value);
209
274
  registerProps.onChange({
210
275
  target: {
211
- value,
276
+ value: getControllerValue(event),
212
277
  name: name,
213
278
  },
214
279
  type: EVENTS.CHANGE,
@@ -251,33 +316,6 @@ const Controller = (props) => props.render(useController(props));
251
316
  var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
252
317
  ? Object.assign(Object.assign({}, errors[name]), { types: Object.assign(Object.assign({}, (errors[name] && errors[name].types ? errors[name].types : {})), { [type]: message || true }) }) : {};
253
318
 
254
- var isKey = (value) => /^\w*$/.test(value);
255
-
256
- var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
257
-
258
- function set(object, path, value) {
259
- let index = -1;
260
- const tempPath = isKey(path) ? [path] : stringToPath(path);
261
- const length = tempPath.length;
262
- const lastIndex = length - 1;
263
- while (++index < length) {
264
- const key = tempPath[index];
265
- let newValue = value;
266
- if (index !== lastIndex) {
267
- const objValue = object[key];
268
- newValue =
269
- isObject(objValue) || Array.isArray(objValue)
270
- ? objValue
271
- : !isNaN(+tempPath[index + 1])
272
- ? []
273
- : {};
274
- }
275
- object[key] = newValue;
276
- object = object[key];
277
- }
278
- return object;
279
- }
280
-
281
319
  const focusFieldBy = (fields, callback, fieldsNames) => {
282
320
  for (const key of fieldsNames || Object.keys(fields)) {
283
321
  const field = get(fields, key);
@@ -390,7 +428,6 @@ const useFieldArray = (props) => {
390
428
  }
391
429
  },
392
430
  subject: control._subjects.array,
393
- skipEarlySubscription: true,
394
431
  });
395
432
  const updateValues = React.useCallback((updatedFieldArrayValuesWithKey) => {
396
433
  const updatedFieldArrayValues = omitKeys(updatedFieldArrayValuesWithKey, keyName);
@@ -538,34 +575,6 @@ function cloneObject(data) {
538
575
  return copy;
539
576
  }
540
577
 
541
- function createSubscription() {
542
- let tearDowns = [];
543
- const add = (tearDown) => {
544
- tearDowns.push(tearDown);
545
- };
546
- const unsubscribe = () => {
547
- for (const teardown of tearDowns) {
548
- teardown();
549
- }
550
- tearDowns = [];
551
- };
552
- return {
553
- add,
554
- unsubscribe,
555
- };
556
- }
557
- function createSubscriber(observer, subscription) {
558
- let closed = false;
559
- subscription.add(() => (closed = true));
560
- const next = (value) => {
561
- if (!closed) {
562
- observer.next(value);
563
- }
564
- };
565
- return {
566
- next,
567
- };
568
- }
569
578
  function createSubject() {
570
579
  let _observers = [];
571
580
  const next = (value) => {
@@ -574,10 +583,12 @@ function createSubject() {
574
583
  }
575
584
  };
576
585
  const subscribe = (observer) => {
577
- const subscription = createSubscription();
578
- const subscriber = createSubscriber(observer, subscription);
579
- _observers.push(subscriber);
580
- return subscription;
586
+ _observers.push(observer);
587
+ return {
588
+ unsubscribe: () => {
589
+ _observers = _observers.filter((o) => o !== observer);
590
+ },
591
+ };
581
592
  };
582
593
  const unsubscribe = () => {
583
594
  _observers = [];
@@ -645,8 +656,6 @@ var isRadioInput = (element) => element.type === 'radio';
645
656
 
646
657
  var isRadioOrCheckboxFunction = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
647
658
 
648
- var isString = (value) => typeof value === 'string';
649
-
650
659
  var isWeb = typeof window !== 'undefined' &&
651
660
  typeof window.HTMLElement !== 'undefined' &&
652
661
  typeof document !== 'undefined';
@@ -1084,7 +1093,6 @@ function createFormControl(props = {}) {
1084
1093
  };
1085
1094
  const _subjects = {
1086
1095
  watch: createSubject(),
1087
- control: createSubject(),
1088
1096
  array: createSubject(),
1089
1097
  state: createSubject(),
1090
1098
  };
@@ -1289,16 +1297,10 @@ function createFormControl(props = {}) {
1289
1297
  : isString(names)
1290
1298
  ? { [names]: defaultValue }
1291
1299
  : defaultValue));
1292
- if (names) {
1293
- const result = convertToArrayPayload(names).map((fieldName) => (isGlobal && _names.watch.add(fieldName),
1294
- get(fieldValues, fieldName)));
1295
- return Array.isArray(names) ? result : result[0];
1296
- }
1297
- isGlobal && (_names.watchAll = true);
1298
- return fieldValues;
1300
+ return generateWatchOutput(names, _names, fieldValues, isGlobal);
1299
1301
  };
1300
1302
  const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, props.shouldUnregister ? get(_defaultValues, name, []) : []);
1301
- const setFieldValue = (name, value, options = {}, shouldRender) => {
1303
+ const setFieldValue = (name, value, options = {}) => {
1302
1304
  const field = get(_fields, name);
1303
1305
  let fieldValue = value;
1304
1306
  if (field) {
@@ -1330,11 +1332,6 @@ function createFormControl(props = {}) {
1330
1332
  else {
1331
1333
  fieldReference.ref.value = fieldValue;
1332
1334
  }
1333
- shouldRender &&
1334
- _subjects.control.next({
1335
- values: _formValues,
1336
- name,
1337
- });
1338
1335
  }
1339
1336
  }
1340
1337
  (options.shouldDirty || options.shouldTouch) &&
@@ -1351,7 +1348,7 @@ function createFormControl(props = {}) {
1351
1348
  (field && !field._f)) &&
1352
1349
  !isDateObject(fieldValue)
1353
1350
  ? setValues(fieldName, fieldValue, options)
1354
- : setFieldValue(fieldName, fieldValue, options, true);
1351
+ : setFieldValue(fieldName, fieldValue, options);
1355
1352
  }
1356
1353
  };
1357
1354
  const setValue = (name, value, options = {}) => {
@@ -1376,7 +1373,7 @@ function createFormControl(props = {}) {
1376
1373
  else {
1377
1374
  field && !field._f && !isNullOrUndefined(value)
1378
1375
  ? setValues(name, value, options)
1379
- : setFieldValue(name, value, options, true);
1376
+ : setFieldValue(name, value, options);
1380
1377
  }
1381
1378
  isFieldWatched(name) && _subjects.state.next({});
1382
1379
  _subjects.watch.next({
@@ -1457,7 +1454,7 @@ function createFormControl(props = {}) {
1457
1454
  const field = get(_fields, fieldName);
1458
1455
  return await executeBuildInValidation(field && field._f ? { [fieldName]: field } : field);
1459
1456
  }))).every(Boolean);
1460
- _updateValid();
1457
+ !(!validationResult && !_formState.isValid) && _updateValid();
1461
1458
  }
1462
1459
  else {
1463
1460
  validationResult = isValid = await executeBuildInValidation(_fields);
@@ -1530,7 +1527,9 @@ function createFormControl(props = {}) {
1530
1527
  _f: Object.assign(Object.assign(Object.assign({}, (field && field._f ? field._f : { ref: { name } })), { name, mount: true }), options),
1531
1528
  });
1532
1529
  _names.mount.add(name);
1533
- !isUndefined(options.value) && set(_formValues, name, options.value);
1530
+ !isUndefined(options.value) &&
1531
+ !options.disabled &&
1532
+ set(_formValues, name, get(_formValues, name, options.value));
1534
1533
  field
1535
1534
  ? isBoolean(options.disabled) &&
1536
1535
  set(_formValues, name, options.disabled
@@ -1586,7 +1585,9 @@ function createFormControl(props = {}) {
1586
1585
  e.persist && e.persist();
1587
1586
  }
1588
1587
  let hasNoPromiseError = true;
1589
- let fieldValues = Object.assign({}, _formValues);
1588
+ let fieldValues = _options.shouldUnregister
1589
+ ? cloneObject(_formValues)
1590
+ : Object.assign({}, _formValues);
1590
1591
  _subjects.state.next({
1591
1592
  isSubmitting: true,
1592
1593
  });
@@ -1628,10 +1629,35 @@ function createFormControl(props = {}) {
1628
1629
  });
1629
1630
  }
1630
1631
  };
1632
+ const resetField = (name, options = {}) => {
1633
+ if (isUndefined(options.defaultValue)) {
1634
+ setValue(name, get(_defaultValues, name));
1635
+ }
1636
+ else {
1637
+ setValue(name, options.defaultValue);
1638
+ set(_defaultValues, name, options.defaultValue);
1639
+ }
1640
+ if (!options.keepTouched) {
1641
+ unset(_formState.touchedFields, name);
1642
+ }
1643
+ if (!options.keepDirty) {
1644
+ unset(_formState.dirtyFields, name);
1645
+ _formState.isDirty = options.defaultValue
1646
+ ? _getDirty(name, get(_defaultValues, name))
1647
+ : _getDirty();
1648
+ }
1649
+ if (!options.keepError) {
1650
+ unset(_formState.errors, name);
1651
+ _proxyFormState.isValid && _updateValid();
1652
+ }
1653
+ _subjects.state.next(Object.assign({}, _formState));
1654
+ };
1631
1655
  const reset = (formValues, keepStateOptions = {}) => {
1632
- const hasUpdatedFormValues = !isEmptyObject(formValues);
1633
1656
  const updatedValues = formValues || _defaultValues;
1634
1657
  const cloneUpdatedValues = cloneObject(updatedValues);
1658
+ const values = !isEmptyObject(formValues)
1659
+ ? cloneUpdatedValues
1660
+ : _defaultValues;
1635
1661
  if (!keepStateOptions.keepDefaultValues) {
1636
1662
  _defaultValues = updatedValues;
1637
1663
  }
@@ -1658,12 +1684,11 @@ function createFormControl(props = {}) {
1658
1684
  : {}
1659
1685
  : cloneUpdatedValues;
1660
1686
  _fields = {};
1661
- _subjects.control.next({
1662
- values: hasUpdatedFormValues ? cloneUpdatedValues : _defaultValues,
1687
+ _subjects.watch.next({
1688
+ values,
1663
1689
  });
1664
- _subjects.watch.next({});
1665
1690
  _subjects.array.next({
1666
- values: cloneUpdatedValues,
1691
+ values,
1667
1692
  });
1668
1693
  }
1669
1694
  _names = {
@@ -1771,6 +1796,7 @@ function createFormControl(props = {}) {
1771
1796
  setValue,
1772
1797
  getValues,
1773
1798
  reset,
1799
+ resetField,
1774
1800
  clearErrors,
1775
1801
  unregister,
1776
1802
  setError,
@@ -1819,38 +1845,9 @@ function useForm(props = {}) {
1819
1845
  }
1820
1846
  control._removeUnmounted();
1821
1847
  });
1822
- React.useEffect(() => () => Object.values(control._subjects).forEach((subject) => subject.unsubscribe()), [control]);
1823
1848
  _formControl.current.formState = getProxyFormState(formState, control._proxyFormState);
1824
1849
  return _formControl.current;
1825
1850
  }
1826
1851
 
1827
- function useWatch(props) {
1828
- const methods = useFormContext();
1829
- const { control = methods.control, name, defaultValue, disabled, } = props || {};
1830
- const _name = React.useRef(name);
1831
- _name.current = name;
1832
- useSubscribe({
1833
- disabled,
1834
- subject: control._subjects.watch,
1835
- callback: (formState) => {
1836
- if (shouldSubscribeByName(_name.current, formState.name)) {
1837
- control._stateFlags.mount = true;
1838
- const fieldValues = control._getWatch(_name.current, defaultValue);
1839
- updateValue(isObject(fieldValues)
1840
- ? Object.assign({}, fieldValues) : Array.isArray(fieldValues)
1841
- ? [...fieldValues]
1842
- : fieldValues);
1843
- }
1844
- },
1845
- });
1846
- const [value, updateValue] = React.useState(isUndefined(defaultValue)
1847
- ? control._getWatch(name)
1848
- : defaultValue);
1849
- React.useEffect(() => {
1850
- control._removeUnmounted();
1851
- });
1852
- return value;
1853
- }
1854
-
1855
1852
  export { Controller, FormProvider, appendErrors, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
1856
1853
  //# sourceMappingURL=index.esm.js.map