@suphark/ui 0.1.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 (147) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +21 -0
  3. package/README.md +120 -0
  4. package/components.json +21 -0
  5. package/package.json +108 -0
  6. package/scripts/audit-base-ui-props.mjs +179 -0
  7. package/scripts/audit-tailwind-typography.mjs +100 -0
  8. package/src/components/design-system/design-system-showcase.tsx +138 -0
  9. package/src/components/design-system/sections/showcase-data-display.tsx +454 -0
  10. package/src/components/design-system/sections/showcase-feedback.tsx +273 -0
  11. package/src/components/design-system/sections/showcase-forms.tsx +373 -0
  12. package/src/components/design-system/sections/showcase-foundations.tsx +384 -0
  13. package/src/components/design-system/sections/showcase-guidelines-recipes.tsx +397 -0
  14. package/src/components/design-system/sections/showcase-overlays-navigation.tsx +479 -0
  15. package/src/components/design-system/sections/showcase-overview.tsx +368 -0
  16. package/src/components/design-system/sections/showcase-primitives.tsx +463 -0
  17. package/src/components/shared/__tests__/multi-select-combobox.test.tsx +180 -0
  18. package/src/components/shared/__tests__/name-id-fields.test.ts +24 -0
  19. package/src/components/shared/button/add-new-button.tsx +19 -0
  20. package/src/components/shared/button/base/action-button.tsx +134 -0
  21. package/src/components/shared/button/base/link-button.tsx +130 -0
  22. package/src/components/shared/button/cancel-button.tsx +27 -0
  23. package/src/components/shared/button/confirm-button.tsx +26 -0
  24. package/src/components/shared/button/delete-button.tsx +36 -0
  25. package/src/components/shared/button/floating-save-button.tsx +89 -0
  26. package/src/components/shared/button/index.ts +13 -0
  27. package/src/components/shared/button/print-button.tsx +67 -0
  28. package/src/components/shared/button/refresh-button.tsx +63 -0
  29. package/src/components/shared/button/save-button.tsx +29 -0
  30. package/src/components/shared/button/submit-button.tsx +58 -0
  31. package/src/components/shared/client-redirect.tsx +11 -0
  32. package/src/components/shared/combobox.tsx +116 -0
  33. package/src/components/shared/data-list.tsx +65 -0
  34. package/src/components/shared/date/date-range-picker.tsx +106 -0
  35. package/src/components/shared/description-list.tsx +27 -0
  36. package/src/components/shared/empty-row.tsx +13 -0
  37. package/src/components/shared/empty-state.tsx +31 -0
  38. package/src/components/shared/env-snippet.tsx +62 -0
  39. package/src/components/shared/form/__tests__/simple-select.test.tsx +72 -0
  40. package/src/components/shared/form/form-field-boolean.tsx +93 -0
  41. package/src/components/shared/form/form-field-color-select.tsx +86 -0
  42. package/src/components/shared/form/form-field-combobox.tsx +167 -0
  43. package/src/components/shared/form/form-field-date.tsx +55 -0
  44. package/src/components/shared/form/form-field-formatted-number.tsx +103 -0
  45. package/src/components/shared/form/form-field-input.tsx +372 -0
  46. package/src/components/shared/form/form-field-radio-cards.tsx +127 -0
  47. package/src/components/shared/form/form-field-radio-group.tsx +56 -0
  48. package/src/components/shared/form/form-field-select.tsx +312 -0
  49. package/src/components/shared/form/simple-select.tsx +152 -0
  50. package/src/components/shared/form-dialog.tsx +109 -0
  51. package/src/components/shared/form-message.tsx +30 -0
  52. package/src/components/shared/initials.tsx +33 -0
  53. package/src/components/shared/layout/error-state.tsx +160 -0
  54. package/src/components/shared/layout/page-shell.tsx +57 -0
  55. package/src/components/shared/link/transition-link.tsx +72 -0
  56. package/src/components/shared/multi-select-combobox.tsx +392 -0
  57. package/src/components/shared/name-id-fields.tsx +133 -0
  58. package/src/components/shared/navigation/page-breadcrumb.tsx +100 -0
  59. package/src/components/shared/notice.tsx +35 -0
  60. package/src/components/shared/number/formatted-number.tsx +133 -0
  61. package/src/components/shared/page-header.tsx +25 -0
  62. package/src/components/shared/page-skeleton.tsx +18 -0
  63. package/src/components/shared/row-actions.tsx +93 -0
  64. package/src/components/shared/row-menu.tsx +55 -0
  65. package/src/components/shared/secret-reveal.tsx +53 -0
  66. package/src/components/shared/section-card.tsx +44 -0
  67. package/src/components/shared/stat.tsx +26 -0
  68. package/src/components/shared/status-badge.tsx +47 -0
  69. package/src/components/shared/text/primary-secondary-text.tsx +186 -0
  70. package/src/components/shared/theme/index.ts +4 -0
  71. package/src/components/shared/theme/theme-menu-items.tsx +43 -0
  72. package/src/components/shared/theme/theme-provider.tsx +39 -0
  73. package/src/components/shared/theme/theme-switch.tsx +36 -0
  74. package/src/components/shared/theme/theme-toggle.tsx +76 -0
  75. package/src/components/shared/time/client-date-formatter.tsx +188 -0
  76. package/src/components/shared/ui-text.tsx +47 -0
  77. package/src/components/ui/__tests__/combobox.test.tsx +40 -0
  78. package/src/components/ui/__tests__/date-picker.test.tsx +53 -0
  79. package/src/components/ui/__tests__/slider.test.tsx +18 -0
  80. package/src/components/ui/__tests__/tabs.test.tsx +33 -0
  81. package/src/components/ui/accordion.tsx +69 -0
  82. package/src/components/ui/alert-dialog.tsx +161 -0
  83. package/src/components/ui/alert.tsx +68 -0
  84. package/src/components/ui/aspect-ratio.tsx +22 -0
  85. package/src/components/ui/attachment.tsx +194 -0
  86. package/src/components/ui/avatar.tsx +92 -0
  87. package/src/components/ui/badge.tsx +48 -0
  88. package/src/components/ui/breadcrumb.tsx +102 -0
  89. package/src/components/ui/button-group.tsx +77 -0
  90. package/src/components/ui/button.tsx +57 -0
  91. package/src/components/ui/calendar.tsx +184 -0
  92. package/src/components/ui/card.tsx +87 -0
  93. package/src/components/ui/carousel.tsx +230 -0
  94. package/src/components/ui/chart.tsx +338 -0
  95. package/src/components/ui/checkbox.tsx +27 -0
  96. package/src/components/ui/collapsible.tsx +17 -0
  97. package/src/components/ui/combobox.tsx +272 -0
  98. package/src/components/ui/command.tsx +180 -0
  99. package/src/components/ui/context-menu.tsx +244 -0
  100. package/src/components/ui/date-picker.tsx +308 -0
  101. package/src/components/ui/dialog.tsx +137 -0
  102. package/src/components/ui/drawer.tsx +208 -0
  103. package/src/components/ui/dropdown-menu.tsx +257 -0
  104. package/src/components/ui/empty.tsx +93 -0
  105. package/src/components/ui/field.tsx +223 -0
  106. package/src/components/ui/form.tsx +161 -0
  107. package/src/components/ui/hover-card.tsx +46 -0
  108. package/src/components/ui/input-group.tsx +145 -0
  109. package/src/components/ui/input-otp.tsx +85 -0
  110. package/src/components/ui/input.tsx +19 -0
  111. package/src/components/ui/item.tsx +187 -0
  112. package/src/components/ui/kbd.tsx +26 -0
  113. package/src/components/ui/label.tsx +19 -0
  114. package/src/components/ui/menubar.tsx +266 -0
  115. package/src/components/ui/navigation-menu.tsx +160 -0
  116. package/src/components/ui/pagination.tsx +117 -0
  117. package/src/components/ui/popover.tsx +76 -0
  118. package/src/components/ui/progress.tsx +66 -0
  119. package/src/components/ui/radio-group.tsx +38 -0
  120. package/src/components/ui/relative-date.tsx +40 -0
  121. package/src/components/ui/resizable.tsx +41 -0
  122. package/src/components/ui/scroll-area.tsx +67 -0
  123. package/src/components/ui/searchable-select.tsx +124 -0
  124. package/src/components/ui/select.tsx +189 -0
  125. package/src/components/ui/separator.tsx +21 -0
  126. package/src/components/ui/sheet.tsx +124 -0
  127. package/src/components/ui/sidebar.tsx +691 -0
  128. package/src/components/ui/skeleton.tsx +13 -0
  129. package/src/components/ui/slider.tsx +55 -0
  130. package/src/components/ui/sonner.tsx +45 -0
  131. package/src/components/ui/spinner.tsx +16 -0
  132. package/src/components/ui/switch.tsx +32 -0
  133. package/src/components/ui/table.tsx +95 -0
  134. package/src/components/ui/tabs.tsx +79 -0
  135. package/src/components/ui/textarea.tsx +17 -0
  136. package/src/components/ui/toggle-group.tsx +86 -0
  137. package/src/components/ui/toggle.tsx +44 -0
  138. package/src/components/ui/tooltip.tsx +54 -0
  139. package/src/hooks/use-copy-to-clipboard.ts +27 -0
  140. package/src/hooks/use-mobile.ts +21 -0
  141. package/src/index.ts +156 -0
  142. package/src/lib/formatters.ts +44 -0
  143. package/src/lib/permission.ts +75 -0
  144. package/src/lib/status-colors.ts +52 -0
  145. package/src/lib/utils.ts +6 -0
  146. package/src/next.ts +15 -0
  147. package/src/styles.css +214 -0
