react-hook-form 7.18.0 → 7.19.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.
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,35 +157,104 @@ 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;
@@ -200,15 +267,13 @@ function useController(props) {
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);
@@ -379,6 +417,7 @@ const useFieldArray = (props) => {
379
417
  const [fields, setFields] = React.useState(mapIds(control._getFieldArray(name), keyName));
380
418
  const _fieldIds = React.useRef(fields);
381
419
  const _name = React.useRef(name);
420
+ const _actioned = React.useRef(false);
382
421
  _name.current = name;
383
422
  _fieldIds.current = fields;
384
423
  control._names.array.add(name);
@@ -389,10 +428,10 @@ const useFieldArray = (props) => {
389
428
  }
390
429
  },
391
430
  subject: control._subjects.array,
392
- skipEarlySubscription: true,
393
431
  });
394
432
  const updateValues = React.useCallback((updatedFieldArrayValuesWithKey) => {
395
433
  const updatedFieldArrayValues = omitKeys(updatedFieldArrayValuesWithKey, keyName);
434
+ _actioned.current = true;
396
435
  set(control._formValues, name, updatedFieldArrayValues);
397
436
  setFields(updatedFieldArrayValuesWithKey);
398
437
  return updatedFieldArrayValues;
@@ -468,15 +507,17 @@ const useFieldArray = (props) => {
468
507
  }
469
508
  }
470
509
  }
