@blocknote/core 0.44.2 → 0.45.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.
Files changed (72) hide show
  1. package/dist/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -1
  2. package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -1
  3. package/dist/{BlockNoteSchema-BsTi0fNS.js → BlockNoteSchema-BOW16JHv.js} +2 -2
  4. package/dist/{BlockNoteSchema-BsTi0fNS.js.map → BlockNoteSchema-BOW16JHv.js.map} +1 -1
  5. package/dist/{BlockNoteSchema-CBNkNhkw.cjs → BlockNoteSchema-CzZbr4Ed.cjs} +2 -2
  6. package/dist/{BlockNoteSchema-CBNkNhkw.cjs.map → BlockNoteSchema-CzZbr4Ed.cjs.map} +1 -1
  7. package/dist/{TrailingNode-CG2a-HDA.js → TrailingNode-8cXFaQUm.js} +484 -487
  8. package/dist/TrailingNode-8cXFaQUm.js.map +1 -0
  9. package/dist/TrailingNode-DPu6X9ym.cjs +2 -0
  10. package/dist/TrailingNode-DPu6X9ym.cjs.map +1 -0
  11. package/dist/{blockToNode-DBNbhwwC.js → blockToNode-BNoNIXU7.js} +2 -2
  12. package/dist/{blockToNode-DBNbhwwC.js.map → blockToNode-BNoNIXU7.js.map} +1 -1
  13. package/dist/{blockToNode-w7H99R6p.cjs → blockToNode-CumVjgem.cjs} +2 -2
  14. package/dist/{blockToNode-w7H99R6p.cjs.map → blockToNode-CumVjgem.cjs.map} +1 -1
  15. package/dist/blocknote.cjs +4 -4
  16. package/dist/blocknote.cjs.map +1 -1
  17. package/dist/blocknote.js +1118 -1077
  18. package/dist/blocknote.js.map +1 -1
  19. package/dist/blocks.cjs +1 -1
  20. package/dist/blocks.js +2 -2
  21. package/dist/defaultBlocks-D1cc0lV9.cjs +6 -0
  22. package/dist/defaultBlocks-D1cc0lV9.cjs.map +1 -0
  23. package/dist/{defaultBlocks-B63ufZ5N.js → defaultBlocks-DvCGYzqu.js} +168 -206
  24. package/dist/defaultBlocks-DvCGYzqu.js.map +1 -0
  25. package/dist/extensions.cjs +1 -1
  26. package/dist/extensions.js +3 -3
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/dist/webpack-stats.json +1 -1
  29. package/dist/yjs.cjs +1 -1
  30. package/dist/yjs.js +1 -1
  31. package/package.json +15 -15
  32. package/src/api/blockManipulation/selections/selection.ts +9 -4
  33. package/src/api/blockManipulation/tables/tables.test.ts +140 -0
  34. package/src/api/blockManipulation/tables/tables.ts +1 -1
  35. package/src/api/parsers/markdown/parseMarkdown.ts +11 -0
  36. package/src/blocks/ListItem/CheckListItem/block.ts +2 -2
  37. package/src/blocks/ListItem/NumberedListItem/block.ts +5 -1
  38. package/src/editor/BlockNoteEditor.test.ts +0 -1
  39. package/src/editor/BlockNoteEditor.ts +9 -39
  40. package/src/editor/BlockNoteExtension.ts +5 -0
  41. package/src/editor/managers/EventManager.ts +1 -1
  42. package/src/editor/managers/ExtensionManager/extensions.ts +2 -12
  43. package/src/editor/managers/ExtensionManager/index.ts +7 -2
  44. package/src/editor/managers/SelectionManager.ts +10 -10
  45. package/src/extensions/BlockChange/BlockChange.ts +2 -2
  46. package/src/extensions/Collaboration/Collaboration.ts +55 -0
  47. package/src/extensions/Collaboration/ForkYDoc.ts +4 -9
  48. package/src/extensions/Collaboration/YCursorPlugin.ts +56 -60
  49. package/src/extensions/Collaboration/YSync.ts +2 -2
  50. package/src/extensions/Collaboration/YUndo.ts +2 -2
  51. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +40 -68
  52. package/src/extensions/TableHandles/TableHandles.ts +9 -5
  53. package/src/index.ts +2 -1
  54. package/src/schema/blocks/createSpec.ts +3 -0
  55. package/src/util/expandToWords.ts +38 -0
  56. package/types/src/api/blockManipulation/selections/selection.d.ts +1 -1
  57. package/types/src/editor/BlockNoteEditor.d.ts +5 -34
  58. package/types/src/editor/BlockNoteExtension.d.ts +4 -0
  59. package/types/src/editor/managers/SelectionManager.d.ts +4 -4
  60. package/types/src/extensions/Collaboration/Collaboration.d.ts +76 -0
  61. package/types/src/extensions/Collaboration/ForkYDoc.d.ts +2 -11
  62. package/types/src/extensions/Collaboration/YCursorPlugin.d.ts +3 -11
  63. package/types/src/extensions/Collaboration/YSync.d.ts +2 -4
  64. package/types/src/extensions/Collaboration/YUndo.d.ts +1 -1
  65. package/types/src/index.d.ts +2 -1
  66. package/types/src/util/expandToWords.d.ts +13 -0
  67. package/dist/TrailingNode-CG2a-HDA.js.map +0 -1
  68. package/dist/TrailingNode-Du4SNHun.cjs +0 -2
  69. package/dist/TrailingNode-Du4SNHun.cjs.map +0 -1
  70. package/dist/defaultBlocks-B63ufZ5N.js.map +0 -1
  71. package/dist/defaultBlocks-BX6UxQa8.cjs +0 -6
  72. package/dist/defaultBlocks-BX6UxQa8.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrailingNode-8cXFaQUm.js","sources":["../src/api/exporters/html/util/serializeBlocksExternalHTML.ts","../src/api/exporters/html/externalHTMLExporter.ts","../src/api/getBlocksChangedByTransaction.ts","../src/extensions/BlockChange/BlockChange.ts","../src/extensions/Collaboration/YCursorPlugin.ts","../src/extensions/Collaboration/YSync.ts","../src/extensions/Collaboration/YUndo.ts","../src/extensions/Collaboration/ForkYDoc.ts","../src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts","../src/extensions/Collaboration/schemaMigration/migrationRules/index.ts","../src/extensions/Collaboration/schemaMigration/SchemaMigration.ts","../src/extensions/DropCursor/DropCursor.ts","../src/extensions/FormattingToolbar/FormattingToolbar.ts","../src/extensions/History/History.ts","../src/extensions/LinkToolbar/LinkToolbar.ts","../src/extensions/LinkToolbar/protocols.ts","../src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.ts","../src/extensions/Placeholder/Placeholder.ts","../src/extensions/PreviousBlockType/PreviousBlockType.ts","../src/extensions/getDraggableBlockFromElement.ts","../src/api/exporters/markdown/util/removeUnderlinesRehypePlugin.ts","../src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts","../src/api/exporters/markdown/util/convertVideoToMarkdownRehypePlugin.ts","../src/api/exporters/markdown/markdownExporter.ts","../src/api/nodeConversions/fragmentToBlocks.ts","../src/extensions/SideMenu/MultipleNodeSelection.ts","../src/extensions/SideMenu/dragging.ts","../src/extensions/SideMenu/SideMenu.ts","../src/extensions/TableHandles/TableHandles.ts","../src/extensions/TrailingNode/TrailingNode.ts"],"sourcesContent":["import { DOMSerializer, Fragment, Node } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../../editor/BlockNoteEditor.js\";\nimport {\n BlockImplementation,\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\";\nimport { nodeToCustomInlineContent } from \"../../../nodeConversions/nodeToBlock.js\";\n\nfunction addAttributesAndRemoveClasses(element: HTMLElement) {\n // Removes all BlockNote specific class names.\n const className =\n Array.from(element.classList).filter(\n (className) => !className.startsWith(\"bn-\"),\n ) || [];\n\n if (className.length > 0) {\n element.className = className.join(\" \");\n } else {\n element.removeAttribute(\"class\");\n }\n}\n\nexport function serializeInlineContentExternalHTML<\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 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);\n } else if (Array.isArray(blockContent)) {\n nodes = inlineContentToNodes(blockContent, editor.pmSchema);\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 or fallback to `render`\n const output = inlineContentImplementation.toExternalHTML\n ? inlineContentImplementation.toExternalHTML(\n inlineContent as any,\n editor as any,\n )\n : 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 = (\n editor.schema.styleSpecs[mark.type.name].implementation\n .toExternalHTML ??\n editor.schema.styleSpecs[mark.type.name].implementation.render\n )(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 if (\n fragment.childNodes.length === 1 &&\n fragment.firstChild?.nodeType === 1 /* Node.ELEMENT_NODE */\n ) {\n addAttributesAndRemoveClasses(fragment.firstChild as HTMLElement);\n }\n\n return fragment;\n}\n\n/**\n * TODO: there's still quite some logic that handles getting and filtering properties,\n * we should make sure the `toExternalHTML` methods of default blocks actually handle this,\n * instead of the serializer.\n */\nfunction serializeBlock<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n fragment: DocumentFragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n block: PartialBlock<BSchema, I, S>,\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) {\n const doc = options?.document ?? document;\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\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 // the container node is just used as a workaround to get some block-level attributes.\n // we should change toExternalHTML so that this is not necessary\n const attrs = Array.from(bc.dom.attributes);\n\n const blockImplementation = editor.blockImplementations[block.type as any]\n .implementation as BlockImplementation;\n const ret =\n blockImplementation.toExternalHTML?.call(\n {},\n { ...block, props } as any,\n editor as any,\n ) ||\n blockImplementation.render.call(\n {},\n { ...block, props } as any,\n editor as any,\n );\n\n const elementFragment = doc.createDocumentFragment();\n\n if ((ret.dom as HTMLElement).classList.contains(\"bn-block-content\")) {\n const blockContentDataAttributes = [\n ...attrs,\n ...Array.from((ret.dom as HTMLElement).attributes),\n ].filter(\n (attr) =>\n attr.name.startsWith(\"data\") &&\n attr.name !== \"data-content-type\" &&\n attr.name !== \"data-file-block\" &&\n attr.name !== \"data-node-view-wrapper\" &&\n attr.name !== \"data-node-type\" &&\n attr.name !== \"data-id\" &&\n attr.name !== \"data-editable\",\n );\n\n // ret.dom = ret.dom.firstChild! as any;\n for (const attr of blockContentDataAttributes) {\n (ret.dom.firstChild! as HTMLElement).setAttribute(attr.name, attr.value);\n }\n\n addAttributesAndRemoveClasses(ret.dom.firstChild! as HTMLElement);\n elementFragment.append(...Array.from(ret.dom.childNodes));\n } else {\n elementFragment.append(ret.dom);\n }\n\n if (ret.contentDOM && block.content) {\n const ic = serializeInlineContentExternalHTML(\n editor,\n block.content as any, // TODO\n serializer,\n options,\n );\n\n ret.contentDOM.appendChild(ic);\n }\n\n let listType = undefined;\n if (orderedListItemBlockTypes.has(block.type!)) {\n listType = \"OL\";\n } else if (unorderedListItemBlockTypes.has(block.type!)) {\n listType = \"UL\";\n }\n\n if (listType) {\n if (fragment.lastChild?.nodeName !== listType) {\n const list = doc.createElement(listType);\n\n if (\n listType === \"OL\" &&\n \"start\" in props &&\n props.start &&\n props?.start !== 1\n ) {\n list.setAttribute(\"start\", props.start + \"\");\n }\n fragment.append(list);\n }\n fragment.lastChild!.appendChild(elementFragment);\n } else {\n fragment.append(elementFragment);\n }\n\n if (block.children && block.children.length > 0) {\n const childFragment = doc.createDocumentFragment();\n serializeBlocksToFragment(\n childFragment,\n editor,\n block.children,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n if (\n fragment.lastChild?.nodeName === \"UL\" ||\n fragment.lastChild?.nodeName === \"OL\"\n ) {\n // add nested lists to the last list item\n while (\n childFragment.firstChild?.nodeName === \"UL\" ||\n childFragment.firstChild?.nodeName === \"OL\"\n ) {\n fragment.lastChild!.lastChild!.appendChild(childFragment.firstChild!);\n }\n }\n\n if (editor.pmSchema.nodes[block.type as any].isInGroup(\"blockContent\")) {\n // default \"blockContainer\" style blocks are flattened (no \"nested block\" support) for externalHTML, so append the child fragment to the outer fragment\n fragment.append(childFragment);\n } else {\n // for columns / column lists, do use nesting\n ret.contentDOM?.append(childFragment);\n }\n }\n}\n\nconst serializeBlocksToFragment = <\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n fragment: DocumentFragment,\n editor: BlockNoteEditor<BSchema, I, S>,\n blocks: PartialBlock<BSchema, I, S>[],\n serializer: DOMSerializer,\n orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) => {\n for (const block of blocks) {\n serializeBlock(\n fragment,\n editor,\n block,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n }\n};\n\nexport const serializeBlocksExternalHTML = <\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 orderedListItemBlockTypes: Set<string>,\n unorderedListItemBlockTypes: Set<string>,\n options?: { document?: Document },\n) => {\n const doc = options?.document ?? document;\n const fragment = doc.createDocumentFragment();\n\n serializeBlocksToFragment(\n fragment,\n editor,\n blocks,\n serializer,\n orderedListItemBlockTypes,\n unorderedListItemBlockTypes,\n options,\n );\n return fragment;\n};\n","import { DOMSerializer, Schema } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n BlockSchema,\n InlineContent,\n InlineContentSchema,\n StyleSchema,\n} from \"../../../schema/index.js\";\nimport {\n serializeBlocksExternalHTML,\n serializeInlineContentExternalHTML,\n} from \"./util/serializeBlocksExternalHTML.js\";\n\n// Used to export BlockNote blocks and ProseMirror nodes to HTML for use outside\n// the editor. Blocks are exported using the `toExternalHTML` method in their\n// `blockSpec`, or `toInternalHTML` if `toExternalHTML` is not defined.\n//\n// The HTML created by this serializer is different to what's rendered by the\n// editor to the DOM. This also means that data is likely to be lost when\n// converting back to original blocks. The differences in the output HTML are:\n// 1. It doesn't include the `blockGroup` and `blockContainer` wrappers meaning\n// that nesting is not preserved for non-list-item blocks.\n// 2. `li` items in the output HTML are wrapped in `ul` or `ol` elements.\n// 3. While nesting for list items is preserved, other types of blocks nested\n// inside a list are un-nested and a new list is created after them.\n// 4. The HTML is wrapped in a single `div` element.\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport const createExternalHTMLExporter = <\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 exportBlocks: (\n blocks: PartialBlock<BSchema, I, S>[],\n options: { document?: Document },\n ) => {\n const html = serializeBlocksExternalHTML(\n editor,\n blocks,\n serializer,\n new Set<string>([\"numberedListItem\"]),\n new Set<string>([\"bulletListItem\", \"checkListItem\", \"toggleListItem\"]),\n options,\n );\n const div = document.createElement(\"div\");\n div.append(html);\n return div.innerHTML;\n },\n\n exportInlineContent: (\n inlineContent: InlineContent<I, S>[],\n options: { document?: Document },\n ) => {\n const domFragment = serializeInlineContentExternalHTML(\n editor,\n inlineContent as any,\n serializer,\n options,\n );\n\n const parent = document.createElement(\"div\");\n parent.append(domFragment.cloneNode(true));\n\n return parent.innerHTML;\n },\n };\n};\n","import { combineTransactionSteps } from \"@tiptap/core\";\nimport deepEqual from \"fast-deep-equal\";\nimport type { Node } from \"prosemirror-model\";\nimport type { Transaction } from \"prosemirror-state\";\nimport {\n Block,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"../blocks/defaultBlocks.js\";\nimport type { BlockSchema } from \"../schema/index.js\";\nimport type { InlineContentSchema } from \"../schema/inlineContent/types.js\";\nimport type { StyleSchema } from \"../schema/styles/types.js\";\nimport { nodeToBlock } from \"./nodeConversions/nodeToBlock.js\";\nimport { isNodeBlock } from \"./nodeUtil.js\";\nimport { getPmSchema } from \"./pmUtil.js\";\n\n/**\n * Change detection utilities for BlockNote.\n *\n * High-level algorithm used by getBlocksChangedByTransaction:\n * 1) Merge appended transactions into one document change.\n * 2) Collect a snapshot of blocks before and after (flat map by id, and per-parent child order).\n * 3) Emit inserts and deletes by diffing ids between snapshots.\n * 4) For ids present in both snapshots:\n * - If parentId changed, emit a move\n * - Else if block changed (ignoring children), emit an update\n * 5) Finally, detect same-parent sibling reorders by comparing child order per parent.\n * We use an inlined O(n log n) LIS inside detectReorderedChildren to keep a\n * longest already-ordered subsequence and mark only the remaining items as moved.\n */\n/**\n * Gets the parent block of a node, if it has one.\n */\nfunction getParentBlockId(doc: Node, pos: number): string | undefined {\n if (pos === 0) {\n return undefined;\n }\n const resolvedPos = doc.resolve(pos);\n for (let i = resolvedPos.depth; i > 0; i--) {\n const parent = resolvedPos.node(i);\n if (isNodeBlock(parent)) {\n return parent.attrs.id;\n }\n }\n return undefined;\n}\n\n/**\n * This attributes the changes to a specific source.\n */\nexport type BlockChangeSource =\n | { type: \"local\" }\n | { type: \"paste\" }\n | { type: \"drop\" }\n | { type: \"undo\" | \"redo\" | \"undo-redo\" }\n | { type: \"yjs-remote\" };\n\nexport type BlocksChanged<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> = Array<\n {\n /**\n * The affected block.\n */\n block: Block<BSchema, ISchema, SSchema>;\n /**\n * The source of the change.\n */\n source: BlockChangeSource;\n } & (\n | {\n type: \"insert\" | \"delete\";\n /**\n * Insert and delete changes don't have a previous block.\n */\n prevBlock: undefined;\n }\n | {\n type: \"update\";\n /**\n * The previous block.\n */\n prevBlock: Block<BSchema, ISchema, SSchema>;\n }\n | {\n type: \"move\";\n /**\n * The affected block.\n */\n block: Block<BSchema, ISchema, SSchema>;\n /**\n * The block before the move.\n */\n prevBlock: Block<BSchema, ISchema, SSchema>;\n /**\n * The previous parent block (if it existed).\n */\n prevParent?: Block<BSchema, ISchema, SSchema>;\n /**\n * The current parent block (if it exists).\n */\n currentParent?: Block<BSchema, ISchema, SSchema>;\n }\n )\n>;\n\nfunction determineChangeSource(transaction: Transaction): BlockChangeSource {\n if (transaction.getMeta(\"paste\")) {\n return { type: \"paste\" };\n }\n if (transaction.getMeta(\"uiEvent\") === \"drop\") {\n return { type: \"drop\" };\n }\n if (transaction.getMeta(\"history$\")) {\n return {\n type: transaction.getMeta(\"history$\").redo ? \"redo\" : \"undo\",\n };\n }\n if (transaction.getMeta(\"y-sync$\")) {\n if (transaction.getMeta(\"y-sync$\").isUndoRedoOperation) {\n return { type: \"undo-redo\" };\n }\n return { type: \"yjs-remote\" };\n }\n return { type: \"local\" };\n}\n\ntype BlockSnapshot<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n> = {\n byId: Record<\n string,\n {\n block: Block<BSchema, ISchema, SSchema>;\n parentId: string | undefined;\n }\n >;\n childrenByParent: Record<string, string[]>;\n};\n\n/**\n * Collects a snapshot of blocks and per-parent child order in a single traversal.\n * Uses \"__root__\" to represent the root level where parentId is undefined.\n */\nfunction collectSnapshot<\n BSchema extends BlockSchema,\n ISchema extends InlineContentSchema,\n SSchema extends StyleSchema,\n>(doc: Node): BlockSnapshot<BSchema, ISchema, SSchema> {\n const ROOT_KEY = \"__root__\";\n const byId: Record<\n string,\n {\n block: Block<BSchema, ISchema, SSchema>;\n parentId: string | undefined;\n }\n > = {};\n const childrenByParent: Record<string, string[]> = {};\n const pmSchema = getPmSchema(doc);\n doc.descendants((node, pos) => {\n if (!isNodeBlock(node)) {\n return true;\n }\n const parentId = getParentBlockId(doc, pos);\n const key = parentId ?? ROOT_KEY;\n if (!childrenByParent[key]) {\n childrenByParent[key] = [];\n }\n const block = nodeToBlock(node, pmSchema);\n byId[node.attrs.id] = { block, parentId };\n childrenByParent[key].push(node.attrs.id);\n return true;\n });\n return { byId, childrenByParent };\n}\n\n/**\n * Determines which child ids have been reordered (moved) within the same parent.\n * Uses LIS to keep the longest ordered subsequence and marks the rest as moved.\n */\nfunction detectReorderedChildren(\n prevOrder: string[] | undefined,\n nextOrder: string[] | undefined,\n): Set<string> {\n const moved = new Set<string>();\n if (!prevOrder || !nextOrder) {\n return moved;\n }\n // Consider only ids present in both orders (ignore inserts/deletes handled elsewhere)\n const prevIds = new Set(prevOrder);\n const commonNext: string[] = nextOrder.filter((id) => prevIds.has(id));\n const commonPrev: string[] = prevOrder.filter((id) =>\n commonNext.includes(id),\n );\n\n if (commonPrev.length <= 1 || commonNext.length <= 1) {\n return moved;\n }\n\n // Map ids to their index in previous order\n const indexInPrev: Record<string, number> = {};\n for (let i = 0; i < commonPrev.length; i++) {\n indexInPrev[commonPrev[i]] = i;\n }\n\n // Build sequence of indices representing next order in terms of previous indices\n const sequence: number[] = commonNext.map((id) => indexInPrev[id]);\n\n // Inline O(n log n) LIS with reconstruction.\n // Why LIS? We want the smallest set of siblings to label as \"moved\".\n // Keeping the longest subsequence that is already in order achieves this,\n // so only items outside the LIS are reported as moves.\n const n = sequence.length;\n const tailsValues: number[] = [];\n const tailsEndsAtIndex: number[] = [];\n const previousIndexInLis: number[] = new Array(n).fill(-1);\n\n const lowerBound = (arr: number[], target: number): number => {\n let lo = 0;\n let hi = arr.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (arr[mid] < target) {\n lo = mid + 1;\n } else {\n hi = mid;\n }\n }\n return lo;\n };\n\n for (let i = 0; i < n; i++) {\n const value = sequence[i];\n const pos = lowerBound(tailsValues, value);\n if (pos > 0) {\n previousIndexInLis[i] = tailsEndsAtIndex[pos - 1];\n }\n if (pos === tailsValues.length) {\n tailsValues.push(value);\n tailsEndsAtIndex.push(i);\n } else {\n tailsValues[pos] = value;\n tailsEndsAtIndex[pos] = i;\n }\n }\n\n const lisIndexSet = new Set<number>();\n let k = tailsEndsAtIndex[tailsEndsAtIndex.length - 1] ?? -1;\n while (k !== -1) {\n lisIndexSet.add(k);\n k = previousIndexInLis[k];\n }\n\n // Items not part of LIS are considered moved\n for (let i = 0; i < commonNext.length; i++) {\n if (!lisIndexSet.has(i)) {\n moved.add(commonNext[i]);\n }\n }\n return moved;\n}\n\n/**\n * Get the blocks that were changed by a transaction.\n */\nexport function getBlocksChangedByTransaction<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n>(\n transaction: Transaction,\n appendedTransactions: Transaction[] = [],\n): BlocksChanged<BSchema, ISchema, SSchema> {\n const source = determineChangeSource(transaction);\n const combinedTransaction = combineTransactionSteps(transaction.before, [\n transaction,\n ...appendedTransactions,\n ]);\n\n const prevSnap = collectSnapshot<BSchema, ISchema, SSchema>(\n combinedTransaction.before,\n );\n const nextSnap = collectSnapshot<BSchema, ISchema, SSchema>(\n combinedTransaction.doc,\n );\n\n const changes: BlocksChanged<BSchema, ISchema, SSchema> = [];\n const changedIds = new Set<string>();\n\n // Handle inserted blocks\n Object.keys(nextSnap.byId)\n .filter((id) => !(id in prevSnap.byId))\n .forEach((id) => {\n changes.push({\n type: \"insert\",\n block: nextSnap.byId[id].block,\n source,\n prevBlock: undefined,\n });\n changedIds.add(id);\n });\n\n // Handle deleted blocks\n Object.keys(prevSnap.byId)\n .filter((id) => !(id in nextSnap.byId))\n .forEach((id) => {\n changes.push({\n type: \"delete\",\n block: prevSnap.byId[id].block,\n source,\n prevBlock: undefined,\n });\n changedIds.add(id);\n });\n\n // Handle updated, moved to different parent, indented, outdented blocks\n Object.keys(nextSnap.byId)\n .filter((id) => id in prevSnap.byId)\n .forEach((id) => {\n const prev = prevSnap.byId[id];\n const next = nextSnap.byId[id];\n const isParentDifferent = prev.parentId !== next.parentId;\n\n if (isParentDifferent) {\n changes.push({\n type: \"move\",\n block: next.block,\n prevBlock: prev.block,\n source,\n prevParent: prev.parentId\n ? prevSnap.byId[prev.parentId]?.block\n : undefined,\n currentParent: next.parentId\n ? nextSnap.byId[next.parentId]?.block\n : undefined,\n });\n changedIds.add(id);\n } else if (\n // Compare blocks while ignoring children to avoid reporting a parent\n // update when only descendants changed.\n !deepEqual(\n { ...prev.block, children: undefined } as any,\n { ...next.block, children: undefined } as any,\n )\n ) {\n changes.push({\n type: \"update\",\n block: next.block,\n prevBlock: prev.block,\n source,\n });\n changedIds.add(id);\n }\n });\n\n // Handle sibling reorders (parent unchanged but relative order changed)\n const prevOrderByParent = prevSnap.childrenByParent;\n const nextOrderByParent = nextSnap.childrenByParent;\n\n // Use a special key for root-level siblings\n const ROOT_KEY = \"__root__\";\n const parents = new Set<string>([\n ...Object.keys(prevOrderByParent),\n ...Object.keys(nextOrderByParent),\n ]);\n\n const addedMoveForId = new Set<string>();\n\n parents.forEach((parentKey) => {\n const movedWithinParent = detectReorderedChildren(\n prevOrderByParent[parentKey],\n nextOrderByParent[parentKey],\n );\n if (movedWithinParent.size === 0) {\n return;\n }\n movedWithinParent.forEach((id) => {\n // Only consider ids that exist in both snapshots and whose parent truly did not change\n const prev = prevSnap.byId[id];\n const next = nextSnap.byId[id];\n if (!prev || !next) {\n return;\n }\n if (prev.parentId !== next.parentId) {\n return;\n }\n // Skip if already accounted for by insert/delete/update/parent move\n if (changedIds.has(id)) {\n return;\n }\n // Verify we're addressing the right parent bucket\n const bucketKey = prev.parentId ?? ROOT_KEY;\n if (bucketKey !== parentKey) {\n return;\n }\n if (addedMoveForId.has(id)) {\n return;\n }\n addedMoveForId.add(id);\n changes.push({\n type: \"move\",\n block: next.block,\n prevBlock: prev.block,\n source,\n prevParent: prev.parentId\n ? prevSnap.byId[prev.parentId]?.block\n : undefined,\n currentParent: next.parentId\n ? nextSnap.byId[next.parentId]?.block\n : undefined,\n });\n changedIds.add(id);\n });\n });\n\n return changes;\n}\n","import { Plugin, PluginKey, Transaction } from \"prosemirror-state\";\nimport {\n BlocksChanged,\n getBlocksChangedByTransaction,\n} from \"../../api/getBlocksChangedByTransaction.js\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\n/**\n * This plugin can filter transactions before they are applied to the editor, but with a higher-level API than `filterTransaction` from prosemirror.\n */\nexport const BlockChangeExtension = createExtension(() => {\n const beforeChangeCallbacks: ((context: {\n getChanges: () => BlocksChanged<any, any, any>;\n tr: Transaction;\n }) => boolean | void)[] = [];\n return {\n key: \"blockChange\",\n prosemirrorPlugins: [\n new Plugin({\n key: new PluginKey(\"blockChange\"),\n filterTransaction: (tr) => {\n let changes:\n | ReturnType<typeof getBlocksChangedByTransaction<any, any, any>>\n | undefined = undefined;\n\n return beforeChangeCallbacks.reduce((acc, cb) => {\n if (acc === false) {\n // We only care that we hit a `false` result, so we can stop iterating.\n return acc;\n }\n return (\n cb({\n getChanges() {\n if (changes) {\n return changes;\n }\n changes = getBlocksChangedByTransaction<any, any, any>(tr);\n return changes;\n },\n tr,\n }) !== false\n );\n }, true);\n },\n }),\n ],\n\n /**\n * Subscribe to the block change events.\n */\n subscribe(\n callback: (context: {\n getChanges: () => BlocksChanged<any, any, any>;\n tr: Transaction;\n }) => boolean | void,\n ) {\n beforeChangeCallbacks.push(callback);\n\n return () => {\n beforeChangeCallbacks.splice(\n beforeChangeCallbacks.indexOf(callback),\n 1,\n );\n };\n },\n } as const;\n});\n","import { defaultSelectionBuilder, yCursorPlugin } from \"y-prosemirror\";\nimport {\n createExtension,\n ExtensionOptions,\n} from \"../../editor/BlockNoteExtension.js\";\nimport { CollaborationOptions } from \"./Collaboration.js\";\n\nexport type CollaborationUser = {\n name: string;\n color: string;\n [key: string]: string;\n};\n\n/**\n * Determine whether the foreground color should be white or black based on a provided background color\n * Inspired by: https://stackoverflow.com/a/3943023\n */\nfunction isDarkColor(bgColor: string): boolean {\n const color = bgColor.charAt(0) === \"#\" ? bgColor.substring(1, 7) : bgColor;\n const r = parseInt(color.substring(0, 2), 16); // hexToR\n const g = parseInt(color.substring(2, 4), 16); // hexToG\n const b = parseInt(color.substring(4, 6), 16); // hexToB\n const uicolors = [r / 255, g / 255, b / 255];\n const c = uicolors.map((col) => {\n if (col <= 0.03928) {\n return col / 12.92;\n }\n return Math.pow((col + 0.055) / 1.055, 2.4);\n });\n const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];\n return L <= 0.179;\n}\n\nfunction defaultCursorRender(user: CollaborationUser) {\n const cursorElement = document.createElement(\"span\");\n\n cursorElement.classList.add(\"bn-collaboration-cursor__base\");\n\n const caretElement = document.createElement(\"span\");\n caretElement.setAttribute(\"contentedEditable\", \"false\");\n caretElement.classList.add(\"bn-collaboration-cursor__caret\");\n caretElement.setAttribute(\n \"style\",\n `background-color: ${user.color}; color: ${\n isDarkColor(user.color) ? \"white\" : \"black\"\n }`,\n );\n\n const labelElement = document.createElement(\"span\");\n\n labelElement.classList.add(\"bn-collaboration-cursor__label\");\n labelElement.setAttribute(\n \"style\",\n `background-color: ${user.color}; color: ${\n isDarkColor(user.color) ? \"white\" : \"black\"\n }`,\n );\n labelElement.insertBefore(document.createTextNode(user.name), null);\n\n caretElement.insertBefore(labelElement, null);\n\n cursorElement.insertBefore(document.createTextNode(\"\\u2060\"), null); // Non-breaking space\n cursorElement.insertBefore(caretElement, null);\n cursorElement.insertBefore(document.createTextNode(\"\\u2060\"), null); // Non-breaking space\n\n return cursorElement;\n}\n\nexport const YCursorExtension = createExtension(\n ({ options }: ExtensionOptions<CollaborationOptions>) => {\n const recentlyUpdatedCursors = new Map();\n const awareness =\n options.provider &&\n \"awareness\" in options.provider &&\n typeof options.provider.awareness === \"object\"\n ? options.provider.awareness\n : undefined;\n if (awareness) {\n if (\n \"setLocalStateField\" in awareness &&\n typeof awareness.setLocalStateField === \"function\"\n ) {\n awareness.setLocalStateField(\"user\", options.user);\n }\n if (\"on\" in awareness && typeof awareness.on === \"function\") {\n if (options.showCursorLabels !== \"always\") {\n awareness.on(\n \"change\",\n ({\n updated,\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n }) => {\n for (const clientID of updated) {\n const cursor = recentlyUpdatedCursors.get(clientID);\n\n if (cursor) {\n cursor.element.setAttribute(\"data-active\", \"\");\n\n if (cursor.hideTimeout) {\n clearTimeout(cursor.hideTimeout);\n }\n\n recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: setTimeout(() => {\n cursor.element.removeAttribute(\"data-active\");\n }, 2000),\n });\n }\n }\n },\n );\n }\n }\n }\n\n return {\n key: \"yCursor\",\n prosemirrorPlugins: [\n awareness\n ? yCursorPlugin(awareness, {\n selectionBuilder: defaultSelectionBuilder,\n cursorBuilder(user: CollaborationUser, clientID: number) {\n let cursorData = recentlyUpdatedCursors.get(clientID);\n\n if (!cursorData) {\n const cursorElement = (\n options.renderCursor ?? defaultCursorRender\n )(user);\n\n if (options.showCursorLabels !== \"always\") {\n cursorElement.addEventListener(\"mouseenter\", () => {\n const cursor = recentlyUpdatedCursors.get(clientID)!;\n cursor.element.setAttribute(\"data-active\", \"\");\n\n if (cursor.hideTimeout) {\n clearTimeout(cursor.hideTimeout);\n recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: undefined,\n });\n }\n });\n\n cursorElement.addEventListener(\"mouseleave\", () => {\n const cursor = recentlyUpdatedCursors.get(clientID)!;\n\n recentlyUpdatedCursors.set(clientID, {\n element: cursor.element,\n hideTimeout: setTimeout(() => {\n cursor.element.removeAttribute(\"data-active\");\n }, 2000),\n });\n });\n }\n\n cursorData = {\n element: cursorElement,\n hideTimeout: undefined,\n };\n\n recentlyUpdatedCursors.set(clientID, cursorData);\n }\n\n return cursorData.element;\n },\n })\n : undefined,\n ].filter(Boolean),\n dependsOn: [\"ySync\"],\n updateUser(user: { name: string; color: string; [key: string]: string }) {\n awareness?.setLocalStateField(\"user\", user);\n },\n } as const;\n },\n);\n","import { ySyncPlugin } from \"y-prosemirror\";\nimport {\n ExtensionOptions,\n createExtension,\n} from \"../../editor/BlockNoteExtension.js\";\nimport { CollaborationOptions } from \"./Collaboration.js\";\n\nexport const YSyncExtension = createExtension(\n ({ options }: ExtensionOptions<Pick<CollaborationOptions, \"fragment\">>) => {\n return {\n key: \"ySync\",\n prosemirrorPlugins: [ySyncPlugin(options.fragment)],\n runsBefore: [\"default\"],\n } as const;\n },\n);\n","import { redoCommand, undoCommand, yUndoPlugin } from \"y-prosemirror\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport const YUndoExtension = createExtension(() => {\n return {\n key: \"yUndo\",\n prosemirrorPlugins: [yUndoPlugin()],\n dependsOn: [\"yCursor\", \"ySync\"],\n undoCommand: undoCommand,\n redoCommand: redoCommand,\n } as const;\n});\n","import { yUndoPluginKey } from \"y-prosemirror\";\nimport * as Y from \"yjs\";\nimport {\n createExtension,\n createStore,\n ExtensionOptions,\n} from \"../../editor/BlockNoteExtension.js\";\nimport { CollaborationOptions } from \"./Collaboration.js\";\nimport { YCursorExtension } from \"./YCursorPlugin.js\";\nimport { YSyncExtension } from \"./YSync.js\";\nimport { YUndoExtension } from \"./YUndo.js\";\n\n/**\n * To find a fragment in another ydoc, we need to search for it.\n */\nfunction findTypeInOtherYdoc<T extends Y.AbstractType<any>>(\n ytype: T,\n otherYdoc: Y.Doc,\n): T {\n const ydoc = ytype.doc!;\n if (ytype._item === null) {\n /**\n * If is a root type, we need to find the root key in the original ydoc\n * and use it to get the type in the other ydoc.\n */\n const rootKey = Array.from(ydoc.share.keys()).find(\n (key) => ydoc.share.get(key) === ytype,\n );\n if (rootKey == null) {\n throw new Error(\"type does not exist in other ydoc\");\n }\n return otherYdoc.get(rootKey, ytype.constructor as new () => T) as T;\n } else {\n /**\n * If it is a sub type, we use the item id to find the history type.\n */\n const ytypeItem = ytype._item;\n const otherStructs = otherYdoc.store.clients.get(ytypeItem.id.client) ?? [];\n const itemIndex = Y.findIndexSS(otherStructs, ytypeItem.id.clock);\n const otherItem = otherStructs[itemIndex] as Y.Item;\n const otherContent = otherItem.content as Y.ContentType;\n return otherContent.type as T;\n }\n}\n\nexport const ForkYDocExtension = createExtension(\n ({ editor, options }: ExtensionOptions<CollaborationOptions>) => {\n let forkedState:\n | {\n originalFragment: Y.XmlFragment;\n undoStack: Y.UndoManager[\"undoStack\"];\n forkedFragment: Y.XmlFragment;\n }\n | undefined = undefined;\n\n const store = createStore({ isForked: false });\n\n return {\n key: \"yForkDoc\",\n store,\n /**\n * Fork the Y.js document from syncing to the remote,\n * allowing modifications to the document without affecting the remote.\n * These changes can later be rolled back or applied to the remote.\n */\n fork() {\n if (forkedState) {\n return;\n }\n\n const originalFragment = options.fragment;\n\n if (!originalFragment) {\n throw new Error(\"No fragment to fork from\");\n }\n\n const doc = new Y.Doc();\n // Copy the original document to a new Yjs document\n Y.applyUpdate(doc, Y.encodeStateAsUpdate(originalFragment.doc!));\n\n // Find the forked fragment in the new Yjs document\n const forkedFragment = findTypeInOtherYdoc(originalFragment, doc);\n\n forkedState = {\n undoStack: yUndoPluginKey.getState(editor.prosemirrorState)!\n .undoManager.undoStack,\n originalFragment,\n forkedFragment,\n };\n\n // Need to reset all the yjs plugins\n editor.unregisterExtension([\n YUndoExtension,\n YCursorExtension,\n YSyncExtension,\n ]);\n const newOptions = {\n ...options,\n fragment: forkedFragment,\n };\n // Register them again, based on the new forked fragment\n editor.registerExtension([\n YSyncExtension(newOptions),\n // No need to register the cursor plugin again, it's a local fork\n YUndoExtension(),\n ]);\n\n // Tell the store that the editor is now forked\n store.setState({ isForked: true });\n },\n\n /**\n * Resume syncing the Y.js document to the remote\n * If `keepChanges` is true, any changes that have been made to the forked document will be applied to the original document.\n * Otherwise, the original document will be restored and the changes will be discarded.\n */\n merge({ keepChanges }: { keepChanges: boolean }) {\n if (!forkedState) {\n return;\n }\n // Remove the forked fragment's plugins\n editor.unregisterExtension([\"ySync\", \"yCursor\", \"yUndo\"]);\n\n const { originalFragment, forkedFragment, undoStack } = forkedState;\n // Register the plugins again, based on the original fragment (which is still in the original options)\n editor.registerExtension([\n YSyncExtension(options),\n YCursorExtension(options),\n YUndoExtension(),\n ]);\n\n // Reset the undo stack to the original undo stack\n yUndoPluginKey.getState(\n editor.prosemirrorState,\n )!.undoManager.undoStack = undoStack;\n\n if (keepChanges) {\n // Apply any changes that have been made to the fork, onto the original doc\n const update = Y.encodeStateAsUpdate(\n forkedFragment.doc!,\n Y.encodeStateVector(originalFragment.doc!),\n );\n // Applying this change will add to the undo stack, allowing it to be undone normally\n Y.applyUpdate(originalFragment.doc!, update, editor);\n }\n // Reset the forked state\n forkedState = undefined;\n // Tell the store that the editor is no longer forked\n store.setState({ isForked: false });\n },\n } as const;\n },\n);\n","import * as Y from \"yjs\";\n\nimport { MigrationRule } from \"./migrationRule.js\";\nimport { defaultProps } from \"../../../../blocks/defaultProps.js\";\n\n// Helper function to recursively traverse a `Y.XMLElement` and its descendant\n// elements.\nconst traverseElement = (\n rootElement: Y.XmlElement,\n cb: (element: Y.XmlElement) => void,\n) => {\n cb(rootElement);\n rootElement.forEach((element) => {\n if (element instanceof Y.XmlElement) {\n traverseElement(element, cb);\n }\n });\n};\n\n// Moves `textColor` and `backgroundColor` attributes from `blockContainer`\n// nodes to their child `blockContent` nodes. This is due to a schema change\n// introduced in PR #TODO.\nexport const moveColorAttributes: MigrationRule = (fragment, tr) => {\n // Stores necessary info for all `blockContainer` nodes which still have\n // `textColor` or `backgroundColor` attributes that need to be moved.\n const targetBlockContainers: Map<\n string,\n {\n textColor: string | undefined;\n backgroundColor: string | undefined;\n }\n > = new Map();\n // Finds all elements which still have `textColor` or `backgroundColor`\n // attributes in the current Yjs fragment.\n fragment.forEach((element) => {\n if (element instanceof Y.XmlElement) {\n traverseElement(element, (element) => {\n if (\n element.nodeName === \"blockContainer\" &&\n element.hasAttribute(\"id\")\n ) {\n const textColor = element.getAttribute(\"textColor\");\n const backgroundColor = element.getAttribute(\"backgroundColor\");\n\n const colors = {\n textColor:\n textColor === defaultProps.textColor.default\n ? undefined\n : textColor,\n backgroundColor:\n backgroundColor === defaultProps.backgroundColor.default\n ? undefined\n : backgroundColor,\n };\n\n if (colors.textColor || colors.backgroundColor) {\n targetBlockContainers.set(element.getAttribute(\"id\")!, colors);\n }\n }\n });\n }\n });\n\n if (targetBlockContainers.size === 0) {\n return false;\n }\n\n // Appends transactions to add the `textColor` and `backgroundColor`\n // attributes found on each `blockContainer` node to move them to the child\n // `blockContent` node.\n tr.doc.descendants((node, pos) => {\n if (\n node.type.name === \"blockContainer\" &&\n targetBlockContainers.has(node.attrs.id)\n ) {\n const el = tr.doc.nodeAt(pos + 1);\n if (!el) {\n throw new Error(\"No element found\");\n }\n\n tr.setNodeMarkup(pos + 1, undefined, {\n // preserve existing attributes\n ...el.attrs,\n // add the textColor and backgroundColor attributes\n ...targetBlockContainers.get(node.attrs.id),\n });\n }\n });\n\n return true;\n};\n","import { MigrationRule } from \"./migrationRule.js\";\nimport { moveColorAttributes } from \"./moveColorAttributes.js\";\n\nexport default [moveColorAttributes] as MigrationRule[];\n","import { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport * as Y from \"yjs\";\n\nimport {\n createExtension,\n ExtensionOptions,\n} from \"../../../editor/BlockNoteExtension.js\";\nimport migrationRules from \"./migrationRules/index.js\";\n\n// This plugin allows us to update collaboration YDocs whenever BlockNote's\n// underlying ProseMirror schema changes. The plugin reads the current Yjs\n// fragment and dispatches additional transactions to the ProseMirror state, in\n// case things are found in the fragment that don't adhere to the editor schema\n// and need to be fixed. These fixes are defined as `MigrationRule`s within the\n// `migrationRules` directory.\nexport const SchemaMigration = createExtension(\n ({ options }: ExtensionOptions<{ fragment: Y.XmlFragment }>) => {\n let migrationDone = false;\n const pluginKey = new PluginKey(\"schemaMigration\");\n\n return {\n key: \"schemaMigration\",\n prosemirrorPlugins: [\n new Plugin({\n key: pluginKey,\n appendTransaction: (transactions, _oldState, newState) => {\n if (migrationDone) {\n return undefined;\n }\n\n if (\n // If any of the transactions are not due to a yjs sync, we don't need to run the migration\n !transactions.some((tr) => tr.getMeta(\"y-sync$\")) ||\n // If none of the transactions result in a document change, we don't need to run the migration\n transactions.every((tr) => !tr.docChanged) ||\n // If the fragment is still empty, we can't run the migration (since it has not yet been applied to the Y.Doc)\n !options.fragment.firstChild\n ) {\n return undefined;\n }\n\n const tr = newState.tr;\n for (const migrationRule of migrationRules) {\n migrationRule(options.fragment, tr);\n }\n\n migrationDone = true;\n\n if (!tr.docChanged) {\n return undefined;\n }\n\n return tr;\n },\n }),\n ],\n } as const;\n },\n);\n","import { dropCursor } from \"prosemirror-dropcursor\";\nimport {\n createExtension,\n ExtensionOptions,\n} from \"../../editor/BlockNoteExtension.js\";\nimport { BlockNoteEditorOptions } from \"../../editor/BlockNoteEditor.js\";\n\nexport const DropCursorExtension = createExtension(\n ({\n editor,\n options,\n }: ExtensionOptions<\n Pick<BlockNoteEditorOptions<any, any, any>, \"dropCursor\">\n >) => {\n return {\n key: \"dropCursor\",\n prosemirrorPlugins: [\n (options.dropCursor ?? dropCursor)({\n width: 5,\n color: \"#ddeeff\",\n editor: editor,\n }),\n ],\n } as const;\n },\n);\n","import { NodeSelection, TextSelection } from \"prosemirror-state\";\n\nimport {\n createExtension,\n createStore,\n} from \"../../editor/BlockNoteExtension.js\";\n\nexport const FormattingToolbarExtension = createExtension(({ editor }) => {\n const store = createStore(false);\n\n const shouldShow = () => {\n return editor.transact((tr) => {\n // Don't show if the selection is empty, or is a text selection with no\n // text.\n if (tr.selection.empty) {\n return false;\n }\n\n // Don't show if a block with inline content is selected.\n if (\n tr.selection instanceof NodeSelection &&\n (tr.selection.node.type.spec.content === \"inline*\" ||\n tr.selection.node.firstChild?.type.spec.content === \"inline*\")\n ) {\n return false;\n }\n\n // Don't show if the selection is a text selection but contains no text.\n if (\n tr.selection instanceof TextSelection &&\n tr.doc.textBetween(tr.selection.from, tr.selection.to).length === 0\n ) {\n return false;\n }\n\n // Searches the content of the selection to see if it spans a node with a\n // code spec.\n let spansCode = false;\n tr.selection.content().content.descendants((node) => {\n if (node.type.spec.code) {\n spansCode = true;\n }\n return !spansCode; // keep descending if we haven't found a code block\n });\n\n // Don't show if the selection spans a code block.\n if (spansCode) {\n return false;\n }\n\n // Show toolbar otherwise.\n return true;\n });\n };\n\n return {\n key: \"formattingToolbar\",\n store,\n mount({ dom, signal }) {\n /**\n * We want to mimic the Notion behavior of not showing the toolbar while the user is holding down the mouse button (to create a selection)\n */\n let preventShowWhileMouseDown = false;\n\n const unsubscribeOnChange = editor.onChange(() => {\n if (preventShowWhileMouseDown) {\n return;\n }\n // re-evaluate whether the toolbar should be shown\n store.setState(shouldShow());\n });\n const unsubscribeOnSelectionChange = editor.onSelectionChange(() => {\n if (preventShowWhileMouseDown) {\n return;\n }\n // re-evaluate whether the toolbar should be shown\n store.setState(shouldShow());\n });\n\n // To mimic Notion's behavior, we listen to the mouse down event to set the `preventShowWhileMouseDown` flag\n dom.addEventListener(\n \"pointerdown\",\n () => {\n preventShowWhileMouseDown = true;\n store.setState(false);\n },\n { signal },\n );\n // To mimic Notion's behavior, we listen to the mouse up event to reset the `preventShowWhileMouseDown` flag and show the toolbar (if it should)\n editor.prosemirrorView.root.addEventListener(\n \"pointerup\",\n () => {\n preventShowWhileMouseDown = false;\n // We only want to re-show the toolbar if the mouse made the selection\n if (editor.isFocused()) {\n store.setState(shouldShow());\n }\n },\n { signal, capture: true },\n );\n // If the pointer gets cancelled, we don't want to be stuck in the `preventShowWhileMouseDown` state\n dom.addEventListener(\n \"pointercancel\",\n () => {\n preventShowWhileMouseDown = false;\n },\n {\n signal,\n capture: true,\n },\n );\n\n signal.addEventListener(\"abort\", () => {\n unsubscribeOnChange();\n unsubscribeOnSelectionChange();\n });\n },\n } as const;\n});\n","import { history, redo, undo } from \"@tiptap/pm/history\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport const HistoryExtension = createExtension(() => {\n return {\n key: \"history\",\n prosemirrorPlugins: [history()],\n undoCommand: undo,\n redoCommand: redo,\n } as const;\n});\n","import { getMarkRange, posToDOMRect } from \"@tiptap/core\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\nimport { getPmSchema } from \"../../api/pmUtil.js\";\n\nexport const LinkToolbarExtension = createExtension(({ editor }) => {\n function getLinkElementAtPos(pos: number) {\n let currentNode = editor.prosemirrorView.nodeDOM(pos);\n while (currentNode && currentNode.parentElement) {\n if (currentNode.nodeName === \"A\") {\n return currentNode as HTMLAnchorElement;\n }\n currentNode = currentNode.parentElement;\n }\n return null;\n }\n\n function getMarkAtPos(pos: number, markType: string) {\n return editor.transact((tr) => {\n const resolvedPos = tr.doc.resolve(pos);\n const mark = resolvedPos\n .marks()\n .find((mark) => mark.type.name === markType);\n\n if (!mark) {\n return;\n }\n\n const markRange = getMarkRange(resolvedPos, mark.type);\n if (!markRange) {\n return;\n }\n\n return {\n range: markRange,\n mark,\n get text() {\n return tr.doc.textBetween(markRange.from, markRange.to);\n },\n get position() {\n // to minimize re-renders, we convert to JSON, which is the same shape anyway\n return posToDOMRect(\n editor.prosemirrorView,\n markRange.from,\n markRange.to,\n ).toJSON() as DOMRect;\n },\n };\n });\n }\n\n function getLinkAtSelection() {\n return editor.transact((tr) => {\n const selection = tr.selection;\n if (!selection.empty) {\n return undefined;\n }\n return getMarkAtPos(selection.anchor, \"link\");\n });\n }\n\n return {\n key: \"linkToolbar\",\n\n getLinkAtSelection,\n getLinkElementAtPos,\n getMarkAtPos,\n\n getLinkAtElement(element: HTMLElement) {\n return editor.transact(() => {\n const posAtElement = editor.prosemirrorView.posAtDOM(element, 0) + 1;\n return getMarkAtPos(posAtElement, \"link\");\n });\n },\n\n editLink(\n url: string,\n text: string,\n position = editor.transact((tr) => tr.selection.anchor),\n ) {\n editor.transact((tr) => {\n const pmSchema = getPmSchema(tr);\n const { range } = getMarkAtPos(position + 1, \"link\") || {\n range: {\n from: tr.selection.from,\n to: tr.selection.to,\n },\n };\n if (!range) {\n return;\n }\n tr.insertText(text, range.from, range.to);\n tr.addMark(\n range.from,\n range.from + text.length,\n pmSchema.mark(\"link\", { href: url }),\n );\n });\n editor.prosemirrorView.focus();\n },\n deleteLink(position = editor.transact((tr) => tr.selection.anchor)) {\n editor.transact((tr) => {\n const pmSchema = getPmSchema(tr);\n const { range } = getMarkAtPos(position + 1, \"link\") || {\n range: {\n from: tr.selection.from,\n to: tr.selection.to,\n },\n };\n if (!range) {\n return;\n }\n\n tr.removeMark(range.from, range.to, pmSchema.marks[\"link\"]).setMeta(\n \"preventAutolink\",\n true,\n );\n });\n editor.prosemirrorView.focus();\n },\n } as const;\n});\n","export const VALID_LINK_PROTOCOLS = [\n \"http\",\n \"https\",\n \"ftp\",\n \"ftps\",\n \"mailto\",\n \"tel\",\n \"callto\",\n \"sms\",\n \"cid\",\n \"xmpp\",\n];\nexport const DEFAULT_LINK_PROTOCOL = \"https\";\n","import { Plugin, PluginKey, TextSelection } from \"prosemirror-state\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(\"node-selection-keyboard\");\n// By default, typing with a node selection active will cause ProseMirror to\n// replace the node with one that contains editable content. This plugin blocks\n// this behaviour without also blocking things like keyboard shortcuts:\n//\n// - Lets through key presses that do not include alphanumeric characters. This\n// includes things like backspace/delete/home/end/etc.\n// - Lets through any key presses that include ctrl/meta keys. These will be\n// shortcuts of some kind like ctrl+C/mod+C.\n// - Special case for Enter key which creates a new paragraph block below and\n// sets the selection to it. This is just to bring the UX closer to Notion\n//\n// While a more elegant solution would probably process transactions instead of\n// keystrokes, this brings us most of the way to Notion's UX without much added\n// complexity.\nexport const NodeSelectionKeyboardExtension = createExtension(\n () =>\n ({\n key: \"nodeSelectionKeyboard\",\n prosemirrorPlugins: [\n new Plugin({\n key: PLUGIN_KEY,\n props: {\n handleKeyDown: (view, event) => {\n // Checks for node selection\n if (\"node\" in view.state.selection) {\n // Checks if key press uses ctrl/meta modifier\n if (event.ctrlKey || event.metaKey) {\n return false;\n }\n // Checks if key press is alphanumeric\n if (event.key.length === 1) {\n event.preventDefault();\n\n return true;\n }\n // Checks if key press is Enter\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey\n ) {\n const tr = view.state.tr;\n view.dispatch(\n tr\n .insert(\n view.state.tr.selection.$to.after(),\n view.state.schema.nodes[\"paragraph\"].createChecked(),\n )\n .setSelection(\n new TextSelection(\n tr.doc.resolve(\n view.state.tr.selection.$to.after() + 1,\n ),\n ),\n ),\n );\n\n return true;\n }\n }\n\n return false;\n },\n },\n }),\n ],\n }) as const,\n);\n","import { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { v4 } from \"uuid\";\nimport {\n createExtension,\n ExtensionOptions,\n} from \"../../editor/BlockNoteExtension.js\";\nimport { BlockNoteEditorOptions } from \"../../editor/BlockNoteEditor.js\";\n\nconst PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);\n\nexport const PlaceholderExtension = createExtension(\n ({\n editor,\n options,\n }: ExtensionOptions<\n Pick<BlockNoteEditorOptions<any, any, any>, \"placeholders\">\n >) => {\n const placeholders = options.placeholders;\n return {\n key: \"placeholder\",\n prosemirrorPlugins: [\n new Plugin({\n key: PLUGIN_KEY,\n view: (view) => {\n const uniqueEditorSelector = `placeholder-selector-${v4()}`;\n view.dom.classList.add(uniqueEditorSelector);\n const styleEl = document.createElement(\"style\");\n\n const nonce = editor._tiptapEditor.options.injectNonce;\n if (nonce) {\n styleEl.setAttribute(\"nonce\", nonce);\n }\n\n if (view.root instanceof window.ShadowRoot) {\n view.root.append(styleEl);\n } else {\n view.root.head.appendChild(styleEl);\n }\n\n const styleSheet = styleEl.sheet!;\n\n const getSelector = (additionalSelectors = \"\") =>\n `.${uniqueEditorSelector} .bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before`;\n\n try {\n // FIXME: the names \"default\" and \"emptyDocument\" are hardcoded\n const {\n default: defaultPlaceholder,\n emptyDocument: emptyPlaceholder,\n ...rest\n } = placeholders || {};\n\n // add block specific placeholders\n for (const [blockType, placeholder] of Object.entries(rest)) {\n const blockTypeSelector = `[data-content-type=\"${blockType}\"]`;\n\n styleSheet.insertRule(\n `${getSelector(blockTypeSelector)} { content: ${JSON.stringify(\n placeholder,\n )}; }`,\n );\n }\n\n const onlyBlockSelector = `[data-is-only-empty-block]`;\n const mustBeFocusedSelector = `[data-is-empty-and-focused]`;\n\n // placeholder for when there's only one empty block\n styleSheet.insertRule(\n `${getSelector(onlyBlockSelector)} { content: ${JSON.stringify(\n emptyPlaceholder,\n )}; }`,\n );\n\n // placeholder for default blocks, only when the cursor is in the block (mustBeFocused)\n styleSheet.insertRule(\n `${getSelector(mustBeFocusedSelector)} { content: ${JSON.stringify(\n defaultPlaceholder,\n )}; }`,\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n `Failed to insert placeholder CSS rule - this is likely due to the browser not supporting certain CSS pseudo-element selectors (:has, :only-child:, or :before)`,\n e,\n );\n }\n\n return {\n destroy: () => {\n if (view.root instanceof window.ShadowRoot) {\n view.root.removeChild(styleEl);\n } else {\n view.root.head.removeChild(styleEl);\n }\n },\n };\n },\n props: {\n decorations: (state) => {\n const { doc, selection } = state;\n\n if (!editor.isEditable) {\n return;\n }\n\n if (!selection.empty) {\n return;\n }\n\n // Don't show placeholder when the cursor is inside a code block\n if (selection.$from.parent.type.spec.code) {\n return;\n }\n\n const decs = [];\n\n // decoration for when there's only one empty block\n // positions are hardcoded for now\n if (state.doc.content.size === 6) {\n decs.push(\n Decoration.node(2, 4, {\n \"data-is-only-empty-block\": \"true\",\n }),\n );\n }\n\n const $pos = selection.$anchor;\n const node = $pos.parent;\n\n if (node.content.size === 0) {\n const before = $pos.before();\n\n decs.push(\n Decoration.node(before, before + node.nodeSize, {\n \"data-is-empty-and-focused\": \"true\",\n }),\n );\n }\n\n return DecorationSet.create(doc, decs);\n },\n },\n }),\n ],\n } as const;\n },\n);\n","import { findChildren } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey(`previous-blocks`);\n\nconst nodeAttributes: Record<string, string> = {\n // Numbered List Items\n index: \"index\",\n // Headings\n level: \"level\",\n // All Blocks\n type: \"type\",\n depth: \"depth\",\n \"depth-change\": \"depth-change\",\n};\n\n/**\n * This plugin tracks transformation of Block node attributes, so we can support CSS transitions.\n *\n * Problem it solves: ProseMirror recreates the DOM when transactions happen. So when a transaction changes a Node attribute,\n * it results in a completely new DOM element. This means CSS transitions don't work.\n *\n * Solution: When attributes change on a node, this plugin sets a data-* attribute with the \"previous\" value. This way we can still use CSS transitions. (See block.module.css)\n */\nexport const PreviousBlockTypeExtension = createExtension(() => {\n let timeout: ReturnType<typeof setTimeout>;\n return {\n key: \"previousBlockType\",\n prosemirrorPlugins: [\n new Plugin({\n key: PLUGIN_KEY,\n view(_editorView) {\n return {\n update: async (view, _prevState) => {\n if (this.key?.getState(view.state).updatedBlocks.size > 0) {\n // use setTimeout 0 to clear the decorations so that at least\n // for one DOM-render the decorations have been applied\n timeout = setTimeout(() => {\n view.dispatch(\n view.state.tr.setMeta(PLUGIN_KEY, { clearUpdate: true }),\n );\n }, 0);\n }\n },\n destroy: () => {\n if (timeout) {\n clearTimeout(timeout);\n }\n },\n };\n },\n state: {\n init() {\n return {\n // Block attributes, by block ID, from just before the previous transaction.\n prevTransactionOldBlockAttrs: {} as any,\n // Block attributes, by block ID, from just before the current transaction.\n currentTransactionOldBlockAttrs: {} as any,\n // Set of IDs of blocks whose attributes changed from the current transaction.\n updatedBlocks: new Set<string>(),\n };\n },\n\n apply(transaction, prev, oldState, newState) {\n prev.currentTransactionOldBlockAttrs = {};\n prev.updatedBlocks.clear();\n\n if (!transaction.docChanged || oldState.doc.eq(newState.doc)) {\n return prev;\n }\n\n // TODO: Instead of iterating through the entire document, only check nodes affected by the transactions. Will\n // also probably require checking nodes affected by the previous transaction too.\n // We didn't get this to work yet:\n // const transform = combineTransactionSteps(oldState.doc, [transaction]);\n // // const { mapping } = transform;\n // const changes = getChangedRanges(transform);\n //\n // changes.forEach(({ oldRange, newRange }) => {\n // const oldNodes = findChildrenInRange(\n // oldState.doc,\n // oldRange,\n // (node) => node.attrs.id\n // );\n //\n // const newNodes = findChildrenInRange(\n // newState.doc,\n // newRange,\n // (node) => node.attrs.id\n // );\n\n const currentTransactionOriginalOldBlockAttrs = {} as any;\n\n const oldNodes = findChildren(\n oldState.doc,\n (node) => node.attrs.id,\n );\n const oldNodesById = new Map(\n oldNodes.map((node) => [node.node.attrs.id, node]),\n );\n const newNodes = findChildren(\n newState.doc,\n (node) => node.attrs.id,\n );\n\n // Traverses all block containers in the new editor state.\n for (const node of newNodes) {\n const oldNode = oldNodesById.get(node.node.attrs.id);\n\n const oldContentNode = oldNode?.node.firstChild;\n const newContentNode = node.node.firstChild;\n\n if (oldNode && oldContentNode && newContentNode) {\n const newAttrs = {\n index: newContentNode.attrs.index,\n level: newContentNode.attrs.level,\n type: newContentNode.type.name,\n depth: newState.doc.resolve(node.pos).depth,\n };\n\n const oldAttrs = {\n index: oldContentNode.attrs.index,\n level: oldContentNode.attrs.level,\n type: oldContentNode.type.name,\n depth: oldState.doc.resolve(oldNode.pos).depth,\n };\n\n currentTransactionOriginalOldBlockAttrs[node.node.attrs.id] =\n oldAttrs;\n\n prev.currentTransactionOldBlockAttrs[node.node.attrs.id] =\n oldAttrs;\n\n // TODO: faster deep equal?\n if (JSON.stringify(oldAttrs) !== JSON.stringify(newAttrs)) {\n (oldAttrs as any)[\"depth-change\"] =\n oldAttrs.depth - newAttrs.depth;\n\n // for debugging:\n // console.log(\n // \"id:\",\n // node.node.attrs.id,\n // \"previousBlockTypePlugin changes detected, oldAttrs\",\n // oldAttrs,\n // \"new\",\n // newAttrs\n // );\n\n prev.updatedBlocks.add(node.node.attrs.id);\n }\n }\n }\n\n prev.prevTransactionOldBlockAttrs =\n currentTransactionOriginalOldBlockAttrs;\n\n return prev;\n },\n },\n props: {\n decorations(state) {\n const pluginState = (this as Plugin).getState(state);\n if (pluginState.updatedBlocks.size === 0) {\n return undefined;\n }\n\n const decorations: Decoration[] = [];\n\n state.doc.descendants((node, pos) => {\n if (!node.attrs.id) {\n return;\n }\n\n if (!pluginState.updatedBlocks.has(node.attrs.id)) {\n return;\n }\n\n const prevAttrs =\n pluginState.currentTransactionOldBlockAttrs[node.attrs.id];\n const decorationAttrs: any = {};\n\n for (const [nodeAttr, val] of Object.entries(prevAttrs)) {\n decorationAttrs[\"data-prev-\" + nodeAttributes[nodeAttr]] =\n val || \"none\";\n }\n\n // for debugging:\n // console.log(\n // \"previousBlockTypePlugin committing decorations\",\n // decorationAttrs\n // );\n\n const decoration = Decoration.node(pos, pos + node.nodeSize, {\n ...decorationAttrs,\n });\n\n decorations.push(decoration);\n });\n\n return DecorationSet.create(state.doc, decorations);\n },\n },\n }),\n ],\n } as const;\n});\n","import { EditorView } from \"prosemirror-view\";\n\nexport function getDraggableBlockFromElement(\n element: Element,\n view: EditorView,\n) {\n while (\n element &&\n element.parentElement &&\n element.parentElement !== view.dom &&\n element.getAttribute?.(\"data-node-type\") !== \"blockContainer\"\n ) {\n element = element.parentElement;\n }\n if (element.getAttribute?.(\"data-node-type\") !== \"blockContainer\") {\n return undefined;\n }\n return { node: element as HTMLElement, id: element.getAttribute(\"data-id\")! };\n}\n","import { Element as HASTElement, Parent as HASTParent } from \"hast\";\n\n/**\n * Rehype plugin which removes <u> tags. Used to remove underlines before converting HTML to markdown, as Markdown\n * doesn't support underlines.\n */\nexport function removeUnderlines() {\n const removeUnderlinesHelper = (tree: HASTParent) => {\n let numChildElements = tree.children.length;\n\n for (let i = 0; i < numChildElements; i++) {\n const node = tree.children[i];\n\n if (node.type === \"element\") {\n // Recursively removes underlines from child elements.\n removeUnderlinesHelper(node);\n\n if ((node as HASTElement).tagName === \"u\") {\n // Lifts child nodes outside underline element, deletes the underline element, and updates current index &\n // the number of child elements.\n if (node.children.length > 0) {\n tree.children.splice(i, 1, ...node.children);\n\n const numElementsAdded = node.children.length - 1;\n numChildElements += numElementsAdded;\n i += numElementsAdded;\n } else {\n tree.children.splice(i, 1);\n\n numChildElements--;\n i--;\n }\n }\n }\n }\n };\n\n return removeUnderlinesHelper;\n}\n","import { Element as HASTElement, Parent as HASTParent } from \"hast\";\nimport { fromDom } from \"hast-util-from-dom\";\n\n/**\n * Rehype plugin which adds a space after each checkbox input element. This is\n * because remark doesn't add any spaces between the checkbox input and the text\n * itself, but these are needed for correct Markdown syntax.\n */\nexport function addSpacesToCheckboxes() {\n const helper = (tree: HASTParent) => {\n if (tree.children && \"length\" in tree.children && tree.children.length) {\n for (let i = tree.children.length - 1; i >= 0; i--) {\n const child = tree.children[i];\n const nextChild =\n i + 1 < tree.children.length ? tree.children[i + 1] : undefined;\n\n // Checks for paragraph element after checkbox input element.\n if (\n child.type === \"element\" &&\n child.tagName === \"input\" &&\n child.properties?.type === \"checkbox\" &&\n nextChild?.type === \"element\" &&\n nextChild.tagName === \"p\"\n ) {\n // Converts paragraph to span, otherwise remark will think it needs to\n // be on a new line.\n nextChild.tagName = \"span\";\n // Adds a space after the checkbox input element.\n nextChild.children.splice(\n 0,\n 0,\n fromDom(document.createTextNode(\" \")) as HASTElement,\n );\n } else {\n helper(child as HASTParent);\n }\n }\n }\n };\n\n return helper;\n}\n","import { Parent as HASTParent } from \"hast\";\nimport { visit } from \"unist-util-visit\";\n\n// Originally, rehypeParse parses videos as links, which is incorrect.\nexport function convertVideoToMarkdown() {\n return (tree: HASTParent) => {\n visit(tree, \"element\", (node, index, parent) => {\n if (parent && node.tagName === \"video\") {\n const src = node.properties?.src || node.properties?.[\"data-url\"] || \"\";\n const name =\n node.properties?.title || node.properties?.[\"data-name\"] || \"\";\n parent.children[index!] = {\n type: \"text\",\n value: `![${name}](${src})`,\n };\n }\n });\n };\n}\n","import { Schema } from \"prosemirror-model\";\nimport rehypeParse from \"rehype-parse\";\nimport rehypeRemark from \"rehype-remark\";\nimport remarkGfm from \"remark-gfm\";\nimport remarkStringify from \"remark-stringify\";\nimport { unified } from \"unified\";\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 { createExternalHTMLExporter } from \"../html/externalHTMLExporter.js\";\nimport { removeUnderlines } from \"./util/removeUnderlinesRehypePlugin.js\";\nimport { addSpacesToCheckboxes } from \"./util/addSpacesToCheckboxesRehypePlugin.js\";\nimport { convertVideoToMarkdown } from \"./util/convertVideoToMarkdownRehypePlugin.js\";\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport function cleanHTMLToMarkdown(cleanHTMLString: string) {\n const markdownString = unified()\n .use(rehypeParse, { fragment: true })\n .use(convertVideoToMarkdown)\n .use(removeUnderlines)\n .use(addSpacesToCheckboxes)\n .use(rehypeRemark)\n .use(remarkGfm)\n .use(remarkStringify, {\n handlers: { text: (node) => node.value },\n })\n .processSync(cleanHTMLString);\n\n return markdownString.value as string;\n}\n\nexport function blocksToMarkdown<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n blocks: PartialBlock<BSchema, I, S>[],\n schema: Schema,\n editor: BlockNoteEditor<BSchema, I, S>,\n options: { document?: Document },\n): string {\n const exporter = createExternalHTMLExporter(schema, editor);\n const externalHTML = exporter.exportBlocks(blocks, options);\n\n return cleanHTMLToMarkdown(externalHTML);\n}\n","import { Fragment } from \"@tiptap/pm/model\";\nimport {\n BlockNoDefaults,\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getPmSchema } from \"../pmUtil.js\";\nimport { nodeToBlock } from \"./nodeToBlock.js\";\n\n/**\n * Converts all Blocks within a fragment to BlockNote blocks.\n */\nexport function fragmentToBlocks<\n B extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(fragment: Fragment) {\n // first convert selection to blocknote-style blocks, and then\n // pass these to the exporter\n const blocks: BlockNoDefaults<B, I, S>[] = [];\n fragment.descendants((node) => {\n const pmSchema = getPmSchema(node);\n if (node.type.name === \"blockContainer\") {\n if (node.firstChild?.type.name === \"blockGroup\") {\n // selection started within a block group\n // in this case the fragment starts with:\n // <blockContainer>\n // <blockGroup>\n // <blockContainer ... />\n // <blockContainer ... />\n // </blockGroup>\n // </blockContainer>\n //\n // instead of:\n // <blockContainer>\n // <blockContent ... />\n // <blockGroup>\n // <blockContainer ... />\n // <blockContainer ... />\n // </blockGroup>\n // </blockContainer>\n //\n // so we don't need to serialize this block, just descend into the children of the blockGroup\n return true;\n }\n }\n\n if (node.type.name === \"columnList\" && node.childCount === 1) {\n // column lists with a single column should be flattened (not the entire column list has been selected)\n node.firstChild?.forEach((child) => {\n blocks.push(nodeToBlock(child, pmSchema));\n });\n return false;\n }\n\n if (node.type.isInGroup(\"bnBlock\")) {\n blocks.push(nodeToBlock(node, pmSchema));\n // don't descend into children, as they're already included in the block returned by nodeToBlock\n return false;\n }\n return true;\n });\n return blocks;\n}\n","import { Fragment, Node, ResolvedPos, Slice } from \"prosemirror-model\";\nimport { Selection } from \"prosemirror-state\";\nimport { Mappable } from \"prosemirror-transform\";\n\n/**\n * This class represents an editor selection which spans multiple nodes/blocks. It's currently only used to allow users\n * to drag multiple blocks at the same time. Expects the selection anchor and head to be between nodes, i.e. just before\n * the first target node and just after the last, and that anchor and head are at the same nesting level.\n *\n * Partially based on ProseMirror's NodeSelection implementation:\n * (https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.ts)\n * MultipleNodeSelection differs from NodeSelection in the following ways:\n * 1. Stores which nodes are included in the selection instead of just a single node.\n * 2. Already expects the selection to start just before the first target node and ends just after the last, while a\n * NodeSelection automatically sets both anchor and head to just before the single target node.\n */\nexport class MultipleNodeSelection extends Selection {\n nodes: Array<Node>;\n\n constructor($anchor: ResolvedPos, $head: ResolvedPos) {\n super($anchor, $head);\n\n // Parent is at the same nesting level as anchor/head since they are just before/ just after target nodes.\n const parentNode = $anchor.node();\n\n this.nodes = [];\n $anchor.doc.nodesBetween($anchor.pos, $head.pos, (node, _pos, parent) => {\n if (parent !== null && parent.eq(parentNode)) {\n this.nodes.push(node);\n return false;\n }\n return;\n });\n }\n\n static create(doc: Node, from: number, to = from): MultipleNodeSelection {\n return new MultipleNodeSelection(doc.resolve(from), doc.resolve(to));\n }\n\n content(): Slice {\n return new Slice(Fragment.from(this.nodes), 0, 0);\n }\n\n eq(selection: Selection): boolean {\n if (!(selection instanceof MultipleNodeSelection)) {\n return false;\n }\n\n if (this.nodes.length !== selection.nodes.length) {\n return false;\n }\n\n if (this.from !== selection.from || this.to !== selection.to) {\n return false;\n }\n\n for (let i = 0; i < this.nodes.length; i++) {\n if (!this.nodes[i].eq(selection.nodes[i])) {\n return false;\n }\n }\n\n return true;\n }\n\n map(doc: Node, mapping: Mappable): Selection {\n const fromResult = mapping.mapResult(this.from);\n const toResult = mapping.mapResult(this.to);\n\n if (toResult.deleted) {\n return Selection.near(doc.resolve(fromResult.pos));\n }\n\n if (fromResult.deleted) {\n return Selection.near(doc.resolve(toResult.pos));\n }\n\n return new MultipleNodeSelection(\n doc.resolve(fromResult.pos),\n doc.resolve(toResult.pos),\n );\n }\n\n toJSON(): any {\n return { type: \"multiple-node\", anchor: this.anchor, head: this.head };\n }\n}\n\nSelection.jsonID(\"multiple-node\", MultipleNodeSelection);\n","import { Node } from \"prosemirror-model\";\nimport { NodeSelection, Selection } from \"prosemirror-state\";\nimport { EditorView } from \"prosemirror-view\";\n\nimport { createExternalHTMLExporter } from \"../../api/exporters/html/externalHTMLExporter.js\";\nimport { cleanHTMLToMarkdown } from \"../../api/exporters/markdown/markdownExporter.js\";\nimport { fragmentToBlocks } from \"../../api/nodeConversions/fragmentToBlocks.js\";\nimport { getNodeById } from \"../../api/nodeUtil.js\";\nimport { Block } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { MultipleNodeSelection } from \"./MultipleNodeSelection.js\";\n\nlet dragImageElement: Element | undefined;\n\nexport type SideMenuState<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // The block that the side menu is attached to.\n block: Block<BSchema, I, S>;\n};\n\nfunction blockPositionsFromSelection(selection: Selection, doc: Node) {\n // Absolute positions just before the first block spanned by the selection, and just after the last block. Having the\n // selection start and end just before and just after the target blocks ensures no whitespace/line breaks are left\n // behind after dragging & dropping them.\n let beforeFirstBlockPos: number;\n let afterLastBlockPos: number;\n\n // Even the user starts dragging blocks but drops them in the same place, the selection will still be moved just\n // before & just after the blocks spanned by the selection, and therefore doesn't need to change if they try to drag\n // the same blocks again. If this happens, the anchor & head move out of the block content node they were originally\n // in. If the anchor should update but the head shouldn't and vice versa, it means the user selection is outside a\n // block content node, which should never happen.\n const selectionStartInBlockContent =\n doc.resolve(selection.from).node().type.spec.group === \"blockContent\";\n const selectionEndInBlockContent =\n doc.resolve(selection.to).node().type.spec.group === \"blockContent\";\n\n // Ensures that entire outermost nodes are selected if the selection spans multiple nesting levels.\n const minDepth = Math.min(selection.$anchor.depth, selection.$head.depth);\n\n if (selectionStartInBlockContent && selectionEndInBlockContent) {\n // Absolute positions at the start of the first block in the selection and at the end of the last block. User\n // selections will always start and end in block content nodes, but we want the start and end positions of their\n // parent block nodes, which is why minDepth - 1 is used.\n const startFirstBlockPos = selection.$from.start(minDepth - 1);\n const endLastBlockPos = selection.$to.end(minDepth - 1);\n\n // Shifting start and end positions by one moves them just outside the first and last selected blocks.\n beforeFirstBlockPos = doc.resolve(startFirstBlockPos - 1).pos;\n afterLastBlockPos = doc.resolve(endLastBlockPos + 1).pos;\n } else {\n beforeFirstBlockPos = selection.from;\n afterLastBlockPos = selection.to;\n }\n\n return { from: beforeFirstBlockPos, to: afterLastBlockPos };\n}\n\nfunction setDragImage(view: EditorView, from: number, to = from) {\n if (from === to) {\n // Moves to position to be just after the first (and only) selected block.\n to += view.state.doc.resolve(from + 1).node().nodeSize;\n }\n\n // Parent element is cloned to remove all unselected children without affecting the editor content.\n const parentClone = view.domAtPos(from).node.cloneNode(true) as Element;\n const parent = view.domAtPos(from).node as Element;\n\n const getElementIndex = (parentElement: Element, targetElement: Element) =>\n Array.prototype.indexOf.call(parentElement.children, targetElement);\n\n const firstSelectedBlockIndex = getElementIndex(\n parent,\n // Expects from position to be just before the first selected block.\n view.domAtPos(from + 1).node.parentElement!,\n );\n const lastSelectedBlockIndex = getElementIndex(\n parent,\n // Expects to position to be just after the last selected block.\n view.domAtPos(to - 1).node.parentElement!,\n );\n\n for (let i = parent.childElementCount - 1; i >= 0; i--) {\n if (i > lastSelectedBlockIndex || i < firstSelectedBlockIndex) {\n parentClone.removeChild(parentClone.children[i]);\n }\n }\n\n // dataTransfer.setDragImage(element) only works if element is attached to the DOM.\n unsetDragImage(view.root);\n dragImageElement = parentClone;\n\n // Browsers may have CORS policies which prevents iframes from being\n // manipulated, so better to stay on the safe side and remove them from the\n // drag preview. The drag preview doesn't work with iframes anyway.\n const iframes = dragImageElement.getElementsByTagName(\"iframe\");\n for (let i = 0; i < iframes.length; i++) {\n const iframe = iframes[i];\n const parent = iframe.parentElement;\n\n if (parent) {\n parent.removeChild(iframe);\n }\n }\n\n // TODO: This is hacky, need a better way of assigning classes to the editor so that they can also be applied to the\n // drag preview.\n const classes = view.dom.className.split(\" \");\n const inheritedClasses = classes\n .filter(\n (className) =>\n className !== \"ProseMirror\" &&\n className !== \"bn-root\" &&\n className !== \"bn-editor\",\n )\n .join(\" \");\n\n dragImageElement.className =\n dragImageElement.className + \" bn-drag-preview \" + inheritedClasses;\n\n if (view.root instanceof ShadowRoot) {\n view.root.appendChild(dragImageElement);\n } else {\n view.root.body.appendChild(dragImageElement);\n }\n}\n\nexport function unsetDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement !== undefined) {\n if (rootEl instanceof ShadowRoot) {\n rootEl.removeChild(dragImageElement);\n } else {\n rootEl.body.removeChild(dragImageElement);\n }\n\n dragImageElement = undefined;\n }\n}\n\nexport function dragStart<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n>(\n e: { dataTransfer: DataTransfer | null; clientY: number },\n block: Block<BSchema, I, S>,\n editor: BlockNoteEditor<BSchema, I, S>,\n) {\n if (!e.dataTransfer) {\n return;\n }\n\n if (editor.headless) {\n return;\n }\n const view = editor.prosemirrorView;\n\n const posInfo = getNodeById(block.id, view.state.doc);\n if (!posInfo) {\n throw new Error(`Block with ID ${block.id} not found`);\n }\n const pos = posInfo.posBeforeNode;\n\n if (pos != null) {\n const selection = view.state.selection;\n const doc = view.state.doc;\n\n const { from, to } = blockPositionsFromSelection(selection, doc);\n\n const draggedBlockInSelection = from <= pos && pos < to;\n const multipleBlocksSelected =\n selection.$anchor.node() !== selection.$head.node() ||\n selection instanceof MultipleNodeSelection;\n\n if (draggedBlockInSelection && multipleBlocksSelected) {\n view.dispatch(\n view.state.tr.setSelection(MultipleNodeSelection.create(doc, from, to)),\n );\n setDragImage(view, from, to);\n } else {\n view.dispatch(\n view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)),\n );\n setDragImage(view, pos);\n }\n\n const selectedSlice = view.state.selection.content();\n const schema = editor.pmSchema;\n\n const clipboardHTML =\n view.serializeForClipboard(selectedSlice).dom.innerHTML;\n\n const externalHTMLExporter = createExternalHTMLExporter(schema, editor);\n\n const blocks = fragmentToBlocks(selectedSlice.content);\n const externalHTML = externalHTMLExporter.exportBlocks(blocks, {});\n\n const plainText = cleanHTMLToMarkdown(externalHTML);\n\n e.dataTransfer.clearData();\n e.dataTransfer.setData(\"blocknote/html\", clipboardHTML);\n e.dataTransfer.setData(\"text/html\", externalHTML);\n e.dataTransfer.setData(\"text/plain\", plainText);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setDragImage(dragImageElement!, 0, 0);\n }\n}\n","import { DOMParser, Slice } from \"@tiptap/pm/model\";\nimport {\n EditorState,\n Plugin,\n PluginKey,\n PluginView,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport { EditorView } from \"@tiptap/pm/view\";\n\nimport { Block } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport {\n createExtension,\n createStore,\n} from \"../../editor/BlockNoteExtension.js\";\nimport { UiElementPosition } from \"../../extensions-shared/UiElementPosition.js\";\nimport {\n BlockSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"../../schema/index.js\";\nimport { getDraggableBlockFromElement } from \"../getDraggableBlockFromElement.js\";\nimport { dragStart, unsetDragImage } from \"./dragging.js\";\n\nexport type SideMenuState<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> = UiElementPosition & {\n // The block that the side menu is attached to.\n block: Block<BSchema, I, S>;\n};\n\nconst DISTANCE_TO_CONSIDER_EDITOR_BOUNDS = 250;\n\nfunction getBlockFromCoords(\n view: EditorView,\n coords: { left: number; top: number },\n adjustForColumns = true,\n) {\n const elements = view.root.elementsFromPoint(coords.left, coords.top);\n\n for (const element of elements) {\n if (!view.dom.contains(element)) {\n // probably a ui overlay like formatting toolbar etc\n continue;\n }\n if (adjustForColumns) {\n const column = element.closest(\"[data-node-type=columnList]\");\n if (column) {\n return getBlockFromCoords(\n view,\n {\n // TODO can we do better than this?\n left: coords.left + 50, // bit hacky, but if we're inside a column, offset x position to right to account for the width of sidemenu itself\n top: coords.top,\n },\n false,\n );\n }\n }\n return getDraggableBlockFromElement(element, view);\n }\n return undefined;\n}\n\nfunction getBlockFromMousePos(\n mousePos: {\n x: number;\n y: number;\n },\n view: EditorView,\n): { node: HTMLElement; id: string } | undefined {\n // Editor itself may have padding or other styling which affects\n // size/position, so we get the boundingRect of the first child (i.e. the\n // blockGroup that wraps all blocks in the editor) for more accurate side\n // menu placement.\n if (!view.dom.firstChild) {\n return;\n }\n\n const editorBoundingBox = (\n view.dom.firstChild as HTMLElement\n ).getBoundingClientRect();\n\n // Gets block at mouse cursor's position.\n const coords = {\n // Clamps the x position to the editor's bounding box.\n left: Math.min(\n Math.max(editorBoundingBox.left + 10, mousePos.x),\n editorBoundingBox.right - 10,\n ),\n top: mousePos.y,\n };\n\n const referenceBlock = getBlockFromCoords(view, coords);\n\n if (!referenceBlock) {\n // could not find the reference block\n return undefined;\n }\n\n /**\n * Because blocks may be nested, we need to check the right edge of the parent block:\n * ```\n * | BlockA |\n * x | BlockB y|\n * ```\n * Hovering at position x (left edge of BlockB) would return BlockA.\n * Instead, we check at position y (right edge of BlockA) to correctly identify BlockB.\n */\n const referenceBlocksBoundingBox =\n referenceBlock.node.getBoundingClientRect();\n return getBlockFromCoords(\n view,\n {\n left: referenceBlocksBoundingBox.right - 10,\n top: mousePos.y,\n },\n false,\n );\n}\n\n/**\n * With the sidemenu plugin we can position a menu next to a hovered block.\n */\nexport class SideMenuView<\n BSchema extends BlockSchema,\n I extends InlineContentSchema,\n S extends StyleSchema,\n> implements PluginView\n{\n public state?: SideMenuState<BSchema, I, S>;\n public readonly emitUpdate: (state: SideMenuState<BSchema, I, S>) => void;\n\n private mousePos: { x: number; y: number } | undefined;\n\n private hoveredBlock: HTMLElement | undefined;\n\n public menuFrozen = false;\n\n public isDragOrigin = false;\n\n constructor(\n private readonly editor: BlockNoteEditor<BSchema, I, S>,\n private readonly pmView: EditorView,\n emitUpdate: (state: SideMenuState<BSchema, I, S>) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized side menu\");\n }\n\n emitUpdate(this.state);\n };\n\n this.pmView.root.addEventListener(\n \"dragstart\",\n this.onDragStart as EventListener,\n );\n this.pmView.root.addEventListener(\n \"dragover\",\n this.onDragOver as EventListener,\n );\n this.pmView.root.addEventListener(\n \"drop\",\n this.onDrop as EventListener,\n true,\n );\n this.pmView.root.addEventListener(\n \"dragend\",\n this.onDragEnd as EventListener,\n true,\n );\n\n // Shows or updates menu position whenever the cursor moves, if the menu isn't frozen.\n this.pmView.root.addEventListener(\n \"mousemove\",\n this.onMouseMove as EventListener,\n true,\n );\n\n // Hides and unfreezes the menu whenever the user presses a key.\n this.pmView.root.addEventListener(\n \"keydown\",\n this.onKeyDown as EventListener,\n true,\n );\n }\n\n updateState = (state: SideMenuState<BSchema, I, S>) => {\n this.state = state;\n this.emitUpdate(this.state);\n };\n\n updateStateFromMousePos = () => {\n if (this.menuFrozen || !this.mousePos) {\n return;\n }\n\n const closestEditor = this.findClosestEditorElement({\n clientX: this.mousePos.x,\n clientY: this.mousePos.y,\n });\n\n if (\n closestEditor?.element !== this.pmView.dom ||\n closestEditor.distance > DISTANCE_TO_CONSIDER_EDITOR_BOUNDS\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.updateState(this.state);\n }\n return;\n }\n\n const block = getBlockFromMousePos(this.mousePos, this.pmView);\n\n // Closes the menu if the mouse cursor is beyond the editor vertically.\n if (!block || !this.editor.isEditable) {\n if (this.state?.show) {\n this.state.show = false;\n this.updateState(this.state);\n }\n\n return;\n }\n\n // Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.\n if (\n this.state?.show &&\n this.hoveredBlock?.hasAttribute(\"data-id\") &&\n this.hoveredBlock?.getAttribute(\"data-id\") === block.id\n ) {\n return;\n }\n\n this.hoveredBlock = block.node;\n\n // Shows or updates elements.\n if (this.editor.isEditable) {\n const blockContentBoundingBox = block.node.getBoundingClientRect();\n const column = block.node.closest(\"[data-node-type=column]\");\n this.state = {\n show: true,\n referencePos: new DOMRect(\n column\n ? // We take the first child as column elements have some default\n // padding. This is a little weird since this child element will\n // be the first block, but since it's always non-nested and we\n // only take the x coordinate, it's ok.\n column.firstElementChild!.getBoundingClientRect().x\n : (\n this.pmView.dom.firstChild as HTMLElement\n ).getBoundingClientRect().x,\n blockContentBoundingBox.y,\n blockContentBoundingBox.width,\n blockContentBoundingBox.height,\n ),\n block: this.editor.getBlock(\n this.hoveredBlock!.getAttribute(\"data-id\")!,\n )!,\n };\n this.updateState(this.state);\n }\n };\n\n /**\n * If a block is being dragged, ProseMirror usually gets the context of what's\n * being dragged from `view.dragging`, which is automatically set when a\n * `dragstart` event fires in the editor. However, if the user tries to drag\n * and drop blocks between multiple editors, only the one in which the drag\n * began has that context, so we need to set it on the others manually. This\n * ensures that PM always drops the blocks in between other blocks, and not\n * inside them.\n *\n * After the `dragstart` event fires on the drag handle, it sets\n * `blocknote/html` data on the clipboard. This handler fires right after,\n * parsing the `blocknote/html` data into nodes and setting them on\n * `view.dragging`.\n *\n * Note: Setting `view.dragging` on `dragover` would be better as the user\n * could then drag between editors in different windows, but you can only\n * access `dataTransfer` contents on `dragstart` and `drop` events.\n */\n onDragStart = (event: DragEvent) => {\n const html = event.dataTransfer?.getData(\"blocknote/html\");\n if (!html) {\n return;\n }\n\n if (this.pmView.dragging) {\n // already dragging, so no-op\n return;\n }\n\n const element = document.createElement(\"div\");\n element.innerHTML = html;\n\n const parser = DOMParser.fromSchema(this.pmView.state.schema);\n const node = parser.parse(element, {\n topNode: this.pmView.state.schema.nodes[\"blockGroup\"].create(),\n });\n\n this.pmView.dragging = {\n slice: new Slice(node.content, 0, 0),\n move: true,\n };\n };\n\n /**\n * Finds the closest editor visually to the given coordinates\n */\n private findClosestEditorElement = (coords: {\n clientX: number;\n clientY: number;\n }) => {\n // Get all editor elements in the document\n const editors = Array.from(this.pmView.root.querySelectorAll(\".bn-editor\"));\n\n if (editors.length === 0) {\n return null;\n }\n\n // Find the editor with the smallest distance to the coordinates\n let closestEditor = editors[0];\n let minDistance = Number.MAX_VALUE;\n\n editors.forEach((editor) => {\n const rect = editor\n .querySelector(\".bn-block-group\")!\n .getBoundingClientRect();\n\n const distanceX =\n coords.clientX < rect.left\n ? rect.left - coords.clientX\n : coords.clientX > rect.right\n ? coords.clientX - rect.right\n : 0;\n\n const distanceY =\n coords.clientY < rect.top\n ? rect.top - coords.clientY\n : coords.clientY > rect.bottom\n ? coords.clientY - rect.bottom\n : 0;\n\n const distance = Math.sqrt(\n Math.pow(distanceX, 2) + Math.pow(distanceY, 2),\n );\n\n if (distance < minDistance) {\n minDistance = distance;\n closestEditor = editor;\n }\n });\n\n return {\n element: closestEditor,\n distance: minDistance,\n };\n };\n\n /**\n * This dragover event handler listens at the document level,\n * and is trying to handle dragover events for all editors.\n *\n * It specifically is trying to handle the following cases:\n * - If the dragover event is within the bounds of any editor, then it does nothing\n * - If the dragover event is outside the bounds of any editor, but close enough (within DISTANCE_TO_CONSIDER_EDITOR_BOUNDS) to the closest editor,\n * then it dispatches a synthetic dragover event to the closest editor (which will trigger the drop-cursor to be shown on that editor)\n * - If the dragover event is outside the bounds of the current editor, then it will dispatch a synthetic dragleave event to the current editor\n * (which will trigger the drop-cursor to be removed from the current editor)\n *\n * The synthetic event is a necessary evil because we do not control prosemirror-dropcursor to be able to show the drop-cursor within the range we want\n */\n onDragOver = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n\n const dragEventContext = this.getDragEventContext(event);\n\n if (!dragEventContext || !dragEventContext.isDropPoint) {\n // This is not a drag event that we are interested in\n // so, we close the drop-cursor\n this.closeDropCursor();\n return;\n }\n\n if (\n dragEventContext.isDropPoint &&\n !dragEventContext.isDropWithinEditorBounds\n ) {\n // we are the drop point, but the drag over event is not within the bounds of this editor instance\n // so, we need to dispatch an event that is in the bounds of this editor instance\n this.dispatchSyntheticEvent(event);\n }\n };\n\n /**\n * Closes the drop-cursor for the current editor\n */\n private closeDropCursor = () => {\n const evt = new Event(\"dragleave\", { bubbles: false });\n // It needs to be synthetic, so we don't accidentally think it is a real dragend event\n (evt as any).synthetic = true;\n // We dispatch the event to the current editor, so that the drop-cursor is removed for it\n this.pmView.dom.dispatchEvent(evt);\n };\n\n /**\n * It is surprisingly difficult to determine the information we need to know about a drag event\n *\n * This function is trying to determine the following:\n * - Whether the current editor instance is the drop point\n * - Whether the current editor instance is the drag origin\n * - Whether the drop event is within the bounds of the current editor instance\n */\n getDragEventContext = (event: DragEvent) => {\n // We need to check if there is text content that is being dragged (select some text & just drag it)\n const textContentIsBeingDragged =\n !event.dataTransfer?.types.includes(\"blocknote/html\") &&\n !!this.pmView.dragging;\n // This is the side menu drag from this plugin\n const sideMenuIsBeingDragged = !!this.isDragOrigin;\n // Tells us that the current editor instance has a drag ongoing (either text or side menu)\n const isDragOrigin = textContentIsBeingDragged || sideMenuIsBeingDragged;\n\n // Tells us which editor instance is the closest to the drag event (whether or not it is actually reasonably close)\n const closestEditor = this.findClosestEditorElement(event);\n\n // We arbitrarily decide how far is \"too far\" from the closest editor to be considered a drop point\n if (\n !closestEditor ||\n closestEditor.distance > DISTANCE_TO_CONSIDER_EDITOR_BOUNDS\n ) {\n // we are too far from the closest editor, or no editor was found\n return undefined;\n }\n\n // We check if the closest editor is the same as the current editor instance (which is the drop point)\n const isDropPoint = closestEditor.element === this.pmView.dom;\n // We check if the current editor instance is the same as the editor instance that the drag event is happening within\n const isDropWithinEditorBounds =\n isDropPoint && closestEditor.distance === 0;\n\n // We never want to handle drop events that are not related to us\n if (!isDropPoint && !isDragOrigin) {\n // we are not the drop point or drag origin, so not relevant to us\n return undefined;\n }\n\n return {\n isDropPoint,\n isDropWithinEditorBounds,\n isDragOrigin,\n };\n };\n\n /**\n * The drop event handler listens at the document level,\n * and handles drop events for all editors.\n *\n * It specifically handles the following cases:\n * - If we are both the drag origin and drop point:\n * - Let normal drop handling take over\n * - If we are the drop point but not the drag origin:\n * - Collapse selection to prevent PM from deleting unrelated content\n * - If drop event is outside our editor bounds, dispatch synthetic drop event to our editor\n * - If we are the drag origin but not the drop point:\n * - Delete the dragged content from our editor after a delay\n */\n onDrop = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n\n const context = this.getDragEventContext(event);\n if (!context) {\n this.closeDropCursor();\n // This is not a drag event that we are interested in\n return;\n }\n const { isDropPoint, isDropWithinEditorBounds, isDragOrigin } = context;\n\n if (!isDropWithinEditorBounds && isDropPoint) {\n // Any time that the drop event is outside of the editor bounds (but still close to an editor instance)\n // We dispatch a synthetic event that is in the bounds of the editor instance, to have the correct drop point\n this.dispatchSyntheticEvent(event);\n }\n\n if (isDropPoint) {\n // The current instance is the drop point\n\n if (this.pmView.dragging) {\n // Do not collapse selection when text content is being dragged\n return;\n }\n // Because the editor selection is unrelated to the dragged content, we\n // don't want PM to delete its content. Therefore, we collapse the\n // selection.\n this.pmView.dispatch(\n this.pmView.state.tr.setSelection(\n TextSelection.create(\n this.pmView.state.tr.doc,\n this.pmView.state.tr.selection.anchor,\n ),\n ),\n );\n return;\n } else if (isDragOrigin) {\n // The current instance is the drag origin, but not the drop point\n // our content got dropped somewhere else\n\n // Because the editor from which the block originates doesn't get a drop\n // event on it, PM doesn't delete its selected content. Therefore, we\n // need to do so manually.\n //\n // Note: Deleting the selected content from the editor from which the\n // block originates, may change its height. This can cause the position of\n // the editor in which the block is being dropping to shift, before it\n // can handle the drop event. That in turn can cause the drop to happen\n // somewhere other than the user intended. To get around this, we delay\n // deleting the selected content until all editors have had the chance to\n // handle the event.\n setTimeout(\n () => this.pmView.dispatch(this.pmView.state.tr.deleteSelection()),\n 0,\n );\n return;\n }\n };\n\n onDragEnd = (event: DragEvent) => {\n if ((event as any).synthetic) {\n return;\n }\n // When the user starts dragging a block, `view.dragging` is set on all\n // BlockNote editors. However, when the drag ends, only the editor that the\n // drag originated in automatically clears `view.dragging`. Therefore, we\n // have to manually clear it on all editors.\n this.pmView.dragging = null;\n };\n\n onKeyDown = (_event: KeyboardEvent) => {\n if (this.state?.show && this.editor.isFocused()) {\n // Typing in editor should hide side menu\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n };\n\n onMouseMove = (event: MouseEvent) => {\n if (this.menuFrozen) {\n return;\n }\n\n this.mousePos = { x: event.clientX, y: event.clientY };\n\n // We want the full area of the editor to check if the cursor is hovering\n // above it though.\n const editorOuterBoundingBox = this.pmView.dom.getBoundingClientRect();\n const cursorWithinEditor =\n this.mousePos.x > editorOuterBoundingBox.left &&\n this.mousePos.x < editorOuterBoundingBox.right &&\n this.mousePos.y > editorOuterBoundingBox.top &&\n this.mousePos.y < editorOuterBoundingBox.bottom;\n\n // TODO: remove parentElement, but then we need to remove padding from boundingbox or find a different solution\n const editorWrapper = this.pmView.dom!.parentElement!;\n\n // Doesn't update if the mouse hovers an element that's over the editor but\n // isn't a part of it or the side menu.\n if (\n // Cursor is within the editor area\n cursorWithinEditor &&\n // An element is hovered\n event &&\n event.target &&\n // Element is outside the editor\n !(\n editorWrapper === event.target ||\n editorWrapper.contains(event.target as HTMLElement)\n )\n ) {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n\n return;\n }\n\n this.updateStateFromMousePos();\n };\n\n private dispatchSyntheticEvent(event: DragEvent) {\n const evt = new Event(event.type as \"dragover\", event) as any;\n const dropPointBoundingBox = (\n this.pmView.dom.firstChild as HTMLElement\n ).getBoundingClientRect();\n evt.clientX = event.clientX;\n evt.clientY = event.clientY;\n\n evt.clientX = Math.min(\n Math.max(event.clientX, dropPointBoundingBox.left),\n dropPointBoundingBox.left + dropPointBoundingBox.width,\n );\n evt.clientY = Math.min(\n Math.max(event.clientY, dropPointBoundingBox.top),\n dropPointBoundingBox.top + dropPointBoundingBox.height,\n );\n\n evt.dataTransfer = event.dataTransfer;\n evt.preventDefault = () => event.preventDefault();\n evt.synthetic = true; // prevent recursion\n this.pmView.dom.dispatchEvent(evt);\n }\n\n // Needed in cases where the editor state updates without the mouse cursor\n // moving, as some state updates can require a side menu update. For example,\n // adding a button to the side menu which removes the block can cause the\n // block below to jump up into the place of the removed block when clicked,\n // allowing the user to click the button again without moving the cursor. This\n // would otherwise not update the side menu, and so clicking the button again\n // would attempt to remove the same block again, causing an error.\n update(_view: EditorView, prevState: EditorState) {\n const docChanged = !prevState.doc.eq(this.pmView.state.doc);\n if (docChanged && this.state?.show) {\n this.updateStateFromMousePos();\n }\n }\n\n destroy() {\n if (this.state?.show) {\n this.state.show = false;\n this.emitUpdate(this.state);\n }\n this.pmView.root.removeEventListener(\n \"mousemove\",\n this.onMouseMove as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"dragstart\",\n this.onDragStart as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"dragover\",\n this.onDragOver as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"drop\",\n this.onDrop as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"dragend\",\n this.onDragEnd as EventListener,\n true,\n );\n this.pmView.root.removeEventListener(\n \"keydown\",\n this.onKeyDown as EventListener,\n true,\n );\n }\n}\n\nexport const sideMenuPluginKey = new PluginKey(\"SideMenuPlugin\");\n\nexport const SideMenuExtension = createExtension(({ editor }) => {\n let view: SideMenuView<any, any, any> | undefined;\n const store = createStore<SideMenuState<any, any, any> | undefined>(\n undefined,\n );\n\n return {\n key: \"sideMenu\",\n store,\n prosemirrorPlugins: [\n new Plugin({\n key: sideMenuPluginKey,\n view: (editorView) => {\n view = new SideMenuView(editor, editorView, (state) => {\n // TODO: Without spreading the state, in some cases like toggling\n // `show`, this doesn't trigger an update.\n store.setState({ ...state });\n });\n return view;\n },\n }),\n ],\n\n /**\n * Handles drag & drop events for blocks.\n */\n blockDragStart(\n event: { dataTransfer: DataTransfer | null; clientY: number },\n block: Block<any, any, any>,\n ) {\n if (view) {\n view.isDragOrigin = true;\n }\n dragStart(event, block, editor);\n },\n\n /**\n * Handles drag & drop events for blocks.\n */\n blockDragEnd() {\n unsetDragImage(editor.prosemirrorView.root);\n if (view) {\n view.isDragOrigin = false;\n }\n\n editor.blur();\n },\n\n /**\n * Freezes the side menu. When frozen, the side menu will stay\n * attached to the same block regardless of which block is hovered by the\n * mouse cursor.\n */\n freezeMenu() {\n view!.menuFrozen = true;\n view!.state!.show = true;\n view!.emitUpdate(view!.state!);\n },\n\n /**\n * Unfreezes the side menu. When frozen, the side menu will stay\n * attached to the same block regardless of which block is hovered by the\n * mouse cursor.\n */\n unfreezeMenu() {\n view!.menuFrozen = false;\n view!.state!.show = false;\n view!.emitUpdate(view!.state!);\n },\n } as const;\n});\n","import { EditorState, Plugin, PluginKey, PluginView } from \"prosemirror-state\";\nimport {\n CellSelection,\n addColumnAfter,\n addColumnBefore,\n addRowAfter,\n addRowBefore,\n deleteColumn,\n deleteRow,\n mergeCells,\n splitCell,\n} from \"prosemirror-tables\";\nimport { Decoration, DecorationSet, EditorView } from \"prosemirror-view\";\nimport {\n RelativeCellIndices,\n addRowsOrColumns,\n areInSameColumn,\n canColumnBeDraggedInto,\n canRowBeDraggedInto,\n cropEmptyRowsOrColumns,\n getCellsAtColumnHandle,\n getCellsAtRowHandle,\n getDimensionsOfTable,\n moveColumn,\n moveRow,\n} from \"../../api/blockManipulation/tables/tables.js\";\nimport { nodeToBlock } from \"../../api/nodeConversions/nodeToBlock.js\";\nimport { getNodeById } from \"../../api/nodeUtil.js\";\nimport {\n editorHasBlockWithType,\n isTableCellSelection,\n} from \"../../blocks/defaultBlockTypeGuards.js\";\nimport { DefaultBlockSchema } from \"../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport {\n createExtension,\n createStore,\n} from \"../../editor/BlockNoteExtension.js\";\nimport {\n BlockFromConfigNoChildren,\n BlockSchemaWithBlock,\n} from \"../../schema/index.js\";\nimport { getDraggableBlockFromElement } from \"../getDraggableBlockFromElement.js\";\n\nlet dragImageElement: HTMLElement | undefined;\n\n// TODO consider switching this to jotai, it is a bit messy and noisy\nexport type TableHandlesState = {\n show: boolean;\n showAddOrRemoveRowsButton: boolean;\n showAddOrRemoveColumnsButton: boolean;\n referencePosCell: DOMRect | undefined;\n referencePosTable: DOMRect;\n\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>;\n colIndex: number | undefined;\n rowIndex: number | undefined;\n\n draggingState:\n | {\n draggedCellOrientation: \"row\" | \"col\";\n originalIndex: number;\n mousePos: number;\n }\n | undefined;\n\n widgetContainer: HTMLElement | undefined;\n};\n\nfunction setHiddenDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement) {\n return;\n }\n\n dragImageElement = document.createElement(\"div\");\n dragImageElement.innerHTML = \"_\";\n dragImageElement.style.opacity = \"0\";\n dragImageElement.style.height = \"1px\";\n dragImageElement.style.width = \"1px\";\n if (rootEl instanceof Document) {\n rootEl.body.appendChild(dragImageElement);\n } else {\n rootEl.appendChild(dragImageElement);\n }\n}\n\nfunction unsetHiddenDragImage(rootEl: Document | ShadowRoot) {\n if (dragImageElement) {\n if (rootEl instanceof Document) {\n rootEl.body.removeChild(dragImageElement);\n } else {\n rootEl.removeChild(dragImageElement);\n }\n dragImageElement = undefined;\n }\n}\n\nfunction getChildIndex(node: Element) {\n return Array.prototype.indexOf.call(node.parentElement!.childNodes, node);\n}\n\n// Finds the DOM element corresponding to the table cell that the target element\n// is currently in. If the target element is not in a table cell, returns null.\nfunction domCellAround(target: Element) {\n let currentTarget: Element | undefined = target;\n while (\n currentTarget &&\n currentTarget.nodeName !== \"TD\" &&\n currentTarget.nodeName !== \"TH\" &&\n !currentTarget.classList.contains(\"tableWrapper\")\n ) {\n if (currentTarget.classList.contains(\"ProseMirror\")) {\n return undefined;\n }\n const parent: ParentNode | null = currentTarget.parentNode;\n\n if (!parent || !(parent instanceof Element)) {\n return undefined;\n }\n currentTarget = parent;\n }\n\n return currentTarget.nodeName === \"TD\" || currentTarget.nodeName === \"TH\"\n ? {\n type: \"cell\",\n domNode: currentTarget,\n tbodyNode: currentTarget.closest(\"tbody\"),\n }\n : {\n type: \"wrapper\",\n domNode: currentTarget,\n tbodyNode: currentTarget.querySelector(\"tbody\"),\n };\n}\n\n// Hides elements in the DOMwith the provided class names.\nfunction hideElements(selector: string, rootEl: Document | ShadowRoot) {\n const elementsToHide = rootEl.querySelectorAll(selector);\n\n for (let i = 0; i < elementsToHide.length; i++) {\n (elementsToHide[i] as HTMLElement).style.visibility = \"hidden\";\n }\n}\n\nexport class TableHandlesView implements PluginView {\n public state?: TableHandlesState;\n public emitUpdate: () => void;\n\n public tableId: string | undefined;\n public tablePos: number | undefined;\n public tableElement: HTMLElement | undefined;\n\n public menuFrozen = false;\n\n public mouseState: \"up\" | \"down\" | \"selecting\" = \"up\";\n\n public prevWasEditable: boolean | null = null;\n\n constructor(\n private readonly editor: BlockNoteEditor<\n BlockSchemaWithBlock<\"table\", DefaultBlockSchema[\"table\"]>,\n any,\n any\n >,\n private readonly pmView: EditorView,\n emitUpdate: (state: TableHandlesState) => void,\n ) {\n this.emitUpdate = () => {\n if (!this.state) {\n throw new Error(\"Attempting to update uninitialized image toolbar\");\n }\n\n emitUpdate(this.state);\n };\n\n pmView.dom.addEventListener(\"mousemove\", this.mouseMoveHandler);\n pmView.dom.addEventListener(\"mousedown\", this.viewMousedownHandler);\n window.addEventListener(\"mouseup\", this.mouseUpHandler);\n\n pmView.root.addEventListener(\n \"dragover\",\n this.dragOverHandler as EventListener,\n );\n pmView.root.addEventListener(\n \"drop\",\n this.dropHandler as unknown as EventListener,\n );\n }\n\n viewMousedownHandler = () => {\n this.mouseState = \"down\";\n };\n\n mouseUpHandler = (event: MouseEvent) => {\n this.mouseState = \"up\";\n this.mouseMoveHandler(event);\n };\n\n mouseMoveHandler = (event: MouseEvent) => {\n if (this.menuFrozen) {\n return;\n }\n\n if (this.mouseState === \"selecting\") {\n return;\n }\n\n if (\n !(event.target instanceof Element) ||\n !this.pmView.dom.contains(event.target)\n ) {\n return;\n }\n\n const target = domCellAround(event.target);\n\n if (\n target?.type === \"cell\" &&\n this.mouseState === \"down\" &&\n !this.state?.draggingState\n ) {\n // hide draghandles when selecting text as they could be in the way of the user\n this.mouseState = \"selecting\";\n\n if (this.state?.show) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n }\n return;\n }\n\n if (!target || !this.editor.isEditable) {\n if (this.state?.show) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n }\n return;\n }\n\n if (!target.tbodyNode) {\n return;\n }\n\n const tableRect = target.tbodyNode.getBoundingClientRect();\n\n const blockEl = getDraggableBlockFromElement(target.domNode, this.pmView);\n if (!blockEl) {\n return;\n }\n this.tableElement = blockEl.node;\n\n let tableBlock:\n | BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>\n | undefined;\n\n const pmNodeInfo = this.editor.transact((tr) =>\n getNodeById(blockEl.id, tr.doc),\n );\n if (!pmNodeInfo) {\n throw new Error(`Block with ID ${blockEl.id} not found`);\n }\n\n const block = nodeToBlock(\n pmNodeInfo.node,\n this.editor.pmSchema,\n this.editor.schema.blockSchema,\n this.editor.schema.inlineContentSchema,\n this.editor.schema.styleSchema,\n );\n\n if (editorHasBlockWithType(this.editor, \"table\")) {\n this.tablePos = pmNodeInfo.posBeforeNode + 1;\n tableBlock = block;\n }\n\n if (!tableBlock) {\n return;\n }\n\n this.tableId = blockEl.id;\n const widgetContainer = target.domNode\n .closest(\".tableWrapper\")\n ?.querySelector(\".table-widgets-container\") as HTMLElement;\n\n if (target?.type === \"wrapper\") {\n // if we're just to the right or below the table, show the extend buttons\n // (this is a bit hacky. It would probably be cleaner to render the extend buttons in the Table NodeView instead)\n const belowTable =\n event.clientY >= tableRect.bottom - 1 && // -1 to account for fractions of pixels in \"bottom\"\n event.clientY < tableRect.bottom + 20;\n const toRightOfTable =\n event.clientX >= tableRect.right - 1 &&\n event.clientX < tableRect.right + 20;\n\n // without this check, we'd also hide draghandles when hovering over them\n const hideHandles =\n event.clientX > tableRect.right || event.clientY > tableRect.bottom;\n\n this.state = {\n ...this.state!,\n show: true,\n showAddOrRemoveRowsButton: belowTable,\n showAddOrRemoveColumnsButton: toRightOfTable,\n referencePosTable: tableRect,\n block: tableBlock,\n widgetContainer,\n colIndex: hideHandles ? undefined : this.state?.colIndex,\n rowIndex: hideHandles ? undefined : this.state?.rowIndex,\n referencePosCell: hideHandles\n ? undefined\n : this.state?.referencePosCell,\n };\n } else {\n const colIndex = getChildIndex(target.domNode);\n const rowIndex = getChildIndex(target.domNode.parentElement!);\n const cellRect = target.domNode.getBoundingClientRect();\n\n if (\n this.state !== undefined &&\n this.state.show &&\n this.tableId === blockEl.id &&\n this.state.rowIndex === rowIndex &&\n this.state.colIndex === colIndex\n ) {\n // no update needed\n return;\n }\n\n this.state = {\n show: true,\n showAddOrRemoveColumnsButton:\n colIndex === tableBlock.content.rows[0].cells.length - 1,\n showAddOrRemoveRowsButton:\n rowIndex === tableBlock.content.rows.length - 1,\n referencePosTable: tableRect,\n\n block: tableBlock,\n draggingState: undefined,\n referencePosCell: cellRect,\n colIndex: colIndex,\n rowIndex: rowIndex,\n\n widgetContainer,\n };\n }\n this.emitUpdate();\n\n return false;\n };\n\n dragOverHandler = (event: DragEvent) => {\n if (this.state?.draggingState === undefined) {\n return;\n }\n\n event.preventDefault();\n event.dataTransfer!.dropEffect = \"move\";\n\n hideElements(\n \".prosemirror-dropcursor-block, .prosemirror-dropcursor-inline\",\n this.pmView.root,\n );\n\n // The mouse cursor coordinates, bounded to the table's bounding box. The\n // bounding box is shrunk by 1px on each side to ensure that the bounded\n // coordinates are always inside a table cell.\n const boundedMouseCoords = {\n left: Math.min(\n Math.max(event.clientX, this.state.referencePosTable.left + 1),\n this.state.referencePosTable.right - 1,\n ),\n top: Math.min(\n Math.max(event.clientY, this.state.referencePosTable.top + 1),\n this.state.referencePosTable.bottom - 1,\n ),\n };\n\n // Gets the table cell element that the bounded mouse cursor coordinates lie\n // in.\n const tableCellElements = this.pmView.root\n .elementsFromPoint(boundedMouseCoords.left, boundedMouseCoords.top)\n .filter(\n (element) => element.tagName === \"TD\" || element.tagName === \"TH\",\n );\n if (tableCellElements.length === 0) {\n return;\n }\n const tableCellElement = tableCellElements[0];\n\n let emitStateUpdate = false;\n\n // Gets current row and column index.\n const rowIndex = getChildIndex(tableCellElement.parentElement!);\n const colIndex = getChildIndex(tableCellElement);\n\n // Checks if the drop cursor needs to be updated. This affects decorations\n // only so it doesn't trigger a state update.\n const oldIndex =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? this.state.rowIndex\n : this.state.colIndex;\n const newIndex =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? rowIndex\n : colIndex;\n const dispatchDecorationsTransaction = newIndex !== oldIndex;\n\n // Checks if either the hovered cell has changed and updates the row and\n // column index. Also updates the reference DOMRect.\n if (this.state.rowIndex !== rowIndex || this.state.colIndex !== colIndex) {\n this.state.rowIndex = rowIndex;\n this.state.colIndex = colIndex;\n\n this.state.referencePosCell = tableCellElement.getBoundingClientRect();\n\n emitStateUpdate = true;\n }\n\n // Checks if the mouse cursor position along the axis that the user is\n // dragging on has changed and updates it.\n const mousePos =\n this.state.draggingState.draggedCellOrientation === \"row\"\n ? boundedMouseCoords.top\n : boundedMouseCoords.left;\n if (this.state.draggingState.mousePos !== mousePos) {\n this.state.draggingState.mousePos = mousePos;\n\n emitStateUpdate = true;\n }\n\n // Emits a state update if any of the fields have changed.\n if (emitStateUpdate) {\n this.emitUpdate();\n }\n\n // Dispatches a dummy transaction to force a decorations update if\n // necessary.\n if (dispatchDecorationsTransaction) {\n this.editor.transact((tr) => tr.setMeta(tableHandlesPluginKey, true));\n }\n };\n\n dropHandler = (event: DragEvent) => {\n this.mouseState = \"up\";\n if (this.state === undefined || this.state.draggingState === undefined) {\n return false;\n }\n\n if (\n this.state.rowIndex === undefined ||\n this.state.colIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drop table row or column, but no table block was hovered prior.\",\n );\n }\n\n event.preventDefault();\n\n const { draggingState, colIndex, rowIndex } = this.state;\n\n const columnWidths = this.state.block.content.columnWidths;\n\n if (draggingState.draggedCellOrientation === \"row\") {\n if (\n !canRowBeDraggedInto(\n this.state.block,\n draggingState.originalIndex,\n rowIndex,\n )\n ) {\n // If the target row is invalid, don't move the row\n return false;\n }\n const newTable = moveRow(\n this.state.block,\n draggingState.originalIndex,\n rowIndex,\n );\n this.editor.updateBlock(this.state.block, {\n type: \"table\",\n content: {\n ...this.state.block.content,\n rows: newTable as any,\n },\n });\n } else {\n if (\n !canColumnBeDraggedInto(\n this.state.block,\n draggingState.originalIndex,\n colIndex,\n )\n ) {\n // If the target column is invalid, don't move the column\n return false;\n }\n const newTable = moveColumn(\n this.state.block,\n draggingState.originalIndex,\n colIndex,\n );\n const [columnWidth] = columnWidths.splice(draggingState.originalIndex, 1);\n columnWidths.splice(colIndex, 0, columnWidth);\n this.editor.updateBlock(this.state.block, {\n type: \"table\",\n content: {\n ...this.state.block.content,\n columnWidths,\n rows: newTable as any,\n },\n });\n }\n\n // Have to reset text cursor position to the block as `updateBlock` moves\n // the existing selection out of the block.\n this.editor.setTextCursorPosition(this.state.block.id);\n\n return true;\n };\n // Updates drag handles when the table is modified or removed.\n update() {\n if (!this.state || !this.state.show) {\n return;\n }\n\n // Hide handles if the table block has been removed.\n this.state.block = this.editor.getBlock(this.state.block.id)!;\n if (\n !this.state.block ||\n this.state.block.type !== \"table\" ||\n // when collaborating, the table element might be replaced and out of date\n // because yjs replaces the element when for example you change the color via the side menu\n !this.tableElement?.isConnected\n ) {\n this.state.show = false;\n this.state.showAddOrRemoveRowsButton = false;\n this.state.showAddOrRemoveColumnsButton = false;\n this.emitUpdate();\n\n return;\n }\n\n const { height: rowCount, width: colCount } = getDimensionsOfTable(\n this.state.block,\n );\n\n if (\n this.state.rowIndex !== undefined &&\n this.state.colIndex !== undefined\n ) {\n // If rows or columns are deleted in the update, the hovered indices for\n // those may now be out of bounds. If this is the case, they are moved to\n // the new last row or column.\n if (this.state.rowIndex >= rowCount) {\n this.state.rowIndex = rowCount - 1;\n }\n if (this.state.colIndex >= colCount) {\n this.state.colIndex = colCount - 1;\n }\n }\n\n // Update bounding boxes.\n const tableBody = this.tableElement!.querySelector(\"tbody\");\n\n if (!tableBody) {\n throw new Error(\n \"Table block does not contain a 'tbody' HTML element. This should never happen.\",\n );\n }\n\n if (\n this.state.rowIndex !== undefined &&\n this.state.colIndex !== undefined\n ) {\n const row = tableBody.children[this.state.rowIndex];\n const cell = row.children[this.state.colIndex];\n if (cell) {\n this.state.referencePosCell = cell.getBoundingClientRect();\n } else {\n this.state.rowIndex = undefined;\n this.state.colIndex = undefined;\n }\n }\n this.state.referencePosTable = tableBody.getBoundingClientRect();\n\n this.emitUpdate();\n }\n\n destroy() {\n this.pmView.dom.removeEventListener(\"mousemove\", this.mouseMoveHandler);\n window.removeEventListener(\"mouseup\", this.mouseUpHandler);\n this.pmView.dom.removeEventListener(\"mousedown\", this.viewMousedownHandler);\n this.pmView.root.removeEventListener(\n \"dragover\",\n this.dragOverHandler as EventListener,\n );\n this.pmView.root.removeEventListener(\n \"drop\",\n this.dropHandler as unknown as EventListener,\n );\n }\n}\n\nexport const tableHandlesPluginKey = new PluginKey(\"TableHandlesPlugin\");\n\nexport const TableHandlesExtension = createExtension(({ editor }) => {\n let view: TableHandlesView | undefined = undefined;\n\n const store = createStore<TableHandlesState | undefined>(undefined);\n\n return {\n key: \"tableHandles\",\n store,\n prosemirrorPlugins: [\n new Plugin({\n key: tableHandlesPluginKey,\n view: (editorView) => {\n view = new TableHandlesView(editor as any, editorView, (state) => {\n store.setState(\n state.block\n ? {\n ...state,\n draggingState: state.draggingState\n ? { ...state.draggingState }\n : undefined,\n }\n : undefined,\n );\n });\n return view;\n },\n // We use decorations to render the drop cursor when dragging a table row\n // or column. The decorations are updated in the `dragOverHandler` method.\n props: {\n decorations: (state) => {\n if (\n view === undefined ||\n view.state === undefined ||\n view.state.draggingState === undefined ||\n view.tablePos === undefined\n ) {\n return;\n }\n\n const newIndex =\n view.state.draggingState.draggedCellOrientation === \"row\"\n ? view.state.rowIndex\n : view.state.colIndex;\n\n if (newIndex === undefined) {\n return;\n }\n\n const decorations: Decoration[] = [];\n const { block, draggingState } = view.state;\n const { originalIndex, draggedCellOrientation } = draggingState;\n\n // Return empty decorations if:\n // - Dragging to same position\n // - No block exists\n // - Row drag not allowed\n // - Column drag not allowed\n if (\n newIndex === originalIndex ||\n !block ||\n (draggedCellOrientation === \"row\" &&\n !canRowBeDraggedInto(block, originalIndex, newIndex)) ||\n (draggedCellOrientation === \"col\" &&\n !canColumnBeDraggedInto(block, originalIndex, newIndex))\n ) {\n return DecorationSet.create(state.doc, decorations);\n }\n\n // Gets the table to show the drop cursor in.\n const tableResolvedPos = state.doc.resolve(view.tablePos + 1);\n\n if (view.state.draggingState.draggedCellOrientation === \"row\") {\n const cellsInRow = getCellsAtRowHandle(\n view.state.block,\n newIndex,\n );\n\n cellsInRow.forEach(({ row, col }) => {\n // Gets each row in the table.\n const rowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(row) + 1,\n );\n\n // Gets the cell within the row.\n const cellResolvedPos = state.doc.resolve(\n rowResolvedPos.posAtIndex(col) + 1,\n );\n const cellNode = cellResolvedPos.node();\n // Creates a decoration at the start or end of each cell,\n // depending on whether the new index is before or after the\n // original index.\n const decorationPos =\n cellResolvedPos.pos +\n (newIndex > originalIndex ? cellNode.nodeSize - 2 : 0);\n decorations.push(\n // The widget is a small bar which spans the width of the cell.\n Decoration.widget(decorationPos, () => {\n const widget = document.createElement(\"div\");\n widget.className = \"bn-table-drop-cursor\";\n widget.style.left = \"0\";\n widget.style.right = \"0\";\n // This is only necessary because the drop indicator's height\n // is an even number of pixels, whereas the border between\n // table cells is an odd number of pixels. So this makes the\n // positioning slightly more consistent regardless of where\n // the row is being dropped.\n if (newIndex > originalIndex) {\n widget.style.bottom = \"-2px\";\n } else {\n widget.style.top = \"-3px\";\n }\n widget.style.height = \"4px\";\n\n return widget;\n }),\n );\n });\n } else {\n const cellsInColumn = getCellsAtColumnHandle(\n view.state.block,\n newIndex,\n );\n\n cellsInColumn.forEach(({ row, col }) => {\n // Gets each row in the table.\n const rowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(row) + 1,\n );\n\n // Gets the cell within the row.\n const cellResolvedPos = state.doc.resolve(\n rowResolvedPos.posAtIndex(col) + 1,\n );\n const cellNode = cellResolvedPos.node();\n\n // Creates a decoration at the start or end of each cell,\n // depending on whether the new index is before or after the\n // original index.\n const decorationPos =\n cellResolvedPos.pos +\n (newIndex > originalIndex ? cellNode.nodeSize - 2 : 0);\n\n decorations.push(\n // The widget is a small bar which spans the height of the cell.\n Decoration.widget(decorationPos, () => {\n const widget = document.createElement(\"div\");\n widget.className = \"bn-table-drop-cursor\";\n widget.style.top = \"0\";\n widget.style.bottom = \"0\";\n // This is only necessary because the drop indicator's width\n // is an even number of pixels, whereas the border between\n // table cells is an odd number of pixels. So this makes the\n // positioning slightly more consistent regardless of where\n // the column is being dropped.\n if (newIndex > originalIndex) {\n widget.style.right = \"-2px\";\n } else {\n widget.style.left = \"-3px\";\n }\n widget.style.width = \"4px\";\n\n return widget;\n }),\n );\n });\n }\n\n return DecorationSet.create(state.doc, decorations);\n },\n },\n }),\n ],\n\n /**\n * Callback that should be set on the `dragStart` event for whichever element\n * is used as the column drag handle.\n */\n colDragStart(event: {\n dataTransfer: DataTransfer | null;\n clientX: number;\n }) {\n if (\n view === undefined ||\n view.state === undefined ||\n view.state.colIndex === undefined\n ) {\n throw new Error(\n \"Attempted to drag table column, but no table block was hovered prior.\",\n );\n }\n\n view.state.draggingState = {\n draggedCellOrientation: \"col\",\n originalIndex: view.state.colIndex,\n mousePos: event.clientX,\n };\n view.emitUpdate();\n\n editor.transact((tr) =>\n tr.setMeta(tableHandlesPluginKey, {\n draggedCellOrientation:\n view!.state!.draggingState!.draggedCellOrientation,\n originalIndex: view!.state!.colIndex,\n newIndex: view!.state!.colIndex,\n tablePos: view!.tablePos,\n }),\n );\n\n if (editor.headless) {\n return;\n }\n\n setHiddenDragImage(editor.prosemirrorView.root);\n event.dataTransfer!.setDragImage(dragImageElement!, 0, 0);\n event.dataTransfer!.effectAllowed = \"move\";\n },\n\n /**\n * Callback that should be set on the `dragStart` event for whichever element\n * is used as the row drag handle.\n */\n rowDragStart(event: {\n dataTransfer: DataTransfer | null;\n clientY: number;\n }) {\n if (view!.state === undefined || view!.state.rowIndex === undefined) {\n throw new Error(\n \"Attempted to drag table row, but no table block was hovered prior.\",\n );\n }\n\n view!.state.draggingState = {\n draggedCellOrientation: \"row\",\n originalIndex: view!.state.rowIndex,\n mousePos: event.clientY,\n };\n view!.emitUpdate();\n\n editor.transact((tr) =>\n tr.setMeta(tableHandlesPluginKey, {\n draggedCellOrientation:\n view!.state!.draggingState!.draggedCellOrientation,\n originalIndex: view!.state!.rowIndex,\n newIndex: view!.state!.rowIndex,\n tablePos: view!.tablePos,\n }),\n );\n\n if (editor.headless) {\n return;\n }\n\n setHiddenDragImage(editor.prosemirrorView.root);\n event.dataTransfer!.setDragImage(dragImageElement!, 0, 0);\n event.dataTransfer!.effectAllowed = \"copyMove\";\n },\n\n /**\n * Callback that should be set on the `dragEnd` event for both the element\n * used as the row drag handle, and the one used as the column drag handle.\n */\n dragEnd() {\n if (view!.state === undefined) {\n throw new Error(\n \"Attempted to drag table row, but no table block was hovered prior.\",\n );\n }\n\n view!.state.draggingState = undefined;\n view!.emitUpdate();\n\n editor.transact((tr) => tr.setMeta(tableHandlesPluginKey, null));\n\n if (editor.headless) {\n return;\n }\n\n unsetHiddenDragImage(editor.prosemirrorView.root);\n },\n\n /**\n * Freezes the drag handles. When frozen, they will stay attached to the same\n * cell regardless of which cell is hovered by the mouse cursor.\n */\n freezeHandles() {\n view!.menuFrozen = true;\n },\n\n /**\n * Unfreezes the drag handles. When frozen, they will stay attached to the\n * same cell regardless of which cell is hovered by the mouse cursor.\n */\n unfreezeHandles() {\n view!.menuFrozen = false;\n },\n\n getCellsAtRowHandle(\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n relativeRowIndex: RelativeCellIndices[\"row\"],\n ) {\n return getCellsAtRowHandle(block, relativeRowIndex);\n },\n\n /**\n * Get all the cells in a column of the table block.\n */\n getCellsAtColumnHandle(\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n relativeColumnIndex: RelativeCellIndices[\"col\"],\n ) {\n return getCellsAtColumnHandle(block, relativeColumnIndex);\n },\n\n /**\n * Sets the selection to the given cell or a range of cells.\n * @returns The new state after the selection has been set.\n */\n setCellSelection(\n state: EditorState,\n relativeStartCell: RelativeCellIndices,\n relativeEndCell: RelativeCellIndices = relativeStartCell,\n ) {\n if (!view) {\n throw new Error(\"Table handles view not initialized\");\n }\n\n const tableResolvedPos = state.doc.resolve(view.tablePos! + 1);\n const startRowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(relativeStartCell.row) + 1,\n );\n const startCellResolvedPos = state.doc.resolve(\n // No need for +1, since CellSelection expects the position before the cell\n startRowResolvedPos.posAtIndex(relativeStartCell.col),\n );\n const endRowResolvedPos = state.doc.resolve(\n tableResolvedPos.posAtIndex(relativeEndCell.row) + 1,\n );\n const endCellResolvedPos = state.doc.resolve(\n // No need for +1, since CellSelection expects the position before the cell\n endRowResolvedPos.posAtIndex(relativeEndCell.col),\n );\n\n // Begin a new transaction to set the selection\n const tr = state.tr;\n\n // Set the selection to the given cell or a range of cells\n tr.setSelection(\n new CellSelection(startCellResolvedPos, endCellResolvedPos),\n );\n\n // Quickly apply the transaction to get the new state to update the selection before splitting the cell\n return state.apply(tr);\n },\n\n /**\n * Adds a row or column to the table using prosemirror-table commands\n */\n addRowOrColumn(\n index: RelativeCellIndices[\"row\"] | RelativeCellIndices[\"col\"],\n direction:\n | { orientation: \"row\"; side: \"above\" | \"below\" }\n | { orientation: \"column\"; side: \"left\" | \"right\" },\n ) {\n editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(\n beforeState,\n direction.orientation === \"row\"\n ? { row: index, col: 0 }\n : { row: 0, col: index },\n );\n\n if (direction.orientation === \"row\") {\n if (direction.side === \"above\") {\n return addRowBefore(state, dispatch);\n } else {\n return addRowAfter(state, dispatch);\n }\n } else {\n if (direction.side === \"left\") {\n return addColumnBefore(state, dispatch);\n } else {\n return addColumnAfter(state, dispatch);\n }\n }\n });\n },\n\n /**\n * Removes a row or column from the table using prosemirror-table commands\n */\n removeRowOrColumn(\n index: RelativeCellIndices[\"row\"] | RelativeCellIndices[\"col\"],\n direction: \"row\" | \"column\",\n ) {\n if (direction === \"row\") {\n return editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(beforeState, {\n row: index,\n col: 0,\n });\n return deleteRow(state, dispatch);\n });\n } else {\n return editor.exec((beforeState, dispatch) => {\n const state = this.setCellSelection(beforeState, {\n row: 0,\n col: index,\n });\n return deleteColumn(state, dispatch);\n });\n }\n },\n\n /**\n * Merges the cells in the table block.\n */\n mergeCells(cellsToMerge?: {\n relativeStartCell: RelativeCellIndices;\n relativeEndCell: RelativeCellIndices;\n }) {\n return editor.exec((beforeState, dispatch) => {\n const state = cellsToMerge\n ? this.setCellSelection(\n beforeState,\n cellsToMerge.relativeStartCell,\n cellsToMerge.relativeEndCell,\n )\n : beforeState;\n\n return mergeCells(state, dispatch);\n });\n },\n\n /**\n * Splits the cell in the table block.\n * If no cell is provided, the current cell selected will be split.\n */\n splitCell(relativeCellToSplit?: RelativeCellIndices) {\n return editor.exec((beforeState, dispatch) => {\n const state = relativeCellToSplit\n ? this.setCellSelection(beforeState, relativeCellToSplit)\n : beforeState;\n\n return splitCell(state, dispatch);\n });\n },\n\n /**\n * Gets the start and end cells of the current cell selection.\n * @returns The start and end cells of the current cell selection.\n */\n getCellSelection():\n | undefined\n | {\n from: RelativeCellIndices;\n to: RelativeCellIndices;\n /**\n * All of the cells that are within the selected range.\n */\n cells: RelativeCellIndices[];\n } {\n // Based on the current selection, find the table cells that are within the selected range\n\n return editor.transact((tr) => {\n const selection = tr.selection;\n\n let $fromCell = selection.$from;\n let $toCell = selection.$to;\n if (isTableCellSelection(selection)) {\n // When the selection is a table cell selection, we can find the\n // from and to cells by iterating over the ranges in the selection\n const { ranges } = selection;\n ranges.forEach((range) => {\n $fromCell = range.$from.min($fromCell ?? range.$from);\n $toCell = range.$to.max($toCell ?? range.$to);\n });\n } else {\n // When the selection is a normal text selection\n // Assumes we are within a tableParagraph\n // And find the from and to cells by resolving the positions\n $fromCell = tr.doc.resolve(\n selection.$from.pos - selection.$from.parentOffset - 1,\n );\n $toCell = tr.doc.resolve(\n selection.$to.pos - selection.$to.parentOffset - 1,\n );\n\n // Opt-out when the selection is not pointing into cells\n if ($fromCell.pos === 0 || $toCell.pos === 0) {\n return undefined;\n }\n }\n\n // Find the row and table that the from and to cells are in\n const $fromRow = tr.doc.resolve(\n $fromCell.pos - $fromCell.parentOffset - 1,\n );\n const $toRow = tr.doc.resolve($toCell.pos - $toCell.parentOffset - 1);\n\n // Find the table\n const $table = tr.doc.resolve($fromRow.pos - $fromRow.parentOffset - 1);\n\n // Find the column and row indices of the from and to cells\n const fromColIndex = $fromCell.index($fromRow.depth);\n const fromRowIndex = $fromRow.index($table.depth);\n const toColIndex = $toCell.index($toRow.depth);\n const toRowIndex = $toRow.index($table.depth);\n\n const cells: RelativeCellIndices[] = [];\n for (let row = fromRowIndex; row <= toRowIndex; row++) {\n for (let col = fromColIndex; col <= toColIndex; col++) {\n cells.push({ row, col });\n }\n }\n\n return {\n from: {\n row: fromRowIndex,\n col: fromColIndex,\n },\n to: {\n row: toRowIndex,\n col: toColIndex,\n },\n cells,\n };\n });\n },\n\n /**\n * Gets the direction of the merge based on the current cell selection.\n *\n * Returns undefined when there is no cell selection, or the selection is not within a table.\n */\n getMergeDirection(\n block:\n | BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>\n | undefined,\n ) {\n return editor.transact((tr) => {\n const isSelectingTableCells = isTableCellSelection(tr.selection)\n ? tr.selection\n : undefined;\n\n if (\n !isSelectingTableCells ||\n !block ||\n // Only offer the merge button if there is more than one cell selected.\n isSelectingTableCells.ranges.length <= 1\n ) {\n return undefined;\n }\n\n const cellSelection = this.getCellSelection();\n\n if (!cellSelection) {\n return undefined;\n }\n\n if (areInSameColumn(cellSelection.from, cellSelection.to, block)) {\n return \"vertical\";\n }\n\n return \"horizontal\";\n });\n },\n\n cropEmptyRowsOrColumns(\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n removeEmpty: \"columns\" | \"rows\",\n ) {\n return cropEmptyRowsOrColumns(block, removeEmpty);\n },\n\n addRowsOrColumns(\n block: BlockFromConfigNoChildren<DefaultBlockSchema[\"table\"], any, any>,\n addType: \"columns\" | \"rows\",\n numToAdd: number,\n ) {\n return addRowsOrColumns(block, addType, numToAdd);\n },\n } as const;\n});\n","import { Plugin, PluginKey } from \"prosemirror-state\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\n// based on https://github.com/ueberdosis/tiptap/blob/40a9404c94c7fef7900610c195536384781ae101/demos/src/Experiments/TrailingNode/Vue/trailing-node.ts\n\n/**\n * Extension based on:\n * - https://github.com/ueberdosis/tiptap/blob/v1/packages/tiptap-extensions/src/extensions/TrailingNode.js\n * - https://github.com/remirror/remirror/blob/e0f1bec4a1e8073ce8f5500d62193e52321155b9/packages/prosemirror-trailing-node/src/trailing-node-plugin.ts\n */\nconst plugin = new PluginKey(\"trailingNode\");\n\n/**\n * Add a trailing node to the document so the user can always click at the bottom of the document and start typing\n */\nexport const TrailingNodeExtension = createExtension(() => {\n return {\n key: \"trailingNode\",\n prosemirrorPlugins: [\n new Plugin({\n key: plugin,\n appendTransaction: (_, __, state) => {\n const { doc, tr, schema } = state;\n const shouldInsertNodeAtEnd = plugin.getState(state);\n const endPosition = doc.content.size - 2;\n const type = schema.nodes[\"blockContainer\"];\n const contentType = schema.nodes[\"paragraph\"];\n if (!shouldInsertNodeAtEnd) {\n return;\n }\n\n return tr.insert(\n endPosition,\n type.create(undefined, contentType.create()),\n );\n },\n state: {\n init: (_, _state) => {\n // (maybe fix): use same logic as apply() here\n // so it works when initializing\n },\n apply: (tr, value) => {\n if (!tr.docChanged) {\n return value;\n }\n\n let lastNode = tr.doc.lastChild;\n\n if (!lastNode || lastNode.type.name !== \"blockGroup\") {\n throw new Error(\"Expected blockGroup\");\n }\n\n lastNode = lastNode.lastChild;\n\n if (!lastNode || lastNode.type.name !== \"blockContainer\") {\n return true; // not a blockContainer, but for example Columns. Insert trailing node\n }\n\n const lastContentNode = lastNode.firstChild;\n\n if (!lastContentNode) {\n throw new Error(\"Expected blockContent\");\n }\n\n // If last node is not empty (size > 4) or it doesn't contain\n // inline content, we need to add a trailing node.\n return (\n lastNode.nodeSize > 4 ||\n lastContentNode.type.spec.content !== \"inline*\"\n );\n },\n },\n }),\n ],\n } as const;\n});\n"],"names":["addAttributesAndRemoveClasses","element","className","serializeInlineContentExternalHTML","editor","blockContent","serializer","options","nodes","inlineContentToNodes","tableContentToNodes","UnreachableCaseError","fragment","node","inlineContentImplementation","inlineContent","nodeToCustomInlineContent","output","contentFragment","dom","mark","newDom","domOutputSpec","DOMSerializer","nodeFragment","Fragment","_a","serializeBlock","block","orderedListItemBlockTypes","unorderedListItemBlockTypes","doc","BC_NODE","props","name","spec","bc","_b","attrs","blockImplementation","ret","_c","elementFragment","blockContentDataAttributes","attr","ic","listType","_d","list","childFragment","serializeBlocksToFragment","_e","_f","_g","_h","_i","blocks","serializeBlocksExternalHTML","createExternalHTMLExporter","schema","html","div","domFragment","parent","getParentBlockId","pos","resolvedPos","i","isNodeBlock","determineChangeSource","transaction","collectSnapshot","ROOT_KEY","byId","childrenByParent","pmSchema","getPmSchema","parentId","key","nodeToBlock","detectReorderedChildren","prevOrder","nextOrder","moved","prevIds","commonNext","id","commonPrev","indexInPrev","sequence","n","tailsValues","tailsEndsAtIndex","previousIndexInLis","lowerBound","arr","target","lo","hi","mid","value","lisIndexSet","k","getBlocksChangedByTransaction","appendedTransactions","source","combinedTransaction","combineTransactionSteps","prevSnap","nextSnap","changes","changedIds","prev","next","deepEqual","prevOrderByParent","nextOrderByParent","parents","addedMoveForId","parentKey","movedWithinParent","BlockChangeExtension","createExtension","beforeChangeCallbacks","Plugin","PluginKey","tr","acc","cb","callback","isDarkColor","bgColor","color","r","g","b","c","col","defaultCursorRender","user","cursorElement","caretElement","labelElement","YCursorExtension","recentlyUpdatedCursors","awareness","updated","clientID","cursor","yCursorPlugin","defaultSelectionBuilder","cursorData","YSyncExtension","ySyncPlugin","YUndoExtension","yUndoPlugin","undoCommand","redoCommand","findTypeInOtherYdoc","ytype","otherYdoc","ydoc","rootKey","ytypeItem","otherStructs","itemIndex","Y","ForkYDocExtension","forkedState","store","createStore","originalFragment","forkedFragment","yUndoPluginKey","newOptions","keepChanges","undoStack","update","traverseElement","rootElement","moveColorAttributes","targetBlockContainers","textColor","backgroundColor","colors","defaultProps","el","migrationRules","SchemaMigration","migrationDone","pluginKey","transactions","_oldState","newState","migrationRule","DropCursorExtension","dropCursor","FormattingToolbarExtension","shouldShow","NodeSelection","TextSelection","spansCode","signal","preventShowWhileMouseDown","unsubscribeOnChange","unsubscribeOnSelectionChange","HistoryExtension","history","undo","redo","LinkToolbarExtension","getLinkElementAtPos","currentNode","getMarkAtPos","markType","markRange","getMarkRange","posToDOMRect","getLinkAtSelection","selection","posAtElement","url","text","position","range","VALID_LINK_PROTOCOLS","DEFAULT_LINK_PROTOCOL","PLUGIN_KEY","NodeSelectionKeyboardExtension","view","event","PlaceholderExtension","placeholders","uniqueEditorSelector","v4","styleEl","nonce","styleSheet","getSelector","additionalSelectors","defaultPlaceholder","emptyPlaceholder","rest","blockType","placeholder","blockTypeSelector","onlyBlockSelector","mustBeFocusedSelector","e","state","decs","Decoration","$pos","before","DecorationSet","nodeAttributes","PreviousBlockTypeExtension","timeout","_editorView","_prevState","oldState","currentTransactionOriginalOldBlockAttrs","oldNodes","findChildren","oldNodesById","newNodes","oldNode","oldContentNode","newContentNode","newAttrs","oldAttrs","pluginState","decorations","prevAttrs","decorationAttrs","nodeAttr","val","decoration","getDraggableBlockFromElement","removeUnderlines","removeUnderlinesHelper","tree","numChildElements","numElementsAdded","addSpacesToCheckboxes","helper","child","nextChild","fromDom","convertVideoToMarkdown","visit","index","src","cleanHTMLToMarkdown","cleanHTMLString","unified","rehypeParse","rehypeRemark","remarkGfm","remarkStringify","blocksToMarkdown","externalHTML","fragmentToBlocks","MultipleNodeSelection","Selection","$anchor","$head","__publicField","parentNode","_pos","from","to","Slice","mapping","fromResult","toResult","dragImageElement","blockPositionsFromSelection","beforeFirstBlockPos","afterLastBlockPos","selectionStartInBlockContent","selectionEndInBlockContent","minDepth","startFirstBlockPos","endLastBlockPos","setDragImage","parentClone","getElementIndex","parentElement","targetElement","firstSelectedBlockIndex","lastSelectedBlockIndex","unsetDragImage","iframes","iframe","inheritedClasses","rootEl","dragStart","posInfo","getNodeById","draggedBlockInSelection","multipleBlocksSelected","selectedSlice","clipboardHTML","externalHTMLExporter","plainText","DISTANCE_TO_CONSIDER_EDITOR_BOUNDS","getBlockFromCoords","coords","adjustForColumns","elements","getBlockFromMousePos","mousePos","editorBoundingBox","referenceBlock","referenceBlocksBoundingBox","SideMenuView","pmView","emitUpdate","closestEditor","blockContentBoundingBox","column","DOMParser","editors","minDistance","rect","distanceX","distanceY","distance","dragEventContext","evt","textContentIsBeingDragged","sideMenuIsBeingDragged","isDragOrigin","isDropPoint","isDropWithinEditorBounds","context","_event","editorOuterBoundingBox","cursorWithinEditor","editorWrapper","dropPointBoundingBox","_view","prevState","sideMenuPluginKey","SideMenuExtension","editorView","setHiddenDragImage","unsetHiddenDragImage","getChildIndex","domCellAround","currentTarget","hideElements","selector","elementsToHide","TableHandlesView","tableRect","blockEl","tableBlock","pmNodeInfo","editorHasBlockWithType","widgetContainer","belowTable","toRightOfTable","hideHandles","colIndex","rowIndex","cellRect","boundedMouseCoords","tableCellElements","tableCellElement","emitStateUpdate","oldIndex","dispatchDecorationsTransaction","tableHandlesPluginKey","draggingState","columnWidths","canRowBeDraggedInto","newTable","moveRow","canColumnBeDraggedInto","moveColumn","columnWidth","rowCount","colCount","getDimensionsOfTable","tableBody","cell","TableHandlesExtension","newIndex","originalIndex","draggedCellOrientation","tableResolvedPos","getCellsAtRowHandle","row","rowResolvedPos","cellResolvedPos","cellNode","decorationPos","widget","getCellsAtColumnHandle","relativeRowIndex","relativeColumnIndex","relativeStartCell","relativeEndCell","startRowResolvedPos","startCellResolvedPos","endRowResolvedPos","endCellResolvedPos","CellSelection","direction","beforeState","dispatch","addRowBefore","addRowAfter","addColumnBefore","addColumnAfter","deleteRow","deleteColumn","cellsToMerge","mergeCells","relativeCellToSplit","splitCell","$fromCell","$toCell","isTableCellSelection","ranges","$fromRow","$toRow","$table","fromColIndex","fromRowIndex","toColIndex","toRowIndex","cells","isSelectingTableCells","cellSelection","areInSameColumn","removeEmpty","cropEmptyRowsOrColumns","addType","numToAdd","addRowsOrColumns","plugin","TrailingNodeExtension","_","__","shouldInsertNodeAtEnd","endPosition","type","contentType","_state","lastNode","lastContentNode"],"mappings":"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"}