{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-block",
  "title": "Code Block",
  "description": "A monospace block for commands and output, with a copy button.",
  "registryDependencies": [
    "https://sproutboat.com/ikada/r/theme.json",
    "https://sproutboat.com/ikada/r/cn.json",
    "https://sproutboat.com/ikada/r/icon-button.json",
    "https://sproutboat.com/ikada/r/icons.json",
    "https://sproutboat.com/ikada/r/inline-confirm.json"
  ],
  "files": [
    {
      "path": "registry/ikada/ui/code-block.tsx",
      "content": "\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { cn, focusRingInset } from \"@/components/ikada/lib/cn\";\nimport { CheckIcon, CopyIcon } from \"@/components/ikada/lib/icons\";\nimport { IconButton } from \"@/components/ikada/icon-button\";\nimport { InlineConfirm } from \"@/components/ikada/inline-confirm\";\n\nexport interface CodeBlockProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n  /** The text. It is shown as is and copied as is. */\n  code: string;\n  /** Names the block for screen readers, e.g. \"Deploy command\". Required. */\n  label: string;\n  /** Wrap long lines instead of scrolling sideways. */\n  wrap?: boolean;\n  /** Hides the copy button. */\n  copyable?: boolean;\n}\n\n/** A monospace block for commands and output, with a copy button. The scroll area is keyboard focusable. */\nexport function CodeBlock({ code, label, wrap = false, copyable = true, className, ref, ...props }: CodeBlockProps) {\n  async function copy(confirm: () => void) {\n    try {\n      await navigator.clipboard.writeText(code);\n    } catch {\n      return;\n    }\n    confirm();\n  }\n  return (\n    <div\n      data-slot=\"code-block\"\n      ref={ref}\n      className={cn(\"relative min-w-0 max-w-full rounded-lg bg-code-bg shadow-tray\", className)}\n      {...props}\n    >\n      <pre\n        role=\"region\"\n        aria-label={label}\n        // oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- a scroll region must be keyboard-focusable\n        tabIndex={0}\n        className={cn(\n          \"m-0 max-w-full overflow-auto rounded-lg py-3 ps-4 pe-12 font-mono text-sb-sm leading-relaxed text-fg [tab-size:2]\",\n          wrap ? \"whitespace-pre-wrap break-words\" : \"whitespace-pre\",\n          focusRingInset,\n        )}\n      >\n        <code>{code}</code>\n      </pre>\n      {copyable ? (\n        <>\n          {/* Text that runs long fades out under the button instead of showing on both sides of it. */}\n          <span\n            aria-hidden=\"true\"\n            className=\"pointer-events-none absolute inset-y-0 end-0 w-14 rounded-e-lg bg-linear-to-r from-transparent via-code-bg/90 to-code-bg\"\n          />\n          <InlineConfirm\n            message=\"Copied\"\n            announce=\"Copied to clipboard\"\n            className=\"absolute end-1.5 top-1.5 rounded-md bg-code-bg\"\n          >\n            {({ confirm, active }) => (\n              <IconButton\n                label={active ? \"Copied\" : `Copy ${label.toLowerCase()}`}\n                size=\"sm\"\n                onClick={() => copy(confirm)}\n                className=\"text-fg-muted hover:text-fg\"\n              >\n                {active ? <CheckIcon className=\"text-brand-fg\" /> : <CopyIcon />}\n              </IconButton>\n            )}\n          </InlineConfirm>\n        </>\n      ) : null}\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@components/ikada/code-block.tsx"
    }
  ],
  "categories": [
    "data-display"
  ],
  "type": "registry:ui"
}