import type { JSX } from "solid-js"; import { Show, createEffect, onCleanup, splitProps } from "solid-js"; import { useInternalHoverCardContext } from "./hover-card-context"; export interface HoverCardContentProps extends JSX.HTMLAttributes { /** Keep mounted when closed. @default false */ forceMount?: boolean | undefined; children?: JSX.Element; } /** * Floating content panel for HoverCard. Displayed when the trigger is hovered. * No role is set since hover card content is supplementary (not announced). * Handles Escape to close and pointer safe-area so the user can move * from the trigger into the content without triggering a close. */ export function HoverCardContent(props: HoverCardContentProps): JSX.Element { const [local, rest] = splitProps(props, ["children", "forceMount"]); const ctx = useInternalHoverCardContext(); const handlePointerEnter: JSX.EventHandler = () => { ctx.cancelTimers(); }; const handlePointerLeave: JSX.EventHandler = () => { ctx.scheduleClose(); }; createEffect(() => { if (!ctx.isOpen()) return; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") { e.preventDefault(); ctx.cancelTimers(); ctx.close(); } }; document.addEventListener("keydown", handleKeyDown); onCleanup(() => document.removeEventListener("keydown", handleKeyDown)); }); return (
ctx.setContentRef(el)} id={ctx.contentId} data-state={ctx.isOpen() ? "open" : "closed"} style={ctx.floatingStyle()} onPointerEnter={handlePointerEnter} onPointerLeave={handlePointerLeave} {...rest} > {local.children}
); }