@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 +137 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -1
- package/dist/index.d.ts +58 -1
- package/dist/index.js +130 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
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
|
-
|
|
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 =
|
|
10
|
-
exports.
|
|
11
|
-
exports.
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
15
|
-
exports.
|
|
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
|
package/dist/index.cjs.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/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 {
|
|
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
|
-
|
|
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 {
|
|
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.
|
|
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.
|
|
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"
|