UNPKG

@atlaskit/editor-plugin-list

Version:

List plugin for @atlaskit/editor-core

83 lines (78 loc) 4.14 kB
import { insertContentDeleteRange, isListNode } from '@atlaskit/editor-common/utils'; import { Fragment } from '@atlaskit/editor-prosemirror/model'; // Case for when a users selection is at the end of a paragraph, the paragraph // is followed by a list, and they delete forward export var joinListItemWithParagraph = function joinListItemWithParagraph(_ref) { var tr = _ref.tr, $next = _ref.$next, $head = _ref.$head; // For empty paragraphs before a list if ($head.parent.content.size < 1) { insertContentDeleteRange(tr, function (tr) { return tr.doc.resolve($head.pos); }, [], [[$head.pos - 1, $head.pos]]); return true; } var paragraphPosition = $head.pos; var list = tr.doc.nodeAt($next.pos - 1); var firstListItem = tr.doc.nodeAt($next.pos); if (!list || !firstListItem) { return false; } var firstChildNodeOfFirstListItem = firstListItem.firstChild; if (!firstChildNodeOfFirstListItem) { return false; } var lastChildOfFirstListItem = firstListItem.lastChild; var firstGrandchildOfFirstListItem = firstChildNodeOfFirstListItem.firstChild; var firstListItemHasOneChildWithNoNestedLists = hasSingleChild(firstListItem) && firstChildNodeOfFirstListItem.childCount < 2 && $next.nodeAfter; var firstListItemContainsParagraphAndNestedList = !hasSingleChild(firstListItem) && lastChildOfFirstListItem && isListNode(lastChildOfFirstListItem); var insertions = []; var deletions = []; // For lists that only have one list item with no children - need to remove remaining list if (hasSingleChild(list) && hasSingleChild(firstListItem) && $next.nodeAfter) { deletions.push([tr.mapping.map($next.pos - 1), tr.mapping.map($next.pos + $next.nodeAfter.nodeSize + 1)]); } // For first list items that have a paragraph and a list if (firstListItemContainsParagraphAndNestedList) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var firstListItemNestedList = Fragment.from(lastChildOfFirstListItem.content); insertions.push([firstListItemNestedList, tr.mapping.map($next.pos)]); } // For first list item has one child & no nested lists OR first list items that have a paragraph and a list if (firstListItemHasOneChildWithNoNestedLists || firstListItemContainsParagraphAndNestedList) { deletions.push([tr.mapping.map($next.pos), tr.mapping.map($next.pos + firstListItem.nodeSize - 1)]); var firstListItemText = Fragment.from(firstChildNodeOfFirstListItem.content); insertions.push([firstListItemText, paragraphPosition]); insertContentDeleteRange(tr, function (tr) { return tr.doc.resolve($head.pos); }, insertions, deletions); return true; } // For any first list items that have multiple children (eg. multiple paragraphs) if (firstListItem.childCount > 1) { insertions.push([Fragment.from(firstChildNodeOfFirstListItem.content), paragraphPosition]); deletions.push([tr.mapping.map($next.pos + 1), tr.mapping.map($next.pos + firstChildNodeOfFirstListItem.nodeSize + 1)]); insertContentDeleteRange(tr, function (tr) { return tr.doc.resolve($head.pos); }, insertions, deletions); return true; } // For any remaining first list items that have a single child (eg. single paragraph, multiple lines of text) if (firstGrandchildOfFirstListItem && firstGrandchildOfFirstListItem.type.name === 'hardBreak') { var nodeSizeOfGrandchild = firstGrandchildOfFirstListItem ? firstGrandchildOfFirstListItem.nodeSize : 0; deletions.push([tr.mapping.map($next.pos + 2), tr.mapping.map($next.pos + 2 + nodeSizeOfGrandchild)]); } else { insertions.push([Fragment.from(firstChildNodeOfFirstListItem.content), paragraphPosition]); var nodeSizeOfFirstChild = firstChildNodeOfFirstListItem.nodeSize; deletions.push([tr.mapping.map($next.pos), tr.mapping.map($next.pos + 2 + nodeSizeOfFirstChild)]); } insertContentDeleteRange(tr, function (tr) { return tr.doc.resolve($head.pos); }, insertions, deletions); return true; }; var hasSingleChild = function hasSingleChild(node) { return node.childCount === 1; };