'use client' import * as React from 'react' import { X } from 'lucide-react' import { cn } from '@/lib/utils' interface TagInputProps { value?: string onChange?: (value: string) => void placeholder?: string className?: string disabled?: boolean } const TagInput = React.forwardRef( ({ value = '', onChange, placeholder, className, disabled }, ref) => { const [inputValue, setInputValue] = React.useState('') const inputRef = React.useRef(null) React.useImperativeHandle(ref, () => inputRef.current!) const tags = React.useMemo( () => value .split(',') .map((t) => t.trim()) .filter(Boolean), [value] ) function commitTag(raw: string) { const trimmed = raw.trim() if (!trimmed) return const next = [...tags, trimmed].join(', ') onChange?.(next) setInputValue('') } function removeTag(index: number) { const next = tags.filter((_, i) => i !== index).join(', ') onChange?.(next) } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === 'Enter' || e.key === ',') { e.preventDefault() commitTag(inputValue) } else if ( e.key === 'Backspace' && inputValue === '' && tags.length > 0 ) { removeTag(tags.length - 1) } } function handleBlur() { if (inputValue.trim()) { commitTag(inputValue) } } function handlePaste(e: React.ClipboardEvent) { const pasted = e.clipboardData.getData('text') if (pasted.includes(',')) { e.preventDefault() const newTags = pasted .split(',') .map((t) => t.trim()) .filter(Boolean) const next = [...tags, ...newTags].join(', ') onChange?.(next) setInputValue('') } } return (
inputRef.current?.focus()} > {tags.map((tag, i) => ( {tag} {!disabled && ( )} ))} setInputValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleBlur} onPaste={handlePaste} placeholder={tags.length === 0 ? placeholder : undefined} disabled={disabled} className="min-w-[80px] flex-1 bg-transparent outline-none placeholder:text-muted-foreground" />
) } ) TagInput.displayName = 'TagInput' export { TagInput }