featuredrop 1.0.1 → 1.1.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/react/context.ts","../src/react/provider.tsx","../src/react/hooks/use-feature-drop.ts","../src/react/hooks/use-new-feature.ts","../src/react/hooks/use-new-count.ts","../src/react/components/new-badge.tsx"],"names":["createContext","useState","useCallback","useMemo","jsx","useContext","isNew","Fragment"],"mappings":"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","file":"react.cjs","sourcesContent":["import type { FeatureEntry, FeatureManifest, StorageAdapter } from \"./types\";\n\n/**\n * Check if a single feature should show as \"new\".\n *\n * A feature is \"new\" when ALL of these are true:\n * 1. Current time is before `showNewUntil`\n * 2. Feature was released after the watermark (or no watermark exists)\n * 3. Feature has not been individually dismissed\n */\nexport function isNew(\n feature: FeatureEntry,\n watermark: string | null,\n dismissedIds: ReadonlySet<string>,\n now: Date = new Date(),\n): boolean {\n // Already dismissed by the user on this device\n if (dismissedIds.has(feature.id)) return false;\n\n const nowMs = now.getTime();\n const showUntilMs = new Date(feature.showNewUntil).getTime();\n\n // Past the display window\n if (nowMs >= showUntilMs) return false;\n\n // If there's a watermark, feature must have been released after it\n if (watermark) {\n const watermarkMs = new Date(watermark).getTime();\n const releasedMs = new Date(feature.releasedAt).getTime();\n if (releasedMs <= watermarkMs) return false;\n }\n\n return true;\n}\n\n/**\n * Get all features that are currently \"new\" for this user.\n */\nexport function getNewFeatures(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter((f) => isNew(f, watermark, dismissedIds, now));\n}\n\n/**\n * Get the count of new features.\n */\nexport function getNewFeatureCount(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n): number {\n return getNewFeatures(manifest, storage, now).length;\n}\n\n/**\n * Check if a specific sidebar key has a new feature.\n */\nexport function hasNewFeature(\n manifest: FeatureManifest,\n sidebarKey: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n): boolean {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.some(\n (f) => f.sidebarKey === sidebarKey && isNew(f, watermark, dismissedIds, now),\n );\n}\n","import { createContext } from \"react\";\nimport type { FeatureEntry } from \"../types\";\n\nexport interface FeatureDropContextValue {\n /** All currently \"new\" features */\n newFeatures: FeatureEntry[];\n /** Count of new features */\n newCount: number;\n /** Check if a sidebar key has any new features */\n isNew: (sidebarKey: string) => boolean;\n /** Dismiss a single feature by ID */\n dismiss: (id: string) => void;\n /** Dismiss all features (marks all as seen) */\n dismissAll: () => Promise<void>;\n /** Get the feature entry for a sidebar key (if it's new) */\n getFeature: (sidebarKey: string) => FeatureEntry | undefined;\n}\n\nexport const FeatureDropContext = createContext<FeatureDropContextValue | null>(\n null,\n);\n","import { useState, useCallback, useMemo, type ReactNode } from \"react\";\nimport type { FeatureManifest, StorageAdapter } from \"../types\";\nimport { getNewFeatures, hasNewFeature } from \"../core\";\nimport { FeatureDropContext } from \"./context\";\n\nexport interface FeatureDropProviderProps {\n /** The feature manifest — typically a frozen array of FeatureEntry objects */\n manifest: FeatureManifest;\n /** Storage adapter instance (e.g. LocalStorageAdapter, MemoryAdapter) */\n storage: StorageAdapter;\n children: ReactNode;\n}\n\n/**\n * Provides feature discovery state to the component tree.\n *\n * Wrap your app (or a subtree) with this provider to enable\n * `useFeatureDrop`, `useNewFeature`, and `useNewCount` hooks.\n */\nexport function FeatureDropProvider({\n manifest,\n storage,\n children,\n}: FeatureDropProviderProps) {\n const [newFeatures, setNewFeatures] = useState(() =>\n getNewFeatures(manifest, storage),\n );\n\n const recompute = useCallback(() => {\n setNewFeatures(getNewFeatures(manifest, storage));\n }, [manifest, storage]);\n\n const dismiss = useCallback(\n (id: string) => {\n storage.dismiss(id);\n recompute();\n },\n [storage, recompute],\n );\n\n const dismissAll = useCallback(async () => {\n await storage.dismissAll(new Date());\n setNewFeatures([]);\n }, [storage]);\n\n const isNewFn = useCallback(\n (sidebarKey: string) => hasNewFeature(manifest, sidebarKey, storage),\n [manifest, storage],\n );\n\n const getFeature = useCallback(\n (sidebarKey: string) =>\n newFeatures.find((f) => f.sidebarKey === sidebarKey),\n [newFeatures],\n );\n\n const value = useMemo(\n () => ({\n newFeatures,\n newCount: newFeatures.length,\n isNew: isNewFn,\n dismiss,\n dismissAll,\n getFeature,\n }),\n [newFeatures, isNewFn, dismiss, dismissAll, getFeature],\n );\n\n return (\n <FeatureDropContext.Provider value={value}>\n {children}\n </FeatureDropContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { FeatureDropContext } from \"../context\";\nimport type { FeatureDropContextValue } from \"../context\";\n\n/**\n * Access the full feature discovery context.\n *\n * Returns: `{ newFeatures, newCount, isNew, dismiss, dismissAll, getFeature }`\n *\n * @throws Error if used outside of `<FeatureDropProvider>`\n */\nexport function useFeatureDrop(): FeatureDropContextValue {\n const context = useContext(FeatureDropContext);\n if (!context) {\n throw new Error(\n \"useFeatureDrop must be used within a <FeatureDropProvider>\",\n );\n }\n return context;\n}\n","import { useFeatureDrop } from \"./use-feature-drop\";\nimport type { FeatureEntry } from \"../../types\";\n\nexport interface UseNewFeatureResult {\n /** Whether this sidebar key has a new feature */\n isNew: boolean;\n /** The feature entry, if new */\n feature: FeatureEntry | undefined;\n /** Dismiss the feature for this sidebar key */\n dismiss: () => void;\n}\n\n/**\n * Check if a single navigation item has a new feature.\n *\n * @param sidebarKey - The key to check (e.g. \"/journal\", \"settings\")\n * @returns `{ isNew, feature, dismiss }`\n */\nexport function useNewFeature(sidebarKey: string): UseNewFeatureResult {\n const { isNew, getFeature, dismiss } = useFeatureDrop();\n\n const feature = getFeature(sidebarKey);\n const isNewValue = isNew(sidebarKey);\n\n return {\n isNew: isNewValue,\n feature,\n dismiss: () => {\n if (feature) {\n dismiss(feature.id);\n }\n },\n };\n}\n","import { useFeatureDrop } from \"./use-feature-drop\";\n\n/**\n * Get the count of currently new features.\n *\n * Useful for rendering a badge count on a \"What's New\" button.\n *\n * @returns The number of new features\n */\nexport function useNewCount(): number {\n const { newCount } = useFeatureDrop();\n return newCount;\n}\n","import type { ReactNode, CSSProperties } from \"react\";\n\nexport interface NewBadgeRenderProps {\n /** Whether the feature is currently new */\n isNew: boolean;\n}\n\nexport interface NewBadgeProps {\n /** Display variant */\n variant?: \"pill\" | \"dot\" | \"count\";\n /** Whether to show the badge (typically from `useNewFeature().isNew`) */\n show?: boolean;\n /** Count to display when variant is \"count\" */\n count?: number;\n /** Text label for the pill variant. Default: \"New\" */\n label?: string;\n /** Dismiss callback. If set with `dismissOnClick`, clicking dismisses. */\n onDismiss?: () => void;\n /** Whether clicking the badge should trigger onDismiss */\n dismissOnClick?: boolean;\n /** Additional CSS class */\n className?: string;\n /** Additional inline styles (merged with defaults) */\n style?: CSSProperties;\n /** Render prop for full customization */\n children?: (props: NewBadgeRenderProps) => ReactNode;\n}\n\nconst baseStyles: CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontFamily: \"inherit\",\n};\n\nconst pillStyles: CSSProperties = {\n ...baseStyles,\n padding: \"2px 6px\",\n borderRadius: \"9999px\",\n fontSize: \"var(--featuredrop-font-size, 10px)\",\n fontWeight: 700,\n textTransform: \"uppercase\" as const,\n letterSpacing: \"0.05em\",\n lineHeight: 1,\n color: \"var(--featuredrop-color, #b45309)\",\n backgroundColor: \"var(--featuredrop-bg, rgba(245, 158, 11, 0.15))\",\n};\n\nconst dotStyles: CSSProperties = {\n ...baseStyles,\n width: \"var(--featuredrop-dot-size, 8px)\",\n height: \"var(--featuredrop-dot-size, 8px)\",\n borderRadius: \"9999px\",\n backgroundColor: \"var(--featuredrop-color, #f59e0b)\",\n boxShadow: \"0 0 6px var(--featuredrop-glow, rgba(245, 158, 11, 0.6))\",\n animation: \"featuredrop-pulse 2s ease-in-out infinite\",\n};\n\nconst countStyles: CSSProperties = {\n ...baseStyles,\n minWidth: \"var(--featuredrop-count-size, 18px)\",\n height: \"var(--featuredrop-count-size, 18px)\",\n padding: \"0 4px\",\n borderRadius: \"9999px\",\n fontSize: \"var(--featuredrop-font-size, 11px)\",\n fontWeight: 700,\n lineHeight: 1,\n color: \"var(--featuredrop-count-color, white)\",\n backgroundColor: \"var(--featuredrop-count-bg, #f59e0b)\",\n};\n\n/**\n * Headless \"New\" badge component.\n *\n * Styled via CSS custom properties — zero CSS framework dependency:\n * - `--featuredrop-color` — text/dot color\n * - `--featuredrop-bg` — pill background\n * - `--featuredrop-font-size` — font size\n * - `--featuredrop-dot-size` — dot diameter\n * - `--featuredrop-glow` — dot glow color\n * - `--featuredrop-count-size` — count badge size\n * - `--featuredrop-count-color` — count text color\n * - `--featuredrop-count-bg` — count background\n *\n * Use `data-featuredrop` attribute for CSS selector styling.\n */\nexport function NewBadge({\n variant = \"pill\",\n show = true,\n count,\n label = \"New\",\n onDismiss,\n dismissOnClick = false,\n className,\n style,\n children,\n}: NewBadgeProps) {\n // Render prop mode\n if (children) {\n return <>{children({ isNew: show })}</>;\n }\n\n if (!show) return null;\n\n const handleClick = dismissOnClick && onDismiss ? onDismiss : undefined;\n\n const variantStyles =\n variant === \"dot\"\n ? dotStyles\n : variant === \"count\"\n ? countStyles\n : pillStyles;\n\n const content =\n variant === \"dot\"\n ? null\n : variant === \"count\"\n ? (count ?? 0)\n : label;\n\n const ariaLabel =\n variant === \"count\"\n ? `${count ?? 0} new features`\n : \"New feature\";\n\n return (\n <span\n data-featuredrop={variant}\n className={className}\n style={{ ...variantStyles, ...style }}\n onClick={handleClick}\n role={dismissOnClick ? \"button\" : undefined}\n tabIndex={dismissOnClick ? 0 : undefined}\n onKeyDown={\n dismissOnClick && onDismiss\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onDismiss();\n }\n }\n : undefined\n }\n aria-label={ariaLabel}\n >\n {content}\n </span>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/core.ts","../src/helpers.ts","../src/react/context.ts","../src/react/provider.tsx","../src/react/hooks/use-feature-drop.ts","../src/react/hooks/use-new-feature.ts","../src/react/hooks/use-new-count.ts","../src/react/hooks/use-tab-notification.ts","../src/react/components/new-badge.tsx","../src/react/components/changelog-widget.tsx","../src/react/components/spotlight.tsx","../src/react/components/banner.tsx","../src/react/components/toast.tsx"],"names":["createContext","useRef","useState","useCallback","useMemo","jsx","useContext","isNew","useEffect","Fragment","jsxs","containerStyles"],"mappings":"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","file":"react.cjs","sourcesContent":["import type { FeatureEntry, FeatureManifest, StorageAdapter } from \"./types\";\n\n/**\n * Check if a single feature should show as \"new\".\n *\n * A feature is \"new\" when ALL of these are true:\n * 1. Current time is before `showNewUntil`\n * 2. Feature was released after the watermark (or no watermark exists)\n * 3. Feature has not been individually dismissed\n * 4. If `publishAt` is set, current time must be after it (scheduled publishing)\n */\nexport function isNew(\n feature: FeatureEntry,\n watermark: string | null,\n dismissedIds: ReadonlySet<string>,\n now: Date = new Date(),\n): boolean {\n // Already dismissed by the user on this device\n if (dismissedIds.has(feature.id)) return false;\n\n const nowMs = now.getTime();\n\n // Scheduled publishing — hidden until publishAt\n if (feature.publishAt) {\n const publishMs = new Date(feature.publishAt).getTime();\n if (nowMs < publishMs) return false;\n }\n\n const showUntilMs = new Date(feature.showNewUntil).getTime();\n\n // Past the display window\n if (nowMs >= showUntilMs) return false;\n\n // If there's a watermark, feature must have been released after it\n if (watermark) {\n const watermarkMs = new Date(watermark).getTime();\n const releasedMs = new Date(feature.releasedAt).getTime();\n if (releasedMs <= watermarkMs) return false;\n }\n\n return true;\n}\n\n/**\n * Get all features that are currently \"new\" for this user.\n */\nexport function getNewFeatures(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter((f) => isNew(f, watermark, dismissedIds, now));\n}\n\n/**\n * Get the count of new features.\n */\nexport function getNewFeatureCount(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n): number {\n return getNewFeatures(manifest, storage, now).length;\n}\n\n/**\n * Check if a specific sidebar key has a new feature.\n */\nexport function hasNewFeature(\n manifest: FeatureManifest,\n sidebarKey: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n): boolean {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.some(\n (f) => f.sidebarKey === sidebarKey && isNew(f, watermark, dismissedIds, now),\n );\n}\n\n/**\n * Get all features sorted by priority (critical first) then by release date (newest first).\n */\nexport function getNewFeaturesSorted(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n): FeatureEntry[] {\n const priorityOrder = { critical: 0, normal: 1, low: 2 };\n return getNewFeatures(manifest, storage, now).sort((a, b) => {\n const pa = priorityOrder[a.priority ?? \"normal\"];\n const pb = priorityOrder[b.priority ?? \"normal\"];\n if (pa !== pb) return pa - pb;\n return new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime();\n });\n}\n","import type { FeatureEntry, FeatureManifest, StorageAdapter } from \"./types\";\nimport { isNew } from \"./core\";\n\n/**\n * Create a frozen feature manifest from an array of entries.\n * Ensures the manifest is immutable at runtime.\n */\nexport function createManifest(\n entries: FeatureEntry[],\n): FeatureManifest {\n return Object.freeze([...entries]);\n}\n\n/**\n * Find a feature by its ID in the manifest.\n * Returns `undefined` if not found.\n */\nexport function getFeatureById(\n manifest: FeatureManifest,\n id: string,\n): FeatureEntry | undefined {\n return manifest.find((f) => f.id === id);\n}\n\n/**\n * Get all new features in a specific category.\n */\nexport function getNewFeaturesByCategory(\n manifest: FeatureManifest,\n category: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter(\n (f) => f.category === category && isNew(f, watermark, dismissedIds, now),\n );\n}\n","import { createContext } from \"react\";\nimport type { FeatureEntry } from \"../types\";\n\nexport interface FeatureDropContextValue {\n /** All currently \"new\" features */\n newFeatures: FeatureEntry[];\n /** Count of new features */\n newCount: number;\n /** All new features sorted by priority then release date */\n newFeaturesSorted: FeatureEntry[];\n /** Check if a sidebar key has any new features */\n isNew: (sidebarKey: string) => boolean;\n /** Dismiss a single feature by ID */\n dismiss: (id: string) => void;\n /** Dismiss all features (marks all as seen) */\n dismissAll: () => Promise<void>;\n /** Get the feature entry for a sidebar key (if it's new) */\n getFeature: (sidebarKey: string) => FeatureEntry | undefined;\n}\n\nexport const FeatureDropContext = createContext<FeatureDropContextValue | null>(\n null,\n);\n","import { useState, useCallback, useMemo, useRef, type ReactNode } from \"react\";\nimport type { FeatureManifest, StorageAdapter, AnalyticsCallbacks } from \"../types\";\nimport { getNewFeatures, hasNewFeature } from \"../core\";\nimport { getFeatureById } from \"../helpers\";\nimport { FeatureDropContext } from \"./context\";\n\nexport interface FeatureDropProviderProps {\n /** The feature manifest — typically a frozen array of FeatureEntry objects */\n manifest: FeatureManifest;\n /** Storage adapter instance (e.g. LocalStorageAdapter, MemoryAdapter) */\n storage: StorageAdapter;\n /** Optional analytics callbacks — pipe to your analytics provider */\n analytics?: AnalyticsCallbacks;\n children: ReactNode;\n}\n\n/**\n * Provides feature discovery state to the component tree.\n *\n * Wrap your app (or a subtree) with this provider to enable\n * `useFeatureDrop`, `useNewFeature`, `useNewCount`, and other hooks.\n */\nexport function FeatureDropProvider({\n manifest,\n storage,\n analytics,\n children,\n}: FeatureDropProviderProps) {\n const analyticsRef = useRef(analytics);\n analyticsRef.current = analytics;\n\n const [newFeatures, setNewFeatures] = useState(() =>\n getNewFeatures(manifest, storage),\n );\n\n const recompute = useCallback(() => {\n setNewFeatures(getNewFeatures(manifest, storage));\n }, [manifest, storage]);\n\n const dismiss = useCallback(\n (id: string) => {\n const feature = getFeatureById(manifest, id);\n storage.dismiss(id);\n if (feature) {\n analyticsRef.current?.onFeatureDismissed?.(feature);\n }\n recompute();\n },\n [manifest, storage, recompute],\n );\n\n const dismissAll = useCallback(async () => {\n await storage.dismissAll(new Date());\n setNewFeatures([]);\n analyticsRef.current?.onAllDismissed?.();\n }, [storage]);\n\n const isNewFn = useCallback(\n (sidebarKey: string) => hasNewFeature(manifest, sidebarKey, storage),\n [manifest, storage],\n );\n\n const getFeature = useCallback(\n (sidebarKey: string) =>\n newFeatures.find((f) => f.sidebarKey === sidebarKey),\n [newFeatures],\n );\n\n const newFeaturesSorted = useMemo(() => {\n const priorityOrder = { critical: 0, normal: 1, low: 2 };\n return [...newFeatures].sort((a, b) => {\n const pa = priorityOrder[a.priority ?? \"normal\"];\n const pb = priorityOrder[b.priority ?? \"normal\"];\n if (pa !== pb) return pa - pb;\n return new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime();\n });\n }, [newFeatures]);\n\n const value = useMemo(\n () => ({\n newFeatures,\n newCount: newFeatures.length,\n newFeaturesSorted,\n isNew: isNewFn,\n dismiss,\n dismissAll,\n getFeature,\n }),\n [newFeatures, newFeaturesSorted, isNewFn, dismiss, dismissAll, getFeature],\n );\n\n return (\n <FeatureDropContext.Provider value={value}>\n {children}\n </FeatureDropContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { FeatureDropContext } from \"../context\";\nimport type { FeatureDropContextValue } from \"../context\";\n\n/**\n * Access the full feature discovery context.\n *\n * Returns: `{ newFeatures, newCount, isNew, dismiss, dismissAll, getFeature }`\n *\n * @throws Error if used outside of `<FeatureDropProvider>`\n */\nexport function useFeatureDrop(): FeatureDropContextValue {\n const context = useContext(FeatureDropContext);\n if (!context) {\n throw new Error(\n \"useFeatureDrop must be used within a <FeatureDropProvider>\",\n );\n }\n return context;\n}\n","import { useFeatureDrop } from \"./use-feature-drop\";\nimport type { FeatureEntry } from \"../../types\";\n\nexport interface UseNewFeatureResult {\n /** Whether this sidebar key has a new feature */\n isNew: boolean;\n /** The feature entry, if new */\n feature: FeatureEntry | undefined;\n /** Dismiss the feature for this sidebar key */\n dismiss: () => void;\n}\n\n/**\n * Check if a single navigation item has a new feature.\n *\n * @param sidebarKey - The key to check (e.g. \"/journal\", \"settings\")\n * @returns `{ isNew, feature, dismiss }`\n */\nexport function useNewFeature(sidebarKey: string): UseNewFeatureResult {\n const { isNew, getFeature, dismiss } = useFeatureDrop();\n\n const feature = getFeature(sidebarKey);\n const isNewValue = isNew(sidebarKey);\n\n return {\n isNew: isNewValue,\n feature,\n dismiss: () => {\n if (feature) {\n dismiss(feature.id);\n }\n },\n };\n}\n","import { useFeatureDrop } from \"./use-feature-drop\";\n\n/**\n * Get the count of currently new features.\n *\n * Useful for rendering a badge count on a \"What's New\" button.\n *\n * @returns The number of new features\n */\nexport function useNewCount(): number {\n const { newCount } = useFeatureDrop();\n return newCount;\n}\n","import { useEffect, useRef } from \"react\";\nimport { useFeatureDrop } from \"./use-feature-drop\";\n\nexport interface UseTabNotificationOptions {\n /** Whether tab notifications are enabled. Default: true */\n enabled?: boolean;\n /** Template string. `{count}` is replaced with the number. Default: \"({count}) {title}\" */\n template?: string;\n /** Enable flashing/blinking pattern for attention. Default: false */\n flash?: boolean;\n /** Flash interval in ms. Default: 1500 */\n flashInterval?: number;\n}\n\n/**\n * Updates the browser tab title with the unread feature count.\n *\n * Shows \"(3) My App\" when there are new features, restores the original\n * title when all features are read. Optional flash/blink pattern for attention.\n *\n * @example\n * ```tsx\n * function App() {\n * useTabNotification();\n * return <div>...</div>;\n * }\n * ```\n *\n * @example With flash\n * ```tsx\n * useTabNotification({ flash: true, template: \"[{count} new] {title}\" });\n * ```\n */\nexport function useTabNotification(options: UseTabNotificationOptions = {}): void {\n const {\n enabled = true,\n template = \"({count}) {title}\",\n flash = false,\n flashInterval = 1500,\n } = options;\n\n const { newCount } = useFeatureDrop();\n const originalTitleRef = useRef<string>(\"\");\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n // Capture original title once\n if (!originalTitleRef.current) {\n originalTitleRef.current = document.title;\n }\n const originalTitle = originalTitleRef.current;\n\n if (!enabled || newCount === 0) {\n // Restore original title\n document.title = originalTitle;\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n return;\n }\n\n const notificationTitle = template\n .replace(\"{count}\", String(newCount))\n .replace(\"{title}\", originalTitle);\n\n if (flash) {\n // Alternate between notification and original title\n let showNotification = true;\n document.title = notificationTitle;\n intervalRef.current = setInterval(() => {\n showNotification = !showNotification;\n document.title = showNotification ? notificationTitle : originalTitle;\n }, flashInterval);\n } else {\n document.title = notificationTitle;\n }\n\n return () => {\n document.title = originalTitle;\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n };\n }, [enabled, newCount, template, flash, flashInterval]);\n}\n","import type { ReactNode, CSSProperties } from \"react\";\n\nexport interface NewBadgeRenderProps {\n /** Whether the feature is currently new */\n isNew: boolean;\n}\n\nexport interface NewBadgeProps {\n /** Display variant */\n variant?: \"pill\" | \"dot\" | \"count\";\n /** Whether to show the badge (typically from `useNewFeature().isNew`) */\n show?: boolean;\n /** Count to display when variant is \"count\" */\n count?: number;\n /** Text label for the pill variant. Default: \"New\" */\n label?: string;\n /** Dismiss callback. If set with `dismissOnClick`, clicking dismisses. */\n onDismiss?: () => void;\n /** Whether clicking the badge should trigger onDismiss */\n dismissOnClick?: boolean;\n /** Additional CSS class */\n className?: string;\n /** Additional inline styles (merged with defaults) */\n style?: CSSProperties;\n /** Render prop for full customization */\n children?: (props: NewBadgeRenderProps) => ReactNode;\n}\n\nconst baseStyles: CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontFamily: \"inherit\",\n};\n\nconst pillStyles: CSSProperties = {\n ...baseStyles,\n padding: \"2px 6px\",\n borderRadius: \"9999px\",\n fontSize: \"var(--featuredrop-font-size, 10px)\",\n fontWeight: 700,\n textTransform: \"uppercase\" as const,\n letterSpacing: \"0.05em\",\n lineHeight: 1,\n color: \"var(--featuredrop-color, #b45309)\",\n backgroundColor: \"var(--featuredrop-bg, rgba(245, 158, 11, 0.15))\",\n};\n\nconst dotStyles: CSSProperties = {\n ...baseStyles,\n width: \"var(--featuredrop-dot-size, 8px)\",\n height: \"var(--featuredrop-dot-size, 8px)\",\n borderRadius: \"9999px\",\n backgroundColor: \"var(--featuredrop-color, #f59e0b)\",\n boxShadow: \"0 0 6px var(--featuredrop-glow, rgba(245, 158, 11, 0.6))\",\n animation: \"featuredrop-pulse 2s ease-in-out infinite\",\n};\n\nconst countStyles: CSSProperties = {\n ...baseStyles,\n minWidth: \"var(--featuredrop-count-size, 18px)\",\n height: \"var(--featuredrop-count-size, 18px)\",\n padding: \"0 4px\",\n borderRadius: \"9999px\",\n fontSize: \"var(--featuredrop-font-size, 11px)\",\n fontWeight: 700,\n lineHeight: 1,\n color: \"var(--featuredrop-count-color, white)\",\n backgroundColor: \"var(--featuredrop-count-bg, #f59e0b)\",\n};\n\n/**\n * Headless \"New\" badge component.\n *\n * Styled via CSS custom properties — zero CSS framework dependency:\n * - `--featuredrop-color` — text/dot color\n * - `--featuredrop-bg` — pill background\n * - `--featuredrop-font-size` — font size\n * - `--featuredrop-dot-size` — dot diameter\n * - `--featuredrop-glow` — dot glow color\n * - `--featuredrop-count-size` — count badge size\n * - `--featuredrop-count-color` — count text color\n * - `--featuredrop-count-bg` — count background\n *\n * Use `data-featuredrop` attribute for CSS selector styling.\n */\nexport function NewBadge({\n variant = \"pill\",\n show = true,\n count,\n label = \"New\",\n onDismiss,\n dismissOnClick = false,\n className,\n style,\n children,\n}: NewBadgeProps) {\n // Render prop mode\n if (children) {\n return <>{children({ isNew: show })}</>;\n }\n\n if (!show) return null;\n\n const handleClick = dismissOnClick && onDismiss ? onDismiss : undefined;\n\n const variantStyles =\n variant === \"dot\"\n ? dotStyles\n : variant === \"count\"\n ? countStyles\n : pillStyles;\n\n const content =\n variant === \"dot\"\n ? null\n : variant === \"count\"\n ? (count ?? 0)\n : label;\n\n const ariaLabel =\n variant === \"count\"\n ? `${count ?? 0} new features`\n : \"New feature\";\n\n return (\n <span\n data-featuredrop={variant}\n className={className}\n style={{ ...variantStyles, ...style }}\n onClick={handleClick}\n role={dismissOnClick ? \"button\" : undefined}\n tabIndex={dismissOnClick ? 0 : undefined}\n onKeyDown={\n dismissOnClick && onDismiss\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onDismiss();\n }\n }\n : undefined\n }\n aria-label={ariaLabel}\n >\n {content}\n </span>\n );\n}\n","import {\n useState,\n useCallback,\n useEffect,\n useRef,\n type ReactNode,\n type CSSProperties,\n} from \"react\";\nimport type { FeatureEntry, AnalyticsCallbacks } from \"../../types\";\nimport { useFeatureDrop } from \"../hooks/use-feature-drop\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface ChangelogEntryRenderProps {\n feature: FeatureEntry;\n dismiss: () => void;\n}\n\nexport interface ChangelogWidgetRenderProps {\n /** Whether the widget is currently open */\n isOpen: boolean;\n /** Open the widget */\n open: () => void;\n /** Close the widget */\n close: () => void;\n /** Toggle open/close */\n toggle: () => void;\n /** Current new feature count */\n count: number;\n /** Sorted features to display */\n features: FeatureEntry[];\n /** Dismiss a single feature */\n dismiss: (id: string) => void;\n /** Dismiss all features */\n dismissAll: () => Promise<void>;\n}\n\nexport interface ChangelogWidgetProps {\n /** Display variant */\n variant?: \"panel\" | \"modal\" | \"popover\";\n /** Title shown in the widget header. Default: \"What's New\" */\n title?: string;\n /** Text for the trigger button. Default: \"What's New\" */\n triggerLabel?: string;\n /** Show trigger badge count. Default: true */\n showCount?: boolean;\n /** Text for the \"mark all as read\" button. Default: \"Mark all as read\" */\n markAllLabel?: string;\n /** Whether to show the mark-all button. Default: true */\n showMarkAll?: boolean;\n /** Text shown when no new features exist. Default: \"You're all caught up!\" */\n emptyLabel?: string;\n /** Max height for the feed area. Default: \"400px\" */\n maxHeight?: string;\n /** Analytics callbacks */\n analytics?: AnalyticsCallbacks;\n /** Additional CSS class for the container */\n className?: string;\n /** Additional inline styles for the container */\n style?: CSSProperties;\n /** Render prop for full customization — receives widget state */\n children?: (props: ChangelogWidgetRenderProps) => ReactNode;\n /** Custom render for each entry — receives feature + dismiss callback */\n renderEntry?: (props: ChangelogEntryRenderProps) => ReactNode;\n /** Custom render for the trigger button */\n renderTrigger?: (props: { count: number; onClick: () => void }) => ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Default Styles (CSS custom properties) */\n/* ------------------------------------------------------------------ */\n\nconst overlayStyles: CSSProperties = {\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"var(--featuredrop-overlay-bg, rgba(0, 0, 0, 0.4))\",\n zIndex: \"var(--featuredrop-z-index, 9998)\" as unknown as number,\n};\n\nconst panelContainerStyles: CSSProperties = {\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n width: \"var(--featuredrop-panel-width, 380px)\",\n maxWidth: \"100vw\",\n backgroundColor: \"var(--featuredrop-widget-bg, #ffffff)\",\n boxShadow: \"var(--featuredrop-widget-shadow, -4px 0 24px rgba(0, 0, 0, 0.12))\",\n zIndex: \"var(--featuredrop-z-index, 9999)\" as unknown as number,\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--featuredrop-font-family, inherit)\",\n};\n\nconst modalContainerStyles: CSSProperties = {\n position: \"fixed\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n width: \"var(--featuredrop-modal-width, 480px)\",\n maxWidth: \"90vw\",\n maxHeight: \"80vh\",\n backgroundColor: \"var(--featuredrop-widget-bg, #ffffff)\",\n borderRadius: \"var(--featuredrop-widget-radius, 12px)\",\n boxShadow: \"var(--featuredrop-widget-shadow, 0 20px 60px rgba(0, 0, 0, 0.15))\",\n zIndex: \"var(--featuredrop-z-index, 9999)\" as unknown as number,\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--featuredrop-font-family, inherit)\",\n};\n\nconst popoverContainerStyles: CSSProperties = {\n position: \"absolute\",\n top: \"100%\",\n right: 0,\n marginTop: \"8px\",\n width: \"var(--featuredrop-popover-width, 340px)\",\n maxWidth: \"90vw\",\n backgroundColor: \"var(--featuredrop-widget-bg, #ffffff)\",\n borderRadius: \"var(--featuredrop-widget-radius, 12px)\",\n boxShadow: \"var(--featuredrop-widget-shadow, 0 8px 30px rgba(0, 0, 0, 0.12))\",\n zIndex: \"var(--featuredrop-z-index, 9999)\" as unknown as number,\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--featuredrop-font-family, inherit)\",\n};\n\nconst headerStyles: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"var(--featuredrop-widget-padding, 16px)\",\n borderBottom: \"1px solid var(--featuredrop-border-color, #e5e7eb)\",\n};\n\nconst titleStyles: CSSProperties = {\n margin: 0,\n fontSize: \"var(--featuredrop-title-size, 16px)\",\n fontWeight: 600,\n color: \"var(--featuredrop-title-color, #111827)\",\n};\n\nconst closeButtonStyles: CSSProperties = {\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n fontSize: \"18px\",\n color: \"var(--featuredrop-close-color, #6b7280)\",\n lineHeight: 1,\n};\n\nconst feedStyles: CSSProperties = {\n flex: 1,\n overflowY: \"auto\",\n padding: \"var(--featuredrop-widget-padding, 16px)\",\n};\n\nconst entryStyles: CSSProperties = {\n padding: \"12px 0\",\n borderBottom: \"1px solid var(--featuredrop-border-color, #e5e7eb)\",\n};\n\nconst entryTitleStyles: CSSProperties = {\n fontSize: \"var(--featuredrop-entry-title-size, 14px)\",\n fontWeight: 600,\n color: \"var(--featuredrop-entry-title-color, #111827)\",\n margin: \"0 0 4px\",\n};\n\nconst entryDescriptionStyles: CSSProperties = {\n fontSize: \"var(--featuredrop-entry-desc-size, 13px)\",\n color: \"var(--featuredrop-entry-desc-color, #6b7280)\",\n margin: \"0 0 6px\",\n lineHeight: 1.5,\n};\n\nconst entryMetaStyles: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n fontSize: \"12px\",\n color: \"var(--featuredrop-entry-meta-color, #9ca3af)\",\n};\n\nconst typeTagStyles: CSSProperties = {\n display: \"inline-block\",\n padding: \"1px 6px\",\n borderRadius: \"4px\",\n fontSize: \"11px\",\n fontWeight: 600,\n textTransform: \"uppercase\" as const,\n};\n\nconst ctaButtonStyles: CSSProperties = {\n display: \"inline-block\",\n marginTop: \"8px\",\n padding: \"6px 12px\",\n borderRadius: \"var(--featuredrop-cta-radius, 6px)\",\n fontSize: \"13px\",\n fontWeight: 600,\n color: \"var(--featuredrop-cta-color, #ffffff)\",\n backgroundColor: \"var(--featuredrop-cta-bg, #3b82f6)\",\n textDecoration: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n};\n\nconst footerStyles: CSSProperties = {\n padding: \"var(--featuredrop-widget-padding, 16px)\",\n borderTop: \"1px solid var(--featuredrop-border-color, #e5e7eb)\",\n textAlign: \"center\",\n};\n\nconst markAllButtonStyles: CSSProperties = {\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: \"13px\",\n fontWeight: 600,\n color: \"var(--featuredrop-mark-all-color, #3b82f6)\",\n padding: \"4px 8px\",\n};\n\nconst triggerButtonStyles: CSSProperties = {\n position: \"relative\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 14px\",\n border: \"1px solid var(--featuredrop-trigger-border, #d1d5db)\",\n borderRadius: \"var(--featuredrop-trigger-radius, 8px)\",\n backgroundColor: \"var(--featuredrop-trigger-bg, #ffffff)\",\n color: \"var(--featuredrop-trigger-color, #374151)\",\n fontSize: \"14px\",\n fontWeight: 500,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n};\n\nconst triggerBadgeStyles: CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minWidth: \"18px\",\n height: \"18px\",\n padding: \"0 4px\",\n borderRadius: \"9999px\",\n fontSize: \"11px\",\n fontWeight: 700,\n color: \"var(--featuredrop-badge-color, white)\",\n backgroundColor: \"var(--featuredrop-badge-bg, #f59e0b)\",\n};\n\nconst emptyStyles: CSSProperties = {\n padding: \"32px 16px\",\n textAlign: \"center\",\n fontSize: \"14px\",\n color: \"var(--featuredrop-empty-color, #9ca3af)\",\n};\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nconst TYPE_COLORS: Record<string, { color: string; bg: string }> = {\n feature: { color: \"#065f46\", bg: \"rgba(16, 185, 129, 0.15)\" },\n improvement: { color: \"#1e40af\", bg: \"rgba(59, 130, 246, 0.15)\" },\n fix: { color: \"#92400e\", bg: \"rgba(245, 158, 11, 0.15)\" },\n breaking: { color: \"#991b1b\", bg: \"rgba(239, 68, 68, 0.15)\" },\n};\n\nfunction formatDate(iso: string): string {\n const d = new Date(iso);\n return d.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Default Entry Renderer */\n/* ------------------------------------------------------------------ */\n\nfunction DefaultEntry({ feature, dismiss }: ChangelogEntryRenderProps) {\n const typeStyle = feature.type\n ? TYPE_COLORS[feature.type] ?? TYPE_COLORS.feature\n : null;\n\n return (\n <div data-featuredrop-entry={feature.id} style={entryStyles}>\n <div style={{ display: \"flex\", alignItems: \"flex-start\", justifyContent: \"space-between\" }}>\n <p style={entryTitleStyles}>{feature.label}</p>\n <button\n onClick={dismiss}\n style={{ ...closeButtonStyles, fontSize: \"14px\", flexShrink: 0 }}\n aria-label={`Dismiss ${feature.label}`}\n >\n &times;\n </button>\n </div>\n {feature.description && (\n <p style={entryDescriptionStyles}>{feature.description}</p>\n )}\n {feature.image && (\n <img\n src={feature.image}\n alt={feature.label}\n style={{\n width: \"100%\",\n borderRadius: \"8px\",\n marginBottom: \"8px\",\n }}\n />\n )}\n <div style={entryMetaStyles}>\n {feature.type && typeStyle && (\n <span\n style={{\n ...typeTagStyles,\n color: typeStyle.color,\n backgroundColor: typeStyle.bg,\n }}\n >\n {feature.type}\n </span>\n )}\n {feature.category && (\n <span>{feature.category}</span>\n )}\n <span>{formatDate(feature.releasedAt)}</span>\n {feature.version && <span>v{feature.version}</span>}\n </div>\n {feature.cta && (\n <a\n href={feature.cta.url}\n style={ctaButtonStyles}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {feature.cta.label}\n </a>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ChangelogWidget Component */\n/* ------------------------------------------------------------------ */\n\n/**\n * Changelog widget — the #1 feature for feature discovery tools.\n *\n * Renders a trigger button with an unread count badge and a\n * slide-out panel, modal, or popover with the changelog feed.\n *\n * Styled via CSS custom properties — zero framework dependency.\n * Use `children` render prop for full headless control.\n *\n * @example\n * ```tsx\n * <ChangelogWidget variant=\"panel\" />\n * ```\n *\n * @example Headless mode\n * ```tsx\n * <ChangelogWidget>\n * {({ isOpen, toggle, features, count }) => (\n * <MyCustomUI ... />\n * )}\n * </ChangelogWidget>\n * ```\n */\nexport function ChangelogWidget({\n variant = \"panel\",\n title = \"What's New\",\n triggerLabel = \"What's New\",\n showCount = true,\n markAllLabel = \"Mark all as read\",\n showMarkAll = true,\n emptyLabel = \"You're all caught up!\",\n maxHeight = \"400px\",\n analytics,\n className,\n style,\n children,\n renderEntry,\n renderTrigger,\n}: ChangelogWidgetProps) {\n const { newFeaturesSorted, newCount, dismiss, dismissAll } = useFeatureDrop();\n const [isOpen, setIsOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const open = useCallback(() => {\n setIsOpen(true);\n analytics?.onWidgetOpened?.();\n }, [analytics]);\n\n const close = useCallback(() => {\n setIsOpen(false);\n analytics?.onWidgetClosed?.();\n }, [analytics]);\n\n const toggle = useCallback(() => {\n if (isOpen) {\n close();\n } else {\n open();\n }\n }, [isOpen, open, close]);\n\n const handleDismiss = useCallback(\n (id: string) => {\n const feature = newFeaturesSorted.find((f) => f.id === id);\n dismiss(id);\n if (feature) {\n analytics?.onFeatureDismissed?.(feature);\n }\n },\n [dismiss, newFeaturesSorted, analytics],\n );\n\n const handleDismissAll = useCallback(async () => {\n await dismissAll();\n analytics?.onAllDismissed?.();\n }, [dismissAll, analytics]);\n\n // Close on click outside (panel/modal)\n useEffect(() => {\n if (!isOpen || variant === \"popover\") return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") close();\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, variant, close]);\n\n // Close popover on outside click\n useEffect(() => {\n if (!isOpen || variant !== \"popover\") return;\n const handleClick = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n close();\n }\n };\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") close();\n };\n document.addEventListener(\"mousedown\", handleClick);\n document.addEventListener(\"keydown\", handleEsc);\n return () => {\n document.removeEventListener(\"mousedown\", handleClick);\n document.removeEventListener(\"keydown\", handleEsc);\n };\n }, [isOpen, variant, close]);\n\n // Headless render prop mode\n if (children) {\n return (\n <>\n {children({\n isOpen,\n open,\n close,\n toggle,\n count: newCount,\n features: newFeaturesSorted,\n dismiss: handleDismiss,\n dismissAll: handleDismissAll,\n })}\n </>\n );\n }\n\n const containerStyles =\n variant === \"modal\"\n ? modalContainerStyles\n : variant === \"popover\"\n ? popoverContainerStyles\n : panelContainerStyles;\n\n return (\n <div\n ref={containerRef}\n data-featuredrop-widget\n className={className}\n style={{ position: \"relative\", display: \"inline-block\", ...style }}\n >\n {/* Trigger */}\n {renderTrigger ? (\n renderTrigger({ count: newCount, onClick: toggle })\n ) : (\n <button\n onClick={toggle}\n style={triggerButtonStyles}\n data-featuredrop-trigger\n aria-label={`${triggerLabel}${newCount > 0 ? ` — ${newCount} new` : \"\"}`}\n >\n {triggerLabel}\n {showCount && newCount > 0 && (\n <span style={triggerBadgeStyles} data-featuredrop-trigger-badge>\n {newCount}\n </span>\n )}\n </button>\n )}\n\n {/* Widget body */}\n {isOpen && (\n <>\n {/* Overlay for panel/modal */}\n {variant !== \"popover\" && (\n <div\n style={overlayStyles}\n onClick={close}\n data-featuredrop-overlay\n aria-hidden=\"true\"\n />\n )}\n\n <div\n style={containerStyles}\n data-featuredrop-container={variant}\n role=\"dialog\"\n aria-label={title}\n >\n {/* Header */}\n <div style={headerStyles} data-featuredrop-header>\n <h2 style={titleStyles}>{title}</h2>\n <button\n onClick={close}\n style={closeButtonStyles}\n aria-label=\"Close\"\n >\n &times;\n </button>\n </div>\n\n {/* Feed */}\n <div style={{ ...feedStyles, maxHeight }} data-featuredrop-feed>\n {newFeaturesSorted.length === 0 ? (\n <div style={emptyStyles} data-featuredrop-empty>\n {emptyLabel}\n </div>\n ) : (\n newFeaturesSorted.map((feature) =>\n renderEntry ? (\n <div key={feature.id}>\n {renderEntry({\n feature,\n dismiss: () => handleDismiss(feature.id),\n })}\n </div>\n ) : (\n <DefaultEntry\n key={feature.id}\n feature={feature}\n dismiss={() => handleDismiss(feature.id)}\n />\n ),\n )\n )}\n </div>\n\n {/* Footer */}\n {showMarkAll && newFeaturesSorted.length > 0 && (\n <div style={footerStyles} data-featuredrop-footer>\n <button\n onClick={handleDismissAll}\n style={markAllButtonStyles}\n data-featuredrop-mark-all\n >\n {markAllLabel}\n </button>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n );\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useRef,\n type ReactNode,\n type CSSProperties,\n type RefObject,\n} from \"react\";\nimport type { FeatureEntry, AnalyticsCallbacks } from \"../../types\";\nimport { useFeatureDrop } from \"../hooks/use-feature-drop\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface SpotlightRenderProps {\n /** The feature being spotlighted */\n feature: FeatureEntry | undefined;\n /** Whether the spotlight is active */\n isActive: boolean;\n /** Whether the tooltip is visible */\n isTooltipOpen: boolean;\n /** Show the tooltip */\n openTooltip: () => void;\n /** Hide the tooltip */\n closeTooltip: () => void;\n /** Dismiss this spotlight permanently */\n dismiss: () => void;\n}\n\nexport interface SpotlightProps {\n /** The feature ID to spotlight */\n featureId: string;\n /** Ref to the target DOM element — beacon will be positioned over it */\n targetRef?: RefObject<HTMLElement | null>;\n /** CSS selector for the target element (alternative to targetRef) */\n targetSelector?: string;\n /** Tooltip placement relative to target */\n placement?: \"top\" | \"bottom\" | \"left\" | \"right\";\n /** Beacon size in pixels. Default: 12 */\n beaconSize?: number;\n /** Auto-dismiss after the tooltip is seen */\n autoDismiss?: boolean;\n /** Delay before auto-dismiss in ms. Default: 5000 */\n autoDismissDelay?: number;\n /** Analytics callbacks */\n analytics?: AnalyticsCallbacks;\n /** Additional CSS class */\n className?: string;\n /** Custom tooltip content */\n tooltipContent?: ReactNode;\n /** Render prop for full customization */\n children?: (props: SpotlightRenderProps) => ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Styles */\n/* ------------------------------------------------------------------ */\n\nconst beaconStyles: CSSProperties = {\n position: \"absolute\",\n borderRadius: \"50%\",\n backgroundColor: \"var(--featuredrop-beacon-color, #f59e0b)\",\n cursor: \"pointer\",\n zIndex: \"var(--featuredrop-z-index, 9999)\" as unknown as number,\n};\n\nconst beaconPulseStyles: CSSProperties = {\n position: \"absolute\",\n inset: \"-4px\",\n borderRadius: \"50%\",\n border: \"2px solid var(--featuredrop-beacon-color, #f59e0b)\",\n opacity: 0.6,\n animation: \"featuredrop-spotlight-pulse 2s ease-in-out infinite\",\n};\n\nconst tooltipStyles: CSSProperties = {\n position: \"absolute\",\n padding: \"var(--featuredrop-tooltip-padding, 12px 16px)\",\n backgroundColor: \"var(--featuredrop-tooltip-bg, #ffffff)\",\n borderRadius: \"var(--featuredrop-tooltip-radius, 8px)\",\n boxShadow: \"var(--featuredrop-tooltip-shadow, 0 4px 20px rgba(0, 0, 0, 0.12))\",\n maxWidth: \"var(--featuredrop-tooltip-max-width, 260px)\",\n zIndex: \"var(--featuredrop-z-index, 10000)\" as unknown as number,\n fontFamily: \"var(--featuredrop-font-family, inherit)\",\n};\n\nconst tooltipTitleStyles: CSSProperties = {\n margin: \"0 0 4px\",\n fontSize: \"var(--featuredrop-tooltip-title-size, 14px)\",\n fontWeight: 600,\n color: \"var(--featuredrop-tooltip-title-color, #111827)\",\n};\n\nconst tooltipDescStyles: CSSProperties = {\n margin: 0,\n fontSize: \"var(--featuredrop-tooltip-desc-size, 13px)\",\n color: \"var(--featuredrop-tooltip-desc-color, #6b7280)\",\n lineHeight: 1.5,\n};\n\nconst tooltipDismissStyles: CSSProperties = {\n display: \"inline-block\",\n marginTop: \"8px\",\n padding: \"4px 10px\",\n border: \"none\",\n borderRadius: \"4px\",\n fontSize: \"12px\",\n fontWeight: 600,\n cursor: \"pointer\",\n backgroundColor: \"var(--featuredrop-tooltip-dismiss-bg, #f3f4f6)\",\n color: \"var(--featuredrop-tooltip-dismiss-color, #374151)\",\n};\n\n/* ------------------------------------------------------------------ */\n/* CSS keyframes injection */\n/* ------------------------------------------------------------------ */\n\nlet injectedKeyframes = false;\nfunction injectKeyframes() {\n if (injectedKeyframes || typeof document === \"undefined\") return;\n injectedKeyframes = true;\n const style = document.createElement(\"style\");\n style.textContent = `\n @keyframes featuredrop-spotlight-pulse {\n 0%, 100% { transform: scale(1); opacity: 0.6; }\n 50% { transform: scale(1.6); opacity: 0; }\n }\n @keyframes featuredrop-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n `;\n document.head.appendChild(style);\n}\n\n/* ------------------------------------------------------------------ */\n/* Spotlight Component */\n/* ------------------------------------------------------------------ */\n\n/**\n * Pulsing beacon that attaches to any DOM element to highlight a new feature.\n *\n * Clicking the beacon reveals a tooltip with feature info.\n * After dismissal, the beacon disappears permanently for this user.\n *\n * @example\n * ```tsx\n * const ref = useRef<HTMLButtonElement>(null);\n * <button ref={ref}>Analytics</button>\n * <Spotlight featureId=\"analytics-v2\" targetRef={ref} />\n * ```\n *\n * @example With CSS selector\n * ```tsx\n * <Spotlight featureId=\"analytics-v2\" targetSelector=\"#analytics-btn\" />\n * ```\n */\nexport function Spotlight({\n featureId,\n targetRef,\n targetSelector,\n placement = \"top\",\n beaconSize = 12,\n autoDismiss = false,\n autoDismissDelay = 5000,\n analytics,\n className,\n tooltipContent,\n children,\n}: SpotlightProps) {\n const { newFeatures, dismiss } = useFeatureDrop();\n const feature = newFeatures.find((f) => f.id === featureId);\n const [isTooltipOpen, setTooltipOpen] = useState(false);\n const [targetRect, setTargetRect] = useState<DOMRect | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const isActive = !!feature;\n\n useEffect(() => {\n injectKeyframes();\n }, []);\n\n // Track target position\n useEffect(() => {\n if (!isActive) return;\n\n const getTarget = (): HTMLElement | null => {\n if (targetRef?.current) return targetRef.current;\n if (targetSelector) return document.querySelector(targetSelector);\n return null;\n };\n\n const update = () => {\n const el = getTarget();\n if (el) setTargetRect(el.getBoundingClientRect());\n };\n\n update();\n window.addEventListener(\"resize\", update);\n window.addEventListener(\"scroll\", update, true);\n return () => {\n window.removeEventListener(\"resize\", update);\n window.removeEventListener(\"scroll\", update, true);\n };\n }, [isActive, targetRef, targetSelector]);\n\n const openTooltip = useCallback(() => {\n setTooltipOpen(true);\n if (feature) analytics?.onFeatureSeen?.(feature);\n if (autoDismiss) {\n timerRef.current = setTimeout(() => {\n dismiss(featureId);\n if (feature) analytics?.onFeatureDismissed?.(feature);\n }, autoDismissDelay);\n }\n }, [feature, featureId, autoDismiss, autoDismissDelay, dismiss, analytics]);\n\n const closeTooltip = useCallback(() => {\n setTooltipOpen(false);\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const handleDismiss = useCallback(() => {\n dismiss(featureId);\n setTooltipOpen(false);\n if (feature) analytics?.onFeatureDismissed?.(feature);\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, [featureId, dismiss, feature, analytics]);\n\n useEffect(() => {\n return () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n };\n }, []);\n\n // Render prop mode\n if (children) {\n return (\n <>\n {children({\n feature,\n isActive,\n isTooltipOpen,\n openTooltip,\n closeTooltip,\n dismiss: handleDismiss,\n })}\n </>\n );\n }\n\n if (!isActive || !targetRect) return null;\n\n // Compute beacon position\n const beaconLeft = targetRect.right - beaconSize / 2;\n const beaconTop = targetRect.top - beaconSize / 2;\n\n // Tooltip offset from beacon\n const tooltipOffset = 12;\n const tooltipPosition: CSSProperties = (() => {\n switch (placement) {\n case \"bottom\":\n return { top: targetRect.bottom + tooltipOffset, left: targetRect.left };\n case \"left\":\n return { top: targetRect.top, right: `calc(100vw - ${targetRect.left - tooltipOffset}px)` };\n case \"right\":\n return { top: targetRect.top, left: targetRect.right + tooltipOffset };\n case \"top\":\n default:\n return { bottom: `calc(100vh - ${targetRect.top - tooltipOffset}px)`, left: targetRect.left };\n }\n })();\n\n return (\n <>\n {/* Beacon */}\n <div\n data-featuredrop-spotlight={featureId}\n className={className}\n style={{\n ...beaconStyles,\n position: \"fixed\",\n left: beaconLeft,\n top: beaconTop,\n width: beaconSize,\n height: beaconSize,\n }}\n onClick={isTooltipOpen ? closeTooltip : openTooltip}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n isTooltipOpen ? closeTooltip() : openTooltip();\n }\n }}\n aria-label={`New: ${feature.label}`}\n >\n <span style={beaconPulseStyles} />\n </div>\n\n {/* Tooltip */}\n {isTooltipOpen && (\n <div\n style={{ ...tooltipStyles, position: \"fixed\", ...tooltipPosition }}\n data-featuredrop-tooltip\n >\n {tooltipContent ?? (\n <>\n <p style={tooltipTitleStyles}>{feature.label}</p>\n {feature.description && (\n <p style={tooltipDescStyles}>{feature.description}</p>\n )}\n <button\n onClick={handleDismiss}\n style={tooltipDismissStyles}\n >\n Got it\n </button>\n </>\n )}\n </div>\n )}\n </>\n );\n}\n","import { useState, useCallback, type ReactNode, type CSSProperties } from \"react\";\nimport type { FeatureEntry, AnalyticsCallbacks } from \"../../types\";\nimport { useFeatureDrop } from \"../hooks/use-feature-drop\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport type BannerVariant = \"info\" | \"success\" | \"warning\" | \"announcement\";\n\nexport interface BannerRenderProps {\n /** The feature being announced */\n feature: FeatureEntry | undefined;\n /** Whether the banner is active */\n isActive: boolean;\n /** Whether the banner has been dismissed this session */\n isDismissed: boolean;\n /** Dismiss the banner permanently */\n dismiss: () => void;\n}\n\nexport interface BannerProps {\n /** Feature ID to display as a banner */\n featureId: string;\n /** Banner visual variant. Default: \"announcement\" */\n variant?: BannerVariant;\n /** Whether the banner is dismissible. Default: true */\n dismissible?: boolean;\n /** Position mode. Default: \"sticky\" */\n position?: \"sticky\" | \"inline\" | \"fixed\";\n /** Analytics callbacks */\n analytics?: AnalyticsCallbacks;\n /** Additional CSS class */\n className?: string;\n /** Additional inline styles */\n style?: CSSProperties;\n /** Render prop for full customization */\n children?: (props: BannerRenderProps) => ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Styles */\n/* ------------------------------------------------------------------ */\n\nconst VARIANT_STYLES: Record<BannerVariant, { bg: string; border: string; color: string; icon: string }> = {\n info: {\n bg: \"var(--featuredrop-banner-info-bg, #eff6ff)\",\n border: \"var(--featuredrop-banner-info-border, #bfdbfe)\",\n color: \"var(--featuredrop-banner-info-color, #1e40af)\",\n icon: \"\\u2139\\uFE0F\",\n },\n success: {\n bg: \"var(--featuredrop-banner-success-bg, #f0fdf4)\",\n border: \"var(--featuredrop-banner-success-border, #bbf7d0)\",\n color: \"var(--featuredrop-banner-success-color, #166534)\",\n icon: \"\\u2705\",\n },\n warning: {\n bg: \"var(--featuredrop-banner-warning-bg, #fffbeb)\",\n border: \"var(--featuredrop-banner-warning-border, #fde68a)\",\n color: \"var(--featuredrop-banner-warning-color, #92400e)\",\n icon: \"\\u26A0\\uFE0F\",\n },\n announcement: {\n bg: \"var(--featuredrop-banner-announce-bg, #faf5ff)\",\n border: \"var(--featuredrop-banner-announce-border, #e9d5ff)\",\n color: \"var(--featuredrop-banner-announce-color, #6b21a8)\",\n icon: \"\\uD83C\\uDF89\",\n },\n};\n\nconst baseBannerStyles: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: \"12px\",\n padding: \"var(--featuredrop-banner-padding, 10px 16px)\",\n fontFamily: \"var(--featuredrop-font-family, inherit)\",\n fontSize: \"var(--featuredrop-banner-font-size, 14px)\",\n lineHeight: 1.5,\n borderBottom: \"1px solid\",\n};\n\nconst bannerTextStyles: CSSProperties = {\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: \"8px\",\n};\n\nconst bannerLabelStyles: CSSProperties = {\n fontWeight: 600,\n};\n\nconst bannerDescStyles: CSSProperties = {\n fontWeight: 400,\n opacity: 0.9,\n};\n\nconst bannerCtaStyles: CSSProperties = {\n display: \"inline-block\",\n padding: \"4px 12px\",\n borderRadius: \"var(--featuredrop-banner-cta-radius, 6px)\",\n fontSize: \"13px\",\n fontWeight: 600,\n textDecoration: \"none\",\n border: \"1px solid currentColor\",\n opacity: 0.9,\n cursor: \"pointer\",\n backgroundColor: \"transparent\",\n color: \"inherit\",\n};\n\nconst bannerCloseStyles: CSSProperties = {\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n fontSize: \"16px\",\n opacity: 0.6,\n color: \"inherit\",\n lineHeight: 1,\n};\n\n/* ------------------------------------------------------------------ */\n/* Banner Component */\n/* ------------------------------------------------------------------ */\n\n/**\n * Announcement banner for major feature launches or important notices.\n *\n * Shows at the top of the page (sticky/fixed) or inline in content.\n * Auto-expires using the same `showNewUntil` logic as badges.\n * Styled via CSS custom properties for each variant.\n *\n * @example\n * ```tsx\n * <Banner featureId=\"v2-launch\" variant=\"announcement\" />\n * ```\n *\n * @example Headless\n * ```tsx\n * <Banner featureId=\"v2-launch\">\n * {({ feature, dismiss }) => (\n * <div>New: {feature?.label} <button onClick={dismiss}>x</button></div>\n * )}\n * </Banner>\n * ```\n */\nexport function Banner({\n featureId,\n variant = \"announcement\",\n dismissible = true,\n position = \"sticky\",\n analytics,\n className,\n style,\n children,\n}: BannerProps) {\n const { newFeatures, dismiss } = useFeatureDrop();\n const feature = newFeatures.find((f) => f.id === featureId);\n const [sessionDismissed, setSessionDismissed] = useState(false);\n\n const isActive = !!feature && !sessionDismissed;\n\n const handleDismiss = useCallback(() => {\n dismiss(featureId);\n setSessionDismissed(true);\n if (feature) analytics?.onFeatureDismissed?.(feature);\n }, [featureId, dismiss, feature, analytics]);\n\n const handleCtaClick = useCallback(() => {\n if (feature) analytics?.onFeatureClicked?.(feature);\n }, [feature, analytics]);\n\n // Headless render prop\n if (children) {\n return (\n <>\n {children({\n feature,\n isActive,\n isDismissed: sessionDismissed,\n dismiss: handleDismiss,\n })}\n </>\n );\n }\n\n if (!isActive) return null;\n\n const variantStyle = VARIANT_STYLES[variant];\n const positionStyles: CSSProperties =\n position === \"fixed\"\n ? { position: \"fixed\", top: 0, left: 0, right: 0, zIndex: \"var(--featuredrop-z-index, 9999)\" as unknown as number }\n : position === \"sticky\"\n ? { position: \"sticky\", top: 0, zIndex: \"var(--featuredrop-z-index, 9999)\" as unknown as number }\n : {};\n\n return (\n <div\n data-featuredrop-banner={variant}\n className={className}\n role=\"alert\"\n style={{\n ...baseBannerStyles,\n ...positionStyles,\n backgroundColor: variantStyle.bg,\n borderColor: variantStyle.border,\n color: variantStyle.color,\n ...style,\n }}\n >\n <div style={bannerTextStyles}>\n <span aria-hidden=\"true\">{variantStyle.icon}</span>\n <span style={bannerLabelStyles}>{feature.label}</span>\n {feature.description && (\n <span style={bannerDescStyles}>— {feature.description}</span>\n )}\n {feature.cta && (\n <a\n href={feature.cta.url}\n style={bannerCtaStyles}\n onClick={handleCtaClick}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {feature.cta.label}\n </a>\n )}\n </div>\n {dismissible && (\n <button\n onClick={handleDismiss}\n style={bannerCloseStyles}\n aria-label=\"Dismiss banner\"\n >\n &times;\n </button>\n )}\n </div>\n );\n}\n","import {\n useState,\n useEffect,\n useCallback,\n useRef,\n type ReactNode,\n type CSSProperties,\n} from \"react\";\nimport type { FeatureEntry, AnalyticsCallbacks } from \"../../types\";\nimport { useFeatureDrop } from \"../hooks/use-feature-drop\";\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface ToastRenderProps {\n /** Features currently showing as toasts */\n toasts: FeatureEntry[];\n /** Dismiss a specific toast */\n dismiss: (id: string) => void;\n /** Dismiss all toasts */\n dismissAll: () => void;\n}\n\nexport interface ToastProps {\n /** Feature IDs to show as toasts. If omitted, shows all new features. */\n featureIds?: string[];\n /** Max number of visible toasts at once. Default: 3 */\n maxVisible?: number;\n /** Auto-dismiss delay in ms. Default: 8000. Set to 0 to disable. */\n autoDismissMs?: number;\n /** Position on screen. Default: \"bottom-right\" */\n position?: \"top-right\" | \"top-left\" | \"bottom-right\" | \"bottom-left\" | \"top-center\" | \"bottom-center\";\n /** Analytics callbacks */\n analytics?: AnalyticsCallbacks;\n /** Additional CSS class for the container */\n className?: string;\n /** Additional inline styles for the container */\n style?: CSSProperties;\n /** Render prop for full customization */\n children?: (props: ToastRenderProps) => ReactNode;\n /** Custom render for each toast */\n renderToast?: (props: { feature: FeatureEntry; dismiss: () => void }) => ReactNode;\n}\n\n/* ------------------------------------------------------------------ */\n/* Styles */\n/* ------------------------------------------------------------------ */\n\nconst POSITION_STYLES: Record<string, CSSProperties> = {\n \"top-right\": { top: 16, right: 16 },\n \"top-left\": { top: 16, left: 16 },\n \"bottom-right\": { bottom: 16, right: 16 },\n \"bottom-left\": { bottom: 16, left: 16 },\n \"top-center\": { top: 16, left: \"50%\", transform: \"translateX(-50%)\" },\n \"bottom-center\": { bottom: 16, left: \"50%\", transform: \"translateX(-50%)\" },\n};\n\nconst containerStyles: CSSProperties = {\n position: \"fixed\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n zIndex: \"var(--featuredrop-toast-z-index, 10000)\" as unknown as number,\n pointerEvents: \"none\",\n};\n\nconst toastStyles: CSSProperties = {\n pointerEvents: \"auto\",\n display: \"flex\",\n alignItems: \"flex-start\",\n gap: \"12px\",\n padding: \"var(--featuredrop-toast-padding, 12px 16px)\",\n backgroundColor: \"var(--featuredrop-toast-bg, #ffffff)\",\n borderRadius: \"var(--featuredrop-toast-radius, 10px)\",\n boxShadow: \"var(--featuredrop-toast-shadow, 0 4px 20px rgba(0, 0, 0, 0.12))\",\n border: \"1px solid var(--featuredrop-toast-border, #e5e7eb)\",\n width: \"var(--featuredrop-toast-width, 340px)\",\n maxWidth: \"calc(100vw - 32px)\",\n fontFamily: \"var(--featuredrop-font-family, inherit)\",\n animation: \"featuredrop-toast-enter 0.3s ease-out\",\n};\n\nconst toastBodyStyles: CSSProperties = {\n flex: 1,\n minWidth: 0,\n};\n\nconst toastTitleStyles: CSSProperties = {\n margin: \"0 0 2px\",\n fontSize: \"var(--featuredrop-toast-title-size, 14px)\",\n fontWeight: 600,\n color: \"var(--featuredrop-toast-title-color, #111827)\",\n};\n\nconst toastDescStyles: CSSProperties = {\n margin: 0,\n fontSize: \"var(--featuredrop-toast-desc-size, 13px)\",\n color: \"var(--featuredrop-toast-desc-color, #6b7280)\",\n lineHeight: 1.4,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n display: \"-webkit-box\",\n WebkitLineClamp: 2,\n WebkitBoxOrient: \"vertical\" as const,\n};\n\nconst toastCloseStyles: CSSProperties = {\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"2px\",\n fontSize: \"16px\",\n color: \"var(--featuredrop-toast-close-color, #9ca3af)\",\n lineHeight: 1,\n flexShrink: 0,\n};\n\nconst toastCtaStyles: CSSProperties = {\n display: \"inline-block\",\n marginTop: \"6px\",\n fontSize: \"13px\",\n fontWeight: 600,\n color: \"var(--featuredrop-toast-cta-color, #3b82f6)\",\n textDecoration: \"none\",\n};\n\nconst TYPE_INDICATORS: Record<string, { color: string; icon: string }> = {\n feature: { color: \"#10b981\", icon: \"\\u2728\" },\n improvement: { color: \"#3b82f6\", icon: \"\\uD83D\\uDCC8\" },\n fix: { color: \"#f59e0b\", icon: \"\\uD83D\\uDD27\" },\n breaking: { color: \"#ef4444\", icon: \"\\u26A0\\uFE0F\" },\n};\n\n/* ------------------------------------------------------------------ */\n/* Keyframes */\n/* ------------------------------------------------------------------ */\n\nlet injectedToastKeyframes = false;\nfunction injectToastKeyframes() {\n if (injectedToastKeyframes || typeof document === \"undefined\") return;\n injectedToastKeyframes = true;\n const style = document.createElement(\"style\");\n style.textContent = `\n @keyframes featuredrop-toast-enter {\n from { opacity: 0; transform: translateY(8px) scale(0.96); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n `;\n document.head.appendChild(style);\n}\n\n/* ------------------------------------------------------------------ */\n/* Toast Component */\n/* ------------------------------------------------------------------ */\n\n/**\n * Toast notification component for feature announcements.\n *\n * Shows brief popups for new features. Auto-dismisses after a timeout.\n * Stacks multiple toasts with configurable max visible count.\n *\n * @example\n * ```tsx\n * <Toast position=\"bottom-right\" maxVisible={3} />\n * ```\n *\n * @example Specific features\n * ```tsx\n * <Toast featureIds={[\"ai-journal\", \"analytics-v2\"]} />\n * ```\n *\n * @example Headless\n * ```tsx\n * <Toast>\n * {({ toasts, dismiss }) => toasts.map(t => (\n * <div key={t.id}>{t.label} <button onClick={() => dismiss(t.id)}>x</button></div>\n * ))}\n * </Toast>\n * ```\n */\nexport function Toast({\n featureIds,\n maxVisible = 3,\n autoDismissMs = 8000,\n position = \"bottom-right\",\n analytics,\n className,\n style,\n children,\n renderToast,\n}: ToastProps) {\n const { newFeaturesSorted, dismiss } = useFeatureDrop();\n const [localDismissed, setLocalDismissed] = useState<Set<string>>(new Set());\n const timersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n injectToastKeyframes();\n }, []);\n\n // Filter features for toasting\n const toastFeatures = newFeaturesSorted.filter((f) => {\n if (localDismissed.has(f.id)) return false;\n if (featureIds && !featureIds.includes(f.id)) return false;\n return true;\n });\n\n const visibleToasts = toastFeatures.slice(0, maxVisible);\n\n const handleDismiss = useCallback(\n (id: string) => {\n setLocalDismissed((prev) => new Set(prev).add(id));\n dismiss(id);\n const feature = newFeaturesSorted.find((f) => f.id === id);\n if (feature) analytics?.onFeatureDismissed?.(feature);\n const timer = timersRef.current.get(id);\n if (timer) {\n clearTimeout(timer);\n timersRef.current.delete(id);\n }\n },\n [dismiss, newFeaturesSorted, analytics],\n );\n\n const handleDismissAllLocal = useCallback(() => {\n for (const f of visibleToasts) {\n handleDismiss(f.id);\n }\n }, [visibleToasts, handleDismiss]);\n\n // Auto-dismiss timers\n useEffect(() => {\n if (autoDismissMs <= 0) return;\n for (const f of visibleToasts) {\n if (!timersRef.current.has(f.id)) {\n timersRef.current.set(\n f.id,\n setTimeout(() => handleDismiss(f.id), autoDismissMs),\n );\n }\n }\n }, [visibleToasts, autoDismissMs, handleDismiss]);\n\n // Fire onFeatureSeen for visible toasts\n useEffect(() => {\n for (const f of visibleToasts) {\n analytics?.onFeatureSeen?.(f);\n }\n }, [visibleToasts, analytics]);\n\n // Cleanup timers\n useEffect(() => {\n const timers = timersRef.current;\n return () => {\n for (const timer of timers.values()) clearTimeout(timer);\n timers.clear();\n };\n }, []);\n\n // Headless render prop\n if (children) {\n return (\n <>\n {children({\n toasts: visibleToasts,\n dismiss: handleDismiss,\n dismissAll: handleDismissAllLocal,\n })}\n </>\n );\n }\n\n if (visibleToasts.length === 0) return null;\n\n const posStyles = POSITION_STYLES[position] ?? POSITION_STYLES[\"bottom-right\"];\n const isBottom = position.startsWith(\"bottom\");\n\n return (\n <div\n data-featuredrop-toast-container\n className={className}\n style={{\n ...containerStyles,\n ...posStyles,\n flexDirection: isBottom ? \"column-reverse\" : \"column\",\n ...style,\n }}\n >\n {visibleToasts.map((feature) => {\n if (renderToast) {\n return (\n <div key={feature.id}>\n {renderToast({ feature, dismiss: () => handleDismiss(feature.id) })}\n </div>\n );\n }\n\n const indicator = feature.type\n ? TYPE_INDICATORS[feature.type] ?? TYPE_INDICATORS.feature\n : null;\n\n return (\n <div\n key={feature.id}\n data-featuredrop-toast={feature.id}\n style={toastStyles}\n >\n {indicator && (\n <span style={{ fontSize: \"20px\", lineHeight: 1 }} aria-hidden=\"true\">\n {indicator.icon}\n </span>\n )}\n <div style={toastBodyStyles}>\n <p style={toastTitleStyles}>{feature.label}</p>\n {feature.description && (\n <p style={toastDescStyles}>{feature.description}</p>\n )}\n {feature.cta && (\n <a\n href={feature.cta.url}\n style={toastCtaStyles}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={() => analytics?.onFeatureClicked?.(feature)}\n >\n {feature.cta.label} &rarr;\n </a>\n )}\n </div>\n <button\n onClick={() => handleDismiss(feature.id)}\n style={toastCloseStyles}\n aria-label={`Dismiss ${feature.label}`}\n >\n &times;\n </button>\n </div>\n );\n })}\n </div>\n );\n}\n"]}