{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command-menu",
  "title": "UI Command Menu",
  "description": "A ⌘K command palette whose opened/closed state is a pure function of the timeline; the panel zoom + backdrop dim are dialog-like keyframed presets. The search row reveals the typed query, the list is filtered by a pure case-insensitive substring on the visible query prefix, and rows reuse the CommandMenuItem row.",
  "dependencies": ["remotion"],
  "registryDependencies": ["@remocn/remocn-ui", "@remocn/command-menu-item"],
  "files": [
    {
      "path": "registry/remocn-ui/command-menu/index.tsx",
      "content": "\"use client\";\n\nimport {\n  type CommandMenuIcon,\n  CommandMenuItemRow,\n  type CommandMenuItemState,\n  type CommandMenuItemStyle,\n  type CommandMenuItemStyleContext,\n  commandMenuItemStyle,\n  commandMenuItemStyleContext,\n} from \"@/components/remocn/command-menu-item\";\nimport {\n  type RemocnTheme,\n  revealedText,\n  useRemocnTheme,\n} from \"@/lib/remocn-ui\";\n\nexport type CommandMenuState = \"opened\" | \"closed\";\n\nexport interface CommandMenuEntry {\n  icon?: CommandMenuIcon;\n  label: string;\n  shortcut?: string;\n}\n\nexport interface CommandMenuProps {\n  state?: CommandMenuState;\n  style?: CommandMenuStyle;\n  query?: string;\n  revealCount?: number;\n  items?: CommandMenuEntry[];\n  selectedIndex?: number;\n  highlightedIndex?: number;\n  pressedIndex?: number;\n  itemStyles?: (CommandMenuItemStyle | undefined)[];\n  theme?: Partial<RemocnTheme>;\n  className?: string;\n}\n\nconst PANEL_WIDTH = 440;\nconst CONTENT_WIDTH = PANEL_WIDTH - 16;\nconst MAX_OVERLAY_ALPHA = 0.5;\n\nexport function filterCommandItems(\n  items: CommandMenuEntry[],\n  query: string,\n  revealCount?: number,\n): CommandMenuEntry[] {\n  const visible = (\n    revealCount === undefined ? query : revealedText(query, revealCount)\n  )\n    .trim()\n    .toLowerCase();\n  if (visible === \"\") return items;\n  return items.filter((item) => item.label.toLowerCase().includes(visible));\n}\n\nexport interface CommandMenuStyle {\n  backdropOpacity: number;\n  panelOpacity: number;\n  panelScale: number;\n  panelTranslateY: number;\n}\n\nexport interface CommandMenuStyleContext {\n  panelBg: string;\n  panelBorder: string;\n  inputFg: string;\n  placeholderFg: string;\n  mutedFg: string;\n  divider: string;\n  caret: string;\n  radius: number;\n  itemCtx: CommandMenuItemStyleContext;\n}\n\nexport function commandMenuStyleContext(\n  theme: RemocnTheme,\n): CommandMenuStyleContext {\n  return {\n    panelBg: theme.popover,\n    panelBorder: theme.border,\n    inputFg: theme.popoverForeground,\n    placeholderFg: theme.mutedForeground,\n    mutedFg: theme.mutedForeground,\n    divider: theme.border,\n    caret: theme.foreground,\n    radius: theme.radius,\n    itemCtx: commandMenuItemStyleContext(theme),\n  };\n}\n\nexport function commandMenuStyle(\n  state: CommandMenuState,\n  _ctx: CommandMenuStyleContext,\n): CommandMenuStyle {\n  switch (state) {\n    case \"opened\":\n      return {\n        backdropOpacity: 1,\n        panelOpacity: 1,\n        panelScale: 1,\n        panelTranslateY: 0,\n      };\n    default:\n      return {\n        backdropOpacity: 0,\n        panelOpacity: 0,\n        panelScale: 0.96,\n        panelTranslateY: 8,\n      };\n  }\n}\n\nfunction rowState(\n  i: number,\n  selectedIndex: number,\n  highlightedIndex: number,\n  pressedIndex: number,\n): CommandMenuItemState {\n  if (i === pressedIndex) return \"press\";\n  if (i === selectedIndex) return \"selected\";\n  if (i === highlightedIndex) return \"hover\";\n  return \"idle\";\n}\n\nexport function CommandMenu({\n  state = \"closed\",\n  style,\n  query = \"\",\n  revealCount,\n  items = [\n    { icon: \"user\", label: \"Profile\", shortcut: \"⌘ P\" },\n    { icon: \"settings\", label: \"Settings\", shortcut: \"⌘ S\" },\n    { icon: \"file\", label: \"New File\", shortcut: \"⌘ N\" },\n    { icon: \"search\", label: \"Search docs\" },\n  ],\n  selectedIndex = -1,\n  highlightedIndex = -1,\n  pressedIndex = -1,\n  itemStyles,\n  theme: themeOverride,\n  className,\n}: CommandMenuProps) {\n  const theme = useRemocnTheme(themeOverride, \"light\");\n  const ctx = commandMenuStyleContext(theme);\n  const v = style ?? commandMenuStyle(state, ctx);\n\n  const visibleQuery =\n    revealCount === undefined ? query : revealedText(query, revealCount);\n  const filtered = filterCommandItems(items, query, revealCount);\n\n  return (\n    <div\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        display: \"flex\",\n        alignItems: \"flex-start\",\n        justifyContent: \"center\",\n        paddingTop: \"18%\",\n        fontFamily:\n          \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\",\n      }}\n    >\n      {}\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          background: `rgba(0, 0, 0, ${MAX_OVERLAY_ALPHA * v.backdropOpacity})`,\n        }}\n      />\n      <div\n        className={className}\n        style={{\n          position: \"relative\",\n          width: PANEL_WIDTH,\n          boxSizing: \"border-box\",\n          transformOrigin: \"top\",\n          transform: `translateY(${v.panelTranslateY}px) scale(${v.panelScale})`,\n          opacity: v.panelOpacity,\n          background: ctx.panelBg,\n          border: `1px solid ${ctx.panelBorder}`,\n          borderRadius: ctx.radius + 6,\n          padding: 8,\n          display: \"flex\",\n          flexDirection: \"column\",\n          boxShadow: \"0 24px 48px -12px rgba(0,0,0,0.25)\",\n        }}\n      >\n        {}\n        <div\n          style={{\n            display: \"flex\",\n            alignItems: \"center\",\n            gap: 10,\n            padding: \"8px 10px\",\n          }}\n        >\n          <svg width={18} height={18} viewBox=\"0 0 24 24\" fill=\"none\">\n            <path\n              d=\"M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14ZM20 20l-3.5-3.5\"\n              stroke={ctx.mutedFg}\n              strokeWidth=\"2\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n            />\n          </svg>\n          <span\n            style={{\n              display: \"flex\",\n              alignItems: \"center\",\n              fontSize: 15,\n              letterSpacing: \"-0.01em\",\n              color: visibleQuery ? ctx.inputFg : ctx.placeholderFg,\n            }}\n          >\n            {visibleQuery || \"Type a command or search…\"}\n            {}\n            <span\n              style={{\n                display: \"inline-block\",\n                width: 1.5,\n                height: 18,\n                marginLeft: 1,\n                background: ctx.caret,\n              }}\n            />\n          </span>\n        </div>\n        {}\n        <div\n          style={{\n            height: 1,\n            background: ctx.divider,\n            margin: \"4px 0\",\n          }}\n        />\n        {}\n        <div\n          style={{\n            display: \"flex\",\n            flexDirection: \"column\",\n            gap: 2,\n            padding: \"4px 0\",\n          }}\n        >\n          {filtered.length === 0 ? (\n            <div\n              style={{\n                padding: \"20px 12px\",\n                textAlign: \"center\",\n                fontSize: 14,\n                color: ctx.mutedFg,\n              }}\n            >\n              No results found.\n            </div>\n          ) : (\n            filtered.map((item, i) => {\n              const override = itemStyles?.[i];\n              return (\n                <CommandMenuItemRow\n                  key={item.label}\n                  style={\n                    override ??\n                    commandMenuItemStyle(\n                      rowState(\n                        i,\n                        selectedIndex,\n                        highlightedIndex,\n                        pressedIndex,\n                      ),\n                      ctx.itemCtx,\n                    )\n                  }\n                  ctx={ctx.itemCtx}\n                  label={item.label}\n                  icon={item.icon}\n                  shortcut={item.shortcut}\n                  width={CONTENT_WIDTH}\n                  radius={theme.radius}\n                />\n              );\n            })\n          )}\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/command-menu.tsx"
    },
    {
      "path": "registry/remocn-ui/command-menu/use-command-menu-transition.ts",
      "content": "\"use client\";\n\nimport {\n  type CommandMenuState,\n  type CommandMenuStyle,\n  commandMenuStyle,\n  commandMenuStyleContext,\n} from \"@/components/remocn/command-menu\";\nimport {\n  easings,\n  type RemocnTheme,\n  type Step,\n  useRemocnTheme,\n  useStateTransition,\n} from \"@/lib/remocn-ui\";\n\nexport const DEFAULT_DURATION = 12;\n\nexport function tweenCommandMenuStyle(\n  a: CommandMenuStyle,\n  b: CommandMenuStyle,\n  t: number,\n): CommandMenuStyle {\n  return {\n    backdropOpacity:\n      a.backdropOpacity + (b.backdropOpacity - a.backdropOpacity) * t,\n    panelOpacity: a.panelOpacity + (b.panelOpacity - a.panelOpacity) * t,\n    panelScale: a.panelScale + (b.panelScale - a.panelScale) * t,\n    panelTranslateY:\n      a.panelTranslateY + (b.panelTranslateY - a.panelTranslateY) * t,\n  };\n}\n\nexport interface CommandMenuTransitionOptions {\n  theme?: Partial<RemocnTheme>;\n  mode?: \"light\" | \"dark\";\n  speed?: number;\n  defaultDuration?: number;\n}\n\nexport function useCommandMenuTransition(\n  steps: Step<CommandMenuState>[],\n  opts: CommandMenuTransitionOptions = {},\n): CommandMenuStyle {\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 = commandMenuStyleContext(theme);\n  const { from, to, progress } = useStateTransition(\n    steps,\n    \"closed\",\n    speed,\n    defaultDuration,\n  );\n  const t = easings.out(progress);\n  return tweenCommandMenuStyle(\n    commandMenuStyle(from, ctx),\n    commandMenuStyle(to, ctx),\n    t,\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/use-command-menu-transition.ts"
    }
  ],
  "type": "registry:component"
}
