"use client"; import * as React from "react"; import { Select as SelectPrimitive } from "@base-ui/react/select"; import { cva, type VariantProps } from "class-variance-authority"; import { outlineControlSurfaceClassName } from "../../lib/control-outline"; import { cn } from "../../lib/utils"; import { PortalLayerContainerProvider, usePortalLayerContainer, } from "./portal-layer-context"; import { PrimitiveArrowIcon } from "./primitive-arrow-icon"; import { ScrollFade } from "./scroll-fade"; import { pressedSelectedItemClassName } from "./selection-state"; import { CheckIcon } from "@phosphor-icons/react"; const Select = SelectPrimitive.Root; const dropdownHoverBorderClassName = "[&:not(:focus):not([aria-expanded=true]):not([data-open]):not([data-popup-open]):not([data-state=open]):hover]:!border-[color:color-mix(in_oklab,var(--border)_20%,transparent)]"; const selectTriggerVariants = cva( "flex w-fit cursor-pointer items-center justify-between gap-1.5 border whitespace-nowrap font-medium transition-colors outline-none select-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-[color:var(--destructive)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:aria-invalid:border-[color:color-mix(in_oklab,var(--destructive)_50%,transparent)] [&_svg]:pointer-events-none [&_svg]:shrink-0", { variants: { placeholderTone: { default: "data-placeholder:text-[color:var(--foreground)]", muted: "data-placeholder:text-[color:var(--muted-foreground)]", }, radius: { default: "rounded-lg", full: "rounded-full", }, variant: { default: `${outlineControlSurfaceClassName} ${dropdownHoverBorderClassName} focus-visible:border-[color:color-mix(in_oklab,var(--border)_30%,transparent)] aria-expanded:border-[color:color-mix(in_oklab,var(--border)_30%,transparent)] data-popup-open:border-[color:color-mix(in_oklab,var(--border)_30%,transparent)] data-open:border-[color:color-mix(in_oklab,var(--border)_30%,transparent)]`, ghost: `border-transparent bg-transparent bg-clip-border text-[color:var(--foreground)] focus-visible:border-[color:var(--ring)] focus-visible:ring-2 focus-visible:ring-[color:color-mix(in_oklab,var(--ring)_30%,transparent)] hover:bg-[color:color-mix(in_oklab,var(--input)_10%,transparent)] hover:text-[color:var(--foreground)] active:bg-[color:color-mix(in_oklab,var(--input)_10%,transparent)] active:text-[color:var(--foreground)] aria-expanded:bg-[color:color-mix(in_oklab,var(--input)_10%,transparent)] aria-expanded:text-[color:var(--foreground)] data-open:bg-[color:color-mix(in_oklab,var(--input)_10%,transparent)] data-open:text-[color:var(--foreground)] data-popup-open:bg-[color:color-mix(in_oklab,var(--input)_10%,transparent)] data-popup-open:text-[color:var(--foreground)] data-[state=open]:bg-[color:color-mix(in_oklab,var(--input)_10%,transparent)] data-[state=open]:text-[color:var(--foreground)] ${pressedSelectedItemClassName}`, }, size: { sm: "h-6 gap-1 px-1.5 pr-1 py-0 text-xs/relaxed *:data-[slot=select-value]:gap-1 [&_svg:not([class*='size-'])]:size-3", default: "h-7 px-2 py-0.5 text-xs/relaxed [&_svg:not([class*='size-'])]:size-3.5", lg: "h-8 px-2.5 py-1 text-sm/relaxed [&_svg:not([class*='size-'])]:size-4", xl: "h-10 px-3 py-1.5 text-base/relaxed [&_svg:not([class*='size-'])]:size-4", }, }, defaultVariants: { placeholderTone: "muted", radius: "default", variant: "default", size: "default", }, }, ); function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) { return ( ); } function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) { return ( ); } function SelectTrigger({ className, placeholderTone = "muted", radius = "default", size = "default", variant = "default", children, ...props }: SelectPrimitive.Trigger.Props & VariantProps) { return ( {children} } /> ); } const selectTriggerArrowOpenClassName = "group-aria-expanded/select-trigger:rotate-180 group-data-popup-open/select-trigger:rotate-180 group-data-open/select-trigger:rotate-180"; const SelectTriggerButton = React.forwardRef< HTMLButtonElement, React.ComponentProps<"button"> & VariantProps & { open?: boolean; } >(function SelectTriggerButton( { children, className, open, placeholderTone = "muted", radius = "default", size = "default", variant = "default", ...props }, ref, ) { return ( ); }); function SelectContent({ className, children, side = "bottom", sideOffset = 4, align = "center", alignOffset = 0, alignItemWithTrigger = true, ...props }: SelectPrimitive.Popup.Props & Pick< SelectPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger" >) { const resolvedContainer = usePortalLayerContainer(); const portalNodeRef = React.useRef(null); return ( {children} ); } function SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) { return ( ); } function getTextTitle( title: unknown, children: React.ReactNode, ): string | undefined { if (typeof title === "string" && title.length > 0) { return title; } if (typeof children === "string" || typeof children === "number") { return String(children); } return undefined; } function useOverflowTitle( viewportRef: React.RefObject, textTitle: string | undefined, ): string | undefined { const [overflowing, setOverflowing] = React.useState(false); React.useEffect(() => { const viewport = viewportRef.current; if (!viewport || !textTitle) { setOverflowing(false); return undefined; } const updateOverflow = () => { setOverflowing(viewport.scrollWidth > viewport.clientWidth + 1); }; updateOverflow(); if (typeof ResizeObserver === "undefined") { return undefined; } const observer = new ResizeObserver(updateOverflow); observer.observe(viewport); if (viewport.firstElementChild instanceof HTMLElement) { observer.observe(viewport.firstElementChild); } return () => { observer.disconnect(); }; }, [textTitle, viewportRef]); return overflowing ? textTitle : undefined; } function SelectItemTextContent({ children, title, }: { children: React.ReactNode; title: string | undefined; }): React.JSX.Element { const viewportRef = React.useRef(null); const resolvedTitle = useOverflowTitle(viewportRef, title); if (!title) { return ( {children} ); } return ( {children} ); } function SelectItem({ className, children, title, ...props }: SelectPrimitive.Item.Props) { const textTitle = getTextTitle(title, children); return ( {children} } > ); } function SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) { return ( ); } function SelectScrollUpButton({ className, ...props }: React.ComponentProps) { return ( ); } function SelectScrollDownButton({ className, ...props }: React.ComponentProps) { return ( ); } export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectTriggerButton, SelectValue, };