@preset.nz/ux-kit 0.0.0-stage → 0.1.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -2
  3. package/THIRD_PARTY_NOTICES.md +253 -0
  4. package/package.json +50 -3
  5. package/src/chat/index.ts +9 -0
  6. package/src/chat/message.tsx +80 -0
  7. package/src/chat/prompt-input.tsx +121 -0
  8. package/src/chat/reasoning.tsx +182 -0
  9. package/src/chat/scroller.tsx +147 -0
  10. package/src/chat/suggestion.tsx +65 -0
  11. package/src/chat/tool.tsx +143 -0
  12. package/src/chat/types.ts +8 -0
  13. package/src/components/avatar.tsx +35 -0
  14. package/src/components/badge.tsx +40 -0
  15. package/src/components/breadcrumb.tsx +100 -0
  16. package/src/components/button.tsx +56 -0
  17. package/src/components/card.tsx +75 -0
  18. package/src/components/checkbox.tsx +25 -0
  19. package/src/components/color-field.tsx +261 -0
  20. package/src/components/color-swatch.tsx +52 -0
  21. package/src/components/context-menu.tsx +249 -0
  22. package/src/components/dialog.tsx +133 -0
  23. package/src/components/dropdown-menu.tsx +249 -0
  24. package/src/components/empty-state.tsx +35 -0
  25. package/src/components/input.tsx +20 -0
  26. package/src/components/label.tsx +19 -0
  27. package/src/components/navigation-menu.tsx +150 -0
  28. package/src/components/number-field.tsx +432 -0
  29. package/src/components/popover.tsx +75 -0
  30. package/src/components/select.tsx +189 -0
  31. package/src/components/separator.tsx +21 -0
  32. package/src/components/sheet.tsx +132 -0
  33. package/src/components/side-panel.tsx +189 -0
  34. package/src/components/sidebar.tsx +698 -0
  35. package/src/components/skeleton.tsx +14 -0
  36. package/src/components/slider.tsx +71 -0
  37. package/src/components/snackbar.tsx +143 -0
  38. package/src/components/status-bar.tsx +45 -0
  39. package/src/components/tabs.tsx +75 -0
  40. package/src/components/textarea.tsx +18 -0
  41. package/src/components/toggle-group.tsx +86 -0
  42. package/src/components/toggle.tsx +43 -0
  43. package/src/components/toolbar.tsx +304 -0
  44. package/src/components/tooltip.tsx +54 -0
  45. package/src/graphics/adsr.ts +78 -0
  46. package/src/graphics/curve-editor.tsx +567 -0
  47. package/src/graphics/curve-edits.ts +146 -0
  48. package/src/graphics/index.ts +16 -0
  49. package/src/graphics/scale.ts +25 -0
  50. package/src/graphics/use-canvas.ts +56 -0
  51. package/src/graphics/use-tokens.ts +35 -0
  52. package/src/icons.ts +3 -0
  53. package/src/index.css +199 -0
  54. package/src/index.ts +35 -0
  55. package/src/lib/use-mobile.ts +18 -0
  56. package/src/lib/utils.ts +6 -0
  57. package/src/shadcn-tailwind.css +665 -0
