{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "navbar-menu",
  "title": "Navbar Menu",
  "description": "Hover-driven menu whose pill and panel morph between items.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/velora/navbar-menu.tsx",
      "content": "\"use client\";\n\nimport {\n  createContext,\n  useContext,\n  useEffect,\n  useId,\n  useRef,\n  useState,\n} from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst MenuContext = createContext<{\n  active: string | null;\n  setActive: (value: string | null) => void;\n}>({ active: null, setActive: () => {} });\n\n/**\n * Hover-driven navigation menu whose panel morphs between items.\n * Wrap `MenuItem`s in `NavbarMenu`. The panel closes when the pointer or\n * keyboard focus leaves the menu, and on Escape.\n */\nexport function NavbarMenu({\n  children,\n  className,\n}: {\n  children: React.ReactNode;\n  className?: string;\n}) {\n  const [active, setActive] = useState<string | null>(null);\n\n  // Escape also dismisses a panel opened by hover, wherever focus is.\n  useEffect(() => {\n    if (!active) return;\n    const onKeyDown = (event: KeyboardEvent) => {\n      if (event.key === \"Escape\") setActive(null);\n    };\n    document.addEventListener(\"keydown\", onKeyDown);\n    return () => document.removeEventListener(\"keydown\", onKeyDown);\n  }, [active]);\n\n  return (\n    <MenuContext.Provider value={{ active, setActive }}>\n      <nav\n        data-slot=\"navbar-menu\"\n        onMouseLeave={() => setActive(null)}\n        onBlur={(event) => {\n          if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n            setActive(null);\n          }\n        }}\n        className={cn(\n          \"relative flex items-center gap-1 rounded-full border bg-background/80 px-3 py-1.5 backdrop-blur-md\",\n          className\n        )}\n      >\n        {children}\n      </nav>\n    </MenuContext.Provider>\n  );\n}\n\nexport function MenuItem({\n  label,\n  href,\n  children,\n  className,\n}: {\n  label: string;\n  /** Renders the item as a link; ignored when the item has a panel */\n  href?: string;\n  children?: React.ReactNode;\n  className?: string;\n}) {\n  const { active, setActive } = useContext(MenuContext);\n  const reducedMotion = useReducedMotion();\n  const triggerRef = useRef<HTMLButtonElement & HTMLAnchorElement>(null);\n  const panelId = useId();\n  const open = active === label;\n  const hasPanel = Boolean(children);\n\n  const triggerClass = cn(\n    \"relative rounded-full px-3.5 py-1.5 text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n    open ? \"text-foreground\" : \"text-muted-foreground hover:text-foreground\",\n    className\n  );\n  const pill = open && (\n    <motion.span\n      layoutId=\"navbar-menu-pill\"\n      className=\"absolute inset-0 -z-10 rounded-full bg-muted\"\n      transition={\n        reducedMotion\n          ? { duration: 0 }\n          : { type: \"spring\", stiffness: 380, damping: 32 }\n      }\n    />\n  );\n\n  return (\n    <div\n      className=\"relative\"\n      onMouseEnter={() => setActive(label)}\n      onFocus={(event) => {\n        // Only open when focus arrives from outside this item, so Escape\n        // can return focus to the trigger without reopening the panel.\n        if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n          setActive(label);\n        }\n      }}\n      onKeyDown={(event) => {\n        if (event.key !== \"Escape\" || !open) return;\n        setActive(null);\n        triggerRef.current?.focus();\n      }}\n    >\n      {href && !hasPanel ? (\n        <a ref={triggerRef} href={href} className={cn(\"block\", triggerClass)}>\n          {pill}\n          {label}\n        </a>\n      ) : (\n        <button\n          ref={triggerRef}\n          type=\"button\"\n          aria-expanded={hasPanel ? open : undefined}\n          aria-controls={hasPanel && open ? panelId : undefined}\n          onClick={() => setActive(label)}\n          className={triggerClass}\n        >\n          {pill}\n          {label}\n        </button>\n      )}\n\n      <AnimatePresence>\n        {open && hasPanel && (\n          <motion.div\n            id={panelId}\n            initial={{ opacity: 0, y: 6, scale: 0.97 }}\n            animate={{ opacity: 1, y: 0, scale: 1 }}\n            exit={{ opacity: 0, y: 6, scale: 0.97 }}\n            transition={{ duration: reducedMotion ? 0 : 0.18, ease: \"easeOut\" }}\n            className=\"absolute left-1/2 top-full z-50 mt-3 w-max -translate-x-1/2 rounded-2xl border bg-popover p-3 text-popover-foreground shadow-xl shadow-foreground/5\"\n          >\n            {children}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/velora/navbar-menu.tsx"
    }
  ],
  "type": "registry:ui"
}