From 78dd4f518902d90a9925343a3fcc667b436ea371 Mon Sep 17 00:00:00 2001 From: Caleb Braaten Date: Wed, 23 Apr 2025 23:30:47 -0700 Subject: [PATCH] Improve types --- src/EditorJSWrapper.tsx | 9 ++++- src/checklist-plugin.tsx | 87 ++++++++++++++++++++++++++-------------- src/types.ts | 41 +++++++++++++++++++ 3 files changed, 105 insertions(+), 32 deletions(-) create mode 100644 src/types.ts diff --git a/src/EditorJSWrapper.tsx b/src/EditorJSWrapper.tsx index 5e24506..80bdec4 100644 --- a/src/EditorJSWrapper.tsx +++ b/src/EditorJSWrapper.tsx @@ -69,10 +69,15 @@ class EditorJSWrapper { try { // If the type exists in tools, add that block type, otherwise treat as paragraph + // TODO: Make more generic and allow for plugin to define this behavior const blockType = this.tools[type] ? type : 'paragraph'; - const data = blockType === 'paragraph' ? { text: type } : undefined; + const data = blockType === 'paragraph' ? + { text: type } : + blockType === 'checklist' ? + { items: [{ text: '', checked: false }] } : + undefined; - await this.editor.blocks.insert(blockType, data); + await this.editor.blocks.insert(blockType, { data }); await this.syncState(); } catch (err) { console.error('Error adding block:', err); diff --git a/src/checklist-plugin.tsx b/src/checklist-plugin.tsx index 8aa76ad..d049b7e 100644 --- a/src/checklist-plugin.tsx +++ b/src/checklist-plugin.tsx @@ -1,5 +1,6 @@ import { API, BlockTool, BlockToolData } from '@editorjs/editorjs'; import './checklist.css'; +import { EditorJSPlugin, CustomEditorJSPlugin, EditorJSPluginData } from './types'; interface ChecklistItem { text: string; @@ -20,8 +21,8 @@ interface ChecklistConfig { } -class ChecklistTool implements BlockTool { - private data: ChecklistData; +class ChecklistTool implements EditorJSPlugin { + protected data: ChecklistData; private wrapper: HTMLElement; private api: API; private readOnly: boolean; @@ -29,6 +30,11 @@ class ChecklistTool implements BlockTool { private itemElements: HTMLElement[] = []; private pendingUpdate = false; + static = { + toolbox: ChecklistTool.toolbox, + sanitize: ChecklistTool.sanitize + }; + static get toolbox() { return { title: 'Checklist', @@ -346,21 +352,23 @@ class ChecklistTool implements BlockTool { void this.notifyChange(); } - save(): BlockToolData { + save(): { data: ChecklistData } { return { - items: this.data.items.map(item => ({ - text: item.text || '', - checked: Boolean(item.checked) - })) + data: { + items: this.data.items.map(item => ({ + text: item.text || '', + checked: Boolean(item.checked) + })) + } }; } - validate(savedData: BlockToolData): boolean { + validate(savedData: { data: ChecklistData }): boolean { try { - const { items } = savedData; - if (!Array.isArray(items)) return false; + const { data } = savedData; + if (!data || !Array.isArray(data.items)) return false; - return items.every(item => + return data.items.every(item => item && typeof item === 'object' && 'text' in item && @@ -382,8 +390,32 @@ class ChecklistTool implements BlockTool { } } -class ReactChecklistTool extends ChecklistTool { +class ReactChecklistTool extends ChecklistTool implements CustomEditorJSPlugin { private settings: { title: string }; + static = { + toolbox: ReactChecklistTool.toolbox, + sanitize: ReactChecklistTool.sanitize + }; + + static renderNewElementTile(onAdd?: () => void): React.ReactElement { + return ( + + ); + } constructor(config: ChecklistConfig) { super(config); @@ -392,6 +424,17 @@ class ReactChecklistTool extends ChecklistTool { }; } + save(): { data: ChecklistData } { + return { + data: { + items: this.data.items.map(item => ({ + text: item.text || '', + checked: Boolean(item.checked) + })) + } + }; + } + public renderSettings(): HTMLElement { const wrapper = document.createElement('div'); wrapper.innerHTML = ` @@ -411,24 +454,8 @@ class ReactChecklistTool extends ChecklistTool { return wrapper; } - public static renderNewElementTile(onAdd?: () => void): React.ReactElement { - return ( - - ); + public renderNewElementTile(onAdd?: () => void): React.ReactElement { + return ReactChecklistTool.renderNewElementTile(onAdd); } } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..9e11ea2 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,41 @@ +import { BlockTool, PasteEvent } from '@editorjs/editorjs'; + +export interface EditorJSPluginConfig { + data?: T; + config?: { + placeholder?: string; + [key: string]: any; + }; +} + +export interface EditorJSPluginData { + data: T; +} + +export interface EditorJSPlugin extends BlockTool { + // Required methods from BlockTool + save(): EditorJSPluginData; + validate(savedData: T): boolean; + render(): HTMLElement; + + // Optional methods + renderSettings?(): HTMLElement; + onPaste?(event: PasteEvent): void; + merge?(data: T): T; + + // Static properties + static: { + toolbox: { + title: string; + icon: string; + }; + sanitize: { + [key: string]: boolean | { [key: string]: boolean }; + }; + } +} + +export interface CustomEditorJSPlugin extends EditorJSPlugin { + renderNewElementTile(onAdd?: () => void): React.ReactElement; + renderSettings(): HTMLElement; +}