'use client' import { useState, type KeyboardEvent } from 'react' type Props = { values: string[] onChange: (next: string[]) => void placeholder?: string maxLength?: number maxItems?: number suggestions?: string[] } /** * Minimal chip / token input. Press Enter or comma to commit the current * value. Backspace on an empty input removes the last chip. Optional * suggestion list shows un-used suggestions as click-to-add chips below. */ export function ChipInput({ values, onChange, placeholder, maxLength = 80, maxItems = 50, suggestions, }: Props) { const [draft, setDraft] = useState('') function commit(raw: string) { const v = raw.trim() if (!v) return if (values.includes(v)) return if (values.length >= maxItems) return onChange([...values, v.slice(0, maxLength)]) setDraft('') } function remove(idx: number) { onChange(values.filter((_, i) => i !== idx)) } function handleKeyDown(e: KeyboardEvent) { if (e.key === 'Enter' || e.key === ',') { e.preventDefault() commit(draft) } else if (e.key === 'Backspace' && draft === '' && values.length > 0) { e.preventDefault() onChange(values.slice(0, -1)) } } const remainingSuggestions = (suggestions ?? []).filter(s => !values.includes(s)) return (
{values.map((v, i) => ( {v} ))} setDraft(e.target.value)} onKeyDown={handleKeyDown} onBlur={() => commit(draft)} placeholder={values.length === 0 ? placeholder : ''} maxLength={maxLength} className="flex-1 min-w-[120px] bg-transparent text-foreground font-sans text-sm py-1 px-1 focus:outline-none" />
{remainingSuggestions.length > 0 && (
{remainingSuggestions.map(s => ( ))}
)}
) }