{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "smooth-dropdown", "title": "Smooth Dropdown", "description": "A dropdown menu with premium layout transitions.", "dependencies": [ "motion", "@hugeicons/core-free-icons", "@hugeicons/react", "clsx", "tailwind-merge" ], "files": [ { "path": "registry/default/example/smooth-dropdown.tsx", "content": "\"use client\";\r\n\r\nimport { useState, useRef, useEffect } from \"react\";\r\nimport { motion } from \"motion/react\";\r\nimport { HugeiconsIcon } from \"@hugeicons/react\";\r\nimport useMeasure from \"react-use-measure\";\r\nimport {\r\n UserIcon,\r\n CreditCardIcon,\r\n FolderIcon,\r\n File01Icon,\r\n SettingsIcon,\r\n HelpCircleIcon,\r\n LogoutIcon,\r\n MoreHorizontalCircle01Icon,\r\n} from \"@hugeicons/core-free-icons\";\r\n\r\n// Change Here\r\nconst menuItems = [\r\n { id: \"profile\", label: \"Profile\", icon: UserIcon },\r\n { id: \"upgrade\", label: \"Upgrade\", icon: CreditCardIcon },\r\n { id: \"projects\", label: \"Projects\", icon: FolderIcon },\r\n { id: \"documentation\", label: \"Documentation\", icon: File01Icon },\r\n { id: \"divider\", label: \"\", icon: null },\r\n { id: \"settings\", label: \"Settings\", icon: SettingsIcon },\r\n { id: \"help\", label: \"Get Help\", icon: HelpCircleIcon },\r\n { id: \"logout\", label: \"Logout\", icon: LogoutIcon },\r\n];\r\n\r\nconst easeOutQuint: [number, number, number, number] = [0.23, 1, 0.32, 1];\r\n\r\nexport default function TwentyTwelveOne() {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [activeItem, setActiveItem] = useState(\"profile\");\r\n const [hoveredItem, setHoveredItem] = useState(null);\r\n const containerRef = useRef(null);\r\n\r\n const [contentRef, contentBounds] = useMeasure();\r\n\r\n useEffect(() => {\r\n const handleClickOutside = (event: MouseEvent) => {\r\n if (\r\n containerRef.current &&\r\n !containerRef.current.contains(event.target as Node)\r\n ) {\r\n setIsOpen(false);\r\n }\r\n };\r\n\r\n if (isOpen) {\r\n document.addEventListener(\"mousedown\", handleClickOutside);\r\n }\r\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\r\n }, [isOpen]);\r\n\r\n const openHeight = Math.max(40, Math.ceil(contentBounds.height));\r\n return (\r\n
\r\n !isOpen && setIsOpen(true)}\r\n >\r\n \r\n \r\n \r\n\r\n {/* Menu Content - visible when open */}\r\n
\r\n \r\n
    \r\n {menuItems.map((item, index) => {\r\n if (item.id === \"divider\") {\r\n return (\r\n \r\n );\r\n }\r\n\r\n const iconRef = item.icon!;\r\n const isActive = activeItem === item.id;\r\n const isLogout = item.id === \"logout\";\r\n const showIndicator = hoveredItem\r\n ? hoveredItem === item.id\r\n : isActive;\r\n\r\n const itemDuration = item.id === \"logout\" ? 0.12 : 0.15;\r\n const itemDelay = isOpen ? 0.06 + index * 0.02 : 0;\r\n\r\n return (\r\n {\r\n setActiveItem(item.id);\r\n if (item.id === \"logout\") {\r\n setIsOpen(false);\r\n }\r\n }}\r\n onMouseEnter={() => setHoveredItem(item.id)}\r\n onMouseLeave={() => setHoveredItem(null)}\r\n className={`relative flex items-center gap-3 rounded-lg text-sm cursor-pointer transition-colors duration-200 ease-out m-0! pl-3! py-2! ${\r\n isLogout && showIndicator\r\n ? \"text-red-600\"\r\n : isActive\r\n ? \"text-foreground\"\r\n : isLogout\r\n ? \"text-muted-foreground hover:text-red-600\"\r\n : \"text-muted-foreground hover:text-foreground\"\r\n }`}\r\n >\r\n {/* Hover/Active background indicator */}\r\n {showIndicator && (\r\n \r\n )}\r\n {/* Left bar indicator */}\r\n {showIndicator && (\r\n \r\n )}\r\n \r\n \r\n {item.label}\r\n \r\n \r\n );\r\n })}\r\n
\r\n \r\n
\r\n \r\n
\r\n );\r\n}\r\n", "type": "registry:component" } ], "type": "registry:component" }