@blocknote/core 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"blocknote.cjs","sources":["../src/schema/inlineContent/createSpec.ts","../src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts","../src/api/blockManipulation/commands/replaceBlocks/util/fixColumnList.ts","../src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts","../src/api/exporters/html/util/serializeBlocksInternalHTML.ts","../src/api/exporters/html/internalHTMLSerializer.ts","../src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts","../src/api/blockManipulation/commands/nestBlock/nestBlock.ts","../src/api/blockManipulation/getBlock/getBlock.ts","../src/editor/managers/BlockManager.ts","../src/editor/managers/EventManager.ts","../src/api/parsers/html/util/nestedLists.ts","../src/api/parsers/html/parseHTML.ts","../src/api/parsers/markdown/parseMarkdown.ts","../src/editor/managers/ExportManager.ts","../src/api/clipboard/fromClipboard/acceptedMIMETypes.ts","../src/api/clipboard/fromClipboard/handleFileInsertion.ts","../src/api/clipboard/fromClipboard/fileDropExtension.ts","../src/api/parsers/markdown/detectMarkdown.ts","../src/api/clipboard/fromClipboard/handleVSCodePaste.ts","../src/api/clipboard/fromClipboard/pasteExtension.ts","../src/api/clipboard/toClipboard/copyExtension.ts","../src/extensions/tiptap-extensions/BackgroundColor/BackgroundColorExtension.ts","../src/extensions/tiptap-extensions/HardBreak/HardBreak.ts","../src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts","../src/extensions/tiptap-extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts","../src/extensions/tiptap-extensions/Suggestions/SuggestionMarks.ts","../src/extensions/tiptap-extensions/TextAlignment/TextAlignmentExtension.ts","../src/extensions/tiptap-extensions/TextColor/TextColorExtension.ts","../src/pm-nodes/BlockContainer.ts","../src/pm-nodes/BlockGroup.ts","../src/pm-nodes/Doc.ts","../src/editor/managers/ExtensionManager/extensions.ts","../src/editor/managers/ExtensionManager/index.ts","../src/api/blockManipulation/selections/selection.ts","../src/api/blockManipulation/selections/textCursorPosition.ts","../src/editor/managers/SelectionManager.ts","../src/editor/managers/StateManager.ts","../src/api/blockManipulation/insertContentAt.ts","../src/editor/managers/StyleManager.ts","../src/editor/transformPasted.ts","../src/editor/BlockNoteEditor.ts","../src/exporter/Exporter.ts","../src/exporter/mapping.ts","../src/util/combineByGroup.ts"],"sourcesContent":["import { Node } from \"@tiptap/core\";\n\nimport { TagParseRule } from \"@tiptap/pm/model\";\nimport { inlineContentToNodes } from \"../../api/nodeConversions/blockToNode.js\";\nimport { nodeToCustomInlineContent } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { propsToAttributes } from \"../blocks/internal.js\";\nimport { Props } from \"../propTypes.js\";\nimport { StyleSchema } from \"../styles/types.js\";\nimport {\n addInlineContentAttributes,\n addInlineContentKeyboardShortcuts,\n createInlineContentSpecFromTipTapNode,\n} from \"./internal.js\";\nimport {\n CustomInlineContentConfig,\n InlineContentFromConfig,\n InlineContentSpec,\n PartialCustomInlineContentFromConfig,\n} from \"./types.js\";\n\nexport type CustomInlineContentImplementation<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n> = {\n meta?: {\n draggable?: boolean;\n };\n\n /**\n * Parses an external HTML element into a inline content of this type when it returns the block props object, otherwise undefined\n */\n parse?: (el: HTMLElement) => Partial<Props<T[\"propSchema\"]>> | undefined;\n\n /**\n * Renders an inline content to DOM elements\n */\n render: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * A callback that allows overriding the inline content element\n */\n updateInlineContent: (\n update: PartialCustomInlineContentFromConfig<T, S>,\n ) => void,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n // (note) if we want to fix the manual cast, we need to prevent circular references and separate block definition and render implementations\n // or allow manually passing <BSchema>, but that's not possible without passing the other generics because Typescript doesn't support partial inferred generics\n ) => {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n destroy?: () => void;\n };\n\n /**\n * Renders an inline content to external HTML elements for use outside the editor\n * If not provided, falls back to the render method\n */\n toExternalHTML?: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n ) =>\n | {\n dom: HTMLElement | DocumentFragment;\n contentDOM?: HTMLElement;\n }\n | undefined;\n\n runsBefore?: string[];\n};\n\nexport function getInlineContentParseRules<C extends CustomInlineContentConfig>(\n config: C,\n customParseFunction?: CustomInlineContentImplementation<C, any>[\"parse\"],\n) {\n const rules: TagParseRule[] = [\n {\n tag: `[data-inline-content-type=\"${config.type}\"]`,\n contentElement: (element) => {\n const htmlElement = element as HTMLElement;\n\n if (htmlElement.matches(\"[data-editable]\")) {\n return htmlElement;\n }\n\n return htmlElement.querySelector(\"[data-editable]\") || htmlElement;\n },\n },\n ];\n\n if (customParseFunction) {\n rules.push({\n tag: \"*\",\n getAttrs(node: string | HTMLElement) {\n if (typeof node === \"string\") {\n return false;\n }\n\n const props = customParseFunction?.(node);\n\n if (props === undefined) {\n return false;\n }\n\n return props;\n },\n });\n }\n return rules;\n}\n\nexport function createInlineContentSpec<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n>(\n inlineContentConfig: T,\n inlineContentImplementation: CustomInlineContentImplementation<T, S>,\n): InlineContentSpec<T> {\n const node = Node.create({\n name: inlineContentConfig.type,\n inline: true,\n group: \"inline\",\n draggable: inlineContentImplementation.meta?.draggable,\n selectable: inlineContentConfig.content === \"styled\",\n atom: inlineContentConfig.content === \"none\",\n content: inlineContentConfig.content === \"styled\" ? \"inline*\" : \"\",\n\n addAttributes() {\n return propsToAttributes(inlineContentConfig.propSchema);\n },\n\n addKeyboardShortcuts() {\n return addInlineContentKeyboardShortcuts(inlineContentConfig);\n },\n\n parseHTML() {\n return getInlineContentParseRules(\n inlineContentConfig,\n inlineContentImplementation.parse,\n );\n },\n\n renderHTML({ node }) {\n const editor = this.options.editor;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"dom\", props: undefined },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n () => {\n // No-op\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n },\n\n addNodeView() {\n return (props) => {\n const { node, getPos } = props;\n const editor = this.options.editor as BlockNoteEditor<any, any, S>;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"nodeView\", props },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n (update) => {\n const content = inlineContentToNodes([update], editor.pmSchema);\n\n const pos = getPos();\n\n if (!pos) {\n return;\n }\n\n editor.transact((tr) =>\n tr.replaceWith(pos, pos + node.nodeSize, content),\n );\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n };\n },\n });\n\n return createInlineContentSpecFromTipTapNode(\n node,\n inlineContentConfig.propSchema,\n {\n ...inlineContentImplementation,\n toExternalHTML: inlineContentImplementation.toExternalHTML,\n render(inlineContent, updateInlineContent, editor) {\n const output = inlineContentImplementation.render(\n inlineContent,\n updateInlineContent,\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n inlineContent.props,\n inlineContentConfig.propSchema,\n );\n },\n },\n ) as InlineContentSpec<T>;\n}\n","import { Fragment, Slice } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport { ReplaceStep } from \"prosemirror-transform\";\nimport { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\n\nexport function insertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n): Block<BSchema, I, S>[] {\n const id =\n typeof referenceBlock === \"string\" ? referenceBlock : referenceBlock.id;\n const pmSchema = getPmSchema(tr);\n const nodesToInsert = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n let pos = posInfo.posBeforeNode;\n if (placement === \"after\") {\n pos += posInfo.node.nodeSize;\n }\n\n tr.step(\n new ReplaceStep(pos, pos, new Slice(Fragment.from(nodesToInsert), 0, 0)),\n );\n\n // Now that the `PartialBlock`s have been converted to nodes, we can\n // re-convert them into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return insertedBlocks;\n}\n","import { Slice, type Node } from \"prosemirror-model\";\nimport { type Transaction } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\n\n/**\n * Checks if a `column` node is empty, i.e. if it has only a single empty\n * paragraph.\n * @param column The column to check.\n * @returns Whether the column is empty.\n */\nexport function isEmptyColumn(column: Node) {\n if (!column || column.type.name !== \"column\") {\n throw new Error(\"Invalid columnPos: does not point to column node.\");\n }\n\n const blockContainer = column.firstChild;\n if (!blockContainer) {\n throw new Error(\"Invalid column: does not have child node.\");\n }\n\n const blockContent = blockContainer.firstChild;\n if (!blockContent) {\n throw new Error(\"Invalid blockContainer: does not have child node.\");\n }\n\n return (\n column.childCount === 1 &&\n blockContainer.childCount === 1 &&\n blockContent.type.name === \"paragraph\" &&\n blockContent.content.content.length === 0\n );\n}\n\n/**\n * Removes all empty `column` nodes in a `columnList`. A `column` node is empty\n * if it has only a single empty block. If, however, removing the `column`s\n * leaves the `columnList` that has fewer than two, ProseMirror will re-add\n * empty columns.\n * @param tr The `Transaction` to add the changes to.\n * @param columnListPos The position just before the `columnList` node.\n */\nexport function removeEmptyColumns(tr: Transaction, columnListPos: number) {\n const $columnListPos = tr.doc.resolve(columnListPos);\n const columnList = $columnListPos.nodeAfter;\n if (!columnList || columnList.type.name !== \"columnList\") {\n throw new Error(\n \"Invalid columnListPos: does not point to columnList node.\",\n );\n }\n\n for (\n let columnIndex = columnList.childCount - 1;\n columnIndex >= 0;\n columnIndex--\n ) {\n const columnPos = tr.doc\n .resolve($columnListPos.pos + 1)\n .posAtIndex(columnIndex);\n const $columnPos = tr.doc.resolve(columnPos);\n const column = $columnPos.nodeAfter;\n if (!column || column.type.name !== \"column\") {\n throw new Error(\"Invalid columnPos: does not point to column node.\");\n }\n\n if (isEmptyColumn(column)) {\n tr.delete(columnPos, columnPos + column.nodeSize);\n }\n }\n}\n\n/**\n * Fixes potential issues in a `columnList` node after a\n * `blockContainer`/`column` node is (re)moved from it:\n *\n * - Removes all empty `column` nodes. A `column` node is empty if it has only\n * a single empty block.\n * - If all but one `column` nodes are empty, replaces the `columnList` with\n * the content of the non-empty `column`.\n * - If all `column` nodes are empty, removes the `columnList` entirely.\n * @param tr The `Transaction` to add the changes to.\n * @param columnListPos\n * @returns The position just before the `columnList` node.\n */\nexport function fixColumnList(tr: Transaction, columnListPos: number) {\n removeEmptyColumns(tr, columnListPos);\n\n const $columnListPos = tr.doc.resolve(columnListPos);\n const columnList = $columnListPos.nodeAfter;\n if (!columnList || columnList.type.name !== \"columnList\") {\n throw new Error(\n \"Invalid columnListPos: does not point to columnList node.\",\n );\n }\n\n if (columnList.childCount > 2) {\n // Do nothing if the `columnList` has more than two non-empty `column`s. In\n // the case that the `columnList` has exactly two columns, we may need to\n // still remove it, as it's possible that one or both columns are empty.\n // This is because after `removeEmptyColumns` is called, if the\n // `columnList` has fewer than two `column`s, ProseMirror will re-add empty\n // `column`s until there are two total, in order to fit the schema.\n return;\n }\n\n if (columnList.childCount < 2) {\n // Throw an error if the `columnList` has fewer than two columns. After\n // `removeEmptyColumns` is called, if the `columnList` has fewer than two\n // `column`s, ProseMirror will re-add empty `column`s until there are two\n // total, in order to fit the schema. So if there are fewer than two here,\n // either the schema, or ProseMirror's internals, must have changed.\n throw new Error(\"Invalid columnList: contains fewer than two children.\");\n }\n\n const firstColumnBeforePos = columnListPos + 1;\n const $firstColumnBeforePos = tr.doc.resolve(firstColumnBeforePos);\n const firstColumn = $firstColumnBeforePos.nodeAfter;\n\n const lastColumnAfterPos = columnListPos + columnList.nodeSize - 1;\n const $lastColumnAfterPos = tr.doc.resolve(lastColumnAfterPos);\n const lastColumn = $lastColumnAfterPos.nodeBefore;\n\n if (!firstColumn || !lastColumn) {\n throw new Error(\"Invalid columnList: does not contain children.\");\n }\n\n const firstColumnEmpty = isEmptyColumn(firstColumn);\n const lastColumnEmpty = isEmptyColumn(lastColumn);\n\n if (firstColumnEmpty && lastColumnEmpty) {\n // Removes `columnList`\n tr.delete(columnListPos, columnListPos + columnList.nodeSize);\n\n return;\n }\n\n if (firstColumnEmpty) {\n tr.step(\n new ReplaceAroundStep(\n // Replaces `columnList`.\n columnListPos,\n columnListPos + columnList.nodeSize,\n // Replaces with content of last `column`.\n lastColumnAfterPos - lastColumn.nodeSize + 1,\n lastColumnAfterPos - 1,\n // Doesn't append anything.\n Slice.empty,\n 0,\n false,\n ),\n );\n\n return;\n }\n\n if (lastColumnEmpty) {\n tr.step(\n new ReplaceAroundStep(\n // Replaces `columnList`.\n columnListPos,\n columnListPos + columnList.nodeSize,\n // Replaces with content of first `column`.\n firstColumnBeforePos + 1,\n firstColumnBeforePos + firstColumn.nodeSize - 1,\n // Doesn't append anything.\n Slice.empty,\n 0,\n false,\n ),\n );\n\n return;\n }\n}\n","import { type Node } from \"prosemirror-model\";\nimport { type Transaction } from \"prosemirror-state\";\nimport type { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\nimport { fixColumnList } from \"./util/fixColumnList.js\";\n\nexport function removeAndInsertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n): {\n insertedBlocks: Block<BSchema, I, S>[];\n removedBlocks: Block<BSchema, I, S>[];\n} {\n const pmSchema = getPmSchema(tr);\n // Converts the `PartialBlock`s to ProseMirror nodes to insert them into the\n // document.\n const nodesToInsert: Node[] = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const idsOfBlocksToRemove = new Set<string>(\n blocksToRemove.map((block) =>\n typeof block === \"string\" ? block : block.id,\n ),\n );\n const removedBlocks: Block<BSchema, I, S>[] = [];\n const columnListPositions = new Set<number>();\n\n const idOfFirstBlock =\n typeof blocksToRemove[0] === \"string\"\n ? blocksToRemove[0]\n : blocksToRemove[0].id;\n let removedSize = 0;\n\n tr.doc.descendants((node, pos) => {\n // Skips traversing nodes after all target blocks have been removed.\n if (idsOfBlocksToRemove.size === 0) {\n return false;\n }\n\n // Keeps traversing nodes if block with target ID has not been found.\n if (\n !node.type.isInGroup(\"bnBlock\") ||\n !idsOfBlocksToRemove.has(node.attrs.id)\n ) {\n return true;\n }\n\n // Saves the block that is being deleted.\n removedBlocks.push(nodeToBlock(node, pmSchema));\n idsOfBlocksToRemove.delete(node.attrs.id);\n\n if (blocksToInsert.length > 0 && node.attrs.id === idOfFirstBlock) {\n const oldDocSize = tr.doc.nodeSize;\n tr.insert(pos, nodesToInsert);\n const newDocSize = tr.doc.nodeSize;\n\n removedSize += oldDocSize - newDocSize;\n }\n\n const oldDocSize = tr.doc.nodeSize;\n\n const $pos = tr.doc.resolve(pos - removedSize);\n\n if ($pos.node().type.name === \"column\") {\n columnListPositions.add($pos.before(-1));\n } else if ($pos.node().type.name === \"columnList\") {\n columnListPositions.add($pos.before());\n }\n\n if (\n $pos.node().type.name === \"blockGroup\" &&\n $pos.node($pos.depth - 1).type.name !== \"doc\" &&\n $pos.node().childCount === 1\n ) {\n // Checks if the block is the only child of a parent `blockGroup` node.\n // In this case, we need to delete the parent `blockGroup` node instead\n // of just the `blockContainer`.\n tr.delete($pos.before(), $pos.after());\n } else {\n tr.delete(pos - removedSize, pos - removedSize + node.nodeSize);\n }\n\n const newDocSize = tr.doc.nodeSize;\n removedSize += oldDocSize - newDocSize;\n\n return false;\n });\n\n // Throws an error if not all blocks could be found.\n if (idsOfBlocksToRemove.size > 0) {\n const notFoundIds = [...idsOfBlocksToRemove].join(\"\\n\");\n\n throw Error(\n \"Blocks with the following IDs could not be found in the editor: \" +\n notFoundIds,\n );\n }\n\n columnListPositions.forEach((pos) => fixColumnList(tr, pos));\n\n // Converts the nodes created from `blocksToInsert` into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return { insertedBlocks, removedBlocks };\n}\n","import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../../util/typescript.js\";\nimport {\n inlineContentToNodes,\n tableContentToNodes,\n} from \"../../../nodeConversions/blockToNode.js\";\n\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\nexport function serializeInlineContentInternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<any, I, S>,\n blockContent: PartialBlock<BSchema, I, S>[\"content\"],\n serializer: DOMSerializer,\n blockType?: string,\n options?: { document?: Document },\n) {\n let nodes: Node[];\n\n // TODO: reuse function from nodeconversions?\n if (!blockContent) {\n throw new Error(\"blockContent is required\");\n } else if (typeof blockContent === \"string\") {\n nodes = inlineContentToNodes([blockContent], editor.pmSchema, blockType);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema, blockType);\n } else if (blockContent.type === \"tableContent\") {\n nodes = tableContentToNodes(blockContent, editor.pmSchema);\n } else {\n throw new UnreachableCaseError(blockContent.type);\n }\n\n // Check if any of the nodes are custom inline content with toExternalHTML\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const node of nodes) {\n // Check if this is a custom inline content node with toExternalHTML\n if (\n node.type.name !== \"text\" &&\n editor.schema.inlineContentSchema[node.type.name]\n ) {\n const inlineContentImplementation =\n editor.schema.inlineContentSpecs[node.type.name].implementation;\n\n if (inlineContentImplementation) {\n // Convert the node to inline content format\n const inlineContent = nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Use the custom toExternalHTML method\n const output = inlineContentImplementation.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n inlineContent as any,\n () => {\n // No-op\n },\n editor as any,\n );\n\n if (output) {\n fragment.appendChild(output.dom);\n\n // If contentDOM exists, render the inline content into it\n if (output.contentDOM) {\n const contentFragment = serializer.serializeFragment(\n node.content,\n options,\n );\n output.contentDOM.dataset.editable = \"\";\n output.contentDOM.appendChild(contentFragment);\n }\n continue;\n }\n }\n } else if (node.type.name === \"text\") {\n // We serialize text nodes manually as we need to serialize the styles/\n // marks using `styleSpec.implementation.render`. When left up to\n // ProseMirror, it'll use `toDOM` which is incorrect.\n let dom: globalThis.Node | Text = document.createTextNode(\n node.textContent,\n );\n // Reverse the order of marks to maintain the correct priority.\n for (const mark of node.marks.toReversed()) {\n if (mark.type.name in editor.schema.styleSpecs) {\n const newDom = editor.schema.styleSpecs[\n mark.type.name\n ].implementation.render(mark.attrs[\"stringValue\"], editor);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n } else {\n const domOutputSpec = mark.type.spec.toDOM!(mark, true);\n const newDom = DOMSerializer.renderSpec(document, domOutputSpec);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n }\n }\n\n fragment.appendChild(dom);\n } else {\n // Fall back to default serialization for this node\n const nodeFragment = serializer.serializeFragment(\n Fragment.from([node]),\n options,\n );\n fragment.appendChild(nodeFragment);\n }\n }\n\n return fragment;\n}\n\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const BC_NODE = editor.pmSchema.nodes[\"blockContainer\"];\n\n // set default props in case we were passed a partial block\n const props = block.props || {};\n for (const [name, spec] of Object.entries(\n editor.schema.blockSchema[block.type as any].propSchema,\n )) {\n if (!(name in props) && spec.default !== undefined) {\n (props as any)[name] = spec.default;\n }\n }\n const children = block.children || [];\n\n const impl = editor.blockImplementations[block.type as any].implementation;\n const ret = impl.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n { ...block, props, children } as any,\n editor as any,\n );\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentInternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n block.type,\n options,\n );\n ret.contentDOM.appendChild(ic);\n }\n\n const pmType = editor.pmSchema.nodes[block.type as any];\n\n if (pmType.isInGroup(\"bnBlock\")) {\n if (block.children && block.children.length > 0) {\n const fragment = serializeBlocks(\n editor,\n block.children,\n serializer,\n options,\n );\n\n ret.contentDOM?.append(fragment);\n }\n return ret.dom;\n }\n\n // wrap the block in a blockContainer\n const bc = BC_NODE.spec?.toDOM?.(\n BC_NODE.create({\n id: block.id,\n ...props,\n }),\n ) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n bc.contentDOM?.appendChild(ret.dom);\n\n if (block.children && block.children.length > 0) {\n bc.contentDOM?.appendChild(\n serializeBlocksInternalHTML(editor, block.children, serializer, options),\n );\n }\n return bc.dom;\n}\n\nfunction serializeBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const block of blocks) {\n const blockDOM = serializeBlock(editor, block, serializer, options);\n fragment.appendChild(blockDOM);\n }\n\n return fragment;\n}\n\nexport const serializeBlocksInternalHTML = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) => {\n const BG_NODE = editor.pmSchema.nodes[\"blockGroup\"];\n\n const bg = BG_NODE.spec!.toDOM!(BG_NODE.create({})) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n const fragment = serializeBlocks(editor, blocks, serializer, options);\n\n bg.contentDOM?.appendChild(fragment);\n\n return bg.dom;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { serializeBlocksInternalHTML } from \"./util/serializeBlocksInternalHTML.js\";\n// Used to serialize BlockNote blocks and ProseMirror nodes to HTML without\n// losing data. Blocks are exported using the `toInternalHTML` method in their\n// `blockSpec`.\n//\n// The HTML created by this serializer is the same as what's rendered by the\n// editor to the DOM. This means that it retains the same structure as the\n// editor, including the `blockGroup` and `blockContainer` wrappers. This also\n// means that it can be converted back to the original blocks without any data\n// loss.\nexport const createInternalHTMLSerializer = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n) => {\n const serializer = DOMSerializer.fromSchema(schema);\n\n return {\n serializeBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n return serializeBlocksInternalHTML(editor, blocks, serializer, options)\n .outerHTML;\n },\n };\n};\n","import {\n NodeSelection,\n Selection,\n TextSelection,\n Transaction,\n} from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor\";\nimport { BlockIdentifier } from \"../../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../../getBlockInfoFromPos.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\n\ntype BlockSelectionData = (\n | {\n type: \"text\";\n headBlockId: string;\n anchorOffset: number;\n headOffset: number;\n }\n | {\n type: \"node\";\n }\n | {\n type: \"cell\";\n anchorCellOffset: number;\n headCellOffset: number;\n }\n) & {\n anchorBlockId: string;\n};\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param editor The BlockNote editor instance to get the selection data from.\n */\nfunction getBlockSelectionData(\n editor: BlockNoteEditor<any, any, any>,\n): BlockSelectionData {\n return editor.transact((tr) => {\n const anchorBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.anchor);\n\n if (tr.selection instanceof CellSelection) {\n return {\n type: \"cell\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n anchorCellOffset:\n tr.selection.$anchorCell.pos - anchorBlockPosInfo.posBeforeNode,\n headCellOffset:\n tr.selection.$headCell.pos - anchorBlockPosInfo.posBeforeNode,\n };\n } else if (tr.selection instanceof NodeSelection) {\n return {\n type: \"node\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n };\n } else {\n const headBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.head);\n\n return {\n type: \"text\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n headBlockId: headBlockPosInfo.node.attrs.id,\n anchorOffset: tr.selection.anchor - anchorBlockPosInfo.posBeforeNode,\n headOffset: tr.selection.head - headBlockPosInfo.posBeforeNode,\n };\n }\n });\n}\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param tr The transaction to update the selection in.\n * @param data The selection data to update the selection with (generated by\n * `getBlockSelectionData`).\n */\nfunction updateBlockSelectionFromData(\n tr: Transaction,\n data: BlockSelectionData,\n) {\n const anchorBlockPos = getNodeById(data.anchorBlockId, tr.doc)?.posBeforeNode;\n if (anchorBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.anchorBlockId} to update selection`,\n );\n }\n\n let selection: Selection;\n if (data.type === \"cell\") {\n selection = CellSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorCellOffset,\n anchorBlockPos + data.headCellOffset,\n );\n } else if (data.type === \"node\") {\n selection = NodeSelection.create(tr.doc, anchorBlockPos + 1);\n } else {\n const headBlockPos = getNodeById(data.headBlockId, tr.doc)?.posBeforeNode;\n if (headBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.headBlockId} to update selection`,\n );\n }\n\n selection = TextSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorOffset,\n headBlockPos + data.headOffset,\n );\n }\n\n tr.setSelection(selection);\n}\n\n/**\n * Replaces any `columnList` blocks with the children of their columns. This is\n * done here instead of in `getSelection` as we still need to remove the entire\n * `columnList` node but only insert the `blockContainer` nodes inside it.\n * @param blocks The blocks to flatten.\n */\nfunction flattenColumns(\n blocks: Block<any, any, any>[],\n): Block<any, any, any>[] {\n return blocks\n .map((block) => {\n if (block.type === \"columnList\") {\n return block.children\n .map((column) => flattenColumns(column.children))\n .flat();\n }\n\n return {\n ...block,\n children: flattenColumns(block.children),\n };\n })\n .flat();\n}\n\n/**\n * Removes the selected blocks from the editor, then inserts them before/after a\n * reference block. Also updates the selection to match the original selection\n * using `getBlockSelectionData` and `updateBlockSelectionFromData`.\n * @param editor The BlockNote editor instance to move the blocks in.\n * @param referenceBlock The reference block to insert the selected blocks\n * before/after.\n * @param placement Whether to insert the selected blocks before or after the\n * reference block.\n */\nexport function moveSelectedBlocksAndSelection(\n editor: BlockNoteEditor<any, any, any>,\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\",\n) {\n // We want this to be a single step in the undo history\n editor.transact((tr) => {\n const blocks = editor.getSelection()?.blocks || [\n editor.getTextCursorPosition().block,\n ];\n const selectionData = getBlockSelectionData(editor);\n\n editor.removeBlocks(blocks);\n editor.insertBlocks(flattenColumns(blocks), referenceBlock, placement);\n\n updateBlockSelectionFromData(tr, selectionData);\n });\n}\n\n// Checks if a block is in a valid place after being moved. This check is\n// primitive at the moment and only returns false if the block's parent is a\n// `columnList` block. This is because regular blocks cannot be direct children\n// of `columnList` blocks.\nfunction checkPlacementIsValid(parentBlock?: Block<any, any, any>): boolean {\n return !parentBlock || parentBlock.type !== \"columnList\";\n}\n\n// Gets the placement for moving a block up. This has 3 cases:\n// 1. If the block has a previous sibling without children, the placement is\n// before it.\n// 2. If the block has a previous sibling with children, the placement is after\n// the last child.\n// 3. If the block has no previous sibling, but is nested, the placement is\n// before its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the top of the document.\nfunction getMoveUpPlacement(\n editor: BlockNoteEditor<any, any, any>,\n prevBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!prevBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"before\";\n }\n } else if (prevBlock.children.length > 0) {\n referenceBlock = prevBlock.children[prevBlock.children.length - 1];\n placement = \"after\";\n } else {\n referenceBlock = prevBlock;\n placement = \"before\";\n }\n\n // Case when the block is already at the top of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveUpPlacement(\n editor,\n placement === \"after\"\n ? referenceBlock\n : editor.getPrevBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\n// Gets the placement for moving a block down. This has 3 cases:\n// 1. If the block has a next sibling without children, the placement is after\n// it.\n// 2. If the block has a next sibling with children, the placement is before the\n// first child.\n// 3. If the block has no next sibling, but is nested, the placement is\n// after its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the bottom of the document.\nfunction getMoveDownPlacement(\n editor: BlockNoteEditor<any, any, any>,\n nextBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!nextBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"after\";\n }\n } else if (nextBlock.children.length > 0) {\n referenceBlock = nextBlock.children[0];\n placement = \"before\";\n } else {\n referenceBlock = nextBlock;\n placement = \"after\";\n }\n\n // Case when the block is already at the bottom of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveDownPlacement(\n editor,\n placement === \"before\"\n ? referenceBlock\n : editor.getNextBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\nexport function moveBlocksUp(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block = selection?.blocks[0] || editor.getTextCursorPosition().block;\n\n const moveUpPlacement = getMoveUpPlacement(\n editor,\n editor.getPrevBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveUpPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveUpPlacement.referenceBlock,\n moveUpPlacement.placement,\n );\n });\n}\n\nexport function moveBlocksDown(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block =\n selection?.blocks[selection?.blocks.length - 1] ||\n editor.getTextCursorPosition().block;\n\n const moveDownPlacement = getMoveDownPlacement(\n editor,\n editor.getNextBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveDownPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveDownPlacement.referenceBlock,\n moveDownPlacement.placement,\n );\n });\n}\n","import { Fragment, NodeType, Slice } from \"prosemirror-model\";\nimport { Transaction } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\n\nimport { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport { getBlockInfoFromTransaction } from \"../../../getBlockInfoFromPos.js\";\n\n// TODO: Unit tests\n/**\n * This is a modified version of https://github.com/ProseMirror/prosemirror-schema-list/blob/569c2770cbb8092d8f11ea53ecf78cb7a4e8f15a/src/schema-list.ts#L232\n *\n * The original function derives too many information from the parentnode and itemtype\n */\nfunction sinkListItem(\n tr: Transaction,\n itemType: NodeType,\n groupType: NodeType,\n) {\n const { $from, $to } = tr.selection;\n const range = $from.blockRange(\n $to,\n (node) =>\n node.childCount > 0 &&\n (node.type.name === \"blockGroup\" || node.type.name === \"column\"), // change necessary to not look at first item child type\n );\n if (!range) {\n return false;\n }\n const startIndex = range.startIndex;\n if (startIndex === 0) {\n return false;\n }\n const parent = range.parent;\n const nodeBefore = parent.child(startIndex - 1);\n if (nodeBefore.type !== itemType) {\n return false;\n }\n const nestedBefore =\n nodeBefore.lastChild && nodeBefore.lastChild.type === groupType; // change necessary to check groupType instead of parent.type\n const inner = Fragment.from(nestedBefore ? itemType.create() : null);\n const slice = new Slice(\n Fragment.from(\n itemType.create(null, Fragment.from(groupType.create(null, inner))), // change necessary to create \"groupType\" instead of parent.type\n ),\n nestedBefore ? 3 : 1,\n 0,\n );\n\n const before = range.start;\n const after = range.end;\n\n tr.step(\n new ReplaceAroundStep(\n before - (nestedBefore ? 3 : 1),\n after,\n before,\n after,\n slice,\n 1,\n true,\n ),\n ).scrollIntoView();\n\n return true;\n}\n\nexport function nestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n return sinkListItem(\n tr,\n editor.pmSchema.nodes[\"blockContainer\"],\n editor.pmSchema.nodes[\"blockGroup\"],\n );\n });\n}\n\nexport function unnestBlock(editor: BlockNoteEditor<any, any, any>) {\n editor._tiptapEditor.commands.liftListItem(\"blockContainer\");\n}\n\nexport function canNestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).nodeBefore !== null;\n });\n}\n\nexport function canUnnestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).depth > 1;\n });\n}\n","import type { Node } from \"prosemirror-model\";\nimport type { Block } from \"../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getPmSchema } from \"../../pmUtil.js\";\n\nexport function getBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n return nodeToBlock(posInfo.node, pmSchema);\n}\n\nexport function getPrevBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const nodeToConvert = $posBeforeNode.nodeBefore;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getNextBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posAfterNode = doc.resolve(\n posInfo.posBeforeNode + posInfo.node.nodeSize,\n );\n const nodeToConvert = $posAfterNode.nodeAfter;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getParentBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const parentNode = $posBeforeNode.node();\n const grandparentNode = $posBeforeNode.node(-1);\n const nodeToConvert =\n grandparentNode.type.name !== \"doc\"\n ? parentNode.type.name === \"blockGroup\"\n ? grandparentNode\n : parentNode\n : undefined;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n","import { insertBlocks } from \"../../api/blockManipulation/commands/insertBlocks/insertBlocks.js\";\nimport {\n moveBlocksDown,\n moveBlocksUp,\n} from \"../../api/blockManipulation/commands/moveBlocks/moveBlocks.js\";\nimport {\n canNestBlock,\n canUnnestBlock,\n nestBlock,\n unnestBlock,\n} from \"../../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { removeAndInsertBlocks } from \"../../api/blockManipulation/commands/replaceBlocks/replaceBlocks.js\";\nimport { updateBlock } from \"../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport {\n getBlock,\n getNextBlock,\n getParentBlock,\n getPrevBlock,\n} from \"../../api/blockManipulation/getBlock/getBlock.js\";\nimport { docToBlocks } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../../blocks/defaultBlocks.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class BlockManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Gets a snapshot of all top-level (non-nested) blocks in the editor.\n * @returns A snapshot of all top-level (non-nested) blocks in the editor.\n */\n public get document(): Block<BSchema, ISchema, SSchema>[] {\n return this.editor.transact((tr) => {\n return docToBlocks(tr.doc, this.editor.pmSchema);\n });\n }\n\n /**\n * Gets a snapshot of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block that should be\n * retrieved.\n * @returns The block that matches the identifier, or `undefined` if no\n * matching block was found.\n */\n public getBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the previous sibling of an existing block from the\n * editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * previous sibling should be retrieved.\n * @returns The previous sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the first child/block\n * in the document.\n */\n public getPrevBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getPrevBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the next sibling of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * next sibling should be retrieved.\n * @returns The next sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the last child/block in\n * the document.\n */\n public getNextBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getNextBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the parent of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * parent should be retrieved.\n * @returns The parent of the block that matches the identifier. `undefined`\n * if no matching block was found, or the block isn't nested.\n */\n public getParentBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) =>\n getParentBlock(tr.doc, blockIdentifier),\n );\n }\n\n /**\n * Traverses all blocks in the editor depth-first, and executes a callback for each.\n * @param callback The callback to execute for each block. Returning `false` stops the traversal.\n * @param reverse Whether the blocks should be traversed in reverse order.\n */\n public forEachBlock(\n callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,\n reverse = false,\n ): void {\n const blocks = this.document.slice();\n\n if (reverse) {\n blocks.reverse();\n }\n\n function traverseBlockArray(\n blockArray: Block<BSchema, ISchema, SSchema>[],\n ): boolean {\n for (const block of blockArray) {\n if (callback(block) === false) {\n return false;\n }\n\n const children = reverse\n ? block.children.slice().reverse()\n : block.children;\n\n if (!traverseBlockArray(children)) {\n return false;\n }\n }\n\n return true;\n }\n\n traverseBlockArray(blocks);\n }\n\n /**\n * Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an\n * error if the reference block could not be found.\n * @param blocksToInsert An array of partial blocks that should be inserted.\n * @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.\n * @param placement Whether the blocks should be inserted just before, just after, or nested inside the\n * `referenceBlock`.\n */\n public insertBlocks(\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n ) {\n return this.editor.transact((tr) =>\n insertBlocks(tr, blocksToInsert, referenceBlock, placement),\n );\n }\n\n /**\n * Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be\n * defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could\n * not be found.\n * @param blockToUpdate The block that should be updated.\n * @param update A partial block which defines how the existing block should be changed.\n */\n public updateBlock(\n blockToUpdate: BlockIdentifier,\n update: PartialBlock<BSchema, ISchema, SSchema>,\n ) {\n return this.editor.transact((tr) => updateBlock(tr, blockToUpdate, update));\n }\n\n /**\n * Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.\n * @param blocksToRemove An array of identifiers for existing blocks that should be removed.\n */\n public removeBlocks(blocksToRemove: BlockIdentifier[]) {\n return this.editor.transact(\n (tr) => removeAndInsertBlocks(tr, blocksToRemove, []).removedBlocks,\n );\n }\n\n /**\n * Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or\n * are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in\n * `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.\n * @param blocksToRemove An array of blocks that should be replaced.\n * @param blocksToInsert An array of partial blocks to replace the old ones with.\n */\n public replaceBlocks(\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n ) {\n return this.editor.transact((tr) =>\n removeAndInsertBlocks(tr, blocksToRemove, blocksToInsert),\n );\n }\n\n /**\n * Checks if the block containing the text cursor can be nested.\n */\n public canNestBlock() {\n return canNestBlock(this.editor);\n }\n\n /**\n * Nests the block containing the text cursor into the block above it.\n */\n public nestBlock() {\n nestBlock(this.editor);\n }\n\n /**\n * Checks if the block containing the text cursor is nested.\n */\n public canUnnestBlock() {\n return canUnnestBlock(this.editor);\n }\n\n /**\n * Lifts the block containing the text cursor out of its parent.\n */\n public unnestBlock() {\n unnestBlock(this.editor);\n }\n\n /**\n * Moves the selected blocks up. If the previous block has children, moves\n * them to the end of its children. If there is no previous block, but the\n * current blocks share a common parent, moves them out of & before it.\n */\n public moveBlocksUp() {\n return moveBlocksUp(this.editor);\n }\n\n /**\n * Moves the selected blocks down. If the next block has children, moves\n * them to the start of its children. If there is no next block, but the\n * current blocks share a common parent, moves them out of & after it.\n */\n public moveBlocksDown() {\n return moveBlocksDown(this.editor);\n }\n}\n","import type { BlockNoteEditor } from \"../BlockNoteEditor.js\";\nimport {\n getBlocksChangedByTransaction,\n type BlocksChanged,\n} from \"../../api/getBlocksChangedByTransaction.js\";\nimport { Transaction } from \"prosemirror-state\";\nimport { EventEmitter } from \"../../util/EventEmitter.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\n/**\n * A function that can be used to unsubscribe from an event.\n */\nexport type Unsubscribe = () => void;\n\n/**\n * EventManager is a class which manages the events of the editor\n */\nexport class EventManager<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends EventEmitter<{\n onChange: [\n ctx: {\n editor: BlockNoteEditor<BSchema, I, S>;\n transaction: Transaction;\n appendedTransactions: Transaction[];\n },\n ];\n onSelectionChange: [\n ctx: { editor: BlockNoteEditor<BSchema, I, S>; transaction: Transaction },\n ];\n onMount: [ctx: { editor: BlockNoteEditor<BSchema, I, S> }];\n onUnmount: [ctx: { editor: BlockNoteEditor<BSchema, I, S> }];\n}> {\n constructor(private editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n // We register tiptap events only once the editor is finished initializing\n // otherwise we would be trying to register events on a tiptap editor which does not exist yet\n editor.on(\"create\", () => {\n editor._tiptapEditor.on(\n \"update\",\n ({ transaction, appendedTransactions }) => {\n this.emit(\"onChange\", { editor, transaction, appendedTransactions });\n },\n );\n editor._tiptapEditor.on(\"selectionUpdate\", ({ transaction }) => {\n this.emit(\"onSelectionChange\", { editor, transaction });\n });\n editor._tiptapEditor.on(\"mount\", () => {\n this.emit(\"onMount\", { editor });\n });\n editor._tiptapEditor.on(\"unmount\", () => {\n this.emit(\"onUnmount\", { editor });\n });\n });\n }\n\n /**\n * Register a callback that will be called when the editor changes.\n */\n public onChange(\n callback: (\n editor: BlockNoteEditor<BSchema, I, S>,\n ctx: {\n getChanges(): BlocksChanged<BSchema, I, S>;\n },\n ) => void,\n /**\n * If true, the callback will be triggered when the changes are caused by a remote user\n * @default true\n */\n includeUpdatesFromRemote = true,\n ): Unsubscribe {\n const cb = ({\n transaction,\n appendedTransactions,\n }: {\n transaction: Transaction;\n appendedTransactions: Transaction[];\n }) => {\n if (!includeUpdatesFromRemote && isRemoteTransaction(transaction)) {\n // don't trigger the callback if the changes are caused by a remote user\n return;\n }\n callback(this.editor, {\n getChanges() {\n return getBlocksChangedByTransaction(\n transaction,\n appendedTransactions,\n );\n },\n });\n };\n this.on(\"onChange\", cb);\n\n return () => {\n this.off(\"onChange\", cb);\n };\n }\n\n /**\n * Register a callback that will be called when the selection changes.\n */\n public onSelectionChange(\n callback: (editor: BlockNoteEditor<BSchema, I, S>) => void,\n /**\n * If true, the callback will be triggered when the selection changes due to a yjs sync (i.e.: other user was typing)\n */\n includeSelectionChangedByRemote = false,\n ): Unsubscribe {\n const cb = (e: { transaction: Transaction }) => {\n if (\n !includeSelectionChangedByRemote &&\n isRemoteTransaction(e.transaction)\n ) {\n // don't trigger the callback if the selection changed because of a remote user\n return;\n }\n callback(this.editor);\n };\n\n this.on(\"onSelectionChange\", cb);\n\n return () => {\n this.off(\"onSelectionChange\", cb);\n };\n }\n\n /**\n * Register a callback that will be called when the editor is mounted.\n */\n public onMount(\n callback: (ctx: { editor: BlockNoteEditor<BSchema, I, S> }) => void,\n ): Unsubscribe {\n this.on(\"onMount\", callback);\n\n return () => {\n this.off(\"onMount\", callback);\n };\n }\n\n /**\n * Register a callback that will be called when the editor is unmounted.\n */\n public onUnmount(\n callback: (ctx: { editor: BlockNoteEditor<BSchema, I, S> }) => void,\n ): Unsubscribe {\n this.on(\"onUnmount\", callback);\n\n return () => {\n this.off(\"onUnmount\", callback);\n };\n }\n}\n\nfunction isRemoteTransaction(transaction: Transaction): boolean {\n return !!transaction.getMeta(\"y-sync$\");\n}\n","function getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\nfunction isWhitespaceNode(node: Node) {\n return node.nodeType === 3 && !/\\S/.test(node.nodeValue || \"\");\n}\n\n/**\n * Step 1, Turns:\n *\n * <ul>\n * <li>item</li>\n * <li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </li>\n *\n * Into:\n * <ul>\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </ul>\n *\n */\nfunction liftNestedListsToParent(element: HTMLElement) {\n element.querySelectorAll(\"li > ul, li > ol\").forEach((list) => {\n const index = getChildIndex(list);\n const parentListItem = list.parentElement!;\n const siblingsAfter = Array.from(parentListItem.childNodes).slice(\n index + 1,\n );\n list.remove();\n siblingsAfter.forEach((sibling) => {\n sibling.remove();\n });\n\n parentListItem.insertAdjacentElement(\"afterend\", list);\n\n siblingsAfter.reverse().forEach((sibling) => {\n if (isWhitespaceNode(sibling)) {\n return;\n }\n const siblingContainer = document.createElement(\"li\");\n siblingContainer.append(sibling);\n list.insertAdjacentElement(\"afterend\", siblingContainer);\n });\n if (parentListItem.childNodes.length === 0) {\n parentListItem.remove();\n }\n });\n}\n\n/**\n * Step 2, Turns (output of liftNestedListsToParent):\n *\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n *\n * Into:\n * <div>\n * <li>item</li>\n * <div data-node-type=\"blockGroup\">\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </div>\n * </div>\n *\n * This resulting format is parsed\n */\nfunction createGroups(element: HTMLElement) {\n element.querySelectorAll(\"li + ul, li + ol\").forEach((list) => {\n const listItem = list.previousElementSibling as HTMLElement;\n const blockContainer = document.createElement(\"div\");\n\n listItem.insertAdjacentElement(\"afterend\", blockContainer);\n blockContainer.append(listItem);\n\n const blockGroup = document.createElement(\"div\");\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n blockContainer.append(blockGroup);\n\n while (\n blockContainer.nextElementSibling?.nodeName === \"UL\" ||\n blockContainer.nextElementSibling?.nodeName === \"OL\"\n ) {\n blockGroup.append(blockContainer.nextElementSibling);\n }\n });\n}\n\n// prevent XSS, similar to https://github.com/ProseMirror/prosemirror-view/blob/1251b2b412656a2a06263e4187574beb43651273/src/clipboard.ts#L204\n// https://github.com/TypeCellOS/BlockNote/issues/601\nlet _detachedDoc: Document | null = null;\nfunction detachedDoc() {\n return (\n _detachedDoc ||\n (_detachedDoc = document.implementation.createHTMLDocument(\"title\"))\n );\n}\n\nexport function nestedListsToBlockNoteStructure(\n elementOrHTML: HTMLElement | string,\n) {\n if (typeof elementOrHTML === \"string\") {\n const element = detachedDoc().createElement(\"div\");\n element.innerHTML = elementOrHTML;\n elementOrHTML = element;\n }\n liftNestedListsToParent(elementOrHTML);\n createGroups(elementOrHTML);\n return elementOrHTML;\n}\n","import { DOMParser, Schema } from \"prosemirror-model\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { nestedListsToBlockNoteStructure } from \"./util/nestedLists.js\";\n\nexport function HTMLToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(html: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlNode = nestedListsToBlockNoteStructure(html);\n const parser = DOMParser.fromSchema(pmSchema);\n\n // Other approach might be to use\n // const doc = pmSchema.nodes[\"doc\"].createAndFill()!;\n // and context: doc.resolve(3),\n\n const parentNode = parser.parse(htmlNode, {\n topNode: pmSchema.nodes[\"blockGroup\"].create(),\n });\n\n const blocks: Block<BSchema, I, S>[] = [];\n\n for (let i = 0; i < parentNode.childCount; i++) {\n blocks.push(nodeToBlock(parentNode.child(i), pmSchema));\n }\n\n return blocks;\n}\n","import { Schema } from \"prosemirror-model\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkParse from \"remark-parse\";\nimport remarkRehype, {\n defaultHandlers as remarkRehypeDefaultHandlers,\n} from \"remark-rehype\";\nimport rehypeStringify from \"rehype-stringify\";\nimport { unified } from \"unified\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { HTMLToBlocks } from \"../html/parseHTML.js\";\nimport { isVideoUrl } from \"../../../util/string.js\";\n\n// modified version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js\n// that outputs a data-language attribute instead of a CSS class (e.g.: language-typescript)\nfunction code(state: any, node: any) {\n const value = node.value ? node.value : \"\";\n /** @type {Properties} */\n const properties: any = {};\n\n if (node.lang) {\n // changed line\n properties[\"data-language\"] = node.lang;\n }\n\n // Create `<code>`.\n /** @type {Element} */\n let result: any = {\n type: \"element\",\n tagName: \"code\",\n properties,\n children: [{ type: \"text\", value }],\n };\n\n if (node.meta) {\n result.data = { meta: node.meta };\n }\n\n state.patch(node, result);\n result = state.applyData(node, result);\n\n // Create `<pre>`.\n result = {\n type: \"element\",\n tagName: \"pre\",\n properties: {},\n children: [result],\n };\n state.patch(node, result);\n return result;\n}\n\nfunction video(state: any, node: any) {\n const url = String(node?.url || \"\");\n const title = node?.title ? String(node.title) : undefined;\n\n let result: any = {\n type: \"element\",\n tagName: \"video\",\n properties: {\n src: url,\n \"data-name\": title,\n \"data-url\": url,\n controls: true,\n },\n children: [],\n };\n state.patch?.(node, result);\n result = state.applyData ? state.applyData(node, result) : result;\n\n return result;\n}\n\nexport function markdownToHTML(markdown: string): string {\n const htmlString = unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, {\n handlers: {\n ...(remarkRehypeDefaultHandlers as any),\n image: (state: any, node: any) => {\n const url = String(node?.url || \"\");\n\n if (isVideoUrl(url)) {\n return video(state, node);\n } else {\n return remarkRehypeDefaultHandlers.image(state, node);\n }\n },\n code,\n },\n })\n .use(rehypeStringify)\n .processSync(markdown);\n\n return htmlString.value as string;\n}\n\nexport function markdownToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(markdown: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlString = markdownToHTML(markdown);\n\n return HTMLToBlocks(htmlString, pmSchema);\n}\n","import { createExternalHTMLExporter } from \"../../api/exporters/html/externalHTMLExporter.js\";\nimport { createInternalHTMLSerializer } from \"../../api/exporters/html/internalHTMLSerializer.js\";\nimport { blocksToMarkdown } from \"../../api/exporters/markdown/markdownExporter.js\";\nimport { HTMLToBlocks } from \"../../api/parsers/html/parseHTML.js\";\nimport {\n markdownToBlocks,\n markdownToHTML,\n} from \"../../api/parsers/markdown/parseMarkdown.js\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../../blocks/defaultBlocks.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class ExportManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list\n * items are un-nested in the output HTML.\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToHTMLLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.editor.document,\n ): string {\n const exporter = createExternalHTMLExporter(\n this.editor.pmSchema,\n this.editor,\n );\n return exporter.exportBlocks(blocks, {});\n }\n\n /**\n * Serializes blocks into an HTML string in the format that would normally be rendered by the editor.\n *\n * Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)\n * and serve it to users without loading the editor on the client (i.e.: displaying the blog post)\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToFullHTML(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.editor.document,\n ): string {\n const exporter = createInternalHTMLSerializer(\n this.editor.pmSchema,\n this.editor,\n );\n return exporter.serializeBlocks(blocks, {});\n }\n\n /**\n * Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and\n * `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote\n * doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.\n * @param html The HTML string to parse blocks from.\n * @returns The blocks parsed from the HTML string.\n */\n public tryParseHTMLToBlocks(\n html: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return HTMLToBlocks(html, this.editor.pmSchema);\n }\n\n /**\n * Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of\n * BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.\n * @param blocks An array of blocks that should be serialized into Markdown.\n * @returns The blocks, serialized as a Markdown string.\n */\n public blocksToMarkdownLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.editor.document,\n ): string {\n return blocksToMarkdown(blocks, this.editor.pmSchema, this.editor, {});\n }\n\n /**\n * Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on\n * Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it\n * as text.\n * @param markdown The Markdown string to parse blocks from.\n * @returns The blocks parsed from the Markdown string.\n */\n public tryParseMarkdownToBlocks(\n markdown: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return markdownToBlocks(markdown, this.editor.pmSchema);\n }\n\n /**\n * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.\n * @param html The HTML to paste.\n * @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.\n */\n public pasteHTML(html: string, raw = false) {\n let htmlToPaste = html;\n if (!raw) {\n const blocks = this.tryParseHTMLToBlocks(html);\n htmlToPaste = this.blocksToFullHTML(blocks);\n }\n if (!htmlToPaste) {\n return;\n }\n this.editor.prosemirrorView?.pasteHTML(htmlToPaste);\n }\n\n /**\n * Paste text into the editor. Defaults to interpreting text as markdown.\n * @param text The text to paste.\n */\n public pasteText(text: string) {\n return this.editor.prosemirrorView?.pasteText(text);\n }\n\n /**\n * Paste markdown into the editor.\n * @param markdown The markdown to paste.\n */\n public pasteMarkdown(markdown: string) {\n const html = markdownToHTML(markdown);\n return this.pasteHTML(html);\n }\n}\n","export const acceptedMIMETypes = [\n \"vscode-editor-data\",\n \"blocknote/html\",\n \"text/markdown\",\n \"text/html\",\n \"text/plain\",\n \"Files\",\n] as const;\n","import { Block, PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\n\nfunction checkFileExtensionsMatch(\n fileExtension1: string,\n fileExtension2: string,\n) {\n if (!fileExtension1.startsWith(\".\") || !fileExtension2.startsWith(\".\")) {\n throw new Error(`The strings provided are not valid file extensions.`);\n }\n\n return fileExtension1 === fileExtension2;\n}\n\nfunction checkMIMETypesMatch(mimeType1: string, mimeType2: string) {\n const types1 = mimeType1.split(\"/\");\n const types2 = mimeType2.split(\"/\");\n\n if (types1.length !== 2) {\n throw new Error(`The string ${mimeType1} is not a valid MIME type.`);\n }\n if (types2.length !== 2) {\n throw new Error(`The string ${mimeType2} is not a valid MIME type.`);\n }\n\n if (types1[1] === \"*\" || types2[1] === \"*\") {\n return types1[0] === types2[0];\n }\n if (types1[0] === \"*\" || types2[0] === \"*\") {\n return types1[1] === types2[1];\n }\n\n return types1[0] === types2[0] && types1[1] === types2[1];\n}\n\nfunction insertOrUpdateBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n referenceBlock: Block<BSchema, I, S>,\n newBlock: PartialBlock<BSchema, I, S>,\n placement: \"before\" | \"after\" = \"after\",\n) {\n let insertedBlockId: string | undefined;\n\n if (\n Array.isArray(referenceBlock.content) &&\n referenceBlock.content.length === 0\n ) {\n insertedBlockId = editor.updateBlock(referenceBlock, newBlock).id;\n } else {\n insertedBlockId = editor.insertBlocks(\n [newBlock],\n referenceBlock,\n placement,\n )[0].id;\n }\n\n return insertedBlockId;\n}\n\nexport async function handleFileInsertion<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(event: DragEvent | ClipboardEvent, editor: BlockNoteEditor<BSchema, I, S>) {\n if (!editor.uploadFile) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Attempted ot insert file, but uploadFile is not set in the BlockNote editor options\",\n );\n return;\n }\n\n const dataTransfer =\n \"dataTransfer\" in event ? event.dataTransfer : event.clipboardData;\n if (dataTransfer === null) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (dataTransfer.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format !== \"Files\") {\n return;\n }\n\n const items = dataTransfer.items;\n if (!items) {\n return;\n }\n\n event.preventDefault();\n\n for (let i = 0; i < items.length; i++) {\n // Gets file block corresponding to MIME type.\n let fileBlockType = \"file\";\n for (const blockSpec of Object.values(editor.schema.blockSpecs)) {\n for (const mimeType of blockSpec.implementation.meta?.fileBlockAccept ||\n []) {\n const isFileExtension = mimeType.startsWith(\".\");\n const file = items[i].getAsFile();\n\n if (file) {\n if (\n (!isFileExtension &&\n file.type &&\n checkMIMETypesMatch(items[i].type, mimeType)) ||\n (isFileExtension &&\n checkFileExtensionsMatch(\n \".\" + file.name.split(\".\").pop(),\n mimeType,\n ))\n ) {\n fileBlockType = blockSpec.config.type;\n break;\n }\n }\n }\n }\n\n const file = items[i].getAsFile();\n if (file) {\n const fileBlock = {\n type: fileBlockType,\n props: {\n name: file.name,\n },\n } as PartialBlock<BSchema, I, S>;\n\n let insertedBlockId: string | undefined = undefined;\n\n if (event.type === \"paste\") {\n const currentBlock = editor.getTextCursorPosition().block;\n insertedBlockId = insertOrUpdateBlock(editor, currentBlock, fileBlock);\n } else if (event.type === \"drop\") {\n const coords = {\n left: (event as DragEvent).clientX,\n top: (event as DragEvent).clientY,\n };\n\n const pos = editor.prosemirrorView.posAtCoords(coords);\n\n if (!pos) {\n return;\n }\n\n insertedBlockId = editor.transact((tr) => {\n const posInfo = getNearestBlockPos(tr.doc, pos.pos);\n const blockElement = editor.prosemirrorView.dom.querySelector(\n `[data-id=\"${posInfo.node.attrs.id}\"]`,\n );\n\n const blockRect = blockElement?.getBoundingClientRect();\n\n return insertOrUpdateBlock(\n editor,\n editor.getBlock(posInfo.node.attrs.id)!,\n fileBlock,\n blockRect && (blockRect.top + blockRect.bottom) / 2 > coords.top\n ? \"before\"\n : \"after\",\n );\n });\n } else {\n return;\n }\n\n const updateData = await editor.uploadFile(file, insertedBlockId);\n\n const updatedFileBlock =\n typeof updateData === \"string\"\n ? ({\n props: {\n url: updateData,\n },\n } as PartialBlock<BSchema, I, S>)\n : { ...updateData };\n\n editor.updateBlock(insertedBlockId, updatedFileBlock);\n }\n }\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\n\nexport const createDropFileExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"dropFile\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n drop(_view, event) {\n if (!editor.isEditable) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (event.dataTransfer!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format === null) {\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n return false;\n },\n },\n },\n }),\n ];\n },\n });\n","// Headings H1-H6.\nconst h1 = /(^|\\n) {0,3}#{1,6} {1,8}[^\\n]{1,64}\\r?\\n\\r?\\n\\s{0,32}\\S/;\n\n// Bold, italic, underline, strikethrough, highlight.\nconst bold =\n /(_|__|\\*|\\*\\*|~~|==|\\+\\+)(?!\\s)(?:[^\\s](?:.{0,62}[^\\s])?|\\S)(?=\\1)/;\n\n// Basic inline link (also captures images).\nconst link = /\\[[^\\]]{1,128}\\]\\(https?:\\/\\/\\S{1,999}\\)/;\n\n// Inline code.\nconst code = /(?:\\s|^)`(?!\\s)(?:[^\\s`](?:[^`]{0,46}[^\\s`])?|[^\\s`])`([^\\w]|$)/;\n\n// Unordered list.\nconst ul = /(?:^|\\n)\\s{0,5}-\\s{1}[^\\n]+\\n\\s{0,15}-\\s/;\n\n// Ordered list.\nconst ol = /(?:^|\\n)\\s{0,5}\\d+\\.\\s{1}[^\\n]+\\n\\s{0,15}\\d+\\.\\s/;\n\n// Horizontal rule.\nconst hr = /\\n{2} {0,3}-{2,48}\\n{2}/;\n\n// Fenced code block.\nconst fences =\n /(?:\\n|^)(```|~~~|\\$\\$)(?!`|~)[^\\s]{0,64} {0,64}[^\\n]{0,64}\\n[\\s\\S]{0,9999}?\\s*\\1 {0,64}(?:\\n+|$)/;\n\n// Classical underlined H1 and H2 headings.\nconst title = /(?:\\n|^)(?!\\s)\\w[^\\n]{0,64}\\r?\\n(-|=)\\1{0,64}\\n\\n\\s{0,64}(\\w|$)/;\n\n// Blockquote.\nconst blockquote =\n /(?:^|(\\r?\\n\\r?\\n))( {0,3}>[^\\n]{1,333}\\n){1,999}($|(\\r?\\n))/;\n\n// Table Header\nconst tableHeader = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n// Table Divider\nconst tableDivider = /^\\s*\\|(\\s*[-:]+[-:]\\s*\\|)+\\s*$/m;\n\n// Table Row\nconst tableRow = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n/**\n * Returns `true` if the source text might be a markdown document.\n *\n * @param src Source text to analyze.\n */\nexport const isMarkdown = (src: string): boolean =>\n h1.test(src) ||\n bold.test(src) ||\n link.test(src) ||\n code.test(src) ||\n ul.test(src) ||\n ol.test(src) ||\n hr.test(src) ||\n fences.test(src) ||\n title.test(src) ||\n blockquote.test(src) ||\n tableHeader.test(src) ||\n tableDivider.test(src) ||\n tableRow.test(src);\n","import { EditorView } from \"prosemirror-view\";\n\nexport async function handleVSCodePaste(\n event: ClipboardEvent,\n view: EditorView,\n) {\n const { schema } = view.state;\n\n if (!event.clipboardData) {\n return false;\n }\n\n const text = event.clipboardData!.getData(\"text/plain\");\n\n if (!text) {\n return false;\n }\n\n if (!schema.nodes.codeBlock) {\n view.pasteText(text);\n return true;\n }\n\n const vscode = event.clipboardData!.getData(\"vscode-editor-data\");\n const vscodeData = vscode ? JSON.parse(vscode) : undefined;\n const language = vscodeData?.mode;\n\n if (!language) {\n return false;\n }\n\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n view.pasteHTML(\n `<pre><code class=\"language-${language}\">${text.replace(\n /\\r\\n?/g,\n \"\\n\",\n )}</code></pre>`,\n );\n\n return true;\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../../editor/BlockNoteEditor\";\nimport { isMarkdown } from \"../../parsers/markdown/detectMarkdown.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\nimport { handleVSCodePaste } from \"./handleVSCodePaste.js\";\n\nfunction defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n}: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<any, any, any>;\n prioritizeMarkdownOverHTML: boolean;\n plainTextAsMarkdown: boolean;\n}) {\n // Special case for code blocks, as they do not support any rich text\n // formatting, so we force pasting plain text.\n const isInCodeBlock = editor.transact(\n (tr) =>\n tr.selection.$from.parent.type.spec.code &&\n tr.selection.$to.parent.type.spec.code,\n );\n\n if (isInCodeBlock) {\n const data = event.clipboardData?.getData(\"text/plain\");\n\n if (data) {\n editor.pasteText(data);\n\n return true;\n }\n }\n\n let format: (typeof acceptedMIMETypes)[number] | undefined;\n for (const mimeType of acceptedMIMETypes) {\n if (event.clipboardData!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n\n if (!format) {\n return true;\n }\n\n if (format === \"vscode-editor-data\") {\n handleVSCodePaste(event, editor.prosemirrorView);\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n const data = event.clipboardData!.getData(format);\n\n if (format === \"blocknote/html\") {\n // Is blocknote/html, so no need to convert it\n editor.pasteHTML(data, true);\n return true;\n }\n\n if (format === \"text/markdown\") {\n editor.pasteMarkdown(data);\n return true;\n }\n\n if (prioritizeMarkdownOverHTML) {\n // Use plain text instead of HTML if it looks like Markdown\n const plainText = event.clipboardData!.getData(\"text/plain\");\n\n if (isMarkdown(plainText)) {\n editor.pasteMarkdown(plainText);\n return true;\n }\n }\n\n if (format === \"text/html\") {\n editor.pasteHTML(data);\n return true;\n }\n\n if (plainTextAsMarkdown) {\n editor.pasteMarkdown(data);\n return true;\n }\n\n editor.pasteText(data);\n return true;\n}\n\nexport const createPasteFromClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n pasteHandler: Exclude<\n BlockNoteEditorOptions<any, any, any>[\"pasteHandler\"],\n undefined\n >,\n) =>\n Extension.create({\n name: \"pasteFromClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n paste(_view, event) {\n event.preventDefault();\n\n if (!editor.isEditable) {\n return;\n }\n\n return pasteHandler({\n event,\n editor,\n defaultPasteHandler: ({\n prioritizeMarkdownOverHTML = true,\n plainTextAsMarkdown = true,\n } = {}) => {\n return defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n });\n },\n });\n },\n },\n },\n }),\n ];\n },\n });\n","import { Extension } from \"@tiptap/core\";\nimport { Fragment, Node } from \"prosemirror-model\";\nimport { NodeSelection, Plugin } from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\nimport type { EditorView } from \"prosemirror-view\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../../exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../nodeConversions/fragmentToBlocks.js\";\nimport {\n contentNodeToInlineContent,\n contentNodeToTableContent,\n} from \"../../nodeConversions/nodeToBlock.js\";\n\nfunction fragmentToExternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n selectedFragment: Fragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n let isWithinBlockContent = false;\n const isWithinTable = view.state.selection instanceof CellSelection;\n\n if (!isWithinTable) {\n // Checks whether block ancestry should be included when creating external\n // HTML. If the selection is within a block content node, the block ancestry\n // is excluded as we only care about the inline content.\n const fragmentWithoutParents = view.state.doc.slice(\n view.state.selection.from,\n view.state.selection.to,\n false,\n ).content;\n\n const children = [];\n for (let i = 0; i < fragmentWithoutParents.childCount; i++) {\n children.push(fragmentWithoutParents.child(i));\n }\n\n isWithinBlockContent =\n children.find(\n (child) =>\n child.type.isInGroup(\"bnBlock\") ||\n child.type.name === \"blockGroup\" ||\n child.type.spec.group === \"blockContent\",\n ) === undefined;\n if (isWithinBlockContent) {\n selectedFragment = fragmentWithoutParents;\n }\n }\n\n let externalHTML: string;\n\n const externalHTMLExporter = createExternalHTMLExporter(\n view.state.schema,\n editor,\n );\n\n if (isWithinTable) {\n if (selectedFragment.firstChild?.type.name === \"table\") {\n // contentNodeToTableContent expects the fragment of the content of a table, not the table node itself\n // but cellselection.content() returns the table node itself if all cells and columns are selected\n selectedFragment = selectedFragment.firstChild.content;\n }\n\n // first convert selection to blocknote-style table content, and then\n // pass this to the exporter\n const ic = contentNodeToTableContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Wrap in table to ensure correct parsing by spreadsheet applications\n externalHTML = `<table>${externalHTMLExporter.exportInlineContent(\n ic as any,\n {},\n )}</table>`;\n } else if (isWithinBlockContent) {\n // first convert selection to blocknote-style inline content, and then\n // pass this to the exporter\n const ic = contentNodeToInlineContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n externalHTML = externalHTMLExporter.exportInlineContent(ic, {});\n } else {\n const blocks = fragmentToBlocks<BSchema, I, S>(selectedFragment);\n externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n }\n return externalHTML;\n}\n\nexport function selectedFragmentToHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n editor: BlockNoteEditor<BSchema, I, S>,\n): {\n clipboardHTML: string;\n externalHTML: string;\n markdown: string;\n} {\n // Checks if a `blockContent` node is being copied and expands\n // the selection to the parent `blockContainer` node. This is\n // for the use-case in which only a block without content is\n // selected, e.g. an image block.\n if (\n \"node\" in view.state.selection &&\n (view.state.selection.node as Node).type.spec.group === \"blockContent\"\n ) {\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(tr.doc.resolve(view.state.selection.from - 1)),\n ),\n );\n }\n\n // Uses default ProseMirror clipboard serialization.\n const clipboardHTML: string = view.serializeForClipboard(\n view.state.selection.content(),\n ).dom.innerHTML;\n\n const selectedFragment = view.state.selection.content().content;\n\n const externalHTML = fragmentToExternalHTML<BSchema, I, S>(\n view,\n selectedFragment,\n editor,\n );\n\n const markdown = cleanHTMLToMarkdown(externalHTML);\n\n return { clipboardHTML, externalHTML, markdown };\n}\n\nconst checkIfSelectionInNonEditableBlock = () => {\n // Let browser handle event if selection is empty (nothing\n // happens).\n const selection = window.getSelection();\n if (!selection || selection.isCollapsed) {\n return true;\n }\n\n // Let browser handle event if it's within a non-editable\n // \"island\". This means it's in selectable content within a\n // non-editable block. We only need to check one node as it's\n // not possible for the browser selection to start in an\n // editable block and end in a non-editable one.\n let node = selection.focusNode;\n while (node) {\n if (\n node instanceof HTMLElement &&\n node.getAttribute(\"contenteditable\") === \"false\"\n ) {\n return true;\n }\n\n node = node.parentElement;\n }\n\n return false;\n};\n\nconst copyToClipboard = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n view: EditorView,\n event: ClipboardEvent,\n) => {\n // Stops the default browser copy behaviour.\n event.preventDefault();\n event.clipboardData!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } = selectedFragmentToHTML(\n view,\n editor,\n );\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.clipboardData!.setData(\"blocknote/html\", clipboardHTML);\n event.clipboardData!.setData(\"text/html\", externalHTML);\n event.clipboardData!.setData(\"text/plain\", markdown);\n};\n\nexport const createCopyToClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"copyToClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n copy(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n // Prevent default PM handler to be called\n return true;\n },\n cut(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n if (view.editable) {\n view.dispatch(view.state.tr.deleteSelection());\n }\n // Prevent default PM handler to be called\n return true;\n },\n // This is for the use-case in which only a block without content\n // is selected, e.g. an image block, and dragged (not using the\n // drag handle).\n dragstart(view, event) {\n // Checks if a `NodeSelection` is active.\n if (!(\"node\" in view.state.selection)) {\n return;\n }\n\n // Checks if a `blockContent` node is being dragged.\n if (\n (view.state.selection.node as Node).type.spec.group !==\n \"blockContent\"\n ) {\n return;\n }\n\n // Expands the selection to the parent `blockContainer` node.\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(\n tr.doc.resolve(view.state.selection.from - 1),\n ),\n ),\n );\n\n // Stops the default browser drag start behaviour.\n event.preventDefault();\n event.dataTransfer!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } =\n selectedFragmentToHTML(view, editor);\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.dataTransfer!.setData(\"blocknote/html\", clipboardHTML);\n event.dataTransfer!.setData(\"text/html\", externalHTML);\n event.dataTransfer!.setData(\"text/plain\", markdown);\n\n // Prevent default PM handler to be called\n return true;\n },\n },\n },\n }),\n ];\n },\n });\n","import { Extension } from \"@tiptap/core\";\nimport { getBackgroundColorAttribute } from \"../../../blocks/defaultProps.js\";\n\nexport const BackgroundColorExtension = Extension.create({\n name: \"blockBackgroundColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n backgroundColor: getBackgroundColorAttribute(),\n },\n },\n ];\n },\n});\n","// Stripped down version of the TipTap HardBreak extension:\n// https://github.com/ueberdosis/tiptap/blob/f3258d9ee5fb7979102fe63434f6ea4120507311/packages/extension-hard-break/src/hard-break.ts#L80\n// Changes:\n// - Removed options\n// - Removed keyboard shortcuts & moved them to the `KeyboardShortcutsExtension`\n// - Removed `setHardBreak` command (added a simpler version in the Shift+Enter\n// handler in `KeyboardShortcutsExtension`).\n// - Added priority\nimport { mergeAttributes, Node } from \"@tiptap/core\";\n\nexport const HardBreak = Node.create({\n name: \"hardBreak\",\n\n inline: true,\n\n group: \"inline\",\n\n selectable: false,\n\n linebreakReplacement: true,\n\n priority: 10,\n\n parseHTML() {\n return [{ tag: \"br\" }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\"br\", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];\n },\n\n renderText() {\n return \"\\n\";\n },\n});\n","import { Node } from \"prosemirror-model\";\nimport { EditorState } from \"prosemirror-state\";\n\nimport {\n BlockInfo,\n getBlockInfoFromResolvedPos,\n} from \"../../../getBlockInfoFromPos.js\";\n\n/**\n * Returns the block info from the parent block\n * or undefined if we're at the root\n */\nexport const getParentBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n if ($pos.depth <= 1) {\n return undefined;\n }\n\n // get start pos of parent\n const parentBeforePos = $pos.posAtIndex(\n $pos.index($pos.depth - 1),\n $pos.depth - 1,\n );\n\n const parentBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(parentBeforePos),\n );\n return parentBlockInfo;\n};\n\n/**\n * Returns the block info from the sibling block before (above) the given block,\n * or undefined if the given block is the first sibling.\n */\nexport const getPrevBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n const indexInParent = $pos.index();\n\n if (indexInParent === 0) {\n return undefined;\n }\n\n const prevBlockBeforePos = $pos.posAtIndex(indexInParent - 1);\n\n const prevBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(prevBlockBeforePos),\n );\n return prevBlockInfo;\n};\n\n/**\n * If a block has children like this:\n * A\n * - B\n * - C\n * -- D\n *\n * Then the bottom nested block returned is D.\n */\nexport const getBottomNestedBlockInfo = (doc: Node, blockInfo: BlockInfo) => {\n while (blockInfo.childContainer) {\n const group = blockInfo.childContainer.node;\n\n const newPos = doc\n .resolve(blockInfo.childContainer.beforePos + 1)\n .posAtIndex(group.childCount - 1);\n blockInfo = getBlockInfoFromResolvedPos(doc.resolve(newPos));\n }\n\n return blockInfo;\n};\n\nconst canMerge = (prevBlockInfo: BlockInfo, nextBlockInfo: BlockInfo) => {\n return (\n prevBlockInfo.isBlockContainer &&\n prevBlockInfo.blockContent.node.type.spec.content === \"inline*\" &&\n prevBlockInfo.blockContent.node.childCount > 0 &&\n nextBlockInfo.isBlockContainer &&\n nextBlockInfo.blockContent.node.type.spec.content === \"inline*\"\n );\n};\n\nconst mergeBlocks = (\n state: EditorState,\n dispatch: ((args?: any) => any) | undefined,\n prevBlockInfo: BlockInfo,\n nextBlockInfo: BlockInfo,\n) => {\n // Un-nests all children of the next block.\n if (!nextBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but next block is not a block container`,\n );\n }\n\n // Removes a level of nesting all children of the next block by 1 level, if it contains both content and block\n // group nodes.\n if (nextBlockInfo.childContainer) {\n const childBlocksStart = state.doc.resolve(\n nextBlockInfo.childContainer.beforePos + 1,\n );\n const childBlocksEnd = state.doc.resolve(\n nextBlockInfo.childContainer.afterPos - 1,\n );\n const childBlocksRange = childBlocksStart.blockRange(childBlocksEnd);\n\n if (dispatch) {\n const pos = state.doc.resolve(nextBlockInfo.bnBlock.beforePos);\n state.tr.lift(childBlocksRange!, pos.depth);\n }\n }\n\n // Deletes the boundary between the two blocks. Can be thought of as\n // removing the closing tags of the first block and the opening tags of the\n // second one to stitch them together.\n if (dispatch) {\n if (!prevBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but previous block is not a block container`,\n );\n }\n\n // TODO: test merging between a columnList and paragraph, between two columnLists, and v.v.\n dispatch(\n state.tr.delete(\n prevBlockInfo.blockContent.afterPos - 1,\n nextBlockInfo.blockContent.beforePos + 1,\n ),\n );\n }\n\n return true;\n};\n\nexport const mergeBlocksCommand =\n (posBetweenBlocks: number) =>\n ({\n state,\n dispatch,\n }: {\n state: EditorState;\n dispatch: ((args?: any) => any) | undefined;\n }) => {\n const $pos = state.doc.resolve(posBetweenBlocks);\n const nextBlockInfo = getBlockInfoFromResolvedPos($pos);\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n nextBlockInfo.bnBlock.beforePos,\n );\n\n if (!prevBlockInfo) {\n return false;\n }\n\n const bottomNestedBlockInfo = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!canMerge(bottomNestedBlockInfo, nextBlockInfo)) {\n return false;\n }\n\n return mergeBlocks(state, dispatch, bottomNestedBlockInfo, nextBlockInfo);\n };\n","import { Extension } from \"@tiptap/core\";\n\nimport { TextSelection } from \"prosemirror-state\";\nimport {\n getBottomNestedBlockInfo,\n getPrevBlockInfo,\n mergeBlocksCommand,\n} from \"../../../api/blockManipulation/commands/mergeBlocks/mergeBlocks.js\";\nimport { nestBlock } from \"../../../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { fixColumnList } from \"../../../api/blockManipulation/commands/replaceBlocks/util/fixColumnList.js\";\nimport { splitBlockCommand } from \"../../../api/blockManipulation/commands/splitBlock/splitBlock.js\";\nimport { updateBlockCommand } from \"../../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport { getBlockInfoFromSelection } from \"../../../api/getBlockInfoFromPos.js\";\nimport { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport { FormattingToolbarExtension } from \"../../FormattingToolbar/FormattingToolbar.js\";\nimport { FilePanelExtension } from \"../../FilePanel/FilePanel.js\";\n\nexport const KeyboardShortcutsExtension = Extension.create<{\n editor: BlockNoteEditor<any, any, any>;\n tabBehavior: \"prefer-navigate-ui\" | \"prefer-indent\";\n}>({\n priority: 50,\n\n // TODO: The shortcuts need a refactor. Do we want to use a command priority\n // design as there is now, or clump the logic into a single function?\n addKeyboardShortcuts() {\n // handleBackspace is partially adapted from https://github.com/ueberdosis/tiptap/blob/ed56337470efb4fd277128ab7ef792b37cfae992/packages/core/src/extensions/keymap.ts\n const handleBackspace = () =>\n this.editor.commands.first(({ chain, commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Undoes an input rule if one was triggered in the last editor state change.\n () => commands.undoInputRule(),\n // Reverts block content type to a paragraph if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const isParagraph =\n blockInfo.blockContent.node.type.name === \"paragraph\";\n\n if (selectionAtBlockStart && !isParagraph) {\n return commands.command(\n updateBlockCommand(blockInfo.bnBlock.beforePos, {\n type: \"paragraph\",\n props: {},\n }),\n );\n }\n\n return false;\n }),\n // Removes a level of nesting if the block is indented if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n\n if (selectionAtBlockStart) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Merges block with the previous one if it isn't indented, and the selection is at the start of the\n // block. The target block for merging must contain inline content.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const posBetweenBlocks = blockContainer.beforePos;\n\n if (selectionAtBlockStart && selectionEmpty) {\n return chain()\n .command(mergeBlocksCommand(posBetweenBlocks))\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n () =>\n commands.command(({ state, tr, dispatch }) => {\n // when at the start of a first block in a column\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n tr.selection.from === blockInfo.blockContent.beforePos + 1;\n if (!selectionAtBlockStart) {\n return false;\n }\n\n const $pos = tr.doc.resolve(blockInfo.bnBlock.beforePos);\n\n const prevBlock = $pos.nodeBefore;\n if (prevBlock) {\n // should be no previous block\n return false;\n }\n\n const parentBlock = $pos.node();\n if (parentBlock.type.name !== \"column\") {\n return false;\n }\n\n const $blockPos = tr.doc.resolve(blockInfo.bnBlock.beforePos);\n const $columnPos = tr.doc.resolve($blockPos.before());\n const columnListPos = $columnPos.before();\n\n if (dispatch) {\n const fragment = tr.doc.slice(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n ).content;\n\n tr.delete(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n );\n\n if ($columnPos.index() === 0) {\n // Fix `columnList` and insert the block before it.\n fixColumnList(tr, columnListPos);\n tr.insert(columnListPos, fragment);\n tr.setSelection(\n TextSelection.near(tr.doc.resolve(columnListPos)),\n );\n } else {\n // Insert the block at the end of the first column and fix\n // `columnList`.\n tr.insert($columnPos.pos - 1, fragment);\n tr.setSelection(\n TextSelection.near(tr.doc.resolve($columnPos.pos - 1)),\n );\n fixColumnList(tr, columnListPos);\n }\n }\n\n return true;\n }),\n // Deletes the current block if it's an empty block with inline content,\n // and moves the selection to the previous block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const blockEmpty =\n blockInfo.blockContent.node.childCount === 0 &&\n blockInfo.blockContent.node.type.spec.content === \"inline*\";\n\n if (blockEmpty) {\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n if (!prevBlockInfo || !prevBlockInfo.isBlockContainer) {\n return false;\n }\n\n let chainedCommands = chain();\n\n if (\n prevBlockInfo.blockContent.node.type.spec.content ===\n \"tableRow+\"\n ) {\n const tableBlockEndPos = blockInfo.bnBlock.beforePos - 1;\n const tableBlockContentEndPos = tableBlockEndPos - 1;\n const lastRowEndPos = tableBlockContentEndPos - 1;\n const lastCellEndPos = lastRowEndPos - 1;\n const lastCellParagraphEndPos = lastCellEndPos - 1;\n\n chainedCommands = chainedCommands.setTextSelection(\n lastCellParagraphEndPos,\n );\n } else if (\n prevBlockInfo.blockContent.node.type.spec.content === \"\"\n ) {\n const nonEditableBlockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands = chainedCommands.setNodeSelection(\n nonEditableBlockContentStartPos,\n );\n } else {\n const blockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands =\n chainedCommands.setTextSelection(blockContentStartPos);\n }\n\n return chainedCommands\n .deleteRange({\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n })\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n // Deletes previous block if it contains no content and isn't a table,\n // when the selection is empty and at the start of the block. Moves the\n // current block into the deleted block's place.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n if (!blockInfo.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (prevBlockInfo && selectionAtBlockStart && selectionEmpty) {\n const bottomBlock = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!bottomBlock.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const prevBlockNotTableAndNoContent =\n bottomBlock.blockContent.node.type.spec.content === \"\" ||\n (bottomBlock.blockContent.node.type.spec.content ===\n \"inline*\" &&\n bottomBlock.blockContent.node.childCount === 0);\n\n if (prevBlockNotTableAndNoContent) {\n return chain()\n .cut(\n {\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n },\n bottomBlock.bnBlock.afterPos,\n )\n .deleteRange({\n from: bottomBlock.bnBlock.beforePos,\n to: bottomBlock.bnBlock.afterPos,\n })\n .run();\n }\n }\n\n return false;\n }),\n ]);\n\n const handleDelete = () =>\n this.editor.commands.first(({ commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Merges block with the next one (at the same nesting level or lower),\n // if one exists, the block has no children, and the selection is at the\n // end of the block.\n () =>\n commands.command(({ state }) => {\n // TODO: Change this to not rely on offsets & schema assumptions\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const {\n bnBlock: blockContainer,\n blockContent,\n childContainer,\n } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n const blockAtDocEnd =\n blockContainer.afterPos === state.doc.nodeSize - 3;\n const selectionAtBlockEnd =\n state.selection.from === blockContent.afterPos - 1;\n const selectionEmpty = state.selection.empty;\n const hasChildBlocks = childContainer !== undefined;\n\n if (\n !blockAtDocEnd &&\n selectionAtBlockEnd &&\n selectionEmpty &&\n !hasChildBlocks\n ) {\n let oldDepth = depth;\n let newPos = blockContainer.afterPos + 1;\n let newDepth = state.doc.resolve(newPos).depth;\n\n while (newDepth < oldDepth) {\n oldDepth = newDepth;\n newPos += 2;\n newDepth = state.doc.resolve(newPos).depth;\n }\n\n return commands.command(mergeBlocksCommand(newPos - 1));\n }\n\n return false;\n }),\n ]);\n\n const handleEnter = (withShift = false) => {\n return this.editor.commands.first(({ commands, tr }) => [\n // Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start\n // of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n const blockIndented = depth > 1;\n\n if (\n selectionAtBlockStart &&\n selectionEmpty &&\n blockEmpty &&\n blockIndented\n ) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Creates a hard break if block is configured to do so.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n const blockHardBreakShortcut =\n this.options.editor.schema.blockSchema[\n blockInfo.blockNoteType as keyof typeof this.options.editor.schema.blockSchema\n ].meta?.hardBreakShortcut ?? \"shift+enter\";\n\n if (blockHardBreakShortcut === \"none\") {\n return false;\n }\n\n if (\n // If shortcut is not configured, or is configured as \"shift+enter\",\n // create a hard break for shift+enter, but not for enter.\n (blockHardBreakShortcut === \"shift+enter\" && withShift) ||\n // If shortcut is configured as \"enter\", create a hard break for\n // both enter and shift+enter.\n blockHardBreakShortcut === \"enter\"\n ) {\n const marks =\n tr.storedMarks ||\n tr.selection.$head\n .marks()\n .filter((m) =>\n this.editor.extensionManager.splittableMarks.includes(\n m.type.name,\n ),\n );\n\n tr.insert(\n tr.selection.head,\n tr.doc.type.schema.nodes.hardBreak.create(),\n ).ensureMarks(marks);\n return true;\n }\n\n return false;\n }),\n // Creates a new block and moves the selection to it if the current one is empty, while the selection is also\n // empty & at the start of the block.\n () =>\n commands.command(({ state, dispatch }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (selectionAtBlockStart && selectionEmpty && blockEmpty) {\n const newBlockInsertionPos = blockContainer.afterPos;\n const newBlockContentPos = newBlockInsertionPos + 2;\n\n if (dispatch) {\n const newBlock =\n state.schema.nodes[\"blockContainer\"].createAndFill()!;\n\n state.tr\n .insert(newBlockInsertionPos, newBlock)\n .scrollIntoView();\n state.tr.setSelection(\n new TextSelection(state.doc.resolve(newBlockContentPos)),\n );\n }\n\n return true;\n }\n\n return false;\n }),\n // Splits the current block, moving content inside that's after the cursor to a new text block below. Also\n // deletes the selection beforehand, if it's not empty.\n () =>\n commands.command(({ state, chain }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (!blockEmpty) {\n chain()\n .deleteSelection()\n .command(\n splitBlockCommand(\n state.selection.from,\n selectionAtBlockStart,\n selectionAtBlockStart,\n ),\n )\n .run();\n\n return true;\n }\n\n return false;\n }),\n ]);\n };\n\n return {\n Backspace: handleBackspace,\n Delete: handleDelete,\n Enter: () => handleEnter(),\n \"Shift-Enter\": () => handleEnter(true),\n // Always returning true for tab key presses ensures they're not captured by the browser. Otherwise, they blur the\n // editor since the browser will try to use tab for keyboard navigation.\n Tab: () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.getExtension(FormattingToolbarExtension)?.store\n .state ||\n this.options.editor.getExtension(FilePanelExtension)?.store\n .state !== undefined)\n // TODO need to check if the link toolbar is open or another alternative entirely\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n return nestBlock(this.options.editor);\n },\n \"Shift-Tab\": () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.getExtension(FormattingToolbarExtension)?.store\n .state ||\n this.options.editor.getExtension(FilePanelExtension)?.store\n .state !== undefined)\n // TODO need to check if the link toolbar is open or another alternative entirely\n // other menu types?\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n return this.editor.commands.liftListItem(\"blockContainer\");\n },\n \"Shift-Mod-ArrowUp\": () => {\n this.options.editor.moveBlocksUp();\n return true;\n },\n \"Shift-Mod-ArrowDown\": () => {\n this.options.editor.moveBlocksDown();\n return true;\n },\n \"Mod-z\": () => this.options.editor.undo(),\n \"Mod-y\": () => this.options.editor.redo(),\n \"Shift-Mod-z\": () => this.options.editor.redo(),\n };\n },\n});\n","import { Mark } from \"@tiptap/core\";\nimport { MarkSpec } from \"prosemirror-model\";\n\n// This copies the marks from @handlewithcare/prosemirror-suggest-changes,\n// but uses the Tiptap Mark API instead so we can use them in BlockNote\n\n// The ideal solution would be to not depend on tiptap nodes / marks, but be able to use prosemirror nodes / marks directly\n// this way we could directly use the exported marks from @handlewithcare/prosemirror-suggest-changes\nexport const SuggestionAddMark = Mark.create({\n name: \"insertion\",\n inclusive: false,\n excludes: \"deletion modification insertion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap, so this doesn't actually work (considered not critical)\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"insertion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n toDOM(mark, inline) {\n return [\n \"ins\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"ins\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionDeleteMark = Mark.create({\n name: \"deletion\",\n inclusive: false,\n excludes: \"insertion modification deletion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"deletion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n // attrs: {\n // id: { validate: \"number\" },\n // },\n toDOM(mark, inline) {\n return [\n \"del\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"del\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionModificationMark = Mark.create({\n name: \"modification\",\n inclusive: false,\n excludes: \"deletion insertion\",\n addAttributes() {\n // note: validate is supported in prosemirror but not in tiptap\n return {\n id: { default: null, validate: \"number\" },\n type: { validate: \"string\" },\n attrName: { default: null, validate: \"string|null\" },\n previousValue: { default: null },\n newValue: { default: null },\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"modification\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n // attrs: {\n // id: { validate: \"number\" },\n // type: { validate: \"string\" },\n // attrName: { default: null, validate: \"string|null\" },\n // previousValue: { default: null },\n // newValue: { default: null },\n // },\n toDOM(mark, inline) {\n return [\n inline ? \"span\" : \"div\",\n {\n \"data-type\": \"modification\",\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-mod-type\": mark.attrs[\"type\"] as string,\n \"data-mod-prev-val\": JSON.stringify(mark.attrs[\"previousValue\"]),\n // TODO: Try to serialize marks with toJSON?\n \"data-mod-new-val\": JSON.stringify(mark.attrs[\"newValue\"]),\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"span[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n newValue: node.dataset[\"modNewVal\"],\n };\n },\n },\n {\n tag: \"div[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport const TextAlignmentExtension = Extension.create({\n name: \"textAlignment\",\n\n addGlobalAttributes() {\n return [\n {\n // Generally text alignment is handled through props using the custom\n // blocks API. Tables are the only blocks that are created as TipTap\n // nodes and ported to blocks, so we need to add text alignment in a\n // separate extension.\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n textAlignment: {\n default: \"left\",\n parseHTML: (element) => {\n return element.getAttribute(\"data-text-alignment\");\n },\n renderHTML: (attributes) => {\n if (attributes.textAlignment === \"left\") {\n return {};\n }\n return {\n \"data-text-alignment\": attributes.textAlignment,\n };\n },\n },\n },\n },\n ];\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { getTextColorAttribute } from \"../../../blocks/defaultProps.js\";\n\nexport const TextColorExtension = Extension.create({\n name: \"blockTextColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"table\", \"tableCell\", \"tableHeader\"],\n attributes: {\n textColor: getTextColorAttribute(),\n },\n },\n ];\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nimport type { BlockNoteEditor } from \"../editor/BlockNoteEditor.js\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\n// Object containing all possible block attributes.\nconst BlockAttributes: Record<string, string> = {\n blockColor: \"data-block-color\",\n blockStyle: \"data-block-style\",\n id: \"data-id\",\n depth: \"data-depth\",\n depthChange: \"data-depth-change\",\n};\n\n/**\n * The main \"Block node\" documents consist of\n */\nexport const BlockContainer = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n editor: BlockNoteEditor<any, any, any>;\n}>({\n name: \"blockContainer\",\n group: \"blockGroupChild bnBlock\",\n // A block always contains content, and optionally a blockGroup which contains nested blocks\n content: \"blockContent blockGroup?\",\n // Ensures content-specific keyboard handlers trigger first.\n priority: 50,\n defining: true,\n marks: \"insertion modification deletion\",\n parseHTML() {\n return [\n {\n tag: \"div[data-node-type=\" + this.name + \"]\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n const attrs: Record<string, string> = {};\n for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {\n if (element.getAttribute(HTMLAttr)) {\n attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;\n }\n }\n\n return attrs;\n },\n },\n // Ignore `blockOuter` divs, but parse the `blockContainer` divs inside them.\n {\n tag: `div[data-node-type=\"blockOuter\"]`,\n skip: true,\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockOuter = document.createElement(\"div\");\n blockOuter.className = \"bn-block-outer\";\n blockOuter.setAttribute(\"data-node-type\", \"blockOuter\");\n for (const [attribute, value] of Object.entries(HTMLAttributes)) {\n if (attribute !== \"class\") {\n blockOuter.setAttribute(attribute, value);\n }\n }\n\n const blockHTMLAttributes = {\n ...(this.options.domAttributes?.block || {}),\n ...HTMLAttributes,\n };\n const block = document.createElement(\"div\");\n block.className = mergeCSSClasses(\"bn-block\", blockHTMLAttributes.class);\n block.setAttribute(\"data-node-type\", this.name);\n for (const [attribute, value] of Object.entries(blockHTMLAttributes)) {\n if (attribute !== \"class\") {\n block.setAttribute(attribute, value);\n }\n }\n\n blockOuter.appendChild(block);\n\n return {\n dom: blockOuter,\n contentDOM: block,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\nexport const BlockGroup = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n}>({\n name: \"blockGroup\",\n group: \"childContainer\",\n content: \"blockGroupChild+\",\n marks: \"deletion insertion modification\",\n parseHTML() {\n return [\n {\n tag: \"div\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n if (element.getAttribute(\"data-node-type\") === \"blockGroup\") {\n // Null means the element matches, but we don't want to add any attributes to the node.\n return null;\n }\n\n return false;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockGroupHTMLAttributes = {\n ...(this.options.domAttributes?.blockGroup || {}),\n ...HTMLAttributes,\n };\n const blockGroup = document.createElement(\"div\");\n blockGroup.className = mergeCSSClasses(\n \"bn-block-group\",\n blockGroupHTMLAttributes.class,\n );\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n for (const [attribute, value] of Object.entries(blockGroupHTMLAttributes)) {\n if (attribute !== \"class\") {\n blockGroup.setAttribute(attribute, value);\n }\n }\n\n return {\n dom: blockGroup,\n contentDOM: blockGroup,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nexport const Doc = Node.create({\n name: \"doc\",\n topNode: true,\n content: \"blockGroup\",\n marks: \"insertion modification deletion\",\n});\n","import {\n AnyExtension as AnyTiptapExtension,\n extensions,\n Node,\n Extension as TiptapExtension,\n} from \"@tiptap/core\";\nimport { Gapcursor } from \"@tiptap/extension-gapcursor\";\nimport { Link } from \"@tiptap/extension-link\";\nimport { Text } from \"@tiptap/extension-text\";\nimport { createDropFileExtension } from \"../../../api/clipboard/fromClipboard/fileDropExtension.js\";\nimport { createPasteFromClipboardExtension } from \"../../../api/clipboard/fromClipboard/pasteExtension.js\";\nimport { createCopyToClipboardExtension } from \"../../../api/clipboard/toClipboard/copyExtension.js\";\nimport {\n BlockChangeExtension,\n DropCursorExtension,\n FilePanelExtension,\n ForkYDocExtension,\n FormattingToolbarExtension,\n HistoryExtension,\n LinkToolbarExtension,\n NodeSelectionKeyboardExtension,\n PlaceholderExtension,\n PreviousBlockTypeExtension,\n SchemaMigration,\n ShowSelectionExtension,\n SideMenuExtension,\n SuggestionMenu,\n TableHandlesExtension,\n TrailingNodeExtension,\n YCursorExtension,\n YSyncExtension,\n YUndoExtension,\n} from \"../../../extensions/index.js\";\nimport {\n DEFAULT_LINK_PROTOCOL,\n VALID_LINK_PROTOCOLS,\n} from \"../../../extensions/LinkToolbar/protocols.js\";\nimport {\n BackgroundColorExtension,\n HardBreak,\n KeyboardShortcutsExtension,\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n TextAlignmentExtension,\n TextColorExtension,\n UniqueID,\n} from \"../../../extensions/tiptap-extensions/index.js\";\nimport { BlockContainer, BlockGroup, Doc } from \"../../../pm-nodes/index.js\";\nimport {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../BlockNoteEditor.js\";\nimport { ExtensionFactoryInstance } from \"../../BlockNoteExtension.js\";\n\n// TODO remove linkify completely by vendoring the link extension & dropping linkifyjs as a dependency\nlet LINKIFY_INITIALIZED = false;\n\n/**\n * Get all the Tiptap extensions BlockNote is configured with by default\n */\nexport function getDefaultTiptapExtensions(\n editor: BlockNoteEditor<any, any, any>,\n options: BlockNoteEditorOptions<any, any, any>,\n) {\n const tiptapExtensions: AnyTiptapExtension[] = [\n extensions.ClipboardTextSerializer,\n extensions.Commands,\n extensions.Editable,\n extensions.FocusEvents,\n extensions.Tabindex,\n Gapcursor,\n\n UniqueID.configure({\n // everything from bnBlock group (nodes that represent a BlockNote block should have an id)\n types: [\"blockContainer\", \"columnList\", \"column\"],\n setIdAttribute: options.setIdAttribute,\n }),\n HardBreak,\n Text,\n\n // marks:\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n Link.extend({\n inclusive: false,\n }).configure({\n defaultProtocol: DEFAULT_LINK_PROTOCOL,\n // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450\n protocols: LINKIFY_INITIALIZED ? [] : VALID_LINK_PROTOCOLS,\n }),\n ...(Object.values(editor.schema.styleSpecs).map((styleSpec) => {\n return styleSpec.implementation.mark.configure({\n editor: editor,\n });\n }) as any[]),\n\n TextColorExtension,\n\n BackgroundColorExtension,\n TextAlignmentExtension,\n\n // make sure escape blurs editor, so that we can tab to other elements in the host page (accessibility)\n TiptapExtension.create({\n name: \"OverrideEscape\",\n addKeyboardShortcuts: () => {\n return {\n Escape: () => {\n if (editor.getExtension(SuggestionMenu)?.shown()) {\n // escape should close the suggestion menu, but not blur the editor\n return false;\n }\n editor.blur();\n return true;\n },\n };\n },\n }),\n\n // nodes\n Doc,\n BlockContainer.configure({\n editor: editor,\n domAttributes: options.domAttributes,\n }),\n KeyboardShortcutsExtension.configure({\n editor: editor,\n tabBehavior: options.tabBehavior,\n }),\n BlockGroup.configure({\n domAttributes: options.domAttributes,\n }),\n ...Object.values(editor.schema.inlineContentSpecs)\n .filter((a) => a.config !== \"link\" && a.config !== \"text\")\n .map((inlineContentSpec) => {\n return inlineContentSpec.implementation!.node.configure({\n editor: editor,\n });\n }),\n\n ...Object.values(editor.schema.blockSpecs).flatMap((blockSpec) => {\n return [\n // the node extension implementations\n ...(\"node\" in blockSpec.implementation\n ? [\n (blockSpec.implementation.node as Node).configure({\n editor: editor,\n domAttributes: options.domAttributes,\n }),\n ]\n : []),\n ];\n }),\n createCopyToClipboardExtension(editor),\n createPasteFromClipboardExtension(\n editor,\n options.pasteHandler ||\n ((context: {\n defaultPasteHandler: (context?: {\n prioritizeMarkdownOverHTML?: boolean;\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => context.defaultPasteHandler()),\n ),\n createDropFileExtension(editor),\n ];\n\n LINKIFY_INITIALIZED = true;\n\n return tiptapExtensions;\n}\n\nexport function getDefaultExtensions(\n editor: BlockNoteEditor<any, any, any>,\n options: BlockNoteEditorOptions<any, any, any>,\n) {\n const extensions = [\n BlockChangeExtension(),\n DropCursorExtension(options),\n FilePanelExtension(options),\n FormattingToolbarExtension(options),\n LinkToolbarExtension(options),\n NodeSelectionKeyboardExtension(),\n PlaceholderExtension(options),\n ShowSelectionExtension(options),\n SideMenuExtension(options),\n SuggestionMenu(options),\n ...(options.trailingBlock !== false ? [TrailingNodeExtension()] : []),\n ] as ExtensionFactoryInstance[];\n\n if (options.collaboration) {\n extensions.push(ForkYDocExtension(options.collaboration));\n if (options.collaboration.provider?.awareness) {\n extensions.push(YCursorExtension(options.collaboration));\n }\n extensions.push(YSyncExtension(options.collaboration));\n extensions.push(YUndoExtension(options.collaboration));\n extensions.push(SchemaMigration(options.collaboration));\n } else {\n // YUndo is not compatible with ProseMirror's history plugin\n extensions.push(HistoryExtension());\n }\n\n if (\"table\" in editor.schema.blockSpecs) {\n extensions.push(TableHandlesExtension(options));\n }\n\n if (options.animations !== false) {\n extensions.push(PreviousBlockTypeExtension());\n }\n\n return extensions;\n}\n","import {\n InputRule,\n inputRules as inputRulesPlugin,\n} from \"@handlewithcare/prosemirror-inputrules\";\nimport {\n AnyExtension as AnyTiptapExtension,\n Extension as TiptapExtension,\n} from \"@tiptap/core\";\nimport { keymap } from \"@tiptap/pm/keymap\";\nimport { Plugin } from \"prosemirror-state\";\nimport { updateBlockTr } from \"../../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport { getBlockInfoFromTransaction } from \"../../../api/getBlockInfoFromPos.js\";\nimport { sortByDependencies } from \"../../../util/topo-sort.js\";\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../BlockNoteEditor.js\";\nimport type {\n Extension,\n ExtensionFactoryInstance,\n ExtensionFactory,\n} from \"../../BlockNoteExtension.js\";\nimport { originalFactorySymbol } from \"./symbol.js\";\nimport {\n getDefaultExtensions,\n getDefaultTiptapExtensions,\n} from \"./extensions.js\";\n\nexport class ExtensionManager {\n /**\n * A set of extension keys which are disabled by the options\n */\n private disabledExtensions = new Set<string>();\n /**\n * A list of all the extensions that are registered to the editor\n */\n private extensions: Extension[] = [];\n /**\n * A map of all the abort controllers for each extension that has an init method defined\n */\n private abortMap = new Map<Extension, AbortController>();\n /**\n * A map of all the extension factories that are registered to the editor\n */\n private extensionFactories = new Map<ExtensionFactory, Extension>();\n /**\n * Because a single blocknote extension can both have it's own prosemirror plugins & additional generated ones (e.g. keymap & input rules plugins)\n * We need to keep track of all the plugins for each extension, so that we can remove them when the extension is unregistered\n */\n private extensionPlugins: Map<Extension, Plugin[]> = new Map();\n\n constructor(\n private editor: BlockNoteEditor<any, any, any>,\n private options: BlockNoteEditorOptions<any, any, any>,\n ) {\n /**\n * When the editor is first mounted, we need to initialize all the extensions\n */\n editor.onMount(() => {\n for (const extension of this.extensions) {\n // If the extension has an init function, we can initialize it, otherwise, it is already added to the editor\n if (extension.mount) {\n // We create an abort controller for each extension, so that we can abort the extension when the editor is unmounted\n const abortController = new window.AbortController();\n const unmountCallback = extension.mount({\n dom: editor.prosemirrorView.dom,\n root: editor.prosemirrorView.root,\n signal: abortController.signal,\n });\n // If the extension returns a method to unmount it, we can register it to be called when the abort controller is aborted\n if (unmountCallback) {\n abortController.signal.addEventListener(\"abort\", () => {\n unmountCallback();\n });\n }\n // Keep track of the abort controller for each extension, so that we can abort it when the editor is unmounted\n this.abortMap.set(extension, abortController);\n }\n }\n });\n\n /**\n * When the editor is unmounted, we need to abort all the extensions' abort controllers\n */\n editor.onUnmount(() => {\n for (const [extension, abortController] of this.abortMap.entries()) {\n // No longer track the abort controller for this extension\n this.abortMap.delete(extension);\n // Abort each extension's abort controller\n abortController.abort();\n }\n });\n\n // TODO do disabled extensions need to be only for editor base extensions? Or all of them?\n this.disabledExtensions = new Set(options.disableExtensions || []);\n\n // Add the default extensions\n for (const extension of getDefaultExtensions(this.editor, this.options)) {\n this.addExtension(extension);\n }\n\n // Add the extensions from the options\n for (const extension of this.options.extensions ?? []) {\n this.addExtension(extension);\n }\n\n // Add the extensions from blocks specs\n for (const block of Object.values(this.editor.schema.blockSpecs)) {\n for (const extension of block.extensions ?? []) {\n this.addExtension(extension);\n }\n }\n }\n\n /**\n * Register one or more extensions to the editor after the editor is initialized.\n *\n * This allows users to switch on & off extensions \"at runtime\".\n */\n public registerExtension(\n extension:\n | Extension\n | ExtensionFactoryInstance\n | (Extension | ExtensionFactoryInstance)[],\n ): void {\n const extensions = ([] as (Extension | ExtensionFactoryInstance)[])\n .concat(extension)\n .filter(Boolean) as (Extension | ExtensionFactoryInstance)[];\n\n if (!extensions.length) {\n // eslint-disable-next-line no-console\n console.warn(`No extensions found to register`, extension);\n return;\n }\n\n const registeredExtensions = extensions\n .map((extension) => this.addExtension(extension))\n .filter(Boolean) as Extension[];\n\n const pluginsToAdd = new Set<Plugin>();\n for (const extension of registeredExtensions) {\n if (extension?.tiptapExtensions) {\n // This is necessary because this can only switch out prosemirror plugins at runtime,\n // it can't switch out Tiptap extensions since that can have more widespread effects (since a Tiptap extension can even add/remove to the schema).\n\n // eslint-disable-next-line no-console\n console.warn(\n `Extension ${extension.key} has tiptap extensions, but these cannot be changed after initializing the editor. Please separate the extension into multiple extensions if you want to add them, or re-initialize the editor.`,\n extension,\n );\n }\n\n if (extension?.inputRules?.length) {\n // This is necessary because input rules are defined in a single prosemirror plugin which cannot be re-initialized.\n // eslint-disable-next-line no-console\n console.warn(\n `Extension ${extension.key} has input rules, but these cannot be changed after initializing the editor. Please separate the extension into multiple extensions if you want to add them, or re-initialize the editor.`,\n extension,\n );\n }\n\n this.getProsemirrorPluginsFromExtension(extension).plugins.forEach(\n (plugin) => {\n pluginsToAdd.add(plugin);\n },\n );\n }\n\n // TODO there isn't a great way to do sorting right now. This is something that should be improved in the future.\n // So, we just append to the end of the list for now.\n this.updatePlugins((plugins) => [...plugins, ...pluginsToAdd]);\n }\n\n /**\n * Register an extension to the editor\n * @param extension - The extension to register\n * @returns The extension instance\n */\n private addExtension(\n extension: Extension | ExtensionFactoryInstance,\n ): Extension | undefined {\n let instance: Extension;\n if (typeof extension === \"function\") {\n instance = extension({ editor: this.editor });\n } else {\n instance = extension;\n }\n\n if (!instance || this.disabledExtensions.has(instance.key)) {\n return undefined as any;\n }\n\n // Now that we know that the extension is not disabled, we can add it to the extension factories\n if (typeof extension === \"function\") {\n const originalFactory = (instance as any)[originalFactorySymbol] as (\n ...args: any[]\n ) => ExtensionFactoryInstance;\n\n if (typeof originalFactory === \"function\") {\n this.extensionFactories.set(originalFactory, instance);\n }\n }\n\n this.extensions.push(instance);\n\n return instance as any;\n }\n\n /**\n * Resolve an extension or a list of extensions into a list of extension instances\n * @param toResolve - The extension or list of extensions to resolve\n * @returns A list of extension instances\n */\n private resolveExtensions(\n toResolve:\n | undefined\n | string\n | Extension\n | ExtensionFactory\n | (Extension | ExtensionFactory | string | undefined)[],\n ): Extension[] {\n const extensions = [] as Extension[];\n if (typeof toResolve === \"function\") {\n const instance = this.extensionFactories.get(toResolve);\n if (instance) {\n extensions.push(instance);\n }\n } else if (Array.isArray(toResolve)) {\n for (const extension of toResolve) {\n extensions.push(...this.resolveExtensions(extension));\n }\n } else if (typeof toResolve === \"object\" && \"key\" in toResolve) {\n extensions.push(toResolve);\n } else if (typeof toResolve === \"string\") {\n const instance = this.extensions.find((e) => e.key === toResolve);\n if (instance) {\n extensions.push(instance);\n }\n }\n return extensions;\n }\n\n /**\n * Unregister an extension from the editor\n * @param toUnregister - The extension to unregister\n * @returns void\n */\n public unregisterExtension(\n toUnregister:\n | undefined\n | string\n | Extension\n | ExtensionFactory\n | (Extension | ExtensionFactory | string | undefined)[],\n ): void {\n const extensions = this.resolveExtensions(toUnregister);\n\n if (!extensions.length) {\n // eslint-disable-next-line no-console\n console.warn(`No extensions found to unregister`, toUnregister);\n return;\n }\n let didWarn = false;\n\n const pluginsToRemove = new Set<Plugin>();\n for (const extension of extensions) {\n this.extensions = this.extensions.filter((e) => e !== extension);\n this.extensionFactories.forEach((instance, factory) => {\n if (instance === extension) {\n this.extensionFactories.delete(factory);\n }\n });\n this.abortMap.get(extension)?.abort();\n this.abortMap.delete(extension);\n\n const plugins = this.extensionPlugins.get(extension);\n plugins?.forEach((plugin) => {\n pluginsToRemove.add(plugin);\n });\n this.extensionPlugins.delete(extension);\n\n if (extension.tiptapExtensions && !didWarn) {\n didWarn = true;\n // eslint-disable-next-line no-console\n console.warn(\n `Extension ${extension.key} has tiptap extensions, but they will not be removed. Please separate the extension into multiple extensions if you want to remove them, or re-initialize the editor.`,\n toUnregister,\n );\n }\n }\n\n this.updatePlugins((plugins) =>\n plugins.filter((plugin) => !pluginsToRemove.has(plugin)),\n );\n }\n\n /**\n * Allows resetting the current prosemirror state's plugins\n * @param update - A function that takes the current plugins and returns the new plugins\n * @returns void\n */\n private updatePlugins(update: (plugins: Plugin[]) => Plugin[]): void {\n const currentState = this.editor.prosemirrorState;\n\n const state = currentState.reconfigure({\n plugins: update(currentState.plugins.slice()),\n });\n\n this.editor.prosemirrorView.updateState(state);\n }\n\n /**\n * Get all the extensions that are registered to the editor\n */\n public getTiptapExtensions(): AnyTiptapExtension[] {\n // Start with the default tiptap extensions\n const tiptapExtensions = getDefaultTiptapExtensions(\n this.editor,\n this.options,\n );\n // TODO filter out the default extensions via the disabledExtensions set?\n\n const getPriority = sortByDependencies(this.extensions);\n\n const inputRulesByPriority = new Map<number, InputRule[]>();\n for (const extension of this.extensions) {\n if (extension.tiptapExtensions) {\n tiptapExtensions.push(...extension.tiptapExtensions);\n }\n\n const priority = getPriority(extension.key);\n\n const { plugins: prosemirrorPlugins, inputRules } =\n this.getProsemirrorPluginsFromExtension(extension);\n // Sometimes a blocknote extension might need to make additional prosemirror plugins, so we generate them here\n if (prosemirrorPlugins.length) {\n tiptapExtensions.push(\n TiptapExtension.create({\n name: extension.key,\n priority,\n addProseMirrorPlugins: () => prosemirrorPlugins,\n }),\n );\n }\n if (inputRules.length) {\n if (!inputRulesByPriority.has(priority)) {\n inputRulesByPriority.set(priority, []);\n }\n inputRulesByPriority.get(priority)!.push(...inputRules);\n }\n }\n\n // Collect all input rules into 1 extension to reduce conflicts\n tiptapExtensions.push(\n TiptapExtension.create({\n name: \"blocknote-input-rules\",\n addProseMirrorPlugins() {\n const rules = [] as InputRule[];\n Array.from(inputRulesByPriority.keys())\n // We sort the rules by their priority (the key)\n .sort()\n .reverse()\n .forEach((priority) => {\n // Append in reverse priority order\n rules.push(...inputRulesByPriority.get(priority)!);\n });\n return [inputRulesPlugin({ rules })];\n },\n }),\n );\n\n // Add any tiptap extensions from the `_tiptapOptions`\n for (const extension of this.options._tiptapOptions?.extensions ?? []) {\n tiptapExtensions.push(extension);\n }\n\n return tiptapExtensions;\n }\n\n /**\n * This maps a blocknote extension into an array of Prosemirror plugins if it has any of the following:\n * - plugins\n * - keyboard shortcuts\n * - input rules\n */\n private getProsemirrorPluginsFromExtension(extension: Extension): {\n plugins: Plugin[];\n inputRules: InputRule[];\n } {\n const plugins: Plugin[] = [...(extension.prosemirrorPlugins ?? [])];\n const inputRules: InputRule[] = [];\n if (\n !extension.prosemirrorPlugins?.length &&\n !Object.keys(extension.keyboardShortcuts || {}).length &&\n !extension.inputRules?.length\n ) {\n // We can bail out early if the extension has no features to add to the tiptap editor\n return { plugins, inputRules };\n }\n\n this.extensionPlugins.set(extension, plugins);\n\n if (extension.inputRules?.length) {\n inputRules.push(\n ...extension.inputRules.map((inputRule) => {\n return new InputRule(inputRule.find, (state, match, start, end) => {\n const replaceWith = inputRule.replace({\n match,\n range: { from: start, to: end },\n editor: this.editor,\n });\n if (replaceWith) {\n const cursorPosition = this.editor.getTextCursorPosition();\n\n if (\n this.editor.schema.blockSchema[cursorPosition.block.type]\n .content !== \"inline\"\n ) {\n return null;\n }\n\n const blockInfo = getBlockInfoFromTransaction(state.tr);\n const tr = state.tr.deleteRange(start, end);\n\n updateBlockTr(tr, blockInfo.bnBlock.beforePos, replaceWith);\n return tr;\n }\n return null;\n });\n }),\n );\n }\n\n if (Object.keys(extension.keyboardShortcuts || {}).length) {\n plugins.push(\n keymap(\n Object.fromEntries(\n Object.entries(extension.keyboardShortcuts!).map(([key, value]) => [\n key,\n () => value({ editor: this.editor }),\n ]),\n ),\n ),\n );\n }\n\n return { plugins, inputRules };\n }\n\n /**\n * Get all extensions\n */\n public getExtensions(): Map<string, Extension> {\n return new Map(\n this.extensions.map((extension) => [extension.key, extension]),\n );\n }\n\n /**\n * Get a specific extension by it's instance\n */\n public getExtension<\n const Ext extends Extension | ExtensionFactory = Extension,\n >(\n extension: string,\n ):\n | (Ext extends Extension\n ? Ext\n : Ext extends ExtensionFactory\n ? ReturnType<ReturnType<Ext>>\n : never)\n | undefined;\n public getExtension<const T extends ExtensionFactory>(\n extension: T,\n ): ReturnType<ReturnType<T>> | undefined;\n public getExtension<const T extends ExtensionFactory | string = string>(\n extension: T,\n ):\n | (T extends ExtensionFactory\n ? ReturnType<ReturnType<T>>\n : T extends string\n ? Extension\n : never)\n | undefined {\n if (typeof extension === \"string\") {\n const instance = this.extensions.find((e) => e.key === extension);\n if (!instance) {\n return undefined;\n }\n return instance as any;\n } else if (typeof extension === \"function\") {\n const instance = this.extensionFactories.get(extension);\n if (!instance) {\n return undefined;\n }\n return instance as any;\n }\n throw new Error(`Invalid extension type: ${typeof extension}`);\n }\n\n /**\n * Check if an extension exists\n */\n public hasExtension(key: string | Extension | ExtensionFactory): boolean {\n if (typeof key === \"string\") {\n return this.extensions.some((e) => e.key === key);\n } else if (typeof key === \"object\" && \"key\" in key) {\n return this.extensions.some((e) => e.key === key.key);\n } else if (typeof key === \"function\") {\n return this.extensionFactories.has(key);\n }\n return false;\n }\n}\n","import { TextSelection, type Transaction } from \"prosemirror-state\";\nimport { TableMap } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { Selection } from \"../../../editor/selectionTypes.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getBlockInfo, getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport {\n nodeToBlock,\n prosemirrorSliceToSlicedBlocks,\n} from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getSelection<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): Selection<BSchema, I, S> | undefined {\n const pmSchema = getPmSchema(tr);\n // Return undefined if the selection is collapsed or a node is selected.\n if (tr.selection.empty || \"node\" in tr.selection) {\n return undefined;\n }\n\n const $startBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.from).posBeforeNode,\n );\n const $endBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.to).posBeforeNode,\n );\n\n // Converts the node at the given index and depth around `$startBlockBeforePos`\n // to a block. Used to get blocks at given indices at the shared depth and\n // at the depth of `$startBlockBeforePos`.\n const indexToBlock = (\n index: number,\n depth?: number,\n ): Block<BSchema, I, S> => {\n const pos = $startBlockBeforePos.posAtIndex(index, depth);\n const node = tr.doc.resolve(pos).nodeAfter;\n\n if (!node) {\n throw new Error(\n `Error getting selection - node not found at position ${pos}`,\n );\n }\n\n return nodeToBlock(node, pmSchema);\n };\n\n const blocks: Block<BSchema, I, S>[] = [];\n // Minimum depth at which the blocks share a common ancestor.\n const sharedDepth = $startBlockBeforePos.sharedDepth($endBlockBeforePos.pos);\n const startIndex = $startBlockBeforePos.index(sharedDepth);\n const endIndex = $endBlockBeforePos.index(sharedDepth);\n\n // In most cases, we want to return the blocks spanned by the selection at the\n // shared depth. However, when the block in which the selection starts is at a\n // higher depth than the shared depth, we omit the first block at the shared\n // depth. Instead, we include the first block at its depth, and any blocks at\n // a higher index up to the shared depth. The following example illustrates\n // this:\n // - id-0\n // - id-1\n // - >|id-2\n // - id-3\n // - id-4\n // - id-5\n // - id-6\n // - id-7\n // - id-8\n // - id-9|<\n // - id-10\n // Here, each block is represented by its ID, and the selection is represented\n // by the `>|` and `|<` markers. So the selection starts in block `id-2` and\n // ends in block `id-8`. In this case, the shared depth is 0, since the blocks\n // `id-6`, `id-7`, and `id-8` set the shared depth, as they are the least\n // nested blocks spanned by the selection. Therefore, these blocks are all\n // added to the `blocks` array. However, the selection starts in block `id-2`,\n // which is at a higher depth than the shared depth. So we add block `id-2` to\n // the `blocks` array, as well as any later siblings (in this case, `id-3`),\n // and move up one level of depth. The ancestor of block `id-2` at this depth\n // is block `id-1`, so we add all its later siblings to the `blocks` array as\n // well, again moving up one level of depth. Since we're now at the shared\n // depth, we are done. The final `blocks` array for this example would be:\n // [ id-2, id-3, id-4, id-6, id-7, id-8, id-9 ]\n if ($startBlockBeforePos.depth > sharedDepth) {\n // Adds the block that the selection starts in.\n blocks.push(nodeToBlock($startBlockBeforePos.nodeAfter!, pmSchema));\n\n // Traverses all depths from the depth of the block in which the selection\n // starts, up to the shared depth.\n for (let depth = $startBlockBeforePos.depth; depth > sharedDepth; depth--) {\n const parentNode = $startBlockBeforePos.node(depth);\n\n if (parentNode.type.isInGroup(\"childContainer\")) {\n const startIndexAtDepth = $startBlockBeforePos.index(depth) + 1;\n const childCountAtDepth = $startBlockBeforePos.node(depth).childCount;\n\n // Adds all blocks after the index of the block in which the selection\n // starts (or its ancestors at lower depths).\n for (let i = startIndexAtDepth; i < childCountAtDepth; i++) {\n blocks.push(indexToBlock(i, depth));\n }\n }\n }\n } else {\n // Adds the first block spanned by the selection at the shared depth.\n blocks.push(indexToBlock(startIndex, sharedDepth));\n }\n\n // Adds all blocks spanned by the selection at the shared depth, excluding\n // the first.\n for (let i = startIndex + 1; i <= endIndex; i++) {\n blocks.push(indexToBlock(i, sharedDepth));\n }\n\n if (blocks.length === 0) {\n throw new Error(\n `Error getting selection - selection doesn't span any blocks (${tr.selection})`,\n );\n }\n\n return {\n blocks,\n };\n}\n\nexport function setSelection(\n tr: Transaction,\n startBlock: BlockIdentifier,\n endBlock: BlockIdentifier,\n) {\n const startBlockId =\n typeof startBlock === \"string\" ? startBlock : startBlock.id;\n const endBlockId = typeof endBlock === \"string\" ? endBlock : endBlock.id;\n const pmSchema = getPmSchema(tr);\n const schema = getBlockNoteSchema(pmSchema);\n\n if (startBlockId === endBlockId) {\n throw new Error(\n `Attempting to set selection with the same anchor and head blocks (id ${startBlockId})`,\n );\n }\n const anchorPosInfo = getNodeById(startBlockId, tr.doc);\n if (!anchorPosInfo) {\n throw new Error(`Block with ID ${startBlockId} not found`);\n }\n const headPosInfo = getNodeById(endBlockId, tr.doc);\n if (!headPosInfo) {\n throw new Error(`Block with ID ${endBlockId} not found`);\n }\n\n const anchorBlockInfo = getBlockInfo(anchorPosInfo);\n const headBlockInfo = getBlockInfo(headPosInfo);\n\n const anchorBlockConfig =\n schema.blockSchema[\n anchorBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n const headBlockConfig =\n schema.blockSchema[\n headBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n\n if (\n !anchorBlockInfo.isBlockContainer ||\n anchorBlockConfig.content === \"none\"\n ) {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${startBlockId})`,\n );\n }\n if (!headBlockInfo.isBlockContainer || headBlockConfig.content === \"none\") {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${endBlockId})`,\n );\n }\n\n let startPos: number;\n let endPos: number;\n\n if (anchorBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(anchorBlockInfo.blockContent.node);\n const firstCellPos =\n anchorBlockInfo.blockContent.beforePos +\n tableMap.positionAt(0, 0, anchorBlockInfo.blockContent.node) +\n 1;\n startPos = firstCellPos + 2;\n } else {\n startPos = anchorBlockInfo.blockContent.beforePos + 1;\n }\n\n if (headBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(headBlockInfo.blockContent.node);\n const lastCellPos =\n headBlockInfo.blockContent.beforePos +\n tableMap.positionAt(\n tableMap.height - 1,\n tableMap.width - 1,\n headBlockInfo.blockContent.node,\n ) +\n 1;\n const lastCellNodeSize = tr.doc.resolve(lastCellPos).nodeAfter!.nodeSize;\n endPos = lastCellPos + lastCellNodeSize - 2;\n } else {\n endPos = headBlockInfo.blockContent.afterPos - 1;\n }\n\n // TODO: We should polish up the `MultipleNodeSelection` and use that instead.\n // Right now it's missing a few things like a jsonID and styling to show\n // which nodes are selected. `TextSelection` is ok for now, but has the\n // restriction that the start/end blocks must have content.\n tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));\n}\n\nexport function getSelectionCutBlocks(tr: Transaction) {\n // TODO: fix image node selection\n\n const pmSchema = getPmSchema(tr);\n let start = tr.selection.$from;\n let end = tr.selection.$to;\n\n // the selection moves below are used to make sure `prosemirrorSliceToSlicedBlocks` returns\n // the correct information about whether content is cut at the start or end of a block\n\n // if the end is at the end of a node (|</span></p>) move it forward so we include all closing tags (</span></p>|)\n while (end.parentOffset >= end.parent.nodeSize - 2 && end.depth > 0) {\n end = tr.doc.resolve(end.pos + 1);\n }\n\n // if the end is at the start of an empty node (</span></p><p>|) move it backwards so we drop empty start tags (</span></p>|)\n while (end.parentOffset === 0 && end.depth > 0) {\n end = tr.doc.resolve(end.pos - 1);\n }\n\n // if the start is at the start of a node (<p><span>|) move it backwards so we include all open tags (|<p><span>)\n while (start.parentOffset === 0 && start.depth > 0) {\n start = tr.doc.resolve(start.pos - 1);\n }\n\n // if the start is at the end of a node (|</p><p><span>|) move it forwards so we drop all closing tags (|<p><span>)\n while (start.parentOffset >= start.parent.nodeSize - 2 && start.depth > 0) {\n start = tr.doc.resolve(start.pos + 1);\n }\n\n const selectionInfo = prosemirrorSliceToSlicedBlocks(\n tr.doc.slice(start.pos, end.pos, true),\n pmSchema,\n );\n\n return {\n _meta: {\n startPos: start.pos,\n endPos: end.pos,\n },\n ...selectionInfo,\n };\n}\n","import type { Node } from \"prosemirror-model\";\nimport {\n NodeSelection,\n TextSelection,\n type Transaction,\n} from \"prosemirror-state\";\nimport type { TextCursorPosition } from \"../../../editor/cursorPositionTypes.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../util/typescript.js\";\nimport {\n getBlockInfo,\n getBlockInfoFromTransaction,\n} from \"../../getBlockInfoFromPos.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getTextCursorPosition<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): TextCursorPosition<BSchema, I, S> {\n const { bnBlock } = getBlockInfoFromTransaction(tr);\n const pmSchema = getPmSchema(tr.doc);\n\n const resolvedPos = tr.doc.resolve(bnBlock.beforePos);\n // Gets previous blockContainer node at the same nesting level, if the current node isn't the first child.\n const prevNode = resolvedPos.nodeBefore;\n\n // Gets next blockContainer node at the same nesting level, if the current node isn't the last child.\n const nextNode = tr.doc.resolve(bnBlock.afterPos).nodeAfter;\n\n // Gets parent blockContainer node, if the current node is nested.\n let parentNode: Node | undefined = undefined;\n if (resolvedPos.depth > 1) {\n // for nodes nested in bnBlocks\n parentNode = resolvedPos.node();\n if (!parentNode.type.isInGroup(\"bnBlock\")) {\n // for blockGroups, we need to go one level up\n parentNode = resolvedPos.node(resolvedPos.depth - 1);\n }\n }\n\n return {\n block: nodeToBlock(bnBlock.node, pmSchema),\n prevBlock: prevNode === null ? undefined : nodeToBlock(prevNode, pmSchema),\n nextBlock: nextNode === null ? undefined : nodeToBlock(nextNode, pmSchema),\n parentBlock:\n parentNode === undefined ? undefined : nodeToBlock(parentNode, pmSchema),\n };\n}\n\nexport function setTextCursorPosition(\n tr: Transaction,\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n) {\n const id = typeof targetBlock === \"string\" ? targetBlock : targetBlock.id;\n const pmSchema = getPmSchema(tr.doc);\n const schema = getBlockNoteSchema(pmSchema);\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n const info = getBlockInfo(posInfo);\n\n const contentType: \"none\" | \"inline\" | \"table\" =\n schema.blockSchema[info.blockNoteType]!.content;\n\n if (info.isBlockContainer) {\n const blockContent = info.blockContent;\n if (contentType === \"none\") {\n tr.setSelection(NodeSelection.create(tr.doc, blockContent.beforePos));\n return;\n }\n\n if (contentType === \"inline\") {\n if (placement === \"start\") {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 1),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 1),\n );\n }\n } else if (contentType === \"table\") {\n if (placement === \"start\") {\n // Need to offset the position as we have to get through the `tableRow`\n // and `tableCell` nodes to get to the `tableParagraph` node we want to\n // set the selection in.\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 4),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 4),\n );\n }\n } else {\n throw new UnreachableCaseError(contentType);\n }\n } else {\n const child =\n placement === \"start\"\n ? info.childContainer.node.firstChild!\n : info.childContainer.node.lastChild!;\n\n setTextCursorPosition(tr, child.attrs.id, placement);\n }\n}\n","import {\n getSelection,\n getSelectionCutBlocks,\n setSelection,\n} from \"../../api/blockManipulation/selections/selection.js\";\nimport {\n getTextCursorPosition,\n setTextCursorPosition,\n} from \"../../api/blockManipulation/selections/textCursorPosition.js\";\nimport { isNodeSelection, posToDOMRect } from \"@tiptap/core\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport {\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../../blocks/defaultBlocks.js\";\nimport { Selection } from \"../selectionTypes.js\";\nimport { TextCursorPosition } from \"../cursorPositionTypes.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class SelectionManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned data will contain the entire block.\n */\n public getSelection(): Selection<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getSelection(tr));\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned block will be\n * only the part of the block that is included in the selection.\n */\n public getSelectionCutBlocks() {\n return this.editor.transact((tr) => getSelectionCutBlocks(tr));\n }\n\n /**\n * Sets the selection to a range of blocks.\n * @param startBlock The identifier of the block that should be the start of the selection.\n * @param endBlock The identifier of the block that should be the end of the selection.\n */\n public setSelection(startBlock: BlockIdentifier, endBlock: BlockIdentifier) {\n return this.editor.transact((tr) => setSelection(tr, startBlock, endBlock));\n }\n\n /**\n * Gets a snapshot of the current text cursor position.\n * @returns A snapshot of the current text cursor position.\n */\n public getTextCursorPosition(): TextCursorPosition<\n BSchema,\n ISchema,\n SSchema\n > {\n return this.editor.transact((tr) => getTextCursorPosition(tr));\n }\n\n /**\n * Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could\n * not be found.\n * @param targetBlock The identifier of an existing block that the text cursor should be moved to.\n * @param placement Whether the text cursor should be placed at the start or end of the block.\n */\n public setTextCursorPosition(\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n ) {\n return this.editor.transact((tr) =>\n setTextCursorPosition(tr, targetBlock, placement),\n );\n }\n\n /**\n * Gets the bounding box of the current selection.\n */\n public getSelectionBoundingBox() {\n if (!this.editor.prosemirrorView) {\n return undefined;\n }\n\n const { selection } = this.editor.prosemirrorState;\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n if (isNodeSelection(selection)) {\n const node = this.editor.prosemirrorView.nodeDOM(from) as HTMLElement;\n if (node) {\n return node.getBoundingClientRect();\n }\n }\n\n return posToDOMRect(\n this.editor.prosemirrorView,\n from,\n to,\n ).toJSON() as DOMRect;\n }\n}\n","import { Command, Transaction } from \"prosemirror-state\";\nimport type { YUndoExtension } from \"../../extensions/Collaboration/YUndo.js\";\nimport type { HistoryExtension } from \"../../extensions/History/History.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class StateManager {\n constructor(private editor: BlockNoteEditor<any, any, any>) {}\n\n /**\n * Stores the currently active transaction, which is the accumulated transaction from all {@link dispatch} calls during a {@link transact} calls\n */\n private activeTransaction: Transaction | null = null;\n\n /**\n * For any command that can be executed, you can check if it can be executed by calling `editor.can(command)`.\n * @example\n * ```ts\n * if (editor.can(editor.undo)) {\n * // show button\n * } else {\n * // hide button\n * }\n */\n public can(cb: () => boolean) {\n try {\n this.isInCan = true;\n return cb();\n } finally {\n this.isInCan = false;\n }\n }\n\n // Flag to indicate if we're in a `can` call\n private isInCan = false;\n\n /**\n * Execute a prosemirror command. This is mostly for backwards compatibility with older code.\n *\n * @note You should prefer the {@link transact} method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.\n *\n * @example\n * ```ts\n * editor.exec((state, dispatch, view) => {\n * dispatch(state.tr.insertText(\"Hello, world!\"));\n * });\n * ```\n */\n public exec(command: Command) {\n if (this.activeTransaction) {\n throw new Error(\n \"`exec` should not be called within a `transact` call, move the `exec` call outside of the `transact` call\",\n );\n }\n if (this.isInCan) {\n return this.canExec(command);\n }\n const state = this.prosemirrorState;\n const view = this.prosemirrorView;\n const dispatch = (tr: Transaction) => this.prosemirrorView.dispatch(tr);\n\n return command(state, dispatch, view);\n }\n\n /**\n * Check if a command can be executed. A command should return `false` if it is not valid in the current state.\n *\n * @example\n * ```ts\n * if (editor.canExec(command)) {\n * // show button\n * } else {\n * // hide button\n * }\n * ```\n */\n public canExec(command: Command): boolean {\n if (this.activeTransaction) {\n throw new Error(\n \"`canExec` should not be called within a `transact` call, move the `canExec` call outside of the `transact` call\",\n );\n }\n const state = this.prosemirrorState;\n const view = this.prosemirrorView;\n\n return command(state, undefined, view);\n }\n\n /**\n * Execute a function within a \"blocknote transaction\".\n * All changes to the editor within the transaction will be grouped together, so that\n * we can dispatch them as a single operation (thus creating only a single undo step)\n *\n * @note There is no need to dispatch the transaction, as it will be automatically dispatched when the callback is complete.\n *\n * @example\n * ```ts\n * // All changes to the editor will be grouped together\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * // These two operations will be grouped together in a single undo step\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * });\n * });\n * ```\n */\n public transact<T>(\n callback: (\n /**\n * The current active transaction, this will automatically be dispatched to the editor when the callback is complete\n * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.\n */\n tr: Transaction,\n ) => T,\n ): T {\n if (this.activeTransaction) {\n // Already in a transaction, so we can just callback immediately\n return callback(this.activeTransaction);\n }\n\n try {\n // Enter transaction mode, by setting a starting transaction\n this.activeTransaction = this.editor._tiptapEditor.state.tr;\n\n // Capture all dispatch'd transactions\n const result = callback(this.activeTransaction);\n\n // Any transactions captured by the `dispatch` call will be stored in `this.activeTransaction`\n const activeTr = this.activeTransaction;\n\n this.activeTransaction = null;\n if (\n activeTr &&\n // Only dispatch if the transaction was actually modified in some way\n (activeTr.docChanged ||\n activeTr.selectionSet ||\n activeTr.scrolledIntoView ||\n activeTr.storedMarksSet ||\n !activeTr.isGeneric)\n ) {\n // Dispatch the transaction if it was modified\n this.prosemirrorView.dispatch(activeTr);\n }\n\n return result;\n } finally {\n // We wrap this in a finally block to ensure we don't disable future transactions just because of an error in the callback\n this.activeTransaction = null;\n }\n }\n /**\n * Get the underlying prosemirror state\n * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date\n * @see https://prosemirror.net/docs/ref/#state.EditorState\n */\n public get prosemirrorState() {\n if (this.activeTransaction) {\n throw new Error(\n \"`prosemirrorState` should not be called within a `transact` call, move the `prosemirrorState` call outside of the `transact` call or use `editor.transact` to read the current editor state\",\n );\n }\n return this.editor._tiptapEditor.state;\n }\n\n /**\n * Get the underlying prosemirror view\n * @see https://prosemirror.net/docs/ref/#view.EditorView\n */\n public get prosemirrorView() {\n return this.editor._tiptapEditor.view;\n }\n\n public isFocused() {\n return this.prosemirrorView?.hasFocus() || false;\n }\n\n public focus() {\n this.prosemirrorView?.focus();\n }\n\n /**\n * Checks if the editor is currently editable, or if it's locked.\n * @returns True if the editor is editable, false otherwise.\n */\n public get isEditable(): boolean {\n if (!this.editor._tiptapEditor) {\n if (!this.editor.headless) {\n throw new Error(\"no editor, but also not headless?\");\n }\n return false;\n }\n return this.editor._tiptapEditor.isEditable === undefined\n ? true\n : this.editor._tiptapEditor.isEditable;\n }\n\n /**\n * Makes the editor editable or locks it, depending on the argument passed.\n * @param editable True to make the editor editable, or false to lock it.\n */\n public set isEditable(editable: boolean) {\n if (!this.editor._tiptapEditor) {\n if (!this.editor.headless) {\n throw new Error(\"no editor, but also not headless?\");\n }\n // not relevant on headless\n return;\n }\n if (this.editor._tiptapEditor.options.editable !== editable) {\n this.editor._tiptapEditor.setEditable(editable);\n }\n }\n\n /**\n * Undo the last action.\n */\n public undo(): boolean {\n // Purposefully not using the UndoPlugin to not import y-prosemirror when not needed\n const undoPlugin = this.editor.getExtension<typeof YUndoExtension>(\"yUndo\");\n if (undoPlugin) {\n return this.exec(undoPlugin.undoCommand);\n }\n\n const historyPlugin =\n this.editor.getExtension<typeof HistoryExtension>(\"history\");\n if (historyPlugin) {\n return this.exec(historyPlugin.undoCommand);\n }\n\n throw new Error(\"No undo plugin found\");\n }\n\n /**\n * Redo the last action.\n */\n public redo() {\n const undoPlugin = this.editor.getExtension<typeof YUndoExtension>(\"yUndo\");\n if (undoPlugin) {\n return this.exec(undoPlugin.redoCommand);\n }\n\n const historyPlugin =\n this.editor.getExtension<typeof HistoryExtension>(\"history\");\n if (historyPlugin) {\n return this.exec(historyPlugin.redoCommand);\n }\n\n throw new Error(\"No redo plugin found\");\n }\n}\n","import { selectionToInsertionEnd } from \"@tiptap/core\";\nimport { Node } from \"prosemirror-model\";\n\nimport type { Transaction } from \"prosemirror-state\";\n\n// similar to tiptap insertContentAt\nexport function insertContentAt(\n tr: Transaction,\n position: number | { from: number; to: number },\n nodes: Node[],\n options: {\n updateSelection: boolean;\n } = { updateSelection: true },\n) {\n // don’t dispatch an empty fragment because this can lead to strange errors\n // if (content.toString() === \"<>\") {\n // return true;\n // }\n\n let { from, to } =\n typeof position === \"number\"\n ? { from: position, to: position }\n : { from: position.from, to: position.to };\n\n let isOnlyTextContent = true;\n let isOnlyBlockContent = true;\n // const nodes = isFragment(content) ? content : [content];\n\n let text = \"\";\n\n nodes.forEach((node) => {\n // check if added node is valid\n node.check();\n\n if (isOnlyTextContent && node.isText && node.marks.length === 0) {\n text += node.text;\n } else {\n isOnlyTextContent = false;\n }\n\n isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;\n });\n\n // check if we can replace the wrapping node by\n // the newly inserted content\n // example:\n // replace an empty paragraph by an inserted image\n // instead of inserting the image below the paragraph\n if (from === to && isOnlyBlockContent) {\n const { parent } = tr.doc.resolve(from);\n const isEmptyTextBlock =\n parent.isTextblock && !parent.type.spec.code && !parent.childCount;\n\n if (isEmptyTextBlock) {\n from -= 1;\n to += 1;\n }\n }\n\n // if there is only plain text we have to use `insertText`\n // because this will keep the current marks\n if (isOnlyTextContent) {\n // if value is string, we can use it directly\n // otherwise if it is an array, we have to join it\n // if (Array.isArray(value)) {\n // tr.insertText(value.map((v) => v.text || \"\").join(\"\"), from, to);\n // } else if (typeof value === \"object\" && !!value && !!value.text) {\n // tr.insertText(value.text, from, to);\n // } else {\n // tr.insertText(value as string, from, to);\n // }\n tr.insertText(text, from, to);\n } else {\n tr.replaceWith(from, to, nodes);\n }\n\n // set cursor at end of inserted content\n if (options.updateSelection) {\n selectionToInsertionEnd(tr, tr.steps.length - 1, -1);\n }\n\n return true;\n}\n","import { insertContentAt } from \"../../api/blockManipulation/insertContentAt.js\";\nimport { inlineContentToNodes } from \"../../api/nodeConversions/blockToNode.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n PartialInlineContent,\n StyleSchema,\n Styles,\n} from \"../../schema/index.js\";\nimport {\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../../blocks/defaultBlocks.js\";\nimport { TextSelection } from \"@tiptap/pm/state\";\nimport { UnreachableCaseError } from \"../../util/typescript.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class StyleManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Insert a piece of content at the current cursor position.\n *\n * @param content can be a string, or array of partial inline content elements\n */\n public insertInlineContent(\n content: PartialInlineContent<ISchema, SSchema>,\n { updateSelection = false }: { updateSelection?: boolean } = {},\n ) {\n const nodes = inlineContentToNodes(content, this.editor.pmSchema);\n\n this.editor.transact((tr) => {\n insertContentAt(\n tr,\n {\n from: tr.selection.from,\n to: tr.selection.to,\n },\n nodes,\n {\n updateSelection,\n },\n );\n });\n }\n\n /**\n * Gets the active text styles at the text cursor position or at the end of the current selection if it's active.\n */\n public getActiveStyles() {\n return this.editor.transact((tr) => {\n const styles: Styles<SSchema> = {};\n const marks = tr.selection.$to.marks();\n\n for (const mark of marks) {\n const config = this.editor.schema.styleSchema[mark.type.name];\n if (!config) {\n if (\n // Links are not considered styles in blocknote\n mark.type.name !== \"link\" &&\n // \"blocknoteIgnore\" tagged marks (such as comments) are also not considered BlockNote \"styles\"\n !mark.type.spec.blocknoteIgnore\n ) {\n // eslint-disable-next-line no-console\n console.warn(\"mark not found in styleschema\", mark.type.name);\n }\n\n continue;\n }\n if (config.propSchema === \"boolean\") {\n (styles as any)[config.type] = true;\n } else {\n (styles as any)[config.type] = mark.attrs.stringValue;\n }\n }\n\n return styles;\n });\n }\n\n /**\n * Adds styles to the currently selected content.\n * @param styles The styles to add.\n */\n public addStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.editor.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this.editor._tiptapEditor.commands.setMark(style);\n } else if (config.propSchema === \"string\") {\n this.editor._tiptapEditor.commands.setMark(style, {\n stringValue: value,\n });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Removes styles from the currently selected content.\n * @param styles The styles to remove.\n */\n public removeStyles(styles: Styles<SSchema>) {\n for (const style of Object.keys(styles)) {\n this.editor._tiptapEditor.commands.unsetMark(style);\n }\n }\n\n /**\n * Toggles styles on the currently selected content.\n * @param styles The styles to toggle.\n */\n public toggleStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.editor.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this.editor._tiptapEditor.commands.toggleMark(style);\n } else if (config.propSchema === \"string\") {\n this.editor._tiptapEditor.commands.toggleMark(style, {\n stringValue: value,\n });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Gets the currently selected text.\n */\n public getSelectedText() {\n return this.editor.transact((tr) => {\n return tr.doc.textBetween(tr.selection.from, tr.selection.to);\n });\n }\n\n /**\n * Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.\n */\n public getSelectedLinkUrl() {\n return this.editor._tiptapEditor.getAttributes(\"link\").href as\n | string\n | undefined;\n }\n\n /**\n * Creates a new link to replace the selected content.\n * @param url The link URL.\n * @param text The text to display the link with.\n */\n public createLink(url: string, text?: string) {\n if (url === \"\") {\n return;\n }\n const mark = this.editor.pmSchema.mark(\"link\", { href: url });\n this.editor.transact((tr) => {\n const { from, to } = tr.selection;\n\n if (text) {\n tr.insertText(text, from, to).addMark(from, from + text.length, mark);\n } else {\n tr.setSelection(TextSelection.create(tr.doc, to)).addMark(\n from,\n to,\n mark,\n );\n }\n });\n }\n}\n","import { Fragment, Schema, Slice } from \"@tiptap/pm/model\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { getBlockInfoFromSelection } from \"../api/getBlockInfoFromPos.js\";\n\n// helper function to remove a child from a fragment\nfunction removeChild(node: Fragment, n: number) {\n const children: any[] = [];\n node.forEach((child, _, i) => {\n if (i !== n) {\n children.push(child);\n }\n });\n return Fragment.from(children);\n}\n\n/**\n * Wrap adjacent tableRow items in a table.\n *\n * This makes sure the content that we paste is always a table (and not a tableRow)\n * A table works better for the remaing paste handling logic, as it's actually a blockContent node\n */\nexport function wrapTableRows(f: Fragment, schema: Schema) {\n const newItems: any[] = [];\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.name === \"tableRow\") {\n if (\n newItems.length > 0 &&\n newItems[newItems.length - 1].type.name === \"table\"\n ) {\n // append to existing table\n const prevTable = newItems[newItems.length - 1];\n const newTable = prevTable.copy(prevTable.content.addToEnd(f.child(i)));\n newItems[newItems.length - 1] = newTable;\n } else {\n // create new table to wrap tableRow with\n const newTable = schema.nodes.table.createChecked(\n undefined,\n f.child(i),\n );\n newItems.push(newTable);\n }\n } else {\n newItems.push(f.child(i));\n }\n }\n f = Fragment.from(newItems);\n return f;\n}\n\n/**\n * fix for https://github.com/ProseMirror/prosemirror/issues/1430#issuecomment-1822570821\n *\n * This fix wraps pasted ProseMirror nodes in their own `blockContainer` nodes\n * in most cases. This is to ensure that ProseMirror inserts them as separate\n * blocks, which it sometimes doesn't do because it doesn't have enough context\n * about the hierarchy of the pasted nodes. The issue can be seen when pasting\n * e.g. an image or two consecutive paragraphs, where PM tries to nest the\n * pasted block(s) when it shouldn't.\n *\n * However, the fix is not applied in a few cases. See `shouldApplyFix` for\n * which cases are excluded.\n */\nexport function transformPasted(slice: Slice, view: EditorView) {\n let f = Fragment.from(slice.content);\n f = wrapTableRows(f, view.state.schema);\n\n if (!shouldApplyFix(f, view)) {\n // Don't apply the fix.\n return new Slice(f, slice.openStart, slice.openEnd);\n }\n\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.spec.group === \"blockContent\") {\n const content = [f.child(i)];\n\n // when there is a blockGroup with lists, it should be nested in the new blockcontainer\n // (if we remove this if-block, the nesting bug will be fixed, but lists won't be nested correctly)\n if (\n i + 1 < f.childCount &&\n f.child(i + 1).type.name === \"blockGroup\" // TODO\n ) {\n const nestedChild = f\n .child(i + 1)\n .child(0)\n .child(0);\n\n if (\n nestedChild.type.name === \"bulletListItem\" ||\n nestedChild.type.name === \"numberedListItem\" ||\n nestedChild.type.name === \"checkListItem\"\n ) {\n content.push(f.child(i + 1));\n f = removeChild(f, i + 1);\n }\n }\n const container = view.state.schema.nodes.blockContainer.createChecked(\n undefined,\n content,\n );\n f = f.replaceChild(i, container);\n }\n }\n return new Slice(f, slice.openStart, slice.openEnd);\n}\n\n/**\n * Used in `transformPasted` to check if the fix there should be applied, i.e.\n * if the pasted fragment should be wrapped in a `blockContainer` node. This\n * will explicitly tell ProseMirror to treat it as a separate block.\n */\nfunction shouldApplyFix(fragment: Fragment, view: EditorView) {\n const nodeHasSingleChild = fragment.childCount === 1;\n const nodeHasInlineContent =\n fragment.firstChild?.type.spec.content === \"inline*\";\n const nodeHasTableContent =\n fragment.firstChild?.type.spec.content === \"tableRow+\";\n\n if (nodeHasSingleChild) {\n if (nodeHasInlineContent) {\n // Case when we paste a single node with inline content, e.g. a paragraph\n // or heading. We want to insert the content in-line for better UX instead\n // of a separate block, so we return false.\n return false;\n }\n\n if (nodeHasTableContent) {\n // Not ideal that we check selection here, as `transformPasted` is called\n // for both paste and drop events. Drop events can potentially cause\n // issues as they don't always happen at the current selection.\n const blockInfo = getBlockInfoFromSelection(view.state);\n if (blockInfo.isBlockContainer) {\n const selectedBlockHasTableContent =\n blockInfo.blockContent.node.type.spec.content === \"tableRow+\";\n\n // Case for when we paste a single node with table content, i.e. a\n // table. Normally, we return true as we want to ensure the table is\n // inserted as a separate block. However, if the selection is in an\n // existing table, we return false, as we want the content of the pasted\n // table to be added to the existing one for better UX.\n return !selectedBlockHasTableContent;\n }\n }\n }\n\n return true;\n}\n","import {\n createDocument,\n EditorOptions,\n FocusPosition,\n getSchema,\n Editor as TiptapEditor,\n} from \"@tiptap/core\";\nimport { type Command, type Plugin, type Transaction } from \"@tiptap/pm/state\";\nimport { Node, Schema } from \"prosemirror-model\";\nimport * as Y from \"yjs\";\n\nimport type { BlocksChanged } from \"../api/getBlocksChangedByTransaction.js\";\nimport { blockToNode } from \"../api/nodeConversions/blockToNode.js\";\nimport {\n Block,\n BlockNoteSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../blocks/index.js\";\nimport { UniqueID } from \"../extensions/tiptap-extensions/UniqueID/UniqueID.js\";\nimport type { Dictionary } from \"../i18n/dictionary.js\";\nimport { en } from \"../i18n/locales/index.js\";\nimport type {\n BlockIdentifier,\n BlockNoteDOMAttributes,\n BlockSchema,\n BlockSpecs,\n CustomBlockNoteSchema,\n InlineContentSchema,\n InlineContentSpecs,\n PartialInlineContent,\n Styles,\n StyleSchema,\n StyleSpecs,\n} from \"../schema/index.js\";\nimport \"../style.css\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\nimport { EventEmitter } from \"../util/EventEmitter.js\";\nimport type { NoInfer } from \"../util/typescript.js\";\nimport { ExtensionFactoryInstance } from \"./BlockNoteExtension.js\";\nimport type { TextCursorPosition } from \"./cursorPositionTypes.js\";\nimport {\n BlockManager,\n EventManager,\n ExportManager,\n ExtensionManager,\n SelectionManager,\n StateManager,\n StyleManager,\n} from \"./managers/index.js\";\nimport type { Selection } from \"./selectionTypes.js\";\nimport { transformPasted } from \"./transformPasted.js\";\n\nexport type BlockCache<\n BSchema extends BlockSchema = any,\n ISchema extends InlineContentSchema = any,\n SSchema extends StyleSchema = any,\n> = WeakMap<Node, Block<BSchema, ISchema, SSchema>>;\n\nexport interface BlockNoteEditorOptions<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> {\n /**\n * Whether changes to blocks (like indentation, creating lists, changing headings) should be animated or not. Defaults to `true`.\n *\n * @default true\n */\n animations?: boolean;\n\n /**\n * Whether the editor should be focused automatically when it's created.\n *\n * @default false\n */\n autofocus?: FocusPosition;\n\n /**\n * When enabled, allows for collaboration between multiple users.\n * See [Real-time Collaboration](https://www.blocknotejs.org/docs/advanced/real-time-collaboration) for more info.\n *\n * @remarks `CollaborationOptions`\n */\n collaboration?: {\n /**\n * The Yjs XML fragment that's used for collaboration.\n */\n fragment: Y.XmlFragment;\n /**\n * The user info for the current user that's shown to other collaborators.\n */\n user: {\n name: string;\n color: string;\n };\n /**\n * A Yjs provider (used for awareness / cursor information)\n */\n provider: any;\n /**\n * Optional function to customize how cursors of users are rendered\n */\n renderCursor?: (user: any) => HTMLElement;\n /**\n * Optional flag to set when the user label should be shown with the default\n * collaboration cursor. Setting to \"always\" will always show the label,\n * while \"activity\" will only show the label when the user moves the cursor\n * or types. Defaults to \"activity\".\n */\n showCursorLabels?: \"always\" | \"activity\";\n };\n\n /**\n * Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.\n *\n * @default true\n */\n defaultStyles?: boolean;\n\n /**\n * A dictionary object containing translations for the editor.\n *\n * See [Localization / i18n](https://www.blocknotejs.org/docs/advanced/localization) for more info.\n *\n * @remarks `Dictionary` is a type that contains all the translations for the editor.\n */\n dictionary?: Dictionary & Record<string, any>;\n\n /**\n * Disable internal extensions (based on keys / extension name)\n *\n * @note Advanced\n */\n disableExtensions?: string[];\n\n /**\n * An object containing attributes that should be added to HTML elements of the editor.\n *\n * See [Adding DOM Attributes](https://www.blocknotejs.org/docs/theming#adding-dom-attributes) for more info.\n *\n * @example { editor: { class: \"my-editor-class\" } }\n * @remarks `Record<string, Record<string, string>>`\n */\n domAttributes?: Partial<BlockNoteDOMAttributes>;\n\n /**\n * A replacement indicator to use when dragging and dropping blocks. Uses the [ProseMirror drop cursor](https://github.com/ProseMirror/prosemirror-dropcursor), or a modified version when [Column Blocks](https://www.blocknotejs.org/docs/document-structure#column-blocks) are enabled.\n * @remarks `() => Plugin`\n */\n dropCursor?: (opts: {\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n color?: string | false;\n width?: number;\n class?: string;\n }) => Plugin;\n\n /**\n * The content that should be in the editor when it's created, represented as an array of {@link PartialBlock} objects.\n *\n * See [Partial Blocks](https://www.blocknotejs.org/docs/editor-api/manipulating-blocks#partial-blocks) for more info.\n *\n * @remarks `PartialBlock[]`\n */\n initialContent?: PartialBlock<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >[];\n\n /**\n * @deprecated, provide placeholders via dictionary instead\n * @internal\n */\n placeholders?: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >;\n\n /**\n * Custom paste handler that can be used to override the default paste behavior.\n *\n * See [Paste Handling](https://www.blocknotejs.org/docs/advanced/paste-handling) for more info.\n *\n * @remarks `PasteHandler`\n * @returns The function should return `true` if the paste event was handled, otherwise it should return `false` if it should be canceled or `undefined` if it should be handled by another handler.\n *\n * @example\n * ```ts\n * pasteHandler: ({ defaultPasteHandler }) => {\n * return defaultPasteHandler({ pasteBehavior: \"prefer-html\" });\n * }\n * ```\n */\n pasteHandler?: (context: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n /**\n * The default paste handler\n * @param context The context object\n * @returns Whether the paste event was handled or not\n */\n defaultPasteHandler: (context?: {\n /**\n * Whether to prioritize Markdown content in `text/plain` over `text/html` when pasting from the clipboard.\n * @default true\n */\n prioritizeMarkdownOverHTML?: boolean;\n /**\n * Whether to parse `text/plain` content from the clipboard as Markdown content.\n * @default true\n */\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => boolean | undefined;\n\n /**\n * Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or\n * implementing custom protocols / schemes\n * @returns The URL that's\n */\n resolveFileUrl?: (url: string) => Promise<string>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n *\n * See [Custom Schemas](https://www.blocknotejs.org/docs/custom-schemas) for more info.\n * @remarks `BlockNoteSchema`\n */\n schema: CustomBlockNoteSchema<BSchema, ISchema, SSchema>;\n\n /**\n * A flag indicating whether to set an HTML ID for every block\n *\n * When set to `true`, on each block an id attribute will be set with the block id\n * Otherwise, the HTML ID attribute will not be set.\n *\n * (note that the id is always set on the `data-id` attribute)\n */\n setIdAttribute?: boolean;\n\n /**\n * Determines behavior when pressing Tab (or Shift-Tab) while multiple blocks are selected and a toolbar is open.\n * - `\"prefer-navigate-ui\"`: Changes focus to the toolbar. User must press Escape to close toolbar before indenting blocks. Better for keyboard accessibility.\n * - `\"prefer-indent\"`: Always indents selected blocks, regardless of toolbar state. Keyboard navigation of toolbars not possible.\n * @default \"prefer-navigate-ui\"\n */\n tabBehavior?: \"prefer-navigate-ui\" | \"prefer-indent\";\n\n /**\n * Allows enabling / disabling features of tables.\n *\n * See [Tables](https://www.blocknotejs.org/docs/editor-basics/document-structure#tables) for more info.\n *\n * @remarks `TableConfig`\n */\n tables?: {\n /**\n * Whether to allow splitting and merging cells within a table.\n *\n * @default false\n */\n splitCells?: boolean;\n /**\n * Whether to allow changing the background color of cells.\n *\n * @default false\n */\n cellBackgroundColor?: boolean;\n /**\n * Whether to allow changing the text color of cells.\n *\n * @default false\n */\n cellTextColor?: boolean;\n /**\n * Whether to allow changing cells into headers.\n *\n * @default false\n */\n headers?: boolean;\n };\n\n /**\n * An option which user can pass with `false` value to disable the automatic creation of a trailing new block on the next line when the user types or edits any block.\n *\n * @default true\n */\n trailingBlock?: boolean;\n\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n * @remarks `(file: File) => Promise<UploadFileResult>`\n */\n uploadFile?: (\n file: File,\n blockId?: string,\n ) => Promise<string | Record<string, any>>;\n\n /**\n * additional tiptap options, undocumented\n * @internal\n */\n _tiptapOptions?: Partial<EditorOptions>;\n\n /**\n * Register extensions to the editor.\n *\n * See [Extensions](/docs/features/extensions) for more info.\n *\n * @remarks `ExtensionFactory[]`\n */\n extensions?: Array<ExtensionFactoryInstance>;\n}\n\nconst blockNoteTipTapOptions = {\n enableInputRules: true,\n enablePasteRules: true,\n enableCoreExtensions: false,\n};\n\nexport class BlockNoteEditor<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> extends EventEmitter<{\n create: void;\n}> {\n /**\n * The underlying prosemirror schema\n */\n public readonly pmSchema: Schema;\n\n public readonly _tiptapEditor: TiptapEditor & {\n contentComponent: any;\n };\n\n /**\n * Used by React to store a reference to an `ElementRenderer` helper utility to make sure we can render React elements\n * in the correct context (used by `ReactRenderUtil`)\n */\n public elementRenderer: ((node: any, container: HTMLElement) => void) | null =\n null;\n\n /**\n * Cache of all blocks. This makes sure we don't have to \"recompute\" blocks if underlying Prosemirror Nodes haven't changed.\n * This is especially useful when we want to keep track of the same block across multiple operations,\n * with this cache, blocks stay the same object reference (referential equality with ===).\n */\n public blockCache: BlockCache = new WeakMap();\n\n /**\n * The dictionary contains translations for the editor.\n */\n public readonly dictionary: Dictionary & Record<string, any>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n */\n public readonly schema: BlockNoteSchema<BSchema, ISchema, SSchema>;\n\n public readonly blockImplementations: BlockSpecs;\n public readonly inlineContentImplementations: InlineContentSpecs;\n public readonly styleImplementations: StyleSpecs;\n\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n */\n public readonly uploadFile:\n | ((file: File, blockId?: string) => Promise<string | Record<string, any>>)\n | undefined;\n\n private onUploadStartCallbacks: ((blockId?: string) => void)[] = [];\n private onUploadEndCallbacks: ((blockId?: string) => void)[] = [];\n\n public readonly resolveFileUrl?: (url: string) => Promise<string>;\n /**\n * Editor settings\n */\n public readonly settings: {\n tables: {\n splitCells: boolean;\n cellBackgroundColor: boolean;\n cellTextColor: boolean;\n headers: boolean;\n };\n };\n public static create<\n Options extends Partial<BlockNoteEditorOptions<any, any, any>> | undefined,\n >(\n options?: Options,\n ): Options extends {\n schema: CustomBlockNoteSchema<infer BSchema, infer ISchema, infer SSchema>;\n }\n ? BlockNoteEditor<BSchema, ISchema, SSchema>\n : BlockNoteEditor<\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema\n > {\n return new BlockNoteEditor(options ?? {}) as any;\n }\n\n protected constructor(\n protected readonly options: Partial<\n BlockNoteEditorOptions<BSchema, ISchema, SSchema>\n >,\n ) {\n super();\n\n this.dictionary = options.dictionary || en;\n this.settings = {\n tables: {\n splitCells: options?.tables?.splitCells ?? false,\n cellBackgroundColor: options?.tables?.cellBackgroundColor ?? false,\n cellTextColor: options?.tables?.cellTextColor ?? false,\n headers: options?.tables?.headers ?? false,\n },\n };\n\n // apply defaults\n const newOptions = {\n defaultStyles: true,\n schema:\n options.schema ||\n (BlockNoteSchema.create() as unknown as CustomBlockNoteSchema<\n BSchema,\n ISchema,\n SSchema\n >),\n ...options,\n placeholders: {\n ...this.dictionary.placeholders,\n ...options.placeholders,\n },\n };\n\n // @ts-ignore\n this.schema = newOptions.schema;\n this.blockImplementations = newOptions.schema.blockSpecs;\n this.inlineContentImplementations = newOptions.schema.inlineContentSpecs;\n this.styleImplementations = newOptions.schema.styleSpecs;\n\n // TODO this should just be an extension\n if (newOptions.uploadFile) {\n const uploadFile = newOptions.uploadFile;\n this.uploadFile = async (file, blockId) => {\n this.onUploadStartCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n try {\n return await uploadFile(file, blockId);\n } finally {\n this.onUploadEndCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n }\n };\n }\n\n this.resolveFileUrl = newOptions.resolveFileUrl;\n\n this._eventManager = new EventManager(this as any);\n this._extensionManager = new ExtensionManager(this, newOptions);\n\n const tiptapExtensions = this._extensionManager.getTiptapExtensions();\n\n const collaborationEnabled =\n this._extensionManager.hasExtension(\"ySync\") ||\n this._extensionManager.hasExtension(\"liveblocksExtension\");\n\n if (collaborationEnabled && newOptions.initialContent) {\n // eslint-disable-next-line no-console\n console.warn(\n \"When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider\",\n );\n }\n\n const tiptapOptions: EditorOptions = {\n ...blockNoteTipTapOptions,\n ...newOptions._tiptapOptions,\n element: null,\n autofocus: newOptions.autofocus ?? false,\n extensions: tiptapExtensions,\n editorProps: {\n ...newOptions._tiptapOptions?.editorProps,\n attributes: {\n // As of TipTap v2.5.0 the tabIndex is removed when the editor is not\n // editable, so you can't focus it. We want to revert this as we have\n // UI behaviour that relies on it.\n tabIndex: \"0\",\n ...newOptions._tiptapOptions?.editorProps?.attributes,\n ...newOptions.domAttributes?.editor,\n class: mergeCSSClasses(\n \"bn-editor\",\n newOptions.defaultStyles ? \"bn-default-styles\" : \"\",\n newOptions.domAttributes?.editor?.class || \"\",\n ),\n },\n transformPasted,\n },\n } as any;\n\n try {\n const initialContent =\n newOptions.initialContent ||\n (collaborationEnabled\n ? [\n {\n type: \"paragraph\",\n id: \"initialBlockId\",\n },\n ]\n : [\n {\n type: \"paragraph\",\n id: UniqueID.options.generateID(),\n },\n ]);\n\n if (!Array.isArray(initialContent) || initialContent.length === 0) {\n throw new Error(\n \"initialContent must be a non-empty array of blocks, received: \" +\n initialContent,\n );\n }\n const schema = getSchema(tiptapOptions.extensions!);\n const pmNodes = initialContent.map((b) =>\n blockToNode(b, schema, this.schema.styleSchema).toJSON(),\n );\n const doc = createDocument(\n {\n type: \"doc\",\n content: [\n {\n type: \"blockGroup\",\n content: pmNodes,\n },\n ],\n },\n schema,\n tiptapOptions.parseOptions,\n );\n\n this._tiptapEditor = new TiptapEditor({\n ...tiptapOptions,\n content: doc.toJSON(),\n }) as any;\n this.pmSchema = this._tiptapEditor.schema;\n } catch (e) {\n throw new Error(\n \"Error creating document from blocks passed as `initialContent`\",\n { cause: e },\n );\n }\n\n // When y-prosemirror creates an empty document, the `blockContainer` node is created with an `id` of `null`.\n // This causes the unique id extension to generate a new id for the initial block, which is not what we want\n // Since it will be randomly generated & cause there to be more updates to the ydoc\n // This is a hack to make it so that anytime `schema.doc.createAndFill` is called, the initial block id is already set to \"initialBlockId\"\n let cache: Node | undefined = undefined;\n const oldCreateAndFill = this.pmSchema.nodes.doc.createAndFill;\n this.pmSchema.nodes.doc.createAndFill = (...args: any) => {\n if (cache) {\n return cache;\n }\n const ret = oldCreateAndFill.apply(this.pmSchema.nodes.doc, args)!;\n\n // create a copy that we can mutate (otherwise, assigning attrs is not safe and corrupts the pm state)\n const jsonNode = JSON.parse(JSON.stringify(ret.toJSON()));\n jsonNode.content[0].content[0].attrs.id = \"initialBlockId\";\n\n cache = Node.fromJSON(this.pmSchema, jsonNode);\n return cache;\n };\n this.pmSchema.cached.blockNoteEditor = this;\n\n // Initialize managers\n this._blockManager = new BlockManager(this as any);\n\n this._exportManager = new ExportManager(this as any);\n this._selectionManager = new SelectionManager(this as any);\n this._stateManager = new StateManager(this as any);\n this._styleManager = new StyleManager(this as any);\n\n this.emit(\"create\");\n }\n\n // Manager instances\n private readonly _blockManager: BlockManager<any, any, any>;\n private readonly _eventManager: EventManager<any, any, any>;\n private readonly _exportManager: ExportManager<any, any, any>;\n private readonly _extensionManager: ExtensionManager;\n private readonly _selectionManager: SelectionManager<any, any, any>;\n private readonly _stateManager: StateManager;\n private readonly _styleManager: StyleManager<any, any, any>;\n\n /**\n * BlockNote extensions that are added to the editor, keyed by the extension key\n */\n public get extensions() {\n return this._extensionManager.getExtensions();\n }\n\n /**\n * Execute a prosemirror command. This is mostly for backwards compatibility with older code.\n *\n * @note You should prefer the {@link transact} method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.\n *\n * @example\n * ```ts\n * editor.exec((state, dispatch, view) => {\n * dispatch(state.tr.insertText(\"Hello, world!\"));\n * });\n * ```\n */\n public exec(command: Command) {\n return this._stateManager.exec(command);\n }\n\n /**\n * Check if a command can be executed. A command should return `false` if it is not valid in the current state.\n *\n * @example\n * ```ts\n * if (editor.canExec(command)) {\n * // show button\n * } else {\n * // hide button\n * }\n * ```\n */\n public canExec(command: Command): boolean {\n return this._stateManager.canExec(command);\n }\n\n /**\n * Execute a function within a \"blocknote transaction\".\n * All changes to the editor within the transaction will be grouped together, so that\n * we can dispatch them as a single operation (thus creating only a single undo step)\n *\n * @note There is no need to dispatch the transaction, as it will be automatically dispatched when the callback is complete.\n *\n * @example\n * ```ts\n * // All changes to the editor will be grouped together\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * // These two operations will be grouped together in a single undo step\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * });\n * });\n * ```\n */\n public transact<T>(\n callback: (\n /**\n * The current active transaction, this will automatically be dispatched to the editor when the callback is complete\n * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.\n */\n tr: Transaction,\n ) => T,\n ): T {\n return this._stateManager.transact(callback);\n }\n\n /**\n * Remove extension(s) from the editor\n */\n public unregisterExtension: ExtensionManager[\"unregisterExtension\"] = (\n ...args: Parameters<ExtensionManager[\"unregisterExtension\"]>\n ) => this._extensionManager.unregisterExtension(...args);\n\n /**\n * Register extension(s) to the editor\n */\n public registerExtension: ExtensionManager[\"registerExtension\"] = (\n ...args: Parameters<ExtensionManager[\"registerExtension\"]>\n ) => this._extensionManager.registerExtension(...args) as any;\n\n /**\n * Get an extension from the editor\n */\n public getExtension: ExtensionManager[\"getExtension\"] = ((\n ...args: Parameters<ExtensionManager[\"getExtension\"]>\n ) => this._extensionManager.getExtension(...args)) as any;\n\n /**\n * Mount the editor to a DOM element.\n *\n * @warning Not needed to call manually when using React, use BlockNoteView to take care of mounting\n */\n public mount = (element: HTMLElement) => {\n this._tiptapEditor.mount({ mount: element });\n };\n\n /**\n * Unmount the editor from the DOM element it is bound to\n */\n public unmount = () => {\n this._tiptapEditor.unmount();\n };\n\n /**\n * Get the underlying prosemirror state\n * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date\n * @see https://prosemirror.net/docs/ref/#state.EditorState\n */\n public get prosemirrorState() {\n return this._stateManager.prosemirrorState;\n }\n\n /**\n * Get the underlying prosemirror view\n * @see https://prosemirror.net/docs/ref/#view.EditorView\n */\n public get prosemirrorView() {\n return this._stateManager.prosemirrorView;\n }\n\n public get domElement() {\n if (this.headless) {\n return undefined;\n }\n return this.prosemirrorView?.dom as HTMLDivElement | undefined;\n }\n\n public isFocused() {\n if (this.headless) {\n return false;\n }\n return this.prosemirrorView?.hasFocus() || false;\n }\n\n public get headless() {\n return !this._tiptapEditor.isInitialized;\n }\n\n /**\n * Focus on the editor\n */\n public focus() {\n if (this.headless) {\n return;\n }\n this.prosemirrorView.focus();\n }\n\n /**\n * Blur the editor\n */\n public blur() {\n if (this.headless) {\n return;\n }\n this.prosemirrorView.dom.blur();\n }\n\n // TODO move to extension\n public onUploadStart(callback: (blockId?: string) => void) {\n this.onUploadStartCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadStartCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadStartCallbacks.splice(index, 1);\n }\n };\n }\n\n public onUploadEnd(callback: (blockId?: string) => void) {\n this.onUploadEndCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadEndCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadEndCallbacks.splice(index, 1);\n }\n };\n }\n\n /**\n * @deprecated, use `editor.document` instead\n */\n public get topLevelBlocks(): Block<BSchema, ISchema, SSchema>[] {\n return this.document;\n }\n\n /**\n * Gets a snapshot of all top-level (non-nested) blocks in the editor.\n * @returns A snapshot of all top-level (non-nested) blocks in the editor.\n */\n public get document(): Block<BSchema, ISchema, SSchema>[] {\n return this._blockManager.document;\n }\n\n /**\n * Gets a snapshot of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block that should be\n * retrieved.\n * @returns The block that matches the identifier, or `undefined` if no\n * matching block was found.\n */\n public getBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getBlock(blockIdentifier);\n }\n\n /**\n * Gets a snapshot of the previous sibling of an existing block from the\n * editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * previous sibling should be retrieved.\n * @returns The previous sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the first child/block\n * in the document.\n */\n public getPrevBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getPrevBlock(blockIdentifier);\n }\n\n /**\n * Gets a snapshot of the next sibling of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * next sibling should be retrieved.\n * @returns The next sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the last child/block in\n * the document.\n */\n public getNextBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getNextBlock(blockIdentifier);\n }\n\n /**\n * Gets a snapshot of the parent of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * parent should be retrieved.\n * @returns The parent of the block that matches the identifier. `undefined`\n * if no matching block was found, or the block isn't nested.\n */\n public getParentBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getParentBlock(blockIdentifier);\n }\n\n /**\n * Traverses all blocks in the editor depth-first, and executes a callback for each.\n * @param callback The callback to execute for each block. Returning `false` stops the traversal.\n * @param reverse Whether the blocks should be traversed in reverse order.\n */\n public forEachBlock(\n callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,\n reverse = false,\n ): void {\n this._blockManager.forEachBlock(callback, reverse);\n }\n\n /**\n * Executes a callback whenever the editor's contents change.\n * @param callback The callback to execute.\n *\n * @deprecated use {@link BlockNoteEditor.onChange} instead\n */\n public onEditorContentChange(callback: () => void) {\n this._tiptapEditor.on(\"update\", callback);\n }\n\n /**\n * Executes a callback whenever the editor's selection changes.\n * @param callback The callback to execute.\n *\n * @deprecated use `onSelectionChange` instead\n */\n public onEditorSelectionChange(callback: () => void) {\n this._tiptapEditor.on(\"selectionUpdate\", callback);\n }\n\n /**\n * Gets a snapshot of the current text cursor position.\n * @returns A snapshot of the current text cursor position.\n */\n public getTextCursorPosition(): TextCursorPosition<\n BSchema,\n ISchema,\n SSchema\n > {\n return this._selectionManager.getTextCursorPosition();\n }\n\n /**\n * Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could\n * not be found.\n * @param targetBlock The identifier of an existing block that the text cursor should be moved to.\n * @param placement Whether the text cursor should be placed at the start or end of the block.\n */\n public setTextCursorPosition(\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n ) {\n return this._selectionManager.setTextCursorPosition(targetBlock, placement);\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned data will contain the entire block.\n */\n public getSelection(): Selection<BSchema, ISchema, SSchema> | undefined {\n return this._selectionManager.getSelection();\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned block will be\n * only the part of the block that is included in the selection.\n */\n public getSelectionCutBlocks() {\n return this._selectionManager.getSelectionCutBlocks();\n }\n\n /**\n * Sets the selection to a range of blocks.\n * @param startBlock The identifier of the block that should be the start of the selection.\n * @param endBlock The identifier of the block that should be the end of the selection.\n */\n public setSelection(startBlock: BlockIdentifier, endBlock: BlockIdentifier) {\n return this._selectionManager.setSelection(startBlock, endBlock);\n }\n\n /**\n * Checks if the editor is currently editable, or if it's locked.\n * @returns True if the editor is editable, false otherwise.\n */\n public get isEditable(): boolean {\n return this._stateManager.isEditable;\n }\n\n /**\n * Makes the editor editable or locks it, depending on the argument passed.\n * @param editable True to make the editor editable, or false to lock it.\n */\n public set isEditable(editable: boolean) {\n this._stateManager.isEditable = editable;\n }\n\n /**\n * Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an\n * error if the reference block could not be found.\n * @param blocksToInsert An array of partial blocks that should be inserted.\n * @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.\n * @param placement Whether the blocks should be inserted just before, just after, or nested inside the\n * `referenceBlock`.\n */\n public insertBlocks(\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n ) {\n return this._blockManager.insertBlocks(\n blocksToInsert,\n referenceBlock,\n placement,\n );\n }\n\n /**\n * Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be\n * defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could\n * not be found.\n * @param blockToUpdate The block that should be updated.\n * @param update A partial block which defines how the existing block should be changed.\n */\n public updateBlock(\n blockToUpdate: BlockIdentifier,\n update: PartialBlock<BSchema, ISchema, SSchema>,\n ) {\n return this._blockManager.updateBlock(blockToUpdate, update);\n }\n\n /**\n * Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.\n * @param blocksToRemove An array of identifiers for existing blocks that should be removed.\n */\n public removeBlocks(blocksToRemove: BlockIdentifier[]) {\n return this._blockManager.removeBlocks(blocksToRemove);\n }\n\n /**\n * Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or\n * are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in\n * `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.\n * @param blocksToRemove An array of blocks that should be replaced.\n * @param blocksToInsert An array of partial blocks to replace the old ones with.\n */\n public replaceBlocks(\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n ) {\n return this._blockManager.replaceBlocks(blocksToRemove, blocksToInsert);\n }\n\n /**\n * Undo the last action.\n */\n public undo(): boolean {\n return this._stateManager.undo();\n }\n\n /**\n * Redo the last action.\n */\n public redo(): boolean {\n return this._stateManager.redo();\n }\n\n /**\n * Insert a piece of content at the current cursor position.\n *\n * @param content can be a string, or array of partial inline content elements\n */\n public insertInlineContent(\n content: PartialInlineContent<ISchema, SSchema>,\n { updateSelection = false }: { updateSelection?: boolean } = {},\n ) {\n this._styleManager.insertInlineContent(content, { updateSelection });\n }\n\n /**\n * Gets the active text styles at the text cursor position or at the end of the current selection if it's active.\n */\n public getActiveStyles(): Styles<SSchema> {\n return this._styleManager.getActiveStyles();\n }\n\n /**\n * Adds styles to the currently selected content.\n * @param styles The styles to add.\n */\n public addStyles(styles: Styles<SSchema>) {\n this._styleManager.addStyles(styles);\n }\n\n /**\n * Removes styles from the currently selected content.\n * @param styles The styles to remove.\n */\n public removeStyles(styles: Styles<SSchema>) {\n this._styleManager.removeStyles(styles);\n }\n\n /**\n * Toggles styles on the currently selected content.\n * @param styles The styles to toggle.\n */\n public toggleStyles(styles: Styles<SSchema>) {\n this._styleManager.toggleStyles(styles);\n }\n\n /**\n * Gets the currently selected text.\n */\n public getSelectedText() {\n return this._styleManager.getSelectedText();\n }\n\n /**\n * Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.\n */\n public getSelectedLinkUrl() {\n return this._styleManager.getSelectedLinkUrl();\n }\n\n /**\n * Creates a new link to replace the selected content.\n * @param url The link URL.\n * @param text The text to display the link with.\n */\n public createLink(url: string, text?: string) {\n this._styleManager.createLink(url, text);\n }\n\n /**\n * Checks if the block containing the text cursor can be nested.\n */\n public canNestBlock() {\n return this._blockManager.canNestBlock();\n }\n\n /**\n * Nests the block containing the text cursor into the block above it.\n */\n public nestBlock() {\n this._blockManager.nestBlock();\n }\n\n /**\n * Checks if the block containing the text cursor is nested.\n */\n public canUnnestBlock() {\n return this._blockManager.canUnnestBlock();\n }\n\n /**\n * Lifts the block containing the text cursor out of its parent.\n */\n public unnestBlock() {\n this._blockManager.unnestBlock();\n }\n\n /**\n * Moves the selected blocks up. If the previous block has children, moves\n * them to the end of its children. If there is no previous block, but the\n * current blocks share a common parent, moves them out of & before it.\n */\n public moveBlocksUp() {\n return this._blockManager.moveBlocksUp();\n }\n\n /**\n * Moves the selected blocks down. If the next block has children, moves\n * them to the start of its children. If there is no next block, but the\n * current blocks share a common parent, moves them out of & after it.\n */\n public moveBlocksDown() {\n return this._blockManager.moveBlocksDown();\n }\n\n /**\n * Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list\n * items are un-nested in the output HTML.\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToHTMLLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return this._exportManager.blocksToHTMLLossy(blocks);\n }\n\n /**\n * Serializes blocks into an HTML string in the format that would normally be rendered by the editor.\n *\n * Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)\n * and serve it to users without loading the editor on the client (i.e.: displaying the blog post)\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToFullHTML(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return this._exportManager.blocksToFullHTML(blocks);\n }\n\n /**\n * Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and\n * `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote\n * doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.\n * @param html The HTML string to parse blocks from.\n * @returns The blocks parsed from the HTML string.\n */\n public tryParseHTMLToBlocks(\n html: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return this._exportManager.tryParseHTMLToBlocks(html);\n }\n\n /**\n * Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of\n * BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.\n * @param blocks An array of blocks that should be serialized into Markdown.\n * @returns The blocks, serialized as a Markdown string.\n */\n public blocksToMarkdownLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return this._exportManager.blocksToMarkdownLossy(blocks);\n }\n\n /**\n * Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on\n * Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it\n * as text.\n * @param markdown The Markdown string to parse blocks from.\n * @returns The blocks parsed from the Markdown string.\n */\n public tryParseMarkdownToBlocks(\n markdown: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return this._exportManager.tryParseMarkdownToBlocks(markdown);\n }\n\n /**\n * A callback function that runs whenever the editor's contents change.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onChange(\n callback: (\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>,\n context: {\n /**\n * Returns the blocks that were inserted, updated, or deleted by the change that occurred.\n */\n getChanges(): BlocksChanged<BSchema, ISchema, SSchema>;\n },\n ) => void,\n /**\n * If true, the callback will be triggered when the changes are caused by a remote user\n * @default true\n */\n includeUpdatesFromRemote?: boolean,\n ) {\n return this._eventManager.onChange(callback, includeUpdatesFromRemote);\n }\n\n /**\n * A callback function that runs whenever the text cursor position or selection changes.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onSelectionChange(\n callback: (editor: BlockNoteEditor<BSchema, ISchema, SSchema>) => void,\n includeSelectionChangedByRemote?: boolean,\n ) {\n return this._eventManager.onSelectionChange(\n callback,\n includeSelectionChangedByRemote,\n );\n }\n\n /**\n * A callback function that runs when the editor has been mounted.\n *\n * This can be useful for plugins to initialize themselves after the editor has been mounted.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onMount(\n callback: (ctx: {\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>;\n }) => void,\n ) {\n this._eventManager.onMount(callback);\n }\n\n /**\n * A callback function that runs when the editor has been unmounted.\n *\n * This can be useful for plugins to clean up themselves after the editor has been unmounted.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onUnmount(\n callback: (ctx: {\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>;\n }) => void,\n ) {\n this._eventManager.onUnmount(callback);\n }\n\n /**\n * Gets the bounding box of the current selection.\n * @returns The bounding box of the current selection.\n */\n public getSelectionBoundingBox() {\n return this._selectionManager.getSelectionBoundingBox();\n }\n\n public get isEmpty() {\n const doc = this.document;\n // Note: only works for paragraphs as default blocks (but for now this is default in blocknote)\n // checking prosemirror directly might be faster\n return (\n doc.length === 0 ||\n (doc.length === 1 &&\n doc[0].type === \"paragraph\" &&\n (doc[0].content as any).length === 0)\n );\n }\n\n /**\n * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.\n * @param html The HTML to paste.\n * @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.\n */\n public pasteHTML(html: string, raw = false) {\n this._exportManager.pasteHTML(html, raw);\n }\n\n /**\n * Paste text into the editor. Defaults to interpreting text as markdown.\n * @param text The text to paste.\n */\n public pasteText(text: string) {\n return this._exportManager.pasteText(text);\n }\n\n /**\n * Paste markdown into the editor.\n * @param markdown The markdown to paste.\n */\n public pasteMarkdown(markdown: string) {\n return this._exportManager.pasteMarkdown(markdown);\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport { COLORS_DEFAULT } from \"../editor/defaultColors.js\";\nimport {\n BlockFromConfig,\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n StyledText,\n Styles,\n} from \"../schema/index.js\";\n\nimport type {\n BlockMapping,\n InlineContentMapping,\n StyleMapping,\n} from \"./mapping.js\";\n\nexport type ExporterOptions = {\n /**\n * A function that can be used to resolve files, images, etc.\n * Exporters might need the binary contents of files like images,\n * which might not always be available from the same origin as the main page.\n * You can use this option to proxy requests through a server you control\n * to avoid cross-origin (CORS) issues.\n *\n * @default uses a BlockNote hosted proxy (https://corsproxy.api.blocknotejs.org/)\n * @param url - The URL of the file to resolve\n * @returns A Promise that resolves to a string (the URL to use instead of the original)\n * or a Blob (you can return the Blob directly if you have already fetched it)\n */\n resolveFileUrl?: (url: string) => Promise<string | Blob>;\n /**\n * Colors to use for background of blocks, font colors, and highlight colors\n */\n colors: typeof COLORS_DEFAULT;\n};\nexport abstract class Exporter<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n RS,\n TS,\n> {\n public constructor(\n _schema: BlockNoteSchema<B, I, S>, // only used for type inference\n protected readonly mappings: {\n blockMapping: BlockMapping<B, I, S, RB, RI>;\n inlineContentMapping: InlineContentMapping<I, S, RI, TS>;\n styleMapping: StyleMapping<S, RS>;\n },\n public readonly options: ExporterOptions,\n ) {}\n\n public async resolveFile(url: string) {\n if (!this.options?.resolveFileUrl) {\n return (await fetch(url)).blob();\n }\n const ret = await this.options.resolveFileUrl(url);\n if (ret instanceof Blob) {\n return ret;\n }\n return (await fetch(ret)).blob();\n }\n\n public mapStyles(styles: Styles<S>) {\n const stylesArray = Object.entries(styles).map(([key, value]) => {\n const mappedStyle = this.mappings.styleMapping[key](value, this);\n return mappedStyle;\n });\n return stylesArray;\n }\n\n public mapInlineContent(inlineContent: InlineContent<I, S>) {\n return this.mappings.inlineContentMapping[inlineContent.type](\n inlineContent,\n this,\n );\n }\n\n public transformInlineContent(inlineContentArray: InlineContent<I, S>[]) {\n return inlineContentArray.map((ic) => this.mapInlineContent(ic));\n }\n\n public abstract transformStyledText(styledText: StyledText<S>): TS;\n\n public async mapBlock(\n block: BlockFromConfig<B[keyof B], I, S>,\n nestingLevel: number,\n numberedListIndex: number,\n children?: Array<Awaited<RB>>,\n ) {\n return this.mappings.blockMapping[block.type](\n block,\n this,\n nestingLevel,\n numberedListIndex,\n children,\n );\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchema,\n InlineContentFromConfig,\n InlineContentSchema,\n StyleSchema,\n Styles,\n} from \"../schema/index.js\";\nimport type { Exporter } from \"./Exporter.js\";\n\n/**\n * Defines a mapping from all block types with a schema to a result type `R`.\n */\nexport type BlockMapping<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n> = {\n [K in keyof B]: (\n block: BlockFromConfigNoChildren<B[K], I, S>,\n // we don't know the exact types that are supported by the exporter at this point,\n // because the mapping only knows about converting certain types (which might be a subset of the supported types)\n // this is why there are many `any` types here (same for types below)\n exporter: Exporter<any, any, any, RB, RI, any, any>,\n nestingLevel: number,\n numberedListIndex?: number,\n children?: Array<Awaited<RB>>,\n ) => RB | Promise<RB>;\n};\n\n/**\n * Defines a mapping from all inline content types with a schema to a result type R.\n */\nexport type InlineContentMapping<\n I extends InlineContentSchema,\n S extends StyleSchema,\n RI,\n TS,\n> = {\n [K in keyof I]: (\n inlineContent: InlineContentFromConfig<I[K], S>,\n exporter: Exporter<any, I, S, any, RI, any, TS>,\n ) => RI;\n};\n\n/**\n * Defines a mapping from all style types with a schema to a result type R.\n */\nexport type StyleMapping<S extends StyleSchema, RS> = {\n [K in keyof S]: (\n style: Styles<S>[K],\n exporter: Exporter<any, any, any, any, any, RS, any>,\n ) => RS;\n};\n\n/**\n * The mapping factory is a utility function to easily create mappings for\n * a BlockNoteSchema. Using the factory makes it easier to get typescript code completion etc.\n */\nexport function mappingFactory<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(_schema: BlockNoteSchema<B, I, S>) {\n return {\n createBlockMapping: <R, RI>(mapping: BlockMapping<B, I, S, R, RI>) =>\n mapping,\n createInlineContentMapping: <R, RS>(\n mapping: InlineContentMapping<I, S, R, RS>,\n ) => mapping,\n createStyleMapping: <R>(mapping: StyleMapping<S, R>) => mapping,\n };\n}\n","/**\n * Combines items by group. This can be used to combine multiple slash menu item arrays,\n * while making sure that items from the same group are adjacent to each other.\n */\nexport function combineByGroup<T extends { group?: string }>(\n items: T[],\n ...additionalItemsArray: {\n group?: string;\n }[][]\n) {\n const combinedItems = [...items];\n for (const additionalItems of additionalItemsArray) {\n for (const additionalItem of additionalItems) {\n const lastItemWithSameGroup = combinedItems.findLastIndex(\n (item) => item.group === additionalItem.group,\n );\n if (lastItemWithSameGroup === -1) {\n combinedItems.push(additionalItem as T);\n } else {\n combinedItems.splice(lastItemWithSameGroup + 1, 0, additionalItem as T);\n }\n }\n }\n return combinedItems;\n}\n"],"names":["getInlineContentParseRules","config","customParseFunction","rules","element","htmlElement","node","props","createInlineContentSpec","inlineContentConfig","inlineContentImplementation","Node","_a","propsToAttributes","addInlineContentKeyboardShortcuts","editor","output","nodeToCustomInlineContent","addInlineContentAttributes","getPos","update","content","inlineContentToNodes","pos","tr","createInlineContentSpecFromTipTapNode","inlineContent","updateInlineContent","insertBlocks","blocksToInsert","referenceBlock","placement","id","pmSchema","getPmSchema","nodesToInsert","block","blockToNode","posInfo","getNodeById","ReplaceStep","Slice","Fragment","nodeToBlock","isEmptyColumn","column","blockContainer","blockContent","removeEmptyColumns","columnListPos","$columnListPos","columnList","columnIndex","columnPos","fixColumnList","firstColumnBeforePos","firstColumn","lastColumnAfterPos","lastColumn","firstColumnEmpty","lastColumnEmpty","ReplaceAroundStep","removeAndInsertBlocks","blocksToRemove","idsOfBlocksToRemove","removedBlocks","columnListPositions","idOfFirstBlock","removedSize","oldDocSize","newDocSize","$pos","notFoundIds","serializeInlineContentInternalHTML","serializer","blockType","options","nodes","tableContentToNodes","UnreachableCaseError","fragment","contentFragment","dom","mark","newDom","domOutputSpec","DOMSerializer","nodeFragment","serializeBlock","BC_NODE","name","spec","children","ret","ic","serializeBlocks","bc","_c","_b","_d","_e","serializeBlocksInternalHTML","blocks","blockDOM","BG_NODE","bg","createInternalHTMLSerializer","schema","getBlockSelectionData","anchorBlockPosInfo","getNearestBlockPos","CellSelection","NodeSelection","headBlockPosInfo","updateBlockSelectionFromData","data","anchorBlockPos","selection","headBlockPos","TextSelection","flattenColumns","moveSelectedBlocksAndSelection","selectionData","checkPlacementIsValid","parentBlock","getMoveUpPlacement","prevBlock","referenceBlockParent","getMoveDownPlacement","nextBlock","moveBlocksUp","moveUpPlacement","moveBlocksDown","moveDownPlacement","sinkListItem","itemType","groupType","$from","$to","range","startIndex","nodeBefore","nestedBefore","inner","slice","before","after","nestBlock","unnestBlock","canNestBlock","getBlockInfoFromTransaction","canUnnestBlock","getBlock","doc","blockIdentifier","getPrevBlock","nodeToConvert","getNextBlock","getParentBlock","$posBeforeNode","parentNode","grandparentNode","BlockManager","docToBlocks","callback","reverse","traverseBlockArray","blockArray","blockToUpdate","updateBlock","EventManager","EventEmitter","transaction","appendedTransactions","includeUpdatesFromRemote","cb","isRemoteTransaction","getBlocksChangedByTransaction","includeSelectionChangedByRemote","e","getChildIndex","isWhitespaceNode","liftNestedListsToParent","list","index","parentListItem","siblingsAfter","sibling","siblingContainer","createGroups","listItem","blockGroup","_detachedDoc","detachedDoc","nestedListsToBlockNoteStructure","elementOrHTML","HTMLToBlocks","html","htmlNode","DOMParser","i","code","state","value","properties","result","video","url","title","markdownToHTML","markdown","unified","remarkParse","remarkGfm","remarkRehype","remarkRehypeDefaultHandlers","isVideoUrl","rehypeStringify","markdownToBlocks","htmlString","ExportManager","createExternalHTMLExporter","blocksToMarkdown","raw","htmlToPaste","text","acceptedMIMETypes","checkFileExtensionsMatch","fileExtension1","fileExtension2","checkMIMETypesMatch","mimeType1","mimeType2","types1","types2","insertOrUpdateBlock","newBlock","insertedBlockId","handleFileInsertion","event","dataTransfer","format","mimeType","items","fileBlockType","blockSpec","isFileExtension","file","fileBlock","currentBlock","coords","blockElement","blockRect","updateData","updatedFileBlock","createDropFileExtension","Extension","Plugin","_view","h1","bold","link","ul","ol","hr","fences","blockquote","tableHeader","tableDivider","tableRow","isMarkdown","src","handleVSCodePaste","view","vscode","vscodeData","language","defaultPasteHandler","prioritizeMarkdownOverHTML","plainTextAsMarkdown","plainText","createPasteFromClipboardExtension","pasteHandler","fragmentToExternalHTML","selectedFragment","isWithinBlockContent","isWithinTable","fragmentWithoutParents","child","externalHTML","externalHTMLExporter","contentNodeToTableContent","contentNodeToInlineContent","fragmentToBlocks","selectedFragmentToHTML","clipboardHTML","cleanHTMLToMarkdown","checkIfSelectionInNonEditableBlock","copyToClipboard","createCopyToClipboardExtension","BackgroundColorExtension","getBackgroundColorAttribute","HardBreak","HTMLAttributes","mergeAttributes","getPrevBlockInfo","beforePos","indexInParent","prevBlockBeforePos","getBlockInfoFromResolvedPos","getBottomNestedBlockInfo","blockInfo","group","newPos","canMerge","prevBlockInfo","nextBlockInfo","mergeBlocks","dispatch","childBlocksStart","childBlocksEnd","childBlocksRange","mergeBlocksCommand","posBetweenBlocks","bottomNestedBlockInfo","KeyboardShortcutsExtension","handleBackspace","chain","commands","getBlockInfoFromSelection","selectionAtBlockStart","isParagraph","updateBlockCommand","selectionEmpty","$blockPos","$columnPos","chainedCommands","lastCellParagraphEndPos","nonEditableBlockContentStartPos","blockContentStartPos","bottomBlock","handleDelete","childContainer","depth","blockAtDocEnd","selectionAtBlockEnd","oldDepth","newDepth","handleEnter","withShift","blockEmpty","blockIndented","blockHardBreakShortcut","marks","m","newBlockInsertionPos","newBlockContentPos","splitBlockCommand","FormattingToolbarExtension","FilePanelExtension","SuggestionAddMark","Mark","extension","inline","SuggestionDeleteMark","SuggestionModificationMark","TextAlignmentExtension","attributes","TextColorExtension","getTextColorAttribute","BlockAttributes","BlockContainer","attrs","nodeAttr","HTMLAttr","blockOuter","attribute","blockHTMLAttributes","mergeCSSClasses","BlockGroup","blockGroupHTMLAttributes","Doc","LINKIFY_INITIALIZED","getDefaultTiptapExtensions","tiptapExtensions","extensions","Gapcursor","UniqueID","Text","Link","DEFAULT_LINK_PROTOCOL","VALID_LINK_PROTOCOLS","styleSpec","TiptapExtension","SuggestionMenu","a","inlineContentSpec","context","getDefaultExtensions","BlockChangeExtension","DropCursorExtension","LinkToolbarExtension","NodeSelectionKeyboardExtension","PlaceholderExtension","ShowSelectionExtension","SideMenuExtension","TrailingNodeExtension","ForkYDocExtension","YCursorExtension","YSyncExtension","YUndoExtension","SchemaMigration","HistoryExtension","TableHandlesExtension","PreviousBlockTypeExtension","ExtensionManager","__publicField","abortController","unmountCallback","registeredExtensions","pluginsToAdd","plugin","plugins","instance","originalFactory","originalFactorySymbol","toResolve","toUnregister","didWarn","pluginsToRemove","factory","currentState","getPriority","sortByDependencies","inputRulesByPriority","priority","prosemirrorPlugins","inputRules","inputRulesPlugin","inputRule","InputRule","match","start","end","replaceWith","cursorPosition","updateBlockTr","keymap","key","getSelection","$startBlockBeforePos","$endBlockBeforePos","indexToBlock","sharedDepth","endIndex","startIndexAtDepth","childCountAtDepth","setSelection","startBlock","endBlock","startBlockId","endBlockId","getBlockNoteSchema","anchorPosInfo","headPosInfo","anchorBlockInfo","getBlockInfo","headBlockInfo","anchorBlockConfig","headBlockConfig","startPos","endPos","tableMap","TableMap","lastCellPos","lastCellNodeSize","getSelectionCutBlocks","selectionInfo","prosemirrorSliceToSlicedBlocks","getTextCursorPosition","bnBlock","resolvedPos","prevNode","nextNode","setTextCursorPosition","targetBlock","info","contentType","SelectionManager","ranges","from","to","isNodeSelection","posToDOMRect","StateManager","command","activeTr","editable","undoPlugin","historyPlugin","insertContentAt","position","isOnlyTextContent","isOnlyBlockContent","parent","selectionToInsertionEnd","StyleManager","updateSelection","styles","style","removeChild","n","_","wrapTableRows","f","newItems","prevTable","newTable","transformPasted","shouldApplyFix","nestedChild","container","nodeHasSingleChild","nodeHasInlineContent","nodeHasTableContent","blockNoteTipTapOptions","BlockNoteEditor","args","en","newOptions","BlockNoteSchema","uploadFile","blockId","collaborationEnabled","tiptapOptions","_g","_f","_h","_j","_i","initialContent","getSchema","pmNodes","b","createDocument","TiptapEditor","cache","oldCreateAndFill","jsonNode","Exporter","_schema","mappings","inlineContentArray","nestingLevel","numberedListIndex","mappingFactory","mapping","combineByGroup","additionalItemsArray","combinedItems","additionalItems","additionalItem","lastItemWithSameGroup","item"],"mappings":"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"}
1
+ {"version":3,"file":"blocknote.cjs","sources":["../src/schema/inlineContent/createSpec.ts","../src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts","../src/api/blockManipulation/commands/replaceBlocks/util/fixColumnList.ts","../src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts","../src/api/exporters/html/util/serializeBlocksInternalHTML.ts","../src/api/exporters/html/internalHTMLSerializer.ts","../src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts","../src/api/blockManipulation/commands/nestBlock/nestBlock.ts","../src/api/blockManipulation/getBlock/getBlock.ts","../src/editor/managers/BlockManager.ts","../src/editor/managers/EventManager.ts","../src/api/parsers/html/util/nestedLists.ts","../src/api/parsers/html/parseHTML.ts","../src/api/parsers/markdown/parseMarkdown.ts","../src/editor/managers/ExportManager.ts","../src/api/clipboard/fromClipboard/acceptedMIMETypes.ts","../src/api/clipboard/fromClipboard/handleFileInsertion.ts","../src/api/clipboard/fromClipboard/fileDropExtension.ts","../src/api/parsers/markdown/detectMarkdown.ts","../src/api/clipboard/fromClipboard/handleVSCodePaste.ts","../src/api/clipboard/fromClipboard/pasteExtension.ts","../src/api/clipboard/toClipboard/copyExtension.ts","../src/extensions/tiptap-extensions/BackgroundColor/BackgroundColorExtension.ts","../src/extensions/tiptap-extensions/HardBreak/HardBreak.ts","../src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts","../src/extensions/tiptap-extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts","../src/extensions/tiptap-extensions/Suggestions/SuggestionMarks.ts","../src/extensions/tiptap-extensions/TextAlignment/TextAlignmentExtension.ts","../src/extensions/tiptap-extensions/TextColor/TextColorExtension.ts","../src/pm-nodes/BlockContainer.ts","../src/pm-nodes/BlockGroup.ts","../src/pm-nodes/Doc.ts","../src/editor/managers/ExtensionManager/extensions.ts","../src/editor/managers/ExtensionManager/index.ts","../src/api/blockManipulation/selections/selection.ts","../src/api/blockManipulation/selections/textCursorPosition.ts","../src/editor/managers/SelectionManager.ts","../src/editor/managers/StateManager.ts","../src/api/blockManipulation/insertContentAt.ts","../src/editor/managers/StyleManager.ts","../src/editor/transformPasted.ts","../src/editor/BlockNoteEditor.ts","../src/exporter/Exporter.ts","../src/exporter/mapping.ts","../src/util/combineByGroup.ts"],"sourcesContent":["import { Node } from \"@tiptap/core\";\n\nimport { TagParseRule } from \"@tiptap/pm/model\";\nimport { inlineContentToNodes } from \"../../api/nodeConversions/blockToNode.js\";\nimport { nodeToCustomInlineContent } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { propsToAttributes } from \"../blocks/internal.js\";\nimport { Props } from \"../propTypes.js\";\nimport { StyleSchema } from \"../styles/types.js\";\nimport {\n addInlineContentAttributes,\n addInlineContentKeyboardShortcuts,\n createInlineContentSpecFromTipTapNode,\n} from \"./internal.js\";\nimport {\n CustomInlineContentConfig,\n InlineContentFromConfig,\n InlineContentSpec,\n PartialCustomInlineContentFromConfig,\n} from \"./types.js\";\n\nexport type CustomInlineContentImplementation<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n> = {\n meta?: {\n draggable?: boolean;\n };\n\n /**\n * Parses an external HTML element into a inline content of this type when it returns the block props object, otherwise undefined\n */\n parse?: (el: HTMLElement) => Partial<Props<T[\"propSchema\"]>> | undefined;\n\n /**\n * Renders an inline content to DOM elements\n */\n render: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * A callback that allows overriding the inline content element\n */\n updateInlineContent: (\n update: PartialCustomInlineContentFromConfig<T, S>,\n ) => void,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n // (note) if we want to fix the manual cast, we need to prevent circular references and separate block definition and render implementations\n // or allow manually passing <BSchema>, but that's not possible without passing the other generics because Typescript doesn't support partial inferred generics\n ) => {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n destroy?: () => void;\n };\n\n /**\n * Renders an inline content to external HTML elements for use outside the editor\n * If not provided, falls back to the render method\n */\n toExternalHTML?: (\n /**\n * The custom inline content to render\n */\n inlineContent: InlineContentFromConfig<T, S>,\n /**\n * The BlockNote editor instance\n * This is typed generically. If you want an editor with your custom schema, you need to\n * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`\n */\n editor: BlockNoteEditor<any, any, S>,\n ) =>\n | {\n dom: HTMLElement | DocumentFragment;\n contentDOM?: HTMLElement;\n }\n | undefined;\n\n runsBefore?: string[];\n};\n\nexport function getInlineContentParseRules<C extends CustomInlineContentConfig>(\n config: C,\n customParseFunction?: CustomInlineContentImplementation<C, any>[\"parse\"],\n) {\n const rules: TagParseRule[] = [\n {\n tag: `[data-inline-content-type=\"${config.type}\"]`,\n contentElement: (element) => {\n const htmlElement = element as HTMLElement;\n\n if (htmlElement.matches(\"[data-editable]\")) {\n return htmlElement;\n }\n\n return htmlElement.querySelector(\"[data-editable]\") || htmlElement;\n },\n },\n ];\n\n if (customParseFunction) {\n rules.push({\n tag: \"*\",\n getAttrs(node: string | HTMLElement) {\n if (typeof node === \"string\") {\n return false;\n }\n\n const props = customParseFunction?.(node);\n\n if (props === undefined) {\n return false;\n }\n\n return props;\n },\n });\n }\n return rules;\n}\n\nexport function createInlineContentSpec<\n T extends CustomInlineContentConfig,\n S extends StyleSchema,\n>(\n inlineContentConfig: T,\n inlineContentImplementation: CustomInlineContentImplementation<T, S>,\n): InlineContentSpec<T> {\n const node = Node.create({\n name: inlineContentConfig.type,\n inline: true,\n group: \"inline\",\n draggable: inlineContentImplementation.meta?.draggable,\n selectable: inlineContentConfig.content === \"styled\",\n atom: inlineContentConfig.content === \"none\",\n content: inlineContentConfig.content === \"styled\" ? \"inline*\" : \"\",\n\n addAttributes() {\n return propsToAttributes(inlineContentConfig.propSchema);\n },\n\n addKeyboardShortcuts() {\n return addInlineContentKeyboardShortcuts(inlineContentConfig);\n },\n\n parseHTML() {\n return getInlineContentParseRules(\n inlineContentConfig,\n inlineContentImplementation.parse,\n );\n },\n\n renderHTML({ node }) {\n const editor = this.options.editor;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"dom\", props: undefined },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n () => {\n // No-op\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n },\n\n addNodeView() {\n return (props) => {\n const { node, getPos } = props;\n const editor = this.options.editor as BlockNoteEditor<any, any, S>;\n\n const output = inlineContentImplementation.render.call(\n { renderType: \"nodeView\", props },\n nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast\n (update) => {\n const content = inlineContentToNodes([update], editor.pmSchema);\n\n const pos = getPos();\n\n if (!pos) {\n return;\n }\n\n editor.transact((tr) =>\n tr.replaceWith(pos, pos + node.nodeSize, content),\n );\n },\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n node.attrs as Props<T[\"propSchema\"]>,\n inlineContentConfig.propSchema,\n );\n };\n },\n });\n\n return createInlineContentSpecFromTipTapNode(\n node,\n inlineContentConfig.propSchema,\n {\n ...inlineContentImplementation,\n toExternalHTML: inlineContentImplementation.toExternalHTML,\n render(inlineContent, updateInlineContent, editor) {\n const output = inlineContentImplementation.render(\n inlineContent,\n updateInlineContent,\n editor,\n );\n\n return addInlineContentAttributes(\n output,\n inlineContentConfig.type,\n inlineContent.props,\n inlineContentConfig.propSchema,\n );\n },\n },\n ) as InlineContentSpec<T>;\n}\n","import { Fragment, Slice } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport { ReplaceStep } from \"prosemirror-transform\";\nimport { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\n\nexport function insertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n): Block<BSchema, I, S>[] {\n const id =\n typeof referenceBlock === \"string\" ? referenceBlock : referenceBlock.id;\n const pmSchema = getPmSchema(tr);\n const nodesToInsert = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n let pos = posInfo.posBeforeNode;\n if (placement === \"after\") {\n pos += posInfo.node.nodeSize;\n }\n\n tr.step(\n new ReplaceStep(pos, pos, new Slice(Fragment.from(nodesToInsert), 0, 0)),\n );\n\n // Now that the `PartialBlock`s have been converted to nodes, we can\n // re-convert them into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return insertedBlocks;\n}\n","import { Slice, type Node } from \"prosemirror-model\";\nimport { type Transaction } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\n\n/**\n * Checks if a `column` node is empty, i.e. if it has only a single empty\n * paragraph.\n * @param column The column to check.\n * @returns Whether the column is empty.\n */\nexport function isEmptyColumn(column: Node) {\n if (!column || column.type.name !== \"column\") {\n throw new Error(\"Invalid columnPos: does not point to column node.\");\n }\n\n const blockContainer = column.firstChild;\n if (!blockContainer) {\n throw new Error(\"Invalid column: does not have child node.\");\n }\n\n const blockContent = blockContainer.firstChild;\n if (!blockContent) {\n throw new Error(\"Invalid blockContainer: does not have child node.\");\n }\n\n return (\n column.childCount === 1 &&\n blockContainer.childCount === 1 &&\n blockContent.type.name === \"paragraph\" &&\n blockContent.content.content.length === 0\n );\n}\n\n/**\n * Removes all empty `column` nodes in a `columnList`. A `column` node is empty\n * if it has only a single empty block. If, however, removing the `column`s\n * leaves the `columnList` that has fewer than two, ProseMirror will re-add\n * empty columns.\n * @param tr The `Transaction` to add the changes to.\n * @param columnListPos The position just before the `columnList` node.\n */\nexport function removeEmptyColumns(tr: Transaction, columnListPos: number) {\n const $columnListPos = tr.doc.resolve(columnListPos);\n const columnList = $columnListPos.nodeAfter;\n if (!columnList || columnList.type.name !== \"columnList\") {\n throw new Error(\n \"Invalid columnListPos: does not point to columnList node.\",\n );\n }\n\n for (\n let columnIndex = columnList.childCount - 1;\n columnIndex >= 0;\n columnIndex--\n ) {\n const columnPos = tr.doc\n .resolve($columnListPos.pos + 1)\n .posAtIndex(columnIndex);\n const $columnPos = tr.doc.resolve(columnPos);\n const column = $columnPos.nodeAfter;\n if (!column || column.type.name !== \"column\") {\n throw new Error(\"Invalid columnPos: does not point to column node.\");\n }\n\n if (isEmptyColumn(column)) {\n tr.delete(columnPos, columnPos + column.nodeSize);\n }\n }\n}\n\n/**\n * Fixes potential issues in a `columnList` node after a\n * `blockContainer`/`column` node is (re)moved from it:\n *\n * - Removes all empty `column` nodes. A `column` node is empty if it has only\n * a single empty block.\n * - If all but one `column` nodes are empty, replaces the `columnList` with\n * the content of the non-empty `column`.\n * - If all `column` nodes are empty, removes the `columnList` entirely.\n * @param tr The `Transaction` to add the changes to.\n * @param columnListPos\n * @returns The position just before the `columnList` node.\n */\nexport function fixColumnList(tr: Transaction, columnListPos: number) {\n removeEmptyColumns(tr, columnListPos);\n\n const $columnListPos = tr.doc.resolve(columnListPos);\n const columnList = $columnListPos.nodeAfter;\n if (!columnList || columnList.type.name !== \"columnList\") {\n throw new Error(\n \"Invalid columnListPos: does not point to columnList node.\",\n );\n }\n\n if (columnList.childCount > 2) {\n // Do nothing if the `columnList` has more than two non-empty `column`s. In\n // the case that the `columnList` has exactly two columns, we may need to\n // still remove it, as it's possible that one or both columns are empty.\n // This is because after `removeEmptyColumns` is called, if the\n // `columnList` has fewer than two `column`s, ProseMirror will re-add empty\n // `column`s until there are two total, in order to fit the schema.\n return;\n }\n\n if (columnList.childCount < 2) {\n // Throw an error if the `columnList` has fewer than two columns. After\n // `removeEmptyColumns` is called, if the `columnList` has fewer than two\n // `column`s, ProseMirror will re-add empty `column`s until there are two\n // total, in order to fit the schema. So if there are fewer than two here,\n // either the schema, or ProseMirror's internals, must have changed.\n throw new Error(\"Invalid columnList: contains fewer than two children.\");\n }\n\n const firstColumnBeforePos = columnListPos + 1;\n const $firstColumnBeforePos = tr.doc.resolve(firstColumnBeforePos);\n const firstColumn = $firstColumnBeforePos.nodeAfter;\n\n const lastColumnAfterPos = columnListPos + columnList.nodeSize - 1;\n const $lastColumnAfterPos = tr.doc.resolve(lastColumnAfterPos);\n const lastColumn = $lastColumnAfterPos.nodeBefore;\n\n if (!firstColumn || !lastColumn) {\n throw new Error(\"Invalid columnList: does not contain children.\");\n }\n\n const firstColumnEmpty = isEmptyColumn(firstColumn);\n const lastColumnEmpty = isEmptyColumn(lastColumn);\n\n if (firstColumnEmpty && lastColumnEmpty) {\n // Removes `columnList`\n tr.delete(columnListPos, columnListPos + columnList.nodeSize);\n\n return;\n }\n\n if (firstColumnEmpty) {\n tr.step(\n new ReplaceAroundStep(\n // Replaces `columnList`.\n columnListPos,\n columnListPos + columnList.nodeSize,\n // Replaces with content of last `column`.\n lastColumnAfterPos - lastColumn.nodeSize + 1,\n lastColumnAfterPos - 1,\n // Doesn't append anything.\n Slice.empty,\n 0,\n false,\n ),\n );\n\n return;\n }\n\n if (lastColumnEmpty) {\n tr.step(\n new ReplaceAroundStep(\n // Replaces `columnList`.\n columnListPos,\n columnListPos + columnList.nodeSize,\n // Replaces with content of first `column`.\n firstColumnBeforePos + 1,\n firstColumnBeforePos + firstColumn.nodeSize - 1,\n // Doesn't append anything.\n Slice.empty,\n 0,\n false,\n ),\n );\n\n return;\n }\n}\n","import { type Node } from \"prosemirror-model\";\nimport { type Transaction } from \"prosemirror-state\";\nimport type { Block, PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { blockToNode } from \"../../../nodeConversions/blockToNode.js\";\nimport { nodeToBlock } from \"../../../nodeConversions/nodeToBlock.js\";\nimport { getPmSchema } from \"../../../pmUtil.js\";\nimport { fixColumnList } from \"./util/fixColumnList.js\";\n\nexport function removeAndInsertBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n tr: Transaction,\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, I, S>[],\n): {\n insertedBlocks: Block<BSchema, I, S>[];\n removedBlocks: Block<BSchema, I, S>[];\n} {\n const pmSchema = getPmSchema(tr);\n // Converts the `PartialBlock`s to ProseMirror nodes to insert them into the\n // document.\n const nodesToInsert: Node[] = blocksToInsert.map((block) =>\n blockToNode(block, pmSchema),\n );\n\n const idsOfBlocksToRemove = new Set<string>(\n blocksToRemove.map((block) =>\n typeof block === \"string\" ? block : block.id,\n ),\n );\n const removedBlocks: Block<BSchema, I, S>[] = [];\n const columnListPositions = new Set<number>();\n\n const idOfFirstBlock =\n typeof blocksToRemove[0] === \"string\"\n ? blocksToRemove[0]\n : blocksToRemove[0].id;\n let removedSize = 0;\n\n tr.doc.descendants((node, pos) => {\n // Skips traversing nodes after all target blocks have been removed.\n if (idsOfBlocksToRemove.size === 0) {\n return false;\n }\n\n // Keeps traversing nodes if block with target ID has not been found.\n if (\n !node.type.isInGroup(\"bnBlock\") ||\n !idsOfBlocksToRemove.has(node.attrs.id)\n ) {\n return true;\n }\n\n // Saves the block that is being deleted.\n removedBlocks.push(nodeToBlock(node, pmSchema));\n idsOfBlocksToRemove.delete(node.attrs.id);\n\n if (blocksToInsert.length > 0 && node.attrs.id === idOfFirstBlock) {\n const oldDocSize = tr.doc.nodeSize;\n tr.insert(pos, nodesToInsert);\n const newDocSize = tr.doc.nodeSize;\n\n removedSize += oldDocSize - newDocSize;\n }\n\n const oldDocSize = tr.doc.nodeSize;\n\n const $pos = tr.doc.resolve(pos - removedSize);\n\n if ($pos.node().type.name === \"column\") {\n columnListPositions.add($pos.before(-1));\n } else if ($pos.node().type.name === \"columnList\") {\n columnListPositions.add($pos.before());\n }\n\n if (\n $pos.node().type.name === \"blockGroup\" &&\n $pos.node($pos.depth - 1).type.name !== \"doc\" &&\n $pos.node().childCount === 1\n ) {\n // Checks if the block is the only child of a parent `blockGroup` node.\n // In this case, we need to delete the parent `blockGroup` node instead\n // of just the `blockContainer`.\n tr.delete($pos.before(), $pos.after());\n } else {\n tr.delete(pos - removedSize, pos - removedSize + node.nodeSize);\n }\n\n const newDocSize = tr.doc.nodeSize;\n removedSize += oldDocSize - newDocSize;\n\n return false;\n });\n\n // Throws an error if not all blocks could be found.\n if (idsOfBlocksToRemove.size > 0) {\n const notFoundIds = [...idsOfBlocksToRemove].join(\"\\n\");\n\n throw Error(\n \"Blocks with the following IDs could not be found in the editor: \" +\n notFoundIds,\n );\n }\n\n columnListPositions.forEach((pos) => fixColumnList(tr, pos));\n\n // Converts the nodes created from `blocksToInsert` into full `Block`s.\n const insertedBlocks = nodesToInsert.map((node) =>\n nodeToBlock(node, pmSchema),\n ) as Block<BSchema, I, S>[];\n\n return { insertedBlocks, removedBlocks };\n}\n","import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../../util/typescript.js\";\nimport {\n inlineContentToNodes,\n tableContentToNodes,\n} from \"../../../nodeConversions/blockToNode.js\";\n\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\nexport function serializeInlineContentInternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<any, I, S>,\n blockContent: PartialBlock<BSchema, I, S>[\"content\"],\n serializer: DOMSerializer,\n blockType?: string,\n options?: { document?: Document },\n) {\n let nodes: Node[];\n\n // TODO: reuse function from nodeconversions?\n if (!blockContent) {\n throw new Error(\"blockContent is required\");\n } else if (typeof blockContent === \"string\") {\n nodes = inlineContentToNodes([blockContent], editor.pmSchema, blockType);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema, blockType);\n } else if (blockContent.type === \"tableContent\") {\n nodes = tableContentToNodes(blockContent, editor.pmSchema);\n } else {\n throw new UnreachableCaseError(blockContent.type);\n }\n\n // Check if any of the nodes are custom inline content with toExternalHTML\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const node of nodes) {\n // Check if this is a custom inline content node with toExternalHTML\n if (\n node.type.name !== \"text\" &&\n editor.schema.inlineContentSchema[node.type.name]\n ) {\n const inlineContentImplementation =\n editor.schema.inlineContentSpecs[node.type.name].implementation;\n\n if (inlineContentImplementation) {\n // Convert the node to inline content format\n const inlineContent = nodeToCustomInlineContent(\n node,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Use the custom toExternalHTML method\n const output = inlineContentImplementation.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n inlineContent as any,\n () => {\n // No-op\n },\n editor as any,\n );\n\n if (output) {\n fragment.appendChild(output.dom);\n\n // If contentDOM exists, render the inline content into it\n if (output.contentDOM) {\n const contentFragment = serializer.serializeFragment(\n node.content,\n options,\n );\n output.contentDOM.dataset.editable = \"\";\n output.contentDOM.appendChild(contentFragment);\n }\n continue;\n }\n }\n } else if (node.type.name === \"text\") {\n // We serialize text nodes manually as we need to serialize the styles/\n // marks using `styleSpec.implementation.render`. When left up to\n // ProseMirror, it'll use `toDOM` which is incorrect.\n let dom: globalThis.Node | Text = document.createTextNode(\n node.textContent,\n );\n // Reverse the order of marks to maintain the correct priority.\n for (const mark of node.marks.toReversed()) {\n if (mark.type.name in editor.schema.styleSpecs) {\n const newDom = editor.schema.styleSpecs[\n mark.type.name\n ].implementation.render(mark.attrs[\"stringValue\"], editor);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n } else {\n const domOutputSpec = mark.type.spec.toDOM!(mark, true);\n const newDom = DOMSerializer.renderSpec(document, domOutputSpec);\n newDom.contentDOM!.appendChild(dom);\n dom = newDom.dom;\n }\n }\n\n fragment.appendChild(dom);\n } else {\n // Fall back to default serialization for this node\n const nodeFragment = serializer.serializeFragment(\n Fragment.from([node]),\n options,\n );\n fragment.appendChild(nodeFragment);\n }\n }\n\n return fragment;\n}\n\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const BC_NODE = editor.pmSchema.nodes[\"blockContainer\"];\n\n // set default props in case we were passed a partial block\n const props = block.props || {};\n for (const [name, spec] of Object.entries(\n editor.schema.blockSchema[block.type as any].propSchema,\n )) {\n if (!(name in props) && spec.default !== undefined) {\n (props as any)[name] = spec.default;\n }\n }\n const children = block.children || [];\n\n const impl = editor.blockImplementations[block.type as any].implementation;\n const ret = impl.render.call(\n {\n renderType: \"dom\",\n props: undefined,\n },\n { ...block, props, children } as any,\n editor as any,\n );\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentInternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n block.type,\n options,\n );\n ret.contentDOM.appendChild(ic);\n }\n\n const pmType = editor.pmSchema.nodes[block.type as any];\n\n if (pmType.isInGroup(\"bnBlock\")) {\n if (block.children && block.children.length > 0) {\n const fragment = serializeBlocks(\n editor,\n block.children,\n serializer,\n options,\n );\n\n ret.contentDOM?.append(fragment);\n }\n return ret.dom;\n }\n\n // wrap the block in a blockContainer\n const bc = BC_NODE.spec?.toDOM?.(\n BC_NODE.create({\n id: block.id,\n ...props,\n }),\n ) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n bc.contentDOM?.appendChild(ret.dom);\n\n if (block.children && block.children.length > 0) {\n bc.contentDOM?.appendChild(\n serializeBlocksInternalHTML(editor, block.children, serializer, options),\n );\n }\n return bc.dom;\n}\n\nfunction serializeBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n for (const block of blocks) {\n const blockDOM = serializeBlock(editor, block, serializer, options);\n fragment.appendChild(blockDOM);\n }\n\n return fragment;\n}\n\nexport const serializeBlocksInternalHTML = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n options?: { document?: Document },\n) => {\n const BG_NODE = editor.pmSchema.nodes[\"blockGroup\"];\n\n const bg = BG_NODE.spec!.toDOM!(BG_NODE.create({})) as {\n dom: HTMLElement;\n contentDOM?: HTMLElement;\n };\n\n const fragment = serializeBlocks(editor, blocks, serializer, options);\n\n bg.contentDOM?.appendChild(fragment);\n\n return bg.dom;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { serializeBlocksInternalHTML } from \"./util/serializeBlocksInternalHTML.js\";\n// Used to serialize BlockNote blocks and ProseMirror nodes to HTML without\n// losing data. Blocks are exported using the `toInternalHTML` method in their\n// `blockSpec`.\n//\n// The HTML created by this serializer is the same as what's rendered by the\n// editor to the DOM. This means that it retains the same structure as the\n// editor, including the `blockGroup` and `blockContainer` wrappers. This also\n// means that it can be converted back to the original blocks without any data\n// loss.\nexport const createInternalHTMLSerializer = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n) => {\n const serializer = DOMSerializer.fromSchema(schema);\n\n return {\n serializeBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n return serializeBlocksInternalHTML(editor, blocks, serializer, options)\n .outerHTML;\n },\n };\n};\n","import {\n NodeSelection,\n Selection,\n TextSelection,\n Transaction,\n} from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor\";\nimport { BlockIdentifier } from \"../../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../../getBlockInfoFromPos.js\";\nimport { getNodeById } from \"../../../nodeUtil.js\";\n\ntype BlockSelectionData = (\n | {\n type: \"text\";\n headBlockId: string;\n anchorOffset: number;\n headOffset: number;\n }\n | {\n type: \"node\";\n }\n | {\n type: \"cell\";\n anchorCellOffset: number;\n headCellOffset: number;\n }\n) & {\n anchorBlockId: string;\n};\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param editor The BlockNote editor instance to get the selection data from.\n */\nfunction getBlockSelectionData(\n editor: BlockNoteEditor<any, any, any>,\n): BlockSelectionData {\n return editor.transact((tr) => {\n const anchorBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.anchor);\n\n if (tr.selection instanceof CellSelection) {\n return {\n type: \"cell\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n anchorCellOffset:\n tr.selection.$anchorCell.pos - anchorBlockPosInfo.posBeforeNode,\n headCellOffset:\n tr.selection.$headCell.pos - anchorBlockPosInfo.posBeforeNode,\n };\n } else if (tr.selection instanceof NodeSelection) {\n return {\n type: \"node\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n };\n } else {\n const headBlockPosInfo = getNearestBlockPos(tr.doc, tr.selection.head);\n\n return {\n type: \"text\" as const,\n anchorBlockId: anchorBlockPosInfo.node.attrs.id,\n headBlockId: headBlockPosInfo.node.attrs.id,\n anchorOffset: tr.selection.anchor - anchorBlockPosInfo.posBeforeNode,\n headOffset: tr.selection.head - headBlockPosInfo.posBeforeNode,\n };\n }\n });\n}\n\n/**\n * `getBlockSelectionData` and `updateBlockSelectionFromData` are used to save\n * and restore the selection within a block, when the block is moved. This is\n * done by first saving the offsets of the anchor and head from the before\n * positions of their surrounding blocks, as well as the IDs of those blocks. We\n * can then recreate the selection by finding the blocks with those IDs, getting\n * their before positions, and adding the offsets to those positions.\n * @param tr The transaction to update the selection in.\n * @param data The selection data to update the selection with (generated by\n * `getBlockSelectionData`).\n */\nfunction updateBlockSelectionFromData(\n tr: Transaction,\n data: BlockSelectionData,\n) {\n const anchorBlockPos = getNodeById(data.anchorBlockId, tr.doc)?.posBeforeNode;\n if (anchorBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.anchorBlockId} to update selection`,\n );\n }\n\n let selection: Selection;\n if (data.type === \"cell\") {\n selection = CellSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorCellOffset,\n anchorBlockPos + data.headCellOffset,\n );\n } else if (data.type === \"node\") {\n selection = NodeSelection.create(tr.doc, anchorBlockPos + 1);\n } else {\n const headBlockPos = getNodeById(data.headBlockId, tr.doc)?.posBeforeNode;\n if (headBlockPos === undefined) {\n throw new Error(\n `Could not find block with ID ${data.headBlockId} to update selection`,\n );\n }\n\n selection = TextSelection.create(\n tr.doc,\n anchorBlockPos + data.anchorOffset,\n headBlockPos + data.headOffset,\n );\n }\n\n tr.setSelection(selection);\n}\n\n/**\n * Replaces any `columnList` blocks with the children of their columns. This is\n * done here instead of in `getSelection` as we still need to remove the entire\n * `columnList` node but only insert the `blockContainer` nodes inside it.\n * @param blocks The blocks to flatten.\n */\nfunction flattenColumns(\n blocks: Block<any, any, any>[],\n): Block<any, any, any>[] {\n return blocks\n .map((block) => {\n if (block.type === \"columnList\") {\n return block.children\n .map((column) => flattenColumns(column.children))\n .flat();\n }\n\n return {\n ...block,\n children: flattenColumns(block.children),\n };\n })\n .flat();\n}\n\n/**\n * Removes the selected blocks from the editor, then inserts them before/after a\n * reference block. Also updates the selection to match the original selection\n * using `getBlockSelectionData` and `updateBlockSelectionFromData`.\n * @param editor The BlockNote editor instance to move the blocks in.\n * @param referenceBlock The reference block to insert the selected blocks\n * before/after.\n * @param placement Whether to insert the selected blocks before or after the\n * reference block.\n */\nexport function moveSelectedBlocksAndSelection(\n editor: BlockNoteEditor<any, any, any>,\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\",\n) {\n // We want this to be a single step in the undo history\n editor.transact((tr) => {\n const blocks = editor.getSelection()?.blocks || [\n editor.getTextCursorPosition().block,\n ];\n const selectionData = getBlockSelectionData(editor);\n\n editor.removeBlocks(blocks);\n editor.insertBlocks(flattenColumns(blocks), referenceBlock, placement);\n\n updateBlockSelectionFromData(tr, selectionData);\n });\n}\n\n// Checks if a block is in a valid place after being moved. This check is\n// primitive at the moment and only returns false if the block's parent is a\n// `columnList` block. This is because regular blocks cannot be direct children\n// of `columnList` blocks.\nfunction checkPlacementIsValid(parentBlock?: Block<any, any, any>): boolean {\n return !parentBlock || parentBlock.type !== \"columnList\";\n}\n\n// Gets the placement for moving a block up. This has 3 cases:\n// 1. If the block has a previous sibling without children, the placement is\n// before it.\n// 2. If the block has a previous sibling with children, the placement is after\n// the last child.\n// 3. If the block has no previous sibling, but is nested, the placement is\n// before its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the top of the document.\nfunction getMoveUpPlacement(\n editor: BlockNoteEditor<any, any, any>,\n prevBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!prevBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"before\";\n }\n } else if (prevBlock.children.length > 0) {\n referenceBlock = prevBlock.children[prevBlock.children.length - 1];\n placement = \"after\";\n } else {\n referenceBlock = prevBlock;\n placement = \"before\";\n }\n\n // Case when the block is already at the top of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveUpPlacement(\n editor,\n placement === \"after\"\n ? referenceBlock\n : editor.getPrevBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\n// Gets the placement for moving a block down. This has 3 cases:\n// 1. If the block has a next sibling without children, the placement is after\n// it.\n// 2. If the block has a next sibling with children, the placement is before the\n// first child.\n// 3. If the block has no next sibling, but is nested, the placement is\n// after its parent.\n// If the placement is invalid, the function is called recursively until a valid\n// placement is found. Returns undefined if no valid placement is found, meaning\n// the block is already at the bottom of the document.\nfunction getMoveDownPlacement(\n editor: BlockNoteEditor<any, any, any>,\n nextBlock?: Block<any, any, any>,\n parentBlock?: Block<any, any, any>,\n):\n | { referenceBlock: BlockIdentifier; placement: \"before\" | \"after\" }\n | undefined {\n let referenceBlock: Block<any, any, any> | undefined;\n let placement: \"before\" | \"after\" | undefined;\n\n if (!nextBlock) {\n if (parentBlock) {\n referenceBlock = parentBlock;\n placement = \"after\";\n }\n } else if (nextBlock.children.length > 0) {\n referenceBlock = nextBlock.children[0];\n placement = \"before\";\n } else {\n referenceBlock = nextBlock;\n placement = \"after\";\n }\n\n // Case when the block is already at the bottom of the document.\n if (!referenceBlock || !placement) {\n return undefined;\n }\n\n const referenceBlockParent = editor.getParentBlock(referenceBlock);\n if (!checkPlacementIsValid(referenceBlockParent)) {\n return getMoveDownPlacement(\n editor,\n placement === \"before\"\n ? referenceBlock\n : editor.getNextBlock(referenceBlock),\n referenceBlockParent,\n );\n }\n\n return { referenceBlock, placement };\n}\n\nexport function moveBlocksUp(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block = selection?.blocks[0] || editor.getTextCursorPosition().block;\n\n const moveUpPlacement = getMoveUpPlacement(\n editor,\n editor.getPrevBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveUpPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveUpPlacement.referenceBlock,\n moveUpPlacement.placement,\n );\n });\n}\n\nexport function moveBlocksDown(editor: BlockNoteEditor<any, any, any>) {\n editor.transact(() => {\n const selection = editor.getSelection();\n const block =\n selection?.blocks[selection?.blocks.length - 1] ||\n editor.getTextCursorPosition().block;\n\n const moveDownPlacement = getMoveDownPlacement(\n editor,\n editor.getNextBlock(block),\n editor.getParentBlock(block),\n );\n\n if (!moveDownPlacement) {\n return;\n }\n\n moveSelectedBlocksAndSelection(\n editor,\n moveDownPlacement.referenceBlock,\n moveDownPlacement.placement,\n );\n });\n}\n","import { Fragment, NodeType, Slice } from \"prosemirror-model\";\nimport { Transaction } from \"prosemirror-state\";\nimport { ReplaceAroundStep } from \"prosemirror-transform\";\n\nimport { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport { getBlockInfoFromTransaction } from \"../../../getBlockInfoFromPos.js\";\n\n// TODO: Unit tests\n/**\n * This is a modified version of https://github.com/ProseMirror/prosemirror-schema-list/blob/569c2770cbb8092d8f11ea53ecf78cb7a4e8f15a/src/schema-list.ts#L232\n *\n * The original function derives too many information from the parentnode and itemtype\n */\nfunction sinkListItem(\n tr: Transaction,\n itemType: NodeType,\n groupType: NodeType,\n) {\n const { $from, $to } = tr.selection;\n const range = $from.blockRange(\n $to,\n (node) =>\n node.childCount > 0 &&\n (node.type.name === \"blockGroup\" || node.type.name === \"column\"), // change necessary to not look at first item child type\n );\n if (!range) {\n return false;\n }\n const startIndex = range.startIndex;\n if (startIndex === 0) {\n return false;\n }\n const parent = range.parent;\n const nodeBefore = parent.child(startIndex - 1);\n if (nodeBefore.type !== itemType) {\n return false;\n }\n const nestedBefore =\n nodeBefore.lastChild && nodeBefore.lastChild.type === groupType; // change necessary to check groupType instead of parent.type\n const inner = Fragment.from(nestedBefore ? itemType.create() : null);\n const slice = new Slice(\n Fragment.from(\n itemType.create(null, Fragment.from(groupType.create(null, inner))), // change necessary to create \"groupType\" instead of parent.type\n ),\n nestedBefore ? 3 : 1,\n 0,\n );\n\n const before = range.start;\n const after = range.end;\n\n tr.step(\n new ReplaceAroundStep(\n before - (nestedBefore ? 3 : 1),\n after,\n before,\n after,\n slice,\n 1,\n true,\n ),\n ).scrollIntoView();\n\n return true;\n}\n\nexport function nestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n return sinkListItem(\n tr,\n editor.pmSchema.nodes[\"blockContainer\"],\n editor.pmSchema.nodes[\"blockGroup\"],\n );\n });\n}\n\nexport function unnestBlock(editor: BlockNoteEditor<any, any, any>) {\n editor._tiptapEditor.commands.liftListItem(\"blockContainer\");\n}\n\nexport function canNestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).nodeBefore !== null;\n });\n}\n\nexport function canUnnestBlock(editor: BlockNoteEditor<any, any, any>) {\n return editor.transact((tr) => {\n const { bnBlock: blockContainer } = getBlockInfoFromTransaction(tr);\n\n return tr.doc.resolve(blockContainer.beforePos).depth > 1;\n });\n}\n","import type { Node } from \"prosemirror-model\";\nimport type { Block } from \"../../../blocks/defaultBlocks.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getPmSchema } from \"../../pmUtil.js\";\n\nexport function getBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n return nodeToBlock(posInfo.node, pmSchema);\n}\n\nexport function getPrevBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const nodeToConvert = $posBeforeNode.nodeBefore;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getNextBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const posInfo = getNodeById(id, doc);\n const pmSchema = getPmSchema(doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posAfterNode = doc.resolve(\n posInfo.posBeforeNode + posInfo.node.nodeSize,\n );\n const nodeToConvert = $posAfterNode.nodeAfter;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n\nexport function getParentBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n doc: Node,\n blockIdentifier: BlockIdentifier,\n): Block<BSchema, I, S> | undefined {\n const id =\n typeof blockIdentifier === \"string\" ? blockIdentifier : blockIdentifier.id;\n const pmSchema = getPmSchema(doc);\n const posInfo = getNodeById(id, doc);\n if (!posInfo) {\n return undefined;\n }\n\n const $posBeforeNode = doc.resolve(posInfo.posBeforeNode);\n const parentNode = $posBeforeNode.node();\n const grandparentNode = $posBeforeNode.node(-1);\n const nodeToConvert =\n grandparentNode.type.name !== \"doc\"\n ? parentNode.type.name === \"blockGroup\"\n ? grandparentNode\n : parentNode\n : undefined;\n if (!nodeToConvert) {\n return undefined;\n }\n\n return nodeToBlock(nodeToConvert, pmSchema);\n}\n","import { insertBlocks } from \"../../api/blockManipulation/commands/insertBlocks/insertBlocks.js\";\nimport {\n moveBlocksDown,\n moveBlocksUp,\n} from \"../../api/blockManipulation/commands/moveBlocks/moveBlocks.js\";\nimport {\n canNestBlock,\n canUnnestBlock,\n nestBlock,\n unnestBlock,\n} from \"../../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { removeAndInsertBlocks } from \"../../api/blockManipulation/commands/replaceBlocks/replaceBlocks.js\";\nimport { updateBlock } from \"../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport {\n getBlock,\n getNextBlock,\n getParentBlock,\n getPrevBlock,\n} from \"../../api/blockManipulation/getBlock/getBlock.js\";\nimport { docToBlocks } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../../blocks/defaultBlocks.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class BlockManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Gets a snapshot of all top-level (non-nested) blocks in the editor.\n * @returns A snapshot of all top-level (non-nested) blocks in the editor.\n */\n public get document(): Block<BSchema, ISchema, SSchema>[] {\n return this.editor.transact((tr) => {\n return docToBlocks(tr.doc, this.editor.pmSchema);\n });\n }\n\n /**\n * Gets a snapshot of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block that should be\n * retrieved.\n * @returns The block that matches the identifier, or `undefined` if no\n * matching block was found.\n */\n public getBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the previous sibling of an existing block from the\n * editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * previous sibling should be retrieved.\n * @returns The previous sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the first child/block\n * in the document.\n */\n public getPrevBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getPrevBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the next sibling of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * next sibling should be retrieved.\n * @returns The next sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the last child/block in\n * the document.\n */\n public getNextBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getNextBlock(tr.doc, blockIdentifier));\n }\n\n /**\n * Gets a snapshot of the parent of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * parent should be retrieved.\n * @returns The parent of the block that matches the identifier. `undefined`\n * if no matching block was found, or the block isn't nested.\n */\n public getParentBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) =>\n getParentBlock(tr.doc, blockIdentifier),\n );\n }\n\n /**\n * Traverses all blocks in the editor depth-first, and executes a callback for each.\n * @param callback The callback to execute for each block. Returning `false` stops the traversal.\n * @param reverse Whether the blocks should be traversed in reverse order.\n */\n public forEachBlock(\n callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,\n reverse = false,\n ): void {\n const blocks = this.document.slice();\n\n if (reverse) {\n blocks.reverse();\n }\n\n function traverseBlockArray(\n blockArray: Block<BSchema, ISchema, SSchema>[],\n ): boolean {\n for (const block of blockArray) {\n if (callback(block) === false) {\n return false;\n }\n\n const children = reverse\n ? block.children.slice().reverse()\n : block.children;\n\n if (!traverseBlockArray(children)) {\n return false;\n }\n }\n\n return true;\n }\n\n traverseBlockArray(blocks);\n }\n\n /**\n * Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an\n * error if the reference block could not be found.\n * @param blocksToInsert An array of partial blocks that should be inserted.\n * @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.\n * @param placement Whether the blocks should be inserted just before, just after, or nested inside the\n * `referenceBlock`.\n */\n public insertBlocks(\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n ) {\n return this.editor.transact((tr) =>\n insertBlocks(tr, blocksToInsert, referenceBlock, placement),\n );\n }\n\n /**\n * Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be\n * defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could\n * not be found.\n * @param blockToUpdate The block that should be updated.\n * @param update A partial block which defines how the existing block should be changed.\n */\n public updateBlock(\n blockToUpdate: BlockIdentifier,\n update: PartialBlock<BSchema, ISchema, SSchema>,\n ) {\n return this.editor.transact((tr) => updateBlock(tr, blockToUpdate, update));\n }\n\n /**\n * Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.\n * @param blocksToRemove An array of identifiers for existing blocks that should be removed.\n */\n public removeBlocks(blocksToRemove: BlockIdentifier[]) {\n return this.editor.transact(\n (tr) => removeAndInsertBlocks(tr, blocksToRemove, []).removedBlocks,\n );\n }\n\n /**\n * Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or\n * are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in\n * `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.\n * @param blocksToRemove An array of blocks that should be replaced.\n * @param blocksToInsert An array of partial blocks to replace the old ones with.\n */\n public replaceBlocks(\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n ) {\n return this.editor.transact((tr) =>\n removeAndInsertBlocks(tr, blocksToRemove, blocksToInsert),\n );\n }\n\n /**\n * Checks if the block containing the text cursor can be nested.\n */\n public canNestBlock() {\n return canNestBlock(this.editor);\n }\n\n /**\n * Nests the block containing the text cursor into the block above it.\n */\n public nestBlock() {\n nestBlock(this.editor);\n }\n\n /**\n * Checks if the block containing the text cursor is nested.\n */\n public canUnnestBlock() {\n return canUnnestBlock(this.editor);\n }\n\n /**\n * Lifts the block containing the text cursor out of its parent.\n */\n public unnestBlock() {\n unnestBlock(this.editor);\n }\n\n /**\n * Moves the selected blocks up. If the previous block has children, moves\n * them to the end of its children. If there is no previous block, but the\n * current blocks share a common parent, moves them out of & before it.\n */\n public moveBlocksUp() {\n return moveBlocksUp(this.editor);\n }\n\n /**\n * Moves the selected blocks down. If the next block has children, moves\n * them to the start of its children. If there is no next block, but the\n * current blocks share a common parent, moves them out of & after it.\n */\n public moveBlocksDown() {\n return moveBlocksDown(this.editor);\n }\n}\n","import type { BlockNoteEditor } from \"../BlockNoteEditor.js\";\nimport {\n getBlocksChangedByTransaction,\n type BlocksChanged,\n} from \"../../api/getBlocksChangedByTransaction.js\";\nimport { Transaction } from \"prosemirror-state\";\nimport { EventEmitter } from \"../../util/EventEmitter.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\n\n/**\n * A function that can be used to unsubscribe from an event.\n */\nexport type Unsubscribe = () => void;\n\n/**\n * EventManager is a class which manages the events of the editor\n */\nexport class EventManager<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> extends EventEmitter<{\n onChange: [\n ctx: {\n editor: BlockNoteEditor<BSchema, I, S>;\n transaction: Transaction;\n appendedTransactions: Transaction[];\n },\n ];\n onSelectionChange: [\n ctx: { editor: BlockNoteEditor<BSchema, I, S>; transaction: Transaction },\n ];\n onMount: [ctx: { editor: BlockNoteEditor<BSchema, I, S> }];\n onUnmount: [ctx: { editor: BlockNoteEditor<BSchema, I, S> }];\n}> {\n constructor(private editor: BlockNoteEditor<BSchema, I, S>) {\n super();\n // We register tiptap events only once the editor is finished initializing\n // otherwise we would be trying to register events on a tiptap editor which does not exist yet\n editor.on(\"create\", () => {\n editor._tiptapEditor.on(\n \"update\",\n ({ transaction, appendedTransactions }) => {\n this.emit(\"onChange\", { editor, transaction, appendedTransactions });\n },\n );\n editor._tiptapEditor.on(\"selectionUpdate\", ({ transaction }) => {\n this.emit(\"onSelectionChange\", { editor, transaction });\n });\n editor._tiptapEditor.on(\"mount\", () => {\n this.emit(\"onMount\", { editor });\n });\n editor._tiptapEditor.on(\"unmount\", () => {\n this.emit(\"onUnmount\", { editor });\n });\n });\n }\n\n /**\n * Register a callback that will be called when the editor changes.\n */\n public onChange(\n callback: (\n editor: BlockNoteEditor<BSchema, I, S>,\n ctx: {\n getChanges(): BlocksChanged<BSchema, I, S>;\n },\n ) => void,\n /**\n * If true, the callback will be triggered when the changes are caused by a remote user\n * @default true\n */\n includeUpdatesFromRemote = true,\n ): Unsubscribe {\n const cb = ({\n transaction,\n appendedTransactions,\n }: {\n transaction: Transaction;\n appendedTransactions: Transaction[];\n }) => {\n if (!includeUpdatesFromRemote && isRemoteTransaction(transaction)) {\n // don't trigger the callback if the changes are caused by a remote user\n return;\n }\n callback(this.editor, {\n getChanges() {\n return getBlocksChangedByTransaction(\n transaction,\n appendedTransactions,\n );\n },\n });\n };\n this.on(\"onChange\", cb);\n\n return () => {\n this.off(\"onChange\", cb);\n };\n }\n\n /**\n * Register a callback that will be called when the selection changes.\n */\n public onSelectionChange(\n callback: (editor: BlockNoteEditor<BSchema, I, S>) => void,\n /**\n * If true, the callback will be triggered when the selection changes due to a yjs sync (i.e.: other user was typing)\n */\n includeSelectionChangedByRemote = false,\n ): Unsubscribe {\n const cb = (e: { transaction: Transaction }) => {\n if (\n !includeSelectionChangedByRemote &&\n isRemoteTransaction(e.transaction)\n ) {\n // don't trigger the callback if the selection changed because of a remote user\n return;\n }\n callback(this.editor);\n };\n\n this.on(\"onSelectionChange\", cb);\n\n return () => {\n this.off(\"onSelectionChange\", cb);\n };\n }\n\n /**\n * Register a callback that will be called when the editor is mounted.\n */\n public onMount(\n callback: (ctx: { editor: BlockNoteEditor<BSchema, I, S> }) => void,\n ): Unsubscribe {\n this.on(\"onMount\", callback);\n\n return () => {\n this.off(\"onMount\", callback);\n };\n }\n\n /**\n * Register a callback that will be called when the editor is unmounted.\n */\n public onUnmount(\n callback: (ctx: { editor: BlockNoteEditor<BSchema, I, S> }) => void,\n ): Unsubscribe {\n this.on(\"onUnmount\", callback);\n\n return () => {\n this.off(\"onUnmount\", callback);\n };\n }\n}\n\nfunction isRemoteTransaction(transaction: Transaction): boolean {\n return !!transaction.getMeta(\"y-sync$\");\n}\n","function getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\nfunction isWhitespaceNode(node: Node) {\n return node.nodeType === 3 && !/\\S/.test(node.nodeValue || \"\");\n}\n\n/**\n * Step 1, Turns:\n *\n * <ul>\n * <li>item</li>\n * <li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </li>\n *\n * Into:\n * <ul>\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </ul>\n *\n */\nfunction liftNestedListsToParent(element: HTMLElement) {\n element.querySelectorAll(\"li > ul, li > ol\").forEach((list) => {\n const index = getChildIndex(list);\n const parentListItem = list.parentElement!;\n const siblingsAfter = Array.from(parentListItem.childNodes).slice(\n index + 1,\n );\n list.remove();\n siblingsAfter.forEach((sibling) => {\n sibling.remove();\n });\n\n parentListItem.insertAdjacentElement(\"afterend\", list);\n\n siblingsAfter.reverse().forEach((sibling) => {\n if (isWhitespaceNode(sibling)) {\n return;\n }\n const siblingContainer = document.createElement(\"li\");\n siblingContainer.append(sibling);\n list.insertAdjacentElement(\"afterend\", siblingContainer);\n });\n if (parentListItem.childNodes.length === 0) {\n parentListItem.remove();\n }\n });\n}\n\n/**\n * Step 2, Turns (output of liftNestedListsToParent):\n *\n * <li>item</li>\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n *\n * Into:\n * <div>\n * <li>item</li>\n * <div data-node-type=\"blockGroup\">\n * <ul>\n * <li>...</li>\n * <li>...</li>\n * </ul>\n * </div>\n * </div>\n *\n * This resulting format is parsed\n */\nfunction createGroups(element: HTMLElement) {\n element.querySelectorAll(\"li + ul, li + ol\").forEach((list) => {\n const listItem = list.previousElementSibling as HTMLElement;\n const blockContainer = document.createElement(\"div\");\n\n listItem.insertAdjacentElement(\"afterend\", blockContainer);\n blockContainer.append(listItem);\n\n const blockGroup = document.createElement(\"div\");\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n blockContainer.append(blockGroup);\n\n while (\n blockContainer.nextElementSibling?.nodeName === \"UL\" ||\n blockContainer.nextElementSibling?.nodeName === \"OL\"\n ) {\n blockGroup.append(blockContainer.nextElementSibling);\n }\n });\n}\n\n// prevent XSS, similar to https://github.com/ProseMirror/prosemirror-view/blob/1251b2b412656a2a06263e4187574beb43651273/src/clipboard.ts#L204\n// https://github.com/TypeCellOS/BlockNote/issues/601\nlet _detachedDoc: Document | null = null;\nfunction detachedDoc() {\n return (\n _detachedDoc ||\n (_detachedDoc = document.implementation.createHTMLDocument(\"title\"))\n );\n}\n\nexport function nestedListsToBlockNoteStructure(\n elementOrHTML: HTMLElement | string,\n) {\n if (typeof elementOrHTML === \"string\") {\n const element = detachedDoc().createElement(\"div\");\n element.innerHTML = elementOrHTML;\n elementOrHTML = element;\n }\n liftNestedListsToParent(elementOrHTML);\n createGroups(elementOrHTML);\n return elementOrHTML;\n}\n","import { DOMParser, Schema } from \"prosemirror-model\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { nestedListsToBlockNoteStructure } from \"./util/nestedLists.js\";\n\nexport function HTMLToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(html: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlNode = nestedListsToBlockNoteStructure(html);\n const parser = DOMParser.fromSchema(pmSchema);\n\n // Other approach might be to use\n // const doc = pmSchema.nodes[\"doc\"].createAndFill()!;\n // and context: doc.resolve(3),\n\n const parentNode = parser.parse(htmlNode, {\n topNode: pmSchema.nodes[\"blockGroup\"].create(),\n });\n\n const blocks: Block<BSchema, I, S>[] = [];\n\n for (let i = 0; i < parentNode.childCount; i++) {\n blocks.push(nodeToBlock(parentNode.child(i), pmSchema));\n }\n\n return blocks;\n}\n","import { Schema } from \"prosemirror-model\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkParse from \"remark-parse\";\nimport remarkRehype, {\n defaultHandlers as remarkRehypeDefaultHandlers,\n} from \"remark-rehype\";\nimport rehypeStringify from \"rehype-stringify\";\nimport { unified } from \"unified\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { HTMLToBlocks } from \"../html/parseHTML.js\";\nimport { isVideoUrl } from \"../../../util/string.js\";\n\n// modified version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js\n// that outputs a data-language attribute instead of a CSS class (e.g.: language-typescript)\nfunction code(state: any, node: any) {\n const value = node.value ? node.value : \"\";\n /** @type {Properties} */\n const properties: any = {};\n\n if (node.lang) {\n // changed line\n properties[\"data-language\"] = node.lang;\n }\n\n // Create `<code>`.\n /** @type {Element} */\n let result: any = {\n type: \"element\",\n tagName: \"code\",\n properties,\n children: [{ type: \"text\", value }],\n };\n\n if (node.meta) {\n result.data = { meta: node.meta };\n }\n\n state.patch(node, result);\n result = state.applyData(node, result);\n\n // Create `<pre>`.\n result = {\n type: \"element\",\n tagName: \"pre\",\n properties: {},\n children: [result],\n };\n state.patch(node, result);\n return result;\n}\n\nfunction video(state: any, node: any) {\n const url = String(node?.url || \"\");\n const title = node?.title ? String(node.title) : undefined;\n\n let result: any = {\n type: \"element\",\n tagName: \"video\",\n properties: {\n src: url,\n \"data-name\": title,\n \"data-url\": url,\n controls: true,\n },\n children: [],\n };\n state.patch?.(node, result);\n result = state.applyData ? state.applyData(node, result) : result;\n\n return result;\n}\n\nexport function markdownToHTML(markdown: string): string {\n const htmlString = unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, {\n handlers: {\n ...(remarkRehypeDefaultHandlers as any),\n image: (state: any, node: any) => {\n const url = String(node?.url || \"\");\n\n if (isVideoUrl(url)) {\n return video(state, node);\n } else {\n return remarkRehypeDefaultHandlers.image(state, node);\n }\n },\n code,\n },\n })\n .use(rehypeStringify)\n .processSync(markdown);\n\n return htmlString.value as string;\n}\n\nexport function markdownToBlocks<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(markdown: string, pmSchema: Schema): Block<BSchema, I, S>[] {\n const htmlString = markdownToHTML(markdown);\n\n return HTMLToBlocks(htmlString, pmSchema);\n}\n","import { createExternalHTMLExporter } from \"../../api/exporters/html/externalHTMLExporter.js\";\nimport { createInternalHTMLSerializer } from \"../../api/exporters/html/internalHTMLSerializer.js\";\nimport { blocksToMarkdown } from \"../../api/exporters/markdown/markdownExporter.js\";\nimport { HTMLToBlocks } from \"../../api/parsers/html/parseHTML.js\";\nimport {\n markdownToBlocks,\n markdownToHTML,\n} from \"../../api/parsers/markdown/parseMarkdown.js\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../../blocks/defaultBlocks.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class ExportManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list\n * items are un-nested in the output HTML.\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToHTMLLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.editor.document,\n ): string {\n const exporter = createExternalHTMLExporter(\n this.editor.pmSchema,\n this.editor,\n );\n return exporter.exportBlocks(blocks, {});\n }\n\n /**\n * Serializes blocks into an HTML string in the format that would normally be rendered by the editor.\n *\n * Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)\n * and serve it to users without loading the editor on the client (i.e.: displaying the blog post)\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToFullHTML(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.editor.document,\n ): string {\n const exporter = createInternalHTMLSerializer(\n this.editor.pmSchema,\n this.editor,\n );\n return exporter.serializeBlocks(blocks, {});\n }\n\n /**\n * Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and\n * `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote\n * doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.\n * @param html The HTML string to parse blocks from.\n * @returns The blocks parsed from the HTML string.\n */\n public tryParseHTMLToBlocks(\n html: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return HTMLToBlocks(html, this.editor.pmSchema);\n }\n\n /**\n * Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of\n * BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.\n * @param blocks An array of blocks that should be serialized into Markdown.\n * @returns The blocks, serialized as a Markdown string.\n */\n public blocksToMarkdownLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.editor.document,\n ): string {\n return blocksToMarkdown(blocks, this.editor.pmSchema, this.editor, {});\n }\n\n /**\n * Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on\n * Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it\n * as text.\n * @param markdown The Markdown string to parse blocks from.\n * @returns The blocks parsed from the Markdown string.\n */\n public tryParseMarkdownToBlocks(\n markdown: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return markdownToBlocks(markdown, this.editor.pmSchema);\n }\n\n /**\n * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.\n * @param html The HTML to paste.\n * @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.\n */\n public pasteHTML(html: string, raw = false) {\n let htmlToPaste = html;\n if (!raw) {\n const blocks = this.tryParseHTMLToBlocks(html);\n htmlToPaste = this.blocksToFullHTML(blocks);\n }\n if (!htmlToPaste) {\n return;\n }\n this.editor.prosemirrorView?.pasteHTML(htmlToPaste);\n }\n\n /**\n * Paste text into the editor. Defaults to interpreting text as markdown.\n * @param text The text to paste.\n */\n public pasteText(text: string) {\n return this.editor.prosemirrorView?.pasteText(text);\n }\n\n /**\n * Paste markdown into the editor.\n * @param markdown The markdown to paste.\n */\n public pasteMarkdown(markdown: string) {\n const html = markdownToHTML(markdown);\n return this.pasteHTML(html);\n }\n}\n","export const acceptedMIMETypes = [\n \"vscode-editor-data\",\n \"blocknote/html\",\n \"text/markdown\",\n \"text/html\",\n \"text/plain\",\n \"Files\",\n] as const;\n","import { Block, PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\n\nfunction checkFileExtensionsMatch(\n fileExtension1: string,\n fileExtension2: string,\n) {\n if (!fileExtension1.startsWith(\".\") || !fileExtension2.startsWith(\".\")) {\n throw new Error(`The strings provided are not valid file extensions.`);\n }\n\n return fileExtension1 === fileExtension2;\n}\n\nfunction checkMIMETypesMatch(mimeType1: string, mimeType2: string) {\n const types1 = mimeType1.split(\"/\");\n const types2 = mimeType2.split(\"/\");\n\n if (types1.length !== 2) {\n throw new Error(`The string ${mimeType1} is not a valid MIME type.`);\n }\n if (types2.length !== 2) {\n throw new Error(`The string ${mimeType2} is not a valid MIME type.`);\n }\n\n if (types1[1] === \"*\" || types2[1] === \"*\") {\n return types1[0] === types2[0];\n }\n if (types1[0] === \"*\" || types2[0] === \"*\") {\n return types1[1] === types2[1];\n }\n\n return types1[0] === types2[0] && types1[1] === types2[1];\n}\n\nfunction insertOrUpdateBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n referenceBlock: Block<BSchema, I, S>,\n newBlock: PartialBlock<BSchema, I, S>,\n placement: \"before\" | \"after\" = \"after\",\n) {\n let insertedBlockId: string | undefined;\n\n if (\n Array.isArray(referenceBlock.content) &&\n referenceBlock.content.length === 0\n ) {\n insertedBlockId = editor.updateBlock(referenceBlock, newBlock).id;\n } else {\n insertedBlockId = editor.insertBlocks(\n [newBlock],\n referenceBlock,\n placement,\n )[0].id;\n }\n\n return insertedBlockId;\n}\n\nexport async function handleFileInsertion<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(event: DragEvent | ClipboardEvent, editor: BlockNoteEditor<BSchema, I, S>) {\n if (!editor.uploadFile) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Attempted ot insert file, but uploadFile is not set in the BlockNote editor options\",\n );\n return;\n }\n\n const dataTransfer =\n \"dataTransfer\" in event ? event.dataTransfer : event.clipboardData;\n if (dataTransfer === null) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (dataTransfer.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format !== \"Files\") {\n return;\n }\n\n const items = dataTransfer.items;\n if (!items) {\n return;\n }\n\n event.preventDefault();\n\n for (let i = 0; i < items.length; i++) {\n // Gets file block corresponding to MIME type.\n let fileBlockType = \"file\";\n for (const blockSpec of Object.values(editor.schema.blockSpecs)) {\n for (const mimeType of blockSpec.implementation.meta?.fileBlockAccept ||\n []) {\n const isFileExtension = mimeType.startsWith(\".\");\n const file = items[i].getAsFile();\n\n if (file) {\n if (\n (!isFileExtension &&\n file.type &&\n checkMIMETypesMatch(items[i].type, mimeType)) ||\n (isFileExtension &&\n checkFileExtensionsMatch(\n \".\" + file.name.split(\".\").pop(),\n mimeType,\n ))\n ) {\n fileBlockType = blockSpec.config.type;\n break;\n }\n }\n }\n }\n\n const file = items[i].getAsFile();\n if (file) {\n const fileBlock = {\n type: fileBlockType,\n props: {\n name: file.name,\n },\n } as PartialBlock<BSchema, I, S>;\n\n let insertedBlockId: string | undefined = undefined;\n\n if (event.type === \"paste\") {\n const currentBlock = editor.getTextCursorPosition().block;\n insertedBlockId = insertOrUpdateBlock(editor, currentBlock, fileBlock);\n } else if (event.type === \"drop\") {\n const coords = {\n left: (event as DragEvent).clientX,\n top: (event as DragEvent).clientY,\n };\n\n const pos = editor.prosemirrorView.posAtCoords(coords);\n\n if (!pos) {\n return;\n }\n\n insertedBlockId = editor.transact((tr) => {\n const posInfo = getNearestBlockPos(tr.doc, pos.pos);\n const blockElement = editor.prosemirrorView.dom.querySelector(\n `[data-id=\"${posInfo.node.attrs.id}\"]`,\n );\n\n const blockRect = blockElement?.getBoundingClientRect();\n\n return insertOrUpdateBlock(\n editor,\n editor.getBlock(posInfo.node.attrs.id)!,\n fileBlock,\n blockRect && (blockRect.top + blockRect.bottom) / 2 > coords.top\n ? \"before\"\n : \"after\",\n );\n });\n } else {\n return;\n }\n\n const updateData = await editor.uploadFile(file, insertedBlockId);\n\n const updatedFileBlock =\n typeof updateData === \"string\"\n ? ({\n props: {\n url: updateData,\n },\n } as PartialBlock<BSchema, I, S>)\n : { ...updateData };\n\n editor.updateBlock(insertedBlockId, updatedFileBlock);\n }\n }\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\n\nexport const createDropFileExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"dropFile\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n drop(_view, event) {\n if (!editor.isEditable) {\n return;\n }\n\n let format: (typeof acceptedMIMETypes)[number] | null = null;\n for (const mimeType of acceptedMIMETypes) {\n if (event.dataTransfer!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n if (format === null) {\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n return false;\n },\n },\n },\n }),\n ];\n },\n });\n","// Headings H1-H6.\nconst h1 = /(^|\\n) {0,3}#{1,6} {1,8}[^\\n]{1,64}\\r?\\n\\r?\\n\\s{0,32}\\S/;\n\n// Bold, italic, underline, strikethrough, highlight.\nconst bold =\n /(_|__|\\*|\\*\\*|~~|==|\\+\\+)(?!\\s)(?:[^\\s](?:.{0,62}[^\\s])?|\\S)(?=\\1)/;\n\n// Basic inline link (also captures images).\nconst link = /\\[[^\\]]{1,128}\\]\\(https?:\\/\\/\\S{1,999}\\)/;\n\n// Inline code.\nconst code = /(?:\\s|^)`(?!\\s)(?:[^\\s`](?:[^`]{0,46}[^\\s`])?|[^\\s`])`([^\\w]|$)/;\n\n// Unordered list.\nconst ul = /(?:^|\\n)\\s{0,5}-\\s{1}[^\\n]+\\n\\s{0,15}-\\s/;\n\n// Ordered list.\nconst ol = /(?:^|\\n)\\s{0,5}\\d+\\.\\s{1}[^\\n]+\\n\\s{0,15}\\d+\\.\\s/;\n\n// Horizontal rule.\nconst hr = /\\n{2} {0,3}-{2,48}\\n{2}/;\n\n// Fenced code block.\nconst fences =\n /(?:\\n|^)(```|~~~|\\$\\$)(?!`|~)[^\\s]{0,64} {0,64}[^\\n]{0,64}\\n[\\s\\S]{0,9999}?\\s*\\1 {0,64}(?:\\n+|$)/;\n\n// Classical underlined H1 and H2 headings.\nconst title = /(?:\\n|^)(?!\\s)\\w[^\\n]{0,64}\\r?\\n(-|=)\\1{0,64}\\n\\n\\s{0,64}(\\w|$)/;\n\n// Blockquote.\nconst blockquote =\n /(?:^|(\\r?\\n\\r?\\n))( {0,3}>[^\\n]{1,333}\\n){1,999}($|(\\r?\\n))/;\n\n// Table Header\nconst tableHeader = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n// Table Divider\nconst tableDivider = /^\\s*\\|(\\s*[-:]+[-:]\\s*\\|)+\\s*$/m;\n\n// Table Row\nconst tableRow = /^\\s*\\|(.+\\|)+\\s*$/m;\n\n/**\n * Returns `true` if the source text might be a markdown document.\n *\n * @param src Source text to analyze.\n */\nexport const isMarkdown = (src: string): boolean =>\n h1.test(src) ||\n bold.test(src) ||\n link.test(src) ||\n code.test(src) ||\n ul.test(src) ||\n ol.test(src) ||\n hr.test(src) ||\n fences.test(src) ||\n title.test(src) ||\n blockquote.test(src) ||\n tableHeader.test(src) ||\n tableDivider.test(src) ||\n tableRow.test(src);\n","import { EditorView } from \"prosemirror-view\";\n\nexport async function handleVSCodePaste(\n event: ClipboardEvent,\n view: EditorView,\n) {\n const { schema } = view.state;\n\n if (!event.clipboardData) {\n return false;\n }\n\n const text = event.clipboardData!.getData(\"text/plain\");\n\n if (!text) {\n return false;\n }\n\n if (!schema.nodes.codeBlock) {\n view.pasteText(text);\n return true;\n }\n\n const vscode = event.clipboardData!.getData(\"vscode-editor-data\");\n const vscodeData = vscode ? JSON.parse(vscode) : undefined;\n const language = vscodeData?.mode;\n\n if (!language) {\n return false;\n }\n\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n view.pasteHTML(\n `<pre><code class=\"language-${language}\">${text.replace(\n /\\r\\n?/g,\n \"\\n\",\n )}</code></pre>`,\n );\n\n return true;\n}\n","import { Extension } from \"@tiptap/core\";\nimport { Plugin } from \"prosemirror-state\";\n\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../../editor/BlockNoteEditor\";\nimport { isMarkdown } from \"../../parsers/markdown/detectMarkdown.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { acceptedMIMETypes } from \"./acceptedMIMETypes.js\";\nimport { handleFileInsertion } from \"./handleFileInsertion.js\";\nimport { handleVSCodePaste } from \"./handleVSCodePaste.js\";\n\nfunction defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n}: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<any, any, any>;\n prioritizeMarkdownOverHTML: boolean;\n plainTextAsMarkdown: boolean;\n}) {\n // Special case for code blocks, as they do not support any rich text\n // formatting, so we force pasting plain text.\n const isInCodeBlock = editor.transact(\n (tr) =>\n tr.selection.$from.parent.type.spec.code &&\n tr.selection.$to.parent.type.spec.code,\n );\n\n if (isInCodeBlock) {\n const data = event.clipboardData?.getData(\"text/plain\");\n\n if (data) {\n editor.pasteText(data);\n\n return true;\n }\n }\n\n let format: (typeof acceptedMIMETypes)[number] | undefined;\n for (const mimeType of acceptedMIMETypes) {\n if (event.clipboardData!.types.includes(mimeType)) {\n format = mimeType;\n break;\n }\n }\n\n if (!format) {\n return true;\n }\n\n if (format === \"vscode-editor-data\") {\n handleVSCodePaste(event, editor.prosemirrorView);\n return true;\n }\n\n if (format === \"Files\") {\n handleFileInsertion(event, editor);\n return true;\n }\n\n const data = event.clipboardData!.getData(format);\n\n if (format === \"blocknote/html\") {\n // Is blocknote/html, so no need to convert it\n editor.pasteHTML(data, true);\n return true;\n }\n\n if (format === \"text/markdown\") {\n editor.pasteMarkdown(data);\n return true;\n }\n\n if (prioritizeMarkdownOverHTML) {\n // Use plain text instead of HTML if it looks like Markdown\n const plainText = event.clipboardData!.getData(\"text/plain\");\n\n if (isMarkdown(plainText)) {\n editor.pasteMarkdown(plainText);\n return true;\n }\n }\n\n if (format === \"text/html\") {\n editor.pasteHTML(data);\n return true;\n }\n\n if (plainTextAsMarkdown) {\n editor.pasteMarkdown(data);\n return true;\n }\n\n editor.pasteText(data);\n return true;\n}\n\nexport const createPasteFromClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n pasteHandler: Exclude<\n BlockNoteEditorOptions<any, any, any>[\"pasteHandler\"],\n undefined\n >,\n) =>\n Extension.create({\n name: \"pasteFromClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n paste(_view, event) {\n event.preventDefault();\n\n if (!editor.isEditable) {\n return;\n }\n\n return pasteHandler({\n event,\n editor,\n defaultPasteHandler: ({\n prioritizeMarkdownOverHTML = true,\n plainTextAsMarkdown = true,\n } = {}) => {\n return defaultPasteHandler({\n event,\n editor,\n prioritizeMarkdownOverHTML,\n plainTextAsMarkdown,\n });\n },\n });\n },\n },\n },\n }),\n ];\n },\n });\n","import { Extension } from \"@tiptap/core\";\nimport { Fragment, Node } from \"prosemirror-model\";\nimport { NodeSelection, Plugin } from \"prosemirror-state\";\nimport { CellSelection } from \"prosemirror-tables\";\nimport type { EditorView } from \"prosemirror-view\";\n\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../../exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../nodeConversions/fragmentToBlocks.js\";\nimport {\n contentNodeToInlineContent,\n contentNodeToTableContent,\n} from \"../../nodeConversions/nodeToBlock.js\";\n\nfunction fragmentToExternalHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n selectedFragment: Fragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n let isWithinBlockContent = false;\n const isWithinTable = view.state.selection instanceof CellSelection;\n\n if (!isWithinTable) {\n // Checks whether block ancestry should be included when creating external\n // HTML. If the selection is within a block content node, the block ancestry\n // is excluded as we only care about the inline content.\n const fragmentWithoutParents = view.state.doc.slice(\n view.state.selection.from,\n view.state.selection.to,\n false,\n ).content;\n\n const children = [];\n for (let i = 0; i < fragmentWithoutParents.childCount; i++) {\n children.push(fragmentWithoutParents.child(i));\n }\n\n isWithinBlockContent =\n children.find(\n (child) =>\n child.type.isInGroup(\"bnBlock\") ||\n child.type.name === \"blockGroup\" ||\n child.type.spec.group === \"blockContent\",\n ) === undefined;\n if (isWithinBlockContent) {\n selectedFragment = fragmentWithoutParents;\n }\n }\n\n let externalHTML: string;\n\n const externalHTMLExporter = createExternalHTMLExporter(\n view.state.schema,\n editor,\n );\n\n if (isWithinTable) {\n if (selectedFragment.firstChild?.type.name === \"table\") {\n // contentNodeToTableContent expects the fragment of the content of a table, not the table node itself\n // but cellselection.content() returns the table node itself if all cells and columns are selected\n selectedFragment = selectedFragment.firstChild.content;\n }\n\n // first convert selection to blocknote-style table content, and then\n // pass this to the exporter\n const ic = contentNodeToTableContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n\n // Wrap in table to ensure correct parsing by spreadsheet applications\n externalHTML = `<table>${externalHTMLExporter.exportInlineContent(\n ic as any,\n {},\n )}</table>`;\n } else if (isWithinBlockContent) {\n // first convert selection to blocknote-style inline content, and then\n // pass this to the exporter\n const ic = contentNodeToInlineContent(\n selectedFragment as any,\n editor.schema.inlineContentSchema,\n editor.schema.styleSchema,\n );\n externalHTML = externalHTMLExporter.exportInlineContent(ic, {});\n } else {\n const blocks = fragmentToBlocks<BSchema, I, S>(selectedFragment);\n externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n }\n return externalHTML;\n}\n\nexport function selectedFragmentToHTML<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n view: EditorView,\n editor: BlockNoteEditor<BSchema, I, S>,\n): {\n clipboardHTML: string;\n externalHTML: string;\n markdown: string;\n} {\n // Checks if a `blockContent` node is being copied and expands\n // the selection to the parent `blockContainer` node. This is\n // for the use-case in which only a block without content is\n // selected, e.g. an image block.\n if (\n \"node\" in view.state.selection &&\n (view.state.selection.node as Node).type.spec.group === \"blockContent\"\n ) {\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(tr.doc.resolve(view.state.selection.from - 1)),\n ),\n );\n }\n\n // Uses default ProseMirror clipboard serialization.\n const clipboardHTML: string = view.serializeForClipboard(\n view.state.selection.content(),\n ).dom.innerHTML;\n\n const selectedFragment = view.state.selection.content().content;\n\n const externalHTML = fragmentToExternalHTML<BSchema, I, S>(\n view,\n selectedFragment,\n editor,\n );\n\n const markdown = cleanHTMLToMarkdown(externalHTML);\n\n return { clipboardHTML, externalHTML, markdown };\n}\n\nconst checkIfSelectionInNonEditableBlock = () => {\n // Let browser handle event if selection is empty (nothing\n // happens).\n const selection = window.getSelection();\n if (!selection || selection.isCollapsed) {\n return true;\n }\n\n // Let browser handle event if it's within a non-editable\n // \"island\". This means it's in selectable content within a\n // non-editable block. We only need to check one node as it's\n // not possible for the browser selection to start in an\n // editable block and end in a non-editable one.\n let node = selection.focusNode;\n while (node) {\n if (\n node instanceof HTMLElement &&\n node.getAttribute(\"contenteditable\") === \"false\"\n ) {\n return true;\n }\n\n node = node.parentElement;\n }\n\n return false;\n};\n\nconst copyToClipboard = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n view: EditorView,\n event: ClipboardEvent,\n) => {\n // Stops the default browser copy behaviour.\n event.preventDefault();\n event.clipboardData!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } = selectedFragmentToHTML(\n view,\n editor,\n );\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.clipboardData!.setData(\"blocknote/html\", clipboardHTML);\n event.clipboardData!.setData(\"text/html\", externalHTML);\n event.clipboardData!.setData(\"text/plain\", markdown);\n};\n\nexport const createCopyToClipboardExtension = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n editor: BlockNoteEditor<BSchema, I, S>,\n) =>\n Extension.create<{ editor: BlockNoteEditor<BSchema, I, S> }, undefined>({\n name: \"copyToClipboard\",\n addProseMirrorPlugins() {\n return [\n new Plugin({\n props: {\n handleDOMEvents: {\n copy(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n // Prevent default PM handler to be called\n return true;\n },\n cut(view, event) {\n if (checkIfSelectionInNonEditableBlock()) {\n return true;\n }\n\n copyToClipboard(editor, view, event);\n if (view.editable) {\n view.dispatch(view.state.tr.deleteSelection());\n }\n // Prevent default PM handler to be called\n return true;\n },\n // This is for the use-case in which only a block without content\n // is selected, e.g. an image block, and dragged (not using the\n // drag handle).\n dragstart(view, event) {\n // Checks if a `NodeSelection` is active.\n if (!(\"node\" in view.state.selection)) {\n return;\n }\n\n // Checks if a `blockContent` node is being dragged.\n if (\n (view.state.selection.node as Node).type.spec.group !==\n \"blockContent\"\n ) {\n return;\n }\n\n // Expands the selection to the parent `blockContainer` node.\n editor.transact((tr) =>\n tr.setSelection(\n new NodeSelection(\n tr.doc.resolve(view.state.selection.from - 1),\n ),\n ),\n );\n\n // Stops the default browser drag start behaviour.\n event.preventDefault();\n event.dataTransfer!.clearData();\n\n const { clipboardHTML, externalHTML, markdown } =\n selectedFragmentToHTML(view, editor);\n\n // TODO: Writing to other MIME types not working in Safari for\n // some reason.\n event.dataTransfer!.setData(\"blocknote/html\", clipboardHTML);\n event.dataTransfer!.setData(\"text/html\", externalHTML);\n event.dataTransfer!.setData(\"text/plain\", markdown);\n\n // Prevent default PM handler to be called\n return true;\n },\n },\n },\n }),\n ];\n },\n });\n","import { Extension } from \"@tiptap/core\";\nimport { getBackgroundColorAttribute } from \"../../../blocks/defaultProps.js\";\n\nexport const BackgroundColorExtension = Extension.create({\n name: \"blockBackgroundColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n backgroundColor: getBackgroundColorAttribute(),\n },\n },\n ];\n },\n});\n","// Stripped down version of the TipTap HardBreak extension:\n// https://github.com/ueberdosis/tiptap/blob/f3258d9ee5fb7979102fe63434f6ea4120507311/packages/extension-hard-break/src/hard-break.ts#L80\n// Changes:\n// - Removed options\n// - Removed keyboard shortcuts & moved them to the `KeyboardShortcutsExtension`\n// - Removed `setHardBreak` command (added a simpler version in the Shift+Enter\n// handler in `KeyboardShortcutsExtension`).\n// - Added priority\nimport { mergeAttributes, Node } from \"@tiptap/core\";\n\nexport const HardBreak = Node.create({\n name: \"hardBreak\",\n\n inline: true,\n\n group: \"inline\",\n\n selectable: false,\n\n linebreakReplacement: true,\n\n priority: 10,\n\n parseHTML() {\n return [{ tag: \"br\" }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\"br\", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];\n },\n\n renderText() {\n return \"\\n\";\n },\n});\n","import { Node } from \"prosemirror-model\";\nimport { EditorState } from \"prosemirror-state\";\n\nimport {\n BlockInfo,\n getBlockInfoFromResolvedPos,\n} from \"../../../getBlockInfoFromPos.js\";\n\n/**\n * Returns the block info from the parent block\n * or undefined if we're at the root\n */\nexport const getParentBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n if ($pos.depth <= 1) {\n return undefined;\n }\n\n // get start pos of parent\n const parentBeforePos = $pos.posAtIndex(\n $pos.index($pos.depth - 1),\n $pos.depth - 1,\n );\n\n const parentBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(parentBeforePos),\n );\n return parentBlockInfo;\n};\n\n/**\n * Returns the block info from the sibling block before (above) the given block,\n * or undefined if the given block is the first sibling.\n */\nexport const getPrevBlockInfo = (doc: Node, beforePos: number) => {\n const $pos = doc.resolve(beforePos);\n\n const indexInParent = $pos.index();\n\n if (indexInParent === 0) {\n return undefined;\n }\n\n const prevBlockBeforePos = $pos.posAtIndex(indexInParent - 1);\n\n const prevBlockInfo = getBlockInfoFromResolvedPos(\n doc.resolve(prevBlockBeforePos),\n );\n return prevBlockInfo;\n};\n\n/**\n * If a block has children like this:\n * A\n * - B\n * - C\n * -- D\n *\n * Then the bottom nested block returned is D.\n */\nexport const getBottomNestedBlockInfo = (doc: Node, blockInfo: BlockInfo) => {\n while (blockInfo.childContainer) {\n const group = blockInfo.childContainer.node;\n\n const newPos = doc\n .resolve(blockInfo.childContainer.beforePos + 1)\n .posAtIndex(group.childCount - 1);\n blockInfo = getBlockInfoFromResolvedPos(doc.resolve(newPos));\n }\n\n return blockInfo;\n};\n\nconst canMerge = (prevBlockInfo: BlockInfo, nextBlockInfo: BlockInfo) => {\n return (\n prevBlockInfo.isBlockContainer &&\n prevBlockInfo.blockContent.node.type.spec.content === \"inline*\" &&\n prevBlockInfo.blockContent.node.childCount > 0 &&\n nextBlockInfo.isBlockContainer &&\n nextBlockInfo.blockContent.node.type.spec.content === \"inline*\"\n );\n};\n\nconst mergeBlocks = (\n state: EditorState,\n dispatch: ((args?: any) => any) | undefined,\n prevBlockInfo: BlockInfo,\n nextBlockInfo: BlockInfo,\n) => {\n // Un-nests all children of the next block.\n if (!nextBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but next block is not a block container`,\n );\n }\n\n // Removes a level of nesting all children of the next block by 1 level, if it contains both content and block\n // group nodes.\n if (nextBlockInfo.childContainer) {\n const childBlocksStart = state.doc.resolve(\n nextBlockInfo.childContainer.beforePos + 1,\n );\n const childBlocksEnd = state.doc.resolve(\n nextBlockInfo.childContainer.afterPos - 1,\n );\n const childBlocksRange = childBlocksStart.blockRange(childBlocksEnd);\n\n if (dispatch) {\n const pos = state.doc.resolve(nextBlockInfo.bnBlock.beforePos);\n state.tr.lift(childBlocksRange!, pos.depth);\n }\n }\n\n // Deletes the boundary between the two blocks. Can be thought of as\n // removing the closing tags of the first block and the opening tags of the\n // second one to stitch them together.\n if (dispatch) {\n if (!prevBlockInfo.isBlockContainer) {\n throw new Error(\n `Attempted to merge block at position ${nextBlockInfo.bnBlock.beforePos} into previous block at position ${prevBlockInfo.bnBlock.beforePos}, but previous block is not a block container`,\n );\n }\n\n // TODO: test merging between a columnList and paragraph, between two columnLists, and v.v.\n dispatch(\n state.tr.delete(\n prevBlockInfo.blockContent.afterPos - 1,\n nextBlockInfo.blockContent.beforePos + 1,\n ),\n );\n }\n\n return true;\n};\n\nexport const mergeBlocksCommand =\n (posBetweenBlocks: number) =>\n ({\n state,\n dispatch,\n }: {\n state: EditorState;\n dispatch: ((args?: any) => any) | undefined;\n }) => {\n const $pos = state.doc.resolve(posBetweenBlocks);\n const nextBlockInfo = getBlockInfoFromResolvedPos($pos);\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n nextBlockInfo.bnBlock.beforePos,\n );\n\n if (!prevBlockInfo) {\n return false;\n }\n\n const bottomNestedBlockInfo = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!canMerge(bottomNestedBlockInfo, nextBlockInfo)) {\n return false;\n }\n\n return mergeBlocks(state, dispatch, bottomNestedBlockInfo, nextBlockInfo);\n };\n","import { Extension } from \"@tiptap/core\";\n\nimport { TextSelection } from \"prosemirror-state\";\nimport {\n getBottomNestedBlockInfo,\n getPrevBlockInfo,\n mergeBlocksCommand,\n} from \"../../../api/blockManipulation/commands/mergeBlocks/mergeBlocks.js\";\nimport { nestBlock } from \"../../../api/blockManipulation/commands/nestBlock/nestBlock.js\";\nimport { fixColumnList } from \"../../../api/blockManipulation/commands/replaceBlocks/util/fixColumnList.js\";\nimport { splitBlockCommand } from \"../../../api/blockManipulation/commands/splitBlock/splitBlock.js\";\nimport { updateBlockCommand } from \"../../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport { getBlockInfoFromSelection } from \"../../../api/getBlockInfoFromPos.js\";\nimport { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport { FormattingToolbarExtension } from \"../../FormattingToolbar/FormattingToolbar.js\";\nimport { FilePanelExtension } from \"../../FilePanel/FilePanel.js\";\n\nexport const KeyboardShortcutsExtension = Extension.create<{\n editor: BlockNoteEditor<any, any, any>;\n tabBehavior: \"prefer-navigate-ui\" | \"prefer-indent\";\n}>({\n priority: 50,\n\n // TODO: The shortcuts need a refactor. Do we want to use a command priority\n // design as there is now, or clump the logic into a single function?\n addKeyboardShortcuts() {\n // handleBackspace is partially adapted from https://github.com/ueberdosis/tiptap/blob/ed56337470efb4fd277128ab7ef792b37cfae992/packages/core/src/extensions/keymap.ts\n const handleBackspace = () =>\n this.editor.commands.first(({ chain, commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Undoes an input rule if one was triggered in the last editor state change.\n () => commands.undoInputRule(),\n // Reverts block content type to a paragraph if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const isParagraph =\n blockInfo.blockContent.node.type.name === \"paragraph\";\n\n if (selectionAtBlockStart && !isParagraph) {\n return commands.command(\n updateBlockCommand(blockInfo.bnBlock.beforePos, {\n type: \"paragraph\",\n props: {},\n }),\n );\n }\n\n return false;\n }),\n // Removes a level of nesting if the block is indented if the selection is at the start of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n\n if (selectionAtBlockStart) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Merges block with the previous one if it isn't indented, and the selection is at the start of the\n // block. The target block for merging must contain inline content.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.from === blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const posBetweenBlocks = blockContainer.beforePos;\n\n if (selectionAtBlockStart && selectionEmpty) {\n return chain()\n .command(mergeBlocksCommand(posBetweenBlocks))\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n () =>\n commands.command(({ state, tr, dispatch }) => {\n // when at the start of a first block in a column\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const selectionAtBlockStart =\n tr.selection.from === blockInfo.blockContent.beforePos + 1;\n if (!selectionAtBlockStart) {\n return false;\n }\n\n const $pos = tr.doc.resolve(blockInfo.bnBlock.beforePos);\n\n const prevBlock = $pos.nodeBefore;\n if (prevBlock) {\n // should be no previous block\n return false;\n }\n\n const parentBlock = $pos.node();\n if (parentBlock.type.name !== \"column\") {\n return false;\n }\n\n const $blockPos = tr.doc.resolve(blockInfo.bnBlock.beforePos);\n const $columnPos = tr.doc.resolve($blockPos.before());\n const columnListPos = $columnPos.before();\n\n if (dispatch) {\n const fragment = tr.doc.slice(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n ).content;\n\n tr.delete(\n blockInfo.bnBlock.beforePos,\n blockInfo.bnBlock.afterPos,\n );\n\n if ($columnPos.index() === 0) {\n // Fix `columnList` and insert the block before it.\n fixColumnList(tr, columnListPos);\n tr.insert(columnListPos, fragment);\n tr.setSelection(\n TextSelection.near(tr.doc.resolve(columnListPos)),\n );\n } else {\n // Insert the block at the end of the first column and fix\n // `columnList`.\n tr.insert($columnPos.pos - 1, fragment);\n tr.setSelection(\n TextSelection.near(tr.doc.resolve($columnPos.pos - 1)),\n );\n fixColumnList(tr, columnListPos);\n }\n }\n\n return true;\n }),\n // Deletes the current block if it's an empty block with inline content,\n // and moves the selection to the previous block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n\n const blockEmpty =\n blockInfo.blockContent.node.childCount === 0 &&\n blockInfo.blockContent.node.type.spec.content === \"inline*\";\n\n if (blockEmpty) {\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n if (!prevBlockInfo || !prevBlockInfo.isBlockContainer) {\n return false;\n }\n\n let chainedCommands = chain();\n\n if (\n prevBlockInfo.blockContent.node.type.spec.content ===\n \"tableRow+\"\n ) {\n const tableBlockEndPos = blockInfo.bnBlock.beforePos - 1;\n const tableBlockContentEndPos = tableBlockEndPos - 1;\n const lastRowEndPos = tableBlockContentEndPos - 1;\n const lastCellEndPos = lastRowEndPos - 1;\n const lastCellParagraphEndPos = lastCellEndPos - 1;\n\n chainedCommands = chainedCommands.setTextSelection(\n lastCellParagraphEndPos,\n );\n } else if (\n prevBlockInfo.blockContent.node.type.spec.content === \"\"\n ) {\n const nonEditableBlockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands = chainedCommands.setNodeSelection(\n nonEditableBlockContentStartPos,\n );\n } else {\n const blockContentStartPos =\n prevBlockInfo.blockContent.afterPos -\n prevBlockInfo.blockContent.node.nodeSize;\n\n chainedCommands =\n chainedCommands.setTextSelection(blockContentStartPos);\n }\n\n return chainedCommands\n .deleteRange({\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n })\n .scrollIntoView()\n .run();\n }\n\n return false;\n }),\n // Deletes previous block if it contains no content and isn't a table,\n // when the selection is empty and at the start of the block. Moves the\n // current block into the deleted block's place.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n if (!blockInfo.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const selectionAtBlockStart =\n state.selection.from === blockInfo.blockContent.beforePos + 1;\n const selectionEmpty = state.selection.empty;\n\n const prevBlockInfo = getPrevBlockInfo(\n state.doc,\n blockInfo.bnBlock.beforePos,\n );\n\n if (prevBlockInfo && selectionAtBlockStart && selectionEmpty) {\n const bottomBlock = getBottomNestedBlockInfo(\n state.doc,\n prevBlockInfo,\n );\n\n if (!bottomBlock.isBlockContainer) {\n // TODO\n throw new Error(`todo`);\n }\n\n const prevBlockNotTableAndNoContent =\n bottomBlock.blockContent.node.type.spec.content === \"\" ||\n (bottomBlock.blockContent.node.type.spec.content ===\n \"inline*\" &&\n bottomBlock.blockContent.node.childCount === 0);\n\n if (prevBlockNotTableAndNoContent) {\n return chain()\n .cut(\n {\n from: blockInfo.bnBlock.beforePos,\n to: blockInfo.bnBlock.afterPos,\n },\n bottomBlock.bnBlock.afterPos,\n )\n .deleteRange({\n from: bottomBlock.bnBlock.beforePos,\n to: bottomBlock.bnBlock.afterPos,\n })\n .run();\n }\n }\n\n return false;\n }),\n ]);\n\n const handleDelete = () =>\n this.editor.commands.first(({ commands }) => [\n // Deletes the selection if it's not empty.\n () => commands.deleteSelection(),\n // Merges block with the next one (at the same nesting level or lower),\n // if one exists, the block has no children, and the selection is at the\n // end of the block.\n () =>\n commands.command(({ state }) => {\n // TODO: Change this to not rely on offsets & schema assumptions\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const {\n bnBlock: blockContainer,\n blockContent,\n childContainer,\n } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n const blockAtDocEnd =\n blockContainer.afterPos === state.doc.nodeSize - 3;\n const selectionAtBlockEnd =\n state.selection.from === blockContent.afterPos - 1;\n const selectionEmpty = state.selection.empty;\n const hasChildBlocks = childContainer !== undefined;\n\n if (\n !blockAtDocEnd &&\n selectionAtBlockEnd &&\n selectionEmpty &&\n !hasChildBlocks\n ) {\n let oldDepth = depth;\n let newPos = blockContainer.afterPos + 1;\n let newDepth = state.doc.resolve(newPos).depth;\n\n while (newDepth < oldDepth) {\n oldDepth = newDepth;\n newPos += 2;\n newDepth = state.doc.resolve(newPos).depth;\n }\n\n return commands.command(mergeBlocksCommand(newPos - 1));\n }\n\n return false;\n }),\n ]);\n\n const handleEnter = (withShift = false) => {\n return this.editor.commands.first(({ commands, tr }) => [\n // Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start\n // of the block.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const { depth } = state.doc.resolve(blockContainer.beforePos);\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n const blockIndented = depth > 1;\n\n if (\n selectionAtBlockStart &&\n selectionEmpty &&\n blockEmpty &&\n blockIndented\n ) {\n return commands.liftListItem(\"blockContainer\");\n }\n\n return false;\n }),\n // Creates a hard break if block is configured to do so.\n () =>\n commands.command(({ state }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n\n const blockHardBreakShortcut =\n this.options.editor.schema.blockSchema[\n blockInfo.blockNoteType as keyof typeof this.options.editor.schema.blockSchema\n ].meta?.hardBreakShortcut ?? \"shift+enter\";\n\n if (blockHardBreakShortcut === \"none\") {\n return false;\n }\n\n if (\n // If shortcut is not configured, or is configured as \"shift+enter\",\n // create a hard break for shift+enter, but not for enter.\n (blockHardBreakShortcut === \"shift+enter\" && withShift) ||\n // If shortcut is configured as \"enter\", create a hard break for\n // both enter and shift+enter.\n blockHardBreakShortcut === \"enter\"\n ) {\n const marks =\n tr.storedMarks ||\n tr.selection.$head\n .marks()\n .filter((m) =>\n this.editor.extensionManager.splittableMarks.includes(\n m.type.name,\n ),\n );\n\n tr.insert(\n tr.selection.head,\n tr.doc.type.schema.nodes.hardBreak.create(),\n ).ensureMarks(marks);\n return true;\n }\n\n return false;\n }),\n // Creates a new block and moves the selection to it if the current one is empty, while the selection is also\n // empty & at the start of the block.\n () =>\n commands.command(({ state, dispatch }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { bnBlock: blockContainer, blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const selectionEmpty =\n state.selection.anchor === state.selection.head;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (selectionAtBlockStart && selectionEmpty && blockEmpty) {\n const newBlockInsertionPos = blockContainer.afterPos;\n const newBlockContentPos = newBlockInsertionPos + 2;\n\n if (dispatch) {\n const newBlock =\n state.schema.nodes[\"blockContainer\"].createAndFill()!;\n\n state.tr\n .insert(newBlockInsertionPos, newBlock)\n .scrollIntoView();\n state.tr.setSelection(\n new TextSelection(state.doc.resolve(newBlockContentPos)),\n );\n }\n\n return true;\n }\n\n return false;\n }),\n // Splits the current block, moving content inside that's after the cursor to a new text block below. Also\n // deletes the selection beforehand, if it's not empty.\n () =>\n commands.command(({ state, chain }) => {\n const blockInfo = getBlockInfoFromSelection(state);\n if (!blockInfo.isBlockContainer) {\n return false;\n }\n const { blockContent } = blockInfo;\n\n const selectionAtBlockStart =\n state.selection.$anchor.parentOffset === 0;\n const blockEmpty = blockContent.node.childCount === 0;\n\n if (!blockEmpty) {\n chain()\n .deleteSelection()\n .command(\n splitBlockCommand(\n state.selection.from,\n selectionAtBlockStart,\n selectionAtBlockStart,\n ),\n )\n .run();\n\n return true;\n }\n\n return false;\n }),\n ]);\n };\n\n return {\n Backspace: handleBackspace,\n Delete: handleDelete,\n Enter: () => handleEnter(),\n \"Shift-Enter\": () => handleEnter(true),\n // Always returning true for tab key presses ensures they're not captured by the browser. Otherwise, they blur the\n // editor since the browser will try to use tab for keyboard navigation.\n Tab: () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.getExtension(FormattingToolbarExtension)?.store\n .state ||\n this.options.editor.getExtension(FilePanelExtension)?.store\n .state !== undefined)\n // TODO need to check if the link toolbar is open or another alternative entirely\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n return nestBlock(this.options.editor);\n },\n \"Shift-Tab\": () => {\n if (\n this.options.tabBehavior !== \"prefer-indent\" &&\n (this.options.editor.getExtension(FormattingToolbarExtension)?.store\n .state ||\n this.options.editor.getExtension(FilePanelExtension)?.store\n .state !== undefined)\n // TODO need to check if the link toolbar is open or another alternative entirely\n // other menu types?\n ) {\n // don't handle tabs if a toolbar is shown, so we can tab into / out of it\n return false;\n }\n return this.editor.commands.liftListItem(\"blockContainer\");\n },\n \"Shift-Mod-ArrowUp\": () => {\n this.options.editor.moveBlocksUp();\n return true;\n },\n \"Shift-Mod-ArrowDown\": () => {\n this.options.editor.moveBlocksDown();\n return true;\n },\n \"Mod-z\": () => this.options.editor.undo(),\n \"Mod-y\": () => this.options.editor.redo(),\n \"Shift-Mod-z\": () => this.options.editor.redo(),\n };\n },\n});\n","import { Mark } from \"@tiptap/core\";\nimport { MarkSpec } from \"prosemirror-model\";\n\n// This copies the marks from @handlewithcare/prosemirror-suggest-changes,\n// but uses the Tiptap Mark API instead so we can use them in BlockNote\n\n// The ideal solution would be to not depend on tiptap nodes / marks, but be able to use prosemirror nodes / marks directly\n// this way we could directly use the exported marks from @handlewithcare/prosemirror-suggest-changes\nexport const SuggestionAddMark = Mark.create({\n name: \"insertion\",\n inclusive: false,\n excludes: \"deletion modification insertion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap, so this doesn't actually work (considered not critical)\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"insertion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n toDOM(mark, inline) {\n return [\n \"ins\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"ins\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionDeleteMark = Mark.create({\n name: \"deletion\",\n inclusive: false,\n excludes: \"insertion modification deletion\",\n addAttributes() {\n return {\n id: { default: null, validate: \"number\" }, // note: validate is supported in prosemirror but not in tiptap\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"deletion\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n\n // attrs: {\n // id: { validate: \"number\" },\n // },\n toDOM(mark, inline) {\n return [\n \"del\",\n {\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-inline\": String(inline),\n ...(!inline && { style: \"display: contents\" }), // changed to \"contents\" to make this work for table rows\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"del\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n\nexport const SuggestionModificationMark = Mark.create({\n name: \"modification\",\n inclusive: false,\n excludes: \"deletion insertion\",\n addAttributes() {\n // note: validate is supported in prosemirror but not in tiptap\n return {\n id: { default: null, validate: \"number\" },\n type: { validate: \"string\" },\n attrName: { default: null, validate: \"string|null\" },\n previousValue: { default: null },\n newValue: { default: null },\n };\n },\n extendMarkSchema(extension) {\n if (extension.name !== \"modification\") {\n return {};\n }\n return {\n blocknoteIgnore: true,\n inclusive: false,\n // attrs: {\n // id: { validate: \"number\" },\n // type: { validate: \"string\" },\n // attrName: { default: null, validate: \"string|null\" },\n // previousValue: { default: null },\n // newValue: { default: null },\n // },\n toDOM(mark, inline) {\n return [\n inline ? \"span\" : \"div\",\n {\n \"data-type\": \"modification\",\n \"data-id\": String(mark.attrs[\"id\"]),\n \"data-mod-type\": mark.attrs[\"type\"] as string,\n \"data-mod-prev-val\": JSON.stringify(mark.attrs[\"previousValue\"]),\n // TODO: Try to serialize marks with toJSON?\n \"data-mod-new-val\": JSON.stringify(mark.attrs[\"newValue\"]),\n },\n 0,\n ];\n },\n parseDOM: [\n {\n tag: \"span[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n newValue: node.dataset[\"modNewVal\"],\n };\n },\n },\n {\n tag: \"div[data-type='modification']\",\n getAttrs(node) {\n if (!node.dataset[\"id\"]) {\n return false;\n }\n return {\n id: parseInt(node.dataset[\"id\"], 10),\n type: node.dataset[\"modType\"],\n previousValue: node.dataset[\"modPrevVal\"],\n };\n },\n },\n ],\n } satisfies MarkSpec;\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport const TextAlignmentExtension = Extension.create({\n name: \"textAlignment\",\n\n addGlobalAttributes() {\n return [\n {\n // Generally text alignment is handled through props using the custom\n // blocks API. Tables are the only blocks that are created as TipTap\n // nodes and ported to blocks, so we need to add text alignment in a\n // separate extension.\n types: [\"tableCell\", \"tableHeader\"],\n attributes: {\n textAlignment: {\n default: \"left\",\n parseHTML: (element) => {\n return element.getAttribute(\"data-text-alignment\");\n },\n renderHTML: (attributes) => {\n if (attributes.textAlignment === \"left\") {\n return {};\n }\n return {\n \"data-text-alignment\": attributes.textAlignment,\n };\n },\n },\n },\n },\n ];\n },\n});\n","import { Extension } from \"@tiptap/core\";\nimport { getTextColorAttribute } from \"../../../blocks/defaultProps.js\";\n\nexport const TextColorExtension = Extension.create({\n name: \"blockTextColor\",\n\n addGlobalAttributes() {\n return [\n {\n types: [\"table\", \"tableCell\", \"tableHeader\"],\n attributes: {\n textColor: getTextColorAttribute(),\n },\n },\n ];\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nimport type { BlockNoteEditor } from \"../editor/BlockNoteEditor.js\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\n// Object containing all possible block attributes.\nconst BlockAttributes: Record<string, string> = {\n blockColor: \"data-block-color\",\n blockStyle: \"data-block-style\",\n id: \"data-id\",\n depth: \"data-depth\",\n depthChange: \"data-depth-change\",\n};\n\n/**\n * The main \"Block node\" documents consist of\n */\nexport const BlockContainer = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n editor: BlockNoteEditor<any, any, any>;\n}>({\n name: \"blockContainer\",\n group: \"blockGroupChild bnBlock\",\n // A block always contains content, and optionally a blockGroup which contains nested blocks\n content: \"blockContent blockGroup?\",\n // Ensures content-specific keyboard handlers trigger first.\n priority: 50,\n defining: true,\n marks: \"insertion modification deletion\",\n parseHTML() {\n return [\n {\n tag: \"div[data-node-type=\" + this.name + \"]\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n const attrs: Record<string, string> = {};\n for (const [nodeAttr, HTMLAttr] of Object.entries(BlockAttributes)) {\n if (element.getAttribute(HTMLAttr)) {\n attrs[nodeAttr] = element.getAttribute(HTMLAttr)!;\n }\n }\n\n return attrs;\n },\n },\n // Ignore `blockOuter` divs, but parse the `blockContainer` divs inside them.\n {\n tag: `div[data-node-type=\"blockOuter\"]`,\n skip: true,\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockOuter = document.createElement(\"div\");\n blockOuter.className = \"bn-block-outer\";\n blockOuter.setAttribute(\"data-node-type\", \"blockOuter\");\n for (const [attribute, value] of Object.entries(HTMLAttributes)) {\n if (attribute !== \"class\") {\n blockOuter.setAttribute(attribute, value);\n }\n }\n\n const blockHTMLAttributes = {\n ...(this.options.domAttributes?.block || {}),\n ...HTMLAttributes,\n };\n const block = document.createElement(\"div\");\n block.className = mergeCSSClasses(\"bn-block\", blockHTMLAttributes.class);\n block.setAttribute(\"data-node-type\", this.name);\n for (const [attribute, value] of Object.entries(blockHTMLAttributes)) {\n if (attribute !== \"class\") {\n block.setAttribute(attribute, value);\n }\n }\n\n blockOuter.appendChild(block);\n\n return {\n dom: blockOuter,\n contentDOM: block,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\nimport { BlockNoteDOMAttributes } from \"../schema/index.js\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\n\nexport const BlockGroup = Node.create<{\n domAttributes?: BlockNoteDOMAttributes;\n}>({\n name: \"blockGroup\",\n group: \"childContainer\",\n content: \"blockGroupChild+\",\n marks: \"deletion insertion modification\",\n parseHTML() {\n return [\n {\n tag: \"div\",\n getAttrs: (element) => {\n if (typeof element === \"string\") {\n return false;\n }\n\n if (element.getAttribute(\"data-node-type\") === \"blockGroup\") {\n // Null means the element matches, but we don't want to add any attributes to the node.\n return null;\n }\n\n return false;\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n const blockGroupHTMLAttributes = {\n ...(this.options.domAttributes?.blockGroup || {}),\n ...HTMLAttributes,\n };\n const blockGroup = document.createElement(\"div\");\n blockGroup.className = mergeCSSClasses(\n \"bn-block-group\",\n blockGroupHTMLAttributes.class,\n );\n blockGroup.setAttribute(\"data-node-type\", \"blockGroup\");\n for (const [attribute, value] of Object.entries(blockGroupHTMLAttributes)) {\n if (attribute !== \"class\") {\n blockGroup.setAttribute(attribute, value);\n }\n }\n\n return {\n dom: blockGroup,\n contentDOM: blockGroup,\n };\n },\n});\n","import { Node } from \"@tiptap/core\";\n\nexport const Doc = Node.create({\n name: \"doc\",\n topNode: true,\n content: \"blockGroup\",\n marks: \"insertion modification deletion\",\n});\n","import {\n AnyExtension as AnyTiptapExtension,\n extensions,\n Node,\n Extension as TiptapExtension,\n} from \"@tiptap/core\";\nimport { Gapcursor } from \"@tiptap/extension-gapcursor\";\nimport { Link } from \"@tiptap/extension-link\";\nimport { Text } from \"@tiptap/extension-text\";\nimport { createDropFileExtension } from \"../../../api/clipboard/fromClipboard/fileDropExtension.js\";\nimport { createPasteFromClipboardExtension } from \"../../../api/clipboard/fromClipboard/pasteExtension.js\";\nimport { createCopyToClipboardExtension } from \"../../../api/clipboard/toClipboard/copyExtension.js\";\nimport {\n BlockChangeExtension,\n DropCursorExtension,\n FilePanelExtension,\n ForkYDocExtension,\n FormattingToolbarExtension,\n HistoryExtension,\n LinkToolbarExtension,\n NodeSelectionKeyboardExtension,\n PlaceholderExtension,\n PreviousBlockTypeExtension,\n SchemaMigration,\n ShowSelectionExtension,\n SideMenuExtension,\n SuggestionMenu,\n TableHandlesExtension,\n TrailingNodeExtension,\n YCursorExtension,\n YSyncExtension,\n YUndoExtension,\n} from \"../../../extensions/index.js\";\nimport {\n DEFAULT_LINK_PROTOCOL,\n VALID_LINK_PROTOCOLS,\n} from \"../../../extensions/LinkToolbar/protocols.js\";\nimport {\n BackgroundColorExtension,\n HardBreak,\n KeyboardShortcutsExtension,\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n TextAlignmentExtension,\n TextColorExtension,\n UniqueID,\n} from \"../../../extensions/tiptap-extensions/index.js\";\nimport { BlockContainer, BlockGroup, Doc } from \"../../../pm-nodes/index.js\";\nimport {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../BlockNoteEditor.js\";\nimport { ExtensionFactoryInstance } from \"../../BlockNoteExtension.js\";\n\n// TODO remove linkify completely by vendoring the link extension & dropping linkifyjs as a dependency\nlet LINKIFY_INITIALIZED = false;\n\n/**\n * Get all the Tiptap extensions BlockNote is configured with by default\n */\nexport function getDefaultTiptapExtensions(\n editor: BlockNoteEditor<any, any, any>,\n options: BlockNoteEditorOptions<any, any, any>,\n) {\n const tiptapExtensions: AnyTiptapExtension[] = [\n extensions.ClipboardTextSerializer,\n extensions.Commands,\n extensions.Editable,\n extensions.FocusEvents,\n extensions.Tabindex,\n Gapcursor,\n\n UniqueID.configure({\n // everything from bnBlock group (nodes that represent a BlockNote block should have an id)\n types: [\"blockContainer\", \"columnList\", \"column\"],\n setIdAttribute: options.setIdAttribute,\n }),\n HardBreak,\n Text,\n\n // marks:\n SuggestionAddMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n Link.extend({\n inclusive: false,\n }).configure({\n defaultProtocol: DEFAULT_LINK_PROTOCOL,\n // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450\n protocols: LINKIFY_INITIALIZED ? [] : VALID_LINK_PROTOCOLS,\n }),\n ...(Object.values(editor.schema.styleSpecs).map((styleSpec) => {\n return styleSpec.implementation.mark.configure({\n editor: editor,\n });\n }) as any[]),\n\n TextColorExtension,\n\n BackgroundColorExtension,\n TextAlignmentExtension,\n\n // make sure escape blurs editor, so that we can tab to other elements in the host page (accessibility)\n TiptapExtension.create({\n name: \"OverrideEscape\",\n addKeyboardShortcuts: () => {\n return {\n Escape: () => {\n if (editor.getExtension(SuggestionMenu)?.shown()) {\n // escape should close the suggestion menu, but not blur the editor\n return false;\n }\n editor.blur();\n return true;\n },\n };\n },\n }),\n\n // nodes\n Doc,\n BlockContainer.configure({\n editor: editor,\n domAttributes: options.domAttributes,\n }),\n KeyboardShortcutsExtension.configure({\n editor: editor,\n tabBehavior: options.tabBehavior,\n }),\n BlockGroup.configure({\n domAttributes: options.domAttributes,\n }),\n ...Object.values(editor.schema.inlineContentSpecs)\n .filter((a) => a.config !== \"link\" && a.config !== \"text\")\n .map((inlineContentSpec) => {\n return inlineContentSpec.implementation!.node.configure({\n editor: editor,\n });\n }),\n\n ...Object.values(editor.schema.blockSpecs).flatMap((blockSpec) => {\n return [\n // the node extension implementations\n ...(\"node\" in blockSpec.implementation\n ? [\n (blockSpec.implementation.node as Node).configure({\n editor: editor,\n domAttributes: options.domAttributes,\n }),\n ]\n : []),\n ];\n }),\n createCopyToClipboardExtension(editor),\n createPasteFromClipboardExtension(\n editor,\n options.pasteHandler ||\n ((context: {\n defaultPasteHandler: (context?: {\n prioritizeMarkdownOverHTML?: boolean;\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => context.defaultPasteHandler()),\n ),\n createDropFileExtension(editor),\n ];\n\n LINKIFY_INITIALIZED = true;\n\n return tiptapExtensions;\n}\n\nexport function getDefaultExtensions(\n editor: BlockNoteEditor<any, any, any>,\n options: BlockNoteEditorOptions<any, any, any>,\n) {\n const extensions = [\n BlockChangeExtension(),\n DropCursorExtension(options),\n FilePanelExtension(options),\n FormattingToolbarExtension(options),\n LinkToolbarExtension(options),\n NodeSelectionKeyboardExtension(),\n PlaceholderExtension(options),\n ShowSelectionExtension(options),\n SideMenuExtension(options),\n SuggestionMenu(options),\n ...(options.trailingBlock !== false ? [TrailingNodeExtension()] : []),\n ] as ExtensionFactoryInstance[];\n\n if (options.collaboration) {\n extensions.push(ForkYDocExtension(options.collaboration));\n if (options.collaboration.provider?.awareness) {\n extensions.push(YCursorExtension(options.collaboration));\n }\n extensions.push(YSyncExtension(options.collaboration));\n extensions.push(YUndoExtension(options.collaboration));\n extensions.push(SchemaMigration(options.collaboration));\n } else {\n // YUndo is not compatible with ProseMirror's history plugin\n extensions.push(HistoryExtension());\n }\n\n if (\"table\" in editor.schema.blockSpecs) {\n extensions.push(TableHandlesExtension(options));\n }\n\n if (options.animations !== false) {\n extensions.push(PreviousBlockTypeExtension());\n }\n\n return extensions;\n}\n","import {\n InputRule,\n inputRules as inputRulesPlugin,\n} from \"@handlewithcare/prosemirror-inputrules\";\nimport {\n AnyExtension as AnyTiptapExtension,\n Extension as TiptapExtension,\n} from \"@tiptap/core\";\nimport { keymap } from \"@tiptap/pm/keymap\";\nimport { Plugin } from \"prosemirror-state\";\nimport { updateBlockTr } from \"../../../api/blockManipulation/commands/updateBlock/updateBlock.js\";\nimport { getBlockInfoFromTransaction } from \"../../../api/getBlockInfoFromPos.js\";\nimport { sortByDependencies } from \"../../../util/topo-sort.js\";\nimport type {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n} from \"../../BlockNoteEditor.js\";\nimport type {\n Extension,\n ExtensionFactoryInstance,\n ExtensionFactory,\n} from \"../../BlockNoteExtension.js\";\nimport { originalFactorySymbol } from \"./symbol.js\";\nimport {\n getDefaultExtensions,\n getDefaultTiptapExtensions,\n} from \"./extensions.js\";\n\nexport class ExtensionManager {\n /**\n * A set of extension keys which are disabled by the options\n */\n private disabledExtensions = new Set<string>();\n /**\n * A list of all the extensions that are registered to the editor\n */\n private extensions: Extension[] = [];\n /**\n * A map of all the abort controllers for each extension that has an init method defined\n */\n private abortMap = new Map<Extension, AbortController>();\n /**\n * A map of all the extension factories that are registered to the editor\n */\n private extensionFactories = new Map<ExtensionFactory, Extension>();\n /**\n * Because a single blocknote extension can both have it's own prosemirror plugins & additional generated ones (e.g. keymap & input rules plugins)\n * We need to keep track of all the plugins for each extension, so that we can remove them when the extension is unregistered\n */\n private extensionPlugins: Map<Extension, Plugin[]> = new Map();\n\n constructor(\n private editor: BlockNoteEditor<any, any, any>,\n private options: BlockNoteEditorOptions<any, any, any>,\n ) {\n /**\n * When the editor is first mounted, we need to initialize all the extensions\n */\n editor.onMount(() => {\n for (const extension of this.extensions) {\n // If the extension has an init function, we can initialize it, otherwise, it is already added to the editor\n if (extension.mount) {\n // We create an abort controller for each extension, so that we can abort the extension when the editor is unmounted\n const abortController = new window.AbortController();\n const unmountCallback = extension.mount({\n dom: editor.prosemirrorView.dom,\n root: editor.prosemirrorView.root,\n signal: abortController.signal,\n });\n // If the extension returns a method to unmount it, we can register it to be called when the abort controller is aborted\n if (unmountCallback) {\n abortController.signal.addEventListener(\"abort\", () => {\n unmountCallback();\n });\n }\n // Keep track of the abort controller for each extension, so that we can abort it when the editor is unmounted\n this.abortMap.set(extension, abortController);\n }\n }\n });\n\n /**\n * When the editor is unmounted, we need to abort all the extensions' abort controllers\n */\n editor.onUnmount(() => {\n for (const [extension, abortController] of this.abortMap.entries()) {\n // No longer track the abort controller for this extension\n this.abortMap.delete(extension);\n // Abort each extension's abort controller\n abortController.abort();\n }\n });\n\n // TODO do disabled extensions need to be only for editor base extensions? Or all of them?\n this.disabledExtensions = new Set(options.disableExtensions || []);\n\n // Add the default extensions\n for (const extension of getDefaultExtensions(this.editor, this.options)) {\n this.addExtension(extension);\n }\n\n // Add the extensions from the options\n for (const extension of this.options.extensions ?? []) {\n this.addExtension(extension);\n }\n\n // Add the extensions from blocks specs\n for (const block of Object.values(this.editor.schema.blockSpecs)) {\n for (const extension of block.extensions ?? []) {\n this.addExtension(extension);\n }\n }\n }\n\n /**\n * Register one or more extensions to the editor after the editor is initialized.\n *\n * This allows users to switch on & off extensions \"at runtime\".\n */\n public registerExtension(\n extension:\n | Extension\n | ExtensionFactoryInstance\n | (Extension | ExtensionFactoryInstance)[],\n ): void {\n const extensions = ([] as (Extension | ExtensionFactoryInstance)[])\n .concat(extension)\n .filter(Boolean) as (Extension | ExtensionFactoryInstance)[];\n\n if (!extensions.length) {\n // eslint-disable-next-line no-console\n console.warn(`No extensions found to register`, extension);\n return;\n }\n\n const registeredExtensions = extensions\n .map((extension) => this.addExtension(extension))\n .filter(Boolean) as Extension[];\n\n const pluginsToAdd = new Set<Plugin>();\n for (const extension of registeredExtensions) {\n if (extension?.tiptapExtensions) {\n // This is necessary because this can only switch out prosemirror plugins at runtime,\n // it can't switch out Tiptap extensions since that can have more widespread effects (since a Tiptap extension can even add/remove to the schema).\n\n // eslint-disable-next-line no-console\n console.warn(\n `Extension ${extension.key} has tiptap extensions, but these cannot be changed after initializing the editor. Please separate the extension into multiple extensions if you want to add them, or re-initialize the editor.`,\n extension,\n );\n }\n\n if (extension?.inputRules?.length) {\n // This is necessary because input rules are defined in a single prosemirror plugin which cannot be re-initialized.\n // eslint-disable-next-line no-console\n console.warn(\n `Extension ${extension.key} has input rules, but these cannot be changed after initializing the editor. Please separate the extension into multiple extensions if you want to add them, or re-initialize the editor.`,\n extension,\n );\n }\n\n this.getProsemirrorPluginsFromExtension(extension).plugins.forEach(\n (plugin) => {\n pluginsToAdd.add(plugin);\n },\n );\n }\n\n // TODO there isn't a great way to do sorting right now. This is something that should be improved in the future.\n // So, we just append to the end of the list for now.\n this.updatePlugins((plugins) => [...plugins, ...pluginsToAdd]);\n }\n\n /**\n * Register an extension to the editor\n * @param extension - The extension to register\n * @returns The extension instance\n */\n private addExtension(\n extension: Extension | ExtensionFactoryInstance,\n ): Extension | undefined {\n let instance: Extension;\n if (typeof extension === \"function\") {\n instance = extension({ editor: this.editor });\n } else {\n instance = extension;\n }\n\n if (!instance || this.disabledExtensions.has(instance.key)) {\n return undefined as any;\n }\n\n // Now that we know that the extension is not disabled, we can add it to the extension factories\n if (typeof extension === \"function\") {\n const originalFactory = (instance as any)[originalFactorySymbol] as (\n ...args: any[]\n ) => ExtensionFactoryInstance;\n\n if (typeof originalFactory === \"function\") {\n this.extensionFactories.set(originalFactory, instance);\n }\n }\n\n this.extensions.push(instance);\n\n return instance as any;\n }\n\n /**\n * Resolve an extension or a list of extensions into a list of extension instances\n * @param toResolve - The extension or list of extensions to resolve\n * @returns A list of extension instances\n */\n private resolveExtensions(\n toResolve:\n | undefined\n | string\n | Extension\n | ExtensionFactory\n | (Extension | ExtensionFactory | string | undefined)[],\n ): Extension[] {\n const extensions = [] as Extension[];\n if (typeof toResolve === \"function\") {\n const instance = this.extensionFactories.get(toResolve);\n if (instance) {\n extensions.push(instance);\n }\n } else if (Array.isArray(toResolve)) {\n for (const extension of toResolve) {\n extensions.push(...this.resolveExtensions(extension));\n }\n } else if (typeof toResolve === \"object\" && \"key\" in toResolve) {\n extensions.push(toResolve);\n } else if (typeof toResolve === \"string\") {\n const instance = this.extensions.find((e) => e.key === toResolve);\n if (instance) {\n extensions.push(instance);\n }\n }\n return extensions;\n }\n\n /**\n * Unregister an extension from the editor\n * @param toUnregister - The extension to unregister\n * @returns void\n */\n public unregisterExtension(\n toUnregister:\n | undefined\n | string\n | Extension\n | ExtensionFactory\n | (Extension | ExtensionFactory | string | undefined)[],\n ): void {\n const extensions = this.resolveExtensions(toUnregister);\n\n if (!extensions.length) {\n // eslint-disable-next-line no-console\n console.warn(`No extensions found to unregister`, toUnregister);\n return;\n }\n let didWarn = false;\n\n const pluginsToRemove = new Set<Plugin>();\n for (const extension of extensions) {\n this.extensions = this.extensions.filter((e) => e !== extension);\n this.extensionFactories.forEach((instance, factory) => {\n if (instance === extension) {\n this.extensionFactories.delete(factory);\n }\n });\n this.abortMap.get(extension)?.abort();\n this.abortMap.delete(extension);\n\n const plugins = this.extensionPlugins.get(extension);\n plugins?.forEach((plugin) => {\n pluginsToRemove.add(plugin);\n });\n this.extensionPlugins.delete(extension);\n\n if (extension.tiptapExtensions && !didWarn) {\n didWarn = true;\n // eslint-disable-next-line no-console\n console.warn(\n `Extension ${extension.key} has tiptap extensions, but they will not be removed. Please separate the extension into multiple extensions if you want to remove them, or re-initialize the editor.`,\n toUnregister,\n );\n }\n }\n\n this.updatePlugins((plugins) =>\n plugins.filter((plugin) => !pluginsToRemove.has(plugin)),\n );\n }\n\n /**\n * Allows resetting the current prosemirror state's plugins\n * @param update - A function that takes the current plugins and returns the new plugins\n * @returns void\n */\n private updatePlugins(update: (plugins: Plugin[]) => Plugin[]): void {\n const currentState = this.editor.prosemirrorState;\n\n const state = currentState.reconfigure({\n plugins: update(currentState.plugins.slice()),\n });\n\n this.editor.prosemirrorView.updateState(state);\n }\n\n /**\n * Get all the extensions that are registered to the editor\n */\n public getTiptapExtensions(): AnyTiptapExtension[] {\n // Start with the default tiptap extensions\n const tiptapExtensions = getDefaultTiptapExtensions(\n this.editor,\n this.options,\n );\n // TODO filter out the default extensions via the disabledExtensions set?\n\n const getPriority = sortByDependencies(this.extensions);\n\n const inputRulesByPriority = new Map<number, InputRule[]>();\n for (const extension of this.extensions) {\n if (extension.tiptapExtensions) {\n tiptapExtensions.push(...extension.tiptapExtensions);\n }\n\n const priority = getPriority(extension.key);\n\n const { plugins: prosemirrorPlugins, inputRules } =\n this.getProsemirrorPluginsFromExtension(extension);\n // Sometimes a blocknote extension might need to make additional prosemirror plugins, so we generate them here\n if (prosemirrorPlugins.length) {\n tiptapExtensions.push(\n TiptapExtension.create({\n name: extension.key,\n priority,\n addProseMirrorPlugins: () => prosemirrorPlugins,\n }),\n );\n }\n if (inputRules.length) {\n if (!inputRulesByPriority.has(priority)) {\n inputRulesByPriority.set(priority, []);\n }\n inputRulesByPriority.get(priority)!.push(...inputRules);\n }\n }\n\n // Collect all input rules into 1 extension to reduce conflicts\n tiptapExtensions.push(\n TiptapExtension.create({\n name: \"blocknote-input-rules\",\n addProseMirrorPlugins() {\n const rules = [] as InputRule[];\n Array.from(inputRulesByPriority.keys())\n // We sort the rules by their priority (the key)\n .sort()\n .reverse()\n .forEach((priority) => {\n // Append in reverse priority order\n rules.push(...inputRulesByPriority.get(priority)!);\n });\n return [inputRulesPlugin({ rules })];\n },\n }),\n );\n\n // Add any tiptap extensions from the `_tiptapOptions`\n for (const extension of this.options._tiptapOptions?.extensions ?? []) {\n tiptapExtensions.push(extension);\n }\n\n return tiptapExtensions;\n }\n\n /**\n * This maps a blocknote extension into an array of Prosemirror plugins if it has any of the following:\n * - plugins\n * - keyboard shortcuts\n * - input rules\n */\n private getProsemirrorPluginsFromExtension(extension: Extension): {\n plugins: Plugin[];\n inputRules: InputRule[];\n } {\n const plugins: Plugin[] = [...(extension.prosemirrorPlugins ?? [])];\n const inputRules: InputRule[] = [];\n if (\n !extension.prosemirrorPlugins?.length &&\n !Object.keys(extension.keyboardShortcuts || {}).length &&\n !extension.inputRules?.length\n ) {\n // We can bail out early if the extension has no features to add to the tiptap editor\n return { plugins, inputRules };\n }\n\n this.extensionPlugins.set(extension, plugins);\n\n if (extension.inputRules?.length) {\n inputRules.push(\n ...extension.inputRules.map((inputRule) => {\n return new InputRule(inputRule.find, (state, match, start, end) => {\n const replaceWith = inputRule.replace({\n match,\n range: { from: start, to: end },\n editor: this.editor,\n });\n if (replaceWith) {\n const cursorPosition = this.editor.getTextCursorPosition();\n\n if (\n this.editor.schema.blockSchema[cursorPosition.block.type]\n .content !== \"inline\"\n ) {\n return null;\n }\n\n const blockInfo = getBlockInfoFromTransaction(state.tr);\n const tr = state.tr.deleteRange(start, end);\n\n updateBlockTr(tr, blockInfo.bnBlock.beforePos, replaceWith);\n return tr;\n }\n return null;\n });\n }),\n );\n }\n\n if (Object.keys(extension.keyboardShortcuts || {}).length) {\n plugins.push(\n keymap(\n Object.fromEntries(\n Object.entries(extension.keyboardShortcuts!).map(([key, value]) => [\n key,\n () => value({ editor: this.editor }),\n ]),\n ),\n ),\n );\n }\n\n return { plugins, inputRules };\n }\n\n /**\n * Get all extensions\n */\n public getExtensions(): Map<string, Extension> {\n return new Map(\n this.extensions.map((extension) => [extension.key, extension]),\n );\n }\n\n /**\n * Get a specific extension by it's instance\n */\n public getExtension<\n const Ext extends Extension | ExtensionFactory = Extension,\n >(\n extension: string,\n ):\n | (Ext extends Extension\n ? Ext\n : Ext extends ExtensionFactory\n ? ReturnType<ReturnType<Ext>>\n : never)\n | undefined;\n public getExtension<const T extends ExtensionFactory>(\n extension: T,\n ): ReturnType<ReturnType<T>> | undefined;\n public getExtension<const T extends ExtensionFactory | string = string>(\n extension: T,\n ):\n | (T extends ExtensionFactory\n ? ReturnType<ReturnType<T>>\n : T extends string\n ? Extension\n : never)\n | undefined {\n if (typeof extension === \"string\") {\n const instance = this.extensions.find((e) => e.key === extension);\n if (!instance) {\n return undefined;\n }\n return instance as any;\n } else if (typeof extension === \"function\") {\n const instance = this.extensionFactories.get(extension);\n if (!instance) {\n return undefined;\n }\n return instance as any;\n }\n throw new Error(`Invalid extension type: ${typeof extension}`);\n }\n\n /**\n * Check if an extension exists\n */\n public hasExtension(key: string | Extension | ExtensionFactory): boolean {\n if (typeof key === \"string\") {\n return this.extensions.some((e) => e.key === key);\n } else if (typeof key === \"object\" && \"key\" in key) {\n return this.extensions.some((e) => e.key === key.key);\n } else if (typeof key === \"function\") {\n return this.extensionFactories.has(key);\n }\n return false;\n }\n}\n","import { TextSelection, type Transaction } from \"prosemirror-state\";\nimport { TableMap } from \"prosemirror-tables\";\n\nimport { Block } from \"../../../blocks/defaultBlocks.js\";\nimport { Selection } from \"../../../editor/selectionTypes.js\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { getBlockInfo, getNearestBlockPos } from \"../../getBlockInfoFromPos.js\";\nimport {\n nodeToBlock,\n prosemirrorSliceToSlicedBlocks,\n} from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getSelection<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): Selection<BSchema, I, S> | undefined {\n const pmSchema = getPmSchema(tr);\n // Return undefined if the selection is collapsed or a node is selected.\n if (tr.selection.empty || \"node\" in tr.selection) {\n return undefined;\n }\n\n const $startBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.from).posBeforeNode,\n );\n const $endBlockBeforePos = tr.doc.resolve(\n getNearestBlockPos(tr.doc, tr.selection.to).posBeforeNode,\n );\n\n // Converts the node at the given index and depth around `$startBlockBeforePos`\n // to a block. Used to get blocks at given indices at the shared depth and\n // at the depth of `$startBlockBeforePos`.\n const indexToBlock = (\n index: number,\n depth?: number,\n ): Block<BSchema, I, S> => {\n const pos = $startBlockBeforePos.posAtIndex(index, depth);\n const node = tr.doc.resolve(pos).nodeAfter;\n\n if (!node) {\n throw new Error(\n `Error getting selection - node not found at position ${pos}`,\n );\n }\n\n return nodeToBlock(node, pmSchema);\n };\n\n const blocks: Block<BSchema, I, S>[] = [];\n // Minimum depth at which the blocks share a common ancestor.\n const sharedDepth = $startBlockBeforePos.sharedDepth($endBlockBeforePos.pos);\n const startIndex = $startBlockBeforePos.index(sharedDepth);\n const endIndex = $endBlockBeforePos.index(sharedDepth);\n\n // In most cases, we want to return the blocks spanned by the selection at the\n // shared depth. However, when the block in which the selection starts is at a\n // higher depth than the shared depth, we omit the first block at the shared\n // depth. Instead, we include the first block at its depth, and any blocks at\n // a higher index up to the shared depth. The following example illustrates\n // this:\n // - id-0\n // - id-1\n // - >|id-2\n // - id-3\n // - id-4\n // - id-5\n // - id-6\n // - id-7\n // - id-8\n // - id-9|<\n // - id-10\n // Here, each block is represented by its ID, and the selection is represented\n // by the `>|` and `|<` markers. So the selection starts in block `id-2` and\n // ends in block `id-8`. In this case, the shared depth is 0, since the blocks\n // `id-6`, `id-7`, and `id-8` set the shared depth, as they are the least\n // nested blocks spanned by the selection. Therefore, these blocks are all\n // added to the `blocks` array. However, the selection starts in block `id-2`,\n // which is at a higher depth than the shared depth. So we add block `id-2` to\n // the `blocks` array, as well as any later siblings (in this case, `id-3`),\n // and move up one level of depth. The ancestor of block `id-2` at this depth\n // is block `id-1`, so we add all its later siblings to the `blocks` array as\n // well, again moving up one level of depth. Since we're now at the shared\n // depth, we are done. The final `blocks` array for this example would be:\n // [ id-2, id-3, id-4, id-6, id-7, id-8, id-9 ]\n if ($startBlockBeforePos.depth > sharedDepth) {\n // Adds the block that the selection starts in.\n blocks.push(nodeToBlock($startBlockBeforePos.nodeAfter!, pmSchema));\n\n // Traverses all depths from the depth of the block in which the selection\n // starts, up to the shared depth.\n for (let depth = $startBlockBeforePos.depth; depth > sharedDepth; depth--) {\n const parentNode = $startBlockBeforePos.node(depth);\n\n if (parentNode.type.isInGroup(\"childContainer\")) {\n const startIndexAtDepth = $startBlockBeforePos.index(depth) + 1;\n const childCountAtDepth = $startBlockBeforePos.node(depth).childCount;\n\n // Adds all blocks after the index of the block in which the selection\n // starts (or its ancestors at lower depths).\n for (let i = startIndexAtDepth; i < childCountAtDepth; i++) {\n blocks.push(indexToBlock(i, depth));\n }\n }\n }\n } else {\n // Adds the first block spanned by the selection at the shared depth.\n blocks.push(indexToBlock(startIndex, sharedDepth));\n }\n\n // Adds all blocks spanned by the selection at the shared depth, excluding\n // the first.\n for (let i = startIndex + 1; i <= endIndex; i++) {\n blocks.push(indexToBlock(i, sharedDepth));\n }\n\n if (blocks.length === 0) {\n throw new Error(\n `Error getting selection - selection doesn't span any blocks (${tr.selection})`,\n );\n }\n\n return {\n blocks,\n };\n}\n\nexport function setSelection(\n tr: Transaction,\n startBlock: BlockIdentifier,\n endBlock: BlockIdentifier,\n) {\n const startBlockId =\n typeof startBlock === \"string\" ? startBlock : startBlock.id;\n const endBlockId = typeof endBlock === \"string\" ? endBlock : endBlock.id;\n const pmSchema = getPmSchema(tr);\n const schema = getBlockNoteSchema(pmSchema);\n\n if (startBlockId === endBlockId) {\n throw new Error(\n `Attempting to set selection with the same anchor and head blocks (id ${startBlockId})`,\n );\n }\n const anchorPosInfo = getNodeById(startBlockId, tr.doc);\n if (!anchorPosInfo) {\n throw new Error(`Block with ID ${startBlockId} not found`);\n }\n const headPosInfo = getNodeById(endBlockId, tr.doc);\n if (!headPosInfo) {\n throw new Error(`Block with ID ${endBlockId} not found`);\n }\n\n const anchorBlockInfo = getBlockInfo(anchorPosInfo);\n const headBlockInfo = getBlockInfo(headPosInfo);\n\n const anchorBlockConfig =\n schema.blockSchema[\n anchorBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n const headBlockConfig =\n schema.blockSchema[\n headBlockInfo.blockNoteType as keyof typeof schema.blockSchema\n ];\n\n if (\n !anchorBlockInfo.isBlockContainer ||\n anchorBlockConfig.content === \"none\"\n ) {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${startBlockId})`,\n );\n }\n if (!headBlockInfo.isBlockContainer || headBlockConfig.content === \"none\") {\n throw new Error(\n `Attempting to set selection anchor in block without content (id ${endBlockId})`,\n );\n }\n\n let startPos: number;\n let endPos: number;\n\n if (anchorBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(anchorBlockInfo.blockContent.node);\n const firstCellPos =\n anchorBlockInfo.blockContent.beforePos +\n tableMap.positionAt(0, 0, anchorBlockInfo.blockContent.node) +\n 1;\n startPos = firstCellPos + 2;\n } else {\n startPos = anchorBlockInfo.blockContent.beforePos + 1;\n }\n\n if (headBlockConfig.content === \"table\") {\n const tableMap = TableMap.get(headBlockInfo.blockContent.node);\n const lastCellPos =\n headBlockInfo.blockContent.beforePos +\n tableMap.positionAt(\n tableMap.height - 1,\n tableMap.width - 1,\n headBlockInfo.blockContent.node,\n ) +\n 1;\n const lastCellNodeSize = tr.doc.resolve(lastCellPos).nodeAfter!.nodeSize;\n endPos = lastCellPos + lastCellNodeSize - 2;\n } else {\n endPos = headBlockInfo.blockContent.afterPos - 1;\n }\n\n // TODO: We should polish up the `MultipleNodeSelection` and use that instead.\n // Right now it's missing a few things like a jsonID and styling to show\n // which nodes are selected. `TextSelection` is ok for now, but has the\n // restriction that the start/end blocks must have content.\n tr.setSelection(TextSelection.create(tr.doc, startPos, endPos));\n}\n\nexport function getSelectionCutBlocks(tr: Transaction) {\n // TODO: fix image node selection\n\n const pmSchema = getPmSchema(tr);\n let start = tr.selection.$from;\n let end = tr.selection.$to;\n\n // the selection moves below are used to make sure `prosemirrorSliceToSlicedBlocks` returns\n // the correct information about whether content is cut at the start or end of a block\n\n // if the end is at the end of a node (|</span></p>) move it forward so we include all closing tags (</span></p>|)\n while (end.parentOffset >= end.parent.nodeSize - 2 && end.depth > 0) {\n end = tr.doc.resolve(end.pos + 1);\n }\n\n // if the end is at the start of an empty node (</span></p><p>|) move it backwards so we drop empty start tags (</span></p>|)\n while (end.parentOffset === 0 && end.depth > 0) {\n end = tr.doc.resolve(end.pos - 1);\n }\n\n // if the start is at the start of a node (<p><span>|) move it backwards so we include all open tags (|<p><span>)\n while (start.parentOffset === 0 && start.depth > 0) {\n start = tr.doc.resolve(start.pos - 1);\n }\n\n // if the start is at the end of a node (|</p><p><span>|) move it forwards so we drop all closing tags (|<p><span>)\n while (start.parentOffset >= start.parent.nodeSize - 2 && start.depth > 0) {\n start = tr.doc.resolve(start.pos + 1);\n }\n\n const selectionInfo = prosemirrorSliceToSlicedBlocks(\n tr.doc.slice(start.pos, end.pos, true),\n pmSchema,\n );\n\n return {\n _meta: {\n startPos: start.pos,\n endPos: end.pos,\n },\n ...selectionInfo,\n };\n}\n","import type { Node } from \"prosemirror-model\";\nimport {\n NodeSelection,\n TextSelection,\n type Transaction,\n} from \"prosemirror-state\";\nimport type { TextCursorPosition } from \"../../../editor/cursorPositionTypes.js\";\nimport type {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport { UnreachableCaseError } from \"../../../util/typescript.js\";\nimport {\n getBlockInfo,\n getBlockInfoFromTransaction,\n} from \"../../getBlockInfoFromPos.js\";\nimport { nodeToBlock } from \"../../nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../nodeUtil.js\";\nimport { getBlockNoteSchema, getPmSchema } from \"../../pmUtil.js\";\n\nexport function getTextCursorPosition<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(tr: Transaction): TextCursorPosition<BSchema, I, S> {\n const { bnBlock } = getBlockInfoFromTransaction(tr);\n const pmSchema = getPmSchema(tr.doc);\n\n const resolvedPos = tr.doc.resolve(bnBlock.beforePos);\n // Gets previous blockContainer node at the same nesting level, if the current node isn't the first child.\n const prevNode = resolvedPos.nodeBefore;\n\n // Gets next blockContainer node at the same nesting level, if the current node isn't the last child.\n const nextNode = tr.doc.resolve(bnBlock.afterPos).nodeAfter;\n\n // Gets parent blockContainer node, if the current node is nested.\n let parentNode: Node | undefined = undefined;\n if (resolvedPos.depth > 1) {\n // for nodes nested in bnBlocks\n parentNode = resolvedPos.node();\n if (!parentNode.type.isInGroup(\"bnBlock\")) {\n // for blockGroups, we need to go one level up\n parentNode = resolvedPos.node(resolvedPos.depth - 1);\n }\n }\n\n return {\n block: nodeToBlock(bnBlock.node, pmSchema),\n prevBlock: prevNode === null ? undefined : nodeToBlock(prevNode, pmSchema),\n nextBlock: nextNode === null ? undefined : nodeToBlock(nextNode, pmSchema),\n parentBlock:\n parentNode === undefined ? undefined : nodeToBlock(parentNode, pmSchema),\n };\n}\n\nexport function setTextCursorPosition(\n tr: Transaction,\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n) {\n const id = typeof targetBlock === \"string\" ? targetBlock : targetBlock.id;\n const pmSchema = getPmSchema(tr.doc);\n const schema = getBlockNoteSchema(pmSchema);\n\n const posInfo = getNodeById(id, tr.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${id} not found`);\n }\n\n const info = getBlockInfo(posInfo);\n\n const contentType: \"none\" | \"inline\" | \"table\" =\n schema.blockSchema[info.blockNoteType]!.content;\n\n if (info.isBlockContainer) {\n const blockContent = info.blockContent;\n if (contentType === \"none\") {\n tr.setSelection(NodeSelection.create(tr.doc, blockContent.beforePos));\n return;\n }\n\n if (contentType === \"inline\") {\n if (placement === \"start\") {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 1),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 1),\n );\n }\n } else if (contentType === \"table\") {\n if (placement === \"start\") {\n // Need to offset the position as we have to get through the `tableRow`\n // and `tableCell` nodes to get to the `tableParagraph` node we want to\n // set the selection in.\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.beforePos + 4),\n );\n } else {\n tr.setSelection(\n TextSelection.create(tr.doc, blockContent.afterPos - 4),\n );\n }\n } else {\n throw new UnreachableCaseError(contentType);\n }\n } else {\n const child =\n placement === \"start\"\n ? info.childContainer.node.firstChild!\n : info.childContainer.node.lastChild!;\n\n setTextCursorPosition(tr, child.attrs.id, placement);\n }\n}\n","import {\n getSelection,\n getSelectionCutBlocks,\n setSelection,\n} from \"../../api/blockManipulation/selections/selection.js\";\nimport {\n getTextCursorPosition,\n setTextCursorPosition,\n} from \"../../api/blockManipulation/selections/textCursorPosition.js\";\nimport { isNodeSelection, posToDOMRect } from \"@tiptap/core\";\nimport {\n BlockIdentifier,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport {\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../../blocks/defaultBlocks.js\";\nimport { Selection } from \"../selectionTypes.js\";\nimport { TextCursorPosition } from \"../cursorPositionTypes.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class SelectionManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned data will contain the entire block.\n */\n public getSelection(): Selection<BSchema, ISchema, SSchema> | undefined {\n return this.editor.transact((tr) => getSelection(tr));\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned block will be\n * only the part of the block that is included in the selection.\n */\n public getSelectionCutBlocks() {\n return this.editor.transact((tr) => getSelectionCutBlocks(tr));\n }\n\n /**\n * Sets the selection to a range of blocks.\n * @param startBlock The identifier of the block that should be the start of the selection.\n * @param endBlock The identifier of the block that should be the end of the selection.\n */\n public setSelection(startBlock: BlockIdentifier, endBlock: BlockIdentifier) {\n return this.editor.transact((tr) => setSelection(tr, startBlock, endBlock));\n }\n\n /**\n * Gets a snapshot of the current text cursor position.\n * @returns A snapshot of the current text cursor position.\n */\n public getTextCursorPosition(): TextCursorPosition<\n BSchema,\n ISchema,\n SSchema\n > {\n return this.editor.transact((tr) => getTextCursorPosition(tr));\n }\n\n /**\n * Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could\n * not be found.\n * @param targetBlock The identifier of an existing block that the text cursor should be moved to.\n * @param placement Whether the text cursor should be placed at the start or end of the block.\n */\n public setTextCursorPosition(\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n ) {\n return this.editor.transact((tr) =>\n setTextCursorPosition(tr, targetBlock, placement),\n );\n }\n\n /**\n * Gets the bounding box of the current selection.\n */\n public getSelectionBoundingBox() {\n if (!this.editor.prosemirrorView) {\n return undefined;\n }\n\n const { selection } = this.editor.prosemirrorState;\n\n // support for CellSelections\n const { ranges } = selection;\n const from = Math.min(...ranges.map((range) => range.$from.pos));\n const to = Math.max(...ranges.map((range) => range.$to.pos));\n\n if (isNodeSelection(selection)) {\n const node = this.editor.prosemirrorView.nodeDOM(from) as HTMLElement;\n if (node) {\n return node.getBoundingClientRect();\n }\n }\n\n return posToDOMRect(\n this.editor.prosemirrorView,\n from,\n to,\n ).toJSON() as DOMRect;\n }\n}\n","import { Command, Transaction } from \"prosemirror-state\";\nimport type { YUndoExtension } from \"../../extensions/Collaboration/YUndo.js\";\nimport type { HistoryExtension } from \"../../extensions/History/History.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class StateManager {\n constructor(private editor: BlockNoteEditor<any, any, any>) {}\n\n /**\n * Stores the currently active transaction, which is the accumulated transaction from all {@link dispatch} calls during a {@link transact} calls\n */\n private activeTransaction: Transaction | null = null;\n\n /**\n * For any command that can be executed, you can check if it can be executed by calling `editor.can(command)`.\n * @example\n * ```ts\n * if (editor.can(editor.undo)) {\n * // show button\n * } else {\n * // hide button\n * }\n */\n public can(cb: () => boolean) {\n try {\n this.isInCan = true;\n return cb();\n } finally {\n this.isInCan = false;\n }\n }\n\n // Flag to indicate if we're in a `can` call\n private isInCan = false;\n\n /**\n * Execute a prosemirror command. This is mostly for backwards compatibility with older code.\n *\n * @note You should prefer the {@link transact} method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.\n *\n * @example\n * ```ts\n * editor.exec((state, dispatch, view) => {\n * dispatch(state.tr.insertText(\"Hello, world!\"));\n * });\n * ```\n */\n public exec(command: Command) {\n if (this.activeTransaction) {\n throw new Error(\n \"`exec` should not be called within a `transact` call, move the `exec` call outside of the `transact` call\",\n );\n }\n if (this.isInCan) {\n return this.canExec(command);\n }\n const state = this.prosemirrorState;\n const view = this.prosemirrorView;\n const dispatch = (tr: Transaction) => this.prosemirrorView.dispatch(tr);\n\n return command(state, dispatch, view);\n }\n\n /**\n * Check if a command can be executed. A command should return `false` if it is not valid in the current state.\n *\n * @example\n * ```ts\n * if (editor.canExec(command)) {\n * // show button\n * } else {\n * // hide button\n * }\n * ```\n */\n public canExec(command: Command): boolean {\n if (this.activeTransaction) {\n throw new Error(\n \"`canExec` should not be called within a `transact` call, move the `canExec` call outside of the `transact` call\",\n );\n }\n const state = this.prosemirrorState;\n const view = this.prosemirrorView;\n\n return command(state, undefined, view);\n }\n\n /**\n * Execute a function within a \"blocknote transaction\".\n * All changes to the editor within the transaction will be grouped together, so that\n * we can dispatch them as a single operation (thus creating only a single undo step)\n *\n * @note There is no need to dispatch the transaction, as it will be automatically dispatched when the callback is complete.\n *\n * @example\n * ```ts\n * // All changes to the editor will be grouped together\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * // These two operations will be grouped together in a single undo step\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * });\n * });\n * ```\n */\n public transact<T>(\n callback: (\n /**\n * The current active transaction, this will automatically be dispatched to the editor when the callback is complete\n * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.\n */\n tr: Transaction,\n ) => T,\n ): T {\n if (this.activeTransaction) {\n // Already in a transaction, so we can just callback immediately\n return callback(this.activeTransaction);\n }\n\n try {\n // Enter transaction mode, by setting a starting transaction\n this.activeTransaction = this.editor._tiptapEditor.state.tr;\n\n // Capture all dispatch'd transactions\n const result = callback(this.activeTransaction);\n\n // Any transactions captured by the `dispatch` call will be stored in `this.activeTransaction`\n const activeTr = this.activeTransaction;\n\n this.activeTransaction = null;\n if (\n activeTr &&\n // Only dispatch if the transaction was actually modified in some way\n (activeTr.docChanged ||\n activeTr.selectionSet ||\n activeTr.scrolledIntoView ||\n activeTr.storedMarksSet ||\n !activeTr.isGeneric)\n ) {\n // Dispatch the transaction if it was modified\n this.prosemirrorView.dispatch(activeTr);\n }\n\n return result;\n } finally {\n // We wrap this in a finally block to ensure we don't disable future transactions just because of an error in the callback\n this.activeTransaction = null;\n }\n }\n /**\n * Get the underlying prosemirror state\n * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date\n * @see https://prosemirror.net/docs/ref/#state.EditorState\n */\n public get prosemirrorState() {\n if (this.activeTransaction) {\n throw new Error(\n \"`prosemirrorState` should not be called within a `transact` call, move the `prosemirrorState` call outside of the `transact` call or use `editor.transact` to read the current editor state\",\n );\n }\n return this.editor._tiptapEditor.state;\n }\n\n /**\n * Get the underlying prosemirror view\n * @see https://prosemirror.net/docs/ref/#view.EditorView\n */\n public get prosemirrorView() {\n return this.editor._tiptapEditor.view;\n }\n\n public isFocused() {\n return this.prosemirrorView?.hasFocus() || false;\n }\n\n public focus() {\n this.prosemirrorView?.focus();\n }\n\n /**\n * Checks if the editor is currently editable, or if it's locked.\n * @returns True if the editor is editable, false otherwise.\n */\n public get isEditable(): boolean {\n if (!this.editor._tiptapEditor) {\n if (!this.editor.headless) {\n throw new Error(\"no editor, but also not headless?\");\n }\n return false;\n }\n return this.editor._tiptapEditor.isEditable === undefined\n ? true\n : this.editor._tiptapEditor.isEditable;\n }\n\n /**\n * Makes the editor editable or locks it, depending on the argument passed.\n * @param editable True to make the editor editable, or false to lock it.\n */\n public set isEditable(editable: boolean) {\n if (!this.editor._tiptapEditor) {\n if (!this.editor.headless) {\n throw new Error(\"no editor, but also not headless?\");\n }\n // not relevant on headless\n return;\n }\n if (this.editor._tiptapEditor.options.editable !== editable) {\n this.editor._tiptapEditor.setEditable(editable);\n }\n }\n\n /**\n * Undo the last action.\n */\n public undo(): boolean {\n // Purposefully not using the UndoPlugin to not import y-prosemirror when not needed\n const undoPlugin = this.editor.getExtension<typeof YUndoExtension>(\"yUndo\");\n if (undoPlugin) {\n return this.exec(undoPlugin.undoCommand);\n }\n\n const historyPlugin =\n this.editor.getExtension<typeof HistoryExtension>(\"history\");\n if (historyPlugin) {\n return this.exec(historyPlugin.undoCommand);\n }\n\n throw new Error(\"No undo plugin found\");\n }\n\n /**\n * Redo the last action.\n */\n public redo() {\n const undoPlugin = this.editor.getExtension<typeof YUndoExtension>(\"yUndo\");\n if (undoPlugin) {\n return this.exec(undoPlugin.redoCommand);\n }\n\n const historyPlugin =\n this.editor.getExtension<typeof HistoryExtension>(\"history\");\n if (historyPlugin) {\n return this.exec(historyPlugin.redoCommand);\n }\n\n throw new Error(\"No redo plugin found\");\n }\n}\n","import { selectionToInsertionEnd } from \"@tiptap/core\";\nimport { Node } from \"prosemirror-model\";\n\nimport type { Transaction } from \"prosemirror-state\";\n\n// similar to tiptap insertContentAt\nexport function insertContentAt(\n tr: Transaction,\n position: number | { from: number; to: number },\n nodes: Node[],\n options: {\n updateSelection: boolean;\n } = { updateSelection: true },\n) {\n // don’t dispatch an empty fragment because this can lead to strange errors\n // if (content.toString() === \"<>\") {\n // return true;\n // }\n\n let { from, to } =\n typeof position === \"number\"\n ? { from: position, to: position }\n : { from: position.from, to: position.to };\n\n let isOnlyTextContent = true;\n let isOnlyBlockContent = true;\n // const nodes = isFragment(content) ? content : [content];\n\n let text = \"\";\n\n nodes.forEach((node) => {\n // check if added node is valid\n node.check();\n\n if (isOnlyTextContent && node.isText && node.marks.length === 0) {\n text += node.text;\n } else {\n isOnlyTextContent = false;\n }\n\n isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;\n });\n\n // check if we can replace the wrapping node by\n // the newly inserted content\n // example:\n // replace an empty paragraph by an inserted image\n // instead of inserting the image below the paragraph\n if (from === to && isOnlyBlockContent) {\n const { parent } = tr.doc.resolve(from);\n const isEmptyTextBlock =\n parent.isTextblock && !parent.type.spec.code && !parent.childCount;\n\n if (isEmptyTextBlock) {\n from -= 1;\n to += 1;\n }\n }\n\n // if there is only plain text we have to use `insertText`\n // because this will keep the current marks\n if (isOnlyTextContent) {\n // if value is string, we can use it directly\n // otherwise if it is an array, we have to join it\n // if (Array.isArray(value)) {\n // tr.insertText(value.map((v) => v.text || \"\").join(\"\"), from, to);\n // } else if (typeof value === \"object\" && !!value && !!value.text) {\n // tr.insertText(value.text, from, to);\n // } else {\n // tr.insertText(value as string, from, to);\n // }\n tr.insertText(text, from, to);\n } else {\n tr.replaceWith(from, to, nodes);\n }\n\n // set cursor at end of inserted content\n if (options.updateSelection) {\n selectionToInsertionEnd(tr, tr.steps.length - 1, -1);\n }\n\n return true;\n}\n","import { insertContentAt } from \"../../api/blockManipulation/insertContentAt.js\";\nimport { inlineContentToNodes } from \"../../api/nodeConversions/blockToNode.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n PartialInlineContent,\n StyleSchema,\n Styles,\n} from \"../../schema/index.js\";\nimport {\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../../blocks/defaultBlocks.js\";\nimport { TextSelection } from \"@tiptap/pm/state\";\nimport { UnreachableCaseError } from \"../../util/typescript.js\";\nimport { BlockNoteEditor } from \"../BlockNoteEditor.js\";\n\nexport class StyleManager<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> {\n constructor(private editor: BlockNoteEditor<BSchema, ISchema, SSchema>) {}\n\n /**\n * Insert a piece of content at the current cursor position.\n *\n * @param content can be a string, or array of partial inline content elements\n */\n public insertInlineContent(\n content: PartialInlineContent<ISchema, SSchema>,\n { updateSelection = false }: { updateSelection?: boolean } = {},\n ) {\n const nodes = inlineContentToNodes(content, this.editor.pmSchema);\n\n this.editor.transact((tr) => {\n insertContentAt(\n tr,\n {\n from: tr.selection.from,\n to: tr.selection.to,\n },\n nodes,\n {\n updateSelection,\n },\n );\n });\n }\n\n /**\n * Gets the active text styles at the text cursor position or at the end of the current selection if it's active.\n */\n public getActiveStyles() {\n return this.editor.transact((tr) => {\n const styles: Styles<SSchema> = {};\n const marks = tr.selection.$to.marks();\n\n for (const mark of marks) {\n const config = this.editor.schema.styleSchema[mark.type.name];\n if (!config) {\n if (\n // Links are not considered styles in blocknote\n mark.type.name !== \"link\" &&\n // \"blocknoteIgnore\" tagged marks (such as comments) are also not considered BlockNote \"styles\"\n !mark.type.spec.blocknoteIgnore\n ) {\n // eslint-disable-next-line no-console\n console.warn(\"mark not found in styleschema\", mark.type.name);\n }\n\n continue;\n }\n if (config.propSchema === \"boolean\") {\n (styles as any)[config.type] = true;\n } else {\n (styles as any)[config.type] = mark.attrs.stringValue;\n }\n }\n\n return styles;\n });\n }\n\n /**\n * Adds styles to the currently selected content.\n * @param styles The styles to add.\n */\n public addStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.editor.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this.editor._tiptapEditor.commands.setMark(style);\n } else if (config.propSchema === \"string\") {\n this.editor._tiptapEditor.commands.setMark(style, {\n stringValue: value,\n });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Removes styles from the currently selected content.\n * @param styles The styles to remove.\n */\n public removeStyles(styles: Styles<SSchema>) {\n for (const style of Object.keys(styles)) {\n this.editor._tiptapEditor.commands.unsetMark(style);\n }\n }\n\n /**\n * Toggles styles on the currently selected content.\n * @param styles The styles to toggle.\n */\n public toggleStyles(styles: Styles<SSchema>) {\n for (const [style, value] of Object.entries(styles)) {\n const config = this.editor.schema.styleSchema[style];\n if (!config) {\n throw new Error(`style ${style} not found in styleSchema`);\n }\n if (config.propSchema === \"boolean\") {\n this.editor._tiptapEditor.commands.toggleMark(style);\n } else if (config.propSchema === \"string\") {\n this.editor._tiptapEditor.commands.toggleMark(style, {\n stringValue: value,\n });\n } else {\n throw new UnreachableCaseError(config.propSchema);\n }\n }\n }\n\n /**\n * Gets the currently selected text.\n */\n public getSelectedText() {\n return this.editor.transact((tr) => {\n return tr.doc.textBetween(tr.selection.from, tr.selection.to);\n });\n }\n\n /**\n * Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.\n */\n public getSelectedLinkUrl() {\n return this.editor._tiptapEditor.getAttributes(\"link\").href as\n | string\n | undefined;\n }\n\n /**\n * Creates a new link to replace the selected content.\n * @param url The link URL.\n * @param text The text to display the link with.\n */\n public createLink(url: string, text?: string) {\n if (url === \"\") {\n return;\n }\n const mark = this.editor.pmSchema.mark(\"link\", { href: url });\n this.editor.transact((tr) => {\n const { from, to } = tr.selection;\n\n if (text) {\n tr.insertText(text, from, to).addMark(from, from + text.length, mark);\n } else {\n tr.setSelection(TextSelection.create(tr.doc, to)).addMark(\n from,\n to,\n mark,\n );\n }\n });\n }\n}\n","import { Fragment, Schema, Slice } from \"@tiptap/pm/model\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { getBlockInfoFromSelection } from \"../api/getBlockInfoFromPos.js\";\n\n// helper function to remove a child from a fragment\nfunction removeChild(node: Fragment, n: number) {\n const children: any[] = [];\n node.forEach((child, _, i) => {\n if (i !== n) {\n children.push(child);\n }\n });\n return Fragment.from(children);\n}\n\n/**\n * Wrap adjacent tableRow items in a table.\n *\n * This makes sure the content that we paste is always a table (and not a tableRow)\n * A table works better for the remaing paste handling logic, as it's actually a blockContent node\n */\nexport function wrapTableRows(f: Fragment, schema: Schema) {\n const newItems: any[] = [];\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.name === \"tableRow\") {\n if (\n newItems.length > 0 &&\n newItems[newItems.length - 1].type.name === \"table\"\n ) {\n // append to existing table\n const prevTable = newItems[newItems.length - 1];\n const newTable = prevTable.copy(prevTable.content.addToEnd(f.child(i)));\n newItems[newItems.length - 1] = newTable;\n } else {\n // create new table to wrap tableRow with\n const newTable = schema.nodes.table.createChecked(\n undefined,\n f.child(i),\n );\n newItems.push(newTable);\n }\n } else {\n newItems.push(f.child(i));\n }\n }\n f = Fragment.from(newItems);\n return f;\n}\n\n/**\n * fix for https://github.com/ProseMirror/prosemirror/issues/1430#issuecomment-1822570821\n *\n * This fix wraps pasted ProseMirror nodes in their own `blockContainer` nodes\n * in most cases. This is to ensure that ProseMirror inserts them as separate\n * blocks, which it sometimes doesn't do because it doesn't have enough context\n * about the hierarchy of the pasted nodes. The issue can be seen when pasting\n * e.g. an image or two consecutive paragraphs, where PM tries to nest the\n * pasted block(s) when it shouldn't.\n *\n * However, the fix is not applied in a few cases. See `shouldApplyFix` for\n * which cases are excluded.\n */\nexport function transformPasted(slice: Slice, view: EditorView) {\n let f = Fragment.from(slice.content);\n f = wrapTableRows(f, view.state.schema);\n\n if (!shouldApplyFix(f, view)) {\n // Don't apply the fix.\n return new Slice(f, slice.openStart, slice.openEnd);\n }\n\n for (let i = 0; i < f.childCount; i++) {\n if (f.child(i).type.spec.group === \"blockContent\") {\n const content = [f.child(i)];\n\n // when there is a blockGroup with lists, it should be nested in the new blockcontainer\n // (if we remove this if-block, the nesting bug will be fixed, but lists won't be nested correctly)\n if (\n i + 1 < f.childCount &&\n f.child(i + 1).type.name === \"blockGroup\" // TODO\n ) {\n const nestedChild = f\n .child(i + 1)\n .child(0)\n .child(0);\n\n if (\n nestedChild.type.name === \"bulletListItem\" ||\n nestedChild.type.name === \"numberedListItem\" ||\n nestedChild.type.name === \"checkListItem\"\n ) {\n content.push(f.child(i + 1));\n f = removeChild(f, i + 1);\n }\n }\n const container = view.state.schema.nodes.blockContainer.createChecked(\n undefined,\n content,\n );\n f = f.replaceChild(i, container);\n }\n }\n return new Slice(f, slice.openStart, slice.openEnd);\n}\n\n/**\n * Used in `transformPasted` to check if the fix there should be applied, i.e.\n * if the pasted fragment should be wrapped in a `blockContainer` node. This\n * will explicitly tell ProseMirror to treat it as a separate block.\n */\nfunction shouldApplyFix(fragment: Fragment, view: EditorView) {\n const nodeHasSingleChild = fragment.childCount === 1;\n const nodeHasInlineContent =\n fragment.firstChild?.type.spec.content === \"inline*\";\n const nodeHasTableContent =\n fragment.firstChild?.type.spec.content === \"tableRow+\";\n\n if (nodeHasSingleChild) {\n if (nodeHasInlineContent) {\n // Case when we paste a single node with inline content, e.g. a paragraph\n // or heading. We want to insert the content in-line for better UX instead\n // of a separate block, so we return false.\n return false;\n }\n\n if (nodeHasTableContent) {\n // Not ideal that we check selection here, as `transformPasted` is called\n // for both paste and drop events. Drop events can potentially cause\n // issues as they don't always happen at the current selection.\n const blockInfo = getBlockInfoFromSelection(view.state);\n if (blockInfo.isBlockContainer) {\n const selectedBlockHasTableContent =\n blockInfo.blockContent.node.type.spec.content === \"tableRow+\";\n\n // Case for when we paste a single node with table content, i.e. a\n // table. Normally, we return true as we want to ensure the table is\n // inserted as a separate block. However, if the selection is in an\n // existing table, we return false, as we want the content of the pasted\n // table to be added to the existing one for better UX.\n return !selectedBlockHasTableContent;\n }\n }\n }\n\n return true;\n}\n","import {\n createDocument,\n EditorOptions,\n FocusPosition,\n getSchema,\n Editor as TiptapEditor,\n} from \"@tiptap/core\";\nimport { type Command, type Plugin, type Transaction } from \"@tiptap/pm/state\";\nimport { Node, Schema } from \"prosemirror-model\";\nimport * as Y from \"yjs\";\n\nimport type { BlocksChanged } from \"../api/getBlocksChangedByTransaction.js\";\nimport { blockToNode } from \"../api/nodeConversions/blockToNode.js\";\nimport {\n Block,\n BlockNoteSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n PartialBlock,\n} from \"../blocks/index.js\";\nimport { UniqueID } from \"../extensions/tiptap-extensions/UniqueID/UniqueID.js\";\nimport type { Dictionary } from \"../i18n/dictionary.js\";\nimport { en } from \"../i18n/locales/index.js\";\nimport type {\n BlockIdentifier,\n BlockNoteDOMAttributes,\n BlockSchema,\n BlockSpecs,\n CustomBlockNoteSchema,\n InlineContentSchema,\n InlineContentSpecs,\n PartialInlineContent,\n Styles,\n StyleSchema,\n StyleSpecs,\n} from \"../schema/index.js\";\nimport \"../style.css\";\nimport { mergeCSSClasses } from \"../util/browser.js\";\nimport { EventEmitter } from \"../util/EventEmitter.js\";\nimport type { NoInfer } from \"../util/typescript.js\";\nimport { ExtensionFactoryInstance } from \"./BlockNoteExtension.js\";\nimport type { TextCursorPosition } from \"./cursorPositionTypes.js\";\nimport {\n BlockManager,\n EventManager,\n ExportManager,\n ExtensionManager,\n SelectionManager,\n StateManager,\n StyleManager,\n} from \"./managers/index.js\";\nimport type { Selection } from \"./selectionTypes.js\";\nimport { transformPasted } from \"./transformPasted.js\";\n\nexport type BlockCache<\n BSchema extends BlockSchema = any,\n ISchema extends InlineContentSchema = any,\n SSchema extends StyleSchema = any,\n> = WeakMap<Node, Block<BSchema, ISchema, SSchema>>;\n\nexport interface BlockNoteEditorOptions<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> {\n /**\n * Whether changes to blocks (like indentation, creating lists, changing headings) should be animated or not. Defaults to `true`.\n *\n * @default true\n */\n animations?: boolean;\n\n /**\n * Whether the editor should be focused automatically when it's created.\n *\n * @default false\n */\n autofocus?: FocusPosition;\n\n /**\n * When enabled, allows for collaboration between multiple users.\n * See [Real-time Collaboration](https://www.blocknotejs.org/docs/advanced/real-time-collaboration) for more info.\n *\n * @remarks `CollaborationOptions`\n */\n collaboration?: {\n /**\n * The Yjs XML fragment that's used for collaboration.\n */\n fragment: Y.XmlFragment;\n /**\n * The user info for the current user that's shown to other collaborators.\n */\n user: {\n name: string;\n color: string;\n };\n /**\n * A Yjs provider (used for awareness / cursor information)\n */\n provider: any;\n /**\n * Optional function to customize how cursors of users are rendered\n */\n renderCursor?: (user: any) => HTMLElement;\n /**\n * Optional flag to set when the user label should be shown with the default\n * collaboration cursor. Setting to \"always\" will always show the label,\n * while \"activity\" will only show the label when the user moves the cursor\n * or types. Defaults to \"activity\".\n */\n showCursorLabels?: \"always\" | \"activity\";\n };\n\n /**\n * Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.\n *\n * @default true\n */\n defaultStyles?: boolean;\n\n /**\n * A dictionary object containing translations for the editor.\n *\n * See [Localization / i18n](https://www.blocknotejs.org/docs/advanced/localization) for more info.\n *\n * @remarks `Dictionary` is a type that contains all the translations for the editor.\n */\n dictionary?: Dictionary & Record<string, any>;\n\n /**\n * Disable internal extensions (based on keys / extension name)\n *\n * @note Advanced\n */\n disableExtensions?: string[];\n\n /**\n * An object containing attributes that should be added to HTML elements of the editor.\n *\n * See [Adding DOM Attributes](https://www.blocknotejs.org/docs/theming#adding-dom-attributes) for more info.\n *\n * @example { editor: { class: \"my-editor-class\" } }\n * @remarks `Record<string, Record<string, string>>`\n */\n domAttributes?: Partial<BlockNoteDOMAttributes>;\n\n /**\n * A replacement indicator to use when dragging and dropping blocks. Uses the [ProseMirror drop cursor](https://github.com/ProseMirror/prosemirror-dropcursor), or a modified version when [Column Blocks](https://www.blocknotejs.org/docs/document-structure#column-blocks) are enabled.\n * @remarks `() => Plugin`\n */\n dropCursor?: (opts: {\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n color?: string | false;\n width?: number;\n class?: string;\n }) => Plugin;\n\n /**\n * The content that should be in the editor when it's created, represented as an array of {@link PartialBlock} objects.\n *\n * See [Partial Blocks](https://www.blocknotejs.org/docs/editor-api/manipulating-blocks#partial-blocks) for more info.\n *\n * @remarks `PartialBlock[]`\n */\n initialContent?: PartialBlock<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >[];\n\n /**\n * @deprecated, provide placeholders via dictionary instead\n * @internal\n */\n placeholders?: Record<\n string | \"default\" | \"emptyDocument\",\n string | undefined\n >;\n\n /**\n * Custom paste handler that can be used to override the default paste behavior.\n *\n * See [Paste Handling](https://www.blocknotejs.org/docs/advanced/paste-handling) for more info.\n *\n * @remarks `PasteHandler`\n * @returns The function should return `true` if the paste event was handled, otherwise it should return `false` if it should be canceled or `undefined` if it should be handled by another handler.\n *\n * @example\n * ```ts\n * pasteHandler: ({ defaultPasteHandler }) => {\n * return defaultPasteHandler({ pasteBehavior: \"prefer-html\" });\n * }\n * ```\n */\n pasteHandler?: (context: {\n event: ClipboardEvent;\n editor: BlockNoteEditor<\n NoInfer<BSchema>,\n NoInfer<ISchema>,\n NoInfer<SSchema>\n >;\n /**\n * The default paste handler\n * @param context The context object\n * @returns Whether the paste event was handled or not\n */\n defaultPasteHandler: (context?: {\n /**\n * Whether to prioritize Markdown content in `text/plain` over `text/html` when pasting from the clipboard.\n * @default true\n */\n prioritizeMarkdownOverHTML?: boolean;\n /**\n * Whether to parse `text/plain` content from the clipboard as Markdown content.\n * @default true\n */\n plainTextAsMarkdown?: boolean;\n }) => boolean | undefined;\n }) => boolean | undefined;\n\n /**\n * Resolve a URL of a file block to one that can be displayed or downloaded. This can be used for creating authenticated URL or\n * implementing custom protocols / schemes\n * @returns The URL that's\n */\n resolveFileUrl?: (url: string) => Promise<string>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n *\n * See [Custom Schemas](https://www.blocknotejs.org/docs/custom-schemas) for more info.\n * @remarks `BlockNoteSchema`\n */\n schema: CustomBlockNoteSchema<BSchema, ISchema, SSchema>;\n\n /**\n * A flag indicating whether to set an HTML ID for every block\n *\n * When set to `true`, on each block an id attribute will be set with the block id\n * Otherwise, the HTML ID attribute will not be set.\n *\n * (note that the id is always set on the `data-id` attribute)\n */\n setIdAttribute?: boolean;\n\n /**\n * Determines behavior when pressing Tab (or Shift-Tab) while multiple blocks are selected and a toolbar is open.\n * - `\"prefer-navigate-ui\"`: Changes focus to the toolbar. User must press Escape to close toolbar before indenting blocks. Better for keyboard accessibility.\n * - `\"prefer-indent\"`: Always indents selected blocks, regardless of toolbar state. Keyboard navigation of toolbars not possible.\n * @default \"prefer-navigate-ui\"\n */\n tabBehavior?: \"prefer-navigate-ui\" | \"prefer-indent\";\n\n /**\n * Allows enabling / disabling features of tables.\n *\n * See [Tables](https://www.blocknotejs.org/docs/editor-basics/document-structure#tables) for more info.\n *\n * @remarks `TableConfig`\n */\n tables?: {\n /**\n * Whether to allow splitting and merging cells within a table.\n *\n * @default false\n */\n splitCells?: boolean;\n /**\n * Whether to allow changing the background color of cells.\n *\n * @default false\n */\n cellBackgroundColor?: boolean;\n /**\n * Whether to allow changing the text color of cells.\n *\n * @default false\n */\n cellTextColor?: boolean;\n /**\n * Whether to allow changing cells into headers.\n *\n * @default false\n */\n headers?: boolean;\n };\n\n /**\n * An option which user can pass with `false` value to disable the automatic creation of a trailing new block on the next line when the user types or edits any block.\n *\n * @default true\n */\n trailingBlock?: boolean;\n\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n * @remarks `(file: File) => Promise<UploadFileResult>`\n */\n uploadFile?: (\n file: File,\n blockId?: string,\n ) => Promise<string | Record<string, any>>;\n\n /**\n * additional tiptap options, undocumented\n * @internal\n */\n _tiptapOptions?: Partial<EditorOptions>;\n\n /**\n * Register extensions to the editor.\n *\n * See [Extensions](/docs/features/extensions) for more info.\n *\n * @remarks `ExtensionFactory[]`\n */\n extensions?: Array<ExtensionFactoryInstance>;\n}\n\nconst blockNoteTipTapOptions = {\n enableInputRules: true,\n enablePasteRules: true,\n enableCoreExtensions: false,\n};\n\nexport class BlockNoteEditor<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> extends EventEmitter<{\n create: void;\n}> {\n /**\n * The underlying prosemirror schema\n */\n public readonly pmSchema: Schema;\n\n public readonly _tiptapEditor: TiptapEditor & {\n contentComponent: any;\n };\n\n /**\n * Used by React to store a reference to an `ElementRenderer` helper utility to make sure we can render React elements\n * in the correct context (used by `ReactRenderUtil`)\n */\n public elementRenderer: ((node: any, container: HTMLElement) => void) | null =\n null;\n\n /**\n * Cache of all blocks. This makes sure we don't have to \"recompute\" blocks if underlying Prosemirror Nodes haven't changed.\n * This is especially useful when we want to keep track of the same block across multiple operations,\n * with this cache, blocks stay the same object reference (referential equality with ===).\n */\n public blockCache: BlockCache = new WeakMap();\n\n /**\n * The dictionary contains translations for the editor.\n */\n public readonly dictionary: Dictionary & Record<string, any>;\n\n /**\n * The schema of the editor. The schema defines which Blocks, InlineContent, and Styles are available in the editor.\n */\n public readonly schema: BlockNoteSchema<BSchema, ISchema, SSchema>;\n\n public readonly blockImplementations: BlockSpecs;\n public readonly inlineContentImplementations: InlineContentSpecs;\n public readonly styleImplementations: StyleSpecs;\n\n /**\n * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).\n * This method should set when creating the editor as this is application-specific.\n *\n * `undefined` means the application doesn't support file uploads.\n *\n * @param file The file that should be uploaded.\n * @returns The URL of the uploaded file OR an object containing props that should be set on the file block (such as an id)\n */\n public readonly uploadFile:\n | ((file: File, blockId?: string) => Promise<string | Record<string, any>>)\n | undefined;\n\n private onUploadStartCallbacks: ((blockId?: string) => void)[] = [];\n private onUploadEndCallbacks: ((blockId?: string) => void)[] = [];\n\n public readonly resolveFileUrl?: (url: string) => Promise<string>;\n /**\n * Editor settings\n */\n public readonly settings: {\n tables: {\n splitCells: boolean;\n cellBackgroundColor: boolean;\n cellTextColor: boolean;\n headers: boolean;\n };\n };\n public static create<\n Options extends Partial<BlockNoteEditorOptions<any, any, any>> | undefined,\n >(\n options?: Options,\n ): Options extends {\n schema: CustomBlockNoteSchema<infer BSchema, infer ISchema, infer SSchema>;\n }\n ? BlockNoteEditor<BSchema, ISchema, SSchema>\n : BlockNoteEditor<\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema\n > {\n return new BlockNoteEditor(options ?? {}) as any;\n }\n\n protected constructor(\n protected readonly options: Partial<\n BlockNoteEditorOptions<BSchema, ISchema, SSchema>\n >,\n ) {\n super();\n\n this.dictionary = options.dictionary || en;\n this.settings = {\n tables: {\n splitCells: options?.tables?.splitCells ?? false,\n cellBackgroundColor: options?.tables?.cellBackgroundColor ?? false,\n cellTextColor: options?.tables?.cellTextColor ?? false,\n headers: options?.tables?.headers ?? false,\n },\n };\n\n // apply defaults\n const newOptions = {\n defaultStyles: true,\n schema:\n options.schema ||\n (BlockNoteSchema.create() as unknown as CustomBlockNoteSchema<\n BSchema,\n ISchema,\n SSchema\n >),\n ...options,\n placeholders: {\n ...this.dictionary.placeholders,\n ...options.placeholders,\n },\n };\n\n // @ts-ignore\n this.schema = newOptions.schema;\n this.blockImplementations = newOptions.schema.blockSpecs;\n this.inlineContentImplementations = newOptions.schema.inlineContentSpecs;\n this.styleImplementations = newOptions.schema.styleSpecs;\n\n // TODO this should just be an extension\n if (newOptions.uploadFile) {\n const uploadFile = newOptions.uploadFile;\n this.uploadFile = async (file, blockId) => {\n this.onUploadStartCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n try {\n return await uploadFile(file, blockId);\n } finally {\n this.onUploadEndCallbacks.forEach((callback) =>\n callback.apply(this, [blockId]),\n );\n }\n };\n }\n\n this.resolveFileUrl = newOptions.resolveFileUrl;\n\n this._eventManager = new EventManager(this as any);\n this._extensionManager = new ExtensionManager(this, newOptions);\n\n const tiptapExtensions = this._extensionManager.getTiptapExtensions();\n\n const collaborationEnabled =\n this._extensionManager.hasExtension(\"ySync\") ||\n this._extensionManager.hasExtension(\"liveblocksExtension\");\n\n if (collaborationEnabled && newOptions.initialContent) {\n // eslint-disable-next-line no-console\n console.warn(\n \"When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider\",\n );\n }\n\n const tiptapOptions: EditorOptions = {\n ...blockNoteTipTapOptions,\n ...newOptions._tiptapOptions,\n element: null,\n autofocus: newOptions.autofocus ?? false,\n extensions: tiptapExtensions,\n editorProps: {\n ...newOptions._tiptapOptions?.editorProps,\n attributes: {\n // As of TipTap v2.5.0 the tabIndex is removed when the editor is not\n // editable, so you can't focus it. We want to revert this as we have\n // UI behaviour that relies on it.\n tabIndex: \"0\",\n ...newOptions._tiptapOptions?.editorProps?.attributes,\n ...newOptions.domAttributes?.editor,\n class: mergeCSSClasses(\n \"bn-editor\",\n newOptions.defaultStyles ? \"bn-default-styles\" : \"\",\n newOptions.domAttributes?.editor?.class || \"\",\n ),\n },\n transformPasted,\n },\n } as any;\n\n try {\n const initialContent =\n newOptions.initialContent ||\n (collaborationEnabled\n ? [\n {\n type: \"paragraph\",\n id: \"initialBlockId\",\n },\n ]\n : [\n {\n type: \"paragraph\",\n id: UniqueID.options.generateID(),\n },\n ]);\n\n if (!Array.isArray(initialContent) || initialContent.length === 0) {\n throw new Error(\n \"initialContent must be a non-empty array of blocks, received: \" +\n initialContent,\n );\n }\n const schema = getSchema(tiptapOptions.extensions!);\n const pmNodes = initialContent.map((b) =>\n blockToNode(b, schema, this.schema.styleSchema).toJSON(),\n );\n const doc = createDocument(\n {\n type: \"doc\",\n content: [\n {\n type: \"blockGroup\",\n content: pmNodes,\n },\n ],\n },\n schema,\n tiptapOptions.parseOptions,\n );\n\n this._tiptapEditor = new TiptapEditor({\n ...tiptapOptions,\n content: doc.toJSON(),\n }) as any;\n this.pmSchema = this._tiptapEditor.schema;\n } catch (e) {\n throw new Error(\n \"Error creating document from blocks passed as `initialContent`\",\n { cause: e },\n );\n }\n\n // When y-prosemirror creates an empty document, the `blockContainer` node is created with an `id` of `null`.\n // This causes the unique id extension to generate a new id for the initial block, which is not what we want\n // Since it will be randomly generated & cause there to be more updates to the ydoc\n // This is a hack to make it so that anytime `schema.doc.createAndFill` is called, the initial block id is already set to \"initialBlockId\"\n let cache: Node | undefined = undefined;\n const oldCreateAndFill = this.pmSchema.nodes.doc.createAndFill;\n this.pmSchema.nodes.doc.createAndFill = (...args: any) => {\n if (cache) {\n return cache;\n }\n const ret = oldCreateAndFill.apply(this.pmSchema.nodes.doc, args)!;\n\n // create a copy that we can mutate (otherwise, assigning attrs is not safe and corrupts the pm state)\n const jsonNode = JSON.parse(JSON.stringify(ret.toJSON()));\n jsonNode.content[0].content[0].attrs.id = \"initialBlockId\";\n\n cache = Node.fromJSON(this.pmSchema, jsonNode);\n return cache;\n };\n this.pmSchema.cached.blockNoteEditor = this;\n\n // Initialize managers\n this._blockManager = new BlockManager(this as any);\n\n this._exportManager = new ExportManager(this as any);\n this._selectionManager = new SelectionManager(this as any);\n this._stateManager = new StateManager(this as any);\n this._styleManager = new StyleManager(this as any);\n\n this.emit(\"create\");\n }\n\n // Manager instances\n private readonly _blockManager: BlockManager<any, any, any>;\n private readonly _eventManager: EventManager<any, any, any>;\n private readonly _exportManager: ExportManager<any, any, any>;\n private readonly _extensionManager: ExtensionManager;\n private readonly _selectionManager: SelectionManager<any, any, any>;\n private readonly _stateManager: StateManager;\n private readonly _styleManager: StyleManager<any, any, any>;\n\n /**\n * BlockNote extensions that are added to the editor, keyed by the extension key\n */\n public get extensions() {\n return this._extensionManager.getExtensions();\n }\n\n /**\n * Execute a prosemirror command. This is mostly for backwards compatibility with older code.\n *\n * @note You should prefer the {@link transact} method when possible, as it will automatically handle the dispatching of the transaction and work across blocknote transactions.\n *\n * @example\n * ```ts\n * editor.exec((state, dispatch, view) => {\n * dispatch(state.tr.insertText(\"Hello, world!\"));\n * });\n * ```\n */\n public exec(command: Command) {\n return this._stateManager.exec(command);\n }\n\n /**\n * Check if a command can be executed. A command should return `false` if it is not valid in the current state.\n *\n * @example\n * ```ts\n * if (editor.canExec(command)) {\n * // show button\n * } else {\n * // hide button\n * }\n * ```\n */\n public canExec(command: Command): boolean {\n return this._stateManager.canExec(command);\n }\n\n /**\n * Execute a function within a \"blocknote transaction\".\n * All changes to the editor within the transaction will be grouped together, so that\n * we can dispatch them as a single operation (thus creating only a single undo step)\n *\n * @note There is no need to dispatch the transaction, as it will be automatically dispatched when the callback is complete.\n *\n * @example\n * ```ts\n * // All changes to the editor will be grouped together\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * // These two operations will be grouped together in a single undo step\n * editor.transact((tr) => {\n * tr.insertText(\"Hello, world!\");\n * });\n * });\n * ```\n */\n public transact<T>(\n callback: (\n /**\n * The current active transaction, this will automatically be dispatched to the editor when the callback is complete\n * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.\n */\n tr: Transaction,\n ) => T,\n ): T {\n return this._stateManager.transact(callback);\n }\n\n /**\n * Remove extension(s) from the editor\n */\n public unregisterExtension: ExtensionManager[\"unregisterExtension\"] = (\n ...args: Parameters<ExtensionManager[\"unregisterExtension\"]>\n ) => this._extensionManager.unregisterExtension(...args);\n\n /**\n * Register extension(s) to the editor\n */\n public registerExtension: ExtensionManager[\"registerExtension\"] = (\n ...args: Parameters<ExtensionManager[\"registerExtension\"]>\n ) => this._extensionManager.registerExtension(...args) as any;\n\n /**\n * Get an extension from the editor\n */\n public getExtension: ExtensionManager[\"getExtension\"] = ((\n ...args: Parameters<ExtensionManager[\"getExtension\"]>\n ) => this._extensionManager.getExtension(...args)) as any;\n\n /**\n * Mount the editor to a DOM element.\n *\n * @warning Not needed to call manually when using React, use BlockNoteView to take care of mounting\n */\n public mount = (element: HTMLElement) => {\n this._tiptapEditor.mount({ mount: element });\n };\n\n /**\n * Unmount the editor from the DOM element it is bound to\n */\n public unmount = () => {\n this._tiptapEditor.unmount();\n };\n\n /**\n * Get the underlying prosemirror state\n * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date\n * @see https://prosemirror.net/docs/ref/#state.EditorState\n */\n public get prosemirrorState() {\n return this._stateManager.prosemirrorState;\n }\n\n /**\n * Get the underlying prosemirror view\n * @see https://prosemirror.net/docs/ref/#view.EditorView\n */\n public get prosemirrorView() {\n return this._stateManager.prosemirrorView;\n }\n\n public get domElement() {\n if (this.headless) {\n return undefined;\n }\n return this.prosemirrorView?.dom as HTMLDivElement | undefined;\n }\n\n public isFocused() {\n if (this.headless) {\n return false;\n }\n return this.prosemirrorView?.hasFocus() || false;\n }\n\n public get headless() {\n return !this._tiptapEditor.isInitialized;\n }\n\n /**\n * Focus on the editor\n */\n public focus() {\n if (this.headless) {\n return;\n }\n this.prosemirrorView.focus();\n }\n\n /**\n * Blur the editor\n */\n public blur() {\n if (this.headless) {\n return;\n }\n this.prosemirrorView.dom.blur();\n }\n\n // TODO move to extension\n public onUploadStart(callback: (blockId?: string) => void) {\n this.onUploadStartCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadStartCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadStartCallbacks.splice(index, 1);\n }\n };\n }\n\n public onUploadEnd(callback: (blockId?: string) => void) {\n this.onUploadEndCallbacks.push(callback);\n\n return () => {\n const index = this.onUploadEndCallbacks.indexOf(callback);\n if (index > -1) {\n this.onUploadEndCallbacks.splice(index, 1);\n }\n };\n }\n\n /**\n * @deprecated, use `editor.document` instead\n */\n public get topLevelBlocks(): Block<BSchema, ISchema, SSchema>[] {\n return this.document;\n }\n\n /**\n * Gets a snapshot of all top-level (non-nested) blocks in the editor.\n * @returns A snapshot of all top-level (non-nested) blocks in the editor.\n */\n public get document(): Block<BSchema, ISchema, SSchema>[] {\n return this._blockManager.document;\n }\n\n /**\n * Gets a snapshot of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block that should be\n * retrieved.\n * @returns The block that matches the identifier, or `undefined` if no\n * matching block was found.\n */\n public getBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getBlock(blockIdentifier);\n }\n\n /**\n * Gets a snapshot of the previous sibling of an existing block from the\n * editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * previous sibling should be retrieved.\n * @returns The previous sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the first child/block\n * in the document.\n */\n public getPrevBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getPrevBlock(blockIdentifier);\n }\n\n /**\n * Gets a snapshot of the next sibling of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * next sibling should be retrieved.\n * @returns The next sibling of the block that matches the identifier.\n * `undefined` if no matching block was found, or it's the last child/block in\n * the document.\n */\n public getNextBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getNextBlock(blockIdentifier);\n }\n\n /**\n * Gets a snapshot of the parent of an existing block from the editor.\n * @param blockIdentifier The identifier of an existing block for which the\n * parent should be retrieved.\n * @returns The parent of the block that matches the identifier. `undefined`\n * if no matching block was found, or the block isn't nested.\n */\n public getParentBlock(\n blockIdentifier: BlockIdentifier,\n ): Block<BSchema, ISchema, SSchema> | undefined {\n return this._blockManager.getParentBlock(blockIdentifier);\n }\n\n /**\n * Traverses all blocks in the editor depth-first, and executes a callback for each.\n * @param callback The callback to execute for each block. Returning `false` stops the traversal.\n * @param reverse Whether the blocks should be traversed in reverse order.\n */\n public forEachBlock(\n callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,\n reverse = false,\n ): void {\n this._blockManager.forEachBlock(callback, reverse);\n }\n\n /**\n * Executes a callback whenever the editor's contents change.\n * @param callback The callback to execute.\n *\n * @deprecated use {@link BlockNoteEditor.onChange} instead\n */\n public onEditorContentChange(callback: () => void) {\n this._tiptapEditor.on(\"update\", callback);\n }\n\n /**\n * Executes a callback whenever the editor's selection changes.\n * @param callback The callback to execute.\n *\n * @deprecated use `onSelectionChange` instead\n */\n public onEditorSelectionChange(callback: () => void) {\n this._tiptapEditor.on(\"selectionUpdate\", callback);\n }\n\n /**\n * Gets a snapshot of the current text cursor position.\n * @returns A snapshot of the current text cursor position.\n */\n public getTextCursorPosition(): TextCursorPosition<\n BSchema,\n ISchema,\n SSchema\n > {\n return this._selectionManager.getTextCursorPosition();\n }\n\n /**\n * Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could\n * not be found.\n * @param targetBlock The identifier of an existing block that the text cursor should be moved to.\n * @param placement Whether the text cursor should be placed at the start or end of the block.\n */\n public setTextCursorPosition(\n targetBlock: BlockIdentifier,\n placement: \"start\" | \"end\" = \"start\",\n ) {\n return this._selectionManager.setTextCursorPosition(targetBlock, placement);\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned data will contain the entire block.\n */\n public getSelection(): Selection<BSchema, ISchema, SSchema> | undefined {\n return this._selectionManager.getSelection();\n }\n\n /**\n * Gets a snapshot of the current selection. This contains all blocks (included nested blocks)\n * that the selection spans across.\n *\n * If the selection starts / ends halfway through a block, the returned block will be\n * only the part of the block that is included in the selection.\n */\n public getSelectionCutBlocks() {\n return this._selectionManager.getSelectionCutBlocks();\n }\n\n /**\n * Sets the selection to a range of blocks.\n * @param startBlock The identifier of the block that should be the start of the selection.\n * @param endBlock The identifier of the block that should be the end of the selection.\n */\n public setSelection(startBlock: BlockIdentifier, endBlock: BlockIdentifier) {\n return this._selectionManager.setSelection(startBlock, endBlock);\n }\n\n /**\n * Checks if the editor is currently editable, or if it's locked.\n * @returns True if the editor is editable, false otherwise.\n */\n public get isEditable(): boolean {\n return this._stateManager.isEditable;\n }\n\n /**\n * Makes the editor editable or locks it, depending on the argument passed.\n * @param editable True to make the editor editable, or false to lock it.\n */\n public set isEditable(editable: boolean) {\n this._stateManager.isEditable = editable;\n }\n\n /**\n * Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an\n * error if the reference block could not be found.\n * @param blocksToInsert An array of partial blocks that should be inserted.\n * @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.\n * @param placement Whether the blocks should be inserted just before, just after, or nested inside the\n * `referenceBlock`.\n */\n public insertBlocks(\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n referenceBlock: BlockIdentifier,\n placement: \"before\" | \"after\" = \"before\",\n ) {\n return this._blockManager.insertBlocks(\n blocksToInsert,\n referenceBlock,\n placement,\n );\n }\n\n /**\n * Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be\n * defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could\n * not be found.\n * @param blockToUpdate The block that should be updated.\n * @param update A partial block which defines how the existing block should be changed.\n */\n public updateBlock(\n blockToUpdate: BlockIdentifier,\n update: PartialBlock<BSchema, ISchema, SSchema>,\n ) {\n return this._blockManager.updateBlock(blockToUpdate, update);\n }\n\n /**\n * Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.\n * @param blocksToRemove An array of identifiers for existing blocks that should be removed.\n */\n public removeBlocks(blocksToRemove: BlockIdentifier[]) {\n return this._blockManager.removeBlocks(blocksToRemove);\n }\n\n /**\n * Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or\n * are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in\n * `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.\n * @param blocksToRemove An array of blocks that should be replaced.\n * @param blocksToInsert An array of partial blocks to replace the old ones with.\n */\n public replaceBlocks(\n blocksToRemove: BlockIdentifier[],\n blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],\n ) {\n return this._blockManager.replaceBlocks(blocksToRemove, blocksToInsert);\n }\n\n /**\n * Undo the last action.\n */\n public undo(): boolean {\n return this._stateManager.undo();\n }\n\n /**\n * Redo the last action.\n */\n public redo(): boolean {\n return this._stateManager.redo();\n }\n\n /**\n * Insert a piece of content at the current cursor position.\n *\n * @param content can be a string, or array of partial inline content elements\n */\n public insertInlineContent(\n content: PartialInlineContent<ISchema, SSchema>,\n { updateSelection = false }: { updateSelection?: boolean } = {},\n ) {\n this._styleManager.insertInlineContent(content, { updateSelection });\n }\n\n /**\n * Gets the active text styles at the text cursor position or at the end of the current selection if it's active.\n */\n public getActiveStyles(): Styles<SSchema> {\n return this._styleManager.getActiveStyles();\n }\n\n /**\n * Adds styles to the currently selected content.\n * @param styles The styles to add.\n */\n public addStyles(styles: Styles<SSchema>) {\n this._styleManager.addStyles(styles);\n }\n\n /**\n * Removes styles from the currently selected content.\n * @param styles The styles to remove.\n */\n public removeStyles(styles: Styles<SSchema>) {\n this._styleManager.removeStyles(styles);\n }\n\n /**\n * Toggles styles on the currently selected content.\n * @param styles The styles to toggle.\n */\n public toggleStyles(styles: Styles<SSchema>) {\n this._styleManager.toggleStyles(styles);\n }\n\n /**\n * Gets the currently selected text.\n */\n public getSelectedText() {\n return this._styleManager.getSelectedText();\n }\n\n /**\n * Gets the URL of the last link in the current selection, or `undefined` if there are no links in the selection.\n */\n public getSelectedLinkUrl() {\n return this._styleManager.getSelectedLinkUrl();\n }\n\n /**\n * Creates a new link to replace the selected content.\n * @param url The link URL.\n * @param text The text to display the link with.\n */\n public createLink(url: string, text?: string) {\n this._styleManager.createLink(url, text);\n }\n\n /**\n * Checks if the block containing the text cursor can be nested.\n */\n public canNestBlock() {\n return this._blockManager.canNestBlock();\n }\n\n /**\n * Nests the block containing the text cursor into the block above it.\n */\n public nestBlock() {\n this._blockManager.nestBlock();\n }\n\n /**\n * Checks if the block containing the text cursor is nested.\n */\n public canUnnestBlock() {\n return this._blockManager.canUnnestBlock();\n }\n\n /**\n * Lifts the block containing the text cursor out of its parent.\n */\n public unnestBlock() {\n this._blockManager.unnestBlock();\n }\n\n /**\n * Moves the selected blocks up. If the previous block has children, moves\n * them to the end of its children. If there is no previous block, but the\n * current blocks share a common parent, moves them out of & before it.\n */\n public moveBlocksUp() {\n return this._blockManager.moveBlocksUp();\n }\n\n /**\n * Moves the selected blocks down. If the next block has children, moves\n * them to the start of its children. If there is no next block, but the\n * current blocks share a common parent, moves them out of & after it.\n */\n public moveBlocksDown() {\n return this._blockManager.moveBlocksDown();\n }\n\n /**\n * Exports blocks into a simplified HTML string. To better conform to HTML standards, children of blocks which aren't list\n * items are un-nested in the output HTML.\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToHTMLLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return this._exportManager.blocksToHTMLLossy(blocks);\n }\n\n /**\n * Serializes blocks into an HTML string in the format that would normally be rendered by the editor.\n *\n * Use this method if you want to server-side render HTML (for example, a blog post that has been edited in BlockNote)\n * and serve it to users without loading the editor on the client (i.e.: displaying the blog post)\n *\n * @param blocks An array of blocks that should be serialized into HTML.\n * @returns The blocks, serialized as an HTML string.\n */\n public blocksToFullHTML(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return this._exportManager.blocksToFullHTML(blocks);\n }\n\n /**\n * Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and\n * `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote\n * doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.\n * @param html The HTML string to parse blocks from.\n * @returns The blocks parsed from the HTML string.\n */\n public tryParseHTMLToBlocks(\n html: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return this._exportManager.tryParseHTMLToBlocks(html);\n }\n\n /**\n * Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of\n * BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.\n * @param blocks An array of blocks that should be serialized into Markdown.\n * @returns The blocks, serialized as a Markdown string.\n */\n public blocksToMarkdownLossy(\n blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,\n ): string {\n return this._exportManager.blocksToMarkdownLossy(blocks);\n }\n\n /**\n * Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on\n * Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it\n * as text.\n * @param markdown The Markdown string to parse blocks from.\n * @returns The blocks parsed from the Markdown string.\n */\n public tryParseMarkdownToBlocks(\n markdown: string,\n ): Block<BSchema, ISchema, SSchema>[] {\n return this._exportManager.tryParseMarkdownToBlocks(markdown);\n }\n\n /**\n * A callback function that runs whenever the editor's contents change.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onChange(\n callback: (\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>,\n context: {\n /**\n * Returns the blocks that were inserted, updated, or deleted by the change that occurred.\n */\n getChanges(): BlocksChanged<BSchema, ISchema, SSchema>;\n },\n ) => void,\n /**\n * If true, the callback will be triggered when the changes are caused by a remote user\n * @default true\n */\n includeUpdatesFromRemote?: boolean,\n ) {\n return this._eventManager.onChange(callback, includeUpdatesFromRemote);\n }\n\n /**\n * A callback function that runs whenever the text cursor position or selection changes.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onSelectionChange(\n callback: (editor: BlockNoteEditor<BSchema, ISchema, SSchema>) => void,\n includeSelectionChangedByRemote?: boolean,\n ) {\n return this._eventManager.onSelectionChange(\n callback,\n includeSelectionChangedByRemote,\n );\n }\n\n /**\n * A callback function that runs when the editor has been mounted.\n *\n * This can be useful for plugins to initialize themselves after the editor has been mounted.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onMount(\n callback: (ctx: {\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>;\n }) => void,\n ) {\n this._eventManager.onMount(callback);\n }\n\n /**\n * A callback function that runs when the editor has been unmounted.\n *\n * This can be useful for plugins to clean up themselves after the editor has been unmounted.\n *\n * @param callback The callback to execute.\n * @returns A function to remove the callback.\n */\n public onUnmount(\n callback: (ctx: {\n editor: BlockNoteEditor<BSchema, ISchema, SSchema>;\n }) => void,\n ) {\n this._eventManager.onUnmount(callback);\n }\n\n /**\n * Gets the bounding box of the current selection.\n * @returns The bounding box of the current selection.\n */\n public getSelectionBoundingBox() {\n return this._selectionManager.getSelectionBoundingBox();\n }\n\n public get isEmpty() {\n const doc = this.document;\n // Note: only works for paragraphs as default blocks (but for now this is default in blocknote)\n // checking prosemirror directly might be faster\n return (\n doc.length === 0 ||\n (doc.length === 1 &&\n doc[0].type === \"paragraph\" &&\n (doc[0].content as any).length === 0)\n );\n }\n\n /**\n * Paste HTML into the editor. Defaults to converting HTML to BlockNote HTML.\n * @param html The HTML to paste.\n * @param raw Whether to paste the HTML as is, or to convert it to BlockNote HTML.\n */\n public pasteHTML(html: string, raw = false) {\n this._exportManager.pasteHTML(html, raw);\n }\n\n /**\n * Paste text into the editor. Defaults to interpreting text as markdown.\n * @param text The text to paste.\n */\n public pasteText(text: string) {\n return this._exportManager.pasteText(text);\n }\n\n /**\n * Paste markdown into the editor.\n * @param markdown The markdown to paste.\n */\n public pasteMarkdown(markdown: string) {\n return this._exportManager.pasteMarkdown(markdown);\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport { COLORS_DEFAULT } from \"../editor/defaultColors.js\";\nimport {\n BlockFromConfig,\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n StyledText,\n Styles,\n} from \"../schema/index.js\";\n\nimport type {\n BlockMapping,\n InlineContentMapping,\n StyleMapping,\n} from \"./mapping.js\";\n\nexport type ExporterOptions = {\n /**\n * A function that can be used to resolve files, images, etc.\n * Exporters might need the binary contents of files like images,\n * which might not always be available from the same origin as the main page.\n * You can use this option to proxy requests through a server you control\n * to avoid cross-origin (CORS) issues.\n *\n * @default uses a BlockNote hosted proxy (https://corsproxy.api.blocknotejs.org/)\n * @param url - The URL of the file to resolve\n * @returns A Promise that resolves to a string (the URL to use instead of the original)\n * or a Blob (you can return the Blob directly if you have already fetched it)\n */\n resolveFileUrl?: (url: string) => Promise<string | Blob>;\n /**\n * Colors to use for background of blocks, font colors, and highlight colors\n */\n colors: typeof COLORS_DEFAULT;\n};\nexport abstract class Exporter<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n RS,\n TS,\n> {\n public constructor(\n _schema: BlockNoteSchema<B, I, S>, // only used for type inference\n protected readonly mappings: {\n blockMapping: BlockMapping<B, I, S, RB, RI>;\n inlineContentMapping: InlineContentMapping<I, S, RI, TS>;\n styleMapping: StyleMapping<S, RS>;\n },\n public readonly options: ExporterOptions,\n ) {}\n\n public async resolveFile(url: string) {\n if (!this.options?.resolveFileUrl) {\n return (await fetch(url)).blob();\n }\n const ret = await this.options.resolveFileUrl(url);\n if (ret instanceof Blob) {\n return ret;\n }\n return (await fetch(ret)).blob();\n }\n\n public mapStyles(styles: Styles<S>) {\n const stylesArray = Object.entries(styles).map(([key, value]) => {\n const mappedStyle = this.mappings.styleMapping[key](value, this);\n return mappedStyle;\n });\n return stylesArray;\n }\n\n public mapInlineContent(inlineContent: InlineContent<I, S>) {\n return this.mappings.inlineContentMapping[inlineContent.type](\n inlineContent,\n this,\n );\n }\n\n public transformInlineContent(inlineContentArray: InlineContent<I, S>[]) {\n return inlineContentArray.map((ic) => this.mapInlineContent(ic));\n }\n\n public abstract transformStyledText(styledText: StyledText<S>): TS;\n\n public async mapBlock(\n block: BlockFromConfig<B[keyof B], I, S>,\n nestingLevel: number,\n numberedListIndex: number,\n children?: Array<Awaited<RB>>,\n ) {\n return this.mappings.blockMapping[block.type](\n block,\n this,\n nestingLevel,\n numberedListIndex,\n children,\n );\n }\n}\n","import { BlockNoteSchema } from \"../blocks/BlockNoteSchema.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchema,\n InlineContentFromConfig,\n InlineContentSchema,\n StyleSchema,\n Styles,\n} from \"../schema/index.js\";\nimport type { Exporter } from \"./Exporter.js\";\n\n/**\n * Defines a mapping from all block types with a schema to a result type `R`.\n */\nexport type BlockMapping<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n RB,\n RI,\n> = {\n [K in keyof B]: (\n block: BlockFromConfigNoChildren<B[K], I, S>,\n // we don't know the exact types that are supported by the exporter at this point,\n // because the mapping only knows about converting certain types (which might be a subset of the supported types)\n // this is why there are many `any` types here (same for types below)\n exporter: Exporter<any, any, any, RB, RI, any, any>,\n nestingLevel: number,\n numberedListIndex?: number,\n children?: Array<Awaited<RB>>,\n ) => RB | Promise<RB>;\n};\n\n/**\n * Defines a mapping from all inline content types with a schema to a result type R.\n */\nexport type InlineContentMapping<\n I extends InlineContentSchema,\n S extends StyleSchema,\n RI,\n TS,\n> = {\n [K in keyof I]: (\n inlineContent: InlineContentFromConfig<I[K], S>,\n exporter: Exporter<any, I, S, any, RI, any, TS>,\n ) => RI;\n};\n\n/**\n * Defines a mapping from all style types with a schema to a result type R.\n */\nexport type StyleMapping<S extends StyleSchema, RS> = {\n [K in keyof S]: (\n style: Styles<S>[K],\n exporter: Exporter<any, any, any, any, any, RS, any>,\n ) => RS;\n};\n\n/**\n * The mapping factory is a utility function to easily create mappings for\n * a BlockNoteSchema. Using the factory makes it easier to get typescript code completion etc.\n */\nexport function mappingFactory<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(_schema: BlockNoteSchema<B, I, S>) {\n return {\n createBlockMapping: <R, RI>(mapping: BlockMapping<B, I, S, R, RI>) =>\n mapping,\n createInlineContentMapping: <R, RS>(\n mapping: InlineContentMapping<I, S, R, RS>,\n ) => mapping,\n createStyleMapping: <R>(mapping: StyleMapping<S, R>) => mapping,\n };\n}\n","/**\n * Combines items by group. This can be used to combine multiple slash menu item arrays,\n * while making sure that items from the same group are adjacent to each other.\n */\nexport function combineByGroup<T extends { group?: string }>(\n items: T[],\n ...additionalItemsArray: {\n group?: string;\n }[][]\n) {\n const combinedItems = [...items];\n for (const additionalItems of additionalItemsArray) {\n for (const additionalItem of additionalItems) {\n const lastItemWithSameGroup = combinedItems.findLastIndex(\n (item) => item.group === additionalItem.group,\n );\n if (lastItemWithSameGroup === -1) {\n combinedItems.push(additionalItem as T);\n } else {\n combinedItems.splice(lastItemWithSameGroup + 1, 0, additionalItem as T);\n }\n }\n }\n return combinedItems;\n}\n"],"names":["getInlineContentParseRules","config","customParseFunction","rules","element","htmlElement","node","props","createInlineContentSpec","inlineContentConfig","inlineContentImplementation","Node","_a","propsToAttributes","addInlineContentKeyboardShortcuts","editor","output","nodeToCustomInlineContent","addInlineContentAttributes","getPos","update","content","inlineContentToNodes","pos","tr","createInlineContentSpecFromTipTapNode","inlineContent","updateInlineContent","insertBlocks","blocksToInsert","referenceBlock","placement","id","pmSchema","getPmSchema","nodesToInsert","block","blockToNode","posInfo","getNodeById","ReplaceStep","Slice","Fragment","nodeToBlock","isEmptyColumn","column","blockContainer","blockContent","removeEmptyColumns","columnListPos","$columnListPos","columnList","columnIndex","columnPos","fixColumnList","firstColumnBeforePos","firstColumn","lastColumnAfterPos","lastColumn","firstColumnEmpty","lastColumnEmpty","ReplaceAroundStep","removeAndInsertBlocks","blocksToRemove","idsOfBlocksToRemove","removedBlocks","columnListPositions","idOfFirstBlock","removedSize","oldDocSize","newDocSize","$pos","notFoundIds","serializeInlineContentInternalHTML","serializer","blockType","options","nodes","tableContentToNodes","UnreachableCaseError","fragment","contentFragment","dom","mark","newDom","domOutputSpec","DOMSerializer","nodeFragment","serializeBlock","BC_NODE","name","spec","children","ret","ic","serializeBlocks","bc","_c","_b","_d","_e","serializeBlocksInternalHTML","blocks","blockDOM","BG_NODE","bg","createInternalHTMLSerializer","schema","getBlockSelectionData","anchorBlockPosInfo","getNearestBlockPos","CellSelection","NodeSelection","headBlockPosInfo","updateBlockSelectionFromData","data","anchorBlockPos","selection","headBlockPos","TextSelection","flattenColumns","moveSelectedBlocksAndSelection","selectionData","checkPlacementIsValid","parentBlock","getMoveUpPlacement","prevBlock","referenceBlockParent","getMoveDownPlacement","nextBlock","moveBlocksUp","moveUpPlacement","moveBlocksDown","moveDownPlacement","sinkListItem","itemType","groupType","$from","$to","range","startIndex","nodeBefore","nestedBefore","inner","slice","before","after","nestBlock","unnestBlock","canNestBlock","getBlockInfoFromTransaction","canUnnestBlock","getBlock","doc","blockIdentifier","getPrevBlock","nodeToConvert","getNextBlock","getParentBlock","$posBeforeNode","parentNode","grandparentNode","BlockManager","docToBlocks","callback","reverse","traverseBlockArray","blockArray","blockToUpdate","updateBlock","EventManager","EventEmitter","transaction","appendedTransactions","includeUpdatesFromRemote","cb","isRemoteTransaction","getBlocksChangedByTransaction","includeSelectionChangedByRemote","e","getChildIndex","isWhitespaceNode","liftNestedListsToParent","list","index","parentListItem","siblingsAfter","sibling","siblingContainer","createGroups","listItem","blockGroup","_detachedDoc","detachedDoc","nestedListsToBlockNoteStructure","elementOrHTML","HTMLToBlocks","html","htmlNode","DOMParser","i","code","state","value","properties","result","video","url","title","markdownToHTML","markdown","unified","remarkParse","remarkGfm","remarkRehype","remarkRehypeDefaultHandlers","isVideoUrl","rehypeStringify","markdownToBlocks","htmlString","ExportManager","createExternalHTMLExporter","blocksToMarkdown","raw","htmlToPaste","text","acceptedMIMETypes","checkFileExtensionsMatch","fileExtension1","fileExtension2","checkMIMETypesMatch","mimeType1","mimeType2","types1","types2","insertOrUpdateBlock","newBlock","insertedBlockId","handleFileInsertion","event","dataTransfer","format","mimeType","items","fileBlockType","blockSpec","isFileExtension","file","fileBlock","currentBlock","coords","blockElement","blockRect","updateData","updatedFileBlock","createDropFileExtension","Extension","Plugin","_view","h1","bold","link","ul","ol","hr","fences","blockquote","tableHeader","tableDivider","tableRow","isMarkdown","src","handleVSCodePaste","view","vscode","vscodeData","language","defaultPasteHandler","prioritizeMarkdownOverHTML","plainTextAsMarkdown","plainText","createPasteFromClipboardExtension","pasteHandler","fragmentToExternalHTML","selectedFragment","isWithinBlockContent","isWithinTable","fragmentWithoutParents","child","externalHTML","externalHTMLExporter","contentNodeToTableContent","contentNodeToInlineContent","fragmentToBlocks","selectedFragmentToHTML","clipboardHTML","cleanHTMLToMarkdown","checkIfSelectionInNonEditableBlock","copyToClipboard","createCopyToClipboardExtension","BackgroundColorExtension","getBackgroundColorAttribute","HardBreak","HTMLAttributes","mergeAttributes","getPrevBlockInfo","beforePos","indexInParent","prevBlockBeforePos","getBlockInfoFromResolvedPos","getBottomNestedBlockInfo","blockInfo","group","newPos","canMerge","prevBlockInfo","nextBlockInfo","mergeBlocks","dispatch","childBlocksStart","childBlocksEnd","childBlocksRange","mergeBlocksCommand","posBetweenBlocks","bottomNestedBlockInfo","KeyboardShortcutsExtension","handleBackspace","chain","commands","getBlockInfoFromSelection","selectionAtBlockStart","isParagraph","updateBlockCommand","selectionEmpty","$blockPos","$columnPos","chainedCommands","lastCellParagraphEndPos","nonEditableBlockContentStartPos","blockContentStartPos","bottomBlock","handleDelete","childContainer","depth","blockAtDocEnd","selectionAtBlockEnd","oldDepth","newDepth","handleEnter","withShift","blockEmpty","blockIndented","blockHardBreakShortcut","marks","m","newBlockInsertionPos","newBlockContentPos","splitBlockCommand","FormattingToolbarExtension","FilePanelExtension","SuggestionAddMark","Mark","extension","inline","SuggestionDeleteMark","SuggestionModificationMark","TextAlignmentExtension","attributes","TextColorExtension","getTextColorAttribute","BlockAttributes","BlockContainer","attrs","nodeAttr","HTMLAttr","blockOuter","attribute","blockHTMLAttributes","mergeCSSClasses","BlockGroup","blockGroupHTMLAttributes","Doc","LINKIFY_INITIALIZED","getDefaultTiptapExtensions","tiptapExtensions","extensions","Gapcursor","UniqueID","Text","Link","DEFAULT_LINK_PROTOCOL","VALID_LINK_PROTOCOLS","styleSpec","TiptapExtension","SuggestionMenu","a","inlineContentSpec","context","getDefaultExtensions","BlockChangeExtension","DropCursorExtension","LinkToolbarExtension","NodeSelectionKeyboardExtension","PlaceholderExtension","ShowSelectionExtension","SideMenuExtension","TrailingNodeExtension","ForkYDocExtension","YCursorExtension","YSyncExtension","YUndoExtension","SchemaMigration","HistoryExtension","TableHandlesExtension","PreviousBlockTypeExtension","ExtensionManager","__publicField","abortController","unmountCallback","registeredExtensions","pluginsToAdd","plugin","plugins","instance","originalFactory","originalFactorySymbol","toResolve","toUnregister","didWarn","pluginsToRemove","factory","currentState","getPriority","sortByDependencies","inputRulesByPriority","priority","prosemirrorPlugins","inputRules","inputRulesPlugin","inputRule","InputRule","match","start","end","replaceWith","cursorPosition","updateBlockTr","keymap","key","getSelection","$startBlockBeforePos","$endBlockBeforePos","indexToBlock","sharedDepth","endIndex","startIndexAtDepth","childCountAtDepth","setSelection","startBlock","endBlock","startBlockId","endBlockId","getBlockNoteSchema","anchorPosInfo","headPosInfo","anchorBlockInfo","getBlockInfo","headBlockInfo","anchorBlockConfig","headBlockConfig","startPos","endPos","tableMap","TableMap","lastCellPos","lastCellNodeSize","getSelectionCutBlocks","selectionInfo","prosemirrorSliceToSlicedBlocks","getTextCursorPosition","bnBlock","resolvedPos","prevNode","nextNode","setTextCursorPosition","targetBlock","info","contentType","SelectionManager","ranges","from","to","isNodeSelection","posToDOMRect","StateManager","command","activeTr","editable","undoPlugin","historyPlugin","insertContentAt","position","isOnlyTextContent","isOnlyBlockContent","parent","selectionToInsertionEnd","StyleManager","updateSelection","styles","style","removeChild","n","_","wrapTableRows","f","newItems","prevTable","newTable","transformPasted","shouldApplyFix","nestedChild","container","nodeHasSingleChild","nodeHasInlineContent","nodeHasTableContent","blockNoteTipTapOptions","BlockNoteEditor","args","en","newOptions","BlockNoteSchema","uploadFile","blockId","collaborationEnabled","tiptapOptions","_g","_f","_h","_j","_i","initialContent","getSchema","pmNodes","b","createDocument","TiptapEditor","cache","oldCreateAndFill","jsonNode","Exporter","_schema","mappings","inlineContentArray","nestingLevel","numberedListIndex","mappingFactory","mapping","combineByGroup","additionalItemsArray","combinedItems","additionalItems","additionalItem","lastItemWithSameGroup","item"],"mappings":"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"}