{
  "name": "dynamic-navigation",
  "type": "registry:ui",
  "title": "Dynamic Navigation",
  "description": "Adaptive pill navigation bar with spring active background highlight and tactile click ripple feedback.",
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/navigation/dynamic-navigation/dynamic-navigation.tsx",
      "type": "registry:ui",
      "target": "components/ui/dynamic-navigation.tsx",
      "content": "import React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { Home, Compass, Layers, User } from \"lucide-react\";\n\nexport interface NavLinkItem {\n  id: string;\n  label: string;\n  href: string;\n  icon?: React.ReactNode;\n}\n\nexport interface DynamicNavigationProps {\n  links?: NavLinkItem[];\n  className?: string;\n  activeLink?: string;\n  onLinkClick?: (id: string) => void;\n  enableRipple?: boolean;\n}\n\nconst defaultLinks: NavLinkItem[] = [\n  { id: \"home\", label: \"Home\", href: \"#home\", icon: <Home className=\"w-3.5 h-3.5\" /> },\n  { id: \"explore\", label: \"Explore\", href: \"#explore\", icon: <Compass className=\"w-3.5 h-3.5\" /> },\n  { id: \"components\", label: \"Components\", href: \"#components\", icon: <Layers className=\"w-3.5 h-3.5\" /> },\n  { id: \"account\", label: \"Account\", href: \"#account\", icon: <User className=\"w-3.5 h-3.5\" /> },\n];\n\nexport const DynamicNavigation: React.FC<DynamicNavigationProps> = ({\n  links = defaultLinks,\n  className,\n  activeLink,\n  onLinkClick,\n  enableRipple = true,\n}) => {\n  const navRef = useRef<HTMLElement>(null);\n  const highlightRef = useRef<HTMLDivElement>(null);\n  const [active, setActive] = useState<string>(activeLink || (links.length > 0 ? links[0].id : \"\"));\n\n  const updateHighlightPosition = (id?: string) => {\n    if (!navRef.current || !highlightRef.current) return;\n    const targetId = id || active;\n    const linkElement = navRef.current.querySelector(`#nav-item-${targetId}`) as HTMLElement;\n    if (!linkElement) return;\n\n    const { left, width } = linkElement.getBoundingClientRect();\n    const navRect = navRef.current.getBoundingClientRect();\n\n    highlightRef.current.style.transform = `translateX(${left - navRect.left}px)`;\n    highlightRef.current.style.width = `${width}px`;\n    highlightRef.current.style.opacity = \"1\";\n  };\n\n  const createRipple = (event: React.MouseEvent<HTMLAnchorElement>) => {\n    if (!enableRipple) return;\n    const button = event.currentTarget;\n    const circle = document.createElement(\"span\");\n    const diameter = Math.max(button.clientWidth, button.clientHeight);\n\n    circle.style.width = circle.style.height = `${diameter}px`;\n    circle.style.left = `${event.clientX - button.getBoundingClientRect().left - diameter / 2}px`;\n    circle.style.top = `${event.clientY - button.getBoundingClientRect().top - diameter / 2}px`;\n    circle.className = \"absolute bg-indigo-500/30 rounded-full pointer-events-none animate-ping\";\n\n    const oldRipple = button.querySelector(\".ripple-dot\");\n    if (oldRipple) oldRipple.remove();\n\n    circle.classList.add(\"ripple-dot\");\n    button.appendChild(circle);\n    setTimeout(() => circle.remove(), 600);\n  };\n\n  const handleLinkClick = (id: string, event: React.MouseEvent<HTMLAnchorElement>) => {\n    createRipple(event);\n    setActive(id);\n    onLinkClick?.(id);\n  };\n\n  useEffect(() => {\n    updateHighlightPosition();\n    const handleResize = () => updateHighlightPosition();\n    window.addEventListener(\"resize\", handleResize);\n    return () => window.removeEventListener(\"resize\", handleResize);\n  }, [active, links]);\n\n  useEffect(() => {\n    if (activeLink && activeLink !== active) {\n      setActive(activeLink);\n    }\n  }, [activeLink]);\n\n  return (\n    <nav\n      ref={navRef}\n      className={cn(\n        \"relative rounded-full border border-zinc-200/80 dark:border-zinc-800/80 bg-white/80 dark:bg-zinc-900/80 backdrop-blur-md shadow-lg shadow-zinc-500/5 dark:shadow-black/40 p-1.5 transition-all select-none isolate\",\n        className\n      )}\n    >\n      {/* Sliding Highlight Pill */}\n      <div\n        ref={highlightRef}\n        className=\"absolute top-1.5 left-0 h-[calc(100%-12px)] rounded-full bg-zinc-100 dark:bg-zinc-800 border border-zinc-200/60 dark:border-zinc-700/60 transition-all duration-300 ease-[cubic-bezier(0.25,1,0.5,1)] z-0 pointer-events-none opacity-0\"\n      />\n\n      <ul className=\"flex items-center gap-1 relative z-10\">\n        {links.map((link) => {\n          const isActive = active === link.id;\n          return (\n            <li key={link.id} id={`nav-item-${link.id}`} className=\"flex-1\">\n              <a\n                href={link.href}\n                onClick={(e) => {\n                  e.preventDefault();\n                  handleLinkClick(link.id, e);\n                }}\n                onMouseEnter={() => updateHighlightPosition(link.id)}\n                onMouseLeave={() => updateHighlightPosition(active)}\n                className={cn(\n                  \"flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-full transition-colors relative overflow-hidden cursor-pointer\",\n                  isActive\n                    ? \"text-zinc-950 dark:text-white font-semibold\"\n                    : \"text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-200\"\n                )}\n              >\n                {link.icon && <span className=\"text-current\">{link.icon}</span>}\n                <span>{link.label}</span>\n              </a>\n            </li>\n          );\n        })}\n      </ul>\n    </nav>\n  );\n};\n\nexport default DynamicNavigation;\n"
    }
  ],
  "$schema": "https://www.cooki-ui.design/schema/registry-item.json"
}