@salesmind-ai/design-system 0.3.4 → 0.3.5

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.
Files changed (197) hide show
  1. package/dist/admin/index.cjs +68 -2928
  2. package/dist/admin/index.cjs.map +1 -1
  3. package/dist/admin/index.js +5 -2915
  4. package/dist/admin/index.js.map +1 -1
  5. package/dist/blog/index.cjs +53 -1064
  6. package/dist/blog/index.cjs.map +1 -1
  7. package/dist/blog/index.js +8 -1054
  8. package/dist/blog/index.js.map +1 -1
  9. package/dist/charts/index.cjs +46 -2694
  10. package/dist/charts/index.cjs.map +1 -1
  11. package/dist/charts/index.js +3 -2680
  12. package/dist/charts/index.js.map +1 -1
  13. package/dist/chunk-2GARWEJK.js +17 -0
  14. package/dist/chunk-2GARWEJK.js.map +1 -0
  15. package/dist/chunk-2KQVZ5FB.js +485 -0
  16. package/dist/chunk-2KQVZ5FB.js.map +1 -0
  17. package/dist/chunk-2ZNR2F2V.cjs +194 -0
  18. package/dist/chunk-2ZNR2F2V.cjs.map +1 -0
  19. package/dist/chunk-3NKRFUAR.js +37 -0
  20. package/dist/chunk-3NKRFUAR.js.map +1 -0
  21. package/dist/chunk-3TGSIILM.cjs +201 -0
  22. package/dist/chunk-3TGSIILM.cjs.map +1 -0
  23. package/dist/chunk-4GM5BGBN.cjs +801 -0
  24. package/dist/chunk-4GM5BGBN.cjs.map +1 -0
  25. package/dist/chunk-5LGDEZWY.cjs +2434 -0
  26. package/dist/chunk-5LGDEZWY.cjs.map +1 -0
  27. package/dist/chunk-6H4DSTXR.js +786 -0
  28. package/dist/chunk-6H4DSTXR.js.map +1 -0
  29. package/dist/chunk-6HKQ5ILL.cjs +1624 -0
  30. package/dist/chunk-6HKQ5ILL.cjs.map +1 -0
  31. package/dist/chunk-6UNG76Y2.js +153 -0
  32. package/dist/chunk-6UNG76Y2.js.map +1 -0
  33. package/dist/chunk-7PX2AZ6Y.js +39 -0
  34. package/dist/chunk-7PX2AZ6Y.js.map +1 -0
  35. package/dist/chunk-B6AVAX4F.js +1415 -0
  36. package/dist/chunk-B6AVAX4F.js.map +1 -0
  37. package/dist/chunk-BILT5KD3.js +264 -0
  38. package/dist/chunk-BILT5KD3.js.map +1 -0
  39. package/dist/chunk-C2BCDNAV.js +24 -0
  40. package/dist/chunk-C2BCDNAV.js.map +1 -0
  41. package/dist/chunk-CH42VPWE.cjs +421 -0
  42. package/dist/chunk-CH42VPWE.cjs.map +1 -0
  43. package/dist/chunk-CJ2MKVAF.cjs +46 -0
  44. package/dist/chunk-CJ2MKVAF.cjs.map +1 -0
  45. package/dist/chunk-DP74LUXG.cjs +98 -0
  46. package/dist/chunk-DP74LUXG.cjs.map +1 -0
  47. package/dist/chunk-E7D6EKJ4.cjs +44 -0
  48. package/dist/chunk-E7D6EKJ4.cjs.map +1 -0
  49. package/dist/chunk-ECXBTUH6.cjs +584 -0
  50. package/dist/chunk-ECXBTUH6.cjs.map +1 -0
  51. package/dist/chunk-EFRAP5ES.js +157 -0
  52. package/dist/chunk-EFRAP5ES.js.map +1 -0
  53. package/dist/chunk-EM7JHRYW.cjs +69 -0
  54. package/dist/chunk-EM7JHRYW.cjs.map +1 -0
  55. package/dist/chunk-FAFAP4L5.js +183 -0
  56. package/dist/chunk-FAFAP4L5.js.map +1 -0
  57. package/dist/chunk-H2Y6BSTL.cjs +69 -0
  58. package/dist/chunk-H2Y6BSTL.cjs.map +1 -0
  59. package/dist/chunk-HN4PHABT.js +126 -0
  60. package/dist/chunk-HN4PHABT.js.map +1 -0
  61. package/dist/chunk-HRENHNDJ.js +211 -0
  62. package/dist/chunk-HRENHNDJ.js.map +1 -0
  63. package/dist/chunk-I75BFEYT.cjs +2561 -0
  64. package/dist/chunk-I75BFEYT.cjs.map +1 -0
  65. package/dist/chunk-IFRATNLU.js +562 -0
  66. package/dist/chunk-IFRATNLU.js.map +1 -0
  67. package/dist/chunk-JNASH4OQ.js +1022 -0
  68. package/dist/chunk-JNASH4OQ.js.map +1 -0
  69. package/dist/chunk-JPJN4YBC.js +409 -0
  70. package/dist/chunk-JPJN4YBC.js.map +1 -0
  71. package/dist/chunk-KCKUSU2M.cjs +166 -0
  72. package/dist/chunk-KCKUSU2M.cjs.map +1 -0
  73. package/dist/chunk-KDLH35OI.cjs +1042 -0
  74. package/dist/chunk-KDLH35OI.cjs.map +1 -0
  75. package/dist/chunk-KJ2OXQF4.js +287 -0
  76. package/dist/chunk-KJ2OXQF4.js.map +1 -0
  77. package/dist/chunk-KK5UO2P4.cjs +717 -0
  78. package/dist/chunk-KK5UO2P4.cjs.map +1 -0
  79. package/dist/chunk-KNQEIU7O.cjs +1202 -0
  80. package/dist/chunk-KNQEIU7O.cjs.map +1 -0
  81. package/dist/chunk-KVGSVGRK.cjs +569 -0
  82. package/dist/chunk-KVGSVGRK.cjs.map +1 -0
  83. package/dist/chunk-L352JRV6.cjs +105 -0
  84. package/dist/chunk-L352JRV6.cjs.map +1 -0
  85. package/dist/chunk-LGNMFBLF.cjs +502 -0
  86. package/dist/chunk-LGNMFBLF.cjs.map +1 -0
  87. package/dist/chunk-LJADZITX.cjs +298 -0
  88. package/dist/chunk-LJADZITX.cjs.map +1 -0
  89. package/dist/chunk-MDB2WCRQ.cjs +137 -0
  90. package/dist/chunk-MDB2WCRQ.cjs.map +1 -0
  91. package/dist/chunk-MQDEE7HC.cjs +283 -0
  92. package/dist/chunk-MQDEE7HC.cjs.map +1 -0
  93. package/dist/chunk-MQRB634A.cjs +34 -0
  94. package/dist/chunk-MQRB634A.cjs.map +1 -0
  95. package/dist/chunk-MU6GW5ZV.js +2317 -0
  96. package/dist/chunk-MU6GW5ZV.js.map +1 -0
  97. package/dist/chunk-NN3TUHIH.js +28 -0
  98. package/dist/chunk-NN3TUHIH.js.map +1 -0
  99. package/dist/chunk-NT4LBP7D.cjs +111 -0
  100. package/dist/chunk-NT4LBP7D.cjs.map +1 -0
  101. package/dist/chunk-OGKGIXFC.cjs +2162 -0
  102. package/dist/chunk-OGKGIXFC.cjs.map +1 -0
  103. package/dist/chunk-OXNXEQY7.js +2538 -0
  104. package/dist/chunk-OXNXEQY7.js.map +1 -0
  105. package/dist/chunk-P5BOFE5A.js +546 -0
  106. package/dist/chunk-P5BOFE5A.js.map +1 -0
  107. package/dist/chunk-PE2KJVRN.js +185 -0
  108. package/dist/chunk-PE2KJVRN.js.map +1 -0
  109. package/dist/chunk-Q2MFGYTE.cjs +1449 -0
  110. package/dist/chunk-Q2MFGYTE.cjs.map +1 -0
  111. package/dist/chunk-Q75DBVDY.cjs +68 -0
  112. package/dist/chunk-Q75DBVDY.cjs.map +1 -0
  113. package/dist/chunk-RQUFZAZ7.js +1608 -0
  114. package/dist/chunk-RQUFZAZ7.js.map +1 -0
  115. package/dist/chunk-SICKWUWB.js +62 -0
  116. package/dist/chunk-SICKWUWB.js.map +1 -0
  117. package/dist/chunk-T343CCH5.js +1190 -0
  118. package/dist/chunk-T343CCH5.js.map +1 -0
  119. package/dist/chunk-T5H5PNLN.js +701 -0
  120. package/dist/chunk-T5H5PNLN.js.map +1 -0
  121. package/dist/chunk-U3LK2GID.js +2122 -0
  122. package/dist/chunk-U3LK2GID.js.map +1 -0
  123. package/dist/chunk-UFAJY2DM.js +62 -0
  124. package/dist/chunk-UFAJY2DM.js.map +1 -0
  125. package/dist/chunk-VC5LMUVQ.cjs +20 -0
  126. package/dist/chunk-VC5LMUVQ.cjs.map +1 -0
  127. package/dist/chunk-VM7WFMKI.cjs +76 -0
  128. package/dist/chunk-VM7WFMKI.cjs.map +1 -0
  129. package/dist/chunk-W2WTP6HS.cjs +233 -0
  130. package/dist/chunk-W2WTP6HS.cjs.map +1 -0
  131. package/dist/chunk-WH7PYHZY.cjs +35 -0
  132. package/dist/chunk-WH7PYHZY.cjs.map +1 -0
  133. package/dist/chunk-XU3OMQ7V.js +98 -0
  134. package/dist/chunk-XU3OMQ7V.js.map +1 -0
  135. package/dist/chunk-XWPDRMZG.js +62 -0
  136. package/dist/chunk-XWPDRMZG.js.map +1 -0
  137. package/dist/chunk-Y3CPKNB7.js +67 -0
  138. package/dist/chunk-Y3CPKNB7.js.map +1 -0
  139. package/dist/chunk-YNVRDD2P.js +98 -0
  140. package/dist/chunk-YNVRDD2P.js.map +1 -0
  141. package/dist/chunk-YSYR54XR.js +92 -0
  142. package/dist/chunk-YSYR54XR.js.map +1 -0
  143. package/dist/chunk-YTYDQBVY.cjs +162 -0
  144. package/dist/chunk-YTYDQBVY.cjs.map +1 -0
  145. package/dist/core/index.cjs +807 -4333
  146. package/dist/core/index.cjs.map +1 -1
  147. package/dist/core/index.js +14 -4130
  148. package/dist/core/index.js.map +1 -1
  149. package/dist/i18n/index.cjs +86 -558
  150. package/dist/i18n/index.cjs.map +1 -1
  151. package/dist/i18n/index.js +1 -544
  152. package/dist/i18n/index.js.map +1 -1
  153. package/dist/index.cjs +1432 -17140
  154. package/dist/index.cjs.map +1 -1
  155. package/dist/index.js +31 -16785
  156. package/dist/index.js.map +1 -1
  157. package/dist/marketing/index.cjs +142 -3072
  158. package/dist/marketing/index.cjs.map +1 -1
  159. package/dist/marketing/index.js +11 -3042
  160. package/dist/marketing/index.js.map +1 -1
  161. package/dist/motion/index.cjs +26 -1222
  162. package/dist/motion/index.cjs.map +1 -1
  163. package/dist/motion/index.js +2 -1215
  164. package/dist/motion/index.js.map +1 -1
  165. package/dist/nav/index.cjs +101 -1518
  166. package/dist/nav/index.cjs.map +1 -1
  167. package/dist/nav/index.js +4 -1498
  168. package/dist/nav/index.js.map +1 -1
  169. package/dist/report/index.cjs +171 -2403
  170. package/dist/report/index.cjs.map +1 -1
  171. package/dist/report/index.js +3 -2363
  172. package/dist/report/index.js.map +1 -1
  173. package/dist/sections/index.cjs +22 -377
  174. package/dist/sections/index.cjs.map +1 -1
  175. package/dist/sections/index.js +6 -369
  176. package/dist/sections/index.js.map +1 -1
  177. package/dist/social-proof/index.cjs +53 -1250
  178. package/dist/social-proof/index.cjs.map +1 -1
  179. package/dist/social-proof/index.js +6 -1235
  180. package/dist/social-proof/index.js.map +1 -1
  181. package/dist/theme/index.cjs +38 -565
  182. package/dist/theme/index.cjs.map +1 -1
  183. package/dist/theme/index.js +2 -555
  184. package/dist/theme/index.js.map +1 -1
  185. package/dist/web/client/index.cjs +38 -491
  186. package/dist/web/client/index.cjs.map +1 -1
  187. package/dist/web/client/index.js +4 -483
  188. package/dist/web/client/index.js.map +1 -1
  189. package/dist/web/index.cjs +158 -1346
  190. package/dist/web/index.cjs.map +1 -1
  191. package/dist/web/index.js +9 -1305
  192. package/dist/web/index.js.map +1 -1
  193. package/dist/web/server/index.cjs +26 -563
  194. package/dist/web/server/index.cjs.map +1 -1
  195. package/dist/web/server/index.js +1 -560
  196. package/dist/web/server/index.js.map +1 -1
  197. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/web/analytics/create-analytics-loader.ts","../../../src/web/analytics/use-cookie-consent.ts","../../../src/web/CookieConsent/CookieConsent.tsx","../../../src/components/Button/Button.tsx","../../../src/components/OutboundLink/OutboundLink.tsx","../../../src/web/utm/useUtmDefaults.ts","../../../src/web/utm/utm-context.ts","../../../src/web/utm/builders.ts","../../../src/web/utm/classifiers.ts","../../../src/components/OutboundLink/outbound-link-utils.ts","../../../src/web/analytics/analytics-provider.tsx","../../../src/web/analytics/analytics-context.ts","../../../src/web/analytics/use-analytics.tsx"],"names":["useState","useEffect","jsx","jsxs","useCallback","createContext","useContext"],"mappings":"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","sourcesContent":["/**\n * Generic analytics script loader.\n *\n * Framework-agnostic: injects a `<script>` tag into `<head>` once,\n * guards against double-loading, and respects cookie consent.\n *\n * @example\n * ```ts\n * import { createAnalyticsLoader } from '@salesmind-ai/design-system/web';\n *\n * const loadGA = createAnalyticsLoader({\n * id: 'ga-script',\n * src: (gaId) => `https://www.googletagmanager.com/gtag/js?id=${gaId}`,\n * onLoad: (gaId) => {\n * window.dataLayer = window.dataLayer || [];\n * function gtag(...args: unknown[]) { window.dataLayer.push(args); }\n * gtag('js', new Date());\n * gtag('config', gaId);\n * },\n * });\n *\n * // Later, after consent:\n * loadGA('G-XXXXXX');\n * ```\n */\n\nexport interface AnalyticsLoaderConfig<TId extends string = string> {\n /** Unique DOM id for the script element (prevents double-loading) */\n id: string;\n /** Build the script src URL from the tracking ID */\n src: (trackingId: TId) => string;\n /** Async attribute on the script tag (default: true) */\n async?: boolean;\n /** Called after the script is appended to the DOM */\n onLoad?: (trackingId: TId) => void;\n /** Custom inline script content instead of an external src */\n inlineScript?: (trackingId: TId) => string;\n}\n\n/**\n * Create a reusable analytics loader function.\n * The returned function injects the script once and is safe to call multiple times.\n */\nexport function createAnalyticsLoader<TId extends string = string>(\n config: AnalyticsLoaderConfig<TId>,\n): (trackingId: TId) => void {\n return (trackingId: TId) => {\n if (typeof document === 'undefined') return;\n if (document.getElementById(config.id)) return;\n\n const script = document.createElement('script');\n script.id = config.id;\n\n if (config.inlineScript) {\n script.textContent = config.inlineScript(trackingId);\n } else {\n script.async = config.async ?? true;\n script.src = config.src(trackingId);\n }\n\n document.head.appendChild(script);\n config.onLoad?.(trackingId);\n };\n}\n\n// ─── Pre-built Loaders ──────────────────────────────────────────────────────\n\ndeclare global {\n interface Window {\n dataLayer: unknown[];\n clarity?: (...args: unknown[]) => void;\n }\n}\n\n/**\n * Load Google Analytics (gtag.js).\n * Call with your GA measurement ID after cookie consent.\n */\nexport const loadGoogleAnalytics = createAnalyticsLoader({\n id: 'ga-script',\n src: (gaId) => `https://www.googletagmanager.com/gtag/js?id=${gaId}`,\n onLoad: (gaId) => {\n window.dataLayer = window.dataLayer || [];\n // Use array push directly to avoid @ts-ignore issues with gtag signature\n window.dataLayer.push(['js', new Date()]);\n window.dataLayer.push(['config', gaId]);\n },\n});\n\n/**\n * Load Microsoft Clarity.\n * Call with your Clarity project ID after cookie consent.\n */\nexport const loadClarity = createAnalyticsLoader({\n id: 'clarity-script',\n src: (clarityId) => `https://www.clarity.ms/tag/${clarityId}`,\n onLoad: () => {\n // Clarity auto-initializes from the script tag.\n // Expose the global `clarity` queue function for custom events.\n if (!window.clarity) {\n const queue: unknown[][] = [];\n window.clarity = (...args: unknown[]) => {\n queue.push(args);\n };\n (window.clarity as unknown as { q: unknown[][] }).q = queue;\n }\n },\n});\n","\"use client\";\nimport { useState, useEffect } from 'react';\nimport { COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, type ConsentStatus } from '../CookieConsent/CookieConsent';\n\n/**\n * React hook that tracks cookie consent status.\n *\n * Returns `true` once the user has granted cookie consent,\n * `false` if denied, `null` if not yet decided.\n *\n * Listens for the `cookie_consent_granted` window event dispatched\n * by the CookieConsent component.\n *\n * @example\n * ```tsx\n * const hasConsent = useCookieConsent();\n *\n * useEffect(() => {\n * if (hasConsent) loadGoogleAnalytics('G-XXXX');\n * }, [hasConsent]);\n * ```\n */\nexport function useCookieConsent(): ConsentStatus {\n const [status, setStatus] = useState<ConsentStatus>(() => {\n if (typeof window === 'undefined') return null;\n const stored = localStorage.getItem(COOKIE_CONSENT_KEY);\n if (stored === 'granted') return 'granted';\n if (stored === 'denied') return 'denied';\n return null;\n });\n\n useEffect(() => {\n const handleConsent = () => setStatus('granted');\n window.addEventListener(COOKIE_CONSENT_EVENT, handleConsent);\n return () => window.removeEventListener(COOKIE_CONSENT_EVENT, handleConsent);\n }, []);\n\n return status;\n}\n","\"use client\";\nimport { useState, useEffect, useCallback } from 'react';\nimport { Button } from '../../components/Button/Button';\nimport { OutboundLink } from '../../components/OutboundLink/OutboundLink';\nimport { X } from 'lucide-react';\nimport './CookieConsent.css';\n\n/** Cookie consent state */\nexport type ConsentStatus = 'granted' | 'denied' | null;\n\n/** Event name dispatched on window when consent changes */\nexport const COOKIE_CONSENT_EVENT = 'cookie_consent_granted';\n\n/** localStorage key for cookie consent */\nexport const COOKIE_CONSENT_KEY = 'cookie_consent';\n\n/** Labels for i18n support */\nexport interface CookieConsentLabels {\n title?: string;\n description?: string;\n privacyLinkText?: string;\n acceptLabel?: string;\n declineLabel?: string;\n}\n\nexport interface CookieConsentProps {\n /** Delay in ms before showing the banner (default: 1000) */\n delay?: number;\n /** URL to the privacy policy page (default: \"/legal/privacy\") */\n privacyUrl?: string;\n /** Called when the user accepts cookies */\n onAccept?: () => void;\n /** Called when the user declines cookies */\n onDecline?: () => void;\n /** Override default labels for i18n */\n labels?: CookieConsentLabels;\n /** Custom className for the container */\n className?: string;\n}\n\n/**\n * CookieConsent — GDPR-compliant cookie consent banner.\n *\n * - Animated entrance/exit via CSS transitions (no framer-motion)\n * - Respects prior consent stored in localStorage\n * - Dispatches a `cookie_consent_granted` event on the window for analytics loaders\n * - Uses DS Button component\n *\n * @example\n * ```tsx\n * import { CookieConsent } from '@salesmind-ai/design-system/web';\n *\n * <CookieConsent\n * privacyUrl=\"/legal/privacy\"\n * onAccept={() => loadGoogleAnalytics('G-XXXX')}\n * />\n * ```\n */\nexport function CookieConsent({\n delay = 1000,\n privacyUrl = '/legal/privacy',\n onAccept,\n onDecline,\n labels,\n className,\n}: CookieConsentProps) {\n // 'idle' = not yet determined, 'open' = visible, 'closing' = exit animation, 'closed' = hidden\n const [state, setState] = useState<'idle' | 'open' | 'closing' | 'closed'>('idle');\n\n useEffect(() => {\n const consent = localStorage.getItem(COOKIE_CONSENT_KEY);\n if (!consent) {\n const timer = setTimeout(() => setState('open'), delay);\n return () => clearTimeout(timer);\n } else {\n setState('closed');\n }\n }, [delay]);\n\n const handleDismiss = useCallback(() => {\n setState('closing');\n }, []);\n\n const handleAccept = useCallback(() => {\n localStorage.setItem(COOKIE_CONSENT_KEY, 'granted');\n handleDismiss();\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new Event(COOKIE_CONSENT_EVENT));\n }\n onAccept?.();\n }, [onAccept, handleDismiss]);\n\n const handleDecline = useCallback(() => {\n localStorage.setItem(COOKIE_CONSENT_KEY, 'denied');\n handleDismiss();\n onDecline?.();\n }, [onDecline, handleDismiss]);\n\n const handleTransitionEnd = useCallback(() => {\n if (state === 'closing') {\n setState('closed');\n }\n }, [state]);\n\n // Don't render anything until we know consent status, or after fully closed\n if (state === 'idle' || state === 'closed') return null;\n\n return (\n <div\n className={`ds-cookie-consent ${className ?? ''}`}\n data-state={state === 'open' ? 'open' : 'closed'}\n onTransitionEnd={handleTransitionEnd}\n role=\"dialog\"\n aria-label={labels?.title ?? 'Cookie consent'}\n >\n <div className=\"ds-cookie-consent__inner\">\n <div className=\"ds-cookie-consent__content\">\n <h3 className=\"ds-cookie-consent__title\">\n {labels?.title ?? 'We use cookies'}\n </h3>\n <p className=\"ds-cookie-consent__description\">\n {labels?.description ??\n 'We use tracking cookies to understand how you use the product and help us improve it.'}\n <OutboundLink href={privacyUrl} context=\"cookie-consent-privacy\" className=\"ds-cookie-consent__link\">\n {labels?.privacyLinkText ?? 'Privacy Policy'}\n </OutboundLink>\n </p>\n </div>\n <div className=\"ds-cookie-consent__actions\">\n <Button variant=\"outline\" size=\"sm\" onClick={handleDecline}>\n {labels?.declineLabel ?? 'Decline'}\n </Button>\n <Button variant=\"primary\" size=\"sm\" onClick={handleAccept}>\n {labels?.acceptLabel ?? 'Accept'}\n </Button>\n </div>\n <button\n onClick={handleDecline}\n className=\"ds-cookie-consent__close\"\n aria-label=\"Close\"\n >\n <X size={16} />\n </button>\n </div>\n </div>\n );\n}\n","import React from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport clsx from 'clsx';\nimport './Button.css';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the button */\n variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'link' | 'destructive';\n /** Size of the button */\n size?: 'sm' | 'md' | 'lg' | 'icon';\n /** Shows a loading spinner and disables the button */\n isLoading?: boolean;\n /**\n * When true, the button renders its child as the root element via Radix Slot.\n * Use this to compose with routing Link components or anchors.\n *\n * @example\n * <Button asChild>\n * <a href=\"/about\">About</a>\n * </Button>\n */\n asChild?: boolean;\n}\n\n/**\n * Primary UI action component with multiple visual variants and polymorphic rendering.\n *\n * Supports `asChild` for rendering as any element (Link, anchor, etc.)\n * while preserving button styling.\n */\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'primary', size = 'md', asChild = false, isLoading = false, children, disabled, ...props }, ref) => {\n const buttonClass = clsx(\n 'ds-button',\n `ds-button--${variant}`,\n size === 'icon' ? 'ds-button--icon ds-button--md' : `ds-button--${size}`,\n isLoading && 'ds-button--loading',\n className,\n );\n\n // When asChild, Slot must receive exactly one child element.\n // Loading state is handled via the ds-button--loading CSS class.\n if (asChild) {\n return (\n <Slot\n ref={ref}\n aria-disabled={isLoading || disabled || undefined}\n className={buttonClass}\n {...props}\n >\n {children}\n </Slot>\n );\n }\n\n return (\n <button\n ref={ref}\n disabled={isLoading || disabled}\n className={buttonClass}\n {...props}\n >\n {isLoading && (\n <svg\n className=\"ds-button__spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n )}\n <span className={clsx(\"ds-button__content\", isLoading && \"ds-button__content--hidden\")}>\n {children}\n </span>\n </button>\n );\n },\n);\n\nButton.displayName = 'Button';\n","import React, { AnchorHTMLAttributes, forwardRef, MouseEvent, useState, useEffect } from 'react';\nimport type { UtmParams } from '../../web/utm/types';\nimport { useUtmDefaults } from '../../web/utm/useUtmDefaults';\nimport { isExemptUrl, appendUTMs, appendGovernedUTMs } from './outbound-link-utils';\n\nexport interface OutboundLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href: string;\n context: string;\n campaignOverride?: string;\n mediumOverride?: string;\n preserveExistingUTM?: boolean;\n openInNewTab?: boolean;\n disableTracking?: boolean;\n /**\n * Governed UTM parameters. When provided, the link uses the UTM governance\n * system (buildUtmUrl) instead of the legacy appendUTMs approach.\n *\n * Preferred for all new code. Existing usages without utmParams continue\n * to work via the legacy path.\n */\n utmParams?: UtmParams;\n children: React.ReactNode;\n}\n\nexport interface OutboundClickEventDetail {\n destination_domain: string;\n destination_url: string;\n utm_medium_type: string;\n page_slug: string;\n component_location: string;\n timestamp: string;\n is_cross_subdomain: boolean;\n}\n\nexport const OutboundLink = forwardRef<HTMLAnchorElement, OutboundLinkProps>(\n (\n {\n href,\n context,\n campaignOverride,\n mediumOverride = 'outbound_link',\n preserveExistingUTM = true,\n openInNewTab = true,\n disableTracking = false,\n utmParams,\n onClick,\n children,\n ...props\n },\n ref\n ) => {\n // ── Resolve UTM params: explicit prop > context > legacy fallback ──\n const contextParams = useUtmDefaults();\n const resolvedUtmParams = utmParams ?? contextParams;\n\n // Parse hostname for analytics events (safe on both server/client)\n let hostname = '';\n try {\n const url = new URL(href);\n hostname = url.hostname;\n } catch {\n // Relative URL or invalid — hostname stays empty\n }\n\n // SSR and initial client render use the plain href to avoid hydration\n // mismatches. UTM params are decorated after hydration via useEffect.\n const [finalHref, setFinalHref] = useState(href);\n\n useEffect(() => {\n let isExternal = false;\n let currentMedium = mediumOverride;\n\n try {\n const url = new URL(href);\n const currentHost = window.location.hostname;\n isExternal = url.hostname !== currentHost;\n\n if (isExternal && currentHost.includes('sales-mind.ai') && url.hostname.includes('sales-mind.ai')) {\n if (currentMedium === 'outbound_link') {\n currentMedium = 'cross_subdomain';\n }\n }\n } catch {\n isExternal = false;\n }\n\n const isExempt = isExemptUrl(href) || disableTracking;\n\n if (isExternal && !isExempt) {\n if (resolvedUtmParams) {\n // Governed path: use buildUtmUrl via appendGovernedUTMs\n setFinalHref(appendGovernedUTMs(href, resolvedUtmParams, preserveExistingUTM));\n } else {\n // Legacy path: use appendUTMs with non-governed defaults\n const pageSlug = window.location.pathname.replace(/^\\/|\\/$/g, '') || 'home';\n setFinalHref(appendUTMs(href, context, pageSlug, {\n mediumOverride: currentMedium,\n campaignOverride,\n preserveExisting: preserveExistingUTM,\n }));\n }\n } else {\n setFinalHref(href);\n }\n }, [href, context, mediumOverride, campaignOverride, preserveExistingUTM, disableTracking, resolvedUtmParams]);\n\n const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {\n if (typeof window === 'undefined' || disableTracking) {\n onClick?.(e);\n return;\n }\n\n let clickExternal = false;\n let clickCrossSubdomain = false;\n let clickMedium = mediumOverride;\n\n try {\n const url = new URL(href);\n const currentHost = window.location.hostname;\n clickExternal = url.hostname !== currentHost;\n\n if (clickExternal && currentHost.includes('sales-mind.ai') && url.hostname.includes('sales-mind.ai')) {\n clickCrossSubdomain = true;\n if (clickMedium === 'outbound_link') {\n clickMedium = 'cross_subdomain';\n }\n }\n } catch { /* relative URL */ }\n\n if (clickExternal) {\n const detail: OutboundClickEventDetail = {\n destination_domain: hostname,\n destination_url: finalHref,\n utm_medium_type: clickMedium,\n page_slug: window.location.pathname,\n component_location: context,\n timestamp: new Date().toISOString(),\n is_cross_subdomain: clickCrossSubdomain,\n };\n\n const event = new CustomEvent('outbound_click', { detail });\n window.dispatchEvent(event);\n }\n\n onClick?.(e);\n };\n\n // Determine SEO attributes\n const relParts = [];\n \n // Check if it's cross-subdomain for target logic (usually open internal links in same tab, external in new)\n let shouldOpenNewTab = openInNewTab;\n try {\n const url = new URL(href);\n if (typeof window !== 'undefined') {\n const currentHost = window.location.hostname;\n if (url.hostname !== currentHost && currentHost.includes('sales-mind.ai') && url.hostname.includes('sales-mind.ai')) {\n shouldOpenNewTab = false; // By default, prefer same tab for cross-subdomain ecosystem links\n }\n }\n } catch { /* empty */ }\n\n if (shouldOpenNewTab) relParts.push('noopener', 'noreferrer');\n if (mediumOverride === 'citation') relParts.push('nofollow');\n const rel = relParts.length > 0 ? relParts.join(' ') : undefined;\n\n return (\n // eslint-disable-next-line no-restricted-syntax\n <a\n ref={ref}\n href={finalHref}\n target={shouldOpenNewTab ? '_blank' : undefined}\n rel={rel}\n onClick={handleClick}\n {...props}\n >\n {children}\n </a>\n );\n }\n);\n\nOutboundLink.displayName = 'OutboundLink';\n","import { useContext } from 'react';\nimport { UtmContext } from './utm-context';\nimport type { UtmParams } from './types';\n\n/**\n * Read the nearest UtmProvider's default params.\n * Returns `null` when no provider is present (callers should fall back gracefully).\n */\nexport function useUtmDefaults(): UtmParams | null {\n return useContext(UtmContext);\n}\n","import { createContext } from 'react';\nimport type { UtmParams } from './types';\n\n/** Internal React context instance. Import via UtmProvider / useUtmDefaults — do not use directly. */\nexport const UtmContext = createContext<UtmParams | null>(null);\n","/* ============================================================================\n UTM URL Builders\n ============================================================================ */\n\nimport type { UtmParams } from './types';\n\n/** Placeholder origin used internally to parse relative URLs. Never appears in output. */\nconst PLACEHOLDER_ORIGIN = 'https://__placeholder__.internal';\n\n/**\n * Build a URL with UTM parameters appended.\n *\n * - Supports both absolute and relative URLs.\n * - Preserves existing query parameters and hash fragments.\n * - Always emits params in canonical order: source → medium → campaign → term → content.\n * - Omits optional params (term, content) when undefined.\n *\n * @example\n * buildUtmUrl('https://app.sales-mind.ai/register', { source: 'linkedin', medium: 'dm', campaign: 'discoveryCall' })\n * // → 'https://app.sales-mind.ai/register?utm_source=linkedin&utm_medium=dm&utm_campaign=discoveryCall'\n *\n * buildUtmUrl('/pricing', { source: 'website', medium: 'webHome', campaign: 'trial' })\n * // → '/pricing?utm_source=website&utm_medium=webHome&utm_campaign=trial'\n */\nexport function buildUtmUrl(baseUrl: string, params: UtmParams): string {\n const isRelative = baseUrl.startsWith('/');\n\n let url: URL;\n try {\n url = isRelative ? new URL(baseUrl, PLACEHOLDER_ORIGIN) : new URL(baseUrl);\n } catch {\n // If URL parsing fails entirely, return the base URL unchanged.\n return baseUrl;\n }\n\n // Preserve existing params by collecting them first, then clearing and re-adding in order.\n const existingParams: [string, string][] = [];\n url.searchParams.forEach((value, key) => {\n existingParams.push([key, value]);\n });\n\n // Clear all params to rebuild in canonical order.\n for (const [key] of existingParams) {\n url.searchParams.delete(key);\n }\n\n // Re-add existing non-UTM params first.\n for (const [key, value] of existingParams) {\n if (!key.startsWith('utm_')) {\n url.searchParams.set(key, value);\n }\n }\n\n // Append UTM params in canonical order.\n url.searchParams.set('utm_source', params.source);\n url.searchParams.set('utm_medium', params.medium);\n url.searchParams.set('utm_campaign', params.campaign);\n if (params.term !== undefined) {\n url.searchParams.set('utm_term', params.term);\n }\n if (params.content !== undefined) {\n url.searchParams.set('utm_content', params.content);\n }\n\n if (isRelative) {\n // Strip placeholder origin to return a relative path.\n return url.href.replace(PLACEHOLDER_ORIGIN, '');\n }\n\n return url.href;\n}\n","/* ============================================================================\n URL Classification & UTM Enforcement Logic\n ============================================================================\n Determines whether a URL requires UTM parameters based on its type.\n No imports from validators — avoids circular dependency.\n ============================================================================ */\n\nimport type { UrlClassification } from './types';\n\n// ── Patterns ─────────────────────────────────────────────────────────────────\n\n/** Internal domains — UTMs not required for same-origin navigation. */\nconst INTERNAL_PATTERNS = [\n /^\\/(?!\\/)/, // Relative paths\n /^https?:\\/\\/(www\\.)?sales-mind\\.ai/i, // Marketing site\n /^https?:\\/\\/app\\.sales-mind\\.ai/i, // Web app\n /^https?:\\/\\/apps\\.sales-mind\\.ai/i, // Web app (legacy)\n /^https?:\\/\\/meet\\.sales-mind\\.ai/i, // Booking\n /^https?:\\/\\/docs\\.sales-mind\\.ai/i, // Docs\n];\n\n/** System endpoints — never receive UTMs. */\nconst SYSTEM_PATTERNS = [\n /^https?:\\/\\/.*\\/api\\//i, // API endpoints\n /^https?:\\/\\/.*\\/webhook/i, // Webhooks\n /^https?:\\/\\/.*\\/oauth/i, // OAuth callbacks\n /^https?:\\/\\/.*\\/callback/i, // Callbacks\n /^https?:\\/\\/.*\\.supabase\\.(co|com)/i, // Supabase\n /^https?:\\/\\/.*\\.firebaseapp\\.com/i, // Firebase\n /^https?:\\/\\/.*\\.cloudfunctions\\.net/i, // Cloud Functions\n];\n\n/** Static assets — never receive UTMs. */\nconst ASSET_PATTERNS = [\n /\\.(css|js|mjs|map|woff2?|ttf|eot|svg|png|jpe?g|gif|webp|avif|ico|pdf)(\\?.*)?$/i,\n];\n\n/** Conversion destinations — always require UTMs. */\nconst CONVERSION_PATTERNS = [\n /^https?:\\/\\/(www\\.)?calendly\\.com/i,\n /^https?:\\/\\/(checkout\\.)?stripe\\.com/i,\n /^https?:\\/\\/buy\\.stripe\\.com/i,\n /^https?:\\/\\/chromewebstore\\.google\\.com/i,\n /^https?:\\/\\/meet\\.sales-mind\\.ai/i,\n];\n\n/** Protocol-level links — never receive UTMs. */\nconst PROTOCOL_EXEMPT = [\n /^mailto:/i,\n /^tel:/i,\n /^#/,\n /^javascript:/i,\n];\n\n// ── Classification ───────────────────────────────────────────────────────────\n\n/**\n * Classify a URL to determine its type.\n *\n * Classification order (first match wins):\n * 1. Protocol links (mailto, tel, anchor)\n * 2. Static assets\n * 3. System endpoints (API, webhooks, OAuth)\n * 4. Conversion destinations (Calendly, Stripe, Chrome Store)\n * 5. Internal (*.sales-mind.ai)\n * 6. External (everything else)\n */\nexport function classifyUrl(url: string): UrlClassification {\n // Protocol links\n if (PROTOCOL_EXEMPT.some(p => p.test(url))) return 'protocol';\n\n // Static assets\n if (ASSET_PATTERNS.some(p => p.test(url))) return 'asset';\n\n // System endpoints\n if (SYSTEM_PATTERNS.some(p => p.test(url))) return 'system';\n\n // Conversion destinations\n if (CONVERSION_PATTERNS.some(p => p.test(url))) return 'conversion';\n\n // Internal\n if (INTERNAL_PATTERNS.some(p => p.test(url))) return 'internal';\n\n // Everything else is external\n return 'external';\n}\n\n/**\n * Determine whether a URL requires UTM parameters.\n *\n * UTMs are mandatory for:\n * - External third-party destinations\n * - Conversion destinations (Calendly, Stripe, Chrome Web Store)\n *\n * UTMs are NOT required for:\n * - Internal navigation\n * - System endpoints\n * - Static assets\n * - Protocol links\n */\nexport function requiresUtm(url: string): boolean {\n const classification = classifyUrl(url);\n return classification === 'external' || classification === 'conversion';\n}\n\n/**\n * Check if a URL is explicitly exempt from UTM requirements.\n */\nexport function isUtmExempt(url: string): boolean {\n const classification = classifyUrl(url);\n return classification === 'protocol'\n || classification === 'asset'\n || classification === 'system'\n || classification === 'internal';\n}\n","import type { UtmParams } from '../../web/utm/types';\nimport { buildUtmUrl } from '../../web/utm/builders';\nimport { classifyUrl } from '../../web/utm/classifiers';\n\n/**\n * @deprecated Use governed `utmParams` prop on OutboundLink instead.\n * Legacy default source — superseded by governed UTM_SOURCES enum.\n */\nconst LEGACY_UTM_SOURCE = 'salesmind';\n\nconst EXEMPT_PATTERNS = [\n /^https?:\\/\\/(www\\.)?(stripe\\.com|checkout\\.stripe\\.com|paypal\\.com)/i,\n /^https?:\\/\\/(www\\.)?github\\.com\\/login\\/oauth/i,\n];\n\n/**\n * Check if a URL is exempt from UTM tagging.\n * Uses both legacy patterns and governed URL classification.\n */\nexport const isExemptUrl = (urlStr: string): boolean => {\n if (urlStr.startsWith('mailto:') || urlStr.startsWith('tel:')) return true;\n\n // Governed classification: system/protocol/asset URLs are exempt\n const classification = classifyUrl(urlStr);\n if (classification === 'system' || classification === 'protocol' || classification === 'asset') {\n return true;\n }\n\n return EXEMPT_PATTERNS.some(pattern => pattern.test(urlStr));\n};\n\n/**\n * Append governed UTM parameters to a URL using `buildUtmUrl`.\n * Preferred over the legacy `appendUTMs` function.\n */\nexport const appendGovernedUTMs = (\n href: string,\n params: UtmParams,\n preserveExisting = true,\n): string => {\n try {\n const url = new URL(href);\n\n // If preserveExisting and all UTM params are already set, return unchanged\n if (preserveExisting) {\n const hasAll = url.searchParams.has('utm_source')\n && url.searchParams.has('utm_medium')\n && url.searchParams.has('utm_campaign');\n if (hasAll) return href;\n }\n\n return buildUtmUrl(href, params);\n } catch {\n return href;\n }\n};\n\n/**\n * @deprecated Prefer `appendGovernedUTMs` with governed `UtmParams`.\n *\n * Legacy UTM append function. Uses non-governed defaults:\n * - utm_source = 'salesmind' (not in governed enum)\n * - utm_medium = 'outbound_link' (snake_case, not in governed enum)\n *\n * Retained for backward compatibility. Consumers should migrate to\n * the `utmParams` prop on OutboundLink.\n */\nexport const appendUTMs = (\n href: string,\n context: string,\n pageSlug: string,\n options: {\n mediumOverride?: string;\n campaignOverride?: string;\n preserveExisting?: boolean;\n }\n): string => {\n try {\n const url = new URL(href);\n const { mediumOverride = 'outbound_link', campaignOverride, preserveExisting = true } = options;\n\n const utms = {\n utm_source: LEGACY_UTM_SOURCE,\n utm_medium: mediumOverride,\n utm_campaign: campaignOverride || pageSlug,\n utm_content: context,\n };\n\n Object.entries(utms).forEach(([key, value]) => {\n if (value) {\n if (preserveExisting && url.searchParams.has(key)) {\n // Do not override if preserve is true\n return;\n }\n url.searchParams.set(key, value);\n }\n });\n\n return url.toString();\n } catch {\n return href; // Return original if not valid URL (e.g. relative)\n }\n};\n","\"use client\";\nimport { useCallback, useMemo } from 'react';\nimport type { ReactNode } from 'react';\nimport { AnalyticsContext } from './analytics-context';\nimport type { TrackFn } from './analytics-context';\n\n/* ============================================================================\n ANALYTICS PROVIDER — Event Tracking Context\n ============================================================================\n\n Provides a unified event tracking interface for all marketing/conversion\n components. Components call `useAnalytics().track(...)` without knowing\n which analytics backend is active.\n\n When no provider is present, all calls are no-ops — safe for Storybook,\n tests, and SSR.\n\n Usage:\n // In your app root:\n <AnalyticsProvider onTrack={(event, props) => gtag('event', event, props)}>\n <App />\n </AnalyticsProvider>\n\n // In any DS component:\n const { track } = useAnalytics();\n track('cta_click', { location: 'hero', label: 'Book Demo' });\n\n ============================================================================ */\n\n/** Props for the AnalyticsProvider component */\nexport interface AnalyticsProviderProps {\n /** Callback invoked on every track() call. Wire this to your analytics backend. */\n onTrack: TrackFn;\n /** Enable console logging in development (default: false) */\n debug?: boolean;\n children: ReactNode;\n}\n\n/**\n * Provides analytics event tracking to all descendant DS components.\n *\n * @example\n * ```tsx\n * <AnalyticsProvider\n * onTrack={(event, props) => {\n * window.gtag?.('event', event, props);\n * }}\n * >\n * <App />\n * </AnalyticsProvider>\n * ```\n */\nexport function AnalyticsProvider({ onTrack, debug = false, children }: AnalyticsProviderProps) {\n const track: TrackFn = useCallback(\n (event, props) => {\n if (debug && typeof console !== 'undefined') {\n // eslint-disable-next-line no-console\n console.log('[DS Analytics]', event, props);\n }\n onTrack(event, props);\n },\n [onTrack, debug],\n );\n\n const value = useMemo(() => ({ track }), [track]);\n\n return <AnalyticsContext.Provider value={value}>{children}</AnalyticsContext.Provider>;\n}\n","import { createContext } from 'react';\n\n/* ============================================================================\n ANALYTICS CONTEXT — Shared types & context object\n ============================================================================ */\n\n/** Arbitrary properties bag attached to every analytics event. */\nexport type AnalyticsEventProps = Record<string, string | number | boolean | undefined>;\n\n/** Signature for the track function provided by AnalyticsProvider. */\nexport type TrackFn = (event: string, props?: AnalyticsEventProps) => void;\n\n/** Value exposed by the AnalyticsContext. */\nexport interface AnalyticsContextValue {\n track: TrackFn;\n}\n\n/**\n * React context for analytics event tracking.\n * When no provider is present the value is `null` — consumers should\n * fall back to a no-op so components remain safe in Storybook / tests / SSR.\n */\nexport const AnalyticsContext = createContext<AnalyticsContextValue | null>(null);\n","\"use client\";\nimport { useContext } from 'react';\nimport { AnalyticsContext } from './analytics-context';\nimport type { AnalyticsContextValue } from './analytics-context';\n\nconst NOOP_VALUE: AnalyticsContextValue = {\n track: () => {\n /* no-op when no provider is present */\n },\n};\n\n/**\n * Access the analytics tracking interface.\n * Returns a no-op tracker when used outside an AnalyticsProvider —\n * components never need to guard against missing providers.\n *\n * @example\n * ```tsx\n * const { track } = useAnalytics();\n * track('form_submit', { form: 'lead-capture', email: true });\n * ```\n */\nexport function useAnalytics(): AnalyticsContextValue {\n return useContext(AnalyticsContext) ?? NOOP_VALUE;\n}\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":""}
