MarkdownEditor

基于 Slate.js 的 Markdown 编辑器组件,支持实时编辑、只读渲染、评论、图片上传、Jinja 模板等能力。

何时使用

  • 需要一个所见即所得的 Markdown 编辑器
  • 需要只读渲染 Markdown 内容(支持轻量 markdown 模式和完整 slate 模式)
  • 需要评论、图片上传、代码高亮、表格编辑等扩展能力

代码演示

基础用法

import { MarkdownEditor } from '@ant-design/agentic-ui';

export default () => {
  return (
    <MarkdownEditor
      initValue={'# Hello World\n\n这是一段示例文本。'}
      height="400px"
      onChange={(value) => console.log('内容变化:', value)}
    />
  );
};

只读模式

import { MarkdownEditor } from '@ant-design/agentic-ui';

export default () => {
  return (
    <MarkdownEditor
      readonly
      initValue={'# 只读模式\n\n用户无法编辑,但可以查看和复制。'}
      height="300px"
    />
  );
};

轻量只读渲染(renderMode: markdown)

import { MarkdownEditor } from '@ant-design/agentic-ui';

export default () => {
  return (
    <MarkdownEditor
      readonly
      renderMode="markdown"
      initValue={'# 轻量渲染\n\n不加载 Slate,首包最小。'}
      height="300px"
    />
  );
};

Markdown 模式自定义块(plugins.renderer)

renderMode: 'markdown' 下,Slate 侧 plugins[].elements 不会生效;请使用 plugins[].renderer:

