Closed ccppoo closed 1 week ago
import { BlockToolConstructorOptions } from '@editorjs/editorjs/types/tools'; import type { NestedListParams } from '@editorjs/nested-list'; import NestedList from '@editorjs/nested-list'; // copied from original code == start == type ListDataStyle = 'ordered' | 'unordered'; interface ListItem { /** * list item text content */ content: string; /** * sublist items */ items: ListItem[]; } interface ListData { /** * list type 'ordered' or 'unordered' */ style: ListDataStyle; /** * list of first-level elements */ items: ListItem[]; } interface NestedListConfig { /** * default list style: ordered or unordered * default is unordered */ defaultStyle?: ListDataStyle; } // copied from original code == end == // this is also implemented in package but couldn't import from dist source, so I just copied it function isHtmlElement(node: Node): boolean { return node instanceof HTMLElement; } // interface for config, interface NestedListCustomParams { maxDepth?: number; } // extending constructor params export type _NestedListParams = BlockToolConstructorOptions< ListData, NestedListConfig & NestedListCustomParams >; export default class LimitedNestedList extends NestedList { constructor({ data, config: _config, api, readOnly }: _NestedListParams) { const { maxDepth, ...config } = _config; // need to cast to original NestedListParams interface super({ data, config, api, readOnly } as NestedListParams); if (!maxDepth || maxDepth < 1) { // min : 1 (could nest like : 1.1, 1.2, 2.1, 2.2, ... ) // default : 2 (could nest like : 1.1.1, 1.2.3, ... ) this.maxDepth = 2; return; } this.maxDepth = maxDepth; } private maxDepth: number; addTab(event: KeyboardEvent): void { // same as original code == start == event.stopPropagation(); event.preventDefault(); const currentItem = this.currentItem; if (!currentItem) { return; } const prevItem = currentItem.previousSibling; if (!prevItem) { return; } if (!isHtmlElement(prevItem)) { return; } const isFirstChild = !prevItem; if (isFirstChild) { return; } // same as original code == end == // find until element class name is : `ce-block__content` const maxHTMLDepth = 2 + 3 * (this.maxDepth - 1); // 0, 2, 5, 8, 11, ... const rootName = 'ce-block__content'; let HTMLDepth = 0; let element: Element | null = currentItem; while (element?.className !== rootName) { element = element?.parentElement || null; HTMLDepth += 1; if (HTMLDepth > maxHTMLDepth) return; } return super.addTab(event); } }
const nestedListTool = { class: LimitedNestedList, inlineToolbar: true, config: { defaultStyle: 'ordered', }, }; .... const editorConfig = { tools: { list : nestedListTool .... } }
I tried to make as finding root element, or Block by using block data
Block
but it was quite hard to override methods, and accessing private variables.
+1 for this feature: it would be really useful to limit user input to 1 or 2 levels at most
I tried to make as finding root element, or
Block
by using block databut it was quite hard to override methods, and accessing private variables.