Improve types
This commit is contained in:
parent
544a1614a0
commit
78dd4f5189
@ -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);
|
||||
|
@ -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<ChecklistData> {
|
||||
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<ChecklistData>): 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 (
|
||||
<button
|
||||
className="w-full border rounded-md p-4 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-left"
|
||||
role="button"
|
||||
aria-label="Add new checklist block"
|
||||
onClick={onAdd}
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 11L12 14L20 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M20 12V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V6C4 4.89543 4.89543 4 6 4H15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-base font-medium">Checklist</h3>
|
||||
<p className="text-sm text-gray-500 mt-1">Add a new checklist</p>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<button
|
||||
className="w-full border rounded-md p-4 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-left"
|
||||
role="button"
|
||||
aria-label="Add new checklist block"
|
||||
onClick={onAdd}
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 11L12 14L20 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M20 12V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V6C4 4.89543 4.89543 4 6 4H15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-base font-medium">Checklist</h3>
|
||||
<p className="text-sm text-gray-500 mt-1">Add a new checklist</p>
|
||||
</button>
|
||||
);
|
||||
public renderNewElementTile(onAdd?: () => void): React.ReactElement {
|
||||
return ReactChecklistTool.renderNewElementTile(onAdd);
|
||||
}
|
||||
}
|
||||
|
||||
|
41
src/types.ts
Normal file
41
src/types.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { BlockTool, PasteEvent } from '@editorjs/editorjs';
|
||||
|
||||
export interface EditorJSPluginConfig<T = any> {
|
||||
data?: T;
|
||||
config?: {
|
||||
placeholder?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface EditorJSPluginData<T = any> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface EditorJSPlugin<T = any> extends BlockTool {
|
||||
// Required methods from BlockTool
|
||||
save(): EditorJSPluginData<T>;
|
||||
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<T = any> extends EditorJSPlugin<T> {
|
||||
renderNewElementTile(onAdd?: () => void): React.ReactElement;
|
||||
renderSettings(): HTMLElement;
|
||||
}
|
Loading…
Reference in New Issue
Block a user