@adea-ai/ui 0.10.8

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 (40) hide show
  1. package/README.md +5 -0
  2. package/components.json +19 -0
  3. package/package.json +56 -0
  4. package/src/components/account-drawer.tsx +133 -0
  5. package/src/components/on-screen-controls.tsx +156 -0
  6. package/src/components/prop-catalog.tsx +583 -0
  7. package/src/components/scene-settings.tsx +202 -0
  8. package/src/components/theme-provider.tsx +30 -0
  9. package/src/components/theme-toggle.tsx +73 -0
  10. package/src/components/ui/badge.tsx +49 -0
  11. package/src/components/ui/button.tsx +60 -0
  12. package/src/components/ui/card.tsx +18 -0
  13. package/src/components/ui/dialog.tsx +129 -0
  14. package/src/components/ui/drawer.tsx +209 -0
  15. package/src/components/ui/dropdown-menu.tsx +258 -0
  16. package/src/components/ui/empty.tsx +94 -0
  17. package/src/components/ui/field.tsx +224 -0
  18. package/src/components/ui/input.tsx +20 -0
  19. package/src/components/ui/label.tsx +20 -0
  20. package/src/components/ui/radio-group.tsx +38 -0
  21. package/src/components/ui/separator.tsx +21 -0
  22. package/src/components/ui/skeleton.tsx +13 -0
  23. package/src/components/ui/spinner.tsx +16 -0
  24. package/src/components/ui/switch.tsx +32 -0
  25. package/src/components/ui/tabs.tsx +75 -0
  26. package/src/components/ui/toggle-group.tsx +87 -0
  27. package/src/components/ui/toggle.tsx +45 -0
  28. package/src/components/ui/tooltip.tsx +56 -0
  29. package/src/components/version-dialog.tsx +366 -0
  30. package/src/components/workspace-brand.tsx +18 -0
  31. package/src/components/workspace-logo.tsx +17 -0
  32. package/src/index.tsx +55 -0
  33. package/src/lib/utils.ts +6 -0
  34. package/src/lib/version-notes.ts +30 -0
  35. package/src/styles/auth-shell.css +67 -0
  36. package/src/styles/conventional-workspace.css +2846 -0
  37. package/src/styles/globals.css +93 -0
  38. package/src/styles/theme.css +94 -0
  39. package/src/styles/workspace-shell.css +145 -0
  40. package/tsconfig.json +10 -0
