{
  "title": "Dropdown Menu",
  "description": "Displays a menu to the user-triggered by a button-with spring entrance transitions, submenus, checkboxes, and radio items.",
  "name": "motion-dropdown-menu",
  "dependencies": [
    "motion",
    "@base-ui/react",
    "lucide-react"
  ],
  "registryDependencies": [],
  "type": "registry:ui",
  "files": [
    {
      "path": "components/paceui/motion/dropdown-menu.tsx",
      "type": "registry:ui",
      "content": "import * as React from \"react\";\n\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\";\nimport { CheckIcon, ChevronRightIcon } from \"lucide-react\";\nimport { AnimatePresence, type Transition, motion } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface DropdownMenuHighlightContextType {\n    highlightLayoutId: string;\n    activeItemId: string | null;\n    setActiveItem: (id: string) => void;\n    clearActiveItemWithDelay: () => void;\n}\n\nconst DropdownMenuHighlightContext = React.createContext<DropdownMenuHighlightContextType | null>(null);\n\nexport interface DropdownMenuProps extends MenuPrimitive.Root.Props {}\n\nfunction DropdownMenu({ ...props }: DropdownMenuProps) {\n    return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {\n    return <MenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />;\n}\n\nfunction DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {\n    return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nexport interface DropdownMenuContentProps\n    extends\n        MenuPrimitive.Popup.Props,\n        Pick<MenuPrimitive.Positioner.Props, \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"> {\n    transition?: Transition;\n}\n\nfunction DropdownMenuContent({\n    align = \"start\",\n    alignOffset = 0,\n    side = \"bottom\",\n    sideOffset = 4,\n    transition = { type: \"spring\", stiffness: 380, damping: 26, mass: 0.8 },\n    className,\n    children,\n    ...props\n}: DropdownMenuContentProps) {\n    const parentHighlightContext = React.useContext(DropdownMenuHighlightContext);\n\n    const generatedLayoutId = React.useId();\n    const highlightLayoutId = parentHighlightContext?.highlightLayoutId ?? generatedLayoutId;\n\n    const [localActiveItemId, setLocalActiveItemId] = React.useState<string | null>(null);\n    const timeoutRef = React.useRef<any>(null);\n\n    const setActiveItem =\n        parentHighlightContext?.setActiveItem ??\n        React.useCallback((id: string) => {\n            if (timeoutRef.current) clearTimeout(timeoutRef.current);\n            setLocalActiveItemId(id);\n        }, []);\n\n    const clearActiveItemWithDelay =\n        parentHighlightContext?.clearActiveItemWithDelay ??\n        React.useCallback(() => {\n            if (timeoutRef.current) clearTimeout(timeoutRef.current);\n            timeoutRef.current = setTimeout(() => {\n                setLocalActiveItemId(null);\n            }, 180);\n        }, []);\n\n    const activeItemId = parentHighlightContext ? parentHighlightContext.activeItemId : localActiveItemId;\n\n    const highlightValue: DropdownMenuHighlightContextType = parentHighlightContext ?? {\n        highlightLayoutId,\n        activeItemId,\n        setActiveItem,\n        clearActiveItemWithDelay,\n    };\n\n    return (\n        <MenuPrimitive.Portal keepMounted>\n            <MenuPrimitive.Positioner\n                className=\"isolate z-500 outline-none\"\n                align={align}\n                alignOffset={alignOffset}\n                side={side}\n                sideOffset={sideOffset}>\n                <MenuPrimitive.Popup\n                    data-slot=\"dropdown-menu-content\"\n                    {...props}\n                    render={(popupProps, state) => (\n                        <AnimatePresence initial={false}>\n                            {state.open && (\n                                <motion.div\n                                    {...popupProps}\n                                    key=\"dropdown-menu-content\"\n                                    initial={{\n                                        opacity: 0,\n                                        scale: 0.94,\n                                        y: side === \"bottom\" ? -8 : side === \"top\" ? 8 : 0,\n                                        x: side === \"right\" ? -12 : side === \"left\" ? 12 : 0,\n                                    }}\n                                    animate={{ opacity: 1, scale: 1, y: 0, x: 0 }}\n                                    exit={{\n                                        opacity: 0,\n                                        scale: 0.94,\n                                        y: side === \"bottom\" ? -6 : side === \"top\" ? 6 : 0,\n                                        x: side === \"right\" ? -8 : side === \"left\" ? 8 : 0,\n                                    }}\n                                    transition={transition}\n                                    className={cn(\n                                        \"ring-foreground/10 bg-popover text-popover-foreground z-50 flex max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) flex-col gap-px overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 outline-none\",\n                                        className,\n                                    )}>\n                                    <DropdownMenuHighlightContext.Provider value={highlightValue}>\n                                        <div onPointerLeave={clearActiveItemWithDelay} className=\"flex flex-col gap-px\">\n                                            {children}\n                                        </div>\n                                    </DropdownMenuHighlightContext.Provider>\n                                </motion.div>\n                            )}\n                        </AnimatePresence>\n                    )}\n                />\n            </MenuPrimitive.Positioner>\n        </MenuPrimitive.Portal>\n    );\n}\n\nfunction DropdownMenuGroup({ className, ...props }: MenuPrimitive.Group.Props) {\n    return <MenuPrimitive.Group data-slot=\"dropdown-menu-group\" className={cn(\"flex flex-col gap-px\", className)} {...props} />;\n}\n\nfunction DropdownMenuLabel({\n    className,\n    inset,\n    ...props\n}: MenuPrimitive.GroupLabel.Props & {\n    inset?: boolean;\n}) {\n    return (\n        <MenuPrimitive.Group>\n            <MenuPrimitive.GroupLabel\n                data-slot=\"dropdown-menu-label\"\n                data-inset={inset}\n                className={cn(\"text-muted-foreground px-2 py-1.5 text-xs font-medium data-inset:pl-8\", className)}\n                {...props}\n            />\n        </MenuPrimitive.Group>\n    );\n}\n\nexport interface DropdownMenuItemProps extends MenuPrimitive.Item.Props {\n    inset?: boolean;\n    variant?: \"default\" | \"destructive\";\n}\n\nfunction DropdownMenuItem({\n    className,\n    inset,\n    variant = \"default\",\n    children,\n    render: customRender,\n    ...props\n}: DropdownMenuItemProps) {\n    const highlightContext = React.useContext(DropdownMenuHighlightContext);\n    const itemId = React.useId();\n\n    return (\n        <MenuPrimitive.Item\n            data-slot=\"dropdown-menu-item\"\n            data-inset={inset}\n            data-variant={variant}\n            {...props}\n            render={(itemProps, state) => {\n                const isCurrentActive = highlightContext?.activeItemId === itemId;\n\n                const innerContent = (\n                    <>\n                        {isCurrentActive && highlightContext?.highlightLayoutId && (\n                            <motion.div\n                                layoutId={highlightContext.highlightLayoutId}\n                                className={cn(\n                                    \"pointer-events-none absolute inset-0 z-0 rounded-sm\",\n                                    variant === \"destructive\"\n                                        ? \"bg-destructive/10 dark:bg-destructive/20\"\n                                        : \"bg-accent\",\n                                )}\n                                transition={{ type: \"spring\", stiffness: 450, damping: 32 }}\n                            />\n                        )}\n                        <span className=\"relative z-10 flex w-full items-center gap-2\">\n                            {React.isValidElement(customRender) && customRender.props.children\n                                ? customRender.props.children\n                                : children}\n                        </span>\n                    </>\n                );\n\n                const itemClassName = cn(\n                    \"group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n                    (state.highlighted || isCurrentActive) &&\n                        (variant === \"destructive\" ? \"text-destructive\" : \"text-accent-foreground\"),\n                    className,\n                    React.isValidElement(customRender) && (customRender.props as any).className,\n                );\n\n                if (React.isValidElement(customRender)) {\n                    return React.cloneElement(customRender as React.ReactElement<any>, {\n                        ...itemProps,\n                        ...(customRender.props as any),\n                        onPointerEnter: (e: any) => {\n                            itemProps.onPointerEnter?.(e);\n                            (customRender.props as any).onPointerEnter?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        },\n                        onFocus: (e: any) => {\n                            itemProps.onFocus?.(e);\n                            (customRender.props as any).onFocus?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        },\n                        className: itemClassName,\n                        children: innerContent,\n                    });\n                }\n\n                return (\n                    <motion.div\n                        {...itemProps}\n                        onPointerEnter={(e: any) => {\n                            itemProps.onPointerEnter?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        onFocus={(e: any) => {\n                            itemProps.onFocus?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        whileTap={{ scale: 0.98 }}\n                        transition={{ type: \"spring\", stiffness: 400, damping: 25 }}\n                        className={itemClassName}>\n                        {innerContent}\n                    </motion.div>\n                );\n            }}\n        />\n    );\n}\n\nfunction DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {\n    return <MenuPrimitive.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nexport interface DropdownMenuSubTriggerProps extends MenuPrimitive.SubmenuTrigger.Props {\n    inset?: boolean;\n}\n\nfunction DropdownMenuSubTrigger({ className, inset, children, ...props }: DropdownMenuSubTriggerProps) {\n    const highlightContext = React.useContext(DropdownMenuHighlightContext);\n    const itemId = React.useId();\n\n    return (\n        <MenuPrimitive.SubmenuTrigger\n            data-slot=\"dropdown-menu-sub-trigger\"\n            data-inset={inset}\n            {...props}\n            render={(triggerProps, state) => {\n                const isCurrentActive = highlightContext?.activeItemId === itemId;\n\n                return (\n                    <motion.div\n                        {...triggerProps}\n                        onPointerEnter={(e: any) => {\n                            triggerProps.onPointerEnter?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        onFocus={(e: any) => {\n                            triggerProps.onFocus?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        whileTap={{ scale: 0.98 }}\n                        transition={{ type: \"spring\", stiffness: 400, damping: 25 }}\n                        className={cn(\n                            \"group/dropdown-menu-sub-trigger relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-inset:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n                            (state.highlighted || state.open || isCurrentActive) && \"text-accent-foreground\",\n                            className,\n                        )}>\n                        {isCurrentActive && highlightContext?.highlightLayoutId ? (\n                            <motion.div\n                                layoutId={highlightContext.highlightLayoutId}\n                                className=\"bg-accent pointer-events-none absolute inset-0 z-0 rounded-sm\"\n                                transition={{ type: \"spring\", stiffness: 450, damping: 32 }}\n                            />\n                        ) : state.open ? (\n                            <div className=\"bg-accent/60 pointer-events-none absolute inset-0 z-0 rounded-sm\" />\n                        ) : null}\n                        <span className=\"relative z-10 flex w-full items-center gap-2\">{children}</span>\n                        <ChevronRightIcon className=\"relative z-10 ml-auto\" />\n                    </motion.div>\n                );\n            }}\n        />\n    );\n}\n\nfunction DropdownMenuSubContent({\n    align = \"start\",\n    alignOffset = -3,\n    side = \"right\",\n    sideOffset = 4,\n    className,\n    ...props\n}: React.ComponentProps<typeof DropdownMenuContent>) {\n    return (\n        <DropdownMenuContent\n            data-slot=\"dropdown-menu-sub-content\"\n            className={cn(\"w-auto min-w-[120px] shadow-lg\", className)}\n            align={align}\n            alignOffset={alignOffset}\n            side={side}\n            sideOffset={sideOffset}\n            {...props}\n        />\n    );\n}\n\nexport interface DropdownMenuCheckboxItemProps extends MenuPrimitive.CheckboxItem.Props {}\n\nfunction DropdownMenuCheckboxItem({ className, children, checked, ...props }: DropdownMenuCheckboxItemProps) {\n    const highlightContext = React.useContext(DropdownMenuHighlightContext);\n    const itemId = React.useId();\n\n    return (\n        <MenuPrimitive.CheckboxItem\n            data-slot=\"dropdown-menu-checkbox-item\"\n            className={cn(\n                \"group/dropdown-menu-checkbox-item relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n                className,\n            )}\n            checked={checked}\n            {...props}\n            render={(itemProps, state) => {\n                const isCurrentActive = highlightContext?.activeItemId === itemId;\n\n                return (\n                    <motion.div\n                        {...itemProps}\n                        onPointerEnter={(e: any) => {\n                            itemProps.onPointerEnter?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        onFocus={(e: any) => {\n                            itemProps.onFocus?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        whileTap={{ scale: 0.98 }}\n                        transition={{ type: \"spring\", stiffness: 400, damping: 25 }}\n                        className={cn(\n                            \"group/dropdown-menu-checkbox-item relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n                            (state.highlighted || isCurrentActive) && \"text-accent-foreground\",\n                            className,\n                        )}>\n                        {isCurrentActive && highlightContext?.highlightLayoutId && (\n                            <motion.div\n                                layoutId={highlightContext.highlightLayoutId}\n                                className=\"bg-accent pointer-events-none absolute inset-0 z-0 rounded-sm\"\n                                transition={{ type: \"spring\", stiffness: 450, damping: 32 }}\n                            />\n                        )}\n                        <span className=\"relative z-10 flex items-center gap-2\">{children}</span>\n                        <span\n                            className=\"pointer-events-none absolute right-2 z-10 flex items-center justify-center\"\n                            data-slot=\"dropdown-menu-checkbox-item-indicator\">\n                            <MenuPrimitive.CheckboxItemIndicator>\n                                <motion.span\n                                    initial={{ scale: 0, opacity: 0 }}\n                                    animate={{ scale: 1, opacity: 1 }}\n                                    exit={{ scale: 0, opacity: 0 }}\n                                    transition={{ type: \"spring\", stiffness: 400, damping: 22 }}\n                                    className=\"flex items-center justify-center\">\n                                    <CheckIcon />\n                                </motion.span>\n                            </MenuPrimitive.CheckboxItemIndicator>\n                        </span>\n                    </motion.div>\n                );\n            }}\n        />\n    );\n}\n\nfunction DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {\n    return <MenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n}\n\nexport interface DropdownMenuRadioItemProps extends MenuPrimitive.RadioItem.Props {}\n\nfunction DropdownMenuRadioItem({ className, children, ...props }: DropdownMenuRadioItemProps) {\n    const highlightContext = React.useContext(DropdownMenuHighlightContext);\n    const itemId = React.useId();\n\n    return (\n        <MenuPrimitive.RadioItem\n            data-slot=\"dropdown-menu-radio-item\"\n            className={cn(\n                \"group/dropdown-menu-radio-item relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n                className,\n            )}\n            {...props}\n            render={(itemProps, state) => {\n                const isCurrentActive = highlightContext?.activeItemId === itemId;\n\n                return (\n                    <motion.div\n                        {...itemProps}\n                        onPointerEnter={(e: any) => {\n                            itemProps.onPointerEnter?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        onFocus={(e: any) => {\n                            itemProps.onFocus?.(e);\n                            highlightContext?.setActiveItem(itemId);\n                        }}\n                        whileTap={{ scale: 0.98 }}\n                        transition={{ type: \"spring\", stiffness: 400, damping: 25 }}\n                        className={cn(\n                            \"group/dropdown-menu-radio-item relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n                            (state.highlighted || isCurrentActive) && \"text-accent-foreground\",\n                            className,\n                        )}>\n                        {isCurrentActive && highlightContext?.highlightLayoutId && (\n                            <motion.div\n                                layoutId={highlightContext.highlightLayoutId}\n                                className=\"bg-accent pointer-events-none absolute inset-0 z-0 rounded-sm\"\n                                transition={{ type: \"spring\", stiffness: 450, damping: 32 }}\n                            />\n                        )}\n                        <span className=\"relative z-10 flex items-center gap-2\">{children}</span>\n                        <span\n                            className=\"pointer-events-none absolute right-2 z-10 flex items-center justify-center\"\n                            data-slot=\"dropdown-menu-radio-item-indicator\">\n                            <MenuPrimitive.RadioItemIndicator>\n                                <motion.span\n                                    initial={{ scale: 0, opacity: 0 }}\n                                    animate={{ scale: 1, opacity: 1 }}\n                                    exit={{ scale: 0, opacity: 0 }}\n                                    transition={{ type: \"spring\", stiffness: 400, damping: 22 }}\n                                    className=\"flex items-center justify-center\">\n                                    <CheckIcon />\n                                </motion.span>\n                            </MenuPrimitive.RadioItemIndicator>\n                        </span>\n                    </motion.div>\n                );\n            }}\n        />\n    );\n}\n\nfunction DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {\n    return (\n        <MenuPrimitive.Separator\n            data-slot=\"dropdown-menu-separator\"\n            className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n            {...props}\n        />\n    );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n    return (\n        <span\n            data-slot=\"dropdown-menu-shortcut\"\n            className={cn(\n                \"text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest\",\n                className,\n            )}\n            {...props}\n        />\n    );\n}\n\nexport {\n    DropdownMenu,\n    DropdownMenuPortal,\n    DropdownMenuTrigger,\n    DropdownMenuContent,\n    DropdownMenuGroup,\n    DropdownMenuLabel,\n    DropdownMenuItem,\n    DropdownMenuCheckboxItem,\n    DropdownMenuRadioGroup,\n    DropdownMenuRadioItem,\n    DropdownMenuSeparator,\n    DropdownMenuShortcut,\n    DropdownMenuSub,\n    DropdownMenuSubTrigger,\n    DropdownMenuSubContent,\n};\n"
    }
  ],
  "mcp": {
    "description": "Displays a menu to the user triggered by a button. Provides smooth spring scale popup, submenus, checkbox and radio transitions.",
    "tags": [
      "component",
      "dropdown-menu",
      "menu",
      "paceui",
      "animation"
    ]
  }
}