import { useEffect, useRef, useState } from "react"; import { AnimatePresence, motion } from "motion/react"; import { Check, ChevronDown, X } from "lucide-react"; import { cn } from "@/lib/utils"; export type AdaptiveSelectOption = { value: string; label: string; disabled?: boolean; }; type AdaptiveSelectProps = { value?: string; options: AdaptiveSelectOption[]; placeholder?: string; sheetTitle?: string; disabled?: boolean; className?: string; onChange: (value: string) => void; }; function useIsMobileViewport() { const [isMobile, setIsMobile] = useState(() => { if (typeof window === "undefined") { return false; } return window.matchMedia("(max-width: 639px)").matches; }); useEffect(() => { if (typeof window === "undefined") { return; } const mediaQuery = window.matchMedia("(max-width: 639px)"); const handleChange = () => setIsMobile(mediaQuery.matches); handleChange(); if (typeof mediaQuery.addEventListener === "function") { mediaQuery.addEventListener("change", handleChange); return () => mediaQuery.removeEventListener("change", handleChange); } mediaQuery.addListener(handleChange); return () => mediaQuery.removeListener(handleChange); }, []); return isMobile; } export function AdaptiveSelect({ value = "", options, placeholder = "请选择", sheetTitle, disabled = false, className, onChange, }: AdaptiveSelectProps) { const [open, setOpen] = useState(false); const containerRef = useRef(null); const isMobile = useIsMobileViewport(); const selectedOption = options.find((option) => option.value === value); const selectedLabel = value ? selectedOption?.label || placeholder : placeholder; useEffect(() => { if (!open || isMobile) { return; } const handlePointerDown = (event: MouseEvent) => { if (!containerRef.current?.contains(event.target as Node)) { setOpen(false); } }; const handleEscape = (event: KeyboardEvent) => { if (event.key === "Escape") { setOpen(false); } }; document.addEventListener("mousedown", handlePointerDown); document.addEventListener("keydown", handleEscape); return () => { document.removeEventListener("mousedown", handlePointerDown); document.removeEventListener("keydown", handleEscape); }; }, [isMobile, open]); useEffect(() => { if (!open || !isMobile) { return; } const previousOverflow = document.body.style.overflow; document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = previousOverflow; }; }, [isMobile, open]); const handleSelect = (nextValue: string) => { onChange(nextValue); setOpen(false); }; const renderOption = (option: AdaptiveSelectOption) => { const isSelected = option.value === value; return ( ); }; return (
{open && !isMobile ? (
{options.map(renderOption)}
) : null}
{open && isMobile ? ( <> setOpen(false)} />

{sheetTitle || placeholder}

请选择一个选项

{options.map(renderOption)}
) : null}
); }