import { useRef, useState } from 'react' import { Codicon } from '@/components/ui/codicon' import { Command, CommandGroup, CommandItem, CommandList } from '@/components/ui/command' import { Input } from '@/components/ui/input' import { Popover, PopoverAnchor, PopoverContent } from '@/components/ui/popover' import { cn } from '@/lib/utils' /** * Free-input combobox for open-world fields (voice/model names): a plain * Input the user can type anything into, plus a dropdown listing ALL known * options. * * Replaces the old `` + `` rendering for * FREE_INPUT_KEYS: native datalists filter by the field's current value, so a * field already holding a valid option (e.g. `gpt-4o-mini-tts`) suggested * only that one entry — users couldn't discover the other models/voices at * all (and on some platforms datalists barely render). Suggestions filter by * substring while typing, but an exact-match value shows the full list so an * already-configured field still exposes every alternative. */ export function ComboboxInput({ value, onChange, options, optionLabels, placeholder, className }: { value: string onChange: (value: string) => void options: string[] optionLabels?: Record placeholder?: string className?: string }) { const [open, setOpen] = useState(false) const inputRef = useRef(null) const query = value.trim().toLowerCase() const isExact = options.some(option => option.toLowerCase() === query) const visible = query && !isExact ? options.filter(option => option.toLowerCase().includes(query)) : options return (
{ onChange(e.target.value) if (!open) { setOpen(true) } }} onFocus={() => setOpen(true)} onKeyDown={e => { if (e.key === 'Escape' || e.key === 'Enter' || e.key === 'Tab') { setOpen(false) } }} placeholder={placeholder} ref={inputRef} value={value} />
e.preventDefault()} > {visible.length > 0 && ( {visible.map(option => ( { onChange(option) setOpen(false) }} value={option} > {optionLabels?.[option] ?? option} ))} )}
) }