{"version":3,"file":"HoverCard.cjs","names":[],"sources":["../../../src/components/HoverCard/HoverCard.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./HoverCard.module.css\";\n\nexport type HoverCardPlacement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface HoverCardProps extends HTMLAttributes<HTMLDivElement> {\n    /** Element the user hovers/focuses to reveal the card. */\n    trigger: ReactNode;\n    /** Card content shown while hovering/focusing the trigger or the card itself. */\n    children: ReactNode;\n    /** Delay in ms before opening on mouseenter/focus. Default 300. */\n    openDelay?: number;\n    /** Delay in ms before closing on mouseleave/blur. Default 150. */\n    closeDelay?: number;\n    /** Where the card is anchored relative to the trigger. Default \"bottom\". */\n    placement?: HoverCardPlacement;\n}\n\n/**\n * Content preview shown when the trigger is hovered or focused.\n *\n * - Opens after `openDelay` on `mouseenter`/`focus`.\n * - Closes after `closeDelay` on `mouseleave`/`blur`.\n * - Positioned relative to the trigger via `placement`.\n * - The card is rendered as a labelled `role=\"dialog\"` region; the trigger stays keyboard focusable.\n *\n * @param props - The hover card props.\n * @returns The trigger wrapper and the anchored card when open.\n */\nexport function HoverCard({\n    trigger,\n    children,\n    openDelay = 300,\n    closeDelay = 150,\n    placement = \"bottom\",\n    className,\n    ...rest\n}: HoverCardProps) {\n    const [open, setOpen] = useState(false);\n    const id = useId();\n    const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n    const clearTimer = useCallback((): void => {\n        if (timerRef.current !== null) {\n            clearTimeout(timerRef.current);\n            timerRef.current = null;\n        }\n    }, []);\n\n    const scheduleOpen = useCallback((): void => {\n        clearTimer();\n        timerRef.current = setTimeout(() => setOpen(true), openDelay);\n    }, [clearTimer, openDelay]);\n\n    const scheduleClose = useCallback((): void => {\n        clearTimer();\n        timerRef.current = setTimeout(() => setOpen(false), closeDelay);\n    }, [clearTimer, closeDelay]);\n\n    useEffect(() => clearTimer, [clearTimer]);\n\n    return (\n        <span\n            className={styles.root}\n            onMouseEnter={scheduleOpen}\n            onMouseLeave={scheduleClose}\n            onFocus={scheduleOpen}\n            onBlur={scheduleClose}\n        >\n            <span aria-describedby={open ? id : undefined} className={styles.trigger}>\n                {trigger}\n            </span>\n            {open && (\n                <div\n                    id={id}\n                    role=\"dialog\"\n                    className={cn(styles.card, styles[placement], className)}\n                    {...rest}\n                >\n                    {children}\n                </div>\n            )}\n        </span>\n    );\n}\n"],"mappings":"gIA+BA,SAAgB,EAAU,CACtB,UACA,WACA,YAAY,IACZ,aAAa,IACb,YAAY,SACZ,YACA,GAAG,GACY,CACf,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAS,EAAK,EAChC,GAAA,EAAK,EAAA,MAAA,CAAM,EACX,GAAA,EAAW,EAAA,OAAA,CAA6C,IAAI,EAE5D,GAAA,EAAa,EAAA,YAAA,KAAwB,CACnC,EAAS,UAAY,OACrB,aAAa,EAAS,OAAO,EAC7B,EAAS,QAAU,KAE3B,EAAG,CAAC,CAAC,EAEC,GAAA,EAAe,EAAA,YAAA,KAAwB,CACzC,EAAW,EACX,EAAS,QAAU,eAAiB,EAAQ,EAAI,EAAG,CAAS,CAChE,EAAG,CAAC,EAAY,CAAS,CAAC,EAEpB,GAAA,EAAgB,EAAA,YAAA,KAAwB,CAC1C,EAAW,EACX,EAAS,QAAU,eAAiB,EAAQ,EAAK,EAAG,CAAU,CAClE,EAAG,CAAC,EAAY,CAAU,CAAC,EAI3B,OAFA,EAAA,EAAA,UAAA,KAAgB,EAAY,CAAC,CAAU,CAAC,GAGpC,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,QAAO,KAClB,aAAc,EACd,aAAc,EACd,QAAS,EACT,OAAQ,EALZ,SAAA,EAOI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,mBAAkB,EAAO,EAAK,IAAA,GAAW,UAAW,EAAA,QAAO,QAC5D,SAAA,CACC,CAAA,EACL,IACG,EAAA,EAAA,IAAA,CAAC,MAAD,CACQ,KACJ,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAA,QAAO,GAAY,CAAS,EACvD,GAAI,EAEH,UACA,CAAA,CAEP,GAEd"}