@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,176 @@
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
+ import { Button } from "#/components/ui/button.tsx";
5
+ import { cn } from "#/lib/utils.ts";
6
+
7
+ function Dialog({ ...props }: DialogPrimitive.Root.Props) {
8
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
9
+ }
10
+
11
+ function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
12
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
13
+ }
14
+
15
+ function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
16
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
17
+ }
18
+
19
+ function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
20
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
21
+ }
22
+
23
+ function DialogOverlay({
24
+ className,
25
+ ...props
26
+ }: DialogPrimitive.Backdrop.Props) {
27
+ return (
28
+ <DialogPrimitive.Backdrop
29
+ data-slot="dialog-overlay"
30
+ className={cn(
31
+ // `bg-black/10` carries the dimming on light pages; on a near-black
32
+ // dark page the blur alone does the work, so deepen the scrim there.
33
+ "fixed inset-0 isolate z-50 bg-black/10 transition-opacity duration-150 supports-backdrop-filter:backdrop-blur-xs data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none dark:bg-black/40",
34
+ className,
35
+ )}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ // `xl` is a documented extra beyond the kit's `sm | default | lg` scale for
42
+ // media-heavy dialogs (gallery lightbox, annuaire match review).
43
+ type DialogContentSize = "sm" | "default" | "lg" | "xl";
44
+
45
+ function DialogContent({
46
+ className,
47
+ children,
48
+ size = "sm",
49
+ showCloseButton = true,
50
+ closeButtonLabel = "Close",
51
+ overlayClassName,
52
+ ...props
53
+ }: DialogPrimitive.Popup.Props & {
54
+ size?: DialogContentSize;
55
+ showCloseButton?: boolean;
56
+ closeButtonLabel?: string;
57
+ overlayClassName?: string;
58
+ }) {
59
+ return (
60
+ <DialogPortal>
61
+ <DialogOverlay className={overlayClassName} />
62
+ <DialogPrimitive.Popup
63
+ data-slot="dialog-content"
64
+ data-size={size}
65
+ className={cn(
66
+ // The default `sm` reproduces the historical `sm:max-w-sm` width;
67
+ // sizes are styled off `data-size`, like `AlertDialogContent`.
68
+ "fixed top-1/2 left-1/2 z-50 grid max-h-[calc(100dvh-2rem)] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 overflow-y-auto rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 transition duration-150 ease-out outline-none data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 motion-reduce:transition-none data-[size=default]:sm:max-w-md data-[size=lg]:sm:max-w-lg data-[size=sm]:sm:max-w-sm data-[size=xl]:sm:max-w-xl",
69
+ className,
70
+ )}
71
+ {...props}
72
+ >
73
+ {children}
74
+ {showCloseButton && (
75
+ <DialogPrimitive.Close
76
+ data-slot="dialog-close-button"
77
+ render={
78
+ <Button
79
+ variant="ghost"
80
+ className="absolute top-2 right-2"
81
+ size="icon-sm"
82
+ />
83
+ }
84
+ >
85
+ <XIcon />
86
+ <span className="sr-only">{closeButtonLabel}</span>
87
+ </DialogPrimitive.Close>
88
+ )}
89
+ </DialogPrimitive.Popup>
90
+ </DialogPortal>
91
+ );
92
+ }
93
+
94
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
95
+ return (
96
+ <div
97
+ data-slot="dialog-header"
98
+ // `pr-8` reserves room so the title never runs under the X button.
99
+ className={cn("flex flex-col gap-2 pr-8", className)}
100
+ {...props}
101
+ />
102
+ );
103
+ }
104
+
105
+ function DialogFooter({
106
+ className,
107
+ closeLabel,
108
+ children,
109
+ ...props
110
+ }: React.ComponentProps<"div"> & {
111
+ closeLabel?: string;
112
+ }) {
113
+ return (
114
+ <div
115
+ data-slot="dialog-footer"
116
+ className={cn(
117
+ "-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
118
+ className,
119
+ )}
120
+ {...props}
121
+ >
122
+ {closeLabel !== undefined && (
123
+ <DialogPrimitive.Close
124
+ data-slot="dialog-footer-close"
125
+ render={<Button variant="outline" />}
126
+ >
127
+ {closeLabel}
128
+ </DialogPrimitive.Close>
129
+ )}
130
+ {children}
131
+ </div>
132
+ );
133
+ }
134
+
135
+ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
136
+ return (
137
+ <DialogPrimitive.Title
138
+ data-slot="dialog-title"
139
+ className={cn(
140
+ "text-base leading-none font-medium text-foreground",
141
+ className,
142
+ )}
143
+ {...props}
144
+ />
145
+ );
146
+ }
147
+
148
+ function DialogDescription({
149
+ className,
150
+ ...props
151
+ }: DialogPrimitive.Description.Props) {
152
+ return (
153
+ <DialogPrimitive.Description
154
+ data-slot="dialog-description"
155
+ className={cn(
156
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-4 *:[a]:hover:text-foreground",
157
+ className,
158
+ )}
159
+ {...props}
160
+ />
161
+ );
162
+ }
163
+
164
+ export {
165
+ Dialog,
166
+ DialogClose,
167
+ DialogContent,
168
+ type DialogContentSize,
169
+ DialogDescription,
170
+ DialogFooter,
171
+ DialogHeader,
172
+ DialogOverlay,
173
+ DialogPortal,
174
+ DialogTitle,
175
+ DialogTrigger,
176
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Re-export of Base UI's reading-direction context.
3
+ *
4
+ * `DirectionProvider` only informs Base UI's logical positioning and keyboard
5
+ * navigation (popup sides like `inline-start`, arrow-key orientation in
6
+ * menus). It does not set the `dir` attribute on the DOM: text alignment,
7
+ * visual ordering, and portaled popups (rendered under `document.body`) still
8
+ * follow the closest DOM `dir` ancestor. When localizing to a right-to-left
9
+ * language, set `dir="rtl"` on `<html>` alongside the provider.
10
+ */
11
+ export {
12
+ DirectionProvider,
13
+ type TextDirection as Direction,
14
+ useDirection,
15
+ } from "@base-ui/react/direction-provider";
@@ -0,0 +1,178 @@
1
+ import { XIcon } from "@phosphor-icons/react";
2
+ import type * as React from "react";
3
+ import { Drawer as DrawerPrimitive } from "vaul";
4
+
5
+ import { Button } from "#/components/ui/button.tsx";
6
+ import { cn } from "#/lib/utils.ts";
7
+
8
+ // Unlike the Base UI overlays in this kit, the drawer is Radix-based (vaul):
9
+ // compose with `asChild` (not `render`) and style against `data-state`.
10
+
11
+ function Drawer({
12
+ ...props
13
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) {
14
+ return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
15
+ }
16
+
17
+ function DrawerTrigger({
18
+ ...props
19
+ }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
20
+ return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
21
+ }
22
+
23
+ function DrawerPortal({
24
+ ...props
25
+ }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
26
+ return <DrawerPrimitive.Portal {...props} />;
27
+ }
28
+
29
+ function DrawerClose({
30
+ ...props
31
+ }: React.ComponentProps<typeof DrawerPrimitive.Close>) {
32
+ return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
33
+ }
34
+
35
+ function DrawerOverlay({
36
+ className,
37
+ ...props
38
+ }: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
39
+ return (
40
+ <DrawerPrimitive.Overlay
41
+ data-slot="drawer-overlay"
42
+ className={cn(
43
+ // `bg-black/10` carries the dimming on light pages; on a near-black
44
+ // dark page the blur alone does the work, so deepen the scrim there.
45
+ "fixed inset-0 isolate z-50 bg-black/10 duration-150 supports-backdrop-filter:backdrop-blur-xs data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 motion-reduce:animate-none dark:bg-black/40",
46
+ className,
47
+ )}
48
+ {...props}
49
+ />
50
+ );
51
+ }
52
+
53
+ function DrawerHandle({ className, ...props }: React.ComponentProps<"div">) {
54
+ return (
55
+ <div
56
+ data-slot="drawer-handle"
57
+ aria-hidden="true"
58
+ className={cn(
59
+ "mx-auto mt-4 h-1 w-24 shrink-0 rounded-full bg-muted-foreground/20",
60
+ className,
61
+ )}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+
67
+ function DrawerContent({
68
+ className,
69
+ children,
70
+ showHandle = true,
71
+ showCloseButton = true,
72
+ closeButtonLabel = "Close",
73
+ overlayClassName,
74
+ ...props
75
+ }: React.ComponentProps<typeof DrawerPrimitive.Content> & {
76
+ showHandle?: boolean;
77
+ /** Renders an X button on `left`/`right` drawers, which have no grab handle. */
78
+ showCloseButton?: boolean;
79
+ closeButtonLabel?: string;
80
+ overlayClassName?: string;
81
+ }) {
82
+ return (
83
+ <DrawerPortal>
84
+ <DrawerOverlay className={overlayClassName} />
85
+ <DrawerPrimitive.Content
86
+ data-slot="drawer-content"
87
+ className={cn(
88
+ "group/drawer-content fixed z-50 flex h-auto flex-col bg-popover text-sm text-popover-foreground ring-1 ring-foreground/10 data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm",
89
+ className,
90
+ )}
91
+ {...props}
92
+ >
93
+ {showHandle && (
94
+ <DrawerHandle className="hidden group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
95
+ )}
96
+ {children}
97
+ {showCloseButton && (
98
+ <DrawerPrimitive.Close asChild>
99
+ <Button
100
+ data-slot="drawer-close-button"
101
+ variant="ghost"
102
+ size="icon-sm"
103
+ className="absolute top-2 right-2 hidden group-data-[vaul-drawer-direction=left]/drawer-content:inline-flex group-data-[vaul-drawer-direction=right]/drawer-content:inline-flex"
104
+ >
105
+ <XIcon />
106
+ <span className="sr-only">{closeButtonLabel}</span>
107
+ </Button>
108
+ </DrawerPrimitive.Close>
109
+ )}
110
+ </DrawerPrimitive.Content>
111
+ </DrawerPortal>
112
+ );
113
+ }
114
+
115
+ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
116
+ return (
117
+ <div
118
+ data-slot="drawer-header"
119
+ className={cn(
120
+ // `pr-8` on side drawers reserves room so the title never runs under
121
+ // the X button; bottom/top drawers center on mobile, left-align on md+.
122
+ "flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=left]/drawer-content:pr-8 group-data-[vaul-drawer-direction=right]/drawer-content:pr-8 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:group-data-[vaul-drawer-direction=bottom]/drawer-content:text-left md:group-data-[vaul-drawer-direction=top]/drawer-content:text-left",
123
+ className,
124
+ )}
125
+ {...props}
126
+ />
127
+ );
128
+ }
129
+
130
+ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
131
+ return (
132
+ <div
133
+ data-slot="drawer-footer"
134
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
135
+ {...props}
136
+ />
137
+ );
138
+ }
139
+
140
+ function DrawerTitle({
141
+ className,
142
+ ...props
143
+ }: React.ComponentProps<typeof DrawerPrimitive.Title>) {
144
+ return (
145
+ <DrawerPrimitive.Title
146
+ data-slot="drawer-title"
147
+ className={cn("text-base font-medium text-foreground", className)}
148
+ {...props}
149
+ />
150
+ );
151
+ }
152
+
153
+ function DrawerDescription({
154
+ className,
155
+ ...props
156
+ }: React.ComponentProps<typeof DrawerPrimitive.Description>) {
157
+ return (
158
+ <DrawerPrimitive.Description
159
+ data-slot="drawer-description"
160
+ className={cn("text-sm text-muted-foreground", className)}
161
+ {...props}
162
+ />
163
+ );
164
+ }
165
+
166
+ export {
167
+ Drawer,
168
+ DrawerClose,
169
+ DrawerContent,
170
+ DrawerDescription,
171
+ DrawerFooter,
172
+ DrawerHandle,
173
+ DrawerHeader,
174
+ DrawerOverlay,
175
+ DrawerPortal,
176
+ DrawerTitle,
177
+ DrawerTrigger,
178
+ };
@@ -0,0 +1,247 @@
1
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
2
+ import { CaretRightIcon, CheckIcon, CircleIcon } from "@phosphor-icons/react";
3
+ import type * as React from "react";
4
+ import {
5
+ menuContentVariants,
6
+ menuIndicatorVariants,
7
+ menuItemVariants,
8
+ menuLabelVariants,
9
+ menuSeparatorVariants,
10
+ menuSubTriggerVariants,
11
+ } from "#/components/ui/menu-variants.ts";
12
+ import { Shortcut } from "#/components/ui/shortcut.tsx";
13
+ import { cn } from "#/lib/utils.ts";
14
+
15
+ function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
16
+ return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
17
+ }
18
+
19
+ function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
20
+ return <MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
21
+ }
22
+
23
+ function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
24
+ return <MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;
25
+ }
26
+
27
+ function DropdownMenuContent({
28
+ align = "start",
29
+ alignOffset = 0,
30
+ side = "bottom",
31
+ sideOffset = 4,
32
+ className,
33
+ ...props
34
+ }: MenuPrimitive.Popup.Props &
35
+ Pick<
36
+ MenuPrimitive.Positioner.Props,
37
+ "align" | "alignOffset" | "side" | "sideOffset"
38
+ >) {
39
+ return (
40
+ <MenuPrimitive.Portal>
41
+ <MenuPrimitive.Positioner
42
+ className="isolate z-50 outline-none"
43
+ align={align}
44
+ alignOffset={alignOffset}
45
+ side={side}
46
+ sideOffset={sideOffset}
47
+ >
48
+ <MenuPrimitive.Popup
49
+ data-slot="dropdown-menu-content"
50
+ className={cn(menuContentVariants(), className)}
51
+ {...props}
52
+ />
53
+ </MenuPrimitive.Positioner>
54
+ </MenuPrimitive.Portal>
55
+ );
56
+ }
57
+
58
+ function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
59
+ return <MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
60
+ }
61
+
62
+ // Plain div, not Menu.GroupLabel: Base UI's GroupLabel throws when rendered
63
+ // outside a Menu.Group, and labels are routinely used standalone.
64
+ function DropdownMenuLabel({
65
+ className,
66
+ inset,
67
+ ...props
68
+ }: React.ComponentProps<"div"> & {
69
+ inset?: boolean;
70
+ }) {
71
+ return (
72
+ <div
73
+ data-slot="dropdown-menu-label"
74
+ data-inset={inset}
75
+ className={cn(menuLabelVariants(), className)}
76
+ {...props}
77
+ />
78
+ );
79
+ }
80
+
81
+ function DropdownMenuItem({
82
+ className,
83
+ inset,
84
+ variant = "default",
85
+ ...props
86
+ }: MenuPrimitive.Item.Props & {
87
+ inset?: boolean;
88
+ variant?: "default" | "destructive";
89
+ }) {
90
+ return (
91
+ <MenuPrimitive.Item
92
+ data-slot="dropdown-menu-item"
93
+ data-inset={inset}
94
+ data-variant={variant}
95
+ className={cn(menuItemVariants({ variant }), className)}
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 & {
111
+ inset?: boolean;
112
+ }) {
113
+ return (
114
+ <MenuPrimitive.SubmenuTrigger
115
+ data-slot="dropdown-menu-sub-trigger"
116
+ data-inset={inset}
117
+ className={cn(menuSubTriggerVariants(), className)}
118
+ {...props}
119
+ >
120
+ {children}
121
+ <CaretRightIcon className="ml-auto" />
122
+ </MenuPrimitive.SubmenuTrigger>
123
+ );
124
+ }
125
+
126
+ function DropdownMenuSubContent({
127
+ alignOffset = -3,
128
+ side = "inline-end",
129
+ sideOffset = 0,
130
+ className,
131
+ ...props
132
+ }: React.ComponentProps<typeof DropdownMenuContent>) {
133
+ return (
134
+ <DropdownMenuContent
135
+ data-slot="dropdown-menu-sub-content"
136
+ className={cn("shadow-lg", className)}
137
+ alignOffset={alignOffset}
138
+ side={side}
139
+ sideOffset={sideOffset}
140
+ {...props}
141
+ />
142
+ );
143
+ }
144
+
145
+ function DropdownMenuCheckboxItem({
146
+ className,
147
+ children,
148
+ checked,
149
+ inset,
150
+ ...props
151
+ }: MenuPrimitive.CheckboxItem.Props & {
152
+ inset?: boolean;
153
+ }) {
154
+ return (
155
+ <MenuPrimitive.CheckboxItem
156
+ data-slot="dropdown-menu-checkbox-item"
157
+ data-inset={inset}
158
+ className={cn(menuItemVariants({ indicator: "end" }), className)}
159
+ checked={checked}
160
+ {...props}
161
+ >
162
+ <span
163
+ className={menuIndicatorVariants()}
164
+ data-slot="dropdown-menu-checkbox-item-indicator"
165
+ >
166
+ <MenuPrimitive.CheckboxItemIndicator>
167
+ <CheckIcon />
168
+ </MenuPrimitive.CheckboxItemIndicator>
169
+ </span>
170
+ {children}
171
+ </MenuPrimitive.CheckboxItem>
172
+ );
173
+ }
174
+
175
+ function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
176
+ return (
177
+ <MenuPrimitive.RadioGroup
178
+ data-slot="dropdown-menu-radio-group"
179
+ {...props}
180
+ />
181
+ );
182
+ }
183
+
184
+ function DropdownMenuRadioItem({
185
+ className,
186
+ children,
187
+ inset,
188
+ ...props
189
+ }: MenuPrimitive.RadioItem.Props & {
190
+ inset?: boolean;
191
+ }) {
192
+ return (
193
+ <MenuPrimitive.RadioItem
194
+ data-slot="dropdown-menu-radio-item"
195
+ data-inset={inset}
196
+ className={cn(menuItemVariants({ indicator: "end" }), className)}
197
+ {...props}
198
+ >
199
+ <span
200
+ className={menuIndicatorVariants()}
201
+ data-slot="dropdown-menu-radio-item-indicator"
202
+ >
203
+ <MenuPrimitive.RadioItemIndicator>
204
+ <CircleIcon weight="fill" className="size-2" />
205
+ </MenuPrimitive.RadioItemIndicator>
206
+ </span>
207
+ {children}
208
+ </MenuPrimitive.RadioItem>
209
+ );
210
+ }
211
+
212
+ function DropdownMenuSeparator({
213
+ className,
214
+ ...props
215
+ }: MenuPrimitive.Separator.Props) {
216
+ return (
217
+ <MenuPrimitive.Separator
218
+ data-slot="dropdown-menu-separator"
219
+ className={cn(menuSeparatorVariants(), className)}
220
+ {...props}
221
+ />
222
+ );
223
+ }
224
+
225
+ function DropdownMenuShortcut({
226
+ ...props
227
+ }: React.ComponentProps<typeof Shortcut>) {
228
+ return <Shortcut data-slot="dropdown-menu-shortcut" {...props} />;
229
+ }
230
+
231
+ export {
232
+ DropdownMenu,
233
+ DropdownMenuCheckboxItem,
234
+ DropdownMenuContent,
235
+ DropdownMenuGroup,
236
+ DropdownMenuItem,
237
+ DropdownMenuLabel,
238
+ DropdownMenuPortal,
239
+ DropdownMenuRadioGroup,
240
+ DropdownMenuRadioItem,
241
+ DropdownMenuSeparator,
242
+ DropdownMenuShortcut,
243
+ DropdownMenuSub,
244
+ DropdownMenuSubContent,
245
+ DropdownMenuSubTrigger,
246
+ DropdownMenuTrigger,
247
+ };