@tiendanube/live-state 1.0.0-beta.4 → 1.0.0-beta.7

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
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`react`);c=s(c,1);let l=require(`swr`);l=s(l,1);let u=require(`@amplitude/analytics-browser`);u=s(u,1);let d=require(`react/jsx-runtime`),f=require(`@nimbus-ds/components`),p=require(`@nimbus-ds/icons`);function m(e){try{if(!e){console.warn(`[LiveState] Amplitude API key not provided`);return}u.init(e,{defaultTracking:!1})}catch(e){console.warn(`[LiveState] Failed to initialize Amplitude:`,e)}}async function h(e){try{if(window.clarity){console.log(`[LiveState] Clarity already initialized by client`);return}let t=e||g();if(!t){console.warn(`[LiveState] Clarity project ID not provided`);return}(await import(`@microsoft/clarity`)).default.init(t)}catch(e){console.warn(`[LiveState] Failed to initialize Clarity:`,e)}}function g(){try{let e=document.querySelector(`script[src*="clarity.ms"]`);if(e)return e.getAttribute(`src`)?.match(/\/([a-z0-9]+)$/)?.[1];let t=window.clarity?.q?.[0]?.[1];if(typeof t==`string`)return t}catch{}}function _(e,t){try{u.track(e,t)}catch(e){console.warn(`[LiveState] Failed to track Amplitude event:`,e)}}function v(e,t){try{window.clarity&&(window.clarity(`event`,e),t&&Object.entries(t).forEach(([e,t])=>{window.clarity?.(`set`,e,String(t))}))}catch(e){console.warn(`[LiveState] Failed to track Clarity event:`,e)}}function y(e){return Object.fromEntries(Object.entries(e).filter(e=>e[1]!==void 0))}function b(e,t){_(e,t),v(e,t)}var x=(0,c.createContext)(null);function S({children:e,fetcher:t,analytics:n}){return(0,c.useEffect)(()=>{n?.amplitudeKey&&m(n.amplitudeKey),n?.clarityProjectId&&h(n.clarityProjectId)},[n]),(0,d.jsx)(l.SWRConfig,{value:{provider:()=>new Map},children:(0,d.jsx)(x.Provider,{value:{fetcher:t,analytics:n},children:e})})}function C(){let e=(0,c.useContext)(x);if(!e)throw Error(`useLiveState must be used within LiveStateProvider`);return e}function w(){let{fetcher:e}=C(),{data:t,error:n,isLoading:r,mutate:i}=(0,l.default)(`live-state`,e,{revalidateOnFocus:!1,revalidateOnReconnect:!0,dedupingInterval:6e4,shouldRetryOnError:!1,onError:e=>{console.warn(`[LiveState] Failed to fetch live state:`,e)}});return{liveState:t??null,isLoading:r,error:n??null,refresh:async()=>{try{await i()}catch(e){console.warn(`[LiveState] Failed to refresh live state:`,e)}}}}function T(e){try{switch(e.type){case`redirect`:window.location.href=e.url;break;case`whatsapp`:{let t=e.whatsappMessage?`${e.url}?text=${encodeURIComponent(e.whatsappMessage)}`:e.url;window.open(t,`_blank`);break}case`external`:window.open(e.url,`_blank`);break;default:console.warn(`[LiveState] Unknown CTA type: ${e.type}`)}}catch(e){console.warn(`[LiveState] Failed to handle CTA click:`,e)}}function E({data:e,trackingConfig:t}){let n=e.type===`alert`?`danger`:`warning`,r=()=>y({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties});return(0,c.useEffect)(()=>{b(`${t.prefix}${t.page}_${e.context}_view`,r())},[]),(0,d.jsxs)(f.Alert,{appearance:n,title:e.title,onRemove:()=>{b(`${t.prefix}${t.page}_${e.context}_close`,r())},children:[(0,d.jsx)(`p`,{dangerouslySetInnerHTML:{__html:e.message}}),(0,d.jsx)(f.Button,{appearance:`neutral`,onClick:()=>{b(`${t.prefix}${t.page}_${e.context}_click`,r()),T(e.cta)},children:e.cta.label})]})}function D({data:e,trackingConfig:t,defaultVariant:n=`blue`}){let r=e.variant||n,i=()=>y({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),a=()=>{b(`${t.prefix}${t.page}_${e.context}_click`,i()),T(e.cta)};(0,c.useEffect)(()=>{b(`${t.prefix}${t.page}_${e.context}_view`,i())},[]);let o=r===`blue`?`currentColor`:`primary-interactive`;return(0,d.jsx)(f.Card,{backgroundColor:r===`blue`?`primary-surface`:`neutral-background`,children:(0,d.jsx)(f.Card.Body,{children:(0,d.jsxs)(`div`,{style:{display:`flex`,gap:`16px`,alignItems:`flex-start`},children:[(0,d.jsx)(`div`,{style:{width:`32px`,height:`32px`,borderRadius:`50%`,display:`flex`,alignItems:`center`,justifyContent:`center`,flexShrink:0},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.ExclamationCircleIcon,{}),color:o})}),(0,d.jsxs)(`div`,{style:{flex:1},children:[(0,d.jsx)(`h3`,{style:{fontSize:`16px`,fontWeight:600,margin:`0 0 8px 0`,lineHeight:`24px`},dangerouslySetInnerHTML:{__html:e.title}}),(0,d.jsx)(`p`,{style:{fontSize:`14px`,margin:`0 0 16px 0`,lineHeight:`20px`},dangerouslySetInnerHTML:{__html:e.message}}),(0,d.jsx)(f.Button,{onClick:a,children:e.cta.label})]})]})})})}function O({data:e,loading:t,trackingConfig:n,allowedContexts:r,defaultVariant:i}){return t||!e?null:!e.context||!e.type||!e.title||!e.message||!e.cta?.label||!e.cta?.url||!e.cta?.type?(console.warn(`[LiveState] Invalid payload, missing required fields`,e),null):r&&!r.includes(e.context)?null:e.type===`alert`||e.type===`warning`?(0,d.jsx)(E,{data:e,trackingConfig:n}):e.type===`info`?(0,d.jsx)(D,{data:e,trackingConfig:n,defaultVariant:i}):(console.warn(`[LiveState] Unknown type: ${e.type}`),null)}exports.LiveStateAlert=E,exports.LiveStateInfo=D,exports.LiveStateProvider=S,exports.LiveStateRenderer=O,exports.handleCtaClick=T,exports.trackEvent=b,exports.useLiveState=w;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`react`);c=s(c,1);let l=require(`swr`);l=s(l,1);let u=require(`@amplitude/analytics-browser`);u=s(u,1);let d=require(`react/jsx-runtime`),f=require(`@nimbus-ds/components`),p=require(`@nimbus-ds/icons`);var m=u.createInstance();function h(e){try{if(!e){console.warn(`[LiveState] Amplitude API key not provided`);return}m.init(e,{defaultTracking:!1})}catch(e){console.warn(`[LiveState] Failed to initialize Amplitude:`,e)}}async function g(e){try{if(window.clarity){console.log(`[LiveState] Clarity already initialized by client`);return}let t=e||_();if(!t){console.warn(`[LiveState] Clarity project ID not provided`);return}(await import(`@microsoft/clarity`)).default.init(t)}catch(e){console.warn(`[LiveState] Failed to initialize Clarity:`,e)}}function _(){try{let e=document.querySelector(`script[src*="clarity.ms"]`);if(e)return e.getAttribute(`src`)?.match(/\/([a-z0-9]+)$/)?.[1];let t=window.clarity?.q?.[0]?.[1];if(typeof t==`string`)return t}catch{}}function v(e,t){try{m.track(e,t)}catch(e){console.warn(`[LiveState] Failed to track Amplitude event:`,e)}}function y(e,t){try{window.clarity&&(window.clarity(`event`,e),t&&Object.entries(t).forEach(([e,t])=>{window.clarity?.(`set`,e,String(t))}))}catch(e){console.warn(`[LiveState] Failed to track Clarity event:`,e)}}function b(e){return Object.fromEntries(Object.entries(e).filter(e=>e[1]!==void 0))}function x(e,t){v(e,t),y(e,t)}var S=(0,c.createContext)(null);function C({children:e,fetcher:t,analytics:n,onEvent:r}){return(0,c.useEffect)(()=>{n?.amplitudeKey&&h(n.amplitudeKey),n?.clarityProjectId&&g(n.clarityProjectId)},[n]),(0,d.jsx)(l.SWRConfig,{value:{provider:()=>new Map},children:(0,d.jsx)(S.Provider,{value:{fetcher:t,analytics:n,onEvent:r},children:e})})}function w(){let e=(0,c.useContext)(S);if(!e)throw Error(`useLiveState must be used within LiveStateProvider`);return e}function T(){let{fetcher:e}=w(),{data:t,error:n,isLoading:r,mutate:i}=(0,l.default)(`live-state`,e,{revalidateOnFocus:!1,revalidateOnReconnect:!0,dedupingInterval:6e4,shouldRetryOnError:!1,onError:e=>{console.warn(`[LiveState] Failed to fetch live state:`,e)}});return{liveState:t??null,isLoading:r,error:n??null,refresh:async()=>{try{await i()}catch(e){console.warn(`[LiveState] Failed to refresh live state:`,e)}}}}function E(){let{onEvent:e}=w();return(0,c.useCallback)((t,n)=>{e?.(t,n),x(t,n)},[e])}var D=`@tiendanube/live-state:closable`;function O(){try{let e=localStorage.getItem(D);if(!e)return{};let t=JSON.parse(e);if(typeof t!=`object`||!t)return{};let n={};for(let[e,r]of Object.entries(t))if(!(typeof r!=`object`||!r)){n[e]={};for(let[t,i]of Object.entries(r))if(typeof i==`number`)n[e][t]={count:i,closedAt:0};else if(typeof i==`object`&&i){let r=i;n[e][t]={count:typeof r.count==`number`?r.count:0,closedAt:typeof r.closedAt==`number`?r.closedAt:0}}}return n}catch{return{}}}function k(e){try{localStorage.setItem(D,JSON.stringify(e))}catch{}}function A({context:e,id:t,maxCloseTimes:n=3,expiresIn:r}){let[i,a]=(0,c.useState)(null);return(0,c.useEffect)(()=>{if(!t){a(!0);return}let i=O(),o=i[e]?.[t];if(!o){a(!0);return}let{count:s,closedAt:c}=o;if(r!=null&&c>0&&Date.now()-c>r){let n={...i};n[e]&&(delete n[e][t],k(n)),a(!0);return}a(s<n)},[e,t,n,r]),{isVisible:i,close:(0,c.useCallback)(()=>{if(!t)return;let n=O(),r=n[e]?.[t]?.count??0,i={...n,[e]:{...n[e]??{},[t]:{count:r+1,closedAt:Date.now()}}};a(!1),k(i)},[e,t])}}function j(e){try{switch(e.type){case`redirect`:window.location.href=e.url;break;case`whatsapp`:{let t=e.whatsappMessage?`${e.url}?text=${encodeURIComponent(e.whatsappMessage)}`:e.url;window.open(t,`_blank`);break}case`external`:window.open(e.url,`_blank`);break;default:console.warn(`[LiveState] Unknown CTA type: ${e.type}`)}}catch(e){console.warn(`[LiveState] Failed to handle CTA click:`,e)}}function M({data:e,trackingConfig:t,onClose:n}){let r=E(),i=e.type===`alert`?`danger`:`warning`,a=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),o=(0,c.useCallback)(()=>{r(`${t.prefix}${t.page}_${e.context}_click`,a()),j(e.cta)},[e,t,a,r]),s=(0,c.useCallback)(()=>{r(`${t.prefix}${t.page}_${e.context}_close`,a()),n?.()},[n,e,t,a,r]);return(0,c.useEffect)(()=>{r(`${t.prefix}${t.page}_${e.context}_view`,a())},[]),(0,d.jsxs)(f.Alert,{appearance:i,title:e.title,onRemove:n?s:void 0,children:[(0,d.jsx)(`p`,{dangerouslySetInnerHTML:{__html:e.message}}),(0,d.jsx)(f.Button,{appearance:`neutral`,onClick:o,children:e.cta.label})]})}function N({data:e,trackingConfig:t,defaultVariant:n=`blue`,onClose:r}){let i=E(),a=e.variant||n,o=(0,c.useCallback)(()=>b({context:e.context,campaignId:e.campaignId,group:e.group,...e.metadata,...t.properties}),[e,t.properties]),s=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_click`,o()),j(e.cta)},[e,t,o,i]),l=(0,c.useCallback)(()=>{i(`${t.prefix}${t.page}_${e.context}_close`,o()),r?.()},[r,e,t,o,i]);(0,c.useEffect)(()=>{i(`${t.prefix}${t.page}_${e.context}_view`,o())},[]);let u=a===`blue`?`currentColor`:`primary-interactive`;return(0,d.jsx)(f.Card,{backgroundColor:a===`blue`?`primary-surface`:`neutral-background`,children:(0,d.jsx)(f.Card.Body,{children:(0,d.jsxs)(`div`,{style:{display:`flex`,gap:`16px`,alignItems:`flex-start`},children:[(0,d.jsx)(`div`,{style:{width:`32px`,height:`32px`,borderRadius:`50%`,display:`flex`,alignItems:`center`,justifyContent:`center`,flexShrink:0},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.ExclamationCircleIcon,{}),color:u})}),(0,d.jsxs)(`div`,{style:{flex:1},children:[(0,d.jsx)(`h3`,{style:{fontSize:`16px`,fontWeight:600,margin:`0 0 8px 0`,lineHeight:`24px`},dangerouslySetInnerHTML:{__html:e.title}}),(0,d.jsx)(`p`,{style:{fontSize:`14px`,margin:`0 0 16px 0`,lineHeight:`20px`},dangerouslySetInnerHTML:{__html:e.message}}),(0,d.jsx)(f.Button,{onClick:s,children:e.cta.label})]}),r&&(0,d.jsx)(`button`,{onClick:l,"aria-label":`Fechar notificação`,"data-testid":`live-state-close-button`,style:{background:`none`,border:`none`,cursor:`pointer`,padding:`4px`,display:`flex`,alignItems:`center`,flexShrink:0},children:(0,d.jsx)(f.Icon,{source:(0,d.jsx)(p.CloseIcon,{size:`small`}),color:`neutral-interactive`})})]})})})}function P({data:e,loading:t,trackingConfig:n,allowedContexts:r,defaultVariant:i}){let{isVisible:a,close:o}=A({context:e?.context??``,id:e?.campaignId,maxCloseTimes:e?.metadata?.maxCloseTimes,expiresIn:e?.metadata?.expiresIn});if(t||!e)return null;if(!e.context||!e.type||!e.title||!e.message||!e.cta?.label||!e.cta?.url||!e.cta?.type)return console.warn(`[LiveState] Invalid payload, missing required fields`,e),null;if(r&&!r.includes(e.context)||a===null||!a)return null;let s=e.closable&&e.campaignId?o:void 0;return e.type===`alert`||e.type===`warning`?(0,d.jsx)(M,{data:e,onClose:s,trackingConfig:n}):e.type===`info`?(0,d.jsx)(N,{data:e,onClose:s,trackingConfig:n,defaultVariant:i}):(console.warn(`[LiveState] Unknown type: ${e.type}`),null)}exports.LiveStateAlert=M,exports.LiveStateInfo=N,exports.LiveStateProvider=C,exports.LiveStateRenderer=P,exports.handleCtaClick=j,exports.trackEvent=x,exports.useLiveState=T,exports.useTrackEvent=E;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitude.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitude.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type { LiveStateFetcher, AnalyticsConfig } from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n}: LiveStateProviderProps) {\n // Initialize analytics on mount\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useEffect } from 'react';\nimport { Alert, Button } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({ data, trackingConfig }: LiveStateAlertProps) {\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n trackEvent(eventName, buildEventProperties());\n }}>\n <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n}\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\n * Automatically tracks view, click, and close events.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n}: LiveStateInfoProps) {\n const variant = data.variant || defaultVariant;\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n </div>\n </Card.Body>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n}: LiveStateRendererProps) {\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return <LiveStateAlert data={data} trackingConfig={trackingConfig} />;\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/hooks/useTrackEvent.ts","../src/utils/closable-storage.ts","../src/hooks/useClosable.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Isolated Amplitude instance for the lib — avoids conflicts with the\n * consumer app's own Amplitude instance when both coexist on the same page.\n */\nconst amplitudeInstance = amplitude.createInstance();\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitudeInstance.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitudeInstance.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type {\n LiveStateFetcher,\n AnalyticsConfig,\n TrackingProperties,\n} from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * The optional `onEvent` callback is fired on every tracking event before\n * sending to Amplitude/Clarity — useful for simulators and debugging tools.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n onEvent,\n}: LiveStateProviderProps) {\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics, onEvent }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import { useCallback } from 'react';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport { trackEvent } from '../utils/analytics';\nimport type { TrackingProperties } from '../types';\n\n/**\n * useTrackEvent\n *\n * Returns a `track` function that fires both the internal analytics\n * (Amplitude + Clarity) and the optional `onEvent` callback provided\n * to LiveStateProvider — useful for simulators and debugging tools.\n */\nexport function useTrackEvent() {\n const { onEvent } = useLiveStateContext();\n\n const track = useCallback(\n (eventName: string, properties?: TrackingProperties) => {\n onEvent?.(eventName, properties);\n trackEvent(eventName, properties);\n },\n [onEvent],\n );\n\n return track;\n}\n","const STORAGE_KEY = '@tiendanube/live-state:closable';\n\nexport interface ClosableState {\n count: number;\n closedAt: number;\n}\n\nexport type ClosableStates = Record<string, Record<string, ClosableState>>;\n\n/**\n * Reads closable states from localStorage.\n * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).\n * Returns an empty object on any error (fail-silent).\n */\nexport function getClosableStates(): ClosableStates {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) return {};\n\n const normalized: ClosableStates = {};\n\n for (const [ctx, ctxState] of Object.entries(\n parsed as Record<string, unknown>,\n )) {\n if (typeof ctxState !== 'object' || ctxState === null) continue;\n\n normalized[ctx] = {};\n\n for (const [id, entry] of Object.entries(\n ctxState as Record<string, unknown>,\n )) {\n if (typeof entry === 'number') {\n // legacy format: plain close count\n normalized[ctx][id] = { count: entry, closedAt: 0 };\n } else if (typeof entry === 'object' && entry !== null) {\n const candidate = entry as Partial<ClosableState>;\n normalized[ctx][id] = {\n count: typeof candidate.count === 'number' ? candidate.count : 0,\n closedAt:\n typeof candidate.closedAt === 'number' ? candidate.closedAt : 0,\n };\n }\n }\n }\n\n return normalized;\n } catch {\n return {};\n }\n}\n\n/**\n * Persists closable states to localStorage.\n * Fails silently if localStorage is unavailable or full.\n */\nexport function setClosableStates(states: ClosableStates): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(states));\n } catch {\n // localStorage unavailable or quota exceeded — application continues normally\n }\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n getClosableStates,\n setClosableStates,\n} from '../utils/closable-storage';\n\nexport interface UseClosableOptions {\n /** Notification context (e.g. 'awareness', 'charge') */\n context: string;\n /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */\n id: string | undefined;\n /** Maximum number of times the user can close before it is hidden permanently */\n maxCloseTimes?: number;\n /** Milliseconds after which the close counter resets (optional) */\n expiresIn?: number;\n}\n\nexport interface UseClosableReturn {\n /** Whether the notification should be shown. null = initial check in progress. */\n isVisible: boolean | null;\n /** Call this to record a close action */\n close: () => void;\n}\n\n/**\n * Manages the close state of a notification using localStorage.\n *\n * After the user closes a notification `maxCloseTimes` times, it is hidden\n * permanently. Optionally, the counter resets after `expiresIn` milliseconds.\n *\n * Fails silently — errors in localStorage never break the application.\n *\n * @example\n * ```tsx\n * const { isVisible, close } = useClosable({\n * context: 'awareness',\n * id: 'awareness-2026-q1',\n * maxCloseTimes: 3,\n * expiresIn: 86_400_000, // 1 day\n * });\n *\n * if (!isVisible) return null;\n * return <Notification onClose={close} />;\n * ```\n */\nexport function useClosable({\n context,\n id,\n maxCloseTimes = 3,\n expiresIn,\n}: UseClosableOptions): UseClosableReturn {\n const [isVisible, setIsVisible] = useState<boolean | null>(null);\n\n useEffect(() => {\n // No ID means no close tracking — always show\n if (!id) {\n setIsVisible(true);\n return;\n }\n\n const states = getClosableStates();\n const entry = states[context]?.[id];\n\n if (!entry) {\n setIsVisible(true);\n return;\n }\n\n const { count, closedAt } = entry;\n\n // Check expiry — reset counter and show if expired\n if (expiresIn != null && closedAt > 0) {\n const elapsed = Date.now() - closedAt;\n if (elapsed > expiresIn) {\n const updated = { ...states };\n if (updated[context]) {\n delete updated[context][id];\n setClosableStates(updated);\n }\n setIsVisible(true);\n return;\n }\n }\n\n setIsVisible(count < maxCloseTimes);\n }, [context, id, maxCloseTimes, expiresIn]);\n\n const close = useCallback(() => {\n if (!id) return;\n\n const states = getClosableStates();\n const currentCount = states[context]?.[id]?.count ?? 0;\n\n const updated: typeof states = {\n ...states,\n [context]: {\n ...(states[context] ?? {}),\n [id]: {\n count: currentCount + 1,\n closedAt: Date.now(),\n },\n },\n };\n\n setIsVisible(false);\n setClosableStates(updated);\n }, [context, id]);\n\n return { isVisible, close };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useCallback, useEffect } from 'react';\nimport { Alert, Button } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({\n data,\n trackingConfig,\n onClose,\n}: LiveStateAlertProps) {\n const track = useTrackEvent();\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={onClose ? handleClose : undefined}>\n <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useCallback, useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon, CloseIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n}\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n onClose,\n}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n\n {onClose && (\n <button\n onClick={handleClose}\n aria-label=\"Fechar notificação\"\n data-testid=\"live-state-close-button\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n display: 'flex',\n alignItems: 'center',\n flexShrink: 0,\n }}>\n <Icon\n source={<CloseIcon size=\"small\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </div>\n </Card.Body>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { useClosable } from '../hooks/useClosable';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n * Handles closable notifications via useClosable when closable is configured.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n}: LiveStateRendererProps) {\n const { isVisible, close } = useClosable({\n context: data?.context ?? '',\n id: data?.campaignId,\n maxCloseTimes: data?.metadata?.maxCloseTimes,\n expiresIn: data?.metadata?.expiresIn,\n });\n\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Awaiting localStorage check\n if (isVisible === null) {\n return null;\n }\n\n // Hidden — user reached maxCloseTimes\n if (!isVisible) {\n return null;\n }\n\n // Only pass onClose when closable is configured and notification has a campaignId to track\n const onClose = data.closable && data.campaignId ? close : undefined;\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return (\n <LiveStateAlert\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n />\n );\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,28 +1,29 @@
1
- import { createContext as e, useContext as t, useEffect as n } from "react";
2
- import r, { SWRConfig as i } from "swr";
3
- import * as a from "@amplitude/analytics-browser";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
5
- import { Alert as c, Button as l, Card as u, Icon as d } from "@nimbus-ds/components";
6
- import { ExclamationCircleIcon as f } from "@nimbus-ds/icons";
1
+ import { createContext as e, useCallback as t, useContext as n, useEffect as r, useState as i } from "react";
2
+ import a, { SWRConfig as o } from "swr";
3
+ import * as s from "@amplitude/analytics-browser";
4
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
+ import { Alert as u, Button as d, Card as f, Icon as p } from "@nimbus-ds/components";
6
+ import { CloseIcon as m, ExclamationCircleIcon as h } from "@nimbus-ds/icons";
7
7
  //#region src/utils/analytics.ts
8
- function p(e) {
8
+ var g = s.createInstance();
9
+ function _(e) {
9
10
  try {
10
11
  if (!e) {
11
12
  console.warn("[LiveState] Amplitude API key not provided");
12
13
  return;
13
14
  }
14
- a.init(e, { defaultTracking: !1 });
15
+ g.init(e, { defaultTracking: !1 });
15
16
  } catch (e) {
16
17
  console.warn("[LiveState] Failed to initialize Amplitude:", e);
17
18
  }
18
19
  }
19
- async function m(e) {
20
+ async function v(e) {
20
21
  try {
21
22
  if (window.clarity) {
22
23
  console.log("[LiveState] Clarity already initialized by client");
23
24
  return;
24
25
  }
25
- let t = e || h();
26
+ let t = e || y();
26
27
  if (!t) {
27
28
  console.warn("[LiveState] Clarity project ID not provided");
28
29
  return;
@@ -32,7 +33,7 @@ async function m(e) {
32
33
  console.warn("[LiveState] Failed to initialize Clarity:", e);
33
34
  }
34
35
  }
35
- function h() {
36
+ function y() {
36
37
  try {
37
38
  let e = document.querySelector("script[src*=\"clarity.ms\"]");
38
39
  if (e) return e.getAttribute("src")?.match(/\/([a-z0-9]+)$/)?.[1];
@@ -40,14 +41,14 @@ function h() {
40
41
  if (typeof t == "string") return t;
41
42
  } catch {}
42
43
  }
43
- function g(e, t) {
44
+ function b(e, t) {
44
45
  try {
45
- a.track(e, t);
46
+ g.track(e, t);
46
47
  } catch (e) {
47
48
  console.warn("[LiveState] Failed to track Amplitude event:", e);
48
49
  }
49
50
  }
50
- function _(e, t) {
51
+ function x(e, t) {
51
52
  try {
52
53
  window.clarity && (window.clarity("event", e), t && Object.entries(t).forEach(([e, t]) => {
53
54
  window.clarity?.("set", e, String(t));
@@ -56,38 +57,39 @@ function _(e, t) {
56
57
  console.warn("[LiveState] Failed to track Clarity event:", e);
57
58
  }
58
59
  }
59
- function v(e) {
60
+ function S(e) {
60
61
  return Object.fromEntries(Object.entries(e).filter((e) => e[1] !== void 0));
61
62
  }
62
- function y(e, t) {
63
- g(e, t), _(e, t);
63
+ function C(e, t) {
64
+ b(e, t), x(e, t);
64
65
  }
65
66
  //#endregion
66
67
  //#region src/providers/LiveStateProvider.tsx
67
- var b = e(null);
68
- function x({ children: e, fetcher: t, analytics: r }) {
69
- return n(() => {
70
- r?.amplitudeKey && p(r.amplitudeKey), r?.clarityProjectId && m(r.clarityProjectId);
71
- }, [r]), /* @__PURE__ */ o(i, {
68
+ var w = e(null);
69
+ function T({ children: e, fetcher: t, analytics: n, onEvent: i }) {
70
+ return r(() => {
71
+ n?.amplitudeKey && _(n.amplitudeKey), n?.clarityProjectId && v(n.clarityProjectId);
72
+ }, [n]), /* @__PURE__ */ c(o, {
72
73
  value: { provider: () => /* @__PURE__ */ new Map() },
73
- children: /* @__PURE__ */ o(b.Provider, {
74
+ children: /* @__PURE__ */ c(w.Provider, {
74
75
  value: {
75
76
  fetcher: t,
76
- analytics: r
77
+ analytics: n,
78
+ onEvent: i
77
79
  },
78
80
  children: e
79
81
  })
80
82
  });
81
83
  }
82
- function S() {
83
- let e = t(b);
84
+ function E() {
85
+ let e = n(w);
84
86
  if (!e) throw Error("useLiveState must be used within LiveStateProvider");
85
87
  return e;
86
88
  }
87
89
  //#endregion
88
90
  //#region src/hooks/useLiveState.ts
89
- function C() {
90
- let { fetcher: e } = S(), { data: t, error: n, isLoading: i, mutate: a } = r("live-state", e, {
91
+ function D() {
92
+ let { fetcher: e } = E(), { data: t, error: n, isLoading: r, mutate: i } = a("live-state", e, {
91
93
  revalidateOnFocus: !1,
92
94
  revalidateOnReconnect: !0,
93
95
  dedupingInterval: 6e4,
@@ -98,11 +100,11 @@ function C() {
98
100
  });
99
101
  return {
100
102
  liveState: t ?? null,
101
- isLoading: i,
103
+ isLoading: r,
102
104
  error: n ?? null,
103
105
  refresh: async () => {
104
106
  try {
105
- await a();
107
+ await i();
106
108
  } catch (e) {
107
109
  console.warn("[LiveState] Failed to refresh live state:", e);
108
110
  }
@@ -110,8 +112,94 @@ function C() {
110
112
  };
111
113
  }
112
114
  //#endregion
115
+ //#region src/hooks/useTrackEvent.ts
116
+ function O() {
117
+ let { onEvent: e } = E();
118
+ return t((t, n) => {
119
+ e?.(t, n), C(t, n);
120
+ }, [e]);
121
+ }
122
+ //#endregion
123
+ //#region src/utils/closable-storage.ts
124
+ var k = "@tiendanube/live-state:closable";
125
+ function A() {
126
+ try {
127
+ let e = localStorage.getItem(k);
128
+ if (!e) return {};
129
+ let t = JSON.parse(e);
130
+ if (typeof t != "object" || !t) return {};
131
+ let n = {};
132
+ for (let [e, r] of Object.entries(t)) if (!(typeof r != "object" || !r)) {
133
+ n[e] = {};
134
+ for (let [t, i] of Object.entries(r)) if (typeof i == "number") n[e][t] = {
135
+ count: i,
136
+ closedAt: 0
137
+ };
138
+ else if (typeof i == "object" && i) {
139
+ let r = i;
140
+ n[e][t] = {
141
+ count: typeof r.count == "number" ? r.count : 0,
142
+ closedAt: typeof r.closedAt == "number" ? r.closedAt : 0
143
+ };
144
+ }
145
+ }
146
+ return n;
147
+ } catch {
148
+ return {};
149
+ }
150
+ }
151
+ function j(e) {
152
+ try {
153
+ localStorage.setItem(k, JSON.stringify(e));
154
+ } catch {}
155
+ }
156
+ //#endregion
157
+ //#region src/hooks/useClosable.ts
158
+ function M({ context: e, id: n, maxCloseTimes: a = 3, expiresIn: o }) {
159
+ let [s, c] = i(null);
160
+ return r(() => {
161
+ if (!n) {
162
+ c(!0);
163
+ return;
164
+ }
165
+ let t = A(), r = t[e]?.[n];
166
+ if (!r) {
167
+ c(!0);
168
+ return;
169
+ }
170
+ let { count: i, closedAt: s } = r;
171
+ if (o != null && s > 0 && Date.now() - s > o) {
172
+ let r = { ...t };
173
+ r[e] && (delete r[e][n], j(r)), c(!0);
174
+ return;
175
+ }
176
+ c(i < a);
177
+ }, [
178
+ e,
179
+ n,
180
+ a,
181
+ o
182
+ ]), {
183
+ isVisible: s,
184
+ close: t(() => {
185
+ if (!n) return;
186
+ let t = A(), r = t[e]?.[n]?.count ?? 0, i = {
187
+ ...t,
188
+ [e]: {
189
+ ...t[e] ?? {},
190
+ [n]: {
191
+ count: r + 1,
192
+ closedAt: Date.now()
193
+ }
194
+ }
195
+ };
196
+ c(!1), j(i);
197
+ }, [e, n])
198
+ };
199
+ }
200
+ //#endregion
113
201
  //#region src/utils/cta.ts
114
- function w(e) {
202
+ function N(e) {
115
203
  try {
116
204
  switch (e.type) {
117
205
  case "redirect":
@@ -133,111 +221,168 @@ function w(e) {
133
221
  }
134
222
  //#endregion
135
223
  //#region src/components/LiveStateAlert.tsx
136
- function T({ data: e, trackingConfig: t }) {
137
- let r = e.type === "alert" ? "danger" : "warning", i = () => v({
224
+ function P({ data: e, trackingConfig: n, onClose: i }) {
225
+ let a = O(), o = e.type === "alert" ? "danger" : "warning", s = t(() => S({
138
226
  context: e.context,
139
227
  campaignId: e.campaignId,
140
228
  group: e.group,
141
229
  ...e.metadata,
142
- ...t.properties
143
- });
144
- return n(() => {
145
- y(`${t.prefix}${t.page}_${e.context}_view`, i());
146
- }, []), /* @__PURE__ */ s(c, {
147
- appearance: r,
230
+ ...n.properties
231
+ }), [e, n.properties]), f = t(() => {
232
+ a(`${n.prefix}${n.page}_${e.context}_click`, s()), N(e.cta);
233
+ }, [
234
+ e,
235
+ n,
236
+ s,
237
+ a
238
+ ]), p = t(() => {
239
+ a(`${n.prefix}${n.page}_${e.context}_close`, s()), i?.();
240
+ }, [
241
+ i,
242
+ e,
243
+ n,
244
+ s,
245
+ a
246
+ ]);
247
+ return r(() => {
248
+ a(`${n.prefix}${n.page}_${e.context}_view`, s());
249
+ }, []), /* @__PURE__ */ l(u, {
250
+ appearance: o,
148
251
  title: e.title,
149
- onRemove: () => {
150
- y(`${t.prefix}${t.page}_${e.context}_close`, i());
151
- },
152
- children: [/* @__PURE__ */ o("p", { dangerouslySetInnerHTML: { __html: e.message } }), /* @__PURE__ */ o(l, {
252
+ onRemove: i ? p : void 0,
253
+ children: [/* @__PURE__ */ c("p", { dangerouslySetInnerHTML: { __html: e.message } }), /* @__PURE__ */ c(d, {
153
254
  appearance: "neutral",
154
- onClick: () => {
155
- y(`${t.prefix}${t.page}_${e.context}_click`, i()), w(e.cta);
156
- },
255
+ onClick: f,
157
256
  children: e.cta.label
158
257
  })]
159
258
  });
160
259
  }
161
260
  //#endregion
162
261
  //#region src/components/LiveStateInfo.tsx
163
- function E({ data: e, trackingConfig: t, defaultVariant: r = "blue" }) {
164
- let i = e.variant || r, a = () => v({
262
+ function F({ data: e, trackingConfig: n, defaultVariant: i = "blue", onClose: a }) {
263
+ let o = O(), s = e.variant || i, u = t(() => S({
165
264
  context: e.context,
166
265
  campaignId: e.campaignId,
167
266
  group: e.group,
168
267
  ...e.metadata,
169
- ...t.properties
170
- }), c = () => {
171
- y(`${t.prefix}${t.page}_${e.context}_click`, a()), w(e.cta);
172
- };
173
- n(() => {
174
- y(`${t.prefix}${t.page}_${e.context}_view`, a());
268
+ ...n.properties
269
+ }), [e, n.properties]), g = t(() => {
270
+ o(`${n.prefix}${n.page}_${e.context}_click`, u()), N(e.cta);
271
+ }, [
272
+ e,
273
+ n,
274
+ u,
275
+ o
276
+ ]), _ = t(() => {
277
+ o(`${n.prefix}${n.page}_${e.context}_close`, u()), a?.();
278
+ }, [
279
+ a,
280
+ e,
281
+ n,
282
+ u,
283
+ o
284
+ ]);
285
+ r(() => {
286
+ o(`${n.prefix}${n.page}_${e.context}_view`, u());
175
287
  }, []);
176
- let p = i === "blue" ? "currentColor" : "primary-interactive";
177
- return /* @__PURE__ */ o(u, {
178
- backgroundColor: i === "blue" ? "primary-surface" : "neutral-background",
179
- children: /* @__PURE__ */ o(u.Body, { children: /* @__PURE__ */ s("div", {
288
+ let v = s === "blue" ? "currentColor" : "primary-interactive";
289
+ return /* @__PURE__ */ c(f, {
290
+ backgroundColor: s === "blue" ? "primary-surface" : "neutral-background",
291
+ children: /* @__PURE__ */ c(f.Body, { children: /* @__PURE__ */ l("div", {
180
292
  style: {
181
293
  display: "flex",
182
294
  gap: "16px",
183
295
  alignItems: "flex-start"
184
296
  },
185
- children: [/* @__PURE__ */ o("div", {
186
- style: {
187
- width: "32px",
188
- height: "32px",
189
- borderRadius: "50%",
190
- display: "flex",
191
- alignItems: "center",
192
- justifyContent: "center",
193
- flexShrink: 0
194
- },
195
- children: /* @__PURE__ */ o(d, {
196
- source: /* @__PURE__ */ o(f, {}),
197
- color: p
198
- })
199
- }), /* @__PURE__ */ s("div", {
200
- style: { flex: 1 },
201
- children: [
202
- /* @__PURE__ */ o("h3", {
203
- style: {
204
- fontSize: "16px",
205
- fontWeight: 600,
206
- margin: "0 0 8px 0",
207
- lineHeight: "24px"
208
- },
209
- dangerouslySetInnerHTML: { __html: e.title }
210
- }),
211
- /* @__PURE__ */ o("p", {
212
- style: {
213
- fontSize: "14px",
214
- margin: "0 0 16px 0",
215
- lineHeight: "20px"
216
- },
217
- dangerouslySetInnerHTML: { __html: e.message }
218
- }),
219
- /* @__PURE__ */ o(l, {
220
- onClick: c,
221
- children: e.cta.label
297
+ children: [
298
+ /* @__PURE__ */ c("div", {
299
+ style: {
300
+ width: "32px",
301
+ height: "32px",
302
+ borderRadius: "50%",
303
+ display: "flex",
304
+ alignItems: "center",
305
+ justifyContent: "center",
306
+ flexShrink: 0
307
+ },
308
+ children: /* @__PURE__ */ c(p, {
309
+ source: /* @__PURE__ */ c(h, {}),
310
+ color: v
222
311
  })
223
- ]
224
- })]
312
+ }),
313
+ /* @__PURE__ */ l("div", {
314
+ style: { flex: 1 },
315
+ children: [
316
+ /* @__PURE__ */ c("h3", {
317
+ style: {
318
+ fontSize: "16px",
319
+ fontWeight: 600,
320
+ margin: "0 0 8px 0",
321
+ lineHeight: "24px"
322
+ },
323
+ dangerouslySetInnerHTML: { __html: e.title }
324
+ }),
325
+ /* @__PURE__ */ c("p", {
326
+ style: {
327
+ fontSize: "14px",
328
+ margin: "0 0 16px 0",
329
+ lineHeight: "20px"
330
+ },
331
+ dangerouslySetInnerHTML: { __html: e.message }
332
+ }),
333
+ /* @__PURE__ */ c(d, {
334
+ onClick: g,
335
+ children: e.cta.label
336
+ })
337
+ ]
338
+ }),
339
+ a && /* @__PURE__ */ c("button", {
340
+ onClick: _,
341
+ "aria-label": "Fechar notificação",
342
+ "data-testid": "live-state-close-button",
343
+ style: {
344
+ background: "none",
345
+ border: "none",
346
+ cursor: "pointer",
347
+ padding: "4px",
348
+ display: "flex",
349
+ alignItems: "center",
350
+ flexShrink: 0
351
+ },
352
+ children: /* @__PURE__ */ c(p, {
353
+ source: /* @__PURE__ */ c(m, { size: "small" }),
354
+ color: "neutral-interactive"
355
+ })
356
+ })
357
+ ]
225
358
  }) })
226
359
  });
227
360
  }
228
361
  //#endregion
229
362
  //#region src/components/LiveStateRenderer.tsx
230
- function D({ data: e, loading: t, trackingConfig: n, allowedContexts: r, defaultVariant: i }) {
231
- return t || !e ? null : !e.context || !e.type || !e.title || !e.message || !e.cta?.label || !e.cta?.url || !e.cta?.type ? (console.warn("[LiveState] Invalid payload, missing required fields", e), null) : r && !r.includes(e.context) ? null : e.type === "alert" || e.type === "warning" ? /* @__PURE__ */ o(T, {
363
+ function I({ data: e, loading: t, trackingConfig: n, allowedContexts: r, defaultVariant: i }) {
364
+ let { isVisible: a, close: o } = M({
365
+ context: e?.context ?? "",
366
+ id: e?.campaignId,
367
+ maxCloseTimes: e?.metadata?.maxCloseTimes,
368
+ expiresIn: e?.metadata?.expiresIn
369
+ });
370
+ if (t || !e) return null;
371
+ if (!e.context || !e.type || !e.title || !e.message || !e.cta?.label || !e.cta?.url || !e.cta?.type) return console.warn("[LiveState] Invalid payload, missing required fields", e), null;
372
+ if (r && !r.includes(e.context) || a === null || !a) return null;
373
+ let s = e.closable && e.campaignId ? o : void 0;
374
+ return e.type === "alert" || e.type === "warning" ? /* @__PURE__ */ c(P, {
232
375
  data: e,
376
+ onClose: s,
233
377
  trackingConfig: n
234
- }) : e.type === "info" ? /* @__PURE__ */ o(E, {
378
+ }) : e.type === "info" ? /* @__PURE__ */ c(F, {
235
379
  data: e,
380
+ onClose: s,
236
381
  trackingConfig: n,
237
382
  defaultVariant: i
238
383
  }) : (console.warn(`[LiveState] Unknown type: ${e.type}`), null);
239
384
  }
240
385
  //#endregion
241
- export { T as LiveStateAlert, E as LiveStateInfo, x as LiveStateProvider, D as LiveStateRenderer, w as handleCtaClick, y as trackEvent, C as useLiveState };
386
+ export { P as LiveStateAlert, F as LiveStateInfo, T as LiveStateProvider, I as LiveStateRenderer, N as handleCtaClick, C as trackEvent, D as useLiveState, O as useTrackEvent };
242
387
 
243
388
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitude.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitude.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type { LiveStateFetcher, AnalyticsConfig } from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n}: LiveStateProviderProps) {\n // Initialize analytics on mount\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useEffect } from 'react';\nimport { Alert, Button } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({ data, trackingConfig }: LiveStateAlertProps) {\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n trackEvent(eventName, buildEventProperties());\n }}>\n <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { trackEvent, buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n}\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\n * Automatically tracks view, click, and close events.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n}: LiveStateInfoProps) {\n const variant = data.variant || defaultVariant;\n\n const buildEventProperties = () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n });\n\n const handleClick = () => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n trackEvent(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n };\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n trackEvent(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n </div>\n </Card.Body>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n}: LiveStateRendererProps) {\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return <LiveStateAlert data={data} trackingConfig={trackingConfig} />;\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/utils/analytics.ts","../src/providers/LiveStateProvider.tsx","../src/hooks/useLiveState.ts","../src/hooks/useTrackEvent.ts","../src/utils/closable-storage.ts","../src/hooks/useClosable.ts","../src/utils/cta.ts","../src/components/LiveStateAlert.tsx","../src/components/LiveStateInfo.tsx","../src/components/LiveStateRenderer.tsx"],"sourcesContent":["import * as amplitude from '@amplitude/analytics-browser';\nimport type { TrackingProperties, TrackingValue } from '../types';\n\n/**\n * Isolated Amplitude instance for the lib — avoids conflicts with the\n * consumer app's own Amplitude instance when both coexist on the same page.\n */\nconst amplitudeInstance = amplitude.createInstance();\n\n/**\n * Initialize Amplitude (fail silently)\n */\nexport function initializeAmplitude(apiKey: string): void {\n try {\n if (!apiKey) {\n console.warn('[LiveState] Amplitude API key not provided');\n return;\n }\n\n amplitudeInstance.init(apiKey, {\n defaultTracking: false,\n });\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Amplitude:', error);\n }\n}\n\n/**\n * Initialize Clarity (fail silently)\n */\nexport async function initializeClarity(projectId?: string): Promise<void> {\n try {\n // Check if Clarity is already loaded by the client\n if (window.clarity) {\n console.log('[LiveState] Clarity already initialized by client');\n return;\n }\n\n // If client provided project ID, use it\n const finalProjectId = projectId || getClientClarityProjectId();\n\n if (!finalProjectId) {\n console.warn('[LiveState] Clarity project ID not provided');\n return;\n }\n\n // Initialize Clarity with project ID\n const Clarity = (await import('@microsoft/clarity')).default;\n Clarity.init(finalProjectId);\n } catch (error) {\n console.warn('[LiveState] Failed to initialize Clarity:', error);\n }\n}\n\n/**\n * Try to extract Clarity project ID from client's installation\n */\nfunction getClientClarityProjectId(): string | undefined {\n try {\n // Check if Clarity script tag exists\n const clarityScript = document.querySelector('script[src*=\"clarity.ms\"]');\n if (clarityScript) {\n const src = clarityScript.getAttribute('src');\n const match = src?.match(/\\/([a-z0-9]+)$/);\n return match?.[1];\n }\n\n // Check global clarity config: shape is clarity.q = [['init', projectId, ...]]\n const projectId = window.clarity?.q?.[0]?.[1];\n if (typeof projectId === 'string') {\n return projectId;\n }\n } catch {\n // Fail silently\n }\n\n return undefined;\n}\n\n/**\n * Track event with Amplitude (fail silently)\n */\nexport function trackAmplitudeEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n amplitudeInstance.track(eventName, properties);\n } catch (error) {\n console.warn('[LiveState] Failed to track Amplitude event:', error);\n }\n}\n\n/**\n * Track event with Clarity (fail silently)\n */\nexport function trackClarityEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n try {\n if (window.clarity) {\n window.clarity('event', eventName);\n\n // Set custom tags for properties\n if (properties) {\n Object.entries(properties).forEach(([key, value]) => {\n window.clarity?.('set', key, String(value));\n });\n }\n }\n } catch (error) {\n console.warn('[LiveState] Failed to track Clarity event:', error);\n }\n}\n\n/**\n * Builds a TrackingProperties object from a loose record, dropping entries\n * whose value is undefined so callers don't need to guard optional fields.\n */\nexport function buildTrackingProperties(\n source: Record<string, TrackingValue | undefined>,\n): TrackingProperties {\n return Object.fromEntries(\n Object.entries(source).filter(\n (entry): entry is [string, TrackingValue] => entry[1] !== undefined,\n ),\n );\n}\n\n/**\n * Track event with both Amplitude and Clarity (fail silently)\n */\nexport function trackEvent(\n eventName: string,\n properties?: TrackingProperties,\n): void {\n trackAmplitudeEvent(eventName, properties);\n trackClarityEvent(eventName, properties);\n}\n\n/**\n * Clarity command API shape as documented in the Clarity SDK\n * https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-api\n */\ntype ClarityCommand =\n | 'init'\n | 'event'\n | 'set'\n | 'identify'\n | 'consent'\n | 'upgrade';\n\ndeclare global {\n interface Window {\n clarity?: {\n (command: ClarityCommand, ...args: string[]): void;\n q?: string[][];\n };\n }\n}\n","import React, { createContext, useContext, useEffect } from 'react';\nimport { SWRConfig } from 'swr';\nimport type {\n LiveStateFetcher,\n AnalyticsConfig,\n TrackingProperties,\n} from '../types';\nimport { initializeAmplitude, initializeClarity } from '../utils/analytics';\n\ninterface LiveStateContextValue {\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\nconst LiveStateContext = createContext<LiveStateContextValue | null>(null);\n\nexport interface LiveStateProviderProps {\n children: React.ReactNode;\n fetcher: LiveStateFetcher;\n analytics?: AnalyticsConfig;\n onEvent?: (eventName: string, properties?: TrackingProperties) => void;\n}\n\n/**\n * LiveStateProvider\n *\n * Root-level provider that configures fetcher function and analytics.\n * Initializes Amplitude and Clarity on mount.\n *\n * The optional `onEvent` callback is fired on every tracking event before\n * sending to Amplitude/Clarity — useful for simulators and debugging tools.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateProvider({\n children,\n fetcher,\n analytics,\n onEvent,\n}: LiveStateProviderProps) {\n useEffect(() => {\n if (analytics?.amplitudeKey) {\n initializeAmplitude(analytics.amplitudeKey);\n }\n\n if (analytics?.clarityProjectId) {\n initializeClarity(analytics.clarityProjectId);\n }\n }, [analytics]);\n\n return (\n <SWRConfig value={{ provider: () => new Map() }}>\n <LiveStateContext.Provider value={{ fetcher, analytics, onEvent }}>\n {children}\n </LiveStateContext.Provider>\n </SWRConfig>\n );\n}\n\n/**\n * useLiveStateContext\n *\n * Internal hook to access LiveStateContext\n */\nexport function useLiveStateContext() {\n const context = useContext(LiveStateContext);\n\n if (!context) {\n throw new Error('useLiveState must be used within LiveStateProvider');\n }\n\n return context;\n}\n","import useSWR from 'swr';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport type { LiveStateResponse } from '../types';\n\ninterface UseLiveStateReturn {\n /** Live state data */\n liveState: LiveStateResponse | null;\n\n /** Loading state */\n isLoading: boolean;\n\n /** Error state */\n error: Error | null;\n\n /** Manual refresh function */\n refresh: () => Promise<void>;\n}\n\n/**\n * useLiveState hook\n *\n * Fetches and manages live state data using SWR with automatic caching,\n * deduplication, and revalidation.\n *\n * Must be used within LiveStateProvider. See examples/ directory for usage.\n */\nexport function useLiveState(): UseLiveStateReturn {\n const { fetcher } = useLiveStateContext();\n\n const { data, error, isLoading, mutate } = useSWR<LiveStateResponse | null>(\n 'live-state',\n fetcher,\n {\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n dedupingInterval: 60000, // 1 minute\n shouldRetryOnError: false, // Fail silently\n onError: err => {\n console.warn('[LiveState] Failed to fetch live state:', err);\n },\n },\n );\n\n const refresh = async () => {\n try {\n await mutate();\n } catch (err) {\n console.warn('[LiveState] Failed to refresh live state:', err);\n }\n };\n\n return {\n liveState: data ?? null,\n isLoading,\n error: error ?? null,\n refresh,\n };\n}\n","import { useCallback } from 'react';\nimport { useLiveStateContext } from '../providers/LiveStateProvider';\nimport { trackEvent } from '../utils/analytics';\nimport type { TrackingProperties } from '../types';\n\n/**\n * useTrackEvent\n *\n * Returns a `track` function that fires both the internal analytics\n * (Amplitude + Clarity) and the optional `onEvent` callback provided\n * to LiveStateProvider — useful for simulators and debugging tools.\n */\nexport function useTrackEvent() {\n const { onEvent } = useLiveStateContext();\n\n const track = useCallback(\n (eventName: string, properties?: TrackingProperties) => {\n onEvent?.(eventName, properties);\n trackEvent(eventName, properties);\n },\n [onEvent],\n );\n\n return track;\n}\n","const STORAGE_KEY = '@tiendanube/live-state:closable';\n\nexport interface ClosableState {\n count: number;\n closedAt: number;\n}\n\nexport type ClosableStates = Record<string, Record<string, ClosableState>>;\n\n/**\n * Reads closable states from localStorage.\n * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).\n * Returns an empty object on any error (fail-silent).\n */\nexport function getClosableStates(): ClosableStates {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return {};\n\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) return {};\n\n const normalized: ClosableStates = {};\n\n for (const [ctx, ctxState] of Object.entries(\n parsed as Record<string, unknown>,\n )) {\n if (typeof ctxState !== 'object' || ctxState === null) continue;\n\n normalized[ctx] = {};\n\n for (const [id, entry] of Object.entries(\n ctxState as Record<string, unknown>,\n )) {\n if (typeof entry === 'number') {\n // legacy format: plain close count\n normalized[ctx][id] = { count: entry, closedAt: 0 };\n } else if (typeof entry === 'object' && entry !== null) {\n const candidate = entry as Partial<ClosableState>;\n normalized[ctx][id] = {\n count: typeof candidate.count === 'number' ? candidate.count : 0,\n closedAt:\n typeof candidate.closedAt === 'number' ? candidate.closedAt : 0,\n };\n }\n }\n }\n\n return normalized;\n } catch {\n return {};\n }\n}\n\n/**\n * Persists closable states to localStorage.\n * Fails silently if localStorage is unavailable or full.\n */\nexport function setClosableStates(states: ClosableStates): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(states));\n } catch {\n // localStorage unavailable or quota exceeded — application continues normally\n }\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n getClosableStates,\n setClosableStates,\n} from '../utils/closable-storage';\n\nexport interface UseClosableOptions {\n /** Notification context (e.g. 'awareness', 'charge') */\n context: string;\n /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */\n id: string | undefined;\n /** Maximum number of times the user can close before it is hidden permanently */\n maxCloseTimes?: number;\n /** Milliseconds after which the close counter resets (optional) */\n expiresIn?: number;\n}\n\nexport interface UseClosableReturn {\n /** Whether the notification should be shown. null = initial check in progress. */\n isVisible: boolean | null;\n /** Call this to record a close action */\n close: () => void;\n}\n\n/**\n * Manages the close state of a notification using localStorage.\n *\n * After the user closes a notification `maxCloseTimes` times, it is hidden\n * permanently. Optionally, the counter resets after `expiresIn` milliseconds.\n *\n * Fails silently — errors in localStorage never break the application.\n *\n * @example\n * ```tsx\n * const { isVisible, close } = useClosable({\n * context: 'awareness',\n * id: 'awareness-2026-q1',\n * maxCloseTimes: 3,\n * expiresIn: 86_400_000, // 1 day\n * });\n *\n * if (!isVisible) return null;\n * return <Notification onClose={close} />;\n * ```\n */\nexport function useClosable({\n context,\n id,\n maxCloseTimes = 3,\n expiresIn,\n}: UseClosableOptions): UseClosableReturn {\n const [isVisible, setIsVisible] = useState<boolean | null>(null);\n\n useEffect(() => {\n // No ID means no close tracking — always show\n if (!id) {\n setIsVisible(true);\n return;\n }\n\n const states = getClosableStates();\n const entry = states[context]?.[id];\n\n if (!entry) {\n setIsVisible(true);\n return;\n }\n\n const { count, closedAt } = entry;\n\n // Check expiry — reset counter and show if expired\n if (expiresIn != null && closedAt > 0) {\n const elapsed = Date.now() - closedAt;\n if (elapsed > expiresIn) {\n const updated = { ...states };\n if (updated[context]) {\n delete updated[context][id];\n setClosableStates(updated);\n }\n setIsVisible(true);\n return;\n }\n }\n\n setIsVisible(count < maxCloseTimes);\n }, [context, id, maxCloseTimes, expiresIn]);\n\n const close = useCallback(() => {\n if (!id) return;\n\n const states = getClosableStates();\n const currentCount = states[context]?.[id]?.count ?? 0;\n\n const updated: typeof states = {\n ...states,\n [context]: {\n ...(states[context] ?? {}),\n [id]: {\n count: currentCount + 1,\n closedAt: Date.now(),\n },\n },\n };\n\n setIsVisible(false);\n setClosableStates(updated);\n }, [context, id]);\n\n return { isVisible, close };\n}\n","import type { CtaConfig } from '../types';\n\n/**\n * Handle CTA click based on type\n *\n * @param cta - CTA configuration from LiveStateResponse\n */\nexport function handleCtaClick(cta: CtaConfig): void {\n try {\n switch (cta.type) {\n case 'redirect':\n // Navigate in same window\n window.location.href = cta.url;\n break;\n\n case 'whatsapp': {\n // Open WhatsApp in new tab\n const whatsappUrl = cta.whatsappMessage\n ? `${cta.url}?text=${encodeURIComponent(cta.whatsappMessage)}`\n : cta.url;\n window.open(whatsappUrl, '_blank');\n break;\n }\n\n case 'external':\n // Open in new tab\n window.open(cta.url, '_blank');\n break;\n\n default:\n console.warn(`[LiveState] Unknown CTA type: ${cta.type}`);\n }\n } catch (error) {\n console.warn('[LiveState] Failed to handle CTA click:', error);\n }\n}\n","import { useCallback, useEffect } from 'react';\nimport { Alert, Button } from '@nimbus-ds/components';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateAlertProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n}\n\n/**\n * LiveStateAlert\n *\n * Renders an Alert component (Nimbus) for alert/warning types.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateAlert({\n data,\n trackingConfig,\n onClose,\n}: LiveStateAlertProps) {\n const track = useTrackEvent();\n const appearance = data.type === 'alert' ? 'danger' : 'warning';\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <Alert\n appearance={appearance}\n title={data.title}\n onRemove={onClose ? handleClose : undefined}>\n <p dangerouslySetInnerHTML={{ __html: data.message }} />\n <Button appearance=\"neutral\" onClick={handleClick}>\n {data.cta.label}\n </Button>\n </Alert>\n );\n}\n","import { useCallback, useEffect } from 'react';\nimport { Card, Button, Icon } from '@nimbus-ds/components';\nimport { ExclamationCircleIcon, CloseIcon } from '@nimbus-ds/icons';\nimport type { LiveStateResponse, TrackingConfig } from '../types';\nimport { buildTrackingProperties } from '../utils/analytics';\nimport { handleCtaClick } from '../utils/cta';\nimport { useTrackEvent } from '../hooks/useTrackEvent';\n\nexport interface LiveStateInfoProps {\n data: LiveStateResponse;\n trackingConfig: TrackingConfig;\n defaultVariant?: 'blue' | 'white';\n /** When provided, shows a close button and calls this on dismiss */\n onClose?: () => void;\n}\n\n/**\n * LiveStateInfo\n *\n * Renders a Card component (Nimbus) for info type with a circular icon.\n * Automatically tracks view, click, and close events.\n * Shows a close button when onClose is provided.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateInfo({\n data,\n trackingConfig,\n defaultVariant = 'blue',\n onClose,\n}: LiveStateInfoProps) {\n const track = useTrackEvent();\n const variant = data.variant || defaultVariant;\n\n const buildEventProperties = useCallback(\n () =>\n buildTrackingProperties({\n context: data.context,\n campaignId: data.campaignId,\n group: data.group,\n ...data.metadata,\n ...trackingConfig.properties,\n }),\n [data, trackingConfig.properties],\n );\n\n const handleClick = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_click`;\n track(eventName, buildEventProperties());\n handleCtaClick(data.cta);\n }, [data, trackingConfig, buildEventProperties, track]);\n\n const handleClose = useCallback(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_close`;\n track(eventName, buildEventProperties());\n onClose?.();\n }, [onClose, data, trackingConfig, buildEventProperties, track]);\n\n useEffect(() => {\n const eventName = `${trackingConfig.prefix}${trackingConfig.page}_${data.context}_view`;\n track(eventName, buildEventProperties());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iconColor = variant === 'blue' ? 'currentColor' : 'primary-interactive';\n\n return (\n <Card\n backgroundColor={\n variant === 'blue' ? 'primary-surface' : 'neutral-background'\n }>\n <Card.Body>\n <div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}>\n <Icon source={<ExclamationCircleIcon />} color={iconColor} />\n </div>\n\n <div style={{ flex: 1 }}>\n <h3\n style={{\n fontSize: '16px',\n fontWeight: 600,\n margin: '0 0 8px 0',\n lineHeight: '24px',\n }}\n dangerouslySetInnerHTML={{ __html: data.title }}\n />\n <p\n style={{\n fontSize: '14px',\n margin: '0 0 16px 0',\n lineHeight: '20px',\n }}\n dangerouslySetInnerHTML={{ __html: data.message }}\n />\n <Button onClick={handleClick}>{data.cta.label}</Button>\n </div>\n\n {onClose && (\n <button\n onClick={handleClose}\n aria-label=\"Fechar notificação\"\n data-testid=\"live-state-close-button\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n display: 'flex',\n alignItems: 'center',\n flexShrink: 0,\n }}>\n <Icon\n source={<CloseIcon size=\"small\" />}\n color=\"neutral-interactive\"\n />\n </button>\n )}\n </div>\n </Card.Body>\n </Card>\n );\n}\n","import type { LiveStateRendererProps } from '../types';\nimport { useClosable } from '../hooks/useClosable';\nimport { LiveStateAlert } from './LiveStateAlert';\nimport { LiveStateInfo } from './LiveStateInfo';\n\n/**\n * LiveStateRenderer\n *\n * Main component that validates payload, filters by context, and renders\n * the appropriate visual component (Alert or Info) based on type.\n * Handles closable notifications via useClosable when closable is configured.\n *\n * See examples/ directory for usage examples.\n */\nexport function LiveStateRenderer({\n data,\n loading,\n trackingConfig,\n allowedContexts,\n defaultVariant,\n}: LiveStateRendererProps) {\n const { isVisible, close } = useClosable({\n context: data?.context ?? '',\n id: data?.campaignId,\n maxCloseTimes: data?.metadata?.maxCloseTimes,\n expiresIn: data?.metadata?.expiresIn,\n });\n\n // Don't render while loading or no data\n if (loading || !data) {\n return null;\n }\n\n // Validate required fields\n if (\n !data.context ||\n !data.type ||\n !data.title ||\n !data.message ||\n !data.cta?.label ||\n !data.cta?.url ||\n !data.cta?.type\n ) {\n console.warn('[LiveState] Invalid payload, missing required fields', data);\n return null;\n }\n\n // Filter by allowed contexts\n if (allowedContexts && !allowedContexts.includes(data.context)) {\n return null;\n }\n\n // Awaiting localStorage check\n if (isVisible === null) {\n return null;\n }\n\n // Hidden — user reached maxCloseTimes\n if (!isVisible) {\n return null;\n }\n\n // Only pass onClose when closable is configured and notification has a campaignId to track\n const onClose = data.closable && data.campaignId ? close : undefined;\n\n // Render appropriate component based on type\n if (data.type === 'alert' || data.type === 'warning') {\n return (\n <LiveStateAlert\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n />\n );\n }\n\n if (data.type === 'info') {\n return (\n <LiveStateInfo\n data={data}\n onClose={onClose}\n trackingConfig={trackingConfig}\n defaultVariant={defaultVariant}\n />\n );\n }\n\n console.warn(`[LiveState] Unknown type: ${data.type}`);\n return null;\n}\n"],"mappings":"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"}
@@ -2,14 +2,17 @@ import { LiveStateResponse, TrackingConfig } from '../types';
2
2
  export interface LiveStateAlertProps {
3
3
  data: LiveStateResponse;
4
4
  trackingConfig: TrackingConfig;
5
+ /** When provided, shows a close button and calls this on dismiss */
6
+ onClose?: () => void;
5
7
  }
6
8
  /**
7
9
  * LiveStateAlert
8
10
  *
9
11
  * Renders an Alert component (Nimbus) for alert/warning types.
10
12
  * Automatically tracks view, click, and close events.
13
+ * Shows a close button when onClose is provided.
11
14
  *
12
15
  * See examples/ directory for usage examples.
13
16
  */
14
- export declare function LiveStateAlert({ data, trackingConfig }: LiveStateAlertProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function LiveStateAlert({ data, trackingConfig, onClose, }: LiveStateAlertProps): import("react/jsx-runtime").JSX.Element;
15
18
  //# sourceMappingURL=LiveStateAlert.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LiveStateAlert.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateAlert.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,mBAAmB,2CAsC3E"}
1
+ {"version":3,"file":"LiveStateAlert.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateAlert.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKlE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,cAAc,EACd,OAAO,GACR,EAAE,mBAAmB,2CA6CrB"}
@@ -3,14 +3,17 @@ export interface LiveStateInfoProps {
3
3
  data: LiveStateResponse;
4
4
  trackingConfig: TrackingConfig;
5
5
  defaultVariant?: 'blue' | 'white';
6
+ /** When provided, shows a close button and calls this on dismiss */
7
+ onClose?: () => void;
6
8
  }
7
9
  /**
8
10
  * LiveStateInfo
9
11
  *
10
12
  * Renders a Card component (Nimbus) for info type with a circular icon.
11
13
  * Automatically tracks view, click, and close events.
14
+ * Shows a close button when onClose is provided.
12
15
  *
13
16
  * See examples/ directory for usage examples.
14
17
  */
15
- export declare function LiveStateInfo({ data, trackingConfig, defaultVariant, }: LiveStateInfoProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function LiveStateInfo({ data, trackingConfig, defaultVariant, onClose, }: LiveStateInfoProps): import("react/jsx-runtime").JSX.Element;
16
19
  //# sourceMappingURL=LiveStateInfo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LiveStateInfo.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateInfo.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAIlE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,cAAc,EACd,cAAuB,GACxB,EAAE,kBAAkB,2CAsEpB"}
1
+ {"version":3,"file":"LiveStateInfo.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateInfo.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKlE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,iBAAiB,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,cAAc,EACd,cAAuB,EACvB,OAAO,GACR,EAAE,kBAAkB,2CAqGpB"}
@@ -4,6 +4,7 @@ import { LiveStateRendererProps } from '../types';
4
4
  *
5
5
  * Main component that validates payload, filters by context, and renders
6
6
  * the appropriate visual component (Alert or Info) based on type.
7
+ * Handles closable notifications via useClosable when closable is configured.
7
8
  *
8
9
  * See examples/ directory for usage examples.
9
10
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LiveStateRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAIvD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,GACf,EAAE,sBAAsB,kDA0CxB"}
1
+ {"version":3,"file":"LiveStateRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/LiveStateRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAKvD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,GACf,EAAE,sBAAsB,kDAqExB"}
@@ -0,0 +1,39 @@
1
+ export interface UseClosableOptions {
2
+ /** Notification context (e.g. 'awareness', 'charge') */
3
+ context: string;
4
+ /** Unique notification ID (campaignId). If absent, always visible — no close tracking. */
5
+ id: string | undefined;
6
+ /** Maximum number of times the user can close before it is hidden permanently */
7
+ maxCloseTimes?: number;
8
+ /** Milliseconds after which the close counter resets (optional) */
9
+ expiresIn?: number;
10
+ }
11
+ export interface UseClosableReturn {
12
+ /** Whether the notification should be shown. null = initial check in progress. */
13
+ isVisible: boolean | null;
14
+ /** Call this to record a close action */
15
+ close: () => void;
16
+ }
17
+ /**
18
+ * Manages the close state of a notification using localStorage.
19
+ *
20
+ * After the user closes a notification `maxCloseTimes` times, it is hidden
21
+ * permanently. Optionally, the counter resets after `expiresIn` milliseconds.
22
+ *
23
+ * Fails silently — errors in localStorage never break the application.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * const { isVisible, close } = useClosable({
28
+ * context: 'awareness',
29
+ * id: 'awareness-2026-q1',
30
+ * maxCloseTimes: 3,
31
+ * expiresIn: 86_400_000, // 1 day
32
+ * });
33
+ *
34
+ * if (!isVisible) return null;
35
+ * return <Notification onClose={close} />;
36
+ * ```
37
+ */
38
+ export declare function useClosable({ context, id, maxCloseTimes, expiresIn, }: UseClosableOptions): UseClosableReturn;
39
+ //# sourceMappingURL=useClosable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClosable.d.ts","sourceRoot":"","sources":["../../../src/hooks/useClosable.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,EAAE,EACF,aAAiB,EACjB,SAAS,GACV,EAAE,kBAAkB,GAAG,iBAAiB,CA2DxC"}
@@ -0,0 +1,10 @@
1
+ import { TrackingProperties } from '../types';
2
+ /**
3
+ * useTrackEvent
4
+ *
5
+ * Returns a `track` function that fires both the internal analytics
6
+ * (Amplitude + Clarity) and the optional `onEvent` callback provided
7
+ * to LiveStateProvider — useful for simulators and debugging tools.
8
+ */
9
+ export declare function useTrackEvent(): (eventName: string, properties?: TrackingProperties) => void;
10
+ //# sourceMappingURL=useTrackEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTrackEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/useTrackEvent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,aAAa,gBAIb,MAAM,eAAe,kBAAkB,UAQtD"}
@@ -1,6 +1,7 @@
1
1
  export type { LiveStateResponse, LiveStateFetcher, TrackingConfig, AnalyticsConfig, LiveStateProviderProps, LiveStateRendererProps, } from './types';
2
2
  export { LiveStateProvider } from './providers/LiveStateProvider';
3
3
  export { useLiveState } from './hooks/useLiveState';
4
+ export { useTrackEvent } from './hooks/useTrackEvent';
4
5
  export { LiveStateRenderer } from './components/LiveStateRenderer';
5
6
  export { LiveStateAlert } from './components/LiveStateAlert';
6
7
  export { LiveStateInfo } from './components/LiveStateInfo';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,13 +1,15 @@
1
1
  import { default as React } from 'react';
2
- import { LiveStateFetcher, AnalyticsConfig } from '../types';
2
+ import { LiveStateFetcher, AnalyticsConfig, TrackingProperties } from '../types';
3
3
  interface LiveStateContextValue {
4
4
  fetcher: LiveStateFetcher;
5
5
  analytics?: AnalyticsConfig;
6
+ onEvent?: (eventName: string, properties?: TrackingProperties) => void;
6
7
  }
7
8
  export interface LiveStateProviderProps {
8
9
  children: React.ReactNode;
9
10
  fetcher: LiveStateFetcher;
10
11
  analytics?: AnalyticsConfig;
12
+ onEvent?: (eventName: string, properties?: TrackingProperties) => void;
11
13
  }
12
14
  /**
13
15
  * LiveStateProvider
@@ -15,9 +17,12 @@ export interface LiveStateProviderProps {
15
17
  * Root-level provider that configures fetcher function and analytics.
16
18
  * Initializes Amplitude and Clarity on mount.
17
19
  *
20
+ * The optional `onEvent` callback is fired on every tracking event before
21
+ * sending to Amplitude/Clarity — useful for simulators and debugging tools.
22
+ *
18
23
  * See examples/ directory for usage examples.
19
24
  */
20
- export declare function LiveStateProvider({ children, fetcher, analytics, }: LiveStateProviderProps): import("react/jsx-runtime").JSX.Element;
25
+ export declare function LiveStateProvider({ children, fetcher, analytics, onEvent, }: LiveStateProviderProps): import("react/jsx-runtime").JSX.Element;
21
26
  /**
22
27
  * useLiveStateContext
23
28
  *
@@ -1 +1 @@
1
- {"version":3,"file":"LiveStateProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/LiveStateProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAGlE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAID,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAO,EACP,SAAS,GACV,EAAE,sBAAsB,2CAmBxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,0BAQlC"}
1
+ {"version":3,"file":"LiveStateProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/LiveStateProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EACnB,MAAM,UAAU,CAAC;AAGlB,UAAU,qBAAqB;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxE;AAID,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,sBAAsB,2CAkBxB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,0BAQlC"}
@@ -40,13 +40,17 @@ export interface LiveStateResponse {
40
40
  group?: string;
41
41
  /** Visual variant */
42
42
  variant?: 'blue' | 'white';
43
- /** Closable configuration */
44
- closable?: {
45
- maxCloseTimes: number;
43
+ /** Whether the notification can be dismissed by the user */
44
+ closable?: boolean;
45
+ /**
46
+ * Additional metadata.
47
+ * When closable=true, may contain maxCloseTimes and expiresIn to control
48
+ * how many times the user can close before it disappears permanently.
49
+ */
50
+ metadata?: TrackingProperties & {
51
+ maxCloseTimes?: number;
46
52
  expiresIn?: number;
47
53
  };
48
- /** Additional metadata for tracking */
49
- metadata?: TrackingProperties;
50
54
  }
51
55
  /**
52
56
  * Fetcher function type
@@ -82,6 +86,15 @@ export interface LiveStateProviderProps {
82
86
  fetcher: LiveStateFetcher;
83
87
  /** Analytics configuration */
84
88
  analytics?: AnalyticsConfig;
89
+ /**
90
+ * Optional observability callback fired on every tracking event
91
+ * (view, click, close) before sending to Amplitude/Clarity.
92
+ * Useful for simulators, debugging tools, and custom analytics pipelines.
93
+ *
94
+ * @example
95
+ * <LiveStateProvider onEvent={(name, props) => console.log(name, props)} />
96
+ */
97
+ onEvent?: (eventName: string, properties?: TrackingProperties) => void;
85
98
  }
86
99
  /**
87
100
  * LiveStateRenderer props
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;IAEZ,wBAAwB;IACxB,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAE3C,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,4BAA4B;IAC5B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAEnC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IAEd,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAEhB,mCAAmC;IACnC,GAAG,EAAE,SAAS,CAAC;IAEf,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE;QACT,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,uCAAuC;IACvC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IAEf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,SAAS,CAAC;IAEpB,8CAA8C;IAC9C,OAAO,EAAE,gBAAgB,CAAC;IAE1B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE/B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,6BAA6B;IAC7B,cAAc,EAAE,cAAc,CAAC;IAE/B,8BAA8B;IAC9B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;IAEZ,wBAAwB;IACxB,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IAE3C,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,4BAA4B;IAC5B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IAEnC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IAEd,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAEhB,mCAAmC;IACnC,GAAG,EAAE,SAAS,CAAC;IAEf,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,kBAAkB,GAAG;QAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IAEf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,SAAS,CAAC;IAEpB,8CAA8C;IAC9C,OAAO,EAAE,gBAAgB,CAAC;IAE1B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,sBAAsB;IACtB,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE/B,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,6BAA6B;IAC7B,cAAc,EAAE,cAAc,CAAC;IAE/B,8BAA8B;IAC9B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../src/utils/analytics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAElE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAaxD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzE;AA2BD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAeN;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,GAChD,kBAAkB,CAMpB;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAGN;AAED;;;GAGG;AACH,KAAK,cAAc,GACf,MAAM,GACN,OAAO,GACP,KAAK,GACL,UAAU,GACV,SAAS,GACT,SAAS,CAAC;AAEd,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,CAAC,EAAE;YACR,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YACnD,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;SAChB,CAAC;KACH;CACF"}
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../src/utils/analytics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQlE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAaxD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzE;AA2BD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAeN;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,GAChD,kBAAkB,CAMpB;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,IAAI,CAGN;AAED;;;GAGG;AACH,KAAK,cAAc,GACf,MAAM,GACN,OAAO,GACP,KAAK,GACL,UAAU,GACV,SAAS,GACT,SAAS,CAAC;AAEd,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,CAAC,EAAE;YACR,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YACnD,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;SAChB,CAAC;KACH;CACF"}
@@ -0,0 +1,17 @@
1
+ export interface ClosableState {
2
+ count: number;
3
+ closedAt: number;
4
+ }
5
+ export type ClosableStates = Record<string, Record<string, ClosableState>>;
6
+ /**
7
+ * Reads closable states from localStorage.
8
+ * Normalises legacy format (plain number) to the current shape ({ count, closedAt }).
9
+ * Returns an empty object on any error (fail-silent).
10
+ */
11
+ export declare function getClosableStates(): ClosableStates;
12
+ /**
13
+ * Persists closable states to localStorage.
14
+ * Fails silently if localStorage is unavailable or full.
15
+ */
16
+ export declare function setClosableStates(states: ClosableStates): void;
17
+ //# sourceMappingURL=closable-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closable-storage.d.ts","sourceRoot":"","sources":["../../../src/utils/closable-storage.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAsClD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAM9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiendanube/live-state",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.7",
4
4
  "description": "Generic React library for rendering live state notifications",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -33,8 +33,6 @@
33
33
  "verify:build": "./scripts/test-build.sh"
34
34
  },
35
35
  "peerDependencies": {
36
- "@amplitude/analytics-browser": "^2.0.0",
37
- "@microsoft/clarity": "^1.0.0",
38
36
  "@nimbus-ds/components": "^5.41.0",
39
37
  "@nimbus-ds/icons": "^1.14.0",
40
38
  "react": "^18.0.0 || ^19.0.0",
@@ -42,14 +40,15 @@
42
40
  "swr": "^2.0.0"
43
41
  },
44
42
  "peerDependenciesMeta": {
45
- "@amplitude/analytics-browser": { "optional": true },
46
- "@microsoft/clarity": { "optional": true },
47
- "swr": { "optional": true }
43
+ "swr": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "dependencies": {
48
+ "@amplitude/analytics-browser": "^2.11.1",
49
+ "@microsoft/clarity": "^1.0.0"
48
50
  },
49
- "dependencies": {},
50
51
  "devDependencies": {
51
- "@amplitude/analytics-browser": "^2.39.0",
52
- "@microsoft/clarity": "^1.0.2",
53
52
  "@eslint/js": "^10.0.1",
54
53
  "@nimbus-ds/components": "5.41.0",
55
54
  "@nimbus-ds/icons": "1.14.0",
@@ -71,13 +70,13 @@
71
70
  "eslint-plugin-react": "^7.37.5",
72
71
  "eslint-plugin-react-hooks": "^7.0.1",
73
72
  "globals": "^17.4.0",
74
- "jsdom": "^29.0.2",
73
+ "jsdom": "26.1.0",
75
74
  "prettier": "^3.8.2",
76
75
  "react": "^19.0.0",
77
76
  "react-dom": "^19.0.0",
77
+ "swr": "^2.4.1",
78
78
  "typescript": "^6.0.2",
79
79
  "vite": "^8.0.8",
80
- "swr": "^2.4.1",
81
80
  "vite-plugin-dts": "^4.5.4",
82
81
  "vitest": "^4.1.4"
83
82
  },