"use client"; import { useEffect, useId, useRef, useState } from "react"; import { AnimatePresence, motion } from "framer-motion"; import { IoListOutline, IoArrowUpOutline, IoArrowDownOutline } from "react-icons/io5"; import { useClickOutside } from "@/hooks/useClickOutside"; import { IconButton } from "@/components/IconButton"; export type SortOption = { value: T; label: string; iconDirection?: "asc" | "desc"; }; type Props = { options: SortOption[]; value: T; onChange: (v: T) => void; ariaLabel: string; className?: string; menuClassName?: string; }; export function SortDropdown({ options, value, onChange, ariaLabel, className, menuClassName, }: Props) { const [open, setOpen] = useState(false); const buttonRef = useRef(null); const menuRef = useRef(null); const listboxId = useId(); const active = options.find((o) => o.value === value) ?? options[0]; useClickOutside([buttonRef, menuRef], () => setOpen(false), open); useEffect(() => { if (!open) return; const onKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); }; window.addEventListener("keydown", onKeyDown); return () => window.removeEventListener("keydown", onKeyDown); }, [open]); return (
setOpen((v) => !v)} className="text-lg" aria-haspopup="listbox" aria-expanded={open} aria-controls={listboxId} > {open ? (
{options.map((opt, idx) => { const selected = opt.value === active.value; return ( ); })}
) : null}
); }