@tanstack/form-core 1.27.0 → 1.27.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.
@@ -1,6 +1,6 @@
1
1
  import { batch, Store, Derived } from "@tanstack/store";
2
2
  import { throttle } from "@tanstack/pacer";
3
- import { evaluate, getSyncValidatorArray, determineFormLevelErrorSourceAndValue, getAsyncValidatorArray, getBy, functionalUpdate, setBy, deleteBy, mergeOpts, uuid, isNonEmptyArray, isGlobalFormValidationError } from "./utils.js";
3
+ import { evaluate, getSyncValidatorArray, determineFormLevelErrorSourceAndValue, getAsyncValidatorArray, getBy, functionalUpdate, setBy, deleteBy, mergeOpts, isGlobalFormValidationError, uuid, isNonEmptyArray } from "./utils.js";
4
4
  import { defaultValidationLogic } from "./ValidationLogic.js";
5
5
  import { standardSchemaValidators, isStandardSchemaValidator } from "./standardSchemaValidator.js";
6
6
  import { defaultFieldMeta, metaHelper } from "./metaHelper.js";
@@ -403,6 +403,121 @@ class FormApi {
403
403
  }
404
404
  return this.validateAsync(cause);
405
405
  };
406
+ this._handleSubmit = async (submitMeta) => {
407
+ this.baseStore.setState((old) => ({
408
+ ...old,
409
+ // Submission attempts mark the form as not submitted
410
+ isSubmitted: false,
411
+ // Count submission attempts
412
+ submissionAttempts: old.submissionAttempts + 1,
413
+ isSubmitSuccessful: false
414
+ // Reset isSubmitSuccessful at the start of submission
415
+ }));
416
+ batch(() => {
417
+ void Object.values(this.fieldInfo).forEach(
418
+ (field) => {
419
+ if (!field.instance) return;
420
+ if (!field.instance.state.meta.isTouched) {
421
+ field.instance.setMeta((prev) => ({ ...prev, isTouched: true }));
422
+ }
423
+ }
424
+ );
425
+ });
426
+ const submitMetaArg = submitMeta ?? this.options.onSubmitMeta;
427
+ if (!this.state.canSubmit && !this._devtoolsSubmissionOverride) {
428
+ this.options.onSubmitInvalid?.({
429
+ value: this.state.values,
430
+ formApi: this,
431
+ meta: submitMetaArg
432
+ });
433
+ return;
434
+ }
435
+ this.baseStore.setState((d) => ({ ...d, isSubmitting: true }));
436
+ const done = () => {
437
+ this.baseStore.setState((prev) => ({ ...prev, isSubmitting: false }));
438
+ };
439
+ await this.validateAllFields("submit");
440
+ if (!this.state.isFieldsValid) {
441
+ done();
442
+ this.options.onSubmitInvalid?.({
443
+ value: this.state.values,
444
+ formApi: this,
445
+ meta: submitMetaArg
446
+ });
447
+ formEventClient.emit("form-submission", {
448
+ id: this._formId,
449
+ submissionAttempt: this.state.submissionAttempts,
450
+ successful: false,
451
+ stage: "validateAllFields",
452
+ errors: Object.values(this.state.fieldMeta).map((meta) => meta.errors).flat()
453
+ });
454
+ return;
455
+ }
456
+ await this.validate("submit");
457
+ if (!this.state.isValid) {
458
+ done();
459
+ this.options.onSubmitInvalid?.({
460
+ value: this.state.values,
461
+ formApi: this,
462
+ meta: submitMetaArg
463
+ });
464
+ formEventClient.emit("form-submission", {
465
+ id: this._formId,
466
+ submissionAttempt: this.state.submissionAttempts,
467
+ successful: false,
468
+ stage: "validate",
469
+ errors: this.state.errors
470
+ });
471
+ return;
472
+ }
473
+ batch(() => {
474
+ void Object.values(this.fieldInfo).forEach(
475
+ (field) => {
476
+ field.instance?.options.listeners?.onSubmit?.({
477
+ value: field.instance.state.value,
478
+ fieldApi: field.instance
479
+ });
480
+ }
481
+ );
482
+ });
483
+ this.options.listeners?.onSubmit?.({ formApi: this, meta: submitMetaArg });
484
+ try {
485
+ await this.options.onSubmit?.({
486
+ value: this.state.values,
487
+ formApi: this,
488
+ meta: submitMetaArg
489
+ });
490
+ batch(() => {
491
+ this.baseStore.setState((prev) => ({
492
+ ...prev,
493
+ isSubmitted: true,
494
+ isSubmitSuccessful: true
495
+ // Set isSubmitSuccessful to true on successful submission
496
+ }));
497
+ formEventClient.emit("form-submission", {
498
+ id: this._formId,
499
+ submissionAttempt: this.state.submissionAttempts,
500
+ successful: true
501
+ });
502
+ done();
503
+ });
504
+ } catch (err) {
505
+ this.baseStore.setState((prev) => ({
506
+ ...prev,
507
+ isSubmitSuccessful: false
508
+ // Ensure isSubmitSuccessful is false if an error occurs
509
+ }));
510
+ formEventClient.emit("form-submission", {
511
+ id: this._formId,
512
+ submissionAttempt: this.state.submissionAttempts,
513
+ successful: false,
514
+ stage: "inflight",
515
+ onError: err
516
+ });
517
+ done();
518
+ throw err;
519
+ }
520
+ };
406
521
  this.getFieldValue = (field) => getBy(this.state.values, field);
