@tanstack/form-core 1.20.0 → 1.21.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.
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const devtoolsEventClient = require("@tanstack/devtools-event-client");
4
+ class FormEventClient extends devtoolsEventClient.EventClient {
5
+ constructor() {
6
+ super({
7
+ pluginId: "form-devtools"
8
+ });
9
+ }
10
+ }
11
+ const formEventClient = new FormEventClient();
12
+ exports.formEventClient = formEventClient;
13
+ //# sourceMappingURL=EventClient.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventClient.cjs","sources":["../../src/EventClient.ts"],"sourcesContent":["import { EventClient } from '@tanstack/devtools-event-client'\n\nimport type { AnyFormOptions, AnyFormState } from './FormApi'\n\ntype ExtractEventNames<T> = T extends `${string}:${infer EventName}`\n ? EventName\n : never\n\nexport type BroadcastFormState = {\n id: string\n state: AnyFormState\n options: AnyFormOptions\n}\n\nexport type BroadcastFormSubmissionState =\n | {\n id: string\n submissionAttempt: number\n successful: false\n stage: 'validateAllFields' | 'validate'\n errors: any[]\n }\n | {\n id: string\n submissionAttempt: number\n successful: false\n stage: 'inflight'\n onError: unknown\n }\n | {\n id: string\n submissionAttempt: number\n successful: true\n }\n\nexport type BroadcastFormUnmounted = {\n id: string\n}\n\nexport type RequestFormState = {\n id: string\n}\n\nexport type RequestFormReset = {\n id: string\n}\n\nexport type RequestFormForceReset = {\n id: string\n}\n\ntype EventMap = {\n 'form-devtools:form-state-change': BroadcastFormState\n 'form-devtools:form-submission-state-change': BroadcastFormSubmissionState\n 'form-devtools:form-unmounted': BroadcastFormUnmounted\n 'form-devtools:request-form-state': RequestFormState\n 'form-devtools:request-form-reset': RequestFormReset\n 'form-devtools:request-form-force-submit': RequestFormForceReset\n}\n\nexport type EventClientEventMap = keyof EventMap\n\nexport type EventClientEventNames = ExtractEventNames<EventClientEventMap>\n\nclass FormEventClient extends EventClient<EventMap> {\n constructor() {\n super({\n pluginId: 'form-devtools',\n })\n }\n}\n\nexport const formEventClient = new FormEventClient()\n"],"names":["EventClient"],"mappings":";;;AAgEA,MAAM,wBAAwBA,oBAAAA,YAAsB;AAAA,EAClD,cAAc;AACZ,UAAM;AAAA,MACJ,UAAU;AAAA,IAAA,CACX;AAAA,EACH;AACF;AAEO,MAAM,kBAAkB,IAAI,gBAAA;;"}
@@ -0,0 +1,52 @@
1
+ import { EventClient } from '@tanstack/devtools-event-client';
2
+ import { AnyFormOptions, AnyFormState } from './FormApi.cjs';
3
+ type ExtractEventNames<T> = T extends `${string}:${infer EventName}` ? EventName : never;
4
+ export type BroadcastFormState = {
5
+ id: string;
6
+ state: AnyFormState;
7
+ options: AnyFormOptions;
8
+ };
9
+ export type BroadcastFormSubmissionState = {
10
+ id: string;
11
+ submissionAttempt: number;
12
+ successful: false;
13
+ stage: 'validateAllFields' | 'validate';
14
+ errors: any[];
15
+ } | {
16
+ id: string;
17
+ submissionAttempt: number;
18
+ successful: false;
19
+ stage: 'inflight';
20
+ onError: unknown;
21
+ } | {
22
+ id: string;
23
+ submissionAttempt: number;
24
+ successful: true;
25
+ };
26
+ export type BroadcastFormUnmounted = {
27
+ id: string;
28
+ };
29
+ export type RequestFormState = {
30
+ id: string;
31
+ };
32
+ export type RequestFormReset = {
33
+ id: string;
34
+ };
35
+ export type RequestFormForceReset = {
36
+ id: string;
37
+ };
38
+ type EventMap = {
39
+ 'form-devtools:form-state-change': BroadcastFormState;
40
+ 'form-devtools:form-submission-state-change': BroadcastFormSubmissionState;
41
+ 'form-devtools:form-unmounted': BroadcastFormUnmounted;
42
+ 'form-devtools:request-form-state': RequestFormState;
43
+ 'form-devtools:request-form-reset': RequestFormReset;
44
+ 'form-devtools:request-form-force-submit': RequestFormForceReset;
45
+ };
46
+ export type EventClientEventMap = keyof EventMap;
47
+ export type EventClientEventNames = ExtractEventNames<EventClientEventMap>;
48
+ declare class FormEventClient extends EventClient<EventMap> {
49
+ constructor();
50
+ }
51
+ export declare const formEventClient: FormEventClient;
52
+ export {};
@@ -5,6 +5,7 @@ const utils = require("./utils.cjs");
5
5
  const ValidationLogic = require("./ValidationLogic.cjs");
6
6
  const standardSchemaValidator = require("./standardSchemaValidator.cjs");
7
7
  const metaHelper = require("./metaHelper.cjs");
