@voila.dev/ui 1.1.9

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 (99) hide show
  1. package/package.json +78 -0
  2. package/src/components/ui/accordion.tsx +79 -0
  3. package/src/components/ui/alert-dialog.tsx +198 -0
  4. package/src/components/ui/alert.tsx +105 -0
  5. package/src/components/ui/aspect-ratio.tsx +30 -0
  6. package/src/components/ui/avatar.tsx +125 -0
  7. package/src/components/ui/badge-variants.ts +166 -0
  8. package/src/components/ui/badge.tsx +45 -0
  9. package/src/components/ui/banner.tsx +84 -0
  10. package/src/components/ui/breadcrumb.tsx +127 -0
  11. package/src/components/ui/button-group.tsx +99 -0
  12. package/src/components/ui/button-variants.ts +108 -0
  13. package/src/components/ui/button.tsx +54 -0
  14. package/src/components/ui/calendar.tsx +266 -0
  15. package/src/components/ui/card.tsx +155 -0
  16. package/src/components/ui/carousel.tsx +319 -0
  17. package/src/components/ui/chat.tsx +896 -0
  18. package/src/components/ui/checkbox-group.tsx +44 -0
  19. package/src/components/ui/checkbox.tsx +34 -0
  20. package/src/components/ui/chip.tsx +60 -0
  21. package/src/components/ui/collapsible.tsx +44 -0
  22. package/src/components/ui/color-picker.tsx +191 -0
  23. package/src/components/ui/combobox.tsx +317 -0
  24. package/src/components/ui/command.tsx +187 -0
  25. package/src/components/ui/confirm-dialog.tsx +125 -0
  26. package/src/components/ui/context-menu.tsx +254 -0
  27. package/src/components/ui/copyable-text.tsx +65 -0
  28. package/src/components/ui/date-picker.tsx +316 -0
  29. package/src/components/ui/date-time-picker.tsx +1071 -0
  30. package/src/components/ui/dialog.tsx +176 -0
  31. package/src/components/ui/direction.tsx +15 -0
  32. package/src/components/ui/drawer.tsx +178 -0
  33. package/src/components/ui/dropdown-menu.tsx +247 -0
  34. package/src/components/ui/empty.tsx +131 -0
  35. package/src/components/ui/field.tsx +257 -0
  36. package/src/components/ui/formatted-input.tsx +219 -0
  37. package/src/components/ui/gallery.tsx +161 -0
  38. package/src/components/ui/hover-card.tsx +77 -0
  39. package/src/components/ui/icon-picker.tsx +193 -0
  40. package/src/components/ui/image-cropper.tsx +787 -0
  41. package/src/components/ui/image-upload-field.tsx +344 -0
  42. package/src/components/ui/input-group.tsx +175 -0
  43. package/src/components/ui/input-otp.tsx +83 -0
  44. package/src/components/ui/input.tsx +21 -0
  45. package/src/components/ui/item.tsx +212 -0
  46. package/src/components/ui/kbd.tsx +62 -0
  47. package/src/components/ui/label.tsx +19 -0
  48. package/src/components/ui/list.tsx +46 -0
  49. package/src/components/ui/menu-variants.ts +71 -0
  50. package/src/components/ui/menubar.tsx +226 -0
  51. package/src/components/ui/money-input.tsx +96 -0
  52. package/src/components/ui/native-date-picker.tsx +120 -0
  53. package/src/components/ui/native-select.tsx +74 -0
  54. package/src/components/ui/navigation-menu.tsx +183 -0
  55. package/src/components/ui/pagination.tsx +150 -0
  56. package/src/components/ui/popover.tsx +104 -0
  57. package/src/components/ui/profile-header.tsx +196 -0
  58. package/src/components/ui/progress.tsx +71 -0
  59. package/src/components/ui/radio-group.tsx +115 -0
  60. package/src/components/ui/rating.tsx +200 -0
  61. package/src/components/ui/resizable.tsx +61 -0
  62. package/src/components/ui/responsive-dialog.tsx +278 -0
  63. package/src/components/ui/responsive-select.tsx +289 -0
  64. package/src/components/ui/responsive-sheet.tsx +225 -0
  65. package/src/components/ui/scroll-area.tsx +51 -0
  66. package/src/components/ui/section.tsx +106 -0
  67. package/src/components/ui/segmented-control.tsx +148 -0
  68. package/src/components/ui/select.tsx +216 -0
  69. package/src/components/ui/separator.tsx +69 -0
  70. package/src/components/ui/sheet.tsx +154 -0
  71. package/src/components/ui/shortcut.tsx +41 -0
  72. package/src/components/ui/sidebar.tsx +739 -0
  73. package/src/components/ui/skeleton.tsx +23 -0
  74. package/src/components/ui/slider.tsx +74 -0
  75. package/src/components/ui/sonner.tsx +64 -0
  76. package/src/components/ui/spinner.tsx +19 -0
  77. package/src/components/ui/stat-card.tsx +138 -0
  78. package/src/components/ui/stepper.tsx +181 -0
  79. package/src/components/ui/sticky-action-bar.tsx +42 -0
  80. package/src/components/ui/switch.tsx +30 -0
  81. package/src/components/ui/table.tsx +132 -0
  82. package/src/components/ui/tabs.tsx +77 -0
  83. package/src/components/ui/textarea.tsx +24 -0
  84. package/src/components/ui/time-picker.tsx +221 -0
  85. package/src/components/ui/toggle-group.tsx +86 -0
  86. package/src/components/ui/toggle.tsx +43 -0
  87. package/src/components/ui/tooltip.tsx +79 -0
  88. package/src/components/ui/translation-input.tsx +126 -0
  89. package/src/components/ui/user-avatar.tsx +74 -0
  90. package/src/css-modules.d.ts +4 -0
  91. package/src/hooks/use-command-palette.ts +28 -0
  92. package/src/hooks/use-mobile.ts +21 -0
  93. package/src/hooks/use-pagination.ts +81 -0
  94. package/src/hooks/use-picker-state.ts +44 -0
  95. package/src/lib/cva.ts +18 -0
  96. package/src/lib/time-math.ts +62 -0
  97. package/src/lib/utils.ts +14 -0
  98. package/src/styles/globals.css +36 -0
  99. package/src/styles.css +10 -0
