# Markdown

Markdown 渲染组件，基于 [react-markdown](https://github.com/remarkjs/react-markdown) 实现，支持插件扩展和自定义渲染器。

## 适用场景

- 渲染用户输入的 Markdown 内容
- 文档展示、文章详情页
- 需要自定义代码高亮或链接行为的 Markdown 渲染场景

## Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| remarkPlugins | `PluggableList` | `-` | 否 | remark 插件列表 |
| rehypePlugins | `PluggableList` | `-` | 否 | rehype 插件列表 |
| remarkRehypeOptions | `Options` | `-` | 否 | remark-rehype 转换选项 |
| allowedElements | `string[]` | `-` | 否 | 允许渲染的 HTML 元素列表 |
| disallowedElements | `string[]` | `-` | 否 | 禁止渲染的 HTML 元素列表 |
| allowElement | `AllowElement` | `-` | 否 | 自定义元素过滤函数 |
| unwrapDisallowed | `boolean` | `-` | 否 | 是否展开被禁止元素的子内容 |
| sourcePos | `boolean` | `-` | 否 | 是否在节点上附加源码位置信息 |
| rawSourcePos | `boolean` | `-` | 否 | 是否在节点上附加原始源码位置信息 |
| skipHtml | `boolean` | `-` | 否 | 是否跳过 HTML 标签 |
| includeElementIndex | `boolean` | `-` | 否 | 是否在节点上包含元素索引 |
| transformLinkUri | `false \| TransformLink` | `-` | 否 | 链接 URI 转换函数 |
| transformImageUri | `TransformImage` | `-` | 否 | 图片 URI 转换函数 |
| linkTarget | `HTMLAttributeAnchorTarget \| TransformLinkTarget` | `-` | 否 | 链接 target 属性 |
| components | `Partial<Omit<NormalComponents, keyof SpecialComponents> & SpecialComponents>` | `-` | 否 | 自定义渲染组件映射 |
| linkComponent | `LinkComponent` | `-` | 否 | 自定义链接渲染组件，用于替换内置的 `<a target=_blank>`；各站点可注入自己的路由 Link（如 react-router `Link`）以实现 SPA 内部跳转 |

## 典型用法

### 基础渲染

```tsx
import {Markdown} from '@befe/brick'

<Markdown>{`# 标题\n\n一段正文内容`}</Markdown>
```

### 使用 GFM 插件（表格、任务列表、删除线等）

```tsx
import gfm from 'remark-gfm'
import {Markdown} from '@befe/brick'

<Markdown remarkPlugins={[gfm]}>{markdownContent}</Markdown>
```

### 自定义代码渲染器

```tsx
import {Code, CodeProps, coy} from '@befe/brick-comp-code'
import {Markdown} from '@befe/brick'

const CustomCode = (props) => {
    const {children, className} = props
    const match = /language-(\w+)/.exec(className || '')
    return match
        ? <Code language={match[1]} theme={coy as CodeProps['theme']}>{String(children).replace(/\n$/, '')}</Code>
        : <code className={className}>{children}</code>
}

<Markdown components={{code: CustomCode}}>{content}</Markdown>
```

### 注入路由 Link 实现站内跳转

```tsx
import {AnchorHTMLAttributes} from 'react'
import {Link} from 'react-router-dom'
import {Markdown} from '@befe/brick'

// 站内绝对路径走 react-router，其余（http(s)、mailto、锚点）保持默认新窗口打开
function MdLink({href, children}: AnchorHTMLAttributes<HTMLAnchorElement>) {
    if (href && href.startsWith('/')) {
        return <Link to={href}>{children}</Link>
    }
    return <a href={href} target={'_blank'} rel={'noreferrer'}>{children}</a>
}

<Markdown linkComponent={MdLink}>{content}</Markdown>
```

## 注意事项

- 引入此组件会增加一个相对较大的资源尺寸，请按需引入
- 代码块默认使用 `@befe/brick-comp-code` 组件渲染
- 链接默认在新窗口打开；需要 SPA 内部跳转时用 `linkComponent` 注入路由 Link，组件本身不引入路由依赖
- `linkComponent` 只替换 `a` 的渲染，不会透传给 `react-markdown`；同时传 `components.a` 会覆盖 `linkComponent`
- 样式基于 [github-markdown-css](https://github.com/sindresorhus/github-markdown-css)
- 可通过 `remark-gfm` 插件支持表格、任务列表、删除线、自动链接等 GFM 语法
