@snapdragonsnursery/react-components 1.7.0 → 1.9.0

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.
@@ -0,0 +1,116 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ChevronsUpDown, Building2 } from "lucide-react"
5
+
6
+ import {
7
+ DropdownMenu,
8
+ DropdownMenuContent,
9
+ DropdownMenuItem,
10
+ DropdownMenuLabel,
11
+ DropdownMenuSeparator,
12
+ DropdownMenuTrigger,
13
+ } from "./ui/dropdown-menu"
14
+ import {
15
+ SidebarMenu,
16
+ SidebarMenuButton,
17
+ SidebarMenuItem,
18
+ useSidebar,
19
+ } from "./ui/sidebar"
20
+
21
+ // SiteSwitcher: shows a list of sites with custom icons; no "Add" entry.
22
+ // Props:
23
+ // - items: Array<{ id?: string, name: string, icon?: React.ComponentType<any> }>
24
+ // - activeId?: string
25
+ // - onChange?: (item) => void
26
+ // - label?: string (default: "Sites")
27
+ export function SiteSwitcher({ items = [], activeId, onChange, label = "Sites", isLoading = false }) {
28
+ const { isMobile } = useSidebar()
29
+ const initial = React.useMemo(() => {
30
+ if (!items?.length) return null
31
+ return activeId
32
+ ? items.find((i) => i.id === activeId) ?? items[0]
33
+ : items[0]
34
+ }, [items, activeId])
35
+ const [active, setActive] = React.useState(initial)
36
+
37
+ React.useEffect(() => {
38
+ if (!items?.length) return
39
+ if (activeId) {
40
+ const next = items.find((i) => i.id === activeId)
41
+ if (next && next !== active) setActive(next)
42
+ }
43
+ }, [activeId, items])
44
+
45
+ if (isLoading) {
46
+ return (
47
+ <SidebarMenu>
48
+ <SidebarMenuItem>
49
+ <SidebarMenuButton size="lg" className="opacity-60">
50
+ <div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary/60 text-sidebar-primary-foreground" />
51
+ <div className="grid flex-1 text-left text-sm leading-tight">
52
+ <span className="truncate font-semibold">Loading…</span>
53
+ <span className="truncate text-xs">{label}</span>
54
+ </div>
55
+ </SidebarMenuButton>
56
+ </SidebarMenuItem>
57
+ </SidebarMenu>
58
+ )
59
+ }
60
+
61
+ if (!active || !items?.length) return null
62
+
63
+ const ActiveIcon = active.icon || active.logo || Building2
64
+
65
+ return (
66
+ <SidebarMenu>
67
+ <SidebarMenuItem>
68
+ <DropdownMenu>
69
+ <DropdownMenuTrigger asChild>
70
+ <SidebarMenuButton
71
+ size="lg"
72
+ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
73
+ <div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
74
+ <ActiveIcon className="size-4" />
75
+ </div>
76
+ <div className="grid flex-1 text-left text-sm leading-tight">
77
+ <span className="truncate font-semibold">{active.name}</span>
78
+ <span className="truncate text-xs">{label}</span>
79
+ </div>
80
+ <ChevronsUpDown className="ml-auto" />
81
+ </SidebarMenuButton>
82
+ </DropdownMenuTrigger>
83
+ <DropdownMenuContent
84
+ className="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
85
+ align="start"
86
+ side={isMobile ? "bottom" : "right"}
87
+ sideOffset={4}>
88
+ <DropdownMenuLabel className="text-xs text-muted-foreground">
89
+ {label}
90
+ </DropdownMenuLabel>
91
+ {items.map((site) => {
92
+ const Icon = site.icon || site.logo || Building2
93
+ return (
94
+ <DropdownMenuItem
95
+ key={site.id ?? site.name}
96
+ onClick={() => {
97
+ setActive(site)
98
+ onChange?.(site)
99
+ }}
100
+ className="gap-2 p-2">
101
+ <div className="flex size-6 items-center justify-center rounded-sm border">
102
+ <Icon className="size-4 shrink-0" />
103
+ </div>
104
+ {site.name}
105
+ </DropdownMenuItem>
106
+ )
107
+ })}
108
+ <DropdownMenuSeparator />
109
+ </DropdownMenuContent>
110
+ </DropdownMenu>
111
+ </SidebarMenuItem>
112
+ </SidebarMenu>
113
+ )
114
+ }
115
+
116
+ export default SiteSwitcher
@@ -0,0 +1,83 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ChevronsUpDown, Plus } from "lucide-react"
5
+
6
+ import {
7
+ DropdownMenu,
8
+ DropdownMenuContent,
9
+ DropdownMenuItem,
10
+ DropdownMenuLabel,
11
+ DropdownMenuSeparator,
12
+ DropdownMenuShortcut,
13
+ DropdownMenuTrigger,
14
+ } from "./ui/dropdown-menu"
15
+ import {
16
+ SidebarMenu,
17
+ SidebarMenuButton,
18
+ SidebarMenuItem,
19
+ useSidebar,
20
+ } from "./ui/sidebar"
21
+
22
+ export function TeamSwitcher({
23
+ teams
24
+ }) {
25
+ const { isMobile } = useSidebar()
26
+ const [activeTeam, setActiveTeam] = React.useState(teams[0])
27
+
28
+ if (!activeTeam) {
29
+ return null
30
+ }
31
+
32
+ return (
33
+ <SidebarMenu>
34
+ <SidebarMenuItem>
35
+ <DropdownMenu>
36
+ <DropdownMenuTrigger asChild>
37
+ <SidebarMenuButton
38
+ size="lg"
39
+ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
40
+ <div
41
+ className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
42
+ <activeTeam.logo className="size-4" />
43
+ </div>
44
+ <div className="grid flex-1 text-left text-sm leading-tight">
45
+ <span className="truncate font-semibold">
46
+ {activeTeam.name}
47
+ </span>
48
+ <span className="truncate text-xs">{activeTeam.plan}</span>
49
+ </div>
50
+ <ChevronsUpDown className="ml-auto" />
51
+ </SidebarMenuButton>
52
+ </DropdownMenuTrigger>
53
+ <DropdownMenuContent
54
+ className="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
55
+ align="start"
56
+ side={isMobile ? "bottom" : "right"}
57
+ sideOffset={4}>
58
+ <DropdownMenuLabel className="text-xs text-muted-foreground">
59
+ Teams
60
+ </DropdownMenuLabel>
61
+ {teams.map((team, index) => (
62
+ <DropdownMenuItem key={team.name} onClick={() => setActiveTeam(team)} className="gap-2 p-2">
63
+ <div className="flex size-6 items-center justify-center rounded-sm border">
64
+ <team.logo className="size-4 shrink-0" />
65
+ </div>
66
+ {team.name}
67
+ <DropdownMenuShortcut>⌘{index + 1}</DropdownMenuShortcut>
68
+ </DropdownMenuItem>
69
+ ))}
70
+ <DropdownMenuSeparator />
71
+ <DropdownMenuItem className="gap-2 p-2">
72
+ <div
73
+ className="flex size-6 items-center justify-center rounded-md border bg-background">
74
+ <Plus className="size-4" />
75
+ </div>
76
+ <div className="font-medium text-muted-foreground">Add team</div>
77
+ </DropdownMenuItem>
78
+ </DropdownMenuContent>
79
+ </DropdownMenu>
80
+ </SidebarMenuItem>
81
+ </SidebarMenu>
82
+ );
83
+ }
@@ -0,0 +1,62 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Laptop, Moon, Sun } from "lucide-react"
5
+ import {
6
+ SidebarMenuButton,
7
+ } from "./ui/sidebar"
8
+
9
+ // Simple theme manager that toggles the `dark` class on <html>.
10
+ // Persists the preference to localStorage under `ui-theme`.
11
+ // Modes: 'system' | 'light' | 'dark'
12
+ const STORAGE_KEY = "ui-theme"
13
+
14
+ function applyTheme(mode) {
15
+ if (typeof document === "undefined") return
16
+ const root = document.documentElement
17
+ const mq = window.matchMedia("(prefers-color-scheme: dark)")
18
+ const isDark = mode === "dark" || (mode === "system" && mq.matches)
19
+ root.classList.toggle("dark", isDark)
20
+ }
21
+
22
+ export function ThemeModeToggle() {
23
+ const [mode, setMode] = React.useState("system")
24
+
25
+ // Initialize from storage and apply
26
+ React.useEffect(() => {
27
+ const stored = window.localStorage.getItem(STORAGE_KEY)
28
+ const initial = stored === "light" || stored === "dark" ? stored : "system"
29
+ setMode(initial)
30
+ applyTheme(initial)
31
+ }, [])
32
+
33
+ // React to OS changes when in system mode
34
+ React.useEffect(() => {
35
+ const mq = window.matchMedia("(prefers-color-scheme: dark)")
36
+ const handler = () => {
37
+ if (mode === "system") applyTheme("system")
38
+ }
39
+ mq.addEventListener("change", handler)
40
+ return () => mq.removeEventListener("change", handler)
41
+ }, [mode])
42
+
43
+ const cycle = React.useCallback(() => {
44
+ const next = mode === "system" ? "light" : mode === "light" ? "dark" : "system"
45
+ setMode(next)
46
+ window.localStorage.setItem(STORAGE_KEY, next)
47
+ applyTheme(next)
48
+ }, [mode])
49
+
50
+ const icon = mode === "system" ? <Laptop /> : mode === "light" ? <Sun /> : <Moon />
51
+ const label = mode === "system" ? "Auto" : mode === "light" ? "Light" : "Dark"
52
+
53
+ return (
54
+ <SidebarMenuButton tooltip="Theme" onClick={cycle}>
55
+ {icon}
56
+ <span>Theme: {label}</span>
57
+ </SidebarMenuButton>
58
+ )
59
+ }
60
+
61
+ export default ThemeModeToggle
62
+
@@ -0,0 +1,47 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ function Avatar({
9
+ className,
10
+ ...props
11
+ }) {
12
+ return (
13
+ <AvatarPrimitive.Root
14
+ data-slot="avatar"
15
+ className={cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className)}
16
+ {...props} />
17
+ );
18
+ }
19
+
20
+ function AvatarImage({
21
+ className,
22
+ ...props
23
+ }) {
24
+ return (
25
+ <AvatarPrimitive.Image
26
+ data-slot="avatar-image"
27
+ className={cn("aspect-square size-full", className)}
28
+ {...props} />
29
+ );
30
+ }
31
+
32
+ function AvatarFallback({
33
+ className,
34
+ ...props
35
+ }) {
36
+ return (
37
+ <AvatarPrimitive.Fallback
38
+ data-slot="avatar-fallback"
39
+ className={cn(
40
+ "bg-muted flex size-full items-center justify-center rounded-full",
41
+ className
42
+ )}
43
+ {...props} />
44
+ );
45
+ }
46
+
47
+ export { Avatar, AvatarImage, AvatarFallback }
@@ -0,0 +1,112 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { ChevronRight, MoreHorizontal } from "lucide-react"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ function Breadcrumb({
8
+ ...props
9
+ }) {
10
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
11
+ }
12
+
13
+ function BreadcrumbList({
14
+ className,
15
+ ...props
16
+ }) {
17
+ return (
18
+ <ol
19
+ data-slot="breadcrumb-list"
20
+ className={cn(
21
+ "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
22
+ className
23
+ )}
24
+ {...props} />
25
+ );
26
+ }
27
+
28
+ function BreadcrumbItem({
29
+ className,
30
+ ...props
31
+ }) {
32
+ return (
33
+ <li
34
+ data-slot="breadcrumb-item"
35
+ className={cn("inline-flex items-center gap-1.5", className)}
36
+ {...props} />
37
+ );
38
+ }
39
+
40
+ function BreadcrumbLink({
41
+ asChild,
42
+ className,
43
+ ...props
44
+ }) {
45
+ const Comp = asChild ? Slot : "a"
46
+
47
+ return (
48
+ <Comp
49
+ data-slot="breadcrumb-link"
50
+ className={cn("hover:text-foreground transition-colors", className)}
51
+ {...props} />
52
+ );
53
+ }
54
+
55
+ function BreadcrumbPage({
56
+ className,
57
+ ...props
58
+ }) {
59
+ return (
60
+ <span
61
+ data-slot="breadcrumb-page"
62
+ role="link"
63
+ aria-disabled="true"
64
+ aria-current="page"
65
+ className={cn("text-foreground font-normal", className)}
66
+ {...props} />
67
+ );
68
+ }
69
+
70
+ function BreadcrumbSeparator({
71
+ children,
72
+ className,
73
+ ...props
74
+ }) {
75
+ return (
76
+ <li
77
+ data-slot="breadcrumb-separator"
78
+ role="presentation"
79
+ aria-hidden="true"
80
+ className={cn("[&>svg]:size-3.5", className)}
81
+ {...props}>
82
+ {children ?? <ChevronRight />}
83
+ </li>
84
+ );
85
+ }
86
+
87
+ function BreadcrumbEllipsis({
88
+ className,
89
+ ...props
90
+ }) {
91
+ return (
92
+ <span
93
+ data-slot="breadcrumb-ellipsis"
94
+ role="presentation"
95
+ aria-hidden="true"
96
+ className={cn("flex size-9 items-center justify-center", className)}
97
+ {...props}>
98
+ <MoreHorizontal className="size-4" />
99
+ <span className="sr-only">More</span>
100
+ </span>
101
+ );
102
+ }
103
+
104
+ export {
105
+ Breadcrumb,
106
+ BreadcrumbList,
107
+ BreadcrumbItem,
108
+ BreadcrumbLink,
109
+ BreadcrumbPage,
110
+ BreadcrumbSeparator,
111
+ BreadcrumbEllipsis,
112
+ }
@@ -0,0 +1,23 @@
1
+ "use client"
2
+
3
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
4
+
5
+ function Collapsible({
6
+ ...props
7
+ }) {
8
+ return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
9
+ }
10
+
11
+ function CollapsibleTrigger({
12
+ ...props
13
+ }) {
14
+ return (<CollapsiblePrimitive.CollapsibleTrigger data-slot="collapsible-trigger" {...props} />);
15
+ }
16
+
17
+ function CollapsibleContent({
18
+ ...props
19
+ }) {
20
+ return (<CollapsiblePrimitive.CollapsibleContent data-slot="collapsible-content" {...props} />);
21
+ }
22
+
23
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent }
@@ -0,0 +1,221 @@
1
+ import * as React from "react"
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
3
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ function DropdownMenu({
8
+ ...props
9
+ }) {
10
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
11
+ }
12
+
13
+ function DropdownMenuPortal({
14
+ ...props
15
+ }) {
16
+ return (<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />);
17
+ }
18
+
19
+ function DropdownMenuTrigger({
20
+ ...props
21
+ }) {
22
+ return (<DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />);
23
+ }
24
+
25
+ function DropdownMenuContent({
26
+ className,
27
+ sideOffset = 4,
28
+ ...props
29
+ }) {
30
+ return (
31
+ <DropdownMenuPrimitive.Portal>
32
+ <DropdownMenuPrimitive.Content
33
+ data-slot="dropdown-menu-content"
34
+ sideOffset={sideOffset}
35
+ className={cn(
36
+ "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 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
37
+ className
38
+ )}
39
+ {...props} />
40
+ </DropdownMenuPrimitive.Portal>
41
+ );
42
+ }
43
+
44
+ function DropdownMenuGroup({
45
+ ...props
46
+ }) {
47
+ return (<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />);
48
+ }
49
+
50
+ function DropdownMenuItem({
51
+ className,
52
+ inset,
53
+ variant = "default",
54
+ ...props
55
+ }) {
56
+ return (
57
+ <DropdownMenuPrimitive.Item
58
+ data-slot="dropdown-menu-item"
59
+ data-inset={inset}
60
+ data-variant={variant}
61
+ className={cn(
62
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
63
+ className
64
+ )}
65
+ {...props} />
66
+ );
67
+ }
68
+
69
+ function DropdownMenuCheckboxItem({
70
+ className,
71
+ children,
72
+ checked,
73
+ ...props
74
+ }) {
75
+ return (
76
+ <DropdownMenuPrimitive.CheckboxItem
77
+ data-slot="dropdown-menu-checkbox-item"
78
+ className={cn(
79
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 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",
80
+ className
81
+ )}
82
+ checked={checked}
83
+ {...props}>
84
+ <span
85
+ className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
86
+ <DropdownMenuPrimitive.ItemIndicator>
87
+ <CheckIcon className="size-4" />
88
+ </DropdownMenuPrimitive.ItemIndicator>
89
+ </span>
90
+ {children}
91
+ </DropdownMenuPrimitive.CheckboxItem>
92
+ );
93
+ }
94
+
95
+ function DropdownMenuRadioGroup({
96
+ ...props
97
+ }) {
98
+ return (<DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />);
99
+ }
100
+
101
+ function DropdownMenuRadioItem({
102
+ className,
103
+ children,
104
+ ...props
105
+ }) {
106
+ return (
107
+ <DropdownMenuPrimitive.RadioItem
108
+ data-slot="dropdown-menu-radio-item"
109
+ className={cn(
110
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 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",
111
+ className
112
+ )}
113
+ {...props}>
114
+ <span
115
+ className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
116
+ <DropdownMenuPrimitive.ItemIndicator>
117
+ <CircleIcon className="size-2 fill-current" />
118
+ </DropdownMenuPrimitive.ItemIndicator>
119
+ </span>
120
+ {children}
121
+ </DropdownMenuPrimitive.RadioItem>
122
+ );
123
+ }
124
+
125
+ function DropdownMenuLabel({
126
+ className,
127
+ inset,
128
+ ...props
129
+ }) {
130
+ return (
131
+ <DropdownMenuPrimitive.Label
132
+ data-slot="dropdown-menu-label"
133
+ data-inset={inset}
134
+ className={cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className)}
135
+ {...props} />
136
+ );
137
+ }
138
+
139
+ function DropdownMenuSeparator({
140
+ className,
141
+ ...props
142
+ }) {
143
+ return (
144
+ <DropdownMenuPrimitive.Separator
145
+ data-slot="dropdown-menu-separator"
146
+ className={cn("bg-border -mx-1 my-1 h-px", className)}
147
+ {...props} />
148
+ );
149
+ }
150
+
151
+ function DropdownMenuShortcut({
152
+ className,
153
+ ...props
154
+ }) {
155
+ return (
156
+ <span
157
+ data-slot="dropdown-menu-shortcut"
158
+ className={cn("text-muted-foreground ml-auto text-xs tracking-widest", className)}
159
+ {...props} />
160
+ );
161
+ }
162
+
163
+ function DropdownMenuSub({
164
+ ...props
165
+ }) {
166
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
167
+ }
168
+
169
+ function DropdownMenuSubTrigger({
170
+ className,
171
+ inset,
172
+ children,
173
+ ...props
174
+ }) {
175
+ return (
176
+ <DropdownMenuPrimitive.SubTrigger
177
+ data-slot="dropdown-menu-sub-trigger"
178
+ data-inset={inset}
179
+ className={cn(
180
+ "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
181
+ className
182
+ )}
183
+ {...props}>
184
+ {children}
185
+ <ChevronRightIcon className="ml-auto size-4" />
186
+ </DropdownMenuPrimitive.SubTrigger>
187
+ );
188
+ }
189
+
190
+ function DropdownMenuSubContent({
191
+ className,
192
+ ...props
193
+ }) {
194
+ return (
195
+ <DropdownMenuPrimitive.SubContent
196
+ data-slot="dropdown-menu-sub-content"
197
+ className={cn(
198
+ "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 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
199
+ className
200
+ )}
201
+ {...props} />
202
+ );
203
+ }
204
+
205
+ export {
206
+ DropdownMenu,
207
+ DropdownMenuPortal,
208
+ DropdownMenuTrigger,
209
+ DropdownMenuContent,
210
+ DropdownMenuGroup,
211
+ DropdownMenuLabel,
212
+ DropdownMenuItem,
213
+ DropdownMenuCheckboxItem,
214
+ DropdownMenuRadioGroup,
215
+ DropdownMenuRadioItem,
216
+ DropdownMenuSeparator,
217
+ DropdownMenuShortcut,
218
+ DropdownMenuSub,
219
+ DropdownMenuSubTrigger,
220
+ DropdownMenuSubContent,
221
+ }
@@ -0,0 +1,25 @@
1
+ import * as React from "react"
2
+ import * as SeparatorPrimitive from "@radix-ui/react-separator"
3
+
4
+ import { cn } from "../../lib/utils"
5
+
6
+ function Separator({
7
+ className,
8
+ orientation = "horizontal",
9
+ decorative = true,
10
+ ...props
11
+ }) {
12
+ return (
13
+ <SeparatorPrimitive.Root
14
+ data-slot="separator"
15
+ decorative={decorative}
16
+ orientation={orientation}
17
+ className={cn(
18
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
19
+ className
20
+ )}
21
+ {...props} />
22
+ );
23
+ }
24
+
25
+ export { Separator }