react-hook-form 7.18.0-next.0 → 7.19.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.
package/dist/index.esm.js CHANGED
@@ -101,35 +101,39 @@ 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
- const tearDown = (_unsubscribe) => {
107
- if (_unsubscribe.current) {
108
- _unsubscribe.current.unsubscribe();
109
- _unsubscribe.current = undefined;
104
+ var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
105
+
106
+ var shouldSubscribeByName = (name, signalName) => !name ||
107
+ !signalName ||
108
+ name === signalName ||
109
+ convertToArrayPayload(name).some((currentName) => currentName &&
110
+ (currentName.startsWith(signalName) ||
111
+ signalName.startsWith(currentName)));
112
+
113
+ const tearDown = (_subscription) => {
114
+ if (_subscription.current) {
115
+ _subscription.current.unsubscribe();
116
+ _subscription.current = undefined;
110
117
  }
111
118
  };
112
- const updateSubscriptionProps = ({ _unsubscribe, props }) => () => {
119
+ const updateSubscriptionProps = ({ _subscription, props }) => {
113
120
  if (props.disabled) {
114
- tearDown(_unsubscribe);
121
+ tearDown(_subscription);
115
122
  }
116
- else if (!_unsubscribe.current) {
117
- _unsubscribe.current = props.subject.subscribe({
123
+ else if (!_subscription.current) {
124
+ _subscription.current = props.subject.subscribe({
118
125
  next: props.callback,
119
126
  });
120
127
  }
121
128
  };
122
129
  function useSubscribe(props) {
123
- const _unsubscribe = React.useRef();
124
- const _updateSubscription = React.useRef(() => { });
125
- _updateSubscription.current = updateSubscriptionProps({
126
- _unsubscribe,
130
+ const _subscription = React.useRef();
131
+ updateSubscriptionProps({
132
+ _subscription,
127
133
  props,
128
134
  });
129
- !props.skipEarlySubscription && _updateSubscription.current();
130
135
  React.useEffect(() => {
131
- _updateSubscription.current();
132
- return () => tearDown(_unsubscribe);
136
+ return () => tearDown(_subscription);
133
137
  }, []);
134
138
  }
135
139
 
@@ -149,9 +153,7 @@ function useFormState(props) {
149
153
  _name.current = name;
150
154
  useSubscribe({
151
155
  disabled,
152
- callback: (formState) => (!_name.current ||
153
- !formState.name ||
154
- convertToArrayPayload(_name.current).includes(formState.name)) &&
156
+ callback: (formState) => shouldSubscribeByName(_name.current, formState.name) &&
155
157
  shouldRenderFormState(formState, _localProxyFormState.current) &&
156
158
  updateFormState(Object.assign(Object.assign({}, control._formState), formState)),
157
159
  subject: control._subjects.state,
@@ -159,29 +161,71 @@ function useFormState(props) {
159
161
  return getProxyFormState(formState, control._proxyFormState, _localProxyFormState.current, false);
160
162
  }
161
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
+ function useWatch(props) {
181
+ const methods = useFormContext();
182
+ const { control = methods.control, name, defaultValue, disabled, } = props || {};
183
+ const _name = React.useRef(name);
184
+ _name.current = name;
185
+ useSubscribe({
186
+ disabled,
187
+ subject: control._subjects.watch,
188
+ callback: (formState) => {
189
+ if (shouldSubscribeByName(_name.current, formState.name)) {
190
+ const fieldValues = generateWatchOutput(_name.current, control._names, control._formValues);
191
+ updateValue(isObject(fieldValues)
192
+ ? Object.assign({}, fieldValues) : Array.isArray(fieldValues)
193
+ ? [...fieldValues]
194
+ : fieldValues);
195
+ }
196
+ },
197
+ });
198
+ const [value, updateValue] = React.useState(isUndefined(defaultValue)
199
+ ? control._getWatch(name)
200
+ : defaultValue);
201
+ React.useEffect(() => {
202
+ control._removeUnmounted();
203
+ });
204
+ return value;
205
+ }
206
+
162
207
  function useController(props) {
163
208
  const methods = useFormContext();
164
209
  const { name, control = methods.control, shouldUnregister } = props;
165
- const [value, setInputStateValue] = React.useState(get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)));
210
+ const value = useWatch({
211
+ control,
212
+ name,
213
+ defaultValue: get(control._formValues, name, get(control._defaultValues, name, props.defaultValue)),
214
+ });
166
215
  const formState = useFormState({
167
- control: control || methods.control,
216
+ control,
168
217
  name,
169
218
  });
170
219
  const _name = React.useRef(name);
171
220
  _name.current = name;
172
- useSubscribe({
173
- subject: control._subjects.control,
174
- callback: (data) => (!data.name || _name.current === data.name) &&
175
- setInputStateValue(get(data.values, _name.current)),
176
- });
177
221
  const registerProps = control.register(name, Object.assign(Object.assign({}, props.rules), { value }));
178
- const updateMounted = React.useCallback((name, value) => {
179
- const field = get(control._fields, name);
180
- if (field) {
181
- field._f.mount = value;
182
- }
183
- }, [control]);
184
222
  React.useEffect(() => {
223
+ const updateMounted = (name, value) => {
224
+ const field = get(control._fields, name);
225
+ if (field) {
226
+ field._f.mount = value;
227
+ }
228
+ };
185
229
  updateMounted(name, true);
186
230
  return () => {
187
231
  const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
@@ -194,15 +238,13 @@ function useController(props) {
194
238
  updateMounted(name, false);
195
239
  }
196
240
  };
197
- }, [name, control, shouldUnregister, updateMounted]);
241
+ }, [name, control, shouldUnregister]);
198
242
  return {
199
243
  field: {
200
244
  onChange: (event) => {
201
- const value = getControllerValue(event);
202
- setInputStateValue(value);
203
245
  registerProps.onChange({
204
246
  target: {
205
- value,
247
+ value: getControllerValue(event),
206
248
  name: name,
207
249
  },
208
250
  type: EVENTS.CHANGE,
@@ -373,6 +415,7 @@ const useFieldArray = (props) => {
373
415
  const [fields, setFields] = React.useState(mapIds(control._getFieldArray(name), keyName));
374
416
  const _fieldIds = React.useRef(fields);
375
417
  const _name = React.useRef(name);
418
+ const _actioned = React.useRef(false);
376
419
  _name.current = name;
377
420
  _fieldIds.current = fields;
378
421
  control._names.array.add(name);
@@ -383,10 +426,10 @@ const useFieldArray = (props) => {
383
426
  }
384
427
  },
385
428
  subject: control._subjects.array,
386
- skipEarlySubscription: true,
387
429
  });
388
430
  const updateValues = React.useCallback((updatedFieldArrayValuesWithKey) => {
389
431
  const updatedFieldArrayValues = omitKeys(updatedFieldArrayValuesWithKey, keyName);
432
+ _actioned.current = true;
390
433
  set(control._formValues, name, updatedFieldArrayValues);
391
434
  setFields(updatedFieldArrayValuesWithKey);
392
435
  return updatedFieldArrayValues;
@@ -462,6 +505,17 @@ const useFieldArray = (props) => {
462
505
  }
463
506
  }
464
507
  }
508
+ if (_actioned.current) {
509
+ control._executeSchema([name]).then((result) => {
510
+ const error = get(result.errors, name);
511
+ if (error && error.type && !get(control._formState.errors, name)) {
512
+ set(control._formState.errors, name, error);
513
+ control._subjects.state.next({
514
+ errors: control._formState.errors,
515
+ });
516
+ }
517
+ });
518
+ }
465
519
  control._subjects.watch.next({
466
520
  name,
467
521
  values: control._formValues,
@@ -519,6 +573,34 @@ function cloneObject(data) {
519
573
  return copy;
520
574
  }
521
575
 
576
+ function createSubject() {
577
+ let _observers = [];
578
+ const next = (value) => {
579
+ for (const observer of _observers) {
580
+ observer.next(value);
581
+ }
582
+ };
583
+ const subscribe = (observer) => {
584
+ _observers.push(observer);
585
+ return {
586
+ unsubscribe: () => {
587
+ _observers = _observers.filter((o) => o !== observer);
588
+ },
589
+ };
590
+ };
591
+ const unsubscribe = () => {
592
+ _observers = [];
593
+ };
594
+ return {
595
+ get observers() {
596
+ return _observers;
597
+ },
598
+ next,
599
+ subscribe,
600
+ unsubscribe,
601
+ };
602
+ }
603
+
522
604
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
523
605
 
524
606
  function deepEqual(object1, object2) {
@@ -562,6 +644,8 @@ var getValidationModes = (mode) => ({
562
644
 
563
645
  var isBoolean = (value) => typeof value === 'boolean';
564
646
 
647
+ var isFileInput = (element) => element.type === 'file';
648
+
565
649
  var isHTMLElement = (value) => value instanceof HTMLElement;
566
650
 
567
651
  var isMultipleSelect = (element) => element.type === `select-multiple`;
@@ -570,59 +654,11 @@ var isRadioInput = (element) => element.type === 'radio';
570
654
 
571
655
  var isRadioOrCheckboxFunction = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
572
656
 
573
- var isString = (value) => typeof value === 'string';
574
-
575
657
  var isWeb = typeof window !== 'undefined' &&
576
658
  typeof window.HTMLElement !== 'undefined' &&
577
659
  typeof document !== 'undefined';
578
660
 
579
- var live = (ref) => !isHTMLElement(ref) || !document.contains(ref);
580
-
581
- class Subscription {
582
- constructor() {
583
- this.tearDowns = [];
584
- }
585
- add(tearDown) {
586
- this.tearDowns.push(tearDown);
587
- }
588
- unsubscribe() {
589
- for (const teardown of this.tearDowns) {
590
- teardown();
591
- }
592
- this.tearDowns = [];
593
- }
594
- }
595
- class Subscriber {
596
- constructor(observer, subscription) {
597
- this.observer = observer;
598
- this.closed = false;
599
- subscription.add(() => (this.closed = true));
600
- }
601
- next(value) {
602
- if (!this.closed) {
603
- this.observer.next(value);
604
- }
605
- }
606
- }
607
- class Subject {
608
- constructor() {
609
- this.observers = [];
610
- }
611
- next(value) {
612
- for (const observer of this.observers) {
613
- observer.next(value);
614
- }
615
- }
616
- subscribe(observer) {
617
- const subscription = new Subscription();
618
- const subscriber = new Subscriber(observer, subscription);
619
- this.observers.push(subscriber);
620
- return subscription;
621
- }
622
- unsubscribe() {
623
- this.observers = [];
624
- }
625
- }
661
+ var live = (ref) => isHTMLElement(ref) && document.contains(ref);
626
662
 
627
663
  function baseGet(object, updatePath) {
628
664
  const length = updatePath.slice(0, -1).length;
@@ -663,8 +699,6 @@ function unset(object, path) {
663
699
  return object;
664
700
  }
665
701
 
666
- var isFileInput = (element) => element.type === 'file';
667
-
668
702
  const defaultResult = {
669
703
  value: false,
670
704
  isValid: false,
@@ -758,6 +792,35 @@ var hasValidation = (options) => options.mount &&
758
792
  options.pattern ||
759
793
  options.validate);
760
794
 
795
+ function schemaErrorLookup(errors, _fields, name) {
796
+ const error = get(errors, name);
797
+ if (error || isKey(name)) {
798
+ return {
799
+ error,
800
+ name,
801
+ };
802
+ }
803
+ const names = name.split('.');
804
+ while (names.length) {
805
+ const fieldName = names.join('.');
806
+ const field = get(_fields, fieldName);
807
+ const foundError = get(errors, fieldName);
808
+ if (field && !Array.isArray(field) && name !== fieldName) {
809
+ return { name };
810
+ }
811
+ if (foundError && foundError.type) {
812
+ return {
813
+ name: fieldName,
814
+ error: foundError,
815
+ };
816
+ }
817
+ names.pop();
818
+ }
819
+ return {
820
+ name,
821
+ };
822
+ }
823
+
761
824
  function deepMerge(target, source) {
762
825
  if (isPrimitive(target) || isPrimitive(source)) {
763
826
  return source;
@@ -1027,10 +1090,9 @@ function createFormControl(props = {}) {
1027
1090
  errors: false,
1028
1091
  };
1029
1092
  const _subjects = {
1030
- watch: new Subject(),
1031
- control: new Subject(),
1032
- array: new Subject(),
1033
- state: new Subject(),
1093
+ watch: createSubject(),
1094
+ array: createSubject(),
1095
+ state: createSubject(),
1034
1096
  };
1035
1097
  const validationModeBeforeSubmit = getValidationModes(_options.mode);
1036
1098
  const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
@@ -1047,7 +1109,7 @@ function createFormControl(props = {}) {
1047
1109
  let isValid = false;
1048
1110
  if (_proxyFormState.isValid) {
1049
1111
  isValid = _options.resolver
1050
- ? isEmptyObject((await executeResolver()).errors)
1112
+ ? isEmptyObject((await _executeSchema()).errors)
1051
1113
  : await executeBuildInValidation(_fields, true);
1052
1114
  if (!shouldSkipRender && isValid !== _formState.isValid) {
1053
1115
  _formState.isValid = isValid;
@@ -1166,11 +1228,11 @@ function createFormControl(props = {}) {
1166
1228
  validateFields = {};
1167
1229
  }
1168
1230
  };
1169
- const executeResolver = async (name) => _options.resolver
1231
+ const _executeSchema = async (name) => _options.resolver
1170
1232
  ? await _options.resolver(Object.assign({}, _formValues), _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation))
1171
1233
  : {};
1172
- const executeResolverValidation = async (names) => {
1173
- const { errors } = await executeResolver();
1234
+ const executeSchemaAndUpdateState = async (names) => {
1235
+ const { errors } = await _executeSchema();
1174
1236
  if (names) {
1175
1237
  for (const name of names) {
1176
1238
  const error = get(errors, name);
@@ -1216,7 +1278,9 @@ function createFormControl(props = {}) {
1216
1278
  for (const name of _names.unMount) {
1217
1279
  const field = get(_fields, name);
1218
1280
  field &&
1219
- (field._f.refs ? field._f.refs.every(live) : live(field._f.ref)) &&
1281
+ (field._f.refs
1282
+ ? field._f.refs.every((ref) => !live(ref))
1283
+ : !live(field._f.ref)) &&
1220
1284
  unregister(name);
1221
1285
  }
1222
1286
  _names.unMount = new Set();
@@ -1231,16 +1295,10 @@ function createFormControl(props = {}) {
1231
1295
  : isString(names)
1232
1296
  ? { [names]: defaultValue }
1233
1297
  : defaultValue));
1234
- if (names) {
1235
- const result = convertToArrayPayload(names).map((fieldName) => (isGlobal && _names.watch.add(fieldName),
1236
- get(fieldValues, fieldName)));
1237
- return Array.isArray(names) ? result : result[0];
1238
- }
1239
- isGlobal && (_names.watchAll = true);
1240
- return fieldValues;
1298
+ return generateWatchOutput(names, _names, fieldValues, isGlobal);
1241
1299
  };
1242
- const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, []);
1243
- const setFieldValue = (name, value, options = {}, shouldRender) => {
1300
+ const _getFieldArray = (name) => get(_stateFlags.mount ? _formValues : _defaultValues, name, props.shouldUnregister ? get(_defaultValues, name, []) : []);
1301
+ const setFieldValue = (name, value, options = {}) => {
1244
1302
  const field = get(_fields, name);
1245
1303
  let fieldValue = value;
1246
1304
  if (field) {
@@ -1251,7 +1309,10 @@ function createFormControl(props = {}) {
1251
1309
  isWeb && isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
1252
1310
  ? ''
1253
1311
  : value;
1254
- if (isMultipleSelect(fieldReference.ref)) {
1312
+ if (isFileInput(fieldReference.ref) && !isString(fieldValue)) {
1313
+ fieldReference.ref.files = fieldValue;
1314
+ }
1315
+ else if (isMultipleSelect(fieldReference.ref)) {
1255
1316
  [...fieldReference.ref.options].forEach((selectRef) => (selectRef.selected = fieldValue.includes(selectRef.value)));
1256
1317
  }
1257
1318
  else if (fieldReference.refs) {
@@ -1269,11 +1330,6 @@ function createFormControl(props = {}) {
1269
1330
  else {
1270
1331
  fieldReference.ref.value = fieldValue;
1271
1332
  }
1272
- shouldRender &&
1273
- _subjects.control.next({
1274
- values: _formValues,
1275
- name,
1276
- });
1277
1333
  }
1278
1334
  }
1279
1335
  (options.shouldDirty || options.shouldTouch) &&
@@ -1290,7 +1346,7 @@ function createFormControl(props = {}) {
1290
1346
  (field && !field._f)) &&
1291
1347
  !isDateObject(fieldValue)
1292
1348
  ? setValues(fieldName, fieldValue, options)
1293
- : setFieldValue(fieldName, fieldValue, options, true);
1349
+ : setFieldValue(fieldName, fieldValue, options);
1294
1350
  }
1295
1351
  };
1296
1352
  const setValue = (name, value, options = {}) => {
@@ -1315,7 +1371,7 @@ function createFormControl(props = {}) {
1315
1371
  else {
1316
1372
  field && !field._f && !isNullOrUndefined(value)
1317
1373
  ? setValues(name, value, options)
1318
- : setFieldValue(name, value, options, true);
1374
+ : setFieldValue(name, value, options);
1319
1375
  }
1320
1376
  isFieldWatched(name) && _subjects.state.next({});
1321
1377
  _subjects.watch.next({
@@ -1362,18 +1418,11 @@ function createFormControl(props = {}) {
1362
1418
  isValidating: true,
1363
1419
  });
1364
1420
  if (_options.resolver) {
1365
- const { errors } = await executeResolver([name]);
1366
- error = get(errors, name);
1367
- if (isCheckBoxInput(target) && !error) {
1368
- const parentNodeName = getNodeParentName(name);
1369
- const parentField = get(_fields, parentNodeName);
1370
- if (Array.isArray(parentField) &&
1371
- parentField.every((field) => field._f && isCheckBoxInput(field._f.ref))) {
1372
- const parentError = get(errors, parentNodeName, {});
1373
- parentError.type && (error = parentError);
1374
- name = parentNodeName;
1375
- }
1376
- }
1421
+ const { errors } = await _executeSchema([name]);
1422
+ const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
1423
+ const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
1424
+ error = errorLookupResult.error;
1425
+ name = errorLookupResult.name;
1377
1426
  isValid = isEmptyObject(errors);
1378
1427
  }
1379
1428
  else {
@@ -1392,7 +1441,7 @@ function createFormControl(props = {}) {
1392
1441
  isValidating: true,
1393
1442
  });
1394
1443
  if (_options.resolver) {
1395
- const errors = await executeResolverValidation(isUndefined(name) ? name : fieldNames);
1444
+ const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
1396
1445
  isValid = isEmptyObject(errors);
1397
1446
  validationResult = name
1398
1447
  ? !fieldNames.some((name) => get(errors, name))
@@ -1403,12 +1452,15 @@ function createFormControl(props = {}) {
1403
1452
  const field = get(_fields, fieldName);
1404
1453
  return await executeBuildInValidation(field && field._f ? { [fieldName]: field } : field);
1405
1454
  }))).every(Boolean);
1406
- _updateValid();
1455
+ !(!validationResult && !_formState.isValid) && _updateValid();
1407
1456
  }
1408
1457
  else {
1409
1458
  validationResult = isValid = await executeBuildInValidation(_fields);
1410
1459
  }
1411
- _subjects.state.next(Object.assign(Object.assign({}, (!isString(name) || isValid !== _formState.isValid ? {} : { name })), { errors: _formState.errors, isValid, isValidating: false }));
1460
+ _subjects.state.next(Object.assign(Object.assign(Object.assign({}, (!isString(name) ||
1461
+ (_proxyFormState.isValid && isValid !== _formState.isValid)
1462
+ ? {}
1463
+ : { name })), (_options.resolver ? { isValid } : {})), { errors: _formState.errors, isValidating: false }));
1412
1464
  options.shouldFocus &&
1413
1465
  !validationResult &&
1414
1466
  focusFieldBy(_fields, (key) => get(_formState.errors, key), name ? fieldNames : _names.mount);
@@ -1428,6 +1480,7 @@ function createFormControl(props = {}) {
1428
1480
  : (_formState.errors = {});
1429
1481
  _subjects.state.next({
1430
1482
  errors: _formState.errors,
1483
+ isValid: true,
1431
1484
  });
1432
1485
  };
1433
1486
  const setError = (name, error, options) => {
@@ -1472,7 +1525,8 @@ function createFormControl(props = {}) {
1472
1525
  _f: Object.assign(Object.assign(Object.assign({}, (field && field._f ? field._f : { ref: { name } })), { name, mount: true }), options),
1473
1526
  });
1474
1527
  _names.mount.add(name);
1475
- !isUndefined(options.value) && set(_formValues, name, options.value);
1528
+ !isUndefined(options.value) &&
1529
+ set(_formValues, name, get(_formValues, name, options.value));
1476
1530
  field
1477
1531
  ? isBoolean(options.disabled) &&
1478
1532
  set(_formValues, name, options.disabled
@@ -1502,7 +1556,7 @@ function createFormControl(props = {}) {
1502
1556
  field = {
1503
1557
  _f: isRadioOrCheckbox
1504
1558
  ? Object.assign(Object.assign({}, field._f), { refs: [
1505
- ...compact(field._f.refs || []).filter((ref) => isHTMLElement(ref) && document.contains(ref)),
1559
+ ...compact(field._f.refs || []).filter(live),
1506
1560
  fieldRef,
1507
1561
  ], ref: { type: fieldRef.type, name } }) : Object.assign(Object.assign({}, field._f), { ref: fieldRef }),
1508
1562
  };
@@ -1534,7 +1588,7 @@ function createFormControl(props = {}) {
1534
1588
  });
1535
1589
  try {
1536
1590
  if (_options.resolver) {
1537
- const { errors, values } = await executeResolver();
1591
+ const { errors, values } = await _executeSchema();
1538
1592
  _formState.errors = errors;
1539
1593
  fieldValues = values;
1540
1594
  }
@@ -1570,10 +1624,35 @@ function createFormControl(props = {}) {
1570
1624
  });
1571
1625
  }
1572
1626
  };
1627
+ const resetField = (name, options = {}) => {
1628
+ if (isUndefined(options.defaultValue)) {
1629
+ setValue(name, get(_defaultValues, name));
1630
+ }
1631
+ else {
1632
+ setValue(name, options.defaultValue);
1633
+ set(_defaultValues, name, options.defaultValue);
1634
+ }
1635
+ if (!options.keepTouched) {
1636
+ unset(_formState.touchedFields, name);
1637
+ }
1638
+ if (!options.keepDirty) {
1639
+ unset(_formState.dirtyFields, name);
1640
+ _formState.isDirty = options.defaultValue
1641
+ ? _getDirty(name, get(_defaultValues, name))
1642
+ : _getDirty();
1643
+ }
1644
+ if (!options.keepError) {
1645
+ unset(_formState.errors, name);
1646
+ _proxyFormState.isValid && _updateValid();
1647
+ }
1648
+ _subjects.state.next(Object.assign({}, _formState));
1649
+ };
1573
1650
  const reset = (formValues, keepStateOptions = {}) => {
1574
- const hasUpdatedFormValues = !isEmptyObject(formValues);
1575
1651
  const updatedValues = formValues || _defaultValues;
1576
1652
  const cloneUpdatedValues = cloneObject(updatedValues);
1653
+ const values = !isEmptyObject(formValues)
1654
+ ? cloneUpdatedValues
1655
+ : _defaultValues;
1577
1656
  if (!keepStateOptions.keepDefaultValues) {
1578
1657
  _defaultValues = updatedValues;
1579
1658
  }
@@ -1594,14 +1673,17 @@ function createFormControl(props = {}) {
1594
1673
  }
1595
1674
  }
1596
1675
  }
1597
- _formValues = props.shouldUnregister ? {} : cloneUpdatedValues;
1676
+ _formValues = props.shouldUnregister
1677
+ ? keepStateOptions.keepDefaultValues
1678
+ ? cloneObject(_defaultValues)
1679
+ : {}
1680
+ : cloneUpdatedValues;
1598
1681
  _fields = {};
1599
- _subjects.control.next({
1600
- values: hasUpdatedFormValues ? cloneUpdatedValues : _defaultValues,
1682
+ _subjects.watch.next({
1683
+ values,
1601
1684
  });
1602
- _subjects.watch.next({});
1603
1685
  _subjects.array.next({
1604
- values: cloneUpdatedValues,
1686
+ values,
1605
1687
  });
1606
1688
  }
1607
1689
  _names = {
@@ -1619,14 +1701,16 @@ function createFormControl(props = {}) {
1619
1701
  isDirty: keepStateOptions.keepDirty
1620
1702
  ? _formState.isDirty
1621
1703
  : keepStateOptions.keepDefaultValues
1622
- ? deepEqual(formValues, _defaultValues)
1704
+ ? !deepEqual(formValues, _defaultValues)
1623
1705
  : false,
1624
1706
  isSubmitted: keepStateOptions.keepIsSubmitted
1625
1707
  ? _formState.isSubmitted
1626
1708
  : false,
1627
1709
  dirtyFields: keepStateOptions.keepDirty
1628
1710
  ? _formState.dirtyFields
1629
- : {},
1711
+ : (keepStateOptions.keepDefaultValues && formValues
1712
+ ? Object.entries(formValues).reduce((previous, [key, value]) => (Object.assign(Object.assign({}, previous), { [key]: value !== get(_defaultValues, key) })), {})
1713
+ : {}),
1630
1714
  touchedFields: keepStateOptions.keepTouched
1631
1715
  ? _formState.touchedFields
1632
1716
  : {},
@@ -1640,11 +1724,15 @@ function createFormControl(props = {}) {
1640
1724
  !_proxyFormState.isValid || !!keepStateOptions.keepIsValid;
1641
1725
  _stateFlags.watch = !!props.shouldUnregister;
1642
1726
  };
1643
- const setFocus = (name) => get(_fields, name)._f.ref.focus();
1727
+ const setFocus = (name) => {
1728
+ const field = get(_fields, name)._f;
1729
+ (field.ref.focus ? field.ref : field.refs[0]).focus();
1730
+ };
1644
1731
  return {
1645
1732
  control: {
1646
1733
  register,
1647
1734
  unregister,
1735
+ _executeSchema,
1648
1736
  _getWatch,
1649
1737
  _getDirty,
1650
1738
  _updateValid,
@@ -1703,6 +1791,7 @@ function createFormControl(props = {}) {
1703
1791
  setValue,
1704
1792
  getValues,
1705
1793
  reset,
1794
+ resetField,
1706
1795
  clearErrors,
1707
1796
  unregister,
1708
1797
  setError,
@@ -1751,42 +1840,10 @@ function useForm(props = {}) {
1751
1840
  }
1752
1841
  control._removeUnmounted();
1753
1842
  });
1843
+ React.useEffect(() => () => Object.values(control._subjects).forEach((subject) => subject.unsubscribe()), [control]);
1754
1844
  _formControl.current.formState = getProxyFormState(formState, control._proxyFormState);
1755
1845
  return _formControl.current;
1756
1846
  }
1757
1847
 
1758
- function useWatch(props) {
1759
- const methods = useFormContext();
1760
- const { control = methods.control, name, defaultValue, disabled, } = props || {};
1761
- const _name = React.useRef(name);
1762
- _name.current = name;
1763
- useSubscribe({
1764
- disabled,
1765
- subject: control._subjects.watch,
1766
- callback: ({ name }) => {
1767
- if (!_name.current ||
1768
- !name ||
1769
- convertToArrayPayload(_name.current).some((currentName) => name &&
1770
- currentName &&
1771
- (name.startsWith(currentName) ||
1772
- currentName.startsWith(name)))) {
1773
- control._stateFlags.mount = true;
1774
- const fieldValues = control._getWatch(_name.current, defaultValue);
1775
- updateValue(isObject(fieldValues)
1776
- ? Object.assign({}, fieldValues) : Array.isArray(fieldValues)
1777
- ? [...fieldValues]
1778
- : fieldValues);
1779
- }
1780
- },
1781
- });
1782
- const [value, updateValue] = React.useState(isUndefined(defaultValue)
1783
- ? control._getWatch(name)
1784
- : defaultValue);
1785
- React.useEffect(() => {
1786
- control._removeUnmounted();
1787
- });
1788
- return value;
1789
- }
1790
-
1791
1848
  export { Controller, FormProvider, appendErrors, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
1792
1849
  //# sourceMappingURL=index.esm.js.map