'use client' import { useState, useRef, useEffect } from 'react' interface Option { value: string label: string } interface SelectProps { value: string onChange: (value: string) => void options: Option[] className?: string /** Form-field style (input-like). Default: toolbar style (btn-secondary). */ variant?: 'default' | 'input' /** Shown when value is empty or does not match any option. */ placeholder?: string /** Full-width trigger and panel. Use in form layouts. */ fullWidth?: boolean /** Id for the trigger (e.g. for label htmlFor). */ id?: string /** Alignment of the dropdown panel. */ align?: 'left' | 'right' } export default function Select({ value, onChange, options, className = '', variant = 'default', placeholder, fullWidth = false, id, align = 'right', }: SelectProps) { const [isOpen, setIsOpen] = useState(false) const ref = useRef(null) useEffect(() => { function handleClickOutside(event: MouseEvent) { if (ref.current && !ref.current.contains(event.target as Node)) { setIsOpen(false) } } document.addEventListener('mousedown', handleClickOutside) return () => document.removeEventListener('mousedown', handleClickOutside) }, []) const selectedOption = options.find((o) => o.value === value) const displayLabel = selectedOption?.label ?? placeholder ?? value ?? '' const triggerBase = variant === 'input' ? 'px-4 py-2 border border-neutral-200 dark:border-neutral-800 rounded-xl bg-neutral-50/50 dark:bg-neutral-900/50 text-neutral-900 dark:text-white text-left text-sm ' + 'focus:outline-none focus:border-brand-orange focus:ring-4 focus:ring-brand-orange/10 transition-all duration-200 ' + (isOpen ? 'ring-4 ring-brand-orange/10 border-brand-orange' : '') : 'btn-secondary min-w-[140px]' const triggerLayout = fullWidth ? 'w-full ' : '' const alignClass = align === 'left' ? 'left-0' : 'right-0' const panelMinW = fullWidth ? 'w-full' : 'min-w-[140px] w-full' return (
{isOpen && (
{options.map((option) => ( ))}
)}
) }