{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "markdown",
  "type": "registry:ui",
  "title": "Markdown",
  "description": "Rendered agent markdown (GFM) whose code fences compose Code, and diff fences compose CodeDiff.",
  "dependencies": [
    "streamdown@^2.5.0"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/code.json",
    "https://control-ui.dev/r/code-diff.json",
    "https://control-ui.dev/r/core.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/markdown-knobs.ts",
      "target": "@components/control-ui/knob-contracts/markdown-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/markdown.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const markdownKnobs = [\n  \"--cui-markdown-foreground\",\n  \"--cui-markdown-blockquote-border-color\",\n  \"--cui-markdown-blockquote-foreground\",\n  \"--cui-markdown-inline-code-background\",\n  \"--cui-markdown-inline-code-foreground\",\n  \"--cui-markdown-inline-code-radius\",\n  \"--cui-markdown-link-foreground\",\n  \"--cui-markdown-table-cell-border-color\",\n  \"--cui-markdown-table-header-background\",\n] as const;\nexport type MarkdownKnobStyle = Partial<Record<(typeof markdownKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/markdown.css",
      "target": "@components/control-ui/styles/recipes/markdown.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"markdown\"][data-slot=\"root\"]) {\n    --cui-markdown-foreground: oklch(from var(--foreground) l c h / 0.9);\n    --cui-markdown-blockquote-border-color: var(--border);\n    --cui-markdown-blockquote-foreground: var(--muted-foreground);\n    --cui-markdown-inline-code-background: color-mix(in oklab, var(--foreground) 8%, transparent);\n    --cui-markdown-inline-code-foreground: var(--foreground);\n    --cui-markdown-inline-code-radius: 0.25rem;\n    --cui-markdown-link-foreground: var(--primary-text);\n    --cui-markdown-table-cell-border-color: var(--border);\n    --cui-markdown-table-header-background: var(--muted);\n    color: var(--cui-markdown-foreground);\n    font-size: var(--text-label);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"table-cell\"]) {\n    border-style: solid;\n    border-width: 1px;\n    border-color: var(--cui-markdown-table-cell-border-color);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"table-header\"]) {\n    border-style: solid;\n    border-width: 1px;\n    border-color: var(--border);\n    background-color: var(--cui-markdown-table-header-background);\n    text-align: left;\n    font-weight: var(--font-weight-semibold);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"table\"]) {\n    border-collapse: collapse;\n    font-size: var(--text-label);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"emphasis\"]) {\n    font-style: italic;\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"strong\"]) {\n    font-weight: var(--font-weight-semibold);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"separator\"]) {\n    border-color: var(--border);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"blockquote\"]) {\n    border-color: var(--cui-markdown-blockquote-border-color);\n    border-left-style: solid;\n    border-left-width: 2px;\n    color: var(--cui-markdown-blockquote-foreground);\n    font-style: italic;\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"link\"]) {\n    font-weight: var(--font-weight-medium);\n    color: var(--cui-markdown-link-foreground);\n    --_markdown-link-decoration: underline;\n    text-decoration-line: var(--_markdown-link-decoration);\n    text-underline-offset: 2px;\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"markdown\"][data-slot=\"link\"]:hover) {\n      --_markdown-link-decoration: none;\n      text-decoration-line: var(--_markdown-link-decoration);\n    }\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"list-item\"]) {\n    line-height: calc(var(--spacing) * 7);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"paragraph\"]) {\n    line-height: calc(var(--spacing) * 7);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"h3\"]) {\n    font-weight: var(--font-weight-semibold);\n    font-size: var(--text-base);\n    line-height: var(--text-base--line-height);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"h2\"]) {\n    font-weight: var(--font-weight-semibold);\n    font-size: var(--text-lg);\n    line-height: var(--text-lg--line-height);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"h1\"]) {\n    font-weight: var(--font-weight-semibold);\n    font-size: var(--text-xl);\n    line-height: var(--text-xl--line-height);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"markdown\"][data-slot=\"inline-code\"]) {\n    border-radius: var(--cui-markdown-inline-code-radius);\n    background-color: var(--cui-markdown-inline-code-background);\n    font-family: var(--font-mono);\n    font-size: 0.9em;\n    color: var(--cui-markdown-inline-code-foreground);\n  }\n}\n\n@property --cui-markdown-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-blockquote-border-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-blockquote-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-inline-code-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-inline-code-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-inline-code-radius {\n  syntax: \"<length-percentage>+\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-markdown-link-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-table-cell-border-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-markdown-table-header-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/markdown-elements.tsx",
      "target": "@components/control-ui/ui/markdown-elements.tsx",
      "type": "registry:ui",
      "content": "import type { ComponentProps, CSSProperties, JSX, ReactNode } from \"react\";\nimport type { MarkdownKnobStyle } from \"@/components/control-ui/knob-contracts/markdown-knobs\";\n\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { Code, CodeActions, CodeContent, CodeCopy, CodeHeader, CodeTitle } from \"@/components/control-ui/ui/code\";\nimport { CodeDiff } from \"@/components/control-ui/ui/code-diff\";\n\ntype MarkdownCodeProps = ComponentProps<\"code\"> & {\n  node?: unknown;\n} & { style?: CSSProperties & MarkdownKnobStyle };\n\ntype MarkdownElementProps<Tag extends keyof JSX.IntrinsicElements> = ComponentProps<Tag> & {\n  node?: unknown;\n} & { style?: CSSProperties & MarkdownKnobStyle };\n\nfunction textValue(children: ReactNode) {\n  return Array.isArray(children) ? children.join(\"\") : String(children ?? \"\");\n}\n\nfunction languageFromClassName(className?: string) {\n  return /language-([\\w-]+)/.exec(className ?? \"\")?.[1];\n}\n\nexport function MarkdownInlineCode({ className, children, node: _node, ...props }: MarkdownCodeProps) {\n  return (\n    <code\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"inline-code\"\n      className={cn(\"px-1 py-0.5\", className)}\n      {...props}\n    >\n      {children}\n    </code>\n  );\n}\n\nexport function MarkdownPre({ children, node: _node }: MarkdownElementProps<\"pre\">) {\n  return <>{children}</>;\n}\n\nexport function MarkdownCode({ className, children, node: _node, ...props }: MarkdownCodeProps) {\n  const lang = languageFromClassName(className);\n  const rawValue = textValue(children);\n  if (!lang && !rawValue.includes(\"\\n\")) {\n    return (\n      <MarkdownInlineCode className={className} {...props}>\n        {children}\n      </MarkdownInlineCode>\n    );\n  }\n\n  const value = rawValue.replace(/^\\n/, \"\").replace(/\\n$/, \"\");\n  if (lang === \"diff\" && value.includes(\"@@\")) {\n    return <CodeDiff patch={value} lang=\"diff\" diffStyle=\"unified\" className=\"my-4\" />;\n  }\n\n  return (\n    <Code className=\"my-4\">\n      <CodeHeader>\n        {lang ? <CodeTitle>{lang}</CodeTitle> : null}\n        <CodeActions>\n          <CodeCopy value={value} />\n        </CodeActions>\n      </CodeHeader>\n      <CodeContent code={value} lang={lang} highlight={lang ? \"auto\" : \"none\"} />\n    </Code>\n  );\n}\n\nexport function MarkdownH1({ className, node: _node, ...props }: MarkdownElementProps<\"h1\">) {\n  return (\n    <h1\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"h1\"\n      className={cn(\"mt-6 mb-3 first:mt-0\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownH2({ className, node: _node, ...props }: MarkdownElementProps<\"h2\">) {\n  return (\n    <h2\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"h2\"\n      className={cn(\"mt-6 mb-3 first:mt-0\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownH3({ className, node: _node, ...props }: MarkdownElementProps<\"h3\">) {\n  return (\n    <h3\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"h3\"\n      className={cn(\"mt-5 mb-2 first:mt-0\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownP({ className, node: _node, ...props }: MarkdownElementProps<\"p\">) {\n  return (\n    <p\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"paragraph\"\n      className={cn(\"my-3 first:mt-0 last:mb-0\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownUl({ className, node: _node, ...props }: MarkdownElementProps<\"ul\">) {\n  return (\n    <ul\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"unordered-list\"\n      className={cn(\"my-3 list-disc space-y-1 pl-6\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownOl({ className, node: _node, ...props }: MarkdownElementProps<\"ol\">) {\n  return (\n    <ol\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"ordered-list\"\n      className={cn(\"my-3 list-decimal space-y-1 pl-6\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownLi({ className, node: _node, ...props }: MarkdownElementProps<\"li\">) {\n  return <li data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"list-item\" className={className} {...props} />;\n}\n\nexport function MarkdownA({ className, node: _node, ...props }: MarkdownElementProps<\"a\">) {\n  return <a data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"link\" className={className} {...props} />;\n}\n\nexport function MarkdownBlockquote({ className, node: _node, ...props }: MarkdownElementProps<\"blockquote\">) {\n  return (\n    <blockquote\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"blockquote\"\n      className={cn(\"my-4 pl-4\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownHr({ className, node: _node, ...props }: MarkdownElementProps<\"hr\">) {\n  return (\n    <hr data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"separator\" className={cn(\"my-6\", className)} {...props} />\n  );\n}\n\nexport function MarkdownStrong({ className, node: _node, ...props }: MarkdownElementProps<\"strong\">) {\n  return <strong data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"strong\" className={className} {...props} />;\n}\n\nexport function MarkdownEm({ className, node: _node, ...props }: MarkdownElementProps<\"em\">) {\n  return <em data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"emphasis\" className={className} {...props} />;\n}\n\nexport function MarkdownTable({ className, children, node: _node, ...props }: MarkdownElementProps<\"table\">) {\n  return (\n    <div data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"table-scroll\" className=\"my-4 overflow-x-auto\">\n      <table data-control-ui=\"markdown\" data-control-family=\"markdown\" data-slot=\"table\" className={cn(\"w-full\", className)} {...props}>\n        {children}\n      </table>\n    </div>\n  );\n}\n\nexport function MarkdownTh({ className, node: _node, ...props }: MarkdownElementProps<\"th\">) {\n  return (\n    <th\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"table-header\"\n      className={cn(\"px-3 py-1.5\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function MarkdownTd({ className, node: _node, ...props }: MarkdownElementProps<\"td\">) {\n  return (\n    <td\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"table-cell\"\n      className={cn(\"px-3 py-1.5\", className)}\n      {...props}\n    />\n  );\n}\n\n// `pre` must stay unoverridden: Streamdown only routes fenced blocks to `code` with language-* className while it is default.\nexport const markdownComponents = {\n  code: MarkdownCode,\n  inlineCode: MarkdownInlineCode,\n  h1: MarkdownH1,\n  h2: MarkdownH2,\n  h3: MarkdownH3,\n  p: MarkdownP,\n  ul: MarkdownUl,\n  ol: MarkdownOl,\n  li: MarkdownLi,\n  a: MarkdownA,\n  blockquote: MarkdownBlockquote,\n  hr: MarkdownHr,\n  strong: MarkdownStrong,\n  em: MarkdownEm,\n  table: MarkdownTable,\n  th: MarkdownTh,\n  td: MarkdownTd,\n};\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/markdown.tsx",
      "target": "@components/control-ui/ui/markdown.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport type { ComponentProps, CSSProperties } from \"react\";\nimport { Streamdown } from \"streamdown\";\nimport type { MarkdownKnobStyle } from \"@/components/control-ui/knob-contracts/markdown-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { markdownComponents } from \"@/components/control-ui/ui/markdown-elements\";\n\nexport type MarkdownProps = Omit<ComponentProps<\"div\">, \"children\" | \"style\"> & {\n  content: string;\n  style?: CSSProperties & MarkdownKnobStyle;\n};\n\n// Chrome-less on purpose so it drops straight into chat message; MarkdownBlock composes it for headered, copyable block.\n\n// Markdown parts read their paint from knobs this root declares, so prose assembled elsewhere (MDX) needs it too.\nexport function MarkdownRoot({\n  className,\n  ...props\n}: Omit<ComponentProps<\"div\">, \"style\"> & { style?: CSSProperties & MarkdownKnobStyle }) {\n  return (\n    <div\n      data-control-ui=\"markdown\"\n      data-control-family=\"markdown\"\n      data-slot=\"root\"\n      className={cn(\"[&>*:first-child]:mt-0 [&>*:last-child]:mb-0\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function Markdown({ content, className, ...props }: MarkdownProps) {\n  return (\n    <MarkdownRoot className={className} {...props}>\n      <Streamdown\n        mode=\"streaming\"\n        parseIncompleteMarkdown\n        controls={false}\n        components={markdownComponents}\n        className=\"space-y-4 whitespace-normal [&>*:first-child]:mt-0 [&>*:last-child]:mb-0\"\n      >\n        {content}\n      </Streamdown>\n    </MarkdownRoot>\n  );\n}\n\nexport type MarkdownComponentProps = ComponentProps<typeof Markdown>;\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/markdown.css\"": {}
  },
  "meta": {}
}
