114 lines
3.8 KiB
JavaScript
114 lines
3.8 KiB
JavaScript
import React, { useRef, useEffect, useState, useCallback } from "react";
|
|
import { Editor } from "@tinymce/tinymce-react";
|
|
|
|
function CustomEditor(props) {
|
|
const editorRef = useRef(null);
|
|
const [isEditorReady, setIsEditorReady] = useState(false);
|
|
const [currentContent, setCurrentContent] = useState(props.initialData || "");
|
|
const isUserTypingRef = useRef(false);
|
|
|
|
// Handle editor initialization
|
|
const handleInit = useCallback((evt, editor) => {
|
|
editorRef.current = editor;
|
|
setIsEditorReady(true);
|
|
|
|
// Set initial content immediately when editor is ready
|
|
if (props.initialData) {
|
|
editor.setContent(props.initialData);
|
|
setCurrentContent(props.initialData);
|
|
}
|
|
|
|
// Simple onChange handler
|
|
editor.on('change', () => {
|
|
isUserTypingRef.current = true; // Mark that user is typing
|
|
const content = editor.getContent();
|
|
setCurrentContent(content);
|
|
if (props.onChange) {
|
|
props.onChange(content);
|
|
}
|
|
// Reset typing flag after a short delay
|
|
setTimeout(() => {
|
|
isUserTypingRef.current = false;
|
|
}, 100);
|
|
});
|
|
}, [props.initialData, props.onChange]);
|
|
|
|
// Watch for changes in initialData prop (from external sources like setValue)
|
|
useEffect(() => {
|
|
if (props.initialData !== currentContent && !isUserTypingRef.current) {
|
|
setCurrentContent(props.initialData || "");
|
|
|
|
// Update editor content if editor is ready
|
|
if (editorRef.current && isEditorReady) {
|
|
editorRef.current.setContent(props.initialData || "");
|
|
}
|
|
}
|
|
}, [props.initialData, isEditorReady]); // Removed currentContent from dependency
|
|
|
|
// Handle initial data when editor becomes ready (only for initialization)
|
|
useEffect(() => {
|
|
if (isEditorReady && props.initialData && editorRef.current && !isUserTypingRef.current) {
|
|
editorRef.current.setContent(props.initialData);
|
|
setCurrentContent(props.initialData);
|
|
}
|
|
}, [isEditorReady]); // Only depend on isEditorReady, not currentContent
|
|
|
|
return (
|
|
<Editor
|
|
onInit={handleInit}
|
|
apiKey={process.env.NEXT_PUBLIC_TINYMCE_API_KEY}
|
|
init={{
|
|
height: 400,
|
|
menubar: false,
|
|
plugins: [
|
|
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
|
|
'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
|
|
'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount'
|
|
],
|
|
toolbar: 'undo redo | blocks | ' +
|
|
'bold italic forecolor | alignleft aligncenter ' +
|
|
'alignright alignjustify | bullist numlist outdent indent | ' +
|
|
'removeformat | table | code | help',
|
|
content_style: `
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
font-size: 14px;
|
|
line-height: 1.6;
|
|
color: #333;
|
|
}
|
|
.mce-content-body {
|
|
padding: 16px;
|
|
min-height: 368px;
|
|
}
|
|
`,
|
|
placeholder: 'Start typing...',
|
|
branding: false,
|
|
elementpath: false,
|
|
resize: false,
|
|
statusbar: false,
|
|
auto_focus: false,
|
|
forced_root_block: 'p',
|
|
entity_encoding: 'raw',
|
|
verify_html: false,
|
|
cleanup: false,
|
|
cleanup_on_startup: false,
|
|
auto_resize: false,
|
|
paste_as_text: false,
|
|
paste_enable_default_filters: true,
|
|
paste_word_valid_elements: 'b,strong,i,em,h1,h2,h3,h4,h5,h6',
|
|
paste_retain_style_properties: 'color background-color font-size font-weight',
|
|
mobile: {
|
|
theme: 'silver',
|
|
plugins: ['lists', 'autolink', 'link', 'image', 'table'],
|
|
toolbar: 'bold italic | bullist numlist | link image'
|
|
}
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default CustomEditor;
|
|
|
|
|
|
|