All files / components/ui select.tsx

100% Statements 7/7
100% Branches 7/7
100% Functions 0/0
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 704x   4x 4x   4x                     4x                             27x                                                                         4x  
import { forwardRef } from "react";
import type { SelectHTMLAttributes } from "react";
import { cn } from "@/utils/class-name";
import { ChevronDownIcon } from "@/components/icons/ChevronDown";
 
const SELECT_VARIANT_CLASSES = {
  default:
    "border-slate-300 bg-white/95 text-slate-900 shadow-sm hover:border-violet-400 focus:border-violet-500 focus:ring-violet-500/20 focus:bg-violet-500/5",
  subtle:
    "border-slate-200 bg-slate-50/90 text-slate-900 hover:border-slate-300",
  ghost:
    "border-transparent bg-transparent text-slate-900 hover:border-slate-200",
  dark:
    "border-white/12 bg-white/6 text-white/80 hover:border-violet-500/50 focus:border-violet-500 focus:ring-2 focus:ring-violet-500/20 focus:bg-violet-500/10 [&>option]:text-slate-900 light:border-slate-300 light:bg-white/95 light:text-slate-900 light:hover:border-slate-400",
} as const;
 
const SELECT_SIZE_CLASSES = {
  sm: "h-8 px-2 text-xs",
  md: "h-10 px-3 text-sm",
  lg: "h-11 px-4 text-sm",
} as const;
 
type SelectVariant = keyof typeof SELECT_VARIANT_CLASSES;
type SelectSize = keyof typeof SELECT_SIZE_CLASSES;
 
export type SelectProps = SelectHTMLAttributes<HTMLSelectElement> & {
  variant?: SelectVariant;
  controlSize?: SelectSize;
  fullWidth?: boolean;
};
 
export const Select = forwardRef<HTMLSelectElement, SelectProps>(
  (
    {
      variant = "default",
      controlSize = "md",
      fullWidth = false,
      className,
      children,
      ...props
    },
    ref,
  ) => (
    <div className={cn("relative", fullWidth && "w-full")}>
      <select
        ref={ref}
        className={cn(
          "peer w-full appearance-none rounded-xl border pr-10 outline-none transition duration-200",
          variant === "dark"
            ? "focus:border-sky-400 focus:ring-2 focus:ring-sky-400/20"
            : "focus:border-sky-400 focus:ring-2 focus:ring-sky-100",
          "cursor-pointer disabled:cursor-not-allowed disabled:opacity-60",
          SELECT_VARIANT_CLASSES[variant],
          SELECT_SIZE_CLASSES[controlSize],
          className,
        )}
        {...props}
      >
        {children}
      </select>
 
      <span className="pointer-events-none absolute inset-y-0 right-3 flex items-center text-slate-500 transition peer-focus:text-sky-500">
        <ChevronDownIcon className="size-4" />
      </span>
    </div>
  ),
);
 
Select.displayName = "Select";