@bupple/vss-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.turbo/turbo-lint.log +4 -0
  2. package/components.json +21 -0
  3. package/eslint.config.js +4 -0
  4. package/index.ts +2 -0
  5. package/package.json +67 -0
  6. package/postcss.config.mjs +6 -0
  7. package/src/components/accordion.tsx +84 -0
  8. package/src/components/alert-dialog.tsx +198 -0
  9. package/src/components/alert.tsx +77 -0
  10. package/src/components/aspect-ratio.tsx +11 -0
  11. package/src/components/avatar.tsx +109 -0
  12. package/src/components/badge.tsx +50 -0
  13. package/src/components/breadcrumb.tsx +118 -0
  14. package/src/components/button-group.tsx +84 -0
  15. package/src/components/button.tsx +68 -0
  16. package/src/components/calendar.tsx +223 -0
  17. package/src/components/card.tsx +102 -0
  18. package/src/components/carousel.tsx +241 -0
  19. package/src/components/chart.tsx +373 -0
  20. package/src/components/checkbox.tsx +32 -0
  21. package/src/components/collapsible.tsx +33 -0
  22. package/src/components/combobox.tsx +299 -0
  23. package/src/components/command.tsx +194 -0
  24. package/src/components/context-menu.tsx +272 -0
  25. package/src/components/dialog.tsx +171 -0
  26. package/src/components/direction.tsx +20 -0
  27. package/src/components/drawer.tsx +130 -0
  28. package/src/components/dropdown-menu.tsx +278 -0
  29. package/src/components/empty.tsx +102 -0
  30. package/src/components/field.tsx +237 -0
  31. package/src/components/hover-card.tsx +43 -0
  32. package/src/components/input-group.tsx +157 -0
  33. package/src/components/input.tsx +18 -0
  34. package/src/components/item.tsx +197 -0
  35. package/src/components/kbd.tsx +26 -0
  36. package/src/components/label.tsx +21 -0
  37. package/src/components/menubar.tsx +283 -0
  38. package/src/components/native-select.tsx +64 -0
  39. package/src/components/navigation-menu.tsx +166 -0
  40. package/src/components/pagination.tsx +131 -0
  41. package/src/components/popover.tsx +88 -0
  42. package/src/components/progress.tsx +30 -0
  43. package/src/components/radio-group.tsx +46 -0
  44. package/src/components/resizable.tsx +49 -0
  45. package/src/components/scroll-area.tsx +52 -0
  46. package/src/components/select.tsx +209 -0
  47. package/src/components/separator.tsx +25 -0
  48. package/src/components/sheet.tsx +152 -0
  49. package/src/components/sidebar.tsx +703 -0
  50. package/src/components/skeleton.tsx +13 -0
  51. package/src/components/slider.tsx +58 -0
  52. package/src/components/sonner.tsx +45 -0
  53. package/src/components/spinner.tsx +15 -0
  54. package/src/components/switch.tsx +32 -0
  55. package/src/components/table.tsx +115 -0
  56. package/src/components/tabs.tsx +89 -0
  57. package/src/components/textarea.tsx +17 -0
  58. package/src/components/toggle-group.tsx +86 -0
  59. package/src/components/toggle.tsx +48 -0
  60. package/src/components/tooltip.tsx +56 -0
  61. package/src/hooks/use-mobile.ts +19 -0
  62. package/src/lib/portal-container.ts +11 -0
  63. package/src/lib/utils.ts +8 -0
  64. package/src/theme.css +125 -0
  65. package/tsconfig.json +15 -0
