import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu' import { Check, ChevronDown, ChevronRight, ChevronUp, Circle } from 'lucide-react' import * as React from 'react' import { cn } from '@/lib/utils' import { createPortal } from 'react-dom' const DropdownMenu = ({ open: controlledOpen, onOpenChange: controlledOnOpenChange, ...props }: React.ComponentPropsWithoutRef) => { const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false) const isControlled = controlledOpen !== undefined const open = isControlled ? controlledOpen : uncontrolledOpen const backdropRef = React.useRef(null) const handleOpenChange = React.useCallback( (newOpen: boolean) => { if (!isControlled) { setUncontrolledOpen(newOpen) } controlledOnOpenChange?.(newOpen) }, [isControlled, controlledOnOpenChange] ) React.useEffect(() => { if (open) { const prevOverflow = document.body.style.overflow document.body.style.overflow = 'hidden' return () => { document.body.style.overflow = prevOverflow } } }, [open]) return ( <> {open && createPortal(
{ e.stopPropagation() handleOpenChange(false) }} />, document.body )} ) } DropdownMenu.displayName = 'DropdownMenu' const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger const DropdownMenuGroup = DropdownMenuPrimitive.Group const DropdownMenuPortal = DropdownMenuPrimitive.Portal const DropdownMenuSub = DropdownMenuPrimitive.Sub const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup const DropdownMenuSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean } >(({ className, inset, children, ...props }, ref) => ( {children} )) DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName const DropdownMenuSubContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { showScrollButtons?: boolean } >(({ className, showScrollButtons = true, ...props }, ref) => { const [canScrollUp, setCanScrollUp] = React.useState(false) const [canScrollDown, setCanScrollDown] = React.useState(false) const contentRef = React.useRef(null) const scrollAreaRef = React.useRef(null) React.useImperativeHandle(ref, () => contentRef.current!) const checkScrollability = React.useCallback(() => { requestAnimationFrame(() => { const scrollArea = scrollAreaRef.current if (!scrollArea) return setCanScrollUp(scrollArea.scrollTop > 0) setCanScrollDown(scrollArea.scrollTop < scrollArea.scrollHeight - scrollArea.clientHeight) }) }, []) const scrollUp = () => { scrollAreaRef.current?.scroll({ top: 0, behavior: 'smooth' }) } const scrollDown = () => { scrollAreaRef.current?.scroll({ top: scrollAreaRef.current.scrollHeight, behavior: 'smooth' }) } return ( { if (showScrollButtons) { checkScrollability() } }} collisionPadding={10} {...props} > {showScrollButtons && canScrollUp && (
)}
{props.children}
{showScrollButtons && canScrollDown && (
)}
) }) DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName const DropdownMenuContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { showScrollButtons?: boolean } >(({ className, sideOffset = 4, showScrollButtons = false, ...props }, ref) => { const [canScrollUp, setCanScrollUp] = React.useState(false) const [canScrollDown, setCanScrollDown] = React.useState(false) const contentRef = React.useRef(null) const scrollAreaRef = React.useRef(null) React.useImperativeHandle(ref, () => contentRef.current!) const checkScrollability = React.useCallback(() => { requestAnimationFrame(() => { const scrollArea = scrollAreaRef.current if (!scrollArea) return setCanScrollUp(scrollArea.scrollTop > 0) setCanScrollDown(scrollArea.scrollTop < scrollArea.scrollHeight - scrollArea.clientHeight) }) }, []) const scrollUp = () => { scrollAreaRef.current?.scroll({ top: 0, behavior: 'smooth' }) } const scrollDown = () => { scrollAreaRef.current?.scroll({ top: scrollAreaRef.current.scrollHeight, behavior: 'smooth' }) } return ( { if (showScrollButtons) { checkScrollability() } }} collisionPadding={10} {...props} > {showScrollButtons && canScrollUp && (
)}
e.stopPropagation()} > {props.children}
{showScrollButtons && canScrollDown && (
)}
) }) DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName const DropdownMenuItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean } >(({ className, inset, ...props }, ref) => ( )) DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName const DropdownMenuCheckboxItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, checked, ...props }, ref) => ( {children} )) DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName const DropdownMenuRadioItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( {children} )) DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName const DropdownMenuLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean } >(({ className, inset, ...props }, ref) => ( )) DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName const DropdownMenuSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )) DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { return } DropdownMenuShortcut.displayName = 'DropdownMenuShortcut' export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger }