{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "navigation-menu",
  "title": "Navigation Menu",
  "description": "Site navigation with panels on Radix: a plain bar, a mega panel of groups, a sliding pill or a sliding underline, and a panel that morphs between triggers.",
  "dependencies": [
    "lucide-react",
    "radix-ui"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/navigation-menu.tsx",
      "content": "import type * as React from \"react\"\nimport { createContext, useContext, useLayoutEffect, useRef, useState } from \"react\"\nimport { NavigationMenu as NavigationMenuPrimitive } from \"radix-ui\"\nimport { ChevronDown } from \"lucide-react\"\nimport {\n  CONTENT_LAYOUT_CLASS,\n  CONTENT_MATERIALIZE_CLASS,\n  CONTENT_WIDTH_CLASS,\n  INDICATOR_BASE_CLASS,\n  INDICATOR_CLASS,\n  ITEM_BASE_CLASS,\n  ITEM_CLASS,\n  LIST_CLASS,\n  PANEL_ENTER_CLASS,\n  PANEL_MATERIALIZE_CLASS,\n  VIEWPORT_LEFT,\n  type NavigationMenuEffect,\n  type NavigationMenuVariant,\n} from \"@/registry/miseui/ui/navigation-menu-classes\"\nimport { NavigationMenuGroup, NavigationMenuPanelLink } from \"@/registry/miseui/ui/navigation-menu-parts\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\nconst HOVER_DELAY_MS = 120\n\ninterface NavigationMenuContextValue {\n  variant: NavigationMenuVariant\n  effect?: NavigationMenuEffect\n}\n\nconst NavigationMenuContext = createContext<NavigationMenuContextValue>({ variant: \"bar\" })\n\ntype NavigationMenuProps = React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {\n  /** `bar` plain links, `mega` a full-width panel of groups, `pill` a sliding pill, `underline` a sliding rule. */\n  variant?: NavigationMenuVariant\n  /** `materialize` grows the panel out of the bar and morphs its size and place between triggers. */\n  effect?: NavigationMenuEffect\n}\n\n/** Keeps the panel under its trigger. Written to the DOM: nothing else in the render depends on it. */\nfunction useTriggerLeft(rootRef: React.RefObject<HTMLElement | null>, open: string, follow: boolean) {\n  useLayoutEffect(() => {\n    const root = rootRef.current\n    if (!root || !open || !follow) return\n    const trigger = root.querySelector(\"[data-slot='navigation-menu-trigger'][data-state='open']\")\n    if (!trigger) return\n    const left = trigger.getBoundingClientRect().left - root.getBoundingClientRect().left\n    root.style.setProperty(\"--navigation-menu-left\", `${left}px`)\n  }, [rootRef, open, follow])\n}\n\nfunction NavigationMenu({\n  variant = \"bar\",\n  effect,\n  value,\n  defaultValue,\n  onValueChange,\n  delayDuration = HOVER_DELAY_MS,\n  className,\n  children,\n  ...props\n}: NavigationMenuProps) {\n  const rootRef = useRef<HTMLElement>(null)\n  const [uncontrolled, setUncontrolled] = useState(defaultValue ?? \"\")\n  const open = value ?? uncontrolled\n  const context = { variant, effect }\n  useTriggerLeft(rootRef, open, variant !== \"mega\")\n  return (\n    <NavigationMenuContext.Provider value={context}>\n      <NavigationMenuPrimitive.Root\n        ref={rootRef}\n        data-slot=\"navigation-menu\"\n        data-variant={variant}\n        data-effect={effect}\n        value={open}\n        delayDuration={delayDuration}\n        onValueChange={(next) => {\n          setUncontrolled(next)\n          onValueChange?.(next)\n        }}\n        // The root is the container for the panel widths. Containment needs a width of its own, hence w-full.\n        className={cn(\"@container relative w-full min-w-0\", className)}\n        {...props}\n      >\n        {children}\n        <NavigationMenuPanel variant={variant} effect={effect} />\n      </NavigationMenuPrimitive.Root>\n    </NavigationMenuContext.Provider>\n  )\n}\n\nfunction NavigationMenuPanel({ variant, effect }: NavigationMenuContextValue) {\n  const mega = variant === \"mega\"\n  return (\n    <div data-slot=\"navigation-menu-positioner\" className=\"pointer-events-none absolute top-full left-0 z-40 w-full pt-2\">\n      <NavigationMenuPrimitive.Viewport\n        data-slot=\"navigation-menu-viewport\"\n        style={mega ? undefined : { left: VIEWPORT_LEFT }}\n        className={cn(\n          \"pointer-events-auto relative h-(--radix-navigation-menu-viewport-height) max-w-full origin-top overflow-hidden rounded-lg border bg-popover text-popover-foreground shadow-lg\",\n          mega ? \"w-full\" : \"w-(--radix-navigation-menu-viewport-width)\",\n          effect === \"materialize\" ? PANEL_MATERIALIZE_CLASS : PANEL_ENTER_CLASS,\n        )}\n      />\n    </div>\n  )\n}\n\nfunction NavigationMenuList({ className, children, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {\n  const { variant } = useContext(NavigationMenuContext)\n  const indicator = INDICATOR_CLASS[variant]\n  return (\n    <NavigationMenuPrimitive.List data-slot=\"navigation-menu-list\" className={cn(LIST_CLASS[variant], className)} {...props}>\n      {children}\n      {indicator ? (\n        <NavigationMenuPrimitive.Indicator data-slot=\"navigation-menu-indicator\" className={cn(INDICATOR_BASE_CLASS, indicator)} />\n      ) : null}\n    </NavigationMenuPrimitive.List>\n  )\n}\n\nfunction NavigationMenuItem(props: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {\n  return <NavigationMenuPrimitive.Item data-slot=\"navigation-menu-item\" {...props} />\n}\n\nfunction NavigationMenuTrigger({ className, children, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {\n  const { variant } = useContext(NavigationMenuContext)\n  return (\n    <NavigationMenuPrimitive.Trigger\n      data-slot=\"navigation-menu-trigger\"\n      className={cn(ITEM_BASE_CLASS, ITEM_CLASS[variant], \"disabled:pointer-events-none disabled:opacity-50\", className)}\n      {...props}\n    >\n      {children}\n      <ChevronDown\n        aria-hidden=\"true\"\n        className=\"size-3 text-muted-foreground transition-transform duration-(--duration-fast) ease-(--ease-mise) group-data-[state=open]/trigger:rotate-180 motion-reduce:transition-none\"\n      />\n    </NavigationMenuPrimitive.Trigger>\n  )\n}\n\nfunction NavigationMenuContent({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {\n  const { variant, effect } = useContext(NavigationMenuContext)\n  return (\n    <NavigationMenuPrimitive.Content\n      data-slot=\"navigation-menu-content\"\n      className={cn(\n        \"absolute top-0 left-0\",\n        CONTENT_WIDTH_CLASS[variant],\n        CONTENT_LAYOUT_CLASS[variant],\n        effect === \"materialize\" && CONTENT_MATERIALIZE_CLASS,\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/** A top-level link in the bar, with no panel. Set `active` on the current page. */\nfunction NavigationMenuLink({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {\n  const { variant } = useContext(NavigationMenuContext)\n  return (\n    <NavigationMenuPrimitive.Link\n      data-slot=\"navigation-menu-link\"\n      className={cn(ITEM_BASE_CLASS, ITEM_CLASS[variant], className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  NavigationMenu,\n  NavigationMenuContent,\n  NavigationMenuGroup,\n  NavigationMenuItem,\n  NavigationMenuLink,\n  NavigationMenuList,\n  NavigationMenuPanelLink,\n  NavigationMenuTrigger,\n  type NavigationMenuEffect,\n  type NavigationMenuProps,\n  type NavigationMenuVariant,\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/miseui/ui/navigation-menu-classes.ts",
      "content": "import { cn } from \"@/registry/miseui/lib/utils\"\n\ntype NavigationMenuVariant = \"bar\" | \"mega\" | \"pill\" | \"underline\"\ntype NavigationMenuEffect = \"materialize\"\n\nconst FOCUS_CLASS = \"outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\n/** `pill` and `underline` slide an indicator that measures one row only, so those two must not wrap. */\nconst LIST_CLASS: Record<NavigationMenuVariant, string> = {\n  bar: \"flex flex-wrap items-center gap-1\",\n  mega: \"flex flex-wrap items-center gap-1\",\n  pill: \"flex w-fit items-center rounded-full bg-muted p-1\",\n  underline: \"flex items-center border-b\",\n}\n\nconst ITEM_CLASS: Record<NavigationMenuVariant, string> = {\n  bar: \"h-9 rounded-md px-3 hover:bg-accent data-[state=open]:bg-accent data-active:font-medium pointer-coarse:h-10\",\n  mega: \"h-9 rounded-md px-3 font-medium hover:bg-accent data-[state=open]:bg-accent pointer-coarse:h-10\",\n  // The moving pill behind them is the indicator; z-10 keeps the words above it.\n  pill: \"relative z-10 h-8 rounded-full px-3 text-muted-foreground hover:text-foreground data-[state=open]:text-foreground data-active:bg-background data-active:text-foreground data-active:shadow-xs pointer-coarse:h-10\",\n  underline:\n    \"relative z-10 -mb-px h-10 border-b-2 border-transparent px-3 text-muted-foreground hover:text-foreground data-[state=open]:text-foreground data-active:border-foreground data-active:text-foreground\",\n}\n\nconst ITEM_BASE_CLASS = cn(\n  \"group/trigger inline-flex items-center justify-center gap-1 text-sm whitespace-nowrap\",\n  \"transition-colors duration-(--duration-fast) ease-(--ease-mise)\",\n  FOCUS_CLASS,\n)\n\nconst INDICATOR_BASE_CLASS = \"transition-[width,transform] duration-(--duration-base) ease-(--ease-mise-out) motion-reduce:transition-none\"\nconst INDICATOR_CLASS: Partial<Record<NavigationMenuVariant, string>> = {\n  pill: \"top-1 z-0 h-[calc(100%-8px)] rounded-full bg-background shadow-xs\",\n  underline: \"bottom-0 z-20 h-0.5 bg-foreground\",\n}\n\nconst PANEL_ENTER_CLASS = cn(\n  \"duration-(--duration-fast) ease-(--ease-mise)\",\n  \"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0\",\n)\n/** The enter and exit values stay unqualified so the media overrides below win on source order. */\nconst PANEL_MATERIALIZE_CLASS = cn(\n  \"transition-[width,height,left] duration-(--duration-base) ease-(--ease-mise-out) will-change-[transform,opacity,filter]\",\n  \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n  \"fade-in-0 zoom-in-90 blur-in-sm fade-out-0 zoom-out-90 blur-out-sm\",\n  \"motion-reduce:transition-none motion-reduce:zoom-in-100 motion-reduce:zoom-out-100 motion-reduce:blur-in-0 motion-reduce:blur-out-0\",\n  \"[@media(prefers-reduced-transparency:reduce)]:blur-in-0 [@media(prefers-reduced-transparency:reduce)]:blur-out-0\",\n)\n\nconst CONTENT_MATERIALIZE_CLASS = cn(\n  \"duration-(--duration-base) ease-(--ease-mise-out)\",\n  \"data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in-0 data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out-0\",\n  \"data-[motion=from-end]:slide-in-from-right-4 data-[motion=from-start]:slide-in-from-left-4\",\n  \"data-[motion=to-end]:slide-out-to-right-4 data-[motion=to-start]:slide-out-to-left-4\",\n  \"motion-reduce:animate-none\",\n)\n\n/** Widths in cqw of the root, which is the container: a narrow column gets a narrow panel and nothing overflows the page. */\nconst CONTENT_WIDTH_CLASS: Record<NavigationMenuVariant, string> = {\n  bar: \"w-[min(20rem,100cqw)]\",\n  mega: \"w-full\",\n  pill: \"w-[min(20rem,100cqw)]\",\n  underline: \"w-[min(20rem,100cqw)]\",\n}\n\nconst CONTENT_LAYOUT_CLASS: Record<NavigationMenuVariant, string> = {\n  bar: \"grid gap-1 p-2\",\n  mega: \"grid gap-4 p-4 @md:grid-cols-2 @2xl:grid-cols-3\",\n  pill: \"grid gap-1 p-2\",\n  underline: \"grid gap-1 p-2\",\n}\n\n/**\n * Follows the open trigger but stops at the right edge. `left` and not a transform, so the percentage\n * means the width of the root; the Radix variable holds the panel's own measured width.\n */\nconst VIEWPORT_LEFT = \"max(0px, min(var(--navigation-menu-left, 0px), calc(100% - var(--radix-navigation-menu-viewport-width, 0px))))\"\n\nconst PANEL_LINK_CLASS = cn(\n  \"flex min-h-10 gap-3 rounded-md p-2 text-left\",\n  \"transition-colors duration-(--duration-fast) ease-(--ease-mise) hover:bg-accent data-active:bg-accent\",\n  FOCUS_CLASS,\n)\n\nexport {\n  CONTENT_LAYOUT_CLASS,\n  CONTENT_MATERIALIZE_CLASS,\n  CONTENT_WIDTH_CLASS,\n  INDICATOR_BASE_CLASS,\n  INDICATOR_CLASS,\n  ITEM_BASE_CLASS,\n  ITEM_CLASS,\n  LIST_CLASS,\n  PANEL_ENTER_CLASS,\n  PANEL_LINK_CLASS,\n  PANEL_MATERIALIZE_CLASS,\n  VIEWPORT_LEFT,\n  type NavigationMenuEffect,\n  type NavigationMenuVariant,\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/miseui/ui/navigation-menu-parts.tsx",
      "content": "import type * as React from \"react\"\nimport { useId } from \"react\"\nimport { NavigationMenu as NavigationMenuPrimitive } from \"radix-ui\"\nimport { PANEL_LINK_CLASS } from \"@/registry/miseui/ui/navigation-menu-classes\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype NavigationMenuPanelLinkProps = Omit<React.ComponentProps<typeof NavigationMenuPrimitive.Link>, \"title\"> & {\n  title: React.ReactNode\n  description?: React.ReactNode\n  icon?: React.ReactNode\n}\n\n/** A row inside a panel, with room for one line saying where it goes. */\nfunction NavigationMenuPanelLink({ title, description, icon, className, ...props }: NavigationMenuPanelLinkProps) {\n  return (\n    <NavigationMenuPrimitive.Link data-slot=\"navigation-menu-panel-link\" className={cn(PANEL_LINK_CLASS, className)} {...props}>\n      {icon ? <span aria-hidden=\"true\" className=\"flex h-5 shrink-0 items-center text-muted-foreground [&_svg]:size-4\">{icon}</span> : null}\n      <span className=\"min-w-0\">\n        <span className=\"block text-sm font-medium\">{title}</span>\n        {description ? <span className=\"block text-[13px] text-muted-foreground\">{description}</span> : null}\n      </span>\n    </NavigationMenuPrimitive.Link>\n  )\n}\n\ninterface NavigationMenuGroupProps extends React.ComponentProps<\"div\"> {\n  title: string\n}\n\n/** One titled column of a `mega` panel. */\nfunction NavigationMenuGroup({ title, className, children, ...props }: NavigationMenuGroupProps) {\n  const titleId = useId()\n  return (\n    <div role=\"group\" aria-labelledby={titleId} data-slot=\"navigation-menu-group\" className={cn(\"grid content-start gap-1\", className)} {...props}>\n      <p id={titleId} className=\"px-2 pb-1 text-[13px] text-muted-foreground\">{title}</p>\n      {children}\n    </div>\n  )\n}\n\nexport { NavigationMenuGroup, NavigationMenuPanelLink, type NavigationMenuPanelLinkProps }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "navigation"
  ],
  "type": "registry:ui"
}