{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-block",
  "title": "Code Block",
  "description": "Tabbed package-manager code block with npm/pnpm/yarn/bun switcher, syntax-highlighted command output, and a one-click copy button.",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/new-york/blocks/code-block/page.tsx",
      "content": "import CodeBlock from \"./components/code-block\"\n\nexport default function Page() {\n  return (\n    <div className=\"px-4 py-10 md:px-6 md:py-14\">\n      <CodeBlock />\n    </div>\n  )\n}\n",
      "type": "registry:page",
      "target": "app/code-block/page.tsx"
    },
    {
      "path": "registry/new-york/blocks/code-block/components/code-block.tsx",
      "content": "\"use client\"\n\nimport { cn } from \"@/lib/utils\"\n\nimport CodeTabs from \"./code-tabs\"\nimport { useCodeBlock } from \"../hooks/use-code-block\"\nimport \"../styles/code-block.css\"\n\nexport default function CodeBlock({ className }: { className?: string }) {\n  const { activeTab, setActiveTab, copied, handleCopy } = useCodeBlock()\n\n  return (\n    <div\n      className={cn(\n        \"mx-auto flex w-full max-w-3xl min-w-0 justify-center px-3.5 py-[18px]\",\n        className\n      )}\n    >\n      <div className=\"w-full max-w-[680px]\">\n        <CodeTabs\n          activeTab={activeTab}\n          copied={copied}\n          onTabChange={setActiveTab}\n          onCopy={handleCopy}\n        />\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "app/code-block/components/code-block.tsx"
    },
    {
      "path": "registry/new-york/blocks/code-block/components/code-tabs.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, Copy } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\nimport { TAB_OPTIONS, COMMANDS, type TabOption } from \"../lib/config\"\n\nimport \"../styles/code-block.css\"\n\ntype Props = {\n  activeTab: TabOption\n  copied: boolean\n  onTabChange: (tab: TabOption) => void\n  onCopy: () => void\n}\n\nexport default function CodeTabs({\n  activeTab,\n  copied,\n  onTabChange,\n  onCopy,\n}: Props) {\n  const tabRefs = React.useRef<(HTMLButtonElement | null)[]>([])\n  const [indicator, setIndicator] = React.useState({ left: 0, width: 0 })\n\n  React.useLayoutEffect(() => {\n    const idx = TAB_OPTIONS.indexOf(activeTab)\n    const el = tabRefs.current[idx]\n    if (el) setIndicator({ left: el.offsetLeft, width: el.offsetWidth })\n  }, [activeTab])\n\n  const cmd = COMMANDS[activeTab]\n  const [pkgManager, action, ...pkgs] = cmd.split(\" \")\n\n  return (\n    <div className=\"overflow-hidden rounded-lg border border-[#eaeaea] bg-white dark:border-[#1a1a1a] dark:bg-black\">\n      <div className=\"relative flex items-center gap-3 border-b border-[#eaeaea] px-4 dark:border-[#1a1a1a]\">\n        {TAB_OPTIONS.map((tab, i) => (\n          <button\n            key={tab}\n            ref={(el) => {\n              tabRefs.current[i] = el\n            }}\n            onClick={() => onTabChange(tab)}\n            className={cn(\n              \"cursor-pointer border-none bg-transparent py-2 text-sm font-medium text-[#a0a0a0] transition-colors duration-150 hover:text-[#171717] dark:hover:text-[#eeeeee]\",\n              activeTab === tab && \"text-[#171717] dark:text-[#eeeeee]\"\n            )}\n          >\n            {tab}\n          </button>\n        ))}\n        <div\n          className=\"pointer-events-none absolute bottom-0 h-px bg-[#9a7b2d] transition-[left,width] duration-200 ease-out motion-reduce:transition-none dark:bg-[#cca649]\"\n          style={{ left: indicator.left, width: indicator.width }}\n        />\n        <div\n          className=\"pointer-events-none absolute bottom-0 h-2 bg-[color-mix(in_srgb,#9a7b2d_25%,transparent)] blur-[3px] transition-[left,width] duration-200 ease-out motion-reduce:transition-none dark:bg-[color-mix(in_srgb,#cca649_25%,transparent)]\"\n          style={{ left: indicator.left, width: indicator.width }}\n        />\n      </div>\n\n      <div className=\"flex items-center justify-between gap-4 overflow-x-auto bg-[#f5f5f5] px-4 py-2.5 font-mono text-sm dark:bg-[#1a1a1a]\">\n        <code\n          key={activeTab}\n          className=\"cblk-cmd inline-flex text-left whitespace-nowrap\"\n        >\n          <span className=\"text-[#0070f3] dark:text-[#47a8ff]\">\n            {pkgManager}\n          </span>\n          <span className=\"ml-2 text-[#d6336c] dark:text-[#ff4d8d]\">\n            {action}\n          </span>\n          <span className=\"ml-2 text-[#067a3d] dark:text-[#00c45c]\">\n            {pkgs.join(\" \")}\n          </span>\n        </code>\n\n        <button\n          onClick={onCopy}\n          className={cn(\n            \"shrink-0 cursor-pointer rounded border-none bg-transparent p-1 text-[#6b7280] transition-colors duration-150 hover:bg-[#f0f0f0] hover:text-[#171717] dark:hover:bg-[#2a2a2a] dark:hover:text-[#eeeeee]\",\n            copied && \"text-[#067a3d] dark:text-[#00c45c]\"\n          )}\n          title=\"Copy command\"\n        >\n          {copied ? <Check size={14} /> : <Copy size={14} />}\n        </button>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "app/code-block/components/code-tabs.tsx"
    },
    {
      "path": "registry/new-york/blocks/code-block/hooks/use-code-block.ts",
      "content": "import { useState } from \"react\"\nimport { COMMANDS, type TabOption } from \"../lib/config\"\n\nexport function useCodeBlock() {\n  const [activeTab, setActiveTab] = useState<TabOption>(\"npm\")\n  const [copied, setCopied] = useState(false)\n\n  const handleCopy = async () => {\n    await navigator.clipboard.writeText(COMMANDS[activeTab])\n    setCopied(true)\n    setTimeout(() => setCopied(false), 2000)\n  }\n\n  return { activeTab, setActiveTab, copied, handleCopy }\n}\n",
      "type": "registry:hook",
      "target": "app/code-block/hooks/use-code-block.ts"
    },
    {
      "path": "registry/new-york/blocks/code-block/lib/config.ts",
      "content": "// Example: Fumadocs installation commands\nexport const TAB_OPTIONS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const\nexport type TabOption = (typeof TAB_OPTIONS)[number]\n\nexport const COMMANDS: Record<TabOption, string> = {\n  npm: \"npm i fumadocs-mdx fumadocs-core @types/mdx\",\n  pnpm: \"pnpm add fumadocs-mdx fumadocs-core @types/mdx\",\n  yarn: \"yarn add fumadocs-mdx fumadocs-core @types/mdx\",\n  bun: \"bun add fumadocs-mdx fumadocs-core @types/mdx\",\n}\n",
      "type": "registry:lib",
      "target": "app/code-block/lib/config.ts"
    },
    {
      "path": "registry/new-york/blocks/code-block/styles/code-block.css",
      "content": "/* code-block — tab switch fade-in */\n\n@keyframes cb-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n\n.cblk-cmd {\n  animation: cb-fade-in 0.15s ease-out forwards;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .cblk-cmd {\n    animation: none;\n  }\n}\n",
      "type": "registry:file",
      "target": "app/code-block/styles/code-block.css"
    }
  ],
  "type": "registry:block"
}