@jwiedeman/gtm-kit-solid 1.0.1
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/README.md +344 -0
- package/dist/index.cjs +17 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +172 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# @react-gtm-kit/solid
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jwiedeman/react-gtm-kit/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/jwiedeman/react-gtm-kit)
|
|
5
|
+
[](https://www.npmjs.com/package/@react-gtm-kit/solid)
|
|
6
|
+
[](https://bundlephobia.com/package/@react-gtm-kit/solid)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://www.solidjs.com/)
|
|
10
|
+
|
|
11
|
+
**SolidJS primitives and context for Google Tag Manager. Fine-grained reactivity.**
|
|
12
|
+
|
|
13
|
+
The SolidJS adapter for GTM Kit - provides context and hooks for idiomatic Solid integration.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @react-gtm-kit/core @react-gtm-kit/solid
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
yarn add @react-gtm-kit/core @react-gtm-kit/solid
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @react-gtm-kit/core @react-gtm-kit/solid
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Step 1: Wrap Your App
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
// App.tsx
|
|
39
|
+
import { GtmProvider } from '@react-gtm-kit/solid';
|
|
40
|
+
|
|
41
|
+
function App() {
|
|
42
|
+
return (
|
|
43
|
+
<GtmProvider containers="GTM-XXXXXX">
|
|
44
|
+
<MyApp />
|
|
45
|
+
</GtmProvider>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Step 2: Push Events
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { useGtmPush } from '@react-gtm-kit/solid';
|
|
54
|
+
|
|
55
|
+
function BuyButton() {
|
|
56
|
+
const push = useGtmPush();
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<button onClick={() => push({ event: 'purchase', value: 49.99 })}>
|
|
60
|
+
Buy Now
|
|
61
|
+
</button>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**That's it!** GTM is now running.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
| Feature | Description |
|
|
73
|
+
|---------|-------------|
|
|
74
|
+
| **SolidJS Native** | Built for Solid's reactivity system |
|
|
75
|
+
| **Fine-Grained** | Only updates what needs to update |
|
|
76
|
+
| **Context-Based** | Uses Solid's context API |
|
|
77
|
+
| **TypeScript** | Full type definitions included |
|
|
78
|
+
| **Consent Mode v2** | Built-in GDPR compliance |
|
|
79
|
+
| **SSR Compatible** | Safe for SolidStart SSR |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Available Hooks
|
|
84
|
+
|
|
85
|
+
### `useGtm()`
|
|
86
|
+
|
|
87
|
+
Get the full GTM context.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { useGtm } from '@react-gtm-kit/solid';
|
|
91
|
+
|
|
92
|
+
function MyComponent() {
|
|
93
|
+
const { push, client, updateConsent, initialized } = useGtm();
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div>
|
|
97
|
+
<p>GTM Initialized: {initialized ? 'Yes' : 'No'}</p>
|
|
98
|
+
<button onClick={() => push({ event: 'click' })}>Track</button>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### `useGtmPush()`
|
|
105
|
+
|
|
106
|
+
Get just the push function.
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { useGtmPush } from '@react-gtm-kit/solid';
|
|
110
|
+
|
|
111
|
+
function MyComponent() {
|
|
112
|
+
const push = useGtmPush();
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<button onClick={() => push({ event: 'purchase', value: 99 })}>
|
|
116
|
+
Buy
|
|
117
|
+
</button>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `useGtmConsent()`
|
|
123
|
+
|
|
124
|
+
Access consent management functions.
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { useGtmConsent } from '@react-gtm-kit/solid';
|
|
128
|
+
|
|
129
|
+
function CookieBanner() {
|
|
130
|
+
const { updateConsent } = useGtmConsent();
|
|
131
|
+
|
|
132
|
+
const acceptAll = () => {
|
|
133
|
+
updateConsent({
|
|
134
|
+
ad_storage: 'granted',
|
|
135
|
+
analytics_storage: 'granted',
|
|
136
|
+
ad_user_data: 'granted',
|
|
137
|
+
ad_personalization: 'granted'
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return <button onClick={acceptAll}>Accept All</button>;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `useGtmClient()`
|
|
146
|
+
|
|
147
|
+
Get the raw GTM client instance.
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { useGtmClient } from '@react-gtm-kit/solid';
|
|
151
|
+
|
|
152
|
+
function MyComponent() {
|
|
153
|
+
const client = useGtmClient();
|
|
154
|
+
|
|
155
|
+
return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `useGtmReady()`
|
|
160
|
+
|
|
161
|
+
Get a function that resolves when GTM is loaded.
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import { useGtmReady } from '@react-gtm-kit/solid';
|
|
165
|
+
import { onMount } from 'solid-js';
|
|
166
|
+
|
|
167
|
+
function MyComponent() {
|
|
168
|
+
const whenReady = useGtmReady();
|
|
169
|
+
|
|
170
|
+
onMount(async () => {
|
|
171
|
+
const states = await whenReady();
|
|
172
|
+
console.log('GTM loaded:', states);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
return <div>Loading...</div>;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Provider Options
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
<GtmProvider
|
|
185
|
+
containers="GTM-XXXXXX"
|
|
186
|
+
autoInit={true}
|
|
187
|
+
dataLayerName="dataLayer"
|
|
188
|
+
host="https://www.googletagmanager.com"
|
|
189
|
+
scriptAttributes={{ nonce: '...' }}
|
|
190
|
+
onBeforeInit={(client) => {
|
|
191
|
+
// Set consent defaults here
|
|
192
|
+
}}
|
|
193
|
+
onAfterInit={(client) => {
|
|
194
|
+
// Called after GTM initializes
|
|
195
|
+
}}
|
|
196
|
+
>
|
|
197
|
+
{children}
|
|
198
|
+
</GtmProvider>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## SolidStart Integration
|
|
204
|
+
|
|
205
|
+
### Basic Setup
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// src/root.tsx
|
|
209
|
+
import { GtmProvider } from '@react-gtm-kit/solid';
|
|
210
|
+
|
|
211
|
+
export default function Root() {
|
|
212
|
+
return (
|
|
213
|
+
<Html>
|
|
214
|
+
<Head />
|
|
215
|
+
<Body>
|
|
216
|
+
<GtmProvider containers="GTM-XXXXXX">
|
|
217
|
+
<Routes />
|
|
218
|
+
</GtmProvider>
|
|
219
|
+
</Body>
|
|
220
|
+
</Html>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Page Tracking with Router
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import { useGtmPush } from '@react-gtm-kit/solid';
|
|
229
|
+
import { useLocation } from '@solidjs/router';
|
|
230
|
+
import { createEffect } from 'solid-js';
|
|
231
|
+
|
|
232
|
+
function PageTracker() {
|
|
233
|
+
const push = useGtmPush();
|
|
234
|
+
const location = useLocation();
|
|
235
|
+
|
|
236
|
+
createEffect(() => {
|
|
237
|
+
push({
|
|
238
|
+
event: 'page_view',
|
|
239
|
+
page_path: location.pathname
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Consent Mode v2 (GDPR)
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
import { GtmProvider, useGtmConsent } from '@react-gtm-kit/solid';
|
|
253
|
+
import { consentPresets } from '@react-gtm-kit/core';
|
|
254
|
+
|
|
255
|
+
// In your root component
|
|
256
|
+
function App() {
|
|
257
|
+
return (
|
|
258
|
+
<GtmProvider
|
|
259
|
+
containers="GTM-XXXXXX"
|
|
260
|
+
onBeforeInit={(client) => {
|
|
261
|
+
// Deny by default for EU users
|
|
262
|
+
client.setConsentDefaults(consentPresets.eeaDefault, { region: ['EEA'] });
|
|
263
|
+
}}
|
|
264
|
+
>
|
|
265
|
+
<MyApp />
|
|
266
|
+
<CookieBanner />
|
|
267
|
+
</GtmProvider>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Cookie banner component
|
|
272
|
+
function CookieBanner() {
|
|
273
|
+
const { updateConsent } = useGtmConsent();
|
|
274
|
+
|
|
275
|
+
return (
|
|
276
|
+
<div class="cookie-banner">
|
|
277
|
+
<p>We use cookies to improve your experience.</p>
|
|
278
|
+
<button onClick={() => updateConsent({
|
|
279
|
+
ad_storage: 'granted',
|
|
280
|
+
analytics_storage: 'granted',
|
|
281
|
+
ad_user_data: 'granted',
|
|
282
|
+
ad_personalization: 'granted'
|
|
283
|
+
})}>
|
|
284
|
+
Accept All
|
|
285
|
+
</button>
|
|
286
|
+
<button onClick={() => updateConsent({
|
|
287
|
+
ad_storage: 'denied',
|
|
288
|
+
analytics_storage: 'denied',
|
|
289
|
+
ad_user_data: 'denied',
|
|
290
|
+
ad_personalization: 'denied'
|
|
291
|
+
})}>
|
|
292
|
+
Reject All
|
|
293
|
+
</button>
|
|
294
|
+
</div>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Multiple Containers
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
<GtmProvider
|
|
305
|
+
containers={[
|
|
306
|
+
{ id: 'GTM-MAIN' },
|
|
307
|
+
{ id: 'GTM-ADS', queryParams: { gtm_auth: 'abc', gtm_preview: 'env-1' } }
|
|
308
|
+
]}
|
|
309
|
+
>
|
|
310
|
+
{children}
|
|
311
|
+
</GtmProvider>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## TypeScript
|
|
317
|
+
|
|
318
|
+
Full TypeScript support is included:
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import type { GtmContextValue, GtmConsentApi } from '@react-gtm-kit/solid';
|
|
322
|
+
import { useGtm, useGtmConsent } from '@react-gtm-kit/solid';
|
|
323
|
+
|
|
324
|
+
function MyComponent() {
|
|
325
|
+
const gtm: GtmContextValue = useGtm();
|
|
326
|
+
const consent: GtmConsentApi = useGtmConsent();
|
|
327
|
+
|
|
328
|
+
// Fully typed!
|
|
329
|
+
gtm.push({ event: 'my_event', custom_param: 'value' });
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Requirements
|
|
336
|
+
|
|
337
|
+
- SolidJS 1.0+
|
|
338
|
+
- `@react-gtm-kit/core` (peer dependency)
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## License
|
|
343
|
+
|
|
344
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var solidJs = require('solid-js');
|
|
4
|
+
var store = require('solid-js/store');
|
|
5
|
+
var gtmKit = require('@jwiedeman/gtm-kit');
|
|
6
|
+
|
|
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
|
+
|
|
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;
|
|
16
|
+
//# sourceMappingURL=out.js.map
|
|
17
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import * as solid_js from 'solid-js';
|
|
2
|
+
import { JSX } from 'solid-js';
|
|
3
|
+
import { CreateGtmClientOptions, GtmClient, DataLayerValue, ConsentState, ConsentRegionOptions, ScriptLoadState } from '@jwiedeman/gtm-kit';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Props for the GTM Provider component.
|
|
7
|
+
*/
|
|
8
|
+
interface GtmProviderProps extends CreateGtmClientOptions {
|
|
9
|
+
/** Child components */
|
|
10
|
+
children: JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to automatically initialize GTM when the provider mounts.
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
autoInit?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Callback executed before GTM initialization.
|
|
18
|
+
* Use this to set consent defaults.
|
|
19
|
+
*/
|
|
20
|
+
onBeforeInit?: (client: GtmClient) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Callback executed after GTM initialization.
|
|
23
|
+
*/
|
|
24
|
+
onAfterInit?: (client: GtmClient) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The GTM context value containing all GTM functionality.
|
|
28
|
+
*/
|
|
29
|
+
interface GtmContextValue {
|
|
30
|
+
/** The underlying GTM client instance */
|
|
31
|
+
client: GtmClient;
|
|
32
|
+
/** Push a value to the data layer */
|
|
33
|
+
push: (value: DataLayerValue) => void;
|
|
34
|
+
/** Set consent defaults (must be called before init) */
|
|
35
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
36
|
+
/** Update consent state */
|
|
37
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
38
|
+
/** Returns a promise that resolves when all GTM scripts are loaded */
|
|
39
|
+
whenReady: () => Promise<ScriptLoadState[]>;
|
|
40
|
+
/** Register a callback for when GTM scripts are ready */
|
|
41
|
+
onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;
|
|
42
|
+
/** Whether GTM has been initialized */
|
|
43
|
+
initialized: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Consent-specific API subset.
|
|
47
|
+
*/
|
|
48
|
+
interface GtmConsentApi {
|
|
49
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
50
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The GTM context for SolidJS.
|
|
54
|
+
*/
|
|
55
|
+
declare const GtmContext: solid_js.Context<GtmContextValue | undefined>;
|
|
56
|
+
/**
|
|
57
|
+
* GTM Provider component for SolidJS.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { GtmProvider } from '@jwiedeman/gtm-kit-solid';
|
|
62
|
+
*
|
|
63
|
+
* function App() {
|
|
64
|
+
* return (
|
|
65
|
+
* <GtmProvider containers="GTM-XXXXXX">
|
|
66
|
+
* <MyApp />
|
|
67
|
+
* </GtmProvider>
|
|
68
|
+
* );
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function GtmProvider(props: GtmProviderProps): JSX.Element;
|
|
73
|
+
/**
|
|
74
|
+
* Hook to access the full GTM context.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```tsx
|
|
78
|
+
* import { useGtm } from '@jwiedeman/gtm-kit-solid';
|
|
79
|
+
*
|
|
80
|
+
* function MyComponent() {
|
|
81
|
+
* const { push, client } = useGtm();
|
|
82
|
+
*
|
|
83
|
+
* return (
|
|
84
|
+
* <button onClick={() => push({ event: 'click' })}>
|
|
85
|
+
* Click me
|
|
86
|
+
* </button>
|
|
87
|
+
* );
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare const useGtm: () => GtmContextValue;
|
|
92
|
+
/**
|
|
93
|
+
* Hook to get just the push function.
|
|
94
|
+
* Use this when you only need to push events.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* import { useGtmPush } from '@jwiedeman/gtm-kit-solid';
|
|
99
|
+
*
|
|
100
|
+
* function MyComponent() {
|
|
101
|
+
* const push = useGtmPush();
|
|
102
|
+
*
|
|
103
|
+
* return (
|
|
104
|
+
* <button onClick={() => push({ event: 'purchase', value: 99 })}>
|
|
105
|
+
* Buy
|
|
106
|
+
* </button>
|
|
107
|
+
* );
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare const useGtmPush: () => ((value: DataLayerValue) => void);
|
|
112
|
+
/**
|
|
113
|
+
* Hook to access consent management functions.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* import { useGtmConsent } from '@jwiedeman/gtm-kit-solid';
|
|
118
|
+
*
|
|
119
|
+
* function CookieBanner() {
|
|
120
|
+
* const { updateConsent } = useGtmConsent();
|
|
121
|
+
*
|
|
122
|
+
* const acceptAll = () => {
|
|
123
|
+
* updateConsent({
|
|
124
|
+
* ad_storage: 'granted',
|
|
125
|
+
* analytics_storage: 'granted'
|
|
126
|
+
* });
|
|
127
|
+
* };
|
|
128
|
+
*
|
|
129
|
+
* return <button onClick={acceptAll}>Accept All</button>;
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare const useGtmConsent: () => GtmConsentApi;
|
|
134
|
+
/**
|
|
135
|
+
* Hook to get the raw GTM client instance.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```tsx
|
|
139
|
+
* import { useGtmClient } from '@jwiedeman/gtm-kit-solid';
|
|
140
|
+
*
|
|
141
|
+
* function MyComponent() {
|
|
142
|
+
* const client = useGtmClient();
|
|
143
|
+
*
|
|
144
|
+
* return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare const useGtmClient: () => GtmClient;
|
|
149
|
+
/**
|
|
150
|
+
* Hook to get the whenReady function.
|
|
151
|
+
* Use this to wait for GTM scripts to load.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```tsx
|
|
155
|
+
* import { useGtmReady } from '@jwiedeman/gtm-kit-solid';
|
|
156
|
+
* import { onMount } from 'solid-js';
|
|
157
|
+
*
|
|
158
|
+
* function MyComponent() {
|
|
159
|
+
* const whenReady = useGtmReady();
|
|
160
|
+
*
|
|
161
|
+
* onMount(async () => {
|
|
162
|
+
* const states = await whenReady();
|
|
163
|
+
* console.log('GTM loaded:', states);
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* return <div>Loading...</div>;
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare const useGtmReady: () => (() => Promise<ScriptLoadState[]>);
|
|
171
|
+
|
|
172
|
+
export { GtmConsentApi, GtmContext, GtmContextValue, GtmProvider, GtmProviderProps, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import * as solid_js from 'solid-js';
|
|
2
|
+
import { JSX } from 'solid-js';
|
|
3
|
+
import { CreateGtmClientOptions, GtmClient, DataLayerValue, ConsentState, ConsentRegionOptions, ScriptLoadState } from '@jwiedeman/gtm-kit';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Props for the GTM Provider component.
|
|
7
|
+
*/
|
|
8
|
+
interface GtmProviderProps extends CreateGtmClientOptions {
|
|
9
|
+
/** Child components */
|
|
10
|
+
children: JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to automatically initialize GTM when the provider mounts.
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
autoInit?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Callback executed before GTM initialization.
|
|
18
|
+
* Use this to set consent defaults.
|
|
19
|
+
*/
|
|
20
|
+
onBeforeInit?: (client: GtmClient) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Callback executed after GTM initialization.
|
|
23
|
+
*/
|
|
24
|
+
onAfterInit?: (client: GtmClient) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The GTM context value containing all GTM functionality.
|
|
28
|
+
*/
|
|
29
|
+
interface GtmContextValue {
|
|
30
|
+
/** The underlying GTM client instance */
|
|
31
|
+
client: GtmClient;
|
|
32
|
+
/** Push a value to the data layer */
|
|
33
|
+
push: (value: DataLayerValue) => void;
|
|
34
|
+
/** Set consent defaults (must be called before init) */
|
|
35
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
36
|
+
/** Update consent state */
|
|
37
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
38
|
+
/** Returns a promise that resolves when all GTM scripts are loaded */
|
|
39
|
+
whenReady: () => Promise<ScriptLoadState[]>;
|
|
40
|
+
/** Register a callback for when GTM scripts are ready */
|
|
41
|
+
onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;
|
|
42
|
+
/** Whether GTM has been initialized */
|
|
43
|
+
initialized: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Consent-specific API subset.
|
|
47
|
+
*/
|
|
48
|
+
interface GtmConsentApi {
|
|
49
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
50
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The GTM context for SolidJS.
|
|
54
|
+
*/
|
|
55
|
+
declare const GtmContext: solid_js.Context<GtmContextValue | undefined>;
|
|
56
|
+
/**
|
|
57
|
+
* GTM Provider component for SolidJS.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { GtmProvider } from '@jwiedeman/gtm-kit-solid';
|
|
62
|
+
*
|
|
63
|
+
* function App() {
|
|
64
|
+
* return (
|
|
65
|
+
* <GtmProvider containers="GTM-XXXXXX">
|
|
66
|
+
* <MyApp />
|
|
67
|
+
* </GtmProvider>
|
|
68
|
+
* );
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function GtmProvider(props: GtmProviderProps): JSX.Element;
|
|
73
|
+
/**
|
|
74
|
+
* Hook to access the full GTM context.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```tsx
|
|
78
|
+
* import { useGtm } from '@jwiedeman/gtm-kit-solid';
|
|
79
|
+
*
|
|
80
|
+
* function MyComponent() {
|
|
81
|
+
* const { push, client } = useGtm();
|
|
82
|
+
*
|
|
83
|
+
* return (
|
|
84
|
+
* <button onClick={() => push({ event: 'click' })}>
|
|
85
|
+
* Click me
|
|
86
|
+
* </button>
|
|
87
|
+
* );
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare const useGtm: () => GtmContextValue;
|
|
92
|
+
/**
|
|
93
|
+
* Hook to get just the push function.
|
|
94
|
+
* Use this when you only need to push events.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* import { useGtmPush } from '@jwiedeman/gtm-kit-solid';
|
|
99
|
+
*
|
|
100
|
+
* function MyComponent() {
|
|
101
|
+
* const push = useGtmPush();
|
|
102
|
+
*
|
|
103
|
+
* return (
|
|
104
|
+
* <button onClick={() => push({ event: 'purchase', value: 99 })}>
|
|
105
|
+
* Buy
|
|
106
|
+
* </button>
|
|
107
|
+
* );
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare const useGtmPush: () => ((value: DataLayerValue) => void);
|
|
112
|
+
/**
|
|
113
|
+
* Hook to access consent management functions.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* import { useGtmConsent } from '@jwiedeman/gtm-kit-solid';
|
|
118
|
+
*
|
|
119
|
+
* function CookieBanner() {
|
|
120
|
+
* const { updateConsent } = useGtmConsent();
|
|
121
|
+
*
|
|
122
|
+
* const acceptAll = () => {
|
|
123
|
+
* updateConsent({
|
|
124
|
+
* ad_storage: 'granted',
|
|
125
|
+
* analytics_storage: 'granted'
|
|
126
|
+
* });
|
|
127
|
+
* };
|
|
128
|
+
*
|
|
129
|
+
* return <button onClick={acceptAll}>Accept All</button>;
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare const useGtmConsent: () => GtmConsentApi;
|
|
134
|
+
/**
|
|
135
|
+
* Hook to get the raw GTM client instance.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```tsx
|
|
139
|
+
* import { useGtmClient } from '@jwiedeman/gtm-kit-solid';
|
|
140
|
+
*
|
|
141
|
+
* function MyComponent() {
|
|
142
|
+
* const client = useGtmClient();
|
|
143
|
+
*
|
|
144
|
+
* return <div>Initialized: {client.isInitialized() ? 'Yes' : 'No'}</div>;
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
declare const useGtmClient: () => GtmClient;
|
|
149
|
+
/**
|
|
150
|
+
* Hook to get the whenReady function.
|
|
151
|
+
* Use this to wait for GTM scripts to load.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```tsx
|
|
155
|
+
* import { useGtmReady } from '@jwiedeman/gtm-kit-solid';
|
|
156
|
+
* import { onMount } from 'solid-js';
|
|
157
|
+
*
|
|
158
|
+
* function MyComponent() {
|
|
159
|
+
* const whenReady = useGtmReady();
|
|
160
|
+
*
|
|
161
|
+
* onMount(async () => {
|
|
162
|
+
* const states = await whenReady();
|
|
163
|
+
* console.log('GTM loaded:', states);
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* return <div>Loading...</div>;
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare const useGtmReady: () => (() => Promise<ScriptLoadState[]>);
|
|
171
|
+
|
|
172
|
+
export { GtmConsentApi, GtmContext, GtmContextValue, GtmProvider, GtmProviderProps, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createContext, onCleanup, useContext } from 'solid-js';
|
|
2
|
+
import { createStore } from 'solid-js/store';
|
|
3
|
+
import { createGtmClient } from '@jwiedeman/gtm-kit';
|
|
4
|
+
|
|
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
|
+
|
|
7
|
+
export { s as GtmContext, v as GtmProvider, S as useGtm, R as useGtmClient, P as useGtmConsent, h as useGtmPush, L as useGtmReady };
|
|
8
|
+
//# sourceMappingURL=out.js.map
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jwiedeman/gtm-kit-solid",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "SolidJS primitives and context for GTM Kit - Google Tag Manager integration.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/jwiedeman/GTM-Kit.git",
|
|
8
|
+
"directory": "packages/solid"
|
|
9
|
+
},
|
|
10
|
+
"author": "jwiedeman",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"gtm",
|
|
13
|
+
"google-tag-manager",
|
|
14
|
+
"solidjs",
|
|
15
|
+
"solid",
|
|
16
|
+
"primitives"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "dist/index.cjs",
|
|
24
|
+
"module": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"solid": "./dist/index.js",
|
|
30
|
+
"import": "./dist/index.js",
|
|
31
|
+
"require": "./dist/index.cjs"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"clean": "rm -rf dist",
|
|
40
|
+
"lint": "eslint --max-warnings=0 \"src/**/*.{ts,tsx}\"",
|
|
41
|
+
"test": "jest --config ./jest.config.cjs --runInBand --passWithNoTests",
|
|
42
|
+
"typecheck": "tsc --noEmit"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@jwiedeman/gtm-kit": "^1.0.1"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"solid-js": "^1.0.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@solidjs/testing-library": "^0.8.7",
|
|
52
|
+
"solid-js": "^1.8.17",
|
|
53
|
+
"solid-testing-library": "^0.5.1",
|
|
54
|
+
"tslib": "^2.6.2"
|
|
55
|
+
}
|
|
56
|
+
}
|