{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code",
  "type": "registry:component",
  "title": "Code",
  "description": "Shiki-highlighted code windows: tabbed snippets with crossfade, and an annotated walkthrough with bidirectional linked highlighting.",
  "framework": "next",
  "dependencies": [
    "shiki"
  ],
  "registryDependencies": [
    "https://mocoui.site/r/tokens.json"
  ],
  "files": [
    {
      "path": "registry/code/code.tsx",
      "type": "registry:component",
      "target": "components/moco/code.tsx",
      "content": "import * as React from \"react\";\nimport { codeToHtml } from \"shiki\";\nimport { CodeTabsClient, WalkthroughClient, type Region } from \"./code-client\";\nimport \"./code.css\";\n\n/** A light TextMate theme keyed to the moco palette. Keywords take the one accent. */\nconst LIGHT = {\n  name: \"moco-plate\",\n  type: \"light\",\n  colors: {\n    \"editor.background\": \"#fcfbf9\",\n    \"editor.foreground\": \"#242424\",\n  },\n  settings: [\n    { settings: { foreground: \"#242424\", background: \"#fcfbf9\" } },\n    {\n      scope: [\"comment\", \"punctuation.definition.comment\"],\n      settings: { foreground: \"#8a8477\", fontStyle: \"italic\" },\n    },\n    {\n      scope: [\"string\", \"string.quoted\", \"constant.other.symbol\", \"meta.embedded.line\"],\n      settings: { foreground: \"#3f6d33\" },\n    },\n    {\n      scope: [\"keyword\", \"storage\", \"storage.type\", \"keyword.control\", \"keyword.operator.new\"],\n      settings: { foreground: \"#5b770c\" },\n    },\n    { scope: [\"constant.numeric\", \"constant.language\"], settings: { foreground: \"#7a4b9c\" } },\n    {\n      scope: [\"entity.name.function\", \"support.function\", \"meta.function-call.generic\"],\n      settings: { foreground: \"#1a1a1a\" },\n    },\n    {\n      scope: [\"variable\", \"meta.definition.variable\", \"support.type\"],\n      settings: { foreground: \"#242424\" },\n    },\n    { scope: [\"punctuation\", \"meta.brace\"], settings: { foreground: \"#8a8477\" } },\n  ],\n} as const;\n\n/** Dark twin: warm near-black ground (the dark token palette), lime takes keyword duty. */\nconst DARK = {\n  name: \"moco-plate-dark\",\n  type: \"dark\",\n  colors: {\n    \"editor.background\": \"#121110\",\n    \"editor.foreground\": \"#dedcd7\",\n  },\n  settings: [\n    { settings: { foreground: \"#dedcd7\", background: \"#121110\" } },\n    {\n      scope: [\"comment\", \"punctuation.definition.comment\"],\n      settings: { foreground: \"#8a8477\", fontStyle: \"italic\" },\n    },\n    {\n      scope: [\"string\", \"string.quoted\", \"constant.other.symbol\", \"meta.embedded.line\"],\n      settings: { foreground: \"#a9c98a\" },\n    },\n    {\n      scope: [\"keyword\", \"storage\", \"storage.type\", \"keyword.control\", \"keyword.operator.new\"],\n      settings: { foreground: \"#c6f24e\" },\n    },\n    { scope: [\"constant.numeric\", \"constant.language\"], settings: { foreground: \"#c9a1ec\" } },\n    {\n      scope: [\"entity.name.function\", \"support.function\", \"meta.function-call.generic\"],\n      settings: { foreground: \"#f2f0ec\" },\n    },\n    {\n      scope: [\"variable\", \"meta.definition.variable\", \"support.type\"],\n      settings: { foreground: \"#dedcd7\" },\n    },\n    { scope: [\"punctuation\", \"meta.brace\"], settings: { foreground: \"#8a8477\" } },\n  ],\n} as const;\n\nexport type { Region };\n\nexport interface Snippet {\n  label: string;\n  filename: string;\n  lang: string;\n  code: string;\n  /** 1-indexed lines to band. Use \"warn\" to band them in --moco-warn instead. */\n  highlight?: number[];\n  highlightTone?: \"true\" | \"warn\";\n  /** Where line numbering starts, for excerpted regions. */\n  startLine?: number;\n}\n\nasync function render(s: Snippet): Promise<string> {\n  const hl = new Set(s.highlight ?? []);\n  const tone = s.highlightTone ?? \"true\";\n  return codeToHtml(s.code.replace(/\\n$/, \"\"), {\n    lang: s.lang,\n    // Dual themes: tokens carry --shiki-light/--shiki-dark vars (defaultColor:\n    // false); code.css switches between them with the color scheme.\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    themes: { light: LIGHT as any, dark: DARK as any },\n    defaultColor: false,\n    transformers: [\n      {\n        line(node, line) {\n          if (hl.has(line)) node.properties[\"data-hl\"] = tone;\n        },\n      },\n    ],\n  });\n}\n\n/** Window chrome, line numbers, line highlights, tabs bottom-right. */\nexport async function CodeTabs({ tabs }: { tabs: Snippet[] }) {\n  const html = await Promise.all(tabs.map(render));\n  return (\n    <CodeTabsClient\n      labels={tabs.map((t) => t.label)}\n      filenames={tabs.map((t) => t.filename)}\n      panes={html.map((h, i) => (\n        <div key={i} dangerouslySetInnerHTML={{ __html: h }} />\n      ))}\n    />\n  );\n}\n\n/** Two-column code walkthrough with bidirectional linked highlighting. */\nexport async function Walkthrough({\n  filename,\n  lang,\n  regions,\n  blocks,\n}: {\n  filename: string;\n  lang: string;\n  regions: (Region & { code: string })[];\n  blocks: { id: string; label: string; sub?: string }[];\n}) {\n  const html = await Promise.all(\n    regions.map((r) => render({ label: r.id, filename, lang, code: r.code })),\n  );\n  return (\n    <WalkthroughClient\n      filename={filename}\n      regions={regions.map(({ id, label, note }) => ({ id, label, note }))}\n      panes={html.map((h, i) => (\n        <div key={i} dangerouslySetInnerHTML={{ __html: h }} />\n      ))}\n      blocks={blocks}\n    />\n  );\n}\n"
    },
    {
      "path": "registry/code/code-client.tsx",
      "type": "registry:component",
      "target": "components/moco/code-client.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\n/** Tabs sit bottom-right and crossfade between versions of the same snippet. */\nexport function CodeTabsClient({\n  labels,\n  filenames,\n  panes,\n}: {\n  labels: string[];\n  filenames: string[];\n  panes: React.ReactNode[];\n}) {\n  const [i, setI] = React.useState(0);\n  return (\n    <div className=\"moco-win\">\n      <div className=\"moco-win-bar\">\n        <span>{filenames[i]}</span>\n      </div>\n      <div className=\"moco-win-body\" key={i}>\n        <div className=\"moco-win-fade\">{panes[i]}</div>\n      </div>\n      {labels.length > 1 ? (\n        <div className=\"moco-win-tabs\" role=\"tablist\" aria-label=\"Snippet versions\">\n          {labels.map((l, j) => (\n            <button\n              key={l}\n              type=\"button\"\n              role=\"tab\"\n              className=\"moco-pill\"\n              aria-selected={i === j}\n              aria-pressed={i === j}\n              onClick={() => setI(j)}\n            >\n              {l}\n            </button>\n          ))}\n        </div>\n      ) : null}\n    </div>\n  );\n}\n\n/* ───────────────── annotated walkthrough with linked highlighting ──────────────── */\n\nexport interface Region {\n  id: string;\n  label: string;\n  note: React.ReactNode;\n}\n\nexport function WalkthroughClient({\n  filename,\n  regions,\n  panes,\n  blocks,\n}: {\n  filename: string;\n  regions: Region[];\n  /** Highlighted markup for each region, same order as `regions`. */\n  panes: React.ReactNode[];\n  /** The adjacent diagram, keyed by the same region ids. */\n  blocks: { id: string; label: string; sub?: string }[];\n}) {\n  const [hover, setHover] = React.useState<string | null>(null);\n  const [pinned, setPinned] = React.useState<string | null>(null);\n  const active = pinned ?? hover;\n\n  const dim = (id: string) => (active != null && active !== id ? \"true\" : undefined);\n\n  return (\n    <div className=\"moco-walk\">\n      <div className=\"moco-win\">\n        <div className=\"moco-win-bar\">\n          <span>{filename}</span>\n          {pinned ? (\n            <button type=\"button\" className=\"moco-btn-sm\" onClick={() => setPinned(null)}>\n              unpin\n            </button>\n          ) : null}\n        </div>\n        <div className=\"moco-win-body\">\n          {regions.map((r, i) => (\n            <div\n              key={r.id}\n              className=\"moco-walk-region\"\n              data-on={active === r.id}\n              data-dim={dim(r.id)}\n              tabIndex={0}\n              role=\"button\"\n              aria-pressed={pinned === r.id}\n              aria-label={`${r.label} — ${pinned === r.id ? \"pinned\" : \"click to pin\"}`}\n              onMouseEnter={() => setHover(r.id)}\n              onMouseLeave={() => setHover(null)}\n              onFocus={() => setHover(r.id)}\n              onBlur={() => setHover(null)}\n              onClick={() => setPinned((p) => (p === r.id ? null : r.id))}\n              onKeyDown={(e) => {\n                if (e.key === \"Enter\" || e.key === \" \") {\n                  e.preventDefault();\n                  setPinned((p) => (p === r.id ? null : r.id));\n                }\n              }}\n            >\n              {panes[i]}\n            </div>\n          ))}\n        </div>\n      </div>\n\n      <div>\n        <div className=\"moco-dgm\" style={{ minWidth: 0, marginBottom: \"1.25rem\" }}>\n          <div className=\"moco-dgm-track\" style={{ flexWrap: \"wrap\" }}>\n            {blocks.map((b) => (\n              <button\n                key={b.id}\n                type=\"button\"\n                className=\"moco-dgm-block\"\n                data-variant={active === b.id ? \"active\" : \"default\"}\n                data-dim={dim(b.id)}\n                style={{ flexBasis: \"45%\" }}\n                onMouseEnter={() => setHover(b.id)}\n                onMouseLeave={() => setHover(null)}\n                onFocus={() => setHover(b.id)}\n                onBlur={() => setHover(null)}\n                onClick={() => setPinned((p) => (p === b.id ? null : b.id))}\n              >\n                <span className=\"moco-b-label\">{b.label}</span>\n                {b.sub ? <span className=\"moco-b-sub\">{b.sub}</span> : null}\n              </button>\n            ))}\n          </div>\n        </div>\n\n        {regions.map((r) => (\n          <button\n            key={r.id}\n            type=\"button\"\n            className=\"moco-walk-note\"\n            data-on={active === r.id}\n            data-dim={dim(r.id)}\n            onMouseEnter={() => setHover(r.id)}\n            onMouseLeave={() => setHover(null)}\n            onFocus={() => setHover(r.id)}\n            onBlur={() => setHover(null)}\n            onClick={() => setPinned((p) => (p === r.id ? null : r.id))}\n          >\n            <b>{r.label}</b>\n            {r.note}\n          </button>\n        ))}\n      </div>\n    </div>\n  );\n}\n"
    },
    {
      "path": "registry/code/code.css",
      "type": "registry:file",
      "target": "components/moco/code.css",
      "content": "/* moco/code — window chrome, line numbers, tabs, annotated walkthrough. */\n\n.moco-win {\n  border: 1px solid var(--moco-line);\n  border-radius: 3px;\n  background: var(--moco-bg);\n  overflow: hidden;\n}\n\n.moco-win-bar {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 1rem;\n  padding: 0.4rem 0.75rem;\n  border-bottom: 1px solid var(--moco-line);\n  font-size: 12px;\n  color: var(--moco-faint);\n}\n\n/* The counter lives here, not on `code`, so line numbers stay continuous\n   across the separately-highlighted regions of a walkthrough. */\n.moco-win-body {\n  position: relative;\n  overflow-x: auto;\n  counter-reset: ln;\n}\n\n.moco-win-body pre {\n  margin: 0;\n  padding: 0.9rem 0;\n  font-size: 12.5px;\n  line-height: 22px;\n  background: transparent !important;\n}\n\n@media (min-width: 560px) {\n  .moco-win-body pre {\n    font-size: 13px;\n  }\n}\n\n.moco-win-body code {\n  display: block;\n}\n\n.moco-win-body .line {\n  display: block;\n  padding: 0 1rem 0 0;\n  min-height: 22px;\n}\n\n.moco-win-body .line::before {\n  counter-increment: ln;\n  content: counter(ln);\n  display: inline-block;\n  width: 2.4rem;\n  padding-right: 0.85rem;\n  text-align: right;\n  color: var(--moco-faint);\n  opacity: 0.7;\n  user-select: none;\n}\n\n/* Shiki dual themes (defaultColor: false): every token carries\n   --shiki-light/--shiki-dark vars; pick one per scheme, mirroring how\n   tokens.css does its dark switching. */\n.moco-win-body .line span {\n  color: var(--shiki-light);\n  font-style: var(--shiki-light-font-style, inherit);\n}\n\n@media (prefers-color-scheme: dark) {\n  :root:not([data-theme=\"light\"]) .moco-win-body .line span {\n    color: var(--shiki-dark);\n    font-style: var(--shiki-dark-font-style, inherit);\n  }\n}\n\n[data-theme=\"dark\"] .moco-win-body .line span {\n  color: var(--shiki-dark);\n  font-style: var(--shiki-dark-font-style, inherit);\n}\n\n/* Line bands use the wash tokens, which already flip with the scheme. */\n.moco-win-body .line[data-hl=\"true\"] {\n  background: var(--moco-accent-wash);\n  box-shadow: inset 2px 0 0 var(--moco-accent-dk);\n}\n\n.moco-win-body .line[data-hl=\"warn\"] {\n  background: var(--moco-warn-wash);\n  box-shadow: inset 2px 0 0 var(--moco-warn);\n}\n\n.moco-win-tabs {\n  display: flex;\n  justify-content: flex-end;\n  gap: 0.35rem;\n  padding: 0.4rem 0.6rem;\n  border-top: 1px solid var(--moco-line);\n}\n\n.moco-win-fade {\n  animation: moco-fadein 220ms var(--moco-ease);\n}\n\n@keyframes moco-fadein {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n\n.moco-pill {\n  border: 1px solid var(--moco-line);\n  border-radius: 999px;\n  padding: 0.2rem 0.75rem;\n  font-size: 12px;\n  color: var(--moco-muted);\n  background: var(--moco-bg);\n  transition:\n    color 150ms var(--moco-ease),\n    border-color 150ms var(--moco-ease),\n    background 150ms var(--moco-ease);\n}\n\n.moco-pill:hover {\n  color: var(--moco-ink);\n  border-color: var(--moco-faint);\n}\n\n.moco-pill[aria-pressed=\"true\"],\n.moco-pill[aria-selected=\"true\"] {\n  background: var(--moco-accent);\n  border-color: var(--moco-accent);\n  color: var(--moco-on-accent);\n}\n\n.moco-btn-sm {\n  border: 1px solid var(--moco-line);\n  border-radius: 2px;\n  padding: 0.2rem 0.6rem;\n  font-size: 12px;\n  color: var(--moco-muted);\n  background: var(--moco-bg);\n  transition:\n    color 150ms var(--moco-ease),\n    border-color 150ms var(--moco-ease);\n}\n\n.moco-btn-sm:hover {\n  color: var(--moco-accent-dk);\n  border-color: var(--moco-accent-dk);\n}\n\n/* Annotated walkthrough */\n.moco-walk {\n  display: grid;\n  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);\n  gap: 1.5rem;\n  align-items: start;\n}\n\n@media (max-width: 860px) {\n  .moco-walk {\n    grid-template-columns: 1fr;\n  }\n}\n\n.moco-walk-note {\n  border-left: 1px solid var(--moco-line);\n  padding: 0.35rem 0 0.35rem 0.9rem;\n  font-size: 13px;\n  line-height: 1.55;\n  color: var(--moco-muted);\n  text-align: left;\n  width: 100%;\n  transition: opacity 200ms var(--moco-ease);\n}\n\n.moco-walk-note b {\n  color: var(--moco-ink);\n  font-weight: 400;\n  display: block;\n}\n\n.moco-walk [data-dim=\"true\"] {\n  opacity: 0.4;\n}\n\n/* Each region is its own <pre>, so the default block padding stacks up into a\n   blank line between every region. Trim it; the window keeps its own padding. */\n.moco-walk-region pre {\n  padding: 0;\n}\n\n.moco-walk-region:first-child pre {\n  padding-top: 0.9rem;\n}\n\n.moco-walk-region:last-child pre {\n  padding-bottom: 0.9rem;\n}\n\n.moco-walk-region[data-on=\"true\"] {\n  background: var(--moco-accent-wash);\n  box-shadow: inset 2px 0 0 var(--moco-accent-dk);\n}\n\n.moco-walk-note[data-on=\"true\"] {\n  border-left-color: var(--moco-accent-dk);\n  color: var(--moco-body);\n}\n\n/* Diagram kit (subset the walkthrough renders) */\n.moco-dgm {\n  display: grid;\n  gap: 1.1rem;\n  min-width: 460px;\n  font-size: 13px;\n  line-height: 1.4;\n}\n\n.moco-dgm-track {\n  display: flex;\n  align-items: stretch;\n  gap: 6px;\n  flex-wrap: nowrap;\n}\n\n.moco-dgm-block {\n  position: relative;\n  flex: 1 1 0;\n  min-width: 0;\n  border: 1px solid var(--moco-line);\n  border-radius: 2px;\n  padding: 0.5rem 0.6rem;\n  background: var(--moco-bg);\n  color: var(--moco-body);\n  text-align: left;\n  transition:\n    opacity 200ms var(--moco-ease),\n    border-color 200ms var(--moco-ease),\n    background 200ms var(--moco-ease),\n    color 200ms var(--moco-ease);\n}\n\n.moco-dgm-block .moco-b-label {\n  display: block;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.moco-dgm-block .moco-b-sub {\n  display: block;\n  color: var(--moco-faint);\n  font-size: 11.5px;\n  margin-top: 2px;\n}\n\n.moco-dgm-block[data-variant=\"active\"] {\n  background: var(--moco-accent);\n  border-color: var(--moco-accent);\n  color: var(--moco-on-accent);\n}\n.moco-dgm-block[data-variant=\"active\"] .moco-b-sub {\n  color: rgba(20, 24, 10, 0.72);\n}\n\n/* Hover: dim siblings. */\n.moco-dgm-track:has(.moco-dgm-block:hover) .moco-dgm-block:not(:hover),\n.moco-dgm-track:has(.moco-dgm-block:focus-visible) .moco-dgm-block:not(:focus-visible) {\n  opacity: 0.4;\n}\n"
    }
  ],
  "docs": "import { CodeTabs, Walkthrough } from \"./code\";\n\nconst BEFORE = `function greet(name) {\n  return \"Hello, \" + name + \"!\";\n}\n`;\n\nconst AFTER = `function greet(name: string): string {\n  return \\`Hello, \\${name}!\\`;\n}\n`;\n\nexport default function Demo() {\n  return (\n    <div style={{ display: \"grid\", gap: \"2rem\" }}>\n      <CodeTabs\n        tabs={[\n          { label: \"before\", filename: \"greet.js\", lang: \"js\", code: BEFORE, highlight: [2], highlightTone: \"warn\" },\n          { label: \"after\", filename: \"greet.ts\", lang: \"ts\", code: AFTER, highlight: [2] },\n        ]}\n      />\n\n      <Walkthrough\n        filename=\"counter.ts\"\n        lang=\"ts\"\n        regions={[\n          {\n            id: \"state\",\n            label: \"State\",\n            note: \"A single mutable count, closed over by the returned functions.\",\n            code: `let count = 0;\\n`,\n          },\n          {\n            id: \"api\",\n            label: \"API\",\n            note: \"Increment and read — the only two ways in.\",\n            code: `export const inc = () => ++count;\\nexport const get = () => count;\\n`,\n          },\n        ]}\n        blocks={[\n          { id: \"state\", label: \"count\", sub: \"module state\" },\n          { id: \"api\", label: \"inc / get\", sub: \"public api\" },\n        ]}\n      />\n    </div>\n  );\n}\n",
  "meta": {
    "tags": [
      "code",
      "shiki",
      "syntax-highlighting",
      "tabs",
      "walkthrough"
    ]
  }
}