diff --git a/packages/core/src/helpers/index.ts b/packages/core/src/helpers/index.ts index eecd100..02958c9 100644 --- a/packages/core/src/helpers/index.ts +++ b/packages/core/src/helpers/index.ts @@ -1,14 +1,15 @@ import { style } from '@vanilla-extract/css'; +import * as childHelpers from './child'; import Element, * as elements from './element'; -import * as logger from './logger'; import * as error from './error'; +import * as logger from './logger'; import Node, * as nodeHelpers from './node'; +import * as normalizeNode from './normlizeNode'; import Path, * as pathHelpers from './path'; import * as rangeHelpers from './range'; import ReactEditor from './reactEditor'; -import * as transforms from './transform'; import Text, * as textHelpers from './text'; -import * as childHelpers from './child'; +import * as transforms from './transform'; export const helpers = { ReactEditor, @@ -16,6 +17,7 @@ export const helpers = { logger, error, Node, + normalizeNode, Path, ...transforms, Text, diff --git a/packages/core/src/helpers/normlizeNode/index.ts b/packages/core/src/helpers/normlizeNode/index.ts new file mode 100644 index 0000000..b5b3578 --- /dev/null +++ b/packages/core/src/helpers/normlizeNode/index.ts @@ -0,0 +1,51 @@ +import { Editor, Element, Node, NodeEntry } from 'slate'; +import { warn } from '../logger'; + +/** + * Delete child of type other than received in argument. + */ +export const nestedElementNormalizeNode = ( + editor: Editor, + entry: NodeEntry, + allowType: string | string[] +) => { + let isRestricted: boolean = false; + const [node, path] = entry; + allowType = Array.isArray(allowType) ? allowType : [allowType]; + const childEntryList = Array.from(Node.children(editor, path)); + const childNodes = childEntryList.map((entry) => { + const [node] = entry; + return node; + }); + const hasCurrentTypeChild = !!childNodes.find((child) => { + if (!Element.isElement(child)) { + return false; + } + return allowType.includes(child.type); + }); + if (!hasCurrentTypeChild) { + editor.removeNodes({ at: path }); + return true; + } + + childEntryList.forEach((childEntry) => { + const [child, childPath] = childEntry; + if (!Element.isElement(child) || !allowType.includes(child.type)) { + warn({ + messages: [ + 'Element removed.', + { + from: [node, path], + target: [child, childPath], + }, + ], + }); + editor.removeNodes({ + at: childPath, + }); + isRestricted = true; + } + }); + + return isRestricted; +}; diff --git a/packages/element-list/src/list/index.ts b/packages/element-list/src/list/index.ts index 72f2764..5aa0fd3 100644 --- a/packages/element-list/src/list/index.ts +++ b/packages/element-list/src/list/index.ts @@ -10,27 +10,11 @@ const element: Element = { editable, toolbox, normalizeNode: (editor, entry) => { - // Allow only elements of type `list-item`. - let isNormalized: boolean = false; - const [node, path] = entry; - for (const [child, childPath] of helpers.Node.children(editor, path)) { - if (!helpers.Element.isElement(child) || child.type !== 'list-item') { - helpers.logger.warn({ - messages: [ - 'Element removed.', - { - from: [node, path], - target: [child, childPath], - }, - ], - }); - editor.removeNodes({ - at: childPath, - }); - isNormalized = true; - } - } - return isNormalized; + return helpers.normalizeNode.nestedElementNormalizeNode( + editor, + entry, + 'list-item' + ); }, }; export default element; diff --git a/packages/element-list/src/ordered/index.ts b/packages/element-list/src/ordered/index.ts index 1f1f90e..aa209c7 100644 --- a/packages/element-list/src/ordered/index.ts +++ b/packages/element-list/src/ordered/index.ts @@ -10,27 +10,11 @@ const element: Element = { editable, toolbox, normalizeNode: (editor, entry) => { - // Allow only elements of type `list-item`. - let isNormalized: boolean = false; - const [node, path] = entry; - for (const [child, childPath] of helpers.Node.children(editor, path)) { - if (!helpers.Element.isElement(child) || child.type !== 'list-item') { - helpers.logger.warn({ - messages: [ - 'Element removed.', - { - from: [node, path], - target: [child, childPath], - }, - ], - }); - editor.removeNodes({ - at: childPath, - }); - isNormalized = true; - } - } - return isNormalized; + return helpers.normalizeNode.nestedElementNormalizeNode( + editor, + entry, + 'list-item' + ); }, insertBreak: (editor, nodeEntry) => { const [node, path] = nodeEntry; diff --git a/packages/element-list/src/todo/index.ts b/packages/element-list/src/todo/index.ts index 2d471ec..45e184d 100644 --- a/packages/element-list/src/todo/index.ts +++ b/packages/element-list/src/todo/index.ts @@ -10,30 +10,11 @@ const element: Element = { editable, toolbox, normalizeNode: (editor, entry) => { - // Allow only elements of type `todo-list-item`. - let isNormalized: boolean = false; - const [node, path] = entry; - for (const [child, childPath] of helpers.Node.children(editor, path)) { - if ( - !helpers.Element.isElement(child) || - child.type !== 'todo-list-item' - ) { - helpers.logger.warn({ - messages: [ - 'Element removed.', - { - from: [node, path], - target: [child, childPath], - }, - ], - }); - editor.removeNodes({ - at: childPath, - }); - isNormalized = true; - } - } - return isNormalized; + return helpers.normalizeNode.nestedElementNormalizeNode( + editor, + entry, + 'todo-list-item' + ); }, }; diff --git a/packages/element-note/src/container/index.ts b/packages/element-note/src/container/index.ts index 6ff8a7d..0af7aa7 100644 --- a/packages/element-note/src/container/index.ts +++ b/packages/element-note/src/container/index.ts @@ -10,7 +10,11 @@ const element: Element = { editable, toolbox, normalizeNode: (editor, entry) => { - return helpers.childHelpers.restrictChild(editor, entry, 'note-body'); + return helpers.normalizeNode.nestedElementNormalizeNode( + editor, + entry, + 'note-body' + ); }, }; diff --git a/packages/element-toggle/src/container/index.ts b/packages/element-toggle/src/container/index.ts index 15a51d4..92a9942 100644 --- a/packages/element-toggle/src/container/index.ts +++ b/packages/element-toggle/src/container/index.ts @@ -10,30 +10,10 @@ const element: Element = { editable, toolbox, normalizeNode: (editor, entry) => { - // Allow only elements of type `list-item`. - let isNormalized: boolean = false; - const [node, path] = entry; - for (const [child, childPath] of helpers.Node.children(editor, path)) { - if ( - !helpers.Element.isElement(child) || - (child.type !== 'toggle-head' && child.type !== 'toggle-body') - ) { - helpers.logger.warn({ - messages: [ - 'Element removed.', - { - from: [node, path], - target: [child, childPath], - }, - ], - }); - editor.removeNodes({ - at: childPath, - }); - isNormalized = true; - } - } - return isNormalized; + return helpers.normalizeNode.nestedElementNormalizeNode(editor, entry, [ + 'toggle-head', + 'toggle-body', + ]); }, }; export default element;