{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "code-block",
  "title": "Code Block",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/code-block/CodeBlock.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Check, ChevronDown, ChevronUp, Copy } from 'lucide-vue-next'\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\n\ninterface Props {\n  /** Source code to display. */\n  code: string\n  /** Language label shown in the header. */\n  language?: string\n  /** Render line numbers in the gutter. */\n  showLineNumbers?: boolean\n  /** Maximum height of the code body before scrolling kicks in. */\n  maxHeight?: string\n  /** Render expanded on first paint. Default true. */\n  defaultExpanded?: boolean\n  /** Show the language label / copy / collapse header. */\n  showHeader?: boolean\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  language: 'vue',\n  showLineNumbers: true,\n  maxHeight: '400px',\n  defaultExpanded: true,\n  showHeader: true,\n})\n\nconst isExpanded = ref(props.defaultExpanded)\nconst copied = ref(false)\n\nconst lines = computed(() => props.code.replace(/\\s+$/, '').split('\\n'))\n\nasync function copyToClipboard() {\n  try {\n    await navigator.clipboard.writeText(props.code)\n    copied.value = true\n    setTimeout(() => (copied.value = false), 1600)\n  } catch (e) {\n    console.warn('Clipboard write failed', e)\n  }\n}\n</script>\n\n<template>\n  <div\n    data-uipkge\n    data-slot=\"code-block\"\n    :class=\"cn('group border-border bg-muted/20 relative overflow-hidden rounded-lg border', props.class)\"\n  >\n    <!-- Header -->\n    <div v-if=\"showHeader\" class=\"border-border bg-muted/40 flex items-center justify-between gap-2 border-b px-3 py-2\">\n      <span class=\"text-muted-foreground text-xs font-medium tracking-wide uppercase\">\n        {{ language }}\n      </span>\n      <div class=\"flex items-center gap-1\">\n        <Button variant=\"ghost\" size=\"xs\" class=\"h-7 gap-1.5 px-2\" @click=\"copyToClipboard\">\n          <Check v-if=\"copied\" class=\"text-success size-3\" aria-hidden=\"true\" />\n          <Copy v-else class=\"size-3\" aria-hidden=\"true\" />\n          <span class=\"text-xs\">{{ copied ? 'Copied' : 'Copy' }}</span>\n        </Button>\n        <Button variant=\"ghost\" size=\"xs\" class=\"h-7 gap-1.5 px-2\" @click=\"isExpanded = !isExpanded\">\n          <ChevronUp v-if=\"isExpanded\" class=\"size-3\" aria-hidden=\"true\" />\n          <ChevronDown v-else class=\"size-3\" aria-hidden=\"true\" />\n          <span class=\"text-xs\">{{ isExpanded ? 'Hide' : 'Show' }} code</span>\n        </Button>\n      </div>\n    </div>\n\n    <!-- Code body. We render line-by-line so the gutter and the code stay in\n         sync without measuring text height. The renderer is intentionally\n         plain: code is displayed as-is and the consumer can layer their own\n         syntax highlighter (shiki, prism, hljs) on top by replacing this\n         file or by wrapping it in their own component. -->\n    <div\n      v-show=\"isExpanded\"\n      class=\"bg-background/40 overflow-auto font-mono text-sm leading-relaxed\"\n      :style=\"{ maxHeight: props.maxHeight }\"\n    >\n      <pre class=\"m-0 flex\"><div\n          v-if=\"showLineNumbers\"\n          aria-hidden=\"true\"\n          class=\"text-muted-foreground/60 sticky left-0 select-none border-r border-border/60 bg-muted/30 px-3 py-3 text-right tabular-nums\"\n        ><div v-for=\"(_, i) in lines\" :key=\"i\">{{ i + 1 }}</div></div><code\n          class=\"block flex-1 px-4 py-3\"\n        ><template v-for=\"(line, i) in lines\" :key=\"i\"><span>{{ line || ' ' }}</span><br v-if=\"i < lines.length - 1\"></template></code></pre>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/code-block/CodeBlock.vue"
    },
    {
      "path": "packages/registry-vue/components/code-block/index.ts",
      "content": "export { default as CodeBlock } from './CodeBlock.vue'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/code-block/index.ts"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/button.json"
  ],
  "description": "Read-only code preview with a header, optional filename, copy button, and `<pre>`-rendered content. Use for installation snippets, API examples, and snippets you want users to copy verbatim.",
  "categories": [
    "data-display"
  ]
}