@aphrody/koharu-ui 0.0.0-stage → 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 (123) hide show
  1. package/README.md +37 -2
  2. package/package.json +70 -4
  3. package/src/assets/NotoSansCJK-VF.otf +0 -0
  4. package/src/assets/OFL.txt +92 -0
  5. package/src/components/ClientOnly.tsx +21 -0
  6. package/src/components/ShenronExportPanel.tsx +213 -0
  7. package/src/components/app/AboutDialog.tsx +64 -0
  8. package/src/components/app/KoharuApp.tsx +58 -0
  9. package/src/components/app/StartupView.tsx +67 -0
  10. package/src/components/app/TitleBar.tsx +322 -0
  11. package/src/components/app/Updater.tsx +143 -0
  12. package/src/components/app/WindowChrome.tsx +137 -0
  13. package/src/components/controls/ColorSampling.tsx +70 -0
  14. package/src/components/controls/ColorWell.tsx +139 -0
  15. package/src/components/controls/CommitTextarea.tsx +63 -0
  16. package/src/components/controls/FontPicker.tsx +543 -0
  17. package/src/components/controls/ModelPicker.tsx +178 -0
  18. package/src/components/controls/OutputPicker.tsx +170 -0
  19. package/src/components/editor/ActivityCenter.tsx +234 -0
  20. package/src/components/editor/AgentPanel.tsx +352 -0
  21. package/src/components/editor/CanvasCommandBar.tsx +38 -0
  22. package/src/components/editor/CanvasOverlay.tsx +194 -0
  23. package/src/components/editor/CanvasWorkspace.tsx +947 -0
  24. package/src/components/editor/Editor.tsx +56 -0
  25. package/src/components/editor/InferenceControl.tsx +457 -0
  26. package/src/components/editor/Inspector.tsx +1073 -0
  27. package/src/components/editor/PageRail.tsx +581 -0
  28. package/src/components/editor/ResourceMonitor.tsx +151 -0
  29. package/src/components/editor/RightSidebar.tsx +50 -0
  30. package/src/components/editor/SelectionControls.tsx +184 -0
  31. package/src/components/editor/StatusBar.tsx +41 -0
  32. package/src/components/editor/ToolBar.tsx +182 -0
  33. package/src/components/editor/useCanvas.ts +194 -0
  34. package/src/components/preferences/GenerationPreferences.tsx +118 -0
  35. package/src/components/preferences/KoharuSettings.tsx +229 -0
  36. package/src/components/preferences/PipelinePreferences.tsx +173 -0
  37. package/src/components/preferences/PreferenceFields.tsx +149 -0
  38. package/src/components/preferences/ProviderPreferences.tsx +173 -0
  39. package/src/components/preferences/SettingsPage.tsx +336 -0
  40. package/src/components/preferences/TranslationPreferences.tsx +187 -0
  41. package/src/components/preferences/TypesettingPreferences.tsx +142 -0
  42. package/src/components/preferences/models.ts +103 -0
  43. package/src/components/start/StartView.tsx +277 -0
  44. package/src/index.ts +59 -0
  45. package/src/internal/components/accordion.tsx +72 -0
  46. package/src/internal/components/alert-dialog.tsx +189 -0
  47. package/src/internal/components/alert.tsx +76 -0
  48. package/src/internal/components/aspect-ratio.tsx +22 -0
  49. package/src/internal/components/attachment.tsx +207 -0
  50. package/src/internal/components/avatar.tsx +109 -0
  51. package/src/internal/components/badge.tsx +52 -0
  52. package/src/internal/components/breadcrumb.tsx +125 -0
  53. package/src/internal/components/bubble.tsx +128 -0
  54. package/src/internal/components/button-group.tsx +87 -0
  55. package/src/internal/components/button.tsx +58 -0
  56. package/src/internal/components/card.tsx +103 -0
  57. package/src/internal/components/checkbox.tsx +29 -0
  58. package/src/internal/components/collapsible.tsx +21 -0
  59. package/src/internal/components/combobox.tsx +298 -0
  60. package/src/internal/components/context-menu.tsx +272 -0
  61. package/src/internal/components/dialog.tsx +162 -0
  62. package/src/internal/components/direction.tsx +6 -0
  63. package/src/internal/components/drawer.tsx +230 -0
  64. package/src/internal/components/dropdown-menu.tsx +278 -0
  65. package/src/internal/components/empty.tsx +104 -0
  66. package/src/internal/components/field.tsx +238 -0
  67. package/src/internal/components/hover-card.tsx +52 -0
  68. package/src/internal/components/input-group.tsx +158 -0
  69. package/src/internal/components/input.tsx +20 -0
  70. package/src/internal/components/item.tsx +201 -0
  71. package/src/internal/components/kbd.tsx +26 -0
  72. package/src/internal/components/label.tsx +20 -0
  73. package/src/internal/components/marker.tsx +71 -0
  74. package/src/internal/components/menubar.tsx +280 -0
  75. package/src/internal/components/message.tsx +92 -0
  76. package/src/internal/components/native-select.tsx +61 -0
  77. package/src/internal/components/navigation-menu.tsx +168 -0
  78. package/src/internal/components/number-field.tsx +68 -0
  79. package/src/internal/components/pagination.tsx +130 -0
  80. package/src/internal/components/popover.tsx +91 -0
  81. package/src/internal/components/progress.tsx +83 -0
  82. package/src/internal/components/radio-group.tsx +38 -0
  83. package/src/internal/components/resizable.tsx +50 -0
  84. package/src/internal/components/scroll-area.tsx +88 -0
  85. package/src/internal/components/select.tsx +191 -0
  86. package/src/internal/components/separator.tsx +25 -0
  87. package/src/internal/components/sheet.tsx +140 -0
  88. package/src/internal/components/sidebar.tsx +723 -0
  89. package/src/internal/components/skeleton.tsx +13 -0
  90. package/src/internal/components/slider.tsx +56 -0
  91. package/src/internal/components/spinner.tsx +10 -0
  92. package/src/internal/components/switch.tsx +32 -0
  93. package/src/internal/components/table.tsx +116 -0
  94. package/src/internal/components/tabs.tsx +82 -0
  95. package/src/internal/components/textarea.tsx +18 -0
  96. package/src/internal/components/toast.tsx +235 -0
  97. package/src/internal/components/toggle-group.tsx +89 -0
  98. package/src/internal/components/toggle.tsx +45 -0
  99. package/src/internal/components/tooltip.tsx +67 -0
  100. package/src/internal/hooks/use-mobile.ts +19 -0
  101. package/src/internal/lib/utils.ts +6 -0
  102. package/src/internal/styles/globals.css +73 -0
  103. package/src/lib/backend.ts +85 -0
  104. package/src/lib/document.ts +46 -0
  105. package/src/lib/geometry.ts +272 -0
  106. package/src/lib/i18n.ts +54 -0
  107. package/src/lib/queries.ts +110 -0
  108. package/src/lib/store.ts +191 -0
  109. package/src/lib/translation.ts +35 -0
  110. package/src/locales/en-US/translation.json +536 -0
  111. package/src/locales/es-ES/translation.json +536 -0
  112. package/src/locales/ja-JP/translation.json +536 -0
  113. package/src/locales/ko-KR/translation.json +536 -0
  114. package/src/locales/pt-BR/translation.json +536 -0
  115. package/src/locales/ru-RU/translation.json +536 -0
  116. package/src/locales/tr-TR/translation.json +536 -0
  117. package/src/locales/zh-CN/translation.json +536 -0
  118. package/src/locales/zh-TW/translation.json +536 -0
  119. package/src/navigation.ts +28 -0
  120. package/src/providers.tsx +132 -0
  121. package/src/shenron-pipeline-env.d.ts +14 -0
  122. package/src/styles.css +246 -0
  123. package/tsconfig.json +21 -0
