<!-- AI SUMMARY -->
## 快速了解

MarkdownContent 将 Markdown 字符串解析为 token 并渲染，集成代码块、公式、Mermaid 等子渲染器。 核心 props 为 content 与 status；内置流式节流、语法补全与 DOMPurify 安全策略。 通常由 ContentRender、AssistantMessage 等间接使用，无需业务直接挂载。

### 关联组件
- **code-content** — fence 代码块语法高亮与复制
- **latex-content** — 数学公式 token 的 KaTeX 渲染
- **mermaid-content** — mermaid 代码块的图表渲染
- **content-render** — 上层按类型分发到本组件渲染 Markdown 字符串

---
<!-- FULL DOC -->

# MarkdownContent Markdown 内容渲染

> **层级**：原子组件 · **功能域**：内容渲染

AI 消息内容渲染的核心原子组件，集成代码高亮、LaTeX 公式、Mermaid 图表等能力，内置流式渲染优化（5ms throttle + 语法补全 + 防闪烁）。

由 `AssistantMessage`、`ReasoningMessage` 等分子组件内部自动使用，通常不需要手动引入。

## 组件结构与渲染流程

```
props.content → completeMarkdownSyntax → md.parse → groupTokens → groupedTokens
                                                                          │
                          div.ai-markdown-content（contain: layout style）
                                        │
                        status === 'error' → CommonErrorContent（:content）
                                        │
                        else → div.markdown-body[data-theme]（contain: content）
                                  │
                            v-for groupedToken
                                  │
                    ┌─────────────┼────────────────────┬───────────────┐
                    │             │                    │               │
              hasMermaid?   hasLatex?           hasCode?         else
                    ↓             ↓                    ↓               ↓
           MermaidContent  LatexContent        CodeContent    VNodeRenderer
           @mounted         @mounted           @mounted       @vue:mounted
                    │
                    └──── handleTokenMounted（throttle 100ms）→ containerScroll.toScrollBottom()
```

### Token 分组（groupTokens）

`groupTokens` 使用栈将扁平 Token 数组转为分组数组，每组对应一个顶层 DOM 节点（段落、标题、列表、代码块等）：

- `nesting === 1`（open）→ 入栈，建立新 group；顶层 group 立刻加入结果
- `nesting === -1`（close）→ 出栈，完成该 group；嵌套 group 合并到父 group
- `nesting === 0`（自闭合/inline）→ 无栈时独立成组，有栈时追加到当前 group

每组第一个 token 的 `attrs` 追加 `class="ai-blueking-markdown-fade-in"`，触发渐显动画。

### 子组件优先级

对每个 token 组按以下顺序判断：

| 优先级 | 检测逻辑                                                             | 使用组件                                  |
| ------ | -------------------------------------------------------------------- | ----------------------------------------- |
| 1      | `fence` token 且 `info === 'mermaid'`                                | `MermaidContent`                          |
| 2      | `math_inline` / `math_block`，或 children 中递归含有（inline token） | `LatexContent`                            |
| 3      | `fence`（非 mermaid）或 `code_block`                                 | `CodeContent`                             |
| 4      | 其余                                                                 | `VNodeRenderer`（HTML 由 DOMPurify 过滤） |

## 基础用法

```vue
<template>
  <MarkdownContent
    :content="markdownText"
    :status="MessageStatus.Complete"
  />
</template>

<script setup lang="ts">
  import { MarkdownContent, MessageStatus } from '@blueking/chat-x';

  const markdownText = `# 标题\n\n这是一段 **Markdown** 内容。`;