能力API说明
自定义 fencecreateRendererCodeBlockPlugin({ 'insight-card': ({ code }) => ... })按 ```language 注册渲染器
合并多个插件mergeMarkdownRendererPlugins(pluginA, pluginB)合并 rendererComponents / remark / rehype
保留默认 DOM 再包装eleRender prop拦截 p / table / img 等,返回 undefined 回退默认
覆盖整块渲染renderer.rendererComponents.table 等完全替换对应 hast 标签组件
import {
  MarkdownEditor,
  createRendererCodeBlockPlugin,
} from '@ant-design/agentic-ui';

const cardPlugin = createRendererCodeBlockPlugin({
  'insight-card': ({ code }) => <MyCard data={JSON.parse(code)} />,
});

export default () => (
  <MarkdownEditor
    readonly
    renderMode="markdown"
    initValue={'```insight-card\n{"topic":"demo"}\n```'}
    plugins={[cardPlugin]}
  />
);

仍仅 Slate 模式支持:新建划词评论(FloatBar 选区提交)、initSchemaValue、eleItemRender(请改用 eleRender 或 renderer 插件)。

markdown 模式已支持(只读,纯 DOM + 原生 CSS):

能力API
评论高亮 + 侧栏comment={{ enable: true, commentList }},依赖 refContent;<mark> + -comment-* CSS 类
文本搜索editorRef.current.store.findByPathAndText([], keyword)
兼容搜索findByPathAndText(editorRef.current.store.editor, [], keyword)
当前内容editorRef.current.getDisplayedContent() / store.getMDContent()
包装默认 DOMeleRender

自定义工具栏

import { MarkdownEditor } from '@ant-design/agentic-ui';
import { Button } from 'antd';

export default () => {
  return (
    <MarkdownEditor
      initValue="# 自定义工具栏"
      toolBar={{
        enable: true,
        hideTools: ['table', 'color'],
        extra: [
          <Button key="save" type="primary" size="small">
            保存
          </Button>,
        ],
      }}
      height="400px"
    />
  );
};

图片上传

import { MarkdownEditor } from '@ant-design/agentic-ui';

export default () => {
  return (
    <MarkdownEditor
      initValue="拖拽图片到编辑器或使用工具栏上传"
      image={{
        upload: async (files) => {
          // 实现图片上传逻辑,返回 URL 数组
          return ['https://example.com/image.png'];
        },
      }}
      height="400px"
    />
  );
};

评论功能

import { MarkdownEditor } from '@ant-design/agentic-ui';
import { useState } from 'react';

export default () => {
  const [comments, setComments] = useState([]);

  return (
    <MarkdownEditor
      readonly
      reportMode
      initValue={'# 评论功能\n\n选中文本即可评论。'}
      comment={{
        enable: true,
        onSubmit: (id, comment) => {
          setComments((prev) => [...prev, comment]);
        },
        onDelete: (id) => {
          setComments((prev) => prev.filter((c) => c.id !== id));
        },
        commentList: comments,
        loadMentions: async (keyword) => {
          return [{ name: 'Alice' }, { name: 'Bob' }].filter((u) =>
            u.name.toLowerCase().includes(keyword.toLowerCase()),
          );
        },
      }}
      height="500px"
    />
  );
};

流式输出

import { MarkdownEditor } from '@ant-design/agentic-ui';

export default () => {
  return (
    <MarkdownEditor
      readonly
      renderMode="markdown"
      streaming
      initValue="正在生成中..."
      height="300px"
    />
  );
};

API

MarkdownEditorProps

布局与样式

属性说明类型默认值版本
className自定义 CSS 类名string--
containerClassName容器自定义类名string--
contentStyle内容区域自定义样式React.CSSProperties--
editorStyle编辑器区域自定义样式React.CSSProperties--
height编辑器高度string | number'auto'-
id编辑器唯一标识string--
style容器自定义样式,支持 CSS 变量自定义表格样式(--agentic-ui-table-border-radius 等)React.CSSProperties--
width编辑器宽度string | number'100%'-

内容与模式

属性说明类型默认值版本
children子元素React.ReactNode--
compact是否启用紧凑模式booleanfalse-
depsMElement 刷新依赖string[]--
initSchemaValue直接传入 Slate schema,优先级高于 initValueElements[]--
initValue初始 Markdown 文本内容string--
isFinished流式是否完成(仅 renderMode: 'markdown'),未传入时回退到 !streamingboolean--
placeholder编辑器空态占位文案;优先级高于 textAreaProps.placeholder 与 titlePlaceholderContentstring--
readonly是否只读模式。与 renderMode 联用决定渲染方式booleanfalse-
renderMode只读渲染模式,默认 'slate'。'slate':Slate 文档树(与编辑态一致);'markdown':轻量 Markdown → hast → React,无 Slate 依赖,仅 readonly 时生效'slate' | 'markdown''slate'-
renderTyperenderMode 的别名,同时传入时以 renderMode 为准'slate' | 'markdown'--
reportMode是否开启报告模式booleanfalse-
slideMode是否开启 PPT 模式booleanfalse-
streaming流式输出模式,同时传入时优先于 typewriterboolean--
throttleOptions流式限流与展示配置(仅 renderMode: 'markdown')。默认 streaming 时开启限流;GPT 风格逐词淡入由 fade 控制(默认 true,传 false 关闭)。详见 MarkdownRendererContentThrottleOptions--
toc是否显示目录booleanfalse-
typewriter已废弃:streaming 的别名,向下兼容,新代码请使用 streamingboolean--

ContentThrottleOptions

属性说明类型默认值
backgroundBatchMultiplier后台每批字符相对前台倍数number10
backgroundInterval标签页不可见时的轮询间隔(ms)number100
charsPerFrame每帧最多推进字符数number3
enabled为 false 时关闭限流,流式内容即时渲染booleantrue
fadeGPT 风格逐词淡入开关,仅 streaming 时生效;传 false 关闭booleantrue
flushOnComplete流式结束时是否立即展示剩余内容booleantrue
speed速度倍率number1

工具栏 (toolBar)

属性说明类型默认值版本
enable是否启用工具栏booleanfalse-
extra额外的自定义工具栏项目React.ReactNode[]--
hideTools需要隐藏的工具栏选项ToolsKeyType[]--
min是否使用最小化工具栏booleanfalse-

ToolsKeyType 可选值:

格式相关:'bold' | 'italic' | 'strikethrough' | 'inline-code' | 'color' | 'clear'

标题:'head' | 'H1' | 'H2' | 'H3'

列表:'b-list'(无序) | 'n-list'(有序) | 't-list'(任务)

块元素:'quote' | 'code' | 'table' | 'column' | 'divider' | 'link'

对齐:'align-left' | 'align-center' | 'align-right'

历史:'undo' | 'redo'

浮动工具栏 (floatBar)

属性说明类型默认值版本
enable是否启用浮动工具栏boolean--

文本区域 (textAreaProps)

属性说明类型默认值版本
enable是否启用文本区域boolean--
placeholder占位符文本string--

拖拽 (drag)

属性说明类型默认值版本
enable是否启用拖拽功能boolean--

Markdown 输入 (markdown)

属性说明类型默认值版本
matchInputToNode是否启用输入到节点匹配(如输入 - 转为列表);未开启时仅文档首段受保护,正文段落仍即时转换booleanfalse-
matchLeaf是否启用叶子节点匹配boolean--

图片 (image)

属性说明类型默认值版本
render自定义图片渲染函数(props: ImageProps, defaultDom: React.ReactNode) => React.ReactNode--
upload图片上传函数,返回图片 URL(files: File[] | string[]) => Promise<string[] | string>--

评论 (comment)

属性说明类型默认值版本
commentList评论列表数据CommentDataType[]--
deleteConfirmText删除评论确认文本string--
editorRender自定义评论编辑器渲染(dom: React.ReactNode) => React.ReactNode--
enable是否启用评论功能boolean--
listItemRender自定义评论列表项渲染(defaultDom: { checkbox: ReactNode | null; mentionsUser: ReactNode | null; children: any }, comment: { element: Elements; children: ReactNode; attributes: any }) => React.ReactNode--
loadMentions加载 @提及用户列表(text: string) => Promise<{ name: string }[]>--
mentionsPlaceholder@提及输入框占位符string--
onClick点击评论回调(id: string | number, comment: CommentDataType) => void--
onDelete删除评论回调(id: string | number, comment: CommentDataType) => void--
onEdit编辑评论回调(id: string | number, comment: CommentDataType) => void--
onSubmit评论提交回调(id: string | number, comment: CommentDataType) => void--
placeholder评论输入框占位符,未提供时回退到顶层的 titlePlaceholderContentstring--

CommentDataType

属性说明类型默认值版本
anchorOffset锚点偏移number--
commentType评论类型string--
content评论内容string--
focusOffset焦点偏移number--
id评论唯一标识string | number--
path节点路径number[]--
refContent引用内容string--
selectionSlate 选区Selection--
time评论时间number | string--
updateTime更新时间number--
user评论用户{ name: string; avatar?: string }--

代码块 (codeProps)

属性说明类型默认值版本
alwaysExpandedDeepThink是否始终展开深度思考块booleanfalse-
disableHtmlPreview是否禁用 HTML 预览boolean--
hideToolBar是否隐藏代码块工具栏booleanfalse-
Languages支持的编程语言列表string[]--
render自定义代码块渲染,返回 undefined 回退默认渲染,返回 null 不渲染(props: CustomLeaf, defaultDom: React.ReactNode, codeProps?: codeProps) => React.ReactNode--
scrollDeepThinkIntoViewOnExpand深度思考块展开时是否将组件滚动到视窗内;传 true 默认 { behavior: 'smooth', block: 'nearest' },也可传 ScrollIntoViewOptions 自定义boolean | ScrollIntoViewOptionsfalse2.32.33
viewModeLabels视图模式标签配置{ preview?: string; code?: string }{ preview: '预览', code: '代码' }-
...支持所有 Ace.EditorOptionsPartial<Ace.EditorOptions>--

表格 (tableConfig)

属性说明类型默认值版本
actions表格操作配置{ fullScreen?: 'modal' | 'drawer'; download?: 'csv'; copy?: 'md' | 'html' | 'csv' }--
cssVariablesCSS 变量自定义表格样式Record<\--${string}`, string>`--
minColumn最小列数number--
minRows最小行数number--
previewTitle预览模式标题string--
pure是否启用纯净模式(无工具栏)boolean--

懒加载 (lazy)

属性说明类型默认值版本
enable是否启用懒加载,只有进入视口才渲染boolean--
placeholderHeight占位高度(px)number25-
renderPlaceholder自定义占位渲染(props: { height: number; style: React.CSSProperties; isIntersecting: boolean; elementInfo?: { type: string; index: number; total: number } }) => React.ReactNode--
rootMarginIntersectionObserver rootMarginstring'200px'-

Jinja 模板 (jinja)

属性说明类型默认值版本
docLink使用说明链接string--
enable总开关:语法高亮 + 模板面板boolean--
templatePanel模板面板配置,传 true 使用默认配置boolean | JinjaTemplatePanelConfig--

JinjaTemplatePanelConfig

属性说明类型默认值
enable是否启用,默认 truebooleantrue
items模板列表,静态数组或异步加载JinjaTemplateItem[] | ((params?: { editor?: Editor }) => Promise<JinjaTemplateItem[]>)内置数据
notFoundContent无数据时的内容React.ReactNode-
trigger触发符string'{}'

JinjaTemplateItem

属性说明类型默认值版本
description模板描述(可选)string--
template模板内容string--
title模板标题string--

粘贴配置 (pasteConfig)

属性说明类型默认值版本
enabled是否启用粘贴boolean--
allowedTypes允许的粘贴类型string[]--
plainTextOnly是否仅粘贴纯文本booleanfalse-

链接配置 (linkConfig)

属性说明类型默认值版本
onClick链接点击回调,返回 false 可阻止默认行为(url?: string) => boolean | void--
openInNewTab是否在新标签页打开链接boolean--

标签输入 (tagInputProps)

属性说明类型默认值版本
enable是否启用标签输入boolean--
placeholder占位符文本string--
type弹出方式'panel' | 'dropdown'--
...支持 TagPopupProps 所有属性TagPopupProps--

插入自动补全 (insertAutocompleteProps)

属性说明类型默认值版本
getContainer获取容器元素() => HTMLElement--
insertOptions插入选项数组InsertAutocompleteItem[]--
optionsRender操作选项渲染(options: ItemType[]) => ItemType[]--
runInsertTask执行插入任务的函数(task: InsertAutocompleteItem, offset: { x: number; y: number }) => Promise<boolean>--

自定义渲染

属性说明类型默认值版本
eleItemRender自定义元素渲染(Slate 模式)(props: RenderElementProps, defaultDom: React.ReactNode) => React.ReactNode--
eleRender自定义元素渲染(仅 renderMode: 'markdown'),返回 undefined 回退默认渲染(props: MarkdownRendererEleProps, defaultDom: React.ReactNode) => React.ReactNode--
leafRender自定义叶子节点渲染(props: Record<string, any> & { children: React.ReactNode }, defaultDom: React.ReactNode) => React.ReactNode--

事件回调

属性说明类型默认值版本
onBlur失焦回调(value: string, schema: Elements[], e: React.MouseEvent<HTMLDivElement, Element>) => void--
onChange内容变化回调(value: string, schema: Elements[]) => void--
onFocus聚焦回调(value: string, schema: Elements[], e: React.FocusEvent<HTMLDivElement, Element>) => void--
onPaste粘贴回调,返回 false 可阻止默认粘贴(e: React.ClipboardEvent<HTMLDivElement>) => boolean | void--
onSelectionChange选区变化回调(selection: Selection | null, selectedMarkdown: string, selectedNodes: Elements[]) => void--

引用与其他

属性说明类型默认值版本
apassifyapaasify 的旧拼写,已废弃,请使用 apaasify{ enable?: boolean; render?: (...) => React.ReactNode }--
anchorProps锚点链接配置AnchorProps--
apaasify低代码渲染配置{ enable?: boolean; render?: (props: RenderElementProps, originData?: MessageBubbleData) => React.ReactNode }--
attachment附件配置Record<string, unknown>--
editorRef编辑器实例引用React.Ref<MarkdownEditorInstance | undefined>--
fileMapConfigFileMapView 配置(仅 renderMode: 'markdown')FileMapConfig--
fncProps脚注配置{ render: (...) => React.ReactNode; onOriginUrlClick?: (url?: string) => void; onFootnoteDefinitionChange?: (data: [...]) => void }--
markdownToHtmlOptions自定义 unified 插件数组,每项为 Plugin 或 [Plugin, ...options],例如 [remarkGfm, [remarkMath, { singleDollarTextMath: false }]]MarkdownToHtmlOptions--
plugins编辑器插件配置any[]--
rootContainer根容器引用React.MutableRefObject<HTMLDivElement | undefined>--
titlePlaceholderContent标题占位符内容;同时作为 comment.placeholder 未指定时的回退值string--
toolbarConfig工具栏配置(另一种方式){ show?: boolean; items?: string[] }--

MarkdownEditorInstance

通过 editorRef 获取编辑器实例,支持以下属性和方法:

属性/方法说明类型默认值版本
exportHtml导出为 HTML 文件(filename?: string) => void--
markdownContainerRefMarkdown 容器 DOM 引用React.MutableRefObject<HTMLDivElement | null>--
markdownEditorRefSlate 编辑器实例引用React.MutableRefObject<BaseEditor & ReactEditor & HistoryEditor>--
range内部使用的选区缓存any--
store编辑器内部状态管理(含 getMDContent / setMDContent 等常用方法)EditorStore--