|
1 | 1 | import { Derived, Store, batch } from '@tanstack/store' |
2 | 2 | import { |
3 | 3 | deleteBy, |
| 4 | + determineErrorValue, |
4 | 5 | functionalUpdate, |
5 | 6 | getAsyncValidatorArray, |
6 | 7 | getBy, |
@@ -729,22 +730,6 @@ export class FormApi< |
729 | 730 | */ |
730 | 731 | prevTransformArray: unknown[] = [] |
731 | 732 |
|
732 | | - /** |
733 | | - * @private Persistent store of all field validation errors originating from form-level validators. |
734 | | - * Maintains the cumulative state across validation cycles, including cleared errors (undefined values). |
735 | | - * This map preserves the complete validation state for all fields. |
736 | | - */ |
737 | | - cumulativeFieldsErrorMap: FormErrorMapFromValidator< |
738 | | - TFormData, |
739 | | - TOnMount, |
740 | | - TOnChange, |
741 | | - TOnChangeAsync, |
742 | | - TOnBlur, |
743 | | - TOnBlurAsync, |
744 | | - TOnSubmit, |
745 | | - TOnSubmitAsync |
746 | | - > = {} |
747 | | - |
748 | 733 | /** |
749 | 734 | * Constructs a new `FormApi` instance with the given form options. |
750 | 735 | */ |
@@ -1300,50 +1285,48 @@ export class FormApi< |
1300 | 1285 |
|
1301 | 1286 | const errorMapKey = getErrorMapKey(validateObj.cause) |
1302 | 1287 |
|
1303 | | - if (fieldErrors) { |
1304 | | - for (const [field, fieldError] of Object.entries(fieldErrors) as [ |
1305 | | - DeepKeys<TFormData>, |
1306 | | - ValidationError, |
1307 | | - ][]) { |
1308 | | - const oldErrorMap = this.cumulativeFieldsErrorMap[field] || {} |
1309 | | - const newErrorMap = { |
1310 | | - ...oldErrorMap, |
1311 | | - [errorMapKey]: fieldError, |
1312 | | - } |
1313 | | - currentValidationErrorMap[field] = newErrorMap |
1314 | | - this.cumulativeFieldsErrorMap[field] = newErrorMap |
| 1288 | + for (const field of Object.keys( |
| 1289 | + this.state.fieldMeta, |
| 1290 | + ) as DeepKeys<TFormData>[]) { |
| 1291 | + const fieldMeta = this.getFieldMeta(field) |
| 1292 | + if (!fieldMeta) continue |
1315 | 1293 |
|
1316 | | - const fieldMeta = this.getFieldMeta(field) |
1317 | | - if (fieldMeta && fieldMeta.errorMap[errorMapKey] !== fieldError) { |
1318 | | - this.setFieldMeta(field, (prev) => ({ |
1319 | | - ...prev, |
1320 | | - errorMap: { |
1321 | | - ...prev.errorMap, |
1322 | | - [errorMapKey]: fieldError, |
1323 | | - }, |
1324 | | - })) |
| 1294 | + const { |
| 1295 | + errorMap: currentErrorMap, |
| 1296 | + errorSourceMap: currentErrorMapSource, |
| 1297 | + } = fieldMeta |
| 1298 | + |
| 1299 | + const newFormValidatorError = fieldErrors?.[field] |
| 1300 | + |
| 1301 | + const { newErrorValue, newSource } = determineErrorValue({ |
| 1302 | + newFormValidatorError, |
| 1303 | + isPreviousErrorFromFormValidator: |
| 1304 | + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 1305 | + currentErrorMapSource?.[errorMapKey] === 'form', |
| 1306 | + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 1307 | + previousErrorValue: currentErrorMap?.[errorMapKey], |
| 1308 | + }) |
| 1309 | + |
| 1310 | + if (newSource === 'form') { |
| 1311 | + currentValidationErrorMap[field] = { |
| 1312 | + ...currentValidationErrorMap[field], |
| 1313 | + [errorMapKey]: newFormValidatorError, |
1325 | 1314 | } |
1326 | 1315 | } |
1327 | | - } |
1328 | 1316 |
|
1329 | | - for (const field of Object.keys(this.cumulativeFieldsErrorMap) as Array< |
1330 | | - DeepKeys<TFormData> |
1331 | | - >) { |
1332 | | - const fieldMeta = this.getFieldMeta(field) |
1333 | 1317 | if ( |
1334 | | - fieldMeta?.errorMap[errorMapKey] && |
1335 | | - !currentValidationErrorMap[field]?.[errorMapKey] |
| 1318 | + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 1319 | + currentErrorMap?.[errorMapKey] !== newErrorValue |
1336 | 1320 | ) { |
1337 | | - this.cumulativeFieldsErrorMap[field] = { |
1338 | | - ...this.cumulativeFieldsErrorMap[field], |
1339 | | - [errorMapKey]: undefined, |
1340 | | - } |
1341 | | - |
1342 | 1321 | this.setFieldMeta(field, (prev) => ({ |
1343 | 1322 | ...prev, |
1344 | 1323 | errorMap: { |
1345 | 1324 | ...prev.errorMap, |
1346 | | - [errorMapKey]: undefined, |
| 1325 | + [errorMapKey]: newErrorValue, |
| 1326 | + }, |
| 1327 | + errorSourceMap: { |
| 1328 | + ...prev.errorSourceMap, |
| 1329 | + [errorMapKey]: newSource, |
1347 | 1330 | }, |
1348 | 1331 | })) |
1349 | 1332 | } |
@@ -1473,20 +1456,47 @@ export class FormApi< |
1473 | 1456 | } |
1474 | 1457 | const errorMapKey = getErrorMapKey(validateObj.cause) |
1475 | 1458 |
|
1476 | | - if (fieldErrors) { |
1477 | | - for (const [field, fieldError] of Object.entries(fieldErrors)) { |
1478 | | - const fieldMeta = this.getFieldMeta(field as DeepKeys<TFormData>) |
1479 | | - if (fieldMeta && fieldMeta.errorMap[errorMapKey] !== fieldError) { |
1480 | | - this.setFieldMeta(field as DeepKeys<TFormData>, (prev) => ({ |
1481 | | - ...prev, |
1482 | | - errorMap: { |
1483 | | - ...prev.errorMap, |
1484 | | - [errorMapKey]: fieldError, |
1485 | | - }, |
1486 | | - })) |
1487 | | - } |
| 1459 | + // if (fieldErrors) { |
| 1460 | + for (const field of Object.keys( |
| 1461 | + this.state.fieldMeta, |
| 1462 | + ) as DeepKeys<TFormData>[]) { |
| 1463 | + const fieldMeta = this.getFieldMeta(field) |
| 1464 | + if (!fieldMeta) continue |
| 1465 | + |
| 1466 | + const { |
| 1467 | + errorMap: currentErrorMap, |
| 1468 | + errorSourceMap: currentErrorMapSource, |
| 1469 | + } = fieldMeta |
| 1470 | + |
| 1471 | + const newFormValidatorError = fieldErrors?.[field] |
| 1472 | + |
| 1473 | + const { newErrorValue, newSource } = determineErrorValue({ |
| 1474 | + newFormValidatorError, |
| 1475 | + isPreviousErrorFromFormValidator: |
| 1476 | + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 1477 | + currentErrorMapSource?.[errorMapKey] === 'form', |
| 1478 | + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 1479 | + previousErrorValue: currentErrorMap?.[errorMapKey], |
| 1480 | + }) |
| 1481 | + |
| 1482 | + if ( |
| 1483 | + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition |
| 1484 | + currentErrorMap?.[errorMapKey] !== newErrorValue |
| 1485 | + ) { |
| 1486 | + this.setFieldMeta(field, (prev) => ({ |
| 1487 | + ...prev, |
| 1488 | + errorMap: { |
| 1489 | + ...prev.errorMap, |
| 1490 | + [errorMapKey]: newErrorValue, |
| 1491 | + }, |
| 1492 | + errorSourceMap: { |
| 1493 | + ...prev.errorSourceMap, |
| 1494 | + [errorMapKey]: newSource, |
| 1495 | + }, |
| 1496 | + })) |
1488 | 1497 | } |
1489 | 1498 | } |
| 1499 | + |
1490 | 1500 | this.baseStore.setState((prev) => ({ |
1491 | 1501 | ...prev, |
1492 | 1502 | errorMap: { |
|
0 commit comments