{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "navigation-menu",
  "title": "Navigation Menu",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenu.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n  import type { RegisteredContent } from './NavigationMenuContext'\n\n  export interface NavigationMenuProps extends HTMLAttributes<HTMLDivElement> {\n    /** Controlled open item value. When omitted the menu is uncontrolled. */\n    value?: string\n    defaultValue?: string\n    /** Render the shared viewport panel. Disable for per-item flyouts. */\n    viewport?: boolean\n    /** Hover delay (ms) before opening when nothing is open. */\n    delayDuration?: number\n    /** Grace window (ms) after closing during which hover opens instantly. */\n    skipDelayDuration?: number\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { setNavigationMenuRootContext } from './NavigationMenuContext'\n  import NavigationMenuViewport from './NavigationMenuViewport.svelte'\n\n  let {\n    class: className,\n    value = $bindable(),\n    defaultValue,\n    viewport = true,\n    delayDuration = 200,\n    skipDelayDuration = 300,\n    children,\n    ref = $bindable(null),\n    onmouseleave,\n    ...restProps\n  }: NavigationMenuProps = $props()\n\n  let seeded = false\n  $effect.pre(() => {\n    if (!seeded && value === undefined && defaultValue !== undefined) value = defaultValue\n    seeded = true\n  })\n\n  let rootEl: HTMLDivElement | null = $state(null)\n  let contentEl: HTMLElement | null = $state(null)\n  $effect(() => {\n    ref = rootEl\n  })\n\n  const triggers: Array<{ value: string; getEl: () => HTMLElement | null }> = []\n  let contents = $state<Record<string, RegisteredContent | undefined>>({})\n  let prevValue: string | undefined = undefined\n  let lastCloseAt = 0\n  let openTimer: ReturnType<typeof setTimeout> | null = null\n\n  function setValue(next: string | undefined, refocusTrigger = false) {\n    if (openTimer) {\n      clearTimeout(openTimer)\n      openTimer = null\n    }\n    if (value !== next) {\n      prevValue = value\n      value = next\n      if (next === undefined) lastCloseAt = Date.now()\n    }\n    if (refocusTrigger && prevValue !== undefined) {\n      const target = prevValue\n      requestAnimationFrame(() => triggers.find((t) => t.value === target)?.getEl()?.focus())\n    }\n  }\n\n  function orderOf(v: string | undefined): number {\n    if (v === undefined) return -1\n    const i = triggers.findIndex((t) => t.value === v)\n    return i === -1 ? Number.MAX_SAFE_INTEGER : i\n  }\n\n  setNavigationMenuRootContext({\n    getValue: () => value,\n    setValue,\n    isViewportEnabled: () => viewport,\n    getRootEl: () => rootEl,\n    getContentEl: () => contentEl,\n    setContentEl: (el) => {\n      contentEl = el\n    },\n    registerTrigger(triggerValue, getEl) {\n      const entry = { value: triggerValue, getEl }\n      triggers.push(entry)\n      return () => {\n        const i = triggers.indexOf(entry)\n        if (i >= 0) triggers.splice(i, 1)\n      }\n    },\n    focusSiblingTrigger(triggerValue, dir) {\n      const live = triggers.filter((t) => t.getEl()?.isConnected)\n      if (live.length === 0) return null\n      let next: number\n      if (dir === 'first') next = 0\n      else if (dir === 'last') next = live.length - 1\n      else {\n        const index = Math.max(0, live.findIndex((t) => t.value === triggerValue))\n        next = (index + dir + live.length) % live.length\n      }\n      const target = live[next]!\n      target.getEl()?.focus()\n      return target.value\n    },\n    registerContent(contentValue, content) {\n      contents[contentValue] = content\n      return () => {\n        if (contents[contentValue] === content) delete contents[contentValue]\n      }\n    },\n    getContent: (v) => contents[v],\n    getMotion: (v) => {\n      if (prevValue === undefined || v === prevValue) return undefined\n      return orderOf(v) > orderOf(prevValue) ? 'from-start' : 'from-end'\n    },\n    openWithDelay: (triggerValue) => {\n      if (value === triggerValue) return\n      if (openTimer) clearTimeout(openTimer)\n      // Instant when something is already open or inside the skip window.\n      if (value !== undefined || Date.now() - lastCloseAt < skipDelayDuration) {\n        prevValue = value\n        value = triggerValue\n        return\n      }\n      openTimer = setTimeout(() => {\n        openTimer = null\n        prevValue = value\n        value = triggerValue\n      }, delayDuration)\n    },\n    cancelDelayedOpen: () => {\n      if (openTimer) {\n        clearTimeout(openTimer)\n        openTimer = null\n      }\n    },\n  })\n\n  $effect(() => {\n    return () => {\n      if (openTimer) clearTimeout(openTimer)\n    }\n  })\n\n  // Outside pointer down closes the open panel.\n  $effect(() => {\n    if (value === undefined) return\n    function onPointerDown(e: PointerEvent) {\n      if (rootEl && !rootEl.contains(e.target as Node)) {\n        prevValue = value\n        value = undefined\n        lastCloseAt = Date.now()\n      }\n    }\n    const t = setTimeout(() => document.addEventListener('pointerdown', onPointerDown), 0)\n    return () => {\n      clearTimeout(t)\n      document.removeEventListener('pointerdown', onPointerDown)\n    }\n  })\n</script>\n\n<div\n  bind:this={rootEl}\n  data-uipkge=\"\"\n  data-slot=\"navigation-menu\"\n  data-viewport={viewport}\n  data-orientation=\"horizontal\"\n  class={cn('group/navigation-menu relative flex max-w-max flex-1 items-center justify-center', className)}\n  onmouseleave={(e) => {\n    setValue(undefined)\n    onmouseleave?.(e)\n  }}\n  {...restProps}\n>\n  {@render children?.()}\n  {#if viewport}\n    <NavigationMenuViewport />\n  {/if}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenu.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuContent.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuContentProps extends HTMLAttributes<HTMLDivElement> {\n    /**\n     * Force inline-flyout rendering even when the root viewport is enabled.\n     * Defaults to following the root `viewport` prop.\n     */\n    forceMount?: boolean\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { getNavigationMenuItemContext, getNavigationMenuRootContext } from './NavigationMenuContext'\n  import { navigationMenuContentVariants } from './navigation-menu-content.variants'\n\n  let {\n    class: className,\n    forceMount = false,\n    children,\n    ref = $bindable(null),\n    onkeydown,\n    ...restProps\n  }: NavigationMenuContentProps = $props()\n\n  const root = getNavigationMenuRootContext()\n  const item = getNavigationMenuItemContext()\n\n  // Viewport mode: register the children snippet with the root — the shared\n  // NavigationMenuViewport renders the active item's snippet (a snippet\n  // hand-off, since Svelte has no portal). Otherwise render inline.\n  const useViewport = $derived((root?.isViewportEnabled() ?? true) && !forceMount)\n\n  $effect(() => {\n    if (useViewport && item && root) {\n      const v = item.value\n      // Read className inside the effect so consumer class changes re-register.\n      const payload = { snippet: children, contentId: item.contentId, triggerId: item.triggerId, className }\n      return root.registerContent(v, payload)\n    }\n  })\n\n  let el: HTMLDivElement | null = $state(null)\n  $effect(() => {\n    ref = el\n    // Inline mode owns the content element for ArrowDown focus jumps.\n    if (!useViewport && item && root && root.getValue() === item.value) root.setContentEl(el)\n  })\n\n  const isOpen = $derived(item?.isOpen() ?? false)\n  const motion = $derived(item && root ? root.getMotion(item.value) : undefined)\n\n  const panelClass = $derived(\n    cn(\n      navigationMenuContentVariants(),\n      'group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:motion-safe:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:motion-safe:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:motion-safe:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:motion-safe:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:motion-safe:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:motion-safe:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none',\n      className,\n    ),\n  )\n</script>\n\n{#if !useViewport && isOpen && item}\n  <div\n    bind:this={el}\n    id={item.contentId}\n    aria-labelledby={item.triggerId}\n    data-uipkge=\"\"\n    data-slot=\"navigation-menu-content\"\n    data-state=\"open\"\n    data-motion={motion}\n    class={panelClass}\n    onkeydown={(e) => {\n      if (e.key === 'Escape') {\n        e.preventDefault()\n        root?.setValue(undefined, true)\n      }\n      onkeydown?.(e)\n    }}\n    {...restProps}\n  >\n    {@render children?.()}\n  </div>\n{/if}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuContent.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuContext.ts",
      "content": "import type { Snippet } from 'svelte'\nimport type { ClassValue } from 'clsx'\nimport { getContext, setContext } from 'svelte'\n\n/** Panel payload one item hands to the shared viewport for rendering. */\nexport interface RegisteredContent {\n  snippet: Snippet | undefined\n  contentId: string\n  triggerId: string\n  className?: ClassValue | null\n}\n\n/** Root open-value state, trigger registry, and shared-viewport content map. */\nexport interface NavigationMenuRootContextValue {\n  getValue: () => string | undefined\n  setValue: (value: string | undefined, refocusTrigger?: boolean) => void\n  isViewportEnabled: () => boolean\n  getRootEl: () => HTMLElement | null\n  getContentEl: () => HTMLElement | null\n  setContentEl: (el: HTMLElement | null) => void\n  registerTrigger: (value: string, getEl: () => HTMLElement | null) => () => void\n  /** Focus the sibling trigger in `dir`; returns the newly focused value. */\n  focusSiblingTrigger: (value: string, dir: 1 | -1 | 'first' | 'last') => string | null\n  registerContent: (value: string, content: RegisteredContent) => () => void\n  getContent: (value: string) => RegisteredContent | undefined\n  /** Enter direction for the active panel (viewport motion classes). */\n  getMotion: (value: string) => 'from-start' | 'from-end' | undefined\n  openWithDelay: (value: string) => void\n  cancelDelayedOpen: () => void\n}\n\n/** One item's identity + trigger/content pairing. */\nexport interface NavigationMenuItemContextValue {\n  value: string\n  triggerId: string\n  contentId: string\n  isOpen: () => boolean\n  getTriggerEl: () => HTMLElement | null\n  setTriggerEl: (el: HTMLElement | null) => void\n}\n\nconst RootKey = Symbol('NavigationMenuRoot')\nconst ItemKey = Symbol('NavigationMenuItem')\n\nexport function setNavigationMenuRootContext(v: NavigationMenuRootContextValue) {\n  setContext(RootKey, v)\n}\nexport function getNavigationMenuRootContext(): NavigationMenuRootContextValue | null {\n  return getContext<NavigationMenuRootContextValue | null>(RootKey) ?? null\n}\n\nexport function setNavigationMenuItemContext(v: NavigationMenuItemContextValue) {\n  setContext(ItemKey, v)\n}\nexport function getNavigationMenuItemContext(): NavigationMenuItemContextValue | null {\n  return getContext<NavigationMenuItemContextValue | null>(ItemKey) ?? null\n}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuContext.ts"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/navigation-menu-content.variants.ts",
      "content": "import { cva } from 'class-variance-authority'\n\n/**\n * Variant definitions live in their own file (rather than the package\n * `index.ts`) so consuming components can import without creating a circular\n * dependency through the index. See card.variants.ts for the canonical\n * example + the SSR symptom that motivated the split.\n */\nexport const navigationMenuContentVariants = cva(\n  'data-[motion^=from-]:motion-safe:animate-in data-[motion^=to-]:motion-safe:animate-out data-[motion^=from-]:motion-safe:fade-in data-[motion^=to-]:motion-safe:fade-out data-[motion=from-end]:motion-safe:slide-in-from-right-52 data-[motion=from-start]:motion-safe:slide-in-from-left-52 data-[motion=to-end]:motion-safe:slide-out-to-right-52 data-[motion=to-start]:motion-safe:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto',\n)\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/navigation-menu-content.variants.ts"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuIndicator.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuIndicatorProps extends HTMLAttributes<HTMLDivElement> {\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { tick } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { getNavigationMenuRootContext } from './NavigationMenuContext'\n\n  let { class: className, ref = $bindable(null), ...restProps }: NavigationMenuIndicatorProps = $props()\n\n  const root = getNavigationMenuRootContext()\n  const value = $derived(root?.getValue())\n  const visible = $derived(value !== undefined)\n\n  // Measured position of the open trigger's center relative to the root\n  // (reka positions this automatically; the hand-rolled twin measures).\n  let left = $state(0)\n\n  $effect(() => {\n    value\n    if (!visible) return\n    tick().then(() => {\n      const rootEl = root?.getRootEl()\n      const trigger = rootEl?.querySelector<HTMLElement>('[data-slot=\"navigation-menu-trigger\"][data-state=\"open\"]')\n      if (rootEl && trigger) {\n        const rootRect = rootEl.getBoundingClientRect()\n        const rect = trigger.getBoundingClientRect()\n        left = rect.left - rootRect.left + rect.width / 2\n      }\n    })\n  })\n</script>\n\n{#if visible}\n  <div\n    bind:this={ref}\n    data-uipkge=\"\"\n    data-slot=\"navigation-menu-indicator\"\n    data-state=\"visible\"\n    class={cn(\n      'data-[state=visible]:motion-safe:animate-in data-[state=hidden]:motion-safe:animate-out data-[state=hidden]:motion-safe:fade-out data-[state=visible]:motion-safe:fade-in absolute top-full z-[1] flex h-1.5 -translate-x-1/2 items-end justify-center overflow-hidden',\n      className,\n    )}\n    style:left=\"{left}px\"\n    aria-hidden=\"true\"\n    {...restProps}\n  >\n    <div class=\"bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md\"></div>\n  </div>\n{/if}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuIndicator.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuItem.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuItemProps extends HTMLAttributes<HTMLLIElement> {\n    /**\n     * Stable value for this item. Defaults to a generated id. Pass one when\n     * controlling the open panel through the root `value` / `defaultValue`.\n     */\n    value?: string\n    ref?: HTMLLIElement | null\n  }\n\n  let itemCounter = 0\n</script>\n\n<script lang=\"ts\">\n  import { untrack } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { getNavigationMenuRootContext, setNavigationMenuItemContext } from './NavigationMenuContext'\n\n  let { class: className, value: valueProp, children, ref = $bindable(null), ...restProps }: NavigationMenuItemProps =\n    $props()\n\n  const root = getNavigationMenuRootContext()\n  // Computed once: ids must stay stable for the component's lifetime (aria\n  // references + root tracking depend on it).\n  const value = untrack(() => valueProp ?? `item-${++itemCounter}`)\n  const triggerId = `navigation-menu-trigger-${value}`\n  const contentId = `navigation-menu-content-${value}`\n\n  const isOpen = $derived(root?.getValue() === value)\n\n  let triggerEl: HTMLElement | null = $state(null)\n\n  setNavigationMenuItemContext({\n    value,\n    triggerId,\n    contentId,\n    isOpen: () => isOpen,\n    getTriggerEl: () => triggerEl,\n    setTriggerEl: (el) => {\n      triggerEl = el\n    },\n  })\n</script>\n\n<li\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"navigation-menu-item\"\n  data-value={value}\n  data-state={isOpen ? 'open' : 'closed'}\n  class={cn('relative', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</li>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuItem.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuLink.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAnchorAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuLinkProps extends HTMLAnchorAttributes {\n    active?: boolean\n    ref?: HTMLAnchorElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { getNavigationMenuRootContext } from './NavigationMenuContext'\n\n  let {\n    class: className,\n    active = false,\n    children,\n    ref = $bindable(null),\n    onclick,\n    ...restProps\n  }: NavigationMenuLinkProps = $props()\n\n  const root = getNavigationMenuRootContext()\n</script>\n\n<a\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"navigation-menu-link\"\n  data-active={active ? '' : undefined}\n  aria-current={active ? 'page' : undefined}\n  class={cn(\n    \"data-active:focus:bg-accent data-active:hover:bg-accent data-active:bg-accent/50 data-active:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-[color,box-shadow] focus-visible:ring-4 focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4\",\n    className,\n  )}\n  onclick={(e) => {\n    onclick?.(e)\n    // Following a link dismisses the menu.\n    root?.setValue(undefined)\n  }}\n  {...restProps}\n>\n  {@render children?.()}\n</a>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuLink.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuList.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuListProps extends HTMLAttributes<HTMLUListElement> {\n    ref?: HTMLUListElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: NavigationMenuListProps = $props()\n</script>\n\n<ul\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"navigation-menu-list\"\n  class={cn('group flex flex-1 list-none items-center justify-center gap-1', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</ul>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuList.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuTrigger.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuTriggerProps extends HTMLButtonAttributes {\n    disabled?: boolean\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { tick } from 'svelte'\n  import { ChevronDown } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n  import { getNavigationMenuItemContext, getNavigationMenuRootContext } from './NavigationMenuContext'\n  import { navigationMenuTriggerStyle } from './navigation-menu.variants'\n\n  let {\n    class: className,\n    disabled,\n    children,\n    ref = $bindable(null),\n    onclick,\n    onkeydown,\n    onmouseenter,\n    onmouseleave,\n    ...restProps\n  }: NavigationMenuTriggerProps = $props()\n\n  const root = getNavigationMenuRootContext()\n  const item = getNavigationMenuItemContext()\n\n  let el: HTMLButtonElement | null = $state(null)\n  $effect(() => {\n    ref = el\n    item?.setTriggerEl(el)\n  })\n  $effect(() => {\n    if (item && root) {\n      const v = item.value\n      return root.registerTrigger(v, () => el)\n    }\n  })\n\n  const isOpen = $derived(item?.isOpen() ?? false)\n\n  function focusFirstInContent() {\n    tick().then(() => {\n      root\n        ?.getContentEl()\n        ?.querySelector<HTMLElement>('a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])')\n        ?.focus()\n    })\n  }\n</script>\n\n<button\n  bind:this={el}\n  type=\"button\"\n  id={item?.triggerId}\n  aria-expanded={isOpen}\n  aria-controls={item?.contentId}\n  aria-disabled={disabled || undefined}\n  data-uipkge=\"\"\n  data-slot=\"navigation-menu-trigger\"\n  data-state={isOpen ? 'open' : 'closed'}\n  data-disabled={disabled ? '' : undefined}\n  {disabled}\n  class={cn(navigationMenuTriggerStyle(), 'group', className)}\n  onclick={(e) => {\n    if (disabled) return\n    if (item && root) root.setValue(isOpen ? undefined : item.value)\n    onclick?.(e)\n  }}\n  onmouseenter={(e) => {\n    if (!disabled && item && root) root.openWithDelay(item.value)\n    onmouseenter?.(e)\n  }}\n  onmouseleave={(e) => {\n    root?.cancelDelayedOpen()\n    onmouseleave?.(e)\n  }}\n  onkeydown={(e) => {\n    if (disabled) {\n      onkeydown?.(e)\n      return\n    }\n    if (e.key === 'ArrowDown') {\n      e.preventDefault()\n      if (item && root) {\n        if (!isOpen) root.setValue(item.value)\n        focusFirstInContent()\n      }\n    } else if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {\n      e.preventDefault()\n      if (item && root) {\n        const next = root.focusSiblingTrigger(item.value, e.key === 'ArrowRight' ? 1 : -1)\n        if (next && root.getValue() !== undefined) root.setValue(next)\n      }\n    } else if (e.key === 'Home') {\n      e.preventDefault()\n      if (item && root) root.focusSiblingTrigger(item.value, 'first')\n    } else if (e.key === 'End') {\n      e.preventDefault()\n      if (item && root) root.focusSiblingTrigger(item.value, 'last')\n    } else if (e.key === 'Escape') {\n      if (isOpen && root) {\n        e.preventDefault()\n        root.setValue(undefined)\n      }\n    }\n    onkeydown?.(e)\n  }}\n  {...restProps}\n>\n  {@render children?.()}\n  <ChevronDown\n    class=\"relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180\"\n    aria-hidden=\"true\"\n  />\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuTrigger.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/NavigationMenuViewport.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface NavigationMenuViewportProps extends HTMLAttributes<HTMLDivElement> {\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { getNavigationMenuRootContext } from './NavigationMenuContext'\n  import { navigationMenuContentVariants } from './navigation-menu-content.variants'\n\n  let {\n    class: className,\n    children,\n    ref = $bindable(null),\n    onkeydown,\n    ...restProps\n  }: NavigationMenuViewportProps = $props()\n\n  const root = getNavigationMenuRootContext()\n\n  let viewportEl: HTMLDivElement | null = $state(null)\n  let panelEl: HTMLDivElement | null = $state(null)\n  $effect(() => {\n    ref = viewportEl\n    root?.setContentEl(panelEl)\n  })\n\n  const value = $derived(root?.getValue())\n  const active = $derived(value !== undefined ? root?.getContent(value) : undefined)\n  const motion = $derived(value !== undefined && root ? root.getMotion(value) : undefined)\n  const isOpen = $derived(value !== undefined && active?.snippet !== undefined)\n\n  const LONG_CONTENT_CLASS =\n    'group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:motion-safe:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:motion-safe:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:motion-safe:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:motion-safe:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:motion-safe:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:motion-safe:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none'\n</script>\n\n<div class=\"absolute top-full left-0 isolate z-50 flex justify-center\">\n  <div\n    bind:this={viewportEl}\n    data-uipkge=\"\"\n    data-slot=\"navigation-menu-viewport\"\n    data-state={isOpen ? 'open' : 'closed'}\n    class={cn(\n      // NOTE: reka auto-measures `--reka-navigation-menu-viewport-*` geometry;\n      // the hand-rolled twin sizes to content instead.\n      'origin-top-center bg-popover text-popover-foreground data-[state=open]:motion-safe:animate-in data-[state=closed]:motion-safe:animate-out data-[state=closed]:motion-safe:zoom-out-95 data-[state=open]:motion-safe:zoom-in-90 relative mt-1.5 h-auto w-full overflow-hidden rounded-md border shadow md:w-max',\n      !isOpen && 'hidden',\n      className,\n    )}\n    onkeydown={(e) => {\n      if (e.key === 'Escape') {\n        e.preventDefault()\n        root?.setValue(undefined, true)\n      }\n      onkeydown?.(e)\n    }}\n    {...restProps}\n  >\n    {#if isOpen && active && value !== undefined}\n      <div\n        bind:this={panelEl}\n        id={active.contentId}\n        aria-labelledby={active.triggerId}\n        data-uipkge=\"\"\n        data-slot=\"navigation-menu-content\"\n        data-state=\"open\"\n        data-motion={motion}\n        class={cn(navigationMenuContentVariants(), LONG_CONTENT_CLASS, active.className)}\n      >\n        {@render active.snippet?.()}\n      </div>\n    {/if}\n    {@render children?.()}\n  </div>\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/NavigationMenuViewport.svelte"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/navigation-menu.variants.ts",
      "content": "import { cva } from 'class-variance-authority'\n\n/**\n * Variant definitions live in their own file (rather than the package\n * `index.ts`) so consuming Vue SFCs can import without creating a circular\n * dependency through the index. See card.variants.ts for the canonical\n * example + the SSR symptom that motivated the split.\n */\n\nexport const navigationMenuTriggerStyle = cva(\n  'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',\n)\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/navigation-menu.variants.ts"
    },
    {
      "path": "packages/registry-svelte/components/navigation-menu/index.ts",
      "content": "export { default as NavigationMenu, type NavigationMenuProps } from './NavigationMenu.svelte'\nexport { default as NavigationMenuContent, type NavigationMenuContentProps } from './NavigationMenuContent.svelte'\nexport { default as NavigationMenuIndicator, type NavigationMenuIndicatorProps } from './NavigationMenuIndicator.svelte'\nexport { default as NavigationMenuItem, type NavigationMenuItemProps } from './NavigationMenuItem.svelte'\nexport { default as NavigationMenuLink, type NavigationMenuLinkProps } from './NavigationMenuLink.svelte'\nexport { default as NavigationMenuList, type NavigationMenuListProps } from './NavigationMenuList.svelte'\nexport { default as NavigationMenuTrigger, type NavigationMenuTriggerProps } from './NavigationMenuTrigger.svelte'\nexport { default as NavigationMenuViewport, type NavigationMenuViewportProps } from './NavigationMenuViewport.svelte'\n\n// Re-export variant API from the sibling files (kept separate to avoid the\n// Component <-> index circular import that broke dev SSR for Card).\nexport { navigationMenuTriggerStyle } from './navigation-menu.variants'\nexport { navigationMenuContentVariants } from './navigation-menu-content.variants'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/navigation-menu/index.ts"
    }
  ],
  "dependencies": [
    "@lucide/svelte",
    "class-variance-authority"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Top-of-page horizontal navigation with hover/click triggered megamenus. Use for marketing sites and product navs that need rich content — featured links, mini-cards, and submenu columns.",
  "categories": [
    "navigation"
  ]
}