@@ -1,486 +1,7 @@
1
1
  "use client";
2
- import React, { createContext, forwardRef, useState, useEffect, useContext, useCallback, useMemo } from 'react';
3
- import { Slot } from '@radix-ui/react-slot';
4
- import clsx from 'clsx';
5
- import { jsx, jsxs } from 'react/jsx-runtime';
6
- import { X } from 'lucide-react';
7
-
8
- // src/web/analytics/create-analytics-loader.ts
9
- function createAnalyticsLoader(config) {
10
- return (trackingId) => {
11
- if (typeof document === "undefined") return;
12
- if (document.getElementById(config.id)) return;
13
- const script = document.createElement("script");
14
- script.id = config.id;
15
- if (config.inlineScript) {
16
- script.textContent = config.inlineScript(trackingId);
17
- } else {
18
- script.async = config.async ?? true;
19
- script.src = config.src(trackingId);
20
- }
21
- document.head.appendChild(script);
22
- config.onLoad?.(trackingId);
23
- };
24
- }
25
- var loadGoogleAnalytics = createAnalyticsLoader({
26
- id: "ga-script",
27
- src: (gaId) => `https://www.googletagmanager.com/gtag/js?id=${gaId}`,
28
- onLoad: (gaId) => {
29
- window.dataLayer = window.dataLayer || [];
30
- window.dataLayer.push(["js", /* @__PURE__ */ new Date()]);
31
- window.dataLayer.push(["config", gaId]);
32
- }
33
- });
34
- var loadClarity = createAnalyticsLoader({
35
- id: "clarity-script",
36
- src: (clarityId) => `https://www.clarity.ms/tag/${clarityId}`,
37
- onLoad: () => {
38
- if (!window.clarity) {
39
- const queue = [];
40
- window.clarity = (...args) => {
41
- queue.push(args);
42
- };
43
- window.clarity.q = queue;
44
- }
45
- }
46
- });
47
- var Button = React.forwardRef(
48
- ({ className, variant = "primary", size = "md", asChild = false, isLoading = false, children, disabled, ...props }, ref) => {
49
- const buttonClass = clsx(
50
- "ds-button",
51
- `ds-button--${variant}`,
52
- size === "icon" ? "ds-button--icon ds-button--md" : `ds-button--${size}`,
53
- isLoading && "ds-button--loading",
54
- className
55
- );
56
- if (asChild) {
57
- return /* @__PURE__ */ jsx(
58
- Slot,
59
- {
60
- ref,
61
- "aria-disabled": isLoading || disabled || void 0,
62
- className: buttonClass,
63
- ...props,
64
- children
65
- }
66
- );
67
- }
68
- return /* @__PURE__ */ jsxs(
69
- "button",
70
- {
71
- ref,
72
- disabled: isLoading || disabled,
73
- className: buttonClass,
74
- ...props,
75
- children: [
76
- isLoading && /* @__PURE__ */ jsx(
77
- "svg",
78
- {
79
- className: "ds-button__spinner",
80
- xmlns: "http://www.w3.org/2000/svg",
81
- width: "1em",
82
- height: "1em",
83
- viewBox: "0 0 24 24",
84
- fill: "none",
85
- stroke: "currentColor",
86
- strokeWidth: "2",
87
- strokeLinecap: "round",
88
- strokeLinejoin: "round",
89
- children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
90
- }
91
- ),
92
- /* @__PURE__ */ jsx("span", { className: clsx("ds-button__content", isLoading && "ds-button__content--hidden"), children })
93
- ]
94
- }
95
- );
96
- }
97
- );
98
- Button.displayName = "Button";
99
- var UtmContext = createContext(null);
100
-
101
- // src/web/utm/useUtmDefaults.ts
102
- function useUtmDefaults() {
103
- return useContext(UtmContext);
104
- }
105
-
106
- // src/web/utm/builders.ts
107
- var PLACEHOLDER_ORIGIN = "https://__placeholder__.internal";
108
- function buildUtmUrl(baseUrl, params) {
109
- const isRelative = baseUrl.startsWith("/");
110
- let url;
111
- try {
112
- url = isRelative ? new URL(baseUrl, PLACEHOLDER_ORIGIN) : new URL(baseUrl);
113
- } catch {
114
- return baseUrl;
115
- }
116
- const existingParams = [];
117
- url.searchParams.forEach((value, key) => {
118
- existingParams.push([key, value]);
119
- });
120
- for (const [key] of existingParams) {
121
- url.searchParams.delete(key);
122
- }
123
- for (const [key, value] of existingParams) {
124
- if (!key.startsWith("utm_")) {
125
- url.searchParams.set(key, value);
126
- }
127
- }
128
- url.searchParams.set("utm_source", params.source);
129
- url.searchParams.set("utm_medium", params.medium);
130
- url.searchParams.set("utm_campaign", params.campaign);
131
- if (params.term !== void 0) {
132
- url.searchParams.set("utm_term", params.term);
133
- }
134
- if (params.content !== void 0) {
135
- url.searchParams.set("utm_content", params.content);
136
- }
137
- if (isRelative) {
138
- return url.href.replace(PLACEHOLDER_ORIGIN, "");
139
- }
140
- return url.href;
141
- }
142
-
143
- // src/web/utm/classifiers.ts
144
- var INTERNAL_PATTERNS = [
145
- /^\/(?!\/)/,
146
- // Relative paths
147
- /^https?:\/\/(www\.)?sales-mind\.ai/i,
148
- // Marketing site
149
- /^https?:\/\/app\.sales-mind\.ai/i,
150
- // Web app
151
- /^https?:\/\/apps\.sales-mind\.ai/i,
152
- // Web app (legacy)
153
- /^https?:\/\/meet\.sales-mind\.ai/i,
154
- // Booking
155
- /^https?:\/\/docs\.sales-mind\.ai/i
156
- // Docs
157
- ];
158
- var SYSTEM_PATTERNS = [
159
- /^https?:\/\/.*\/api\//i,
160
- // API endpoints
161
- /^https?:\/\/.*\/webhook/i,
162
- // Webhooks
163
- /^https?:\/\/.*\/oauth/i,
164
- // OAuth callbacks
165
- /^https?:\/\/.*\/callback/i,
166
- // Callbacks
167
- /^https?:\/\/.*\.supabase\.(co|com)/i,
168
- // Supabase
169
- /^https?:\/\/.*\.firebaseapp\.com/i,
170
- // Firebase
171
- /^https?:\/\/.*\.cloudfunctions\.net/i
172
- // Cloud Functions
173
- ];
174
- var ASSET_PATTERNS = [
175
- /\.(css|js|mjs|map|woff2?|ttf|eot|svg|png|jpe?g|gif|webp|avif|ico|pdf)(\?.*)?$/i
176
- ];
177
- var CONVERSION_PATTERNS = [
178
- /^https?:\/\/(www\.)?calendly\.com/i,
179
- /^https?:\/\/(checkout\.)?stripe\.com/i,
180
- /^https?:\/\/buy\.stripe\.com/i,
181
- /^https?:\/\/chromewebstore\.google\.com/i,
182
- /^https?:\/\/meet\.sales-mind\.ai/i
183
- ];
184
- var PROTOCOL_EXEMPT = [
185
- /^mailto:/i,
186
- /^tel:/i,
187
- /^#/,
188
- /^javascript:/i
189
- ];
190
- function classifyUrl(url) {
191
- if (PROTOCOL_EXEMPT.some((p) => p.test(url))) return "protocol";
192
- if (ASSET_PATTERNS.some((p) => p.test(url))) return "asset";
193
- if (SYSTEM_PATTERNS.some((p) => p.test(url))) return "system";
194
- if (CONVERSION_PATTERNS.some((p) => p.test(url))) return "conversion";
195
- if (INTERNAL_PATTERNS.some((p) => p.test(url))) return "internal";
196
- return "external";
197
- }
198
-
199
- // src/components/OutboundLink/outbound-link-utils.ts
200
- var LEGACY_UTM_SOURCE = "salesmind";
201
- var EXEMPT_PATTERNS = [
202
- /^https?:\/\/(www\.)?(stripe\.com|checkout\.stripe\.com|paypal\.com)/i,
203
- /^https?:\/\/(www\.)?github\.com\/login\/oauth/i
204
- ];
205
- var isExemptUrl = (urlStr) => {
206
- if (urlStr.startsWith("mailto:") || urlStr.startsWith("tel:")) return true;
207
- const classification = classifyUrl(urlStr);
208
- if (classification === "system" || classification === "protocol" || classification === "asset") {
209
- return true;
210
- }
211
- return EXEMPT_PATTERNS.some((pattern) => pattern.test(urlStr));
212
- };
213
- var appendGovernedUTMs = (href, params, preserveExisting = true) => {
214
- try {
215
- const url = new URL(href);
216
- if (preserveExisting) {
217
- const hasAll = url.searchParams.has("utm_source") && url.searchParams.has("utm_medium") && url.searchParams.has("utm_campaign");
218
- if (hasAll) return href;
219
- }
220
- return buildUtmUrl(href, params);
221
- } catch {
222
- return href;
223
- }
224
- };
225
- var appendUTMs = (href, context, pageSlug, options) => {
226
- try {
227
- const url = new URL(href);
228
- const { mediumOverride = "outbound_link", campaignOverride, preserveExisting = true } = options;
229
- const utms = {
230
- utm_source: LEGACY_UTM_SOURCE,
231
- utm_medium: mediumOverride,
232
- utm_campaign: campaignOverride || pageSlug,
233
- utm_content: context
234
- };
235
- Object.entries(utms).forEach(([key, value]) => {
236
- if (value) {
237
- if (preserveExisting && url.searchParams.has(key)) {
238
- return;
239
- }
240
- url.searchParams.set(key, value);
241
- }
242
- });
243
- return url.toString();
244
- } catch {
245
- return href;
246
- }
247
- };
248
- var OutboundLink = forwardRef(
249
- ({
250
- href,
251
- context,
252
- campaignOverride,
253
- mediumOverride = "outbound_link",
254
- preserveExistingUTM = true,
255
- openInNewTab = true,
256
- disableTracking = false,
257
- utmParams,
258
- onClick,
259
- children,
260
- ...props
261
- }, ref) => {
262
- const contextParams = useUtmDefaults();
263
- const resolvedUtmParams = utmParams ?? contextParams;
264
- let hostname = "";
265
- try {
266
- const url = new URL(href);
267
- hostname = url.hostname;
268
- } catch {
269
- }
270
- const [finalHref, setFinalHref] = useState(href);
271
- useEffect(() => {
272
- let isExternal = false;
273
- let currentMedium = mediumOverride;
274
- try {
275
- const url = new URL(href);
276
- const currentHost = window.location.hostname;
277
- isExternal = url.hostname !== currentHost;
278
- if (isExternal && currentHost.includes("sales-mind.ai") && url.hostname.includes("sales-mind.ai")) {
279
- if (currentMedium === "outbound_link") {
280
- currentMedium = "cross_subdomain";
281
- }
282
- }
283
- } catch {
284
- isExternal = false;
285
- }
286
- const isExempt = isExemptUrl(href) || disableTracking;
287
- if (isExternal && !isExempt) {
288
- if (resolvedUtmParams) {
289
- setFinalHref(appendGovernedUTMs(href, resolvedUtmParams, preserveExistingUTM));
290
- } else {
291
- const pageSlug = window.location.pathname.replace(/^\/|\/$/g, "") || "home";
292
- setFinalHref(appendUTMs(href, context, pageSlug, {
293
- mediumOverride: currentMedium,
294
- campaignOverride,
295
- preserveExisting: preserveExistingUTM
296
- }));
297
- }
298
- } else {
299
- setFinalHref(href);
300
- }
301
- }, [href, context, mediumOverride, campaignOverride, preserveExistingUTM, disableTracking, resolvedUtmParams]);
302
- const handleClick = (e) => {
303
- if (typeof window === "undefined" || disableTracking) {
304
- onClick?.(e);
305
- return;
306
- }
307
- let clickExternal = false;
308
- let clickCrossSubdomain = false;
309
- let clickMedium = mediumOverride;
310
- try {
311
- const url = new URL(href);
312
- const currentHost = window.location.hostname;
313
- clickExternal = url.hostname !== currentHost;
314
- if (clickExternal && currentHost.includes("sales-mind.ai") && url.hostname.includes("sales-mind.ai")) {
315
- clickCrossSubdomain = true;
316
- if (clickMedium === "outbound_link") {
317
- clickMedium = "cross_subdomain";
318
- }
319
- }
320
- } catch {
321
- }
322
- if (clickExternal) {
323
- const detail = {
324
- destination_domain: hostname,
325
- destination_url: finalHref,
326
- utm_medium_type: clickMedium,
327
- page_slug: window.location.pathname,
328
- component_location: context,
329
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
330
- is_cross_subdomain: clickCrossSubdomain
331
- };
332
- const event = new CustomEvent("outbound_click", { detail });
333
- window.dispatchEvent(event);
334
- }
335
- onClick?.(e);
336
- };
337
- const relParts = [];
338
- let shouldOpenNewTab = openInNewTab;
339
- try {
340
- const url = new URL(href);
341
- if (typeof window !== "undefined") {
342
- const currentHost = window.location.hostname;
343
- if (url.hostname !== currentHost && currentHost.includes("sales-mind.ai") && url.hostname.includes("sales-mind.ai")) {
344
- shouldOpenNewTab = false;
345
- }
346
- }
347
- } catch {
348
- }
349
- if (shouldOpenNewTab) relParts.push("noopener", "noreferrer");
350
- if (mediumOverride === "citation") relParts.push("nofollow");
351
- const rel = relParts.length > 0 ? relParts.join(" ") : void 0;
352
- return (
353
- // eslint-disable-next-line no-restricted-syntax
354
- /* @__PURE__ */ jsx(
355
- "a",
356
- {
357
- ref,
358
- href: finalHref,
359
- target: shouldOpenNewTab ? "_blank" : void 0,
360
- rel,
361
- onClick: handleClick,
362
- ...props,
363
- children
364
- }
365
- )
366
- );
367
- }
368
- );
369
- OutboundLink.displayName = "OutboundLink";
370
- var COOKIE_CONSENT_EVENT = "cookie_consent_granted";
371
- var COOKIE_CONSENT_KEY = "cookie_consent";
372
- function CookieConsent({
373
- delay = 1e3,
374
- privacyUrl = "/legal/privacy",
375
- onAccept,
376
- onDecline,
377
- labels,
378
- className
379
- }) {
380
- const [state, setState] = useState("idle");
381
- useEffect(() => {
382
- const consent = localStorage.getItem(COOKIE_CONSENT_KEY);
383
- if (!consent) {
384
- const timer = setTimeout(() => setState("open"), delay);
385
- return () => clearTimeout(timer);
386
- } else {
387
- setState("closed");
388
- }
389
- }, [delay]);
390
- const handleDismiss = useCallback(() => {
391
- setState("closing");
392
- }, []);
393
- const handleAccept = useCallback(() => {
394
- localStorage.setItem(COOKIE_CONSENT_KEY, "granted");
395
- handleDismiss();
396
- if (typeof window !== "undefined") {
397
- window.dispatchEvent(new Event(COOKIE_CONSENT_EVENT));
398
- }
399
- onAccept?.();
400
- }, [onAccept, handleDismiss]);
401
- const handleDecline = useCallback(() => {
402
- localStorage.setItem(COOKIE_CONSENT_KEY, "denied");
403
- handleDismiss();
404
- onDecline?.();
405
- }, [onDecline, handleDismiss]);
406
- const handleTransitionEnd = useCallback(() => {
407
- if (state === "closing") {
408
- setState("closed");
409
- }
410
- }, [state]);
411
- if (state === "idle" || state === "closed") return null;
412
- return /* @__PURE__ */ jsx(
413
- "div",
414
- {
415
- className: `ds-cookie-consent ${className ?? ""}`,
416
- "data-state": state === "open" ? "open" : "closed",
417
- onTransitionEnd: handleTransitionEnd,
418
- role: "dialog",
419
- "aria-label": labels?.title ?? "Cookie consent",
420
- children: /* @__PURE__ */ jsxs("div", { className: "ds-cookie-consent__inner", children: [
421
- /* @__PURE__ */ jsxs("div", { className: "ds-cookie-consent__content", children: [
422
- /* @__PURE__ */ jsx("h3", { className: "ds-cookie-consent__title", children: labels?.title ?? "We use cookies" }),
423
- /* @__PURE__ */ jsxs("p", { className: "ds-cookie-consent__description", children: [
424
- labels?.description ?? "We use tracking cookies to understand how you use the product and help us improve it.",
425
- /* @__PURE__ */ jsx(OutboundLink, { href: privacyUrl, context: "cookie-consent-privacy", className: "ds-cookie-consent__link", children: labels?.privacyLinkText ?? "Privacy Policy" })
426
- ] })
427
- ] }),
428
- /* @__PURE__ */ jsxs("div", { className: "ds-cookie-consent__actions", children: [
429
- /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleDecline, children: labels?.declineLabel ?? "Decline" }),
430
- /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleAccept, children: labels?.acceptLabel ?? "Accept" })
431
- ] }),
432
- /* @__PURE__ */ jsx(
433
- "button",
434
- {
435
- onClick: handleDecline,
436
- className: "ds-cookie-consent__close",
437
- "aria-label": "Close",
438
- children: /* @__PURE__ */ jsx(X, { size: 16 })
439
- }
440
- )
441
- ] })
442
- }
443
- );
444
- }
445
-
446
- // src/web/analytics/use-cookie-consent.ts
447
- function useCookieConsent() {
448
- const [status, setStatus] = useState(() => {
449
- if (typeof window === "undefined") return null;
450
- const stored = localStorage.getItem(COOKIE_CONSENT_KEY);
451
- if (stored === "granted") return "granted";
452
- if (stored === "denied") return "denied";
453
- return null;
454
- });
455
- useEffect(() => {
456
- const handleConsent = () => setStatus("granted");
457
- window.addEventListener(COOKIE_CONSENT_EVENT, handleConsent);
458
- return () => window.removeEventListener(COOKIE_CONSENT_EVENT, handleConsent);
459
- }, []);
460
- return status;
461
- }
462
- var AnalyticsContext = createContext(null);
463
- function AnalyticsProvider({ onTrack, debug = false, children }) {
464
- const track = useCallback(
465
- (event, props) => {
466
- if (debug && typeof console !== "undefined") {
467
- console.log("[DS Analytics]", event, props);
468
- }
469
- onTrack(event, props);
470
- },
471
- [onTrack, debug]
472
- );
473
- const value = useMemo(() => ({ track }), [track]);
474
- return /* @__PURE__ */ jsx(AnalyticsContext.Provider, { value, children });
475
- }
476
- var NOOP_VALUE = {
477
- track: () => {
478
- }
479
- };
480
- function useAnalytics() {
481
- return useContext(AnalyticsContext) ?? NOOP_VALUE;
482
- }
483
-
484
- export { AnalyticsProvider, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, CookieConsent, createAnalyticsLoader, loadClarity, loadGoogleAnalytics, useAnalytics, useCookieConsent };
2
+ export { AnalyticsProvider, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, CookieConsent, createAnalyticsLoader, loadClarity, loadGoogleAnalytics, useCookieConsent } from '../../chunk-6UNG76Y2.js';
3
+ import '../../chunk-SICKWUWB.js';
4
+ export { useAnalytics } from '../../chunk-2GARWEJK.js';
5
+ import '../../chunk-KJ2OXQF4.js';
485
6
  //# sourceMappingURL=out.js.map
486
7
  //# sourceMappingURL=index.js.map