{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-block",
  "type": "registry:ui",
  "description": "A beautiful code block component with tabs, copy functionality, and smooth animations",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/default/ui/code-block.tsx",
      "content": "\"use client\"\n\nimport { useCallback, useLayoutEffect, useMemo, useRef, useState } from \"react\"\nimport { Check, Copy } from \"lucide-react\"\nimport { AnimatePresence, motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface CodeTab {\n  label: string\n  code: string\n  language?: string\n}\n\ninterface CodeBlockProps {\n  tabs?: CodeTab[]\n  code?: string\n  language?: string\n  className?: string\n}\n\nexport function CodeBlock({\n  tabs,\n  code,\n  language = \"bash\",\n  className,\n}: CodeBlockProps) {\n  const [activeTab, setActiveTab] = useState(0)\n  const [copied, setCopied] = useState(false)\n  const [direction, setDirection] = useState(0)\n  const preRef = useRef<HTMLPreElement>(null)\n  const tabsContainerRef = useRef<HTMLDivElement>(null)\n  const tabRefs = useRef<(HTMLButtonElement | null)[]>([])\n  const [hasOverflow, setHasOverflow] = useState(false)\n  const [indicator, setIndicator] = useState<{\n    left: number\n    width: number\n  } | null>(null)\n\n  const measureIndicator = useCallback(() => {\n    const container = tabsContainerRef.current\n    const activeEl = tabRefs.current[activeTab]\n\n    if (!container || !activeEl) {\n      return\n    }\n\n    const containerRect = container.getBoundingClientRect()\n    const tabRect = activeEl.getBoundingClientRect()\n\n    setIndicator({\n      left: tabRect.left - containerRect.left,\n      width: tabRect.width,\n    })\n  }, [activeTab])\n\n  const codeContent = useMemo(() => {\n    if (tabs && tabs.length > 0) {\n      return tabs\n    }\n    if (code) {\n      return [{ label: language, code, language }]\n    }\n    return []\n  }, [tabs, code, language])\n\n  const currentCode = codeContent[activeTab]?.code || \"\"\n\n  // Check overflow when tab changes or content updates\n  // biome-ignore lint/correctness/useExhaustiveDependencies: activeTab is needed to recheck overflow when content changes\n  useLayoutEffect(() => {\n    const checkOverflow = () => {\n      if (preRef.current) {\n        const hasHorizontalOverflow =\n          preRef.current.scrollWidth > preRef.current.clientWidth\n        setHasOverflow(hasHorizontalOverflow)\n      }\n    }\n\n    checkOverflow()\n    const resizeObserver = new ResizeObserver(checkOverflow)\n    if (preRef.current) {\n      resizeObserver.observe(preRef.current)\n    }\n\n    return () => {\n      resizeObserver.disconnect()\n    }\n  }, [activeTab])\n\n  useLayoutEffect(() => {\n    measureIndicator()\n\n    const resizeObserver = new ResizeObserver(measureIndicator)\n    const container = tabsContainerRef.current\n\n    if (container) {\n      resizeObserver.observe(container)\n    }\n\n    for (const tab of tabRefs.current) {\n      if (tab) {\n        resizeObserver.observe(tab)\n      }\n    }\n\n    return () => {\n      resizeObserver.disconnect()\n    }\n  }, [measureIndicator])\n\n  const handleCopy = async () => {\n    await navigator.clipboard.writeText(currentCode)\n    setCopied(true)\n    setTimeout(() => setCopied(false), 2000)\n  }\n\n  const handleTabChange = (index: number) => {\n    setDirection(index > activeTab ? 1 : -1)\n    setActiveTab(index)\n  }\n\n  if (codeContent.length === 0) return null\n\n  return (\n    <div\n      className={cn(\n        \"group relative overflow-hidden rounded-2xl border p-0.5\",\n        \"border-zinc-950/10 dark:border-white/10\",\n        \"bg-zinc-50 dark:bg-white/5\",\n        \"text-zinc-950 dark:text-zinc-50\",\n        className\n      )}\n    >\n      {/* Tab Bar */}\n      {codeContent.length > 1 && (\n        <div className=\"relative flex items-center pr-2.5\">\n          <div\n            role=\"tablist\"\n            className={cn(\n              \"flex min-w-0 flex-1 gap-1 rounded-tl-xl text-xs leading-6\",\n              \"overflow-x-auto overflow-y-hidden\",\n              \"scrollbar-thin scrollbar-thumb-rounded\",\n              \"scrollbar-thumb-black/15 hover:scrollbar-thumb-black/20\",\n              \"dark:scrollbar-thumb-white/20 dark:hover:scrollbar-thumb-white/25\"\n            )}\n          >\n            <div ref={tabsContainerRef} className=\"relative flex gap-1\">\n              {codeContent.map((tab, index) => (\n                <button\n                  key={`${tab.label}-${index}`}\n                  ref={(element) => {\n                    tabRefs.current[index] = element\n                  }}\n                  type=\"button\"\n                  role=\"tab\"\n                  aria-selected={activeTab === index}\n                  onClick={() => handleTabChange(index)}\n                  className={cn(\n                    \"relative my-1 mb-1.5 flex items-center gap-1.5 outline-0\",\n                    \"font-medium whitespace-nowrap transition-colors duration-150\",\n                    \"rounded-lg px-1.5\",\n                    \"first:ml-2.5\",\n                    \"hover:bg-zinc-200/50 dark:hover:bg-zinc-700/70\",\n                    activeTab === index\n                      ? \"text-zinc-950 dark:text-zinc-50\"\n                      : \"text-zinc-500 dark:text-zinc-400\"\n                  )}\n                >\n                  {tab.label}\n                </button>\n              ))}\n              {indicator && (\n                <motion.div\n                  aria-hidden=\"true\"\n                  className=\"pointer-events-none absolute bottom-0 h-0.5 rounded-full bg-zinc-950 dark:bg-zinc-50\"\n                  initial={false}\n                  animate={{\n                    left: indicator.left,\n                    width: indicator.width,\n                  }}\n                  transition={{\n                    type: \"spring\",\n                    stiffness: 500,\n                    damping: 35,\n                  }}\n                />\n              )}\n            </div>\n          </div>\n        </div>\n      )}\n\n      {/* Code Content */}\n      <div className=\"relative overflow-hidden\">\n        {/* Copy Button */}\n        <motion.button\n          onClick={handleCopy}\n          whileTap={{ scale: 0.95 }}\n          className={cn(\n            \"absolute top-2 right-2 z-10\",\n            \"flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium\",\n            \"text-zinc-500 dark:text-zinc-400\",\n            \"bg-white/80 backdrop-blur-sm dark:bg-zinc-950/80\",\n            \"border border-zinc-200/50 dark:border-zinc-800/50\",\n            \"opacity-70 group-hover:opacity-100\",\n            \"hover:bg-zinc-200/50 dark:hover:bg-zinc-700/70\",\n            \"hover:text-zinc-950 dark:hover:text-zinc-50\",\n            \"transition-all duration-150\",\n            \"focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:outline-none\"\n          )}\n          aria-label=\"Copy code\"\n        >\n          <span className=\"relative size-3.5\">\n            <motion.div\n              initial={false}\n              animate={{\n                scale: copied ? 0 : 1,\n                opacity: copied ? 0 : 1,\n                rotate: copied ? 90 : 0,\n              }}\n              transition={{ duration: 0.2 }}\n              className=\"absolute inset-0\"\n            >\n              <Copy className=\"size-full\" />\n            </motion.div>\n            <motion.div\n              initial={false}\n              animate={{\n                scale: copied ? 1 : 0,\n                opacity: copied ? 1 : 0,\n                rotate: copied ? 0 : -90,\n              }}\n              transition={{ duration: 0.2 }}\n              className=\"absolute inset-0\"\n            >\n              <Check className=\"size-full\" />\n            </motion.div>\n          </span>\n          <span>{copied ? \"Copied\" : \"Copy\"}</span>\n        </motion.button>\n        <pre\n          ref={preRef}\n          className={cn(\n            \"m-0 p-4 text-sm leading-relaxed\",\n            \"bg-white dark:bg-zinc-950/50\",\n            codeContent.length > 1 ? \"rounded-b-2xl\" : \"rounded-2xl\",\n            hasOverflow ? \"overflow-x-auto\" : \"overflow-x-hidden\",\n            hasOverflow && \"scrollbar-thin scrollbar-thumb-rounded\",\n            hasOverflow &&\n              \"scrollbar-thumb-black/15 hover:scrollbar-thumb-black/20\",\n            hasOverflow &&\n              \"dark:scrollbar-thumb-white/20 dark:hover:scrollbar-thumb-white/25\",\n            hasOverflow && \"[&::-webkit-scrollbar]:h-2\",\n            hasOverflow && \"[&::-webkit-scrollbar-thumb]:rounded-full\",\n            hasOverflow && \"[&::-webkit-scrollbar-thumb]:bg-black/15\",\n            hasOverflow && \"[&::-webkit-scrollbar-thumb]:dark:bg-white/20\",\n            hasOverflow && \"[&::-webkit-scrollbar-thumb:hover]:bg-black/20\",\n            hasOverflow &&\n              \"[&::-webkit-scrollbar-thumb:hover]:dark:bg-white/25\",\n            hasOverflow && \"[&::-webkit-scrollbar-track]:bg-transparent\"\n          )}\n        >\n          <AnimatePresence mode=\"wait\" initial={false} custom={direction}>\n            <motion.code\n              key={activeTab}\n              custom={direction}\n              initial={{\n                opacity: 0,\n                x: direction > 0 ? 20 : -20,\n                filter: \"blur(4px)\",\n              }}\n              animate={{\n                opacity: 1,\n                x: 0,\n                filter: \"blur(0px)\",\n              }}\n              exit={{\n                opacity: 0,\n                x: direction > 0 ? -20 : 20,\n                filter: \"blur(4px)\",\n              }}\n              transition={{\n                duration: 0.15,\n                ease: \"easeOut\",\n              }}\n              className=\"block font-mono whitespace-pre text-zinc-950 dark:text-zinc-50\"\n            >\n              {currentCode}\n            </motion.code>\n          </AnimatePresence>\n        </pre>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ]
}