"use client" import * as React from "react" import * as SelectPrimitive from "@radix-ui/react-select" import { Check, ChevronDown, ChevronUp, Loader2 } from "lucide-react" import { cn } from "../../lib/utils" /** * Premium Select Component * * Advanced dropdown/select component with variants, sizes and accessibility features. * Compatible with dark and light mode, providing a modern user experience with smooth animations. */ // Directly re-exporting the Root component const Select = SelectPrimitive.Root Select.displayName = "Select" const SelectGroup = SelectPrimitive.Group const SelectValue = SelectPrimitive.Value type SelectTriggerVariant = "standard" | "outline" | "ghost" | "underline"; type SelectTriggerSize = "sm" | "md" | "lg"; interface SelectTriggerProps extends React.ComponentPropsWithoutRef { /** Visual variant */ variant?: SelectTriggerVariant; /** Size */ size?: SelectTriggerSize; /** Error state */ error?: boolean | string; /** Success state */ success?: boolean; /** Loading state */ loading?: boolean; /** Icon displayed on the left */ leftIcon?: React.ReactNode; /** Icon displayed on the right (instead of default chevron) */ rightIcon?: React.ReactNode; } const SelectTrigger = React.forwardRef< React.ElementRef, SelectTriggerProps >(({ className, children, variant = "standard", size = "md", error, success, loading, leftIcon, rightIcon, ...props }, ref) => ( span]:line-clamp-1", "focus-visible:outline-none", /* Error state */ error && "border-error focus-visible:ring-error/30 focus-visible:border-error", /* Success state */ success && "border-success focus-visible:ring-success/30 focus-visible:border-success", /* Size variants */ size === "sm" && "h-8 text-xs px-2", size === "md" && "h-10 text-sm px-3", size === "lg" && "h-12 text-base px-4", /* Visual variants */ variant === "standard" && "border border-gray-300 dark:border-gray-700 bg-background dark:bg-gray-800/80 dark:shadow-inner dark:shadow-gray-950/10 dark:text-gray-200 hover:border-gray-400 dark:hover:border-gray-600 focus-visible:ring-2 focus-visible:ring-primary/30 dark:focus-visible:ring-primary/20 focus-visible:border-primary dark:focus-visible:border-primary/80", variant === "outline" && "border border-gray-300 dark:border-gray-700 bg-transparent dark:text-gray-200 hover:border-gray-400 dark:hover:border-gray-600 focus-visible:ring-2 focus-visible:ring-primary/30 dark:focus-visible:ring-primary/20 focus-visible:border-primary dark:focus-visible:border-primary/80", variant === "ghost" && "border-none bg-gray-100 dark:bg-gray-800 dark:shadow-inner dark:shadow-gray-950/10 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-700 focus-visible:ring-2 focus-visible:ring-primary/30 dark:focus-visible:ring-primary/20", variant === "underline" && "border-t-0 border-l-0 border-r-0 border-b border-gray-300 dark:border-gray-600 rounded-none px-0 dark:text-gray-200 dark:bg-transparent hover:border-gray-400 dark:hover:border-gray-500 focus-visible:ring-0 focus-visible:border-b-2 focus-visible:border-primary dark:focus-visible:border-primary/80", className )} {...props} disabled={props.disabled || loading} data-error={error ? true : undefined} data-success={success ? true : undefined} data-loading={loading ? true : undefined} >
{leftIcon && ( {leftIcon} )} {loading ? (
Loading...
) : children}
{!loading && ( {rightIcon ? ( {rightIcon} ) : ( )} )}
)) SelectTrigger.displayName = SelectPrimitive.Trigger.displayName /** * Scroll Up Button Component */ const SelectScrollUpButton = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )) SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName /** * Scroll Down Button Component */ const SelectScrollDownButton = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )) SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName const SelectContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, position = "popper", side = "bottom", sideOffset = 4, align = "start", ...props }, ref) => ( {children} )) SelectContent.displayName = SelectPrimitive.Content.displayName const SelectLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )) SelectLabel.displayName = SelectPrimitive.Label.displayName type SelectItemVariant = "default" | "subtle" | "destructive" | "success" | "warning"; type SelectItemSize = "sm" | "md" | "lg"; interface SelectItemProps extends React.ComponentPropsWithoutRef { /** Visual variant */ variant?: SelectItemVariant; /** Size */ size?: SelectItemSize; /** Icon displayed on the right */ rightIcon?: React.ReactNode; /** Custom indicator icon (instead of default check) */ customIndicator?: React.ReactNode; } const SelectItem = React.forwardRef< React.ElementRef, SelectItemProps >(({ className, children, variant = "default", size = "md", rightIcon, customIndicator, ...props }, ref) => ( {customIndicator || } {children} {rightIcon && ( {rightIcon} )} )) SelectItem.displayName = SelectPrimitive.Item.displayName const SelectSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )) SelectSeparator.displayName = SelectPrimitive.Separator.displayName export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton, }