{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "context-menu",
  "title": "Context Menu",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenu.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n\n  export interface ContextMenuProps {\n    open?: boolean\n    onOpenChange?: (open: boolean) => void\n    children?: Snippet\n  }\n</script>\n\n<script lang=\"ts\">\n  import { setContextMenuContext, type MenuPosition } from './context'\n\n  let { open = $bindable(false), onOpenChange, children }: ContextMenuProps = $props()\n\n  let position = $state<MenuPosition>({ x: 0, y: 0 })\n  const menuElements = new Set<HTMLElement>()\n  let triggerEl: HTMLElement | null = null\n\n  function setOpen(next: boolean) {\n    if (next === open) return\n    open = next\n    onOpenChange?.(next)\n  }\n\n  function isInsideMenu(target: EventTarget | null): boolean {\n    if (!(target instanceof HTMLElement)) return false\n    if (triggerEl?.contains(target)) return true\n    for (const el of menuElements) {\n      if (el.contains(target)) return true\n    }\n    return false\n  }\n\n  $effect(() => {\n    if (!open) return\n    const onPointerDown = (e: PointerEvent) => {\n      if (!isInsideMenu(e.target)) setOpen(false)\n    }\n    const onContextMenu = (e: MouseEvent) => {\n      // Right-clicking elsewhere moves or closes the menu; the new trigger (if\n      // any) reopens at its own position.\n      if (!isInsideMenu(e.target)) setOpen(false)\n    }\n    const onKeyDown = (e: KeyboardEvent) => {\n      if (e.key === 'Escape') {\n        e.preventDefault()\n        setOpen(false)\n      }\n    }\n    window.addEventListener('pointerdown', onPointerDown, true)\n    window.addEventListener('contextmenu', onContextMenu, true)\n    window.addEventListener('keydown', onKeyDown)\n    return () => {\n      window.removeEventListener('pointerdown', onPointerDown, true)\n      window.removeEventListener('contextmenu', onContextMenu, true)\n      window.removeEventListener('keydown', onKeyDown)\n    }\n  })\n\n  setContextMenuContext({\n    get open() {\n      return open\n    },\n    openAt(pos) {\n      position = pos\n      setOpen(true)\n    },\n    close() {\n      setOpen(false)\n    },\n    get position() {\n      return position\n    },\n    registerMenuElement(el) {\n      menuElements.add(el)\n    },\n    unregisterMenuElement(el) {\n      menuElements.delete(el)\n    },\n    registerTrigger(el) {\n      triggerEl = el\n    },\n    isInsideMenu,\n  })\n</script>\n\n{@render children?.()}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenu.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuCheckboxItem.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuCheckboxItemProps extends HTMLAttributes<HTMLDivElement> {\n    checked?: boolean | 'indeterminate'\n    onCheckedChange?: (checked: boolean | 'indeterminate') => void\n    disabled?: boolean\n    /** Override the check indicator. */\n    indicator?: Snippet\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { Check } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n\n  type OnClick = NonNullable<HTMLAttributes<HTMLDivElement>['onclick']>\n  type OnMouseEnter = NonNullable<HTMLAttributes<HTMLDivElement>['onmouseenter']>\n\n  let {\n    class: className,\n    checked = $bindable(false),\n    onCheckedChange,\n    disabled = false,\n    indicator,\n    children,\n    ref = $bindable(null),\n    onclick,\n    onmouseenter,\n    ...restProps\n  }: ContextMenuCheckboxItemProps = $props()\n\n  const handleClick: OnClick = (e) => {\n    onclick?.(e)\n    if (e.defaultPrevented || disabled) return\n    const next = checked === true ? false : true\n    checked = next\n    onCheckedChange?.(next)\n  }\n\n  const handleMouseEnter: OnMouseEnter = (e) => {\n    onmouseenter?.(e)\n    if (!disabled) ref?.focus()\n  }\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-checkbox-item\"\n  data-context-menu-item=\"\"\n  role=\"menuitemcheckbox\"\n  tabindex=\"-1\"\n  aria-checked={checked === 'indeterminate' ? 'mixed' : checked}\n  data-state={checked === 'indeterminate' ? 'indeterminate' : checked ? 'checked' : 'unchecked'}\n  data-disabled={disabled ? '' : undefined}\n  aria-disabled={disabled || undefined}\n  class={cn(\n    \"focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus-visible:ring-2 focus-visible:ring-inset data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n    className,\n  )}\n  {...restProps}\n  onclick={handleClick}\n  onmouseenter={handleMouseEnter}\n>\n  <span class=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n    {#if checked === true || checked === 'indeterminate'}\n      {#if indicator}\n        {@render indicator()}\n      {:else}\n        <Check class=\"size-4\" aria-hidden=\"true\" />\n      {/if}\n    {/if}\n  </span>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuCheckboxItem.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuContent.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuContentProps 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 { getContextMenuContext, menuItemsOf } from './context'\n  import { portal } from './portal'\n\n  type OnKeyDown = NonNullable<HTMLAttributes<HTMLDivElement>['onkeydown']>\n\n  let { class: className, children, ref = $bindable(null), onkeydown, ...restProps }: ContextMenuContentProps = $props()\n\n  const ctx = getContextMenuContext()\n\n  let adjusted = $state<{ x: number; y: number } | null>(null)\n\n  $effect(() => {\n    if (!ctx.open || !ref) return\n    ctx.registerMenuElement(ref)\n    const el = ref\n    // Clamp into the viewport once measured.\n    tick().then(() => {\n      const rect = el.getBoundingClientRect()\n      adjusted = {\n        x: Math.max(8, Math.min(ctx.position.x, window.innerWidth - rect.width - 8)),\n        y: Math.max(8, Math.min(ctx.position.y, window.innerHeight - rect.height - 8)),\n      }\n    })\n    tick().then(() => el.focus({ preventScroll: true }))\n    return () => {\n      ctx.unregisterMenuElement(el)\n      adjusted = null\n    }\n  })\n\n  const x = $derived(adjusted?.x ?? ctx.position.x)\n  const y = $derived(adjusted?.y ?? ctx.position.y)\n\n  const handleKeyDown: OnKeyDown = (e) => {\n    onkeydown?.(e)\n    if (e.defaultPrevented || !ref) return\n    const items = menuItemsOf(ref)\n    if (!items.length) return\n    const current = items.indexOf(document.activeElement as HTMLElement)\n    if (e.key === 'ArrowDown') {\n      e.preventDefault()\n      ;(items[current === -1 ? 0 : (current + 1) % items.length]!).focus()\n    } else if (e.key === 'ArrowUp') {\n      e.preventDefault()\n      ;(items[current === -1 ? items.length - 1 : (current - 1 + items.length) % items.length]!).focus()\n    } else if (e.key === 'Home') {\n      e.preventDefault()\n      items[0]!.focus()\n    } else if (e.key === 'End') {\n      e.preventDefault()\n      items[items.length - 1]!.focus()\n    } else if (e.key === 'Tab') {\n      ctx.close()\n    }\n  }\n</script>\n\n{#if ctx.open}\n  <div\n    bind:this={ref}\n    use:portal\n    data-uipkge\n    data-slot=\"context-menu-content\"\n    role=\"menu\"\n    tabindex=\"-1\"\n    data-state=\"open\"\n    data-side=\"bottom\"\n    style:position=\"fixed\"\n    style:left=\"{x}px\"\n    style:top=\"{y}px\"\n    class={cn(\n      'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-[min(24rem,calc(100vh-1rem))] min-w-32 overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',\n      className,\n    )}\n    {...restProps}\n    onkeydown={handleKeyDown}\n  >\n    {@render children?.()}\n  </div>\n{/if}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuContent.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuGroup.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuGroupProps extends HTMLAttributes<HTMLDivElement> {\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  let { class: className, children, ref = $bindable(null), ...restProps }: ContextMenuGroupProps = $props()\n</script>\n\n<div bind:this={ref} data-uipkge data-slot=\"context-menu-group\" role=\"group\" class={className} {...restProps}>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuGroup.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuItem.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n  import type { ContextMenuItemVariants } from './context-menu-item.variants'\n\n  export interface ContextMenuItemProps extends HTMLAttributes<HTMLDivElement> {\n    inset?: boolean\n    variant?: ContextMenuItemVariants['variant']\n    disabled?: boolean\n    onSelect?: () => void\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n  import { getContextMenuContext } from './context'\n  import { contextMenuItemVariants } from './context-menu-item.variants'\n\n  type OnClick = NonNullable<HTMLAttributes<HTMLDivElement>['onclick']>\n  type OnMouseEnter = NonNullable<HTMLAttributes<HTMLDivElement>['onmouseenter']>\n\n  let {\n    class: className,\n    inset = false,\n    variant = 'default',\n    disabled = false,\n    onSelect,\n    children,\n    ref = $bindable(null),\n    onclick,\n    onmouseenter,\n    ...restProps\n  }: ContextMenuItemProps = $props()\n\n  const ctx = getContextMenuContext()\n\n  const handleClick: OnClick = (e) => {\n    onclick?.(e)\n    if (e.defaultPrevented || disabled) return\n    onSelect?.()\n    ctx.close()\n  }\n\n  const handleMouseEnter: OnMouseEnter = (e) => {\n    onmouseenter?.(e)\n    if (!disabled) ref?.focus()\n  }\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-item\"\n  data-context-menu-item=\"\"\n  role=\"menuitem\"\n  tabindex=\"-1\"\n  data-inset={inset ? '' : undefined}\n  data-variant={variant}\n  data-disabled={disabled ? '' : undefined}\n  aria-disabled={disabled || undefined}\n  class={cn(contextMenuItemVariants({ variant, inset }), className)}\n  {...restProps}\n  onclick={handleClick}\n  onmouseenter={handleMouseEnter}\n>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuItem.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/context-menu-item.variants.ts",
      "content": "import type { VariantProps } from 'class-variance-authority'\nimport { 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.\n */\nexport const contextMenuItemVariants = cva(\n  'relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus-visible:ring-2 focus-visible:ring-inset data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\"size-\"])]:size-4 [&_svg:not([class*=\"text-\"])]:text-muted-foreground',\n  {\n    variants: {\n      variant: {\n        default: '',\n        destructive:\n          'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/40 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive',\n      },\n      inset: {\n        true: 'data-[inset]:pl-8',\n        false: '',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      inset: false,\n    },\n  },\n)\n\nexport type ContextMenuItemVariants = VariantProps<typeof contextMenuItemVariants>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/context-menu-item.variants.ts"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuLabel.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuLabelProps extends HTMLAttributes<HTMLDivElement> {\n    inset?: boolean\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    inset = false,\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: ContextMenuLabelProps = $props()\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-label\"\n  data-inset={inset ? '' : undefined}\n  class={cn('text-foreground px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuLabel.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuPortal.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n\n  export interface ContextMenuPortalProps {\n    children?: Snippet\n  }\n</script>\n\n<script lang=\"ts\">\n  import { portal } from './portal'\n\n  let { children }: ContextMenuPortalProps = $props()\n</script>\n\n<div use:portal data-uipkge data-slot=\"context-menu-portal\" style:display=\"contents\">\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuPortal.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuRadioGroup.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuRadioGroupProps extends HTMLAttributes<HTMLDivElement> {\n    value?: string\n    onValueChange?: (value: string) => void\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { setContextMenuRadioContext } from './context'\n\n  let {\n    class: className,\n    value = $bindable(''),\n    onValueChange,\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: ContextMenuRadioGroupProps = $props()\n\n  setContextMenuRadioContext({\n    get value() {\n      return value\n    },\n    setValue(v) {\n      value = v\n      onValueChange?.(v)\n    },\n  })\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-radio-group\"\n  role=\"group\"\n  class={className}\n  {...restProps}\n>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuRadioGroup.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuRadioItem.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuRadioItemProps extends HTMLAttributes<HTMLDivElement> {\n    value: string\n    disabled?: boolean\n    /** Override the dot indicator. */\n    indicator?: Snippet\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { Circle } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n  import { getContextMenuRadioContext } from './context'\n\n  type OnClick = NonNullable<HTMLAttributes<HTMLDivElement>['onclick']>\n  type OnMouseEnter = NonNullable<HTMLAttributes<HTMLDivElement>['onmouseenter']>\n\n  let {\n    class: className,\n    value: valueProp,\n    disabled = false,\n    indicator,\n    children,\n    ref = $bindable(null),\n    onclick,\n    onmouseenter,\n    ...restProps\n  }: ContextMenuRadioItemProps = $props()\n\n  const radio = getContextMenuRadioContext()\n  const selected = $derived(radio.value === valueProp)\n\n  const handleClick: OnClick = (e) => {\n    onclick?.(e)\n    if (e.defaultPrevented || disabled) return\n    radio.setValue(valueProp)\n  }\n\n  const handleMouseEnter: OnMouseEnter = (e) => {\n    onmouseenter?.(e)\n    if (!disabled) ref?.focus()\n  }\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-radio-item\"\n  data-context-menu-item=\"\"\n  role=\"menuitemradio\"\n  tabindex=\"-1\"\n  aria-checked={selected}\n  data-state={selected ? 'checked' : 'unchecked'}\n  data-disabled={disabled ? '' : undefined}\n  aria-disabled={disabled || undefined}\n  class={cn(\n    \"focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus-visible:ring-2 focus-visible:ring-inset data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n    className,\n  )}\n  {...restProps}\n  onclick={handleClick}\n  onmouseenter={handleMouseEnter}\n>\n  <span class=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n    {#if selected}\n      {#if indicator}\n        {@render indicator()}\n      {:else}\n        <Circle class=\"size-2 fill-current\" aria-hidden=\"true\" />\n      {/if}\n    {/if}\n  </span>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuRadioItem.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuSeparator.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuSeparatorProps extends HTMLAttributes<HTMLDivElement> {\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let { class: className, ref = $bindable(null), ...restProps }: ContextMenuSeparatorProps = $props()\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-separator\"\n  role=\"separator\"\n  class={cn('bg-border -mx-1 my-1 h-px', className)}\n  {...restProps}\n></div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuSeparator.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuShortcut.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuShortcutProps extends HTMLAttributes<HTMLElement> {\n    ref?: HTMLElement | 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 }: ContextMenuShortcutProps = $props()\n</script>\n\n<span\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-shortcut\"\n  class={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</span>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuShortcut.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuSub.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n\n  export interface ContextMenuSubProps {\n    open?: boolean\n    onOpenChange?: (open: boolean) => void\n    children?: Snippet\n  }\n</script>\n\n<script lang=\"ts\">\n  import { tick } from 'svelte'\n  import { menuItemsOf, setContextMenuSubContext } from './context'\n\n  let { open = $bindable(false), onOpenChange, children }: ContextMenuSubProps = $props()\n\n  let triggerEl: HTMLElement | null = null\n  let contentEl: HTMLElement | null = null\n\n  function setOpen(next: boolean) {\n    if (next === open) return\n    open = next\n    onOpenChange?.(next)\n  }\n\n  setContextMenuSubContext({\n    get open() {\n      return open\n    },\n    setOpen,\n    getTriggerElement() {\n      return triggerEl\n    },\n    registerTriggerElement(el) {\n      triggerEl = el\n    },\n    registerContentElement(el) {\n      contentEl = el\n    },\n    focusFirstItem() {\n      tick().then(() => {\n        if (contentEl) menuItemsOf(contentEl)[0]?.focus()\n      })\n    },\n    focusTrigger() {\n      triggerEl?.focus()\n    },\n  })\n</script>\n\n{@render children?.()}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuSub.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuSubContent.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuSubContentProps 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 { getContextMenuContext, getContextMenuSubContext, menuItemsOf } from './context'\n  import { portal } from './portal'\n\n  type OnKeyDown = NonNullable<HTMLAttributes<HTMLDivElement>['onkeydown']>\n\n  let {\n    class: className,\n    children,\n    ref = $bindable(null),\n    onkeydown,\n    ...restProps\n  }: ContextMenuSubContentProps = $props()\n\n  const ctx = getContextMenuContext()\n  const sub = getContextMenuSubContext()\n\n  let pos = $state({ x: 0, y: 0 })\n\n  $effect(() => {\n    if (!ctx.open || !sub.open || !ref) return\n    const el = ref\n    ctx.registerMenuElement(el)\n    sub.registerContentElement(el)\n    // Anchor to the trigger's right edge, then flip/clamp into the viewport.\n    tick().then(() => {\n      const trigger = sub.getTriggerElement()\n      const rect = el.getBoundingClientRect()\n      let x = pos.x || window.innerWidth / 2\n      let y = pos.y || window.innerHeight / 2\n      if (trigger) {\n        const t = trigger.getBoundingClientRect()\n        x = t.right - 4\n        y = t.top - 4\n        if (x + rect.width > window.innerWidth - 8) x = t.left - rect.width + 4\n      }\n      pos = {\n        x: Math.max(8, Math.min(x, window.innerWidth - rect.width - 8)),\n        y: Math.max(8, Math.min(y, window.innerHeight - rect.height - 8)),\n      }\n    })\n    return () => {\n      ctx.unregisterMenuElement(el)\n      sub.registerContentElement(null)\n    }\n  })\n\n  const handleKeyDown: OnKeyDown = (e) => {\n    onkeydown?.(e)\n    if (e.defaultPrevented || !ref) return\n    if (e.key === 'Escape' || e.key === 'ArrowLeft') {\n      // Close only the submenu — stop the root Escape handler from closing all.\n      e.preventDefault()\n      e.stopPropagation()\n      sub.setOpen(false)\n      sub.focusTrigger()\n      return\n    }\n    const items = menuItemsOf(ref)\n    if (!items.length) return\n    const current = items.indexOf(document.activeElement as HTMLElement)\n    if (e.key === 'ArrowDown') {\n      e.preventDefault()\n      ;(items[current === -1 ? 0 : (current + 1) % items.length]!).focus()\n    } else if (e.key === 'ArrowUp') {\n      e.preventDefault()\n      ;(items[current === -1 ? items.length - 1 : (current - 1 + items.length) % items.length]!).focus()\n    } else if (e.key === 'Tab') {\n      ctx.close()\n    }\n  }\n</script>\n\n{#if ctx.open && sub.open}\n  <div\n    bind:this={ref}\n    use:portal\n    data-uipkge\n    data-slot=\"context-menu-sub-content\"\n    role=\"menu\"\n    tabindex=\"-1\"\n    data-state=\"open\"\n    data-side=\"right\"\n    style:position=\"fixed\"\n    style:left=\"{pos.x}px\"\n    style:top=\"{pos.y}px\"\n    class={cn(\n      'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg',\n      className,\n    )}\n    {...restProps}\n    onkeydown={handleKeyDown}\n  >\n    {@render children?.()}\n  </div>\n{/if}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuSubContent.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuSubTrigger.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuSubTriggerProps extends HTMLAttributes<HTMLDivElement> {\n    inset?: boolean\n    disabled?: boolean\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { ChevronRight } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n  import { getContextMenuSubContext } from './context'\n\n  type OnClick = NonNullable<HTMLAttributes<HTMLDivElement>['onclick']>\n  type OnMouseEnter = NonNullable<HTMLAttributes<HTMLDivElement>['onmouseenter']>\n  type OnKeyDown = NonNullable<HTMLAttributes<HTMLDivElement>['onkeydown']>\n\n  let {\n    class: className,\n    inset = false,\n    disabled = false,\n    children,\n    ref = $bindable(null),\n    onclick,\n    onmouseenter,\n    onkeydown,\n    ...restProps\n  }: ContextMenuSubTriggerProps = $props()\n\n  const sub = getContextMenuSubContext()\n\n  $effect(() => {\n    sub.registerTriggerElement(ref)\n    return () => sub.registerTriggerElement(null)\n  })\n\n  const handleClick: OnClick = (e) => {\n    onclick?.(e)\n    if (e.defaultPrevented || disabled) return\n    sub.setOpen(!sub.open)\n    if (!sub.open) sub.focusFirstItem()\n  }\n\n  const handleMouseEnter: OnMouseEnter = (e) => {\n    onmouseenter?.(e)\n    if (disabled) return\n    ref?.focus()\n    sub.setOpen(true)\n  }\n\n  const handleKeyDown: OnKeyDown = (e) => {\n    onkeydown?.(e)\n    if (e.defaultPrevented || disabled) return\n    if (e.key === 'ArrowRight' || e.key === 'Enter') {\n      e.preventDefault()\n      sub.setOpen(true)\n      sub.focusFirstItem()\n    }\n  }\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-sub-trigger\"\n  data-context-menu-item=\"\"\n  role=\"menuitem\"\n  tabindex=\"-1\"\n  aria-haspopup=\"menu\"\n  aria-expanded={sub.open}\n  data-state={sub.open ? 'open' : 'closed'}\n  data-inset={inset ? '' : undefined}\n  data-disabled={disabled ? '' : undefined}\n  aria-disabled={disabled || undefined}\n  class={cn(\n    \"focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus-visible:ring-2 focus-visible:ring-inset data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n    className,\n  )}\n  {...restProps}\n  onclick={handleClick}\n  onmouseenter={handleMouseEnter}\n  onkeydown={handleKeyDown}\n>\n  {@render children?.()}\n  <ChevronRight class=\"ml-auto\" aria-hidden=\"true\" />\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuSubTrigger.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/ContextMenuTrigger.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface ContextMenuTriggerProps extends HTMLAttributes<HTMLSpanElement> {\n    disabled?: boolean\n    ref?: HTMLSpanElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContextMenuContext } from './context'\n\n  type OnContextMenu = NonNullable<HTMLAttributes<HTMLSpanElement>['oncontextmenu']>\n\n  let {\n    class: className,\n    disabled = false,\n    children,\n    ref = $bindable(null),\n    oncontextmenu,\n    ...restProps\n  }: ContextMenuTriggerProps = $props()\n\n  const ctx = getContextMenuContext()\n\n  $effect(() => {\n    ctx.registerTrigger(ref)\n    return () => ctx.registerTrigger(null)\n  })\n\n  const handleContextMenu: OnContextMenu = (e) => {\n    oncontextmenu?.(e)\n    if (e.defaultPrevented || disabled) return\n    e.preventDefault()\n    ctx.openAt({ x: e.clientX, y: e.clientY })\n  }\n</script>\n\n<span\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"context-menu-trigger\"\n  data-state={ctx.open ? 'open' : 'closed'}\n  data-disabled={disabled ? '' : undefined}\n  class={className}\n  {...restProps}\n  oncontextmenu={handleContextMenu}\n>\n  {@render children?.()}\n</span>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/ContextMenuTrigger.svelte"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/context.ts",
      "content": "import { getContext, setContext } from 'svelte'\n\nexport interface MenuPosition {\n  x: number\n  y: number\n}\n\nexport interface ContextMenuContextValue {\n  readonly open: boolean\n  openAt: (position: MenuPosition) => void\n  close: () => void\n  readonly position: MenuPosition\n  registerMenuElement: (el: HTMLElement) => void\n  unregisterMenuElement: (el: HTMLElement) => void\n  registerTrigger: (el: HTMLElement | null) => void\n  isInsideMenu: (target: EventTarget | null) => boolean\n}\n\nexport interface ContextMenuSubContextValue {\n  readonly open: boolean\n  setOpen: (open: boolean) => void\n  getTriggerElement: () => HTMLElement | null\n  registerTriggerElement: (el: HTMLElement | null) => void\n  registerContentElement: (el: HTMLElement | null) => void\n  focusFirstItem: () => void\n  focusTrigger: () => void\n}\n\nexport interface ContextMenuRadioContextValue {\n  readonly value: string\n  setValue: (value: string) => void\n}\n\nconst CONTEXT_MENU_CONTEXT_KEY = Symbol('uipkge-context-menu')\nconst CONTEXT_MENU_SUB_CONTEXT_KEY = Symbol('uipkge-context-menu-sub')\nconst CONTEXT_MENU_RADIO_CONTEXT_KEY = Symbol('uipkge-context-menu-radio')\n\nexport function setContextMenuContext(value: ContextMenuContextValue): void {\n  setContext(CONTEXT_MENU_CONTEXT_KEY, value)\n}\n\nexport function getContextMenuContext(): ContextMenuContextValue {\n  const value = getContext<ContextMenuContextValue | undefined>(CONTEXT_MENU_CONTEXT_KEY)\n  if (!value) throw new Error('ContextMenu parts must be used inside <ContextMenu>')\n  return value\n}\n\nexport function setContextMenuSubContext(value: ContextMenuSubContextValue): void {\n  setContext(CONTEXT_MENU_SUB_CONTEXT_KEY, value)\n}\n\nexport function getContextMenuSubContext(): ContextMenuSubContextValue {\n  const value = getContext<ContextMenuSubContextValue | undefined>(CONTEXT_MENU_SUB_CONTEXT_KEY)\n  if (!value) throw new Error('ContextMenuSub parts must be used inside <ContextMenuSub>')\n  return value\n}\n\nexport function setContextMenuRadioContext(value: ContextMenuRadioContextValue): void {\n  setContext(CONTEXT_MENU_RADIO_CONTEXT_KEY, value)\n}\n\nexport function getContextMenuRadioContext(): ContextMenuRadioContextValue {\n  const value = getContext<ContextMenuRadioContextValue | undefined>(CONTEXT_MENU_RADIO_CONTEXT_KEY)\n  if (!value) throw new Error('ContextMenuRadioItem must be used inside <ContextMenuRadioGroup>')\n  return value\n}\n\n/** Enabled menu items within a menu container, in DOM order. */\nexport function menuItemsOf(container: HTMLElement): HTMLElement[] {\n  return [...container.querySelectorAll<HTMLElement>('[data-context-menu-item]')].filter(\n    (el) => !el.hasAttribute('data-disabled') && el.getAttribute('aria-disabled') !== 'true',\n  )\n}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/context.ts"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/portal.ts",
      "content": "import type { Action } from 'svelte/action'\n\n/**\n * Move the node to `document.body` (or a selector/element target) while it is\n * mounted. Actions only run in the browser, so this is SSR-safe.\n */\nexport const portal: Action<HTMLElement, HTMLElement | string | undefined> = (node, target) => {\n  const targetEl = typeof target === 'string' ? document.querySelector(target) : (target ?? document.body)\n  ;(targetEl ?? document.body).appendChild(node)\n  return {\n    destroy() {\n      node.remove()\n    },\n  }\n}\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/portal.ts"
    },
    {
      "path": "packages/registry-svelte/components/context-menu/index.ts",
      "content": "export { default as ContextMenu, type ContextMenuProps } from './ContextMenu.svelte'\nexport { default as ContextMenuCheckboxItem, type ContextMenuCheckboxItemProps } from './ContextMenuCheckboxItem.svelte'\nexport { default as ContextMenuContent, type ContextMenuContentProps } from './ContextMenuContent.svelte'\nexport { default as ContextMenuGroup, type ContextMenuGroupProps } from './ContextMenuGroup.svelte'\nexport { default as ContextMenuItem, type ContextMenuItemProps } from './ContextMenuItem.svelte'\nexport { default as ContextMenuLabel, type ContextMenuLabelProps } from './ContextMenuLabel.svelte'\nexport { default as ContextMenuPortal, type ContextMenuPortalProps } from './ContextMenuPortal.svelte'\nexport { default as ContextMenuRadioGroup, type ContextMenuRadioGroupProps } from './ContextMenuRadioGroup.svelte'\nexport { default as ContextMenuRadioItem, type ContextMenuRadioItemProps } from './ContextMenuRadioItem.svelte'\nexport { default as ContextMenuSeparator, type ContextMenuSeparatorProps } from './ContextMenuSeparator.svelte'\nexport { default as ContextMenuShortcut, type ContextMenuShortcutProps } from './ContextMenuShortcut.svelte'\nexport { default as ContextMenuSub, type ContextMenuSubProps } from './ContextMenuSub.svelte'\nexport { default as ContextMenuSubContent, type ContextMenuSubContentProps } from './ContextMenuSubContent.svelte'\nexport { default as ContextMenuSubTrigger, type ContextMenuSubTriggerProps } from './ContextMenuSubTrigger.svelte'\nexport { default as ContextMenuTrigger, type ContextMenuTriggerProps } from './ContextMenuTrigger.svelte'\nexport { contextMenuItemVariants, type ContextMenuItemVariants } from './context-menu-item.variants'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/context-menu/index.ts"
    }
  ],
  "dependencies": [
    "@lucide/svelte",
    "class-variance-authority"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Right-click menu with items, checkbox/radio items, submenus, labels, and shortcuts. Hand-rolled runes behavior: cursor-anchored portal, viewport clamping, outside/Escape close, and arrow-key navigation with roving focus.",
  "categories": [
    "overlay"
  ]
}