</script>
```

## 扩展文本格式

支持标准 Markdown + 扩展插件：`++下划线++`（markdown-it-ins）、`==高亮==`（markdown-it-mark）、`~下标~`（markdown-it-sub）、`^上标^`（markdown-it-sup）：

## 列表与任务清单

## 代码块

代码块由 `CodeContent` 渲染，支持 highlight.js 语法高亮、语言标签、一键复制：

## 表格

## LaTeX 公式

公式由 `LatexContent`（KaTeX）渲染，支持行内 `$...$` 和块级 `$$...$$`：

## Mermaid 图表

## 错误状态

`status === MessageStatus.Error` 时渲染 `CommonErrorContent`，将 `content` 作为错误文本显示：

## 流式渲染

````vue
<template>
  <MarkdownContent
    :content="streamingContent"
    :status="isStreaming ? MessageStatus.Streaming : MessageStatus.Complete"
  />
</template>

<script setup lang="ts">
  import { ref } from 'vue';
  import { MarkdownContent, MessageStatus } from '@blueking/chat-x';

  const streamingContent = ref('');
  const isStreaming = ref(false);

  const simulate = async () => {
    const fullText = '## Hello\n\n**流式输出**演示。\n\n```js\nconsole.log(1);\n```';
    isStreaming.value = true;
    for (const char of fullText) {
      await new Promise(r => setTimeout(r, 30));
      streamingContent.value += char;
    }
    isStreaming.value = false;
  };
</script>
````

### 流式优化机制

| 机制              | 实现                                                                                      | 作用                                                       |
| ----------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| 极速节流          | `parseMarkdownContent` throttle **5ms**，leading + trailing                               | 每 5ms 最多解析一次，兼顾实时性与性能                      |
| Markdown 语法补全 | `completeMarkdownSyntax(content)`                                                         | 自动闭合代码块、行内代码、粗斜体、删除线、链接等未完成语法 |
| LaTeX 防闪烁      | `isIncomplete=true` 且已有渲染结果 → **跳过本次更新**                                     | 正在输入 LaTeX 命令时保持上一帧，避免闪白                  |
| 子组件 throttle   | `handleTokenMounted` throttle 100ms                                                       | 限制子组件挂载后触发的滚动到底部频率                       |
| CSS contain       | `.ai-markdown-content { contain: layout style }`<br>`.markdown-body { contain: content }` | 限制重排/重绘范围，减少流式渲染的布局开销                  |
| 渐显动画          | 每组首 token 追加 `.ai-blueking-markdown-fade-in`                                         | 新内容块淡入，减少视觉跳跃感                               |

## 主题支持

组件通过 `data-theme` 属性和内联 CSS 变量覆盖来控制主题，默认为 `light`。引入完整版 `github-markdown.css`（同时包含 light/dark 定义），并通过内联变量强制指定主题色，避免受宿主页面 `@media (prefers-color-scheme)` 影响。

- **Light 模式**（默认）：`.markdown-body[data-theme="light"]`，内联 light 变量 + `color-scheme: light`
- **Dark 模式**：`.markdown-body[data-theme="dark"]`，内联 dark 变量 + `color-scheme: dark`

> 根容器类名为 `.ai-markdown-content`（而非 `.markdown-content`），以避免与 `github-markdown-css` 库自身样式冲突。

## API

### Props

| 属性名  | 类型            | 必填 | 说明                                                      |
| ------- | --------------- | ---- | --------------------------------------------------------- |
| content | `string`        | —    | Markdown 文本；为空时清空渲染结果                         |
| status  | `MessageStatus` | —    | `'error'` 时显示 `CommonErrorContent`，其余状态均正常渲染 |

### Slots

| 插槽名     | 参数                                   | 说明                                                                                    |
| ---------- | -------------------------------------- | --------------------------------------------------------------------------------------- |
| codeHeader | `{ language: string; token: Token[] }` | 代码块头部自定义操作区域，透传给 CodeContent 的 header 插槽，可添加"插入"、"应用"等按钮 |

### 内置插件

| 插件                        | 语法                | 功能                 |
| --------------------------- | ------------------- | -------------------- |
| `markdown-it-footnote`      | `[^1]`              | 脚注                 |
| `markdown-it-ins`           | `++text++`          | 下划线               |
| `markdown-it-mark`          | `==text==`          | 高亮                 |
| `markdown-it-sub`           | `~text~`            | 下标                 |
| `markdown-it-sup`           | `^text^`            | 上标                 |
| `markdown-it-task-checkbox` | `- [x]`             | 任务列表             |
| `markdownItMermaid`         | ` ```mermaid `      | Mermaid 图表 token   |
| `markdownItLatex`           | `$...$` / `$$...$$` | KaTeX 数学公式 token |

### 安全性

`VNodeRenderer` 渲染的 HTML 统一经过 DOMPurify 过滤，并额外允许 KaTeX 所需标签：

```typescript
const domPurifyConfig = {
  ADD_TAGS: ['semantics', 'mrow', 'mi', 'mo', 'mn', 'msup', 'msub', 'mfrac', 'mtext', 'annotation'],
  ADD_ATTR: ['xmlns', 'mathvariant', 'encoding', 'style'],
};
```

> `CodeContent`、`MermaidContent`、`LatexContent` 各自内部处理安全性（KaTeX `errorColor`、highlight.js 转义等），不经过 DOMPurify。

## 关联组件

- [CodeContent](./code-content.md) — 代码 fence 高亮
- [LatexContent](./latex-content.md) — 公式渲染
- [MermaidContent](./mermaid-content.md) — Mermaid 图表
- [ContentRender](../molecular/content-render.md) — 内容类型分发入口