@@ -0,0 +1,212 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import type * as React from "react";
4
+ import { Separator } from "#/components/ui/separator.tsx";
5
+ import { cva, type VariantProps } from "#/lib/cva.ts";
6
+ import { cn } from "#/lib/utils.ts";
7
+
8
+ function ItemGroup({
9
+ className,
10
+ render,
11
+ ...props
12
+ }: useRender.ComponentProps<"div">) {
13
+ return useRender({
14
+ defaultTagName: "div",
15
+ props: mergeProps<"div">(
16
+ {
17
+ className: cn(
18
+ "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
19
+ className,
20
+ ),
21
+ },
22
+ props,
23
+ ),
24
+ render,
25
+ state: {
26
+ slot: "item-group",
27
+ },
28
+ });
29
+ }
30
+
31
+ function ItemSeparator({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof Separator>) {
35
+ return (
36
+ <Separator
37
+ data-slot="item-separator"
38
+ orientation="horizontal"
39
+ className={cn("my-2", className)}
40
+ {...props}
41
+ />
42
+ );
43
+ }
44
+
45
+ const itemVariants = cva({
46
+ base: "group/item flex w-full flex-wrap items-center rounded-lg border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
47
+ variants: {
48
+ variant: {
49
+ default: "border-transparent",
50
+ outline: "border-border",
51
+ muted: "border-transparent bg-muted/50",
52
+ },
53
+ size: {
54
+ default: "gap-2.5 px-3 py-2.5",
55
+ sm: "gap-2.5 px-3 py-2",
56
+ xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0",
57
+ },
58
+ },
59
+ defaultVariants: {
60
+ variant: "default",
61
+ size: "default",
62
+ },
63
+ });
64
+
65
+ function Item({
66
+ className,
67
+ variant = "default",
68
+ size = "default",
69
+ render,
70
+ ...props
71
+ }: useRender.ComponentProps<"div"> & VariantProps<typeof itemVariants>) {
72
+ return useRender({
73
+ defaultTagName: "div",
74
+ props: mergeProps<"div">(
75
+ {
76
+ className: cn(itemVariants({ variant, size }), className),
77
+ },
78
+ props,
79
+ ),
80
+ render,
81
+ state: {
82
+ slot: "item",
83
+ variant,
84
+ size,
85
+ },
86
+ });
87
+ }
88
+
89
+ const itemMediaVariants = cva({
90
+ base: "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
91
+ variants: {
92
+ variant: {
93
+ default: "bg-transparent",
94
+ icon: "[&_svg:not([class*='size-'])]:size-4",
95
+ image:
96
+ "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover",
97
+ },
98
+ },
99
+ defaultVariants: {
100
+ variant: "default",
101
+ },
102
+ });
103
+
104
+ function ItemMedia({
105
+ className,
106
+ variant = "default",
107
+ render,
108
+ ...props
109
+ }: useRender.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
110
+ return useRender({
111
+ defaultTagName: "div",
112
+ props: mergeProps<"div">(
113
+ {
114
+ className: cn(itemMediaVariants({ variant }), className),
115
+ },
116
+ props,
117
+ ),
118
+ render,
119
+ state: {
120
+ slot: "item-media",
121
+ variant,
122
+ },
123
+ });
124
+ }
125
+
126
+ function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
127
+ return (
128
+ <div
129
+ data-slot="item-content"
130
+ className={cn(
131
+ "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
132
+ className,
133
+ )}
134
+ {...props}
135
+ />
136
+ );
137
+ }
138
+
139
+ function ItemTitle({ className, ...props }: React.ComponentProps<"span">) {
140
+ return (
141
+ <span
142
+ data-slot="item-title"
143
+ className={cn(
144
+ "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
145
+ className,
146
+ )}
147
+ {...props}
148
+ />
149
+ );
150
+ }
151
+
152
+ function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
153
+ return (
154
+ <p
155
+ data-slot="item-description"
156
+ className={cn(
157
+ "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
158
+ className,
159
+ )}
160
+ {...props}
161
+ />
162
+ );
163
+ }
164
+
165
+ function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
166
+ return (
167
+ <div
168
+ data-slot="item-actions"
169
+ className={cn("flex items-center gap-2", className)}
170
+ {...props}
171
+ />
172
+ );
173
+ }
174
+
175
+ function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
176
+ return (
177
+ <div
178
+ data-slot="item-header"
179
+ className={cn(
180
+ "flex basis-full items-center justify-between gap-2",
181
+ className,
182
+ )}
183
+ {...props}
184
+ />
185
+ );
186
+ }
187
+
188
+ function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
189
+ return (
190
+ <div
191
+ data-slot="item-footer"
192
+ className={cn(
193
+ "flex basis-full items-center justify-between gap-2",
194
+ className,
195
+ )}
196
+ {...props}
197
+ />
198
+ );
199
+ }
200
+
201
+ export {
202
+ Item,
203
+ ItemActions,
204
+ ItemContent,
205
+ ItemDescription,
206
+ ItemFooter,
207
+ ItemGroup,
208
+ ItemHeader,
209
+ ItemMedia,
210
+ ItemSeparator,
211
+ ItemTitle,
212
+ };
@@ -0,0 +1,62 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "#/lib/cva.ts";
3
+ import { cn } from "#/lib/utils.ts";
4
+
5
+ const kbdVariants = cva({
6
+ base: "pointer-events-none inline-flex w-fit items-center justify-center rounded-sm bg-muted font-sans font-medium text-muted-foreground select-none in-data-[slot=input-group-addon]:rounded-[calc(var(--radius)-5px)] in-data-[slot=tooltip-content]:bg-background/20 in-data-[slot=tooltip-content]:text-background dark:in-data-[slot=tooltip-content]:bg-background/10",
7
+ variants: {
8
+ size: {
9
+ default:
10
+ "h-5 min-w-5 gap-1 px-1 text-xs [&_svg:not([class*='size-'])]:size-3",
11
+ sm: "h-4 min-w-4 gap-0.5 px-0.5 text-[10px] [&_svg:not([class*='size-'])]:size-2.5",
12
+ },
13
+ },
14
+ });
15
+
16
+ function Kbd({
17
+ className,
18
+ size = "default",
19
+ ...props
20
+ }: React.ComponentProps<"kbd"> & VariantProps<typeof kbdVariants>) {
21
+ return (
22
+ <kbd
23
+ data-slot="kbd"
24
+ data-size={size}
25
+ className={cn(kbdVariants({ size }), className)}
26
+ {...props}
27
+ />
28
+ );
29
+ }
30
+
31
+ function KbdGroup({
32
+ className,
33
+ separator,
34
+ children,
35
+ ...props
36
+ }: React.ComponentProps<"kbd"> & { separator?: React.ReactNode }) {
37
+ return (
38
+ <kbd
39
+ data-slot="kbd-group"
40
+ className={cn(
41
+ "inline-flex items-center gap-1 text-muted-foreground",
42
+ className,
43
+ )}
44
+ {...props}
45
+ >
46
+ {separator === undefined
47
+ ? children
48
+ : React.Children.toArray(children).map((child, index) => (
49
+ <React.Fragment key={index}>
50
+ {index > 0 && (
51
+ <span aria-hidden="true" data-slot="kbd-separator">
52
+ {separator}
53
+ </span>
54
+ )}
55
+ {child}
56
+ </React.Fragment>
57
+ ))}
58
+ </kbd>
59
+ );
60
+ }
61
+
62
+ export { Kbd, KbdGroup };
@@ -0,0 +1,19 @@
1
+ import type * as React from "react";
2
+
3
+ import { cn } from "#/lib/utils.ts";
4
+
5
+ function Label({ className, ...props }: React.ComponentProps<"label">) {
6
+ return (
7
+ // biome-ignore lint/a11y/noLabelWithoutControl: This component is meant to be used as a wrapper for form controls, so it may not always have a control associated with it.
8
+ <label
9
+ data-slot="label"
10
+ className={cn(
11
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50 peer-data-disabled:cursor-not-allowed peer-data-disabled:opacity-50",
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ export { Label };
@@ -0,0 +1,46 @@
1
+ import type * as React from "react";
2
+
3
+ import { Item, ItemGroup, ItemSeparator } from "#/components/ui/item.tsx";
4
+ import { cn } from "#/lib/utils.ts";
5
+
6
+ /**
7
+ * Semantic `ul`/`li` counterparts of `ItemGroup`/`Item`: same styling and
8
+ * variants, but screen readers announce the collection and its size. The
9
+ * explicit `role="list"` restores list semantics that Safari/VoiceOver drop
10
+ * once `list-style: none` is applied.
11
+ */
12
+ function List({
13
+ className,
14
+ ...props
15
+ }: Omit<React.ComponentProps<typeof ItemGroup>, "render">) {
16
+ return (
17
+ <ItemGroup
18
+ data-slot="list"
19
+ render={
20
+ // biome-ignore lint/a11y/noRedundantRoles: Safari/VoiceOver drop the implicit list role once list-style is none; the explicit role restores it.
21
+ <ul role="list" />
22
+ }
23
+ className={cn("list-none", className)}
24
+ {...props}
25
+ />
26
+ );
27
+ }
28
+
29
+ function ListItem(props: Omit<React.ComponentProps<typeof Item>, "render">) {
30
+ return <Item data-slot="list-item" render={<li />} {...props} />;
31
+ }
32
+
33
+ /** A separator between list items, hidden from the accessibility tree so it
34
+ * does not count as an item and the `ul` only contains `li` children. */
35
+ function ListSeparator({
36
+ className,
37
+ ...props
38
+ }: React.ComponentProps<typeof ItemSeparator>) {
39
+ return (
40
+ <li role="presentation" aria-hidden="true" data-slot="list-separator">
41
+ <ItemSeparator className={className} {...props} />
42
+ </li>
43
+ );
44
+ }
45
+
46
+ export { List, ListItem, ListSeparator };
@@ -0,0 +1,71 @@
1
+ import { cva } from "#/lib/cva.ts";
2
+
3
+ /**
4
+ * Shared menu recipe consumed by dropdown-menu, context-menu, menubar (via
5
+ * dropdown-menu), combobox and command, so their popups and items stay
6
+ * visually identical instead of each restating — and drifting from — the same
7
+ * class strings.
8
+ *
9
+ * The underlying primitives expose their active/disabled state differently:
10
+ * Base UI menus focus the item (`:focus`), Base UI combobox highlights it
11
+ * (`data-highlighted`), and cmdk selects it (`data-selected="true"`). cmdk
12
+ * also always renders `data-disabled="true"|"false"` while Base UI only adds
13
+ * a bare `data-disabled` when actually disabled. Item-level recipes therefore
14
+ * style every state selector at once — only the one matching the rendering
15
+ * primitive ever activates — and gate disabled styles behind
16
+ * `not-data-[disabled=false]` so cmdk's enabled items are unaffected.
17
+ */
18
+
19
+ const menuItemBase =
20
+ "group/menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none data-inset:pl-7 data-disabled:not-data-[disabled=false]:pointer-events-none data-disabled:not-data-[disabled=false]:opacity-50 focus:bg-accent focus:text-accent-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 focus:*:[svg]:text-accent-foreground data-highlighted:*:[svg]:text-accent-foreground data-[selected=true]:*:[svg]:text-accent-foreground";
21
+
22
+ /** Popup container for floating menus (dropdown, context, combobox). */
23
+ export const menuContentVariants = cva({
24
+ base: "z-50 max-h-(--available-height) 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",
25
+ });
26
+
27
+ /**
28
+ * Menu row. `indicator: "end"` reserves right-side space (`pr-8`) for the
29
+ * kit-consistent end-aligned check/dot indicator on selectable rows.
30
+ */
31
+ export const menuItemVariants = cva({
32
+ base: menuItemBase,
33
+ variants: {
34
+ variant: {
35
+ default: "",
36
+ destructive:
37
+ "text-destructive *:[svg]:text-destructive focus:bg-destructive/10 focus:text-destructive data-highlighted:bg-destructive/10 data-highlighted:text-destructive data-[selected=true]:bg-destructive/10 data-[selected=true]:text-destructive dark:focus:bg-destructive/20 dark:data-highlighted:bg-destructive/20 dark:data-[selected=true]:bg-destructive/20",
38
+ },
39
+ indicator: {
40
+ none: "",
41
+ end: "pr-8",
42
+ },
43
+ },
44
+ defaultVariants: {
45
+ variant: "default",
46
+ indicator: "none",
47
+ },
48
+ });
49
+
50
+ /** Submenu trigger: a menu row that also lights up while its popup is open. */
51
+ export const menuSubTriggerVariants = cva({
52
+ base: `${menuItemBase} data-popup-open:bg-accent data-popup-open:text-accent-foreground`,
53
+ });
54
+
55
+ /** End-aligned wrapper for the check/dot indicator of selectable rows. */
56
+ export const menuIndicatorVariants = cva({
57
+ base: "pointer-events-none absolute right-2 flex size-4 items-center justify-center",
58
+ });
59
+
60
+ export const menuLabelVariants = cva({
61
+ base: "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
62
+ });
63
+
64
+ export const menuSeparatorVariants = cva({
65
+ base: "-mx-1 my-1 h-px bg-border",
66
+ });
67
+
68
+ /** Right-aligned shortcut hint; recolors with the active menu row. */
69
+ export const menuShortcutVariants = cva({
70
+ base: "ml-auto text-xs tracking-widest text-muted-foreground group-focus/menu-item:text-accent-foreground group-data-highlighted/menu-item:text-accent-foreground group-data-[selected=true]/menu-item:text-accent-foreground",
71
+ });
@@ -0,0 +1,226 @@
1
+ import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar";
2
+ import type * as React from "react";
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuCheckboxItem,
6
+ DropdownMenuContent,
7
+ DropdownMenuGroup,
8
+ DropdownMenuItem,
9
+ DropdownMenuLabel,
10
+ DropdownMenuPortal,
11
+ DropdownMenuRadioGroup,
12
+ DropdownMenuRadioItem,
13
+ DropdownMenuSeparator,
14
+ DropdownMenuShortcut,
15
+ DropdownMenuSub,
16
+ DropdownMenuSubContent,
17
+ DropdownMenuSubTrigger,
18
+ DropdownMenuTrigger,
19
+ } from "#/components/ui/dropdown-menu.tsx";
20
+ import { cn } from "#/lib/utils.ts";
21
+
22
+ function Menubar({ className, ...props }: MenubarPrimitive.Props) {
23
+ return (
24
+ <MenubarPrimitive
25
+ data-slot="menubar"
26
+ className={cn(
27
+ "flex h-8 w-fit items-center gap-0.5 rounded-lg border p-[3px]",
28
+ className,
29
+ )}
30
+ {...props}
31
+ />
32
+ );
33
+ }
34
+
35
+ function MenubarMenu({ ...props }: React.ComponentProps<typeof DropdownMenu>) {
36
+ return <DropdownMenu data-slot="menubar-menu" {...props} />;
37
+ }
38
+
39
+ function MenubarGroup({
40
+ ...props
41
+ }: React.ComponentProps<typeof DropdownMenuGroup>) {
42
+ return <DropdownMenuGroup data-slot="menubar-group" {...props} />;
43
+ }
44
+
45
+ function MenubarPortal({
46
+ ...props
47
+ }: React.ComponentProps<typeof DropdownMenuPortal>) {
48
+ return <DropdownMenuPortal data-slot="menubar-portal" {...props} />;
49
+ }
50
+
51
+ function MenubarTrigger({
52
+ className,
53
+ ...props
54
+ }: React.ComponentProps<typeof DropdownMenuTrigger>) {
55
+ return (
56
+ <DropdownMenuTrigger
57
+ data-slot="menubar-trigger"
58
+ className={cn(
59
+ "flex items-center rounded-sm px-1.5 py-[2px] text-sm font-medium outline-hidden select-none hover:bg-muted aria-expanded:bg-muted",
60
+ className,
61
+ )}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+
67
+ function MenubarContent({
68
+ className,
69
+ align = "start",
70
+ alignOffset = -4,
71
+ sideOffset = 8,
72
+ ...props
73
+ }: React.ComponentProps<typeof DropdownMenuContent>) {
74
+ return (
75
+ <DropdownMenuContent
76
+ data-slot="menubar-content"
77
+ align={align}
78
+ alignOffset={alignOffset}
79
+ sideOffset={sideOffset}
80
+ className={cn("min-w-36", className)}
81
+ {...props}
82
+ />
83
+ );
84
+ }
85
+
86
+ function MenubarItem({
87
+ className,
88
+ ...props
89
+ }: React.ComponentProps<typeof DropdownMenuItem>) {
90
+ return (
91
+ <DropdownMenuItem
92
+ data-slot="menubar-item"
93
+ className={className}
94
+ {...props}
95
+ />
96
+ );
97
+ }
98
+
99
+ function MenubarCheckboxItem({
100
+ className,
101
+ ...props
102
+ }: React.ComponentProps<typeof DropdownMenuCheckboxItem>) {
103
+ return (
104
+ <DropdownMenuCheckboxItem
105
+ data-slot="menubar-checkbox-item"
106
+ className={className}
107
+ {...props}
108
+ />
109
+ );
110
+ }
111
+
112
+ function MenubarRadioGroup({
113
+ ...props
114
+ }: React.ComponentProps<typeof DropdownMenuRadioGroup>) {
115
+ return <DropdownMenuRadioGroup data-slot="menubar-radio-group" {...props} />;
116
+ }
117
+
118
+ function MenubarRadioItem({
119
+ className,
120
+ ...props
121
+ }: React.ComponentProps<typeof DropdownMenuRadioItem>) {
122
+ return (
123
+ <DropdownMenuRadioItem
124
+ data-slot="menubar-radio-item"
125
+ className={className}
126
+ {...props}
127
+ />
128
+ );
129
+ }
130
+
131
+ function MenubarLabel({
132
+ className,
133
+ inset,
134
+ ...props
135
+ }: React.ComponentProps<typeof DropdownMenuLabel> & {
136
+ inset?: boolean;
137
+ }) {
138
+ return (
139
+ <DropdownMenuLabel
140
+ data-slot="menubar-label"
141
+ data-inset={inset}
142
+ className={cn(
143
+ "px-1.5 py-1 text-sm font-medium data-inset:pl-7",
144
+ className,
145
+ )}
146
+ {...props}
147
+ />
148
+ );
149
+ }
150
+
151
+ function MenubarSeparator({
152
+ className,
153
+ ...props
154
+ }: React.ComponentProps<typeof DropdownMenuSeparator>) {
155
+ return (
156
+ <DropdownMenuSeparator
157
+ data-slot="menubar-separator"
158
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
159
+ {...props}
160
+ />
161
+ );
162
+ }
163
+
164
+ function MenubarShortcut({
165
+ className,
166
+ ...props
167
+ }: React.ComponentProps<typeof DropdownMenuShortcut>) {
168
+ return (
169
+ <DropdownMenuShortcut
170
+ data-slot="menubar-shortcut"
171
+ className={className}
172
+ {...props}
173
+ />
174
+ );
175
+ }
176
+
177
+ function MenubarSub({
178
+ ...props
179
+ }: React.ComponentProps<typeof DropdownMenuSub>) {
180
+ return <DropdownMenuSub data-slot="menubar-sub" {...props} />;
181
+ }
182
+
183
+ function MenubarSubTrigger({
184
+ className,
185
+ ...props
186
+ }: React.ComponentProps<typeof DropdownMenuSubTrigger>) {
187
+ return (
188
+ <DropdownMenuSubTrigger
189
+ data-slot="menubar-sub-trigger"
190
+ className={className}
191
+ {...props}
192
+ />
193
+ );
194
+ }
195
+
196
+ function MenubarSubContent({
197
+ className,
198
+ ...props
199
+ }: React.ComponentProps<typeof DropdownMenuSubContent>) {
200
+ return (
201
+ <DropdownMenuSubContent
202
+ data-slot="menubar-sub-content"
203
+ className={cn("min-w-32", className)}
204
+ {...props}
205
+ />
206
+ );
207
+ }
208
+
209
+ export {
210
+ Menubar,
211
+ MenubarCheckboxItem,
212
+ MenubarContent,
213
+ MenubarGroup,
214
+ MenubarItem,
215
+ MenubarLabel,
216
+ MenubarMenu,
217
+ MenubarPortal,
218
+ MenubarRadioGroup,
219
+ MenubarRadioItem,
220
+ MenubarSeparator,
221
+ MenubarShortcut,
222
+ MenubarSub,
223
+ MenubarSubContent,
224
+ MenubarSubTrigger,
225
+ MenubarTrigger,
226
+ };