51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import type { SelectHTMLAttributes } from 'react';
|
|
import { ChevronDown } from 'lucide-react';
|
|
import { cn } from '../../lib/cn';
|
|
|
|
export interface SelectOption {
|
|
value: string;
|
|
label: string;
|
|
}
|
|
|
|
export interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
|
label?: string;
|
|
hint?: string;
|
|
/** Either strings or {value,label} objects. */
|
|
options?: Array<string | SelectOption>;
|
|
/** Class for the outer label wrapper. */
|
|
className?: string;
|
|
}
|
|
|
|
/** Labeled native select styled to match Input. */
|
|
export function Select({ label, hint, options = [], required, className, ...rest }: SelectProps) {
|
|
return (
|
|
<label className={cn('flex flex-col gap-1.5 font-sans', className)}>
|
|
{label && (
|
|
<span className="text-sm font-medium text-muted">
|
|
{label}
|
|
{required && <span className="text-ruby-600"> *</span>}
|
|
</span>
|
|
)}
|
|
<div className="relative bg-card rounded-md h-[42px] border border-border-default transition-[border-color,box-shadow] duration-150 focus-ring">
|
|
<select
|
|
required={required}
|
|
className="w-full h-full border-none outline-none bg-transparent appearance-none pl-3 pr-9 font-sans text-base text-strong cursor-pointer"
|
|
{...rest}
|
|
>
|
|
{options.map((o) => {
|
|
const val = typeof o === 'string' ? o : o.value;
|
|
const lab = typeof o === 'string' ? o : o.label;
|
|
return (
|
|
<option key={val} value={val}>
|
|
{lab}
|
|
</option>
|
|
);
|
|
})}
|
|
</select>
|
|
<ChevronDown size={15} className="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none text-faint" />
|
|
</div>
|
|
{hint && <span className="text-xs text-faint">{hint}</span>}
|
|
</label>
|
|
);
|
|
}
|