This is an automated email from the ASF dual-hosted git repository. robin0716 pushed a commit to branch feat/1.7.2/ui in repository https://gitbox.apache.org/repos/asf/answer.git
commit 3d43700556306965f7816e6cdb031327c16193a6 Author: robin <[email protected]> AuthorDate: Tue Dec 16 14:50:29 2025 +0800 refactor(editor): streamline editor component structure and enhance command methods - Removed unnecessary conditional rendering in the MDEditor component for the PluginRender. - Simplified the MarkdownEditor component's useEffect hooks for better clarity. - Refactored command methods to utilize self-referencing for improved maintainability. --- ui/src/components/Editor/MarkdownEditor.tsx | 9 +--- ui/src/components/Editor/index.tsx | 50 +++++++++++----------- .../components/Editor/utils/codemirror/commands.ts | 43 ++++++++++--------- 3 files changed, 48 insertions(+), 54 deletions(-) diff --git a/ui/src/components/Editor/MarkdownEditor.tsx b/ui/src/components/Editor/MarkdownEditor.tsx index 10145a22..fe5d8bb4 100644 --- a/ui/src/components/Editor/MarkdownEditor.tsx +++ b/ui/src/components/Editor/MarkdownEditor.tsx @@ -55,30 +55,25 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ autoFocus, }); - // 初始化内容(只在编辑器创建时执行) useEffect(() => { if (!editor) { return; } - // 初始化编辑器内容 editor.setValue(value || ''); lastSyncedValueRef.current = value || ''; onEditorReady?.(editor); - }, [editor]); // 只在编辑器创建时执行 + }, [editor]); - // 当外部 value 变化时更新(但不是用户输入导致的) useEffect(() => { if (!editor) { return; } - // 如果 value 和 lastSyncedValueRef 相同,说明是用户输入导致的更新,跳过 if (value === lastSyncedValueRef.current) { return; } - // 外部 value 真正变化,更新编辑器 const currentValue = editor.getValue(); if (currentValue !== value) { editor.setValue(value || ''); @@ -86,11 +81,9 @@ const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ } }, [editor, value]); - // 清理:组件卸载时销毁编辑器 useEffect(() => { return () => { if (editor) { - // CodeMirror EditorView 有 destroy 方法 const view = editor as unknown as EditorView; if (view.destroy) { view.destroy(); diff --git a/ui/src/components/Editor/index.tsx b/ui/src/components/Editor/index.tsx index a914d912..94bd5836 100644 --- a/ui/src/components/Editor/index.tsx +++ b/ui/src/components/Editor/index.tsx @@ -123,32 +123,30 @@ const MDEditor: ForwardRefRenderFunction<EditorRef, Props> = ( <div className={classNames('md-editor-wrap rounded', className)}> <div className="toolbar-wrap px-3 d-flex align-items-center flex-wrap"> <EditorContext.Provider value={currentEditor}> - {currentEditor && ( - <PluginRender - type={PluginType.Editor} - className="d-flex align-items-center flex-wrap" - editor={currentEditor} - previewElement={previewRef.current?.element}> - <Heading /> - <Bold /> - <Italice /> - <div className="toolbar-divider" /> - <Code /> - <LinkItem /> - <BlockQuote /> - <Image /> - <File /> - <Table /> - <div className="toolbar-divider" /> - <OL /> - <UL /> - <Indent /> - <Outdent /> - <Hr /> - <div className="toolbar-divider" /> - <Help /> - </PluginRender> - )} + <PluginRender + type={PluginType.Editor} + className="d-flex align-items-center flex-wrap" + editor={currentEditor} + previewElement={previewRef.current?.element}> + <Heading /> + <Bold /> + <Italice /> + <div className="toolbar-divider" /> + <Code /> + <LinkItem /> + <BlockQuote /> + <Image /> + <File /> + <Table /> + <div className="toolbar-divider" /> + <OL /> + <UL /> + <Indent /> + <Outdent /> + <Hr /> + <div className="toolbar-divider" /> + <Help /> + </PluginRender> </EditorContext.Provider> <div className="btn-group ms-auto" role="group"> diff --git a/ui/src/components/Editor/utils/codemirror/commands.ts b/ui/src/components/Editor/utils/codemirror/commands.ts index 59ab064e..152bc632 100644 --- a/ui/src/components/Editor/utils/codemirror/commands.ts +++ b/ui/src/components/Editor/utils/codemirror/commands.ts @@ -33,7 +33,8 @@ import { Editor, Level } from '../../types'; * @returns Object containing all command methods */ export function createCommandMethods(editor: Editor) { - return { + // Create methods object that allows self-reference + const methods = { wrapText: (before: string, after = before, defaultText) => { const range = editor.state.selection.ranges[0]; const selectedText = editor.state.sliceDoc(range.from, range.to); @@ -79,39 +80,39 @@ export function createCommandMethods(editor: Editor) { }, insertBold: (text?: string) => { - editor.wrapText('**', '**', text || 'bold text'); + methods.wrapText('**', '**', text || 'bold text'); }, insertItalic: (text?: string) => { - editor.wrapText('*', '*', text || 'italic text'); + methods.wrapText('*', '*', text || 'italic text'); }, insertCode: (text?: string) => { - editor.wrapText('`', '`', text || 'code'); + methods.wrapText('`', '`', text || 'code'); }, insertStrikethrough: (text?: string) => { - editor.wrapText('~~', '~~', text || 'strikethrough text'); + methods.wrapText('~~', '~~', text || 'strikethrough text'); }, insertHeading: (level: Level, text?: string) => { const headingText = '#'.repeat(level); - editor.wrapText(`${headingText} `, '', text || 'heading'); + methods.wrapText(`${headingText} `, '', text || 'heading'); }, insertBlockquote: (text?: string) => { - editor.wrapText('> ', '', text || 'quote'); + methods.wrapText('> ', '', text || 'quote'); }, insertCodeBlock: (language?: string, code?: string) => { const lang = language || ''; const codeText = code || ''; const block = `\`\`\`${lang}\n${codeText}\n\`\`\``; - editor.appendBlock(block); + methods.appendBlock(block); }, insertHorizontalRule: () => { - editor.appendBlock('---'); + methods.appendBlock('---'); }, insertOrderedList: () => { @@ -121,7 +122,7 @@ export function createCommandMethods(editor: Editor) { if (/^\d+\.\s/.test(lineText)) { return; } - editor.replaceLines((lineItem) => { + methods.replaceLines((lineItem) => { if (lineItem.trim() === '') { return lineItem; } @@ -136,7 +137,7 @@ export function createCommandMethods(editor: Editor) { if (/^[-*+]\s/.test(lineText)) { return; } - editor.replaceLines((lineItem) => { + methods.replaceLines((lineItem) => { if (lineItem.trim() === '') { return lineItem; } @@ -149,11 +150,11 @@ export function createCommandMethods(editor: Editor) { const line = editor.state.doc.line(cursor.line); const lineText = line.text.trim(); if (/^\d+\.\s/.test(lineText)) { - editor.replaceLines((lineItem) => { + methods.replaceLines((lineItem) => { return lineItem.replace(/^\d+\.\s/, ''); }); } else { - editor.insertOrderedList(); + methods.insertOrderedList(); } }, @@ -162,22 +163,22 @@ export function createCommandMethods(editor: Editor) { const line = editor.state.doc.line(cursor.line); const lineText = line.text.trim(); if (/^[-*+]\s/.test(lineText)) { - editor.replaceLines((lineItem) => { + methods.replaceLines((lineItem) => { return lineItem.replace(/^[-*+]\s/, ''); }); } else { - editor.insertUnorderedList(); + methods.insertUnorderedList(); } }, insertLink: (url: string, text?: string) => { const linkText = text || url; - editor.wrapText('[', `](${url})`, linkText); + methods.wrapText('[', `](${url})`, linkText); }, insertImage: (url: string, alt?: string) => { const altText = alt || ''; - editor.wrapText('`, altText); + methods.wrapText('`, altText); }, insertTable: (rows = 3, cols = 3) => { @@ -192,11 +193,11 @@ export function createCommandMethods(editor: Editor) { table.push(`| ${'---'.repeat(cols).split('').join(' | ')} |`); } } - editor.appendBlock(table.join('\n')); + methods.appendBlock(table.join('\n')); }, indent: () => { - editor.replaceLines((line) => { + methods.replaceLines((line) => { if (line.trim() === '') { return line; } @@ -205,7 +206,7 @@ export function createCommandMethods(editor: Editor) { }, outdent: () => { - editor.replaceLines((line) => { + methods.replaceLines((line) => { if (line.trim() === '') { return line; } @@ -261,4 +262,6 @@ export function createCommandMethods(editor: Editor) { return /^[-*+]\s/.test(lineText); }, }; + + return methods; }
