@vercel/agent-eval-playground 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +50 -0
  2. package/app/compare/page.tsx +40 -0
  3. package/app/evals/[name]/page.tsx +22 -0
  4. package/app/evals/page.tsx +18 -0
  5. package/app/experiments/[name]/[timestamp]/page.tsx +23 -0
  6. package/app/experiments/page.tsx +28 -0
  7. package/app/globals.css +126 -0
  8. package/app/layout.tsx +102 -0
  9. package/app/page.tsx +179 -0
  10. package/app/transcript/[experiment]/[timestamp]/[evalName]/[run]/page.tsx +43 -0
  11. package/bin.mjs +86 -0
  12. package/components/ComparePage.tsx +312 -0
  13. package/components/EvalDetail.tsx +114 -0
  14. package/components/EvalsPage.tsx +80 -0
  15. package/components/ExperimentDetail.tsx +162 -0
  16. package/components/ExperimentList.tsx +103 -0
  17. package/components/O11ySummary.tsx +114 -0
  18. package/components/RunResultCard.tsx +72 -0
  19. package/components/ShowMore.tsx +60 -0
  20. package/components/TranscriptPage.tsx +46 -0
  21. package/components/TranscriptViewer.tsx +201 -0
  22. package/components/ui/alert-dialog.tsx +184 -0
  23. package/components/ui/badge.tsx +45 -0
  24. package/components/ui/button.tsx +60 -0
  25. package/components/ui/card.tsx +94 -0
  26. package/components/ui/collapsible.tsx +34 -0
  27. package/components/ui/combobox.tsx +297 -0
  28. package/components/ui/dropdown-menu.tsx +269 -0
  29. package/components/ui/field.tsx +227 -0
  30. package/components/ui/input-group.tsx +147 -0
  31. package/components/ui/input.tsx +19 -0
  32. package/components/ui/label.tsx +24 -0
  33. package/components/ui/progress.tsx +31 -0
  34. package/components/ui/scroll-area.tsx +58 -0
  35. package/components/ui/select.tsx +191 -0
  36. package/components/ui/separator.tsx +28 -0
  37. package/components/ui/table.tsx +116 -0
  38. package/components/ui/tabs.tsx +91 -0
  39. package/components/ui/textarea.tsx +18 -0
  40. package/components/ui/tooltip.tsx +57 -0
  41. package/components.json +25 -0
  42. package/lib/data.ts +297 -0
  43. package/lib/types.ts +113 -0
  44. package/lib/utils.ts +6 -0
  45. package/next.config.ts +5 -0
  46. package/package.json +51 -0
  47. package/postcss.config.mjs +7 -0
  48. package/public/vercel.svg +1 -0
  49. package/tsconfig.json +42 -0
