react-hook-form 7.79.0 → 7.81.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.
@@ -1 +1 @@
1
- {"version":3,"file":"createFormControl.d.ts","sourceRoot":"","sources":["../../src/logic/createFormControl.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAcV,WAAW,EAiBX,YAAY,EAKZ,aAAa,EAYd,MAAM,UAAU,CAAC;AAuDlB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;CAY9B,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,QAAQ,GAAG,GAAG,EACd,kBAAkB,GAAG,YAAY,EAEjC,KAAK,GAAE,YAAY,CAAC,YAAY,EAAE,QAAQ,EAAE,kBAAkB,CAAM,GACnE,IAAI,CACL,aAAa,CAAC,YAAY,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EACzD,WAAW,CACZ,GAAG;IACF,WAAW,EAAE,IAAI,CACf,aAAa,CAAC,YAAY,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EACzD,WAAW,CACZ,CAAC;CACH,CAwwDA"}
1
+ {"version":3,"file":"createFormControl.d.ts","sourceRoot":"","sources":["../../src/logic/createFormControl.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAcV,WAAW,EAiBX,YAAY,EAKZ,aAAa,EAYd,MAAM,UAAU,CAAC;AA0DlB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;CAY9B,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,QAAQ,GAAG,GAAG,EACd,kBAAkB,GAAG,YAAY,EAEjC,KAAK,GAAE,YAAY,CAAC,YAAY,EAAE,QAAQ,EAAE,kBAAkB,CAAM,GACnE,IAAI,CACL,aAAa,CAAC,YAAY,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EACzD,WAAW,CACZ,GAAG;IACF,WAAW,EAAE,IAAI,CACf,aAAa,CAAC,YAAY,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EACzD,WAAW,CACZ,CAAC;CACH,CA2zDA"}
@@ -1 +1 @@
1
- {"version":3,"file":"getNodeParentName.d.ts","sourceRoot":"","sources":["../../src/logic/getNodeParentName.ts"],"names":[],"mappings":"yBAAgB,MAAM,MAAM;AAA5B,wBACwD"}
1
+ {"version":3,"file":"getNodeParentName.d.ts","sourceRoot":"","sources":["../../src/logic/getNodeParentName.ts"],"names":[],"mappings":"yBAEgB,MAAM,MAAM;AAA5B,wBACyD"}
@@ -1 +1 @@
1
- {"version":3,"file":"hasPromiseValidation.d.ts","sourceRoot":"","sources":["../../src/logic/hasPromiseValidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAY,MAAM,UAAU,CAAC;yBAMhC,gBAAgB,KAAK,CAAC,IAAI,CAAC;AAA3C,wBAWI"}
1
+ {"version":3,"file":"hasPromiseValidation.d.ts","sourceRoot":"","sources":["../../src/logic/hasPromiseValidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAY,MAAM,UAAU,CAAC;yBAMhC,gBAAgB,KAAK,CAAC,IAAI,CAAC;AAA3C,wBAmBE"}
@@ -1 +1 @@
1
- {"version":3,"file":"isWatched.d.ts","sourceRoot":"","sources":["../../src/logic/isWatched.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;yBAGvD,MAAM,iBAAiB,EACvB,QAAQ,KAAK,EACb,cAAc,OAAO;AAHvB,wBAQ6E"}
1
+ {"version":3,"file":"isWatched.d.ts","sourceRoot":"","sources":["../../src/logic/isWatched.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;yBAGvD,MAAM,iBAAiB,EACvB,QAAQ,KAAK,EACb,cAAc,OAAO;AAHvB,wBAYE"}
@@ -1 +1 @@
1
- {"version":3,"file":"shouldRenderFormState.d.ts","sourceRoot":"","sources":["../../src/logic/shouldRenderFormState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,EACd,MAAM,UAAU,CAAC;yBAGF,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,aAAa,EAC5D,eAAe,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG;IACrC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,CAAC;CACZ,EACD,iBAAiB,CAAC,EAClB,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAC3D,SAAS,OAAO;AAPlB,wBAsBE"}
1
+ {"version":3,"file":"shouldRenderFormState.d.ts","sourceRoot":"","sources":["../../src/logic/shouldRenderFormState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,EACd,MAAM,UAAU,CAAC;yBAEF,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,aAAa,EAC5D,eAAe,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG;IACrC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,CAAC;CACZ,EACD,iBAAiB,CAAC,EAClB,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAC3D,SAAS,OAAO;AAPlB,wBAsBE"}
@@ -31,7 +31,6 @@ const INPUT_VALIDATION_RULES = {
31
31
  required: 'required',
32
32
  validate: 'validate',
33
33
  };
34
- const FORM_ERROR_TYPE = 'form';
35
34
  const ROOT_ERROR_TYPE = 'root';
36
35
  const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
37
36
 
@@ -129,6 +128,9 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
129
128
  isEmptyObjectWithCustomPrototype(object2, keys2)) {
130
129
  return Object.is(object1, object2);
131
130
  }
131
+ if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
132
+ return false;
133
+ }
132
134
  const visitedPairs = visited.get(object1);
133
135
  if (visitedPairs && visitedPairs.has(object2)) {
134
136
  return true;
@@ -137,7 +139,9 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
137
139
  visitedPairs.add(object2);
138
140
  }
139
141
  else {
140
- visited.set(object1, new WeakSet([object2]));
142
+ const ws = new WeakSet();
143
+ ws.add(object2);
144
+ visited.set(object1, ws);
141
145
  }
142
146
  for (const key of keys1) {
143
147
  const val1 = object1[key];
@@ -178,11 +182,31 @@ function extractFormValues(fieldsState, formValues) {
178
182
  return values;
179
183
  }
180
184
 
181
- var isKey = (value) => /^\w*$/.test(value);
185
+ const flatten = (obj) => {
186
+ const output = {};
187
+ for (const key of Object.keys(obj)) {
188
+ if (isObjectType(obj[key]) &&
189
+ obj[key] !== null &&
190
+ !isDateObject(obj[key])) {
191
+ const nested = flatten(obj[key]);
192
+ for (const nestedKey of Object.keys(nested)) {
193
+ output[`${key}.${nestedKey}`] = nested[nestedKey];
194
+ }
195
+ }
196
+ else {
197
+ output[key] = obj[key];
198
+ }
199
+ }
200
+ return output;
201
+ };
202
+
203
+ const IS_KEY_RE = /^\w*$/;
204
+ var isKey = (value) => IS_KEY_RE.test(value);
182
205
 
183
206
  var isUndefined = (val) => val === undefined;
184
207
 
185
- var stringToPath = (input) => input.split(/[.[\]'"]/g).filter(Boolean);
208
+ const FIELD_PATH_RE = /[.[\]'"]/;
209
+ var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
186
210
 
187
211
  var get = (object, path, defaultValue) => {
188
212
  if (!path || !isObject(object)) {
@@ -287,6 +311,9 @@ function unset(object, path) {
287
311
  : isKey(path)
288
312
  ? [path]
289
313
  : stringToPath(path);
314
+ if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
315
+ return object;
316
+ }
290
317
  const childObject = paths.length === 1 ? object : baseGet(object, paths);
291
318
  const index = paths.length - 1;
292
319
  const key = paths[index];
@@ -494,12 +521,22 @@ var getValidationModes = (mode) => ({
494
521
  });
495
522
 
496
523
  const ASYNC_FUNCTION = 'AsyncFunction';
497
- var hasPromiseValidation = (fieldReference) => !!fieldReference &&
498
- !!fieldReference.validate &&
499
- !!((isFunction(fieldReference.validate) &&
500
- fieldReference.validate.constructor.name === ASYNC_FUNCTION) ||
501
- (isObject(fieldReference.validate) &&
502
- Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION)));
524
+ var hasPromiseValidation = (fieldReference) => {
525
+ if (!fieldReference || !fieldReference.validate)
526
+ return false;
527
+ if (isFunction(fieldReference.validate)) {
528
+ return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
529
+ }
530
+ if (isObject(fieldReference.validate)) {
531
+ for (const key in fieldReference.validate) {
532
+ if (fieldReference.validate[key].constructor
533
+ .name === ASYNC_FUNCTION) {
534
+ return true;
535
+ }
536
+ }
537
+ }
538
+ return false;
539
+ };
503
540
 
504
541
  var hasValidation = (options) => options.mount &&
505
542
  (options.required ||
@@ -514,10 +551,17 @@ var isNameInFieldArray = (names, name) => name
514
551
  .split('.')
515
552
  .some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
516
553
 
517
- var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
518
- (_names.watchAll ||
519
- _names.watch.has(name) ||
520
- [..._names.watch].some((watchName) => name.startsWith(`${watchName}.`)));
554
+ var isWatched = (name, _names, isBlurEvent) => {
555
+ if (isBlurEvent)
556
+ return false;
557
+ if (_names.watchAll || _names.watch.has(name))
558
+ return true;
559
+ for (const watchName of _names.watch) {
560
+ if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
561
+ return true;
562
+ }
563
+ return false;
564
+ };
521
565
 
522
566
  const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
523
567
  for (const key of fieldsNames || Object.keys(fields)) {
@@ -585,10 +629,10 @@ function schemaErrorLookup(errors, _fields, name) {
585
629
  var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
586
630
  updateFormState(formStateData);
587
631
  const { name, ...formState } = formStateData;
588
- return (isEmptyObject(formState) ||
589
- (isRoot &&
590
- Object.keys(formState).length >= Object.keys(_proxyFormState).length) ||
591
- Object.keys(formState).find((key) => _proxyFormState[key] ===
632
+ const keys = Object.keys(formState);
633
+ return (!keys.length ||
634
+ (isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
635
+ keys.find((key) => _proxyFormState[key] ===
592
636
  (!isRoot || VALIDATION_MODE.all)));
593
637
  };
594
638
 
@@ -597,7 +641,7 @@ var shouldSubscribeByName = (name, signalName, exact) => !name ||
597
641
  name === signalName ||
598
642
  convertToArrayPayload(name).some((currentName) => currentName &&
599
643
  (exact
600
- ? currentName === signalName
644
+ ? currentName === signalName || currentName.startsWith(signalName + '.')
601
645
  : currentName.startsWith(signalName) ||
602
646
  signalName.startsWith(currentName)));
603
647
 
@@ -836,6 +880,7 @@ const defaultOptions = {
836
880
  reValidateMode: VALIDATION_MODE.onChange,
837
881
  shouldFocusError: true,
838
882
  };
883
+ const FORM_ERROR_TYPE = 'form';
839
884
  const DEFAULT_FORM_STATE = {
840
885
  submitCount: 0,
841
886
  isDirty: false,
@@ -883,6 +928,9 @@ function createFormControl(props = {}) {
883
928
  };
884
929
  let delayErrorCallback;
885
930
  let timer = 0;
931
+ let _valuesSubscriberCount = 0;
932
+ let _validationModeBeforeSubmit = getValidationModes(_options.mode);
933
+ let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
886
934
  const defaultProxyFormState = {
887
935
  isDirty: false,
888
936
  dirtyFields: false,
@@ -1036,12 +1084,6 @@ function createFormControl(props = {}) {
1036
1084
  : setFieldValue(name, defaultValue);
1037
1085
  if (_state.mount && !_state.action) {
1038
1086
  _setValid();
1039
- // Re-registering a field after a prior unregister puts its key back
1040
- // into _formValues, which can flip isDirty back to false (#13397).
1041
- // Only run when we are currently dirty, otherwise an initial register
1042
- // for a field with no defaultValue would flip isDirty to true. Reset
1043
- // paths repopulate _formValues before re-register, so the key is
1044
- // present then and this branch is skipped (preserves keepDirty).
1045
1087
  if (wasUnsetInFormValues &&
1046
1088
  _formState.isDirty &&
1047
1089
  (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
@@ -1051,9 +1093,6 @@ function createFormControl(props = {}) {
1051
1093
  _subjects.state.next({ ..._formState });
1052
1094
  }
1053
1095
  }
1054
- // When a watched field is re-registered after being unregistered and
1055
- // its value is restored, trigger a deferred watch broadcast so that
1056
- // components using watch() re-render with the new value.
1057
1096
  if (props.shouldUnregister &&
1058
1097
  wasUnsetInFormValues &&
1059
1098
  !isUndefined(get(_formValues, name)) &&
@@ -1071,12 +1110,13 @@ function createFormControl(props = {}) {
1071
1110
  };
1072
1111
  if (!_options.disabled) {
1073
1112
  if (!isBlurEvent || shouldDirty) {
1113
+ const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1074
1114
  if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
1075
1115
  isPreviousDirty = _formState.isDirty;
1076
- _formState.isDirty = output.isDirty = _getDirty();
1116
+ _formState.isDirty = output.isDirty =
1117
+ !isCurrentFieldPristine || _getDirty();
1077
1118
  shouldUpdateField = isPreviousDirty !== output.isDirty;
1078
1119
  }
1079
- const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1080
1120
  isPreviousDirty = !!get(_formState.dirtyFields, name);
1081
1121
  if (isCurrentFieldPristine !== _formState.isDirty) {
1082
1122
  _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
@@ -1275,7 +1315,7 @@ function createFormControl(props = {}) {
1275
1315
  };
1276
1316
  const _getDirty = (name, data) => !_options.disabled &&
1277
1317
  (name && data && set(_formValues, name, data),
1278
- !deepEqual(getValues(), _defaultValues));
1318
+ !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
1279
1319
  const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
1280
1320
  ...(_state.mount
1281
1321
  ? _formValues
@@ -1286,7 +1326,7 @@ function createFormControl(props = {}) {
1286
1326
  : defaultValue),
1287
1327
  }, isGlobal, defaultValue);
1288
1328
  const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
1289
- const setFieldValue = (name, value, options = {}, skipClone = false) => {
1329
+ const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
1290
1330
  const field = get(_fields, name);
1291
1331
  let fieldValue = value;
1292
1332
  if (field) {
@@ -1324,7 +1364,7 @@ function createFormControl(props = {}) {
1324
1364
  }
1325
1365
  else {
1326
1366
  fieldReference.ref.value = fieldValue;
1327
- if (!fieldReference.ref.type) {
1367
+ if (!fieldReference.ref.type && !skipRender) {
1328
1368
  _subjects.state.next({
1329
1369
  name,
1330
1370
  values: skipClone ? _formValues : cloneObject(_formValues),
@@ -1334,10 +1374,10 @@ function createFormControl(props = {}) {
1334
1374
  }
1335
1375
  }
1336
1376
  (options.shouldDirty || options.shouldTouch) &&
1337
- updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, true);
1377
+ updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
1338
1378
  options.shouldValidate && trigger(name);
1339
1379
  };
1340
- const setFieldValues = (name, value, options, skipClone = false) => {
1380
+ const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
1341
1381
  for (const fieldKey in value) {
1342
1382
  if (!value.hasOwnProperty(fieldKey)) {
1343
1383
  return;
@@ -1349,11 +1389,11 @@ function createFormControl(props = {}) {
1349
1389
  isObject(fieldValue) ||
1350
1390
  (field && !field._f)) &&
1351
1391
  !isDateObject(fieldValue)
1352
- ? setFieldValues(fieldName, fieldValue, options, skipClone)
1353
- : setFieldValue(fieldName, fieldValue, options, skipClone);
1392
+ ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
1393
+ : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
1354
1394
  }
1355
1395
  };
1356
- const _setValue = (name, value, options, skipClone) => {
1396
+ const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
1357
1397
  const field = get(_fields, name);
1358
1398
  const isFieldArray = _names.array.has(name);
1359
1399
  const cloneValue = skipClone ? value : cloneObject(value);
@@ -1373,24 +1413,26 @@ function createFormControl(props = {}) {
1373
1413
  _proxySubscribeFormState.dirtyFields) &&
1374
1414
  options.shouldDirty) {
1375
1415
  _updateDirtyFields();
1376
- _subjects.state.next({
1377
- name,
1378
- dirtyFields: _formState.dirtyFields,
1379
- isDirty: _getDirty(name, cloneValue),
1380
- });
1416
+ if (!skipStateEmit) {
1417
+ _subjects.state.next({
1418
+ name,
1419
+ dirtyFields: _formState.dirtyFields,
1420
+ isDirty: _getDirty(name, cloneValue),
1421
+ });
1422
+ }
1381
1423
  }
1382
1424
  }
1383
1425
  else {
1384
1426
  const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
1385
1427
  isEmptyObject(cloneValue);
1386
1428
  if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
1387
- setFieldValue(name, cloneValue, options, skipClone);
1429
+ setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
1388
1430
  }
1389
1431
  else {
1390
- setFieldValues(name, cloneValue, options, skipClone);
1432
+ setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
1391
1433
  }
1392
1434
  }
1393
- if (!isValueUnchanged) {
1435
+ if (!isValueUnchanged && !skipStateEmit) {
1394
1436
  const watched = isWatched(name, _names);
1395
1437
  const values = skipClone ? _formValues : cloneObject(_formValues);
1396
1438
  _subjects.state.next({
@@ -1410,14 +1452,17 @@ function createFormControl(props = {}) {
1410
1452
  ..._formValues,
1411
1453
  ...updatedFormValues,
1412
1454
  };
1455
+ const flattenedUpdates = flatten(updatedFormValues);
1413
1456
  for (const fieldName of _names.mount) {
1414
- _setValue(fieldName, get(updatedFormValues, fieldName), options, true);
1457
+ if (fieldName in flattenedUpdates) {
1458
+ _setValue(fieldName, flattenedUpdates[fieldName], options, true, true);
1459
+ }
1415
1460
  }
1416
1461
  _subjects.state.next({
1417
1462
  ..._formState,
1418
1463
  name: undefined,
1419
1464
  type: undefined,
1420
- values: _formValues,
1465
+ ...(_valuesSubscriberCount ? { values: _formValues } : {}),
1421
1466
  });
1422
1467
  if (options.shouldValidate) {
1423
1468
  _setValid();
@@ -1436,8 +1481,6 @@ function createFormControl(props = {}) {
1436
1481
  (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
1437
1482
  deepEqual(fieldValue, get(_formValues, name, fieldValue));
1438
1483
  };
1439
- const validationModeBeforeSubmit = getValidationModes(_options.mode);
1440
- const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1441
1484
  if (field) {
1442
1485
  let error;
1443
1486
  let isValid;
@@ -1445,12 +1488,13 @@ function createFormControl(props = {}) {
1445
1488
  ? getFieldValue(field._f)
1446
1489
  : getEventValue(event);
1447
1490
  const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1448
- const shouldSkipValidation = (!hasValidation(field._f) &&
1491
+ const hasNoValidationEffect = !hasValidation(field._f) &&
1449
1492
  !props.validate &&
1450
1493
  !_options.resolver &&
1451
1494
  !get(_formState.errors, name) &&
1452
- !field._f.deps) ||
1453
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
1495
+ !field._f.deps;
1496
+ const shouldSkipValidation = hasNoValidationEffect ||
1497
+ skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
1454
1498
  const watched = isWatched(name, _names, isBlurEvent);
1455
1499
  set(_formValues, name, fieldValue);
1456
1500
  if (isBlurEvent) {
@@ -1468,10 +1512,13 @@ function createFormControl(props = {}) {
1468
1512
  _subjects.state.next({
1469
1513
  name,
1470
1514
  type: event.type,
1471
- values: cloneObject(_formValues),
1515
+ ...(_valuesSubscriberCount
1516
+ ? { values: cloneObject(_formValues) }
1517
+ : {}),
1472
1518
  });
1473
1519
  if (shouldSkipValidation) {
1474
- if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) {
1520
+ if ((!hasNoValidationEffect || !_formState.isValid) &&
1521
+ (_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
1475
1522
  if (_options.mode === 'onBlur') {
1476
1523
  if (isBlurEvent) {
1477
1524
  _setValid();
@@ -1606,8 +1653,6 @@ function createFormControl(props = {}) {
1606
1653
  const names = name ? convertToArrayPayload(name) : undefined;
1607
1654
  names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
1608
1655
  if (names) {
1609
- // Emit for each cleared field with the field name so that
1610
- // shouldSubscribeByName can filter and avoid broad re-renders
1611
1656
  names.forEach((inputName) => {
1612
1657
  _subjects.state.next({
1613
1658
  name: inputName,
@@ -1616,7 +1661,6 @@ function createFormControl(props = {}) {
1616
1661
  });
1617
1662
  }
1618
1663
  else {
1619
- // Clear all errors - emit without name to notify all subscribers
1620
1664
  _subjects.state.next({
1621
1665
  errors: {},
1622
1666
  });
@@ -1625,7 +1669,6 @@ function createFormControl(props = {}) {
1625
1669
  const setError = (name, error, options) => {
1626
1670
  const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
1627
1671
  const currentError = get(_formState.errors, name) || {};
1628
- // Don't override existing error messages elsewhere in the object tree.
1629
1672
  const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
1630
1673
  set(_formState.errors, name, {
1631
1674
  ...restOfErrorTree,
@@ -1639,26 +1682,60 @@ function createFormControl(props = {}) {
1639
1682
  });
1640
1683
  options && options.shouldFocus && ref && ref.focus && ref.focus();
1641
1684
  };
1642
- const watch = (name, defaultValue) => isFunction(name)
1643
- ? _subjects.state.subscribe({
1644
- next: (payload) => 'values' in payload &&
1645
- name(payload.values || _getWatch(undefined, defaultValue), payload),
1646
- })
1647
- : _getWatch(name, defaultValue, true);
1648
- const _subscribe = (props) => _subjects.state.subscribe({
1649
- next: (formState) => {
1650
- if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
1651
- shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
1652
- const snapshot = { ..._formValues };
1653
- props.callback({
1654
- values: snapshot,
1655
- ..._formState,
1656
- ...formState,
1657
- defaultValues: _defaultValues,
1658
- });
1685
+ const watch = (name, defaultValue) => {
1686
+ if (isFunction(name)) {
1687
+ _valuesSubscriberCount++;
1688
+ const { unsubscribe } = _subjects.state.subscribe({
1689
+ next: (payload) => 'values' in payload &&
1690
+ name(payload.values || _getWatch(undefined, defaultValue), payload),
1691
+ });
1692
+ let called = false;
1693
+ return {
1694
+ unsubscribe: () => {
1695
+ if (called) {
1696
+ return;
1697
+ }
1698
+ called = true;
1699
+ _valuesSubscriberCount--;
1700
+ unsubscribe();
1701
+ },
1702
+ };
1703
+ }
1704
+ return _getWatch(name, defaultValue, true);
1705
+ };
1706
+ const _subscribe = (props) => {
1707
+ var _a;
1708
+ const needsValues = !!((_a = props.formState) === null || _a === void 0 ? void 0 : _a.values);
1709
+ if (needsValues) {
1710
+ _valuesSubscriberCount++;
1711
+ }
1712
+ const { unsubscribe } = _subjects.state.subscribe({
1713
+ next: (formState) => {
1714
+ if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
1715
+ shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
1716
+ const snapshot = { ..._formValues };
1717
+ props.callback({
1718
+ values: snapshot,
1719
+ ..._formState,
1720
+ ...formState,
1721
+ defaultValues: _defaultValues,
1722
+ });
1723
+ }
1724
+ },
1725
+ });
1726
+ if (!needsValues) {
1727
+ return unsubscribe;
1728
+ }
1729
+ let called = false;
1730
+ return () => {
1731
+ if (called) {
1732
+ return;
1659
1733
  }
1660
- },
1661
- }).unsubscribe;
1734
+ called = true;
1735
+ _valuesSubscriberCount--;
1736
+ unsubscribe();
1737
+ };
1738
+ };
1662
1739
  const subscribe = (props) => {
1663
1740
  _state.mount = true;
1664
1741
  _proxySubscribeFormState = {
@@ -1971,6 +2048,8 @@ function createFormControl(props = {}) {
1971
2048
  values: { ...values },
1972
2049
  });
1973
2050
  _subjects.state.next({
2051
+ name: undefined,
2052
+ type: undefined,
1974
2053
  values: { ...values },
1975
2054
  });
1976
2055
  }
@@ -1992,9 +2071,6 @@ function createFormControl(props = {}) {
1992
2071
  _state.watch = !!_options.shouldUnregister;
1993
2072
  _state.keepIsValid = !!keepStateOptions.keepIsValid;
1994
2073
  _state.action = false;
1995
- // Clear errors synchronously to prevent validation errors on subsequent submissions
1996
- // This fixes the issue where form.reset() causes validation errors on subsequent
1997
- // submissions in Next.js 16 with Server Actions
1998
2074
  if (!keepStateOptions.keepErrors) {
1999
2075
  _formState.errors = {};
2000
2076
  }
@@ -2046,8 +2122,6 @@ function createFormControl(props = {}) {
2046
2122
  ? fieldReference.refs[0]
2047
2123
  : fieldReference.ref;
2048
2124
  if (fieldRef.focus) {
2049
- // Use setTimeout to ensure focus happens after any pending state updates
2050
- // This fixes the issue where setFocus doesn't work immediately after setError
2051
2125
  setTimeout(() => {
2052
2126
  fieldRef.focus();
2053
2127
  options.shouldSelect &&
@@ -2058,9 +2132,15 @@ function createFormControl(props = {}) {
2058
2132
  }
2059
2133
  };
2060
2134
  const _setFormState = (updatedFormState) => {
2135
+ // `name`, `type`, and `values` describe the event that produced this
2136
+ // update, not the form's persisted state (they aren't part of
2137
+ // `FormState`). Merging them in would leak a stale `name`/`type` from
2138
+ // one event into a later, unrelated notification that doesn't specify
2139
+ // its own.
2140
+ const { name, type, values, ...formState } = updatedFormState;
2061
2141
  _formState = {
2062
2142
  ..._formState,
2063
- ...updatedFormState,
2143
+ ...formState,
2064
2144
  };
2065
2145
  };
2066
2146
  const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
@@ -2141,6 +2221,8 @@ function createFormControl(props = {}) {
2141
2221
  ..._options,
2142
2222
  ...value,
2143
2223
  };
2224
+ _validationModeBeforeSubmit = getValidationModes(_options.mode);
2225
+ _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
2144
2226
  },
2145
2227
  },
2146
2228
  subscribe,