@@ -0,0 +1,180 @@
1
+ "use client";
2
+
3
+ import {
4
+ Dialog,
5
+ DialogContent,
6
+ DialogDescription,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ } from "@suphark/ui/components/ui/dialog";
10
+ import { InputGroup, InputGroupAddon } from "@suphark/ui/components/ui/input-group";
11
+ import { cn } from "@suphark/ui/lib/utils";
12
+ import { Command as CommandPrimitive } from "cmdk";
13
+ import { CheckIcon, SearchIcon } from "lucide-react";
14
+ import type * as React from "react";
15
+
16
+ function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
17
+ return (
18
+ <CommandPrimitive
19
+ data-slot="command"
20
+ className={cn(
21
+ "flex size-full flex-col overflow-hidden rounded-xl! bg-popover p-1 text-popover-foreground",
22
+ className,
23
+ )}
24
+ {...props}
25
+ />
26
+ );
27
+ }
28
+
29
+ function CommandDialog({
30
+ title = "Command Palette",
31
+ description = "Search for a command to run...",
32
+ children,
33
+ className,
34
+ showCloseButton = false,
35
+ ...props
36
+ }: Omit<React.ComponentProps<typeof Dialog>, "children"> & {
37
+ title?: string;
38
+ description?: string;
39
+ className?: string;
40
+ showCloseButton?: boolean;
41
+ children: React.ReactNode;
42
+ }) {
43
+ return (
44
+ <Dialog {...props}>
45
+ <DialogHeader className="sr-only">
46
+ <DialogTitle>{title}</DialogTitle>
47
+ <DialogDescription>{description}</DialogDescription>
48
+ </DialogHeader>
49
+ <DialogContent
50
+ className={cn("top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0", className)}
51
+ showCloseButton={showCloseButton}
52
+ >
53
+ {children}
54
+ </DialogContent>
55
+ </Dialog>
56
+ );
57
+ }
58
+
59
+ function CommandInput({
60
+ className,
61
+ ...props
62
+ }: React.ComponentProps<typeof CommandPrimitive.Input>) {
63
+ return (
64
+ <div data-slot="command-input-wrapper" className="p-1 pb-0">
65
+ <InputGroup className="h-8! rounded-lg! border-input/30 bg-input/30 shadow-none! *:data-[slot=input-group-addon]:pl-2!">
66
+ <CommandPrimitive.Input
67
+ data-slot="command-input"
68
+ className={cn(
69
+ "w-full text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
70
+ className,
71
+ )}
72
+ {...props}
73
+ />
74
+ <InputGroupAddon>
75
+ <SearchIcon className="size-4 shrink-0 opacity-50" />
76
+ </InputGroupAddon>
77
+ </InputGroup>
78
+ </div>
79
+ );
80
+ }
81
+
82
+ function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
83
+ return (
84
+ <CommandPrimitive.List
85
+ data-slot="command-list"
86
+ className={cn(
87
+ "no-scrollbar max-h-72 scroll-py-1 overflow-y-auto overflow-x-hidden outline-none",
88
+ className,
89
+ )}
90
+ {...props}
91
+ />
92
+ );
93
+ }
94
+
95
+ function CommandEmpty({
96
+ className,
97
+ ...props
98
+ }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
99
+ return (
100
+ <CommandPrimitive.Empty
101
+ data-slot="command-empty"
102
+ className={cn("py-6 text-center text-sm", className)}
103
+ {...props}
104
+ />
105
+ );
106
+ }
107
+
108
+ function CommandGroup({
109
+ className,
110
+ ...props
111
+ }: React.ComponentProps<typeof CommandPrimitive.Group>) {
112
+ return (
113
+ <CommandPrimitive.Group
114
+ data-slot="command-group"
115
+ className={cn(
116
+ "overflow-hidden p-1 text-foreground **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group-heading]]:text-muted-foreground **:[[cmdk-group-heading]]:text-xs",
117
+ className,
118
+ )}
119
+ {...props}
120
+ />
121
+ );
122
+ }
123
+
124
+ function CommandSeparator({
125
+ className,
126
+ ...props
127
+ }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
128
+ return (
129
+ <CommandPrimitive.Separator
130
+ data-slot="command-separator"
131
+ className={cn("-mx-1 h-px bg-border", className)}
132
+ {...props}
133
+ />
134
+ );
135
+ }
136
+
137
+ function CommandItem({
138
+ className,
139
+ children,
140
+ ...props
141
+ }: React.ComponentProps<typeof CommandPrimitive.Item>) {
142
+ return (
143
+ <CommandPrimitive.Item
144
+ data-slot="command-item"
145
+ className={cn(
146
+ "group/command-item relative flex cursor-default select-none items-center gap-2 in-data-[slot=dialog-content]:rounded-lg! rounded-sm px-2 py-1.5 text-sm outline-hidden data-[disabled=true]:pointer-events-none data-selected:bg-muted data-selected:text-foreground data-[disabled=true]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 data-selected:*:[svg]:text-foreground",
147
+ className,
148
+ )}
149
+ {...props}
150
+ >
151
+ {children}
152
+ <CheckIcon className="ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" />
153
+ </CommandPrimitive.Item>
154
+ );
155
+ }
156
+
157
+ function CommandShortcut({ className, ...props }: React.ComponentProps<"span">) {
158
+ return (
159
+ <span
160
+ data-slot="command-shortcut"
161
+ className={cn(
162
+ "ml-auto text-muted-foreground text-xs tracking-widest group-data-selected/command-item:text-foreground",
163
+ className,
164
+ )}
165
+ {...props}
166
+ />
167
+ );
168
+ }
169
+
170
+ export {
171
+ Command,
172
+ CommandDialog,
173
+ CommandEmpty,
174
+ CommandGroup,
175
+ CommandInput,
176
+ CommandItem,
177
+ CommandList,
178
+ CommandSeparator,
179
+ CommandShortcut,
180
+ };
@@ -0,0 +1,244 @@
1
+ "use client";
2
+
3
+ import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
4
+ import { cn } from "@suphark/ui/lib/utils";
5
+ import { CheckIcon, ChevronRightIcon } from "lucide-react";
6
+ import type * as React from "react";
7
+
8
+ function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
9
+ return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
10
+ }
11
+
12
+ function ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) {
13
+ return <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />;
14
+ }
15
+
16
+ function ContextMenuTrigger({ className, ...props }: ContextMenuPrimitive.Trigger.Props) {
17
+ return (
18
+ <ContextMenuPrimitive.Trigger
19
+ data-slot="context-menu-trigger"
20
+ className={cn("select-none", className)}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+
26
+ function ContextMenuContent({
27
+ className,
28
+ align = "start",
29
+ alignOffset = 4,
30
+ side = "right",
31
+ sideOffset = 0,
32
+ ...props
33
+ }: ContextMenuPrimitive.Popup.Props &
34
+ Pick<ContextMenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
35
+ return (
36
+ <ContextMenuPrimitive.Portal>
37
+ <ContextMenuPrimitive.Positioner
38
+ className="isolate z-50 outline-none"
39
+ align={align}
40
+ alignOffset={alignOffset}
41
+ side={side}
42
+ sideOffset={sideOffset}
43
+ >
44
+ <ContextMenuPrimitive.Popup
45
+ data-slot="context-menu-content"
46
+ className={cn(
47
+ "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:fade-in-0 data-open:zoom-in-95 data-closed:fade-out-0 data-closed:zoom-out-95 z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-y-auto overflow-x-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-md outline-none ring-1 ring-foreground/10 duration-100 data-closed:animate-out data-open:animate-in",
48
+ className,
49
+ )}
50
+ {...props}
51
+ />
52
+ </ContextMenuPrimitive.Positioner>
53
+ </ContextMenuPrimitive.Portal>
54
+ );
55
+ }
56
+
57
+ function ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) {
58
+ return <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />;
59
+ }
60
+
61
+ function ContextMenuLabel({
62
+ className,
63
+ inset,
64
+ ...props
65
+ }: ContextMenuPrimitive.GroupLabel.Props & {
66
+ inset?: boolean;
67
+ }) {
68
+ return (
69
+ <ContextMenuPrimitive.GroupLabel
70
+ data-slot="context-menu-label"
71
+ data-inset={inset}
72
+ className={cn(
73
+ "px-1.5 py-1 font-medium text-muted-foreground text-xs data-inset:pl-7",
74
+ className,
75
+ )}
76
+ {...props}
77
+ />
78
+ );
79
+ }
80
+
81
+ function ContextMenuItem({
82
+ className,
83
+ inset,
84
+ variant = "default",
85
+ ...props
86
+ }: ContextMenuPrimitive.Item.Props & {
87
+ inset?: boolean;
88
+ variant?: "default" | "destructive";
89
+ }) {
90
+ return (
91
+ <ContextMenuPrimitive.Item
92
+ data-slot="context-menu-item"
93
+ data-inset={inset}
94
+ data-variant={variant}
95
+ className={cn(
96
+ "group/context-menu-item relative flex cursor-default select-none items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-[variant=destructive]:text-destructive data-disabled:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive",
97
+ className,
98
+ )}
99
+ {...props}
100
+ />
101
+ );
102
+ }
103
+
104
+ function ContextMenuSub({ ...props }: ContextMenuPrimitive.SubmenuRoot.Props) {
105
+ return <ContextMenuPrimitive.SubmenuRoot data-slot="context-menu-sub" {...props} />;
106
+ }
107
+
108
+ function ContextMenuSubTrigger({
109
+ className,
110
+ inset,
111
+ children,
112
+ ...props
113
+ }: ContextMenuPrimitive.SubmenuTrigger.Props & {
114
+ inset?: boolean;
115
+ }) {
116
+ return (
117
+ <ContextMenuPrimitive.SubmenuTrigger
118
+ data-slot="context-menu-sub-trigger"
119
+ data-inset={inset}
120
+ className={cn(
121
+ "flex cursor-default select-none items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-inset:pl-7 data-open:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
122
+ className,
123
+ )}
124
+ {...props}
125
+ >
126
+ {children}
127
+ <ChevronRightIcon className="ml-auto" />
128
+ </ContextMenuPrimitive.SubmenuTrigger>
129
+ );
130
+ }
131
+
132
+ function ContextMenuSubContent({ ...props }: React.ComponentProps<typeof ContextMenuContent>) {
133
+ return (
134
+ <ContextMenuContent
135
+ data-slot="context-menu-sub-content"
136
+ className="shadow-lg"
137
+ side="right"
138
+ {...props}
139
+ />
140
+ );
141
+ }
142
+
143
+ function ContextMenuCheckboxItem({
144
+ className,
145
+ children,
146
+ checked,
147
+ inset,
148
+ ...props
149
+ }: ContextMenuPrimitive.CheckboxItem.Props & {
150
+ inset?: boolean;
151
+ }) {
152
+ return (
153
+ <ContextMenuPrimitive.CheckboxItem
154
+ data-slot="context-menu-checkbox-item"
155
+ data-inset={inset}
156
+ className={cn(
157
+ "relative flex cursor-default select-none items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
158
+ className,
159
+ )}
160
+ checked={checked}
161
+ {...props}
162
+ >
163
+ <span className="pointer-events-none absolute right-2">
164
+ <ContextMenuPrimitive.CheckboxItemIndicator>
165
+ <CheckIcon />
166
+ </ContextMenuPrimitive.CheckboxItemIndicator>
167
+ </span>
168
+ {children}
169
+ </ContextMenuPrimitive.CheckboxItem>
170
+ );
171
+ }
172
+
173
+ function ContextMenuRadioGroup({ ...props }: ContextMenuPrimitive.RadioGroup.Props) {
174
+ return <ContextMenuPrimitive.RadioGroup data-slot="context-menu-radio-group" {...props} />;
175
+ }
176
+
177
+ function ContextMenuRadioItem({
178
+ className,
179
+ children,
180
+ inset,
181
+ ...props
182
+ }: ContextMenuPrimitive.RadioItem.Props & {
183
+ inset?: boolean;
184
+ }) {
185
+ return (
186
+ <ContextMenuPrimitive.RadioItem
187
+ data-slot="context-menu-radio-item"
188
+ data-inset={inset}
189
+ className={cn(
190
+ "relative flex cursor-default select-none items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
191
+ className,
192
+ )}
193
+ {...props}
194
+ >
195
+ <span className="pointer-events-none absolute right-2">
196
+ <ContextMenuPrimitive.RadioItemIndicator>
197
+ <CheckIcon />
198
+ </ContextMenuPrimitive.RadioItemIndicator>
199
+ </span>
200
+ {children}
201
+ </ContextMenuPrimitive.RadioItem>
202
+ );
203
+ }
204
+
205
+ function ContextMenuSeparator({ className, ...props }: ContextMenuPrimitive.Separator.Props) {
206
+ return (
207
+ <ContextMenuPrimitive.Separator
208
+ data-slot="context-menu-separator"
209
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
210
+ {...props}
211
+ />
212
+ );
213
+ }
214
+
215
+ function ContextMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
216
+ return (
217
+ <span
218
+ data-slot="context-menu-shortcut"
219
+ className={cn(
220
+ "ml-auto text-muted-foreground text-xs tracking-widest group-focus/context-menu-item:text-accent-foreground",
221
+ className,
222
+ )}
223
+ {...props}
224
+ />
225
+ );
226
+ }
227
+
228
+ export {
229
+ ContextMenu,
230
+ ContextMenuCheckboxItem,
231
+ ContextMenuContent,
232
+ ContextMenuGroup,
233
+ ContextMenuItem,
234
+ ContextMenuLabel,
235
+ ContextMenuPortal,
236
+ ContextMenuRadioGroup,
237
+ ContextMenuRadioItem,
238
+ ContextMenuSeparator,
239
+ ContextMenuShortcut,
240
+ ContextMenuSub,
241
+ ContextMenuSubContent,
242
+ ContextMenuSubTrigger,
243
+ ContextMenuTrigger,
244
+ };