diff --git a/packages/core/src/api/blockManipulation/commands/removeBlocks/__snapshots__/removeBlocks.test.ts.snap b/packages/core/src/api/blockManipulation/commands/removeBlocks/__snapshots__/removeBlocks.test.ts.snap index 27ed2158a4..713566c788 100644 --- a/packages/core/src/api/blockManipulation/commands/removeBlocks/__snapshots__/removeBlocks.test.ts.snap +++ b/packages/core/src/api/blockManipulation/commands/removeBlocks/__snapshots__/removeBlocks.test.ts.snap @@ -1,5 +1,445 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`Test removeBlocks > Remove all child blocks 1`] = ` +[ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 0", + "type": "text", + }, + ], + "id": "paragraph-0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 1", + "type": "text", + }, + ], + "id": "paragraph-1", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph with children", + "type": "text", + }, + ], + "id": "paragraph-with-children", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 2", + "type": "text", + }, + ], + "id": "paragraph-2", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph with props", + "type": "text", + }, + ], + "id": "paragraph-with-props", + "props": { + "backgroundColor": "default", + "textAlignment": "center", + "textColor": "red", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 3", + "type": "text", + }, + ], + "id": "paragraph-3", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": { + "bold": true, + }, + "text": "Paragraph", + "type": "text", + }, + { + "styles": {}, + "text": " with styled ", + "type": "text", + }, + { + "styles": { + "italic": true, + }, + "text": "content", + "type": "text", + }, + ], + "id": "paragraph-with-styled-content", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 4", + "type": "text", + }, + ], + "id": "paragraph-4", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Heading 1", + "type": "text", + }, + ], + "id": "heading-0", + "props": { + "backgroundColor": "default", + "level": 1, + "textAlignment": "left", + "textColor": "default", + }, + "type": "heading", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 5", + "type": "text", + }, + ], + "id": "paragraph-5", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": undefined, + "id": "image-0", + "props": { + "backgroundColor": "default", + "caption": "", + "name": "", + "previewWidth": 512, + "showPreview": true, + "textAlignment": "left", + "url": "https://via.placeholder.com/150", + }, + "type": "image", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 6", + "type": "text", + }, + ], + "id": "paragraph-6", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": { + "columnWidths": [ + undefined, + undefined, + undefined, + ], + "rows": [ + { + "cells": [ + [ + { + "styles": {}, + "text": "Cell 1", + "type": "text", + }, + ], + [ + { + "styles": {}, + "text": "Cell 2", + "type": "text", + }, + ], + [ + { + "styles": {}, + "text": "Cell 3", + "type": "text", + }, + ], + ], + }, + { + "cells": [ + [ + { + "styles": {}, + "text": "Cell 4", + "type": "text", + }, + ], + [ + { + "styles": {}, + "text": "Cell 5", + "type": "text", + }, + ], + [ + { + "styles": {}, + "text": "Cell 6", + "type": "text", + }, + ], + ], + }, + { + "cells": [ + [ + { + "styles": {}, + "text": "Cell 7", + "type": "text", + }, + ], + [ + { + "styles": {}, + "text": "Cell 8", + "type": "text", + }, + ], + [ + { + "styles": {}, + "text": "Cell 9", + "type": "text", + }, + ], + ], + }, + ], + "type": "tableContent", + }, + "id": "table-0", + "props": { + "backgroundColor": "default", + "textColor": "default", + }, + "type": "table", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 7", + "type": "text", + }, + ], + "id": "paragraph-7", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [], + "id": "empty-paragraph", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Paragraph 8", + "type": "text", + }, + ], + "id": "paragraph-8", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [ + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Double Nested Paragraph 1", + "type": "text", + }, + ], + "id": "double-nested-paragraph-1", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": [ + { + "styles": {}, + "text": "Nested Paragraph 1", + "type": "text", + }, + ], + "id": "nested-paragraph-1", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": [ + { + "styles": { + "bold": true, + }, + "text": "Heading", + "type": "text", + }, + { + "styles": {}, + "text": " with styled ", + "type": "text", + }, + { + "styles": { + "italic": true, + }, + "text": "content", + "type": "text", + }, + ], + "id": "heading-with-everything", + "props": { + "backgroundColor": "red", + "level": 2, + "textAlignment": "center", + "textColor": "red", + }, + "type": "heading", + }, + { + "children": [], + "content": [], + "id": "trailing-paragraph", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, +] +`; + exports[`Test removeBlocks > Remove multiple consecutive blocks 1`] = ` [ { diff --git a/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.ts b/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.ts index 55625e11d7..fcdbd4cf07 100644 --- a/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.ts +++ b/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.ts @@ -31,4 +31,10 @@ describe("Test removeBlocks", () => { expect(getEditor().document).toMatchSnapshot(); }); + + it("Remove all child blocks", () => { + removeBlocks(getEditor(), ["nested-paragraph-0"]); + + expect(getEditor().document).toMatchSnapshot(); + }); }); diff --git a/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts b/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts index f5cd55d2cc..d01606aecb 100644 --- a/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts +++ b/packages/core/src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts @@ -1,6 +1,3 @@ -import { Node } from "prosemirror-model"; -import { Transaction } from "prosemirror-state"; - import { Block } from "../../../../blocks/defaultBlocks.js"; import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor"; import { @@ -9,84 +6,7 @@ import { InlineContentSchema, StyleSchema, } from "../../../../schema/index.js"; -import { nodeToBlock } from "../../../nodeConversions/nodeToBlock.js"; - -export function removeBlocksWithCallback< - BSchema extends BlockSchema, - I extends InlineContentSchema, - S extends StyleSchema ->( - editor: BlockNoteEditor, - blocksToRemove: BlockIdentifier[], - // Should return new removedSize. - callback?: ( - node: Node, - pos: number, - tr: Transaction, - removedSize: number - ) => number -): Block[] { - const ttEditor = editor._tiptapEditor; - const tr = ttEditor.state.tr; - - const idsOfBlocksToRemove = new Set( - blocksToRemove.map((block) => - typeof block === "string" ? block : block.id - ) - ); - const removedBlocks: Block[] = []; - let removedSize = 0; - - ttEditor.state.doc.descendants((node, pos) => { - // Skips traversing nodes after all target blocks have been removed. - if (idsOfBlocksToRemove.size === 0) { - return false; - } - - // Keeps traversing nodes if block with target ID has not been found. - if ( - !node.type.isInGroup("bnBlock") || - !idsOfBlocksToRemove.has(node.attrs.id) - ) { - return true; - } - - // Saves the block that is being deleted. - removedBlocks.push( - nodeToBlock( - node, - editor.schema.blockSchema, - editor.schema.inlineContentSchema, - editor.schema.styleSchema, - editor.blockCache - ) - ); - idsOfBlocksToRemove.delete(node.attrs.id); - - // Removes the block and calculates the change in document size. - removedSize = callback?.(node, pos, tr, removedSize) || removedSize; - const oldDocSize = tr.doc.nodeSize; - tr.delete(pos - removedSize - 1, pos - removedSize + node.nodeSize + 1); - const newDocSize = tr.doc.nodeSize; - removedSize += oldDocSize - newDocSize; - - return false; - }); - - // Throws an error if now all blocks could be found. - if (idsOfBlocksToRemove.size > 0) { - const notFoundIds = [...idsOfBlocksToRemove].join("\n"); - - throw Error( - "Blocks with the following IDs could not be found in the editor: " + - notFoundIds - ); - } - - editor.dispatch(tr); - - return removedBlocks; -} +import { removeAndInsertBlocks } from "../replaceBlocks/replaceBlocks.js"; export function removeBlocks< BSchema extends BlockSchema, @@ -96,5 +16,5 @@ export function removeBlocks< editor: BlockNoteEditor, blocksToRemove: BlockIdentifier[] ): Block[] { - return removeBlocksWithCallback(editor, blocksToRemove); + return removeAndInsertBlocks(editor, blocksToRemove, []).removedBlocks; } diff --git a/packages/core/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts b/packages/core/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts index 536c8b5d89..bd6ad6687e 100644 --- a/packages/core/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +++ b/packages/core/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts @@ -1,5 +1,3 @@ -import { Node } from "prosemirror-model"; - import { Block, PartialBlock } from "../../../../blocks/defaultBlocks.js"; import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor"; import { @@ -8,11 +6,11 @@ import { InlineContentSchema, StyleSchema, } from "../../../../schema/index.js"; +import { Node } from "prosemirror-model"; import { blockToNode } from "../../../nodeConversions/blockToNode.js"; import { nodeToBlock } from "../../../nodeConversions/nodeToBlock.js"; -import { removeBlocksWithCallback } from "../removeBlocks/removeBlocks.js"; -export function replaceBlocks< +export function removeAndInsertBlocks< BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema @@ -24,6 +22,11 @@ export function replaceBlocks< insertedBlocks: Block[]; removedBlocks: Block[]; } { + const ttEditor = editor._tiptapEditor; + let tr = ttEditor.state.tr; + + // Converts the `PartialBlock`s to ProseMirror nodes to insert them into the + // document. const nodesToInsert: Node[] = []; for (const block of blocksToInsert) { nodesToInsert.push( @@ -31,28 +34,86 @@ export function replaceBlocks< ); } + const idsOfBlocksToRemove = new Set( + blocksToRemove.map((block) => + typeof block === "string" ? block : block.id + ) + ); + const removedBlocks: Block[] = []; + const idOfFirstBlock = typeof blocksToRemove[0] === "string" ? blocksToRemove[0] : blocksToRemove[0].id; - const removedBlocks = removeBlocksWithCallback( - editor, - blocksToRemove, - (node, pos, tr, removedSize) => { - if (node.attrs.id === idOfFirstBlock) { - const oldDocSize = tr.doc.nodeSize; - tr.insert(pos, nodesToInsert); - const newDocSize = tr.doc.nodeSize; - - return removedSize + oldDocSize - newDocSize; - } - - return removedSize; + let removedSize = 0; + + ttEditor.state.doc.descendants((node, pos) => { + // Skips traversing nodes after all target blocks have been removed. + if (idsOfBlocksToRemove.size === 0) { + return false; + } + + // Keeps traversing nodes if block with target ID has not been found. + if ( + !node.type.isInGroup("bnBlock") || + !idsOfBlocksToRemove.has(node.attrs.id) + ) { + return true; + } + + // Saves the block that is being deleted. + removedBlocks.push( + nodeToBlock( + node, + editor.schema.blockSchema, + editor.schema.inlineContentSchema, + editor.schema.styleSchema, + editor.blockCache + ) + ); + idsOfBlocksToRemove.delete(node.attrs.id); + + if (blocksToInsert.length > 0 && node.attrs.id === idOfFirstBlock) { + const oldDocSize = tr.doc.nodeSize; + tr = tr.insert(pos, nodesToInsert); + const newDocSize = tr.doc.nodeSize; + + removedSize += oldDocSize - newDocSize; } - ); - // Now that the `PartialBlock`s have been converted to nodes, we can - // re-convert them into full `Block`s. + const oldDocSize = tr.doc.nodeSize; + // Checks if the block is the only child of its parent. In this case, we + // need to delete the parent `blockGroup` node instead of just the + // `blockContainer`. + const $pos = tr.doc.resolve(pos - removedSize); + if ( + $pos.node().type.name === "blockGroup" && + $pos.node($pos.depth - 1).type.name !== "doc" && + $pos.node().childCount === 1 + ) { + tr = tr.delete($pos.before(), $pos.after()); + } else { + tr = tr.delete(pos - removedSize, pos - removedSize + node.nodeSize); + } + const newDocSize = tr.doc.nodeSize; + removedSize += oldDocSize - newDocSize; + + return false; + }); + + // Throws an error if now all blocks could be found. + if (idsOfBlocksToRemove.size > 0) { + const notFoundIds = [...idsOfBlocksToRemove].join("\n"); + + throw Error( + "Blocks with the following IDs could not be found in the editor: " + + notFoundIds + ); + } + + editor.dispatch(tr); + + // Converts the nodes created from `blocksToInsert` into full `Block`s. const insertedBlocks: Block[] = []; for (const node of nodesToInsert) { insertedBlocks.push( @@ -68,3 +129,18 @@ export function replaceBlocks< return { insertedBlocks, removedBlocks }; } + +export function replaceBlocks< + BSchema extends BlockSchema, + I extends InlineContentSchema, + S extends StyleSchema +>( + editor: BlockNoteEditor, + blocksToRemove: BlockIdentifier[], + blocksToInsert: PartialBlock[] +): { + insertedBlocks: Block[]; + removedBlocks: Block[]; +} { + return removeAndInsertBlocks(editor, blocksToRemove, blocksToInsert); +} diff --git a/packages/xl-multi-column/src/extensions/ColumnResize/ColumnResizeExtension.ts b/packages/xl-multi-column/src/extensions/ColumnResize/ColumnResizeExtension.ts index a9a3ba445a..aed630092e 100644 --- a/packages/xl-multi-column/src/extensions/ColumnResize/ColumnResizeExtension.ts +++ b/packages/xl-multi-column/src/extensions/ColumnResize/ColumnResizeExtension.ts @@ -296,9 +296,11 @@ class ColumnResizePluginView implements PluginView { this.editor.sideMenu.unfreezeMenu(); }; - // This is a required method for PluginView, so we get a type error if we - // don't implement it. - update: undefined; + destroy() { + this.view.dom.removeEventListener("mousedown", this.mouseDownHandler); + document.body.removeEventListener("mousemove", this.mouseMoveHandler); + document.body.removeEventListener("mouseup", this.mouseUpHandler); + } } const createColumnResizePlugin = (editor: BlockNoteEditor) => diff --git a/packages/xl-multi-column/src/extensions/DropCursor/MultiColumnDropCursorPlugin.ts b/packages/xl-multi-column/src/extensions/DropCursor/MultiColumnDropCursorPlugin.ts index c586a0f942..71c8b40743 100644 --- a/packages/xl-multi-column/src/extensions/DropCursor/MultiColumnDropCursorPlugin.ts +++ b/packages/xl-multi-column/src/extensions/DropCursor/MultiColumnDropCursorPlugin.ts @@ -130,17 +130,24 @@ export function multiColumnDropCursor( (b) => b.id === blockInfo.bnBlock.node.attrs.id ); - const newChildren = columnList.children.toSpliced( - position === "left" ? index : index + 1, - 0, - { + const newChildren = columnList.children + // If the dragged block is in one of the columns, remove it. + .map((column) => ({ + ...column, + children: column.children.filter( + (block) => block.id !== draggedBlock.id + ), + })) + // Remove empty columns (can happen when dragged block is removed). + .filter((column) => column.children.length > 0) + // Insert the dragged block in the correct position. + .toSpliced(position === "left" ? index : index + 1, 0, { type: "column", children: [draggedBlock], props: {}, content: undefined, id: UniqueID.options.generateID(), - } - ); + }); editor.removeBlocks([draggedBlock]); @@ -201,14 +208,25 @@ class DropCursorView { const handler = (e: Event) => { (this as any)[name](e); }; - editorView.dom.addEventListener(name, handler); + editorView.dom.addEventListener( + name, + handler, + // drop event captured in bubbling phase to make sure + // "cursorPos" is set to undefined before the "handleDrop" handler is called + // (otherwise an error could be thrown, see https://github.com/TypeCellOS/BlockNote/pull/1240) + name === "drop" ? true : undefined + ); return { name, handler }; }); } destroy() { this.handlers.forEach(({ name, handler }) => - this.editorView.dom.removeEventListener(name, handler) + this.editorView.dom.removeEventListener( + name, + handler, + name === "drop" ? true : undefined + ) ); } @@ -267,6 +285,10 @@ class DropCursorView { ) { const block = this.editorView.nodeDOM(this.cursorPos.pos); + if (!block) { + throw new Error("nodeDOM returned null in updateOverlay"); + } + const blockRect = (block as HTMLElement).getBoundingClientRect(); const halfWidth = (this.width / 2) * scaleY; const left = @@ -434,7 +456,7 @@ class DropCursorView { target = point; } } - // console.log("target", target); + this.setCursor({ pos: target, position }); this.scheduleRemoval(5000); } @@ -445,7 +467,7 @@ class DropCursorView { } drop() { - this.scheduleRemoval(20); + this.setCursor(undefined); } dragleave(event: DragEvent) { diff --git a/packages/xl-multi-column/src/test/commands/__snapshots__/removeBlocks.test.ts.snap b/packages/xl-multi-column/src/test/commands/__snapshots__/removeBlocks.test.ts.snap new file mode 100644 index 0000000000..ed727925db --- /dev/null +++ b/packages/xl-multi-column/src/test/commands/__snapshots__/removeBlocks.test.ts.snap @@ -0,0 +1,226 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Test removeBlocks > Remove all blocks in column 1`] = ` +[ + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Nested Paragraph 0", + "type": "text", + }, + ], + "id": "nested-paragraph-0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": [ + { + "styles": {}, + "text": "Paragraph 0", + "type": "text", + }, + ], + "id": "paragraph-0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [ + { + "children": [ + { + "children": [], + "content": [], + "id": "0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "column-0", + "props": { + "width": 1, + }, + "type": "column", + }, + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Column Paragraph 2", + "type": "text", + }, + ], + "id": "column-paragraph-2", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Column Paragraph 3", + "type": "text", + }, + ], + "id": "column-paragraph-3", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "column-1", + "props": { + "width": 1, + }, + "type": "column", + }, + ], + "content": undefined, + "id": "column-list-0", + "props": {}, + "type": "columnList", + }, + { + "children": [], + "content": [], + "id": "trailing-paragraph", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, +] +`; + +exports[`Test removeBlocks > Remove all columns in columnList 1`] = ` +[ + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Nested Paragraph 0", + "type": "text", + }, + ], + "id": "nested-paragraph-0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": [ + { + "styles": {}, + "text": "Paragraph 0", + "type": "text", + }, + ], + "id": "paragraph-0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [ + { + "children": [ + { + "children": [], + "content": [], + "id": "1", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "0", + "props": { + "width": 1, + }, + "type": "column", + }, + { + "children": [ + { + "children": [], + "content": [], + "id": "3", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "2", + "props": { + "width": 1, + }, + "type": "column", + }, + ], + "content": undefined, + "id": "column-list-0", + "props": {}, + "type": "columnList", + }, + { + "children": [], + "content": [], + "id": "trailing-paragraph", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, +] +`; diff --git a/packages/xl-multi-column/src/test/commands/__snapshots__/replaceBlocks.test.ts.snap b/packages/xl-multi-column/src/test/commands/__snapshots__/replaceBlocks.test.ts.snap new file mode 100644 index 0000000000..c0c756e5a4 --- /dev/null +++ b/packages/xl-multi-column/src/test/commands/__snapshots__/replaceBlocks.test.ts.snap @@ -0,0 +1,175 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Test replaceBlocks > Replace paragraph with column list above column list empty column list 1`] = ` +[ + { + "children": [ + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Inserted Column Paragraph", + "type": "text", + }, + ], + "id": "2", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "1", + "props": { + "width": 1, + }, + "type": "column", + }, + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Inserted Column Paragraph", + "type": "text", + }, + ], + "id": "4", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "3", + "props": { + "width": 1, + }, + "type": "column", + }, + ], + "content": undefined, + "id": "0", + "props": {}, + "type": "columnList", + }, + { + "children": [ + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Column Paragraph 0", + "type": "text", + }, + ], + "id": "column-paragraph-0", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Column Paragraph 1", + "type": "text", + }, + ], + "id": "column-paragraph-1", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "column-0", + "props": { + "width": 1, + }, + "type": "column", + }, + { + "children": [ + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Column Paragraph 2", + "type": "text", + }, + ], + "id": "column-paragraph-2", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + { + "children": [], + "content": [ + { + "styles": {}, + "text": "Column Paragraph 3", + "type": "text", + }, + ], + "id": "column-paragraph-3", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, + ], + "content": undefined, + "id": "column-1", + "props": { + "width": 1, + }, + "type": "column", + }, + ], + "content": undefined, + "id": "column-list-0", + "props": {}, + "type": "columnList", + }, + { + "children": [], + "content": [], + "id": "trailing-paragraph", + "props": { + "backgroundColor": "default", + "textAlignment": "left", + "textColor": "default", + }, + "type": "paragraph", + }, +] +`; diff --git a/packages/xl-multi-column/src/test/commands/removeBlocks.test.ts b/packages/xl-multi-column/src/test/commands/removeBlocks.test.ts new file mode 100644 index 0000000000..2e5e4977e7 --- /dev/null +++ b/packages/xl-multi-column/src/test/commands/removeBlocks.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from "vitest"; + +import { setupTestEnv } from "../setupTestEnv.js"; + +const getEditor = setupTestEnv(); + +describe("Test removeBlocks", () => { + it("Remove all blocks in column", () => { + getEditor().removeBlocks(["column-paragraph-0", "column-paragraph-1"]); + + expect(getEditor().document).toMatchSnapshot(); + }); + + it("Remove all columns in columnList", () => { + getEditor().removeBlocks(["column-0", "column-1"]); + + expect(getEditor().document).toMatchSnapshot(); + }); +}); diff --git a/packages/xl-multi-column/src/test/commands/replaceBlocks.test.ts b/packages/xl-multi-column/src/test/commands/replaceBlocks.test.ts new file mode 100644 index 0000000000..a5be953031 --- /dev/null +++ b/packages/xl-multi-column/src/test/commands/replaceBlocks.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from "vitest"; + +import { setupTestEnv } from "../setupTestEnv.js"; + +const getEditor = setupTestEnv(); + +describe("Test replaceBlocks", () => { + it("Replace paragraph with column list above column list empty column list", () => { + getEditor().replaceBlocks( + ["paragraph-0"], + [ + { + type: "columnList", + children: [ + { + type: "column", + children: [ + { + type: "paragraph", + content: "Inserted Column Paragraph", + }, + ], + }, + { + type: "column", + children: [ + { + type: "paragraph", + content: "Inserted Column Paragraph", + }, + ], + }, + ], + }, + ] + ); + + expect(getEditor().document).toMatchSnapshot(); + }); +});