@@ -0,0 +1,157 @@
1
+ 'use client'
2
+
3
+ import type { VariantProps } from 'class-variance-authority'
4
+
5
+ import { Button } from '@bupple/vss-ui/components/button'
6
+ import { Input } from '@bupple/vss-ui/components/input'
7
+ import { Textarea } from '@bupple/vss-ui/components/textarea'
8
+ import { cn } from '@bupple/vss-ui/lib/utils'
9
+ import { cva } from 'class-variance-authority'
10
+ import * as React from 'react'
11
+
12
+ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
13
+ return (
14
+ <div
15
+ data-slot='input-group'
16
+ role='group'
17
+ className={cn(
18
+ 'group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5',
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ )
24
+ }
25
+
26
+ const inputGroupAddonVariants = cva(
27
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
28
+ {
29
+ variants: {
30
+ align: {
31
+ 'inline-start':
32
+ 'order-first pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem]',
33
+ 'inline-end':
34
+ 'order-last pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem]',
35
+ 'block-start':
36
+ 'order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2',
37
+ 'block-end':
38
+ 'order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2',
39
+ },
40
+ },
41
+ defaultVariants: {
42
+ align: 'inline-start',
43
+ },
44
+ },
45
+ )
46
+
47
+ function InputGroupAddon({
48
+ className,
49
+ align = 'inline-start',
50
+ ...props
51
+ }: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
52
+ return (
53
+ <div
54
+ role='group'
55
+ data-slot='input-group-addon'
56
+ data-align={align}
57
+ className={cn(inputGroupAddonVariants({ align }), className)}
58
+ onClick={(e) => {
59
+ if ((e.target as HTMLElement).closest('button')) {
60
+ return
61
+ }
62
+ e.currentTarget.parentElement?.querySelector('input')?.focus()
63
+ }}
64
+ {...props}
65
+ />
66
+ )
67
+ }
68
+
69
+ const inputGroupButtonVariants = cva(
70
+ 'flex items-center gap-2 text-sm shadow-none',
71
+ {
72
+ variants: {
73
+ size: {
74
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
75
+ sm: '',
76
+ 'icon-xs':
77
+ 'size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0',
78
+ 'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
79
+ },
80
+ },
81
+ defaultVariants: {
82
+ size: 'xs',
83
+ },
84
+ },
85
+ )
86
+
87
+ function InputGroupButton({
88
+ className,
89
+ type = 'button',
90
+ variant = 'ghost',
91
+ size = 'xs',
92
+ ...props
93
+ }: Omit<React.ComponentProps<typeof Button>, 'size'> &
94
+ VariantProps<typeof inputGroupButtonVariants>) {
95
+ return (
96
+ <Button
97
+ type={type}
98
+ data-size={size}
99
+ variant={variant}
100
+ className={cn(inputGroupButtonVariants({ size }), className)}
101
+ {...props}
102
+ />
103
+ )
104
+ }
105
+
106
+ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
107
+ return (
108
+ <span
109
+ className={cn(
110
+ "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
111
+ className,
112
+ )}
113
+ {...props}
114
+ />
115
+ )
116
+ }
117
+
118
+ function InputGroupInput({
119
+ className,
120
+ ...props
121
+ }: React.ComponentProps<'input'>) {
122
+ return (
123
+ <Input
124
+ data-slot='input-group-control'
125
+ className={cn(
126
+ 'flex-1 rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent',
127
+ className,
128
+ )}
129
+ {...props}
130
+ />
131
+ )
132
+ }
133
+
134
+ function InputGroupTextarea({
135
+ className,
136
+ ...props
137
+ }: React.ComponentProps<'textarea'>) {
138
+ return (
139
+ <Textarea
140
+ data-slot='input-group-control'
141
+ className={cn(
142
+ 'flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent',
143
+ className,
144
+ )}
145
+ {...props}
146
+ />
147
+ )
148
+ }
149
+
150
+ export {
151
+ InputGroup,
152
+ InputGroupAddon,
153
+ InputGroupButton,
154
+ InputGroupText,
155
+ InputGroupInput,
156
+ InputGroupTextarea,
157
+ }
@@ -0,0 +1,18 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+ import * as React from 'react'
3
+
4
+ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
5
+ return (
6
+ <input
7
+ type={type}
8
+ data-slot='input'
9
+ className={cn(
10
+ 'h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 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-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',
11
+ className,
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ export { Input }
@@ -0,0 +1,197 @@
1
+ import type { VariantProps } from 'class-variance-authority'
2
+
3
+ import { Separator } from '@bupple/vss-ui/components/separator'
4
+ import { cn } from '@bupple/vss-ui/lib/utils'
5
+ import { cva } from 'class-variance-authority'
6
+ import { Slot } from 'radix-ui'
7
+ import * as React from 'react'
8
+
9
+ function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) {
10
+ return (
11
+ <div
12
+ role='list'
13
+ data-slot='item-group'
14
+ className={cn(
15
+ 'group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2',
16
+ className,
17
+ )}
18
+ {...props}
19
+ />
20
+ )
21
+ }
22
+
23
+ function ItemSeparator({
24
+ className,
25
+ ...props
26
+ }: React.ComponentProps<typeof Separator>) {
27
+ return (
28
+ <Separator
29
+ data-slot='item-separator'
30
+ orientation='horizontal'
31
+ className={cn('my-2', className)}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ const itemVariants = cva(
38
+ '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-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted',
39
+ {
40
+ variants: {
41
+ variant: {
42
+ default: 'border-transparent',
43
+ outline: 'border-border',
44
+ muted: 'border-transparent bg-muted/50',
45
+ },
46
+ size: {
47
+ default: 'gap-2.5 px-3 py-2.5',
48
+ sm: 'gap-2.5 px-3 py-2.5',
49
+ xs: 'gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0',
50
+ },
51
+ },
52
+ defaultVariants: {
53
+ variant: 'default',
54
+ size: 'default',
55
+ },
56
+ },
57
+ )
58
+
59
+ function Item({
60
+ className,
61
+ variant = 'default',
62
+ size = 'default',
63
+ asChild = false,
64
+ ...props
65
+ }: React.ComponentProps<'div'> &
66
+ VariantProps<typeof itemVariants> & { asChild?: boolean }) {
67
+ const Comp = asChild ? Slot.Root : 'div'
68
+ return (
69
+ <Comp
70
+ data-slot='item'
71
+ data-variant={variant}
72
+ data-size={size}
73
+ className={cn(itemVariants({ variant, size, className }))}
74
+ {...props}
75
+ />
76
+ )
77
+ }
78
+
79
+ const itemMediaVariants = cva(
80
+ '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',
81
+ {
82
+ variants: {
83
+ variant: {
84
+ default: 'bg-transparent',
85
+ icon: "[&_svg:not([class*='size-'])]:size-4",
86
+ image:
87
+ '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',
88
+ },
89
+ },
90
+ defaultVariants: {
91
+ variant: 'default',
92
+ },
93
+ },
94
+ )
95
+
96
+ function ItemMedia({
97
+ className,
98
+ variant = 'default',
99
+ ...props
100
+ }: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>) {
101
+ return (
102
+ <div
103
+ data-slot='item-media'
104
+ data-variant={variant}
105
+ className={cn(itemMediaVariants({ variant, className }))}
106
+ {...props}
107
+ />
108
+ )
109
+ }
110
+
111
+ function ItemContent({ className, ...props }: React.ComponentProps<'div'>) {
112
+ return (
113
+ <div
114
+ data-slot='item-content'
115
+ className={cn(
116
+ 'flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none',
117
+ className,
118
+ )}
119
+ {...props}
120
+ />
121
+ )
122
+ }
123
+
124
+ function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) {
125
+ return (
126
+ <div
127
+ data-slot='item-title'
128
+ className={cn(
129
+ 'line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4',
130
+ className,
131
+ )}
132
+ {...props}
133
+ />
134
+ )
135
+ }
136
+
137
+ function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) {
138
+ return (
139
+ <p
140
+ data-slot='item-description'
141
+ className={cn(
142
+ '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',
143
+ className,
144
+ )}
145
+ {...props}
146
+ />
147
+ )
148
+ }
149
+
150
+ function ItemActions({ className, ...props }: React.ComponentProps<'div'>) {
151
+ return (
152
+ <div
153
+ data-slot='item-actions'
154
+ className={cn('flex items-center gap-2', className)}
155
+ {...props}
156
+ />
157
+ )
158
+ }
159
+
160
+ function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) {
161
+ return (
162
+ <div
163
+ data-slot='item-header'
164
+ className={cn(
165
+ 'flex basis-full items-center justify-between gap-2',
166
+ className,
167
+ )}
168
+ {...props}
169
+ />
170
+ )
171
+ }
172
+
173
+ function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) {
174
+ return (
175
+ <div
176
+ data-slot='item-footer'
177
+ className={cn(
178
+ 'flex basis-full items-center justify-between gap-2',
179
+ className,
180
+ )}
181
+ {...props}
182
+ />
183
+ )
184
+ }
185
+
186
+ export {
187
+ Item,
188
+ ItemMedia,
189
+ ItemContent,
190
+ ItemActions,
191
+ ItemGroup,
192
+ ItemSeparator,
193
+ ItemTitle,
194
+ ItemDescription,
195
+ ItemHeader,
196
+ ItemFooter,
197
+ }
@@ -0,0 +1,26 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+
3
+ function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
4
+ return (
5
+ <kbd
6
+ data-slot='kbd'
7
+ className={cn(
8
+ "pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none in-data-[slot=tooltip-content]:bg-background/20 in-data-[slot=tooltip-content]:text-background dark:in-data-[slot=tooltip-content]:bg-background/10 [&_svg:not([class*='size-'])]:size-3",
9
+ className,
10
+ )}
11
+ {...props}
12
+ />
13
+ )
14
+ }
15
+
16
+ function KbdGroup({ className, ...props }: React.ComponentProps<'div'>) {
17
+ return (
18
+ <kbd
19
+ data-slot='kbd-group'
20
+ className={cn('inline-flex items-center gap-1', className)}
21
+ {...props}
22
+ />
23
+ )
24
+ }
25
+
26
+ export { Kbd, KbdGroup }
@@ -0,0 +1,21 @@
1
+ import { cn } from '@bupple/vss-ui/lib/utils'
2
+ import { Label as LabelPrimitive } from 'radix-ui'
3
+ import * as React from 'react'
4
+
5
+ function Label({
6
+ className,
7
+ ...props
8
+ }: React.ComponentProps<typeof LabelPrimitive.Root>) {
9
+ return (
10
+ <LabelPrimitive.Root
11
+ data-slot='label'
12
+ className={cn(
13
+ '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',
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ export { Label }
@@ -0,0 +1,283 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@bupple/vss-ui/lib/utils'
4
+ import { CheckIcon, ChevronRightIcon } from 'lucide-react'
5
+ import { Menubar as MenubarPrimitive } from 'radix-ui'
6
+ import * as React from 'react'
7
+
8
+ function Menubar({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof MenubarPrimitive.Root>) {
12
+ return (
13
+ <MenubarPrimitive.Root
14
+ data-slot='menubar'
15
+ className={cn(
16
+ 'flex h-8 items-center gap-0.5 rounded-lg border p-[3px]',
17
+ className,
18
+ )}
19
+ {...props}
20
+ />
21
+ )
22
+ }
23
+
24
+ function MenubarMenu({
25
+ ...props
26
+ }: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
27
+ return <MenubarPrimitive.Menu data-slot='menubar-menu' {...props} />
28
+ }
29
+
30
+ function MenubarGroup({
31
+ ...props
32
+ }: React.ComponentProps<typeof MenubarPrimitive.Group>) {
33
+ return <MenubarPrimitive.Group data-slot='menubar-group' {...props} />
34
+ }
35
+
36
+ function MenubarPortal({
37
+ ...props
38
+ }: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
39
+ return <MenubarPrimitive.Portal data-slot='menubar-portal' {...props} />
40
+ }
41
+
42
+ function MenubarRadioGroup({
43
+ ...props
44
+ }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
45
+ return (
46
+ <MenubarPrimitive.RadioGroup data-slot='menubar-radio-group' {...props} />
47
+ )
48
+ }
49
+
50
+ function MenubarTrigger({
51
+ className,
52
+ ...props
53
+ }: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
54
+ return (
55
+ <MenubarPrimitive.Trigger
56
+ data-slot='menubar-trigger'
57
+ className={cn(
58
+ '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',
59
+ className,
60
+ )}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ function MenubarContent({
67
+ className,
68
+ align = 'start',
69
+ alignOffset = -4,
70
+ sideOffset = 8,
71
+ ...props
72
+ }: React.ComponentProps<typeof MenubarPrimitive.Content>) {
73
+ return (
74
+ <MenubarPortal>
75
+ <MenubarPrimitive.Content
76
+ data-slot='menubar-content'
77
+ align={align}
78
+ alignOffset={alignOffset}
79
+ sideOffset={sideOffset}
80
+ className={cn(
81
+ 'z-50 min-w-36 origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-md 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',
82
+ className,
83
+ )}
84
+ {...props}
85
+ />
86
+ </MenubarPortal>
87
+ )
88
+ }
89
+
90
+ function MenubarItem({
91
+ className,
92
+ inset,
93
+ variant = 'default',
94
+ ...props
95
+ }: React.ComponentProps<typeof MenubarPrimitive.Item> & {
96
+ inset?: boolean
97
+ variant?: 'default' | 'destructive'
98
+ }) {
99
+ return (
100
+ <MenubarPrimitive.Item
101
+ data-slot='menubar-item'
102
+ data-inset={inset}
103
+ data-variant={variant}
104
+ className={cn(
105
+ "group/menubar-item relative flex cursor-default 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!",
106
+ className,
107
+ )}
108
+ {...props}
109
+ />
110
+ )
111
+ }
112
+
113
+ function MenubarCheckboxItem({
114
+ className,
115
+ children,
116
+ checked,
117
+ inset,
118
+ ...props
119
+ }: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem> & {
120
+ inset?: boolean
121
+ }) {
122
+ return (
123
+ <MenubarPrimitive.CheckboxItem
124
+ data-slot='menubar-checkbox-item'
125
+ data-inset={inset}
126
+ className={cn(
127
+ 'relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 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 [&_svg]:pointer-events-none [&_svg]:shrink-0',
128
+ className,
129
+ )}
130
+ checked={checked}
131
+ {...props}
132
+ >
133
+ <span className="pointer-events-none absolute left-1.5 flex size-4 items-center justify-center [&_svg:not([class*='size-'])]:size-4">
134
+ <MenubarPrimitive.ItemIndicator>
135
+ <CheckIcon />
136
+ </MenubarPrimitive.ItemIndicator>
137
+ </span>
138
+ {children}
139
+ </MenubarPrimitive.CheckboxItem>
140
+ )
141
+ }
142
+
143
+ function MenubarRadioItem({
144
+ className,
145
+ children,
146
+ inset,
147
+ ...props
148
+ }: React.ComponentProps<typeof MenubarPrimitive.RadioItem> & {
149
+ inset?: boolean
150
+ }) {
151
+ return (
152
+ <MenubarPrimitive.RadioItem
153
+ data-slot='menubar-radio-item'
154
+ data-inset={inset}
155
+ className={cn(
156
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 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",
157
+ className,
158
+ )}
159
+ {...props}
160
+ >
161
+ <span className="pointer-events-none absolute left-1.5 flex size-4 items-center justify-center [&_svg:not([class*='size-'])]:size-4">
162
+ <MenubarPrimitive.ItemIndicator>
163
+ <CheckIcon />
164
+ </MenubarPrimitive.ItemIndicator>
165
+ </span>
166
+ {children}
167
+ </MenubarPrimitive.RadioItem>
168
+ )
169
+ }
170
+
171
+ function MenubarLabel({
172
+ className,
173
+ inset,
174
+ ...props
175
+ }: React.ComponentProps<typeof MenubarPrimitive.Label> & {
176
+ inset?: boolean
177
+ }) {
178
+ return (
179
+ <MenubarPrimitive.Label
180
+ data-slot='menubar-label'
181
+ data-inset={inset}
182
+ className={cn(
183
+ 'px-1.5 py-1 text-sm font-medium data-inset:pl-7',
184
+ className,
185
+ )}
186
+ {...props}
187
+ />
188
+ )
189
+ }
190
+
191
+ function MenubarSeparator({
192
+ className,
193
+ ...props
194
+ }: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
195
+ return (
196
+ <MenubarPrimitive.Separator
197
+ data-slot='menubar-separator'
198
+ className={cn('-mx-1 my-1 h-px bg-border', className)}
199
+ {...props}
200
+ />
201
+ )
202
+ }
203
+
204
+ function MenubarShortcut({
205
+ className,
206
+ ...props
207
+ }: React.ComponentProps<'span'>) {
208
+ return (
209
+ <span
210
+ data-slot='menubar-shortcut'
211
+ className={cn(
212
+ 'ml-auto text-xs tracking-widest text-muted-foreground group-focus/menubar-item:text-accent-foreground',
213
+ className,
214
+ )}
215
+ {...props}
216
+ />
217
+ )
218
+ }
219
+
220
+ function MenubarSub({
221
+ ...props
222
+ }: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
223
+ return <MenubarPrimitive.Sub data-slot='menubar-sub' {...props} />
224
+ }
225
+
226
+ function MenubarSubTrigger({
227
+ className,
228
+ inset,
229
+ children,
230
+ ...props
231
+ }: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
232
+ inset?: boolean
233
+ }) {
234
+ return (
235
+ <MenubarPrimitive.SubTrigger
236
+ data-slot='menubar-sub-trigger'
237
+ data-inset={inset}
238
+ className={cn(
239
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg:not([class*='size-'])]:size-4",
240
+ className,
241
+ )}
242
+ {...props}
243
+ >
244
+ {children}
245
+ <ChevronRightIcon className='ml-auto size-4' />
246
+ </MenubarPrimitive.SubTrigger>
247
+ )
248
+ }
249
+
250
+ function MenubarSubContent({
251
+ className,
252
+ ...props
253
+ }: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
254
+ return (
255
+ <MenubarPrimitive.SubContent
256
+ data-slot='menubar-sub-content'
257
+ className={cn(
258
+ 'z-50 min-w-32 origin-(--radix-menubar-content-transform-origin) overflow-hidden 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',
259
+ className,
260
+ )}
261
+ {...props}
262
+ />
263
+ )
264
+ }
265
+
266
+ export {
267
+ Menubar,
268
+ MenubarPortal,
269
+ MenubarMenu,
270
+ MenubarTrigger,
271
+ MenubarContent,
272
+ MenubarGroup,
273
+ MenubarSeparator,
274
+ MenubarLabel,
275
+ MenubarItem,
276
+ MenubarShortcut,
277
+ MenubarCheckboxItem,
278
+ MenubarRadioGroup,
279
+ MenubarRadioItem,
280
+ MenubarSub,
281
+ MenubarSubTrigger,
282
+ MenubarSubContent,
283
+ }