@@ -0,0 +1,227 @@
1
+ "use client"
2
+
3
+ import { useMemo } from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "@/lib/utils"
7
+ import { Label } from "@/components/ui/label"
8
+ import { Separator } from "@/components/ui/separator"
9
+
10
+ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
11
+ return (
12
+ <fieldset
13
+ data-slot="field-set"
14
+ className={cn("gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3 flex flex-col", className)}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function FieldLegend({
21
+ className,
22
+ variant = "legend",
23
+ ...props
24
+ }: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
25
+ return (
26
+ <legend
27
+ data-slot="field-legend"
28
+ data-variant={variant}
29
+ className={cn("mb-2 font-medium data-[variant=label]:text-xs/relaxed data-[variant=legend]:text-sm", className)}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
36
+ return (
37
+ <div
38
+ data-slot="field-group"
39
+ className={cn(
40
+ "gap-4 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 group/field-group @container/field-group flex w-full flex-col",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ const fieldVariants = cva("data-[invalid=true]:text-destructive gap-2 group/field flex w-full", {
49
+ variants: {
50
+ orientation: {
51
+ vertical:
52
+ "flex-col *:w-full [&>.sr-only]:w-auto",
53
+ horizontal:
54
+ "flex-row items-center *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
55
+ responsive:
56
+ "flex-col *:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:*:data-[slot=field-label]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
57
+ },
58
+ },
59
+ defaultVariants: {
60
+ orientation: "vertical",
61
+ },
62
+ })
63
+
64
+ function Field({
65
+ className,
66
+ orientation = "vertical",
67
+ ...props
68
+ }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
69
+ return (
70
+ <div
71
+ role="group"
72
+ data-slot="field"
73
+ data-orientation={orientation}
74
+ className={cn(fieldVariants({ orientation }), className)}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
81
+ return (
82
+ <div
83
+ data-slot="field-content"
84
+ className={cn(
85
+ "gap-0.5 group/field-content flex flex-1 flex-col leading-snug",
86
+ className
87
+ )}
88
+ {...props}
89
+ />
90
+ )
91
+ }
92
+
93
+ function FieldLabel({
94
+ className,
95
+ ...props
96
+ }: React.ComponentProps<typeof Label>) {
97
+ return (
98
+ <Label
99
+ data-slot="field-label"
100
+ className={cn(
101
+ "has-data-checked:bg-primary/5 dark:has-data-checked:bg-primary/10 gap-2 group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border *:data-[slot=field]:p-2 group/field-label peer/field-label flex w-fit leading-snug",
102
+ "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
103
+ className
104
+ )}
105
+ {...props}
106
+ />
107
+ )
108
+ }
109
+
110
+ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
111
+ return (
112
+ <div
113
+ data-slot="field-label"
114
+ className={cn(
115
+ "gap-2 text-xs/relaxed font-medium group-data-[disabled=true]/field:opacity-50 flex w-fit items-center leading-snug",
116
+ className
117
+ )}
118
+ {...props}
119
+ />
120
+ )
121
+ }
122
+
123
+ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
124
+ return (
125
+ <p
126
+ data-slot="field-description"
127
+ className={cn(
128
+ "text-muted-foreground text-left text-xs/relaxed [[data-variant=legend]+&]:-mt-1.5 leading-normal font-normal group-has-data-horizontal/field:text-balance",
129
+ "last:mt-0 nth-last-2:-mt-1",
130
+ "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
131
+ className
132
+ )}
133
+ {...props}
134
+ />
135
+ )
136
+ }
137
+
138
+ function FieldSeparator({
139
+ children,
140
+ className,
141
+ ...props
142
+ }: React.ComponentProps<"div"> & {
143
+ children?: React.ReactNode
144
+ }) {
145
+ return (
146
+ <div
147
+ data-slot="field-separator"
148
+ data-content={!!children}
149
+ className={cn("-my-2 h-5 text-xs/relaxed group-data-[variant=outline]/field-group:-mb-2 relative", className)}
150
+ {...props}
151
+ >
152
+ <Separator className="absolute inset-0 top-1/2" />
153
+ {children && (
154
+ <span
155
+ className="text-muted-foreground px-2 bg-background relative mx-auto block w-fit"
156
+ data-slot="field-separator-content"
157
+ >
158
+ {children}
159
+ </span>
160
+ )}
161
+ </div>
162
+ )
163
+ }
164
+
165
+ function FieldError({
166
+ className,
167
+ children,
168
+ errors,
169
+ ...props
170
+ }: React.ComponentProps<"div"> & {
171
+ errors?: Array<{ message?: string } | undefined>
172
+ }) {
173
+ const content = useMemo(() => {
174
+ if (children) {
175
+ return children
176
+ }
177
+
178
+ if (!errors?.length) {
179
+ return null
180
+ }
181
+
182
+ const uniqueErrors = [
183
+ ...new Map(errors.map((error) => [error?.message, error])).values(),
184
+ ]
185
+
186
+ if (uniqueErrors?.length == 1) {
187
+ return uniqueErrors[0]?.message
188
+ }
189
+
190
+ return (
191
+ <ul className="ml-4 flex list-disc flex-col gap-1">
192
+ {uniqueErrors.map(
193
+ (error, index) =>
194
+ error?.message && <li key={index}>{error.message}</li>
195
+ )}
196
+ </ul>
197
+ )
198
+ }, [children, errors])
199
+
200
+ if (!content) {
201
+ return null
202
+ }
203
+
204
+ return (
205
+ <div
206
+ role="alert"
207
+ data-slot="field-error"
208
+ className={cn("text-destructive text-xs/relaxed font-normal", className)}
209
+ {...props}
210
+ >
211
+ {content}
212
+ </div>
213
+ )
214
+ }
215
+
216
+ export {
217
+ Field,
218
+ FieldLabel,
219
+ FieldDescription,
220
+ FieldError,
221
+ FieldGroup,
222
+ FieldLegend,
223
+ FieldSeparator,
224
+ FieldSet,
225
+ FieldContent,
226
+ FieldTitle,
227
+ }
@@ -0,0 +1,147 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "@/lib/utils"
7
+ import { Button } from "@/components/ui/button"
8
+ import { Input } from "@/components/ui/input"
9
+ import { Textarea } from "@/components/ui/textarea"
10
+
11
+ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
12
+ return (
13
+ <div
14
+ data-slot="input-group"
15
+ role="group"
16
+ className={cn(
17
+ "border-input bg-input/20 dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/30 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 h-7 rounded-md border transition-colors in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-data-[align=block-end]:rounded-md has-data-[align=block-start]:rounded-md has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot][aria-invalid=true]]:ring-2 has-[textarea]:rounded-md has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 group/input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto",
18
+ className
19
+ )}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+
25
+ const inputGroupAddonVariants = cva(
26
+ "text-muted-foreground **:data-[slot=kbd]:bg-muted-foreground/10 h-auto gap-1 py-2 text-xs/relaxed font-medium group-data-[disabled=true]/input-group:opacity-50 **:data-[slot=kbd]:rounded-[calc(var(--radius-sm)-2px)] **:data-[slot=kbd]:px-1 **:data-[slot=kbd]:text-[0.625rem] [&>svg:not([class*='size-'])]:size-3.5 flex cursor-text items-center justify-center select-none",
27
+ {
28
+ variants: {
29
+ align: {
30
+ "inline-start": "pl-2 has-[>button]:ml-[-0.275rem] has-[>kbd]:ml-[-0.275rem] order-first",
31
+ "inline-end": "pr-2 has-[>button]:mr-[-0.275rem] has-[>kbd]:mr-[-0.275rem] order-last",
32
+ "block-start":
33
+ "px-2 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start",
34
+ "block-end":
35
+ "px-2 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start",
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ align: "inline-start",
40
+ },
41
+ }
42
+ )
43
+
44
+ function InputGroupAddon({
45
+ className,
46
+ align = "inline-start",
47
+ ...props
48
+ }: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
49
+ return (
50
+ <div
51
+ role="group"
52
+ data-slot="input-group-addon"
53
+ data-align={align}
54
+ className={cn(inputGroupAddonVariants({ align }), className)}
55
+ onClick={(e) => {
56
+ if ((e.target as HTMLElement).closest("button")) {
57
+ return
58
+ }
59
+ e.currentTarget.parentElement?.querySelector("input")?.focus()
60
+ }}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ const inputGroupButtonVariants = cva(
67
+ "gap-2 rounded-md text-xs/relaxed shadow-none flex items-center",
68
+ {
69
+ variants: {
70
+ size: {
71
+ xs: "h-5 gap-1 rounded-[calc(var(--radius-sm)-2px)] px-1 [&>svg:not([class*='size-'])]:size-3",
72
+ sm: "",
73
+ "icon-xs": "size-6 p-0 has-[>svg]:p-0",
74
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0",
75
+ },
76
+ },
77
+ defaultVariants: {
78
+ size: "xs",
79
+ },
80
+ }
81
+ )
82
+
83
+ function InputGroupButton({
84
+ className,
85
+ type = "button",
86
+ variant = "ghost",
87
+ size = "xs",
88
+ ...props
89
+ }: Omit<React.ComponentProps<typeof Button>, "size"> &
90
+ VariantProps<typeof inputGroupButtonVariants>) {
91
+ return (
92
+ <Button
93
+ type={type}
94
+ data-size={size}
95
+ variant={variant}
96
+ className={cn(inputGroupButtonVariants({ size }), className)}
97
+ {...props}
98
+ />
99
+ )
100
+ }
101
+
102
+ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
103
+ return (
104
+ <span
105
+ className={cn(
106
+ "text-muted-foreground gap-2 text-xs/relaxed [&_svg:not([class*='size-'])]:size-4 flex items-center [&_svg]:pointer-events-none",
107
+ className
108
+ )}
109
+ {...props}
110
+ />
111
+ )
112
+ }
113
+
114
+ function InputGroupInput({
115
+ className,
116
+ ...props
117
+ }: React.ComponentProps<"input">) {
118
+ return (
119
+ <Input
120
+ data-slot="input-group-control"
121
+ className={cn("rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent flex-1", className)}
122
+ {...props}
123
+ />
124
+ )
125
+ }
126
+
127
+ function InputGroupTextarea({
128
+ className,
129
+ ...props
130
+ }: React.ComponentProps<"textarea">) {
131
+ return (
132
+ <Textarea
133
+ data-slot="input-group-control"
134
+ className={cn("rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent flex-1 resize-none", className)}
135
+ {...props}
136
+ />
137
+ )
138
+ }
139
+
140
+ export {
141
+ InputGroup,
142
+ InputGroupAddon,
143
+ InputGroupButton,
144
+ InputGroupText,
145
+ InputGroupInput,
146
+ InputGroupTextarea,
147
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
+ return (
7
+ <input
8
+ type={type}
9
+ data-slot="input"
10
+ className={cn(
11
+ "bg-input/20 dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 h-7 rounded-md border px-2 py-0.5 text-sm transition-colors file:h-6 file:text-xs/relaxed file:font-medium focus-visible:ring-2 aria-invalid:ring-2 md:text-xs/relaxed file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
12
+ className
13
+ )}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ export { Input }
@@ -0,0 +1,24 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Label as LabelPrimitive } from "radix-ui"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Label({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof LabelPrimitive.Root>) {
12
+ return (
13
+ <LabelPrimitive.Root
14
+ data-slot="label"
15
+ className={cn(
16
+ "gap-2 text-xs/relaxed leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ )
22
+ }
23
+
24
+ export { Label }
@@ -0,0 +1,31 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Progress as ProgressPrimitive } from "radix-ui"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Progress({
9
+ className,
10
+ value,
11
+ ...props
12
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
13
+ return (
14
+ <ProgressPrimitive.Root
15
+ data-slot="progress"
16
+ className={cn(
17
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ <ProgressPrimitive.Indicator
23
+ data-slot="progress-indicator"
24
+ className="bg-primary h-full w-full flex-1 transition-all"
25
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
26
+ />
27
+ </ProgressPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ export { Progress }
@@ -0,0 +1,58 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function ScrollArea({
9
+ className,
10
+ children,
11
+ ...props
12
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
13
+ return (
14
+ <ScrollAreaPrimitive.Root
15
+ data-slot="scroll-area"
16
+ className={cn("relative", className)}
17
+ {...props}
18
+ >
19
+ <ScrollAreaPrimitive.Viewport
20
+ data-slot="scroll-area-viewport"
21
+ className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
22
+ >
23
+ {children}
24
+ </ScrollAreaPrimitive.Viewport>
25
+ <ScrollBar />
26
+ <ScrollAreaPrimitive.Corner />
27
+ </ScrollAreaPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ function ScrollBar({
32
+ className,
33
+ orientation = "vertical",
34
+ ...props
35
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
36
+ return (
37
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
38
+ data-slot="scroll-area-scrollbar"
39
+ orientation={orientation}
40
+ className={cn(
41
+ "flex touch-none p-px transition-colors select-none",
42
+ orientation === "vertical" &&
43
+ "h-full w-2.5 border-l border-l-transparent",
44
+ orientation === "horizontal" &&
45
+ "h-2.5 flex-col border-t border-t-transparent",
46
+ className
47
+ )}
48
+ {...props}
49
+ >
50
+ <ScrollAreaPrimitive.ScrollAreaThumb
51
+ data-slot="scroll-area-thumb"
52
+ className="bg-border relative flex-1 rounded-full"
53
+ />
54
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
55
+ )
56
+ }
57
+
58
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1,191 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Select as SelectPrimitive } from "radix-ui"
5
+
6
+ import { cn } from "@/lib/utils"
7
+ import { RiArrowDownSLine, RiCheckLine, RiArrowUpSLine } from "@remixicon/react"
8
+
9
+ function Select({
10
+ ...props
11
+ }: React.ComponentProps<typeof SelectPrimitive.Root>) {
12
+ return <SelectPrimitive.Root data-slot="select" {...props} />
13
+ }
14
+
15
+ function SelectGroup({
16
+ className,
17
+ ...props
18
+ }: React.ComponentProps<typeof SelectPrimitive.Group>) {
19
+ return (
20
+ <SelectPrimitive.Group
21
+ data-slot="select-group"
22
+ className={cn("scroll-my-1 p-1", className)}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ function SelectValue({
29
+ ...props
30
+ }: React.ComponentProps<typeof SelectPrimitive.Value>) {
31
+ return <SelectPrimitive.Value data-slot="select-value" {...props} />
32
+ }
33
+
34
+ function SelectTrigger({
35
+ className,
36
+ size = "default",
37
+ children,
38
+ ...props
39
+ }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
40
+ size?: "sm" | "default"
41
+ }) {
42
+ return (
43
+ <SelectPrimitive.Trigger
44
+ data-slot="select-trigger"
45
+ data-size={size}
46
+ className={cn(
47
+ "cursor-pointer border-input data-placeholder:text-muted-foreground bg-input/20 dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-md border px-2 py-1.5 text-xs/relaxed transition-colors focus-visible:ring-2 aria-invalid:ring-2 data-[size=default]:h-7 data-[size=sm]:h-6 *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-3.5 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
48
+ className
49
+ )}
50
+ {...props}
51
+ >
52
+ {children}
53
+ <SelectPrimitive.Icon asChild>
54
+ <RiArrowDownSLine className="text-muted-foreground size-3.5 pointer-events-none" />
55
+ </SelectPrimitive.Icon>
56
+ </SelectPrimitive.Trigger>
57
+ )
58
+ }
59
+
60
+ function SelectContent({
61
+ className,
62
+ children,
63
+ position = "item-aligned",
64
+ align = "center",
65
+ ...props
66
+ }: React.ComponentProps<typeof SelectPrimitive.Content>) {
67
+ return (
68
+ <SelectPrimitive.Portal>
69
+ <SelectPrimitive.Content
70
+ data-slot="select-content"
71
+ data-align-trigger={position === "item-aligned"}
72
+ className={cn(
73
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 min-w-32 rounded-lg shadow-md ring-1 duration-100 dark relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
74
+ position === "popper" &&
75
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
76
+ className
77
+ )}
78
+ position={position}
79
+ align={align}
80
+ {...props}
81
+ >
82
+ <SelectScrollUpButton />
83
+ <SelectPrimitive.Viewport
84
+ data-position={position}
85
+ className={cn(
86
+ "data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)",
87
+ position === "popper" && ""
88
+ )}
89
+ >
90
+ {children}
91
+ </SelectPrimitive.Viewport>
92
+ <SelectScrollDownButton />
93
+ </SelectPrimitive.Content>
94
+ </SelectPrimitive.Portal>
95
+ )
96
+ }
97
+
98
+ function SelectLabel({
99
+ className,
100
+ ...props
101
+ }: React.ComponentProps<typeof SelectPrimitive.Label>) {
102
+ return (
103
+ <SelectPrimitive.Label
104
+ data-slot="select-label"
105
+ className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
106
+ {...props}
107
+ />
108
+ )
109
+ }
110
+
111
+ function SelectItem({
112
+ className,
113
+ children,
114
+ ...props
115
+ }: React.ComponentProps<typeof SelectPrimitive.Item>) {
116
+ return (
117
+ <SelectPrimitive.Item
118
+ data-slot="select-item"
119
+ className={cn(
120
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground min-h-7 gap-2 rounded-md px-2 py-1 text-xs/relaxed [&_svg:not([class*='size-'])]:size-3.5 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
121
+ className
122
+ )}
123
+ {...props}
124
+ >
125
+ <span className="pointer-events-none absolute right-2 flex items-center justify-center">
126
+ <SelectPrimitive.ItemIndicator>
127
+ <RiCheckLine className="pointer-events-none" />
128
+ </SelectPrimitive.ItemIndicator>
129
+ </span>
130
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
131
+ </SelectPrimitive.Item>
132
+ )
133
+ }
134
+
135
+ function SelectSeparator({
136
+ className,
137
+ ...props
138
+ }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
139
+ return (
140
+ <SelectPrimitive.Separator
141
+ data-slot="select-separator"
142
+ className={cn("bg-border/50 -mx-1 my-1 h-px pointer-events-none", className)}
143
+ {...props}
144
+ />
145
+ )
146
+ }
147
+
148
+ function SelectScrollUpButton({
149
+ className,
150
+ ...props
151
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
152
+ return (
153
+ <SelectPrimitive.ScrollUpButton
154
+ data-slot="select-scroll-up-button"
155
+ className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-3.5", className)}
156
+ {...props}
157
+ >
158
+ <RiArrowUpSLine
159
+ />
160
+ </SelectPrimitive.ScrollUpButton>
161
+ )
162
+ }
163
+
164
+ function SelectScrollDownButton({
165
+ className,
166
+ ...props
167
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
168
+ return (
169
+ <SelectPrimitive.ScrollDownButton
170
+ data-slot="select-scroll-down-button"
171
+ className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-3.5", className)}
172
+ {...props}
173
+ >
174
+ <RiArrowDownSLine
175
+ />
176
+ </SelectPrimitive.ScrollDownButton>
177
+ )
178
+ }
179
+
180
+ export {
181
+ Select,
182
+ SelectContent,
183
+ SelectGroup,
184
+ SelectItem,
185
+ SelectLabel,
186
+ SelectScrollDownButton,
187
+ SelectScrollUpButton,
188
+ SelectSeparator,
189
+ SelectTrigger,
190
+ SelectValue,
191
+ }