8
+ const EventClient = require("./EventClient.cjs");
8
9
  function getDefaultFormState(defaultState) {
9
10
  return {
10
11
  values: defaultState.values ?? {},
@@ -39,9 +40,17 @@ class FormApi {
39
40
  const cleanup = () => {
40
41
  cleanupFieldMetaDerived();
41
42
  cleanupStoreDerived();
43
+ EventClient.formEventClient.emit("form-unmounted", {
44
+ id: this._formId
45
+ });
42
46
  };
43
47
  this.options.listeners?.onMount?.({ formApi: this });
44
48
  const { onMount } = this.options.validators || {};
49
+ EventClient.formEventClient.emit("form-state-change", {
50
+ id: this._formId,
51
+ state: this.store.state,
52
+ options: this.options
53
+ });
45
54
  if (!onMount) return cleanup;
46
55
  this.validateSync("mount");
47
56
  return cleanup;
@@ -623,6 +632,8 @@ class FormApi {
623
632
  listeners: {},
624
633
  formListeners: {}
625
634
  };
635
+ this._formId = opts?.formId ?? crypto.randomUUID();
636
+ this._devtoolsSubmissionOverride = false;
626
637
  this.baseStore = new store.Store(
627
638
  getDefaultFormState({
628
639
  ...opts?.defaultState,
@@ -772,12 +783,40 @@ class FormApi {
772
783
  });
773
784
  this.handleSubmit = this.handleSubmit.bind(this);
774
785
  this.update(opts || {});
786
+ this.store.subscribe(() => {
787
+ EventClient.formEventClient.emit("form-state-change", {
788
+ id: this._formId,
789
+ state: this.store.state,
790
+ options: this.options
791
+ });
792
+ });
793
+ EventClient.formEventClient.on("request-form-state", (e) => {
794
+ if (e.payload.id === this._formId) {
795
+ EventClient.formEventClient.emit("form-state-change", {
796
+ id: this._formId,
797
+ state: this.store.state,
798
+ options: this.options
799
+ });
800
+ }
801
+ });
802
+ EventClient.formEventClient.on("request-form-reset", (e) => {
803
+ if (e.payload.id === this._formId) {
804
+ this.reset();
805
+ }
806
+ });
807
+ EventClient.formEventClient.on("request-form-force-submit", (e) => {
808
+ if (e.payload.id === this._formId) {
809
+ this._devtoolsSubmissionOverride = true;
810
+ this.handleSubmit();
811
+ this._devtoolsSubmissionOverride = false;
812
+ }
813
+ });
775
814
  }
776
815
  get state() {
777
816
  return this.store.state;
778
817
  }
779
- get formId() {
780
- return this.options.formId;
818
+ formId() {
819
+ return this._formId;
781
820
  }
782
821
  /**
783
822
  * @private
@@ -811,7 +850,7 @@ class FormApi {
811
850
  }
812
851
  );
813
852
  });
814
- if (!this.state.canSubmit) return;
853
+ if (!this.state.canSubmit && !this._devtoolsSubmissionOverride) return;
815
854
  const submitMetaArg = submitMeta ?? this.options.onSubmitMeta;
816
855
  this.baseStore.setState((d) => ({ ...d, isSubmitting: true }));
817
856
  const done = () => {
@@ -825,6 +864,13 @@ class FormApi {
825
864
  formApi: this,
826
865
  meta: submitMetaArg
827
866
  });
867
+ EventClient.formEventClient.emit("form-submission-state-change", {
868
+ id: this._formId,
869
+ submissionAttempt: this.state.submissionAttempts,
870
+ successful: false,
871
+ stage: "validateAllFields",
872
+ errors: Object.values(this.state.fieldMeta).map((meta) => meta.errors).flat()
873
+ });
828
874
  return;
829
875
  }
830
876
  await this.validate("submit");
@@ -835,6 +881,13 @@ class FormApi {
835
881
  formApi: this,
836
882
  meta: submitMetaArg
837
883
  });
884
+ EventClient.formEventClient.emit("form-submission-state-change", {
885
+ id: this._formId,
886
+ submissionAttempt: this.state.submissionAttempts,
887
+ successful: false,
888
+ stage: "validate",
889
+ errors: this.state.errors
890
+ });
838
891
  return;
839
892
  }
840
893
  store.batch(() => {
@@ -861,6 +914,11 @@ class FormApi {
861
914
  isSubmitSuccessful: true
862
915
  // Set isSubmitSuccessful to true on successful submission
863
916
  }));
917
+ EventClient.formEventClient.emit("form-submission-state-change", {
918
+ id: this._formId,
919
+ submissionAttempt: this.state.submissionAttempts,
920
+ successful: true
921
+ });
864
922
  done();
865
923
  });
866
924
  } catch (err) {
@@ -869,6 +927,13 @@ class FormApi {
869
927
  isSubmitSuccessful: false
870
928
  // Ensure isSubmitSuccessful is false if an error occurs
871
929
  }));
930
+ EventClient.formEventClient.emit("form-submission-state-change", {
931
+ id: this._formId,
932
+ submissionAttempt: this.state.submissionAttempts,
933
+ successful: false,
934
+ stage: "inflight",
935
+ onError: err
936
+ });
872
937
  done();
873
938
  throw err;
874
939
  }