@jwiedeman/gtm-kit-vue 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 +335 -0
- package/dist/index.cjs +16 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +167 -0
- package/dist/index.d.ts +167 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# @react-gtm-kit/vue
|
|
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/vue)
|
|
6
|
+
[](https://bundlephobia.com/package/@react-gtm-kit/vue)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://vuejs.org/)
|
|
10
|
+
|
|
11
|
+
**Vue 3 plugin and composables for Google Tag Manager. Composition API ready.**
|
|
12
|
+
|
|
13
|
+
The Vue adapter for GTM Kit - provides a plugin and composables for clean Vue integration.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @react-gtm-kit/core @react-gtm-kit/vue
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
yarn add @react-gtm-kit/core @react-gtm-kit/vue
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @react-gtm-kit/core @react-gtm-kit/vue
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Step 1: Add Plugin
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// main.ts
|
|
39
|
+
import { createApp } from 'vue';
|
|
40
|
+
import { GtmPlugin } from '@react-gtm-kit/vue';
|
|
41
|
+
import App from './App.vue';
|
|
42
|
+
|
|
43
|
+
createApp(App).use(GtmPlugin, { containers: 'GTM-XXXXXX' }).mount('#app');
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Step 2: Push Events
|
|
47
|
+
|
|
48
|
+
```vue
|
|
49
|
+
<script setup>
|
|
50
|
+
import { useGtm } from '@react-gtm-kit/vue';
|
|
51
|
+
|
|
52
|
+
const { push } = useGtm();
|
|
53
|
+
|
|
54
|
+
function handleClick() {
|
|
55
|
+
push({ event: 'purchase', value: 49.99 });
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<button @click="handleClick">Buy Now</button>
|
|
61
|
+
</template>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**That's it!** GTM is now running.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Features
|
|
69
|
+
|
|
70
|
+
| Feature | Description |
|
|
71
|
+
| ------------------- | ------------------------------ |
|
|
72
|
+
| **Vue 3 Native** | Built for Composition API |
|
|
73
|
+
| **Composables** | Clean, reactive Vue patterns |
|
|
74
|
+
| **TypeScript** | Full type definitions included |
|
|
75
|
+
| **Consent Mode v2** | Built-in GDPR compliance |
|
|
76
|
+
| **SSR Compatible** | Safe for Nuxt and Vite SSR |
|
|
77
|
+
| **Lightweight** | ~4KB gzipped |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Available Composables
|
|
82
|
+
|
|
83
|
+
### `useGtm()`
|
|
84
|
+
|
|
85
|
+
Get the full GTM API.
|
|
86
|
+
|
|
87
|
+
```vue
|
|
88
|
+
<script setup>
|
|
89
|
+
import { useGtm } from '@react-gtm-kit/vue';
|
|
90
|
+
|
|
91
|
+
const { client, push, updateConsent, setConsentDefaults } = useGtm();
|
|
92
|
+
|
|
93
|
+
push({ event: 'page_view', page_path: '/' });
|
|
94
|
+
</script>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `useGtmPush()`
|
|
98
|
+
|
|
99
|
+
Get just the push function.
|
|
100
|
+
|
|
101
|
+
```vue
|
|
102
|
+
<script setup>
|
|
103
|
+
import { useGtmPush } from '@react-gtm-kit/vue';
|
|
104
|
+
|
|
105
|
+
const push = useGtmPush();
|
|
106
|
+
|
|
107
|
+
push({ event: 'button_click', button_id: 'cta-main' });
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `useGtmConsent()`
|
|
112
|
+
|
|
113
|
+
Manage consent state.
|
|
114
|
+
|
|
115
|
+
```vue
|
|
116
|
+
<script setup>
|
|
117
|
+
import { useGtmConsent } from '@react-gtm-kit/vue';
|
|
118
|
+
|
|
119
|
+
const { updateConsent } = useGtmConsent();
|
|
120
|
+
|
|
121
|
+
function acceptAll() {
|
|
122
|
+
updateConsent({
|
|
123
|
+
ad_storage: 'granted',
|
|
124
|
+
analytics_storage: 'granted',
|
|
125
|
+
ad_user_data: 'granted',
|
|
126
|
+
ad_personalization: 'granted'
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
</script>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `useGtmClient()`
|
|
133
|
+
|
|
134
|
+
Get the raw GTM client instance.
|
|
135
|
+
|
|
136
|
+
```vue
|
|
137
|
+
<script setup>
|
|
138
|
+
import { useGtmClient } from '@react-gtm-kit/vue';
|
|
139
|
+
|
|
140
|
+
const client = useGtmClient();
|
|
141
|
+
|
|
142
|
+
onMounted(async () => {
|
|
143
|
+
await client.whenReady();
|
|
144
|
+
console.log('GTM is ready!');
|
|
145
|
+
});
|
|
146
|
+
</script>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### `useGtmReady()`
|
|
150
|
+
|
|
151
|
+
Get a function that resolves when GTM is loaded.
|
|
152
|
+
|
|
153
|
+
```vue
|
|
154
|
+
<script setup>
|
|
155
|
+
import { useGtmReady } from '@react-gtm-kit/vue';
|
|
156
|
+
|
|
157
|
+
const whenReady = useGtmReady();
|
|
158
|
+
|
|
159
|
+
onMounted(async () => {
|
|
160
|
+
await whenReady();
|
|
161
|
+
console.log('GTM scripts loaded!');
|
|
162
|
+
});
|
|
163
|
+
</script>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Plugin Options
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
app.use(GtmPlugin, {
|
|
172
|
+
containers: 'GTM-XXXXXX', // Required
|
|
173
|
+
dataLayerName: 'dataLayer', // Optional
|
|
174
|
+
host: 'https://custom.host.com', // Optional
|
|
175
|
+
scriptAttributes: { nonce: '...' }, // Optional: CSP
|
|
176
|
+
onBeforeInit: (client) => {
|
|
177
|
+
// Called before GTM initializes
|
|
178
|
+
// Perfect for consent defaults
|
|
179
|
+
},
|
|
180
|
+
onAfterInit: (client) => {
|
|
181
|
+
// Called after GTM initializes
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Vue Router Integration
|
|
189
|
+
|
|
190
|
+
```vue
|
|
191
|
+
<script setup>
|
|
192
|
+
import { useGtm } from '@react-gtm-kit/vue';
|
|
193
|
+
import { watch } from 'vue';
|
|
194
|
+
import { useRoute } from 'vue-router';
|
|
195
|
+
|
|
196
|
+
const route = useRoute();
|
|
197
|
+
const { push } = useGtm();
|
|
198
|
+
|
|
199
|
+
watch(
|
|
200
|
+
() => route.fullPath,
|
|
201
|
+
(path) => {
|
|
202
|
+
push({ event: 'page_view', page_path: path });
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
</script>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Or create a reusable composable:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// composables/usePageTracking.ts
|
|
212
|
+
import { useGtm } from '@react-gtm-kit/vue';
|
|
213
|
+
import { watch, onMounted } from 'vue';
|
|
214
|
+
import { useRoute } from 'vue-router';
|
|
215
|
+
|
|
216
|
+
export function usePageTracking() {
|
|
217
|
+
const route = useRoute();
|
|
218
|
+
const { push } = useGtm();
|
|
219
|
+
|
|
220
|
+
onMounted(() => {
|
|
221
|
+
// Track initial page
|
|
222
|
+
push({ event: 'page_view', page_path: route.fullPath });
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
watch(
|
|
226
|
+
() => route.fullPath,
|
|
227
|
+
(path, oldPath) => {
|
|
228
|
+
if (path !== oldPath) {
|
|
229
|
+
push({ event: 'page_view', page_path: path });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Consent Mode v2 (GDPR)
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
// main.ts
|
|
242
|
+
import { createApp } from 'vue';
|
|
243
|
+
import { GtmPlugin } from '@react-gtm-kit/vue';
|
|
244
|
+
import { consentPresets } from '@react-gtm-kit/core';
|
|
245
|
+
import App from './App.vue';
|
|
246
|
+
|
|
247
|
+
createApp(App)
|
|
248
|
+
.use(GtmPlugin, {
|
|
249
|
+
containers: 'GTM-XXXXXX',
|
|
250
|
+
onBeforeInit: (client) => {
|
|
251
|
+
// Deny by default for EU users
|
|
252
|
+
client.setConsentDefaults(consentPresets.eeaDefault, { region: ['EEA'] });
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
.mount('#app');
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```vue
|
|
259
|
+
<!-- CookieBanner.vue -->
|
|
260
|
+
<script setup>
|
|
261
|
+
import { useGtmConsent } from '@react-gtm-kit/vue';
|
|
262
|
+
import { consentPresets } from '@react-gtm-kit/core';
|
|
263
|
+
|
|
264
|
+
const { updateConsent } = useGtmConsent();
|
|
265
|
+
|
|
266
|
+
// Accept all tracking
|
|
267
|
+
const acceptAll = () => updateConsent(consentPresets.allGranted);
|
|
268
|
+
|
|
269
|
+
// Reject all tracking
|
|
270
|
+
const rejectAll = () => updateConsent(consentPresets.eeaDefault);
|
|
271
|
+
|
|
272
|
+
// Analytics only (mixed consent)
|
|
273
|
+
const analyticsOnly = () => updateConsent(consentPresets.analyticsOnly);
|
|
274
|
+
|
|
275
|
+
// Granular: custom selection
|
|
276
|
+
const customChoice = () =>
|
|
277
|
+
updateConsent({
|
|
278
|
+
analytics_storage: 'granted',
|
|
279
|
+
ad_storage: 'denied',
|
|
280
|
+
ad_user_data: 'denied',
|
|
281
|
+
ad_personalization: 'denied'
|
|
282
|
+
});
|
|
283
|
+
</script>
|
|
284
|
+
|
|
285
|
+
<template>
|
|
286
|
+
<div class="cookie-banner">
|
|
287
|
+
<p>We use cookies to improve your experience.</p>
|
|
288
|
+
<button @click="acceptAll">Accept All</button>
|
|
289
|
+
<button @click="rejectAll">Reject All</button>
|
|
290
|
+
<button @click="analyticsOnly">Analytics Only</button>
|
|
291
|
+
</div>
|
|
292
|
+
</template>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Partial Updates** - Only update changed categories:
|
|
296
|
+
|
|
297
|
+
```vue
|
|
298
|
+
<script setup>
|
|
299
|
+
import { useGtmConsent } from '@react-gtm-kit/vue';
|
|
300
|
+
|
|
301
|
+
const { updateConsent } = useGtmConsent();
|
|
302
|
+
|
|
303
|
+
// User later opts into ads from preference center
|
|
304
|
+
const enableAds = () =>
|
|
305
|
+
updateConsent({
|
|
306
|
+
ad_storage: 'granted',
|
|
307
|
+
ad_user_data: 'granted'
|
|
308
|
+
});
|
|
309
|
+
// Other categories (analytics_storage, ad_personalization) remain unchanged
|
|
310
|
+
</script>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Nuxt 3
|
|
316
|
+
|
|
317
|
+
For Nuxt 3 projects, use [`@react-gtm-kit/nuxt`](https://www.npmjs.com/package/@react-gtm-kit/nuxt) which provides:
|
|
318
|
+
|
|
319
|
+
- Native Nuxt module integration
|
|
320
|
+
- Auto-import of composables
|
|
321
|
+
- Automatic page tracking
|
|
322
|
+
- SSR support out of the box
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Requirements
|
|
327
|
+
|
|
328
|
+
- Vue 3.3+
|
|
329
|
+
- `@react-gtm-kit/core` (peer dependency)
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## License
|
|
334
|
+
|
|
335
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vue = require('vue');
|
|
4
|
+
var gtmKit = require('@jwiedeman/gtm-kit');
|
|
5
|
+
|
|
6
|
+
var a=Symbol("gtm-kit"),c={install(t,s){let{autoInit:u=!0,onBeforeInit:p,...m}=s,e=gtmKit.createGtmClient(m),r={client:e,push:n=>e.push(n),setConsentDefaults:(n,i)=>e.setConsentDefaults(n,i),updateConsent:(n,i)=>e.updateConsent(n,i),whenReady:()=>e.whenReady(),onReady:n=>e.onReady(n)};t.provide(a,r),t.config.globalProperties.$gtm=r,p&&p(e),u&&e.init(),t.mixin({unmounted(){}});}},o=()=>{let t=vue.inject(a);if(!t)throw new Error('[gtm-kit] useGtm() was called outside of a Vue app with GtmPlugin installed. Make sure to call app.use(GtmPlugin, { containers: "GTM-XXXXXX" }) before using GTM composables.');return t},G=()=>o(),d=()=>o().push,y=()=>{let{setConsentDefaults:t,updateConsent:s}=o();return {setConsentDefaults:t,updateConsent:s}},x=()=>o().client,g=()=>o().whenReady;
|
|
7
|
+
|
|
8
|
+
exports.GTM_INJECTION_KEY = a;
|
|
9
|
+
exports.GtmPlugin = c;
|
|
10
|
+
exports.useGtm = G;
|
|
11
|
+
exports.useGtmClient = x;
|
|
12
|
+
exports.useGtmConsent = y;
|
|
13
|
+
exports.useGtmPush = d;
|
|
14
|
+
exports.useGtmReady = g;
|
|
15
|
+
//# sourceMappingURL=out.js.map
|
|
16
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"names":["inject","createGtmClient","GTM_INJECTION_KEY","GtmPlugin","app","options","autoInit","onBeforeInit","clientOptions","client","context","value","state","regionOptions","callback","useGtmContext","useGtm","useGtmPush","useGtmConsent","setConsentDefaults","updateConsent","useGtmClient","useGtmReady"],"mappings":"AAAA,OAAS,UAAAA,MAA2C,MACpD,OACE,mBAAAC,MAOK,qBAkDA,IAAMC,EAA8C,OAAO,SAAS,EAe9DC,EAAY,CACvB,QAAQC,EAAUC,EAAiC,CACjD,GAAM,CAAE,SAAAC,EAAW,GAAM,aAAAC,EAAc,GAAGC,CAAc,EAAIH,EAEtDI,EAASR,EAAgBO,CAAa,EAEtCE,EAAsB,CAC1B,OAAAD,EACA,KAAOE,GAA0BF,EAAO,KAAKE,CAAK,EAClD,mBAAoB,CAACC,EAAqBC,IACxCJ,EAAO,mBAAmBG,EAAOC,CAAa,EAChD,cAAe,CAACD,EAAqBC,IACnCJ,EAAO,cAAcG,EAAOC,CAAa,EAC3C,UAAW,IAAMJ,EAAO,UAAU,EAClC,QAAUK,GAAiDL,EAAO,QAAQK,CAAQ,CACpF,EAGAV,EAAI,QAAQF,EAAmBQ,CAAO,EAGtCN,EAAI,OAAO,iBAAiB,KAAOM,EAG/BH,GACFA,EAAaE,CAAM,EAIjBH,GACFG,EAAO,KAAK,EAIdL,EAAI,MAAM,CACR,WAAY,CAGZ,CACF,CAAC,CACH,CACF,EAKMW,EAAgB,IAAkB,CACtC,IAAML,EAAUV,EAAOE,CAAiB,EACxC,GAAI,CAACQ,EACH,MAAM,IAAI,MACR,+KAEF,EAEF,OAAOA,CACT,EAkBaM,EAAS,IACbD,EAAc,EAoBVE,EAAa,IACjBF,EAAc,EAAE,KAwBZG,EAAgB,IAAqB,CAChD,GAAM,CAAE,mBAAAC,EAAoB,cAAAC,CAAc,EAAIL,EAAc,EAC5D,MAAO,CAAE,mBAAAI,EAAoB,cAAAC,CAAc,CAC7C,EAoBaC,EAAe,IACnBN,EAAc,EAAE,OAsBZO,EAAc,IAClBP,EAAc,EAAE","sourcesContent":["import { inject, type App, type InjectionKey } from 'vue';\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 * Options for the GTM Vue plugin.\n * Extends CreateGtmClientOptions with Vue-specific options.\n */\nexport interface GtmPluginOptions extends CreateGtmClientOptions {\n /**\n * Whether to automatically initialize GTM when the plugin is installed.\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/**\n * The GTM context value provided to components via inject().\n */\nexport interface GtmContext {\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}\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 * Injection key for the GTM context.\n * Use this with inject() to access the GTM context directly.\n */\nexport const GTM_INJECTION_KEY: InjectionKey<GtmContext> = Symbol('gtm-kit');\n\n/**\n * Vue 3 plugin for GTM Kit.\n *\n * @example\n * ```ts\n * import { createApp } from 'vue';\n * import { GtmPlugin } from '@jwiedeman/gtm-kit-vue';\n *\n * createApp(App)\n * .use(GtmPlugin, { containers: 'GTM-XXXXXX' })\n * .mount('#app');\n * ```\n */\nexport const GtmPlugin = {\n install(app: App, options: GtmPluginOptions): void {\n const { autoInit = true, onBeforeInit, ...clientOptions } = options;\n\n const client = createGtmClient(clientOptions);\n\n const context: GtmContext = {\n client,\n push: (value: DataLayerValue) => client.push(value),\n setConsentDefaults: (state: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.setConsentDefaults(state, regionOptions),\n updateConsent: (state: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.updateConsent(state, regionOptions),\n whenReady: () => client.whenReady(),\n onReady: (callback: (state: ScriptLoadState[]) => void) => client.onReady(callback)\n };\n\n // Provide the context to all components\n app.provide(GTM_INJECTION_KEY, context);\n\n // Also make it available as a global property for Options API users\n app.config.globalProperties.$gtm = context;\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 }\n\n // Register cleanup on app unmount\n app.mixin({\n unmounted() {\n // Note: This runs for each component, but teardown is idempotent\n // The actual teardown should only happen when the app is fully unmounted\n }\n });\n }\n};\n\n/**\n * Internal helper to get the GTM context with proper error handling.\n */\nconst useGtmContext = (): GtmContext => {\n const context = inject(GTM_INJECTION_KEY);\n if (!context) {\n throw new Error(\n '[gtm-kit] useGtm() was called outside of a Vue app with GtmPlugin installed. ' +\n 'Make sure to call app.use(GtmPlugin, { containers: \"GTM-XXXXXX\" }) before using GTM composables.'\n );\n }\n return context;\n};\n\n/**\n * Composable to access the full GTM context.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtm } from '@jwiedeman/gtm-kit-vue';\n *\n * const { push, client, whenReady } = useGtm();\n *\n * function trackClick() {\n * push({ event: 'button_click', button_name: 'hero_cta' });\n * }\n * </script>\n * ```\n */\nexport const useGtm = (): GtmContext => {\n return useGtmContext();\n};\n\n/**\n * Composable to get just the push function.\n * Use this when you only need to push events.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmPush } from '@jwiedeman/gtm-kit-vue';\n *\n * const push = useGtmPush();\n *\n * function handlePurchase() {\n * push({ event: 'purchase', value: 99.99 });\n * }\n * </script>\n * ```\n */\nexport const useGtmPush = (): ((value: DataLayerValue) => void) => {\n return useGtmContext().push;\n};\n\n/**\n * Composable to access consent management functions.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmConsent } from '@jwiedeman/gtm-kit-vue';\n *\n * const { updateConsent } = useGtmConsent();\n *\n * function acceptAll() {\n * updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted',\n * ad_user_data: 'granted',\n * ad_personalization: 'granted'\n * });\n * }\n * </script>\n * ```\n */\nexport const useGtmConsent = (): GtmConsentApi => {\n const { setConsentDefaults, updateConsent } = useGtmContext();\n return { setConsentDefaults, updateConsent };\n};\n\n/**\n * Composable to get the raw GTM client instance.\n * Use this when you need direct access to the client.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmClient } from '@jwiedeman/gtm-kit-vue';\n *\n * const client = useGtmClient();\n *\n * // Check if client is initialized\n * if (client.isInitialized()) {\n * console.log('GTM is ready');\n * }\n * </script>\n * ```\n */\nexport const useGtmClient = (): GtmClient => {\n return useGtmContext().client;\n};\n\n/**\n * Composable to get the whenReady function.\n * Use this to wait for GTM scripts to load.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmReady } from '@jwiedeman/gtm-kit-vue';\n * import { onMounted } from 'vue';\n *\n * const whenReady = useGtmReady();\n *\n * onMounted(async () => {\n * const states = await whenReady();\n * console.log('GTM scripts loaded:', states);\n * });\n * </script>\n * ```\n */\nexport const useGtmReady = (): (() => Promise<ScriptLoadState[]>) => {\n return useGtmContext().whenReady;\n};\n\n// Extend Vue's ComponentCustomProperties for Options API users\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $gtm: GtmContext;\n }\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { InjectionKey, App } from 'vue';
|
|
2
|
+
import { CreateGtmClientOptions, GtmClient, DataLayerValue, ConsentState, ConsentRegionOptions, ScriptLoadState } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for the GTM Vue plugin.
|
|
6
|
+
* Extends CreateGtmClientOptions with Vue-specific options.
|
|
7
|
+
*/
|
|
8
|
+
interface GtmPluginOptions extends CreateGtmClientOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Whether to automatically initialize GTM when the plugin is installed.
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
autoInit?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Callback executed before GTM initialization.
|
|
16
|
+
* Use this to set consent defaults.
|
|
17
|
+
*/
|
|
18
|
+
onBeforeInit?: (client: GtmClient) => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The GTM context value provided to components via inject().
|
|
22
|
+
*/
|
|
23
|
+
interface GtmContext {
|
|
24
|
+
/** The underlying GTM client instance */
|
|
25
|
+
client: GtmClient;
|
|
26
|
+
/** Push a value to the data layer */
|
|
27
|
+
push: (value: DataLayerValue) => void;
|
|
28
|
+
/** Set consent defaults (must be called before init) */
|
|
29
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
30
|
+
/** Update consent state */
|
|
31
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
32
|
+
/** Returns a promise that resolves when all GTM scripts are loaded */
|
|
33
|
+
whenReady: () => Promise<ScriptLoadState[]>;
|
|
34
|
+
/** Register a callback for when GTM scripts are ready */
|
|
35
|
+
onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Consent-specific API subset.
|
|
39
|
+
*/
|
|
40
|
+
interface GtmConsentApi {
|
|
41
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
42
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Injection key for the GTM context.
|
|
46
|
+
* Use this with inject() to access the GTM context directly.
|
|
47
|
+
*/
|
|
48
|
+
declare const GTM_INJECTION_KEY: InjectionKey<GtmContext>;
|
|
49
|
+
/**
|
|
50
|
+
* Vue 3 plugin for GTM Kit.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { createApp } from 'vue';
|
|
55
|
+
* import { GtmPlugin } from '@jwiedeman/gtm-kit-vue';
|
|
56
|
+
*
|
|
57
|
+
* createApp(App)
|
|
58
|
+
* .use(GtmPlugin, { containers: 'GTM-XXXXXX' })
|
|
59
|
+
* .mount('#app');
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare const GtmPlugin: {
|
|
63
|
+
install(app: App, options: GtmPluginOptions): void;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Composable to access the full GTM context.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```vue
|
|
70
|
+
* <script setup>
|
|
71
|
+
* import { useGtm } from '@jwiedeman/gtm-kit-vue';
|
|
72
|
+
*
|
|
73
|
+
* const { push, client, whenReady } = useGtm();
|
|
74
|
+
*
|
|
75
|
+
* function trackClick() {
|
|
76
|
+
* push({ event: 'button_click', button_name: 'hero_cta' });
|
|
77
|
+
* }
|
|
78
|
+
* </script>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare const useGtm: () => GtmContext;
|
|
82
|
+
/**
|
|
83
|
+
* Composable to get just the push function.
|
|
84
|
+
* Use this when you only need to push events.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```vue
|
|
88
|
+
* <script setup>
|
|
89
|
+
* import { useGtmPush } from '@jwiedeman/gtm-kit-vue';
|
|
90
|
+
*
|
|
91
|
+
* const push = useGtmPush();
|
|
92
|
+
*
|
|
93
|
+
* function handlePurchase() {
|
|
94
|
+
* push({ event: 'purchase', value: 99.99 });
|
|
95
|
+
* }
|
|
96
|
+
* </script>
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare const useGtmPush: () => ((value: DataLayerValue) => void);
|
|
100
|
+
/**
|
|
101
|
+
* Composable to access consent management functions.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```vue
|
|
105
|
+
* <script setup>
|
|
106
|
+
* import { useGtmConsent } from '@jwiedeman/gtm-kit-vue';
|
|
107
|
+
*
|
|
108
|
+
* const { updateConsent } = useGtmConsent();
|
|
109
|
+
*
|
|
110
|
+
* function acceptAll() {
|
|
111
|
+
* updateConsent({
|
|
112
|
+
* ad_storage: 'granted',
|
|
113
|
+
* analytics_storage: 'granted',
|
|
114
|
+
* ad_user_data: 'granted',
|
|
115
|
+
* ad_personalization: 'granted'
|
|
116
|
+
* });
|
|
117
|
+
* }
|
|
118
|
+
* </script>
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare const useGtmConsent: () => GtmConsentApi;
|
|
122
|
+
/**
|
|
123
|
+
* Composable to get the raw GTM client instance.
|
|
124
|
+
* Use this when you need direct access to the client.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```vue
|
|
128
|
+
* <script setup>
|
|
129
|
+
* import { useGtmClient } from '@jwiedeman/gtm-kit-vue';
|
|
130
|
+
*
|
|
131
|
+
* const client = useGtmClient();
|
|
132
|
+
*
|
|
133
|
+
* // Check if client is initialized
|
|
134
|
+
* if (client.isInitialized()) {
|
|
135
|
+
* console.log('GTM is ready');
|
|
136
|
+
* }
|
|
137
|
+
* </script>
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare const useGtmClient: () => GtmClient;
|
|
141
|
+
/**
|
|
142
|
+
* Composable to get the whenReady function.
|
|
143
|
+
* Use this to wait for GTM scripts to load.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```vue
|
|
147
|
+
* <script setup>
|
|
148
|
+
* import { useGtmReady } from '@jwiedeman/gtm-kit-vue';
|
|
149
|
+
* import { onMounted } from 'vue';
|
|
150
|
+
*
|
|
151
|
+
* const whenReady = useGtmReady();
|
|
152
|
+
*
|
|
153
|
+
* onMounted(async () => {
|
|
154
|
+
* const states = await whenReady();
|
|
155
|
+
* console.log('GTM scripts loaded:', states);
|
|
156
|
+
* });
|
|
157
|
+
* </script>
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
declare const useGtmReady: () => (() => Promise<ScriptLoadState[]>);
|
|
161
|
+
declare module 'vue' {
|
|
162
|
+
interface ComponentCustomProperties {
|
|
163
|
+
$gtm: GtmContext;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export { GTM_INJECTION_KEY, GtmConsentApi, GtmContext, GtmPlugin, GtmPluginOptions, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { InjectionKey, App } from 'vue';
|
|
2
|
+
import { CreateGtmClientOptions, GtmClient, DataLayerValue, ConsentState, ConsentRegionOptions, ScriptLoadState } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for the GTM Vue plugin.
|
|
6
|
+
* Extends CreateGtmClientOptions with Vue-specific options.
|
|
7
|
+
*/
|
|
8
|
+
interface GtmPluginOptions extends CreateGtmClientOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Whether to automatically initialize GTM when the plugin is installed.
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
autoInit?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Callback executed before GTM initialization.
|
|
16
|
+
* Use this to set consent defaults.
|
|
17
|
+
*/
|
|
18
|
+
onBeforeInit?: (client: GtmClient) => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The GTM context value provided to components via inject().
|
|
22
|
+
*/
|
|
23
|
+
interface GtmContext {
|
|
24
|
+
/** The underlying GTM client instance */
|
|
25
|
+
client: GtmClient;
|
|
26
|
+
/** Push a value to the data layer */
|
|
27
|
+
push: (value: DataLayerValue) => void;
|
|
28
|
+
/** Set consent defaults (must be called before init) */
|
|
29
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
30
|
+
/** Update consent state */
|
|
31
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
32
|
+
/** Returns a promise that resolves when all GTM scripts are loaded */
|
|
33
|
+
whenReady: () => Promise<ScriptLoadState[]>;
|
|
34
|
+
/** Register a callback for when GTM scripts are ready */
|
|
35
|
+
onReady: (callback: (state: ScriptLoadState[]) => void) => () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Consent-specific API subset.
|
|
39
|
+
*/
|
|
40
|
+
interface GtmConsentApi {
|
|
41
|
+
setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
42
|
+
updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Injection key for the GTM context.
|
|
46
|
+
* Use this with inject() to access the GTM context directly.
|
|
47
|
+
*/
|
|
48
|
+
declare const GTM_INJECTION_KEY: InjectionKey<GtmContext>;
|
|
49
|
+
/**
|
|
50
|
+
* Vue 3 plugin for GTM Kit.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { createApp } from 'vue';
|
|
55
|
+
* import { GtmPlugin } from '@jwiedeman/gtm-kit-vue';
|
|
56
|
+
*
|
|
57
|
+
* createApp(App)
|
|
58
|
+
* .use(GtmPlugin, { containers: 'GTM-XXXXXX' })
|
|
59
|
+
* .mount('#app');
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare const GtmPlugin: {
|
|
63
|
+
install(app: App, options: GtmPluginOptions): void;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Composable to access the full GTM context.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```vue
|
|
70
|
+
* <script setup>
|
|
71
|
+
* import { useGtm } from '@jwiedeman/gtm-kit-vue';
|
|
72
|
+
*
|
|
73
|
+
* const { push, client, whenReady } = useGtm();
|
|
74
|
+
*
|
|
75
|
+
* function trackClick() {
|
|
76
|
+
* push({ event: 'button_click', button_name: 'hero_cta' });
|
|
77
|
+
* }
|
|
78
|
+
* </script>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare const useGtm: () => GtmContext;
|
|
82
|
+
/**
|
|
83
|
+
* Composable to get just the push function.
|
|
84
|
+
* Use this when you only need to push events.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```vue
|
|
88
|
+
* <script setup>
|
|
89
|
+
* import { useGtmPush } from '@jwiedeman/gtm-kit-vue';
|
|
90
|
+
*
|
|
91
|
+
* const push = useGtmPush();
|
|
92
|
+
*
|
|
93
|
+
* function handlePurchase() {
|
|
94
|
+
* push({ event: 'purchase', value: 99.99 });
|
|
95
|
+
* }
|
|
96
|
+
* </script>
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare const useGtmPush: () => ((value: DataLayerValue) => void);
|
|
100
|
+
/**
|
|
101
|
+
* Composable to access consent management functions.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```vue
|
|
105
|
+
* <script setup>
|
|
106
|
+
* import { useGtmConsent } from '@jwiedeman/gtm-kit-vue';
|
|
107
|
+
*
|
|
108
|
+
* const { updateConsent } = useGtmConsent();
|
|
109
|
+
*
|
|
110
|
+
* function acceptAll() {
|
|
111
|
+
* updateConsent({
|
|
112
|
+
* ad_storage: 'granted',
|
|
113
|
+
* analytics_storage: 'granted',
|
|
114
|
+
* ad_user_data: 'granted',
|
|
115
|
+
* ad_personalization: 'granted'
|
|
116
|
+
* });
|
|
117
|
+
* }
|
|
118
|
+
* </script>
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare const useGtmConsent: () => GtmConsentApi;
|
|
122
|
+
/**
|
|
123
|
+
* Composable to get the raw GTM client instance.
|
|
124
|
+
* Use this when you need direct access to the client.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```vue
|
|
128
|
+
* <script setup>
|
|
129
|
+
* import { useGtmClient } from '@jwiedeman/gtm-kit-vue';
|
|
130
|
+
*
|
|
131
|
+
* const client = useGtmClient();
|
|
132
|
+
*
|
|
133
|
+
* // Check if client is initialized
|
|
134
|
+
* if (client.isInitialized()) {
|
|
135
|
+
* console.log('GTM is ready');
|
|
136
|
+
* }
|
|
137
|
+
* </script>
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare const useGtmClient: () => GtmClient;
|
|
141
|
+
/**
|
|
142
|
+
* Composable to get the whenReady function.
|
|
143
|
+
* Use this to wait for GTM scripts to load.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```vue
|
|
147
|
+
* <script setup>
|
|
148
|
+
* import { useGtmReady } from '@jwiedeman/gtm-kit-vue';
|
|
149
|
+
* import { onMounted } from 'vue';
|
|
150
|
+
*
|
|
151
|
+
* const whenReady = useGtmReady();
|
|
152
|
+
*
|
|
153
|
+
* onMounted(async () => {
|
|
154
|
+
* const states = await whenReady();
|
|
155
|
+
* console.log('GTM scripts loaded:', states);
|
|
156
|
+
* });
|
|
157
|
+
* </script>
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
declare const useGtmReady: () => (() => Promise<ScriptLoadState[]>);
|
|
161
|
+
declare module 'vue' {
|
|
162
|
+
interface ComponentCustomProperties {
|
|
163
|
+
$gtm: GtmContext;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export { GTM_INJECTION_KEY, GtmConsentApi, GtmContext, GtmPlugin, GtmPluginOptions, useGtm, useGtmClient, useGtmConsent, useGtmPush, useGtmReady };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { inject } from 'vue';
|
|
2
|
+
import { createGtmClient } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
var a=Symbol("gtm-kit"),c={install(t,s){let{autoInit:u=!0,onBeforeInit:p,...m}=s,e=createGtmClient(m),r={client:e,push:n=>e.push(n),setConsentDefaults:(n,i)=>e.setConsentDefaults(n,i),updateConsent:(n,i)=>e.updateConsent(n,i),whenReady:()=>e.whenReady(),onReady:n=>e.onReady(n)};t.provide(a,r),t.config.globalProperties.$gtm=r,p&&p(e),u&&e.init(),t.mixin({unmounted(){}});}},o=()=>{let t=inject(a);if(!t)throw new Error('[gtm-kit] useGtm() was called outside of a Vue app with GtmPlugin installed. Make sure to call app.use(GtmPlugin, { containers: "GTM-XXXXXX" }) before using GTM composables.');return t},G=()=>o(),d=()=>o().push,y=()=>{let{setConsentDefaults:t,updateConsent:s}=o();return {setConsentDefaults:t,updateConsent:s}},x=()=>o().client,g=()=>o().whenReady;
|
|
5
|
+
|
|
6
|
+
export { a as GTM_INJECTION_KEY, c as GtmPlugin, G as useGtm, x as useGtmClient, y as useGtmConsent, d as useGtmPush, g as useGtmReady };
|
|
7
|
+
//# sourceMappingURL=out.js.map
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"names":["inject","createGtmClient","GTM_INJECTION_KEY","GtmPlugin","app","options","autoInit","onBeforeInit","clientOptions","client","context","value","state","regionOptions","callback","useGtmContext","useGtm","useGtmPush","useGtmConsent","setConsentDefaults","updateConsent","useGtmClient","useGtmReady"],"mappings":"AAAA,OAAS,UAAAA,MAA2C,MACpD,OACE,mBAAAC,MAOK,qBAkDA,IAAMC,EAA8C,OAAO,SAAS,EAe9DC,EAAY,CACvB,QAAQC,EAAUC,EAAiC,CACjD,GAAM,CAAE,SAAAC,EAAW,GAAM,aAAAC,EAAc,GAAGC,CAAc,EAAIH,EAEtDI,EAASR,EAAgBO,CAAa,EAEtCE,EAAsB,CAC1B,OAAAD,EACA,KAAOE,GAA0BF,EAAO,KAAKE,CAAK,EAClD,mBAAoB,CAACC,EAAqBC,IACxCJ,EAAO,mBAAmBG,EAAOC,CAAa,EAChD,cAAe,CAACD,EAAqBC,IACnCJ,EAAO,cAAcG,EAAOC,CAAa,EAC3C,UAAW,IAAMJ,EAAO,UAAU,EAClC,QAAUK,GAAiDL,EAAO,QAAQK,CAAQ,CACpF,EAGAV,EAAI,QAAQF,EAAmBQ,CAAO,EAGtCN,EAAI,OAAO,iBAAiB,KAAOM,EAG/BH,GACFA,EAAaE,CAAM,EAIjBH,GACFG,EAAO,KAAK,EAIdL,EAAI,MAAM,CACR,WAAY,CAGZ,CACF,CAAC,CACH,CACF,EAKMW,EAAgB,IAAkB,CACtC,IAAML,EAAUV,EAAOE,CAAiB,EACxC,GAAI,CAACQ,EACH,MAAM,IAAI,MACR,+KAEF,EAEF,OAAOA,CACT,EAkBaM,EAAS,IACbD,EAAc,EAoBVE,EAAa,IACjBF,EAAc,EAAE,KAwBZG,EAAgB,IAAqB,CAChD,GAAM,CAAE,mBAAAC,EAAoB,cAAAC,CAAc,EAAIL,EAAc,EAC5D,MAAO,CAAE,mBAAAI,EAAoB,cAAAC,CAAc,CAC7C,EAoBaC,EAAe,IACnBN,EAAc,EAAE,OAsBZO,EAAc,IAClBP,EAAc,EAAE","sourcesContent":["import { inject, type App, type InjectionKey } from 'vue';\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 * Options for the GTM Vue plugin.\n * Extends CreateGtmClientOptions with Vue-specific options.\n */\nexport interface GtmPluginOptions extends CreateGtmClientOptions {\n /**\n * Whether to automatically initialize GTM when the plugin is installed.\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/**\n * The GTM context value provided to components via inject().\n */\nexport interface GtmContext {\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}\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 * Injection key for the GTM context.\n * Use this with inject() to access the GTM context directly.\n */\nexport const GTM_INJECTION_KEY: InjectionKey<GtmContext> = Symbol('gtm-kit');\n\n/**\n * Vue 3 plugin for GTM Kit.\n *\n * @example\n * ```ts\n * import { createApp } from 'vue';\n * import { GtmPlugin } from '@jwiedeman/gtm-kit-vue';\n *\n * createApp(App)\n * .use(GtmPlugin, { containers: 'GTM-XXXXXX' })\n * .mount('#app');\n * ```\n */\nexport const GtmPlugin = {\n install(app: App, options: GtmPluginOptions): void {\n const { autoInit = true, onBeforeInit, ...clientOptions } = options;\n\n const client = createGtmClient(clientOptions);\n\n const context: GtmContext = {\n client,\n push: (value: DataLayerValue) => client.push(value),\n setConsentDefaults: (state: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.setConsentDefaults(state, regionOptions),\n updateConsent: (state: ConsentState, regionOptions?: ConsentRegionOptions) =>\n client.updateConsent(state, regionOptions),\n whenReady: () => client.whenReady(),\n onReady: (callback: (state: ScriptLoadState[]) => void) => client.onReady(callback)\n };\n\n // Provide the context to all components\n app.provide(GTM_INJECTION_KEY, context);\n\n // Also make it available as a global property for Options API users\n app.config.globalProperties.$gtm = context;\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 }\n\n // Register cleanup on app unmount\n app.mixin({\n unmounted() {\n // Note: This runs for each component, but teardown is idempotent\n // The actual teardown should only happen when the app is fully unmounted\n }\n });\n }\n};\n\n/**\n * Internal helper to get the GTM context with proper error handling.\n */\nconst useGtmContext = (): GtmContext => {\n const context = inject(GTM_INJECTION_KEY);\n if (!context) {\n throw new Error(\n '[gtm-kit] useGtm() was called outside of a Vue app with GtmPlugin installed. ' +\n 'Make sure to call app.use(GtmPlugin, { containers: \"GTM-XXXXXX\" }) before using GTM composables.'\n );\n }\n return context;\n};\n\n/**\n * Composable to access the full GTM context.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtm } from '@jwiedeman/gtm-kit-vue';\n *\n * const { push, client, whenReady } = useGtm();\n *\n * function trackClick() {\n * push({ event: 'button_click', button_name: 'hero_cta' });\n * }\n * </script>\n * ```\n */\nexport const useGtm = (): GtmContext => {\n return useGtmContext();\n};\n\n/**\n * Composable to get just the push function.\n * Use this when you only need to push events.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmPush } from '@jwiedeman/gtm-kit-vue';\n *\n * const push = useGtmPush();\n *\n * function handlePurchase() {\n * push({ event: 'purchase', value: 99.99 });\n * }\n * </script>\n * ```\n */\nexport const useGtmPush = (): ((value: DataLayerValue) => void) => {\n return useGtmContext().push;\n};\n\n/**\n * Composable to access consent management functions.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmConsent } from '@jwiedeman/gtm-kit-vue';\n *\n * const { updateConsent } = useGtmConsent();\n *\n * function acceptAll() {\n * updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted',\n * ad_user_data: 'granted',\n * ad_personalization: 'granted'\n * });\n * }\n * </script>\n * ```\n */\nexport const useGtmConsent = (): GtmConsentApi => {\n const { setConsentDefaults, updateConsent } = useGtmContext();\n return { setConsentDefaults, updateConsent };\n};\n\n/**\n * Composable to get the raw GTM client instance.\n * Use this when you need direct access to the client.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmClient } from '@jwiedeman/gtm-kit-vue';\n *\n * const client = useGtmClient();\n *\n * // Check if client is initialized\n * if (client.isInitialized()) {\n * console.log('GTM is ready');\n * }\n * </script>\n * ```\n */\nexport const useGtmClient = (): GtmClient => {\n return useGtmContext().client;\n};\n\n/**\n * Composable to get the whenReady function.\n * Use this to wait for GTM scripts to load.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useGtmReady } from '@jwiedeman/gtm-kit-vue';\n * import { onMounted } from 'vue';\n *\n * const whenReady = useGtmReady();\n *\n * onMounted(async () => {\n * const states = await whenReady();\n * console.log('GTM scripts loaded:', states);\n * });\n * </script>\n * ```\n */\nexport const useGtmReady = (): (() => Promise<ScriptLoadState[]>) => {\n return useGtmContext().whenReady;\n};\n\n// Extend Vue's ComponentCustomProperties for Options API users\ndeclare module 'vue' {\n interface ComponentCustomProperties {\n $gtm: GtmContext;\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jwiedeman/gtm-kit-vue",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Vue 3 composables and plugin for GTM Kit - Google Tag Manager integration.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/jwiedeman/GTM-Kit.git",
|
|
8
|
+
"directory": "packages/vue"
|
|
9
|
+
},
|
|
10
|
+
"author": "jwiedeman",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"gtm",
|
|
13
|
+
"google-tag-manager",
|
|
14
|
+
"vue",
|
|
15
|
+
"vue3",
|
|
16
|
+
"composables"
|
|
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
|
+
"import": "./dist/index.js",
|
|
30
|
+
"require": "./dist/index.cjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"clean": "rm -rf dist",
|
|
39
|
+
"lint": "eslint --max-warnings=0 \"src/**/*.{ts,tsx}\"",
|
|
40
|
+
"test": "jest --config ./jest.config.cjs --runInBand",
|
|
41
|
+
"typecheck": "tsc --noEmit"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@jwiedeman/gtm-kit": "^1.0.1"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"vue": "^3.3.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@vue/test-utils": "^2.4.6",
|
|
51
|
+
"@vue/vue3-jest": "^29.2.6",
|
|
52
|
+
"vue": "^3.4.21",
|
|
53
|
+
"tslib": "^2.6.2"
|
|
54
|
+
}
|
|
55
|
+
}
|