471
- control._executeSchema([name]).then((result) => {
472
- const error = get(result.errors, name);
473
- if (error && error.type && !get(control._formState.errors, name)) {
474
- set(control._formState.errors, name, error);
475
- control._subjects.state.next({
476
- errors: control._formState.errors,
477
- });
478
- }
479
- });
510
+ if (_actioned.current) {
511
+ control._executeSchema([name]).then((result) => {
512
+ const error = get(result.errors, name);
513
+ if (error && error.type && !get(control._formState.errors, name)) {
514
+ set(control._formState.errors, name, error);
515
+ control._subjects.state.next({
516
+ errors: control._formState.errors,
517
+ });
518
+ }
519
+ });
520
+ }
480
521
  control._subjects.watch.next({
481
522
  name,
482
523
  values: control._formValues,
@@ -534,34 +575,6 @@ function cloneObject(data) {
534
575
  return copy;
535
576
  }
536
577
 
537
- function createSubscription() {
538
- let tearDowns = [];
539
- const add = (tearDown) => {
540
- tearDowns.push(tearDown);
541
- };
542
- const unsubscribe = () => {
543
- for (const teardown of tearDowns) {
544
- teardown();
545
- }
546
- tearDowns = [];
547
- };
548
- return {
549
- add,
550
- unsubscribe,
551
- };
552
- }
553
- function createSubscriber(observer, subscription) {
554
- let closed = false;
555
- subscription.add(() => (closed = true));
556
- const next = (value) => {
557
- if (!closed) {
558
- observer.next(value);
559
- }
560
- };
561
- return {
562
- next,
563
- };
564
- }
565
578
  function createSubject() {
566
579
  let _observers = [];
567
580
  const next = (value) => {
@@ -570,10 +583,12 @@ function createSubject() {
570
583
  }
571
584
  };
572
585
  const subscribe = (observer) => {
573
- const subscription = createSubscription();
574
- const subscriber = createSubscriber(observer, subscription);
575
- _observers.push(subscriber);
576
- return subscription;
586
+ _observers.push(observer);
587
+ return {
588
+ unsubscribe: () => {
589
+ _observers = _observers.filter((o) => o !== observer);
590
+ },
591
+ };
577
592
  };
578
593
  const unsubscribe = () => {
579
594
  _observers = [];
@@ -641,8 +656,6 @@ var isRadioInput = (element) => element.type === 'radio';
641
656
 
642
657
  var isRadioOrCheckboxFunction = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
643
658
 
644
- var isString = (value) => typeof value === 'string';
645
-
646
659
  var isWeb = typeof window !== 'undefined' &&
647
660
  typeof window.HTMLElement !== 'undefined' &&
648
661
  typeof document !== 'undefined';
@@ -1080,7 +1093,6 @@ function createFormControl(props = {}) {
1080
1093
  };
1081
1094
  const _subjects = {
1082
1095
  watch: createSubject(),
1083
- control: createSubject(),
1084
1096
  array: createSubject(),
1085
1097
  state: createSubject(),
1086
1098
  };
@@ -1285,16 +1297,10 @@ function createFormControl(props = {}) {
1285
1297
  : isString(names)
1286
1298
  ? { [names]: defaultValue }
1287
1299
  : defaultValue));
1288
- if (names) {
1289
- const result = convertToArrayPayload(names).map((fieldName) => (isGlobal && _names.watch.add(fieldName),
1290
- get(fieldValues, fieldName)));
1291
- return Array.isArray(names) ? result : result[0];
1292
- }
1293
- isGlobal && (_names.watchAll = true);
1294
- return fieldValues;
1300
+ return generateWatchOutput(names, _names, fieldValues, isGlobal);
1295
1301
  };
1296
1302
  const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, props.shouldUnregister ? get(_defaultValues, name, []) : []);
1297
- const setFieldValue = (name, value, options = {}, shouldRender) => {
1303
+ const setFieldValue = (name, value, options = {}) => {
1298
1304
  const field = get(_fields, name);
1299
1305
  let fieldValue = value;
1300
1306
  if (field) {
@@ -1326,11 +1332,6 @@ function createFormControl(props = {}) {
1326
1332
  else {
1327
1333
  fieldReference.ref.value = fieldValue;
1328
1334
  }
1329
- shouldRender &&
1330
- _subjects.control.next({
1331
- values: _formValues,
1332
- name,
1333
- });
1334
1335
  }
1335
1336
  }
1336
1337
  (options.shouldDirty || options.shouldTouch) &&
@@ -1347,7 +1348,7 @@ function createFormControl(props = {}) {
1347
1348
  (field && !field._f)) &&
1348
1349
  !isDateObject(fieldValue)
1349
1350
  ? setValues(fieldName, fieldValue, options)
1350
- : setFieldValue(fieldName, fieldValue, options, true);
1351
+ : setFieldValue(fieldName, fieldValue, options);
1351
1352
  }
1352
1353
  };
1353
1354
  const setValue = (name, value, options = {}) => {
@@ -1372,7 +1373,7 @@ function createFormControl(props = {}) {
1372
1373
  else {
1373
1374
  field && !field._f && !isNullOrUndefined(value)
1374
1375
  ? setValues(name, value, options)
1375
- : setFieldValue(name, value, options, true);
1376
+ : setFieldValue(name, value, options);
1376
1377
  }
1377
1378
  isFieldWatched(name) && _subjects.state.next({});
1378
1379
  _subjects.watch.next({
@@ -1453,7 +1454,7 @@ function createFormControl(props = {}) {
1453
1454
  const field = get(_fields, fieldName);
1454
1455
  return await executeBuildInValidation(field && field._f ? { [fieldName]: field } : field);
1455
1456
  }))).every(Boolean);
1456
- _updateValid();
1457
+ !(!validationResult && !_formState.isValid) && _updateValid();
1457
1458
  }
1458
1459
  else {
1459
1460
  validationResult = isValid = await executeBuildInValidation(_fields);
@@ -1526,7 +1527,9 @@ function createFormControl(props = {}) {
1526
1527
  _f: Object.assign(Object.assign(Object.assign({}, (field && field._f ? field._f : { ref: { name } })), { name, mount: true }), options),
1527
1528
  });
1528
1529
  _names.mount.add(name);
1529
- !isUndefined(options.value) && set(_formValues, name, options.value);
1530
+ !isUndefined(options.value) &&
1531
+ !options.disabled &&
1532
+ set(_formValues, name, get(_formValues, name, options.value));
1530
1533
  field
1531
1534
  ? isBoolean(options.disabled) &&
1532
1535
  set(_formValues, name, options.disabled
@@ -1624,10 +1627,35 @@ function createFormControl(props = {}) {
1624
1627
  });
1625
1628
  }
