{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-block",
  "type": "registry:component",
  "title": "Code Block",
  "description": "Syntax-highlighted code display with copy support.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/code-block/code-block.tsx",
      "content": "\"use client\";\n\nimport { type ReactNode, useEffect, useRef, useState } from \"react\";\n\nimport { Check, Copy } from \"lucide-react\";\nimport { useTheme } from \"next-themes\";\nimport { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\";\nimport {\n  oneDark,\n  oneLight,\n} from \"react-syntax-highlighter/dist/esm/styles/prism\";\n\nimport { cn } from \"@vllnt/ui\";\nimport { Button } from \"@vllnt/ui\";\n\ntype CodeBlockProps = {\n  children: ReactNode;\n  className?: string;\n  language?: string;\n  showLanguage?: boolean;\n};\n\nfunction extractTextFromChildren(children: ReactNode): string {\n  if (typeof children === \"string\") {\n    return children;\n  }\n  if (typeof children === \"number\") {\n    return String(children);\n  }\n  if (Array.isArray(children)) {\n    return children.map(extractTextFromChildren).join(\"\");\n  }\n  if (\n    children &&\n    typeof children === \"object\" &&\n    \"props\" in children &&\n    children.props &&\n    typeof children.props === \"object\" &&\n    \"children\" in children.props\n  ) {\n    return extractTextFromChildren(children.props.children as ReactNode);\n  }\n  return String(children ?? \"\");\n}\n\nfunction findScrollableParent(\n  element: HTMLElement | null,\n): HTMLElement | undefined {\n  if (!element) return undefined;\n  if (element.scrollHeight > element.clientHeight) return element;\n  return findScrollableParent(element.parentElement);\n}\n\nexport function CodeBlock({\n  children,\n  className,\n  language = \"typescript\",\n  showLanguage = false,\n}: CodeBlockProps) {\n  const [copied, setCopied] = useState(false);\n  const { systemTheme, theme } = useTheme();\n\n  const resolvedTheme = theme === \"system\" ? systemTheme : theme;\n  const isDark = resolvedTheme !== \"light\";\n  const codeStyle = isDark ? oneDark : oneLight;\n  const code = extractTextFromChildren(children);\n\n  const scrollRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const element = scrollRef.current;\n    if (!element) return;\n\n    const onWheel = (event: WheelEvent) => {\n      if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) return;\n      const scrollable = findScrollableParent(element);\n      if (scrollable) {\n        scrollable.scrollTop += event.deltaY;\n        event.preventDefault();\n      }\n    };\n\n    element.addEventListener(\"wheel\", onWheel, { passive: false });\n    return () => {\n      element.removeEventListener(\"wheel\", onWheel);\n    };\n  }, []);\n\n  const handleCopy = async () => {\n    await navigator.clipboard.writeText(code);\n    setCopied(true);\n    setTimeout(() => {\n      setCopied(false);\n    }, 2000);\n  };\n\n  return (\n    <div\n      className={cn(\n        \"relative w-full overflow-hidden rounded-md border bg-background\",\n        className,\n      )}\n    >\n      <div\n        className=\"relative overflow-x-auto overflow-y-hidden touch-pan-y\"\n        ref={scrollRef}\n      >\n        <SyntaxHighlighter\n          codeTagProps={{\n            className: \"font-mono text-sm\",\n            style: {\n              background: \"transparent\",\n              display: \"block\",\n            },\n          }}\n          customStyle={{\n            background: \"hsl(var(--background))\",\n            fontSize: \"0.875rem\",\n            margin: 0,\n            minWidth: \"fit-content\",\n            overflowY: \"hidden\",\n            padding: \"1rem\",\n          }}\n          language={language}\n          style={codeStyle}\n        >\n          {code}\n        </SyntaxHighlighter>\n        <div className=\"absolute right-2 top-2 flex items-center gap-2\">\n          {showLanguage ? (\n            <span className=\"text-xs font-mono text-muted-foreground uppercase tracking-wider\">\n              {language}\n            </span>\n          ) : null}\n          <Button\n            className=\"size-8\"\n            onClick={handleCopy}\n            size=\"icon\"\n            variant=\"ghost\"\n          >\n            {copied ? (\n              <Check className=\"size-3\" />\n            ) : (\n              <Copy className=\"size-3\" />\n            )}\n          </Button>\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
