remons-markdown-editor 1.0.0-beta.13 → 1.0.0-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/App.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare function App(): import("react").JSX.Element;
1
+ declare function App(): import('react').JSX.Element;
2
2
  export default App;
@@ -17,5 +17,5 @@ interface EditDialogProps {
17
17
  * 属性编辑弹窗组件
18
18
  * 根据组件 schema 的 renderDialog 函数渲染弹窗内容
19
19
  */
20
- export default function EditDialog({ visible, typeName, currentProps, onSave, onClose }: EditDialogProps): import("react").JSX.Element | null;
20
+ export default function EditDialog({ visible, typeName, currentProps, onSave, onClose }: EditDialogProps): import('react').JSX.Element | null;
21
21
  export {};
@@ -12,5 +12,5 @@ interface EditorProps {
12
12
  /** 未配置上传时的提示回调 */
13
13
  onMessageNoUploadConfig?: () => void;
14
14
  }
15
- export default function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer, uploadConfig, onMessageNoUploadConfig }: EditorProps): import("react").JSX.Element;
15
+ export default function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer, uploadConfig, onMessageNoUploadConfig }: EditorProps): import('react').JSX.Element;
16
16
  export {};
@@ -9,5 +9,5 @@ interface ToolbarProps {
9
9
  /** 图片上传配置 */
10
10
  uploadConfig?: ImageUploadConfig;
11
11
  }
12
- export default function Toolbar({ editorView, fullscreen, onToggleFullscreen, extraItems, uploadConfig }: ToolbarProps): import("react").JSX.Element;
12
+ export default function Toolbar({ editorView, fullscreen, onToggleFullscreen, extraItems, uploadConfig }: ToolbarProps): import('react').JSX.Element;
13
13
  export {};
