import type { ReactNode } from "react"; import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { useClickOutside } from "../hooks/use-click-outside.js"; import { useSwipeToDismissDown } from "../hooks/use-swipe-to-dismiss.js"; import { cn } from "../lib/utils.js"; interface DetailPopoverProps { readonly anchorRect: DOMRect; readonly onClose: () => void; readonly ariaLabel: string; readonly children: ReactNode; } function DesktopPanel({ anchorRect, onClose, ariaLabel, children, }: Readonly) { const ref = useRef(null); const [pos, setPos] = useState<{ top: number; left: number } | null>(null); useLayoutEffect(() => { const el = ref.current; if (!el) return; const popover = el.getBoundingClientRect(); const vw = document.documentElement.clientWidth; const vh = document.documentElement.clientHeight; // Prefer placement to the LEFT of the anchor (panel is on the right edge) let left = anchorRect.left - popover.width - 8; if (left < 8) { left = anchorRect.right + 8; } if (left + popover.width > vw - 8) { left = vw - popover.width - 8; } let top = anchorRect.top; if (top + popover.height > vh - 8) { top = vh - popover.height - 8; } if (top < 8) top = 8; setPos({ top, left }); }, [anchorRect]); useClickOutside(ref, onClose); return (
{children}
); } function MobileSheet({ onClose, ariaLabel, children, }: Readonly>) { const { offsetY, isSwiping, handlers } = useSwipeToDismissDown(onClose); useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; document.addEventListener("keydown", handler); return () => document.removeEventListener("keydown", handler); }, [onClose]); return (