@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 ADDED
@@ -0,0 +1,335 @@
1
+ # @react-gtm-kit/vue
2
+
3
+ [![CI](https://github.com/jwiedeman/react-gtm-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/jwiedeman/react-gtm-kit/actions/workflows/ci.yml)
4
+ [![Coverage](https://codecov.io/gh/jwiedeman/react-gtm-kit/graph/badge.svg?flag=vue)](https://codecov.io/gh/jwiedeman/react-gtm-kit)
5
+ [![npm version](https://img.shields.io/npm/v/@react-gtm-kit/vue.svg)](https://www.npmjs.com/package/@react-gtm-kit/vue)
6
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@react-gtm-kit/vue)](https://bundlephobia.com/package/@react-gtm-kit/vue)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+ [![Vue 3](https://img.shields.io/badge/Vue-3.3+-4FC08D.svg?logo=vue.js)](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"]}
@@ -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 };
@@ -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
+ }