407
522
  this.getFieldMeta = (field) => {
408
523
  return this.state.fieldMeta[field];
@@ -625,6 +740,48 @@ class FormApi {
625
740
  };
626
741
  });
627
742
  };
743
+ this.setErrorMap = (errorMap) => {
744
+ batch(() => {
745
+ Object.entries(errorMap).forEach(([key, value]) => {
746
+ const errorMapKey = key;
747
+ if (isGlobalFormValidationError(value)) {
748
+ const { formError, fieldErrors } = normalizeError(value);
749
+ for (const fieldName of Object.keys(
750
+ this.fieldInfo
751
+ )) {
752
+ const fieldMeta = this.getFieldMeta(fieldName);
753
+ if (!fieldMeta) continue;
754
+ this.setFieldMeta(fieldName, (prev) => ({
755
+ ...prev,
756
+ errorMap: {
757
+ ...prev.errorMap,
758
+ [errorMapKey]: fieldErrors?.[fieldName]
759
+ },
760
+ errorSourceMap: {
761
+ ...prev.errorSourceMap,
762
+ [errorMapKey]: "form"
763
+ }
764
+ }));
765
+ }
766
+ this.baseStore.setState((prev) => ({
767
+ ...prev,
768
+ errorMap: {
769
+ ...prev.errorMap,
770
+ [errorMapKey]: formError
771
+ }
772
+ }));
773
+ } else {
774
+ this.baseStore.setState((prev) => ({
775
+ ...prev,
776
+ errorMap: {
777
+ ...prev.errorMap,
778
+ [errorMapKey]: value
779
+ }
780
+ }));
781
+ }
782
+ });
783
+ });
784
+ };
628
785
  this.getAllErrors = () => {
629
786
  return {
630
787
  form: {
@@ -863,165 +1020,8 @@ class FormApi {
863
1020
  }
864
1021
  return props.validate(props.value);
865
1022
  }
866
- async handleSubmit(submitMeta) {
867
- this.baseStore.setState((old) => ({
868
- ...old,
869
- // Submission attempts mark the form as not submitted
870
- isSubmitted: false,
871
- // Count submission attempts
872
- submissionAttempts: old.submissionAttempts + 1,
873
- isSubmitSuccessful: false
874
- // Reset isSubmitSuccessful at the start of submission
875
- }));
876
- batch(() => {
877
- void Object.values(this.fieldInfo).forEach(
878
- (field) => {
879
- if (!field.instance) return;
880
- if (!field.instance.state.meta.isTouched) {
881
- field.instance.setMeta((prev) => ({ ...prev, isTouched: true }));
882
- }
883
- }
884
- );
885
- });
886
- const submitMetaArg = submitMeta ?? this.options.onSubmitMeta;
887
- if (!this.state.canSubmit && !this._devtoolsSubmissionOverride) {
888
- this.options.onSubmitInvalid?.({
889
- value: this.state.values,
890
- formApi: this,
891
- meta: submitMetaArg
892
- });
893
- return;
894
- }
895
- this.baseStore.setState((d) => ({ ...d, isSubmitting: true }));
896
- const done = () => {
897
- this.baseStore.setState((prev) => ({ ...prev, isSubmitting: false }));
898
- };
899
- await this.validateAllFields("submit");
900
- if (!this.state.isFieldsValid) {
901
- done();
902
- this.options.onSubmitInvalid?.({
903
- value: this.state.values,
904
- formApi: this,
905
- meta: submitMetaArg
906
- });
907
- formEventClient.emit("form-submission", {
908
- id: this._formId,
909
- submissionAttempt: this.state.submissionAttempts,
910
- successful: false,
911
- stage: "validateAllFields",
912
- errors: Object.values(this.state.fieldMeta).map((meta) => meta.errors).flat()
913
- });
914
- return;
915
- }
916
- await this.validate("submit");
917
- if (!this.state.isValid) {
918
- done();
919
- this.options.onSubmitInvalid?.({
920
- value: this.state.values,
921
- formApi: this,
922
- meta: submitMetaArg
923
- });
924
- formEventClient.emit("form-submission", {
925
- id: this._formId,
926
- submissionAttempt: this.state.submissionAttempts,
927
- successful: false,
928
- stage: "validate",
929
- errors: this.state.errors
930
- });
931
- return;
932
- }
933
- batch(() => {
934
- void Object.values(this.fieldInfo).forEach(
935
- (field) => {
936
- field.instance?.options.listeners?.onSubmit?.({
937
- value: field.instance.state.value,
938
- fieldApi: field.instance
939
- });
940
- }
941
- );
942
- });
943
- this.options.listeners?.onSubmit?.({ formApi: this, meta: submitMetaArg });
944
- try {
945
- await this.options.onSubmit?.({
946
- value: this.state.values,
947
- formApi: this,
948
- meta: submitMetaArg
949
- });
950
- batch(() => {
951
- this.baseStore.setState((prev) => ({
952
- ...prev,
953
- isSubmitted: true,
954
- isSubmitSuccessful: true
955
- // Set isSubmitSuccessful to true on successful submission
956
- }));
957
- formEventClient.emit("form-submission", {
958
- id: this._formId,
959
- submissionAttempt: this.state.submissionAttempts,
960
- successful: true
961
- });
962
- done();
963
- });
964
- } catch (err) {
965
- this.baseStore.setState((prev) => ({
966
- ...prev,
967
- isSubmitSuccessful: false
968
- // Ensure isSubmitSuccessful is false if an error occurs
969
- }));
970
- formEventClient.emit("form-submission", {
971
- id: this._formId,
972
- submissionAttempt: this.state.submissionAttempts,
973
- successful: false,
974
- stage: "inflight",
975
- onError: err
976
- });
977
- done();
978
- throw err;
979
- }
980
- }
981
- /**
982
- * Updates the form's errorMap
983
- */
984
- setErrorMap(errorMap) {
985
- batch(() => {
986
- Object.entries(errorMap).forEach(([key, value]) => {
987
- const errorMapKey = key;
988
- if (isGlobalFormValidationError(value)) {
989
- const { formError, fieldErrors } = normalizeError(value);
990
- for (const fieldName of Object.keys(
991
- this.fieldInfo
992
- )) {
993
- const fieldMeta = this.getFieldMeta(fieldName);
994
- if (!fieldMeta) continue;
995
- this.setFieldMeta(fieldName, (prev) => ({
996
- ...prev,
997
- errorMap: {
998
- ...prev.errorMap,
999
- [errorMapKey]: fieldErrors?.[fieldName]
1000
- },
1001
- errorSourceMap: {
1002
- ...prev.errorSourceMap,
1003
- [errorMapKey]: "form"
1004
- }
1005
- }));
1006
- }
1007
- this.baseStore.setState((prev) => ({
1008
- ...prev,
1009
- errorMap: {
1010
- ...prev.errorMap,
1011
- [errorMapKey]: formError
1012
- }
1013
- }));
1014
- } else {
1015
- this.baseStore.setState((prev) => ({
1016
- ...prev,
1017
- errorMap: {
1018
- ...prev.errorMap,
1019
- [errorMapKey]: value
1020
- }
1021
- }));
1022
- }
1023
- });
1024
- });
1023
+ handleSubmit(submitMeta) {
1024
+ return this._handleSubmit(submitMeta);
1025
1025
  }
1026
1026
  }
1027
1027
  function normalizeError(rawError) {