Repository Public
1'use client';2import * as React from 'react';3import * as S from '@radix-ui/react-select';4import { Check, ChevronDown } from 'lucide-react';5import { cn } from '@/lib/cn';67export interface SelectOption {8 value: string;9 label: string;10 hint?: string;11}12/** Radix Select forbids empty-string values; `NONE` stands in for "no selection". */13export const NONE = '__none__';1415export function Select({16 value, onValueChange, options, placeholder, label, className, id, disabled,17}: {18 value: string;19 onValueChange: (v: string) => void;20 options: SelectOption[];21 placeholder?: string;22 label?: string;23 className?: string;24 id?: string;25 disabled?: boolean;26}) {27 return (28 <S.Root value={value} onValueChange={onValueChange} disabled={disabled}>29 <S.Trigger30 id={id}31 aria-label={label}32 className={cn(33 'inline-flex h-8 w-full items-center justify-between gap-2 rounded-sm border border-line-2 bg-surface px-3 text-[13px] text-text hover:border-line-3 focus:border-accent focus:outline-none disabled:opacity-50 pointer-coarse:h-12 pointer-coarse:rounded-[14px] pointer-coarse:px-4 pointer-coarse:text-base',34 className,35 )}36 >37 <span className="truncate">38 <S.Value placeholder={placeholder} />39 </span>40 <S.Icon>41 <ChevronDown className="size-3.5 text-muted" />42 </S.Icon>43 </S.Trigger>44 <S.Portal>45 <S.Content position="popper" sideOffset={4} className="anim-fade z-[70] max-h-72 min-w-[var(--radix-select-trigger-width)] overflow-hidden rounded-md border border-line-2 bg-elevated shadow-pop">46 <S.Viewport className="p-1">47 {options.map((o) => (48 <S.Item49 key={o.value}50 value={o.value}51 className="flex h-8 cursor-default select-none items-center gap-2 rounded-sm pl-2 pr-7 text-[13px] outline-none data-[highlighted]:bg-hover pointer-coarse:h-11 pointer-coarse:text-sm"52 >53 <S.ItemText>{o.label}</S.ItemText>54 {o.hint && <span className="ml-auto text-xs text-muted">{o.hint}</span>}55 <S.ItemIndicator className="absolute right-2">56 <Check className="size-3.5 text-accent" />57 </S.ItemIndicator>58 </S.Item>59 ))}60 </S.Viewport>61 </S.Content>62 </S.Portal>63 </S.Root>64 );65}66