@beemafrica/ui 0.1.13 → 0.1.15

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beemafrica/ui",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Shared Beem UI components built on shadcn/Radix",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -24,9 +24,12 @@
24
24
  "clsx": "^2.1.1",
25
25
  "cmdk": "^1.1.1",
26
26
  "cn": "^0.2.6",
27
+ "date-fns": "^4.4.0",
27
28
  "lucide-react": "^1.31.0",
28
29
  "next-themes": "^0.4.6",
29
30
  "radix-ui": "^1.6.7",
31
+ "react-day-picker": "^10.0.1",
32
+ "recharts": "^3.8.0",
30
33
  "shadcn": "^4.16.2",
31
34
  "tailwind-merge": "^3.6.0",
32
35
  "tailwind-scrollbar": "^4.0.2",
@@ -0,0 +1,222 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import {
6
+ DayPicker,
7
+ getDefaultClassNames,
8
+ type DayButton,
9
+ type Locale,
10
+ } from "react-day-picker"
11
+
12
+ import { Button, buttonVariants } from "@beemafrica/ui/components/button"
13
+ import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"
14
+
15
+ function Calendar({
16
+ className,
17
+ classNames,
18
+ showOutsideDays = true,
19
+ captionLayout = "label",
20
+ buttonVariant = "ghost",
21
+ locale,
22
+ formatters,
23
+ components,
24
+ ...props
25
+ }: React.ComponentProps<typeof DayPicker> & {
26
+ buttonVariant?: React.ComponentProps<typeof Button>["variant"]
27
+ }) {
28
+ const defaultClassNames = getDefaultClassNames()
29
+
30
+ return (
31
+ <DayPicker
32
+ showOutsideDays={showOutsideDays}
33
+ className={cn(
34
+ "group/calendar bg-background p-2 [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
35
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
36
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
37
+ className
38
+ )}
39
+ captionLayout={captionLayout}
40
+ locale={locale}
41
+ formatters={{
42
+ formatMonthDropdown: (date) =>
43
+ date.toLocaleString(locale?.code, { month: "short" }),
44
+ ...formatters,
45
+ }}
46
+ classNames={{
47
+ root: cn("w-fit", defaultClassNames.root),
48
+ months: cn(
49
+ "relative flex flex-col gap-4 md:flex-row",
50
+ defaultClassNames.months
51
+ ),
52
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
53
+ nav: cn(
54
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
55
+ defaultClassNames.nav
56
+ ),
57
+ button_previous: cn(
58
+ buttonVariants({ variant: buttonVariant }),
59
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
60
+ defaultClassNames.button_previous
61
+ ),
62
+ button_next: cn(
63
+ buttonVariants({ variant: buttonVariant }),
64
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
65
+ defaultClassNames.button_next
66
+ ),
67
+ month_caption: cn(
68
+ "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
69
+ defaultClassNames.month_caption
70
+ ),
71
+ dropdowns: cn(
72
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
73
+ defaultClassNames.dropdowns
74
+ ),
75
+ dropdown_root: cn(
76
+ "relative rounded-(--cell-radius)",
77
+ defaultClassNames.dropdown_root
78
+ ),
79
+ dropdown: cn(
80
+ "absolute inset-0 bg-popover opacity-0",
81
+ defaultClassNames.dropdown
82
+ ),
83
+ caption_label: cn(
84
+ "font-medium select-none",
85
+ captionLayout === "label"
86
+ ? "text-sm"
87
+ : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
88
+ defaultClassNames.caption_label
89
+ ),
90
+ month_grid: cn("w-full border-collapse", defaultClassNames.month_grid),
91
+ weekdays: cn("flex", defaultClassNames.weekdays),
92
+ weekday: cn(
93
+ "flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none",
94
+ defaultClassNames.weekday
95
+ ),
96
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
97
+ week_number_header: cn(
98
+ "w-(--cell-size) select-none",
99
+ defaultClassNames.week_number_header
100
+ ),
101
+ week_number: cn(
102
+ "text-[0.8rem] text-muted-foreground select-none",
103
+ defaultClassNames.week_number
104
+ ),
105
+ day: cn(
106
+ "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-e-(--cell-radius)",
107
+ props.showWeekNumber
108
+ ? "[&:nth-child(2)[data-selected=true]_button]:rounded-s-(--cell-radius)"
109
+ : "[&:first-child[data-selected=true]_button]:rounded-s-(--cell-radius)",
110
+ defaultClassNames.day
111
+ ),
112
+ range_start: cn(
113
+ "relative isolate z-0 rounded-s-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:end-0 after:w-4 after:bg-muted",
114
+ defaultClassNames.range_start
115
+ ),
116
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
117
+ range_end: cn(
118
+ "relative isolate z-0 rounded-e-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:start-0 after:w-4 after:bg-muted",
119
+ defaultClassNames.range_end
120
+ ),
121
+ today: cn(
122
+ "rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none",
123
+ defaultClassNames.today
124
+ ),
125
+ outside: cn(
126
+ "text-muted-foreground aria-selected:text-muted-foreground",
127
+ defaultClassNames.outside
128
+ ),
129
+ disabled: cn(
130
+ "text-muted-foreground opacity-50",
131
+ defaultClassNames.disabled
132
+ ),
133
+ hidden: cn("invisible", defaultClassNames.hidden),
134
+ ...classNames,
135
+ }}
136
+ components={{
137
+ Root: ({ className, rootRef, ...props }) => {
138
+ return (
139
+ <div
140
+ data-slot="calendar"
141
+ ref={rootRef}
142
+ className={cn(className)}
143
+ {...props}
144
+ />
145
+ )
146
+ },
147
+ Chevron: ({ className, orientation, ...props }) => {
148
+ if (orientation === "left") {
149
+ return (
150
+ <ChevronLeftIcon className={cn("rtl:rotate-180 size-4", className)} {...props} />
151
+ )
152
+ }
153
+
154
+ if (orientation === "right") {
155
+ return (
156
+ <ChevronRightIcon className={cn("rtl:rotate-180 size-4", className)} {...props} />
157
+ )
158
+ }
159
+
160
+ return (
161
+ <ChevronDownIcon className={cn("size-4", className)} {...props} />
162
+ )
163
+ },
164
+ DayButton: ({ ...props }) => (
165
+ <CalendarDayButton locale={locale} {...props} />
166
+ ),
167
+ WeekNumber: ({ children, ...props }) => {
168
+ return (
169
+ <td {...props}>
170
+ <div className="flex size-(--cell-size) items-center justify-center text-center">
171
+ {children}
172
+ </div>
173
+ </td>
174
+ )
175
+ },
176
+ ...components,
177
+ }}
178
+ {...props}
179
+ />
180
+ )
181
+ }
182
+
183
+ function CalendarDayButton({
184
+ className,
185
+ day,
186
+ modifiers,
187
+ locale,
188
+ ...props
189
+ }: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
190
+ const defaultClassNames = getDefaultClassNames()
191
+
192
+ const ref = React.useRef<HTMLButtonElement>(null)
193
+ React.useEffect(() => {
194
+ if (modifiers.focused) ref.current?.focus()
195
+ }, [modifiers.focused])
196
+
197
+ return (
198
+ <Button
199
+ ref={ref}
200
+ variant="ghost"
201
+ size="icon"
202
+ data-day={day.date.toLocaleDateString(locale?.code)}
203
+ data-selected-single={
204
+ modifiers.selected &&
205
+ !modifiers.range_start &&
206
+ !modifiers.range_end &&
207
+ !modifiers.range_middle
208
+ }
209
+ data-range-start={modifiers.range_start}
210
+ data-range-end={modifiers.range_end}
211
+ data-range-middle={modifiers.range_middle}
212
+ className={cn(
213
+ "relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-e-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-s-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70",
214
+ defaultClassNames.day,
215
+ className
216
+ )}
217
+ {...props}
218
+ />
219
+ )
220
+ }
221
+
222
+ export { Calendar, CalendarDayButton }
@@ -0,0 +1,372 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import * as RechartsPrimitive from "recharts"
6
+ import type { TooltipValueType } from "recharts"
7
+
8
+ // Format: { THEME_NAME: CSS_SELECTOR }
9
+ const THEMES = { light: "", dark: ".dark" } as const
10
+
11
+ const INITIAL_DIMENSION = { width: 320, height: 200 } as const
12
+ type TooltipNameType = number | string
13
+
14
+ export type ChartConfig = Record<
15
+ string,
16
+ {
17
+ label?: React.ReactNode
18
+ icon?: React.ComponentType
19
+ } & (
20
+ | { color?: string; theme?: never }
21
+ | { color?: never; theme: Record<keyof typeof THEMES, string> }
22
+ )
23
+ >
24
+
25
+ type ChartContextProps = {
26
+ config: ChartConfig
27
+ }
28
+
29
+ const ChartContext = React.createContext<ChartContextProps | null>(null)
30
+
31
+ function useChart() {
32
+ const context = React.useContext(ChartContext)
33
+
34
+ if (!context) {
35
+ throw new Error("useChart must be used within a <ChartContainer />")
36
+ }
37
+
38
+ return context
39
+ }
40
+
41
+ function ChartContainer({
42
+ id,
43
+ className,
44
+ children,
45
+ config,
46
+ initialDimension = INITIAL_DIMENSION,
47
+ ...props
48
+ }: React.ComponentProps<"div"> & {
49
+ config: ChartConfig
50
+ children: React.ComponentProps<
51
+ typeof RechartsPrimitive.ResponsiveContainer
52
+ >["children"]
53
+ initialDimension?: {
54
+ width: number
55
+ height: number
56
+ }
57
+ }) {
58
+ const uniqueId = React.useId()
59
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`
60
+
61
+ return (
62
+ <ChartContext.Provider value={{ config }}>
63
+ <div
64
+ data-slot="chart"
65
+ data-chart={chartId}
66
+ className={cn(
67
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
68
+ className
69
+ )}
70
+ {...props}
71
+ >
72
+ <ChartStyle id={chartId} config={config} />
73
+ <RechartsPrimitive.ResponsiveContainer
74
+ initialDimension={initialDimension}
75
+ >
76
+ {children}
77
+ </RechartsPrimitive.ResponsiveContainer>
78
+ </div>
79
+ </ChartContext.Provider>
80
+ )
81
+ }
82
+
83
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
84
+ const colorConfig = Object.entries(config).filter(
85
+ ([, config]) => config.theme ?? config.color
86
+ )
87
+
88
+ if (!colorConfig.length) {
89
+ return null
90
+ }
91
+
92
+ return (
93
+ <style
94
+ dangerouslySetInnerHTML={{
95
+ __html: Object.entries(THEMES)
96
+ .map(
97
+ ([theme, prefix]) => `
98
+ ${prefix} [data-chart=${id}] {
99
+ ${colorConfig
100
+ .map(([key, itemConfig]) => {
101
+ const color =
102
+ itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ??
103
+ itemConfig.color
104
+ return color ? ` --color-${key}: ${color};` : null
105
+ })
106
+ .join("\n")}
107
+ }
108
+ `
109
+ )
110
+ .join("\n"),
111
+ }}
112
+ />
113
+ )
114
+ }
115
+
116
+ const ChartTooltip = RechartsPrimitive.Tooltip
117
+
118
+ function ChartTooltipContent({
119
+ active,
120
+ payload,
121
+ className,
122
+ indicator = "dot",
123
+ hideLabel = false,
124
+ hideIndicator = false,
125
+ label,
126
+ labelFormatter,
127
+ labelClassName,
128
+ formatter,
129
+ color,
130
+ nameKey,
131
+ labelKey,
132
+ }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
133
+ React.ComponentProps<"div"> & {
134
+ hideLabel?: boolean
135
+ hideIndicator?: boolean
136
+ indicator?: "line" | "dot" | "dashed"
137
+ nameKey?: string
138
+ labelKey?: string
139
+ } & Omit<
140
+ RechartsPrimitive.DefaultTooltipContentProps<
141
+ TooltipValueType,
142
+ TooltipNameType
143
+ >,
144
+ "accessibilityLayer"
145
+ >) {
146
+ const { config } = useChart()
147
+
148
+ const tooltipLabel = React.useMemo(() => {
149
+ if (hideLabel || !payload?.length) {
150
+ return null
151
+ }
152
+
153
+ const [item] = payload
154
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`
155
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
156
+ const value =
157
+ !labelKey && typeof label === "string"
158
+ ? (config[label]?.label ?? label)
159
+ : itemConfig?.label
160
+
161
+ if (labelFormatter) {
162
+ return (
163
+ <div className={cn("font-medium", labelClassName)}>
164
+ {labelFormatter(value, payload)}
165
+ </div>
166
+ )
167
+ }
168
+
169
+ if (!value) {
170
+ return null
171
+ }
172
+
173
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
174
+ }, [
175
+ label,
176
+ labelFormatter,
177
+ payload,
178
+ hideLabel,
179
+ labelClassName,
180
+ config,
181
+ labelKey,
182
+ ])
183
+
184
+ if (!active || !payload?.length) {
185
+ return null
186
+ }
187
+
188
+ const nestLabel = payload.length === 1 && indicator !== "dot"
189
+
190
+ return (
191
+ <div
192
+ className={cn(
193
+ "grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
194
+ className
195
+ )}
196
+ >
197
+ {!nestLabel ? tooltipLabel : null}
198
+ <div className="grid gap-1.5">
199
+ {payload
200
+ .filter((item) => item.type !== "none")
201
+ .map((item, index) => {
202
+ const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`
203
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
204
+ const indicatorColor = color ?? item.payload?.fill ?? item.color
205
+
206
+ return (
207
+ <div
208
+ key={index}
209
+ className={cn(
210
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
211
+ indicator === "dot" && "items-center"
212
+ )}
213
+ >
214
+ {formatter && item?.value !== undefined && item.name ? (
215
+ formatter(item.value, item.name, item, index, item.payload)
216
+ ) : (
217
+ <>
218
+ {itemConfig?.icon ? (
219
+ <itemConfig.icon />
220
+ ) : (
221
+ !hideIndicator && (
222
+ <div
223
+ className={cn(
224
+ "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
225
+ {
226
+ "h-2.5 w-2.5": indicator === "dot",
227
+ "w-1": indicator === "line",
228
+ "w-0 border-[1.5px] border-dashed bg-transparent":
229
+ indicator === "dashed",
230
+ "my-0.5": nestLabel && indicator === "dashed",
231
+ }
232
+ )}
233
+ style={
234
+ {
235
+ "--color-bg": indicatorColor,
236
+ "--color-border": indicatorColor,
237
+ } as React.CSSProperties
238
+ }
239
+ />
240
+ )
241
+ )}
242
+ <div
243
+ className={cn(
244
+ "flex flex-1 justify-between leading-none",
245
+ nestLabel ? "items-end" : "items-center"
246
+ )}
247
+ >
248
+ <div className="grid gap-1.5">
249
+ {nestLabel ? tooltipLabel : null}
250
+ <span className="text-muted-foreground">
251
+ {itemConfig?.label ?? item.name}
252
+ </span>
253
+ </div>
254
+ {item.value != null && (
255
+ <span className="font-mono font-medium text-foreground tabular-nums">
256
+ {typeof item.value === "number"
257
+ ? item.value.toLocaleString()
258
+ : String(item.value)}
259
+ </span>
260
+ )}
261
+ </div>
262
+ </>
263
+ )}
264
+ </div>
265
+ )
266
+ })}
267
+ </div>
268
+ </div>
269
+ )
270
+ }
271
+
272
+ const ChartLegend = RechartsPrimitive.Legend
273
+
274
+ function ChartLegendContent({
275
+ className,
276
+ hideIcon = false,
277
+ payload,
278
+ verticalAlign = "bottom",
279
+ nameKey,
280
+ }: React.ComponentProps<"div"> & {
281
+ hideIcon?: boolean
282
+ nameKey?: string
283
+ } & RechartsPrimitive.DefaultLegendContentProps) {
284
+ const { config } = useChart()
285
+
286
+ if (!payload?.length) {
287
+ return null
288
+ }
289
+
290
+ return (
291
+ <div
292
+ className={cn(
293
+ "flex items-center justify-center gap-4",
294
+ verticalAlign === "top" ? "pb-3" : "pt-3",
295
+ className
296
+ )}
297
+ >
298
+ {payload
299
+ .filter((item) => item.type !== "none")
300
+ .map((item, index) => {
301
+ const key = `${nameKey ?? item.dataKey ?? "value"}`
302
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
303
+
304
+ return (
305
+ <div
306
+ key={index}
307
+ className={cn(
308
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
309
+ )}
310
+ >
311
+ {itemConfig?.icon && !hideIcon ? (
312
+ <itemConfig.icon />
313
+ ) : (
314
+ <div
315
+ className="h-2 w-2 shrink-0 rounded-[2px]"
316
+ style={{
317
+ backgroundColor: item.color,
318
+ }}
319
+ />
320
+ )}
321
+ {itemConfig?.label}
322
+ </div>
323
+ )
324
+ })}
325
+ </div>
326
+ )
327
+ }
328
+
329
+ function getPayloadConfigFromPayload(
330
+ config: ChartConfig,
331
+ payload: unknown,
332
+ key: string
333
+ ) {
334
+ if (typeof payload !== "object" || payload === null) {
335
+ return undefined
336
+ }
337
+
338
+ const payloadPayload =
339
+ "payload" in payload &&
340
+ typeof payload.payload === "object" &&
341
+ payload.payload !== null
342
+ ? payload.payload
343
+ : undefined
344
+
345
+ let configLabelKey: string = key
346
+
347
+ if (
348
+ key in payload &&
349
+ typeof payload[key as keyof typeof payload] === "string"
350
+ ) {
351
+ configLabelKey = payload[key as keyof typeof payload] as string
352
+ } else if (
353
+ payloadPayload &&
354
+ key in payloadPayload &&
355
+ typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
356
+ ) {
357
+ configLabelKey = payloadPayload[
358
+ key as keyof typeof payloadPayload
359
+ ] as string
360
+ }
361
+
362
+ return configLabelKey in config ? config[configLabelKey] : config[key]
363
+ }
364
+
365
+ export {
366
+ ChartContainer,
367
+ ChartTooltip,
368
+ ChartTooltipContent,
369
+ ChartLegend,
370
+ ChartLegendContent,
371
+ ChartStyle,
372
+ }
@@ -0,0 +1,268 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
6
+ import { CheckIcon, ChevronRightIcon } from "lucide-react"
7
+
8
+ function DropdownMenu({
9
+ ...props
10
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
11
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
12
+ }
13
+
14
+ function DropdownMenuPortal({
15
+ ...props
16
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
17
+ return (
18
+ <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
19
+ )
20
+ }
21
+
22
+ function DropdownMenuTrigger({
23
+ ...props
24
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
25
+ return (
26
+ <DropdownMenuPrimitive.Trigger
27
+ data-slot="dropdown-menu-trigger"
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ function DropdownMenuContent({
34
+ className,
35
+ align = "start",
36
+ sideOffset = 4,
37
+ ...props
38
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39
+ return (
40
+ <DropdownMenuPrimitive.Portal>
41
+ <DropdownMenuPrimitive.Content
42
+ data-slot="dropdown-menu-content"
43
+ sideOffset={sideOffset}
44
+ align={align}
45
+ className={cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 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 data-[state=closed]:overflow-hidden 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 )}
46
+ {...props}
47
+ />
48
+ </DropdownMenuPrimitive.Portal>
49
+ )
50
+ }
51
+
52
+ function DropdownMenuGroup({
53
+ ...props
54
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
55
+ return (
56
+ <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
57
+ )
58
+ }
59
+
60
+ function DropdownMenuItem({
61
+ className,
62
+ inset,
63
+ variant = "default",
64
+ ...props
65
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
66
+ inset?: boolean
67
+ variant?: "default" | "destructive"
68
+ }) {
69
+ return (
70
+ <DropdownMenuPrimitive.Item
71
+ data-slot="dropdown-menu-item"
72
+ data-inset={inset}
73
+ data-variant={variant}
74
+ className={cn(
75
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:ps-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ function DropdownMenuCheckboxItem({
84
+ className,
85
+ children,
86
+ checked,
87
+ inset,
88
+ ...props
89
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
90
+ inset?: boolean
91
+ }) {
92
+ return (
93
+ <DropdownMenuPrimitive.CheckboxItem
94
+ data-slot="dropdown-menu-checkbox-item"
95
+ data-inset={inset}
96
+ className={cn(
97
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pe-8 ps-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:ps-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
98
+ className
99
+ )}
100
+ checked={checked}
101
+ {...props}
102
+ >
103
+ <span
104
+ className="pointer-events-none absolute end-2 flex items-center justify-center"
105
+ data-slot="dropdown-menu-checkbox-item-indicator"
106
+ >
107
+ <DropdownMenuPrimitive.ItemIndicator>
108
+ <CheckIcon
109
+ />
110
+ </DropdownMenuPrimitive.ItemIndicator>
111
+ </span>
112
+ {children}
113
+ </DropdownMenuPrimitive.CheckboxItem>
114
+ )
115
+ }
116
+
117
+ function DropdownMenuRadioGroup({
118
+ ...props
119
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
120
+ return (
121
+ <DropdownMenuPrimitive.RadioGroup
122
+ data-slot="dropdown-menu-radio-group"
123
+ {...props}
124
+ />
125
+ )
126
+ }
127
+
128
+ function DropdownMenuRadioItem({
129
+ className,
130
+ children,
131
+ inset,
132
+ ...props
133
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {
134
+ inset?: boolean
135
+ }) {
136
+ return (
137
+ <DropdownMenuPrimitive.RadioItem
138
+ data-slot="dropdown-menu-radio-item"
139
+ data-inset={inset}
140
+ className={cn(
141
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pe-8 ps-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:ps-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
142
+ className
143
+ )}
144
+ {...props}
145
+ >
146
+ <span
147
+ className="pointer-events-none absolute end-2 flex items-center justify-center"
148
+ data-slot="dropdown-menu-radio-item-indicator"
149
+ >
150
+ <DropdownMenuPrimitive.ItemIndicator>
151
+ <CheckIcon
152
+ />
153
+ </DropdownMenuPrimitive.ItemIndicator>
154
+ </span>
155
+ {children}
156
+ </DropdownMenuPrimitive.RadioItem>
157
+ )
158
+ }
159
+
160
+ function DropdownMenuLabel({
161
+ className,
162
+ inset,
163
+ ...props
164
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
165
+ inset?: boolean
166
+ }) {
167
+ return (
168
+ <DropdownMenuPrimitive.Label
169
+ data-slot="dropdown-menu-label"
170
+ data-inset={inset}
171
+ className={cn(
172
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:ps-7",
173
+ className
174
+ )}
175
+ {...props}
176
+ />
177
+ )
178
+ }
179
+
180
+ function DropdownMenuSeparator({
181
+ className,
182
+ ...props
183
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
184
+ return (
185
+ <DropdownMenuPrimitive.Separator
186
+ data-slot="dropdown-menu-separator"
187
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
188
+ {...props}
189
+ />
190
+ )
191
+ }
192
+
193
+ function DropdownMenuShortcut({
194
+ className,
195
+ ...props
196
+ }: React.ComponentProps<"span">) {
197
+ return (
198
+ <span
199
+ data-slot="dropdown-menu-shortcut"
200
+ className={cn(
201
+ "ms-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
202
+ className
203
+ )}
204
+ {...props}
205
+ />
206
+ )
207
+ }
208
+
209
+ function DropdownMenuSub({
210
+ ...props
211
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
212
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
213
+ }
214
+
215
+ function DropdownMenuSubTrigger({
216
+ className,
217
+ inset,
218
+ children,
219
+ ...props
220
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
221
+ inset?: boolean
222
+ }) {
223
+ return (
224
+ <DropdownMenuPrimitive.SubTrigger
225
+ data-slot="dropdown-menu-sub-trigger"
226
+ data-inset={inset}
227
+ className={cn(
228
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:ps-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
229
+ className
230
+ )}
231
+ {...props}
232
+ >
233
+ {children}
234
+ <ChevronRightIcon className="rtl:rotate-180 ms-auto" />
235
+ </DropdownMenuPrimitive.SubTrigger>
236
+ )
237
+ }
238
+
239
+ function DropdownMenuSubContent({
240
+ className,
241
+ ...props
242
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
243
+ return (
244
+ <DropdownMenuPrimitive.SubContent
245
+ data-slot="dropdown-menu-sub-content"
246
+ className={cn("z-50 min-w-[96px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 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 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 )}
247
+ {...props}
248
+ />
249
+ )
250
+ }
251
+
252
+ export {
253
+ DropdownMenu,
254
+ DropdownMenuPortal,
255
+ DropdownMenuTrigger,
256
+ DropdownMenuContent,
257
+ DropdownMenuGroup,
258
+ DropdownMenuLabel,
259
+ DropdownMenuItem,
260
+ DropdownMenuCheckboxItem,
261
+ DropdownMenuRadioGroup,
262
+ DropdownMenuRadioItem,
263
+ DropdownMenuSeparator,
264
+ DropdownMenuShortcut,
265
+ DropdownMenuSub,
266
+ DropdownMenuSubTrigger,
267
+ DropdownMenuSubContent,
268
+ }
@@ -0,0 +1,88 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import { Popover as PopoverPrimitive } from "radix-ui"
6
+
7
+ function Popover({
8
+ ...props
9
+ }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
10
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />
11
+ }
12
+
13
+ function PopoverTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
16
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
17
+ }
18
+
19
+ function PopoverContent({
20
+ className,
21
+ align = "center",
22
+ sideOffset = 4,
23
+ ...props
24
+ }: React.ComponentProps<typeof PopoverPrimitive.Content>) {
25
+ return (
26
+ <PopoverPrimitive.Portal>
27
+ <PopoverPrimitive.Content
28
+ data-slot="popover-content"
29
+ align={align}
30
+ sideOffset={sideOffset}
31
+ className={cn(
32
+ "z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 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 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",
33
+ className
34
+ )}
35
+ {...props}
36
+ />
37
+ </PopoverPrimitive.Portal>
38
+ )
39
+ }
40
+
41
+ function PopoverAnchor({
42
+ ...props
43
+ }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
44
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
45
+ }
46
+
47
+ function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
48
+ return (
49
+ <div
50
+ data-slot="popover-header"
51
+ className={cn("flex flex-col gap-0.5 text-sm", className)}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) {
58
+ return (
59
+ <div
60
+ data-slot="popover-title"
61
+ className={cn("font-medium", className)}
62
+ {...props}
63
+ />
64
+ )
65
+ }
66
+
67
+ function PopoverDescription({
68
+ className,
69
+ ...props
70
+ }: React.ComponentProps<"p">) {
71
+ return (
72
+ <p
73
+ data-slot="popover-description"
74
+ className={cn("text-muted-foreground", className)}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ export {
81
+ Popover,
82
+ PopoverAnchor,
83
+ PopoverContent,
84
+ PopoverDescription,
85
+ PopoverHeader,
86
+ PopoverTitle,
87
+ PopoverTrigger,
88
+ }
@@ -0,0 +1,54 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
6
+
7
+ function ScrollArea({
8
+ className,
9
+ children,
10
+ ...props
11
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
12
+ return (
13
+ <ScrollAreaPrimitive.Root
14
+ data-slot="scroll-area"
15
+ className={cn("relative", className)}
16
+ {...props}
17
+ >
18
+ <ScrollAreaPrimitive.Viewport
19
+ data-slot="scroll-area-viewport"
20
+ className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
21
+ >
22
+ {children}
23
+ </ScrollAreaPrimitive.Viewport>
24
+ <ScrollBar />
25
+ <ScrollAreaPrimitive.Corner />
26
+ </ScrollAreaPrimitive.Root>
27
+ )
28
+ }
29
+
30
+ function ScrollBar({
31
+ className,
32
+ orientation = "vertical",
33
+ ...props
34
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
35
+ return (
36
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
37
+ data-slot="scroll-area-scrollbar"
38
+ data-orientation={orientation}
39
+ orientation={orientation}
40
+ className={cn(
41
+ "flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-s data-vertical:border-s-transparent",
42
+ className
43
+ )}
44
+ {...props}
45
+ >
46
+ <ScrollAreaPrimitive.ScrollAreaThumb
47
+ data-slot="scroll-area-thumb"
48
+ className="relative flex-1 rounded-full bg-border"
49
+ />
50
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
51
+ )
52
+ }
53
+
54
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1,191 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import { Select as SelectPrimitive } from "radix-ui"
6
+ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
7
+
8
+ function Select({
9
+ ...props
10
+ }: React.ComponentProps<typeof SelectPrimitive.Root>) {
11
+ return <SelectPrimitive.Root data-slot="select" {...props} />
12
+ }
13
+
14
+ function SelectGroup({
15
+ className,
16
+ ...props
17
+ }: React.ComponentProps<typeof SelectPrimitive.Group>) {
18
+ return (
19
+ <SelectPrimitive.Group
20
+ data-slot="select-group"
21
+ className={cn("scroll-my-1 p-1", className)}
22
+ {...props}
23
+ />
24
+ )
25
+ }
26
+
27
+ function SelectValue({
28
+ ...props
29
+ }: React.ComponentProps<typeof SelectPrimitive.Value>) {
30
+ return <SelectPrimitive.Value data-slot="select-value" {...props} />
31
+ }
32
+
33
+ function SelectTrigger({
34
+ className,
35
+ size = "default",
36
+ children,
37
+ ...props
38
+ }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
39
+ size?: "sm" | "default"
40
+ }) {
41
+ return (
42
+ <SelectPrimitive.Trigger
43
+ data-slot="select-trigger"
44
+ data-size={size}
45
+ className={cn(
46
+ "flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pe-2 ps-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *: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:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
47
+ className
48
+ )}
49
+ {...props}
50
+ >
51
+ {children}
52
+ <SelectPrimitive.Icon asChild>
53
+ <ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
54
+ </SelectPrimitive.Icon>
55
+ </SelectPrimitive.Trigger>
56
+ )
57
+ }
58
+
59
+ function SelectContent({
60
+ className,
61
+ children,
62
+ position = "item-aligned",
63
+ align = "center",
64
+ ...props
65
+ }: React.ComponentProps<typeof SelectPrimitive.Content>) {
66
+ return (
67
+ <SelectPrimitive.Portal>
68
+ <SelectPrimitive.Content
69
+ data-slot="select-content"
70
+ data-align-trigger={position === "item-aligned"}
71
+ className={cn("relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none 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 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", position ==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 rtl:data-[side=left]:translate-x-1 data-[side=right]:translate-x-1 rtl:data-[side=right]:-translate-x-1 data-[side=top]:-translate-y-1", className )}
72
+ position={position}
73
+ align={align}
74
+ {...props}
75
+ >
76
+ <SelectScrollUpButton />
77
+ <SelectPrimitive.Viewport
78
+ data-position={position}
79
+ className={cn(
80
+ "data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)",
81
+ position === "popper" && ""
82
+ )}
83
+ >
84
+ {children}
85
+ </SelectPrimitive.Viewport>
86
+ <SelectScrollDownButton />
87
+ </SelectPrimitive.Content>
88
+ </SelectPrimitive.Portal>
89
+ )
90
+ }
91
+
92
+ function SelectLabel({
93
+ className,
94
+ ...props
95
+ }: React.ComponentProps<typeof SelectPrimitive.Label>) {
96
+ return (
97
+ <SelectPrimitive.Label
98
+ data-slot="select-label"
99
+ className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)}
100
+ {...props}
101
+ />
102
+ )
103
+ }
104
+
105
+ function SelectItem({
106
+ className,
107
+ children,
108
+ ...props
109
+ }: React.ComponentProps<typeof SelectPrimitive.Item>) {
110
+ return (
111
+ <SelectPrimitive.Item
112
+ data-slot="select-item"
113
+ className={cn(
114
+ "relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pe-8 ps-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground 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",
115
+ className
116
+ )}
117
+ {...props}
118
+ >
119
+ <span className="pointer-events-none absolute end-2 flex size-4 items-center justify-center">
120
+ <SelectPrimitive.ItemIndicator>
121
+ <CheckIcon className="pointer-events-none" />
122
+ </SelectPrimitive.ItemIndicator>
123
+ </span>
124
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
125
+ </SelectPrimitive.Item>
126
+ )
127
+ }
128
+
129
+ function SelectSeparator({
130
+ className,
131
+ ...props
132
+ }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
133
+ return (
134
+ <SelectPrimitive.Separator
135
+ data-slot="select-separator"
136
+ className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
137
+ {...props}
138
+ />
139
+ )
140
+ }
141
+
142
+ function SelectScrollUpButton({
143
+ className,
144
+ ...props
145
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
146
+ return (
147
+ <SelectPrimitive.ScrollUpButton
148
+ data-slot="select-scroll-up-button"
149
+ className={cn(
150
+ "z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
151
+ className
152
+ )}
153
+ {...props}
154
+ >
155
+ <ChevronUpIcon
156
+ />
157
+ </SelectPrimitive.ScrollUpButton>
158
+ )
159
+ }
160
+
161
+ function SelectScrollDownButton({
162
+ className,
163
+ ...props
164
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
165
+ return (
166
+ <SelectPrimitive.ScrollDownButton
167
+ data-slot="select-scroll-down-button"
168
+ className={cn(
169
+ "z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
170
+ className
171
+ )}
172
+ {...props}
173
+ >
174
+ <ChevronDownIcon
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
+ }
@@ -0,0 +1,13 @@
1
+ import { cn } from "cn"
2
+
3
+ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
4
+ return (
5
+ <div
6
+ data-slot="skeleton"
7
+ className={cn("animate-pulse rounded-md bg-muted", className)}
8
+ {...props}
9
+ />
10
+ )
11
+ }
12
+
13
+ export { Skeleton }
@@ -133,7 +133,7 @@ function Ticket({
133
133
  Product details
134
134
  </Button>
135
135
  </CollapsibleTrigger>
136
- <CollapsibleContent className="scrollbar scrollbar-thin scrollbar-thumb-rounded-full scrollbar-track-rounded-full flex max-h-[150px] flex-col items-start gap-2 overflow-y-auto p-2.5 pt-0 text-sm">
136
+ <CollapsibleContent className="flex max-h-[150px] flex-col items-start gap-2 overflow-y-auto p-2.5 pt-0 text-sm">
137
137
  {history.map((hs, index) => {
138
138
  return (
139
139
  // biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
@@ -0,0 +1,56 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import { Tooltip as TooltipPrimitive } from "radix-ui"
6
+
7
+ function TooltipProvider({
8
+ delayDuration = 0,
9
+ ...props
10
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
11
+ return (
12
+ <TooltipPrimitive.Provider
13
+ data-slot="tooltip-provider"
14
+ delayDuration={delayDuration}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function Tooltip({
21
+ ...props
22
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
23
+ return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
24
+ }
25
+
26
+ function TooltipTrigger({
27
+ ...props
28
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
29
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
30
+ }
31
+
32
+ function TooltipContent({
33
+ className,
34
+ sideOffset = 0,
35
+ children,
36
+ ...props
37
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
38
+ return (
39
+ <TooltipPrimitive.Portal>
40
+ <TooltipPrimitive.Content
41
+ data-slot="tooltip-content"
42
+ sideOffset={sideOffset}
43
+ className={cn(
44
+ "z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pe-1.5 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 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 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",
45
+ className
46
+ )}
47
+ {...props}
48
+ >
49
+ {children}
50
+ <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
51
+ </TooltipPrimitive.Content>
52
+ </TooltipPrimitive.Portal>
53
+ )
54
+ }
55
+
56
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }