"use client"; import { useEffect, useId, useRef, useState, type ReactNode, type ToggleEvent, } from "react"; export function Popover({ label, children, side = "bottom", align = "start", className = "", }: { label: string; children: ReactNode; side?: "top" | "bottom"; align?: "start" | "end"; className?: string; }) { const id = useId(); const trigger = useRef(null); const panel = useRef(null); const [open, setOpen] = useState(false); useEffect(() => { if (trigger.current && panel.current) trigger.current.popoverTargetElement = panel.current; }, []); useEffect(() => { if (!open) return; const place = () => { const button = trigger.current?.getBoundingClientRect(); const box = panel.current; if (!button || !box) return; const fits = (top: number) => top >= 8 && top + box.offsetHeight <= innerHeight - 8; const below = button.bottom + 8; const above = button.top - 8 - box.offsetHeight; const top = side === "bottom" ? fits(below) || !fits(above) ? below : above : fits(above) || !fits(below) ? above : below; const left = align === "start" ? button.left : button.right - box.offsetWidth; box.style.top = `${Math.max(8, top)}px`; box.style.left = `${Math.min(Math.max(8, left), innerWidth - box.offsetWidth - 8)}px`; }; place(); addEventListener("scroll", place, { capture: true, passive: true }); addEventListener("resize", place); return () => { removeEventListener("scroll", place, { capture: true }); removeEventListener("resize", place); }; }, [open, side, align]); return ( ); }