import Placeholder from "@tiptap/extension-placeholder"; import { useEditor, EditorContent } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; import { useEffect } from "react"; import { HighlightTextExtension } from "../ui/main-editor/HighlightText"; /** * 高亮编辑器组件 * 使用 Tiptap 实现高亮和文本编辑功能 * 让 文本中的xxxx标签高亮 */ export const HighlightEditor = ({ content, onContentChange, type, placeholder, cursorPosition, onCursorPositionChange, }: { /** 内容 */ content: string; /** 内容变化回调 */ onContentChange: (content: string) => void; /** 标签类型*/ type: string; /**提示语 */ placeholder: string; /** 光标位置 */ cursorPosition?: number; /** 光标位置变化回调 */ onCursorPositionChange?: (position: number) => void; }) => { console.log(44444); const editor = useEditor({ extensions: [ StarterKit, HighlightTextExtension, Placeholder.configure({ placeholder, emptyEditorClass: "is-editor-empty", }), ], content: "", onUpdate: ({ editor }) => { const textContent = editor.getText(); if (!textContent.trim()) { onContentChange(""); return; } // 获取 HTML 内容并转换 highlight-text 标签 const htmlContent = editor.getHTML(); const convertedContent = htmlContent.replace( /]*type="([^"]*)"[^>]*text="([^"]*)"[^>]*>([^<]*)<\/highlight-text>/g, '<$1>$2' ); console.log('convertedContent:::', convertedContent); // 保存当前光标位置 const { from } = editor.state.selection; onCursorPositionChange?.(from); // 传递转换后的内容 onContentChange(convertedContent); }, editorProps: { handleKeyDown: (view, event) => { const { from, to } = view.state.selection; const doc = view.state.doc; // 检查光标前后是否有标签 const textBefore = from > 0 ? doc.textBetween(Math.max(0, from - 50), from) : ""; const textAfter = to < doc.content.size ? doc.textBetween(to, Math.min(doc.content.size, to + 50)) : ""; const beforeMatch = textBefore.match(new RegExp(`<${type}[^>]*>[^<]*$`)); const afterMatch = textAfter.match(new RegExp(`^[^>]*<\\/${type}>`)); // 只允许删除操作) if (beforeMatch || afterMatch) { if (event.key !== "Backspace" && event.key !== "Delete") { event.preventDefault(); return true; } } return false; }, }, immediatelyRender: false, }); useEffect(() => { if (editor) { if (!content || content.trim() === "") { editor.commands.clearContent(true); return; } // 将带标签的内容转换为高亮显示(支持新的标签格式) const htmlContent = content.replace( new RegExp(`<${type}[^>]*>([^<]+)<\/${type}>`, "g"), '$1' ); console.log('111111', 111111) editor.commands.setContent(htmlContent, { emitUpdate: false }); // 恢复光标位置 if (cursorPosition && cursorPosition > 0) { // 确保光标位置不超出文档范围 const docSize = editor.state.doc.content.size; const safePosition = Math.min(cursorPosition, docSize); if (safePosition > 0) { editor.commands.setTextSelection(safePosition); } } } }, [content, editor, cursorPosition]); return (
); };