201 lines
5.5 KiB
TypeScript
201 lines
5.5 KiB
TypeScript
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
|
import { Select as SelectPrimitive } from "@base-ui/react/select"
|
|
|
|
import { cn } from "@/shared/ui/utils"
|
|
|
|
function Select<Value, Multiple extends boolean | undefined = false>(
|
|
props: SelectPrimitive.Root.Props<Value, Multiple>,
|
|
) {
|
|
return <SelectPrimitive.Root data-slot="select" {...props} />
|
|
}
|
|
|
|
function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
|
|
return (
|
|
<SelectPrimitive.Group
|
|
data-slot="select-group"
|
|
className={cn("p-1", className)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function SelectLabel({
|
|
className,
|
|
...props
|
|
}: SelectPrimitive.GroupLabel.Props) {
|
|
return (
|
|
<SelectPrimitive.GroupLabel
|
|
data-slot="select-label"
|
|
className={cn(
|
|
"px-2 py-1.5 text-xs font-medium text-muted-foreground",
|
|
className,
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function SelectTrigger({
|
|
className,
|
|
children,
|
|
size = "default",
|
|
...props
|
|
}: SelectPrimitive.Trigger.Props & {
|
|
size?: "sm" | "default"
|
|
}) {
|
|
return (
|
|
<SelectPrimitive.Trigger
|
|
data-slot="select-trigger"
|
|
data-size={size}
|
|
className={cn(
|
|
"flex w-full items-center justify-between gap-2 rounded-lg border border-input bg-transparent px-2.5 text-sm whitespace-nowrap outline-none transition-colors focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 [&>span]:line-clamp-1 [&>svg]:pointer-events-none [&>svg]:size-4 [&>svg]:shrink-0",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
<SelectPrimitive.Icon
|
|
data-slot="select-icon"
|
|
className="text-muted-foreground"
|
|
>
|
|
<ChevronDown aria-hidden="true" />
|
|
</SelectPrimitive.Icon>
|
|
</SelectPrimitive.Trigger>
|
|
)
|
|
}
|
|
|
|
function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
|
|
return (
|
|
<SelectPrimitive.Value
|
|
data-slot="select-value"
|
|
className={cn("line-clamp-1", className)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function SelectContent({
|
|
className,
|
|
children,
|
|
sideOffset = 4,
|
|
...props
|
|
}: SelectPrimitive.Popup.Props & {
|
|
sideOffset?: number
|
|
}) {
|
|
return (
|
|
<SelectPrimitive.Portal>
|
|
<SelectPrimitive.Positioner
|
|
data-slot="select-positioner"
|
|
sideOffset={sideOffset}
|
|
className="z-50 outline-none"
|
|
>
|
|
<SelectPrimitive.Popup
|
|
data-slot="select-content"
|
|
className={cn(
|
|
"relative z-50 max-h-(--available-height) min-w-[8rem] origin-(--transform-origin) overflow-hidden rounded-lg border border-border bg-card text-card-foreground shadow-lg ring-1 ring-foreground/10 outline-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
<SelectScrollUpButton />
|
|
<SelectPrimitive.List
|
|
data-slot="select-list"
|
|
className="max-h-72 overflow-y-auto p-1"
|
|
>
|
|
{children}
|
|
</SelectPrimitive.List>
|
|
<SelectScrollDownButton />
|
|
</SelectPrimitive.Popup>
|
|
</SelectPrimitive.Positioner>
|
|
</SelectPrimitive.Portal>
|
|
)
|
|
}
|
|
|
|
function SelectItem({
|
|
className,
|
|
children,
|
|
...props
|
|
}: SelectPrimitive.Item.Props) {
|
|
return (
|
|
<SelectPrimitive.Item
|
|
data-slot="select-item"
|
|
className={cn(
|
|
"relative flex min-h-8 w-full cursor-default items-center rounded-md py-1.5 pr-8 pl-2 text-sm outline-none select-none data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
<span className="absolute right-2 flex size-4 items-center justify-center">
|
|
<SelectPrimitive.ItemIndicator data-slot="select-item-indicator">
|
|
<Check aria-hidden="true" className="size-4" />
|
|
</SelectPrimitive.ItemIndicator>
|
|
</span>
|
|
<SelectPrimitive.ItemText data-slot="select-item-text">
|
|
{children}
|
|
</SelectPrimitive.ItemText>
|
|
</SelectPrimitive.Item>
|
|
)
|
|
}
|
|
|
|
function SelectSeparator({
|
|
className,
|
|
...props
|
|
}: SelectPrimitive.Separator.Props) {
|
|
return (
|
|
<SelectPrimitive.Separator
|
|
data-slot="select-separator"
|
|
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function SelectScrollUpButton({
|
|
className,
|
|
...props
|
|
}: SelectPrimitive.ScrollUpArrow.Props) {
|
|
return (
|
|
<SelectPrimitive.ScrollUpArrow
|
|
data-slot="select-scroll-up-button"
|
|
className={cn(
|
|
"flex h-6 items-center justify-center bg-card text-muted-foreground",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
<ChevronUp aria-hidden="true" className="size-4" />
|
|
</SelectPrimitive.ScrollUpArrow>
|
|
)
|
|
}
|
|
|
|
function SelectScrollDownButton({
|
|
className,
|
|
...props
|
|
}: SelectPrimitive.ScrollDownArrow.Props) {
|
|
return (
|
|
<SelectPrimitive.ScrollDownArrow
|
|
data-slot="select-scroll-down-button"
|
|
className={cn(
|
|
"flex h-6 items-center justify-center bg-card text-muted-foreground",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
<ChevronDown aria-hidden="true" className="size-4" />
|
|
</SelectPrimitive.ScrollDownArrow>
|
|
)
|
|
}
|
|
|
|
export {
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectLabel,
|
|
SelectScrollDownButton,
|
|
SelectScrollUpButton,
|
|
SelectSeparator,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
}
|