{"version":3,"file":"extensions-Cutrafjg.cjs","names":[],"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/utils.ts","../src/extensions/DropCursor/DropCursor.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/htmlToMarkdown.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/SuggestionMenu/getDefaultEmojiPickerItems.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; blockType?: string },\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(\n      [blockContent],\n      editor.pmSchema,\n      options?.blockType,\n    );\n  } else if (Array.isArray(blockContent)) {\n    nodes = inlineContentToNodes(\n      blockContent,\n      editor.pmSchema,\n      options?.blockType,\n    );\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  nestingLevel: number,\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        nestingLevel,\n      },\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    if (nestingLevel > 0) {\n      (ret.dom.firstChild! as HTMLElement).setAttribute(\n        \"data-nesting-level\",\n        nestingLevel.toString(),\n      );\n    }\n    elementFragment.append(...Array.from(ret.dom.childNodes));\n  } else {\n    elementFragment.append(ret.dom);\n    if (nestingLevel > 0) {\n      (ret.dom as HTMLElement).setAttribute(\n        \"data-nesting-level\",\n        nestingLevel.toString(),\n      );\n    }\n  }\n\n  if (ret.contentDOM && block.content) {\n    const ic = serializeInlineContentExternalHTML(\n      editor,\n      block.content as any, // TODO\n      serializer,\n      { ...options, blockType: block.type },\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      nestingLevel + 1,\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 (\"childrenDOM\" in ret && ret.childrenDOM) {\n      // block specifies where children should go (e.g. toggle blocks\n      // place children inside <details>)\n      ret.childrenDOM.append(childFragment);\n    } else if (\n      editor.pmSchema.nodes[block.type as any].isInGroup(\"blockContent\")\n    ) {\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  nestingLevel = 0,\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      nestingLevel,\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    0,\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                  setTimeout(() => {\n                    cursor.element.setAttribute(\"data-active\", \"\");\n                  }, 10);\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 type { EditorView } from \"prosemirror-view\";\n\n/**\n * The orientation of the drop cursor.\n */\nexport type DropCursorOrientation =\n  | \"inline\" // Vertical line within text\n  | \"block-horizontal\" // Horizontal line between blocks\n  | \"block-vertical-left\" // Vertical line on left edge of block\n  | \"block-vertical-right\"; // Vertical line on right edge of block\n\n/**\n * The position and orientation of the drop cursor.\n */\nexport type DropCursorPosition = {\n  pos: number; // Document position\n  orientation: DropCursorOrientation;\n};\n/**\n * Bounding rectangle in viewport coordinates (e.g. from getBoundingClientRect).\n */\nexport type Rect = {\n  left: number;\n  right: number;\n  top: number;\n  bottom: number;\n};\n\n/**\n * Returns true if the element or any ancestor has the given CSS class.\n * Used to skip drop cursor for elements marked with the exclusion class (e.g. drag handles).\n */\nexport function hasExclusionClassname(\n  element: Element | null,\n  exclude: string,\n): boolean {\n  if (!element || !exclude) {\n    return false;\n  }\n  return !!element.closest(`.${exclude}`);\n}\n\n/**\n * Computes the viewport rect for a block-level drop cursor (horizontal line between blocks\n * or vertical line on left/right edge). Returns null for inline positions or when no DOM node exists.\n */\nexport function getBlockDropRect(\n  view: EditorView,\n  cursorPos: DropCursorPosition,\n  width: number,\n  scaleX: number,\n  scaleY: number,\n): Rect | null {\n  const $pos = view.state.doc.resolve(cursorPos.pos);\n  const isBlock = !$pos.parent.inlineContent;\n\n  if (!isBlock || cursorPos.orientation === \"inline\") {\n    return null;\n  }\n\n  const before = $pos.nodeBefore;\n\n  const after = $pos.nodeAfter;\n\n  if (!before && !after) {\n    return null;\n  }\n\n  const isVertical =\n    cursorPos.orientation === \"block-vertical-left\" ||\n    cursorPos.orientation === \"block-vertical-right\";\n  // For vertical cursors, position is at the node position, for horizontal cursors, position is at the node before position\n  const nodePos = isVertical\n    ? cursorPos.pos\n    : cursorPos.pos - (before ? before.nodeSize : 0);\n\n  const node = view.nodeDOM(nodePos) as HTMLElement | null;\n  if (!node) {\n    return null;\n  }\n\n  const nodeRect = node.getBoundingClientRect();\n\n  if (isVertical) {\n    const halfWidth = (width / 2) * scaleX;\n    const left =\n      cursorPos.orientation === \"block-vertical-left\"\n        ? nodeRect.left\n        : nodeRect.right;\n\n    return {\n      left: left - halfWidth,\n      right: left + halfWidth,\n      top: nodeRect.top,\n      bottom: nodeRect.bottom,\n    };\n  }\n\n  let top = before ? nodeRect.bottom : nodeRect.top;\n  if (before && after) {\n    top =\n      (top +\n        (view.nodeDOM(cursorPos.pos) as HTMLElement).getBoundingClientRect()\n          .top) /\n      2;\n  }\n  const halfHeight = (width / 2) * scaleY;\n\n  return {\n    left: nodeRect.left,\n    right: nodeRect.right,\n    top: top - halfHeight,\n    bottom: top + halfHeight,\n  };\n}\n\n/**\n * Computes the viewport rect for an inline drop cursor (vertical line within text).\n */\nexport function getInlineDropRect(\n  view: EditorView,\n  cursorPos: DropCursorPosition,\n  width: number,\n  scaleX: number,\n): Rect {\n  const coords = view.coordsAtPos(cursorPos.pos);\n  const halfWidth = (width / 2) * scaleX;\n\n  return {\n    left: coords.left - halfWidth,\n    right: coords.left + halfWidth,\n    top: coords.top,\n    bottom: coords.bottom,\n  };\n}\n\n/**\n * Applies orientation-specific CSS classes to the drop cursor element so it can be\n * styled correctly (e.g. horizontal vs vertical line, inline vs block).\n */\nexport function applyOrientationClasses(\n  el: HTMLElement,\n  orientation: DropCursorOrientation,\n) {\n  el.classList.toggle(\n    \"prosemirror-dropcursor-inline\",\n    orientation === \"inline\",\n  );\n  el.classList.toggle(\n    \"prosemirror-dropcursor-block-horizontal\",\n    orientation === \"block-horizontal\",\n  );\n  el.classList.toggle(\n    \"prosemirror-dropcursor-block-vertical-left\",\n    orientation === \"block-vertical-left\",\n  );\n  el.classList.toggle(\n    \"prosemirror-dropcursor-block-vertical-right\",\n    orientation === \"block-vertical-right\",\n  );\n  el.classList.toggle(\n    \"prosemirror-dropcursor-block\",\n    orientation === \"block-horizontal\",\n  );\n  el.classList.toggle(\n    \"prosemirror-dropcursor-vertical\",\n    orientation === \"block-vertical-left\" ||\n      orientation === \"block-vertical-right\",\n  );\n}\n\n/**\n * Returns the offset of the parent element for converting viewport coordinates to\n * parent-relative coordinates. Handles document.body and static positioning.\n */\nexport function getParentOffsets(parent: HTMLElement | null) {\n  if (\n    !parent ||\n    (parent === document.body && getComputedStyle(parent).position === \"static\")\n  ) {\n    return {\n      parentLeft: -window.pageXOffset,\n      parentTop: -window.pageYOffset,\n    };\n  }\n\n  const parentRect = parent.getBoundingClientRect();\n  const parentScaleX = parentRect.width / parent.offsetWidth;\n  const parentScaleY = parentRect.height / parent.offsetHeight;\n\n  return {\n    parentLeft: parentRect.left - parent.scrollLeft * parentScaleX,\n    parentTop: parentRect.top - parent.scrollTop * parentScaleY,\n  };\n}\n","import { dropPoint } from \"prosemirror-transform\";\nimport type { EditorView } from \"prosemirror-view\";\nimport {\n  applyOrientationClasses,\n  getBlockDropRect,\n  getInlineDropRect,\n  getParentOffsets,\n  hasExclusionClassname,\n  type DropCursorPosition,\n} from \"./utils.js\";\nimport type { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.js\";\n\nexport const DRAG_EXCLUSION_CLASSNAME = \"bn-drag-exclude\";\n\n/**\n * Context passed to the computeDropPosition hook.\n */\nexport interface ComputeDropPositionContext {\n  editor: BlockNoteEditor<any, any, any>;\n  event: DragEvent;\n  view: EditorView;\n  defaultPosition: DropCursorPosition | null;\n}\n\n/**\n * Hooks for customizing drop cursor behavior.\n */\nexport interface DropCursorHooks {\n  /**\n   * Compute cursor position and orientation.\n   * Return null to prevent dropping (no cursor shown).\n   */\n  computeDropPosition?: (\n    context: ComputeDropPositionContext,\n  ) => DropCursorPosition | null;\n}\n\n/**\n * Options for the DropCursor extension.\n */\nexport interface DropCursorOptions {\n  width?: number; // Cursor width in pixels (default: 5)\n  color?: string | false; // Cursor color (default: \"#ddeeff\")\n  exclude?: string; // CSS class for exclusion (default: \"bn-drag-exclude\")\n  hooks?: DropCursorHooks; // Optional behavior hooks\n}\n\n/**\n * Drop cursor visualization based on prosemirror-dropcursor:\n * https://github.com/ProseMirror/prosemirror-dropcursor/blob/master/src/dropcursor.ts\n *\n * Refactored to use BlockNote extension pattern with mount callback and AbortSignal\n * for lifecycle management instead of ProseMirror PluginView.\n */\nexport const DropCursorExtension = createExtension<\n  any,\n  {\n    dropCursor?: DropCursorOptions;\n  }\n>(({ editor, options }) => {\n  // State\n  let cursorPos: DropCursorPosition | null = null;\n  let element: HTMLElement | null = null;\n  let timeout = -1;\n  let dragSourceElement: Element | null = null;\n\n  const config = {\n    width: options.dropCursor?.width ?? 5,\n    color: options.dropCursor?.color ?? \"#ddeeff\",\n    exclude: options.dropCursor?.exclude ?? DRAG_EXCLUSION_CLASSNAME,\n    hooks: options.dropCursor?.hooks,\n  } as const;\n\n  // Helper functions\n  const setCursor = (pos: DropCursorPosition | null) => {\n    if (\n      pos?.pos === cursorPos?.pos &&\n      pos?.orientation === cursorPos?.orientation\n    ) {\n      return;\n    }\n    cursorPos = pos;\n\n    if (pos == null) {\n      if (element && element.parentNode) {\n        element.parentNode.removeChild(element);\n      }\n      element = null;\n    } else {\n      updateOverlay();\n    }\n  };\n\n  const updateOverlay = () => {\n    if (!cursorPos) {\n      return;\n    }\n\n    const view = editor.prosemirrorView;\n    const editorDOM = view.dom;\n    const editorRect = editorDOM.getBoundingClientRect();\n    const scaleX = editorRect.width / editorDOM.offsetWidth;\n    const scaleY = editorRect.height / editorDOM.offsetHeight;\n\n    const blockRect = getBlockDropRect(\n      view,\n      cursorPos,\n      config.width,\n      scaleX,\n      scaleY,\n    );\n    const rect =\n      blockRect ?? getInlineDropRect(view, cursorPos, config.width, scaleX);\n\n    const parent = view.dom.offsetParent as HTMLElement;\n    if (!element) {\n      element = parent.appendChild(document.createElement(\"div\"));\n      element.style.cssText =\n        \"position: absolute; z-index: 50; pointer-events: none;\";\n      if (config.color) {\n        element.style.backgroundColor = config.color;\n      }\n    }\n\n    applyOrientationClasses(element, cursorPos.orientation);\n\n    const { parentLeft, parentTop } = getParentOffsets(parent);\n\n    element.style.left = (rect.left - parentLeft) / scaleX + \"px\";\n    element.style.top = (rect.top - parentTop) / scaleY + \"px\";\n    element.style.width = (rect.right - rect.left) / scaleX + \"px\";\n    element.style.height = (rect.bottom - rect.top) / scaleY + \"px\";\n  };\n\n  const scheduleRemoval = (ms: number) => {\n    clearTimeout(timeout);\n    timeout = window.setTimeout(() => setCursor(null), ms);\n  };\n\n  // Event handlers\n  const onDragStart = (event: Event) => {\n    const e = event as DragEvent;\n    dragSourceElement = e.target instanceof Element ? e.target : null;\n  };\n\n  const onDragOver = (event: Event) => {\n    const e = event as DragEvent;\n\n    // Check if drag source has exclusion classname\n    if (\n      dragSourceElement &&\n      hasExclusionClassname(dragSourceElement, config.exclude)\n    ) {\n      return;\n    }\n\n    // Check if drop target has exclusion classname\n    if (\n      e.target instanceof Element &&\n      hasExclusionClassname(e.target, config.exclude)\n    ) {\n      return;\n    }\n\n    const view = editor.prosemirrorView;\n    if (!view.editable) {\n      return;\n    }\n\n    const pos = view.posAtCoords({\n      left: e.clientX,\n      top: e.clientY,\n    });\n\n    const node = pos && pos.inside >= 0 && view.state.doc.nodeAt(pos.inside);\n    const disableDropCursor = node && (node.type.spec as any).disableDropCursor;\n    const disabled =\n      typeof disableDropCursor === \"function\"\n        ? disableDropCursor(view, pos, e)\n        : disableDropCursor;\n\n    if (pos && !disabled) {\n      let target = pos.pos;\n      if (view.dragging && view.dragging.slice) {\n        const point = dropPoint(view.state.doc, target, view.dragging.slice);\n        if (point != null) {\n          target = point;\n        }\n      }\n\n      // Compute default position\n      const $pos = view.state.doc.resolve(target);\n      const isBlock = !$pos.parent.inlineContent;\n      const defaultPosition: DropCursorPosition = {\n        pos: target,\n        orientation: isBlock ? \"block-horizontal\" : \"inline\",\n      };\n\n      // Allow hook to override position\n      let finalPosition = defaultPosition;\n      if (config.hooks?.computeDropPosition) {\n        const hookResult = config.hooks.computeDropPosition({\n          editor,\n          event: e,\n          view,\n          defaultPosition,\n        });\n        if (hookResult === null) {\n          // Hook returned null - don't show cursor\n          setCursor(null);\n          return;\n        }\n        finalPosition = hookResult;\n      }\n\n      setCursor(finalPosition);\n      scheduleRemoval(5000);\n    }\n  };\n\n  const onDragLeave = (event: Event) => {\n    const e = event as DragEvent;\n    if (\n      !(e.relatedTarget instanceof Node) ||\n      !editor.prosemirrorView.dom.contains(e.relatedTarget)\n    ) {\n      setCursor(null);\n    }\n  };\n\n  const onDrop = () => {\n    scheduleRemoval(20);\n  };\n\n  const onDragEnd = () => {\n    scheduleRemoval(20);\n    dragSourceElement = null;\n  };\n\n  return {\n    key: \"dropCursor\",\n    mount({ signal, dom, root }) {\n      // Track drag source at document level\n      root.addEventListener(\"dragstart\", onDragStart, {\n        capture: true,\n        signal,\n      });\n\n      // Handle drag events on the editor\n      dom.addEventListener(\"dragover\", onDragOver, { signal });\n      dom.addEventListener(\"dragleave\", onDragLeave, { signal });\n      dom.addEventListener(\"drop\", onDrop, { signal });\n      dom.addEventListener(\"dragend\", onDragEnd, { signal });\n\n      // Clean up on unmount\n      signal.addEventListener(\"abort\", () => {\n        clearTimeout(timeout);\n        setCursor(null);\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 { posToDOMRect } from \"@tiptap/core\";\nimport { createExtension } from \"../../editor/BlockNoteExtension.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 getLinkAtPos(pos: number) {\n    const linkData = editor.getLinkMarkAtPos(pos);\n    if (!linkData) {\n      return undefined;\n    }\n\n    return {\n      range: { from: linkData.from, to: linkData.to },\n      // Expose mark-like attrs for backward compat with React LinkToolbarController\n      mark: { attrs: { href: linkData.href } },\n      get text() {\n        return linkData.text;\n      },\n      get position() {\n        return posToDOMRect(\n          editor.prosemirrorView,\n          linkData.from,\n          linkData.to,\n        ).toJSON() as DOMRect;\n      },\n    };\n  }\n\n  function getLinkAtSelection() {\n    return editor.transact((tr) => {\n      if (!tr.selection.empty) {\n        return undefined;\n      }\n      return getLinkAtPos(tr.selection.anchor);\n    });\n  }\n\n  return {\n    key: \"linkToolbar\",\n\n    getLinkAtSelection,\n    getLinkElementAtPos,\n    getMarkAtPos(pos: number, _markType: string) {\n      return getLinkAtPos(pos);\n    },\n\n    getLinkAtElement(element: HTMLElement) {\n      return editor.transact(() => {\n        const posAtElement = editor.prosemirrorView.posAtDOM(element, 0) + 1;\n        return getLinkAtPos(posAtElement);\n      });\n    },\n\n    editLink(\n      url: string,\n      text: string,\n      position = editor.transact((tr) => tr.selection.anchor),\n    ) {\n      editor.editLink(url, text, position);\n    },\n\n    deleteLink(position = editor.transact((tr) => tr.selection.anchor)) {\n      editor.deleteLink(position);\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.isComposing &&\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 { uuidv4 } from \"lib0/random\";\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-${uuidv4()}`;\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}:has(.ProseMirror-trailingBreak:only-child):after`;\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 { findChildrenInRange } 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) {\n              return prev;\n            }\n\n            // Only check nodes affected by the transaction, not the entire document.\n            // changedRange() is O(steps) unlike tiptap's getChangedRanges which is O(steps²).\n            const newRange = transaction.changedRange();\n            if (!newRange) {\n              return prev;\n            }\n\n            // Map the new-doc range back to old-doc coordinates\n            const invertedMapping = transaction.mapping.invert();\n            const oldRange = {\n              from: invertedMapping.map(newRange.from, -1),\n              to: invertedMapping.map(newRange.to, 1),\n            };\n\n            const currentTransactionOriginalOldBlockAttrs = {} as any;\n\n            const oldNodes = findChildrenInRange(\n              oldState.doc,\n              oldRange,\n              (node) => node.attrs.id,\n            );\n            const oldNodesById = new Map(\n              oldNodes.map((node) => [node.node.attrs.id, node]),\n            );\n            const newNodes = findChildrenInRange(\n              newState.doc,\n              newRange,\n              (node) => node.attrs.id,\n            );\n\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[\n                  node.node.attrs.id\n                ] = oldAttrs;\n\n                prev.currentTransactionOldBlockAttrs[node.node.attrs.id] =\n                  oldAttrs;\n\n                if (\n                  oldAttrs.index !== newAttrs.index ||\n                  oldAttrs.level !== newAttrs.level ||\n                  oldAttrs.type !== newAttrs.type ||\n                  oldAttrs.depth !== newAttrs.depth\n                ) {\n                  (oldAttrs as any)[\"depth-change\"] =\n                    oldAttrs.depth - newAttrs.depth;\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              decorations.push(\n                Decoration.node(pos, pos + node.nodeSize, {\n                  ...decorationAttrs,\n                }),\n              );\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","/**\n * Custom HTML-to-Markdown serializer for BlockNote.\n * Replaces the unified/rehype-remark pipeline with a direct DOM-based implementation.\n *\n * Input: HTML string from createExternalHTMLExporter\n * Output: GFM-compatible markdown string\n */\n\n/**\n * Convert an HTML string (from BlockNote's external HTML exporter) to markdown.\n */\nexport function htmlToMarkdown(html: string): string {\n  // Use a temporary element to parse HTML. This works in both browser and\n  // server (JSDOM) environments, unlike `new DOMParser()` which may not be\n  // globally available in Node.js.\n  const container = document.createElement(\"div\");\n  container.innerHTML = html;\n  const result = serializeChildren(container, {\n    indent: \"\",\n    inListItem: false,\n  });\n  return result.trim() + \"\\n\";\n}\n\ninterface SerializeContext {\n  indent: string; // current indentation prefix for list nesting\n  // True when the current node is being serialized as continuation content\n  // of a parent list item. Used to suppress trailing blank lines that would\n  // otherwise turn the parent list into a \"loose\" list.\n  inListItem: boolean;\n}\n\n// ─── Main Serializer ─────────────────────────────────────────────────────────\n\nfunction serializeChildren(node: Node, ctx: SerializeContext): string {\n  let result = \"\";\n  const children = Array.from(node.childNodes);\n\n  for (let i = 0; i < children.length; i++) {\n    const child = children[i];\n    result += serializeNode(child, ctx);\n  }\n\n  return result;\n}\n\nfunction serializeNode(node: Node, ctx: SerializeContext): string {\n  if (node.nodeType === 3 /* Node.TEXT_NODE */) {\n    return node.textContent || \"\";\n  }\n\n  if (node.nodeType !== 1 /* Node.ELEMENT_NODE */) {\n    return \"\";\n  }\n\n  const el = node as HTMLElement;\n  const tag = el.tagName.toLowerCase();\n\n  switch (tag) {\n    case \"p\":\n      return serializeParagraph(el, ctx);\n    case \"h1\":\n    case \"h2\":\n    case \"h3\":\n    case \"h4\":\n    case \"h5\":\n    case \"h6\":\n      return serializeHeading(el, ctx);\n    case \"blockquote\":\n      return serializeBlockquote(el, ctx);\n    case \"pre\":\n      return serializeCodeBlock(el, ctx);\n    case \"ul\":\n      return serializeUnorderedList(el, ctx);\n    case \"ol\":\n      return serializeOrderedList(el, ctx);\n    case \"table\":\n      return serializeTable(el, ctx);\n    case \"hr\":\n      return ctx.indent + \"***\\n\\n\";\n    case \"img\":\n      return serializeImage(el, ctx);\n    case \"video\":\n      return serializeVideo(el, ctx);\n    case \"audio\":\n      return serializeAudio(el, ctx);\n    case \"embed\":\n      return serializeEmbed(el, ctx);\n    case \"figure\":\n      return serializeFigure(el, ctx);\n    case \"a\":\n      // Block-level link (file block)\n      return serializeBlockLink(el, ctx);\n    case \"details\":\n      return serializeDetails(el, ctx);\n    case \"div\":\n      // Page break or generic container — serialize children\n      return serializeChildren(el, ctx);\n    case \"br\":\n      return \"\";\n    default:\n      return serializeChildren(el, ctx);\n  }\n}\n\n// ─── Block Serializers ───────────────────────────────────────────────────────\n\nfunction serializeParagraph(el: HTMLElement, ctx: SerializeContext): string {\n  const content = serializeInlineContent(el);\n  // Trim leading/trailing hard breaks (matching remark behavior)\n  const trimmed = trimHardBreaks(content);\n  if (ctx.inListItem) {\n    return trimmed;\n  }\n  return ctx.indent + trimmed + \"\\n\\n\";\n}\n\nfunction serializeHeading(el: HTMLElement, ctx: SerializeContext): string {\n  const level = parseInt(el.tagName[1], 10);\n  const prefix = \"#\".repeat(level) + \" \";\n  const content = serializeInlineContent(el);\n  return ctx.indent + prefix + content + \"\\n\\n\";\n}\n\nfunction serializeBlockquote(el: HTMLElement, ctx: SerializeContext): string {\n  // Check if blockquote contains block-level elements (like <p>)\n  const blockChildren = Array.from(el.children).filter((child) => {\n    const tag = child.tagName.toLowerCase();\n    return [\"p\", \"ul\", \"ol\", \"pre\", \"blockquote\", \"table\", \"hr\"].includes(tag);\n  });\n\n  let content: string;\n  if (blockChildren.length > 0) {\n    // Has block-level children — serialize each\n    const parts: string[] = [];\n    for (const child of blockChildren) {\n      const tag = child.tagName.toLowerCase();\n      if (tag === \"p\") {\n        parts.push(serializeInlineContent(child as HTMLElement));\n      } else {\n        const innerCtx: SerializeContext = { indent: \"\", inListItem: false };\n        parts.push(serializeNode(child, innerCtx).trim());\n      }\n    }\n    content = parts.join(\"\\n\\n\");\n  } else {\n    // No block-level children — treat entire content as inline\n    content = serializeInlineContent(el);\n  }\n\n  const lines = content.split(\"\\n\");\n  return lines.map((line) => ctx.indent + \"> \" + line).join(\"\\n\") + \"\\n\\n\";\n}\n\nfunction serializeCodeBlock(el: HTMLElement, ctx: SerializeContext): string {\n  const codeEl = el.querySelector(\"code\");\n  if (!codeEl) {return \"\";}\n\n  const language =\n    codeEl.getAttribute(\"data-language\") ||\n    extractLanguageFromClass(codeEl.className) ||\n    \"\";\n\n  // Extract code content, handling <br> elements as newlines\n  const code = extractCodeContent(codeEl);\n\n  // Use a fence longer than the longest backtick run in the code\n  const longestRun = Math.max(\n    0,\n    ...((code.match(/`+/g) ?? []).map((run) => run.length))\n  );\n  const fence = \"`\".repeat(Math.max(3, longestRun + 1));\n\n  // For empty code blocks, don't add a newline between the fences\n  if (!code) {\n    return ctx.indent + fence + language + \"\\n\" + fence + \"\\n\\n\";\n  }\n\n  return (\n    ctx.indent +\n    fence +\n    language +\n    \"\\n\" +\n    code +\n    (code.endsWith(\"\\n\") ? \"\" : \"\\n\") +\n    fence +\n    \"\\n\\n\"\n  );\n}\n\nfunction extractCodeContent(el: Element): string {\n  let result = \"\";\n  for (const child of Array.from(el.childNodes)) {\n    if (child.nodeType === 3 /* Node.TEXT_NODE */) {\n      result += child.textContent || \"\";\n    } else if (child.nodeType === 1 /* Node.ELEMENT_NODE */) {\n      const tag = (child as HTMLElement).tagName.toLowerCase();\n      if (tag === \"br\") {\n        result += \"\\n\";\n      } else {\n        result += extractCodeContent(child as Element);\n      }\n    }\n  }\n  return result;\n}\n\nfunction extractLanguageFromClass(className: string): string {\n  const match = className.match(/language-(\\S+)/);\n  return match ? match[1] : \"\";\n}\n\nfunction serializeUnorderedList(\n  el: HTMLElement,\n  ctx: SerializeContext\n): string {\n  let result = \"\";\n  const items = Array.from(el.children).filter(\n    (child) => child.tagName.toLowerCase() === \"li\"\n  );\n\n  for (const item of items) {\n    result += serializeListItem(item as HTMLElement, \"bullet\", ctx);\n  }\n\n  // Trailing blank line separates the list from the next block. Skip when\n  // this list is nested inside another list item — adding it would convert\n  // the parent list into a \"loose\" list (or break tightness).\n  if (!ctx.inListItem) {\n    result += \"\\n\";\n  }\n  return result;\n}\n\nfunction serializeOrderedList(el: HTMLElement, ctx: SerializeContext): string {\n  let result = \"\";\n  const items = Array.from(el.children).filter(\n    (child) => child.tagName.toLowerCase() === \"li\"\n  );\n  const startNum = parseInt(el.getAttribute(\"start\") || \"1\", 10);\n\n  for (let i = 0; i < items.length; i++) {\n    const num = startNum + i;\n    result += serializeListItem(items[i] as HTMLElement, \"ordered\", ctx, num);\n  }\n\n  if (!ctx.inListItem) {\n    result += \"\\n\";\n  }\n  return result;\n}\n\nfunction serializeListItem(\n  el: HTMLElement,\n  listType: \"bullet\" | \"ordered\",\n  ctx: SerializeContext,\n  num?: number\n): string {\n  // Check for checkbox (task list) - direct children only\n  let checkbox: HTMLInputElement | null = null;\n  let details: HTMLElement | null = null;\n\n  for (const child of Array.from(el.children)) {\n    const tag = child.tagName.toLowerCase();\n    if (tag === \"input\" && (child as HTMLInputElement).type === \"checkbox\") {\n      checkbox = child as HTMLInputElement;\n    }\n    if (tag === \"details\") {\n      details = child as HTMLElement;\n    }\n  }\n\n  let marker: string;\n  let markerWidth: number;\n\n  if (checkbox) {\n    const state = checkbox.checked ? \"[x]\" : \"[ ]\";\n    marker = `* ${state} `;\n    // For child indentation, use bullet width (2), not full checkbox marker width\n    markerWidth = 2;\n  } else if (listType === \"ordered\") {\n    marker = `${num}. `;\n    markerWidth = marker.length;\n  } else {\n    marker = \"* \";\n    markerWidth = 2;\n  }\n\n  // Collect the item's inline content\n  let inlineContent: string;\n  let firstContentEl: Element | null;\n\n  if (details) {\n    // Toggle item: get content from summary\n    const summary = details.querySelector(\"summary\");\n    const summaryP = summary?.querySelector(\"p\");\n    firstContentEl = details;\n    inlineContent = summaryP ? serializeInlineContent(summaryP) : \"\";\n  } else {\n    firstContentEl = getFirstContentElement(el, checkbox);\n    inlineContent = firstContentEl ? serializeInlineContent(firstContentEl) : \"\";\n  }\n\n  // The marker line ends with a single `\\n` so that consecutive list items\n  // produce a \"tight\" list (no blank line between markers). Continuation\n  // content within the item (nested lists, continuation paragraphs, other\n  // blocks) injects its own spacing as needed.\n  let result = ctx.indent + marker + inlineContent + \"\\n\";\n\n  // Serialize child content (nested lists, continuation paragraphs, etc.)\n  const childIndent = ctx.indent + \" \".repeat(markerWidth);\n  const childCtx: SerializeContext = { indent: childIndent, inListItem: true };\n\n  // For toggle items, also serialize children inside the details element\n  if (details) {\n    const summary = details.querySelector(\"summary\");\n    for (const child of Array.from(details.children)) {\n      if (child === summary) {continue;}\n      const childTag = child.tagName.toLowerCase();\n      if (childTag === \"p\") {\n        const content = serializeInlineContent(child as HTMLElement);\n        // Continuation paragraph needs a blank line to separate it from the\n        // previous content; CommonMark would otherwise treat it as a soft\n        // wrap of that content.\n        result += \"\\n\" + childIndent + content + \"\\n\";\n      } else {\n        result += serializeNode(child, childCtx);\n      }\n    }\n  }\n\n  const children = Array.from(el.children);\n  for (const child of children) {\n    const childTag = child.tagName.toLowerCase();\n\n    // Skip the first content element and checkbox\n    if (child === firstContentEl || (child as HTMLElement) === checkbox) {continue;}\n    if (childTag === \"input\") {continue;}\n\n    // Nested lists and other block content\n    if (childTag === \"ul\" || childTag === \"ol\") {\n      // Nested list flows directly under the parent marker — no blank line.\n      result += serializeNode(child, childCtx);\n    } else if (childTag === \"p\") {\n      // Continuation paragraph within list item — requires blank line before\n      // so it isn't read as part of the marker line's text.\n      const content = serializeInlineContent(child as HTMLElement);\n      result += \"\\n\" + childIndent + content + \"\\n\";\n    } else {\n      // Other block-level children (code blocks, blockquotes, etc.) already\n      // emit their own separating newlines; prefix with a blank line so they\n      // are recognized as separate blocks.\n      result += \"\\n\" + serializeNode(child, childCtx);\n    }\n  }\n\n  return result;\n}\n\nfunction getFirstContentElement(\n  li: HTMLElement,\n  checkbox: HTMLInputElement | null\n): HTMLElement | null {\n  for (const child of Array.from(li.children)) {\n    if (child === checkbox) {continue;}\n    if (child.tagName.toLowerCase() === \"input\") {continue;}\n    const tag = child.tagName.toLowerCase();\n    if (tag === \"p\" || tag === \"span\") {return child as HTMLElement;}\n  }\n  return null;\n}\n\n// ─── Table Serializer ────────────────────────────────────────────────────────\n\nfunction serializeTable(el: HTMLElement, ctx: SerializeContext): string {\n  // First, determine column count from colgroup or first row\n  const colgroup = el.querySelector(\"colgroup\");\n  let colCount = 0;\n\n  if (colgroup) {\n    colCount = colgroup.querySelectorAll(\"col\").length;\n  }\n\n  const rows: string[][] = [];\n  let hasHeader = false;\n\n  // Collect all rows, handling colspan/rowspan\n  const trElements = el.querySelectorAll(\"tr\");\n  // Build a grid to handle colspan/rowspan\n  const grid: (string | null)[][] = [];\n\n  trElements.forEach((tr, rowIdx) => {\n    if (!grid[rowIdx]) {grid[rowIdx] = [];}\n    const cellElements = tr.querySelectorAll(\"th, td\");\n    let gridCol = 0;\n\n    cellElements.forEach((cell) => {\n      // Find next empty column in this row\n      while (grid[rowIdx][gridCol] !== undefined) {gridCol++;}\n\n      if (rowIdx === 0 && cell.tagName.toLowerCase() === \"th\") {\n        hasHeader = true;\n      }\n\n      const content = escapeTableCell(\n        serializeInlineContent(cell as HTMLElement).trim()\n      );\n      const colspan = parseInt(cell.getAttribute(\"colspan\") || \"1\", 10);\n      const rowspan = parseInt(cell.getAttribute(\"rowspan\") || \"1\", 10);\n\n      // Fill the grid\n      for (let r = 0; r < rowspan; r++) {\n        for (let c = 0; c < colspan; c++) {\n          const ri = rowIdx + r;\n          if (!grid[ri]) {grid[ri] = [];}\n          grid[ri][gridCol + c] = r === 0 && c === 0 ? content : \"\";\n        }\n      }\n\n      gridCol += colspan;\n    });\n\n    // Update colCount\n    if (grid[rowIdx]) {\n      colCount = Math.max(colCount, grid[rowIdx].length);\n    }\n  });\n\n  // Convert grid to rows\n  for (const gridRow of grid) {\n    const row: string[] = [];\n    for (let c = 0; c < colCount; c++) {\n      row.push(gridRow && gridRow[c] !== undefined ? (gridRow[c] ?? \"\") : \"\");\n    }\n    rows.push(row);\n  }\n\n  if (rows.length === 0) {return \"\";}\n\n  // Determine column widths\n  const colWidths: number[] = [];\n  for (let c = 0; c < colCount; c++) {\n    let maxWidth = 3; // minimum width for separator \"---\"\n    for (const row of rows) {\n      const cellWidth = c < row.length ? row[c].length : 0;\n      maxWidth = Math.max(maxWidth, cellWidth);\n    }\n    // Use minimum of 10 to match remark output\n    colWidths.push(Math.max(maxWidth, 10));\n  }\n\n  let result = \"\";\n\n  if (hasHeader) {\n    result += ctx.indent + formatTableRow(rows[0], colWidths, colCount) + \"\\n\";\n    result += ctx.indent + formatSeparatorRow(colWidths, colCount) + \"\\n\";\n    for (let r = 1; r < rows.length; r++) {\n      result +=\n        ctx.indent + formatTableRow(rows[r], colWidths, colCount) + \"\\n\";\n    }\n  } else {\n    // No header — emit empty header + separator\n    const emptyRow = new Array(colCount).fill(\"\");\n    result += ctx.indent + formatTableRow(emptyRow, colWidths, colCount) + \"\\n\";\n    result += ctx.indent + formatSeparatorRow(colWidths, colCount) + \"\\n\";\n    for (const row of rows) {\n      result +=\n        ctx.indent + formatTableRow(row, colWidths, colCount) + \"\\n\";\n    }\n  }\n\n  result += \"\\n\";\n  return result;\n}\n\nfunction escapeTableCell(text: string): string {\n  return text.replace(/\\|/g, \"\\\\|\");\n}\n\nfunction formatTableRow(\n  cells: string[],\n  colWidths: number[],\n  colCount: number\n): string {\n  const parts: string[] = [];\n  for (let c = 0; c < colCount; c++) {\n    const cell = c < cells.length ? cells[c] : \"\";\n    parts.push(\" \" + cell.padEnd(colWidths[c]) + \" \");\n  }\n  return \"|\" + parts.join(\"|\") + \"|\";\n}\n\nfunction formatSeparatorRow(colWidths: number[], colCount: number): string {\n  const parts: string[] = [];\n  for (let c = 0; c < colCount; c++) {\n    parts.push(\" \" + \"-\".repeat(colWidths[c]) + \" \");\n  }\n  return \"|\" + parts.join(\"|\") + \"|\";\n}\n\n// ─── Media Serializers ───────────────────────────────────────────────────────\n\nfunction serializeImage(el: HTMLElement, ctx: SerializeContext): string {\n  const src = el.getAttribute(\"src\") || \"\";\n  const alt = el.getAttribute(\"alt\") || \"\";\n  // Empty placeholder — preserve the block-level break, matching how\n  // serializeParagraph/serializeHeading emit `\\n\\n` for empty content.\n  if (!src) {return \"\\n\\n\";}\n  return ctx.indent + `![${alt}](${src})\\n\\n`;\n}\n\nfunction serializeVideo(el: HTMLElement, ctx: SerializeContext): string {\n  const src =\n    el.getAttribute(\"src\") || el.getAttribute(\"data-url\") || \"\";\n  const name = el.getAttribute(\"data-name\") || el.getAttribute(\"title\") || \"\";\n  if (!src) {return \"\\n\\n\";}\n  return ctx.indent + `![${name}](${src})\\n\\n`;\n}\n\nfunction serializeAudio(el: HTMLElement, ctx: SerializeContext): string {\n  const src = el.getAttribute(\"src\") || \"\";\n  if (!src) {return \"\\n\\n\";}\n  // Audio has no markdown syntax, so emit raw HTML. The markdown parser\n  // passes <audio> blocks through verbatim and BlockNote's audio block parser\n  // recognizes them, giving a clean round-trip.\n  return ctx.indent + `<audio src=\"${escapeHtmlAttr(src)}\" controls></audio>\\n\\n`;\n}\n\nfunction serializeEmbed(el: HTMLElement, ctx: SerializeContext): string {\n  const src = el.getAttribute(\"src\") || \"\";\n  if (!src) {return \"\\n\\n\";}\n  return ctx.indent + `[](${src})\\n\\n`;\n}\n\nfunction serializeFigure(el: HTMLElement, ctx: SerializeContext): string {\n  const img = el.querySelector(\"img\");\n  const video = el.querySelector(\"video\");\n  const audio = el.querySelector(\"audio\");\n  const link = el.querySelector(\"a\");\n\n  const figcaption = el.querySelector(\"figcaption\");\n  const captionText = figcaption?.textContent?.trim() || \"\";\n\n  if (img) {\n    return serializeMediaFigure(\n      \"img\",\n      img.getAttribute(\"src\") || \"\",\n      img.getAttribute(\"alt\") || \"\",\n      captionText,\n      ctx,\n    );\n  }\n  if (video) {\n    const src =\n      video.getAttribute(\"src\") || video.getAttribute(\"data-url\") || \"\";\n    const name =\n      video.getAttribute(\"data-name\") || video.getAttribute(\"title\") || \"\";\n    return serializeMediaFigure(\"video\", src, name, captionText, ctx);\n  }\n  if (audio) {\n    return serializeMediaFigure(\n      \"audio\",\n      audio.getAttribute(\"src\") || \"\",\n      \"\",\n      captionText,\n      ctx,\n    );\n  }\n  if (link) {\n    return serializeBlockLink(link as HTMLElement, ctx);\n  }\n  return \"\";\n}\n\nfunction serializeMediaFigure(\n  kind: \"img\" | \"video\" | \"audio\",\n  src: string,\n  descriptor: string,\n  captionText: string,\n  ctx: SerializeContext,\n): string {\n  if (!src) {return \"\";}\n\n  // No caption + has a markdown shorthand → use it.\n  if (!captionText && kind !== \"audio\") {\n    return ctx.indent + `![${descriptor}](${src})\\n\\n`;\n  }\n\n  // The descriptor (alt / data-name) is dropped when it duplicates the\n  // caption text; otherwise on round-trip both `name` and `caption` would\n  // get set to the same string (BlockNote's HTML exporter writes alt =\n  // name || caption, so a caption-only image has alt === figcaption text).\n  const showDescriptor = descriptor && descriptor !== captionText;\n  const descAttr =\n    !showDescriptor\n      ? \"\"\n      : kind === \"img\"\n        ? ` alt=\"${escapeHtmlAttr(descriptor)}\"`\n        : kind === \"video\"\n          ? ` data-name=\"${escapeHtmlAttr(descriptor)}\"`\n          : \"\";\n\n  const tag =\n    kind === \"img\"\n      ? `<img${descAttr} src=\"${escapeHtmlAttr(src)}\">`\n      : `<${kind} src=\"${escapeHtmlAttr(src)}\"${descAttr} controls></${kind}>`;\n\n  const captionPart = captionText\n    ? `<figcaption>${escapeHtmlText(captionText)}</figcaption>`\n    : \"\";\n  return ctx.indent + `<figure>${tag}${captionPart}</figure>\\n\\n`;\n}\n\nfunction escapeHtmlAttr(value: string): string {\n  return value\n    .replace(/&/g, \"&amp;\")\n    .replace(/\"/g, \"&quot;\")\n    .replace(/</g, \"&lt;\")\n    .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeHtmlText(value: string): string {\n  return value\n    .replace(/&/g, \"&amp;\")\n    .replace(/</g, \"&lt;\")\n    .replace(/>/g, \"&gt;\");\n}\n\nfunction serializeBlockLink(el: HTMLElement, ctx: SerializeContext): string {\n  const href = el.getAttribute(\"href\") || \"\";\n  const text = el.textContent?.trim() || \"\";\n  if (!href) {return ctx.indent + text + \"\\n\\n\";}\n  return ctx.indent + formatLink(text, href) + \"\\n\\n\";\n}\n\n/**\n * Render a link, mirroring the remark-stringify behavior from\n * TypeCellOS/BlockNote#2661: when the link label equals the URL (or is\n * empty), emit the bare URL so that pasting the link into another input\n * produces a valid href instead of `<url>`-autolink brackets or redundant\n * `[url](url)` markup. Otherwise emit `[text](url)` with the URL escaped so\n * a `)` inside the URL does not prematurely close the destination.\n */\nfunction formatLink(text: string, href: string): string {\n  if (!text || text === href) {\n    return href;\n  }\n  return `[${text}](${escapeLinkDestination(href)})`;\n}\n\nfunction escapeLinkDestination(url: string): string {\n  return url.replace(/[\\\\()]/g, \"\\\\$&\");\n}\n\nfunction serializeDetails(el: HTMLElement, ctx: SerializeContext): string {\n  // Toggle heading or toggle list item\n  const summary = el.querySelector(\"summary\");\n  if (!summary) {return serializeChildren(el, ctx);}\n\n  // Check if summary contains a heading\n  const heading = summary.querySelector(\"h1, h2, h3, h4, h5, h6\");\n  if (heading) {\n    let result = serializeHeading(heading as HTMLElement, ctx);\n    // Also serialize non-summary children of details\n    for (const child of Array.from(el.children)) {\n      if (child !== summary) {\n        result += serializeNode(child, ctx);\n      }\n    }\n    return result;\n  }\n\n  // Otherwise serialize the summary content\n  return serializeChildren(summary, ctx);\n}\n\n// ─── Inline Content Serializer ───────────────────────────────────────────────\n\nfunction serializeInlineContent(el: Element): string {\n  let result = \"\";\n\n  for (const child of Array.from(el.childNodes)) {\n    if (child.nodeType === 3 /* Node.TEXT_NODE */) {\n      result += child.textContent || \"\";\n    } else if (child.nodeType === 1 /* Node.ELEMENT_NODE */) {\n      const childEl = child as HTMLElement;\n      const tag = childEl.tagName.toLowerCase();\n\n      switch (tag) {\n        case \"strong\":\n        case \"b\": {\n          const inner = serializeInlineContent(childEl);\n          const { content, trailing } = extractTrailingWhitespace(inner);\n          if (content) {\n            result += `**${content}**${trailing}`;\n          } else {\n            // All whitespace — just output it without emphasis\n            result += trailing;\n          }\n          break;\n        }\n        case \"em\":\n        case \"i\": {\n          const inner = serializeInlineContent(childEl);\n          const { content, trailing } = extractTrailingWhitespace(inner);\n          if (content) {\n            result += `*${content}*${trailing}`;\n          } else {\n            result += trailing;\n          }\n          break;\n        }\n        case \"s\":\n        case \"del\":\n          result += `~~${serializeInlineContent(childEl)}~~`;\n          break;\n        case \"code\": {\n          const text = childEl.textContent || \"\";\n          const longestRun = Math.max(\n            0,\n            ...((text.match(/`+/g) ?? []).map((run) => run.length))\n          );\n          const fence = \"`\".repeat(longestRun + 1);\n          const needsPadding =\n            text.startsWith(\"`\") || text.endsWith(\"`\");\n          result += fence + (needsPadding ? ` ${text} ` : text) + fence;\n          break;\n        }\n        case \"u\":\n          // No markdown equivalent — strip the tag, keep content\n          result += serializeInlineContent(childEl);\n          break;\n        case \"a\": {\n          const href = childEl.getAttribute(\"href\") || \"\";\n          const text = serializeInlineContent(childEl);\n          result += formatLink(text, href);\n          break;\n        }\n        case \"br\":\n          result += \"\\\\\\n\";\n          break;\n        case \"span\":\n          // Color spans, etc. — strip the tag, keep content\n          result += serializeInlineContent(childEl);\n          break;\n        case \"img\": {\n          const src = childEl.getAttribute(\"src\") || \"\";\n          const alt = childEl.getAttribute(\"alt\") || \"\";\n          result += `![${alt}](${src})`;\n          break;\n        }\n        case \"video\": {\n          const src =\n            childEl.getAttribute(\"src\") ||\n            childEl.getAttribute(\"data-url\") ||\n            \"\";\n          const name =\n            childEl.getAttribute(\"data-name\") ||\n            childEl.getAttribute(\"title\") ||\n            \"\";\n          result += `![${name}](${src})`;\n          break;\n        }\n        case \"p\":\n          // Paragraph inside inline context (e.g., table cell)\n          result += serializeInlineContent(childEl);\n          break;\n        case \"input\":\n          // Checkbox in task list — handled at block level\n          break;\n        default:\n          result += serializeInlineContent(childEl);\n          break;\n      }\n    }\n  }\n\n  return result;\n}\n\n/**\n * Extract trailing whitespace from emphasis content.\n * Moves trailing spaces outside the emphasis delimiters to produce valid markdown.\n * E.g., `<strong>Bold </strong>` → `**Bold** ` instead of `**Bold **`.\n */\nfunction extractTrailingWhitespace(text: string): {\n  content: string;\n  trailing: string;\n} {\n  const match = text.match(/^(.*?)(\\s*)$/);\n  if (match) {\n    return { content: match[1], trailing: match[2] };\n  }\n  return { content: text, trailing: \"\" };\n}\n\n/**\n * Escape leading character after emphasis if it could break parsing.\n * For example, \"Heading\" after \"**Bold **\" — the 'H' should be escaped\n * if the trailing space was escaped.\n */\n\n/**\n * Trim leading/trailing hard breaks from inline content.\n * Matches remark behavior where <br> at start/end of paragraph is dropped.\n */\nfunction trimHardBreaks(content: string): string {\n  // Remove leading hard breaks\n  let result = content.replace(/^(\\\\\\n)+/, \"\");\n  // Remove trailing hard breaks produced by `<br>`\n  result = result.replace(/(\\\\\\n)+$/, \"\");\n  return result;\n}\n","import { Schema } from \"prosemirror-model\";\n\nimport { PartialBlock } from \"../../../blocks/defaultBlocks.js\";\nimport type { BlockNoteEditor } from \"../../../editor/BlockNoteEditor.js\";\nimport {\n  BlockSchema,\n  InlineContentSchema,\n  StyleSchema,\n} from \"../../../schema/index.js\";\nimport { createExternalHTMLExporter } from \"../html/externalHTMLExporter.js\";\nimport { htmlToMarkdown } from \"./htmlToMarkdown.js\";\n\n// Needs to be sync because it's used in drag handler event (SideMenuPlugin)\nexport function cleanHTMLToMarkdown(cleanHTMLString: string) {\n  return htmlToMarkdown(cleanHTMLString);\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 embedded documents\n  // (iframe/embed/object) anyway, and including an <embed> (e.g. a PDF)\n  // can prevent the drag from initiating at all.\n  const embeddedDocs = dragImageElement.querySelectorAll(\n    \"iframe, embed, object\",\n  );\n  embeddedDocs.forEach((el) => el.parentElement?.removeChild(el));\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    // Relevance gate: Only handle drags that belong to BlockNote\n    // This prevents interference with external drag-and-drop libraries\n    // by avoiding calls to closeDropCursor() for non-BlockNote drags\n    const isBlockNoteDrag =\n      this.pmView.dragging !== null ||\n      this.isDragOrigin ||\n      event.dataTransfer?.types.includes(\"blocknote/html\") ||\n      (event.target instanceof Node && this.pmView.dom.contains(event.target));\n\n    if (!isBlockNoteDrag) {\n      // Not a BlockNote-related drag, return early without any processing\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    // Relevance gate: Only handle drags that belong to BlockNote\n    // Check if at least one of the following is true:\n    // 1. ProseMirror drag started in an editor\n    // 2. Side menu drag\n    // 3. BlockNote-specific data type in the drag\n    // 4. (optional stricter mode) Event target is inside this editor\n    const isBlockNoteDrag =\n      this.pmView.dragging !== null ||\n      this.isDragOrigin ||\n      event.dataTransfer?.types.includes(\"blocknote/html\") ||\n      (event.target instanceof Node && this.pmView.dom.contains(event.target));\n\n    if (!isBlockNoteDrag) {\n      // Not a BlockNote-related drag, return early\n      return undefined;\n    }\n\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    // Relevance gate: Only handle drags that belong to BlockNote\n    // This prevents interference with external drag-and-drop libraries\n    const isBlockNoteDrag =\n      this.pmView.dragging !== null ||\n      this.isDragOrigin ||\n      event.dataTransfer?.types.includes(\"blocknote/html\") ||\n      (event.target instanceof Node && this.pmView.dom.contains(event.target));\n\n    if (!isBlockNoteDrag) {\n      // Not a BlockNote-related drag, return early without any processing\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    // 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 this editor and its portaled UI\n      !this.editor.isWithinEditor(event.target as HTMLElement)\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\n    /**\n     * Hides the side menu unless it is currently frozen (e.g. the drag\n     * handle menu is open). Used to dismiss the menu on scroll without\n     * interfering with open submenus.\n     */\n    hideMenuIfNotFrozen() {\n      if (!view!.menuFrozen && view!.state?.show) {\n        view!.state.show = false;\n        view!.emitUpdate(view!.state!);\n      }\n    },\n  } as const;\n});\n","import type { Emoji, EmojiMartData } from \"@emoji-mart/data\";\n\nimport { defaultInlineContentSchema } from \"../../blocks/defaultBlocks.js\";\nimport { BlockNoteEditor } from \"../../editor/BlockNoteEditor.js\";\nimport {\n  BlockSchema,\n  InlineContentSchema,\n  StyleSchema,\n} from \"../../schema/index.js\";\nimport { DefaultGridSuggestionItem } from \"./DefaultGridSuggestionItem.js\";\n\n// Temporary fix for https://github.com/missive/emoji-mart/pull/929\nlet emojiLoadingPromise:\n  | Promise<{\n      emojiMart: typeof import(\"emoji-mart\");\n      emojiData: EmojiMartData;\n    }>\n  | undefined;\n\nasync function loadEmojiMart() {\n  if (emojiLoadingPromise) {\n    return emojiLoadingPromise;\n  }\n\n  emojiLoadingPromise = (async () => {\n    // load dynamically because emoji-mart doesn't specify type: module and breaks in nodejs\n    const [emojiMartModule, emojiDataModule] = await Promise.all([\n      import(\"emoji-mart\"),\n      // use a dynamic import to encourage bundle-splitting\n      // and a smaller initial client bundle size\n      import(\"@emoji-mart/data\"),\n    ]);\n\n    const emojiMart =\n      \"default\" in emojiMartModule ? emojiMartModule.default : emojiMartModule;\n    const emojiData =\n      \"default\" in emojiDataModule\n        ? (emojiDataModule.default as EmojiMartData)\n        : (emojiDataModule as EmojiMartData);\n\n    await emojiMart.init({ data: emojiData });\n\n    return { emojiMart, emojiData };\n  })();\n\n  return emojiLoadingPromise;\n}\n\nexport async function getDefaultEmojiPickerItems<\n  BSchema extends BlockSchema,\n  I extends InlineContentSchema,\n  S extends StyleSchema,\n>(\n  editor: BlockNoteEditor<BSchema, I, S>,\n  query: string,\n): Promise<DefaultGridSuggestionItem[]> {\n  if (\n    !(\"text\" in editor.schema.inlineContentSchema) ||\n    editor.schema.inlineContentSchema[\"text\"] !==\n      defaultInlineContentSchema[\"text\"]\n  ) {\n    return [];\n  }\n\n  const { emojiData, emojiMart } = await loadEmojiMart();\n\n  const emojisToShow =\n    query.trim() === \"\"\n      ? Object.values(emojiData.emojis)\n      : ((await emojiMart!.SearchIndex.search(query)) as Emoji[]);\n\n  return emojisToShow.map((emoji) => ({\n    id: emoji.skins[0].native,\n    onItemClick: () => editor.insertInlineContent(emoji.skins[0].native + \" \"),\n  }));\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      const hideHandles =\n        // always hide handles when the actively hovered table changed\n        this.state?.block.id !== tableBlock.id ||\n        // make sure we don't hide existing handles (keep col / row index) when\n        // we're hovering just above or to the right of a table\n        event.clientX > tableRect.right ||\n        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    // Clear so a re-dispatched drop short-circuits above (issue #2691).\n    this.state.draggingState = undefined;\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    /**\n     * Hides the table handles unless they are currently frozen (e.g. a\n     * handle menu is open). Used to dismiss the handles on scroll without\n     * interfering with open submenus.\n     */\n    hideHandlesIfNotFrozen() {\n      if (!view!.menuFrozen && view!.state?.show) {\n        view!.state.show = false;\n        view!.state.showAddOrRemoveRowsButton = false;\n        view!.state.showAddOrRemoveColumnsButton = false;\n        view!.emitUpdate();\n      }\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 type { Node as PMNode } from \"prosemirror-model\";\nimport { Plugin, PluginKey, type Transaction } from \"prosemirror-state\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\nimport {\n  createExtension,\n  ExtensionOptions,\n} from \"../../editor/BlockNoteExtension.js\";\n\nconst PLUGIN_KEY = new PluginKey<DecorationSet>(\"trailingNode\");\n\n// Skip the widget when the editor isn't editable, or when the document already\n// ends with an empty paragraph block (since the user can just type into it).\nfunction shouldShowTrailingWidget(doc: PMNode, isEditable: boolean): boolean {\n  if (!isEditable) {\n    return false;\n  }\n\n  const rootGroup = doc.lastChild;\n  const lastBlock = rootGroup?.lastChild;\n  const lastContent = lastBlock?.firstChild;\n\n  return !(\n    lastBlock?.type.name === \"blockContainer\" &&\n    lastContent?.type.name === \"paragraph\" &&\n    lastContent.content.size === 0\n  );\n}\n\n/**\n * Renders a fake trailing block as a widget decoration after the last block of\n * the document. Clicking it inserts a real trailing block and moves the\n * selection into it. This way the trailing block is not part of the document\n * content, so it doesn't appear when the editor is read-only or when the\n * content is exported.\n */\nexport const TrailingNodeExtension = createExtension(\n  ({ editor }: ExtensionOptions) => {\n    function createTrailingWidget(pos: number): Decoration {\n      return Decoration.widget(\n        pos,\n        () => {\n          const el = document.createElement(\"div\");\n          el.className = \"bn-trailing-block\";\n          el.contentEditable = \"false\";\n          el.addEventListener(\"mousedown\", (event) => {\n            // Stop ProseMirror from trying to place the selection somewhere\n            // based on this click.\n            event.preventDefault();\n\n            editor.transact((tr) => {\n              const [insertedBlock] = editor.insertBlocks(\n                [{ type: \"paragraph\" }],\n                editor.document[editor.document.length - 1],\n                \"after\",\n              );\n              editor.setTextCursorPosition(insertedBlock, \"start\");\n              tr.scrollIntoView();\n            });\n\n            editor.prosemirrorView?.focus();\n          });\n          return el;\n        },\n        { side: 1 },\n      );\n    }\n\n    // Maps the existing DecorationSet through the transaction, then\n    // incrementally adds or removes the widget only if the show/hide state\n    // crossed over. The underlying Decoration (and its rendered DOM) stays\n    // reference-stable across transactions.\n    function nextDecorationSet(\n      tr: Transaction,\n      oldSet: DecorationSet,\n      isEditable: boolean,\n    ): DecorationSet {\n      const mapped = oldSet.map(tr.mapping, tr.doc);\n      const existing = mapped.find();\n      const wasShowing = existing.length > 0;\n      const shouldShow = shouldShowTrailingWidget(tr.doc, isEditable);\n\n      if (wasShowing === shouldShow) {\n        return mapped;\n      }\n      if (wasShowing) {\n        return mapped.remove(existing);\n      }\n      return mapped.add(tr.doc, [\n        createTrailingWidget(tr.doc.content.size - 1),\n      ]);\n    }\n\n    return {\n      key: \"trailingNode\",\n      prosemirrorPlugins: [\n        new Plugin<DecorationSet>({\n          key: PLUGIN_KEY,\n          state: {\n            init: (_, state) =>\n              nextDecorationSet(\n                state.tr,\n                DecorationSet.empty,\n                editor.isEditable,\n              ),\n            apply: (tr, oldSet) => {\n              if (!tr.docChanged && !tr.getMeta(PLUGIN_KEY)) {\n                return oldSet;\n              }\n              return nextDecorationSet(tr, oldSet, editor.isEditable);\n            },\n          },\n          // Editable changes don't dispatch a transaction on their own, so the\n          // plugin state can't re-evaluate on its own. Watch for the change\n          // and dispatch a no-op transaction tagged with this plugin's key so\n          // `apply` re-runs and adds or removes the widget.\n          view(view) {\n            let lastEditable = view.editable;\n            return {\n              update(view) {\n                if (view.editable === lastEditable) {\n                  return;\n                }\n                lastEditable = view.editable;\n                view.dispatch(view.state.tr.setMeta(PLUGIN_KEY, true));\n              },\n            };\n          },\n          props: {\n            decorations: (state) => PLUGIN_KEY.getState(state),\n          },\n        }),\n      ],\n    } as const;\n  },\n);\n"],"mappings":"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"}