@@ -5,5 +5,5 @@ interface TableSize {
5
5
  interface TablePickerProps {
6
6
  onSelect: (size: TableSize) => void;
7
7
  }
8
- export default function TablePicker({ onSelect }: TablePickerProps): import("react").JSX.Element;
8
+ export default function TablePicker({ onSelect }: TablePickerProps): import('react').JSX.Element;
9
9
  export {};
@@ -3,5 +3,5 @@ interface Props {
3
3
  item: ToolbarButtonConfig;
4
4
  onClick: (item: ToolbarButtonConfig) => void;
5
5
  }
6
- export declare function ToolbarItemRenderer({ item, onClick }: Props): import("react").JSX.Element;
6
+ export declare function ToolbarItemRenderer({ item, onClick }: Props): import('react').JSX.Element;
7
7
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/parseContainer.ts","../src/registry/componentRegistry.tsx","../src/components/Editor/containerWidget.ts","../src/components/Toolbar/buttons.tsx","../src/components/Editor/codemirrorExtensions.ts","../src/components/Editor/index.tsx","../src/components/Preview/index.tsx","../src/components/Panel/SplitPanels.tsx","../src/components/Toolbar/config.ts","../src/components/Toolbar/hooks/useToolbar.ts","../src/components/Toolbar/renderers/ToolbarItemRenderer.tsx","../src/components/Toolbar/renderers/TablePicker/index.module.less","../src/components/Toolbar/renderers/TablePicker/index.tsx","../src/components/Toolbar/renderers/TablePicker/TableDropdown.tsx","../src/components/Toolbar/index.tsx","../src/components/Dialog/EditDialog.tsx","../src/utils/writeContainer.ts","../src/hooks/useFullscreen.ts","../src/hooks/useScrollSync.ts","../src/MarkdownEditor.tsx","../src/hooks/useRegisterToolbar.ts"],"sourcesContent":["/**\n * 解析容器属性 JSON 字符串。\n * 支持标准 JSON 和宽松格式: { key: 'value', key2: 'value2' }\n */\nexport function parseContainerProps(jsonStr: string): Record<string, string> {\n try {\n const props: Record<string, string> = {}\n const trimmed = jsonStr.trim()\n if (trimmed.startsWith('{') && trimmed.endsWith('}')) {\n const inner = trimmed.slice(1, -1).trim()\n if (!inner) return props\n // 匹配 key: 'value' 或 key: \"value\" 格式\n const matches = inner.matchAll(/(?:[\"']?)(\\w+)(?:[\"']?)\\s*:\\s*(?:\"([^\"]*)\"|'([^']*)'|(\\d+))/g)\n for (const m of matches) {\n props[m[1]] = m[2] ?? m[3] ?? m[4] ?? ''\n }\n }\n return props\n } catch {\n return {}\n }\n}\n\n/**\n * 在编辑器文档中查找容器块。\n * 返回包含类型、属性和行位置的容器位置数组。\n */\nexport interface ContainerBlock {\n startPos: number // ::: 打开行位置\n typeName: string // 组件类型名称 (如 \"linkCard\")\n propsLineFrom: number // JSON 属性行起始位置\n propsLineTo: number // JSON 属性行结束位置\n props: Record<string, string>\n endPos: number // ::: 关闭行位置\n}\n\nexport function findContainers(\n docText: string\n): ContainerBlock[] {\n const containers: ContainerBlock[] = []\n const lines = docText.split('\\n')\n\n let i = 0\n while (i < lines.length) {\n const line = lines[i]\n const match = line.match(/^:::(\\w+)$/)\n if (match) {\n const typeName = match[1]\n // 计算字符位置\n let charPos = 0\n for (let l = 0; l < i; l++) {\n charPos += lines[l].length + 1 // +1 for newline\n }\n\n // 查找下一行的 JSON 属性\n let props: Record<string, string> = {}\n let propsLineFrom = 0\n let propsLineTo = 0\n let propsLineIndex = i + 1\n\n if (propsLineIndex < lines.length) {\n const propsLine = lines[propsLineIndex].trim()\n const propsMatch = propsLine.match(/^\\{[\\s\\S]*\\}$/)\n if (propsMatch) {\n props = parseContainerProps(propsLine)\n propsLineFrom = charPos + line.length + 1\n propsLineTo = propsLineFrom + lines[propsLineIndex].length\n }\n }\n\n // 查找闭合 :::\n let endPos = 0\n for (let j = i + 1; j < lines.length; j++) {\n if (lines[j].trim() === ':::') {\n let endCharPos = 0\n for (let l = 0; l < j; l++) {\n endCharPos += lines[l].length + 1\n }\n endPos = endCharPos\n i = j + 1\n break\n }\n }\n\n containers.push({\n startPos: charPos,\n typeName,\n propsLineFrom,\n propsLineTo,\n props,\n endPos,\n })\n }\n i++\n }\n\n return containers\n}","import type { ComponentSchema } from '../types'\n\n/**\n * 组件注册中心,用于管理自定义组件的 schema。\n * 每个容器组件(如 :::linkCard)在此注册其可编辑字段。\n */\nclass ComponentRegistry {\n private schemas = new Map<string, ComponentSchema>()\n\n /**\n * 注册组件 schema\n */\n register(name: string, schema: ComponentSchema): void {\n this.schemas.set(name, schema)\n }\n\n /**\n * 根据组件名获取已注册的 schema\n */\n get(name: string): ComponentSchema | undefined {\n return this.schemas.get(name)\n }\n\n /**\n * 检查组件类型是否已注册\n */\n has(name: string): boolean {\n return this.schemas.has(name)\n }\n\n /**\n * 获取所有已注册的组件名\n */\n getAllNames(): string[] {\n return Array.from(this.schemas.keys())\n }\n\n /**\n * 获取所有已注册的 schema\n */\n getAll(): ComponentSchema[] {\n return Array.from(this.schemas.values())\n }\n\n /**\n * 移除组件注册\n */\n unregister(name: string): void {\n this.schemas.delete(name)\n }\n}\n\n// 单例实例\nconst componentRegistry = new ComponentRegistry()\n\nexport default componentRegistry","import { ViewPlugin, Decoration, WidgetType } from '@codemirror/view'\r\nimport type { DecorationSet } from '@codemirror/view'\r\nimport { EditorState, Facet } from '@codemirror/state'\r\nimport { findContainers } from '../../utils/parseContainer'\r\nimport componentRegistry from '../../registry/componentRegistry'\r\n\r\n/**\r\n * 编辑容器属性的回调函数类型\r\n */\r\nexport interface OnEditContainer {\r\n (view: any, typeName: string, propsLineFrom: number, propsLineTo: number, currentProps: Record<string, string>): void\r\n}\r\n\r\n/**\r\n * 自定义 facet 用于传递编辑回调\r\n */\r\nexport const containerEditCallback = Facet.define<any, OnEditContainer>({\r\n combine: (values) => values[0],\r\n})\r\n\r\n/**\r\n * 只读的容器头行 Widget(显示 :::typeName + 编辑按钮)\r\n * 使用 Decoration.replace 替换原始文本,使其不可直接编辑\r\n */\r\nclass ContainerHeaderWidget extends WidgetType {\r\n public typeName: string\r\n\r\n constructor(typeName: string) {\r\n super()\r\n this.typeName = typeName\r\n }\r\n\r\n public toDOM(): HTMLElement {\r\n const container = document.createElement('span')\r\n container.className = 'container-widget-header'\r\n\r\n const text = document.createElement('span')\r\n text.className = 'container-widget-text'\r\n text.textContent = `:::${this.typeName}`\r\n\r\n const button = document.createElement('button')\r\n button.className = 'container-edit-btn'\r\n button.title = `编辑 ${componentRegistry.get(this.typeName)?.label ?? this.typeName}`\r\n button.textContent = '✎'\r\n ;(button as any).__typeName = this.typeName\r\n\r\n container.appendChild(text)\r\n container.appendChild(button)\r\n return container\r\n }\r\n\r\n public eq(other: ContainerHeaderWidget): boolean {\r\n return this.typeName === other.typeName\r\n }\r\n\r\n public ignoreEvent(): boolean {\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * 只读的容器属性行 Widget(显示 { key: value, ... })\r\n * 使用 Decoration.replace 替换原始文本,使其不可直接编辑\r\n */\r\nclass ContainerPropsWidget extends WidgetType {\r\n public propsText: string\r\n\r\n constructor(propsText: string) {\r\n super()\r\n this.propsText = propsText\r\n }\r\n\r\n public toDOM(): HTMLElement {\r\n const span = document.createElement('span')\r\n span.className = 'container-widget-props'\r\n span.textContent = this.propsText\r\n return span\r\n }\r\n\r\n public eq(other: ContainerPropsWidget): boolean {\r\n return this.propsText === other.propsText\r\n }\r\n\r\n public ignoreEvent(): boolean {\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * 只读的容器结束行 Widget(显示 :::)\r\n * 使用 Decoration.replace 替换原始文本,使其不可直接编辑\r\n */\r\nclass ContainerCloseWidget extends WidgetType {\r\n public toDOM(): HTMLElement {\r\n const span = document.createElement('span')\r\n span.className = 'container-widget-text'\r\n span.textContent = ':::'\r\n return span\r\n }\r\n\r\n public eq(): boolean {\r\n return true\r\n }\r\n\r\n public ignoreEvent(): boolean {\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * 查找文档中的容器,创建 Decoration 装饰物\r\n * 将 ::: 头行、{} 属性行和 ::: 结束行替换为只读 widget,使其无法在编辑器中直接编辑\r\n */\r\nfunction findContainerDecorations(state: EditorState): Array<{ from: number; to: number; value: Decoration }> {\r\n const docText = state.doc.toString()\r\n const containers = findContainers(docText)\r\n const decorations: Array<{ from: number; to: number; value: Decoration }> = []\r\n\r\n for (const container of containers) {\r\n const headerLine = state.doc.lineAt(container.startPos)\r\n\r\n // 替换 :::typeName 头行为只读 widget\r\n decorations.push({\r\n from: headerLine.from,\r\n to: headerLine.to,\r\n value: Decoration.replace({\r\n widget: new ContainerHeaderWidget(container.typeName),\r\n }),\r\n })\r\n\r\n // 替换 {} 属性行为只读 widget\r\n if (container.propsLineFrom > 0 && container.propsLineTo > 0) {\r\n const propsLine = state.doc.lineAt(container.propsLineFrom)\r\n const propsText = propsLine.text\r\n\r\n decorations.push({\r\n from: propsLine.from,\r\n to: propsLine.to,\r\n value: Decoration.replace({\r\n widget: new ContainerPropsWidget(propsText),\r\n }),\r\n })\r\n }\r\n\r\n // 替换 ::: 结束行为只读 widget\r\n if (container.endPos > 0) {\r\n const endLine = state.doc.lineAt(container.endPos)\r\n decorations.push({\r\n from: endLine.from,\r\n to: endLine.to,\r\n value: Decoration.replace({\r\n widget: new ContainerCloseWidget(),\r\n }),\r\n })\r\n }\r\n }\r\n\r\n return decorations\r\n}\r\n\r\n/**\r\n * 容器编辑 ViewPlugin\r\n * 将容器的 ::: 头行和 {} 属性行替换为只读 widget,使其无法在编辑器中直接编辑\r\n */\r\nexport const containerWidgetPlugin = ViewPlugin.fromClass(\r\n class {\r\n public decorations: DecorationSet\r\n\r\n constructor(view: any) {\r\n this.decorations = Decoration.set(findContainerDecorations(view.state), true)\r\n }\r\n\r\n public update(update: any) {\r\n if (update.docChanged || update.selectionSet) {\r\n this.decorations = Decoration.set(findContainerDecorations(update.state), true)\r\n }\r\n }\r\n },\r\n {\r\n decorations: (value) => value.decorations,\r\n eventHandlers: {\r\n // 阻止编辑按钮的 mousedown 事件,防止焦点移动\r\n mousedown: (event: MouseEvent, view: any) => {\r\n const target = event.target as HTMLElement\r\n if (target.classList.contains('container-edit-btn')) {\r\n event.preventDefault()\r\n return true\r\n }\r\n return false\r\n },\r\n // 点击编辑按钮时触发回调\r\n click: (event: MouseEvent, view: any) => {\r\n const target = event.target as HTMLElement\r\n if (target.classList.contains('container-edit-btn')) {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n const typeName = (target as any).__typeName\r\n if (typeName) {\r\n const docText = view.state.doc.toString()\r\n const containers = findContainers(docText)\r\n const buttonPos = view.posAtDOM(target)\r\n\r\n // 通过 button 位置匹配最近的容器头行,避免多个同类型容器匹配错误\r\n for (const container of containers) {\r\n const headerLine = view.state.doc.lineAt(container.startPos)\r\n // 按钮位置在头行的范围内(允许一定偏差,因为 widget 替换后位置可能略有偏移)\r\n if (buttonPos >= headerLine.from - 5 && buttonPos <= headerLine.to + 5) {\r\n const callback = view.state.facet(containerEditCallback)\r\n if (callback) {\r\n callback(view, container.typeName, container.propsLineFrom, container.propsLineTo, { ...container.props })\r\n }\r\n return true\r\n }\r\n }\r\n }\r\n return false\r\n }\r\n return false\r\n },\r\n },\r\n }\r\n)","import { EditorView } from '@codemirror/view'\nimport type { ImageUploadConfig } from '../../types'\n\n/**\n * 在光标位置插入文本\n */\nexport function insertAtCursor(view: EditorView, before: string, after: string = '', placeholder: string = ''): void {\n const { from, to } = view.state.selection.main\n const selectedText = view.state.doc.sliceString(from, to)\n const insert = selectedText\n ? `${before}${selectedText}${after}`\n : `${before}${placeholder}${after}`\n view.dispatch({ changes: { from, to, insert } })\n if (!selectedText && placeholder) {\n view.dispatch({ selection: { anchor: from + before.length } })\n }\n}\n\n/**\n * 在当前行行首插入文本\n */\nexport function insertAtLineStart(view: EditorView, text: string): void {\n const { from } = view.state.selection.main\n const line = view.state.doc.lineAt(from)\n view.dispatch({ changes: { from: line.from, to: line.from, insert: text } })\n view.dispatch({ selection: { anchor: line.from + text.length } })\n}\n\n/**\n * 上传图片\n * @param file - 要上传的文件\n * @param uploadConfig - 上传配置\n */\nexport async function uploadFileToServer(\n file: File,\n uploadConfig: ImageUploadConfig\n): Promise<string | null> {\n // 优先使用自定义上传函数\n if (uploadConfig.onUploadImage) {\n return uploadConfig.onUploadImage(file)\n }\n\n // 使用 uploadUrl 上传\n if (uploadConfig.uploadUrl) {\n const formData = new FormData()\n formData.append('file', file)\n\n const response = await fetch(uploadConfig.uploadUrl, {\n method: 'POST',\n body: formData,\n })\n\n if (!response.ok) return null\n\n const result = await response.json()\n \n // 如果外部提供了 URL 提取回调,使用它\n if (uploadConfig.onGetUploadUrl) {\n return uploadConfig.onGetUploadUrl(result)\n }\n \n // 默认行为\n return result.data?.path || null\n }\n\n return null\n}\n\n/**\n * 判断是否配置了图片上传\n */\nexport function isUploadConfigured(\n uploadConfig?: ImageUploadConfig\n): boolean {\n return !!(uploadConfig?.uploadUrl || uploadConfig?.onUploadImage)\n}\n\n/**\n * 图片上传:创建隐藏的 file input 触发选择,上传后插入 markdown 图片语法\n * @param view - CodeMirror 编辑器实例\n * @param uploadConfig - 上传配置(包含 uploadUrl 或 onUploadImage)\n */\nexport function uploadImage(\n view: EditorView,\n uploadConfig: ImageUploadConfig\n): void {\n const input = document.createElement('input')\n input.type = 'file'\n input.accept = 'image/*'\n input.style.display = 'none'\n\n input.addEventListener('change', async () => {\n if (!input.files || input.files.length === 0) return\n\n const file = input.files[0]\n const { from, to } = view.state.selection.main\n const selectedText = view.state.doc.sliceString(from, to) || '描述'\n\n const url = await uploadFileToServer(file, uploadConfig)\n if (url) {\n const insert = `![${selectedText}](${url})`\n view.dispatch({ changes: { from, to, insert } })\n }\n\n input.remove()\n })\n\n document.body.appendChild(input)\n input.click()\n}\n\n/**\n * 用前缀和后缀包裹选中文本\n */\nexport function wrapSelection(view: EditorView, prefix: string, suffix: string): void {\n const { from, to, empty } = view.state.selection.main\n if (empty) return\n const selected = view.state.doc.sliceString(from, to)\n view.dispatch({ changes: { from, to, insert: `${prefix}${selected}${suffix}` } })\n}\n\n/**\n * 切换包裹:选中的文本已包含标签则移除,否则添加\n */\nexport function toggleWrap(\n view: EditorView,\n openTag: string,\n closeTag: string\n): void {\n const { from, to, empty } = view.state.selection.main\n const doc = view.state.doc\n\n // 选区完整包含标签 → 移除\n if (!empty) {\n const selected = doc.sliceString(from, to)\n if (selected.startsWith(openTag) && selected.endsWith(closeTag)) {\n const inner = selected.slice(openTag.length, -closeTag.length)\n view.dispatch({ changes: { from, to, insert: inner } })\n return\n }\n }\n\n // 光标/选区在标签内部 → 查找当前行的标签并移除\n {\n const cursorPos = empty ? from : to\n const line = doc.lineAt(cursorPos)\n const lineText = doc.sliceString(line.from, line.to)\n const openIdx = lineText.indexOf(openTag)\n const closeIdx = lineText.lastIndexOf(closeTag)\n\n if (openIdx >= 0 && closeIdx > openIdx) {\n const absOpen = line.from + openIdx\n const absClose = line.from + closeIdx\n // 确认光标/选区在标签范围内\n if (cursorPos >= absOpen + openTag.length && cursorPos <= absClose) {\n const inner = doc.sliceString(absOpen + openTag.length, absClose)\n view.dispatch({\n changes: {\n from: absOpen,\n to: absClose + closeTag.length,\n insert: inner,\n },\n })\n return\n }\n }\n }\n\n // 默认:添加包裹\n wrapSelection(view, openTag, closeTag)\n}","import { EditorView, keymap } from '@codemirror/view'\r\nimport { defaultKeymap, indentWithTab } from '@codemirror/commands'\r\nimport { markdown } from '@codemirror/lang-markdown'\r\nimport { oneDark } from '@codemirror/theme-one-dark'\r\nimport { Facet } from '@codemirror/state'\r\nimport { containerWidgetPlugin, containerEditCallback } from './containerWidget'\r\nimport type { OnEditContainer } from './containerWidget'\r\nimport { uploadFileToServer, isUploadConfigured } from '../Toolbar/buttons'\r\nimport type { ImageUploadConfig } from '../../types'\r\n\r\n/** 图片上传配置 facet */\r\nconst uploadConfigFacet = Facet.define<ImageUploadConfig | undefined, ImageUploadConfig | undefined>({\r\n combine: (values) => values[values.length - 1],\r\n})\r\n\r\n/** 未配置上传时的提示回调 facet */\r\nconst messageFacet = Facet.define<(() => void) | undefined, (() => void) | undefined>({\r\n combine: (values) => values[values.length - 1],\r\n})\r\n\r\n/** 粘贴事件处理:拦截图片并上传 */\r\nconst pasteHandler = EditorView.domEventHandlers({\r\n paste: (event: ClipboardEvent, view: EditorView) => {\r\n const files = event.clipboardData?.files\r\n if (!files) return false\r\n\r\n const imageFiles = Array.from(files).filter((f) => f.type.startsWith('image/'))\r\n if (imageFiles.length === 0) return false\r\n\r\n event.preventDefault()\r\n\r\n const uploadConfig = view.state.facet(uploadConfigFacet)\r\n const showMessage = view.state.facet(messageFacet)\r\n\r\n if (!isUploadConfigured(uploadConfig)) {\r\n showMessage?.()\r\n return true\r\n }\r\n\r\n // 上传所有粘贴的图片\r\n const { from, to } = view.state.selection.main\r\n let offset = 0\r\n\r\n for (const file of imageFiles) {\r\n uploadFileToServer(file, uploadConfig!).then((url) => {\r\n if (url) {\r\n const name = file.name.replace(/\\.[^.]+$/, '')\r\n const insert = `![${name}](${url})`\r\n view.dispatch({ changes: { from: from + offset, to: to + offset, insert } })\r\n offset += insert.length\r\n }\r\n })\r\n }\r\n\r\n return true\r\n },\r\n})\r\n\r\ninterface GetCodeMirrorExtensionsOptions {\r\n /** 编辑容器属性的回调函数 */\r\n onEditContainer?: OnEditContainer\r\n /** 图片上传配置 */\r\n uploadConfig?: ImageUploadConfig\r\n /** 未配置上传时的提示回调 */\r\n onMessageNoUploadConfig?: () => void\r\n}\r\n\r\nexport const getCodeMirrorExtensions = (opts?: GetCodeMirrorExtensionsOptions) => {\r\n const extensions = [\r\n markdown(),\r\n oneDark,\r\n keymap.of([...defaultKeymap, indentWithTab]),\r\n EditorView.lineWrapping,\r\n pasteHandler,\r\n EditorView.baseTheme({\r\n '.cm-scroller': {\r\n height: '100%',\r\n overflow: 'auto',\r\n },\r\n // 容器头行 Widget 样式\r\n '.container-widget-header': {\r\n display: 'inline',\r\n fontSize: 'inherit',\r\n fontFamily: 'inherit',\r\n },\r\n '.container-widget-text': {\r\n fontWeight: 'bold',\r\n color: '#79c0ff',\r\n },\r\n // 容器属性行 Widget 样式\r\n '.container-widget-props': {\r\n display: 'inline',\r\n fontSize: 'inherit',\r\n fontFamily: 'inherit',\r\n color: '#a5d6ff',\r\n },\r\n // 容器编辑按钮样式\r\n '.container-edit-btn': {\r\n display: 'inline-block',\r\n padding: '0 4px',\r\n fontSize: '12px',\r\n color: '#58a6ff',\r\n background: 'transparent',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n marginRight: '4px',\r\n verticalAlign: 'middle',\r\n },\r\n '.container-edit-btn:hover': {\r\n background: 'rgba(88, 166, 255, 0.16)',\r\n },\r\n }),\r\n ]\r\n\r\n // 添加容器 widget 插件\r\n extensions.push(containerWidgetPlugin)\r\n\r\n // 如果有编辑回调,注册 facet\r\n if (opts?.onEditContainer) {\r\n extensions.push(containerEditCallback.of(opts.onEditContainer))\r\n }\r\n\r\n // 如果有图片上传配置,注册 facet\r\n if (opts?.uploadConfig) {\r\n extensions.push(uploadConfigFacet.of(opts.uploadConfig))\r\n }\r\n\r\n // 如果有消息回调,注册 facet\r\n if (opts?.onMessageNoUploadConfig) {\r\n extensions.push(messageFacet.of(opts.onMessageNoUploadConfig))\r\n }\r\n\r\n return extensions\r\n}\r\n\r\nexport default getCodeMirrorExtensions","import { useEffect, useRef } from 'react'\nimport { EditorView, basicSetup } from 'codemirror'\nimport { EditorState } from '@codemirror/state'\nimport { getCodeMirrorExtensions } from './codemirrorExtensions'\nimport type { ImageUploadConfig } from '../../types'\n\ninterface EditorProps {\n value: string\n onChange: (value: string) => void\n onScrollReady?: (scrollDOM: HTMLElement) => void\n onViewReady?: (view: EditorView) => void\n /** 编辑容器属性的回调 */\n onEditContainer?: (view: any, typeName: string, propsLineFrom: number, propsLineTo: number, currentProps: Record<string, string>) => void\n /** 图片上传配置 */\n uploadConfig?: ImageUploadConfig\n /** 未配置上传时的提示回调 */\n onMessageNoUploadConfig?: () => void\n}\n\nexport default function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer, uploadConfig, onMessageNoUploadConfig }: EditorProps) {\n const editorRef = useRef<HTMLDivElement>(null)\n const viewRef = useRef<EditorView | null>(null)\n\n useEffect(() => {\n if (!editorRef.current) return\n\n const extensions = [\n basicSetup,\n ...getCodeMirrorExtensions({ onEditContainer, uploadConfig, onMessageNoUploadConfig }),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n onChange(update.state.doc.toString())\n }\n }),\n ]\n\n const state = EditorState.create({\n doc: value,\n extensions,\n })\n\n viewRef.current = new EditorView({\n state,\n parent: editorRef.current,\n })\n\n if (onScrollReady && viewRef.current) {\n onScrollReady(viewRef.current.scrollDOM)\n }\n\n if (onViewReady) {\n onViewReady(viewRef.current)\n }\n\n return () => {\n viewRef.current?.destroy()\n }\n }, [])\n\n // 外部 value 变化时更新编辑器内容\n useEffect(() => {\n if (viewRef.current && viewRef.current.state.doc.toString() !== value) {\n viewRef.current.dispatch({\n changes: { from: 0, to: viewRef.current.state.doc.length, insert: value },\n })\n }\n }, [value])\n\n return <div ref={editorRef} className=\"editor\" />\n}","import { forwardRef, useEffect } from 'react'\nimport RenderMarkdown, { languagesCommon, initHighlighter } from 'remons-render-markdown';\nimport type { RenderMarkdownProps } from 'remons-render-markdown';\nimport 'remons-render-markdown/dist/index.css';\n\nexport type PreviewOptions = Omit<RenderMarkdownProps, 'content'> & {\n languages?: Record<string, any> | null | undefined\n}\n\nexport interface PreviewProps {\n content: string\n previewOptions?: PreviewOptions\n}\n\n\nconst Preview = forwardRef<HTMLDivElement, PreviewProps>(({ content, previewOptions }, ref) => {\n useEffect(() => {\n initHighlighter({\n ...languagesCommon,\n ...(previewOptions?.languages ? previewOptions?.languages : {})\n })\n }, [previewOptions?.languages])\n\n return (\n <div ref={ref} className=\"preview\">\n <RenderMarkdown content={content} {...previewOptions} />\n </div>\n )\n})\n\nPreview.displayName = 'Preview'\n\nexport default Preview","import React from 'react'\nimport { Splitter } from 'antd'\n\nconst { Panel } = Splitter\n\ninterface SplitPanelsProps {\n leftPanel: React.ReactNode\n rightPanel: React.ReactNode\n}\n\nexport default function SplitPanels({ leftPanel, rightPanel }: SplitPanelsProps) {\n return (\n <Splitter className=\"split-panels\">\n <Panel defaultSize=\"50%\" min=\"20%\" max=\"80%\">\n {leftPanel}\n </Panel>\n <Panel>{rightPanel}</Panel>\n </Splitter>\n )\n}","import type { ToolbarButtonConfig, ImageUploadConfig } from '../../types'\nimport {\n BoldOutlined,\n ItalicOutlined,\n StrikethroughOutlined,\n UnderlineOutlined,\n UnorderedListOutlined,\n OrderedListOutlined,\n LinkOutlined,\n PictureOutlined,\n CodeOutlined,\n BlockOutlined,\n MinusOutlined,\n FieldStringOutlined,\n FontSizeOutlined,\n} from '@ant-design/icons'\nimport { insertAtCursor, insertAtLineStart, wrapSelection, uploadImage, isUploadConfigured } from './buttons'\n\n/**\n * 创建工具栏配置\n * @param options - 配置选项\n */\nexport function createToolbarConfig(options?: ImageUploadConfig): ToolbarButtonConfig[] {\n // 判断是否配置了图片上传\n const hasUploadConfig = isUploadConfigured(options)\n return [\n {\n id: 'heading',\n icon: FontSizeOutlined,\n label: '标题',\n children: [\n { id: 'heading1', label: '标题 1', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '# ') },\n { id: 'heading2', label: '标题 2', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '## ') },\n { id: 'heading3', label: '标题 3', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '### ') },\n { id: 'heading4', label: '标题 4', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '#### ') },\n { id: 'heading5', label: '标题 5', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '##### ') },\n { id: 'heading6', label: '标题 6', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '###### ') },\n ],\n },\n { separatorBefore: true },\n { id: 'bold', label: '加粗', icon: BoldOutlined, handler: (v) => wrapSelection(v, '**', '**') },\n { id: 'italic', label: '斜体', icon: ItalicOutlined, handler: (v) => wrapSelection(v, '*', '*') },\n { id: 'strikethrough', label: '删除线', icon: StrikethroughOutlined, handler: (v) => wrapSelection(v, '~~', '~~') },\n { id: 'underline', label: '下划线', icon: UnderlineOutlined, handler: (v) => wrapSelection(v, '<u>', '</u>') },\n { separatorBefore: true },\n { id: 'ul', label: '无序列表', icon: UnorderedListOutlined, handler: (v) => insertAtLineStart(v, '- ') },\n { id: 'ol', label: '有序列表', icon: OrderedListOutlined, handler: (v) => insertAtLineStart(v, '1. ') },\n { separatorBefore: true },\n { id: 'link', label: '链接', icon: LinkOutlined, handler: (v) => insertAtCursor(v, '[', '](url)', '文本') },\n // 图片按钮:未配置上传时禁用并提示\n {\n id: 'image',\n label: hasUploadConfig ? '图片' : '请配置图片上传地址',\n icon: PictureOutlined,\n disabled: !hasUploadConfig,\n handler: hasUploadConfig ? (v) => uploadImage(v, { uploadUrl: options?.uploadUrl, onUploadImage: options?.onUploadImage }) : undefined,\n },\n { separatorBefore: true },\n { id: 'code', label: '行内代码', icon: FieldStringOutlined, handler: (v) => wrapSelection(v, '`', '`') },\n {\n id: 'codeblock',\n label: '代码块',\n icon: CodeOutlined,\n handler: (v) => {\n const { from, to } = v.state.selection.main\n const selected = v.state.doc.sliceString(from, to)\n const insert = selected ? '```\\n' + selected + '\\n```' : '```\\n\\n```'\n v.dispatch({ changes: { from, to, insert } })\n },\n },\n { id: 'quote', label: '引用', icon: BlockOutlined, handler: (v) => insertAtLineStart(v, '> ') },\n {\n id: 'hr',\n label: '分割线',\n icon: MinusOutlined,\n handler: (v) => {\n const { from } = v.state.selection.main\n v.dispatch({ changes: { from, insert: '\\n---\\n' } })\n },\n },\n ]\n}","import { useCallback, useMemo } from 'react'\nimport type { EditorView } from '@codemirror/view'\nimport type { ToolbarButtonConfig, ImageUploadConfig } from '../../../types'\nimport { createToolbarConfig } from '../config'\nimport { toggleWrap } from '../buttons'\n\nexport interface UseToolbarOptions {\n /** 第三方扩展的按钮配置,将追加到工具栏末尾 */\n extraItems?: ToolbarButtonConfig[]\n /** 图片上传配置 */\n uploadConfig?: ImageUploadConfig\n}\n\nexport interface UseToolbarReturn {\n config: ToolbarButtonConfig[]\n extraItemsConfig: ToolbarButtonConfig[]\n handleClick: (button: ToolbarButtonConfig) => void\n}\n\nexport function useToolbar(\n editorView: EditorView | null,\n options?: UseToolbarOptions\n): UseToolbarReturn {\n const { extraItems, uploadConfig } = options || {}\n const config = useMemo(() => {\n const base = createToolbarConfig(uploadConfig)\n return base\n }, [uploadConfig])\n\n const extraItemsConfig = useMemo(() => {\n return extraItems || []\n }, [extraItems])\n\n const handleClick = useCallback((button: ToolbarButtonConfig) => {\n if (!editorView) return\n\n // 如果配置了 wrapTags,优先使用 toggleWrap\n if (button.wrapTags) {\n const [openTag, closeTag] = button.wrapTags\n toggleWrap(editorView, openTag, closeTag)\n return\n }\n\n // 有 handler 则执行自定义逻辑\n if (button.handler) {\n editorView.focus()\n button.handler(editorView, editorView.state)\n }\n }, [editorView])\n\n return { config, extraItemsConfig, handleClick }\n}","import { Button, Dropdown, Tooltip } from 'antd'\nimport { DownOutlined } from '@ant-design/icons'\nimport type { ToolbarButtonConfig } from '../../../types'\n\ninterface Props {\n item: ToolbarButtonConfig\n onClick: (item: ToolbarButtonConfig) => void\n}\n\nexport function ToolbarItemRenderer({ item, onClick }: Props) {\n const Icon = item.icon!\n\n // 有 children 的渲染为下拉菜单\n if (item.children && item.children.length > 0) {\n return (\n <>\n {item.separatorBefore && <div className=\"toolbar-separator\" />}\n <div className=\"toolbar-group\">\n <Tooltip title={item.label}>\n <Dropdown\n menu={{\n items: item.children.map(child => ({\n type: 'item',\n key: child.id ?? '',\n label: (\n <span onClick={() => onClick(child)}>\n {child.icon && (() => { const ChildIcon = child.icon; return <ChildIcon />; })()}\n {' '}{child.label}\n </span>\n ),\n })),\n }}\n placement=\"bottomLeft\"\n >\n <Button className=\"toolbar-button\" type=\"text\" size=\"small\">\n <Icon />\n <DownOutlined style={{ marginLeft: 2, fontSize: 10 }} />\n </Button>\n </Dropdown>\n </Tooltip>\n </div>\n </>\n )\n }\n\n // 普通按钮\n const isDisabled = item.disabled\n return (\n <>\n {item.separatorBefore && <div className=\"toolbar-separator\" />}\n <div className=\"toolbar-group\">\n <Tooltip title={item.label}>\n <Button\n id={item.id}\n className=\"toolbar-button\"\n type=\"text\"\n size=\"small\"\n disabled={isDisabled}\n onClick={() => !isDisabled && onClick(item)}\n >\n <Icon />\n </Button>\n </Tooltip>\n </div>\n </>\n )\n}",".container {\n padding: 4px;\n display: block;\n min-width: 200px;\n background: var(--remons-md-editor-bg-picker);\n border: 1px solid var(--remons-md-editor-color-border-light);\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n\n.grid {\n display: grid;\n gap: 2px;\n transition: all 0.1s ease;\n justify-content: flex-start;\n\n .cell {\n width: 24px;\n height: 24px;\n border: 1px solid var(--remons-md-editor-color-border-light);\n border-radius: 2px;\n background: transparent;\n cursor: pointer;\n transition: all 0.1s ease;\n\n &.cellActive {\n border-color: var(--remons-md-editor-color-cell-active);\n background: var(--remons-md-editor-bg-cell-active);\n }\n }\n}\n\n.hint {\n padding: 12px 16px;\n color: var(--remons-md-editor-color-hint);\n font-size: 12px;\n text-align: center;\n cursor: pointer;\n}\n\n.label {\n margin-top: 8px;\n font-size: 13px;\n color: var(--remons-md-editor-color-label);\n font-weight: 500;\n min-height: 20px;\n text-align: center;\n}\n","import { useState, useRef, useEffect, useCallback } from 'react'\nimport styles from './index.module.less'\n\ninterface TableSize {\n rows: number\n cols: number\n}\n\ninterface TablePickerProps {\n onSelect: (size: TableSize) => void\n}\n\nconst MAX_ROW = 8\nconst MAX_COL = 8\n\nexport default function TablePicker({ onSelect }: TablePickerProps) {\n const [hoverSize, setHoverSize] = useState({ row: 0, col: 0 })\n const [confirmedSize, setConfirmedSize] = useState({ row: 0, col: 0 })\n const maxColRef = useRef(0)\n const prevRowRef = useRef(0)\n const timerIdRef = useRef<any>(null)\n const refreshTimerRef = useRef<any>(null)\n const commitRef = useRef<{ cols: number; rows: number } | null>(null)\n\n const clearTimer = useCallback(() => {\n if (timerIdRef.current) {\n clearTimeout(timerIdRef.current)\n timerIdRef.current = null\n }\n }, [])\n\n const clearFlash = useCallback(() => {\n if (refreshTimerRef.current) {\n clearInterval(refreshTimerRef.current)\n refreshTimerRef.current = null\n }\n }, [])\n\n useEffect(\n () => () => {\n // 组件卸载时清理定时器\n if (timerIdRef.current) clearTimeout(timerIdRef.current)\n if (refreshTimerRef.current) clearInterval(refreshTimerRef.current)\n },\n []\n )\n\n /**\n * 扩展选中区域至 (col, row)\n */\n function extend(col: number, row: number) {\n if (row < prevRowRef.current || col < maxColRef.current) {\n // 鼠标回撤(向上或向左),重置列跟踪\n maxColRef.current = 0\n }\n if (col > maxColRef.current) {\n maxColRef.current = col\n }\n setHoverSize({ row, col })\n setConfirmedSize({ row, col: maxColRef.current })\n\n if (row === 1) {\n commitRef.current = { cols: maxColRef.current, rows: 1 }\n }\n }\n\n /**\n * 跳跃动画效果\n */\n function flash(\n col: number,\n dir: 1 | -1,\n limit: number,\n finalCallback: (finalCol: number, finalRow: number) => void\n ) {\n let current = dir === 1 ? 1 : limit\n const step = dir === 1 ? 1 : -1\n\n refreshTimerRef.current = setInterval(() => {\n setHoverSize({ row: current, col })\n if (current > confirmedSize.row || dir === -1) {\n maxColRef.current = Math.min(MAX_COL, col)\n }\n current += step\n if ((dir === 1 && current > limit) || (dir === -1 && current < 1)) {\n clearInterval(refreshTimerRef.current)\n refreshTimerRef.current = null\n const finalRow = current - step\n setHoverSize({ row: finalRow, col })\n finalCallback(col, finalRow)\n }\n }, 50)\n }\n\n /**\n * 核心逻辑:鼠标进入格子\n */\n function onCellEnterCheck(index: number) {\n clearTimer()\n clearFlash()\n const row = Math.floor(index / MAX_COL) + 1\n const col = (index % MAX_COL) + 1\n\n const prevRow = prevRowRef.current\n const isJump = Math.abs(row - prevRow) > 1\n const isDown = row > prevRow\n prevRowRef.current = row\n\n if (!isJump) {\n // 正常悬停:相邻行或同一行\n extend(col, row)\n } else if (isDown) {\n // 快速向下跳跃\n if (col > maxColRef.current || maxColRef.current >= MAX_COL) {\n const finalRow = Math.min(row, MAX_ROW)\n flash(col, 1, finalRow, (c, r) => {\n setConfirmedSize({ row: r, col: c })\n })\n } else {\n extend(col, row)\n }\n } else {\n // 快速向上跳跃:重置列跟踪并播放动画\n maxColRef.current = 0\n flash(col, -1, row, (c, r) => {\n setConfirmedSize({ row: r, col: c })\n if (r === 1) {\n commitRef.current = { cols: Math.min(MAX_COL, col), rows: 1 }\n setConfirmedSize({ row: 1, col: Math.min(MAX_COL, col) })\n }\n })\n }\n }\n\n function onMouseDown() {\n const size = commitRef.current || { cols: maxColRef.current, rows: confirmedSize.row }\n if (size.rows > 0 && size.cols > 0) {\n onSelect(size)\n }\n }\n\n return (\n <div\n className={styles.container}\n onMouseDown={onMouseDown}\n >\n <div\n className={styles.grid}\n style={{ gridTemplateColumns: `repeat(${MAX_COL}, 24px)` }}\n >\n {Array.from({ length: MAX_ROW * MAX_COL }).map((_, i) => {\n const row = Math.floor(i / MAX_COL) + 1\n const col = (i % MAX_COL) + 1\n const isSelected = row <= hoverSize.row && col <= maxColRef.current\n return (\n <div\n key={i}\n className={`${styles.cell} ${isSelected ? styles.cellActive : ''}`}\n onMouseEnter={() => onCellEnterCheck(i)}\n />\n )\n })}\n </div>\n <div className={styles.label}>\n {hoverSize.row} x {maxColRef.current || 1}\n </div>\n </div>\n )\n}\n","import React, { useCallback, useRef } from 'react'\nimport { EditorView } from '@codemirror/view'\nimport { Button, Dropdown } from 'antd'\nimport { TableOutlined } from '@ant-design/icons'\nimport TablePicker from './index'\n\nexport default function TableDropdown({ editorView }: { editorView: EditorView | null }) {\n const [open, setOpen] = React.useState(false)\n const openCountRef = useRef(0)\n\n const handleTableSelect = useCallback((rows: number, cols: number) => {\n if (!editorView || rows <= 0 || cols <= 0) return\n editorView.focus()\n const headerCells = Array(cols).fill(null).map((_, i) => ` 列${i + 1} `).join('|')\n const separator = Array(cols).fill(' --- ').join('|')\n const dataCell = Array(cols).fill(' 内容 ').join('|')\n const dataRows = Array(rows).fill(`|${dataCell}|`).join('\\n')\n const table = `\\n|${headerCells}|\\n|${separator}|\\n${dataRows}\\n`\n const { from } = editorView.state.selection.main\n editorView.dispatch({ changes: { from, insert: table } })\n }, [editorView])\n\n return (\n <Dropdown\n trigger={['click']}\n open={open}\n onOpenChange={setOpen}\n popupRender={() => {\n openCountRef.current++\n return (\n <div style={{ padding: 4 }} onClick={(e) => e.stopPropagation()}>\n <TablePicker\n key={openCountRef.current}\n onSelect={(size) => {\n handleTableSelect(size.rows, size.cols)\n setOpen(false)\n }}\n />\n </div>\n )\n }}\n placement=\"bottomLeft\"\n >\n <Button className=\"toolbar-button\" type=\"text\" size=\"small\" title=\"表格\">\n <TableOutlined />\n </Button>\n </Dropdown>\n )\n}","import { useCallback } from 'react'\nimport { EditorView } from '@codemirror/view'\nimport { Button } from 'antd'\nimport { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons'\nimport { useToolbar } from './hooks/useToolbar'\nimport { ToolbarItemRenderer } from './renderers/ToolbarItemRenderer'\nimport TableDropdown from './renderers/TablePicker/TableDropdown'\nimport type { ToolbarButtonConfig, ImageUploadConfig } from '../../types'\n\ninterface ToolbarProps {\n editorView: EditorView | null\n fullscreen?: boolean\n onToggleFullscreen?: () => void\n /** 第三方扩展的按钮配置,将追加到工具栏末尾 */\n extraItems?: ToolbarButtonConfig[]\n /** 图片上传配置 */\n uploadConfig?: ImageUploadConfig\n}\n\nexport default function Toolbar({ editorView, fullscreen = true, onToggleFullscreen, extraItems, uploadConfig }: ToolbarProps) {\n const { config, extraItemsConfig, handleClick } = useToolbar(editorView, { extraItems, uploadConfig })\n\n const renderFullscreen = useCallback(() => {\n if (!onToggleFullscreen) return null\n const Icon = fullscreen ? FullscreenExitOutlined : FullscreenOutlined\n return (\n <Button\n className=\"toolbar-button\"\n type=\"text\"\n size=\"small\"\n title={fullscreen ? '退出全屏' : '全屏'}\n onClick={() => {\n onToggleFullscreen()\n }}\n >\n <Icon />\n </Button>\n )\n }, [fullscreen, onToggleFullscreen])\n\n function isSeparator(item: ToolbarButtonConfig): boolean {\n return !!(!item.id && item.separatorBefore)\n }\n\n return (\n <div className=\"toolbar\">\n {config.map((item, idx) => {\n if (isSeparator(item)) {\n return <div key={`sep-${idx}`} className=\"toolbar-separator\" />\n }\n return (\n <ToolbarItemRenderer\n key={item.id}\n item={item}\n onClick={handleClick}\n />\n )\n })}\n <TableDropdown editorView={editorView} />\n {extraItemsConfig?.map((item, idx) => {\n if (isSeparator(item)) {\n return <div key={`extra-sep-${idx}`} className=\"toolbar-separator\" />\n }\n return (\n <ToolbarItemRenderer\n key={item.id}\n item={item}\n onClick={handleClick}\n />\n )\n })}\n {renderFullscreen()}\n </div>\n )\n}","import { useState, useMemo, useEffect, type FC } from 'react'\nimport { Modal, Form, Input, InputNumber, Select, Switch, Slider, Rate, DatePicker, ColorPicker } from 'antd'\nimport type { FormInstance, FormItemProps } from 'antd'\nimport componentRegistry from '../../registry/componentRegistry'\nimport type { DialogField } from '../../types'\n\n/**\n * 组件类型到 antd 表单组件的映射\n */\nconst FormComponents: Record<string, FC<any>> = {\n input: Input,\n textarea: Input.TextArea,\n number: InputNumber,\n select: Select,\n switch: Switch,\n slider: Slider,\n rate: Rate,\n color: ColorPicker,\n date: DatePicker,\n dateRange: DatePicker.RangePicker,\n}\n\n/**\n * 渲染对应类型的 antd 表单组件\n */\nfunction renderFormItemComponent(field: DialogField) {\n const props = field.componentProps || {}\n const Component = field.componentType ? FormComponents[field.componentType] : Input\n return <Component {...props} />\n}\n\n/**\n * 根据 fields 自动生成 Form.Item 列表\n */\nfunction renderAutoForm(form: FormInstance, fields: DialogField[]) {\n if (!fields || fields.length === 0) {\n return null\n }\n\n return (\n <Form form={form} layout=\"vertical\">\n {fields.map(field => {\n if (!field.componentType) {\n return null\n }\n\n const formItemProps: FormItemProps = {\n name: field.key,\n label: field.name || field.key,\n valuePropName: field.componentType === 'switch' ? 'checked' : undefined,\n ...field.componentProps,\n }\n\n return (\n <Form.Item key={field.key} {...formItemProps}>\n {renderFormItemComponent(field)}\n </Form.Item>\n )\n })}\n </Form>\n )\n}\n\n/**\n * 弹窗编辑容器属性的组件\n */\ninterface EditDialogProps {\n /** 弹窗是否显示 */\n visible: boolean\n /** 容器类型名称 */\n typeName: string\n /** 当前属性值 */\n currentProps: Record<string, string>\n /** 保存回调 */\n onSave: (props: Record<string, string>) => void\n /** 关闭回调 */\n onClose: () => void\n}\n\n/**\n * 属性编辑弹窗组件\n * 根据组件 schema 的 renderDialog 函数渲染弹窗内容\n */\nexport default function EditDialog({ visible, typeName, currentProps, onSave, onClose }: EditDialogProps) {\n const schema = componentRegistry.get(typeName)\n const [formProps, setFormProps] = useState<Record<string, string>>({})\n const [form] = Form.useForm()\n\n // 当弹窗打开时,初始化表单值\n const mergedProps = useMemo(() => {\n if (!schema) return currentProps\n const defaults: Record<string, string> = {}\n for (const field of schema.fields || []) {\n defaults[field.key] = field.defaultValue ?? ''\n }\n return { ...defaults, ...currentProps }\n }, [schema, currentProps])\n\n // 弹窗打开时设置表单值\n useEffect(() => {\n if (visible) {\n form.setFieldsValue(mergedProps)\n setFormProps({})\n }\n }, [visible, mergedProps, form])\n\n const handleDialogChange = (key: string, value: string) => {\n setFormProps(prev => ({ ...prev, [key]: value }))\n }\n\n const handleOk = async () => {\n let finalProps: Record<string, any> = visible ? { ...mergedProps, ...formProps } : mergedProps\n\n // 尝试从 Form 获取值(如果用户使用了 Form.Item 或自动表单)\n try {\n const formValues = await form.validateFields()\n finalProps = { ...finalProps, ...formValues }\n } catch {\n // 用户没有使用 Form.Item,使用原有的逻辑\n }\n\n onSave(finalProps)\n }\n\n const handleClose = () => {\n setFormProps({})\n onClose()\n }\n\n if (!schema) {\n return null\n }\n\n // 构建 context 对象,供 renderDialog 使用\n const context = {\n props: mergedProps,\n form,\n onChange: handleDialogChange,\n onSave,\n }\n\n // 渲染策略:\n // 1. 如果有 renderDialog,使用自定义渲染\n // 2. 否则如果 fields 中有 componentType,自动生成表单\n // 3. 否则不渲染任何内容\n const renderDialogContent = () => {\n if (schema.renderDialog) {\n return schema.renderDialog(context)\n }\n // 检查是否有字段配置了 componentType\n const hasComponentType = schema.fields?.some(f => f.componentType)\n if (hasComponentType && schema.fields) {\n return renderAutoForm(form, schema.fields)\n }\n return null\n }\n\n return (\n <Modal\n title={`${schema.label} 属性编辑`}\n open={visible}\n onOk={handleOk}\n onCancel={handleClose}\n okText=\"保存\"\n cancelText=\"取消\"\n >\n {renderDialogContent()}\n </Modal>\n )\n}","import type { EditorView } from '@codemirror/view'\n\n/**\n * 从属性对象生成 JSON 属性行。\n * 格式: { key: 'value', key2: 'value2' }\n */\nexport function writeContainerProps(props: Record<string, string>): string {\n const entries = Object.entries(props)\n .map(([k, v]) => `${k}: '${v}'`)\n .join(', ')\n return entries ? `{ ${entries} }` : '{}'\n}\n\n/**\n * 更新编辑器文档中的容器属性。\n * 替换 JSON 属性行(::: 打开行之后的一行)为新属性。\n */\nexport function updateContainerProps(\n view: EditorView,\n propsLineFrom: number,\n propsLineTo: number,\n newProps: Record<string, string>\n): void {\n const newPropsLine = writeContainerProps(newProps)\n view.dispatch({\n changes: {\n from: propsLineFrom,\n to: propsLineTo,\n insert: newPropsLine,\n },\n })\n}\n\n/**\n * 在当前光标位置插入新容器。\n * 创建 :::type 打开行 + JSON 属性 + ::: 关闭行的结构。\n */\nexport function insertContainer(\n view: EditorView,\n typeName: string,\n defaultProps: Record<string, string>\n): void {\n const { from } = view.state.selection.main\n const propsLine = writeContainerProps(defaultProps)\n const container = `:::${typeName}\\n${propsLine}\\n:::\\n`\n view.dispatch({ changes: { from, insert: container } })\n}","import { useState, useEffect, useCallback } from 'react'\n\nexport function useFullscreen() {\n const [fullscreen, setFullscreen] = useState(false)\n\n const toggleFullscreen = useCallback(() => {\n if (document.fullscreenElement) {\n document.exitFullscreen().catch((e) => {\n console.error('退出全屏失败:', e)\n })\n } else {\n const el = document.documentElement\n const requestMethod = el.requestFullscreen ||\n (el as any).webkitRequestFullscreen ||\n (el as any).mozRequestFullScreen ||\n (el as any).msRequestFullscreen\n if (requestMethod) {\n requestMethod.call(el).catch((e) => {\n console.error('进入全屏失败:', e)\n })\n }\n }\n }, [])\n\n useEffect(() => {\n const handleFullscreenChange = () => {\n setFullscreen(!!document.fullscreenElement)\n }\n document.addEventListener('fullscreenchange', handleFullscreenChange)\n document.addEventListener('webkitfullscreenchange', handleFullscreenChange)\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange)\n document.removeEventListener('webkitfullscreenchange', handleFullscreenChange)\n }\n }, [])\n\n return { fullscreen, toggleFullscreen }\n}\n","import { useEffect, useRef } from 'react'\n\n/**\n * 双向滚动同步 Hook\n * 编辑器与预览区互相同步滚动位置(基于比例)\n * 使用 síncing 锁防止双向循环触发\n */\nexport function useScrollSync(\n sourceRef: React.RefObject<HTMLElement | null>,\n targetRef: React.RefObject<HTMLDivElement | null>\n) {\n const rafIdRef = useRef<number | null>(null)\n // 锁:'source' 表示正在同步 source→target,'target' 表示反向\n const syncingRef = useRef<'source' | 'target' | null>(null)\n\n const syncScroll = (\n from: 'source' | 'target',\n fromEl: HTMLElement,\n toEl: HTMLElement\n ) => {\n if (rafIdRef.current) return\n rafIdRef.current = requestAnimationFrame(() => {\n const fromScrollHeight = fromEl.scrollHeight - fromEl.clientHeight\n if (fromScrollHeight <= 0) { rafIdRef.current = null; syncingRef.current = null; return }\n const ratio = fromEl.scrollTop / fromScrollHeight\n const toScrollHeight = toEl.scrollHeight - toEl.clientHeight\n if (toScrollHeight > 0) {\n syncingRef.current = from // 加锁\n toEl.scrollTop = ratio * toScrollHeight\n // 下一帧解锁,让对面的 listener 可以响应新的一次滚动\n requestAnimationFrame(() => { syncingRef.current = null })\n }\n rafIdRef.current = null\n })\n }\n\n useEffect(() => {\n const source = sourceRef.current\n const target = targetRef.current\n if (!source || !target) return\n\n const onSourceScroll = () => {\n if (syncingRef.current !== null) return // 锁住,正在被反向同步\n const s = sourceRef.current!\n const t = targetRef.current!\n syncScroll('source', s, t)\n }\n\n const onTargetScroll = () => {\n if (syncingRef.current !== null) return // 锁住,正在被正向同步\n const s = sourceRef.current!\n const t = targetRef.current!\n syncScroll('target', t, s)\n }\n\n source.addEventListener('scroll', onSourceScroll, { passive: true })\n target.addEventListener('scroll', onTargetScroll, { passive: true })\n\n return () => {\n source.removeEventListener('scroll', onSourceScroll)\n target.removeEventListener('scroll', onTargetScroll)\n if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current)\n }\n }, [sourceRef, targetRef])\n}\n","import { useState, useRef, useCallback, useEffect, forwardRef, useImperativeHandle } from 'react'\nimport { message } from 'antd'\nimport Editor from './components/Editor'\nimport Preview from './components/Preview'\nimport SplitPanels from './components/Panel/SplitPanels'\nimport Toolbar from './components/Toolbar'\nimport EditDialog from './components/Dialog/EditDialog'\nimport componentRegistry from './registry/componentRegistry'\nimport { updateContainerProps, insertContainer } from './utils/writeContainer'\nimport type { ToolbarButtonConfig, ImageUploadConfig } from './types'\nimport type { PreviewOptions } from './components/Preview'\nimport { ReadOutlined } from '@ant-design/icons'\nimport { useFullscreen } from './hooks/useFullscreen'\nimport { useScrollSync } from './hooks/useScrollSync'\n\nexport interface MarkdownEditorRef {\n getContent: () => string\n}\n\nexport interface MarkdownEditorProps {\n /** 初始内容 */\n defaultValue?: string\n /** 受控内容 */\n value?: string\n /** 内容变化回调 */\n onChange?: (value: string) => void\n /** 是否显示预览面板 */\n showPreview?: boolean\n /** 是否支持全屏 */\n fullscreen?: boolean\n /** Preview 渲染配置 */\n previewOptions?: PreviewOptions\n /** 图片上传配置 */\n uploadConfig?: ImageUploadConfig\n}\n\nexport default forwardRef<MarkdownEditorRef, MarkdownEditorProps>(function MarkdownEditor({\n defaultValue = '',\n value,\n onChange,\n showPreview = true,\n fullscreen: fullscreenProp = true,\n previewOptions,\n uploadConfig,\n}, ref) {\n const [content, setContent] = useState(value ?? defaultValue)\n const [editorView, setEditorView] = useState<any>(null)\n const scrollDOMRef = useRef<HTMLElement | null>(null)\n const previewElRef = useRef<HTMLDivElement | null>(null)\n const { fullscreen, toggleFullscreen } = useFullscreen()\n useScrollSync(scrollDOMRef, previewElRef)\n\n // 容器编辑弹窗状态\n const [dialogVisible, setDialogVisible] = useState(false)\n const [dialogTypeName, setDialogTypeName] = useState('')\n const [dialogProps, setDialogProps] = useState<Record<string, string>>({})\n const [dialogPropsRange, setDialogPropsRange] = useState<[number, number]>([0, 0])\n\n // 受控模式:外部 value 变化时同步\n useEffect(() => {\n if (value !== undefined) {\n setContent(value)\n }\n }, [value])\n\n const internalSetContent = useCallback((newContent: string) => {\n setContent(newContent)\n onChange?.(newContent)\n }, [onChange])\n\n // 暴露 getContent 方法\n useImperativeHandle(ref, () => ({\n getContent: () => content,\n }), [content])\n\n // 从注册中心自动生成工具栏按钮\n const extraToolbarItems: ToolbarButtonConfig[] = componentRegistry.getAll().flatMap(schema => {\n // 支持 wrapTags 的标签包裹模式\n if (schema.wrapTags) {\n return {\n id: `wrap-${schema.name}`,\n label: schema.label,\n icon: () => (schema.icon ?? <ReadOutlined />),\n wrapTags: schema.wrapTags,\n }\n }\n // 容器插入模式\n const defaultProps: Record<string, string> = {}\n for (const field of schema?.fields ?? []) {\n defaultProps[field.key] = field.defaultValue ?? ''\n }\n return {\n id: `container-${schema.name}`,\n label: schema.label,\n icon: () => (schema.icon ?? <ReadOutlined />),\n handler: (view, _state) => insertContainer(view, schema.name, defaultProps),\n }\n })\n\n // 滚动同步 (already handled by useScrollSync hook)\n const handleScrollReady = useCallback((scrollDOM: HTMLElement) => {\n scrollDOMRef.current = scrollDOM\n }, [])\n\n const handlePreviewRef = useCallback((node: HTMLDivElement | null) => {\n previewElRef.current = node\n }, [])\n\n const handleViewReady = useCallback((view: any) => {\n setEditorView(view)\n }, [])\n\n // 编辑容器属性时触发\n const handleEditContainer = useCallback((_view: any, typeName: string, propsLineFrom: number, propsLineTo: number, currentProps: Record<string, string>) => {\n setDialogTypeName(typeName)\n setDialogProps({ ...currentProps })\n setDialogPropsRange([propsLineFrom, propsLineTo])\n setDialogVisible(true)\n }, [])\n\n // 保存容器属性\n const handleDialogSave = useCallback((newProps: Record<string, string>) => {\n setDialogVisible(false)\n if (editorView) {\n updateContainerProps(editorView, dialogPropsRange[0], dialogPropsRange[1], newProps)\n }\n }, [editorView, dialogPropsRange])\n\n // 关闭弹窗\n const handleDialogClose = useCallback(() => {\n setDialogVisible(false)\n }, [])\n\n return (\n <div className={fullscreen ? 'markdown-editor-app fullscreen' : 'markdown-editor-app'}>\n <Toolbar\n editorView={editorView}\n fullscreen={fullscreen}\n onToggleFullscreen={fullscreenProp ? toggleFullscreen : undefined}\n extraItems={extraToolbarItems}\n uploadConfig={uploadConfig}\n />\n {showPreview ? (\n <SplitPanels\n leftPanel={\n <Editor\n value={content}\n onChange={internalSetContent}\n onScrollReady={handleScrollReady}\n onViewReady={handleViewReady}\n onEditContainer={handleEditContainer}\n uploadConfig={uploadConfig}\n onMessageNoUploadConfig={() => message.warning('请先配置图片上传功能')}\n />\n }\n rightPanel={\n <Preview\n content={content}\n ref={handlePreviewRef}\n previewOptions={previewOptions}\n />\n }\n />\n ) : (\n <Editor\n value={content}\n onChange={internalSetContent}\n onScrollReady={handleScrollReady}\n onViewReady={handleViewReady}\n onEditContainer={handleEditContainer}\n uploadConfig={uploadConfig}\n onMessageNoUploadConfig={() => message.warning('请先配置图片上传功能')}\n />\n )}\n {/* 容器属性编辑弹窗 */}\n <EditDialog\n visible={dialogVisible}\n typeName={dialogTypeName}\n currentProps={dialogProps}\n onSave={handleDialogSave}\n onClose={handleDialogClose}\n />\n </div>\n )\n})\n","import { useEffect } from 'react'\nimport componentRegistry from '../registry/componentRegistry'\nimport type { ComponentSchema } from '../types'\n\n/**\n * 注册自定义容器组件到工具栏。支持单个或批量注册。\n * 支持两种模式:\n * \n * 1. 容器模式(linkCard):name + fields + renderDialog\n * 插入 :::name 格式的容器,支持弹窗编辑属性\n * \n * 2. 标签包裹模式:name + wrapTags\n * 插入简单的标签包裹文本,如 <plugin-container>...</plugin-container>\n * \n * @example 容器模式 - 使用 fields 自动生成表单(最简)\n * ```tsx\n * const schema: ComponentSchema = {\n * name: 'alert',\n * label: '警告框',\n * icon: <AlertOutlined />,\n * fields: [\n * { key: 'type', name: '类型', componentType: 'select',\n * componentProps: { options: [{ value: 'price', label: '价格' }, { value: 'info', label: '信息' }] } },\n * { key: 'content', name: '内容', componentType: 'textarea',\n * componentProps: { rows: 3 } },\n * { key: 'enabled', name: '启用', componentType: 'switch' },\n * ],\n * }\n * // 支持的 componentType: 'input' | 'textarea' | 'number' | 'select' | 'switch' | 'slider' | 'rate' | 'color' | 'date' | 'dateRange'\n * ```\n * \n * @example 容器模式 - 使用 Form.Item 自动绑定(推荐)\n * ```tsx\n * const schema: ComponentSchema = {\n * name: 'alert',\n * label: '警告框',\n * icon: <AlertOutlined />,\n * fields: [{ key: 'level', defaultValue: 'info' }],\n * renderDialog: ({ form }) => (\n * <Form form={form} layout=\"vertical\">\n * <Form.Item name=\"level\" label=\"级别\">\n * <Input />\n * </Form.Item>\n * </Form>\n * ),\n * }\n * \n * function MyPage() {\n * useRegisterToolbar(schema)\n * return <MarkdownEditor />\n * }\n * ```\n * \n * @example 容器模式 - 手动控制\n * ```tsx\n * const schema: ComponentSchema = {\n * name: 'alert',\n * label: '警告框',\n * icon: <AlertOutlined />,\n * fields: [{ key: 'level', defaultValue: 'info' }],\n * renderDialog: ({ props, onChange }) => (\n * <Input value={props.level} onChange={e => onChange('level', e.target.value)} />\n * ),\n * }\n * ```\n * \n * @example 容器模式 - 完全自定义弹窗\n * ```tsx\n * const schema: ComponentSchema = {\n * name: 'alert',\n * label: '警告框',\n * icon: <AlertOutlined />,\n * fields: [{ key: 'level', defaultValue: 'info' }],\n * renderDialog: ({ props, onSave }) => (\n * <MyCustomEditor\n * value={props.level}\n * onSave={({ level }) => onSave({ level })}\n * />\n * ),\n * }\n * ```\n * \n * @example 标签包裹模式\n * ```tsx\n * function MyPage() {\n * useRegisterToolbar({\n * name: 'plugin-container',\n * label: '自定义容器',\n * icon: <AlertOutlined />,\n * wrapTags: ['<plugin-container>', '</plugin-container>'],\n * })\n * return <MarkdownEditor />\n * }\n * ```\n * \n * @example 批量注册\n * ```tsx\n * function MyPage() {\n * useRegisterToolbar([schema1, schema2, schema3])\n * return <MarkdownEditor />\n * }\n * ```\n */\nexport function useRegisterToolbar(schemas: ComponentSchema | ComponentSchema[]) {\n const schemaList: ComponentSchema[] = Array.isArray(schemas) ? schemas : [schemas]\n\n useEffect(() => {\n schemaList.forEach(schema => {\n componentRegistry.register(schema.name, schema)\n })\n return () => {\n schemaList.forEach(schema => {\n componentRegistry.unregister(schema.name)\n })\n }\n }, [schemaList])\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/utils/parseContainer.ts","../src/registry/componentRegistry.tsx","../src/components/Editor/containerWidget.ts","../src/components/Toolbar/buttons.tsx","../src/components/Editor/codemirrorExtensions.ts","../src/components/Editor/index.tsx","../src/components/Preview/index.tsx","../src/components/Panel/SplitPanels.tsx","../src/components/Toolbar/config.ts","../src/components/Toolbar/hooks/useToolbar.ts","../src/components/Toolbar/renderers/ToolbarItemRenderer.tsx","../src/components/Toolbar/renderers/TablePicker/index.module.less","../src/components/Toolbar/renderers/TablePicker/index.tsx","../src/components/Toolbar/renderers/TablePicker/TableDropdown.tsx","../src/components/Toolbar/index.tsx","../src/components/Dialog/EditDialog.tsx","../src/utils/writeContainer.ts","../src/hooks/useFullscreen.ts","../src/hooks/useScrollSync.ts","../src/MarkdownEditor.tsx","../src/hooks/useRegisterToolbar.ts"],"sourcesContent":["/**\r\n * 解析容器属性 JSON 字符串。\r\n * 支持标准 JSON 和宽松格式: { key: 'value', key2: 'value2' }\r\n */\r\nexport function parseContainerProps(jsonStr: string): Record<string, string> {\r\n try {\r\n const props: Record<string, string> = {}\r\n const trimmed = jsonStr.trim()\r\n if (trimmed.startsWith('{') && trimmed.endsWith('}')) {\r\n const inner = trimmed.slice(1, -1).trim()\r\n if (!inner) return props\r\n // 匹配 key: 'value' 或 key: \"value\" 格式\r\n const matches = inner.matchAll(/(?:[\"']?)(\\w+)(?:[\"']?)\\s*:\\s*(?:\"([^\"]*)\"|'([^']*)'|(\\d+))/g)\r\n for (const m of matches) {\r\n props[m[1]] = m[2] ?? m[3] ?? m[4] ?? ''\r\n }\r\n }\r\n return props\r\n } catch {\r\n return {}\r\n }\r\n}\r\n\r\n/**\r\n * 在编辑器文档中查找容器块。\r\n * 返回包含类型、属性和行位置的容器位置数组。\r\n */\r\nexport interface ContainerBlock {\r\n startPos: number // ::: 打开行位置\r\n typeName: string // 组件类型名称 (如 \"linkCard\")\r\n propsLineFrom: number // JSON 属性行起始位置\r\n propsLineTo: number // JSON 属性行结束位置\r\n props: Record<string, string>\r\n endPos: number // ::: 关闭行位置\r\n}\r\n\r\nexport function findContainers(\r\n docText: string\r\n): ContainerBlock[] {\r\n const containers: ContainerBlock[] = []\r\n const lines = docText.split('\\n')\r\n\r\n let i = 0\r\n while (i < lines.length) {\r\n const line = lines[i]\r\n const match = line.match(/^:::(\\w+)$/)\r\n if (match) {\r\n const typeName = match[1]\r\n // 计算字符位置\r\n let charPos = 0\r\n for (let l = 0; l < i; l++) {\r\n charPos += lines[l].length + 1 // +1 for newline\r\n }\r\n\r\n // 查找下一行的 JSON 属性\r\n let props: Record<string, string> = {}\r\n let propsLineFrom = 0\r\n let propsLineTo = 0\r\n let propsLineIndex = i + 1\r\n\r\n if (propsLineIndex < lines.length) {\r\n const propsLine = lines[propsLineIndex].trim()\r\n const propsMatch = propsLine.match(/^\\{[\\s\\S]*\\}$/)\r\n if (propsMatch) {\r\n props = parseContainerProps(propsLine)\r\n propsLineFrom = charPos + line.length + 1\r\n propsLineTo = propsLineFrom + lines[propsLineIndex].length\r\n }\r\n }\r\n\r\n // 查找闭合 :::\r\n let endPos = 0\r\n for (let j = i + 1; j < lines.length; j++) {\r\n if (lines[j].trim() === ':::') {\r\n let endCharPos = 0\r\n for (let l = 0; l < j; l++) {\r\n endCharPos += lines[l].length + 1\r\n }\r\n endPos = endCharPos\r\n i = j + 1\r\n break\r\n }\r\n }\r\n\r\n containers.push({\r\n startPos: charPos,\r\n typeName,\r\n propsLineFrom,\r\n propsLineTo,\r\n props,\r\n endPos,\r\n })\r\n }\r\n i++\r\n }\r\n\r\n return containers\r\n}","import type { ComponentSchema } from '../types'\r\n\r\n/**\r\n * 组件注册中心,用于管理自定义组件的 schema。\r\n * 每个容器组件(如 :::linkCard)在此注册其可编辑字段。\r\n */\r\nclass ComponentRegistry {\r\n private schemas = new Map<string, ComponentSchema>()\r\n\r\n /**\r\n * 注册组件 schema\r\n */\r\n register(name: string, schema: ComponentSchema): void {\r\n this.schemas.set(name, schema)\r\n }\r\n\r\n /**\r\n * 根据组件名获取已注册的 schema\r\n */\r\n get(name: string): ComponentSchema | undefined {\r\n return this.schemas.get(name)\r\n }\r\n\r\n /**\r\n * 检查组件类型是否已注册\r\n */\r\n has(name: string): boolean {\r\n return this.schemas.has(name)\r\n }\r\n\r\n /**\r\n * 获取所有已注册的组件名\r\n */\r\n getAllNames(): string[] {\r\n return Array.from(this.schemas.keys())\r\n }\r\n\r\n /**\r\n * 获取所有已注册的 schema\r\n */\r\n getAll(): ComponentSchema[] {\r\n return Array.from(this.schemas.values())\r\n }\r\n\r\n /**\r\n * 移除组件注册\r\n */\r\n unregister(name: string): void {\r\n this.schemas.delete(name)\r\n }\r\n}\r\n\r\n// 单例实例\r\nconst componentRegistry = new ComponentRegistry()\r\n\r\nexport default componentRegistry","import { ViewPlugin, Decoration, WidgetType } from '@codemirror/view'\r\nimport type { DecorationSet } from '@codemirror/view'\r\nimport { EditorState, Facet } from '@codemirror/state'\r\nimport { findContainers } from '../../utils/parseContainer'\r\nimport componentRegistry from '../../registry/componentRegistry'\r\n\r\n/**\r\n * 编辑容器属性的回调函数类型\r\n */\r\nexport interface OnEditContainer {\r\n (view: any, typeName: string, propsLineFrom: number, propsLineTo: number, currentProps: Record<string, string>): void\r\n}\r\n\r\n/**\r\n * 自定义 facet 用于传递编辑回调\r\n */\r\nexport const containerEditCallback = Facet.define<any, OnEditContainer>({\r\n combine: (values) => values[0],\r\n})\r\n\r\n/**\r\n * 只读的容器头行 Widget(显示 :::typeName + 编辑按钮)\r\n * 使用 Decoration.replace 替换原始文本,使其不可直接编辑\r\n */\r\nclass ContainerHeaderWidget extends WidgetType {\r\n public typeName: string\r\n\r\n constructor(typeName: string) {\r\n super()\r\n this.typeName = typeName\r\n }\r\n\r\n public toDOM(): HTMLElement {\r\n const container = document.createElement('span')\r\n container.className = 'container-widget-header'\r\n\r\n const text = document.createElement('span')\r\n text.className = 'container-widget-text'\r\n text.textContent = `:::${this.typeName}`\r\n\r\n const button = document.createElement('button')\r\n button.className = 'container-edit-btn'\r\n button.title = `编辑 ${componentRegistry.get(this.typeName)?.label ?? this.typeName}`\r\n button.textContent = '✎'\r\n ;(button as any).__typeName = this.typeName\r\n\r\n container.appendChild(text)\r\n container.appendChild(button)\r\n return container\r\n }\r\n\r\n public eq(other: ContainerHeaderWidget): boolean {\r\n return this.typeName === other.typeName\r\n }\r\n\r\n public ignoreEvent(): boolean {\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * 只读的容器属性行 Widget(显示 { key: value, ... })\r\n * 使用 Decoration.replace 替换原始文本,使其不可直接编辑\r\n */\r\nclass ContainerPropsWidget extends WidgetType {\r\n public propsText: string\r\n\r\n constructor(propsText: string) {\r\n super()\r\n this.propsText = propsText\r\n }\r\n\r\n public toDOM(): HTMLElement {\r\n const span = document.createElement('span')\r\n span.className = 'container-widget-props'\r\n span.textContent = this.propsText\r\n return span\r\n }\r\n\r\n public eq(other: ContainerPropsWidget): boolean {\r\n return this.propsText === other.propsText\r\n }\r\n\r\n public ignoreEvent(): boolean {\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * 只读的容器结束行 Widget(显示 :::)\r\n * 使用 Decoration.replace 替换原始文本,使其不可直接编辑\r\n */\r\nclass ContainerCloseWidget extends WidgetType {\r\n public toDOM(): HTMLElement {\r\n const span = document.createElement('span')\r\n span.className = 'container-widget-text'\r\n span.textContent = ':::'\r\n return span\r\n }\r\n\r\n public eq(): boolean {\r\n return true\r\n }\r\n\r\n public ignoreEvent(): boolean {\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * 查找文档中的容器,创建 Decoration 装饰物\r\n * 将 ::: 头行、{} 属性行和 ::: 结束行替换为只读 widget,使其无法在编辑器中直接编辑\r\n */\r\nfunction findContainerDecorations(state: EditorState): Array<{ from: number; to: number; value: Decoration }> {\r\n const docText = state.doc.toString()\r\n const containers = findContainers(docText)\r\n const decorations: Array<{ from: number; to: number; value: Decoration }> = []\r\n\r\n for (const container of containers) {\r\n const headerLine = state.doc.lineAt(container.startPos)\r\n\r\n // 替换 :::typeName 头行为只读 widget\r\n decorations.push({\r\n from: headerLine.from,\r\n to: headerLine.to,\r\n value: Decoration.replace({\r\n widget: new ContainerHeaderWidget(container.typeName),\r\n }),\r\n })\r\n\r\n // 替换 {} 属性行为只读 widget\r\n if (container.propsLineFrom > 0 && container.propsLineTo > 0) {\r\n const propsLine = state.doc.lineAt(container.propsLineFrom)\r\n const propsText = propsLine.text\r\n\r\n decorations.push({\r\n from: propsLine.from,\r\n to: propsLine.to,\r\n value: Decoration.replace({\r\n widget: new ContainerPropsWidget(propsText),\r\n }),\r\n })\r\n }\r\n\r\n // 替换 ::: 结束行为只读 widget\r\n if (container.endPos > 0) {\r\n const endLine = state.doc.lineAt(container.endPos)\r\n decorations.push({\r\n from: endLine.from,\r\n to: endLine.to,\r\n value: Decoration.replace({\r\n widget: new ContainerCloseWidget(),\r\n }),\r\n })\r\n }\r\n }\r\n\r\n return decorations\r\n}\r\n\r\n/**\r\n * 容器编辑 ViewPlugin\r\n * 将容器的 ::: 头行和 {} 属性行替换为只读 widget,使其无法在编辑器中直接编辑\r\n */\r\nexport const containerWidgetPlugin = ViewPlugin.fromClass(\r\n class {\r\n public decorations: DecorationSet\r\n\r\n constructor(view: any) {\r\n this.decorations = Decoration.set(findContainerDecorations(view.state), true)\r\n }\r\n\r\n public update(update: any) {\r\n if (update.docChanged || update.selectionSet) {\r\n this.decorations = Decoration.set(findContainerDecorations(update.state), true)\r\n }\r\n }\r\n },\r\n {\r\n decorations: (value) => value.decorations,\r\n eventHandlers: {\r\n // 阻止编辑按钮的 mousedown 事件,防止焦点移动\r\n mousedown: (event: MouseEvent, view: any) => {\r\n const target = event.target as HTMLElement\r\n if (target.classList.contains('container-edit-btn')) {\r\n event.preventDefault()\r\n return true\r\n }\r\n return false\r\n },\r\n // 点击编辑按钮时触发回调\r\n click: (event: MouseEvent, view: any) => {\r\n const target = event.target as HTMLElement\r\n if (target.classList.contains('container-edit-btn')) {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n const typeName = (target as any).__typeName\r\n if (typeName) {\r\n const docText = view.state.doc.toString()\r\n const containers = findContainers(docText)\r\n const buttonPos = view.posAtDOM(target)\r\n\r\n // 通过 button 位置匹配最近的容器头行,避免多个同类型容器匹配错误\r\n for (const container of containers) {\r\n const headerLine = view.state.doc.lineAt(container.startPos)\r\n // 按钮位置在头行的范围内(允许一定偏差,因为 widget 替换后位置可能略有偏移)\r\n if (buttonPos >= headerLine.from - 5 && buttonPos <= headerLine.to + 5) {\r\n const callback = view.state.facet(containerEditCallback)\r\n if (callback) {\r\n callback(view, container.typeName, container.propsLineFrom, container.propsLineTo, { ...container.props })\r\n }\r\n return true\r\n }\r\n }\r\n }\r\n return false\r\n }\r\n return false\r\n },\r\n },\r\n }\r\n)","import { EditorView } from '@codemirror/view'\r\nimport type { ImageUploadConfig } from '../../types'\r\n\r\n/**\r\n * 在光标位置插入文本\r\n */\r\nexport function insertAtCursor(view: EditorView, before: string, after: string = '', placeholder: string = ''): void {\r\n const { from, to } = view.state.selection.main\r\n const selectedText = view.state.doc.sliceString(from, to)\r\n const insert = selectedText\r\n ? `${before}${selectedText}${after}`\r\n : `${before}${placeholder}${after}`\r\n view.dispatch({ changes: { from, to, insert } })\r\n if (!selectedText && placeholder) {\r\n view.dispatch({ selection: { anchor: from + before.length } })\r\n }\r\n}\r\n\r\n/**\r\n * 在当前行行首插入文本\r\n */\r\nexport function insertAtLineStart(view: EditorView, text: string): void {\r\n const { from } = view.state.selection.main\r\n const line = view.state.doc.lineAt(from)\r\n view.dispatch({ changes: { from: line.from, to: line.from, insert: text } })\r\n view.dispatch({ selection: { anchor: line.from + text.length } })\r\n}\r\n\r\n/**\r\n * 上传图片\r\n * @param file - 要上传的文件\r\n * @param uploadConfig - 上传配置\r\n */\r\nexport async function uploadFileToServer(\r\n file: File,\r\n uploadConfig: ImageUploadConfig\r\n): Promise<string | null> {\r\n // 优先使用自定义上传函数\r\n if (uploadConfig.onUploadImage) {\r\n return uploadConfig.onUploadImage(file)\r\n }\r\n\r\n // 使用 uploadUrl 上传\r\n if (uploadConfig.uploadUrl) {\r\n const formData = new FormData()\r\n formData.append('file', file)\r\n\r\n const response = await fetch(uploadConfig.uploadUrl, {\r\n method: 'POST',\r\n body: formData,\r\n })\r\n\r\n if (!response.ok) return null\r\n\r\n const result = await response.json()\r\n \r\n // 如果外部提供了 URL 提取回调,使用它\r\n if (uploadConfig.onGetUploadUrl) {\r\n return uploadConfig.onGetUploadUrl(result)\r\n }\r\n \r\n // 默认行为\r\n return result.data?.path || null\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * 判断是否配置了图片上传\r\n */\r\nexport function isUploadConfigured(\r\n uploadConfig?: ImageUploadConfig\r\n): boolean {\r\n return !!(uploadConfig?.uploadUrl || uploadConfig?.onUploadImage)\r\n}\r\n\r\n/**\r\n * 图片上传:创建隐藏的 file input 触发选择,上传后插入 markdown 图片语法\r\n * @param view - CodeMirror 编辑器实例\r\n * @param uploadConfig - 上传配置(包含 uploadUrl 或 onUploadImage)\r\n */\r\nexport function uploadImage(\r\n view: EditorView,\r\n uploadConfig: ImageUploadConfig\r\n): void {\r\n const input = document.createElement('input')\r\n input.type = 'file'\r\n input.accept = 'image/*'\r\n input.style.display = 'none'\r\n\r\n input.addEventListener('change', async () => {\r\n if (!input.files || input.files.length === 0) return\r\n\r\n const file = input.files[0]\r\n const { from, to } = view.state.selection.main\r\n const selectedText = view.state.doc.sliceString(from, to) || '描述'\r\n\r\n const url = await uploadFileToServer(file, uploadConfig)\r\n if (url) {\r\n const insert = `![${selectedText}](${url})`\r\n view.dispatch({ changes: { from, to, insert } })\r\n }\r\n\r\n input.remove()\r\n })\r\n\r\n document.body.appendChild(input)\r\n input.click()\r\n}\r\n\r\n/**\r\n * 用前缀和后缀包裹选中文本\r\n */\r\nexport function wrapSelection(view: EditorView, prefix: string, suffix: string): void {\r\n const { from, to, empty } = view.state.selection.main\r\n if (empty) return\r\n const selected = view.state.doc.sliceString(from, to)\r\n view.dispatch({ changes: { from, to, insert: `${prefix}${selected}${suffix}` } })\r\n}\r\n\r\n/**\r\n * 切换包裹:选中的文本已包含标签则移除,否则添加\r\n */\r\nexport function toggleWrap(\r\n view: EditorView,\r\n openTag: string,\r\n closeTag: string\r\n): void {\r\n const { from, to, empty } = view.state.selection.main\r\n const doc = view.state.doc\r\n\r\n // 选区完整包含标签 → 移除\r\n if (!empty) {\r\n const selected = doc.sliceString(from, to)\r\n if (selected.startsWith(openTag) && selected.endsWith(closeTag)) {\r\n const inner = selected.slice(openTag.length, -closeTag.length)\r\n view.dispatch({ changes: { from, to, insert: inner } })\r\n return\r\n }\r\n }\r\n\r\n // 光标/选区在标签内部 → 查找当前行的标签并移除\r\n {\r\n const cursorPos = empty ? from : to\r\n const line = doc.lineAt(cursorPos)\r\n const lineText = doc.sliceString(line.from, line.to)\r\n const openIdx = lineText.indexOf(openTag)\r\n const closeIdx = lineText.lastIndexOf(closeTag)\r\n\r\n if (openIdx >= 0 && closeIdx > openIdx) {\r\n const absOpen = line.from + openIdx\r\n const absClose = line.from + closeIdx\r\n // 确认光标/选区在标签范围内\r\n if (cursorPos >= absOpen + openTag.length && cursorPos <= absClose) {\r\n const inner = doc.sliceString(absOpen + openTag.length, absClose)\r\n view.dispatch({\r\n changes: {\r\n from: absOpen,\r\n to: absClose + closeTag.length,\r\n insert: inner,\r\n },\r\n })\r\n return\r\n }\r\n }\r\n }\r\n\r\n // 默认:添加包裹\r\n wrapSelection(view, openTag, closeTag)\r\n}","import { EditorView, keymap } from '@codemirror/view'\r\nimport { defaultKeymap, indentWithTab } from '@codemirror/commands'\r\nimport { markdown } from '@codemirror/lang-markdown'\r\nimport { oneDark } from '@codemirror/theme-one-dark'\r\nimport { Facet } from '@codemirror/state'\r\nimport { containerWidgetPlugin, containerEditCallback } from './containerWidget'\r\nimport type { OnEditContainer } from './containerWidget'\r\nimport { uploadFileToServer, isUploadConfigured } from '../Toolbar/buttons'\r\nimport type { ImageUploadConfig } from '../../types'\r\n\r\n/** 图片上传配置 facet */\r\nconst uploadConfigFacet = Facet.define<ImageUploadConfig | undefined, ImageUploadConfig | undefined>({\r\n combine: (values) => values[values.length - 1],\r\n})\r\n\r\n/** 未配置上传时的提示回调 facet */\r\nconst messageFacet = Facet.define<(() => void) | undefined, (() => void) | undefined>({\r\n combine: (values) => values[values.length - 1],\r\n})\r\n\r\n/** 粘贴事件处理:拦截图片并上传 */\r\nconst pasteHandler = EditorView.domEventHandlers({\r\n paste: (event: ClipboardEvent, view: EditorView) => {\r\n const files = event.clipboardData?.files\r\n if (!files) return false\r\n\r\n const imageFiles = Array.from(files).filter((f) => f.type.startsWith('image/'))\r\n if (imageFiles.length === 0) return false\r\n\r\n event.preventDefault()\r\n\r\n const uploadConfig = view.state.facet(uploadConfigFacet)\r\n const showMessage = view.state.facet(messageFacet)\r\n\r\n if (!isUploadConfigured(uploadConfig)) {\r\n showMessage?.()\r\n return true\r\n }\r\n\r\n // 上传所有粘贴的图片\r\n const { from, to } = view.state.selection.main\r\n let offset = 0\r\n\r\n for (const file of imageFiles) {\r\n uploadFileToServer(file, uploadConfig!).then((url) => {\r\n if (url) {\r\n const name = file.name.replace(/\\.[^.]+$/, '')\r\n const insert = `![${name}](${url})`\r\n view.dispatch({ changes: { from: from + offset, to: to + offset, insert } })\r\n offset += insert.length\r\n }\r\n })\r\n }\r\n\r\n return true\r\n },\r\n})\r\n\r\ninterface GetCodeMirrorExtensionsOptions {\r\n /** 编辑容器属性的回调函数 */\r\n onEditContainer?: OnEditContainer\r\n /** 图片上传配置 */\r\n uploadConfig?: ImageUploadConfig\r\n /** 未配置上传时的提示回调 */\r\n onMessageNoUploadConfig?: () => void\r\n}\r\n\r\nexport const getCodeMirrorExtensions = (opts?: GetCodeMirrorExtensionsOptions) => {\r\n const extensions = [\r\n markdown(),\r\n oneDark,\r\n keymap.of([...defaultKeymap, indentWithTab]),\r\n EditorView.lineWrapping,\r\n pasteHandler,\r\n EditorView.baseTheme({\r\n '.cm-scroller': {\r\n height: '100%',\r\n overflow: 'auto',\r\n },\r\n // 容器头行 Widget 样式\r\n '.container-widget-header': {\r\n display: 'inline',\r\n fontSize: 'inherit',\r\n fontFamily: 'inherit',\r\n },\r\n '.container-widget-text': {\r\n fontWeight: 'bold',\r\n color: '#79c0ff',\r\n },\r\n // 容器属性行 Widget 样式\r\n '.container-widget-props': {\r\n display: 'inline',\r\n fontSize: 'inherit',\r\n fontFamily: 'inherit',\r\n color: '#a5d6ff',\r\n },\r\n // 容器编辑按钮样式\r\n '.container-edit-btn': {\r\n display: 'inline-block',\r\n padding: '0 4px',\r\n fontSize: '12px',\r\n color: '#58a6ff',\r\n background: 'transparent',\r\n border: 'none',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n marginRight: '4px',\r\n verticalAlign: 'middle',\r\n },\r\n '.container-edit-btn:hover': {\r\n background: 'rgba(88, 166, 255, 0.16)',\r\n },\r\n }),\r\n ]\r\n\r\n // 添加容器 widget 插件\r\n extensions.push(containerWidgetPlugin)\r\n\r\n // 如果有编辑回调,注册 facet\r\n if (opts?.onEditContainer) {\r\n extensions.push(containerEditCallback.of(opts.onEditContainer))\r\n }\r\n\r\n // 如果有图片上传配置,注册 facet\r\n if (opts?.uploadConfig) {\r\n extensions.push(uploadConfigFacet.of(opts.uploadConfig))\r\n }\r\n\r\n // 如果有消息回调,注册 facet\r\n if (opts?.onMessageNoUploadConfig) {\r\n extensions.push(messageFacet.of(opts.onMessageNoUploadConfig))\r\n }\r\n\r\n return extensions\r\n}\r\n\r\nexport default getCodeMirrorExtensions","import { useEffect, useRef } from 'react'\r\nimport { EditorView, basicSetup } from 'codemirror'\r\nimport { EditorState } from '@codemirror/state'\r\nimport { getCodeMirrorExtensions } from './codemirrorExtensions'\r\nimport type { ImageUploadConfig } from '../../types'\r\n\r\ninterface EditorProps {\r\n value: string\r\n onChange: (value: string) => void\r\n onScrollReady?: (scrollDOM: HTMLElement) => void\r\n onViewReady?: (view: EditorView) => void\r\n /** 编辑容器属性的回调 */\r\n onEditContainer?: (view: any, typeName: string, propsLineFrom: number, propsLineTo: number, currentProps: Record<string, string>) => void\r\n /** 图片上传配置 */\r\n uploadConfig?: ImageUploadConfig\r\n /** 未配置上传时的提示回调 */\r\n onMessageNoUploadConfig?: () => void\r\n}\r\n\r\nexport default function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer, uploadConfig, onMessageNoUploadConfig }: EditorProps) {\r\n const editorRef = useRef<HTMLDivElement>(null)\r\n const viewRef = useRef<EditorView | null>(null)\r\n\r\n useEffect(() => {\r\n if (!editorRef.current) return\r\n\r\n const extensions = [\r\n basicSetup,\r\n ...getCodeMirrorExtensions({ onEditContainer, uploadConfig, onMessageNoUploadConfig }),\r\n EditorView.updateListener.of((update) => {\r\n if (update.docChanged) {\r\n onChange(update.state.doc.toString())\r\n }\r\n }),\r\n ]\r\n\r\n const state = EditorState.create({\r\n doc: value,\r\n extensions,\r\n })\r\n\r\n viewRef.current = new EditorView({\r\n state,\r\n parent: editorRef.current,\r\n })\r\n\r\n if (onScrollReady && viewRef.current) {\r\n onScrollReady(viewRef.current.scrollDOM)\r\n }\r\n\r\n if (onViewReady) {\r\n onViewReady(viewRef.current)\r\n }\r\n\r\n return () => {\r\n viewRef.current?.destroy()\r\n }\r\n }, [])\r\n\r\n // 外部 value 变化时更新编辑器内容\r\n useEffect(() => {\r\n if (viewRef.current && viewRef.current.state.doc.toString() !== value) {\r\n viewRef.current.dispatch({\r\n changes: { from: 0, to: viewRef.current.state.doc.length, insert: value },\r\n })\r\n }\r\n }, [value])\r\n\r\n return <div ref={editorRef} className=\"editor\" />\r\n}","import { forwardRef, useEffect } from 'react'\r\nimport RenderMarkdown, { languagesCommon, initHighlighter } from 'remons-render-markdown';\r\nimport type { RenderMarkdownProps } from 'remons-render-markdown';\r\nimport 'remons-render-markdown/dist/index.css';\r\n\r\nexport type PreviewOptions = Omit<RenderMarkdownProps, 'content'> & {\r\n languages?: Record<string, any> | null | undefined\r\n}\r\n\r\nexport interface PreviewProps {\r\n content: string\r\n previewOptions?: PreviewOptions\r\n}\r\n\r\n\r\nconst Preview = forwardRef<HTMLDivElement, PreviewProps>(({ content, previewOptions }, ref) => {\r\n useEffect(() => {\r\n initHighlighter({\r\n ...languagesCommon,\r\n ...(previewOptions?.languages ? previewOptions?.languages : {})\r\n })\r\n }, [previewOptions?.languages])\r\n\r\n return (\r\n <div ref={ref} className=\"preview\">\r\n <RenderMarkdown content={content} {...previewOptions} />\r\n </div>\r\n )\r\n})\r\n\r\nPreview.displayName = 'Preview'\r\n\r\nexport default Preview","import React from 'react'\r\nimport { Splitter } from 'antd'\r\n\r\nconst { Panel } = Splitter\r\n\r\ninterface SplitPanelsProps {\r\n leftPanel: React.ReactNode\r\n rightPanel: React.ReactNode\r\n}\r\n\r\nexport default function SplitPanels({ leftPanel, rightPanel }: SplitPanelsProps) {\r\n return (\r\n <Splitter className=\"split-panels\">\r\n <Panel defaultSize=\"50%\" min=\"20%\" max=\"80%\">\r\n {leftPanel}\r\n </Panel>\r\n <Panel>{rightPanel}</Panel>\r\n </Splitter>\r\n )\r\n}","import type { ToolbarButtonConfig, ImageUploadConfig } from '../../types'\r\nimport {\r\n BoldOutlined,\r\n ItalicOutlined,\r\n StrikethroughOutlined,\r\n UnderlineOutlined,\r\n UnorderedListOutlined,\r\n OrderedListOutlined,\r\n LinkOutlined,\r\n PictureOutlined,\r\n CodeOutlined,\r\n BlockOutlined,\r\n MinusOutlined,\r\n FieldStringOutlined,\r\n FontSizeOutlined,\r\n} from '@ant-design/icons'\r\nimport { insertAtCursor, insertAtLineStart, wrapSelection, uploadImage, isUploadConfigured } from './buttons'\r\n\r\n/**\r\n * 创建工具栏配置\r\n * @param options - 配置选项\r\n */\r\nexport function createToolbarConfig(options?: ImageUploadConfig): ToolbarButtonConfig[] {\r\n // 判断是否配置了图片上传\r\n const hasUploadConfig = isUploadConfigured(options)\r\n return [\r\n {\r\n id: 'heading',\r\n icon: FontSizeOutlined,\r\n label: '标题',\r\n children: [\r\n { id: 'heading1', label: '标题 1', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '# ') },\r\n { id: 'heading2', label: '标题 2', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '## ') },\r\n { id: 'heading3', label: '标题 3', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '### ') },\r\n { id: 'heading4', label: '标题 4', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '#### ') },\r\n { id: 'heading5', label: '标题 5', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '##### ') },\r\n { id: 'heading6', label: '标题 6', icon: FontSizeOutlined, handler: (v) => insertAtLineStart(v, '###### ') },\r\n ],\r\n },\r\n { separatorBefore: true },\r\n { id: 'bold', label: '加粗', icon: BoldOutlined, handler: (v) => wrapSelection(v, '**', '**') },\r\n { id: 'italic', label: '斜体', icon: ItalicOutlined, handler: (v) => wrapSelection(v, '*', '*') },\r\n { id: 'strikethrough', label: '删除线', icon: StrikethroughOutlined, handler: (v) => wrapSelection(v, '~~', '~~') },\r\n { id: 'underline', label: '下划线', icon: UnderlineOutlined, handler: (v) => wrapSelection(v, '<u>', '</u>') },\r\n { separatorBefore: true },\r\n { id: 'ul', label: '无序列表', icon: UnorderedListOutlined, handler: (v) => insertAtLineStart(v, '- ') },\r\n { id: 'ol', label: '有序列表', icon: OrderedListOutlined, handler: (v) => insertAtLineStart(v, '1. ') },\r\n { separatorBefore: true },\r\n { id: 'link', label: '链接', icon: LinkOutlined, handler: (v) => insertAtCursor(v, '[', '](url)', '文本') },\r\n // 图片按钮:未配置上传时禁用并提示\r\n {\r\n id: 'image',\r\n label: hasUploadConfig ? '图片' : '请配置图片上传地址',\r\n icon: PictureOutlined,\r\n disabled: !hasUploadConfig,\r\n handler: hasUploadConfig ? (v) => uploadImage(v, { uploadUrl: options?.uploadUrl, onUploadImage: options?.onUploadImage }) : undefined,\r\n },\r\n { separatorBefore: true },\r\n { id: 'code', label: '行内代码', icon: FieldStringOutlined, handler: (v) => wrapSelection(v, '`', '`') },\r\n {\r\n id: 'codeblock',\r\n label: '代码块',\r\n icon: CodeOutlined,\r\n handler: (v) => {\r\n const { from, to } = v.state.selection.main\r\n const selected = v.state.doc.sliceString(from, to)\r\n const insert = selected ? '```\\n' + selected + '\\n```' : '```\\n\\n```'\r\n v.dispatch({ changes: { from, to, insert } })\r\n },\r\n },\r\n { id: 'quote', label: '引用', icon: BlockOutlined, handler: (v) => insertAtLineStart(v, '> ') },\r\n {\r\n id: 'hr',\r\n label: '分割线',\r\n icon: MinusOutlined,\r\n handler: (v) => {\r\n const { from } = v.state.selection.main\r\n v.dispatch({ changes: { from, insert: '\\n---\\n' } })\r\n },\r\n },\r\n ]\r\n}","import { useCallback, useMemo } from 'react'\r\nimport type { EditorView } from '@codemirror/view'\r\nimport type { ToolbarButtonConfig, ImageUploadConfig } from '../../../types'\r\nimport { createToolbarConfig } from '../config'\r\nimport { toggleWrap } from '../buttons'\r\n\r\nexport interface UseToolbarOptions {\r\n /** 第三方扩展的按钮配置,将追加到工具栏末尾 */\r\n extraItems?: ToolbarButtonConfig[]\r\n /** 图片上传配置 */\r\n uploadConfig?: ImageUploadConfig\r\n}\r\n\r\nexport interface UseToolbarReturn {\r\n config: ToolbarButtonConfig[]\r\n extraItemsConfig: ToolbarButtonConfig[]\r\n handleClick: (button: ToolbarButtonConfig) => void\r\n}\r\n\r\nexport function useToolbar(\r\n editorView: EditorView | null,\r\n options?: UseToolbarOptions\r\n): UseToolbarReturn {\r\n const { extraItems, uploadConfig } = options || {}\r\n const config = useMemo(() => {\r\n const base = createToolbarConfig(uploadConfig)\r\n return base\r\n }, [uploadConfig])\r\n\r\n const extraItemsConfig = useMemo(() => {\r\n return extraItems || []\r\n }, [extraItems])\r\n\r\n const handleClick = useCallback((button: ToolbarButtonConfig) => {\r\n if (!editorView) return\r\n\r\n // 如果配置了 wrapTags,优先使用 toggleWrap\r\n if (button.wrapTags) {\r\n const [openTag, closeTag] = button.wrapTags\r\n toggleWrap(editorView, openTag, closeTag)\r\n return\r\n }\r\n\r\n // 有 handler 则执行自定义逻辑\r\n if (button.handler) {\r\n editorView.focus()\r\n button.handler(editorView, editorView.state)\r\n }\r\n }, [editorView])\r\n\r\n return { config, extraItemsConfig, handleClick }\r\n}","import { Button, Dropdown, Tooltip } from 'antd'\r\nimport { DownOutlined } from '@ant-design/icons'\r\nimport type { ToolbarButtonConfig } from '../../../types'\r\n\r\ninterface Props {\r\n item: ToolbarButtonConfig\r\n onClick: (item: ToolbarButtonConfig) => void\r\n}\r\n\r\nexport function ToolbarItemRenderer({ item, onClick }: Props) {\r\n const Icon = item.icon!\r\n\r\n // 有 children 的渲染为下拉菜单\r\n if (item.children && item.children.length > 0) {\r\n return (\r\n <>\r\n {item.separatorBefore && <div className=\"toolbar-separator\" />}\r\n <div className=\"toolbar-group\">\r\n <Tooltip title={item.label}>\r\n <Dropdown\r\n menu={{\r\n items: item.children.map(child => ({\r\n type: 'item',\r\n key: child.id ?? '',\r\n label: (\r\n <span onClick={() => onClick(child)}>\r\n {child.icon && (() => { const ChildIcon = child.icon; return <ChildIcon />; })()}\r\n {' '}{child.label}\r\n </span>\r\n ),\r\n })),\r\n }}\r\n placement=\"bottomLeft\"\r\n >\r\n <Button className=\"toolbar-button\" type=\"text\" size=\"small\">\r\n <Icon />\r\n <DownOutlined style={{ marginLeft: 2, fontSize: 10 }} />\r\n </Button>\r\n </Dropdown>\r\n </Tooltip>\r\n </div>\r\n </>\r\n )\r\n }\r\n\r\n // 普通按钮\r\n const isDisabled = item.disabled\r\n return (\r\n <>\r\n {item.separatorBefore && <div className=\"toolbar-separator\" />}\r\n <div className=\"toolbar-group\">\r\n <Tooltip title={item.label}>\r\n <Button\r\n id={item.id}\r\n className=\"toolbar-button\"\r\n type=\"text\"\r\n size=\"small\"\r\n disabled={isDisabled}\r\n onClick={() => !isDisabled && onClick(item)}\r\n >\r\n <Icon />\r\n </Button>\r\n </Tooltip>\r\n </div>\r\n </>\r\n )\r\n}",".container {\r\n padding: 4px;\r\n display: block;\r\n min-width: 200px;\r\n background: var(--remons-md-editor-bg-picker);\r\n border: 1px solid var(--remons-md-editor-color-border-light);\r\n border-radius: 6px;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n.grid {\r\n display: grid;\r\n gap: 2px;\r\n transition: all 0.1s ease;\r\n justify-content: flex-start;\r\n\r\n .cell {\r\n width: 24px;\r\n height: 24px;\r\n border: 1px solid var(--remons-md-editor-color-border-light);\r\n border-radius: 2px;\r\n background: transparent;\r\n cursor: pointer;\r\n transition: all 0.1s ease;\r\n\r\n &.cellActive {\r\n border-color: var(--remons-md-editor-color-cell-active);\r\n background: var(--remons-md-editor-bg-cell-active);\r\n }\r\n }\r\n}\r\n\r\n.hint {\r\n padding: 12px 16px;\r\n color: var(--remons-md-editor-color-hint);\r\n font-size: 12px;\r\n text-align: center;\r\n cursor: pointer;\r\n}\r\n\r\n.label {\r\n margin-top: 8px;\r\n font-size: 13px;\r\n color: var(--remons-md-editor-color-label);\r\n font-weight: 500;\r\n min-height: 20px;\r\n text-align: center;\r\n}\r\n","import { useState, useRef, useEffect, useCallback } from 'react'\r\nimport styles from './index.module.less'\r\n\r\ninterface TableSize {\r\n rows: number\r\n cols: number\r\n}\r\n\r\ninterface TablePickerProps {\r\n onSelect: (size: TableSize) => void\r\n}\r\n\r\nconst MAX_ROW = 8\r\nconst MAX_COL = 8\r\n\r\nexport default function TablePicker({ onSelect }: TablePickerProps) {\r\n const [hoverSize, setHoverSize] = useState({ row: 0, col: 0 })\r\n const [confirmedSize, setConfirmedSize] = useState({ row: 0, col: 0 })\r\n const maxColRef = useRef(0)\r\n const prevRowRef = useRef(0)\r\n const timerIdRef = useRef<any>(null)\r\n const refreshTimerRef = useRef<any>(null)\r\n const commitRef = useRef<{ cols: number; rows: number } | null>(null)\r\n\r\n const clearTimer = useCallback(() => {\r\n if (timerIdRef.current) {\r\n clearTimeout(timerIdRef.current)\r\n timerIdRef.current = null\r\n }\r\n }, [])\r\n\r\n const clearFlash = useCallback(() => {\r\n if (refreshTimerRef.current) {\r\n clearInterval(refreshTimerRef.current)\r\n refreshTimerRef.current = null\r\n }\r\n }, [])\r\n\r\n useEffect(\r\n () => () => {\r\n // 组件卸载时清理定时器\r\n if (timerIdRef.current) clearTimeout(timerIdRef.current)\r\n if (refreshTimerRef.current) clearInterval(refreshTimerRef.current)\r\n },\r\n []\r\n )\r\n\r\n /**\r\n * 扩展选中区域至 (col, row)\r\n */\r\n function extend(col: number, row: number) {\r\n if (row < prevRowRef.current || col < maxColRef.current) {\r\n // 鼠标回撤(向上或向左),重置列跟踪\r\n maxColRef.current = 0\r\n }\r\n if (col > maxColRef.current) {\r\n maxColRef.current = col\r\n }\r\n setHoverSize({ row, col })\r\n setConfirmedSize({ row, col: maxColRef.current })\r\n\r\n if (row === 1) {\r\n commitRef.current = { cols: maxColRef.current, rows: 1 }\r\n }\r\n }\r\n\r\n /**\r\n * 跳跃动画效果\r\n */\r\n function flash(\r\n col: number,\r\n dir: 1 | -1,\r\n limit: number,\r\n finalCallback: (finalCol: number, finalRow: number) => void\r\n ) {\r\n let current = dir === 1 ? 1 : limit\r\n const step = dir === 1 ? 1 : -1\r\n\r\n refreshTimerRef.current = setInterval(() => {\r\n setHoverSize({ row: current, col })\r\n if (current > confirmedSize.row || dir === -1) {\r\n maxColRef.current = Math.min(MAX_COL, col)\r\n }\r\n current += step\r\n if ((dir === 1 && current > limit) || (dir === -1 && current < 1)) {\r\n clearInterval(refreshTimerRef.current)\r\n refreshTimerRef.current = null\r\n const finalRow = current - step\r\n setHoverSize({ row: finalRow, col })\r\n finalCallback(col, finalRow)\r\n }\r\n }, 50)\r\n }\r\n\r\n /**\r\n * 核心逻辑:鼠标进入格子\r\n */\r\n function onCellEnterCheck(index: number) {\r\n clearTimer()\r\n clearFlash()\r\n const row = Math.floor(index / MAX_COL) + 1\r\n const col = (index % MAX_COL) + 1\r\n\r\n const prevRow = prevRowRef.current\r\n const isJump = Math.abs(row - prevRow) > 1\r\n const isDown = row > prevRow\r\n prevRowRef.current = row\r\n\r\n if (!isJump) {\r\n // 正常悬停:相邻行或同一行\r\n extend(col, row)\r\n } else if (isDown) {\r\n // 快速向下跳跃\r\n if (col > maxColRef.current || maxColRef.current >= MAX_COL) {\r\n const finalRow = Math.min(row, MAX_ROW)\r\n flash(col, 1, finalRow, (c, r) => {\r\n setConfirmedSize({ row: r, col: c })\r\n })\r\n } else {\r\n extend(col, row)\r\n }\r\n } else {\r\n // 快速向上跳跃:重置列跟踪并播放动画\r\n maxColRef.current = 0\r\n flash(col, -1, row, (c, r) => {\r\n setConfirmedSize({ row: r, col: c })\r\n if (r === 1) {\r\n commitRef.current = { cols: Math.min(MAX_COL, col), rows: 1 }\r\n setConfirmedSize({ row: 1, col: Math.min(MAX_COL, col) })\r\n }\r\n })\r\n }\r\n }\r\n\r\n function onMouseDown() {\r\n const size = commitRef.current || { cols: maxColRef.current, rows: confirmedSize.row }\r\n if (size.rows > 0 && size.cols > 0) {\r\n onSelect(size)\r\n }\r\n }\r\n\r\n return (\r\n <div\r\n className={styles.container}\r\n onMouseDown={onMouseDown}\r\n >\r\n <div\r\n className={styles.grid}\r\n style={{ gridTemplateColumns: `repeat(${MAX_COL}, 24px)` }}\r\n >\r\n {Array.from({ length: MAX_ROW * MAX_COL }).map((_, i) => {\r\n const row = Math.floor(i / MAX_COL) + 1\r\n const col = (i % MAX_COL) + 1\r\n const isSelected = row <= hoverSize.row && col <= maxColRef.current\r\n return (\r\n <div\r\n key={i}\r\n className={`${styles.cell} ${isSelected ? styles.cellActive : ''}`}\r\n onMouseEnter={() => onCellEnterCheck(i)}\r\n />\r\n )\r\n })}\r\n </div>\r\n <div className={styles.label}>\r\n {hoverSize.row} x {maxColRef.current || 1}\r\n </div>\r\n </div>\r\n )\r\n}\r\n","import React, { useCallback, useRef } from 'react'\r\nimport { EditorView } from '@codemirror/view'\r\nimport { Button, Dropdown } from 'antd'\r\nimport { TableOutlined } from '@ant-design/icons'\r\nimport TablePicker from './index'\r\n\r\nexport default function TableDropdown({ editorView }: { editorView: EditorView | null }) {\r\n const [open, setOpen] = React.useState(false)\r\n const openCountRef = useRef(0)\r\n\r\n const handleTableSelect = useCallback((rows: number, cols: number) => {\r\n if (!editorView || rows <= 0 || cols <= 0) return\r\n editorView.focus()\r\n const headerCells = Array(cols).fill(null).map((_, i) => ` 列${i + 1} `).join('|')\r\n const separator = Array(cols).fill(' --- ').join('|')\r\n const dataCell = Array(cols).fill(' 内容 ').join('|')\r\n const dataRows = Array(rows).fill(`|${dataCell}|`).join('\\n')\r\n const table = `\\n|${headerCells}|\\n|${separator}|\\n${dataRows}\\n`\r\n const { from } = editorView.state.selection.main\r\n editorView.dispatch({ changes: { from, insert: table } })\r\n }, [editorView])\r\n\r\n return (\r\n <Dropdown\r\n trigger={['click']}\r\n open={open}\r\n onOpenChange={setOpen}\r\n popupRender={() => {\r\n openCountRef.current++\r\n return (\r\n <div style={{ padding: 4 }} onClick={(e) => e.stopPropagation()}>\r\n <TablePicker\r\n key={openCountRef.current}\r\n onSelect={(size) => {\r\n handleTableSelect(size.rows, size.cols)\r\n setOpen(false)\r\n }}\r\n />\r\n </div>\r\n )\r\n }}\r\n placement=\"bottomLeft\"\r\n >\r\n <Button className=\"toolbar-button\" type=\"text\" size=\"small\" title=\"表格\">\r\n <TableOutlined />\r\n </Button>\r\n </Dropdown>\r\n )\r\n}","import { useCallback } from 'react'\r\nimport { EditorView } from '@codemirror/view'\r\nimport { Button } from 'antd'\r\nimport { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons'\r\nimport { useToolbar } from './hooks/useToolbar'\r\nimport { ToolbarItemRenderer } from './renderers/ToolbarItemRenderer'\r\nimport TableDropdown from './renderers/TablePicker/TableDropdown'\r\nimport type { ToolbarButtonConfig, ImageUploadConfig } from '../../types'\r\n\r\ninterface ToolbarProps {\r\n editorView: EditorView | null\r\n fullscreen?: boolean\r\n onToggleFullscreen?: () => void\r\n /** 第三方扩展的按钮配置,将追加到工具栏末尾 */\r\n extraItems?: ToolbarButtonConfig[]\r\n /** 图片上传配置 */\r\n uploadConfig?: ImageUploadConfig\r\n}\r\n\r\nexport default function Toolbar({ editorView, fullscreen = true, onToggleFullscreen, extraItems, uploadConfig }: ToolbarProps) {\r\n const { config, extraItemsConfig, handleClick } = useToolbar(editorView, { extraItems, uploadConfig })\r\n\r\n const renderFullscreen = useCallback(() => {\r\n if (!onToggleFullscreen) return null\r\n const Icon = fullscreen ? FullscreenExitOutlined : FullscreenOutlined\r\n return (\r\n <Button\r\n className=\"toolbar-button\"\r\n type=\"text\"\r\n size=\"small\"\r\n title={fullscreen ? '退出全屏' : '全屏'}\r\n onClick={() => {\r\n onToggleFullscreen()\r\n }}\r\n >\r\n <Icon />\r\n </Button>\r\n )\r\n }, [fullscreen, onToggleFullscreen])\r\n\r\n function isSeparator(item: ToolbarButtonConfig): boolean {\r\n return !!(!item.id && item.separatorBefore)\r\n }\r\n\r\n return (\r\n <div className=\"toolbar\">\r\n {config.map((item, idx) => {\r\n if (isSeparator(item)) {\r\n return <div key={`sep-${idx}`} className=\"toolbar-separator\" />\r\n }\r\n return (\r\n <ToolbarItemRenderer\r\n key={item.id}\r\n item={item}\r\n onClick={handleClick}\r\n />\r\n )\r\n })}\r\n <TableDropdown editorView={editorView} />\r\n {extraItemsConfig?.map((item, idx) => {\r\n if (isSeparator(item)) {\r\n return <div key={`extra-sep-${idx}`} className=\"toolbar-separator\" />\r\n }\r\n return (\r\n <ToolbarItemRenderer\r\n key={item.id}\r\n item={item}\r\n onClick={handleClick}\r\n />\r\n )\r\n })}\r\n {renderFullscreen()}\r\n </div>\r\n )\r\n}","import { useState, useMemo, useEffect, type FC } from 'react'\r\nimport { Modal, Form, Input, InputNumber, Select, Switch, Slider, Rate, DatePicker, ColorPicker } from 'antd'\r\nimport type { FormInstance, FormItemProps } from 'antd'\r\nimport componentRegistry from '../../registry/componentRegistry'\r\nimport type { DialogField } from '../../types'\r\n\r\n/**\r\n * 组件类型到 antd 表单组件的映射\r\n */\r\nconst FormComponents: Record<string, FC<any>> = {\r\n input: Input,\r\n textarea: Input.TextArea,\r\n number: InputNumber,\r\n select: Select,\r\n switch: Switch,\r\n slider: Slider,\r\n rate: Rate,\r\n color: ColorPicker,\r\n date: DatePicker,\r\n dateRange: DatePicker.RangePicker,\r\n}\r\n\r\n/**\r\n * 渲染对应类型的 antd 表单组件\r\n */\r\nfunction renderFormItemComponent(field: DialogField) {\r\n const props = field.componentProps || {}\r\n const Component = field.componentType ? FormComponents[field.componentType] : Input\r\n return <Component {...props} />\r\n}\r\n\r\n/**\r\n * 根据 fields 自动生成 Form.Item 列表\r\n */\r\nfunction renderAutoForm(form: FormInstance, fields: DialogField[]) {\r\n if (!fields || fields.length === 0) {\r\n return null\r\n }\r\n\r\n return (\r\n <Form form={form} layout=\"vertical\">\r\n {fields.map(field => {\r\n if (!field.componentType) {\r\n return null\r\n }\r\n\r\n const formItemProps: FormItemProps = {\r\n name: field.key,\r\n label: field.name || field.key,\r\n valuePropName: field.componentType === 'switch' ? 'checked' : undefined,\r\n ...field.componentProps,\r\n }\r\n\r\n return (\r\n <Form.Item key={field.key} {...formItemProps}>\r\n {renderFormItemComponent(field)}\r\n </Form.Item>\r\n )\r\n })}\r\n </Form>\r\n )\r\n}\r\n\r\n/**\r\n * 弹窗编辑容器属性的组件\r\n */\r\ninterface EditDialogProps {\r\n /** 弹窗是否显示 */\r\n visible: boolean\r\n /** 容器类型名称 */\r\n typeName: string\r\n /** 当前属性值 */\r\n currentProps: Record<string, string>\r\n /** 保存回调 */\r\n onSave: (props: Record<string, string>) => void\r\n /** 关闭回调 */\r\n onClose: () => void\r\n}\r\n\r\n/**\r\n * 属性编辑弹窗组件\r\n * 根据组件 schema 的 renderDialog 函数渲染弹窗内容\r\n */\r\nexport default function EditDialog({ visible, typeName, currentProps, onSave, onClose }: EditDialogProps) {\r\n const schema = componentRegistry.get(typeName)\r\n const [formProps, setFormProps] = useState<Record<string, string>>({})\r\n const [form] = Form.useForm()\r\n\r\n // 当弹窗打开时,初始化表单值\r\n const mergedProps = useMemo(() => {\r\n if (!schema) return currentProps\r\n const defaults: Record<string, string> = {}\r\n for (const field of schema.fields || []) {\r\n defaults[field.key] = field.defaultValue ?? ''\r\n }\r\n return { ...defaults, ...currentProps }\r\n }, [schema, currentProps])\r\n\r\n // 弹窗打开时设置表单值\r\n useEffect(() => {\r\n if (visible) {\r\n form.setFieldsValue(mergedProps)\r\n setFormProps({})\r\n }\r\n }, [visible, mergedProps, form])\r\n\r\n const handleDialogChange = (key: string, value: string) => {\r\n setFormProps(prev => ({ ...prev, [key]: value }))\r\n }\r\n\r\n const handleOk = async () => {\r\n let finalProps: Record<string, any> = visible ? { ...mergedProps, ...formProps } : mergedProps\r\n\r\n // 尝试从 Form 获取值(如果用户使用了 Form.Item 或自动表单)\r\n try {\r\n const formValues = await form.validateFields()\r\n finalProps = { ...finalProps, ...formValues }\r\n } catch {\r\n // 用户没有使用 Form.Item,使用原有的逻辑\r\n }\r\n\r\n onSave(finalProps)\r\n }\r\n\r\n const handleClose = () => {\r\n setFormProps({})\r\n onClose()\r\n }\r\n\r\n if (!schema) {\r\n return null\r\n }\r\n\r\n // 构建 context 对象,供 renderDialog 使用\r\n const context = {\r\n props: mergedProps,\r\n form,\r\n onChange: handleDialogChange,\r\n onSave,\r\n }\r\n\r\n // 渲染策略:\r\n // 1. 如果有 renderDialog,使用自定义渲染\r\n // 2. 否则如果 fields 中有 componentType,自动生成表单\r\n // 3. 否则不渲染任何内容\r\n const renderDialogContent = () => {\r\n if (schema.renderDialog) {\r\n return schema.renderDialog(context)\r\n }\r\n // 检查是否有字段配置了 componentType\r\n const hasComponentType = schema.fields?.some(f => f.componentType)\r\n if (hasComponentType && schema.fields) {\r\n return renderAutoForm(form, schema.fields)\r\n }\r\n return null\r\n }\r\n\r\n return (\r\n <Modal\r\n title={`${schema.label} 属性编辑`}\r\n open={visible}\r\n onOk={handleOk}\r\n onCancel={handleClose}\r\n okText=\"保存\"\r\n cancelText=\"取消\"\r\n >\r\n {renderDialogContent()}\r\n </Modal>\r\n )\r\n}","import type { EditorView } from '@codemirror/view'\r\n\r\n/**\r\n * 从属性对象生成 JSON 属性行。\r\n * 格式: { key: 'value', key2: 'value2' }\r\n */\r\nexport function writeContainerProps(props: Record<string, string>): string {\r\n const entries = Object.entries(props)\r\n .map(([k, v]) => `${k}: '${v}'`)\r\n .join(', ')\r\n return entries ? `{ ${entries} }` : '{}'\r\n}\r\n\r\n/**\r\n * 更新编辑器文档中的容器属性。\r\n * 替换 JSON 属性行(::: 打开行之后的一行)为新属性。\r\n */\r\nexport function updateContainerProps(\r\n view: EditorView,\r\n propsLineFrom: number,\r\n propsLineTo: number,\r\n newProps: Record<string, string>\r\n): void {\r\n const newPropsLine = writeContainerProps(newProps)\r\n view.dispatch({\r\n changes: {\r\n from: propsLineFrom,\r\n to: propsLineTo,\r\n insert: newPropsLine,\r\n },\r\n })\r\n}\r\n\r\n/**\r\n * 在当前光标位置插入新容器。\r\n * 创建 :::type 打开行 + JSON 属性 + ::: 关闭行的结构。\r\n */\r\nexport function insertContainer(\r\n view: EditorView,\r\n typeName: string,\r\n defaultProps: Record<string, string>\r\n): void {\r\n const { from } = view.state.selection.main\r\n const propsLine = writeContainerProps(defaultProps)\r\n const container = `:::${typeName}\\n${propsLine}\\n:::\\n`\r\n view.dispatch({ changes: { from, insert: container } })\r\n}","import { useState, useEffect, useCallback } from 'react'\r\n\r\nexport function useFullscreen() {\r\n const [fullscreen, setFullscreen] = useState(false)\r\n\r\n const toggleFullscreen = useCallback(() => {\r\n if (document.fullscreenElement) {\r\n document.exitFullscreen().catch((e) => {\r\n console.error('退出全屏失败:', e)\r\n })\r\n } else {\r\n const el = document.documentElement\r\n const requestMethod = el.requestFullscreen ||\r\n (el as any).webkitRequestFullscreen ||\r\n (el as any).mozRequestFullScreen ||\r\n (el as any).msRequestFullscreen\r\n if (requestMethod) {\r\n requestMethod.call(el).catch((e) => {\r\n console.error('进入全屏失败:', e)\r\n })\r\n }\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n const handleFullscreenChange = () => {\r\n setFullscreen(!!document.fullscreenElement)\r\n }\r\n document.addEventListener('fullscreenchange', handleFullscreenChange)\r\n document.addEventListener('webkitfullscreenchange', handleFullscreenChange)\r\n return () => {\r\n document.removeEventListener('fullscreenchange', handleFullscreenChange)\r\n document.removeEventListener('webkitfullscreenchange', handleFullscreenChange)\r\n }\r\n }, [])\r\n\r\n return { fullscreen, toggleFullscreen }\r\n}\r\n","import { useEffect, useRef } from 'react'\r\n\r\n/**\r\n * 双向滚动同步 Hook\r\n * 编辑器与预览区互相同步滚动位置(基于比例)\r\n * 使用 síncing 锁防止双向循环触发\r\n */\r\nexport function useScrollSync(\r\n sourceRef: React.RefObject<HTMLElement | null>,\r\n targetRef: React.RefObject<HTMLDivElement | null>\r\n) {\r\n const rafIdRef = useRef<number | null>(null)\r\n // 锁:'source' 表示正在同步 source→target,'target' 表示反向\r\n const syncingRef = useRef<'source' | 'target' | null>(null)\r\n\r\n const syncScroll = (\r\n from: 'source' | 'target',\r\n fromEl: HTMLElement,\r\n toEl: HTMLElement\r\n ) => {\r\n if (rafIdRef.current) return\r\n rafIdRef.current = requestAnimationFrame(() => {\r\n const fromScrollHeight = fromEl.scrollHeight - fromEl.clientHeight\r\n if (fromScrollHeight <= 0) { rafIdRef.current = null; syncingRef.current = null; return }\r\n const ratio = fromEl.scrollTop / fromScrollHeight\r\n const toScrollHeight = toEl.scrollHeight - toEl.clientHeight\r\n if (toScrollHeight > 0) {\r\n syncingRef.current = from // 加锁\r\n toEl.scrollTop = ratio * toScrollHeight\r\n // 下一帧解锁,让对面的 listener 可以响应新的一次滚动\r\n requestAnimationFrame(() => { syncingRef.current = null })\r\n }\r\n rafIdRef.current = null\r\n })\r\n }\r\n\r\n useEffect(() => {\r\n const source = sourceRef.current\r\n const target = targetRef.current\r\n if (!source || !target) return\r\n\r\n const onSourceScroll = () => {\r\n if (syncingRef.current !== null) return // 锁住,正在被反向同步\r\n const s = sourceRef.current!\r\n const t = targetRef.current!\r\n syncScroll('source', s, t)\r\n }\r\n\r\n const onTargetScroll = () => {\r\n if (syncingRef.current !== null) return // 锁住,正在被正向同步\r\n const s = sourceRef.current!\r\n const t = targetRef.current!\r\n syncScroll('target', t, s)\r\n }\r\n\r\n source.addEventListener('scroll', onSourceScroll, { passive: true })\r\n target.addEventListener('scroll', onTargetScroll, { passive: true })\r\n\r\n return () => {\r\n source.removeEventListener('scroll', onSourceScroll)\r\n target.removeEventListener('scroll', onTargetScroll)\r\n if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current)\r\n }\r\n }, [sourceRef, targetRef])\r\n}\r\n","import { useState, useRef, useCallback, useEffect, forwardRef, useImperativeHandle } from 'react'\r\nimport { message } from 'antd'\r\nimport Editor from './components/Editor'\r\nimport Preview from './components/Preview'\r\nimport SplitPanels from './components/Panel/SplitPanels'\r\nimport Toolbar from './components/Toolbar'\r\nimport EditDialog from './components/Dialog/EditDialog'\r\nimport componentRegistry from './registry/componentRegistry'\r\nimport { updateContainerProps, insertContainer } from './utils/writeContainer'\r\nimport type { ToolbarButtonConfig, ImageUploadConfig } from './types'\r\nimport type { PreviewOptions } from './components/Preview'\r\nimport { ReadOutlined } from '@ant-design/icons'\r\nimport { useFullscreen } from './hooks/useFullscreen'\r\nimport { useScrollSync } from './hooks/useScrollSync'\r\n\r\nexport interface MarkdownEditorRef {\r\n getContent: () => string\r\n}\r\n\r\nexport interface MarkdownEditorProps {\r\n /** 初始内容 */\r\n defaultValue?: string\r\n /** 受控内容 */\r\n value?: string\r\n /** 内容变化回调 */\r\n onChange?: (value: string) => void\r\n /** 是否显示预览面板 */\r\n showPreview?: boolean\r\n /** 是否支持全屏 */\r\n fullscreen?: boolean\r\n /** Preview 渲染配置 */\r\n previewOptions?: PreviewOptions\r\n /** 图片上传配置 */\r\n uploadConfig?: ImageUploadConfig\r\n}\r\n\r\nexport default forwardRef<MarkdownEditorRef, MarkdownEditorProps>(function MarkdownEditor({\r\n defaultValue = '',\r\n value,\r\n onChange,\r\n showPreview = true,\r\n fullscreen: fullscreenProp = true,\r\n previewOptions,\r\n uploadConfig,\r\n}, ref) {\r\n const [content, setContent] = useState(value ?? defaultValue)\r\n const [editorView, setEditorView] = useState<any>(null)\r\n const scrollDOMRef = useRef<HTMLElement | null>(null)\r\n const previewElRef = useRef<HTMLDivElement | null>(null)\r\n const { fullscreen, toggleFullscreen } = useFullscreen()\r\n useScrollSync(scrollDOMRef, previewElRef)\r\n\r\n // 容器编辑弹窗状态\r\n const [dialogVisible, setDialogVisible] = useState(false)\r\n const [dialogTypeName, setDialogTypeName] = useState('')\r\n const [dialogProps, setDialogProps] = useState<Record<string, string>>({})\r\n const [dialogPropsRange, setDialogPropsRange] = useState<[number, number]>([0, 0])\r\n\r\n // 受控模式:外部 value 变化时同步\r\n useEffect(() => {\r\n if (value !== undefined) {\r\n setContent(value)\r\n }\r\n }, [value])\r\n\r\n const internalSetContent = useCallback((newContent: string) => {\r\n setContent(newContent)\r\n onChange?.(newContent)\r\n }, [onChange])\r\n\r\n // 暴露 getContent 方法\r\n useImperativeHandle(ref, () => ({\r\n getContent: () => content,\r\n }), [content])\r\n\r\n // 从注册中心自动生成工具栏按钮\r\n const extraToolbarItems: ToolbarButtonConfig[] = componentRegistry.getAll().flatMap(schema => {\r\n // 支持 wrapTags 的标签包裹模式\r\n if (schema.wrapTags) {\r\n return {\r\n id: `wrap-${schema.name}`,\r\n label: schema.label,\r\n icon: () => (schema.icon ?? <ReadOutlined />),\r\n wrapTags: schema.wrapTags,\r\n }\r\n }\r\n // 容器插入模式\r\n const defaultProps: Record<string, string> = {}\r\n for (const field of schema?.fields ?? []) {\r\n defaultProps[field.key] = field.defaultValue ?? ''\r\n }\r\n return {\r\n id: `container-${schema.name}`,\r\n label: schema.label,\r\n icon: () => (schema.icon ?? <ReadOutlined />),\r\n handler: (view, _state) => insertContainer(view, schema.name, defaultProps),\r\n }\r\n })\r\n\r\n // 滚动同步 (already handled by useScrollSync hook)\r\n const handleScrollReady = useCallback((scrollDOM: HTMLElement) => {\r\n scrollDOMRef.current = scrollDOM\r\n }, [])\r\n\r\n const handlePreviewRef = useCallback((node: HTMLDivElement | null) => {\r\n previewElRef.current = node\r\n }, [])\r\n\r\n const handleViewReady = useCallback((view: any) => {\r\n setEditorView(view)\r\n }, [])\r\n\r\n // 编辑容器属性时触发\r\n const handleEditContainer = useCallback((_view: any, typeName: string, propsLineFrom: number, propsLineTo: number, currentProps: Record<string, string>) => {\r\n setDialogTypeName(typeName)\r\n setDialogProps({ ...currentProps })\r\n setDialogPropsRange([propsLineFrom, propsLineTo])\r\n setDialogVisible(true)\r\n }, [])\r\n\r\n // 保存容器属性\r\n const handleDialogSave = useCallback((newProps: Record<string, string>) => {\r\n setDialogVisible(false)\r\n if (editorView) {\r\n updateContainerProps(editorView, dialogPropsRange[0], dialogPropsRange[1], newProps)\r\n }\r\n }, [editorView, dialogPropsRange])\r\n\r\n // 关闭弹窗\r\n const handleDialogClose = useCallback(() => {\r\n setDialogVisible(false)\r\n }, [])\r\n\r\n return (\r\n <div className={fullscreen ? 'markdown-editor-app fullscreen' : 'markdown-editor-app'}>\r\n <Toolbar\r\n editorView={editorView}\r\n fullscreen={fullscreen}\r\n onToggleFullscreen={fullscreenProp ? toggleFullscreen : undefined}\r\n extraItems={extraToolbarItems}\r\n uploadConfig={uploadConfig}\r\n />\r\n {showPreview ? (\r\n <SplitPanels\r\n leftPanel={\r\n <Editor\r\n value={content}\r\n onChange={internalSetContent}\r\n onScrollReady={handleScrollReady}\r\n onViewReady={handleViewReady}\r\n onEditContainer={handleEditContainer}\r\n uploadConfig={uploadConfig}\r\n onMessageNoUploadConfig={() => message.warning('请先配置图片上传功能')}\r\n />\r\n }\r\n rightPanel={\r\n <Preview\r\n content={content}\r\n ref={handlePreviewRef}\r\n previewOptions={previewOptions}\r\n />\r\n }\r\n />\r\n ) : (\r\n <Editor\r\n value={content}\r\n onChange={internalSetContent}\r\n onScrollReady={handleScrollReady}\r\n onViewReady={handleViewReady}\r\n onEditContainer={handleEditContainer}\r\n uploadConfig={uploadConfig}\r\n onMessageNoUploadConfig={() => message.warning('请先配置图片上传功能')}\r\n />\r\n )}\r\n {/* 容器属性编辑弹窗 */}\r\n <EditDialog\r\n visible={dialogVisible}\r\n typeName={dialogTypeName}\r\n currentProps={dialogProps}\r\n onSave={handleDialogSave}\r\n onClose={handleDialogClose}\r\n />\r\n </div>\r\n )\r\n})\r\n","import { useEffect } from 'react'\r\nimport componentRegistry from '../registry/componentRegistry'\r\nimport type { ComponentSchema } from '../types'\r\n\r\n/**\r\n * 注册自定义容器组件到工具栏。支持单个或批量注册。\r\n * 支持两种模式:\r\n * \r\n * 1. 容器模式(linkCard):name + fields + renderDialog\r\n * 插入 :::name 格式的容器,支持弹窗编辑属性\r\n * \r\n * 2. 标签包裹模式:name + wrapTags\r\n * 插入简单的标签包裹文本,如 <plugin-container>...</plugin-container>\r\n * \r\n * @example 容器模式 - 使用 fields 自动生成表单(最简)\r\n * ```tsx\r\n * const schema: ComponentSchema = {\r\n * name: 'alert',\r\n * label: '警告框',\r\n * icon: <AlertOutlined />,\r\n * fields: [\r\n * { key: 'type', name: '类型', componentType: 'select',\r\n * componentProps: { options: [{ value: 'price', label: '价格' }, { value: 'info', label: '信息' }] } },\r\n * { key: 'content', name: '内容', componentType: 'textarea',\r\n * componentProps: { rows: 3 } },\r\n * { key: 'enabled', name: '启用', componentType: 'switch' },\r\n * ],\r\n * }\r\n * // 支持的 componentType: 'input' | 'textarea' | 'number' | 'select' | 'switch' | 'slider' | 'rate' | 'color' | 'date' | 'dateRange'\r\n * ```\r\n * \r\n * @example 容器模式 - 使用 Form.Item 自动绑定(推荐)\r\n * ```tsx\r\n * const schema: ComponentSchema = {\r\n * name: 'alert',\r\n * label: '警告框',\r\n * icon: <AlertOutlined />,\r\n * fields: [{ key: 'level', defaultValue: 'info' }],\r\n * renderDialog: ({ form }) => (\r\n * <Form form={form} layout=\"vertical\">\r\n * <Form.Item name=\"level\" label=\"级别\">\r\n * <Input />\r\n * </Form.Item>\r\n * </Form>\r\n * ),\r\n * }\r\n * \r\n * function MyPage() {\r\n * useRegisterToolbar(schema)\r\n * return <MarkdownEditor />\r\n * }\r\n * ```\r\n * \r\n * @example 容器模式 - 手动控制\r\n * ```tsx\r\n * const schema: ComponentSchema = {\r\n * name: 'alert',\r\n * label: '警告框',\r\n * icon: <AlertOutlined />,\r\n * fields: [{ key: 'level', defaultValue: 'info' }],\r\n * renderDialog: ({ props, onChange }) => (\r\n * <Input value={props.level} onChange={e => onChange('level', e.target.value)} />\r\n * ),\r\n * }\r\n * ```\r\n * \r\n * @example 容器模式 - 完全自定义弹窗\r\n * ```tsx\r\n * const schema: ComponentSchema = {\r\n * name: 'alert',\r\n * label: '警告框',\r\n * icon: <AlertOutlined />,\r\n * fields: [{ key: 'level', defaultValue: 'info' }],\r\n * renderDialog: ({ props, onSave }) => (\r\n * <MyCustomEditor\r\n * value={props.level}\r\n * onSave={({ level }) => onSave({ level })}\r\n * />\r\n * ),\r\n * }\r\n * ```\r\n * \r\n * @example 标签包裹模式\r\n * ```tsx\r\n * function MyPage() {\r\n * useRegisterToolbar({\r\n * name: 'plugin-container',\r\n * label: '自定义容器',\r\n * icon: <AlertOutlined />,\r\n * wrapTags: ['<plugin-container>', '</plugin-container>'],\r\n * })\r\n * return <MarkdownEditor />\r\n * }\r\n * ```\r\n * \r\n * @example 批量注册\r\n * ```tsx\r\n * function MyPage() {\r\n * useRegisterToolbar([schema1, schema2, schema3])\r\n * return <MarkdownEditor />\r\n * }\r\n * ```\r\n */\r\nexport function useRegisterToolbar(schemas: ComponentSchema | ComponentSchema[]) {\r\n const schemaList: ComponentSchema[] = Array.isArray(schemas) ? schemas : [schemas]\r\n\r\n useEffect(() => {\r\n schemaList.forEach(schema => {\r\n componentRegistry.register(schema.name, schema)\r\n })\r\n return () => {\r\n schemaList.forEach(schema => {\r\n componentRegistry.unregister(schema.name)\r\n })\r\n }\r\n }, [schemaList])\r\n}\r\n"],"mappings":"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"}