{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-menu",
  "title": "UI Context Menu",
  "description": "A right-click context menu whose opened/closed state is a pure function of the timeline; the panel scales from its top-left corner (the click point) with a fade + lift. No trigger — the caller positions it. Rows reuse the DropdownMenuItem row; items are plain string labels.",
  "dependencies": ["remotion"],
  "registryDependencies": ["@remocn/remocn-ui", "@remocn/dropdown-menu-item"],
  "files": [
    {
      "path": "registry/remocn-ui/context-menu/index.tsx",
      "content": "\"use client\";\n\nimport {\n  DropdownMenuItemRow,\n  type DropdownMenuItemState,\n  type DropdownMenuItemStyle,\n  type DropdownMenuItemStyleContext,\n  dropdownMenuItemStyle,\n  dropdownMenuItemStyleContext,\n} from \"@/components/remocn/dropdown-menu-item\";\nimport { type RemocnTheme, useRemocnTheme } from \"@/lib/remocn-ui\";\n\nexport type ContextMenuState = \"opened\" | \"closed\";\n\nexport interface ContextMenuProps {\n  state?: ContextMenuState;\n  style?: ContextMenuStyle;\n  items?: string[];\n  highlightedIndex?: number;\n  pressedIndex?: number;\n  itemStyles?: (DropdownMenuItemStyle | undefined)[];\n  theme?: Partial<RemocnTheme>;\n  className?: string;\n}\n\nconst WIDTH = 200;\n\nexport interface ContextMenuStyle {\n  opacity: number;\n  scale: number;\n  translateY: number;\n}\n\nexport interface ContextMenuStyleContext {\n  panelBg: string;\n  panelBorder: string;\n  radius: number;\n  itemCtx: DropdownMenuItemStyleContext;\n}\n\nexport function contextMenuStyleContext(\n  theme: RemocnTheme,\n): ContextMenuStyleContext {\n  return {\n    panelBg: theme.popover,\n    panelBorder: theme.border,\n    radius: theme.radius,\n    itemCtx: dropdownMenuItemStyleContext(theme),\n  };\n}\n\nexport function contextMenuStyle(\n  state: ContextMenuState,\n  _ctx: ContextMenuStyleContext,\n): ContextMenuStyle {\n  switch (state) {\n    case \"opened\":\n      return { opacity: 1, scale: 1, translateY: 0 };\n    default:\n      return { opacity: 0, scale: 0.95, translateY: -4 };\n  }\n}\n\nfunction rowState(\n  i: number,\n  highlightedIndex: number,\n  pressedIndex: number,\n): DropdownMenuItemState {\n  if (i === pressedIndex) return \"press\";\n  if (i === highlightedIndex) return \"hover\";\n  return \"idle\";\n}\n\nexport function ContextMenu({\n  state = \"closed\",\n  style,\n  items = [\"Back\", \"Reload\", \"Save As…\", \"Inspect\"],\n  highlightedIndex = -1,\n  pressedIndex = -1,\n  itemStyles,\n  theme: themeOverride,\n  className,\n}: ContextMenuProps) {\n  const theme = useRemocnTheme(themeOverride, \"light\");\n  const ctx = contextMenuStyleContext(theme);\n  const v = style ?? contextMenuStyle(state, ctx);\n\n  return (\n    <div\n      className={className}\n      style={{\n        width: WIDTH,\n        opacity: v.opacity,\n        transformOrigin: \"top left\",\n        transform: `translateY(${v.translateY}px) scale(${v.scale})`,\n        background: ctx.panelBg,\n        border: `1px solid ${ctx.panelBorder}`,\n        borderRadius: ctx.radius + 2,\n        padding: 4,\n        display: \"flex\",\n        flexDirection: \"column\",\n        gap: 2,\n        boxShadow: \"0 12px 32px -8px rgba(0,0,0,0.18)\",\n        boxSizing: \"border-box\",\n        fontFamily:\n          \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\",\n      }}\n    >\n      {items.map((item, i) => {\n        const override = itemStyles?.[i];\n        const rowStyle =\n          override ??\n          dropdownMenuItemStyle(\n            rowState(i, highlightedIndex, pressedIndex),\n            ctx.itemCtx,\n          );\n        return (\n          <DropdownMenuItemRow\n            key={item}\n            style={rowStyle}\n            label={item}\n            width={WIDTH - 8}\n            theme={themeOverride}\n          />\n        );\n      })}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/context-menu.tsx"
    },
    {
      "path": "registry/remocn-ui/context-menu/use-context-menu-transition.ts",
      "content": "\"use client\";\n\nimport {\n  type ContextMenuState,\n  type ContextMenuStyle,\n  contextMenuStyle,\n  contextMenuStyleContext,\n} from \"@/components/remocn/context-menu\";\nimport {\n  easings,\n  type RemocnTheme,\n  type Step,\n  useRemocnTheme,\n  useStateTransition,\n} from \"@/lib/remocn-ui\";\n\nexport const DEFAULT_DURATION = 10;\n\nexport function tweenContextMenuStyle(\n  a: ContextMenuStyle,\n  b: ContextMenuStyle,\n  t: number,\n): ContextMenuStyle {\n  return {\n    opacity: a.opacity + (b.opacity - a.opacity) * t,\n    scale: a.scale + (b.scale - a.scale) * t,\n    translateY: a.translateY + (b.translateY - a.translateY) * t,\n  };\n}\n\nexport interface ContextMenuTransitionOptions {\n  theme?: Partial<RemocnTheme>;\n  mode?: \"light\" | \"dark\";\n  speed?: number;\n  defaultDuration?: number;\n}\n\nexport function useContextMenuTransition(\n  steps: Step<ContextMenuState>[],\n  opts: ContextMenuTransitionOptions = {},\n): ContextMenuStyle {\n  const {\n    theme: themeOverride,\n    mode,\n    speed = 1,\n    defaultDuration = DEFAULT_DURATION,\n  } = opts;\n  const theme = useRemocnTheme(themeOverride, mode);\n  const ctx = contextMenuStyleContext(theme);\n  const { from, to, progress } = useStateTransition(\n    steps,\n    \"closed\",\n    speed,\n    defaultDuration,\n  );\n  const t = easings.out(progress);\n  return tweenContextMenuStyle(\n    contextMenuStyle(from, ctx),\n    contextMenuStyle(to, ctx),\n    t,\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/use-context-menu-transition.ts"
    }
  ],
  "type": "registry:component"
}
