select.tsx
1'use client'
2
3import * as React from 'react'
4import * as SelectPrimitive from '@radix-ui/react-select'
5import { Check, ChevronDown } from 'lucide-react'
6import { cn } from '@/lib/utils'
7
8export interface SelectOption {
9 value: string | null
10 label: string
11}
12
13interface SelectProps {
14 value: string | null
15 onValueChange: (value: string | null) => void
16 options: SelectOption[]
17}
18
19export function Select({ value, onValueChange, options }: SelectProps) {
20 return (
21 <SelectPrimitive.Root
22 value={value || undefined}
23 onValueChange={onValueChange}
24 >
25 <SelectPrimitive.Trigger className="flex h-10 w-full items-center justify-between rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
26 <SelectPrimitive.Value>
27 {options.find((opt) => opt.value === value)?.label}
28 </SelectPrimitive.Value>
29 <SelectPrimitive.Icon>
30 <ChevronDown className="h-4 w-4 opacity-50" />
31 </SelectPrimitive.Icon>
32 </SelectPrimitive.Trigger>
33 <SelectPrimitive.Portal>
34 <SelectPrimitive.Content className="relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-gray-700 bg-gray-800 text-gray-300 shadow-md animate-in fade-in-80">
35 <SelectPrimitive.Viewport className="p-1">
36 {options.map((option) => (
37 <SelectPrimitive.Item
38 key={option.value ?? 'all'}
39 value={option.value ?? 'all'}
40 className={cn(
41 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-gray-700 data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
42 )}
43 disabled={option.value === null}
44 >
45 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
46 <SelectPrimitive.ItemIndicator>
47 <Check className="h-4 w-4" />
48 </SelectPrimitive.ItemIndicator>
49 </span>
50 <SelectPrimitive.ItemText>
51 {option.label}
52 </SelectPrimitive.ItemText>
53 </SelectPrimitive.Item>
54 ))}
55 </SelectPrimitive.Viewport>
56 </SelectPrimitive.Content>
57 </SelectPrimitive.Portal>
58 </SelectPrimitive.Root>
59 )
60}
61