@shadow-js/ui 0.0.0-stage → 1.0.1
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.
- package/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +598 -2
- package/dist/cli.mjs +2281 -0
- package/dist/dev/cli/schema.d.ts +71 -0
- package/dist/dev/index.d.ts +6 -0
- package/dist/dev/index.js +5 -0
- package/dist/dev/locales/ar.d.ts +139 -0
- package/dist/dev/locales/ar.js +127 -0
- package/dist/dev/locales/ar.js.map +1 -0
- package/dist/dev/locales/en.d.ts +139 -0
- package/dist/dev/locales/en.js +127 -0
- package/dist/dev/locales/en.js.map +1 -0
- package/dist/dev/registry/utils/utils.d.ts +27 -0
- package/dist/dev/registry/utils/utils.js +26 -0
- package/dist/dev/registry/utils/utils.js.map +1 -0
- package/dist/dev/theme/theme-logic.d.ts +185 -0
- package/dist/dev/theme/theme-logic.js +183 -0
- package/dist/dev/theme/theme-logic.js.map +1 -0
- package/dist/dev/theme/theme-provider.d.ts +88 -0
- package/dist/dev/theme/theme-provider.js +149 -0
- package/dist/dev/theme/theme-provider.js.map +1 -0
- package/dist/prod/index.js +1 -0
- package/dist/prod/locales/ar.js +2 -0
- package/dist/prod/locales/ar.js.map +1 -0
- package/dist/prod/locales/en.js +2 -0
- package/dist/prod/locales/en.js.map +1 -0
- package/dist/prod/registry/utils/utils.js +2 -0
- package/dist/prod/registry/utils/utils.js.map +1 -0
- package/dist/prod/theme/theme-logic.js +2 -0
- package/dist/prod/theme/theme-logic.js.map +1 -0
- package/dist/prod/theme/theme-provider.js +2 -0
- package/dist/prod/theme/theme-provider.js.map +1 -0
- package/package.json +102 -4
- package/registry/accordion/accordion.tsx +210 -0
- package/registry/accordion/item.json +4 -0
- package/registry/alert/alert.tsx +200 -0
- package/registry/alert/item.json +4 -0
- package/registry/alert-dialog/alert-dialog.tsx +530 -0
- package/registry/alert-dialog/item.json +4 -0
- package/registry/aspect-ratio/aspect-ratio.tsx +71 -0
- package/registry/aspect-ratio/item.json +4 -0
- package/registry/attachment/attachment.tsx +459 -0
- package/registry/attachment/item.json +4 -0
- package/registry/avatar/avatar.tsx +385 -0
- package/registry/avatar/item.json +4 -0
- package/registry/badge/badge.tsx +108 -0
- package/registry/badge/item.json +4 -0
- package/registry/breadcrumb/breadcrumb.tsx +354 -0
- package/registry/breadcrumb/item.json +4 -0
- package/registry/bubble/bubble.tsx +260 -0
- package/registry/bubble/item.json +4 -0
- package/registry/button/button.tsx +125 -0
- package/registry/button/item.json +4 -0
- package/registry/button-group/button-group.tsx +189 -0
- package/registry/button-group/item.json +4 -0
- package/registry/calendar/calendar.tsx +348 -0
- package/registry/calendar/item.json +4 -0
- package/registry/card/card.tsx +311 -0
- package/registry/card/item.json +4 -0
- package/registry/carousel/carousel.tsx +851 -0
- package/registry/carousel/item.json +4 -0
- package/registry/chart/chart.tsx +1956 -0
- package/registry/chart/item.json +4 -0
- package/registry/chart-scale/chart-scale.ts +670 -0
- package/registry/chart-scale/item.json +5 -0
- package/registry/checkbox/checkbox.tsx +79 -0
- package/registry/checkbox/item.json +4 -0
- package/registry/code-block/code-block.tsx +470 -0
- package/registry/code-block/item.json +4 -0
- package/registry/collapsible/collapsible.tsx +117 -0
- package/registry/collapsible/item.json +4 -0
- package/registry/combobox/combobox.tsx +977 -0
- package/registry/combobox/item.json +4 -0
- package/registry/command/command.tsx +757 -0
- package/registry/command/item.json +4 -0
- package/registry/context-menu/context-menu.tsx +697 -0
- package/registry/context-menu/item.json +4 -0
- package/registry/data-table/data-table.tsx +437 -0
- package/registry/data-table/item.json +4 -0
- package/registry/date-picker/date-picker.tsx +349 -0
- package/registry/date-picker/item.json +4 -0
- package/registry/dialog/dialog.tsx +412 -0
- package/registry/dialog/item.json +4 -0
- package/registry/direction/direction.tsx +88 -0
- package/registry/direction/item.json +4 -0
- package/registry/drawer/drawer.tsx +787 -0
- package/registry/drawer/item.json +4 -0
- package/registry/dropdown-menu/dropdown-menu.tsx +692 -0
- package/registry/dropdown-menu/item.json +4 -0
- package/registry/empty/empty.tsx +240 -0
- package/registry/empty/item.json +4 -0
- package/registry/field/field.tsx +624 -0
- package/registry/field/item.json +4 -0
- package/registry/form/form.tsx +1112 -0
- package/registry/form/item.json +4 -0
- package/registry/hover-card/hover-card.tsx +144 -0
- package/registry/hover-card/item.json +4 -0
- package/registry/icons/icons.tsx +1691 -0
- package/registry/icons/item.json +4 -0
- package/registry/input/input.tsx +43 -0
- package/registry/input/item.json +4 -0
- package/registry/input-group/input-group.tsx +315 -0
- package/registry/input-group/item.json +4 -0
- package/registry/input-otp/input-otp.tsx +329 -0
- package/registry/input-otp/item.json +4 -0
- package/registry/item/item.json +4 -0
- package/registry/item/item.tsx +439 -0
- package/registry/kbd/item.json +4 -0
- package/registry/kbd/kbd.tsx +65 -0
- package/registry/label/item.json +4 -0
- package/registry/label/label.tsx +60 -0
- package/registry/marker/item.json +4 -0
- package/registry/marker/marker.tsx +175 -0
- package/registry/menubar/item.json +4 -0
- package/registry/menubar/menubar.tsx +694 -0
- package/registry/message/item.json +4 -0
- package/registry/message/message.tsx +280 -0
- package/registry/message-scroller/item.json +4 -0
- package/registry/message-scroller/message-scroller.tsx +262 -0
- package/registry/native-select/item.json +4 -0
- package/registry/native-select/native-select.tsx +113 -0
- package/registry/navigation-menu/item.json +4 -0
- package/registry/navigation-menu/navigation-menu.tsx +362 -0
- package/registry/pagination/item.json +4 -0
- package/registry/pagination/pagination.tsx +460 -0
- package/registry/password-input/item.json +5 -0
- package/registry/password-input/password-input.tsx +494 -0
- package/registry/popover/item.json +4 -0
- package/registry/popover/popover.tsx +284 -0
- package/registry/progress/item.json +4 -0
- package/registry/progress/progress.tsx +190 -0
- package/registry/questionnaire/item.json +4 -0
- package/registry/questionnaire/questionnaire.tsx +569 -0
- package/registry/radio-group/item.json +4 -0
- package/registry/radio-group/radio-group.tsx +101 -0
- package/registry/resizable/item.json +4 -0
- package/registry/resizable/resizable.tsx +455 -0
- package/registry/scroll-area/item.json +4 -0
- package/registry/scroll-area/scroll-area.tsx +149 -0
- package/registry/select/item.json +4 -0
- package/registry/select/select.tsx +571 -0
- package/registry/separator/item.json +4 -0
- package/registry/separator/separator.tsx +52 -0
- package/registry/sheet/item.json +4 -0
- package/registry/sheet/sheet.tsx +476 -0
- package/registry/sidebar/item.json +4 -0
- package/registry/sidebar/sidebar.tsx +1870 -0
- package/registry/skeleton/item.json +4 -0
- package/registry/skeleton/skeleton.tsx +47 -0
- package/registry/slider/item.json +4 -0
- package/registry/slider/slider.tsx +149 -0
- package/registry/spinner/item.json +4 -0
- package/registry/spinner/spinner.tsx +51 -0
- package/registry/switch/item.json +4 -0
- package/registry/switch/switch.tsx +93 -0
- package/registry/table/item.json +4 -0
- package/registry/table/table.tsx +373 -0
- package/registry/tabs/item.json +4 -0
- package/registry/tabs/tabs.tsx +209 -0
- package/registry/textarea/item.json +4 -0
- package/registry/textarea/textarea.tsx +51 -0
- package/registry/toast/item.json +4 -0
- package/registry/toast/toast.tsx +949 -0
- package/registry/toggle/item.json +4 -0
- package/registry/toggle/toggle.tsx +110 -0
- package/registry/toggle-group/item.json +4 -0
- package/registry/toggle-group/toggle-group.tsx +189 -0
- package/registry/tooltip/item.json +4 -0
- package/registry/tooltip/tooltip.tsx +169 -0
- package/registry/trace/item.json +4 -0
- package/registry/trace/trace.tsx +356 -0
- package/registry/ui-strings/item.json +5 -0
- package/registry/ui-strings/ui-strings.tsx +454 -0
- package/registry/use-highlighted-code/item.json +5 -0
- package/registry/use-highlighted-code/use-highlighted-code.tsx +145 -0
- package/registry/use-mobile/item.json +5 -0
- package/registry/use-mobile/use-mobile.ts +46 -0
- package/registry/utils/item.json +5 -0
- package/registry/utils/utils.ts +38 -0
- package/registry.json +3274 -0
- package/styles/animations.css +321 -0
- package/styles/theme-core.css +55 -0
- package/styles/theme.css +12 -0
- package/styles/themes/gray.css +69 -0
- package/styles/themes/neutral.css +69 -0
- package/styles/themes/slate.css +69 -0
- package/styles/themes/stone.css +69 -0
- package/styles/themes/zinc.css +69 -0
- package/styles/typeset.css +251 -0
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
import { splitProps } from "@shadow-js/core";
|
|
2
|
+
import {
|
|
3
|
+
type ContextMenuContentProps,
|
|
4
|
+
ContextMenu as ContextMenuPrimitive,
|
|
5
|
+
type ContextMenuProps,
|
|
6
|
+
type ContextMenuTriggerProps,
|
|
7
|
+
type MenuCheckboxItemProps,
|
|
8
|
+
type MenuGroupProps,
|
|
9
|
+
type MenuItemOwnProps,
|
|
10
|
+
type MenuLabelProps,
|
|
11
|
+
type MenuPortalProps,
|
|
12
|
+
type MenuRadioGroupProps,
|
|
13
|
+
type MenuRadioItemProps,
|
|
14
|
+
type MenuSeparatorProps,
|
|
15
|
+
type MenuSubContentProps,
|
|
16
|
+
type MenuSubProps,
|
|
17
|
+
type MenuSubTriggerProps,
|
|
18
|
+
type PolymorphicProps,
|
|
19
|
+
type PolymorphicTarget,
|
|
20
|
+
} from "@shadow-js/primitives";
|
|
21
|
+
import type { ComponentProps, JSX } from "@shadow-js/web";
|
|
22
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "@/components/ui/icons";
|
|
23
|
+
import { type ClassValue, cn } from "@/lib/utils";
|
|
24
|
+
|
|
25
|
+
/** The props as the implementation sees them: the typed own props plus whatever the target takes. */
|
|
26
|
+
type Loose = {
|
|
27
|
+
readonly as?: PolymorphicTarget;
|
|
28
|
+
readonly class?: ClassValue;
|
|
29
|
+
readonly inset?: boolean | undefined;
|
|
30
|
+
readonly variant?: "default" | "destructive" | undefined;
|
|
31
|
+
readonly children?: JSX.Element | undefined;
|
|
32
|
+
readonly [prop: string]: unknown;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** The placement and entrance animation shared by the menu panels. */
|
|
36
|
+
const PANEL =
|
|
37
|
+
"z-50 min-w-[8rem] origin-(--primitives-transform-origin) rounded-md border bg-popover p-1 text-popover-foreground outline-hidden 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-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95";
|
|
38
|
+
|
|
39
|
+
/** What every selectable row shares. */
|
|
40
|
+
const ROW =
|
|
41
|
+
"relative flex cursor-default items-center gap-2 rounded-sm text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 forced-colors:focus:bg-[Highlight] forced-colors:focus:text-[HighlightText] forced-colors:data-[disabled]:text-[GrayText] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A menu opened at the pointer by a right click, the keyboard's menu key or Shift+F10, or by a long
|
|
45
|
+
* press on touch. Use it for actions on one area of the page, such as a canvas or a file row.
|
|
46
|
+
* `dir="rtl"` mirrors the arrow keys and the side of submenus.
|
|
47
|
+
*
|
|
48
|
+
* Keyboard and ARIA: Shift+F10 or the ContextMenu key on the focused trigger opens the menu with its
|
|
49
|
+
* first item focused. The menu is a `role="menu"` of `menuitem`, `menuitemcheckbox` and
|
|
50
|
+
* `menuitemradio` items. Arrow keys, Home, End and typeahead move between items, Enter or Space
|
|
51
|
+
* selects the focused item, and Escape or Tab closes the menu and returns focus to the element that had it before the menu opened. The
|
|
52
|
+
* trigger is a Tab stop and has no role of its own. A disabled item is skipped by the arrow keys and
|
|
53
|
+
* cannot be selected.
|
|
54
|
+
*
|
|
55
|
+
* shadcn/ui differences: the trigger renders a `span`, so pass `as="div"` for a block-level area.
|
|
56
|
+
* `as` replaces `asChild`. The prop is `class`, not `className`, and every part has a `data-slot`.
|
|
57
|
+
*
|
|
58
|
+
* @param props The root props: see {@link ContextMenuProps}.
|
|
59
|
+
* @returns The menu, which renders no element of its own.
|
|
60
|
+
* @example
|
|
61
|
+
* import {
|
|
62
|
+
* ContextMenu,
|
|
63
|
+
* ContextMenuContent,
|
|
64
|
+
* ContextMenuItem,
|
|
65
|
+
* ContextMenuTrigger,
|
|
66
|
+
* } from "@/components/ui/context-menu";
|
|
67
|
+
*
|
|
68
|
+
* export function Canvas() {
|
|
69
|
+
* return (
|
|
70
|
+
* <ContextMenu>
|
|
71
|
+
* <ContextMenuTrigger class="flex h-40 w-72 items-center justify-center rounded-md border border-dashed">
|
|
72
|
+
* Right click here
|
|
73
|
+
* </ContextMenuTrigger>
|
|
74
|
+
* <ContextMenuContent class="w-52">
|
|
75
|
+
* <ContextMenuItem>Back</ContextMenuItem>
|
|
76
|
+
* <ContextMenuItem>Forward</ContextMenuItem>
|
|
77
|
+
* </ContextMenuContent>
|
|
78
|
+
* </ContextMenu>
|
|
79
|
+
* );
|
|
80
|
+
* }
|
|
81
|
+
* @see {@link ContextMenuTrigger}
|
|
82
|
+
* @see {@link ContextMenuContent}
|
|
83
|
+
* @since 1.0.0
|
|
84
|
+
*/
|
|
85
|
+
function ContextMenu(props: ContextMenuProps): JSX.Element {
|
|
86
|
+
return <ContextMenuPrimitive {...props} />;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Renders the menu into `document.body`, or into the `container` you pass, while it is open. Nothing
|
|
91
|
+
* is rendered on the server. {@link ContextMenuContent} already portals itself, so use this only to
|
|
92
|
+
* choose another container.
|
|
93
|
+
*
|
|
94
|
+
* @param props The portal props: `container` (where to render the menu) and `forceMount`.
|
|
95
|
+
* @returns The portal, or nothing while the menu is closed.
|
|
96
|
+
* @example
|
|
97
|
+
* import {
|
|
98
|
+
* ContextMenu,
|
|
99
|
+
* ContextMenuContent,
|
|
100
|
+
* ContextMenuItem,
|
|
101
|
+
* ContextMenuPortal,
|
|
102
|
+
* ContextMenuTrigger,
|
|
103
|
+
* } from "@/components/ui/context-menu";
|
|
104
|
+
*
|
|
105
|
+
* export function Panel() {
|
|
106
|
+
* return (
|
|
107
|
+
* <ContextMenu>
|
|
108
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
109
|
+
* <ContextMenuPortal>
|
|
110
|
+
* <ContextMenuContent>
|
|
111
|
+
* <ContextMenuItem>Back</ContextMenuItem>
|
|
112
|
+
* </ContextMenuContent>
|
|
113
|
+
* </ContextMenuPortal>
|
|
114
|
+
* </ContextMenu>
|
|
115
|
+
* );
|
|
116
|
+
* }
|
|
117
|
+
* @see {@link ContextMenuContent}
|
|
118
|
+
* @since 1.0.0
|
|
119
|
+
*/
|
|
120
|
+
function ContextMenuPortal(props: MenuPortalProps): JSX.Element {
|
|
121
|
+
return <ContextMenuPrimitive.Portal {...props} />;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The area that opens the menu. It renders a focusable `span` (a Tab stop); pass `as="div"` for a
|
|
126
|
+
* block-level area. A right click, a touch or pen held down for 700 ms, Shift+F10 and the ContextMenu
|
|
127
|
+
* key open the menu at the trigger. Set `disabled` to keep the browser's own context menu.
|
|
128
|
+
*
|
|
129
|
+
* @param props The trigger props: the attributes of the rendered element, `as`, and `disabled`.
|
|
130
|
+
* @returns The trigger element.
|
|
131
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
132
|
+
* @example
|
|
133
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
134
|
+
*
|
|
135
|
+
* export function Row() {
|
|
136
|
+
* return (
|
|
137
|
+
* <ContextMenu>
|
|
138
|
+
* <ContextMenuTrigger as="div" class="h-40 rounded-md border">
|
|
139
|
+
* Right click here
|
|
140
|
+
* </ContextMenuTrigger>
|
|
141
|
+
* <ContextMenuContent>
|
|
142
|
+
* <ContextMenuItem>Back</ContextMenuItem>
|
|
143
|
+
* </ContextMenuContent>
|
|
144
|
+
* </ContextMenu>
|
|
145
|
+
* );
|
|
146
|
+
* }
|
|
147
|
+
* @see {@link ContextMenu}
|
|
148
|
+
* @since 1.0.0
|
|
149
|
+
*/
|
|
150
|
+
function ContextMenuTrigger<T extends PolymorphicTarget = "span">(
|
|
151
|
+
props: ContextMenuTriggerProps<T>,
|
|
152
|
+
): JSX.Element {
|
|
153
|
+
return <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The menu panel. It is rendered in `document.body` and placed beside the point that opened it, and
|
|
158
|
+
* it takes focus when it opens. Its height is limited to the space available in the viewport.
|
|
159
|
+
*
|
|
160
|
+
* @param props The panel props: the attributes of the rendered `div` and `class`, which is merged with
|
|
161
|
+
* the panel classes.
|
|
162
|
+
* @returns The panel, rendered in a portal.
|
|
163
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
164
|
+
* @example
|
|
165
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
166
|
+
*
|
|
167
|
+
* export function Menu() {
|
|
168
|
+
* return (
|
|
169
|
+
* <ContextMenu>
|
|
170
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
171
|
+
* <ContextMenuContent class="w-52">
|
|
172
|
+
* <ContextMenuItem>Back</ContextMenuItem>
|
|
173
|
+
* </ContextMenuContent>
|
|
174
|
+
* </ContextMenu>
|
|
175
|
+
* );
|
|
176
|
+
* }
|
|
177
|
+
* @see {@link ContextMenuTrigger}
|
|
178
|
+
* @since 1.0.0
|
|
179
|
+
*/
|
|
180
|
+
function ContextMenuContent(props: ContextMenuContentProps): JSX.Element {
|
|
181
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
182
|
+
return (
|
|
183
|
+
<ContextMenuPortal>
|
|
184
|
+
<ContextMenuPrimitive.Content
|
|
185
|
+
data-slot="context-menu-content"
|
|
186
|
+
class={cn(
|
|
187
|
+
PANEL,
|
|
188
|
+
"max-h-(--primitives-available-height) overflow-x-hidden overflow-y-auto shadow-md",
|
|
189
|
+
local.class,
|
|
190
|
+
)}
|
|
191
|
+
{...rest}
|
|
192
|
+
/>
|
|
193
|
+
</ContextMenuPortal>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* A group of related items, announced as a `role="group"`. The arrow keys skip it.
|
|
199
|
+
*
|
|
200
|
+
* @param props The group props: the attributes of the rendered `div`.
|
|
201
|
+
* @returns The group.
|
|
202
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
203
|
+
* @example
|
|
204
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
205
|
+
*
|
|
206
|
+
* export function Account() {
|
|
207
|
+
* return (
|
|
208
|
+
* <ContextMenu>
|
|
209
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
210
|
+
* <ContextMenuContent>
|
|
211
|
+
* <ContextMenuGroup>
|
|
212
|
+
* <ContextMenuItem>Profile</ContextMenuItem>
|
|
213
|
+
* </ContextMenuGroup>
|
|
214
|
+
* </ContextMenuContent>
|
|
215
|
+
* </ContextMenu>
|
|
216
|
+
* );
|
|
217
|
+
* }
|
|
218
|
+
* @see {@link ContextMenuItem}
|
|
219
|
+
* @since 1.0.0
|
|
220
|
+
*/
|
|
221
|
+
function ContextMenuGroup(props: MenuGroupProps): JSX.Element {
|
|
222
|
+
return <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Own props of {@link ContextMenuItem}: the extra parts the item adds to the menu item props.
|
|
227
|
+
* @see {@link ContextMenuItem}
|
|
228
|
+
* @since 1.0.0
|
|
229
|
+
*/
|
|
230
|
+
export interface ContextMenuItemExtraProps {
|
|
231
|
+
/**
|
|
232
|
+
* Indents the item so it lines up with items that have an indicator.
|
|
233
|
+
* @default false
|
|
234
|
+
*/
|
|
235
|
+
readonly inset?: boolean | undefined;
|
|
236
|
+
/**
|
|
237
|
+
* Colors the item for a dangerous action when `destructive`.
|
|
238
|
+
* @default "default"
|
|
239
|
+
*/
|
|
240
|
+
readonly variant?: "default" | "destructive" | undefined;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Props of {@link ContextMenuItem}: `onSelect` (called when the item is picked, and `preventDefault()`
|
|
245
|
+
* keeps the menu open), `disabled`, `inset`, `variant` and every attribute of the chosen element.
|
|
246
|
+
* @see {@link ContextMenuItem}
|
|
247
|
+
* @since 1.0.0
|
|
248
|
+
*/
|
|
249
|
+
export type ContextMenuItemProps<T extends PolymorphicTarget = "div"> = PolymorphicProps<
|
|
250
|
+
"div",
|
|
251
|
+
MenuItemOwnProps & ContextMenuItemExtraProps,
|
|
252
|
+
T
|
|
253
|
+
>;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* An action in the menu. Selecting it, by a click, by Enter or by Space, closes the menu unless
|
|
257
|
+
* `onSelect` calls `event.preventDefault()`. A disabled item is skipped by the arrow keys and cannot
|
|
258
|
+
* be selected. While it has focus it has `data-highlighted`.
|
|
259
|
+
*
|
|
260
|
+
* Keyboard and ARIA: the item is a `role="menuitem"` with `tabindex="-1"`; the menu moves focus to it.
|
|
261
|
+
* The item renders as a `div` by default. shadcn's `asChild` is the `as` prop here, for example
|
|
262
|
+
* `<ContextMenuItem as="a" href="/settings">`.
|
|
263
|
+
*
|
|
264
|
+
* @param props The item props: see {@link ContextMenuItemProps}.
|
|
265
|
+
* @returns The menu item.
|
|
266
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
267
|
+
* @example
|
|
268
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
269
|
+
*
|
|
270
|
+
* export function Delete() {
|
|
271
|
+
* const remove = (): void => {
|
|
272
|
+
* // Delete the selected row here.
|
|
273
|
+
* };
|
|
274
|
+
* return (
|
|
275
|
+
* <ContextMenu>
|
|
276
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
277
|
+
* <ContextMenuContent>
|
|
278
|
+
* <ContextMenuItem variant="destructive" onSelect={remove}>
|
|
279
|
+
* Delete
|
|
280
|
+
* </ContextMenuItem>
|
|
281
|
+
* </ContextMenuContent>
|
|
282
|
+
* </ContextMenu>
|
|
283
|
+
* );
|
|
284
|
+
* }
|
|
285
|
+
* @see {@link ContextMenuContent}
|
|
286
|
+
* @see {@link ContextMenuCheckboxItem}
|
|
287
|
+
* @since 1.0.0
|
|
288
|
+
*/
|
|
289
|
+
function ContextMenuItem<T extends PolymorphicTarget = "div">(
|
|
290
|
+
props: ContextMenuItemProps<T>,
|
|
291
|
+
): JSX.Element {
|
|
292
|
+
const [local, rest] = splitProps(props as unknown as Loose, ["class", "inset", "variant"]);
|
|
293
|
+
return (
|
|
294
|
+
<ContextMenuPrimitive.Item
|
|
295
|
+
data-slot="context-menu-item"
|
|
296
|
+
data-inset={local.inset === true ? "" : undefined}
|
|
297
|
+
data-variant={local.variant ?? "default"}
|
|
298
|
+
class={cn(
|
|
299
|
+
ROW,
|
|
300
|
+
"px-2 py-1.5 data-[inset]:ps-8 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-[variant=destructive]:*:[svg]:text-destructive! [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
301
|
+
local.class,
|
|
302
|
+
)}
|
|
303
|
+
{...rest}
|
|
304
|
+
/>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* An item that toggles a boolean and shows a check mark while it is checked. Enter, Space and a click
|
|
310
|
+
* toggle it, and it has `role="menuitemcheckbox"` with `aria-checked` (`"mixed"` while indeterminate).
|
|
311
|
+
* The state changes even when `onSelect` keeps the menu open.
|
|
312
|
+
*
|
|
313
|
+
* @param props The item props: `checked` (`true`, `false` or `"indeterminate"`), `onCheckedChange`, and
|
|
314
|
+
* the attributes of the item.
|
|
315
|
+
* @returns The checkbox item.
|
|
316
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
317
|
+
* @example
|
|
318
|
+
* import { useSignal } from "@shadow-js/core";
|
|
319
|
+
* import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
320
|
+
*
|
|
321
|
+
* export function View() {
|
|
322
|
+
* const [bookmarks, setBookmarks] = useSignal(true);
|
|
323
|
+
* return (
|
|
324
|
+
* <ContextMenu>
|
|
325
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
326
|
+
* <ContextMenuContent>
|
|
327
|
+
* <ContextMenuCheckboxItem checked={bookmarks()} onCheckedChange={setBookmarks}>
|
|
328
|
+
* Show bookmarks
|
|
329
|
+
* </ContextMenuCheckboxItem>
|
|
330
|
+
* </ContextMenuContent>
|
|
331
|
+
* </ContextMenu>
|
|
332
|
+
* );
|
|
333
|
+
* }
|
|
334
|
+
* @see {@link ContextMenuRadioGroup}
|
|
335
|
+
* @since 1.0.0
|
|
336
|
+
*/
|
|
337
|
+
function ContextMenuCheckboxItem(props: MenuCheckboxItemProps): JSX.Element {
|
|
338
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
339
|
+
return (
|
|
340
|
+
<ContextMenuPrimitive.CheckboxItem
|
|
341
|
+
data-slot="context-menu-checkbox-item"
|
|
342
|
+
class={cn(ROW, "py-1.5 ps-8 pe-2", local.class)}
|
|
343
|
+
{...rest}
|
|
344
|
+
>
|
|
345
|
+
<span class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
|
|
346
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
347
|
+
<CheckIcon class="size-4" />
|
|
348
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
349
|
+
</span>
|
|
350
|
+
{local.children}
|
|
351
|
+
</ContextMenuPrimitive.CheckboxItem>
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* A group of mutually exclusive {@link ContextMenuRadioItem}s. It is a `role="group"` and handles no
|
|
357
|
+
* keys itself; the items are navigated like any other menu item.
|
|
358
|
+
*
|
|
359
|
+
* @param props The group props: `value` (the selected item's value), `onValueChange`, and the
|
|
360
|
+
* attributes of the rendered `div`.
|
|
361
|
+
* @returns The group.
|
|
362
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
363
|
+
* @example
|
|
364
|
+
* import { useSignal } from "@shadow-js/core";
|
|
365
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
366
|
+
*
|
|
367
|
+
* export function Position() {
|
|
368
|
+
* const [position, setPosition] = useSignal("bottom");
|
|
369
|
+
* return (
|
|
370
|
+
* <ContextMenu>
|
|
371
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
372
|
+
* <ContextMenuContent>
|
|
373
|
+
* <ContextMenuRadioGroup value={position()} onValueChange={setPosition}>
|
|
374
|
+
* <ContextMenuRadioItem value="top">Top</ContextMenuRadioItem>
|
|
375
|
+
* <ContextMenuRadioItem value="bottom">Bottom</ContextMenuRadioItem>
|
|
376
|
+
* </ContextMenuRadioGroup>
|
|
377
|
+
* </ContextMenuContent>
|
|
378
|
+
* </ContextMenu>
|
|
379
|
+
* );
|
|
380
|
+
* }
|
|
381
|
+
* @see {@link ContextMenuRadioItem}
|
|
382
|
+
* @since 1.0.0
|
|
383
|
+
*/
|
|
384
|
+
function ContextMenuRadioGroup(props: MenuRadioGroupProps): JSX.Element {
|
|
385
|
+
return <ContextMenuPrimitive.RadioGroup data-slot="context-menu-radio-group" {...props} />;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* An item of a {@link ContextMenuRadioGroup}, with a dot while it is the selected one. It is a
|
|
390
|
+
* `role="menuitemradio"` with `aria-checked`. Enter, Space and a click select it, even when `onSelect`
|
|
391
|
+
* keeps the menu open.
|
|
392
|
+
*
|
|
393
|
+
* @param props The item props: `value` and the attributes of the item.
|
|
394
|
+
* @returns The radio item.
|
|
395
|
+
* @throws Error when rendered outside a {@link ContextMenuRadioGroup}.
|
|
396
|
+
* @example
|
|
397
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
398
|
+
*
|
|
399
|
+
* export function Density() {
|
|
400
|
+
* return (
|
|
401
|
+
* <ContextMenu>
|
|
402
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
403
|
+
* <ContextMenuContent>
|
|
404
|
+
* <ContextMenuRadioGroup value="compact">
|
|
405
|
+
* <ContextMenuRadioItem value="compact">Compact</ContextMenuRadioItem>
|
|
406
|
+
* </ContextMenuRadioGroup>
|
|
407
|
+
* </ContextMenuContent>
|
|
408
|
+
* </ContextMenu>
|
|
409
|
+
* );
|
|
410
|
+
* }
|
|
411
|
+
* @see {@link ContextMenuRadioGroup}
|
|
412
|
+
* @since 1.0.0
|
|
413
|
+
*/
|
|
414
|
+
function ContextMenuRadioItem(props: MenuRadioItemProps): JSX.Element {
|
|
415
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
416
|
+
return (
|
|
417
|
+
<ContextMenuPrimitive.RadioItem
|
|
418
|
+
data-slot="context-menu-radio-item"
|
|
419
|
+
class={cn(ROW, "py-1.5 ps-8 pe-2", local.class)}
|
|
420
|
+
{...rest}
|
|
421
|
+
>
|
|
422
|
+
<span class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
|
|
423
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
424
|
+
<CircleIcon class="size-2 fill-current" />
|
|
425
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
426
|
+
</span>
|
|
427
|
+
{local.children}
|
|
428
|
+
</ContextMenuPrimitive.RadioItem>
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Props of {@link ContextMenuLabel}: the attributes of the rendered `div` and `inset`, which indents the
|
|
434
|
+
* heading to line up with indented items.
|
|
435
|
+
* @see {@link ContextMenuLabel}
|
|
436
|
+
* @since 1.0.0
|
|
437
|
+
*/
|
|
438
|
+
export type ContextMenuLabelProps = MenuLabelProps & {
|
|
439
|
+
/**
|
|
440
|
+
* Indents the heading to line up with items that have an indicator.
|
|
441
|
+
* @default false
|
|
442
|
+
*/
|
|
443
|
+
readonly inset?: boolean | undefined;
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* A heading for a group of items. It has no role, is not focusable, and the arrow keys skip it.
|
|
448
|
+
*
|
|
449
|
+
* @param props The heading props: see {@link ContextMenuLabelProps}.
|
|
450
|
+
* @returns The heading.
|
|
451
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
452
|
+
* @example
|
|
453
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
454
|
+
*
|
|
455
|
+
* export function AccountMenu() {
|
|
456
|
+
* return (
|
|
457
|
+
* <ContextMenu>
|
|
458
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
459
|
+
* <ContextMenuContent>
|
|
460
|
+
* <ContextMenuLabel>My Account</ContextMenuLabel>
|
|
461
|
+
* <ContextMenuGroup>
|
|
462
|
+
* <ContextMenuItem>Profile</ContextMenuItem>
|
|
463
|
+
* </ContextMenuGroup>
|
|
464
|
+
* </ContextMenuContent>
|
|
465
|
+
* </ContextMenu>
|
|
466
|
+
* );
|
|
467
|
+
* }
|
|
468
|
+
* @see {@link ContextMenuGroup}
|
|
469
|
+
* @since 1.0.0
|
|
470
|
+
*/
|
|
471
|
+
function ContextMenuLabel(props: ContextMenuLabelProps): JSX.Element {
|
|
472
|
+
const [local, rest] = splitProps(props, ["class", "inset"]);
|
|
473
|
+
return (
|
|
474
|
+
<ContextMenuPrimitive.Label
|
|
475
|
+
data-slot="context-menu-label"
|
|
476
|
+
data-inset={local.inset === true ? "" : undefined}
|
|
477
|
+
class={cn("px-2 py-1.5 text-sm font-medium data-[inset]:ps-8", local.class)}
|
|
478
|
+
{...rest}
|
|
479
|
+
/>
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* A divider between groups of items. It is a `role="separator"` with a horizontal orientation.
|
|
485
|
+
*
|
|
486
|
+
* @param props The separator props: the attributes of the rendered `div`.
|
|
487
|
+
* @returns The separator.
|
|
488
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
489
|
+
* @example
|
|
490
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
491
|
+
*
|
|
492
|
+
* export function Divided() {
|
|
493
|
+
* return (
|
|
494
|
+
* <ContextMenu>
|
|
495
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
496
|
+
* <ContextMenuContent>
|
|
497
|
+
* <ContextMenuItem>Back</ContextMenuItem>
|
|
498
|
+
* <ContextMenuSeparator />
|
|
499
|
+
* <ContextMenuItem>Delete</ContextMenuItem>
|
|
500
|
+
* </ContextMenuContent>
|
|
501
|
+
* </ContextMenu>
|
|
502
|
+
* );
|
|
503
|
+
* }
|
|
504
|
+
* @see {@link ContextMenuGroup}
|
|
505
|
+
* @since 1.0.0
|
|
506
|
+
*/
|
|
507
|
+
function ContextMenuSeparator(props: MenuSeparatorProps): JSX.Element {
|
|
508
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
509
|
+
return (
|
|
510
|
+
<ContextMenuPrimitive.Separator
|
|
511
|
+
data-slot="context-menu-separator"
|
|
512
|
+
class={cn("-mx-1 my-1 h-px bg-border", local.class)}
|
|
513
|
+
{...rest}
|
|
514
|
+
/>
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* A keyboard shortcut hint at the end of an item. It is decorative: it does not add a key binding.
|
|
520
|
+
*
|
|
521
|
+
* @param props The hint props: the attributes of the rendered `span`, and `children` (the shortcut text).
|
|
522
|
+
* @returns The hint.
|
|
523
|
+
* @example
|
|
524
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuShortcut, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
525
|
+
*
|
|
526
|
+
* export function Editing() {
|
|
527
|
+
* return (
|
|
528
|
+
* <ContextMenu>
|
|
529
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
530
|
+
* <ContextMenuContent>
|
|
531
|
+
* <ContextMenuItem>
|
|
532
|
+
* Save
|
|
533
|
+
* <ContextMenuShortcut>Ctrl+S</ContextMenuShortcut>
|
|
534
|
+
* </ContextMenuItem>
|
|
535
|
+
* </ContextMenuContent>
|
|
536
|
+
* </ContextMenu>
|
|
537
|
+
* );
|
|
538
|
+
* }
|
|
539
|
+
* @see {@link ContextMenuItem}
|
|
540
|
+
* @since 1.0.0
|
|
541
|
+
*/
|
|
542
|
+
function ContextMenuShortcut(props: ComponentProps<"span">): JSX.Element {
|
|
543
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
544
|
+
return (
|
|
545
|
+
<span
|
|
546
|
+
data-slot="context-menu-shortcut"
|
|
547
|
+
class={cn("ms-auto text-xs tracking-widest text-muted-foreground", local.class)}
|
|
548
|
+
{...rest}
|
|
549
|
+
/>
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* The root of a submenu. It renders no element; place a {@link ContextMenuSubTrigger} and a
|
|
555
|
+
* {@link ContextMenuSubContent} in it, inside a {@link ContextMenuContent}. The submenu closes when its
|
|
556
|
+
* menu does.
|
|
557
|
+
*
|
|
558
|
+
* @param props The submenu props: `open`, `defaultOpen` and `onOpenChange` of the submenu.
|
|
559
|
+
* @returns The submenu's context around its children.
|
|
560
|
+
* @throws Error when rendered outside a {@link ContextMenu}.
|
|
561
|
+
* @example
|
|
562
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
563
|
+
*
|
|
564
|
+
* export function Share() {
|
|
565
|
+
* return (
|
|
566
|
+
* <ContextMenu>
|
|
567
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
568
|
+
* <ContextMenuContent>
|
|
569
|
+
* <ContextMenuSub>
|
|
570
|
+
* <ContextMenuSubTrigger>Invite users</ContextMenuSubTrigger>
|
|
571
|
+
* <ContextMenuSubContent>
|
|
572
|
+
* <ContextMenuItem>Email</ContextMenuItem>
|
|
573
|
+
* </ContextMenuSubContent>
|
|
574
|
+
* </ContextMenuSub>
|
|
575
|
+
* </ContextMenuContent>
|
|
576
|
+
* </ContextMenu>
|
|
577
|
+
* );
|
|
578
|
+
* }
|
|
579
|
+
* @see {@link ContextMenuSubTrigger}
|
|
580
|
+
* @see {@link ContextMenuSubContent}
|
|
581
|
+
* @since 1.0.0
|
|
582
|
+
*/
|
|
583
|
+
function ContextMenuSub(props: MenuSubProps): JSX.Element {
|
|
584
|
+
return <ContextMenuPrimitive.Sub {...props} />;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* The item that opens a submenu, with a chevron that points the other way in right-to-left layouts.
|
|
589
|
+
* It is a `role="menuitem"` with `aria-haspopup="menu"` and `aria-expanded`. ArrowRight opens the
|
|
590
|
+
* submenu (ArrowLeft in right-to-left layouts), and the item has `data-state="open"` or
|
|
591
|
+
* `data-state="closed"`.
|
|
592
|
+
*
|
|
593
|
+
* @param props The trigger props: the attributes of the rendered `div`, `inset`, and `children`.
|
|
594
|
+
* @returns The submenu trigger.
|
|
595
|
+
* @throws Error when rendered outside a {@link ContextMenuSub}.
|
|
596
|
+
* @example
|
|
597
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
598
|
+
*
|
|
599
|
+
* export function Invite() {
|
|
600
|
+
* return (
|
|
601
|
+
* <ContextMenu>
|
|
602
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
603
|
+
* <ContextMenuContent>
|
|
604
|
+
* <ContextMenuSub>
|
|
605
|
+
* <ContextMenuSubTrigger inset>Invite users</ContextMenuSubTrigger>
|
|
606
|
+
* <ContextMenuSubContent>
|
|
607
|
+
* <ContextMenuItem>Email</ContextMenuItem>
|
|
608
|
+
* </ContextMenuSubContent>
|
|
609
|
+
* </ContextMenuSub>
|
|
610
|
+
* </ContextMenuContent>
|
|
611
|
+
* </ContextMenu>
|
|
612
|
+
* );
|
|
613
|
+
* }
|
|
614
|
+
* @see {@link ContextMenuSub}
|
|
615
|
+
* @since 1.0.0
|
|
616
|
+
*/
|
|
617
|
+
function ContextMenuSubTrigger<T extends PolymorphicTarget = "div">(
|
|
618
|
+
props: MenuSubTriggerProps<T> & { readonly inset?: boolean | undefined },
|
|
619
|
+
): JSX.Element {
|
|
620
|
+
const [local, rest] = splitProps(props as unknown as Loose, ["class", "inset", "children"]);
|
|
621
|
+
return (
|
|
622
|
+
<ContextMenuPrimitive.SubTrigger
|
|
623
|
+
data-slot="context-menu-sub-trigger"
|
|
624
|
+
data-inset={local.inset === true ? "" : undefined}
|
|
625
|
+
class={cn(
|
|
626
|
+
ROW,
|
|
627
|
+
"px-2 py-1.5 data-[inset]:ps-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground forced-colors:data-[state=open]:bg-[Highlight] forced-colors:data-[state=open]:text-[HighlightText] [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
628
|
+
local.class,
|
|
629
|
+
)}
|
|
630
|
+
{...rest}
|
|
631
|
+
>
|
|
632
|
+
{local.children}
|
|
633
|
+
<ChevronRightIcon class="ms-auto size-4 rtl:rotate-180" />
|
|
634
|
+
</ContextMenuPrimitive.SubTrigger>
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* The submenu panel, placed beside its trigger. It is a `role="menu"` labeled by its trigger.
|
|
640
|
+
* ArrowLeft (ArrowRight in right-to-left layouts) and Escape close it and return focus to the trigger.
|
|
641
|
+
*
|
|
642
|
+
* @param props The panel props: the attributes of the rendered `div` and `class`.
|
|
643
|
+
* @returns The submenu panel.
|
|
644
|
+
* @throws Error when rendered outside a {@link ContextMenuSub}.
|
|
645
|
+
* @example
|
|
646
|
+
* import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "@/components/ui/context-menu";
|
|
647
|
+
*
|
|
648
|
+
* export function Share() {
|
|
649
|
+
* return (
|
|
650
|
+
* <ContextMenu>
|
|
651
|
+
* <ContextMenuTrigger>Right click here</ContextMenuTrigger>
|
|
652
|
+
* <ContextMenuContent>
|
|
653
|
+
* <ContextMenuSub>
|
|
654
|
+
* <ContextMenuSubTrigger>Invite users</ContextMenuSubTrigger>
|
|
655
|
+
* <ContextMenuSubContent class="w-44">
|
|
656
|
+
* <ContextMenuItem>Email</ContextMenuItem>
|
|
657
|
+
* </ContextMenuSubContent>
|
|
658
|
+
* </ContextMenuSub>
|
|
659
|
+
* </ContextMenuContent>
|
|
660
|
+
* </ContextMenu>
|
|
661
|
+
* );
|
|
662
|
+
* }
|
|
663
|
+
* @see {@link ContextMenuSubTrigger}
|
|
664
|
+
* @since 1.0.0
|
|
665
|
+
*/
|
|
666
|
+
function ContextMenuSubContent(props: MenuSubContentProps): JSX.Element {
|
|
667
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
668
|
+
return (
|
|
669
|
+
<ContextMenuPrimitive.SubContent
|
|
670
|
+
data-slot="context-menu-sub-content"
|
|
671
|
+
class={cn(
|
|
672
|
+
PANEL,
|
|
673
|
+
"max-h-(--primitives-available-height) overflow-x-hidden overflow-y-auto shadow-lg",
|
|
674
|
+
local.class,
|
|
675
|
+
)}
|
|
676
|
+
{...rest}
|
|
677
|
+
/>
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
export {
|
|
682
|
+
ContextMenu,
|
|
683
|
+
ContextMenuCheckboxItem,
|
|
684
|
+
ContextMenuContent,
|
|
685
|
+
ContextMenuGroup,
|
|
686
|
+
ContextMenuItem,
|
|
687
|
+
ContextMenuLabel,
|
|
688
|
+
ContextMenuPortal,
|
|
689
|
+
ContextMenuRadioGroup,
|
|
690
|
+
ContextMenuRadioItem,
|
|
691
|
+
ContextMenuSeparator,
|
|
692
|
+
ContextMenuShortcut,
|
|
693
|
+
ContextMenuSub,
|
|
694
|
+
ContextMenuSubContent,
|
|
695
|
+
ContextMenuSubTrigger,
|
|
696
|
+
ContextMenuTrigger,
|
|
697
|
+
};
|