262 lines
6.6 KiB
TypeScript
262 lines
6.6 KiB
TypeScript
"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,
|
|
}
|