snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
261
apps/v4/registry/bases/aria/ui/dropdown-menu.tsx
Normal file
261
apps/v4/registry/bases/aria/ui/dropdown-menu.tsx
Normal file
@@ -0,0 +1,261 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { cva } from "class-variance-authority"
|
||||
import { cn } from "cn"
|
||||
import {
|
||||
composeRenderProps,
|
||||
Header as HeaderPrimitive,
|
||||
MenuItem as MenuItemPrimitive,
|
||||
Menu as MenuPrimitive,
|
||||
MenuSection as MenuSectionPrimitive,
|
||||
MenuTrigger as MenuTriggerPrimitive,
|
||||
Popover as PopoverPrimitive,
|
||||
Separator as SeparatorPrimitive,
|
||||
SubmenuTrigger as SubmenuTriggerPrimitive,
|
||||
type MenuItemProps as MenuItemPrimitiveProps,
|
||||
type MenuSectionProps as MenuSectionPrimitiveProps,
|
||||
} from "react-aria-components"
|
||||
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
function DropdownMenuTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenuTriggerPrimitive>) {
|
||||
return <MenuTriggerPrimitive data-slot="dropdown-menu-trigger" {...props} />
|
||||
}
|
||||
|
||||
function DropdownMenu({
|
||||
"data-slot": dataSlot = "dropdown-menu-content",
|
||||
placement = "bottom start",
|
||||
offset = 4,
|
||||
crossOffset = 0,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: Omit<
|
||||
React.ComponentProps<typeof MenuPrimitive<object>>,
|
||||
"children" | "className"
|
||||
> &
|
||||
Pick<
|
||||
React.ComponentProps<typeof PopoverPrimitive>,
|
||||
"placement" | "offset" | "crossOffset"
|
||||
> & {
|
||||
"data-slot"?: string
|
||||
className?: string
|
||||
children?: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<PopoverPrimitive
|
||||
data-slot={dataSlot}
|
||||
placement={placement}
|
||||
offset={offset}
|
||||
crossOffset={crossOffset}
|
||||
className={cn(
|
||||
"cn-dropdown-menu-content-aria cn-menu-target cn-menu-translucent cn-menu-translucent-aria z-50 w-(--trigger-width) origin-(--trigger-anchor-point) overflow-x-hidden overflow-y-auto outline-none data-exiting:overflow-hidden",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<MenuPrimitive
|
||||
className="max-h-[inherit] overflow-x-hidden overflow-y-auto outline-hidden"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MenuPrimitive>
|
||||
</PopoverPrimitive>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuGroup({
|
||||
...props
|
||||
}: Omit<MenuSectionPrimitiveProps<object>, "children"> & {
|
||||
children?: React.ReactNode
|
||||
}) {
|
||||
return <MenuSectionPrimitive data-slot="dropdown-menu-group" {...props} />
|
||||
}
|
||||
|
||||
function DropdownMenuLabel({
|
||||
className,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof HeaderPrimitive> & {
|
||||
inset?: boolean
|
||||
}) {
|
||||
return (
|
||||
<HeaderPrimitive
|
||||
data-slot="dropdown-menu-label"
|
||||
data-inset={inset}
|
||||
className={cn("cn-dropdown-menu-label", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const dropdownMenuItemVariants = cva(
|
||||
"group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
selectionMode: {
|
||||
none: "cn-dropdown-menu-item",
|
||||
single: "cn-dropdown-menu-radio-item",
|
||||
multiple: "cn-dropdown-menu-checkbox-item",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function DropdownMenuItem({
|
||||
className,
|
||||
inset,
|
||||
variant = "default",
|
||||
children,
|
||||
...props
|
||||
}: MenuItemPrimitiveProps<object> & {
|
||||
inset?: boolean
|
||||
variant?: "default" | "destructive"
|
||||
}) {
|
||||
return (
|
||||
<MenuItemPrimitive
|
||||
data-slot="dropdown-menu-item"
|
||||
data-inset={inset}
|
||||
data-variant={variant}
|
||||
textValue={typeof children === "string" ? children : props.textValue}
|
||||
className={composeRenderProps(className, (className, { selectionMode }) =>
|
||||
cn(dropdownMenuItemVariants({ selectionMode }), className)
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{composeRenderProps(
|
||||
children,
|
||||
(children, { isSelected, selectionMode }) => (
|
||||
<>
|
||||
{selectionMode !== "none" ? (
|
||||
<span
|
||||
className="cn-dropdown-menu-item-indicator pointer-events-none"
|
||||
data-slot={
|
||||
selectionMode === "single"
|
||||
? "dropdown-menu-radio-item-indicator"
|
||||
: "dropdown-menu-checkbox-item-indicator"
|
||||
}
|
||||
>
|
||||
{isSelected ? (
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
) : null}
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</MenuItemPrimitive>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSub({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SubmenuTriggerPrimitive>) {
|
||||
return <SubmenuTriggerPrimitive data-slot="dropdown-menu-sub" {...props} />
|
||||
}
|
||||
|
||||
function DropdownMenuSubTrigger({
|
||||
className,
|
||||
inset,
|
||||
children,
|
||||
...props
|
||||
}: MenuItemPrimitiveProps<object> & {
|
||||
inset?: boolean
|
||||
}) {
|
||||
return (
|
||||
<MenuItemPrimitive
|
||||
data-slot="dropdown-menu-sub-trigger"
|
||||
data-inset={inset}
|
||||
textValue={typeof children === "string" ? children : props.textValue}
|
||||
className={cn(
|
||||
"cn-dropdown-menu-sub-trigger flex cursor-default items-center outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{composeRenderProps(children, (children) => (
|
||||
<>
|
||||
{children}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="cn-rtl-flip ml-auto"
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
</MenuItemPrimitive>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSubContent({
|
||||
placement = "end top",
|
||||
crossOffset = -3,
|
||||
offset = 0,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenu>) {
|
||||
return (
|
||||
<DropdownMenu
|
||||
data-slot="dropdown-menu-sub-content"
|
||||
className={cn(
|
||||
"cn-dropdown-menu-sub-content-aria cn-menu-target cn-menu-translucent w-auto",
|
||||
className
|
||||
)}
|
||||
placement={placement}
|
||||
crossOffset={crossOffset}
|
||||
offset={offset}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SeparatorPrimitive>) {
|
||||
return (
|
||||
<SeparatorPrimitive
|
||||
data-slot="dropdown-menu-separator"
|
||||
className={cn("cn-dropdown-menu-separator", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuShortcut({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) {
|
||||
return (
|
||||
<span
|
||||
data-slot="dropdown-menu-shortcut"
|
||||
className={cn("cn-dropdown-menu-shortcut", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
}
|
||||
Reference in New Issue
Block a user