@multicomma/arkcn 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.
- package/README.md +78 -0
- package/bin/arkcn.mjs +78 -0
- package/cli/commands.mjs +251 -0
- package/cli/project.mjs +168 -0
- package/cli/registry.mjs +50 -0
- package/cli/ui.mjs +46 -0
- package/mcp/server.mjs +149 -0
- package/package.json +201 -0
- package/registry/base.css +680 -0
- package/registry/index.json +1833 -0
- package/registry/items/accordion.json +18 -0
- package/registry/items/activity-feed.json +18 -0
- package/registry/items/alert-dialog.json +18 -0
- package/registry/items/alert.json +17 -0
- package/registry/items/angle-slider.json +17 -0
- package/registry/items/app-shell.json +28 -0
- package/registry/items/aspect-ratio.json +13 -0
- package/registry/items/attachment.json +19 -0
- package/registry/items/avatar.json +17 -0
- package/registry/items/badge.json +18 -0
- package/registry/items/breadcrumb.json +18 -0
- package/registry/items/bubble.json +18 -0
- package/registry/items/button-group.json +19 -0
- package/registry/items/button.json +18 -0
- package/registry/items/calendar.json +19 -0
- package/registry/items/canvas.json +24 -0
- package/registry/items/card.json +15 -0
- package/registry/items/carousel.json +19 -0
- package/registry/items/cascader.json +23 -0
- package/registry/items/chart.json +17 -0
- package/registry/items/chat.json +23 -0
- package/registry/items/checkbox.json +18 -0
- package/registry/items/clipboard.json +19 -0
- package/registry/items/collapsible.json +15 -0
- package/registry/items/color-picker.json +19 -0
- package/registry/items/combobox.json +20 -0
- package/registry/items/command.json +21 -0
- package/registry/items/comment-thread.json +25 -0
- package/registry/items/context-menu.json +18 -0
- package/registry/items/controllable.json +14 -0
- package/registry/items/data-grid.json +24 -0
- package/registry/items/data-table-adapter.json +14 -0
- package/registry/items/data-table.json +32 -0
- package/registry/items/date-input.json +17 -0
- package/registry/items/dialog.json +19 -0
- package/registry/items/direction.json +13 -0
- package/registry/items/drag-preview.json +16 -0
- package/registry/items/drawer.json +18 -0
- package/registry/items/dropdown-menu.json +18 -0
- package/registry/items/editable.json +17 -0
- package/registry/items/empty.json +17 -0
- package/registry/items/field.json +19 -0
- package/registry/items/file-upload.json +19 -0
- package/registry/items/floating-panel.json +19 -0
- package/registry/items/floating-toolbar.json +16 -0
- package/registry/items/form.json +14 -0
- package/registry/items/format.json +15 -0
- package/registry/items/gantt.json +22 -0
- package/registry/items/history.json +14 -0
- package/registry/items/hotkeys.json +18 -0
- package/registry/items/hover-card.json +17 -0
- package/registry/items/image-cropper.json +17 -0
- package/registry/items/input-group.json +20 -0
- package/registry/items/input-otp.json +18 -0
- package/registry/items/input.json +15 -0
- package/registry/items/item.json +19 -0
- package/registry/items/json-tree-view.json +17 -0
- package/registry/items/kanban.json +26 -0
- package/registry/items/kbd.json +15 -0
- package/registry/items/label.json +15 -0
- package/registry/items/live-region.json +16 -0
- package/registry/items/marker.json +18 -0
- package/registry/items/marquee.json +17 -0
- package/registry/items/menubar.json +19 -0
- package/registry/items/message.json +15 -0
- package/registry/items/navigation-menu.json +19 -0
- package/registry/items/node-graph.json +22 -0
- package/registry/items/number-input.json +18 -0
- package/registry/items/pagination.json +18 -0
- package/registry/items/password-input.json +18 -0
- package/registry/items/popconfirm.json +20 -0
- package/registry/items/popover.json +18 -0
- package/registry/items/progress.json +17 -0
- package/registry/items/qr-code.json +17 -0
- package/registry/items/query-builder.json +23 -0
- package/registry/items/radio-group.json +17 -0
- package/registry/items/rating-group.json +18 -0
- package/registry/items/resizable.json +17 -0
- package/registry/items/rich-text-editor.json +37 -0
- package/registry/items/row-layout.json +15 -0
- package/registry/items/scheduler.json +23 -0
- package/registry/items/scroll-area.json +17 -0
- package/registry/items/segment-group.json +17 -0
- package/registry/items/select.json +19 -0
- package/registry/items/separator.json +15 -0
- package/registry/items/sheet.json +19 -0
- package/registry/items/sidebar.json +27 -0
- package/registry/items/signature-pad.json +19 -0
- package/registry/items/skeleton.json +15 -0
- package/registry/items/slider.json +17 -0
- package/registry/items/sonner.json +17 -0
- package/registry/items/spinner.json +17 -0
- package/registry/items/steps.json +19 -0
- package/registry/items/swap.json +17 -0
- package/registry/items/switch.json +17 -0
- package/registry/items/table.json +16 -0
- package/registry/items/tabs.json +18 -0
- package/registry/items/tags-input.json +18 -0
- package/registry/items/textarea.json +15 -0
- package/registry/items/time.json +14 -0
- package/registry/items/timer.json +18 -0
- package/registry/items/toc.json +17 -0
- package/registry/items/toggle-group.json +19 -0
- package/registry/items/toggle.json +18 -0
- package/registry/items/tooltip.json +17 -0
- package/registry/items/tour.json +19 -0
- package/registry/items/transfer-list.json +24 -0
- package/registry/items/tree-select.json +24 -0
- package/registry/items/tree-view.json +18 -0
- package/registry/items/use-mobile.json +13 -0
- package/registry/items/utils.json +17 -0
- package/registry/items/virtual-list.json +16 -0
- package/src/components/ui/accordion.tsx +111 -0
- package/src/components/ui/activity-feed.tsx +228 -0
- package/src/components/ui/alert-dialog.tsx +204 -0
- package/src/components/ui/alert.tsx +55 -0
- package/src/components/ui/angle-slider.tsx +117 -0
- package/src/components/ui/app-shell.tsx +985 -0
- package/src/components/ui/aspect-ratio.tsx +35 -0
- package/src/components/ui/attachment.tsx +193 -0
- package/src/components/ui/avatar.tsx +94 -0
- package/src/components/ui/badge.tsx +45 -0
- package/src/components/ui/breadcrumb.tsx +93 -0
- package/src/components/ui/bubble.tsx +119 -0
- package/src/components/ui/button-group.tsx +79 -0
- package/src/components/ui/button.tsx +65 -0
- package/src/components/ui/calendar.tsx +172 -0
- package/src/components/ui/canvas.tsx +723 -0
- package/src/components/ui/card.tsx +69 -0
- package/src/components/ui/carousel.tsx +228 -0
- package/src/components/ui/cascader.tsx +754 -0
- package/src/components/ui/chart.tsx +303 -0
- package/src/components/ui/chat.tsx +544 -0
- package/src/components/ui/checkbox.tsx +94 -0
- package/src/components/ui/clipboard.tsx +94 -0
- package/src/components/ui/collapsible.tsx +32 -0
- package/src/components/ui/color-picker.tsx +441 -0
- package/src/components/ui/combobox.tsx +400 -0
- package/src/components/ui/command.tsx +292 -0
- package/src/components/ui/comment-thread.tsx +923 -0
- package/src/components/ui/context-menu.tsx +331 -0
- package/src/components/ui/data-grid.tsx +1227 -0
- package/src/components/ui/data-table.tsx +993 -0
- package/src/components/ui/date-input.tsx +103 -0
- package/src/components/ui/dialog.tsx +159 -0
- package/src/components/ui/direction.tsx +32 -0
- package/src/components/ui/drawer.tsx +200 -0
- package/src/components/ui/dropdown-menu.tsx +329 -0
- package/src/components/ui/editable.tsx +90 -0
- package/src/components/ui/empty.tsx +86 -0
- package/src/components/ui/field.tsx +218 -0
- package/src/components/ui/file-upload.tsx +204 -0
- package/src/components/ui/floating-panel.tsx +199 -0
- package/src/components/ui/floating-toolbar.tsx +79 -0
- package/src/components/ui/format.tsx +22 -0
- package/src/components/ui/gantt.tsx +950 -0
- package/src/components/ui/hotkeys.tsx +340 -0
- package/src/components/ui/hover-card.tsx +83 -0
- package/src/components/ui/image-cropper.tsx +100 -0
- package/src/components/ui/input-group.tsx +133 -0
- package/src/components/ui/input-otp.tsx +82 -0
- package/src/components/ui/input.tsx +18 -0
- package/src/components/ui/item.tsx +174 -0
- package/src/components/ui/json-tree-view.tsx +37 -0
- package/src/components/ui/kanban.tsx +884 -0
- package/src/components/ui/kbd.tsx +20 -0
- package/src/components/ui/label.tsx +30 -0
- package/src/components/ui/live-region.tsx +54 -0
- package/src/components/ui/marker.tsx +66 -0
- package/src/components/ui/marquee.tsx +61 -0
- package/src/components/ui/menubar.tsx +456 -0
- package/src/components/ui/message.tsx +74 -0
- package/src/components/ui/navigation-menu.tsx +202 -0
- package/src/components/ui/node-graph.tsx +1723 -0
- package/src/components/ui/number-input.tsx +148 -0
- package/src/components/ui/pagination.tsx +88 -0
- package/src/components/ui/password-input.tsx +104 -0
- package/src/components/ui/popconfirm.tsx +149 -0
- package/src/components/ui/popover.tsx +126 -0
- package/src/components/ui/progress.tsx +114 -0
- package/src/components/ui/qr-code.tsx +51 -0
- package/src/components/ui/query-builder.tsx +938 -0
- package/src/components/ui/radio-group.tsx +108 -0
- package/src/components/ui/rating-group.tsx +91 -0
- package/src/components/ui/resizable.tsx +41 -0
- package/src/components/ui/rich-text-editor.tsx +845 -0
- package/src/components/ui/scheduler.tsx +1164 -0
- package/src/components/ui/scroll-area.tsx +82 -0
- package/src/components/ui/segment-group.tsx +95 -0
- package/src/components/ui/select.tsx +354 -0
- package/src/components/ui/separator.tsx +32 -0
- package/src/components/ui/sheet.tsx +130 -0
- package/src/components/ui/sidebar.tsx +665 -0
- package/src/components/ui/signature-pad.tsx +112 -0
- package/src/components/ui/skeleton.tsx +7 -0
- package/src/components/ui/slider.tsx +183 -0
- package/src/components/ui/sonner.tsx +37 -0
- package/src/components/ui/spinner.tsx +16 -0
- package/src/components/ui/steps.tsx +152 -0
- package/src/components/ui/swap.tsx +33 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/table.tsx +72 -0
- package/src/components/ui/tabs.tsx +100 -0
- package/src/components/ui/tags-input.tsx +153 -0
- package/src/components/ui/textarea.tsx +17 -0
- package/src/components/ui/timer.tsx +67 -0
- package/src/components/ui/toc.tsx +64 -0
- package/src/components/ui/toggle-group.tsx +89 -0
- package/src/components/ui/toggle.tsx +46 -0
- package/src/components/ui/tooltip.tsx +113 -0
- package/src/components/ui/tour.tsx +168 -0
- package/src/components/ui/transfer-list.tsx +700 -0
- package/src/components/ui/tree-select.tsx +638 -0
- package/src/components/ui/tree-view.tsx +217 -0
- package/src/components/ui/virtual-list.tsx +343 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/lib/controllable.ts +31 -0
- package/src/lib/data-table-adapter.ts +67 -0
- package/src/lib/drag-preview.ts +39 -0
- package/src/lib/form.ts +39 -0
- package/src/lib/history.ts +55 -0
- package/src/lib/row-layout.ts +81 -0
- package/src/lib/table.ts +483 -0
- package/src/lib/time.ts +37 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/arkcn.css +764 -0
- package/src/styles/index.css +3 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cn } from "@/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 <kbd data-slot="kbd-group" className={cn("inline-flex items-center gap-1", className)} {...props} />
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Kbd, KbdGroup }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cn } from "@/lib/utils"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Ark UI has no standalone Label primitive (its labels live inside each
|
|
6
|
+
* component's anatomy). This mirrors Radix's: a native `label` that ignores
|
|
7
|
+
* double-click text selection.
|
|
8
|
+
*/
|
|
9
|
+
function Label({ className, onMouseDown, ...props }: React.ComponentProps<"label">) {
|
|
10
|
+
return (
|
|
11
|
+
<label
|
|
12
|
+
data-slot="label"
|
|
13
|
+
className={cn(
|
|
14
|
+
"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",
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
onMouseDown={(event) => {
|
|
18
|
+
// Only prevent text selection if clicking inside the label itself
|
|
19
|
+
const target = event.target as HTMLElement
|
|
20
|
+
if (target.closest("button, input, select, textarea")) return
|
|
21
|
+
onMouseDown?.(event)
|
|
22
|
+
// Prevent text selection when double clicking label
|
|
23
|
+
if (!event.defaultPrevented && event.detail > 1) event.preventDefault()
|
|
24
|
+
}}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { Label }
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared screen-reader announcer. `announce` re-fires even when the same text is
|
|
8
|
+
* announced twice, and `clearAfter` (ms) empties the region so stale text is not
|
|
9
|
+
* re-read when a user lands on it.
|
|
10
|
+
*/
|
|
11
|
+
function useLiveRegion(options: { clearAfter?: number } = {}) {
|
|
12
|
+
const { clearAfter } = options
|
|
13
|
+
const [message, setMessage] = React.useState("")
|
|
14
|
+
const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
15
|
+
const announce = React.useCallback(
|
|
16
|
+
(text: string) => {
|
|
17
|
+
setMessage("")
|
|
18
|
+
queueMicrotask(() => setMessage(text))
|
|
19
|
+
if (timer.current) clearTimeout(timer.current)
|
|
20
|
+
if (clearAfter) timer.current = setTimeout(() => setMessage(""), clearAfter)
|
|
21
|
+
},
|
|
22
|
+
[clearAfter]
|
|
23
|
+
)
|
|
24
|
+
React.useEffect(
|
|
25
|
+
() => () => {
|
|
26
|
+
if (timer.current) clearTimeout(timer.current)
|
|
27
|
+
},
|
|
28
|
+
[]
|
|
29
|
+
)
|
|
30
|
+
return { message, announce }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Visually hidden `role="status"` region. Pair with `useLiveRegion`. */
|
|
34
|
+
function LiveRegion({
|
|
35
|
+
message,
|
|
36
|
+
assertive = false,
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
39
|
+
}: React.ComponentProps<"div"> & { message: string; assertive?: boolean }) {
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
data-slot="live-region"
|
|
43
|
+
role={assertive ? "alert" : "status"}
|
|
44
|
+
aria-live={assertive ? "assertive" : "polite"}
|
|
45
|
+
aria-atomic="true"
|
|
46
|
+
className={cn("sr-only", className)}
|
|
47
|
+
{...props}
|
|
48
|
+
>
|
|
49
|
+
{message}
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { LiveRegion, useLiveRegion }
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
import { ark } from "@ark-ui/react"
|
|
5
|
+
|
|
6
|
+
const markerVariants = cva(
|
|
7
|
+
"group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "",
|
|
12
|
+
separator:
|
|
13
|
+
"before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border",
|
|
14
|
+
border: "border-b border-border pb-2",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
function Marker({
|
|
21
|
+
className,
|
|
22
|
+
variant = "default",
|
|
23
|
+
asChild = false,
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<"div"> &
|
|
26
|
+
VariantProps<typeof markerVariants> & {
|
|
27
|
+
asChild?: boolean
|
|
28
|
+
}) {
|
|
29
|
+
const Comp = ark.div
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Comp
|
|
33
|
+
asChild={asChild}
|
|
34
|
+
data-slot="marker"
|
|
35
|
+
data-variant={variant}
|
|
36
|
+
className={cn(markerVariants({ variant, className }))}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function MarkerIcon({ className, ...props }: React.ComponentProps<"span">) {
|
|
43
|
+
return (
|
|
44
|
+
<span
|
|
45
|
+
data-slot="marker-icon"
|
|
46
|
+
aria-hidden="true"
|
|
47
|
+
className={cn("size-4 shrink-0 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function MarkerContent({ className, ...props }: React.ComponentProps<"span">) {
|
|
54
|
+
return (
|
|
55
|
+
<span
|
|
56
|
+
data-slot="marker-content"
|
|
57
|
+
className={cn(
|
|
58
|
+
"min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { Marker, MarkerIcon, MarkerContent, markerVariants }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
import { Marquee as MarqueePrimitive } from "@ark-ui/react"
|
|
6
|
+
|
|
7
|
+
function Marquee({ className, ...props }: React.ComponentProps<typeof MarqueePrimitive.Root>) {
|
|
8
|
+
return (
|
|
9
|
+
<MarqueePrimitive.Root
|
|
10
|
+
data-slot="marquee"
|
|
11
|
+
className={cn("group/marquee relative w-full overflow-hidden", className)}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function MarqueeContext({ ...props }: React.ComponentProps<typeof MarqueePrimitive.Context>) {
|
|
18
|
+
return <MarqueePrimitive.Context {...props} />
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function MarqueeViewport({ className, ...props }: React.ComponentProps<typeof MarqueePrimitive.Viewport>) {
|
|
22
|
+
return (
|
|
23
|
+
<MarqueePrimitive.Viewport
|
|
24
|
+
data-slot="marquee-viewport"
|
|
25
|
+
className={cn("flex w-full overflow-hidden", className)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function MarqueeContent({ className, ...props }: React.ComponentProps<typeof MarqueePrimitive.Content>) {
|
|
32
|
+
return (
|
|
33
|
+
<MarqueePrimitive.Content
|
|
34
|
+
data-slot="marquee-content"
|
|
35
|
+
className={cn(
|
|
36
|
+
"flex shrink-0 items-center group-data-paused/marquee:paused data-reverse:shimmer-reverse data-horizontal:animate-marquee-x data-vertical:animate-marquee-y",
|
|
37
|
+
className
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function MarqueeItem({ className, ...props }: React.ComponentProps<typeof MarqueePrimitive.Item>) {
|
|
45
|
+
return <MarqueePrimitive.Item data-slot="marquee-item" className={cn("shrink-0", className)} {...props} />
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function MarqueeEdge({ className, ...props }: React.ComponentProps<typeof MarqueePrimitive.Edge>) {
|
|
49
|
+
return (
|
|
50
|
+
<MarqueePrimitive.Edge
|
|
51
|
+
data-slot="marquee-edge"
|
|
52
|
+
className={cn(
|
|
53
|
+
"pointer-events-none absolute inset-y-0 z-10 w-12 from-background to-transparent data-[side=end]:right-0 data-[side=end]:bg-linear-to-l data-[side=start]:left-0 data-[side=start]:bg-linear-to-r",
|
|
54
|
+
className
|
|
55
|
+
)}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { Marquee, MarqueeContent, MarqueeContext, MarqueeEdge, MarqueeItem, MarqueeViewport }
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
import { useControllable } from "@/lib/controllable"
|
|
6
|
+
import { Menu as MenubarPrimitive, Portal as PortalPrimitive } from "@ark-ui/react"
|
|
7
|
+
import { CheckIcon, ChevronRightIcon } from "lucide-react"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ark UI has no Menubar primitive. `Menubar` composes Ark `Menu` roots and adds
|
|
11
|
+
* the menubar behaviours Radix provides: one open menu at a time, hover
|
|
12
|
+
* switching between triggers once a menu is open, roving tabindex across
|
|
13
|
+
* triggers, and ArrowLeft/ArrowRight moving between menus.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
type MenubarContextValue = {
|
|
17
|
+
value: string | null
|
|
18
|
+
setValue: (value: string | null) => void
|
|
19
|
+
loop: boolean
|
|
20
|
+
register: (id: string) => () => void
|
|
21
|
+
order: string[]
|
|
22
|
+
rootRef: React.RefObject<HTMLDivElement | null>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const MenubarContext = React.createContext<MenubarContextValue | null>(null)
|
|
26
|
+
const MenubarMenuContext = React.createContext<string | null>(null)
|
|
27
|
+
|
|
28
|
+
function useMenubar(component: string) {
|
|
29
|
+
const ctx = React.useContext(MenubarContext)
|
|
30
|
+
if (!ctx) throw new Error(`${component} must be used within <Menubar>`)
|
|
31
|
+
return ctx
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function useMenubarMenu(component: string) {
|
|
35
|
+
const id = React.useContext(MenubarMenuContext)
|
|
36
|
+
if (!id) throw new Error(`${component} must be used within <MenubarMenu>`)
|
|
37
|
+
return id
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function Menubar({
|
|
41
|
+
className,
|
|
42
|
+
value: valueProp,
|
|
43
|
+
defaultValue = null,
|
|
44
|
+
onValueChange,
|
|
45
|
+
loop = false,
|
|
46
|
+
...props
|
|
47
|
+
}: Omit<React.ComponentProps<"div">, "value" | "defaultValue"> & {
|
|
48
|
+
/** The id of the open menu (controlled). */
|
|
49
|
+
value?: string | null
|
|
50
|
+
defaultValue?: string | null
|
|
51
|
+
onValueChange?: (value: string | null) => void
|
|
52
|
+
/** Whether ArrowLeft/ArrowRight wrap around at the ends. */
|
|
53
|
+
loop?: boolean
|
|
54
|
+
}) {
|
|
55
|
+
const [value, setValue] = useControllable(valueProp, defaultValue, onValueChange)
|
|
56
|
+
const [order, setOrder] = React.useState<string[]>([])
|
|
57
|
+
const register = React.useCallback((id: string) => {
|
|
58
|
+
setOrder((prev) => (prev.includes(id) ? prev : [...prev, id]))
|
|
59
|
+
return () => setOrder((prev) => prev.filter((x) => x !== id))
|
|
60
|
+
}, [])
|
|
61
|
+
const rootRef = React.useRef<HTMLDivElement>(null)
|
|
62
|
+
const ctx = React.useMemo(
|
|
63
|
+
() => ({ value, setValue, loop, register, order, rootRef }),
|
|
64
|
+
[value, setValue, loop, register, order]
|
|
65
|
+
)
|
|
66
|
+
return (
|
|
67
|
+
<MenubarContext.Provider value={ctx}>
|
|
68
|
+
<div
|
|
69
|
+
ref={rootRef}
|
|
70
|
+
role="menubar"
|
|
71
|
+
data-slot="menubar"
|
|
72
|
+
className={cn("flex h-8 items-center gap-0.5 rounded-lg border p-0.75", className)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
</MenubarContext.Provider>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function useMenubarNavigation() {
|
|
80
|
+
const ctx = useMenubar("MenubarTrigger")
|
|
81
|
+
return React.useCallback(
|
|
82
|
+
(fromId: string, direction: 1 | -1, open: boolean) => {
|
|
83
|
+
const { order, loop, rootRef, setValue } = ctx
|
|
84
|
+
const index = order.indexOf(fromId)
|
|
85
|
+
let next = index + direction
|
|
86
|
+
if (next < 0) next = loop ? order.length - 1 : 0
|
|
87
|
+
if (next >= order.length) next = loop ? 0 : order.length - 1
|
|
88
|
+
const nextId = order[next]
|
|
89
|
+
if (!nextId || nextId === fromId) return
|
|
90
|
+
const trigger = rootRef.current?.querySelector<HTMLElement>(
|
|
91
|
+
`[data-slot="menubar-trigger"][data-menubar-value="${nextId}"]`
|
|
92
|
+
)
|
|
93
|
+
trigger?.focus()
|
|
94
|
+
setValue(open ? nextId : null)
|
|
95
|
+
},
|
|
96
|
+
[ctx]
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function MenubarMenu({
|
|
101
|
+
value: valueProp,
|
|
102
|
+
positioning,
|
|
103
|
+
lazyMount = true,
|
|
104
|
+
unmountOnExit = true,
|
|
105
|
+
onOpenChange,
|
|
106
|
+
...props
|
|
107
|
+
}: Omit<React.ComponentProps<typeof MenubarPrimitive.Root>, "open" | "defaultOpen"> & {
|
|
108
|
+
/** Identifies this menu within the menubar. Auto-generated when omitted. */
|
|
109
|
+
value?: string
|
|
110
|
+
}) {
|
|
111
|
+
const ctx = useMenubar("MenubarMenu")
|
|
112
|
+
const generated = React.useId()
|
|
113
|
+
const id = valueProp ?? generated
|
|
114
|
+
const { register } = ctx
|
|
115
|
+
React.useEffect(() => register(id), [register, id])
|
|
116
|
+
return (
|
|
117
|
+
<MenubarMenuContext.Provider value={id}>
|
|
118
|
+
<MenubarPrimitive.Root
|
|
119
|
+
open={ctx.value === id}
|
|
120
|
+
onOpenChange={(details) => {
|
|
121
|
+
ctx.setValue(details.open ? id : ctx.value === id ? null : ctx.value)
|
|
122
|
+
onOpenChange?.(details)
|
|
123
|
+
}}
|
|
124
|
+
positioning={{
|
|
125
|
+
placement: "bottom-start",
|
|
126
|
+
gutter: 8,
|
|
127
|
+
offset: { crossAxis: -4 },
|
|
128
|
+
...positioning,
|
|
129
|
+
}}
|
|
130
|
+
lazyMount={lazyMount}
|
|
131
|
+
unmountOnExit={unmountOnExit}
|
|
132
|
+
{...props}
|
|
133
|
+
/>
|
|
134
|
+
</MenubarMenuContext.Provider>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function MenubarTrigger({
|
|
139
|
+
className,
|
|
140
|
+
onPointerEnter,
|
|
141
|
+
onKeyDown,
|
|
142
|
+
...props
|
|
143
|
+
}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
|
|
144
|
+
const ctx = useMenubar("MenubarTrigger")
|
|
145
|
+
const id = useMenubarMenu("MenubarTrigger")
|
|
146
|
+
const navigate = useMenubarNavigation()
|
|
147
|
+
const isOpen = ctx.value === id
|
|
148
|
+
const isFirst = ctx.order[0] === id
|
|
149
|
+
return (
|
|
150
|
+
<MenubarPrimitive.Trigger
|
|
151
|
+
data-slot="menubar-trigger"
|
|
152
|
+
data-menubar-value={id}
|
|
153
|
+
tabIndex={isOpen || (ctx.value === null && isFirst) ? 0 : -1}
|
|
154
|
+
className={cn(
|
|
155
|
+
"flex items-center rounded-sm px-1.5 py-0.5 text-sm font-medium outline-hidden select-none hover:bg-muted aria-expanded:bg-muted",
|
|
156
|
+
className
|
|
157
|
+
)}
|
|
158
|
+
onPointerEnter={(event) => {
|
|
159
|
+
onPointerEnter?.(event)
|
|
160
|
+
if (ctx.value !== null && ctx.value !== id) ctx.setValue(id)
|
|
161
|
+
}}
|
|
162
|
+
onKeyDown={(event) => {
|
|
163
|
+
onKeyDown?.(event)
|
|
164
|
+
if (event.defaultPrevented) return
|
|
165
|
+
if (event.key === "ArrowRight" || event.key === "ArrowLeft") {
|
|
166
|
+
event.preventDefault()
|
|
167
|
+
navigate(id, event.key === "ArrowRight" ? 1 : -1, isOpen)
|
|
168
|
+
}
|
|
169
|
+
}}
|
|
170
|
+
{...props}
|
|
171
|
+
/>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function MenubarPortal({ ...props }: React.ComponentProps<typeof PortalPrimitive>) {
|
|
176
|
+
return <PortalPrimitive {...props} />
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function MenubarMenuContext_({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Context>) {
|
|
180
|
+
return <MenubarPrimitive.Context {...props} />
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function MenubarPositioner({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Positioner>) {
|
|
184
|
+
return (
|
|
185
|
+
<MenubarPrimitive.Positioner
|
|
186
|
+
data-slot="menubar-positioner"
|
|
187
|
+
className={cn("[--z-index:50]", className)}
|
|
188
|
+
{...props}
|
|
189
|
+
/>
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function MenubarContent({ className, onKeyDown, ...props }: React.ComponentProps<typeof MenubarPrimitive.Content>) {
|
|
194
|
+
const id = useMenubarMenu("MenubarContent")
|
|
195
|
+
const navigate = useMenubarNavigation()
|
|
196
|
+
return (
|
|
197
|
+
<MenubarPortal>
|
|
198
|
+
<MenubarPositioner>
|
|
199
|
+
<MenubarPrimitive.Content
|
|
200
|
+
data-slot="menubar-content"
|
|
201
|
+
className={cn(
|
|
202
|
+
"z-50 min-w-36 origin-(--transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden 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",
|
|
203
|
+
className
|
|
204
|
+
)}
|
|
205
|
+
onKeyDown={(event) => {
|
|
206
|
+
onKeyDown?.(event)
|
|
207
|
+
if (event.defaultPrevented) return
|
|
208
|
+
if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return
|
|
209
|
+
const target = event.target as HTMLElement
|
|
210
|
+
// Inside a submenu, Ark owns ArrowLeft (close) and ArrowRight.
|
|
211
|
+
if (target.closest('[data-slot="menubar-sub-content"]')) return
|
|
212
|
+
// On a highlighted sub trigger, ArrowRight opens the submenu.
|
|
213
|
+
if (
|
|
214
|
+
event.key === "ArrowRight" &&
|
|
215
|
+
event.currentTarget.querySelector('[data-slot="menubar-sub-trigger"][data-highlighted]')
|
|
216
|
+
)
|
|
217
|
+
return
|
|
218
|
+
event.preventDefault()
|
|
219
|
+
navigate(id, event.key === "ArrowRight" ? 1 : -1, true)
|
|
220
|
+
}}
|
|
221
|
+
{...props}
|
|
222
|
+
/>
|
|
223
|
+
</MenubarPositioner>
|
|
224
|
+
</MenubarPortal>
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function MenubarArrow({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Arrow>) {
|
|
229
|
+
return (
|
|
230
|
+
<MenubarPrimitive.Arrow
|
|
231
|
+
data-slot="menubar-arrow"
|
|
232
|
+
className={cn("[--arrow-background:var(--color-popover)] [--arrow-size:0.625rem]", className)}
|
|
233
|
+
{...props}
|
|
234
|
+
>
|
|
235
|
+
<MenubarPrimitive.ArrowTip data-slot="menubar-arrow-tip" className="border-t border-l border-foreground/10" />
|
|
236
|
+
</MenubarPrimitive.Arrow>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function MenubarGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.ItemGroup>) {
|
|
241
|
+
return <MenubarPrimitive.ItemGroup data-slot="menubar-group" {...props} />
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function MenubarItem({
|
|
245
|
+
className,
|
|
246
|
+
inset,
|
|
247
|
+
variant = "default",
|
|
248
|
+
value,
|
|
249
|
+
...props
|
|
250
|
+
}: Omit<React.ComponentProps<typeof MenubarPrimitive.Item>, "value"> & {
|
|
251
|
+
value?: string
|
|
252
|
+
inset?: boolean
|
|
253
|
+
variant?: "default" | "destructive"
|
|
254
|
+
}) {
|
|
255
|
+
const id = React.useId()
|
|
256
|
+
return (
|
|
257
|
+
<MenubarPrimitive.Item
|
|
258
|
+
data-slot="menubar-item"
|
|
259
|
+
data-inset={inset}
|
|
260
|
+
data-variant={variant}
|
|
261
|
+
value={value ?? id}
|
|
262
|
+
className={cn(
|
|
263
|
+
"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 data-highlighted:bg-accent data-highlighted:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 data-[variant=destructive]:data-highlighted:text-destructive dark:data-[variant=destructive]:data-highlighted: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-highlighted:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive",
|
|
264
|
+
className
|
|
265
|
+
)}
|
|
266
|
+
{...props}
|
|
267
|
+
/>
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function MenubarItemText({ ...props }: React.ComponentProps<typeof MenubarPrimitive.ItemText>) {
|
|
272
|
+
return <MenubarPrimitive.ItemText data-slot="menubar-item-text" {...props} />
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function MenubarItemIndicator({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.ItemIndicator>) {
|
|
276
|
+
return (
|
|
277
|
+
<MenubarPrimitive.ItemIndicator
|
|
278
|
+
data-slot="menubar-item-indicator"
|
|
279
|
+
className={cn("pointer-events-none absolute right-2 flex items-center justify-center", className)}
|
|
280
|
+
{...props}
|
|
281
|
+
/>
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const optionItemClassName =
|
|
286
|
+
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted: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"
|
|
287
|
+
|
|
288
|
+
function MenubarCheckboxItem({
|
|
289
|
+
className,
|
|
290
|
+
children,
|
|
291
|
+
checked = false,
|
|
292
|
+
inset,
|
|
293
|
+
value,
|
|
294
|
+
...props
|
|
295
|
+
}: Omit<React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>, "checked" | "value"> & {
|
|
296
|
+
checked?: boolean
|
|
297
|
+
value?: string
|
|
298
|
+
inset?: boolean
|
|
299
|
+
}) {
|
|
300
|
+
const id = React.useId()
|
|
301
|
+
return (
|
|
302
|
+
<MenubarPrimitive.CheckboxItem
|
|
303
|
+
data-slot="menubar-checkbox-item"
|
|
304
|
+
data-inset={inset}
|
|
305
|
+
className={cn(optionItemClassName, className)}
|
|
306
|
+
checked={checked}
|
|
307
|
+
value={value ?? id}
|
|
308
|
+
{...props}
|
|
309
|
+
>
|
|
310
|
+
<MenubarItemIndicator data-slot="menubar-checkbox-item-indicator">
|
|
311
|
+
<CheckIcon />
|
|
312
|
+
</MenubarItemIndicator>
|
|
313
|
+
{children}
|
|
314
|
+
</MenubarPrimitive.CheckboxItem>
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function MenubarRadioGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.RadioItemGroup>) {
|
|
319
|
+
return <MenubarPrimitive.RadioItemGroup data-slot="menubar-radio-group" {...props} />
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function MenubarRadioItem({
|
|
323
|
+
className,
|
|
324
|
+
children,
|
|
325
|
+
inset,
|
|
326
|
+
...props
|
|
327
|
+
}: React.ComponentProps<typeof MenubarPrimitive.RadioItem> & {
|
|
328
|
+
inset?: boolean
|
|
329
|
+
}) {
|
|
330
|
+
return (
|
|
331
|
+
<MenubarPrimitive.RadioItem
|
|
332
|
+
data-slot="menubar-radio-item"
|
|
333
|
+
data-inset={inset}
|
|
334
|
+
className={cn(optionItemClassName, className)}
|
|
335
|
+
{...props}
|
|
336
|
+
>
|
|
337
|
+
<MenubarItemIndicator data-slot="menubar-radio-item-indicator">
|
|
338
|
+
<CheckIcon />
|
|
339
|
+
</MenubarItemIndicator>
|
|
340
|
+
{children}
|
|
341
|
+
</MenubarPrimitive.RadioItem>
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function MenubarLabel({
|
|
346
|
+
className,
|
|
347
|
+
inset,
|
|
348
|
+
...props
|
|
349
|
+
}: React.ComponentProps<typeof MenubarPrimitive.ItemGroupLabel> & {
|
|
350
|
+
inset?: boolean
|
|
351
|
+
}) {
|
|
352
|
+
return (
|
|
353
|
+
<MenubarPrimitive.ItemGroupLabel
|
|
354
|
+
data-slot="menubar-label"
|
|
355
|
+
data-inset={inset}
|
|
356
|
+
className={cn("px-1.5 py-1 text-sm font-medium data-inset:pl-7", className)}
|
|
357
|
+
{...props}
|
|
358
|
+
/>
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function MenubarSeparator({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
|
|
363
|
+
return (
|
|
364
|
+
<MenubarPrimitive.Separator
|
|
365
|
+
data-slot="menubar-separator"
|
|
366
|
+
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
|
367
|
+
{...props}
|
|
368
|
+
/>
|
|
369
|
+
)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function MenubarShortcut({ className, ...props }: React.ComponentProps<"span">) {
|
|
373
|
+
return (
|
|
374
|
+
<span
|
|
375
|
+
data-slot="menubar-shortcut"
|
|
376
|
+
className={cn(
|
|
377
|
+
"ml-auto text-xs tracking-widest text-muted-foreground group-data-highlighted/menubar-item:text-accent-foreground",
|
|
378
|
+
className
|
|
379
|
+
)}
|
|
380
|
+
{...props}
|
|
381
|
+
/>
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function MenubarSub({
|
|
386
|
+
lazyMount = true,
|
|
387
|
+
unmountOnExit = true,
|
|
388
|
+
...props
|
|
389
|
+
}: React.ComponentProps<typeof MenubarPrimitive.Root>) {
|
|
390
|
+
return <MenubarPrimitive.Root lazyMount={lazyMount} unmountOnExit={unmountOnExit} {...props} />
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function MenubarSubTrigger({
|
|
394
|
+
className,
|
|
395
|
+
inset,
|
|
396
|
+
children,
|
|
397
|
+
...props
|
|
398
|
+
}: React.ComponentProps<typeof MenubarPrimitive.TriggerItem> & {
|
|
399
|
+
inset?: boolean
|
|
400
|
+
}) {
|
|
401
|
+
return (
|
|
402
|
+
<MenubarPrimitive.TriggerItem
|
|
403
|
+
data-slot="menubar-sub-trigger"
|
|
404
|
+
data-inset={inset}
|
|
405
|
+
className={cn(
|
|
406
|
+
"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted: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",
|
|
407
|
+
className
|
|
408
|
+
)}
|
|
409
|
+
{...props}
|
|
410
|
+
>
|
|
411
|
+
{children}
|
|
412
|
+
<ChevronRightIcon className="ml-auto" />
|
|
413
|
+
</MenubarPrimitive.TriggerItem>
|
|
414
|
+
)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function MenubarSubContent({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Content>) {
|
|
418
|
+
return (
|
|
419
|
+
<MenubarPortal>
|
|
420
|
+
<MenubarPositioner>
|
|
421
|
+
<MenubarPrimitive.Content
|
|
422
|
+
data-slot="menubar-sub-content"
|
|
423
|
+
className={cn(
|
|
424
|
+
"z-50 min-w-32 origin-(--transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 outline-hidden 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",
|
|
425
|
+
className
|
|
426
|
+
)}
|
|
427
|
+
{...props}
|
|
428
|
+
/>
|
|
429
|
+
</MenubarPositioner>
|
|
430
|
+
</MenubarPortal>
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export {
|
|
435
|
+
Menubar,
|
|
436
|
+
MenubarArrow,
|
|
437
|
+
MenubarCheckboxItem,
|
|
438
|
+
MenubarContent,
|
|
439
|
+
MenubarMenuContext_ as MenubarContext,
|
|
440
|
+
MenubarGroup,
|
|
441
|
+
MenubarItem,
|
|
442
|
+
MenubarItemIndicator,
|
|
443
|
+
MenubarItemText,
|
|
444
|
+
MenubarLabel,
|
|
445
|
+
MenubarMenu,
|
|
446
|
+
MenubarPortal,
|
|
447
|
+
MenubarPositioner,
|
|
448
|
+
MenubarRadioGroup,
|
|
449
|
+
MenubarRadioItem,
|
|
450
|
+
MenubarSeparator,
|
|
451
|
+
MenubarShortcut,
|
|
452
|
+
MenubarSub,
|
|
453
|
+
MenubarSubContent,
|
|
454
|
+
MenubarSubTrigger,
|
|
455
|
+
MenubarTrigger,
|
|
456
|
+
}
|