@jwiedeman/gtm-kit-next 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5,7 +5,7 @@ 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 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:g=!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(g?s!=null?s:t.whenReady():null),T=react.useRef(!0);react.useEffect(()=>(T.current=!0,()=>{T.current=!1;}),[]),react.useEffect(()=>{k.current=g?s!=null?s:t.whenReady():null;},[t,s,g]);let D=react.useCallback(d=>{let c=d.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((d,c,v)=>{if(!d)return;let w=i?J(v):"",C=c?`${d}?${c}`:d,R=`${C}${w}`,G=K(C,w);if(!l&&!h.current){a.current={key:R,pathname:d,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:d,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:d,search:c,hash:w,pagePath:C,url:G},h.current=!0;};if(g&&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,g]);react.useEffect(()=>{var c;if(typeof window=="undefined")return;let d=i&&(c=window.location.hash)!=null?c:"";E(u,p,d);},[E,u,p,i]),react.useEffect(()=>{if(!i||typeof window=="undefined")return;let d=()=>{var c;E(u,p,(c=window.location.hash)!=null?c:"");};return window.addEventListener("hashchange",d),()=>{window.removeEventListener("hashchange",d);}},[E,u,p,i]);};var 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=gtmKit.DEFAULT_GTM_HOST,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},g=$(e,o.id,f,i),{async:s,defer:u,nonce:m,...p}=r!=null?r:{},a={src:g,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,g)=>g.toUpperCase()),o=i.trim();return !l||!o||(e[l]=o),e},{}),pt=({containers:t,host:e=gtmKit.DEFAULT_GTM_HOST,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},g=H(e,o.id,f,i),s={...gtmKit.DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...r},u={src:g};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)})})};
9
9
 
10
10
  exports.GtmHeadScript = ot;
11
11
  exports.GtmNoScript = pt;
@@ -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","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, DEFAULT_GTM_HOST } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ContainerDescriptor } from '@jwiedeman/gtm-kit';\n\n// Re-export for convenience\nexport { DEFAULT_GTM_HOST };\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"]}
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
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, DEFAULT_GTM_HOST, DEFAULT_DATA_LAYER_NAME, 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 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:g=!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(g?s!=null?s:t.whenReady():null),T=useRef(!0);useEffect(()=>(T.current=!0,()=>{T.current=!1;}),[]),useEffect(()=>{k.current=g?s!=null?s:t.whenReady():null;},[t,s,g]);let D=useCallback(d=>{let c=d.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((d,c,v)=>{if(!d)return;let w=i?J(v):"",C=c?`${d}?${c}`:d,R=`${C}${w}`,G=K(C,w);if(!l&&!h.current){a.current={key:R,pathname:d,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:d,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:d,search:c,hash:w,pagePath:C,url:G},h.current=!0;};if(g&&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,g]);useEffect(()=>{var c;if(typeof window=="undefined")return;let d=i&&(c=window.location.hash)!=null?c:"";E(u,p,d);},[E,u,p,i]),useEffect(()=>{if(!i||typeof window=="undefined")return;let d=()=>{var c;E(u,p,(c=window.location.hash)!=null?c:"");};return window.addEventListener("hashchange",d),()=>{window.removeEventListener("hashchange",d);}},[E,u,p,i]);};var 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=DEFAULT_GTM_HOST,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},g=$(e,o.id,f,i),{async:s,defer:u,nonce:m,...p}=r!=null?r:{},a={src:g,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,g)=>g.toUpperCase()),o=i.trim();return !l||!o||(e[l]=o),e},{}),pt=({containers:t,host:e=DEFAULT_GTM_HOST,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},g=H(e,o.id,f,i),s={...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...r},u={src:g};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)})})};
7
7
 
8
8
  export { ot as GtmHeadScript, pt as GtmNoScript, X as useTrackPageViews };
9
9
  //# sourceMappingURL=out.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","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, DEFAULT_GTM_HOST } from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ContainerDescriptor } from '@jwiedeman/gtm-kit';\n\n// Re-export for convenience\nexport { DEFAULT_GTM_HOST };\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jwiedeman/gtm-kit-next",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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.0"
44
+ "@jwiedeman/gtm-kit": "^1.1.2"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "next": "^13.4.0 || ^14.0.0 || ^15.0.0",