@@ -0,0 +1,249 @@
1
+ import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu"
2
+ import { CaretRightIcon, CheckIcon } from "@phosphor-icons/react"
3
+ import type * as React from "react"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
8
+ return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
9
+ }
10
+
11
+ function ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) {
12
+ return <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
13
+ }
14
+
15
+ function ContextMenuTrigger({ className, ...props }: ContextMenuPrimitive.Trigger.Props) {
16
+ return (
17
+ <ContextMenuPrimitive.Trigger
18
+ data-slot="context-menu-trigger"
19
+ className={cn("select-none", className)}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+
25
+ function ContextMenuContent({
26
+ align = "start",
27
+ alignOffset = 0,
28
+ side = "bottom",
29
+ sideOffset = 4,
30
+ className,
31
+ ...props
32
+ }: ContextMenuPrimitive.Popup.Props &
33
+ Pick<ContextMenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
34
+ return (
35
+ <ContextMenuPrimitive.Portal>
36
+ <ContextMenuPrimitive.Positioner
37
+ className="isolate z-50 outline-none"
38
+ align={align}
39
+ alignOffset={alignOffset}
40
+ side={side}
41
+ sideOffset={sideOffset}
42
+ >
43
+ <ContextMenuPrimitive.Popup
44
+ data-slot="context-menu-content"
45
+ className={cn(
46
+ "z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md 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=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",
47
+ className,
48
+ )}
49
+ {...props}
50
+ />
51
+ </ContextMenuPrimitive.Positioner>
52
+ </ContextMenuPrimitive.Portal>
53
+ )
54
+ }
55
+
56
+ function ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) {
57
+ return <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
58
+ }
59
+
60
+ function ContextMenuLabel({
61
+ className,
62
+ inset,
63
+ ...props
64
+ }: ContextMenuPrimitive.GroupLabel.Props & { inset?: boolean }) {
65
+ return (
66
+ <ContextMenuPrimitive.GroupLabel
67
+ data-slot="context-menu-label"
68
+ data-inset={inset}
69
+ className={cn(
70
+ "px-2 py-1.5 text-xs font-medium text-muted-foreground data-inset:pl-8",
71
+ className,
72
+ )}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function ContextMenuItem({
79
+ className,
80
+ inset,
81
+ variant = "default",
82
+ ...props
83
+ }: ContextMenuPrimitive.Item.Props & {
84
+ inset?: boolean
85
+ variant?: "default" | "destructive"
86
+ }) {
87
+ return (
88
+ <ContextMenuPrimitive.Item
89
+ data-slot="context-menu-item"
90
+ data-inset={inset}
91
+ data-variant={variant}
92
+ className={cn(
93
+ "group/context-menu-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 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",
94
+ className,
95
+ )}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ function ContextMenuSub({ ...props }: ContextMenuPrimitive.SubmenuRoot.Props) {
102
+ return <ContextMenuPrimitive.SubmenuRoot data-slot="context-menu-sub" {...props} />
103
+ }
104
+
105
+ function ContextMenuSubTrigger({
106
+ className,
107
+ inset,
108
+ children,
109
+ ...props
110
+ }: ContextMenuPrimitive.SubmenuTrigger.Props & { inset?: boolean }) {
111
+ return (
112
+ <ContextMenuPrimitive.SubmenuTrigger
113
+ data-slot="context-menu-sub-trigger"
114
+ data-inset={inset}
115
+ className={cn(
116
+ "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 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
+ <CaretRightIcon className="ml-auto" />
123
+ </ContextMenuPrimitive.SubmenuTrigger>
124
+ )
125
+ }
126
+
127
+ function ContextMenuSubContent({
128
+ align = "start",
129
+ alignOffset = -3,
130
+ side = "right",
131
+ sideOffset = 0,
132
+ className,
133
+ ...props
134
+ }: React.ComponentProps<typeof ContextMenuContent>) {
135
+ return (
136
+ <ContextMenuContent
137
+ data-slot="context-menu-sub-content"
138
+ className={cn("min-w-32 shadow-lg", className)}
139
+ align={align}
140
+ alignOffset={alignOffset}
141
+ side={side}
142
+ sideOffset={sideOffset}
143
+ {...props}
144
+ />
145
+ )
146
+ }
147
+
148
+ function ContextMenuCheckboxItem({
149
+ className,
150
+ children,
151
+ inset,
152
+ ...props
153
+ }: ContextMenuPrimitive.CheckboxItem.Props & { inset?: boolean }) {
154
+ return (
155
+ <ContextMenuPrimitive.CheckboxItem
156
+ data-slot="context-menu-checkbox-item"
157
+ data-inset={inset}
158
+ className={cn(
159
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
160
+ className,
161
+ )}
162
+ {...props}
163
+ >
164
+ <span
165
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
166
+ data-slot="context-menu-checkbox-item-indicator"
167
+ >
168
+ <ContextMenuPrimitive.CheckboxItemIndicator>
169
+ <CheckIcon />
170
+ </ContextMenuPrimitive.CheckboxItemIndicator>
171
+ </span>
172
+ {children}
173
+ </ContextMenuPrimitive.CheckboxItem>
174
+ )
175
+ }
176
+
177
+ function ContextMenuRadioGroup({ ...props }: ContextMenuPrimitive.RadioGroup.Props) {
178
+ return <ContextMenuPrimitive.RadioGroup data-slot="context-menu-radio-group" {...props} />
179
+ }
180
+
181
+ function ContextMenuRadioItem({
182
+ className,
183
+ children,
184
+ inset,
185
+ ...props
186
+ }: ContextMenuPrimitive.RadioItem.Props & { inset?: boolean }) {
187
+ return (
188
+ <ContextMenuPrimitive.RadioItem
189
+ data-slot="context-menu-radio-item"
190
+ data-inset={inset}
191
+ className={cn(
192
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
193
+ className,
194
+ )}
195
+ {...props}
196
+ >
197
+ <span
198
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
199
+ data-slot="context-menu-radio-item-indicator"
200
+ >
201
+ <ContextMenuPrimitive.RadioItemIndicator>
202
+ <CheckIcon />
203
+ </ContextMenuPrimitive.RadioItemIndicator>
204
+ </span>
205
+ {children}
206
+ </ContextMenuPrimitive.RadioItem>
207
+ )
208
+ }
209
+
210
+ function ContextMenuSeparator({ className, ...props }: ContextMenuPrimitive.Separator.Props) {
211
+ return (
212
+ <ContextMenuPrimitive.Separator
213
+ data-slot="context-menu-separator"
214
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
215
+ {...props}
216
+ />
217
+ )
218
+ }
219
+
220
+ function ContextMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
221
+ return (
222
+ <span
223
+ data-slot="context-menu-shortcut"
224
+ className={cn(
225
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground",
226
+ className,
227
+ )}
228
+ {...props}
229
+ />
230
+ )
231
+ }
232
+
233
+ export {
234
+ ContextMenu,
235
+ ContextMenuCheckboxItem,
236
+ ContextMenuContent,
237
+ ContextMenuGroup,
238
+ ContextMenuItem,
239
+ ContextMenuLabel,
240
+ ContextMenuPortal,
241
+ ContextMenuRadioGroup,
242
+ ContextMenuRadioItem,
243
+ ContextMenuSeparator,
244
+ ContextMenuShortcut,
245
+ ContextMenuSub,
246
+ ContextMenuSubContent,
247
+ ContextMenuSubTrigger,
248
+ ContextMenuTrigger,
249
+ }
@@ -0,0 +1,133 @@
1
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
2
+ import { XIcon } from "@phosphor-icons/react"
3
+ import type * as React from "react"
4
+
5
+ import { cn } from "../lib/utils"
6
+ import { Button } from "./button"
7
+
8
+ function Dialog({ ...props }: DialogPrimitive.Root.Props) {
9
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
10
+ }
11
+
12
+ function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
13
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
14
+ }
15
+
16
+ function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
17
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
18
+ }
19
+
20
+ function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
21
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
22
+ }
23
+
24
+ function DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {
25
+ return (
26
+ <DialogPrimitive.Backdrop
27
+ data-slot="dialog-overlay"
28
+ className={cn(
29
+ "fixed inset-0 isolate z-50 bg-foreground/15 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
30
+ className,
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ function DialogContent({
38
+ className,
39
+ children,
40
+ showCloseButton = true,
41
+ ...props
42
+ }: DialogPrimitive.Popup.Props & {
43
+ showCloseButton?: boolean
44
+ }) {
45
+ return (
46
+ <DialogPortal>
47
+ <DialogOverlay />
48
+ <DialogPrimitive.Popup
49
+ data-slot="dialog-content"
50
+ className={cn(
51
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl bg-popover p-6 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-md 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",
52
+ className,
53
+ )}
54
+ {...props}
55
+ >
56
+ {children}
57
+ {showCloseButton && (
58
+ <DialogPrimitive.Close
59
+ data-slot="dialog-close"
60
+ render={<Button variant="ghost" className="absolute top-4 right-4" size="icon-sm" />}
61
+ >
62
+ <XIcon />
63
+ <span className="sr-only">Close</span>
64
+ </DialogPrimitive.Close>
65
+ )}
66
+ </DialogPrimitive.Popup>
67
+ </DialogPortal>
68
+ )
69
+ }
70
+
71
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
72
+ return (
73
+ <div data-slot="dialog-header" className={cn("flex flex-col gap-2", className)} {...props} />
74
+ )
75
+ }
76
+
77
+ function DialogFooter({
78
+ className,
79
+ showCloseButton = false,
80
+ children,
81
+ ...props
82
+ }: React.ComponentProps<"div"> & {
83
+ showCloseButton?: boolean
84
+ }) {
85
+ return (
86
+ <div
87
+ data-slot="dialog-footer"
88
+ className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
89
+ {...props}
90
+ >
91
+ {children}
92
+ {showCloseButton && (
93
+ <DialogPrimitive.Close render={<Button variant="outline" />}>Close</DialogPrimitive.Close>
94
+ )}
95
+ </div>
96
+ )
97
+ }
98
+
99
+ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
100
+ return (
101
+ <DialogPrimitive.Title
102
+ data-slot="dialog-title"
103
+ className={cn("font-heading leading-none font-medium", className)}
104
+ {...props}
105
+ />
106
+ )
107
+ }
108
+
109
+ function DialogDescription({ className, ...props }: DialogPrimitive.Description.Props) {
110
+ return (
111
+ <DialogPrimitive.Description
112
+ data-slot="dialog-description"
113
+ className={cn(
114
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
115
+ className,
116
+ )}
117
+ {...props}
118
+ />
119
+ )
120
+ }
121
+
122
+ export {
123
+ Dialog,
124
+ DialogClose,
125
+ DialogContent,
126
+ DialogDescription,
127
+ DialogFooter,
128
+ DialogHeader,
129
+ DialogOverlay,
130
+ DialogPortal,
131
+ DialogTitle,
132
+ DialogTrigger,
133
+ }
@@ -0,0 +1,249 @@
1
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu"
2
+ import { CaretRightIcon, CheckIcon } from "@phosphor-icons/react"
3
+ import type * as React from "react"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
8
+ return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />
9
+ }
10
+
11
+ function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
12
+ return <MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
13
+ }
14
+
15
+ function DropdownMenuTrigger({ className, ...props }: MenuPrimitive.Trigger.Props) {
16
+ return (
17
+ <MenuPrimitive.Trigger
18
+ data-slot="dropdown-menu-trigger"
19
+ className={cn("select-none", className)}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+
25
+ function DropdownMenuContent({
26
+ align = "start",
27
+ alignOffset = 0,
28
+ side = "bottom",
29
+ sideOffset = 4,
30
+ className,
31
+ ...props
32
+ }: MenuPrimitive.Popup.Props &
33
+ Pick<MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
34
+ return (
35
+ <MenuPrimitive.Portal>
36
+ <MenuPrimitive.Positioner
37
+ className="isolate z-50 outline-none"
38
+ align={align}
39
+ alignOffset={alignOffset}
40
+ side={side}
41
+ sideOffset={sideOffset}
42
+ >
43
+ <MenuPrimitive.Popup
44
+ data-slot="dropdown-menu-content"
45
+ className={cn(
46
+ "z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md 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=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",
47
+ className,
48
+ )}
49
+ {...props}
50
+ />
51
+ </MenuPrimitive.Positioner>
52
+ </MenuPrimitive.Portal>
53
+ )
54
+ }
55
+
56
+ function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
57
+ return <MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
58
+ }
59
+
60
+ function DropdownMenuLabel({
61
+ className,
62
+ inset,
63
+ ...props
64
+ }: MenuPrimitive.GroupLabel.Props & { inset?: boolean }) {
65
+ return (
66
+ <MenuPrimitive.GroupLabel
67
+ data-slot="dropdown-menu-label"
68
+ data-inset={inset}
69
+ className={cn(
70
+ "px-2 py-1.5 text-xs font-medium text-muted-foreground data-inset:pl-8",
71
+ className,
72
+ )}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function DropdownMenuItem({
79
+ className,
80
+ inset,
81
+ variant = "default",
82
+ ...props
83
+ }: MenuPrimitive.Item.Props & {
84
+ inset?: boolean
85
+ variant?: "default" | "destructive"
86
+ }) {
87
+ return (
88
+ <MenuPrimitive.Item
89
+ data-slot="dropdown-menu-item"
90
+ data-inset={inset}
91
+ data-variant={variant}
92
+ className={cn(
93
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 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",
94
+ className,
95
+ )}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
102
+ return <MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />
103
+ }
104
+
105
+ function DropdownMenuSubTrigger({
106
+ className,
107
+ inset,
108
+ children,
109
+ ...props
110
+ }: MenuPrimitive.SubmenuTrigger.Props & { inset?: boolean }) {
111
+ return (
112
+ <MenuPrimitive.SubmenuTrigger
113
+ data-slot="dropdown-menu-sub-trigger"
114
+ data-inset={inset}
115
+ className={cn(
116
+ "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 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
+ <CaretRightIcon 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("min-w-32 shadow-lg", className)}
139
+ align={align}
140
+ alignOffset={alignOffset}
141
+ side={side}
142
+ sideOffset={sideOffset}
143
+ {...props}
144
+ />
145
+ )
146
+ }
147
+
148
+ function DropdownMenuCheckboxItem({
149
+ className,
150
+ children,
151
+ inset,
152
+ ...props
153
+ }: MenuPrimitive.CheckboxItem.Props & { inset?: boolean }) {
154
+ return (
155
+ <MenuPrimitive.CheckboxItem
156
+ data-slot="dropdown-menu-checkbox-item"
157
+ data-inset={inset}
158
+ className={cn(
159
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
160
+ className,
161
+ )}
162
+ {...props}
163
+ >
164
+ <span
165
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
166
+ data-slot="dropdown-menu-checkbox-item-indicator"
167
+ >
168
+ <MenuPrimitive.CheckboxItemIndicator>
169
+ <CheckIcon />
170
+ </MenuPrimitive.CheckboxItemIndicator>
171
+ </span>
172
+ {children}
173
+ </MenuPrimitive.CheckboxItem>
174
+ )
175
+ }
176
+
177
+ function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
178
+ return <MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
179
+ }
180
+
181
+ function DropdownMenuRadioItem({
182
+ className,
183
+ children,
184
+ inset,
185
+ ...props
186
+ }: MenuPrimitive.RadioItem.Props & { inset?: boolean }) {
187
+ return (
188
+ <MenuPrimitive.RadioItem
189
+ data-slot="dropdown-menu-radio-item"
190
+ data-inset={inset}
191
+ className={cn(
192
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-8 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
193
+ className,
194
+ )}
195
+ {...props}
196
+ >
197
+ <span
198
+ className="pointer-events-none absolute right-2 flex items-center justify-center"
199
+ data-slot="dropdown-menu-radio-item-indicator"
200
+ >
201
+ <MenuPrimitive.RadioItemIndicator>
202
+ <CheckIcon />
203
+ </MenuPrimitive.RadioItemIndicator>
204
+ </span>
205
+ {children}
206
+ </MenuPrimitive.RadioItem>
207
+ )
208
+ }
209
+
210
+ function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {
211
+ return (
212
+ <MenuPrimitive.Separator
213
+ data-slot="dropdown-menu-separator"
214
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
215
+ {...props}
216
+ />
217
+ )
218
+ }
219
+
220
+ function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
221
+ return (
222
+ <span
223
+ data-slot="dropdown-menu-shortcut"
224
+ className={cn(
225
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
226
+ className,
227
+ )}
228
+ {...props}
229
+ />
230
+ )
231
+ }
232
+
233
+ export {
234
+ DropdownMenu,
235
+ DropdownMenuCheckboxItem,
236
+ DropdownMenuContent,
237
+ DropdownMenuGroup,
238
+ DropdownMenuItem,
239
+ DropdownMenuLabel,
240
+ DropdownMenuPortal,
241
+ DropdownMenuRadioGroup,
242
+ DropdownMenuRadioItem,
243
+ DropdownMenuSeparator,
244
+ DropdownMenuShortcut,
245
+ DropdownMenuSub,
246
+ DropdownMenuSubContent,
247
+ DropdownMenuSubTrigger,
248
+ DropdownMenuTrigger,
249
+ }
@@ -0,0 +1,35 @@
1
+ import type * as React from "react"
2
+
3
+ import { cn } from "../lib/utils"
4
+
5
+ // EmptyState: what a view says when there is nothing to show: an icon, a
6
+ // title, one line of help and, if it helps, the action that fixes it.
7
+
8
+ interface EmptyStateProps extends Omit<React.ComponentProps<"div">, "title"> {
9
+ icon?: React.ReactNode
10
+ title: React.ReactNode
11
+ description?: React.ReactNode
12
+ /** Usually one Button. */
13
+ action?: React.ReactNode
14
+ }
15
+
16
+ function EmptyState({ icon, title, description, action, className, ...props }: EmptyStateProps) {
17
+ return (
18
+ <div
19
+ data-slot="empty-state"
20
+ className={cn(
21
+ "flex h-full flex-col items-center justify-center gap-2 p-8 text-center",
22
+ className,
23
+ )}
24
+ {...props}
25
+ >
26
+ {icon ? <div className="text-muted-foreground [&_svg]:size-8">{icon}</div> : null}
27
+ <p className="font-heading text-base font-medium">{title}</p>
28
+ {description ? <p className="max-w-xs text-sm text-muted-foreground">{description}</p> : null}
29
+ {action ? <div className="mt-2">{action}</div> : null}
30
+ </div>
31
+ )
32
+ }
33
+
34
+ export type { EmptyStateProps }
35
+ export { EmptyState }
@@ -0,0 +1,20 @@
1
+ import { Input as InputPrimitive } from "@base-ui/react/input"
2
+ import type * as React from "react"
3
+
4
+ import { cn } from "../lib/utils"
5
+
6
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
7
+ return (
8
+ <InputPrimitive
9
+ type={type}
10
+ data-slot="input"
11
+ className={cn(
12
+ "h-8 w-full min-w-0 rounded-none border border-input bg-transparent px-2.5 py-1 text-xs transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 md:text-xs dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
13
+ className,
14
+ )}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ export { Input }