@@ -0,0 +1,298 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Combobox as ComboboxPrimitive } from "@base-ui/react"
5
+
6
+ import { cn } from "../lib/utils"
7
+ import { Button } from "./button"
8
+ import {
9
+ InputGroup,
10
+ InputGroupAddon,
11
+ InputGroupButton,
12
+ InputGroupInput,
13
+ } from "./input-group"
14
+ import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react"
15
+
16
+ const Combobox = ComboboxPrimitive.Root
17
+
18
+ function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
19
+ return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />
20
+ }
21
+
22
+ function ComboboxTrigger({
23
+ className,
24
+ children,
25
+ ...props
26
+ }: ComboboxPrimitive.Trigger.Props) {
27
+ return (
28
+ <ComboboxPrimitive.Trigger
29
+ data-slot="combobox-trigger"
30
+ className={cn("[&_svg:not([class*='size-'])]:size-4", className)}
31
+ {...props}
32
+ >
33
+ {children}
34
+ <ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
35
+ </ComboboxPrimitive.Trigger>
36
+ )
37
+ }
38
+
39
+ function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
40
+ return (
41
+ <ComboboxPrimitive.Clear
42
+ data-slot="combobox-clear"
43
+ render={<InputGroupButton variant="ghost" size="icon-xs" />}
44
+ className={cn(className)}
45
+ {...props}
46
+ >
47
+ <XIcon className="pointer-events-none" />
48
+ </ComboboxPrimitive.Clear>
49
+ )
50
+ }
51
+
52
+ function ComboboxInput({
53
+ className,
54
+ children,
55
+ disabled = false,
56
+ showTrigger = true,
57
+ showClear = false,
58
+ ...props
59
+ }: ComboboxPrimitive.Input.Props & {
60
+ showTrigger?: boolean
61
+ showClear?: boolean
62
+ }) {
63
+ return (
64
+ <InputGroup className={cn("w-auto", className)}>
65
+ <ComboboxPrimitive.Input
66
+ render={<InputGroupInput disabled={disabled} />}
67
+ {...props}
68
+ />
69
+ <InputGroupAddon align="inline-end">
70
+ {showTrigger && (
71
+ <InputGroupButton
72
+ size="icon-xs"
73
+ variant="ghost"
74
+ render={<ComboboxTrigger />}
75
+ data-slot="input-group-button"
76
+ className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
77
+ disabled={disabled}
78
+ />
79
+ )}
80
+ {showClear && <ComboboxClear disabled={disabled} />}
81
+ </InputGroupAddon>
82
+ {children}
83
+ </InputGroup>
84
+ )
85
+ }
86
+
87
+ function ComboboxContent({
88
+ className,
89
+ side = "bottom",
90
+ sideOffset = 6,
91
+ align = "start",
92
+ alignOffset = 0,
93
+ anchor,
94
+ ...props
95
+ }: ComboboxPrimitive.Popup.Props &
96
+ Pick<
97
+ ComboboxPrimitive.Positioner.Props,
98
+ "side" | "align" | "sideOffset" | "alignOffset" | "anchor"
99
+ >) {
100
+ return (
101
+ <ComboboxPrimitive.Portal>
102
+ <ComboboxPrimitive.Positioner
103
+ side={side}
104
+ sideOffset={sideOffset}
105
+ align={align}
106
+ alignOffset={alignOffset}
107
+ anchor={anchor}
108
+ className="isolate z-50"
109
+ >
110
+ <ComboboxPrimitive.Popup
111
+ data-koharu-ui-layer=""
112
+ data-slot="combobox-content"
113
+ data-chips={!!anchor}
114
+ className={cn("group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[chips=true]:min-w-(--anchor-width) 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-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none 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", className )}
115
+ {...props}
116
+ />
117
+ </ComboboxPrimitive.Positioner>
118
+ </ComboboxPrimitive.Portal>
119
+ )
120
+ }
121
+
122
+ function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
123
+ return (
124
+ <ComboboxPrimitive.List
125
+ data-slot="combobox-list"
126
+ className={cn(
127
+ "no-scrollbar max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0",
128
+ className
129
+ )}
130
+ {...props}
131
+ />
132
+ )
133
+ }
134
+
135
+ function ComboboxItem({
136
+ className,
137
+ children,
138
+ ...props
139
+ }: ComboboxPrimitive.Item.Props) {
140
+ return (
141
+ <ComboboxPrimitive.Item
142
+ data-slot="combobox-item"
143
+ className={cn(
144
+ "relative flex w-full cursor-default items-center gap-2 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted:text-accent-foreground not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
145
+ className
146
+ )}
147
+ {...props}
148
+ >
149
+ {children}
150
+ <ComboboxPrimitive.ItemIndicator
151
+ render={
152
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
153
+ }
154
+ >
155
+ <CheckIcon className="pointer-events-none" />
156
+ </ComboboxPrimitive.ItemIndicator>
157
+ </ComboboxPrimitive.Item>
158
+ )
159
+ }
160
+
161
+ function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
162
+ return (
163
+ <ComboboxPrimitive.Group
164
+ data-slot="combobox-group"
165
+ className={cn(className)}
166
+ {...props}
167
+ />
168
+ )
169
+ }
170
+
171
+ function ComboboxLabel({
172
+ className,
173
+ ...props
174
+ }: ComboboxPrimitive.GroupLabel.Props) {
175
+ return (
176
+ <ComboboxPrimitive.GroupLabel
177
+ data-slot="combobox-label"
178
+ className={cn("px-2 py-1.5 text-xs text-muted-foreground", className)}
179
+ {...props}
180
+ />
181
+ )
182
+ }
183
+
184
+ function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {
185
+ return (
186
+ <ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />
187
+ )
188
+ }
189
+
190
+ function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
191
+ return (
192
+ <ComboboxPrimitive.Empty
193
+ data-slot="combobox-empty"
194
+ className={cn(
195
+ "hidden w-full justify-center py-2 text-center text-sm text-muted-foreground group-data-empty/combobox-content:flex",
196
+ className
197
+ )}
198
+ {...props}
199
+ />
200
+ )
201
+ }
202
+
203
+ function ComboboxSeparator({
204
+ className,
205
+ ...props
206
+ }: ComboboxPrimitive.Separator.Props) {
207
+ return (
208
+ <ComboboxPrimitive.Separator
209
+ data-slot="combobox-separator"
210
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
211
+ {...props}
212
+ />
213
+ )
214
+ }
215
+
216
+ function ComboboxChips({
217
+ className,
218
+ ...props
219
+ }: React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &
220
+ ComboboxPrimitive.Chips.Props) {
221
+ return (
222
+ <ComboboxPrimitive.Chips
223
+ data-slot="combobox-chips"
224
+ className={cn(
225
+ "flex min-h-8 flex-wrap items-center gap-1 rounded-lg border border-input bg-transparent bg-clip-padding px-2.5 py-1 text-sm transition-colors focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 has-aria-invalid:border-destructive has-aria-invalid:ring-3 has-aria-invalid:ring-destructive/20 has-data-[slot=combobox-chip]:px-1 dark:bg-input/30 dark:has-aria-invalid:border-destructive/50 dark:has-aria-invalid:ring-destructive/40",
226
+ className
227
+ )}
228
+ {...props}
229
+ />
230
+ )
231
+ }
232
+
233
+ function ComboboxChip({
234
+ className,
235
+ children,
236
+ showRemove = true,
237
+ ...props
238
+ }: ComboboxPrimitive.Chip.Props & {
239
+ showRemove?: boolean
240
+ }) {
241
+ return (
242
+ <ComboboxPrimitive.Chip
243
+ data-slot="combobox-chip"
244
+ className={cn(
245
+ "flex h-[calc(--spacing(5.25))] w-fit items-center justify-center gap-1 rounded-sm bg-muted px-1.5 text-xs font-medium whitespace-nowrap text-foreground has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pr-0",
246
+ className
247
+ )}
248
+ {...props}
249
+ >
250
+ {children}
251
+ {showRemove && (
252
+ <ComboboxPrimitive.ChipRemove
253
+ render={<Button variant="ghost" size="icon-xs" />}
254
+ className="-ml-1 opacity-50 hover:opacity-100"
255
+ data-slot="combobox-chip-remove"
256
+ >
257
+ <XIcon className="pointer-events-none" />
258
+ </ComboboxPrimitive.ChipRemove>
259
+ )}
260
+ </ComboboxPrimitive.Chip>
261
+ )
262
+ }
263
+
264
+ function ComboboxChipsInput({
265
+ className,
266
+ ...props
267
+ }: ComboboxPrimitive.Input.Props) {
268
+ return (
269
+ <ComboboxPrimitive.Input
270
+ data-slot="combobox-chip-input"
271
+ className={cn("min-w-16 flex-1 outline-none", className)}
272
+ {...props}
273
+ />
274
+ )
275
+ }
276
+
277
+ function useComboboxAnchor() {
278
+ return React.useRef<HTMLDivElement | null>(null)
279
+ }
280
+
281
+ export {
282
+ Combobox,
283
+ ComboboxInput,
284
+ ComboboxContent,
285
+ ComboboxList,
286
+ ComboboxItem,
287
+ ComboboxGroup,
288
+ ComboboxLabel,
289
+ ComboboxCollection,
290
+ ComboboxEmpty,
291
+ ComboboxSeparator,
292
+ ComboboxChips,
293
+ ComboboxChip,
294
+ ComboboxChipsInput,
295
+ ComboboxTrigger,
296
+ ComboboxValue,
297
+ useComboboxAnchor,
298
+ }
@@ -0,0 +1,272 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu"
5
+
6
+ import { cn } from "../lib/utils"
7
+ import { ChevronRightIcon, CheckIcon } from "lucide-react"
8
+
9
+ function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
10
+ return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
11
+ }
12
+
13
+ function ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) {
14
+ return (
15
+ <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
16
+ )
17
+ }
18
+
19
+ function ContextMenuTrigger({
20
+ className,
21
+ ...props
22
+ }: ContextMenuPrimitive.Trigger.Props) {
23
+ return (
24
+ <ContextMenuPrimitive.Trigger
25
+ data-slot="context-menu-trigger"
26
+ className={cn("select-none", className)}
27
+ {...props}
28
+ />
29
+ )
30
+ }
31
+
32
+ function ContextMenuContent({
33
+ className,
34
+ align = "start",
35
+ alignOffset = 4,
36
+ side = "right",
37
+ sideOffset = 0,
38
+ ...props
39
+ }: ContextMenuPrimitive.Popup.Props &
40
+ Pick<
41
+ ContextMenuPrimitive.Positioner.Props,
42
+ "align" | "alignOffset" | "side" | "sideOffset"
43
+ >) {
44
+ return (
45
+ <ContextMenuPrimitive.Portal>
46
+ <ContextMenuPrimitive.Positioner
47
+ className="isolate z-50 outline-none"
48
+ align={align}
49
+ alignOffset={alignOffset}
50
+ side={side}
51
+ sideOffset={sideOffset}
52
+ >
53
+ <ContextMenuPrimitive.Popup
54
+ data-koharu-ui-layer=""
55
+ data-slot="context-menu-content"
56
+ className={cn("z-50 max-h-(--available-height) min-w-36 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:fade-out-0 data-closed:zoom-out-95", className )}
57
+ {...props}
58
+ />
59
+ </ContextMenuPrimitive.Positioner>
60
+ </ContextMenuPrimitive.Portal>
61
+ )
62
+ }
63
+
64
+ function ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) {
65
+ return (
66
+ <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
67
+ )
68
+ }
69
+
70
+ function ContextMenuLabel({
71
+ className,
72
+ inset,
73
+ ...props
74
+ }: ContextMenuPrimitive.GroupLabel.Props & {
75
+ inset?: boolean
76
+ }) {
77
+ return (
78
+ <ContextMenuPrimitive.GroupLabel
79
+ data-slot="context-menu-label"
80
+ data-inset={inset}
81
+ className={cn(
82
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
83
+ className
84
+ )}
85
+ {...props}
86
+ />
87
+ )
88
+ }
89
+
90
+ function ContextMenuItem({
91
+ className,
92
+ inset,
93
+ variant = "default",
94
+ ...props
95
+ }: ContextMenuPrimitive.Item.Props & {
96
+ inset?: boolean
97
+ variant?: "default" | "destructive"
98
+ }) {
99
+ return (
100
+ <ContextMenuPrimitive.Item
101
+ data-slot="context-menu-item"
102
+ data-inset={inset}
103
+ data-variant={variant}
104
+ className={cn(
105
+ "group/context-menu-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 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 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive",
106
+ className
107
+ )}
108
+ {...props}
109
+ />
110
+ )
111
+ }
112
+
113
+ function ContextMenuSub({ ...props }: ContextMenuPrimitive.SubmenuRoot.Props) {
114
+ return (
115
+ <ContextMenuPrimitive.SubmenuRoot data-slot="context-menu-sub" {...props} />
116
+ )
117
+ }
118
+
119
+ function ContextMenuSubTrigger({
120
+ className,
121
+ inset,
122
+ children,
123
+ ...props
124
+ }: ContextMenuPrimitive.SubmenuTrigger.Props & {
125
+ inset?: boolean
126
+ }) {
127
+ return (
128
+ <ContextMenuPrimitive.SubmenuTrigger
129
+ data-slot="context-menu-sub-trigger"
130
+ data-inset={inset}
131
+ className={cn(
132
+ "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 data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
133
+ className
134
+ )}
135
+ {...props}
136
+ >
137
+ {children}
138
+ <ChevronRightIcon className="ml-auto" />
139
+ </ContextMenuPrimitive.SubmenuTrigger>
140
+ )
141
+ }
142
+
143
+ function ContextMenuSubContent({
144
+ ...props
145
+ }: React.ComponentProps<typeof ContextMenuContent>) {
146
+ return (
147
+ <ContextMenuContent
148
+ data-slot="context-menu-sub-content"
149
+ className="shadow-lg"
150
+ side="right"
151
+ {...props}
152
+ />
153
+ )
154
+ }
155
+
156
+ function ContextMenuCheckboxItem({
157
+ className,
158
+ children,
159
+ checked,
160
+ inset,
161
+ ...props
162
+ }: ContextMenuPrimitive.CheckboxItem.Props & {
163
+ inset?: boolean
164
+ }) {
165
+ return (
166
+ <ContextMenuPrimitive.CheckboxItem
167
+ data-slot="context-menu-checkbox-item"
168
+ data-inset={inset}
169
+ className={cn(
170
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent 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",
171
+ className
172
+ )}
173
+ checked={checked}
174
+ {...props}
175
+ >
176
+ <span className="pointer-events-none absolute right-2">
177
+ <ContextMenuPrimitive.CheckboxItemIndicator>
178
+ <CheckIcon
179
+ />
180
+ </ContextMenuPrimitive.CheckboxItemIndicator>
181
+ </span>
182
+ {children}
183
+ </ContextMenuPrimitive.CheckboxItem>
184
+ )
185
+ }
186
+
187
+ function ContextMenuRadioGroup({
188
+ ...props
189
+ }: ContextMenuPrimitive.RadioGroup.Props) {
190
+ return (
191
+ <ContextMenuPrimitive.RadioGroup
192
+ data-slot="context-menu-radio-group"
193
+ {...props}
194
+ />
195
+ )
196
+ }
197
+
198
+ function ContextMenuRadioItem({
199
+ className,
200
+ children,
201
+ inset,
202
+ ...props
203
+ }: ContextMenuPrimitive.RadioItem.Props & {
204
+ inset?: boolean
205
+ }) {
206
+ return (
207
+ <ContextMenuPrimitive.RadioItem
208
+ data-slot="context-menu-radio-item"
209
+ data-inset={inset}
210
+ className={cn(
211
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent 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",
212
+ className
213
+ )}
214
+ {...props}
215
+ >
216
+ <span className="pointer-events-none absolute right-2">
217
+ <ContextMenuPrimitive.RadioItemIndicator>
218
+ <CheckIcon
219
+ />
220
+ </ContextMenuPrimitive.RadioItemIndicator>
221
+ </span>
222
+ {children}
223
+ </ContextMenuPrimitive.RadioItem>
224
+ )
225
+ }
226
+
227
+ function ContextMenuSeparator({
228
+ className,
229
+ ...props
230
+ }: ContextMenuPrimitive.Separator.Props) {
231
+ return (
232
+ <ContextMenuPrimitive.Separator
233
+ data-slot="context-menu-separator"
234
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
235
+ {...props}
236
+ />
237
+ )
238
+ }
239
+
240
+ function ContextMenuShortcut({
241
+ className,
242
+ ...props
243
+ }: React.ComponentProps<"span">) {
244
+ return (
245
+ <span
246
+ data-slot="context-menu-shortcut"
247
+ className={cn(
248
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground",
249
+ className
250
+ )}
251
+ {...props}
252
+ />
253
+ )
254
+ }
255
+
256
+ export {
257
+ ContextMenu,
258
+ ContextMenuTrigger,
259
+ ContextMenuContent,
260
+ ContextMenuItem,
261
+ ContextMenuCheckboxItem,
262
+ ContextMenuRadioItem,
263
+ ContextMenuLabel,
264
+ ContextMenuSeparator,
265
+ ContextMenuShortcut,
266
+ ContextMenuGroup,
267
+ ContextMenuPortal,
268
+ ContextMenuSub,
269
+ ContextMenuSubContent,
270
+ ContextMenuSubTrigger,
271
+ ContextMenuRadioGroup,
272
+ }