242 lines · 9.4 KB · TypeScript
RawDownload
"use client"; import { mergeProps } from "@base-ui/react/merge-props";import { Select as SelectPrimitive } from "@base-ui/react/select";import { useRender } from "@base-ui/react/use-render";import { cva, type VariantProps } from "class-variance-authority";import { ChevronDownIcon, ChevronsUpDownIcon, ChevronUpIcon } from "lucide-react";import type * as React from "react"; import { cn } from "~/lib/utils"; const Select = SelectPrimitive.Root; const selectTriggerVariants = cva(  "relative inline-flex cursor-pointer select-none items-center justify-between gap-2 border rounded-lg text-left text-base outline-none transition-[color,box-shadow,background-color] data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4",  {    defaultVariants: {      size: "default",      variant: "default",    },    variants: {      variant: {        default:          "w-full min-w-36 border-input bg-background not-dark:bg-clip-padding text-foreground shadow-xs/5 ring-ring/24 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/16 dark:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='text-'])]:text-icon-muted [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none",        ghost:          "border-transparent text-secondary-label focus-visible:ring-2 focus-visible:ring-ring data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent [:hover,[data-pressed]]:text-foreground",      },      size: {        compact:          "h-7 gap-1 rounded-md px-[calc(--spacing(2)-1px)] text-xs before:rounded-[calc(var(--radius-md)-1px)] [&_svg:not([class*='size-'])]:size-3.5",        default: "min-h-9 px-[calc(--spacing(3)-1px)] sm:min-h-8",        lg: "min-h-10 px-[calc(--spacing(3)-1px)] sm:min-h-9",        sm: "min-h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:min-h-7",        xs: "h-7 gap-1 rounded-md px-[calc(--spacing(2)-1px)] text-sm before:rounded-[calc(var(--radius-md)-1px)] sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5",      },    },  },); const selectTriggerIconClassName = "-me-1 size-4.5 opacity-80 sm:size-4"; interface SelectButtonProps extends useRender.ComponentProps<"button"> {  size?: VariantProps<typeof selectTriggerVariants>["size"];  variant?: VariantProps<typeof selectTriggerVariants>["variant"];} function SelectButton({ className, size, variant, render, children, ...props }: SelectButtonProps) {  const typeValue: React.ButtonHTMLAttributes<HTMLButtonElement>["type"] = render    ? undefined    : "button";   const defaultProps = {    children: (      <>        <span className="flex-1 truncate in-data-placeholder:text-placeholder">{children}</span>        {variant === "ghost" ? (          <ChevronDownIcon className="-me-1 size-3 opacity-50" />        ) : (          <ChevronsUpDownIcon className={selectTriggerIconClassName} />        )}      </>    ),    className: cn(selectTriggerVariants({ size, variant }), "min-w-none", className),    "data-slot": "select-button",    type: typeValue,  };   return useRender({    defaultTagName: "button",    props: mergeProps<"button">(defaultProps, props),    render,  });} function SelectTrigger({  className,  size = "default",  variant = "default",  children,  icon,  ...props}: SelectPrimitive.Trigger.Props &  VariantProps<typeof selectTriggerVariants> & { icon?: React.ReactNode }) {  return (    <SelectPrimitive.Trigger      className={cn(selectTriggerVariants({ size, variant }), className)}      data-slot="select-trigger"      {...props}    >      {children}      <SelectPrimitive.Icon data-slot="select-icon">        {icon ?? <ChevronDownIcon className="-me-1 size-3 opacity-50" />}      </SelectPrimitive.Icon>    </SelectPrimitive.Trigger>  );} function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {  return (    <SelectPrimitive.Value      className={cn("flex-1 truncate data-placeholder:text-placeholder", className)}      data-slot="select-value"      {...props}    />  );} function SelectPopup({  className,  popupClassName,  children,  side = "bottom",  sideOffset = 4,  align = "start",  alignOffset = 0,  alignItemWithTrigger = true,  matchTriggerWidth = true,  anchor,  ...props}: SelectPrimitive.Popup.Props & {  popupClassName?: string;  side?: SelectPrimitive.Positioner.Props["side"];  sideOffset?: SelectPrimitive.Positioner.Props["sideOffset"];  align?: SelectPrimitive.Positioner.Props["align"];  alignOffset?: SelectPrimitive.Positioner.Props["alignOffset"];  alignItemWithTrigger?: SelectPrimitive.Positioner.Props["alignItemWithTrigger"];  matchTriggerWidth?: boolean;  anchor?: SelectPrimitive.Positioner.Props["anchor"];}) {  return (    <SelectPrimitive.Portal>      <SelectPrimitive.Positioner        align={align}        alignItemWithTrigger={alignItemWithTrigger}        alignOffset={alignOffset}        anchor={anchor}        className="z-[130] select-none"        data-slot="select-positioner"        side={side}        sideOffset={sideOffset}      >        <SelectPrimitive.Popup          className="origin-(--transform-origin) rounded-lg text-foreground outline-none"          data-slot="select-popup"          {...props}        >          <SelectPrimitive.ScrollUpArrow            className="top-0 z-50 flex h-6 w-full cursor-default items-center justify-center before:pointer-events-none before:absolute before:inset-x-px before:top-px before:h-[200%] before:rounded-t-[calc(var(--radius-lg)-1px)] before:bg-linear-to-b before:from-50% before:from-popover"            data-slot="select-scroll-up-arrow"          >            <ChevronUpIcon className="relative size-4.5 sm:size-4" />          </SelectPrimitive.ScrollUpArrow>          <div            className={cn(              "dropdown-glass relative h-full rounded-lg shadow-[0_16px_40px_-18px_rgb(0_0_0/55%)] dark:shadow-[0_18px_44px_-18px_rgb(0_0_0/80%)]",              matchTriggerWidth && "min-w-(--anchor-width)",              popupClassName,            )}          >            <SelectPrimitive.List              className={cn("max-h-(--available-height) overflow-y-auto p-1", className)}              data-slot="select-list"            >              {children}            </SelectPrimitive.List>          </div>          <SelectPrimitive.ScrollDownArrow            className="bottom-0 z-50 flex h-6 w-full cursor-default items-center justify-center before:pointer-events-none before:absolute before:inset-x-px before:bottom-px before:h-[200%] before:rounded-b-[calc(var(--radius-lg)-1px)] before:bg-linear-to-t before:from-50% before:from-popover"            data-slot="select-scroll-down-arrow"          >            <ChevronDownIcon className="relative size-4.5 sm:size-4" />          </SelectPrimitive.ScrollDownArrow>        </SelectPrimitive.Popup>      </SelectPrimitive.Positioner>    </SelectPrimitive.Portal>  );} function SelectItem({  className,  children,  hideIndicator: _hideIndicator = false,  ...props}: SelectPrimitive.Item.Props & {  hideIndicator?: boolean;}) {  return (    <SelectPrimitive.Item      className={cn(        "flex min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-pointer items-center rounded-sm px-2 py-1 text-base outline-none data-selected:bg-foreground/[0.08] data-disabled:pointer-events-none data-disabled:cursor-not-allowed data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",        className,      )}      data-slot="select-item"      {...props}    >      <SelectPrimitive.ItemText        className="min-w-0 flex-1 [&_svg:not([class*='text-'])]:text-muted-foreground"        data-slot="select-item-text"      >        {children}      </SelectPrimitive.ItemText>    </SelectPrimitive.Item>  );} function SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {  return (    <SelectPrimitive.Separator      className={cn("mx-2 my-1 h-px bg-border", className)}      data-slot="select-separator"      {...props}    />  );} function SelectGroup(props: SelectPrimitive.Group.Props) {  return <SelectPrimitive.Group data-slot="select-group" {...props} />;} function SelectGroupLabel(props: SelectPrimitive.GroupLabel.Props) {  return (    <SelectPrimitive.GroupLabel      className="px-2 py-1.5 font-medium text-muted-foreground text-xs"      data-slot="select-group-label"      {...props}    />  );} export {  Select,  SelectTrigger,  SelectButton,  selectTriggerVariants,  SelectValue,  SelectPopup,  SelectPopup as SelectContent,  SelectItem,  SelectSeparator,  SelectGroup,  SelectGroupLabel,};