@jwiedeman/gtm-kit-solid 1.1.6 → 1.2.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/index.cjs CHANGED
@@ -1,17 +1,146 @@
1
1
  'use strict';
2
2
 
3
+ var web = require('solid-js/web');
3
4
  var solidJs = require('solid-js');
4
5
  var store = require('solid-js/store');
5
6
  var gtmKit = require('@jwiedeman/gtm-kit');
6
7
 
7
- var s=solidJs.createContext();function v(t){var l;let i=(l=t.autoInit)!=null?l:!0,r=t.onBeforeInit,u=t.onAfterInit,m={containers:t.containers,...t.dataLayerName&&{dataLayerName:t.dataLayerName},...t.host&&{host:t.host},...t.scriptAttributes&&{scriptAttributes:t.scriptAttributes}},e=gtmKit.createGtmClient(m),[C,d]=store.createStore({initialized:!1}),c={client:e,push:n=>e.push(n),setConsentDefaults:(n,a)=>e.setConsentDefaults(n,a),updateConsent:(n,a)=>e.updateConsent(n,a),whenReady:()=>e.whenReady(),onReady:n=>e.onReady(n),get initialized(){return C.initialized}};return r&&r(e),i&&(e.init(),d("initialized",!0),u&&u(e)),solidJs.onCleanup(()=>{e.teardown();}),React.createElement(s.Provider,{value:c},t.children)}var o=()=>{let t=solidJs.useContext(s);if(!t)throw new Error('[gtm-kit] useGtm() was called outside of a GtmProvider. Make sure to wrap your app with <GtmProvider containers="GTM-XXXXXX">.');return t},S=()=>o(),h=()=>o().push,P=()=>{let{setConsentDefaults:t,updateConsent:i}=o();return {setConsentDefaults:t,updateConsent:i}},R=()=>o().client,L=()=>o().whenReady;
8
+ // src/context.tsx
9
+ var GtmContext = solidJs.createContext();
10
+ var warnOnNestedProvider = () => {
11
+ if (process.env.NODE_ENV !== "production") {
12
+ console.warn("[gtm-kit/solid] Nested GtmProvider detected. You should only have one GtmProvider at the root of your app. The nested provider will be ignored.");
13
+ }
14
+ };
15
+ function GtmProvider(props) {
16
+ var _a;
17
+ const existingContext = solidJs.useContext(GtmContext);
18
+ if (existingContext) {
19
+ warnOnNestedProvider();
20
+ return web.memo(() => props.children);
21
+ }
22
+ const autoInit = (_a = props.autoInit) != null ? _a : true;
23
+ const onBeforeInit = props.onBeforeInit;
24
+ const onAfterInit = props.onAfterInit;
25
+ const clientOptions = {
26
+ containers: props.containers,
27
+ ...props.dataLayerName && {
28
+ dataLayerName: props.dataLayerName
29
+ },
30
+ ...props.host && {
31
+ host: props.host
32
+ },
33
+ ...props.scriptAttributes && {
34
+ scriptAttributes: props.scriptAttributes
35
+ }
36
+ };
37
+ const client = gtmKit.createGtmClient(clientOptions);
38
+ const [state, setState] = store.createStore({
39
+ initialized: false
40
+ });
41
+ const contextValue = {
42
+ client,
43
+ push: (value) => client.push(value),
44
+ setConsentDefaults: (consentState, regionOptions) => client.setConsentDefaults(consentState, regionOptions),
45
+ updateConsent: (consentState, regionOptions) => client.updateConsent(consentState, regionOptions),
46
+ isReady: () => client.isReady(),
47
+ whenReady: () => client.whenReady(),
48
+ onReady: (callback) => client.onReady(callback),
49
+ get initialized() {
50
+ return state.initialized;
51
+ }
52
+ };
53
+ if (onBeforeInit) {
54
+ onBeforeInit(client);
55
+ }
56
+ if (autoInit) {
57
+ client.init();
58
+ setState("initialized", true);
59
+ if (onAfterInit) {
60
+ onAfterInit(client);
61
+ }
62
+ }
63
+ solidJs.onCleanup(() => {
64
+ client.teardown();
65
+ });
66
+ return web.createComponent(GtmContext.Provider, {
67
+ value: contextValue,
68
+ get children() {
69
+ return props.children;
70
+ }
71
+ });
72
+ }
73
+ var useGtmContext = () => {
74
+ const context = solidJs.useContext(GtmContext);
75
+ if (!context) {
76
+ throw new Error('[gtm-kit/solid] useGtm() was called outside of a GtmProvider. Make sure to wrap your app with <GtmProvider containers="GTM-XXXXXX">.');
77
+ }
78
+ return context;
79
+ };
80
+ var useGtm = () => {
81
+ return useGtmContext();
82
+ };
83
+ var useGtmPush = () => {
84
+ return useGtmContext().push;
85
+ };
86
+ var useGtmConsent = () => {
87
+ const {
88
+ setConsentDefaults,
89
+ updateConsent
90
+ } = useGtmContext();
91
+ return {
92
+ setConsentDefaults,
93
+ updateConsent
94
+ };
95
+ };
96
+ var useGtmClient = () => {
97
+ return useGtmContext().client;
98
+ };
99
+ var useGtmReady = () => {
100
+ return useGtmContext().whenReady;
101
+ };
102
+ var useIsGtmReady = () => {
103
+ return useGtmContext().isReady;
104
+ };
105
+ function GtmErrorBoundary(props) {
106
+ var _a, _b;
107
+ const logErrors = (_a = props.logErrors) != null ? _a : process.env.NODE_ENV !== "production";
108
+ const onError = props.onError;
109
+ const handleError = (err) => {
110
+ if (logErrors) {
111
+ console.error("[gtm-kit/solid] Error caught by GtmErrorBoundary:", err);
112
+ }
113
+ if (onError) {
114
+ try {
115
+ onError(err);
116
+ } catch (e) {
117
+ }
118
+ }
119
+ };
120
+ const defaultFallback = (_err, _reset) => props.children;
121
+ const fallback = (_b = props.fallback) != null ? _b : defaultFallback;
122
+ return web.createComponent(solidJs.ErrorBoundary, {
123
+ fallback: (err, reset) => {
124
+ handleError(err);
125
+ if (typeof fallback === "function") {
126
+ return fallback(err, reset);
127
+ }
128
+ return fallback;
129
+ },
130
+ get children() {
131
+ return props.children;
132
+ }
133
+ });
134
+ }
8
135
 
9
- exports.GtmContext = s;
10
- exports.GtmProvider = v;
11
- exports.useGtm = S;
12
- exports.useGtmClient = R;
13
- exports.useGtmConsent = P;
14
- exports.useGtmPush = h;
15
- exports.useGtmReady = L;
136
+ exports.GtmContext = GtmContext;
137
+ exports.GtmErrorBoundary = GtmErrorBoundary;
138
+ exports.GtmProvider = GtmProvider;
139
+ exports.useGtm = useGtm;
140
+ exports.useGtmClient = useGtmClient;
141
+ exports.useGtmConsent = useGtmConsent;
142
+ exports.useGtmPush = useGtmPush;
143
+ exports.useGtmReady = useGtmReady;
144
+ exports.useIsGtmReady = useIsGtmReady;
16
145
  //# sourceMappingURL=out.js.map
