diff --git a/src/app/globals.css b/src/app/globals.css index 898c748..3db856b 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -59,20 +59,6 @@ body { color: rgba(255, 255, 255, 0.3); } -select.glass-input { - appearance: none; - -webkit-appearance: none; - color-scheme: dark; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: right 12px center; - padding-right: 36px; -} - -select option { - background-color: #0d0d1a; - color: #f3f4f6; -} /* ─── Glass Shine (top border gradient) ───────────────────────── */ diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select.tsx index c551601..9a25c65 100644 --- a/src/components/ui/Select.tsx +++ b/src/components/ui/Select.tsx @@ -1,49 +1,124 @@ -import { forwardRef } from 'react' +'use client' -interface SelectProps extends React.SelectHTMLAttributes { +import { useState, useRef, useEffect } from 'react' +import { ChevronDown } from 'lucide-react' + +interface SelectProps { label?: string error?: string required?: boolean options: { label: string; value: string }[] placeholder?: string + value?: string + defaultValue?: string + onChange?: (e: { target: { value: string; name?: string } }) => void + disabled?: boolean + className?: string + name?: string + id?: string } -const Select = forwardRef( - ({ label, error, required, options, placeholder, className = '', ...props }, ref) => { - return ( -
- {label && ( - - )} - - {error &&

{error}

} -
- ) - } -) +export default function Select({ + label, + error, + required, + options, + placeholder, + value, + defaultValue, + onChange, + disabled, + className = '', + name, + id, +}: SelectProps) { + const isControlled = value !== undefined + const [internalValue, setInternalValue] = useState(defaultValue ?? '') + const [open, setOpen] = useState(false) + const ref = useRef(null) -Select.displayName = 'Select' -export default Select + const currentValue = isControlled ? value : internalValue + const selected = options.find(o => o.value === currentValue) + + useEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) { + setOpen(false) + } + } + document.addEventListener('mousedown', handleClickOutside) + return () => document.removeEventListener('mousedown', handleClickOutside) + }, []) + + const handleSelect = (optValue: string) => { + if (!isControlled) setInternalValue(optValue) + onChange?.({ target: { value: optValue, name } }) + setOpen(false) + } + + return ( +
+ {label && ( + + )} + + {/* Hidden input for FormData compatibility */} + {name && } + +
+ + + {open && ( +
+ {placeholder && ( + + )} + {options.map(opt => ( + + ))} +
+ )} +
+ + {error &&

{error}

} +
+ ) +}