Skip to content

Commit c65c05d

Browse files
committed
✨ Add Select component
1 parent 27b060d commit c65c05d

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import * as React from "react"
2+
import * as SelectPrimitive from "@radix-ui/react-select"
3+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
4+
5+
import { cn } from "@/lib/utils"
6+
7+
function Select({
8+
...props
9+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
10+
return <SelectPrimitive.Root data-slot="select" {...props} />
11+
}
12+
13+
function SelectGroup({
14+
...props
15+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
16+
return <SelectPrimitive.Group data-slot="select-group" {...props} />
17+
}
18+
19+
function SelectValue({
20+
...props
21+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
22+
return <SelectPrimitive.Value data-slot="select-value" {...props} />
23+
}
24+
25+
function SelectTrigger({
26+
className,
27+
size = "default",
28+
children,
29+
...props
30+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
31+
size?: "sm" | "default"
32+
}) {
33+
return (
34+
<SelectPrimitive.Trigger
35+
data-slot="select-trigger"
36+
data-size={size}
37+
className={cn(
38+
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
39+
className
40+
)}
41+
{...props}
42+
>
43+
{children}
44+
<SelectPrimitive.Icon asChild>
45+
<ChevronDownIcon className="size-4 opacity-50" />
46+
</SelectPrimitive.Icon>
47+
</SelectPrimitive.Trigger>
48+
)
49+
}
50+
51+
function SelectContent({
52+
className,
53+
children,
54+
position = "popper",
55+
align = "center",
56+
...props
57+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
58+
return (
59+
<SelectPrimitive.Portal>
60+
<SelectPrimitive.Content
61+
data-slot="select-content"
62+
className={cn(
63+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
64+
position === "popper" &&
65+
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
66+
className
67+
)}
68+
position={position}
69+
align={align}
70+
{...props}
71+
>
72+
<SelectScrollUpButton />
73+
<SelectPrimitive.Viewport
74+
className={cn(
75+
"p-1",
76+
position === "popper" &&
77+
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
78+
)}
79+
>
80+
{children}
81+
</SelectPrimitive.Viewport>
82+
<SelectScrollDownButton />
83+
</SelectPrimitive.Content>
84+
</SelectPrimitive.Portal>
85+
)
86+
}
87+
88+
function SelectLabel({
89+
className,
90+
...props
91+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
92+
return (
93+
<SelectPrimitive.Label
94+
data-slot="select-label"
95+
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
96+
{...props}
97+
/>
98+
)
99+
}
100+
101+
function SelectItem({
102+
className,
103+
children,
104+
...props
105+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
106+
return (
107+
<SelectPrimitive.Item
108+
data-slot="select-item"
109+
className={cn(
110+
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
111+
className
112+
)}
113+
{...props}
114+
>
115+
<span className="absolute right-2 flex size-3.5 items-center justify-center">
116+
<SelectPrimitive.ItemIndicator>
117+
<CheckIcon className="size-4" />
118+
</SelectPrimitive.ItemIndicator>
119+
</span>
120+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
121+
</SelectPrimitive.Item>
122+
)
123+
}
124+
125+
function SelectSeparator({
126+
className,
127+
...props
128+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
129+
return (
130+
<SelectPrimitive.Separator
131+
data-slot="select-separator"
132+
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
133+
{...props}
134+
/>
135+
)
136+
}
137+
138+
function SelectScrollUpButton({
139+
className,
140+
...props
141+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
142+
return (
143+
<SelectPrimitive.ScrollUpButton
144+
data-slot="select-scroll-up-button"
145+
className={cn(
146+
"flex cursor-default items-center justify-center py-1",
147+
className
148+
)}
149+
{...props}
150+
>
151+
<ChevronUpIcon className="size-4" />
152+
</SelectPrimitive.ScrollUpButton>
153+
)
154+
}
155+
156+
function SelectScrollDownButton({
157+
className,
158+
...props
159+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
160+
return (
161+
<SelectPrimitive.ScrollDownButton
162+
data-slot="select-scroll-down-button"
163+
className={cn(
164+
"flex cursor-default items-center justify-center py-1",
165+
className
166+
)}
167+
{...props}
168+
>
169+
<ChevronDownIcon className="size-4" />
170+
</SelectPrimitive.ScrollDownButton>
171+
)
172+
}
173+
174+
export {
175+
Select,
176+
SelectContent,
177+
SelectGroup,
178+
SelectItem,
179+
SelectLabel,
180+
SelectScrollDownButton,
181+
SelectScrollUpButton,
182+
SelectSeparator,
183+
SelectTrigger,
184+
SelectValue,
185+
}

0 commit comments

Comments
 (0)