17
146
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/context.tsx"],"names":["createContext","useContext","onCleanup","createStore","createGtmClient","GtmContext","GtmProvider","props","_a","autoInit","onBeforeInit","onAfterInit","clientOptions","client","state","setState","contextValue","value","consentState","regionOptions","callback","useGtmContext","context","useGtm","useGtmPush","useGtmConsent","setConsentDefaults","updateConsent","useGtmClient","useGtmReady"],"mappings":"AAAA,OAAS,iBAAAA,EAAe,cAAAC,EAAY,aAAAC,MAA2B,WAC/D,OAAS,eAAAC,MAAmB,iBAC5B,OACE,mBAAAC,MAOK,qBA0DA,IAAMC,EAAaL,EAA+B,EAkBlD,SAASM,EAAYC,EAAsC,CAtFlE,IAAAC,EAyFE,IAAMC,GAAWD,EAAAD,EAAM,WAAN,KAAAC,EAAkB,GAC7BE,EAAeH,EAAM,aACrBI,EAAcJ,EAAM,YAGpBK,EAAwC,CAC5C,WAAYL,EAAM,WAClB,GAAIA,EAAM,eAAiB,CAAE,cAAeA,EAAM,aAAc,EAChE,GAAIA,EAAM,MAAQ,CAAE,KAAMA,EAAM,IAAK,EACrC,GAAIA,EAAM,kBAAoB,CAAE,iBAAkBA,EAAM,gBAAiB,CAC3E,EAEMM,EAAST,EAAgBQ,CAAa,EAEtC,CAACE,EAAOC,CAAQ,EAAIZ,EAAsC,CAC9D,YAAa,EACf,CAAC,EAEKa,EAAgC,CACpC,OAAAH,EACA,KAAOI,GAA0BJ,EAAO,KAAKI,CAAK,EAClD,mBAAoB,CAACC,EAA4BC,IAC/CN,EAAO,mBAAmBK,EAAcC,CAAa,EACvD,cAAe,CAACD,EAA4BC,IAC1CN,EAAO,cAAcK,EAAcC,CAAa,EAClD,UAAW,IAAMN,EAAO,UAAU,EAClC,QAAUO,GAAqDP,EAAO,QAAQO,CAAQ,EACtF,IAAI,aAAc,CAChB,OAAON,EAAM,WACf,CACF,EAGA,OAAIJ,GACFA,EAAaG,CAAM,EAIjBJ,IACFI,EAAO,KAAK,EACZE,EAAS,cAAe,EAAI,EAGxBJ,GACFA,EAAYE,CAAM,GAKtBX,EAAU,IAAM,CACdW,EAAO,SAAS,CAClB,CAAC,EAEM,oBAACR,EAAW,SAAX,CAAoB,MAAOW,GAAeT,EAAM,QAAS,CACnE,CAKA,IAAMc,EAAgB,IAAuB,CAC3C,IAAMC,EAAUrB,EAAWI,CAAU,EACrC,GAAI,CAACiB,EACH,MAAM,IAAI,MACR,gIAEF,EAEF,OAAOA,CACT,EAoBaC,EAAS,IACbF,EAAc,EAsBVG,EAAa,IACjBH,EAAc,EAAE,KAwBZI,EAAgB,IAAqB,CAChD,GAAM,CAAE,mBAAAC,EAAoB,cAAAC,CAAc,EAAIN,EAAc,EAC5D,MAAO,CAAE,mBAAAK,EAAoB,cAAAC,CAAc,CAC7C,EAgBaC,EAAe,IACnBP,EAAc,EAAE,OAwBZQ,EAAc,IAClBR,EAAc,EAAE","sourcesContent":["import { createContext, useContext, onCleanup, type JSX } from 'solid-js';\nimport { createStore } from 'solid-js/store';\nimport {\n createGtmClient,\n type ConsentRegionOptions,\n type ConsentState,\n type CreateGtmClientOptions,\n type DataLayerValue,\n type GtmClient,\n type ScriptLoadState\n} from '@jwiedeman/gtm-kit';\n\n/**\n * Props for the GTM Provider component.\n */\nexport interface GtmProviderProps extends CreateGtmClientOptions {\n /** Child components */\n children: JSX.Element;\n\n /**\n * Whether to automatically initialize GTM when the provider mounts.\n * @default true\n */\n autoInit?: boolean;\n\n /**\n * Callback executed before GTM initialization.\n * Use this to set consent defaults.\n */\n onBeforeInit?: (client: GtmClient) => void;\n\n /**\n * Callback executed after GTM initialization.\n */\n onAfterInit?: (client: GtmClient) => void;\n}\n\n/**\n * The GTM context value containing all GTM functionality.\n */\nexport interface GtmContextValue {\n /** The underlying GTM client instance */\n client: GtmClient;\n /** Push a value to the data layer */\n push: (value: DataLayerValue) => void;\n /** Set consent defaults (must be called before init) */\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Update consent state */\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Returns a promise that resolves when all GTM scripts are loaded */\n whenReady: () => Promise<ScriptLoadState[]>;\n /** Register a callback for when GTM scripts are ready */\n onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;\n /** Whether GTM has been initialized */\n initialized: boolean;\n}\n\n/**\n * Consent-specific API subset.\n */\nexport interface GtmConsentApi {\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n}\n\n/**\n * The GTM context for SolidJS.\n */\nexport const GtmContext = createContext<GtmContextValue>();\n\n/**\n * GTM Provider component for SolidJS.\n *\n * @example\n * ```tsx\n * import { GtmProvider } from '@jwiedeman/gtm-kit-solid';\n *\n * function App() {\n * return (\n * <GtmProvider containers=\"GTM-XXXXXX\">\n * <MyApp />\n * </GtmProvider>\n * );\n * }\n * ```\n */\nexport function GtmProvider(props: GtmProviderProps): JSX.Element {\n // Note: Don't destructure children - in Solid.js, children is a getter that\n // should only be accessed inside the returned JSX to maintain proper reactivity\n const autoInit = props.autoInit ?? true;\n const onBeforeInit = props.onBeforeInit;\n const onAfterInit = props.onAfterInit;\n\n // Extract client options (everything except children and lifecycle hooks)\n const clientOptions: CreateGtmClientOptions = {\n containers: props.containers,\n ...(props.dataLayerName && { dataLayerName: props.dataLayerName }),\n ...(props.host && { host: props.host }),\n ...(props.scriptAttributes && { scriptAttributes: props.scriptAttributes })\n };\n\n const client = createGtmClient(clientOptions);\n\n const [state, setState] = createStore<{ initialized: boolean }>({\n initialized: false\n });\n\n const contextValue: GtmContextValue = {\n client,\n push: (value: DataLayerValue) => client.push(value),\n setConsentDefaults: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.setConsentDefaults(consentState, regionOptions),\n updateConsent: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.updateConsent(consentState, regionOptions),\n whenReady: () => client.whenReady(),\n onReady: (callback: (loadState: ScriptLoadState[]) => void) => client.onReady(callback),\n get initialized() {\n return state.initialized;\n }\n };\n\n // Call onBeforeInit hook if provided (for consent defaults)\n if (onBeforeInit) {\n onBeforeInit(client);\n }\n\n // Auto-initialize if enabled\n if (autoInit) {\n client.init();\n setState('initialized', true);\n\n // Call onAfterInit hook if provided\n if (onAfterInit) {\n onAfterInit(client);\n }\n }\n\n // Cleanup on unmount\n onCleanup(() => {\n client.teardown();\n });\n\n return <GtmContext.Provider value={contextValue}>{props.children}</GtmContext.Provider>;\n}\n\n/**\n * Internal helper to get the GTM context with proper error handling.\n */\nconst useGtmContext = (): GtmContextValue => {\n const context = useContext(GtmContext);\n if (!context) {\n throw new Error(\n '[gtm-kit] useGtm() was called outside of a GtmProvider. ' +\n 'Make sure to wrap your app with <GtmProvider containers=\"GTM-XXXXXX\">.'\n );\n }\n return context;\n};\n\n/**\n * Hook to access the full GTM context.\n *\n * @example\n * ```tsx\n * import { useGtm } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const { push, client } = useGtm();\n *\n * return (\n * <button onClick={() => push({ event: 'click' })}>\n * Click me\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtm = (): GtmContextValue => {\n return useGtmContext();\n};\n\n/**\n * Hook to get just the push function.\n * Use this when you only need to push events.\n *\n * @example\n * ```tsx\n * import { useGtmPush } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const push = useGtmPush();\n *\n * return (\n * <button onClick={() => push({ event: 'purchase', value: 99 })}>\n * Buy\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtmPush = (): ((value: DataLayerValue) => void) => {\n return useGtmContext().push;\n};\n\n/**\n * Hook to access consent management functions.\n *\n * @example\n * ```tsx\n * import { useGtmConsent } from '@jwiedeman/gtm-kit-solid';\n *\n * function CookieBanner() {\n * const { updateConsent } = useGtmConsent();\n *\n * const acceptAll = () => {\n * updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted'\n * });\n * };\n *\n * return <button onClick={acceptAll}>Accept All</button>;\n * }\n * ```\n */\nexport const useGtmConsent = (): GtmConsentApi => {\n const { setConsentDefaults, updateConsent } = useGtmContext();\n return { setConsentDefaults, updateConsent };\n};\n\n/**\n * Hook to get the raw GTM client instance.\n *\n * @example\n * ```tsx\n * import { useGtmClient } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const client = useGtmClient();\n *\n * return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;\n * }\n * ```\n */\nexport const useGtmClient = (): GtmClient => {\n return useGtmContext().client;\n};\n\n/**\n * Hook to get the whenReady function.\n * Use this to wait for GTM scripts to load.\n *\n * @example\n * ```tsx\n * import { useGtmReady } from '@jwiedeman/gtm-kit-solid';\n * import { onMount } from 'solid-js';\n *\n * function MyComponent() {\n * const whenReady = useGtmReady();\n *\n * onMount(async () => {\n * const states = await whenReady();\n * console.log('GTM loaded:', states);\n * });\n *\n * return <div>Loading...</div>;\n * }\n * ```\n */\nexport const useGtmReady = (): (() => Promise<ScriptLoadState[]>) => {\n return useGtmContext().whenReady;\n};\n"]}
1
+ {"version":3,"sources":["../src/context.tsx"],"names":["createContext","useContext","onCleanup","ErrorBoundary","createStore","createGtmClient","GtmContext","warnOnNestedProvider","process","env","NODE_ENV","console","warn","GtmProvider","props","existingContext","_$memo","children","autoInit","onBeforeInit","onAfterInit","clientOptions","containers","dataLayerName","host","scriptAttributes","client","state","setState","initialized","contextValue","push","value","setConsentDefaults","consentState","regionOptions","updateConsent","isReady","whenReady","onReady","callback","init","teardown","_$createComponent","Provider","useGtmContext","context","Error","useGtm","useGtmPush","useGtmConsent","useGtmClient","useGtmReady","useIsGtmReady","GtmErrorBoundary","logErrors","onError","handleError","err","error","defaultFallback","_err","_reset","fallback","reset"],"mappings":";;;AAAA,SAASA,eAAeC,YAAYC,WAAWC,qBAA+B;AAC9E,SAASC,mBAAmB;AAC5B,SACEC,uBAOK;AA4DA,IAAMC,aAAaN,cAA+B;AAEzD,IAAMO,uBAAuBA,MAAY;AACvC,MAAIC,QAAQC,IAAIC,aAAa,cAAc;AACzCC,YAAQC,KACN,iJAEF;EACF;AACF;AAkBO,SAASC,YAAYC,OAAsC;;AAEhE,QAAMC,kBAAkBd,WAAWK,UAAU;AAC7C,MAAIS,iBAAiB;AACnBR,yBAAqB;AACrB,WAAAS,OAAA,MAAUF,MAAMG,QAAQ;EAC1B;AAIA,QAAMC,YAAWJ,WAAMI,aAANJ,YAAkB;AACnC,QAAMK,eAAeL,MAAMK;AAC3B,QAAMC,cAAcN,MAAMM;AAG1B,QAAMC,gBAAwC;IAC5CC,YAAYR,MAAMQ;IAClB,GAAIR,MAAMS,iBAAiB;MAAEA,eAAeT,MAAMS;IAAc;IAChE,GAAIT,MAAMU,QAAQ;MAAEA,MAAMV,MAAMU;IAAK;IACrC,GAAIV,MAAMW,oBAAoB;MAAEA,kBAAkBX,MAAMW;IAAiB;EAC3E;AAEA,QAAMC,SAASrB,gBAAgBgB,aAAa;AAE5C,QAAM,CAACM,OAAOC,QAAQ,IAAIxB,YAAsC;IAC9DyB,aAAa;EACf,CAAC;AAED,QAAMC,eAAgC;IACpCJ;IACAK,MAAOC,WAA0BN,OAAOK,KAAKC,KAAK;IAClDC,oBAAoBA,CAACC,cAA4BC,kBAC/CT,OAAOO,mBAAmBC,cAAcC,aAAa;IACvDC,eAAeA,CAACF,cAA4BC,kBAC1CT,OAAOU,cAAcF,cAAcC,aAAa;IAClDE,SAASA,MAAMX,OAAOW,QAAQ;IAC9BC,WAAWA,MAAMZ,OAAOY,UAAU;IAClCC,SAAUC,cAAqDd,OAAOa,QAAQC,QAAQ;IACtF,IAAIX,cAAc;AAChB,aAAOF,MAAME;IACf;EACF;AAGA,MAAIV,cAAc;AAChBA,iBAAaO,MAAM;EACrB;AAGA,MAAIR,UAAU;AACZQ,WAAOe,KAAK;AACZb,aAAS,eAAe,IAAI;AAG5B,QAAIR,aAAa;AACfA,kBAAYM,MAAM;IACpB;EACF;AAGAxB,YAAU,MAAM;AACdwB,WAAOgB,SAAS;EAClB,CAAC;AAED,SAAAC,kBAAQrC,WAAWsC,UAAQ;IAACZ,OAAOF;IAAY,IAAAb,WAAA;AAAA,aAAGH,MAAMG;IAAQ;EAAA,CAAA;AAClE;AAKA,IAAM4B,gBAAgBA,MAAuB;AAC3C,QAAMC,UAAU7C,WAAWK,UAAU;AACrC,MAAI,CAACwC,SAAS;AACZ,UAAM,IAAIC,MACR,sIAEF;EACF;AACA,SAAOD;AACT;AAoBO,IAAME,SAASA,MAAuB;AAC3C,SAAOH,cAAc;AACvB;AAqBO,IAAMI,aAAaA,MAAyC;AACjE,SAAOJ,cAAc,EAAEd;AACzB;AAuBO,IAAMmB,gBAAgBA,MAAqB;AAChD,QAAM;IAAEjB;IAAoBG;EAAc,IAAIS,cAAc;AAC5D,SAAO;IAAEZ;IAAoBG;EAAc;AAC7C;AAgBO,IAAMe,eAAeA,MAAiB;AAC3C,SAAON,cAAc,EAAEnB;AACzB;AAuBO,IAAM0B,cAAcA,MAA0C;AACnE,SAAOP,cAAc,EAAEP;AACzB;AAgBO,IAAMe,gBAAgBA,MAAuB;AAClD,SAAOR,cAAc,EAAER;AACzB;AA0CO,SAASiB,iBAAiBxC,OAA2C;;AAC1E,QAAMyC,aAAYzC,WAAMyC,cAANzC,YAAmBN,QAAQC,IAAIC,aAAa;AAC9D,QAAM8C,UAAU1C,MAAM0C;AAEtB,QAAMC,cAAeC,SAAe;AAClC,QAAIH,WAAW;AACb5C,cAAQgD,MAAM,qDAAqDD,GAAG;IACxE;AAEA,QAAIF,SAAS;AACX,UAAI;AACFA,gBAAQE,GAAG;MACb,SAAQ;MACN;IAEJ;EACF;AAGA,QAAME,kBAAkBA,CAACC,MAAaC,WAAuBhD,MAAMG;AAEnE,QAAM8C,YAAWjD,WAAMiD,aAANjD,YAAkB8C;AAEnC,SAAAjB,kBACGxC,eAAa;IACZ4D,UAAUA,CAACL,KAAYM,UAAsB;AAC3CP,kBAAYC,GAAG;AACf,UAAI,OAAOK,aAAa,YAAY;AAClC,eAAOA,SAASL,KAAKM,KAAK;MAC5B;AACA,aAAOD;IACT;IAAC,IAAA9C,WAAA;AAAA,aAEAH,MAAMG;IAAQ;EAAA,CAAA;AAGrB","sourcesContent":["import { createContext, useContext, onCleanup, ErrorBoundary, type JSX } from 'solid-js';\nimport { createStore } from 'solid-js/store';\nimport {\n createGtmClient,\n type ConsentRegionOptions,\n type ConsentState,\n type CreateGtmClientOptions,\n type DataLayerValue,\n type GtmClient,\n type ScriptLoadState\n} from '@jwiedeman/gtm-kit';\n\n/**\n * Props for the GTM Provider component.\n */\nexport interface GtmProviderProps extends CreateGtmClientOptions {\n /** Child components */\n children: JSX.Element;\n\n /**\n * Whether to automatically initialize GTM when the provider mounts.\n * @default true\n */\n autoInit?: boolean;\n\n /**\n * Callback executed before GTM initialization.\n * Use this to set consent defaults.\n */\n onBeforeInit?: (client: GtmClient) => void;\n\n /**\n * Callback executed after GTM initialization.\n */\n onAfterInit?: (client: GtmClient) => void;\n}\n\n/**\n * The GTM context value containing all GTM functionality.\n */\nexport interface GtmContextValue {\n /** The underlying GTM client instance */\n client: GtmClient;\n /** Push a value to the data layer */\n push: (value: DataLayerValue) => void;\n /** Set consent defaults (must be called before init) */\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Update consent state */\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Synchronously check if all GTM scripts have finished loading */\n isReady: () => boolean;\n /** Returns a promise that resolves when all GTM scripts are loaded */\n whenReady: () => Promise<ScriptLoadState[]>;\n /** Register a callback for when GTM scripts are ready */\n onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;\n /** Whether GTM has been initialized */\n initialized: boolean;\n}\n\n/**\n * Consent-specific API subset.\n */\nexport interface GtmConsentApi {\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n}\n\n/**\n * The GTM context for SolidJS.\n */\nexport const GtmContext = createContext<GtmContextValue>();\n\nconst warnOnNestedProvider = (): void => {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[gtm-kit/solid] Nested GtmProvider detected. You should only have one GtmProvider at the root of your app. ' +\n 'The nested provider will be ignored.'\n );\n }\n};\n\n/**\n * GTM Provider component for SolidJS.\n *\n * @example\n * ```tsx\n * import { GtmProvider } from '@jwiedeman/gtm-kit-solid';\n *\n * function App() {\n * return (\n * <GtmProvider containers=\"GTM-XXXXXX\">\n * <MyApp />\n * </GtmProvider>\n * );\n * }\n * ```\n */\nexport function GtmProvider(props: GtmProviderProps): JSX.Element {\n // Check for nested provider\n const existingContext = useContext(GtmContext);\n if (existingContext) {\n warnOnNestedProvider();\n return <>{props.children}</>;\n }\n\n // Note: Don't destructure children - in Solid.js, children is a getter that\n // should only be accessed inside the returned JSX to maintain proper reactivity\n const autoInit = props.autoInit ?? true;\n const onBeforeInit = props.onBeforeInit;\n const onAfterInit = props.onAfterInit;\n\n // Extract client options (everything except children and lifecycle hooks)\n const clientOptions: CreateGtmClientOptions = {\n containers: props.containers,\n ...(props.dataLayerName && { dataLayerName: props.dataLayerName }),\n ...(props.host && { host: props.host }),\n ...(props.scriptAttributes && { scriptAttributes: props.scriptAttributes })\n };\n\n const client = createGtmClient(clientOptions);\n\n const [state, setState] = createStore<{ initialized: boolean }>({\n initialized: false\n });\n\n const contextValue: GtmContextValue = {\n client,\n push: (value: DataLayerValue) => client.push(value),\n setConsentDefaults: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.setConsentDefaults(consentState, regionOptions),\n updateConsent: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.updateConsent(consentState, regionOptions),\n isReady: () => client.isReady(),\n whenReady: () => client.whenReady(),\n onReady: (callback: (loadState: ScriptLoadState[]) => void) => client.onReady(callback),\n get initialized() {\n return state.initialized;\n }\n };\n\n // Call onBeforeInit hook if provided (for consent defaults)\n if (onBeforeInit) {\n onBeforeInit(client);\n }\n\n // Auto-initialize if enabled\n if (autoInit) {\n client.init();\n setState('initialized', true);\n\n // Call onAfterInit hook if provided\n if (onAfterInit) {\n onAfterInit(client);\n }\n }\n\n // Cleanup on unmount\n onCleanup(() => {\n client.teardown();\n });\n\n return <GtmContext.Provider value={contextValue}>{props.children}</GtmContext.Provider>;\n}\n\n/**\n * Internal helper to get the GTM context with proper error handling.\n */\nconst useGtmContext = (): GtmContextValue => {\n const context = useContext(GtmContext);\n if (!context) {\n throw new Error(\n '[gtm-kit/solid] useGtm() was called outside of a GtmProvider. ' +\n 'Make sure to wrap your app with <GtmProvider containers=\"GTM-XXXXXX\">.'\n );\n }\n return context;\n};\n\n/**\n * Hook to access the full GTM context.\n *\n * @example\n * ```tsx\n * import { useGtm } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const { push, client } = useGtm();\n *\n * return (\n * <button onClick={() => push({ event: 'click' })}>\n * Click me\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtm = (): GtmContextValue => {\n return useGtmContext();\n};\n\n/**\n * Hook to get just the push function.\n * Use this when you only need to push events.\n *\n * @example\n * ```tsx\n * import { useGtmPush } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const push = useGtmPush();\n *\n * return (\n * <button onClick={() => push({ event: 'purchase', value: 99 })}>\n * Buy\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtmPush = (): ((value: DataLayerValue) => void) => {\n return useGtmContext().push;\n};\n\n/**\n * Hook to access consent management functions.\n *\n * @example\n * ```tsx\n * import { useGtmConsent } from '@jwiedeman/gtm-kit-solid';\n *\n * function CookieBanner() {\n * const { updateConsent } = useGtmConsent();\n *\n * const acceptAll = () => {\n * updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted'\n * });\n * };\n *\n * return <button onClick={acceptAll}>Accept All</button>;\n * }\n * ```\n */\nexport const useGtmConsent = (): GtmConsentApi => {\n const { setConsentDefaults, updateConsent } = useGtmContext();\n return { setConsentDefaults, updateConsent };\n};\n\n/**\n * Hook to get the raw GTM client instance.\n *\n * @example\n * ```tsx\n * import { useGtmClient } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const client = useGtmClient();\n *\n * return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;\n * }\n * ```\n */\nexport const useGtmClient = (): GtmClient => {\n return useGtmContext().client;\n};\n\n/**\n * Hook to get the whenReady function.\n * Use this to wait for GTM scripts to load.\n *\n * @example\n * ```tsx\n * import { useGtmReady } from '@jwiedeman/gtm-kit-solid';\n * import { onMount } from 'solid-js';\n *\n * function MyComponent() {\n * const whenReady = useGtmReady();\n *\n * onMount(async () => {\n * const states = await whenReady();\n * console.log('GTM loaded:', states);\n * });\n *\n * return <div>Loading...</div>;\n * }\n * ```\n */\nexport const useGtmReady = (): (() => Promise<ScriptLoadState[]>) => {\n return useGtmContext().whenReady;\n};\n\n/**\n * Hook to check if GTM scripts have finished loading synchronously.\n *\n * @example\n * ```tsx\n * import { useIsGtmReady } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const isReady = useIsGtmReady();\n *\n * return <div>GTM Ready: {isReady() ? 'Yes' : 'No'}</div>;\n * }\n * ```\n */\nexport const useIsGtmReady = (): (() => boolean) => {\n return useGtmContext().isReady;\n};\n\n/**\n * Props for GtmErrorBoundary component.\n */\nexport interface GtmErrorBoundaryProps {\n /** Child components */\n children: JSX.Element;\n /** Fallback UI to render when an error occurs */\n fallback?: JSX.Element | ((err: Error, reset: () => void) => JSX.Element);\n /** Callback invoked when an error is caught */\n onError?: (error: Error) => void;\n /** Whether to log errors to console (default: true in development) */\n logErrors?: boolean;\n}\n\n/**\n * Error boundary component for GTM provider in SolidJS apps.\n * Catches errors during GTM initialization and renders a fallback UI.\n *\n * @example\n * ```tsx\n * import { GtmProvider, GtmErrorBoundary } from '@jwiedeman/gtm-kit-solid';\n *\n * function App() {\n * return (\n * <GtmErrorBoundary\n * fallback={(err, reset) => (\n * <div>\n * <p>GTM failed: {err.message}</p>\n * <button onClick={reset}>Retry</button>\n * </div>\n * )}\n * >\n * <GtmProvider containers=\"GTM-XXXXXX\">\n * <MyApp />\n * </GtmProvider>\n * </GtmErrorBoundary>\n * );\n * }\n * ```\n */\nexport function GtmErrorBoundary(props: GtmErrorBoundaryProps): JSX.Element {\n const logErrors = props.logErrors ?? process.env.NODE_ENV !== 'production';\n const onError = props.onError;\n\n const handleError = (err: Error) => {\n if (logErrors) {\n console.error('[gtm-kit/solid] Error caught by GtmErrorBoundary:', err);\n }\n\n if (onError) {\n try {\n onError(err);\n } catch {\n // Ignore callback errors\n }\n }\n };\n\n // Default fallback - just render children (silent degradation)\n const defaultFallback = (_err: Error, _reset: () => void) => props.children;\n\n const fallback = props.fallback ?? defaultFallback;\n\n return (\n <ErrorBoundary\n fallback={(err: Error, reset: () => void) => {\n handleError(err);\n if (typeof fallback === 'function') {\n return fallback(err, reset);\n }\n return fallback;\n }}\n >\n {props.children}\n </ErrorBoundary>\n );\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -35,6 +35,8 @@ interface GtmContextValue {
35
35
  setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
36
36
  /** Update consent state */
37
37
  updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
38
+ /** Synchronously check if all GTM scripts have finished loading */
39
+ isReady: () => boolean;
38
40
  /** Returns a promise that resolves when all GTM scripts are loaded */
39
41
  whenReady: () => Promise<ScriptLoadState[]>;
40
42
  /** Register a callback for when GTM scripts are ready */
@@ -168,5 +170,60 @@ declare const useGtmClient: () => GtmClient;
168
170
  * ```
169
171
  */
170
172
  declare const useGtmReady: () => (() => Promise<ScriptLoadState[]>);
173
+ /**
174
+ * Hook to check if GTM scripts have finished loading synchronously.
175
+ *
176
+ * @example
177
+ * ```tsx
178
+ * import { useIsGtmReady } from '@jwiedeman/gtm-kit-solid';
179
+ *
180
+ * function MyComponent() {
181
+ * const isReady = useIsGtmReady();
182
+ *
183
+ * return <div>GTM Ready: {isReady() ? 'Yes' : 'No'}</div>;
184
+ * }
185
+ * ```
186
+ */
187
+ declare const useIsGtmReady: () => (() => boolean);
188
+ /**
189
+ * Props for GtmErrorBoundary component.
190
+ */
191
+ interface GtmErrorBoundaryProps {
192
+ /** Child components */
193
+ children: JSX.Element;
194
+ /** Fallback UI to render when an error occurs */
195
+ fallback?: JSX.Element | ((err: Error, reset: () => void) => JSX.Element);
196
+ /** Callback invoked when an error is caught */
197
+ onError?: (error: Error) => void;
198
+ /** Whether to log errors to console (default: true in development) */
199
+ logErrors?: boolean;
200
+ }
201
+ /**
202
+ * Error boundary component for GTM provider in SolidJS apps.
203
+ * Catches errors during GTM initialization and renders a fallback UI.
204
+ *
205
+ * @example
206
+ * ```tsx
207
+ * import { GtmProvider, GtmErrorBoundary } from '@jwiedeman/gtm-kit-solid';
208
+ *
209
+ * function App() {
210
+ * return (
211
+ * <GtmErrorBoundary
212
+ * fallback={(err, reset) => (
213
+ * <div>
214
+ * <p>GTM failed: {err.message}</p>
215
+ * <button onClick={reset}>Retry</button>
216
+ * </div>
217
+ * )}
218
+ * >
219
+ * <GtmProvider containers="GTM-XXXXXX">
220
+ * <MyApp />
221
+ * </GtmProvider>
222
+ * </GtmErrorBoundary>
223
+ * );
224
+ * }
225
+ * ```
226
+ */
227
+ declare function GtmErrorBoundary(props: GtmErrorBoundaryProps): JSX.Element;
171
228
 
172
- export { GtmConsentApi, GtmContext, GtmContextValue, GtmProvider, GtmProviderProps, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady };
229
+ export { GtmConsentApi, GtmContext, GtmContextValue, GtmErrorBoundary, GtmErrorBoundaryProps, GtmProvider, GtmProviderProps, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady, useIsGtmReady };
package/dist/index.d.ts CHANGED
@@ -35,6 +35,8 @@ interface GtmContextValue {
35
35
  setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
36
36
  /** Update consent state */
37
37
  updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
38
+ /** Synchronously check if all GTM scripts have finished loading */
39
+ isReady: () => boolean;
38
40
  /** Returns a promise that resolves when all GTM scripts are loaded */
39
41
  whenReady: () => Promise<ScriptLoadState[]>;
40
42
  /** Register a callback for when GTM scripts are ready */
@@ -168,5 +170,60 @@ declare const useGtmClient: () => GtmClient;
168
170
  * ```
169
171
  */
170
172
  declare const useGtmReady: () => (() => Promise<ScriptLoadState[]>);
173
+ /**
174
+ * Hook to check if GTM scripts have finished loading synchronously.
175
+ *
176
+ * @example
177
+ * ```tsx
178
+ * import { useIsGtmReady } from '@jwiedeman/gtm-kit-solid';
179
+ *
180
+ * function MyComponent() {
181
+ * const isReady = useIsGtmReady();
182
+ *
183
+ * return <div>GTM Ready: {isReady() ? 'Yes' : 'No'}</div>;
184
+ * }
185
+ * ```
186
+ */
187
+ declare const useIsGtmReady: () => (() => boolean);
188
+ /**
189
+ * Props for GtmErrorBoundary component.
190
+ */
191
+ interface GtmErrorBoundaryProps {
192
+ /** Child components */
193
+ children: JSX.Element;
194
+ /** Fallback UI to render when an error occurs */
195
+ fallback?: JSX.Element | ((err: Error, reset: () => void) => JSX.Element);
196
+ /** Callback invoked when an error is caught */
197
+ onError?: (error: Error) => void;
198
+ /** Whether to log errors to console (default: true in development) */
199
+ logErrors?: boolean;
200
+ }
201
+ /**
202
+ * Error boundary component for GTM provider in SolidJS apps.
203
+ * Catches errors during GTM initialization and renders a fallback UI.
204
+ *
205
+ * @example
206
+ * ```tsx
207
+ * import { GtmProvider, GtmErrorBoundary } from '@jwiedeman/gtm-kit-solid';
208
+ *
209
+ * function App() {
210
+ * return (
211
+ * <GtmErrorBoundary
212
+ * fallback={(err, reset) => (
213
+ * <div>
214
+ * <p>GTM failed: {err.message}</p>
215
+ * <button onClick={reset}>Retry</button>
216
+ * </div>
217
+ * )}
218
+ * >
219
+ * <GtmProvider containers="GTM-XXXXXX">
220
+ * <MyApp />
221
+ * </GtmProvider>
222
+ * </GtmErrorBoundary>
223
+ * );
224
+ * }
225
+ * ```
226
+ */
227
+ declare function GtmErrorBoundary(props: GtmErrorBoundaryProps): JSX.Element;
171
228
 
172
- export { GtmConsentApi, GtmContext, GtmContextValue, GtmProvider, GtmProviderProps, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady };
229
+ export { GtmConsentApi, GtmContext, GtmContextValue, GtmErrorBoundary, GtmErrorBoundaryProps, GtmProvider, GtmProviderProps, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady, useIsGtmReady };
package/dist/index.js CHANGED
@@ -1,9 +1,136 @@
1
- import { createContext, onCleanup, useContext } from 'solid-js';
1
+ import { memo, createComponent } from 'solid-js/web';
2
+ import { createContext, useContext, onCleanup, ErrorBoundary } from 'solid-js';
2
3
  import { createStore } from 'solid-js/store';
3
4
  import { createGtmClient } from '@jwiedeman/gtm-kit';
4
5
 
5
- var s=createContext();function v(t){var l;let i=(l=t.autoInit)!=null?l:!0,r=t.onBeforeInit,u=t.onAfterInit,m={containers:t.containers,...t.dataLayerName&&{dataLayerName:t.dataLayerName},...t.host&&{host:t.host},...t.scriptAttributes&&{scriptAttributes:t.scriptAttributes}},e=createGtmClient(m),[C,d]=createStore({initialized:!1}),c={client:e,push:n=>e.push(n),setConsentDefaults:(n,a)=>e.setConsentDefaults(n,a),updateConsent:(n,a)=>e.updateConsent(n,a),whenReady:()=>e.whenReady(),onReady:n=>e.onReady(n),get initialized(){return C.initialized}};return r&&r(e),i&&(e.init(),d("initialized",!0),u&&u(e)),onCleanup(()=>{e.teardown();}),React.createElement(s.Provider,{value:c},t.children)}var o=()=>{let t=useContext(s);if(!t)throw new Error('[gtm-kit] useGtm() was called outside of a GtmProvider. Make sure to wrap your app with <GtmProvider containers="GTM-XXXXXX">.');return t},S=()=>o(),h=()=>o().push,P=()=>{let{setConsentDefaults:t,updateConsent:i}=o();return {setConsentDefaults:t,updateConsent:i}},R=()=>o().client,L=()=>o().whenReady;
6
+ // src/context.tsx
7
+ var GtmContext = createContext();
8
+ var warnOnNestedProvider = () => {
9
+ if (process.env.NODE_ENV !== "production") {
10
+ console.warn("[gtm-kit/solid] Nested GtmProvider detected. You should only have one GtmProvider at the root of your app. The nested provider will be ignored.");
11
+ }
12
+ };
13
+ function GtmProvider(props) {
14
+ var _a;
15
+ const existingContext = useContext(GtmContext);
16
+ if (existingContext) {
17
+ warnOnNestedProvider();
18
+ return memo(() => props.children);
19
+ }
20
+ const autoInit = (_a = props.autoInit) != null ? _a : true;
21
+ const onBeforeInit = props.onBeforeInit;
22
+ const onAfterInit = props.onAfterInit;
23
+ const clientOptions = {
24
+ containers: props.containers,
25
+ ...props.dataLayerName && {
26
+ dataLayerName: props.dataLayerName
27
+ },
28
+ ...props.host && {
29
+ host: props.host
30
+ },
31
+ ...props.scriptAttributes && {
32
+ scriptAttributes: props.scriptAttributes
33
+ }
34
+ };
35
+ const client = createGtmClient(clientOptions);
36
+ const [state, setState] = createStore({
37
+ initialized: false
38
+ });
39
+ const contextValue = {
40
+ client,
41
+ push: (value) => client.push(value),
42
+ setConsentDefaults: (consentState, regionOptions) => client.setConsentDefaults(consentState, regionOptions),
43
+ updateConsent: (consentState, regionOptions) => client.updateConsent(consentState, regionOptions),
44
+ isReady: () => client.isReady(),
45
+ whenReady: () => client.whenReady(),
46
+ onReady: (callback) => client.onReady(callback),
47
+ get initialized() {
48
+ return state.initialized;
49
+ }
50
+ };
51
+ if (onBeforeInit) {
52
+ onBeforeInit(client);
53
+ }
54
+ if (autoInit) {
55
+ client.init();
56
+ setState("initialized", true);
57
+ if (onAfterInit) {
58
+ onAfterInit(client);
59
+ }
60
+ }
61
+ onCleanup(() => {
62
+ client.teardown();
63
+ });
64
+ return createComponent(GtmContext.Provider, {
65
+ value: contextValue,
66
+ get children() {
67
+ return props.children;
68
+ }
69
+ });
70
+ }
71
+ var useGtmContext = () => {
72
+ const context = useContext(GtmContext);
73
+ if (!context) {
74
+ throw new Error('[gtm-kit/solid] useGtm() was called outside of a GtmProvider. Make sure to wrap your app with <GtmProvider containers="GTM-XXXXXX">.');
75
+ }
76
+ return context;
77
+ };
78
+ var useGtm = () => {
79
+ return useGtmContext();
80
+ };
81
+ var useGtmPush = () => {
82
+ return useGtmContext().push;
83
+ };
84
+ var useGtmConsent = () => {
85
+ const {
86
+ setConsentDefaults,
87
+ updateConsent
88
+ } = useGtmContext();
89
+ return {
90
+ setConsentDefaults,
91
+ updateConsent
92
+ };
93
+ };
94
+ var useGtmClient = () => {
95
+ return useGtmContext().client;
96
+ };
97
+ var useGtmReady = () => {
98
+ return useGtmContext().whenReady;
99
+ };
100
+ var useIsGtmReady = () => {
101
+ return useGtmContext().isReady;
102
+ };
103
+ function GtmErrorBoundary(props) {
104
+ var _a, _b;
105
+ const logErrors = (_a = props.logErrors) != null ? _a : process.env.NODE_ENV !== "production";
106
+ const onError = props.onError;
107
+ const handleError = (err) => {
108
+ if (logErrors) {
109
+ console.error("[gtm-kit/solid] Error caught by GtmErrorBoundary:", err);
110
+ }
111
+ if (onError) {
112
+ try {
113
+ onError(err);
114
+ } catch (e) {
115
+ }
116
+ }
117
+ };
118
+ const defaultFallback = (_err, _reset) => props.children;
119
+ const fallback = (_b = props.fallback) != null ? _b : defaultFallback;
120
+ return createComponent(ErrorBoundary, {
121
+ fallback: (err, reset) => {
122
+ handleError(err);
123
+ if (typeof fallback === "function") {
124
+ return fallback(err, reset);
125
+ }
126
+ return fallback;
127
+ },
128
+ get children() {
129
+ return props.children;
130
+ }
131
+ });
132
+ }
6
133
 
7
- export { s as GtmContext, v as GtmProvider, S as useGtm, R as useGtmClient, P as useGtmConsent, h as useGtmPush, L as useGtmReady };
134
+ export { GtmContext, GtmErrorBoundary, GtmProvider, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady, useIsGtmReady };
8
135
  //# sourceMappingURL=out.js.map
9
136
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/context.tsx"],"names":["createContext","useContext","onCleanup","createStore","createGtmClient","GtmContext","GtmProvider","props","_a","autoInit","onBeforeInit","onAfterInit","clientOptions","client","state","setState","contextValue","value","consentState","regionOptions","callback","useGtmContext","context","useGtm","useGtmPush","useGtmConsent","setConsentDefaults","updateConsent","useGtmClient","useGtmReady"],"mappings":"AAAA,OAAS,iBAAAA,EAAe,cAAAC,EAAY,aAAAC,MAA2B,WAC/D,OAAS,eAAAC,MAAmB,iBAC5B,OACE,mBAAAC,MAOK,qBA0DA,IAAMC,EAAaL,EAA+B,EAkBlD,SAASM,EAAYC,EAAsC,CAtFlE,IAAAC,EAyFE,IAAMC,GAAWD,EAAAD,EAAM,WAAN,KAAAC,EAAkB,GAC7BE,EAAeH,EAAM,aACrBI,EAAcJ,EAAM,YAGpBK,EAAwC,CAC5C,WAAYL,EAAM,WAClB,GAAIA,EAAM,eAAiB,CAAE,cAAeA,EAAM,aAAc,EAChE,GAAIA,EAAM,MAAQ,CAAE,KAAMA,EAAM,IAAK,EACrC,GAAIA,EAAM,kBAAoB,CAAE,iBAAkBA,EAAM,gBAAiB,CAC3E,EAEMM,EAAST,EAAgBQ,CAAa,EAEtC,CAACE,EAAOC,CAAQ,EAAIZ,EAAsC,CAC9D,YAAa,EACf,CAAC,EAEKa,EAAgC,CACpC,OAAAH,EACA,KAAOI,GAA0BJ,EAAO,KAAKI,CAAK,EAClD,mBAAoB,CAACC,EAA4BC,IAC/CN,EAAO,mBAAmBK,EAAcC,CAAa,EACvD,cAAe,CAACD,EAA4BC,IAC1CN,EAAO,cAAcK,EAAcC,CAAa,EAClD,UAAW,IAAMN,EAAO,UAAU,EAClC,QAAUO,GAAqDP,EAAO,QAAQO,CAAQ,EACtF,IAAI,aAAc,CAChB,OAAON,EAAM,WACf,CACF,EAGA,OAAIJ,GACFA,EAAaG,CAAM,EAIjBJ,IACFI,EAAO,KAAK,EACZE,EAAS,cAAe,EAAI,EAGxBJ,GACFA,EAAYE,CAAM,GAKtBX,EAAU,IAAM,CACdW,EAAO,SAAS,CAClB,CAAC,EAEM,oBAACR,EAAW,SAAX,CAAoB,MAAOW,GAAeT,EAAM,QAAS,CACnE,CAKA,IAAMc,EAAgB,IAAuB,CAC3C,IAAMC,EAAUrB,EAAWI,CAAU,EACrC,GAAI,CAACiB,EACH,MAAM,IAAI,MACR,gIAEF,EAEF,OAAOA,CACT,EAoBaC,EAAS,IACbF,EAAc,EAsBVG,EAAa,IACjBH,EAAc,EAAE,KAwBZI,EAAgB,IAAqB,CAChD,GAAM,CAAE,mBAAAC,EAAoB,cAAAC,CAAc,EAAIN,EAAc,EAC5D,MAAO,CAAE,mBAAAK,EAAoB,cAAAC,CAAc,CAC7C,EAgBaC,EAAe,IACnBP,EAAc,EAAE,OAwBZQ,EAAc,IAClBR,EAAc,EAAE","sourcesContent":["import { createContext, useContext, onCleanup, type JSX } from 'solid-js';\nimport { createStore } from 'solid-js/store';\nimport {\n createGtmClient,\n type ConsentRegionOptions,\n type ConsentState,\n type CreateGtmClientOptions,\n type DataLayerValue,\n type GtmClient,\n type ScriptLoadState\n} from '@jwiedeman/gtm-kit';\n\n/**\n * Props for the GTM Provider component.\n */\nexport interface GtmProviderProps extends CreateGtmClientOptions {\n /** Child components */\n children: JSX.Element;\n\n /**\n * Whether to automatically initialize GTM when the provider mounts.\n * @default true\n */\n autoInit?: boolean;\n\n /**\n * Callback executed before GTM initialization.\n * Use this to set consent defaults.\n */\n onBeforeInit?: (client: GtmClient) => void;\n\n /**\n * Callback executed after GTM initialization.\n */\n onAfterInit?: (client: GtmClient) => void;\n}\n\n/**\n * The GTM context value containing all GTM functionality.\n */\nexport interface GtmContextValue {\n /** The underlying GTM client instance */\n client: GtmClient;\n /** Push a value to the data layer */\n push: (value: DataLayerValue) => void;\n /** Set consent defaults (must be called before init) */\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Update consent state */\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Returns a promise that resolves when all GTM scripts are loaded */\n whenReady: () => Promise<ScriptLoadState[]>;\n /** Register a callback for when GTM scripts are ready */\n onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;\n /** Whether GTM has been initialized */\n initialized: boolean;\n}\n\n/**\n * Consent-specific API subset.\n */\nexport interface GtmConsentApi {\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n}\n\n/**\n * The GTM context for SolidJS.\n */\nexport const GtmContext = createContext<GtmContextValue>();\n\n/**\n * GTM Provider component for SolidJS.\n *\n * @example\n * ```tsx\n * import { GtmProvider } from '@jwiedeman/gtm-kit-solid';\n *\n * function App() {\n * return (\n * <GtmProvider containers=\"GTM-XXXXXX\">\n * <MyApp />\n * </GtmProvider>\n * );\n * }\n * ```\n */\nexport function GtmProvider(props: GtmProviderProps): JSX.Element {\n // Note: Don't destructure children - in Solid.js, children is a getter that\n // should only be accessed inside the returned JSX to maintain proper reactivity\n const autoInit = props.autoInit ?? true;\n const onBeforeInit = props.onBeforeInit;\n const onAfterInit = props.onAfterInit;\n\n // Extract client options (everything except children and lifecycle hooks)\n const clientOptions: CreateGtmClientOptions = {\n containers: props.containers,\n ...(props.dataLayerName && { dataLayerName: props.dataLayerName }),\n ...(props.host && { host: props.host }),\n ...(props.scriptAttributes && { scriptAttributes: props.scriptAttributes })\n };\n\n const client = createGtmClient(clientOptions);\n\n const [state, setState] = createStore<{ initialized: boolean }>({\n initialized: false\n });\n\n const contextValue: GtmContextValue = {\n client,\n push: (value: DataLayerValue) => client.push(value),\n setConsentDefaults: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.setConsentDefaults(consentState, regionOptions),\n updateConsent: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.updateConsent(consentState, regionOptions),\n whenReady: () => client.whenReady(),\n onReady: (callback: (loadState: ScriptLoadState[]) => void) => client.onReady(callback),\n get initialized() {\n return state.initialized;\n }\n };\n\n // Call onBeforeInit hook if provided (for consent defaults)\n if (onBeforeInit) {\n onBeforeInit(client);\n }\n\n // Auto-initialize if enabled\n if (autoInit) {\n client.init();\n setState('initialized', true);\n\n // Call onAfterInit hook if provided\n if (onAfterInit) {\n onAfterInit(client);\n }\n }\n\n // Cleanup on unmount\n onCleanup(() => {\n client.teardown();\n });\n\n return <GtmContext.Provider value={contextValue}>{props.children}</GtmContext.Provider>;\n}\n\n/**\n * Internal helper to get the GTM context with proper error handling.\n */\nconst useGtmContext = (): GtmContextValue => {\n const context = useContext(GtmContext);\n if (!context) {\n throw new Error(\n '[gtm-kit] useGtm() was called outside of a GtmProvider. ' +\n 'Make sure to wrap your app with <GtmProvider containers=\"GTM-XXXXXX\">.'\n );\n }\n return context;\n};\n\n/**\n * Hook to access the full GTM context.\n *\n * @example\n * ```tsx\n * import { useGtm } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const { push, client } = useGtm();\n *\n * return (\n * <button onClick={() => push({ event: 'click' })}>\n * Click me\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtm = (): GtmContextValue => {\n return useGtmContext();\n};\n\n/**\n * Hook to get just the push function.\n * Use this when you only need to push events.\n *\n * @example\n * ```tsx\n * import { useGtmPush } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const push = useGtmPush();\n *\n * return (\n * <button onClick={() => push({ event: 'purchase', value: 99 })}>\n * Buy\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtmPush = (): ((value: DataLayerValue) => void) => {\n return useGtmContext().push;\n};\n\n/**\n * Hook to access consent management functions.\n *\n * @example\n * ```tsx\n * import { useGtmConsent } from '@jwiedeman/gtm-kit-solid';\n *\n * function CookieBanner() {\n * const { updateConsent } = useGtmConsent();\n *\n * const acceptAll = () => {\n * updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted'\n * });\n * };\n *\n * return <button onClick={acceptAll}>Accept All</button>;\n * }\n * ```\n */\nexport const useGtmConsent = (): GtmConsentApi => {\n const { setConsentDefaults, updateConsent } = useGtmContext();\n return { setConsentDefaults, updateConsent };\n};\n\n/**\n * Hook to get the raw GTM client instance.\n *\n * @example\n * ```tsx\n * import { useGtmClient } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const client = useGtmClient();\n *\n * return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;\n * }\n * ```\n */\nexport const useGtmClient = (): GtmClient => {\n return useGtmContext().client;\n};\n\n/**\n * Hook to get the whenReady function.\n * Use this to wait for GTM scripts to load.\n *\n * @example\n * ```tsx\n * import { useGtmReady } from '@jwiedeman/gtm-kit-solid';\n * import { onMount } from 'solid-js';\n *\n * function MyComponent() {\n * const whenReady = useGtmReady();\n *\n * onMount(async () => {\n * const states = await whenReady();\n * console.log('GTM loaded:', states);\n * });\n *\n * return <div>Loading...</div>;\n * }\n * ```\n */\nexport const useGtmReady = (): (() => Promise<ScriptLoadState[]>) => {\n return useGtmContext().whenReady;\n};\n"]}
1
+ {"version":3,"sources":["../src/context.tsx"],"names":["createContext","useContext","onCleanup","ErrorBoundary","createStore","createGtmClient","GtmContext","warnOnNestedProvider","process","env","NODE_ENV","console","warn","GtmProvider","props","existingContext","_$memo","children","autoInit","onBeforeInit","onAfterInit","clientOptions","containers","dataLayerName","host","scriptAttributes","client","state","setState","initialized","contextValue","push","value","setConsentDefaults","consentState","regionOptions","updateConsent","isReady","whenReady","onReady","callback","init","teardown","_$createComponent","Provider","useGtmContext","context","Error","useGtm","useGtmPush","useGtmConsent","useGtmClient","useGtmReady","useIsGtmReady","GtmErrorBoundary","logErrors","onError","handleError","err","error","defaultFallback","_err","_reset","fallback","reset"],"mappings":"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","sourcesContent":["import { createContext, useContext, onCleanup, ErrorBoundary, type JSX } from 'solid-js';\nimport { createStore } from 'solid-js/store';\nimport {\n createGtmClient,\n type ConsentRegionOptions,\n type ConsentState,\n type CreateGtmClientOptions,\n type DataLayerValue,\n type GtmClient,\n type ScriptLoadState\n} from '@jwiedeman/gtm-kit';\n\n/**\n * Props for the GTM Provider component.\n */\nexport interface GtmProviderProps extends CreateGtmClientOptions {\n /** Child components */\n children: JSX.Element;\n\n /**\n * Whether to automatically initialize GTM when the provider mounts.\n * @default true\n */\n autoInit?: boolean;\n\n /**\n * Callback executed before GTM initialization.\n * Use this to set consent defaults.\n */\n onBeforeInit?: (client: GtmClient) => void;\n\n /**\n * Callback executed after GTM initialization.\n */\n onAfterInit?: (client: GtmClient) => void;\n}\n\n/**\n * The GTM context value containing all GTM functionality.\n */\nexport interface GtmContextValue {\n /** The underlying GTM client instance */\n client: GtmClient;\n /** Push a value to the data layer */\n push: (value: DataLayerValue) => void;\n /** Set consent defaults (must be called before init) */\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Update consent state */\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n /** Synchronously check if all GTM scripts have finished loading */\n isReady: () => boolean;\n /** Returns a promise that resolves when all GTM scripts are loaded */\n whenReady: () => Promise<ScriptLoadState[]>;\n /** Register a callback for when GTM scripts are ready */\n onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;\n /** Whether GTM has been initialized */\n initialized: boolean;\n}\n\n/**\n * Consent-specific API subset.\n */\nexport interface GtmConsentApi {\n setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;\n updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;\n}\n\n/**\n * The GTM context for SolidJS.\n */\nexport const GtmContext = createContext<GtmContextValue>();\n\nconst warnOnNestedProvider = (): void => {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[gtm-kit/solid] Nested GtmProvider detected. You should only have one GtmProvider at the root of your app. ' +\n 'The nested provider will be ignored.'\n );\n }\n};\n\n/**\n * GTM Provider component for SolidJS.\n *\n * @example\n * ```tsx\n * import { GtmProvider } from '@jwiedeman/gtm-kit-solid';\n *\n * function App() {\n * return (\n * <GtmProvider containers=\"GTM-XXXXXX\">\n * <MyApp />\n * </GtmProvider>\n * );\n * }\n * ```\n */\nexport function GtmProvider(props: GtmProviderProps): JSX.Element {\n // Check for nested provider\n const existingContext = useContext(GtmContext);\n if (existingContext) {\n warnOnNestedProvider();\n return <>{props.children}</>;\n }\n\n // Note: Don't destructure children - in Solid.js, children is a getter that\n // should only be accessed inside the returned JSX to maintain proper reactivity\n const autoInit = props.autoInit ?? true;\n const onBeforeInit = props.onBeforeInit;\n const onAfterInit = props.onAfterInit;\n\n // Extract client options (everything except children and lifecycle hooks)\n const clientOptions: CreateGtmClientOptions = {\n containers: props.containers,\n ...(props.dataLayerName && { dataLayerName: props.dataLayerName }),\n ...(props.host && { host: props.host }),\n ...(props.scriptAttributes && { scriptAttributes: props.scriptAttributes })\n };\n\n const client = createGtmClient(clientOptions);\n\n const [state, setState] = createStore<{ initialized: boolean }>({\n initialized: false\n });\n\n const contextValue: GtmContextValue = {\n client,\n push: (value: DataLayerValue) => client.push(value),\n setConsentDefaults: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.setConsentDefaults(consentState, regionOptions),\n updateConsent: (consentState: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.updateConsent(consentState, regionOptions),\n isReady: () => client.isReady(),\n whenReady: () => client.whenReady(),\n onReady: (callback: (loadState: ScriptLoadState[]) => void) => client.onReady(callback),\n get initialized() {\n return state.initialized;\n }\n };\n\n // Call onBeforeInit hook if provided (for consent defaults)\n if (onBeforeInit) {\n onBeforeInit(client);\n }\n\n // Auto-initialize if enabled\n if (autoInit) {\n client.init();\n setState('initialized', true);\n\n // Call onAfterInit hook if provided\n if (onAfterInit) {\n onAfterInit(client);\n }\n }\n\n // Cleanup on unmount\n onCleanup(() => {\n client.teardown();\n });\n\n return <GtmContext.Provider value={contextValue}>{props.children}</GtmContext.Provider>;\n}\n\n/**\n * Internal helper to get the GTM context with proper error handling.\n */\nconst useGtmContext = (): GtmContextValue => {\n const context = useContext(GtmContext);\n if (!context) {\n throw new Error(\n '[gtm-kit/solid] useGtm() was called outside of a GtmProvider. ' +\n 'Make sure to wrap your app with <GtmProvider containers=\"GTM-XXXXXX\">.'\n );\n }\n return context;\n};\n\n/**\n * Hook to access the full GTM context.\n *\n * @example\n * ```tsx\n * import { useGtm } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const { push, client } = useGtm();\n *\n * return (\n * <button onClick={() => push({ event: 'click' })}>\n * Click me\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtm = (): GtmContextValue => {\n return useGtmContext();\n};\n\n/**\n * Hook to get just the push function.\n * Use this when you only need to push events.\n *\n * @example\n * ```tsx\n * import { useGtmPush } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const push = useGtmPush();\n *\n * return (\n * <button onClick={() => push({ event: 'purchase', value: 99 })}>\n * Buy\n * </button>\n * );\n * }\n * ```\n */\nexport const useGtmPush = (): ((value: DataLayerValue) => void) => {\n return useGtmContext().push;\n};\n\n/**\n * Hook to access consent management functions.\n *\n * @example\n * ```tsx\n * import { useGtmConsent } from '@jwiedeman/gtm-kit-solid';\n *\n * function CookieBanner() {\n * const { updateConsent } = useGtmConsent();\n *\n * const acceptAll = () => {\n * updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted'\n * });\n * };\n *\n * return <button onClick={acceptAll}>Accept All</button>;\n * }\n * ```\n */\nexport const useGtmConsent = (): GtmConsentApi => {\n const { setConsentDefaults, updateConsent } = useGtmContext();\n return { setConsentDefaults, updateConsent };\n};\n\n/**\n * Hook to get the raw GTM client instance.\n *\n * @example\n * ```tsx\n * import { useGtmClient } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const client = useGtmClient();\n *\n * return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;\n * }\n * ```\n */\nexport const useGtmClient = (): GtmClient => {\n return useGtmContext().client;\n};\n\n/**\n * Hook to get the whenReady function.\n * Use this to wait for GTM scripts to load.\n *\n * @example\n * ```tsx\n * import { useGtmReady } from '@jwiedeman/gtm-kit-solid';\n * import { onMount } from 'solid-js';\n *\n * function MyComponent() {\n * const whenReady = useGtmReady();\n *\n * onMount(async () => {\n * const states = await whenReady();\n * console.log('GTM loaded:', states);\n * });\n *\n * return <div>Loading...</div>;\n * }\n * ```\n */\nexport const useGtmReady = (): (() => Promise<ScriptLoadState[]>) => {\n return useGtmContext().whenReady;\n};\n\n/**\n * Hook to check if GTM scripts have finished loading synchronously.\n *\n * @example\n * ```tsx\n * import { useIsGtmReady } from '@jwiedeman/gtm-kit-solid';\n *\n * function MyComponent() {\n * const isReady = useIsGtmReady();\n *\n * return <div>GTM Ready: {isReady() ? 'Yes' : 'No'}</div>;\n * }\n * ```\n */\nexport const useIsGtmReady = (): (() => boolean) => {\n return useGtmContext().isReady;\n};\n\n/**\n * Props for GtmErrorBoundary component.\n */\nexport interface GtmErrorBoundaryProps {\n /** Child components */\n children: JSX.Element;\n /** Fallback UI to render when an error occurs */\n fallback?: JSX.Element | ((err: Error, reset: () => void) => JSX.Element);\n /** Callback invoked when an error is caught */\n onError?: (error: Error) => void;\n /** Whether to log errors to console (default: true in development) */\n logErrors?: boolean;\n}\n\n/**\n * Error boundary component for GTM provider in SolidJS apps.\n * Catches errors during GTM initialization and renders a fallback UI.\n *\n * @example\n * ```tsx\n * import { GtmProvider, GtmErrorBoundary } from '@jwiedeman/gtm-kit-solid';\n *\n * function App() {\n * return (\n * <GtmErrorBoundary\n * fallback={(err, reset) => (\n * <div>\n * <p>GTM failed: {err.message}</p>\n * <button onClick={reset}>Retry</button>\n * </div>\n * )}\n * >\n * <GtmProvider containers=\"GTM-XXXXXX\">\n * <MyApp />\n * </GtmProvider>\n * </GtmErrorBoundary>\n * );\n * }\n * ```\n */\nexport function GtmErrorBoundary(props: GtmErrorBoundaryProps): JSX.Element {\n const logErrors = props.logErrors ?? process.env.NODE_ENV !== 'production';\n const onError = props.onError;\n\n const handleError = (err: Error) => {\n if (logErrors) {\n console.error('[gtm-kit/solid] Error caught by GtmErrorBoundary:', err);\n }\n\n if (onError) {\n try {\n onError(err);\n } catch {\n // Ignore callback errors\n }\n }\n };\n\n // Default fallback - just render children (silent degradation)\n const defaultFallback = (_err: Error, _reset: () => void) => props.children;\n\n const fallback = props.fallback ?? defaultFallback;\n\n return (\n <ErrorBoundary\n fallback={(err: Error, reset: () => void) => {\n handleError(err);\n if (typeof fallback === 'function') {\n return fallback(err, reset);\n }\n return fallback;\n }}\n >\n {props.children}\n </ErrorBoundary>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jwiedeman/gtm-kit-solid",
3
- "version": "1.1.6",
3
+ "version": "1.2.0",
4
4
  "description": "SolidJS primitives and context for GTM Kit - Google Tag Manager integration with signals.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -50,13 +50,14 @@
50
50
  "typecheck": "tsc --noEmit"
51
51
  },
52
52
  "dependencies": {
53
- "@jwiedeman/gtm-kit": "^1.0.0"
53
+ "@jwiedeman/gtm-kit": "^1.2.0"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "solid-js": "^1.0.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@solidjs/testing-library": "^0.8.7",
60
+ "esbuild-plugin-solid": "^0.6.0",
60
61
  "solid-js": "^1.8.17",
61
62
  "solid-testing-library": "^0.5.1",
62
63
  "tslib": "^2.6.2"