File size: 1,941 Bytes
212c959 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import { cloneElement, isValidElement } from 'react'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import clsx from 'clsx'
export default function Dropdown({
trigger,
items = [],
align = 'end',
contentClassName,
disabled = false,
}) {
const triggerNode =
isValidElement(trigger) && disabled
? cloneElement(trigger, {
disabled: true,
'aria-disabled': true,
})
: trigger
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild disabled={disabled}>
{triggerNode}
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
align={align}
sideOffset={8}
className={clsx(
'z-50 min-w-[12rem] rounded-lg border border-border bg-card p-1 shadow-panel',
contentClassName,
)}
>
{items.map((item) => {
if (item.type === 'separator') {
return <DropdownMenu.Separator key={item.key} className="my-1 h-px bg-border/80" />
}
const Icon = item.icon
return (
<DropdownMenu.Item
key={item.key}
disabled={item.disabled}
onSelect={item.onSelect}
className={clsx(
'flex cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-sm outline-none transition data-[disabled]:pointer-events-none data-[disabled]:opacity-40',
item.destructive
? 'text-danger focus:bg-danger/10'
: 'text-foreground focus:bg-secondary',
)}
>
{Icon ? <Icon className="h-4 w-4" /> : null}
<span className="flex-1">{item.label}</span>
</DropdownMenu.Item>
)
})}
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
)
}
|