From 80fb1813cf338f82468c537696eb006d8583f2ec Mon Sep 17 00:00:00 2001 From: Caleb Braaten Date: Wed, 23 Apr 2025 15:40:50 -0700 Subject: [PATCH] Class approach --- src/App.tsx | 178 ++++++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 88 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 88b7716..1147100 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,103 +2,105 @@ import { useEffect, useRef, useState } from 'react' import './App.css' import EditorJS, { OutputData } from '@editorjs/editorjs' -interface EditorWrapper { - instance: EditorJS | null; - addBlock: (text: string) => Promise; - clear: () => Promise; - getData: () => Promise; - holderRef: React.RefObject; -} +class EditorJSWrapper { + private editor: EditorJS | null = null; + private holder: HTMLDivElement | null = null; + private onChange!: (data: OutputData) => void; + private static instance: EditorJSWrapper | null = null; -function useEditorJS(onChange: (data: OutputData) => void): EditorWrapper { - const [editor, setEditor] = useState(null); - const holderRef = useRef(null); - const isDestroyed = useRef(false); - - // Initialize editor - useEffect(() => { - if (!holderRef.current || editor || isDestroyed.current) return; - - const instance = new EditorJS({ - holder: holderRef.current, - placeholder: 'Start writing...', - onChange: async () => { - try { - const content = await instance.save(); - onChange(content); - } catch (err) { - console.error('Error saving editor content:', err); - } - } - }); - - setEditor(instance); - - return () => { - isDestroyed.current = true; - const cleanup = async () => { - if (instance) { - try { - await instance.destroy(); - setEditor(null); - } catch (error: unknown) { - console.error('Error destroying editor:', error); - } - } - }; - void cleanup(); - }; - }, []); - - const wrapper: EditorWrapper = { - instance: editor, - holderRef, - addBlock: async (text: string) => { - if (!editor) return; - - try { - const currentData = await editor.save(); - const newBlock = { - id: String(Date.now()), - type: 'paragraph', - data: { - text - } - }; - - await editor.blocks.insert('paragraph', { text }); - - const updatedData = await editor.save(); - onChange(updatedData); - } catch (err) { - console.error('Error adding block:', err); - } - }, - clear: async () => { - if (!editor) return; - try { - await editor.clear(); - } catch (err) { - console.error('Error clearing editor:', err); - } - }, - getData: async () => { - if (!editor) throw new Error('Editor not initialized'); - return editor.save(); + constructor(onChange: (data: OutputData) => void) { + if (EditorJSWrapper.instance) { + return EditorJSWrapper.instance; } - }; + this.onChange = onChange; + EditorJSWrapper.instance = this; + } - return wrapper; + initialize(holder: HTMLDivElement) { + if (this.editor || !holder) return; + + // Ensure any existing instance is destroyed first + if (EditorJSWrapper.instance?.editor) { + void EditorJSWrapper.instance.destroy(); + } + + this.holder = holder; + try { + this.editor = new EditorJS({ + holder: holder, + placeholder: 'Start writing...', + onChange: async () => { + try { + const content = await this.editor!.save(); + this.onChange(content); + } catch (err) { + console.error('Error saving editor content:', err); + } + } + }); + } catch (error) { + console.error('Error initializing editor:', error); + } + } + + async addBlock(text: string) { + if (!this.editor) return; + + try { + await this.editor.blocks.insert('paragraph', { text }); + const updatedData = await this.editor.save(); + this.onChange(updatedData); + } catch (err) { + console.error('Error adding block:', err); + } + } + + async clear() { + if (!this.editor) return; + try { + await this.editor.clear(); + } catch (err) { + console.error('Error clearing editor:', err); + } + } + + async getData(): Promise { + if (!this.editor) throw new Error('Editor not initialized'); + return this.editor.save(); + } + + async destroy() { + try { + if (this.editor && typeof this.editor.destroy === 'function') { + await this.editor.destroy(); + this.editor = null; + this.holder = null; + EditorJSWrapper.instance = null; + } + } catch (error: unknown) { + console.error('Error destroying editor:', error); + } + } } function App() { const [editorData, setEditorData] = useState(null); const [inputText, setInputText] = useState(""); + const [editor] = useState(() => new EditorJSWrapper((data) => setEditorData(data))); const inputRef = useRef(null); + const editorRef = useRef(null); - const editor = useEditorJS((data) => { - setEditorData(data); - }); + useEffect(() => { + if (editorRef.current) { + editor.initialize(editorRef.current); + } + return () => { + const cleanup = async () => { + await editor.destroy(); + }; + void cleanup(); + }; + }, [editor]); const handleAdd = async () => { if (!inputText.trim()) return; @@ -121,7 +123,7 @@ function App() {
-
+