@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.
- package/dist/cjs/EventClient.cjs +13 -0
- package/dist/cjs/EventClient.cjs.map +1 -0
- package/dist/cjs/EventClient.d.cts +52 -0
- package/dist/cjs/FormApi.cjs +68 -3
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +11 -2
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/esm/EventClient.d.ts +52 -0
- package/dist/esm/EventClient.js +13 -0
- package/dist/esm/EventClient.js.map +1 -0
- package/dist/esm/FormApi.d.ts +11 -2
- package/dist/esm/FormApi.js +68 -3
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -2
- package/src/EventClient.ts +73 -0
- package/src/FormApi.ts +123 -5
- package/src/index.ts +1 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventClient } from "@tanstack/devtools-event-client";
|
|
2
|
+
class FormEventClient extends EventClient {
|
|
3
|
+
constructor() {
|
|
4
|
+
super({
|
|
5
|
+
pluginId: "form-devtools"
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const formEventClient = new FormEventClient();
|
|
10
|
+
export {
|
|
11
|
+
formEventClient
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=EventClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventClient.js","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":[],"mappings":";AAgEA,MAAM,wBAAwB,YAAsB;AAAA,EAClD,cAAc;AACZ,UAAM;AAAA,MACJ,UAAU;AAAA,IAAA,CACX;AAAA,EACH;AACF;AAEO,MAAM,kBAAkB,IAAI,gBAAA;"}
|
package/dist/esm/FormApi.d.ts
CHANGED
|
@@ -164,6 +164,7 @@ export interface FormOptions<in out TFormData, in out TOnMount extends undefined
|
|
|
164
164
|
}) => void;
|
|
165
165
|
transform?: FormTransform<NoInfer<TFormData>, NoInfer<TOnMount>, NoInfer<TOnChange>, NoInfer<TOnChangeAsync>, NoInfer<TOnBlur>, NoInfer<TOnBlurAsync>, NoInfer<TOnSubmit>, NoInfer<TOnSubmitAsync>, NoInfer<TOnDynamic>, NoInfer<TOnDynamicAsync>, NoInfer<TOnServer>, NoInfer<TSubmitMeta>>;
|
|
166
166
|
}
|
|
167
|
+
export type AnyFormOptions = FormOptions<any, any, any, any, any, any, any, any, any, any, any, any>;
|
|
167
168
|
/**
|
|
168
169
|
* An object representing the validation metadata for a field. Not intended for public usage.
|
|
169
170
|
*/
|
|
@@ -332,18 +333,26 @@ export declare class FormApi<in out TFormData, in out TOnMount extends undefined
|
|
|
332
333
|
*/
|
|
333
334
|
prevTransformArray: unknown[];
|
|
334
335
|
/**
|
|
335
|
-
*
|
|
336
|
+
* @private
|
|
336
337
|
*/
|
|
337
338
|
timeoutIds: {
|
|
338
339
|
validations: Record<ValidationCause, ReturnType<typeof setTimeout> | null>;
|
|
339
340
|
listeners: Record<ListenerCause, ReturnType<typeof setTimeout> | null>;
|
|
340
341
|
formListeners: Record<ListenerCause, ReturnType<typeof setTimeout> | null>;
|
|
341
342
|
};
|
|
343
|
+
/**
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
private _formId;
|
|
347
|
+
/**
|
|
348
|
+
* @private
|
|
349
|
+
*/
|
|
350
|
+
private _devtoolsSubmissionOverride;
|
|
342
351
|
/**
|
|
343
352
|
* Constructs a new `FormApi` instance with the given form options.
|
|
344
353
|
*/
|
|
345
354
|
constructor(opts?: FormOptions<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta>);
|
|
346
|
-
|
|
355
|
+
formId(): string | undefined;
|
|
347
356
|
/**
|
|
348
357
|
* @private
|
|
349
358
|
*/
|
package/dist/esm/FormApi.js
CHANGED
|
@@ -3,6 +3,7 @@ import { evaluate, getSyncValidatorArray, determineFormLevelErrorSourceAndValue,
|
|
|
3
3
|
import { defaultValidationLogic } from "./ValidationLogic.js";
|
|
4
4
|
import { standardSchemaValidators, isStandardSchemaValidator } from "./standardSchemaValidator.js";
|
|
5
5
|
import { defaultFieldMeta, metaHelper } from "./metaHelper.js";
|
|
6
|
+
import { formEventClient } from "./EventClient.js";
|
|
6
7
|
function getDefaultFormState(defaultState) {
|
|
7
8
|
return {
|
|
8
9
|
values: defaultState.values ?? {},
|
|
@@ -37,9 +38,17 @@ class FormApi {
|
|
|
37
38
|
const cleanup = () => {
|
|
38
39
|
cleanupFieldMetaDerived();
|
|
39
40
|
cleanupStoreDerived();
|
|
41
|
+
formEventClient.emit("form-unmounted", {
|
|
42
|
+
id: this._formId
|
|
43
|
+
});
|
|
40
44
|
};
|
|
41
45
|
this.options.listeners?.onMount?.({ formApi: this });
|
|
42
46
|
const { onMount } = this.options.validators || {};
|
|
47
|
+
formEventClient.emit("form-state-change", {
|
|
48
|
+
id: this._formId,
|
|
49
|
+
state: this.store.state,
|
|
50
|
+
options: this.options
|
|
51
|
+
});
|
|
43
52
|
if (!onMount) return cleanup;
|
|
44
53
|
this.validateSync("mount");
|
|
45
54
|
return cleanup;
|
|
@@ -621,6 +630,8 @@ class FormApi {
|
|
|
621
630
|
listeners: {},
|
|
622
631
|
formListeners: {}
|
|
623
632
|
};
|
|
633
|
+
this._formId = opts?.formId ?? crypto.randomUUID();
|
|
634
|
+
this._devtoolsSubmissionOverride = false;
|
|
624
635
|
this.baseStore = new Store(
|
|
625
636
|
getDefaultFormState({
|
|
626
637
|
...opts?.defaultState,
|
|
@@ -770,12 +781,40 @@ class FormApi {
|
|
|
770
781
|
});
|
|
771
782
|
this.handleSubmit = this.handleSubmit.bind(this);
|
|
772
783
|
this.update(opts || {});
|
|
784
|
+
this.store.subscribe(() => {
|
|
785
|
+
formEventClient.emit("form-state-change", {
|
|
786
|
+
id: this._formId,
|
|
787
|
+
state: this.store.state,
|
|
788
|
+
options: this.options
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
formEventClient.on("request-form-state", (e) => {
|
|
792
|
+
if (e.payload.id === this._formId) {
|
|
793
|
+
formEventClient.emit("form-state-change", {
|
|
794
|
+
id: this._formId,
|
|
795
|
+
state: this.store.state,
|
|
796
|
+
options: this.options
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
formEventClient.on("request-form-reset", (e) => {
|
|
801
|
+
if (e.payload.id === this._formId) {
|
|
802
|
+
this.reset();
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
formEventClient.on("request-form-force-submit", (e) => {
|
|
806
|
+
if (e.payload.id === this._formId) {
|
|
807
|
+
this._devtoolsSubmissionOverride = true;
|
|
808
|
+
this.handleSubmit();
|
|
809
|
+
this._devtoolsSubmissionOverride = false;
|
|
810
|
+
}
|
|
811
|
+
});
|
|
773
812
|
}
|
|
774
813
|
get state() {
|
|
775
814
|
return this.store.state;
|
|
776
815
|
}
|
|
777
|
-
|
|
778
|
-
return this.
|
|
816
|
+
formId() {
|
|
817
|
+
return this._formId;
|
|
779
818
|
}
|
|
780
819
|
/**
|
|
781
820
|
* @private
|
|
@@ -809,7 +848,7 @@ class FormApi {
|
|
|
809
848
|
}
|
|
810
849
|
);
|
|
811
850
|
});
|
|
812
|
-
if (!this.state.canSubmit) return;
|
|
851
|
+
if (!this.state.canSubmit && !this._devtoolsSubmissionOverride) return;
|
|
813
852
|
const submitMetaArg = submitMeta ?? this.options.onSubmitMeta;
|
|
814
853
|
this.baseStore.setState((d) => ({ ...d, isSubmitting: true }));
|
|
815
854
|
const done = () => {
|
|
@@ -823,6 +862,13 @@ class FormApi {
|
|
|
823
862
|
formApi: this,
|
|
824
863
|
meta: submitMetaArg
|
|
825
864
|
});
|
|
865
|
+
formEventClient.emit("form-submission-state-change", {
|
|
866
|
+
id: this._formId,
|
|
867
|
+
submissionAttempt: this.state.submissionAttempts,
|
|
868
|
+
successful: false,
|
|
869
|
+
stage: "validateAllFields",
|
|
870
|
+
errors: Object.values(this.state.fieldMeta).map((meta) => meta.errors).flat()
|
|
871
|
+
});
|
|
826
872
|
return;
|
|
827
873
|
}
|
|
828
874
|
await this.validate("submit");
|
|
@@ -833,6 +879,13 @@ class FormApi {
|
|
|
833
879
|
formApi: this,
|
|
834
880
|
meta: submitMetaArg
|
|
835
881
|
});
|
|
882
|
+
formEventClient.emit("form-submission-state-change", {
|
|
883
|
+
id: this._formId,
|
|
884
|
+
submissionAttempt: this.state.submissionAttempts,
|
|
885
|
+
successful: false,
|
|
886
|
+
stage: "validate",
|
|
887
|
+
errors: this.state.errors
|
|
888
|
+
});
|
|
836
889
|
return;
|
|
837
890
|
}
|
|
838
891
|
batch(() => {
|
|
@@ -859,6 +912,11 @@ class FormApi {
|
|
|
859
912
|
isSubmitSuccessful: true
|
|
860
913
|
// Set isSubmitSuccessful to true on successful submission
|
|
861
914
|
}));
|
|
915
|
+
formEventClient.emit("form-submission-state-change", {
|
|
916
|
+
id: this._formId,
|
|
917
|
+
submissionAttempt: this.state.submissionAttempts,
|
|
918
|
+
successful: true
|
|
919
|
+
});
|
|
862
920
|
done();
|
|
863
921
|
});
|
|
864
922
|
} catch (err) {
|
|
@@ -867,6 +925,13 @@ class FormApi {
|
|
|
867
925
|
isSubmitSuccessful: false
|
|
868
926
|
// Ensure isSubmitSuccessful is false if an error occurs
|
|
869
927
|
}));
|
|
928
|
+
formEventClient.emit("form-submission-state-change", {
|
|
929
|
+
id: this._formId,
|
|
930
|
+
submissionAttempt: this.state.submissionAttempts,
|
|
931
|
+
successful: false,
|
|
932
|
+
stage: "inflight",
|
|
933
|
+
onError: err
|
|
934
|
+
});
|
|
870
935
|
done();
|
|
871
936
|
throw err;
|
|
872
937
|
}
|