import React, { useState, useCallback, useEffect } from 'react'; import { flushSync } from 'react-dom'; import { EditorContent, useEditor } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import { HighlightTextExtension } from './HighlightText'; interface MainEditorProps { content: any[]; onChangeContent?: (content: any[]) => void; } export default function MainEditor({ content, onChangeContent }: MainEditorProps) { const [renderContent, setRenderContent] = useState(content); useEffect(() => { onChangeContent?.(renderContent); }, [renderContent]); const editor = useEditor({ extensions: [ StarterKit.configure({ paragraph: { HTMLAttributes: { class: 'paragraph' } }, }), HighlightTextExtension, ], content: { type: 'doc', content: renderContent.length === 0 ? [{ type: 'paragraph', content: [] }] : renderContent }, editorProps: { attributes: { class: 'prose prose-invert max-w-none focus:outline-none' }, handleDOMEvents: { keydown: (view, event) => { // 如果内容为空且按下删除键或退格键,阻止默认行为 if ( (event.key === 'Backspace' || event.key === 'Delete') && editor?.isEmpty ) { event.preventDefault(); return true; } return false; } } }, onCreate: ({ editor }) => { editor.setOptions({ editable: true }); }, onUpdate: ({ editor }) => { try { const json = editor.getJSON(); // 确保至少有一个空段落 const safeContent = json.content.length === 0 ? [{ type: 'paragraph', content: [] }] : json.content; flushSync(() => { setRenderContent(safeContent); }); } catch (error) { console.error('Editor update error:', error); } }, immediatelyRender: false, // 解决 SSR 水合问题 }); // 监听编辑器内容变化,确保始终有一个段落 useEffect(() => { const handleEmpty = () => { if (editor?.isEmpty) { editor.commands.setContent([{ type: 'paragraph', content: [] }]); } }; editor?.on('update', handleEmpty); return () => { editor?.off('update', handleEmpty); }; }, [editor]); if (!editor) { return null; } return ( ); }