@jwiedeman/gtm-kit-next 1.1.1 → 1.1.3

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 CHANGED
@@ -1,9 +1,9 @@
1
- # @react-gtm-kit/next
1
+ # @jwiedeman/gtm-kit-next
2
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=next)](https://codecov.io/gh/jwiedeman/react-gtm-kit)
5
- [![npm version](https://img.shields.io/npm/v/@react-gtm-kit/next.svg)](https://www.npmjs.com/package/@react-gtm-kit/next)
6
- [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@react-gtm-kit/next)](https://bundlephobia.com/package/@react-gtm-kit/next)
3
+ [![CI](https://github.com/jwiedeman/GTM-Kit/actions/workflows/ci.yml/badge.svg)](https://github.com/jwiedeman/GTM-Kit/actions/workflows/ci.yml)
4
+ [![Coverage](https://codecov.io/gh/jwiedeman/GTM-Kit/graph/badge.svg?flag=next)](https://codecov.io/gh/jwiedeman/GTM-Kit)
5
+ [![npm version](https://img.shields.io/npm/v/@jwiedeman/gtm-kit-next.svg)](https://www.npmjs.com/package/@jwiedeman/gtm-kit-next)
6
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@jwiedeman/gtm-kit-next)](https://bundlephobia.com/package/@jwiedeman/gtm-kit-next)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
  [![Next.js](https://img.shields.io/badge/Next.js-13+-000000.svg?logo=next.js)](https://nextjs.org/)
@@ -17,15 +17,15 @@ The Next.js adapter for GTM Kit - provides server components and route tracking
17
17
  ## Installation
18
18
 
19
19
  ```bash
20
- npm install @react-gtm-kit/core @react-gtm-kit/next
20
+ npm install @jwiedeman/gtm-kit @jwiedeman/gtm-kit-next
21
21
  ```
22
22
 
23
23
  ```bash
24
- yarn add @react-gtm-kit/core @react-gtm-kit/next
24
+ yarn add @jwiedeman/gtm-kit @jwiedeman/gtm-kit-next
25
25
  ```
26
26
 
27
27
  ```bash
28
- pnpm add @react-gtm-kit/core @react-gtm-kit/next
28
+ pnpm add @jwiedeman/gtm-kit @jwiedeman/gtm-kit-next
29
29
  ```
30
30
 
31
31
  ---
@@ -36,7 +36,7 @@ pnpm add @react-gtm-kit/core @react-gtm-kit/next
36
36
 
37
37
  ```tsx
38
38
  // app/layout.tsx
39
- import { GtmHeadScript, GtmNoScript } from '@react-gtm-kit/next';
39
+ import { GtmHeadScript, GtmNoScript } from '@jwiedeman/gtm-kit-next';
40
40
 
41
41
  export default function RootLayout({ children }) {
42
42
  return (
@@ -58,8 +58,8 @@ export default function RootLayout({ children }) {
58
58
  ```tsx
59
59
  // app/providers/gtm.tsx
60
60
  'use client';
61
- import { createGtmClient } from '@react-gtm-kit/core';
62
- import { useTrackPageViews } from '@react-gtm-kit/next';
61
+ import { createGtmClient } from '@jwiedeman/gtm-kit';
62
+ import { useTrackPageViews } from '@jwiedeman/gtm-kit-next';
63
63
 
64
64
  const client = createGtmClient({ containers: 'GTM-XXXXXX' });
65
65
  client.init();
@@ -74,7 +74,7 @@ export function GtmProvider({ children }) {
74
74
 
75
75
  ```tsx
76
76
  'use client';
77
- import { pushEvent } from '@react-gtm-kit/core';
77
+ import { pushEvent } from '@jwiedeman/gtm-kit';
78
78
 
79
79
  // In any client component
80
80
  function BuyButton({ client }) {
@@ -104,7 +104,7 @@ function BuyButton({ client }) {
104
104
  Renders the GTM script tag. Place in your `<head>`.
105
105
 
106
106
  ```tsx
107
- import { GtmHeadScript } from '@react-gtm-kit/next';
107
+ import { GtmHeadScript } from '@jwiedeman/gtm-kit-next';
108
108
 
109
109
  <GtmHeadScript
110
110
  containers="GTM-XXXXXX"
@@ -117,7 +117,7 @@ import { GtmHeadScript } from '@react-gtm-kit/next';
117
117
  Renders the noscript fallback iframe. Place at the start of `<body>`.
118
118
 
119
119
  ```tsx
120
- import { GtmNoScript } from '@react-gtm-kit/next';
120
+ import { GtmNoScript } from '@jwiedeman/gtm-kit-next';
121
121
 
122
122
  <GtmNoScript containers="GTM-XXXXXX" />;
123
123
  ```
@@ -132,7 +132,7 @@ Automatically tracks page views on route changes.
132
132
 
133
133
  ```tsx
134
134
  'use client';
135
- import { useTrackPageViews } from '@react-gtm-kit/next';
135
+ import { useTrackPageViews } from '@jwiedeman/gtm-kit-next';
136
136
 
137
137
  export function GtmProvider({ children, client }) {
138
138
  useTrackPageViews({ client });
@@ -148,7 +148,7 @@ export function GtmProvider({ children, client }) {
148
148
 
149
149
  ```tsx
150
150
  // app/layout.tsx
151
- import { GtmHeadScript, GtmNoScript } from '@react-gtm-kit/next';
151
+ import { GtmHeadScript, GtmNoScript } from '@jwiedeman/gtm-kit-next';
152
152
  import { GtmProvider } from './providers/gtm';
153
153
 
154
154
  export default function RootLayout({ children }) {
@@ -171,8 +171,8 @@ export default function RootLayout({ children }) {
171
171
  ```tsx
172
172
  // app/providers/gtm.tsx
173
173
  'use client';
174
- import { createGtmClient } from '@react-gtm-kit/core';
175
- import { useTrackPageViews } from '@react-gtm-kit/next';
174
+ import { createGtmClient } from '@jwiedeman/gtm-kit';
175
+ import { useTrackPageViews } from '@jwiedeman/gtm-kit-next';
176
176
  import { createContext, useContext } from 'react';
177
177
 
178
178
  const client = createGtmClient({ containers: 'GTM-XXXXXX' });
@@ -195,7 +195,7 @@ export function useGtmClient() {
195
195
  ```tsx
196
196
  // app/components/BuyButton.tsx
197
197
  'use client';
198
- import { pushEvent } from '@react-gtm-kit/core';
198
+ import { pushEvent } from '@jwiedeman/gtm-kit';
199
199
  import { useGtmClient } from '../providers/gtm';
200
200
 
201
201
  export function BuyButton() {
@@ -212,8 +212,8 @@ export function BuyButton() {
212
212
  ```tsx
213
213
  // app/providers/gtm.tsx
214
214
  'use client';
215
- import { createGtmClient, consentPresets } from '@react-gtm-kit/core';
216
- import { useTrackPageViews } from '@react-gtm-kit/next';
215
+ import { createGtmClient, consentPresets } from '@jwiedeman/gtm-kit';
216
+ import { useTrackPageViews } from '@jwiedeman/gtm-kit-next';
217
217
 
218
218
  const client = createGtmClient({ containers: 'GTM-XXXXXX' });
219
219
 
@@ -234,7 +234,7 @@ export { client };
234
234
  // app/components/CookieBanner.tsx
235
235
  'use client';
236
236
  import { client } from '../providers/gtm';
237
- import { consentPresets } from '@react-gtm-kit/core';
237
+ import { consentPresets } from '@jwiedeman/gtm-kit';
238
238
 
239
239
  export function CookieBanner() {
240
240
  // Accept all tracking
@@ -280,7 +280,7 @@ For strict CSP configurations, pass a nonce:
280
280
  ```tsx
281
281
  // app/layout.tsx
282
282
  import { headers } from 'next/headers';
283
- import { GtmHeadScript, GtmNoScript } from '@react-gtm-kit/next';
283
+ import { GtmHeadScript, GtmNoScript } from '@jwiedeman/gtm-kit-next';
284
284
 
285
285
  export default function RootLayout({ children }) {
286
286
  const nonce = headers().get('x-nonce') || '';
@@ -313,11 +313,11 @@ export default function RootLayout({ children }) {
313
313
 
314
314
  ## Pages Router (Legacy)
315
315
 
316
- For Next.js Pages Router, use `@react-gtm-kit/react-modern` instead:
316
+ For Next.js Pages Router, use `@jwiedeman/gtm-kit-react` instead:
317
317
 
318
318
  ```tsx
319
319
  // pages/_app.tsx
320
- import { GtmProvider } from '@react-gtm-kit/react-modern';
320
+ import { GtmProvider } from '@jwiedeman/gtm-kit-react';
321
321
 
322
322
  export default function App({ Component, pageProps }) {
323
323
  return (
@@ -334,7 +334,7 @@ export default function App({ Component, pageProps }) {
334
334
 
335
335
  - Next.js 13.4+ (App Router)
336
336
  - React 18+
337
- - `@react-gtm-kit/core` (peer dependency)
337
+ - `@jwiedeman/gtm-kit` (peer dependency)
338
338
 
339
339
  ---
340
340
 
package/dist/index.cjs CHANGED
@@ -5,10 +5,10 @@ var navigation = require('next/navigation');
5
5
  var gtmKit = require('@jwiedeman/gtm-kit');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
- var Q="page_view",W=({pagePath:t,url:e,title:n})=>{let r={page_path:t,page_location:e};return n&&(r.page_title=n),r},K=(t,e)=>{var r;let n=typeof window!="undefined"&&((r=window.location)!=null&&r.origin)?window.location.origin:"";return n?`${n}${t}${e}`:`${t}${e}`},J=t=>t&&t.startsWith("#")?t:t?`#${t}`:"",X=({client:t,eventName:e=Q,buildPayload:n=W,includeSearchParams:r=!0,trackHash:i=!1,trackOnMount:l=!0,skipSamePath:o=!0,pushEventFn:f=gtmKit.pushEvent,waitForReady:d=!1,readyPromise:s})=>{if(!t)throw new Error("A GTM client is required to track page views.");let u=navigation.usePathname(),m=navigation.useSearchParams(),p=react.useMemo(()=>!r||!m?"":m.toString(),[r,m]),a=react.useRef(null),h=react.useRef(!1),S=react.useRef(null),k=react.useRef(d?s!=null?s:t.whenReady():null),T=react.useRef(!0);react.useEffect(()=>(T.current=!0,()=>{T.current=!1;}),[]),react.useEffect(()=>{k.current=d?s!=null?s:t.whenReady():null;},[t,s,d]);let D=react.useCallback(g=>{let c=g.filter(w=>w.status==="failed");if(!c.length)return;let v=c.map(w=>w.containerId).join(", ");console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${v}`,c);},[]),E=react.useCallback((g,c,v)=>{if(!g)return;let w=i?J(v):"",C=c?`${g}?${c}`:g,R=`${C}${w}`,G=K(C,w);if(!l&&!h.current){a.current={key:R,pathname:g,search:c,hash:w,pagePath:C,url:G},h.current=!0;return}if(o&&a.current&&a.current.key===R)return;let O=typeof document!="undefined"?document.title:void 0,V=a.current?{pathname:a.current.pathname,search:a.current.search,hash:a.current.hash,pagePath:a.current.pagePath,url:a.current.url}:void 0,F={pathname:g,search:c,hash:w,pagePath:C,url:G,title:O,previous:V},M=()=>{let y=n(F);f(t,e,y),a.current={key:R,pathname:g,search:c,hash:w,pagePath:C,url:G},h.current=!0;};if(d&&k.current){S.current=R,k.current.then(y=>{!T.current||S.current!==R||(D(y),M());}).catch(y=>{!T.current||S.current!==R||(console.error("[react-gtm-kit] Error while waiting for GTM readiness.",y),M());});return}M();},[n,t,e,D,f,o,i,l,d]);react.useEffect(()=>{var c;if(typeof window=="undefined")return;let g=i&&(c=window.location.hash)!=null?c:"";E(u,p,g);},[E,u,p,i]),react.useEffect(()=>{if(!i||typeof window=="undefined")return;let g=()=>{var c;E(u,p,(c=window.location.hash)!=null?c:"");};return window.addEventListener("hashchange",g),()=>{window.removeEventListener("hashchange",g);}},[E,u,p,i]);};var L="https://www.googletagmanager.com",Z=t=>typeof t=="string",I=t=>Z(t)?{id:t}:t,_=t=>Array.isArray(t)?t.map(I):[I(t)],tt=t=>t?Object.entries(t).reduce((e,[n,r])=>(e[n]=String(r),e),{}):{},et=t=>t.endsWith("/")?t.slice(0,-1):t,N=(t,e,n,r,i=gtmKit.DEFAULT_DATA_LAYER_NAME)=>{let l=et(e),o=new URLSearchParams({id:n}),f=tt(r);i!==gtmKit.DEFAULT_DATA_LAYER_NAME&&f.l===void 0&&(f.l=i);for(let[s,u]of Object.entries(f))s!=="id"&&o.set(s,u);return `${l}/${t==="gtm"?"gtm.js":"ns.html"}?${o.toString()}`},$=(t,e,n,r=gtmKit.DEFAULT_DATA_LAYER_NAME)=>N("gtm",t,e,n,r),H=(t,e,n,r=gtmKit.DEFAULT_DATA_LAYER_NAME)=>N("ns",t,e,n,r);var nt=!0,ot=({containers:t,host:e=L,defaultQueryParams:n,scriptAttributes:r,dataLayerName:i=gtmKit.DEFAULT_DATA_LAYER_NAME})=>{let l=_(t);if(!l.length)throw new Error("At least one GTM container is required to render script tags.");return jsxRuntime.jsx(jsxRuntime.Fragment,{children:l.map(o=>{if(!o.id)throw new Error("Container id is required to render GTM script tags.");let f={...n,...o.queryParams},d=$(e,o.id,f,i),{async:s,defer:u,nonce:m,...p}=r!=null?r:{},a={src:d,async:s!=null?s:nt};u!==void 0&&(a.defer=u),m&&(a.nonce=m);for(let[h,S]of Object.entries(p))h==="async"||h==="defer"||h==="nonce"||h==="src"||S!=null&&(a[h]=S);return jsxRuntime.jsx("script",{"data-gtm-container-id":o.id,...a},o.id)})})};var ct=t=>String(t),ut=t=>t.split(";").map(e=>e.trim()).filter(Boolean).reduce((e,n)=>{let[r,i]=n.split(":");if(!r||i===void 0)return e;let l=r.trim().replace(/-([a-z])/g,(f,d)=>d.toUpperCase()),o=i.trim();return !l||!o||(e[l]=o),e},{}),pt=({containers:t,host:e=L,defaultQueryParams:n,iframeAttributes:r,dataLayerName:i=gtmKit.DEFAULT_DATA_LAYER_NAME})=>{let l=_(t);if(!l.length)throw new Error("At least one GTM container is required to render noscript markup.");return jsxRuntime.jsx(jsxRuntime.Fragment,{children:l.map(o=>{if(!o.id)throw new Error("Container id is required to render GTM noscript markup.");let f={...n,...o.queryParams},d=H(e,o.id,f,i),s={...gtmKit.DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...r},u={src:d};for(let[m,p]of Object.entries(s))if(m!=="src"&&p!=null){if(m==="style"){typeof p=="string"?u.style=ut(p):typeof p=="object"&&(u.style=p);continue}u[m]=ct(p);}return jsxRuntime.jsx("noscript",{children:jsxRuntime.jsx("iframe",{...u})},o.id)})})};
8
+ var B="page_view",j=({pagePath:t,url:e,title:a})=>{let r={page_path:t,page_location:e};return a&&(r.page_title=a),r},Y=(t,e)=>{var r;let a=typeof window!="undefined"&&((r=window.location)!=null&&r.origin)?window.location.origin:"";return a?`${a}${t}${e}`:`${t}${e}`},Q=t=>t&&t.startsWith("#")?t:t?`#${t}`:"",K=({client:t,eventName:e=B,buildPayload:a=j,includeSearchParams:r=!0,trackHash:c=!1,trackOnMount:d=!0,skipSamePath:n=!0,pushEventFn:w=gtmKit.pushEvent,waitForReady:f=!1,readyPromise:u})=>{if(!t)throw new Error("A GTM client is required to track page views.");let l=navigation.usePathname(),m=navigation.useSearchParams(),s=react.useMemo(()=>!r||!m?"":m.toString(),[r,m]),o=react.useRef(null),g=react.useRef(!1),S=react.useRef(null),G=react.useRef(f?u!=null?u:t.whenReady():null),b=react.useRef(!0);react.useEffect(()=>(b.current=!0,()=>{b.current=!1;}),[]),react.useEffect(()=>{G.current=f?u!=null?u:t.whenReady():null;},[t,u,f]);let U=react.useCallback(p=>{let i=p.filter(h=>h.status==="failed");if(!i.length)return;let _=i.map(h=>h.containerId).join(", ");console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${_}`,i);},[]),C=react.useCallback((p,i,_)=>{if(!p)return;let h=c?Q(_):"",y=i?`${p}?${i}`:p,R=`${y}${h}`,k=Y(y,h);if(!d&&!g.current){o.current={key:R,pathname:p,search:i,hash:h,pagePath:y,url:k},g.current=!0;return}if(n&&o.current&&o.current.key===R)return;let V=typeof document!="undefined"?document.title:void 0,$=o.current?{pathname:o.current.pathname,search:o.current.search,hash:o.current.hash,pagePath:o.current.pagePath,url:o.current.url}:void 0,H={pathname:p,search:i,hash:h,pagePath:y,url:k,title:V,previous:$},v=()=>{let T=a(H);w(t,e,T),o.current={key:R,pathname:p,search:i,hash:h,pagePath:y,url:k},g.current=!0;};if(f&&G.current){S.current=R,G.current.then(T=>{!b.current||S.current!==R||(U(T),v());}).catch(T=>{!b.current||S.current!==R||(console.error("[react-gtm-kit] Error while waiting for GTM readiness.",T),v());});return}v();},[a,t,e,U,w,n,c,d,f]);react.useEffect(()=>{var i;if(typeof window=="undefined")return;let p=c&&(i=window.location.hash)!=null?i:"";C(l,s,p);},[C,l,s,c]),react.useEffect(()=>{if(!c||typeof window=="undefined")return;let p=()=>{var i;C(l,s,(i=window.location.hash)!=null?i:"");};return window.addEventListener("hashchange",p),()=>{window.removeEventListener("hashchange",p);}},[C,l,s,c]);};var J=!0,X=({containers:t,host:e=gtmKit.DEFAULT_GTM_HOST,defaultQueryParams:a,scriptAttributes:r,dataLayerName:c=gtmKit.DEFAULT_DATA_LAYER_NAME})=>{let d=gtmKit.normalizeContainers(t);if(!d.length)throw new Error("At least one GTM container is required to render script tags.");return jsxRuntime.jsx(jsxRuntime.Fragment,{children:d.map(n=>{if(!n.id)throw new Error("Container id is required to render GTM script tags.");let w={...a,...n.queryParams},f=gtmKit.buildGtmScriptUrl(e,n.id,w,c),{async:u,defer:l,nonce:m,...s}=r!=null?r:{},o={src:f,async:u!=null?u:J};l!==void 0&&(o.defer=l),m&&(o.nonce=m);for(let[g,S]of Object.entries(s))g==="async"||g==="defer"||g==="nonce"||g==="src"||S!=null&&(o[g]=S);return jsxRuntime.jsx("script",{"data-gtm-container-id":n.id,...o},n.id)})})};var rt=t=>String(t),nt=t=>t.split(";").map(e=>e.trim()).filter(Boolean).reduce((e,a)=>{let[r,c]=a.split(":");if(!r||c===void 0)return e;let d=r.trim().replace(/-([a-z])/g,(w,f)=>f.toUpperCase()),n=c.trim();return !d||!n||(e[d]=n),e},{}),ot=({containers:t,host:e=gtmKit.DEFAULT_GTM_HOST,defaultQueryParams:a,iframeAttributes:r,dataLayerName:c=gtmKit.DEFAULT_DATA_LAYER_NAME})=>{let d=gtmKit.normalizeContainers(t);if(!d.length)throw new Error("At least one GTM container is required to render noscript markup.");return jsxRuntime.jsx(jsxRuntime.Fragment,{children:d.map(n=>{if(!n.id)throw new Error("Container id is required to render GTM noscript markup.");let w={...a,...n.queryParams},f=gtmKit.buildGtmNoscriptUrl(e,n.id,w,c),u={...gtmKit.DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...r},l={src:f};for(let[m,s]of Object.entries(u))if(m!=="src"&&s!=null){if(m==="style"){typeof s=="string"?l.style=nt(s):typeof s=="object"&&(l.style=s);continue}l[m]=rt(s);}return jsxRuntime.jsx("noscript",{children:jsxRuntime.jsx("iframe",{...l})},n.id)})})};
9
9
 
10
- exports.GtmHeadScript = ot;
11
- exports.GtmNoScript = pt;
12
- exports.useTrackPageViews = X;
10
+ exports.GtmHeadScript = X;
11
+ exports.GtmNoScript = ot;
12
+ exports.useTrackPageViews = K;
13
13
  //# sourceMappingURL=out.js.map
14
14
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/route-listener.ts","../src/head-script.tsx","../src/internal/container-helpers.ts","../src/noscript.tsx"],"names":["useCallback","useEffect","useMemo","useRef","usePathname","useSearchParams","pushEvent","DEFAULT_EVENT_NAME","defaultBuildPayload","pagePath","url","title","payload","buildUrl","hash","_a","origin","sanitizeHash","useTrackPageViews","client","eventName","buildPayload","includeSearchParams","trackHash","trackOnMount","skipSamePath","pushEventFn","waitForReady","readyPromise","pathname","searchParams","search","previousRef","hasTrackedRef","pendingKeyRef","readinessRef","isMountedRef","logFailures","states","failed","state","details","handleRouteChange","nextPathname","searchValue","rawHash","normalizedHash","key","previous","pushPayload","error","listener","DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","isString","value","normalizeContainer","input","normalizeContainers","containers","toRecord","params","acc","normalizeHost","host","kind","containerId","queryParams","dataLayerName","normalizedHost","buildScriptUrl","buildNoscriptUrl","Fragment","jsx","DEFAULT_ASYNC","GtmHeadScript","defaultQueryParams","scriptAttributes","normalized","container","src","asyncAttr","defer","nonce","restAttributes","scriptProps","attribute","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","toStringValue","parseStyle","style","chunk","declaration","property","rawValue","_","char","GtmNoScript","iframeAttributes","attributes","iframeProps"],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { usePathname, useSearchParams } from 'next/navigation';\nimport type { GtmClient, PageViewPayload, ScriptLoadState } from '@jwiedeman/gtm-kit';\nimport { pushEvent } from '@jwiedeman/gtm-kit';\n\nconst DEFAULT_EVENT_NAME = 'page_view';\n\nexport interface RouteLocationSnapshot {\n pathname: string;\n search: string;\n hash: string;\n pagePath: string;\n url: string;\n}\n\nexport interface RouteChangeEventDetails extends RouteLocationSnapshot {\n title?: string;\n previous?: RouteLocationSnapshot;\n}\n\nexport type PageViewPayloadBuilder = (details: RouteChangeEventDetails) => PageViewPayload;\n\nexport interface UseTrackPageViewsOptions {\n client: Pick<GtmClient, 'push' | 'whenReady'>;\n eventName?: string;\n buildPayload?: PageViewPayloadBuilder;\n includeSearchParams?: boolean;\n trackHash?: boolean;\n trackOnMount?: boolean;\n skipSamePath?: boolean;\n pushEventFn?: typeof pushEvent;\n waitForReady?: boolean;\n readyPromise?: Promise<ScriptLoadState[]>;\n}\n\ninterface RouteSnapshot extends RouteLocationSnapshot {\n key: string;\n}\n\nconst defaultBuildPayload: PageViewPayloadBuilder = ({ pagePath, url, title }) => {\n const payload: PageViewPayload = {\n page_path: pagePath,\n page_location: url\n };\n\n if (title) {\n payload.page_title = title;\n }\n\n return payload;\n};\n\nconst buildUrl = (pagePath: string, hash: string): string => {\n const origin = typeof window !== 'undefined' && window.location?.origin ? window.location.origin : '';\n if (!origin) {\n return `${pagePath}${hash}`;\n }\n\n return `${origin}${pagePath}${hash}`;\n};\n\nconst sanitizeHash = (hash: string): string => (hash && hash.startsWith('#') ? hash : hash ? `#${hash}` : '');\n\nexport const useTrackPageViews = ({\n client,\n eventName = DEFAULT_EVENT_NAME,\n buildPayload = defaultBuildPayload,\n includeSearchParams = true,\n trackHash = false,\n trackOnMount = true,\n skipSamePath = true,\n pushEventFn = pushEvent,\n waitForReady = false,\n readyPromise\n}: UseTrackPageViewsOptions): void => {\n if (!client) {\n throw new Error('A GTM client is required to track page views.');\n }\n\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const search = useMemo(() => {\n if (!includeSearchParams || !searchParams) {\n return '';\n }\n\n return searchParams.toString();\n }, [includeSearchParams, searchParams]);\n\n const previousRef = useRef<RouteSnapshot | null>(null);\n const hasTrackedRef = useRef(false);\n const pendingKeyRef = useRef<string | null>(null);\n const readinessRef = useRef<Promise<ScriptLoadState[]> | null>(\n waitForReady ? (readyPromise ?? client.whenReady()) : null\n );\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n readinessRef.current = waitForReady ? (readyPromise ?? client.whenReady()) : null;\n }, [client, readyPromise, waitForReady]);\n\n const logFailures = useCallback((states: ScriptLoadState[]) => {\n const failed = states.filter((state) => state.status === 'failed');\n if (!failed.length) {\n return;\n }\n\n const details = failed.map((state) => state.containerId).join(', ');\n // eslint-disable-next-line no-console\n console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${details}`, failed);\n }, []);\n\n const handleRouteChange = useCallback(\n (nextPathname: string | null, searchValue: string, rawHash: string) => {\n if (!nextPathname) {\n return;\n }\n\n const normalizedHash = trackHash ? sanitizeHash(rawHash) : '';\n const pagePath = searchValue ? `${nextPathname}?${searchValue}` : nextPathname;\n const key = `${pagePath}${normalizedHash}`;\n const url = buildUrl(pagePath, normalizedHash);\n\n if (!trackOnMount && !hasTrackedRef.current) {\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n return;\n }\n\n if (skipSamePath && previousRef.current && previousRef.current.key === key) {\n return;\n }\n\n const title = typeof document !== 'undefined' ? document.title : undefined;\n const previous = previousRef.current\n ? {\n pathname: previousRef.current.pathname,\n search: previousRef.current.search,\n hash: previousRef.current.hash,\n pagePath: previousRef.current.pagePath,\n url: previousRef.current.url\n }\n : undefined;\n\n const details: RouteChangeEventDetails = {\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url,\n title,\n previous\n };\n\n const pushPayload = (): void => {\n const payload = buildPayload(details);\n pushEventFn(client, eventName, payload);\n\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n };\n\n if (waitForReady && readinessRef.current) {\n pendingKeyRef.current = key;\n readinessRef.current\n .then((states) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n\n logFailures(states);\n pushPayload();\n })\n .catch((error) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n // eslint-disable-next-line no-console\n console.error('[react-gtm-kit] Error while waiting for GTM readiness.', error);\n pushPayload();\n });\n\n return;\n }\n\n pushPayload();\n },\n [buildPayload, client, eventName, logFailures, pushEventFn, skipSamePath, trackHash, trackOnMount, waitForReady]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const hash = trackHash ? (window.location.hash ?? '') : '';\n handleRouteChange(pathname, search, hash);\n }, [handleRouteChange, pathname, search, trackHash]);\n\n useEffect(() => {\n if (!trackHash || typeof window === 'undefined') {\n return;\n }\n\n const listener = (): void => {\n handleRouteChange(pathname, search, window.location.hash ?? '');\n };\n\n window.addEventListener('hashchange', listener);\n return () => {\n window.removeEventListener('hashchange', listener);\n };\n }, [handleRouteChange, pathname, search, trackHash]);\n};\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';\nimport { buildScriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmHeadScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n scriptAttributes?: ScriptAttributes;\n dataLayerName?: string;\n}\n\nconst DEFAULT_ASYNC = true;\n\nexport const GtmHeadScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n scriptAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmHeadScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render script tags.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM script tags.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildScriptUrl(host, container.id, params, dataLayerName);\n const { async: asyncAttr, defer, nonce, ...restAttributes } = scriptAttributes ?? {};\n\n const scriptProps: React.ScriptHTMLAttributes<HTMLScriptElement> = {\n src,\n async: asyncAttr ?? DEFAULT_ASYNC\n };\n\n if (defer !== undefined) {\n scriptProps.defer = defer;\n }\n\n if (nonce) {\n scriptProps.nonce = nonce;\n }\n\n for (const [attribute, value] of Object.entries(restAttributes)) {\n if (attribute === 'async' || attribute === 'defer' || attribute === 'nonce' || attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n (scriptProps as Record<string, unknown>)[attribute] = value;\n }\n\n return <script key={container.id} data-gtm-container-id={container.id} {...scriptProps} />;\n })}\n </>\n );\n};\n","import { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ContainerDescriptor } from '@jwiedeman/gtm-kit';\n\nexport const DEFAULT_GTM_HOST = 'https://www.googletagmanager.com';\n\nconst isString = (value: unknown): value is string => typeof value === 'string';\n\nexport const normalizeContainer = (input: ContainerConfigInput): ContainerDescriptor => {\n if (isString(input)) {\n return { id: input };\n }\n\n return input;\n};\n\nexport const normalizeContainers = (\n containers: ContainerConfigInput | ContainerConfigInput[]\n): ContainerDescriptor[] => {\n if (Array.isArray(containers)) {\n return containers.map(normalizeContainer);\n }\n\n return [normalizeContainer(containers)];\n};\n\nconst toRecord = (params?: Record<string, string | number | boolean>): Record<string, string> => {\n if (!params) {\n return {};\n }\n\n return Object.entries(params).reduce<Record<string, string>>((acc, [key, value]) => {\n acc[key] = String(value);\n return acc;\n }, {});\n};\n\nconst normalizeHost = (host: string): string => (host.endsWith('/') ? host.slice(0, -1) : host);\n\nconst buildUrl = (\n kind: 'gtm' | 'ns',\n host: string,\n containerId: string,\n queryParams?: Record<string, string | number | boolean>,\n dataLayerName: string = DEFAULT_DATA_LAYER_NAME\n): string => {\n const normalizedHost = normalizeHost(host);\n const searchParams = new URLSearchParams({ id: containerId });\n\n const params = toRecord(queryParams);\n if (dataLayerName !== DEFAULT_DATA_LAYER_NAME && params.l === undefined) {\n params.l = dataLayerName;\n }\n\n for (const [key, value] of Object.entries(params)) {\n if (key === 'id') {\n continue;\n }\n searchParams.set(key, value);\n }\n\n const suffix = kind === 'gtm' ? 'gtm.js' : 'ns.html';\n return `${normalizedHost}/${suffix}?${searchParams.toString()}`;\n};\n\nexport const buildScriptUrl = (\n host: string,\n containerId: string,\n queryParams?: Record<string, string | number | boolean>,\n dataLayerName: string = DEFAULT_DATA_LAYER_NAME\n): string => buildUrl('gtm', host, containerId, queryParams, dataLayerName);\n\nexport const buildNoscriptUrl = (\n host: string,\n containerId: string,\n queryParams?: Record<string, string | number | boolean>,\n dataLayerName: string = DEFAULT_DATA_LAYER_NAME\n): string => buildUrl('ns', host, containerId, queryParams, dataLayerName);\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput } from '@jwiedeman/gtm-kit';\nimport { DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES } from '@jwiedeman/gtm-kit';\nimport { buildNoscriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmNoScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n iframeAttributes?: Record<string, string | number | boolean>;\n dataLayerName?: string;\n}\n\nconst toStringValue = (value: string | number | boolean): string => String(value);\n\nconst parseStyle = (style: string): React.CSSProperties => {\n return style\n .split(';')\n .map((chunk) => chunk.trim())\n .filter(Boolean)\n .reduce<React.CSSProperties>((acc, declaration) => {\n const [property, rawValue] = declaration.split(':');\n if (!property || rawValue === undefined) {\n return acc;\n }\n\n const key = property.trim().replace(/-([a-z])/g, (_, char: string) => char.toUpperCase());\n const value = rawValue.trim();\n if (!key || !value) {\n return acc;\n }\n\n (acc as Record<string, string>)[key] = value;\n return acc;\n }, {});\n};\n\nexport const GtmNoScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n iframeAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmNoScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render noscript markup.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM noscript markup.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildNoscriptUrl(host, container.id, params, dataLayerName);\n const attributes = {\n ...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n ...iframeAttributes\n };\n\n const iframeProps: React.IframeHTMLAttributes<HTMLIFrameElement> = {\n src\n };\n\n for (const [attribute, value] of Object.entries(attributes)) {\n if (attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n if (attribute === 'style') {\n if (typeof value === 'string') {\n iframeProps.style = parseStyle(value);\n } else if (typeof value === 'object') {\n iframeProps.style = value as React.CSSProperties;\n }\n continue;\n }\n\n (iframeProps as Record<string, unknown>)[attribute] = toStringValue(value as string | number | boolean);\n }\n\n return (\n <noscript key={container.id}>\n <iframe {...iframeProps} />\n </noscript>\n );\n })}\n </>\n );\n};\n"]}
1
+ {"version":3,"sources":["../src/route-listener.ts","../src/head-script.tsx","../src/internal/container-helpers.ts","../src/noscript.tsx"],"names":["useCallback","useEffect","useMemo","useRef","usePathname","useSearchParams","pushEvent","DEFAULT_EVENT_NAME","defaultBuildPayload","pagePath","url","title","payload","buildUrl","hash","_a","origin","sanitizeHash","useTrackPageViews","client","eventName","buildPayload","includeSearchParams","trackHash","trackOnMount","skipSamePath","pushEventFn","waitForReady","readyPromise","pathname","searchParams","search","previousRef","hasTrackedRef","pendingKeyRef","readinessRef","isMountedRef","logFailures","states","failed","state","details","handleRouteChange","nextPathname","searchValue","rawHash","normalizedHash","key","previous","pushPayload","error","listener","DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","normalizeContainer","normalizeContainers","buildGtmScriptUrl","buildGtmNoscriptUrl","Fragment","jsx","DEFAULT_ASYNC","GtmHeadScript","containers","host","defaultQueryParams","scriptAttributes","dataLayerName","normalized","container","params","src","asyncAttr","defer","nonce","restAttributes","scriptProps","attribute","value","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","toStringValue","parseStyle","style","chunk","acc","declaration","property","rawValue","_","char","GtmNoScript","iframeAttributes","attributes","iframeProps"],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { usePathname, useSearchParams } from 'next/navigation';\nimport type { GtmClient, PageViewPayload, ScriptLoadState } from '@jwiedeman/gtm-kit';\nimport { pushEvent } from '@jwiedeman/gtm-kit';\n\nconst DEFAULT_EVENT_NAME = 'page_view';\n\nexport interface RouteLocationSnapshot {\n pathname: string;\n search: string;\n hash: string;\n pagePath: string;\n url: string;\n}\n\nexport interface RouteChangeEventDetails extends RouteLocationSnapshot {\n title?: string;\n previous?: RouteLocationSnapshot;\n}\n\nexport type PageViewPayloadBuilder = (details: RouteChangeEventDetails) => PageViewPayload;\n\nexport interface UseTrackPageViewsOptions {\n client: Pick<GtmClient, 'push' | 'whenReady'>;\n eventName?: string;\n buildPayload?: PageViewPayloadBuilder;\n includeSearchParams?: boolean;\n trackHash?: boolean;\n trackOnMount?: boolean;\n skipSamePath?: boolean;\n pushEventFn?: typeof pushEvent;\n waitForReady?: boolean;\n readyPromise?: Promise<ScriptLoadState[]>;\n}\n\ninterface RouteSnapshot extends RouteLocationSnapshot {\n key: string;\n}\n\nconst defaultBuildPayload: PageViewPayloadBuilder = ({ pagePath, url, title }) => {\n const payload: PageViewPayload = {\n page_path: pagePath,\n page_location: url\n };\n\n if (title) {\n payload.page_title = title;\n }\n\n return payload;\n};\n\nconst buildUrl = (pagePath: string, hash: string): string => {\n const origin = typeof window !== 'undefined' && window.location?.origin ? window.location.origin : '';\n if (!origin) {\n return `${pagePath}${hash}`;\n }\n\n return `${origin}${pagePath}${hash}`;\n};\n\nconst sanitizeHash = (hash: string): string => (hash && hash.startsWith('#') ? hash : hash ? `#${hash}` : '');\n\nexport const useTrackPageViews = ({\n client,\n eventName = DEFAULT_EVENT_NAME,\n buildPayload = defaultBuildPayload,\n includeSearchParams = true,\n trackHash = false,\n trackOnMount = true,\n skipSamePath = true,\n pushEventFn = pushEvent,\n waitForReady = false,\n readyPromise\n}: UseTrackPageViewsOptions): void => {\n if (!client) {\n throw new Error('A GTM client is required to track page views.');\n }\n\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const search = useMemo(() => {\n if (!includeSearchParams || !searchParams) {\n return '';\n }\n\n return searchParams.toString();\n }, [includeSearchParams, searchParams]);\n\n const previousRef = useRef<RouteSnapshot | null>(null);\n const hasTrackedRef = useRef(false);\n const pendingKeyRef = useRef<string | null>(null);\n const readinessRef = useRef<Promise<ScriptLoadState[]> | null>(\n waitForReady ? (readyPromise ?? client.whenReady()) : null\n );\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n readinessRef.current = waitForReady ? (readyPromise ?? client.whenReady()) : null;\n }, [client, readyPromise, waitForReady]);\n\n const logFailures = useCallback((states: ScriptLoadState[]) => {\n const failed = states.filter((state) => state.status === 'failed');\n if (!failed.length) {\n return;\n }\n\n const details = failed.map((state) => state.containerId).join(', ');\n // eslint-disable-next-line no-console\n console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${details}`, failed);\n }, []);\n\n const handleRouteChange = useCallback(\n (nextPathname: string | null, searchValue: string, rawHash: string) => {\n if (!nextPathname) {\n return;\n }\n\n const normalizedHash = trackHash ? sanitizeHash(rawHash) : '';\n const pagePath = searchValue ? `${nextPathname}?${searchValue}` : nextPathname;\n const key = `${pagePath}${normalizedHash}`;\n const url = buildUrl(pagePath, normalizedHash);\n\n if (!trackOnMount && !hasTrackedRef.current) {\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n return;\n }\n\n if (skipSamePath && previousRef.current && previousRef.current.key === key) {\n return;\n }\n\n const title = typeof document !== 'undefined' ? document.title : undefined;\n const previous = previousRef.current\n ? {\n pathname: previousRef.current.pathname,\n search: previousRef.current.search,\n hash: previousRef.current.hash,\n pagePath: previousRef.current.pagePath,\n url: previousRef.current.url\n }\n : undefined;\n\n const details: RouteChangeEventDetails = {\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url,\n title,\n previous\n };\n\n const pushPayload = (): void => {\n const payload = buildPayload(details);\n pushEventFn(client, eventName, payload);\n\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n };\n\n if (waitForReady && readinessRef.current) {\n pendingKeyRef.current = key;\n readinessRef.current\n .then((states) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n\n logFailures(states);\n pushPayload();\n })\n .catch((error) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n // eslint-disable-next-line no-console\n console.error('[react-gtm-kit] Error while waiting for GTM readiness.', error);\n pushPayload();\n });\n\n return;\n }\n\n pushPayload();\n },\n [buildPayload, client, eventName, logFailures, pushEventFn, skipSamePath, trackHash, trackOnMount, waitForReady]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const hash = trackHash ? (window.location.hash ?? '') : '';\n handleRouteChange(pathname, search, hash);\n }, [handleRouteChange, pathname, search, trackHash]);\n\n useEffect(() => {\n if (!trackHash || typeof window === 'undefined') {\n return;\n }\n\n const listener = (): void => {\n handleRouteChange(pathname, search, window.location.hash ?? '');\n };\n\n window.addEventListener('hashchange', listener);\n return () => {\n window.removeEventListener('hashchange', listener);\n };\n }, [handleRouteChange, pathname, search, trackHash]);\n};\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';\nimport { buildScriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmHeadScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n scriptAttributes?: ScriptAttributes;\n dataLayerName?: string;\n}\n\nconst DEFAULT_ASYNC = true;\n\nexport const GtmHeadScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n scriptAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmHeadScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render script tags.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM script tags.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildScriptUrl(host, container.id, params, dataLayerName);\n const { async: asyncAttr, defer, nonce, ...restAttributes } = scriptAttributes ?? {};\n\n const scriptProps: React.ScriptHTMLAttributes<HTMLScriptElement> = {\n src,\n async: asyncAttr ?? DEFAULT_ASYNC\n };\n\n if (defer !== undefined) {\n scriptProps.defer = defer;\n }\n\n if (nonce) {\n scriptProps.nonce = nonce;\n }\n\n for (const [attribute, value] of Object.entries(restAttributes)) {\n if (attribute === 'async' || attribute === 'defer' || attribute === 'nonce' || attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n (scriptProps as Record<string, unknown>)[attribute] = value;\n }\n\n return <script key={container.id} data-gtm-container-id={container.id} {...scriptProps} />;\n })}\n </>\n );\n};\n","// Re-export URL utilities from core for internal use\nexport {\n DEFAULT_GTM_HOST,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n} from '@jwiedeman/gtm-kit';\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput } from '@jwiedeman/gtm-kit';\nimport { DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES } from '@jwiedeman/gtm-kit';\nimport { buildNoscriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmNoScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n iframeAttributes?: Record<string, string | number | boolean>;\n dataLayerName?: string;\n}\n\nconst toStringValue = (value: string | number | boolean): string => String(value);\n\nconst parseStyle = (style: string): React.CSSProperties => {\n return style\n .split(';')\n .map((chunk) => chunk.trim())\n .filter(Boolean)\n .reduce<React.CSSProperties>((acc, declaration) => {\n const [property, rawValue] = declaration.split(':');\n if (!property || rawValue === undefined) {\n return acc;\n }\n\n const key = property.trim().replace(/-([a-z])/g, (_, char: string) => char.toUpperCase());\n const value = rawValue.trim();\n if (!key || !value) {\n return acc;\n }\n\n (acc as Record<string, string>)[key] = value;\n return acc;\n }, {});\n};\n\nexport const GtmNoScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n iframeAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmNoScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render noscript markup.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM noscript markup.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildNoscriptUrl(host, container.id, params, dataLayerName);\n const attributes = {\n ...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n ...iframeAttributes\n };\n\n const iframeProps: React.IframeHTMLAttributes<HTMLIFrameElement> = {\n src\n };\n\n for (const [attribute, value] of Object.entries(attributes)) {\n if (attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n if (attribute === 'style') {\n if (typeof value === 'string') {\n iframeProps.style = parseStyle(value);\n } else if (typeof value === 'object') {\n iframeProps.style = value as React.CSSProperties;\n }\n continue;\n }\n\n (iframeProps as Record<string, unknown>)[attribute] = toStringValue(value as string | number | boolean);\n }\n\n return (\n <noscript key={container.id}>\n <iframe {...iframeProps} />\n </noscript>\n );\n })}\n </>\n );\n};\n"]}
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { useMemo, useRef, useEffect, useCallback } from 'react';
2
2
  import { usePathname, useSearchParams } from 'next/navigation';
3
- import { pushEvent, DEFAULT_DATA_LAYER_NAME, DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES } from '@jwiedeman/gtm-kit';
3
+ import { pushEvent, normalizeContainers, buildGtmScriptUrl, DEFAULT_GTM_HOST, DEFAULT_DATA_LAYER_NAME, buildGtmNoscriptUrl, DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES } from '@jwiedeman/gtm-kit';
4
4
  import { jsx, Fragment } from 'react/jsx-runtime';
5
5
 
6
- var Q="page_view",W=({pagePath:t,url:e,title:n})=>{let r={page_path:t,page_location:e};return n&&(r.page_title=n),r},K=(t,e)=>{var r;let n=typeof window!="undefined"&&((r=window.location)!=null&&r.origin)?window.location.origin:"";return n?`${n}${t}${e}`:`${t}${e}`},J=t=>t&&t.startsWith("#")?t:t?`#${t}`:"",X=({client:t,eventName:e=Q,buildPayload:n=W,includeSearchParams:r=!0,trackHash:i=!1,trackOnMount:l=!0,skipSamePath:o=!0,pushEventFn:f=pushEvent,waitForReady:d=!1,readyPromise:s})=>{if(!t)throw new Error("A GTM client is required to track page views.");let u=usePathname(),m=useSearchParams(),p=useMemo(()=>!r||!m?"":m.toString(),[r,m]),a=useRef(null),h=useRef(!1),S=useRef(null),k=useRef(d?s!=null?s:t.whenReady():null),T=useRef(!0);useEffect(()=>(T.current=!0,()=>{T.current=!1;}),[]),useEffect(()=>{k.current=d?s!=null?s:t.whenReady():null;},[t,s,d]);let D=useCallback(g=>{let c=g.filter(w=>w.status==="failed");if(!c.length)return;let v=c.map(w=>w.containerId).join(", ");console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${v}`,c);},[]),E=useCallback((g,c,v)=>{if(!g)return;let w=i?J(v):"",C=c?`${g}?${c}`:g,R=`${C}${w}`,G=K(C,w);if(!l&&!h.current){a.current={key:R,pathname:g,search:c,hash:w,pagePath:C,url:G},h.current=!0;return}if(o&&a.current&&a.current.key===R)return;let O=typeof document!="undefined"?document.title:void 0,V=a.current?{pathname:a.current.pathname,search:a.current.search,hash:a.current.hash,pagePath:a.current.pagePath,url:a.current.url}:void 0,F={pathname:g,search:c,hash:w,pagePath:C,url:G,title:O,previous:V},M=()=>{let y=n(F);f(t,e,y),a.current={key:R,pathname:g,search:c,hash:w,pagePath:C,url:G},h.current=!0;};if(d&&k.current){S.current=R,k.current.then(y=>{!T.current||S.current!==R||(D(y),M());}).catch(y=>{!T.current||S.current!==R||(console.error("[react-gtm-kit] Error while waiting for GTM readiness.",y),M());});return}M();},[n,t,e,D,f,o,i,l,d]);useEffect(()=>{var c;if(typeof window=="undefined")return;let g=i&&(c=window.location.hash)!=null?c:"";E(u,p,g);},[E,u,p,i]),useEffect(()=>{if(!i||typeof window=="undefined")return;let g=()=>{var c;E(u,p,(c=window.location.hash)!=null?c:"");};return window.addEventListener("hashchange",g),()=>{window.removeEventListener("hashchange",g);}},[E,u,p,i]);};var L="https://www.googletagmanager.com",Z=t=>typeof t=="string",I=t=>Z(t)?{id:t}:t,_=t=>Array.isArray(t)?t.map(I):[I(t)],tt=t=>t?Object.entries(t).reduce((e,[n,r])=>(e[n]=String(r),e),{}):{},et=t=>t.endsWith("/")?t.slice(0,-1):t,N=(t,e,n,r,i=DEFAULT_DATA_LAYER_NAME)=>{let l=et(e),o=new URLSearchParams({id:n}),f=tt(r);i!==DEFAULT_DATA_LAYER_NAME&&f.l===void 0&&(f.l=i);for(let[s,u]of Object.entries(f))s!=="id"&&o.set(s,u);return `${l}/${t==="gtm"?"gtm.js":"ns.html"}?${o.toString()}`},$=(t,e,n,r=DEFAULT_DATA_LAYER_NAME)=>N("gtm",t,e,n,r),H=(t,e,n,r=DEFAULT_DATA_LAYER_NAME)=>N("ns",t,e,n,r);var nt=!0,ot=({containers:t,host:e=L,defaultQueryParams:n,scriptAttributes:r,dataLayerName:i=DEFAULT_DATA_LAYER_NAME})=>{let l=_(t);if(!l.length)throw new Error("At least one GTM container is required to render script tags.");return jsx(Fragment,{children:l.map(o=>{if(!o.id)throw new Error("Container id is required to render GTM script tags.");let f={...n,...o.queryParams},d=$(e,o.id,f,i),{async:s,defer:u,nonce:m,...p}=r!=null?r:{},a={src:d,async:s!=null?s:nt};u!==void 0&&(a.defer=u),m&&(a.nonce=m);for(let[h,S]of Object.entries(p))h==="async"||h==="defer"||h==="nonce"||h==="src"||S!=null&&(a[h]=S);return jsx("script",{"data-gtm-container-id":o.id,...a},o.id)})})};var ct=t=>String(t),ut=t=>t.split(";").map(e=>e.trim()).filter(Boolean).reduce((e,n)=>{let[r,i]=n.split(":");if(!r||i===void 0)return e;let l=r.trim().replace(/-([a-z])/g,(f,d)=>d.toUpperCase()),o=i.trim();return !l||!o||(e[l]=o),e},{}),pt=({containers:t,host:e=L,defaultQueryParams:n,iframeAttributes:r,dataLayerName:i=DEFAULT_DATA_LAYER_NAME})=>{let l=_(t);if(!l.length)throw new Error("At least one GTM container is required to render noscript markup.");return jsx(Fragment,{children:l.map(o=>{if(!o.id)throw new Error("Container id is required to render GTM noscript markup.");let f={...n,...o.queryParams},d=H(e,o.id,f,i),s={...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...r},u={src:d};for(let[m,p]of Object.entries(s))if(m!=="src"&&p!=null){if(m==="style"){typeof p=="string"?u.style=ut(p):typeof p=="object"&&(u.style=p);continue}u[m]=ct(p);}return jsx("noscript",{children:jsx("iframe",{...u})},o.id)})})};
6
+ var B="page_view",j=({pagePath:t,url:e,title:a})=>{let r={page_path:t,page_location:e};return a&&(r.page_title=a),r},Y=(t,e)=>{var r;let a=typeof window!="undefined"&&((r=window.location)!=null&&r.origin)?window.location.origin:"";return a?`${a}${t}${e}`:`${t}${e}`},Q=t=>t&&t.startsWith("#")?t:t?`#${t}`:"",K=({client:t,eventName:e=B,buildPayload:a=j,includeSearchParams:r=!0,trackHash:c=!1,trackOnMount:d=!0,skipSamePath:n=!0,pushEventFn:w=pushEvent,waitForReady:f=!1,readyPromise:u})=>{if(!t)throw new Error("A GTM client is required to track page views.");let l=usePathname(),m=useSearchParams(),s=useMemo(()=>!r||!m?"":m.toString(),[r,m]),o=useRef(null),g=useRef(!1),S=useRef(null),G=useRef(f?u!=null?u:t.whenReady():null),b=useRef(!0);useEffect(()=>(b.current=!0,()=>{b.current=!1;}),[]),useEffect(()=>{G.current=f?u!=null?u:t.whenReady():null;},[t,u,f]);let U=useCallback(p=>{let i=p.filter(h=>h.status==="failed");if(!i.length)return;let _=i.map(h=>h.containerId).join(", ");console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${_}`,i);},[]),C=useCallback((p,i,_)=>{if(!p)return;let h=c?Q(_):"",y=i?`${p}?${i}`:p,R=`${y}${h}`,k=Y(y,h);if(!d&&!g.current){o.current={key:R,pathname:p,search:i,hash:h,pagePath:y,url:k},g.current=!0;return}if(n&&o.current&&o.current.key===R)return;let V=typeof document!="undefined"?document.title:void 0,$=o.current?{pathname:o.current.pathname,search:o.current.search,hash:o.current.hash,pagePath:o.current.pagePath,url:o.current.url}:void 0,H={pathname:p,search:i,hash:h,pagePath:y,url:k,title:V,previous:$},v=()=>{let T=a(H);w(t,e,T),o.current={key:R,pathname:p,search:i,hash:h,pagePath:y,url:k},g.current=!0;};if(f&&G.current){S.current=R,G.current.then(T=>{!b.current||S.current!==R||(U(T),v());}).catch(T=>{!b.current||S.current!==R||(console.error("[react-gtm-kit] Error while waiting for GTM readiness.",T),v());});return}v();},[a,t,e,U,w,n,c,d,f]);useEffect(()=>{var i;if(typeof window=="undefined")return;let p=c&&(i=window.location.hash)!=null?i:"";C(l,s,p);},[C,l,s,c]),useEffect(()=>{if(!c||typeof window=="undefined")return;let p=()=>{var i;C(l,s,(i=window.location.hash)!=null?i:"");};return window.addEventListener("hashchange",p),()=>{window.removeEventListener("hashchange",p);}},[C,l,s,c]);};var J=!0,X=({containers:t,host:e=DEFAULT_GTM_HOST,defaultQueryParams:a,scriptAttributes:r,dataLayerName:c=DEFAULT_DATA_LAYER_NAME})=>{let d=normalizeContainers(t);if(!d.length)throw new Error("At least one GTM container is required to render script tags.");return jsx(Fragment,{children:d.map(n=>{if(!n.id)throw new Error("Container id is required to render GTM script tags.");let w={...a,...n.queryParams},f=buildGtmScriptUrl(e,n.id,w,c),{async:u,defer:l,nonce:m,...s}=r!=null?r:{},o={src:f,async:u!=null?u:J};l!==void 0&&(o.defer=l),m&&(o.nonce=m);for(let[g,S]of Object.entries(s))g==="async"||g==="defer"||g==="nonce"||g==="src"||S!=null&&(o[g]=S);return jsx("script",{"data-gtm-container-id":n.id,...o},n.id)})})};var rt=t=>String(t),nt=t=>t.split(";").map(e=>e.trim()).filter(Boolean).reduce((e,a)=>{let[r,c]=a.split(":");if(!r||c===void 0)return e;let d=r.trim().replace(/-([a-z])/g,(w,f)=>f.toUpperCase()),n=c.trim();return !d||!n||(e[d]=n),e},{}),ot=({containers:t,host:e=DEFAULT_GTM_HOST,defaultQueryParams:a,iframeAttributes:r,dataLayerName:c=DEFAULT_DATA_LAYER_NAME})=>{let d=normalizeContainers(t);if(!d.length)throw new Error("At least one GTM container is required to render noscript markup.");return jsx(Fragment,{children:d.map(n=>{if(!n.id)throw new Error("Container id is required to render GTM noscript markup.");let w={...a,...n.queryParams},f=buildGtmNoscriptUrl(e,n.id,w,c),u={...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...r},l={src:f};for(let[m,s]of Object.entries(u))if(m!=="src"&&s!=null){if(m==="style"){typeof s=="string"?l.style=nt(s):typeof s=="object"&&(l.style=s);continue}l[m]=rt(s);}return jsx("noscript",{children:jsx("iframe",{...l})},n.id)})})};
7
7
 
8
- export { ot as GtmHeadScript, pt as GtmNoScript, X as useTrackPageViews };
8
+ export { X as GtmHeadScript, ot as GtmNoScript, K as useTrackPageViews };
9
9
  //# sourceMappingURL=out.js.map
10
10
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/route-listener.ts","../src/head-script.tsx","../src/internal/container-helpers.ts","../src/noscript.tsx"],"names":["useCallback","useEffect","useMemo","useRef","usePathname","useSearchParams","pushEvent","DEFAULT_EVENT_NAME","defaultBuildPayload","pagePath","url","title","payload","buildUrl","hash","_a","origin","sanitizeHash","useTrackPageViews","client","eventName","buildPayload","includeSearchParams","trackHash","trackOnMount","skipSamePath","pushEventFn","waitForReady","readyPromise","pathname","searchParams","search","previousRef","hasTrackedRef","pendingKeyRef","readinessRef","isMountedRef","logFailures","states","failed","state","details","handleRouteChange","nextPathname","searchValue","rawHash","normalizedHash","key","previous","pushPayload","error","listener","DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","isString","value","normalizeContainer","input","normalizeContainers","containers","toRecord","params","acc","normalizeHost","host","kind","containerId","queryParams","dataLayerName","normalizedHost","buildScriptUrl","buildNoscriptUrl","Fragment","jsx","DEFAULT_ASYNC","GtmHeadScript","defaultQueryParams","scriptAttributes","normalized","container","src","asyncAttr","defer","nonce","restAttributes","scriptProps","attribute","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","toStringValue","parseStyle","style","chunk","declaration","property","rawValue","_","char","GtmNoScript","iframeAttributes","attributes","iframeProps"],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { usePathname, useSearchParams } from 'next/navigation';\nimport type { GtmClient, PageViewPayload, ScriptLoadState } from '@jwiedeman/gtm-kit';\nimport { pushEvent } from '@jwiedeman/gtm-kit';\n\nconst DEFAULT_EVENT_NAME = 'page_view';\n\nexport interface RouteLocationSnapshot {\n pathname: string;\n search: string;\n hash: string;\n pagePath: string;\n url: string;\n}\n\nexport interface RouteChangeEventDetails extends RouteLocationSnapshot {\n title?: string;\n previous?: RouteLocationSnapshot;\n}\n\nexport type PageViewPayloadBuilder = (details: RouteChangeEventDetails) => PageViewPayload;\n\nexport interface UseTrackPageViewsOptions {\n client: Pick<GtmClient, 'push' | 'whenReady'>;\n eventName?: string;\n buildPayload?: PageViewPayloadBuilder;\n includeSearchParams?: boolean;\n trackHash?: boolean;\n trackOnMount?: boolean;\n skipSamePath?: boolean;\n pushEventFn?: typeof pushEvent;\n waitForReady?: boolean;\n readyPromise?: Promise<ScriptLoadState[]>;\n}\n\ninterface RouteSnapshot extends RouteLocationSnapshot {\n key: string;\n}\n\nconst defaultBuildPayload: PageViewPayloadBuilder = ({ pagePath, url, title }) => {\n const payload: PageViewPayload = {\n page_path: pagePath,\n page_location: url\n };\n\n if (title) {\n payload.page_title = title;\n }\n\n return payload;\n};\n\nconst buildUrl = (pagePath: string, hash: string): string => {\n const origin = typeof window !== 'undefined' && window.location?.origin ? window.location.origin : '';\n if (!origin) {\n return `${pagePath}${hash}`;\n }\n\n return `${origin}${pagePath}${hash}`;\n};\n\nconst sanitizeHash = (hash: string): string => (hash && hash.startsWith('#') ? hash : hash ? `#${hash}` : '');\n\nexport const useTrackPageViews = ({\n client,\n eventName = DEFAULT_EVENT_NAME,\n buildPayload = defaultBuildPayload,\n includeSearchParams = true,\n trackHash = false,\n trackOnMount = true,\n skipSamePath = true,\n pushEventFn = pushEvent,\n waitForReady = false,\n readyPromise\n}: UseTrackPageViewsOptions): void => {\n if (!client) {\n throw new Error('A GTM client is required to track page views.');\n }\n\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const search = useMemo(() => {\n if (!includeSearchParams || !searchParams) {\n return '';\n }\n\n return searchParams.toString();\n }, [includeSearchParams, searchParams]);\n\n const previousRef = useRef<RouteSnapshot | null>(null);\n const hasTrackedRef = useRef(false);\n const pendingKeyRef = useRef<string | null>(null);\n const readinessRef = useRef<Promise<ScriptLoadState[]> | null>(\n waitForReady ? (readyPromise ?? client.whenReady()) : null\n );\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n readinessRef.current = waitForReady ? (readyPromise ?? client.whenReady()) : null;\n }, [client, readyPromise, waitForReady]);\n\n const logFailures = useCallback((states: ScriptLoadState[]) => {\n const failed = states.filter((state) => state.status === 'failed');\n if (!failed.length) {\n return;\n }\n\n const details = failed.map((state) => state.containerId).join(', ');\n // eslint-disable-next-line no-console\n console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${details}`, failed);\n }, []);\n\n const handleRouteChange = useCallback(\n (nextPathname: string | null, searchValue: string, rawHash: string) => {\n if (!nextPathname) {\n return;\n }\n\n const normalizedHash = trackHash ? sanitizeHash(rawHash) : '';\n const pagePath = searchValue ? `${nextPathname}?${searchValue}` : nextPathname;\n const key = `${pagePath}${normalizedHash}`;\n const url = buildUrl(pagePath, normalizedHash);\n\n if (!trackOnMount && !hasTrackedRef.current) {\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n return;\n }\n\n if (skipSamePath && previousRef.current && previousRef.current.key === key) {\n return;\n }\n\n const title = typeof document !== 'undefined' ? document.title : undefined;\n const previous = previousRef.current\n ? {\n pathname: previousRef.current.pathname,\n search: previousRef.current.search,\n hash: previousRef.current.hash,\n pagePath: previousRef.current.pagePath,\n url: previousRef.current.url\n }\n : undefined;\n\n const details: RouteChangeEventDetails = {\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url,\n title,\n previous\n };\n\n const pushPayload = (): void => {\n const payload = buildPayload(details);\n pushEventFn(client, eventName, payload);\n\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n };\n\n if (waitForReady && readinessRef.current) {\n pendingKeyRef.current = key;\n readinessRef.current\n .then((states) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n\n logFailures(states);\n pushPayload();\n })\n .catch((error) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n // eslint-disable-next-line no-console\n console.error('[react-gtm-kit] Error while waiting for GTM readiness.', error);\n pushPayload();\n });\n\n return;\n }\n\n pushPayload();\n },\n [buildPayload, client, eventName, logFailures, pushEventFn, skipSamePath, trackHash, trackOnMount, waitForReady]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const hash = trackHash ? (window.location.hash ?? '') : '';\n handleRouteChange(pathname, search, hash);\n }, [handleRouteChange, pathname, search, trackHash]);\n\n useEffect(() => {\n if (!trackHash || typeof window === 'undefined') {\n return;\n }\n\n const listener = (): void => {\n handleRouteChange(pathname, search, window.location.hash ?? '');\n };\n\n window.addEventListener('hashchange', listener);\n return () => {\n window.removeEventListener('hashchange', listener);\n };\n }, [handleRouteChange, pathname, search, trackHash]);\n};\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';\nimport { buildScriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmHeadScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n scriptAttributes?: ScriptAttributes;\n dataLayerName?: string;\n}\n\nconst DEFAULT_ASYNC = true;\n\nexport const GtmHeadScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n scriptAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmHeadScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render script tags.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM script tags.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildScriptUrl(host, container.id, params, dataLayerName);\n const { async: asyncAttr, defer, nonce, ...restAttributes } = scriptAttributes ?? {};\n\n const scriptProps: React.ScriptHTMLAttributes<HTMLScriptElement> = {\n src,\n async: asyncAttr ?? DEFAULT_ASYNC\n };\n\n if (defer !== undefined) {\n scriptProps.defer = defer;\n }\n\n if (nonce) {\n scriptProps.nonce = nonce;\n }\n\n for (const [attribute, value] of Object.entries(restAttributes)) {\n if (attribute === 'async' || attribute === 'defer' || attribute === 'nonce' || attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n (scriptProps as Record<string, unknown>)[attribute] = value;\n }\n\n return <script key={container.id} data-gtm-container-id={container.id} {...scriptProps} />;\n })}\n </>\n );\n};\n","import { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ContainerDescriptor } from '@jwiedeman/gtm-kit';\n\nexport const DEFAULT_GTM_HOST = 'https://www.googletagmanager.com';\n\nconst isString = (value: unknown): value is string => typeof value === 'string';\n\nexport const normalizeContainer = (input: ContainerConfigInput): ContainerDescriptor => {\n if (isString(input)) {\n return { id: input };\n }\n\n return input;\n};\n\nexport const normalizeContainers = (\n containers: ContainerConfigInput | ContainerConfigInput[]\n): ContainerDescriptor[] => {\n if (Array.isArray(containers)) {\n return containers.map(normalizeContainer);\n }\n\n return [normalizeContainer(containers)];\n};\n\nconst toRecord = (params?: Record<string, string | number | boolean>): Record<string, string> => {\n if (!params) {\n return {};\n }\n\n return Object.entries(params).reduce<Record<string, string>>((acc, [key, value]) => {\n acc[key] = String(value);\n return acc;\n }, {});\n};\n\nconst normalizeHost = (host: string): string => (host.endsWith('/') ? host.slice(0, -1) : host);\n\nconst buildUrl = (\n kind: 'gtm' | 'ns',\n host: string,\n containerId: string,\n queryParams?: Record<string, string | number | boolean>,\n dataLayerName: string = DEFAULT_DATA_LAYER_NAME\n): string => {\n const normalizedHost = normalizeHost(host);\n const searchParams = new URLSearchParams({ id: containerId });\n\n const params = toRecord(queryParams);\n if (dataLayerName !== DEFAULT_DATA_LAYER_NAME && params.l === undefined) {\n params.l = dataLayerName;\n }\n\n for (const [key, value] of Object.entries(params)) {\n if (key === 'id') {\n continue;\n }\n searchParams.set(key, value);\n }\n\n const suffix = kind === 'gtm' ? 'gtm.js' : 'ns.html';\n return `${normalizedHost}/${suffix}?${searchParams.toString()}`;\n};\n\nexport const buildScriptUrl = (\n host: string,\n containerId: string,\n queryParams?: Record<string, string | number | boolean>,\n dataLayerName: string = DEFAULT_DATA_LAYER_NAME\n): string => buildUrl('gtm', host, containerId, queryParams, dataLayerName);\n\nexport const buildNoscriptUrl = (\n host: string,\n containerId: string,\n queryParams?: Record<string, string | number | boolean>,\n dataLayerName: string = DEFAULT_DATA_LAYER_NAME\n): string => buildUrl('ns', host, containerId, queryParams, dataLayerName);\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput } from '@jwiedeman/gtm-kit';\nimport { DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES } from '@jwiedeman/gtm-kit';\nimport { buildNoscriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmNoScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n iframeAttributes?: Record<string, string | number | boolean>;\n dataLayerName?: string;\n}\n\nconst toStringValue = (value: string | number | boolean): string => String(value);\n\nconst parseStyle = (style: string): React.CSSProperties => {\n return style\n .split(';')\n .map((chunk) => chunk.trim())\n .filter(Boolean)\n .reduce<React.CSSProperties>((acc, declaration) => {\n const [property, rawValue] = declaration.split(':');\n if (!property || rawValue === undefined) {\n return acc;\n }\n\n const key = property.trim().replace(/-([a-z])/g, (_, char: string) => char.toUpperCase());\n const value = rawValue.trim();\n if (!key || !value) {\n return acc;\n }\n\n (acc as Record<string, string>)[key] = value;\n return acc;\n }, {});\n};\n\nexport const GtmNoScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n iframeAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmNoScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render noscript markup.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM noscript markup.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildNoscriptUrl(host, container.id, params, dataLayerName);\n const attributes = {\n ...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n ...iframeAttributes\n };\n\n const iframeProps: React.IframeHTMLAttributes<HTMLIFrameElement> = {\n src\n };\n\n for (const [attribute, value] of Object.entries(attributes)) {\n if (attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n if (attribute === 'style') {\n if (typeof value === 'string') {\n iframeProps.style = parseStyle(value);\n } else if (typeof value === 'object') {\n iframeProps.style = value as React.CSSProperties;\n }\n continue;\n }\n\n (iframeProps as Record<string, unknown>)[attribute] = toStringValue(value as string | number | boolean);\n }\n\n return (\n <noscript key={container.id}>\n <iframe {...iframeProps} />\n </noscript>\n );\n })}\n </>\n );\n};\n"]}
1
+ {"version":3,"sources":["../src/route-listener.ts","../src/head-script.tsx","../src/internal/container-helpers.ts","../src/noscript.tsx"],"names":["useCallback","useEffect","useMemo","useRef","usePathname","useSearchParams","pushEvent","DEFAULT_EVENT_NAME","defaultBuildPayload","pagePath","url","title","payload","buildUrl","hash","_a","origin","sanitizeHash","useTrackPageViews","client","eventName","buildPayload","includeSearchParams","trackHash","trackOnMount","skipSamePath","pushEventFn","waitForReady","readyPromise","pathname","searchParams","search","previousRef","hasTrackedRef","pendingKeyRef","readinessRef","isMountedRef","logFailures","states","failed","state","details","handleRouteChange","nextPathname","searchValue","rawHash","normalizedHash","key","previous","pushPayload","error","listener","DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","normalizeContainer","normalizeContainers","buildGtmScriptUrl","buildGtmNoscriptUrl","Fragment","jsx","DEFAULT_ASYNC","GtmHeadScript","containers","host","defaultQueryParams","scriptAttributes","dataLayerName","normalized","container","params","src","asyncAttr","defer","nonce","restAttributes","scriptProps","attribute","value","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","toStringValue","parseStyle","style","chunk","acc","declaration","property","rawValue","_","char","GtmNoScript","iframeAttributes","attributes","iframeProps"],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { usePathname, useSearchParams } from 'next/navigation';\nimport type { GtmClient, PageViewPayload, ScriptLoadState } from '@jwiedeman/gtm-kit';\nimport { pushEvent } from '@jwiedeman/gtm-kit';\n\nconst DEFAULT_EVENT_NAME = 'page_view';\n\nexport interface RouteLocationSnapshot {\n pathname: string;\n search: string;\n hash: string;\n pagePath: string;\n url: string;\n}\n\nexport interface RouteChangeEventDetails extends RouteLocationSnapshot {\n title?: string;\n previous?: RouteLocationSnapshot;\n}\n\nexport type PageViewPayloadBuilder = (details: RouteChangeEventDetails) => PageViewPayload;\n\nexport interface UseTrackPageViewsOptions {\n client: Pick<GtmClient, 'push' | 'whenReady'>;\n eventName?: string;\n buildPayload?: PageViewPayloadBuilder;\n includeSearchParams?: boolean;\n trackHash?: boolean;\n trackOnMount?: boolean;\n skipSamePath?: boolean;\n pushEventFn?: typeof pushEvent;\n waitForReady?: boolean;\n readyPromise?: Promise<ScriptLoadState[]>;\n}\n\ninterface RouteSnapshot extends RouteLocationSnapshot {\n key: string;\n}\n\nconst defaultBuildPayload: PageViewPayloadBuilder = ({ pagePath, url, title }) => {\n const payload: PageViewPayload = {\n page_path: pagePath,\n page_location: url\n };\n\n if (title) {\n payload.page_title = title;\n }\n\n return payload;\n};\n\nconst buildUrl = (pagePath: string, hash: string): string => {\n const origin = typeof window !== 'undefined' && window.location?.origin ? window.location.origin : '';\n if (!origin) {\n return `${pagePath}${hash}`;\n }\n\n return `${origin}${pagePath}${hash}`;\n};\n\nconst sanitizeHash = (hash: string): string => (hash && hash.startsWith('#') ? hash : hash ? `#${hash}` : '');\n\nexport const useTrackPageViews = ({\n client,\n eventName = DEFAULT_EVENT_NAME,\n buildPayload = defaultBuildPayload,\n includeSearchParams = true,\n trackHash = false,\n trackOnMount = true,\n skipSamePath = true,\n pushEventFn = pushEvent,\n waitForReady = false,\n readyPromise\n}: UseTrackPageViewsOptions): void => {\n if (!client) {\n throw new Error('A GTM client is required to track page views.');\n }\n\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const search = useMemo(() => {\n if (!includeSearchParams || !searchParams) {\n return '';\n }\n\n return searchParams.toString();\n }, [includeSearchParams, searchParams]);\n\n const previousRef = useRef<RouteSnapshot | null>(null);\n const hasTrackedRef = useRef(false);\n const pendingKeyRef = useRef<string | null>(null);\n const readinessRef = useRef<Promise<ScriptLoadState[]> | null>(\n waitForReady ? (readyPromise ?? client.whenReady()) : null\n );\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n readinessRef.current = waitForReady ? (readyPromise ?? client.whenReady()) : null;\n }, [client, readyPromise, waitForReady]);\n\n const logFailures = useCallback((states: ScriptLoadState[]) => {\n const failed = states.filter((state) => state.status === 'failed');\n if (!failed.length) {\n return;\n }\n\n const details = failed.map((state) => state.containerId).join(', ');\n // eslint-disable-next-line no-console\n console.error(`[react-gtm-kit] Failed to load GTM container script(s): ${details}`, failed);\n }, []);\n\n const handleRouteChange = useCallback(\n (nextPathname: string | null, searchValue: string, rawHash: string) => {\n if (!nextPathname) {\n return;\n }\n\n const normalizedHash = trackHash ? sanitizeHash(rawHash) : '';\n const pagePath = searchValue ? `${nextPathname}?${searchValue}` : nextPathname;\n const key = `${pagePath}${normalizedHash}`;\n const url = buildUrl(pagePath, normalizedHash);\n\n if (!trackOnMount && !hasTrackedRef.current) {\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n return;\n }\n\n if (skipSamePath && previousRef.current && previousRef.current.key === key) {\n return;\n }\n\n const title = typeof document !== 'undefined' ? document.title : undefined;\n const previous = previousRef.current\n ? {\n pathname: previousRef.current.pathname,\n search: previousRef.current.search,\n hash: previousRef.current.hash,\n pagePath: previousRef.current.pagePath,\n url: previousRef.current.url\n }\n : undefined;\n\n const details: RouteChangeEventDetails = {\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url,\n title,\n previous\n };\n\n const pushPayload = (): void => {\n const payload = buildPayload(details);\n pushEventFn(client, eventName, payload);\n\n previousRef.current = {\n key,\n pathname: nextPathname,\n search: searchValue,\n hash: normalizedHash,\n pagePath,\n url\n };\n hasTrackedRef.current = true;\n };\n\n if (waitForReady && readinessRef.current) {\n pendingKeyRef.current = key;\n readinessRef.current\n .then((states) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n\n logFailures(states);\n pushPayload();\n })\n .catch((error) => {\n if (!isMountedRef.current || pendingKeyRef.current !== key) {\n return;\n }\n // eslint-disable-next-line no-console\n console.error('[react-gtm-kit] Error while waiting for GTM readiness.', error);\n pushPayload();\n });\n\n return;\n }\n\n pushPayload();\n },\n [buildPayload, client, eventName, logFailures, pushEventFn, skipSamePath, trackHash, trackOnMount, waitForReady]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const hash = trackHash ? (window.location.hash ?? '') : '';\n handleRouteChange(pathname, search, hash);\n }, [handleRouteChange, pathname, search, trackHash]);\n\n useEffect(() => {\n if (!trackHash || typeof window === 'undefined') {\n return;\n }\n\n const listener = (): void => {\n handleRouteChange(pathname, search, window.location.hash ?? '');\n };\n\n window.addEventListener('hashchange', listener);\n return () => {\n window.removeEventListener('hashchange', listener);\n };\n }, [handleRouteChange, pathname, search, trackHash]);\n};\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';\nimport { buildScriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmHeadScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n scriptAttributes?: ScriptAttributes;\n dataLayerName?: string;\n}\n\nconst DEFAULT_ASYNC = true;\n\nexport const GtmHeadScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n scriptAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmHeadScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render script tags.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM script tags.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildScriptUrl(host, container.id, params, dataLayerName);\n const { async: asyncAttr, defer, nonce, ...restAttributes } = scriptAttributes ?? {};\n\n const scriptProps: React.ScriptHTMLAttributes<HTMLScriptElement> = {\n src,\n async: asyncAttr ?? DEFAULT_ASYNC\n };\n\n if (defer !== undefined) {\n scriptProps.defer = defer;\n }\n\n if (nonce) {\n scriptProps.nonce = nonce;\n }\n\n for (const [attribute, value] of Object.entries(restAttributes)) {\n if (attribute === 'async' || attribute === 'defer' || attribute === 'nonce' || attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n (scriptProps as Record<string, unknown>)[attribute] = value;\n }\n\n return <script key={container.id} data-gtm-container-id={container.id} {...scriptProps} />;\n })}\n </>\n );\n};\n","// Re-export URL utilities from core for internal use\nexport {\n DEFAULT_GTM_HOST,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n} from '@jwiedeman/gtm-kit';\n","import type React from 'react';\nimport { DEFAULT_DATA_LAYER_NAME } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput } from '@jwiedeman/gtm-kit';\nimport { DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES } from '@jwiedeman/gtm-kit';\nimport { buildNoscriptUrl, DEFAULT_GTM_HOST, normalizeContainers } from './internal/container-helpers';\n\nexport interface GtmNoScriptProps {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n iframeAttributes?: Record<string, string | number | boolean>;\n dataLayerName?: string;\n}\n\nconst toStringValue = (value: string | number | boolean): string => String(value);\n\nconst parseStyle = (style: string): React.CSSProperties => {\n return style\n .split(';')\n .map((chunk) => chunk.trim())\n .filter(Boolean)\n .reduce<React.CSSProperties>((acc, declaration) => {\n const [property, rawValue] = declaration.split(':');\n if (!property || rawValue === undefined) {\n return acc;\n }\n\n const key = property.trim().replace(/-([a-z])/g, (_, char: string) => char.toUpperCase());\n const value = rawValue.trim();\n if (!key || !value) {\n return acc;\n }\n\n (acc as Record<string, string>)[key] = value;\n return acc;\n }, {});\n};\n\nexport const GtmNoScript = ({\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n iframeAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n}: GtmNoScriptProps): React.ReactElement => {\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required to render noscript markup.');\n }\n\n return (\n <>\n {normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required to render GTM noscript markup.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildNoscriptUrl(host, container.id, params, dataLayerName);\n const attributes = {\n ...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n ...iframeAttributes\n };\n\n const iframeProps: React.IframeHTMLAttributes<HTMLIFrameElement> = {\n src\n };\n\n for (const [attribute, value] of Object.entries(attributes)) {\n if (attribute === 'src') {\n continue;\n }\n\n if (value === undefined || value === null) {\n continue;\n }\n\n if (attribute === 'style') {\n if (typeof value === 'string') {\n iframeProps.style = parseStyle(value);\n } else if (typeof value === 'object') {\n iframeProps.style = value as React.CSSProperties;\n }\n continue;\n }\n\n (iframeProps as Record<string, unknown>)[attribute] = toStringValue(value as string | number | boolean);\n }\n\n return (\n <noscript key={container.id}>\n <iframe {...iframeProps} />\n </noscript>\n );\n })}\n </>\n );\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jwiedeman/gtm-kit-next",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Next.js App Router helpers for GTM Kit - Google Tag Manager integration.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,7 +41,7 @@
41
41
  "typecheck": "tsc --noEmit"
42
42
  },
43
43
  "dependencies": {
44
- "@jwiedeman/gtm-kit": "^1.1.1"
44
+ "@jwiedeman/gtm-kit": "^1.1.3"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "next": "^13.4.0 || ^14.0.0 || ^15.0.0",