@@ -0,0 +1,209 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Drawer as DrawerPrimitive } from "@base-ui/react/drawer";
5
+
6
+ import { cn } from "#lib/utils";
7
+
8
+ type DrawerContextProps = {
9
+ hasSnapPoints: boolean;
10
+ modal: DrawerPrimitive.Root.Props["modal"];
11
+ showSwipeHandle: boolean;
12
+ swipeDirection: NonNullable<DrawerPrimitive.Root.Props["swipeDirection"]>;
13
+ };
14
+
15
+ const DrawerContext = React.createContext<DrawerContextProps | null>(null);
16
+
17
+ function useDrawer() {
18
+ const context = React.useContext(DrawerContext);
19
+
20
+ if (!context) {
21
+ throw new Error("useDrawer must be used within a Drawer.");
22
+ }
23
+
24
+ return context;
25
+ }
26
+
27
+ function Drawer({
28
+ modal = true,
29
+ showSwipeHandle = false,
30
+ snapPoints,
31
+ swipeDirection = "down",
32
+ ...props
33
+ }: DrawerPrimitive.Root.Props & {
34
+ showSwipeHandle?: boolean;
35
+ }) {
36
+ const hasSnapPoints = snapPoints != null && snapPoints.length > 0;
37
+ const contextValue = React.useMemo(
38
+ () => ({ hasSnapPoints, modal, showSwipeHandle, swipeDirection }),
39
+ [hasSnapPoints, modal, showSwipeHandle, swipeDirection]
40
+ );
41
+
42
+ return (
43
+ <DrawerContext.Provider value={contextValue}>
44
+ <DrawerPrimitive.Root
45
+ data-slot="drawer"
46
+ modal={modal}
47
+ snapPoints={snapPoints}
48
+ swipeDirection={swipeDirection}
49
+ {...props}
50
+ />
51
+ </DrawerContext.Provider>
52
+ );
53
+ }
54
+
55
+ function DrawerTrigger({ ...props }: DrawerPrimitive.Trigger.Props) {
56
+ return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
57
+ }
58
+
59
+ function DrawerPortal({ ...props }: DrawerPrimitive.Portal.Props) {
60
+ return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
61
+ }
62
+
63
+ function DrawerClose({ ...props }: DrawerPrimitive.Close.Props) {
64
+ return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
65
+ }
66
+
67
+ function DrawerOverlay({ className, ...props }: DrawerPrimitive.Backdrop.Props) {
68
+ return (
69
+ <DrawerPrimitive.Backdrop
70
+ data-slot="drawer-overlay"
71
+ className={cn(
72
+ "fixed inset-0 z-[110] min-h-dvh bg-black/10 opacity-[max(var(--drawer-overlay-min-opacity,0),calc(1-var(--drawer-swipe-progress)))] transition-opacity duration-450 ease-[cubic-bezier(0.32,0.72,0,1)] select-none data-ending-style:pointer-events-none data-ending-style:opacity-0 data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-snap-points:[--drawer-overlay-min-opacity:0.5] data-starting-style:opacity-0 data-swiping:duration-0 supports-backdrop-filter:backdrop-blur-xs supports-[-webkit-touch-callout:none]:absolute",
73
+ className
74
+ )}
75
+ {...props}
76
+ />
77
+ );
78
+ }
79
+
80
+ function DrawerSwipeHandle({ className, ...props }: React.ComponentProps<"div">) {
81
+ return (
82
+ <div
83
+ data-slot="drawer-swipe-handle"
84
+ aria-hidden="true"
85
+ className={cn(
86
+ "relative z-10 flex shrink-0 cursor-grab transition-opacity duration-200 group-data-nested-drawer-open/drawer-popup:opacity-0 group-data-nested-drawer-swiping/drawer-popup:opacity-100 group-data-[swipe-axis=x]/drawer-popup:h-full group-data-[swipe-axis=x]/drawer-popup:w-3 group-data-[swipe-axis=x]/drawer-popup:items-center group-data-[swipe-axis=y]/drawer-popup:h-3 group-data-[swipe-axis=y]/drawer-popup:w-full group-data-[swipe-axis=y]/drawer-popup:justify-center group-data-[swipe-direction=down]/drawer-popup:items-end group-data-[swipe-direction=left]/drawer-popup:order-last group-data-[swipe-direction=left]/drawer-popup:justify-start group-data-[swipe-direction=right]/drawer-popup:justify-end group-data-[swipe-direction=up]/drawer-popup:order-last group-data-[swipe-direction=up]/drawer-popup:items-start after:block after:shrink-0 after:rounded-full after:bg-muted group-data-[swipe-axis=x]/drawer-popup:after:h-24 group-data-[swipe-axis=x]/drawer-popup:after:w-1 group-data-[swipe-axis=y]/drawer-popup:after:h-1 group-data-[swipe-axis=y]/drawer-popup:after:w-24 active:cursor-grabbing",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ );
92
+ }
93
+
94
+ function DrawerContent({ className, children, ...props }: DrawerPrimitive.Popup.Props) {
95
+ const { hasSnapPoints, modal, showSwipeHandle, swipeDirection } = useDrawer();
96
+ const swipeAxis = swipeDirection === "down" || swipeDirection === "up" ? "y" : "x";
97
+
98
+ return (
99
+ <DrawerPortal data-slot="drawer-portal">
100
+ {modal === true && <DrawerOverlay data-snap-points={hasSnapPoints ? "" : undefined} />}
101
+ <DrawerPrimitive.Viewport
102
+ data-slot="drawer-viewport"
103
+ data-modal={modal}
104
+ className="pointer-events-none fixed inset-0 z-[110] select-none data-[modal=true]:pointer-events-auto"
105
+ >
106
+ <DrawerPrimitive.Popup
107
+ data-slot="drawer-popup"
108
+ data-swipe-axis={swipeAxis}
109
+ data-snap-points={hasSnapPoints ? "" : undefined}
110
+ className={cn(
111
+ // Base.
112
+ "group/drawer-popup pointer-events-auto fixed z-[110] m-(--drawer-inset,0px) flex h-(--drawer-content-height) max-h-(--drawer-content-max-height,none) min-h-0 w-(--drawer-content-width,auto) transform-[translate3d(var(--translate-x,0px),var(--translate-y,0px),0)_scale(var(--stack-scale))] flex-col bg-popover text-sm text-popover-foreground transition-[transform,height,opacity,filter] duration-450 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform outline-none select-none [interpolate-size:allow-keywords] data-[swipe-direction=down]:rounded-t-xl data-[swipe-direction=down]:border-t data-[swipe-direction=left]:rounded-r-xl data-[swipe-direction=left]:border-r data-[swipe-direction=right]:rounded-l-xl data-[swipe-direction=right]:border-l data-[swipe-direction=up]:rounded-b-xl data-[swipe-direction=up]:border-b",
113
+ // Nested.
114
+ "data-nested-drawer-open:overflow-hidden data-nested-drawer-open:brightness-95",
115
+ // Bleed.
116
+ "after:pointer-events-none after:absolute after:bg-(--drawer-bleed-background,var(--color-popover)) data-[swipe-axis=x]:after:inset-y-0 data-[swipe-axis=x]:after:w-(--bleed) data-[swipe-axis=y]:after:inset-x-0 data-[swipe-axis=y]:after:h-(--bleed) data-[swipe-direction=down]:after:top-full data-[swipe-direction=left]:after:right-full data-[swipe-direction=right]:after:left-full data-[swipe-direction=up]:after:bottom-full",
117
+ // Sizing.
118
+ "[--drawer-content-height:var(--drawer-height,auto)] data-[swipe-axis=x]:[--drawer-content-width:75%] data-[swipe-axis=y]:[--drawer-content-max-height:calc(100dvh-6rem)] data-[swipe-axis=y]:data-snap-points:[--drawer-content-height:100dvh] data-[swipe-axis=x]:sm:[--drawer-content-width:24rem]",
119
+ // Stack.
120
+ "[--bleed:3rem] [--peek:1rem] [--stack-height:var(--drawer-frontmost-height,var(--drawer-height,0px))] [--stack-peek-offset:max(0px,calc((var(--nested-drawers)-var(--stack-progress))*var(--peek)))] [--stack-progress:clamp(0,var(--drawer-swipe-progress),1)] [--stack-scale-base:max(0,calc(1-(var(--nested-drawers)*var(--stack-step))))] [--stack-scale:clamp(0,calc(var(--stack-scale-base)+(var(--stack-step)*var(--stack-progress))),1)] [--stack-shrink:calc(1-var(--stack-scale))] [--stack-step:0.05]",
121
+ // Transitions.
122
+ "data-ending-style:transform-(--closed-transform) data-ending-style:opacity-[0.9999] data-ending-style:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-nested-drawer-swiping:duration-0 data-ending-style:data-nested-drawer-swiping:duration-[calc(var(--drawer-swipe-strength)*400ms)] data-starting-style:transform-(--closed-transform) data-swiping:duration-0 data-ending-style:data-swiping:duration-[calc(var(--drawer-swipe-strength)*400ms)]",
123
+ // Axis: y.
124
+ "data-[swipe-axis=y]:inset-x-0 data-[swipe-axis=y]:data-nested-drawer-open:h-(--stack-height)",
125
+ // Axis: x.
126
+ "data-[swipe-axis=x]:inset-y-0 data-[swipe-axis=x]:flex-row",
127
+ // Direction: down.
128
+ "data-[swipe-direction=down]:bottom-0 data-[swipe-direction=down]:origin-bottom data-[swipe-direction=down]:[--closed-transform:translate3d(0,calc(100%+var(--drawer-inset,0px)+2px),0)] data-[swipe-direction=down]:[--translate-y:calc(var(--drawer-snap-point-offset,0px)+var(--drawer-swipe-movement-y)-var(--stack-peek-offset)-(var(--stack-shrink)*var(--stack-height)))]",
129
+ // Direction: up.
130
+ "data-[swipe-direction=up]:top-0 data-[swipe-direction=up]:origin-top data-[swipe-direction=up]:[--closed-transform:translate3d(0,calc(-100%-var(--drawer-inset,0px)-2px),0)] data-[swipe-direction=up]:[--translate-y:calc(var(--drawer-snap-point-offset,0px)+var(--drawer-swipe-movement-y)+var(--stack-peek-offset)+(var(--stack-shrink)*var(--stack-height)))]",
131
+ // Direction: left.
132
+ "data-[swipe-direction=left]:left-0 data-[swipe-direction=left]:origin-left data-[swipe-direction=left]:[--closed-transform:translate3d(calc(-100%-var(--drawer-inset,0px)-2px),0,0)] data-[swipe-direction=left]:[--translate-x:calc(var(--drawer-swipe-movement-x)+var(--stack-peek-offset)+(var(--stack-shrink)*100%))]",
133
+ // Direction: right.
134
+ "data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:origin-right data-[swipe-direction=right]:[--closed-transform:translate3d(calc(100%+var(--drawer-inset,0px)+2px),0,0)] data-[swipe-direction=right]:[--translate-x:calc(var(--drawer-swipe-movement-x)-var(--stack-peek-offset)-(var(--stack-shrink)*100%))]",
135
+ className
136
+ )}
137
+ {...props}
138
+ >
139
+ {showSwipeHandle && <DrawerSwipeHandle />}
140
+ <DrawerPrimitive.Content
141
+ data-slot="drawer-content"
142
+ className={cn(
143
+ "flex min-h-0 flex-1 flex-col overflow-hidden overscroll-contain rounded-[inherit] transition-opacity duration-300 ease-[cubic-bezier(0.45,1.005,0,1.005)] select-text group-data-nested-drawer-open/drawer-popup:opacity-0 group-data-nested-drawer-swiping/drawer-popup:opacity-100 group-data-swiping/drawer-popup:select-none"
144
+ )}
145
+ >
146
+ {children}
147
+ </DrawerPrimitive.Content>
148
+ </DrawerPrimitive.Popup>
149
+ </DrawerPrimitive.Viewport>
150
+ </DrawerPortal>
151
+ );
152
+ }
153
+
154
+ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
155
+ return (
156
+ <div
157
+ data-slot="drawer-header"
158
+ className={cn(
159
+ "flex shrink-0 flex-col gap-0.5 p-4 pb-0 group-data-[swipe-axis=y]/drawer-popup:text-center md:gap-0.5 md:text-left",
160
+ className
161
+ )}
162
+ {...props}
163
+ />
164
+ );
165
+ }
166
+
167
+ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
168
+ return (
169
+ <div
170
+ data-slot="drawer-footer"
171
+ className={cn("mt-auto flex shrink-0 flex-col gap-2 p-4 pt-0", className)}
172
+ {...props}
173
+ />
174
+ );
175
+ }
176
+
177
+ function DrawerTitle({ className, ...props }: DrawerPrimitive.Title.Props) {
178
+ return (
179
+ <DrawerPrimitive.Title
180
+ data-slot="drawer-title"
181
+ className={cn("text-base font-medium text-foreground", className)}
182
+ {...props}
183
+ />
184
+ );
185
+ }
186
+
187
+ function DrawerDescription({ className, ...props }: DrawerPrimitive.Description.Props) {
188
+ return (
189
+ <DrawerPrimitive.Description
190
+ data-slot="drawer-description"
191
+ className={cn("text-sm text-balance text-muted-foreground", className)}
192
+ {...props}
193
+ />
194
+ );
195
+ }
196
+
197
+ export {
198
+ Drawer,
199
+ DrawerPortal,
200
+ DrawerOverlay,
201
+ DrawerSwipeHandle,
202
+ DrawerTrigger,
203
+ DrawerClose,
204
+ DrawerContent,
205
+ DrawerHeader,
206
+ DrawerFooter,
207
+ DrawerTitle,
208
+ DrawerDescription,
209
+ };
@@ -0,0 +1,258 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
5
+
6
+ import { cn } from "#lib/utils";
7
+ import { ChevronRightIcon, CheckIcon } from "lucide-react";
8
+
9
+ function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
10
+ return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
11
+ }
12
+
13
+ function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
14
+ return <MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
15
+ }
16
+
17
+ function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
18
+ return <MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;
19
+ }
20
+
21
+ function DropdownMenuContent({
22
+ align = "start",
23
+ alignOffset = 0,
24
+ side = "bottom",
25
+ sideOffset = 4,
26
+ className,
27
+ ...props
28
+ }: MenuPrimitive.Popup.Props &
29
+ Pick<MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
30
+ return (
31
+ <MenuPrimitive.Portal>
32
+ <MenuPrimitive.Positioner
33
+ className="isolate z-[140] outline-none"
34
+ align={align}
35
+ alignOffset={alignOffset}
36
+ side={side}
37
+ sideOffset={sideOffset}
38
+ >
39
+ <MenuPrimitive.Popup
40
+ data-slot="dropdown-menu-content"
41
+ className={cn(
42
+ "z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--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 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95",
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ </MenuPrimitive.Positioner>
48
+ </MenuPrimitive.Portal>
49
+ );
50
+ }
51
+
52
+ function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
53
+ return <MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
54
+ }
55
+
56
+ function DropdownMenuLabel({
57
+ className,
58
+ inset,
59
+ ...props
60
+ }: MenuPrimitive.GroupLabel.Props & {
61
+ inset?: boolean;
62
+ }) {
63
+ return (
64
+ <MenuPrimitive.GroupLabel
65
+ data-slot="dropdown-menu-label"
66
+ data-inset={inset}
67
+ className={cn(
68
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
69
+ className
70
+ )}
71
+ {...props}
72
+ />
73
+ );
74
+ }
75
+
76
+ function DropdownMenuItem({
77
+ className,
78
+ inset,
79
+ variant = "default",
80
+ ...props
81
+ }: MenuPrimitive.Item.Props & {
82
+ inset?: boolean;
83
+ variant?: "default" | "destructive";
84
+ }) {
85
+ return (
86
+ <MenuPrimitive.Item
87
+ data-slot="dropdown-menu-item"
88
+ data-inset={inset}
89
+ data-variant={variant}
90
+ className={cn(
91
+ "group/dropdown-menu-item relative flex cursor-pointer 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:pl-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",
92
+ className
93
+ )}
94
+ {...props}
95
+ />
96
+ );
97
+ }
98
+
99
+ function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
100
+ return <MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />;
101
+ }
102
+
103
+ function DropdownMenuSubTrigger({
104
+ className,
105
+ inset,
106
+ children,
107
+ ...props
108
+ }: MenuPrimitive.SubmenuTrigger.Props & {
109
+ inset?: boolean;
110
+ }) {
111
+ return (
112
+ <MenuPrimitive.SubmenuTrigger
113
+ data-slot="dropdown-menu-sub-trigger"
114
+ data-inset={inset}
115
+ className={cn(
116
+ "flex cursor-pointer 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:pl-7 data-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
117
+ className
118
+ )}
119
+ {...props}
120
+ >
121
+ {children}
122
+ <ChevronRightIcon className="ml-auto" />
123
+ </MenuPrimitive.SubmenuTrigger>
124
+ );
125
+ }
126
+
127
+ function DropdownMenuSubContent({
128
+ align = "start",
129
+ alignOffset = -3,
130
+ side = "right",
131
+ sideOffset = 0,
132
+ className,
133
+ ...props
134
+ }: React.ComponentProps<typeof DropdownMenuContent>) {
135
+ return (
136
+ <DropdownMenuContent
137
+ data-slot="dropdown-menu-sub-content"
138
+ className={cn(
139
+ "w-auto min-w-[96px] 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",
140
+ className
141
+ )}
142
+ align={align}
143
+ alignOffset={alignOffset}
144
+ side={side}
145
+ sideOffset={sideOffset}
146
+ {...props}
147
+ />
148
+ );
149
+ }
150
+
151
+ function DropdownMenuCheckboxItem({
152
+ className,
153
+ children,
154
+ checked,
155
+ inset,
156
+ ...props
157
+ }: MenuPrimitive.CheckboxItem.Props & {
158
+ inset?: boolean;
159
+ }) {
160
+ return (
161
+ <MenuPrimitive.CheckboxItem
162
+ data-slot="dropdown-menu-checkbox-item"
163
+ data-inset={inset}
164
+ className={cn(
165
+ "relative flex cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
166
+ className
167
+ )}
168
+ checked={checked}
169
+ {...props}
170
+ >
171
+ <span
172
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
173
+ data-slot="dropdown-menu-checkbox-item-indicator"
174
+ >
175
+ <MenuPrimitive.CheckboxItemIndicator>
176
+ <CheckIcon />
177
+ </MenuPrimitive.CheckboxItemIndicator>
178
+ </span>
179
+ {children}
180
+ </MenuPrimitive.CheckboxItem>
181
+ );
182
+ }
183
+
184
+ function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
185
+ return <MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
186
+ }
187
+
188
+ function DropdownMenuRadioItem({
189
+ className,
190
+ children,
191
+ inset,
192
+ ...props
193
+ }: MenuPrimitive.RadioItem.Props & {
194
+ inset?: boolean;
195
+ }) {
196
+ return (
197
+ <MenuPrimitive.RadioItem
198
+ data-slot="dropdown-menu-radio-item"
199
+ data-inset={inset}
200
+ className={cn(
201
+ "relative flex cursor-pointer items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
202
+ className
203
+ )}
204
+ {...props}
205
+ >
206
+ <span
207
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
208
+ data-slot="dropdown-menu-radio-item-indicator"
209
+ >
210
+ <MenuPrimitive.RadioItemIndicator>
211
+ <CheckIcon />
212
+ </MenuPrimitive.RadioItemIndicator>
213
+ </span>
214
+ {children}
215
+ </MenuPrimitive.RadioItem>
216
+ );
217
+ }
218
+
219
+ function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {
220
+ return (
221
+ <MenuPrimitive.Separator
222
+ data-slot="dropdown-menu-separator"
223
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
224
+ {...props}
225
+ />
226
+ );
227
+ }
228
+
229
+ function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
230
+ return (
231
+ <span
232
+ data-slot="dropdown-menu-shortcut"
233
+ className={cn(
234
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
235
+ className
236
+ )}
237
+ {...props}
238
+ />
239
+ );
240
+ }
241
+
242
+ export {
243
+ DropdownMenu,
244
+ DropdownMenuPortal,
245
+ DropdownMenuTrigger,
246
+ DropdownMenuContent,
247
+ DropdownMenuGroup,
248
+ DropdownMenuLabel,
249
+ DropdownMenuItem,
250
+ DropdownMenuCheckboxItem,
251
+ DropdownMenuRadioGroup,
252
+ DropdownMenuRadioItem,
253
+ DropdownMenuSeparator,
254
+ DropdownMenuShortcut,
255
+ DropdownMenuSub,
256
+ DropdownMenuSubTrigger,
257
+ DropdownMenuSubContent,
258
+ };
@@ -0,0 +1,94 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+
3
+ import { cn } from "#lib/utils";
4
+
5
+ function Empty({ className, ...props }: React.ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="empty"
9
+ className={cn(
10
+ "flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 rounded-xl border-dashed p-6 text-center text-balance",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) {
19
+ return (
20
+ <div
21
+ data-slot="empty-header"
22
+ className={cn("flex max-w-sm flex-col items-center gap-2", className)}
23
+ {...props}
24
+ />
25
+ );
26
+ }
27
+
28
+ const emptyMediaVariants = cva(
29
+ "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
30
+ {
31
+ variants: {
32
+ variant: {
33
+ default: "bg-transparent",
34
+ icon: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-4",
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ variant: "default",
39
+ },
40
+ }
41
+ );
42
+
43
+ function EmptyMedia({
44
+ className,
45
+ variant = "default",
46
+ ...props
47
+ }: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>) {
48
+ return (
49
+ <div
50
+ data-slot="empty-icon"
51
+ data-variant={variant}
52
+ className={cn(emptyMediaVariants({ variant, className }))}
53
+ {...props}
54
+ />
55
+ );
56
+ }
57
+
58
+ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
59
+ return (
60
+ <div
61
+ data-slot="empty-title"
62
+ className={cn("text-sm font-medium tracking-tight", className)}
63
+ {...props}
64
+ />
65
+ );
66
+ }
67
+
68
+ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
69
+ return (
70
+ <div
71
+ data-slot="empty-description"
72
+ className={cn(
73
+ "text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
74
+ className
75
+ )}
76
+ {...props}
77
+ />
78
+ );
79
+ }
80
+
81
+ function EmptyContent({ className, ...props }: React.ComponentProps<"div">) {
82
+ return (
83
+ <div
84
+ data-slot="empty-content"
85
+ className={cn(
86
+ "flex w-full max-w-sm min-w-0 flex-col items-center gap-2.5 text-sm text-balance",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ );
92
+ }
93
+
94
+ export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia };