@blocknote/core
Version:
A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.
55 lines (48 loc) • 1.67 kB
text/typescript
import { Fragment, Slice } from "prosemirror-model";
import type { Transaction } from "prosemirror-state";
import { ReplaceStep } from "prosemirror-transform";
import { Block, PartialBlock } from "../../../../blocks/defaultBlocks.js";
import {
BlockIdentifier,
BlockSchema,
InlineContentSchema,
StyleSchema,
} from "../../../../schema/index.js";
import { blockToNode } from "../../../nodeConversions/blockToNode.js";
import { nodeToBlock } from "../../../nodeConversions/nodeToBlock.js";
import { getNodeById } from "../../../nodeUtil.js";
import { getPmSchema } from "../../../pmUtil.js";
export function insertBlocks<
BSchema extends BlockSchema,
I extends InlineContentSchema,
S extends StyleSchema,
>(
tr: Transaction,
blocksToInsert: PartialBlock<BSchema, I, S>[],
referenceBlock: BlockIdentifier,
placement: "before" | "after" = "before",
): Block<BSchema, I, S>[] {
const id =
typeof referenceBlock === "string" ? referenceBlock : referenceBlock.id;
const pmSchema = getPmSchema(tr);
const nodesToInsert = blocksToInsert.map((block) =>
blockToNode(block, pmSchema),
);
const posInfo = getNodeById(id, tr.doc);
if (!posInfo) {
throw new Error(`Block with ID ${id} not found`);
}
let pos = posInfo.posBeforeNode;
if (placement === "after") {
pos += posInfo.node.nodeSize;
}
tr.step(
new ReplaceStep(pos, pos, new Slice(Fragment.from(nodesToInsert), 0, 0)),
);
// Now that the `PartialBlock`s have been converted to nodes, we can
// re-convert them into full `Block`s.
const insertedBlocks = nodesToInsert.map((node) =>
nodeToBlock(node, pmSchema),
);
return insertedBlocks;
}