"use client"; import { useEffect, useMemo, useState } from "react"; import { Check, ChevronsUpDown } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { ScrollArea } from "@/components/ui/scroll-area"; import { cn } from "@/lib/utils"; interface SearchableSelectProps { value: string; options: string[]; placeholder: string; searchPlaceholder?: string; emptyText?: string; onValueChange: (value: string) => void; theme?: "light" | "dark"; disabled?: boolean; } export function SearchableSelect({ value, options, placeholder, searchPlaceholder = "输入关键字搜索", emptyText = "暂无可选项", onValueChange, theme = "light", disabled = false, }: SearchableSelectProps) { const [open, setOpen] = useState(false); const [query, setQuery] = useState(""); const isDark = theme === "dark"; useEffect(() => { if (!open) { setQuery(""); } }, [open]); const filteredOptions = useMemo(() => { const normalizedQuery = query.trim().toLowerCase(); if (!normalizedQuery) return options; return options.filter((item) => item.toLowerCase().includes(normalizedQuery)); }, [options, query]); return (
setQuery(event.target.value)} placeholder={searchPlaceholder} disabled={disabled} className={cn( !isDark && "border-slate-200 bg-white text-slate-900 placeholder:text-slate-400 focus-visible:ring-slate-300/80 focus-visible:ring-offset-0", isDark && "border-white/12 bg-white/[0.04] text-white placeholder:text-white/28 focus-visible:ring-emerald-400/30 focus-visible:ring-offset-0" )} />
{filteredOptions.length > 0 ? ( filteredOptions.map((item) => { const selected = item === value; return ( ); }) ) : (
{emptyText}
)}
); }