1626
1629
  };
1630
+ const resetField = (name, options = {}) => {
1631
+ if (isUndefined(options.defaultValue)) {
1632
+ setValue(name, get(_defaultValues, name));
1633
+ }
1634
+ else {
1635
+ setValue(name, options.defaultValue);
1636
+ set(_defaultValues, name, options.defaultValue);
1637
+ }
1638
+ if (!options.keepTouched) {
1639
+ unset(_formState.touchedFields, name);
1640
+ }
1641
+ if (!options.keepDirty) {
1642
+ unset(_formState.dirtyFields, name);
1643
+ _formState.isDirty = options.defaultValue
1644
+ ? _getDirty(name, get(_defaultValues, name))
1645
+ : _getDirty();
1646
+ }
1647
+ if (!options.keepError) {
1648
+ unset(_formState.errors, name);
1649
+ _proxyFormState.isValid && _updateValid();
1650
+ }
1651
+ _subjects.state.next(Object.assign({}, _formState));
1652
+ };
1627
1653
  const reset = (formValues, keepStateOptions = {}) => {
1628
- const hasUpdatedFormValues = !isEmptyObject(formValues);
1629
1654
  const updatedValues = formValues || _defaultValues;
1630
1655
  const cloneUpdatedValues = cloneObject(updatedValues);
1656
+ const values = !isEmptyObject(formValues)
1657
+ ? cloneUpdatedValues
1658
+ : _defaultValues;
1631
1659
  if (!keepStateOptions.keepDefaultValues) {
1632
1660
  _defaultValues = updatedValues;
1633
1661
  }
@@ -1654,12 +1682,11 @@ function createFormControl(props = {}) {
1654
1682
  : {}
1655
1683
  : cloneUpdatedValues;
1656
1684
  _fields = {};
1657
- _subjects.control.next({
1658
- values: hasUpdatedFormValues ? cloneUpdatedValues : _defaultValues,
1685
+ _subjects.watch.next({
1686
+ values,
1659
1687
  });
1660
- _subjects.watch.next({});
1661
1688
  _subjects.array.next({
1662
- values: cloneUpdatedValues,
1689
+ values,
1663
1690
  });
1664
1691
  }
1665
1692
  _names = {
@@ -1767,6 +1794,7 @@ function createFormControl(props = {}) {
1767
1794
  setValue,
1768
1795
  getValues,
1769
1796
  reset,
1797
+ resetField,
1770
1798
  clearErrors,
1771
1799
  unregister,
1772
1800
  setError,
@@ -1820,33 +1848,5 @@ function useForm(props = {}) {
1820
1848
  return _formControl.current;
1821
1849
  }
1822
1850
 
1823
- function useWatch(props) {
1824
- const methods = useFormContext();
1825
- const { control = methods.control, name, defaultValue, disabled, } = props || {};
1826
- const _name = React.useRef(name);
1827
- _name.current = name;
1828
- useSubscribe({
1829
- disabled,
1830
- subject: control._subjects.watch,
1831
- callback: (formState) => {
1832
- if (shouldSubscribeByName(_name.current, formState.name)) {
1833
- control._stateFlags.mount = true;
1834
- const fieldValues = control._getWatch(_name.current, defaultValue);
1835
- updateValue(isObject(fieldValues)
1836
- ? Object.assign({}, fieldValues) : Array.isArray(fieldValues)
1837
- ? [...fieldValues]
1838
- : fieldValues);
1839
- }
1840
- },
1841
- });
1842
- const [value, updateValue] = React.useState(isUndefined(defaultValue)
1843
- ? control._getWatch(name)
1844
- : defaultValue);
1845
- React.useEffect(() => {
1846
- control._removeUnmounted();
1847
- });
1848
- return value;
1849
- }
1850
-
1851
1851
  export { Controller, FormProvider, appendErrors, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
1852
1852
  //# sourceMappingURL=index.esm.js.map