'use client' import { useEffect, useMemo, useRef, useState } from 'react' import { createPortal } from 'react-dom' import { ChevronDown, Search, X } from 'lucide-react' import { cn } from '@/lib/utils' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Input } from '@/components/ui/input' import type { LanguageOption } from '@/lib/languages' type Props = { value: string onValueChange: (value: string) => void options: LanguageOption[] commonOptions?: LanguageOption[] placeholder?: string searchPlaceholder?: string disabled?: boolean allowAuto?: boolean autoOption?: LanguageOption triggerClassName?: string } export default function LanguageSelect({ value, onValueChange, options, commonOptions, placeholder = '选择语言', searchPlaceholder = '搜索语言(名称 / 代码)', disabled, allowAuto, autoOption, triggerClassName, }: Props) { const [open, setOpen] = useState(false) const [query, setQuery] = useState('') const inputRef = useRef(null) const allOptions = useMemo(() => { const list = [...options] if (allowAuto && autoOption) { return [autoOption, ...list] } return list }, [allowAuto, autoOption, options]) const selected = useMemo(() => { return allOptions.find((o) => o.code === value) || null }, [allOptions, value]) const languageCount = options.length const filtered = useMemo(() => { const q = query.trim().toLowerCase() if (!q) return allOptions return allOptions.filter((o) => (o.search || `${o.name} ${o.code}`).toLowerCase().includes(q)) }, [allOptions, query]) useEffect(() => { if (!open) return setQuery('') const id = window.setTimeout(() => inputRef.current?.focus(), 0) return () => window.clearTimeout(id) }, [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]) const handleSelect = (code: string) => { onValueChange(code) setOpen(false) } return ( <> {open && typeof document !== 'undefined' && createPortal(
{ if (e.target === e.currentTarget) setOpen(false) }} >
选择语言 支持 {languageCount} 种语言{allowAuto ? ' + 自动检测' : ''},支持搜索
setQuery(e.target.value)} placeholder={searchPlaceholder} className="pl-9" />
{query && ( )}
{!query.trim() && commonOptions && commonOptions.length > 0 && (
{commonOptions.map((o) => ( ))}
)}
{filtered.length === 0 ? (
无匹配语言
) : (
{filtered.map((o) => ( ))}
)}
, document.body )} ) }