@blocknote/core 0.29.1 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +125 -0
  2. package/dist/blocknote.cjs +9 -9
  3. package/dist/blocknote.cjs.map +1 -1
  4. package/dist/blocknote.js +1501 -1359
  5. package/dist/blocknote.js.map +1 -1
  6. package/dist/comments.cjs.map +1 -1
  7. package/dist/comments.js.map +1 -1
  8. package/dist/locales.cjs +1 -1
  9. package/dist/locales.cjs.map +1 -1
  10. package/dist/locales.js +751 -9
  11. package/dist/locales.js.map +1 -1
  12. package/dist/style.css +1 -1
  13. package/dist/tsconfig.tsbuildinfo +1 -1
  14. package/dist/webpack-stats.json +1 -1
  15. package/package.json +7 -8
  16. package/src/api/README.md +1 -1
  17. package/src/api/blockManipulation/commands/insertBlocks/__snapshots__/insertBlocks.test.ts.snap +0 -7
  18. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.test.ts +19 -14
  19. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +5 -5
  20. package/src/api/blockManipulation/commands/mergeBlocks/__snapshots__/mergeBlocks.test.ts.snap +0 -5
  21. package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts +3 -3
  22. package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts +12 -12
  23. package/src/api/blockManipulation/commands/moveBlocks/__snapshots__/moveBlocks.test.ts.snap +0 -20
  24. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.ts +14 -14
  25. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts +16 -16
  26. package/src/api/blockManipulation/commands/nestBlock/nestBlock.ts +8 -8
  27. package/src/api/blockManipulation/commands/replaceBlocks/__snapshots__/replaceBlocks.test.ts.snap +0 -12
  28. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.test.ts +12 -12
  29. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +7 -7
  30. package/src/api/blockManipulation/commands/splitBlock/__snapshots__/splitBlock.test.ts.snap +0 -6
  31. package/src/api/blockManipulation/commands/splitBlock/splitBlock.test.ts +10 -10
  32. package/src/api/blockManipulation/commands/splitBlock/splitBlock.ts +2 -2
  33. package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +0 -17
  34. package/src/api/blockManipulation/commands/updateBlock/updateBlock.test.ts +42 -42
  35. package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +18 -18
  36. package/src/api/blockManipulation/getBlock/getBlock.ts +9 -9
  37. package/src/api/blockManipulation/insertContentAt.ts +1 -1
  38. package/src/api/blockManipulation/selections/selection.ts +11 -11
  39. package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.ts +7 -7
  40. package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts +6 -6
  41. package/src/api/blockManipulation/tables/tables.test.ts +106 -106
  42. package/src/api/blockManipulation/tables/tables.ts +35 -35
  43. package/src/api/clipboard/fromClipboard/fileDropExtension.ts +2 -2
  44. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +9 -9
  45. package/src/api/clipboard/fromClipboard/handleVSCodePaste.ts +3 -3
  46. package/src/api/clipboard/fromClipboard/pasteExtension.ts +21 -3
  47. package/src/api/clipboard/toClipboard/copyExtension.ts +22 -22
  48. package/src/api/exporters/html/externalHTMLExporter.ts +6 -6
  49. package/src/api/exporters/html/internalHTMLSerializer.ts +3 -3
  50. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +16 -16
  51. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +14 -14
  52. package/src/api/exporters/markdown/markdownExporter.ts +3 -3
  53. package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +3 -3
  54. package/src/api/getBlockInfoFromPos.ts +6 -6
  55. package/src/api/nodeConversions/blockToNode.ts +26 -26
  56. package/src/api/nodeConversions/fragmentToBlocks.ts +1 -1
  57. package/src/api/nodeConversions/nodeToBlock.ts +37 -33
  58. package/src/api/nodeUtil.test.ts +16 -16
  59. package/src/api/nodeUtil.ts +10 -10
  60. package/src/api/parsers/html/parseHTML.ts +1 -1
  61. package/src/api/parsers/html/util/nestedLists.ts +2 -2
  62. package/src/api/parsers/markdown/parseMarkdown.ts +1 -1
  63. package/src/api/pmUtil.ts +4 -4
  64. package/src/api/positionMapping.test.ts +3 -3
  65. package/src/api/positionMapping.ts +5 -5
  66. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +9 -4
  67. package/src/blocks/CodeBlockContent/CodeBlockContent.ts +40 -26
  68. package/src/blocks/FileBlockContent/FileBlockContent.ts +7 -2
  69. package/src/blocks/FileBlockContent/helpers/parse/parseFigureElement.ts +2 -2
  70. package/src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts +5 -5
  71. package/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts +2 -2
  72. package/src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.ts +1 -1
  73. package/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts +15 -8
  74. package/src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.ts +1 -1
  75. package/src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.ts +1 -1
  76. package/src/blocks/FileBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts +2 -2
  77. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +9 -6
  78. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +14 -6
  79. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +13 -29
  80. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +24 -13
  81. package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +1 -1
  82. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +1 -1
  83. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +13 -30
  84. package/src/blocks/ListItemBlockContent/getListItemContent.ts +115 -0
  85. package/src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts +1 -1
  86. package/src/blocks/PageBreakBlockContent/getPageBreakSlashMenuItems.ts +3 -3
  87. package/src/blocks/PageBreakBlockContent/schema.ts +2 -2
  88. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +9 -5
  89. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +10 -5
  90. package/src/blocks/README.md +1 -1
  91. package/src/blocks/TableBlockContent/TableBlockContent.ts +76 -19
  92. package/src/blocks/TableBlockContent/TableExtension.ts +3 -3
  93. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +14 -6
  94. package/src/blocks/defaultBlockHelpers.ts +24 -8
  95. package/src/blocks/defaultBlockTypeGuards.ts +16 -16
  96. package/src/blocks/defaultBlocks.ts +3 -3
  97. package/src/comments/threadstore/DefaultThreadStoreAuth.ts +3 -3
  98. package/src/comments/threadstore/ThreadStore.ts +1 -1
  99. package/src/comments/threadstore/TipTapThreadStore.ts +10 -10
  100. package/src/comments/threadstore/yjs/RESTYjsThreadStore.ts +4 -4
  101. package/src/comments/threadstore/yjs/YjsThreadStore.test.ts +2 -2
  102. package/src/comments/threadstore/yjs/YjsThreadStore.ts +14 -14
  103. package/src/comments/threadstore/yjs/YjsThreadStoreBase.ts +1 -1
  104. package/src/comments/threadstore/yjs/yjsHelpers.ts +6 -6
  105. package/src/editor/Block.css +10 -1
  106. package/src/editor/BlockNoteEditor.test.ts +3 -3
  107. package/src/editor/BlockNoteEditor.ts +110 -61
  108. package/src/editor/BlockNoteExtensions.ts +24 -15
  109. package/src/editor/BlockNoteSchema.ts +4 -4
  110. package/src/editor/BlockNoteTipTapEditor.ts +10 -10
  111. package/src/editor/README.md +1 -1
  112. package/src/editor/cursorPositionTypes.ts +1 -1
  113. package/src/editor/editor.css +15 -3
  114. package/src/editor/selectionTypes.ts +1 -1
  115. package/src/editor/transformPasted.ts +2 -2
  116. package/src/exporter/Exporter.ts +5 -5
  117. package/src/exporter/mapping.ts +7 -7
  118. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +1 -1
  119. package/src/extensions/Collaboration/CursorPlugin.ts +152 -0
  120. package/src/extensions/Collaboration/SyncPlugin.ts +15 -0
  121. package/src/extensions/Collaboration/UndoPlugin.ts +14 -0
  122. package/src/extensions/Comments/CommentsPlugin.ts +9 -9
  123. package/src/extensions/Comments/userstore/UserStore.ts +2 -2
  124. package/src/extensions/FilePanel/FilePanelPlugin.ts +37 -28
  125. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +6 -8
  126. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +29 -26
  127. package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +11 -11
  128. package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +4 -4
  129. package/src/extensions/Placeholder/PlaceholderPlugin.ts +10 -10
  130. package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +2 -2
  131. package/src/extensions/README.md +1 -1
  132. package/src/extensions/SideMenu/MultipleNodeSelection.ts +1 -1
  133. package/src/extensions/SideMenu/SideMenuPlugin.ts +31 -31
  134. package/src/extensions/SideMenu/dragging.ts +8 -8
  135. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +17 -17
  136. package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +2 -2
  137. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +12 -12
  138. package/src/extensions/TableHandles/TableHandlesPlugin.ts +54 -53
  139. package/src/extensions/TrailingNode/TrailingNodeExtension.ts +1 -1
  140. package/src/extensions/UniqueID/UniqueID.ts +6 -6
  141. package/src/extensions/getDraggableBlockFromElement.ts +1 -1
  142. package/src/fonts/inter.css +18 -9
  143. package/src/i18n/locales/index.ts +2 -0
  144. package/src/i18n/locales/ru.ts +2 -2
  145. package/src/i18n/locales/sk.ts +355 -0
  146. package/src/i18n/locales/zh-tw.ts +390 -0
  147. package/src/locales.ts +1 -1
  148. package/src/pm-nodes/BlockContainer.ts +7 -6
  149. package/src/pm-nodes/BlockGroup.ts +1 -1
  150. package/src/pm-nodes/Doc.ts +4 -4
  151. package/src/schema/README.md +1 -1
  152. package/src/schema/blocks/createSpec.ts +15 -15
  153. package/src/schema/blocks/internal.ts +17 -18
  154. package/src/schema/blocks/types.ts +27 -26
  155. package/src/schema/inlineContent/createSpec.ts +16 -20
  156. package/src/schema/inlineContent/internal.ts +9 -9
  157. package/src/schema/inlineContent/types.ts +26 -26
  158. package/src/schema/propTypes.ts +8 -8
  159. package/src/schema/styles/createSpec.ts +2 -2
  160. package/src/schema/styles/internal.ts +7 -7
  161. package/src/schema/styles/types.ts +2 -2
  162. package/src/util/EventEmitter.ts +4 -4
  163. package/src/util/README.md +1 -1
  164. package/src/util/combineByGroup.ts +1 -1
  165. package/src/util/table.ts +33 -30
  166. package/types/src/api/blockManipulation/setupTestEnv.d.ts +8 -4
  167. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +8 -4
  168. package/types/src/blocks/ListItemBlockContent/getListItemContent.d.ts +28 -0
  169. package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +8 -4
  170. package/types/src/blocks/defaultBlockHelpers.d.ts +1 -0
  171. package/types/src/blocks/defaultBlocks.d.ts +16 -8
  172. package/types/src/editor/BlockNoteEditor.d.ts +21 -2
  173. package/types/src/extensions/Collaboration/CursorPlugin.d.ts +31 -0
  174. package/types/src/extensions/Collaboration/SyncPlugin.d.ts +7 -0
  175. package/types/src/extensions/Collaboration/UndoPlugin.d.ts +6 -0
  176. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +1 -1
  177. package/types/src/i18n/locales/index.d.ts +2 -0
  178. package/types/src/i18n/locales/sk.d.ts +313 -0
  179. package/types/src/i18n/locales/zh-tw.d.ts +2 -0
  180. package/types/src/schema/blocks/types.d.ts +2 -1
  181. package/src/extensions/Collaboration/createCollaborationExtensions.ts +0 -147
  182. package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +0 -17
@@ -18,7 +18,7 @@ it("creates an editor", () => {
18
18
  it("immediately replaces doc", async () => {
19
19
  const editor = BlockNoteEditor.create();
20
20
  const blocks = await editor.tryParseMarkdownToBlocks(
21
- "This is a normal text\n\n# And this is a large heading"
21
+ "This is a normal text\n\n# And this is a large heading",
22
22
  );
23
23
  editor.replaceBlocks(editor.document, blocks);
24
24
  expect(editor.document).toMatchInlineSnapshot(`
@@ -67,11 +67,11 @@ it("adds id attribute when requested", async () => {
67
67
  setIdAttribute: true,
68
68
  });
69
69
  const blocks = await editor.tryParseMarkdownToBlocks(
70
- "This is a normal text\n\n# And this is a large heading"
70
+ "This is a normal text\n\n# And this is a large heading",
71
71
  );
72
72
  editor.replaceBlocks(editor.document, blocks);
73
73
  expect(await editor.blocksToFullHTML(editor.document)).toMatchInlineSnapshot(
74
- `"<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1" id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1" id="1"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">This is a normal text</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="2" id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2" id="2"><div class="bn-block-content" data-content-type="heading"><h1 class="bn-inline-content">And this is a large heading</h1></div></div></div></div>"`
74
+ `"<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1" id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1" id="1"><div class="bn-block-content" data-content-type="paragraph"><p class="bn-inline-content">This is a normal text</p></div></div></div><div class="bn-block-outer" data-node-type="blockOuter" data-id="2" id="2"><div class="bn-block" data-node-type="blockContainer" data-id="2" id="2"><div class="bn-block-content" data-content-type="heading"><h1 class="bn-inline-content">And this is a large heading</h1></div></div></div></div>"`,
75
75
  );
76
76
  });
77
77
 
@@ -101,7 +101,8 @@ import {
101
101
  } from "@tiptap/pm/state";
102
102
  import { dropCursor } from "prosemirror-dropcursor";
103
103
  import { EditorView } from "prosemirror-view";
104
- import { ySyncPluginKey } from "y-prosemirror";
104
+ import { undoCommand, redoCommand, ySyncPluginKey } from "y-prosemirror";
105
+ import { undo, redo } from "@tiptap/pm/history";
105
106
  import { createInternalHTMLSerializer } from "../api/exporters/html/internalHTMLSerializer.js";
106
107
  import { inlineContentToNodes } from "../api/nodeConversions/blockToNode.js";
107
108
  import { nodeToBlock } from "../api/nodeConversions/nodeToBlock.js";
@@ -114,27 +115,29 @@ import { CodeBlockOptions } from "../blocks/CodeBlockContent/CodeBlockContent.js
114
115
  import type { ThreadStore, User } from "../comments/index.js";
115
116
  import "../style.css";
116
117
  import { EventEmitter } from "../util/EventEmitter.js";
118
+ import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
117
119
 
118
120
  export type BlockNoteExtensionFactory = (
119
- editor: BlockNoteEditor<any, any, any>
121
+ editor: BlockNoteEditor<any, any, any>,
120
122
  ) => BlockNoteExtension;
121
123
 
122
124
  export type BlockNoteExtension =
123
125
  | AnyExtension
124
126
  | {
125
127
  plugin: Plugin;
128
+ priority?: number;
126
129
  };
127
130
 
128
131
  export type BlockCache<
129
132
  BSchema extends BlockSchema = any,
130
133
  ISchema extends InlineContentSchema = any,
131
- SSchema extends StyleSchema = any
134
+ SSchema extends StyleSchema = any,
132
135
  > = WeakMap<Node, Block<BSchema, ISchema, SSchema>>;
133
136
 
134
137
  export type BlockNoteEditorOptions<
135
138
  BSchema extends BlockSchema,
136
139
  ISchema extends InlineContentSchema,
137
- SSchema extends StyleSchema
140
+ SSchema extends StyleSchema,
138
141
  > = {
139
142
  /**
140
143
  * Whether changes to blocks (like indentation, creating lists, changing headings) should be animated or not. Defaults to `true`.
@@ -357,7 +360,7 @@ export type BlockNoteEditorOptions<
357
360
  */
358
361
  uploadFile: (
359
362
  file: File,
360
- blockId?: string
363
+ blockId?: string,
361
364
  ) => Promise<string | Record<string, any>>;
362
365
 
363
366
  /**
@@ -389,7 +392,7 @@ const blockNoteTipTapOptions = {
389
392
  export class BlockNoteEditor<
390
393
  BSchema extends BlockSchema = DefaultBlockSchema,
391
394
  ISchema extends InlineContentSchema = DefaultInlineContentSchema,
392
- SSchema extends StyleSchema = DefaultStyleSchema
395
+ SSchema extends StyleSchema = DefaultStyleSchema,
393
396
  > extends EventEmitter<{
394
397
  create: void;
395
398
  }> {
@@ -412,11 +415,10 @@ export class BlockNoteEditor<
412
415
  */
413
416
  public readonly headless: boolean = false;
414
417
 
415
- public readonly _tiptapEditor:
416
- | Omit<BlockNoteTipTapEditor, "view"> & {
417
- view: EditorView | undefined;
418
- contentComponent: any;
419
- } = undefined as any; // TODO: Type should actually reflect that it can be `undefined` in headless mode
418
+ public readonly _tiptapEditor: Omit<BlockNoteTipTapEditor, "view"> & {
419
+ view: EditorView | undefined;
420
+ contentComponent: any;
421
+ } = undefined as any; // TODO: Type should actually reflect that it can be `undefined` in headless mode
420
422
 
421
423
  /**
422
424
  * Used by React to store a reference to an `ElementRenderer` helper utility to make sure we can render React elements
@@ -471,6 +473,8 @@ export class BlockNoteEditor<
471
473
 
472
474
  private readonly showSelectionPlugin: ShowSelectionPlugin;
473
475
 
476
+ private readonly cursorPlugin: CursorPlugin;
477
+
474
478
  /**
475
479
  * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).
476
480
  * This method should set when creating the editor as this is application-specific.
@@ -505,37 +509,37 @@ export class BlockNoteEditor<
505
509
  public static create<
506
510
  BSchema extends BlockSchema = DefaultBlockSchema,
507
511
  ISchema extends InlineContentSchema = DefaultInlineContentSchema,
508
- SSchema extends StyleSchema = DefaultStyleSchema
512
+ SSchema extends StyleSchema = DefaultStyleSchema,
509
513
  >(options: Partial<BlockNoteEditorOptions<BSchema, ISchema, SSchema>> = {}) {
510
514
  return new BlockNoteEditor<BSchema, ISchema, SSchema>(options);
511
515
  }
512
516
 
513
517
  protected constructor(
514
- protected readonly options: Partial<BlockNoteEditorOptions<any, any, any>>
518
+ protected readonly options: Partial<BlockNoteEditorOptions<any, any, any>>,
515
519
  ) {
516
520
  super();
517
521
  const anyOpts = options as any;
518
522
  if (anyOpts.onEditorContentChange) {
519
523
  throw new Error(
520
- "onEditorContentChange initialization option is deprecated, use <BlockNoteView onChange={...} />, the useEditorChange(...) hook, or editor.onChange(...)"
524
+ "onEditorContentChange initialization option is deprecated, use <BlockNoteView onChange={...} />, the useEditorChange(...) hook, or editor.onChange(...)",
521
525
  );
522
526
  }
523
527
 
524
528
  if (anyOpts.onTextCursorPositionChange) {
525
529
  throw new Error(
526
- "onTextCursorPositionChange initialization option is deprecated, use <BlockNoteView onSelectionChange={...} />, the useEditorSelectionChange(...) hook, or editor.onSelectionChange(...)"
530
+ "onTextCursorPositionChange initialization option is deprecated, use <BlockNoteView onSelectionChange={...} />, the useEditorSelectionChange(...) hook, or editor.onSelectionChange(...)",
527
531
  );
528
532
  }
529
533
 
530
534
  if (anyOpts.onEditorReady) {
531
535
  throw new Error(
532
- "onEditorReady is deprecated. Editor is immediately ready for use after creation."
536
+ "onEditorReady is deprecated. Editor is immediately ready for use after creation.",
533
537
  );
534
538
  }
535
539
 
536
540
  if (anyOpts.editable) {
537
541
  throw new Error(
538
- "editable initialization option is deprecated, use <BlockNoteView editable={true/false} />, or alternatively editor.isEditable = true/false"
542
+ "editable initialization option is deprecated, use <BlockNoteView editable={true/false} />, or alternatively editor.isEditable = true/false",
539
543
  );
540
544
  }
541
545
 
@@ -621,18 +625,19 @@ export class BlockNoteEditor<
621
625
  this.tableHandles = this.extensions["tableHandles"] as any;
622
626
  this.comments = this.extensions["comments"] as any;
623
627
  this.showSelectionPlugin = this.extensions["showSelection"] as any;
628
+ this.cursorPlugin = this.extensions["yCursorPlugin"] as any;
624
629
 
625
630
  if (newOptions.uploadFile) {
626
631
  const uploadFile = newOptions.uploadFile;
627
- this.uploadFile = async (file, block) => {
632
+ this.uploadFile = async (file, blockId) => {
628
633
  this.onUploadStartCallbacks.forEach((callback) =>
629
- callback.apply(this, [block])
634
+ callback.apply(this, [blockId]),
630
635
  );
631
636
  try {
632
- return await uploadFile(file, block);
637
+ return await uploadFile(file, blockId);
633
638
  } finally {
634
639
  this.onUploadEndCallbacks.forEach((callback) =>
635
- callback.apply(this, [block])
640
+ callback.apply(this, [blockId]),
636
641
  );
637
642
  }
638
643
  };
@@ -642,13 +647,13 @@ export class BlockNoteEditor<
642
647
  this.headless = newOptions._headless;
643
648
 
644
649
  const collaborationEnabled =
645
- "collaboration" in this.extensions ||
650
+ "ySyncPlugin" in this.extensions ||
646
651
  "liveblocksExtension" in this.extensions;
647
652
 
648
653
  if (collaborationEnabled && newOptions.initialContent) {
649
654
  // eslint-disable-next-line no-console
650
655
  console.warn(
651
- "When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider"
656
+ "When using Collaboration, initialContent might cause conflicts, because changes should come from the collaboration provider",
652
657
  );
653
658
  }
654
659
 
@@ -671,7 +676,7 @@ export class BlockNoteEditor<
671
676
  if (!Array.isArray(initialContent) || initialContent.length === 0) {
672
677
  throw new Error(
673
678
  "initialContent must be a non-empty array of blocks, received: " +
674
- initialContent
679
+ initialContent,
675
680
  );
676
681
  }
677
682
 
@@ -688,13 +693,14 @@ export class BlockNoteEditor<
688
693
 
689
694
  if (!ext.plugin) {
690
695
  throw new Error(
691
- "Extension should either be a TipTap extension or a ProseMirror plugin in a plugin property"
696
+ "Extension should either be a TipTap extension or a ProseMirror plugin in a plugin property",
692
697
  );
693
698
  }
694
699
 
695
700
  // "blocknote" extensions (prosemirror plugins)
696
701
  return Extension.create({
697
702
  name: key,
703
+ priority: ext.priority,
698
704
  addProseMirrorPlugins: () => [ext.plugin],
699
705
  });
700
706
  }),
@@ -716,7 +722,7 @@ export class BlockNoteEditor<
716
722
  class: mergeCSSClasses(
717
723
  "bn-editor",
718
724
  newOptions.defaultStyles ? "bn-default-styles" : "",
719
- newOptions.domAttributes?.editor?.class || ""
725
+ newOptions.domAttributes?.editor?.class || "",
720
726
  ),
721
727
  },
722
728
  transformPasted,
@@ -726,7 +732,7 @@ export class BlockNoteEditor<
726
732
  if (!this.headless) {
727
733
  this._tiptapEditor = BlockNoteTipTapEditor.create(
728
734
  tiptapOptions,
729
- this.schema.styleSchema
735
+ this.schema.styleSchema,
730
736
  ) as BlockNoteTipTapEditor & {
731
737
  view: any;
732
738
  contentComponent: any;
@@ -761,7 +767,7 @@ export class BlockNoteEditor<
761
767
  public exec(command: Command) {
762
768
  if (this.activeTransaction) {
763
769
  throw new Error(
764
- "`exec` should not be called within a `transact` call, move the `exec` call outside of the `transact` call"
770
+ "`exec` should not be called within a `transact` call, move the `exec` call outside of the `transact` call",
765
771
  );
766
772
  }
767
773
  const state = this._tiptapEditor.state;
@@ -786,7 +792,7 @@ export class BlockNoteEditor<
786
792
  public canExec(command: Command): boolean {
787
793
  if (this.activeTransaction) {
788
794
  throw new Error(
789
- "`canExec` should not be called within a `transact` call, move the `canExec` call outside of the `transact` call"
795
+ "`canExec` should not be called within a `transact` call, move the `canExec` call outside of the `transact` call",
790
796
  );
791
797
  }
792
798
  const state = this._tiptapEditor.state;
@@ -820,8 +826,8 @@ export class BlockNoteEditor<
820
826
  * The current active transaction, this will automatically be dispatched to the editor when the callback is complete
821
827
  * If another `transact` call is made within the callback, it will be passed the same transaction as the parent call.
822
828
  */
823
- tr: Transaction
824
- ) => T
829
+ tr: Transaction,
830
+ ) => T,
825
831
  ): T {
826
832
  if (this.activeTransaction) {
827
833
  // Already in a transaction, so we can just callback immediately
@@ -866,13 +872,28 @@ export class BlockNoteEditor<
866
872
  */
867
873
  public mount = (
868
874
  parentElement?: HTMLElement | null,
869
- contentComponent?: any
875
+ contentComponent?: any,
870
876
  ) => {
871
877
  this._tiptapEditor.mount(this, parentElement, contentComponent);
872
878
  };
873
879
 
880
+ /**
881
+ * Get the underlying prosemirror state
882
+ * @note Prefer using `editor.transact` to read the current editor state, as that will ensure the state is up to date
883
+ * @see https://prosemirror.net/docs/ref/#state.EditorState
884
+ */
885
+ public get prosemirrorState() {
886
+ if (this.activeTransaction) {
887
+ throw new Error(
888
+ "`prosemirrorState` should not be called within a `transact` call, move the `prosemirrorState` call outside of the `transact` call or use `editor.transact` to read the current editor state",
889
+ );
890
+ }
891
+ return this._tiptapEditor.state;
892
+ }
893
+
874
894
  /**
875
895
  * Get the underlying prosemirror view
896
+ * @see https://prosemirror.net/docs/ref/#view.EditorView
876
897
  */
877
898
  public get prosemirrorView() {
878
899
  return this._tiptapEditor.view;
@@ -945,7 +966,7 @@ export class BlockNoteEditor<
945
966
  * matching block was found.
946
967
  */
947
968
  public getBlock(
948
- blockIdentifier: BlockIdentifier
969
+ blockIdentifier: BlockIdentifier,
949
970
  ): Block<BSchema, ISchema, SSchema> | undefined {
950
971
  return this.transact((tr) => getBlock(tr.doc, blockIdentifier));
951
972
  }
@@ -960,7 +981,7 @@ export class BlockNoteEditor<
960
981
  * in the document.
961
982
  */
962
983
  public getPrevBlock(
963
- blockIdentifier: BlockIdentifier
984
+ blockIdentifier: BlockIdentifier,
964
985
  ): Block<BSchema, ISchema, SSchema> | undefined {
965
986
  return this.transact((tr) => getPrevBlock(tr.doc, blockIdentifier));
966
987
  }
@@ -974,7 +995,7 @@ export class BlockNoteEditor<
974
995
  * the document.
975
996
  */
976
997
  public getNextBlock(
977
- blockIdentifier: BlockIdentifier
998
+ blockIdentifier: BlockIdentifier,
978
999
  ): Block<BSchema, ISchema, SSchema> | undefined {
979
1000
  return this.transact((tr) => getNextBlock(tr.doc, blockIdentifier));
980
1001
  }
@@ -987,7 +1008,7 @@ export class BlockNoteEditor<
987
1008
  * if no matching block was found, or the block isn't nested.
988
1009
  */
989
1010
  public getParentBlock(
990
- blockIdentifier: BlockIdentifier
1011
+ blockIdentifier: BlockIdentifier,
991
1012
  ): Block<BSchema, ISchema, SSchema> | undefined {
992
1013
  return this.transact((tr) => getParentBlock(tr.doc, blockIdentifier));
993
1014
  }
@@ -999,7 +1020,7 @@ export class BlockNoteEditor<
999
1020
  */
1000
1021
  public forEachBlock(
1001
1022
  callback: (block: Block<BSchema, ISchema, SSchema>) => boolean,
1002
- reverse = false
1023
+ reverse = false,
1003
1024
  ): void {
1004
1025
  const blocks = this.document.slice();
1005
1026
 
@@ -1008,7 +1029,7 @@ export class BlockNoteEditor<
1008
1029
  }
1009
1030
 
1010
1031
  function traverseBlockArray(
1011
- blockArray: Block<BSchema, ISchema, SSchema>[]
1032
+ blockArray: Block<BSchema, ISchema, SSchema>[],
1012
1033
  ): boolean {
1013
1034
  for (const block of blockArray) {
1014
1035
  if (callback(block) === false) {
@@ -1034,7 +1055,7 @@ export class BlockNoteEditor<
1034
1055
  * Executes a callback whenever the editor's contents change.
1035
1056
  * @param callback The callback to execute.
1036
1057
  *
1037
- * @deprecated use `onChange` instead
1058
+ * @deprecated use {@link BlockNoteEditor.onChange} instead
1038
1059
  */
1039
1060
  public onEditorContentChange(callback: () => void) {
1040
1061
  this._tiptapEditor.on("update", callback);
@@ -1070,10 +1091,10 @@ export class BlockNoteEditor<
1070
1091
  */
1071
1092
  public setTextCursorPosition(
1072
1093
  targetBlock: BlockIdentifier,
1073
- placement: "start" | "end" = "start"
1094
+ placement: "start" | "end" = "start",
1074
1095
  ) {
1075
1096
  return this.transact((tr) =>
1076
- setTextCursorPosition(tr, targetBlock, placement)
1097
+ setTextCursorPosition(tr, targetBlock, placement),
1077
1098
  );
1078
1099
  }
1079
1100
 
@@ -1137,10 +1158,10 @@ export class BlockNoteEditor<
1137
1158
  public insertBlocks(
1138
1159
  blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],
1139
1160
  referenceBlock: BlockIdentifier,
1140
- placement: "before" | "after" = "before"
1161
+ placement: "before" | "after" = "before",
1141
1162
  ) {
1142
1163
  return this.transact((tr) =>
1143
- insertBlocks(tr, blocksToInsert, referenceBlock, placement)
1164
+ insertBlocks(tr, blocksToInsert, referenceBlock, placement),
1144
1165
  );
1145
1166
  }
1146
1167
 
@@ -1153,7 +1174,7 @@ export class BlockNoteEditor<
1153
1174
  */
1154
1175
  public updateBlock(
1155
1176
  blockToUpdate: BlockIdentifier,
1156
- update: PartialBlock<BSchema, ISchema, SSchema>
1177
+ update: PartialBlock<BSchema, ISchema, SSchema>,
1157
1178
  ) {
1158
1179
  return this.transact((tr) => updateBlock(tr, blockToUpdate, update));
1159
1180
  }
@@ -1164,7 +1185,7 @@ export class BlockNoteEditor<
1164
1185
  */
1165
1186
  public removeBlocks(blocksToRemove: BlockIdentifier[]) {
1166
1187
  return this.transact(
1167
- (tr) => removeAndInsertBlocks(tr, blocksToRemove, []).removedBlocks
1188
+ (tr) => removeAndInsertBlocks(tr, blocksToRemove, []).removedBlocks,
1168
1189
  );
1169
1190
  }
1170
1191
 
@@ -1177,19 +1198,43 @@ export class BlockNoteEditor<
1177
1198
  */
1178
1199
  public replaceBlocks(
1179
1200
  blocksToRemove: BlockIdentifier[],
1180
- blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[]
1201
+ blocksToInsert: PartialBlock<BSchema, ISchema, SSchema>[],
1181
1202
  ) {
1182
1203
  return this.transact((tr) =>
1183
- removeAndInsertBlocks(tr, blocksToRemove, blocksToInsert)
1204
+ removeAndInsertBlocks(tr, blocksToRemove, blocksToInsert),
1184
1205
  );
1185
1206
  }
1186
1207
 
1208
+ /**
1209
+ * Undo the last action.
1210
+ */
1211
+ public undo() {
1212
+ if (this.options.collaboration) {
1213
+ return this.exec(undoCommand);
1214
+ }
1215
+
1216
+ return this.exec(undo);
1217
+ }
1218
+
1219
+ /**
1220
+ * Redo the last action.
1221
+ */
1222
+ public redo() {
1223
+ if (this.options.collaboration) {
1224
+ return this.exec(redoCommand);
1225
+ }
1226
+ return this.exec(redo);
1227
+ }
1228
+
1187
1229
  /**
1188
1230
  * Insert a piece of content at the current cursor position.
1189
1231
  *
1190
1232
  * @param content can be a string, or array of partial inline content elements
1191
1233
  */
1192
- public insertInlineContent(content: PartialInlineContent<ISchema, SSchema>) {
1234
+ public insertInlineContent(
1235
+ content: PartialInlineContent<ISchema, SSchema>,
1236
+ { updateSelection = false }: { updateSelection?: boolean } = {},
1237
+ ) {
1193
1238
  const nodes = inlineContentToNodes(content, this.pmSchema);
1194
1239
 
1195
1240
  this.transact((tr) => {
@@ -1199,7 +1244,10 @@ export class BlockNoteEditor<
1199
1244
  from: tr.selection.from,
1200
1245
  to: tr.selection.to,
1201
1246
  },
1202
- nodes
1247
+ nodes,
1248
+ {
1249
+ updateSelection,
1250
+ },
1203
1251
  );
1204
1252
  });
1205
1253
  }
@@ -1323,7 +1371,7 @@ export class BlockNoteEditor<
1323
1371
  tr.setSelection(TextSelection.create(tr.doc, to)).addMark(
1324
1372
  from,
1325
1373
  to,
1326
- mark
1374
+ mark,
1327
1375
  );
1328
1376
  }
1329
1377
  });
@@ -1383,7 +1431,7 @@ export class BlockNoteEditor<
1383
1431
  * @returns The blocks, serialized as an HTML string.
1384
1432
  */
1385
1433
  public async blocksToHTMLLossy(
1386
- blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document
1434
+ blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,
1387
1435
  ): Promise<string> {
1388
1436
  const exporter = createExternalHTMLExporter(this.pmSchema, this);
1389
1437
  return exporter.exportBlocks(blocks, {});
@@ -1399,7 +1447,7 @@ export class BlockNoteEditor<
1399
1447
  * @returns The blocks, serialized as an HTML string.
1400
1448
  */
1401
1449
  public async blocksToFullHTML(
1402
- blocks: PartialBlock<BSchema, ISchema, SSchema>[]
1450
+ blocks: PartialBlock<BSchema, ISchema, SSchema>[],
1403
1451
  ): Promise<string> {
1404
1452
  const exporter = createInternalHTMLSerializer(this.pmSchema, this);
1405
1453
  return exporter.serializeBlocks(blocks, {});
@@ -1412,7 +1460,7 @@ export class BlockNoteEditor<
1412
1460
  * @returns The blocks parsed from the HTML string.
1413
1461
  */
1414
1462
  public async tryParseHTMLToBlocks(
1415
- html: string
1463
+ html: string,
1416
1464
  ): Promise<Block<BSchema, ISchema, SSchema>[]> {
1417
1465
  return HTMLToBlocks(html, this.pmSchema);
1418
1466
  }
@@ -1424,7 +1472,7 @@ export class BlockNoteEditor<
1424
1472
  * @returns The blocks, serialized as a Markdown string.
1425
1473
  */
1426
1474
  public async blocksToMarkdownLossy(
1427
- blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document
1475
+ blocks: PartialBlock<BSchema, ISchema, SSchema>[] = this.document,
1428
1476
  ): Promise<string> {
1429
1477
  return blocksToMarkdown(blocks, this.pmSchema, this, {});
1430
1478
  }
@@ -1437,7 +1485,7 @@ export class BlockNoteEditor<
1437
1485
  * @returns The blocks parsed from the Markdown string.
1438
1486
  */
1439
1487
  public async tryParseMarkdownToBlocks(
1440
- markdown: string
1488
+ markdown: string,
1441
1489
  ): Promise<Block<BSchema, ISchema, SSchema>[]> {
1442
1490
  return markdownToBlocks(markdown, this.pmSchema);
1443
1491
  }
@@ -1448,10 +1496,11 @@ export class BlockNoteEditor<
1448
1496
  public updateCollaborationUserInfo(user: { name: string; color: string }) {
1449
1497
  if (!this.options.collaboration) {
1450
1498
  throw new Error(
1451
- "Cannot update collaboration user info when collaboration is disabled."
1499
+ "Cannot update collaboration user info when collaboration is disabled.",
1452
1500
  );
1453
1501
  }
1454
- this._tiptapEditor.commands.updateUser(user);
1502
+
1503
+ this.cursorPlugin.updateUser(user);
1455
1504
  }
1456
1505
 
1457
1506
  /**
@@ -1468,8 +1517,8 @@ export class BlockNoteEditor<
1468
1517
  * Returns the blocks that were inserted, updated, or deleted by the change that occurred.
1469
1518
  */
1470
1519
  getChanges(): BlocksChanged<BSchema, ISchema, SSchema>;
1471
- }
1472
- ) => void
1520
+ },
1521
+ ) => void,
1473
1522
  ) {
1474
1523
  if (this.headless) {
1475
1524
  // Note: would be nice if this is possible in headless mode as well
@@ -1504,7 +1553,7 @@ export class BlockNoteEditor<
1504
1553
  */
1505
1554
  public onSelectionChange(
1506
1555
  callback: (editor: BlockNoteEditor<BSchema, ISchema, SSchema>) => void,
1507
- includeSelectionChangedByRemote?: boolean
1556
+ includeSelectionChangedByRemote?: boolean,
1508
1557
  ) {
1509
1558
  if (this.headless) {
1510
1559
  return;
@@ -1581,7 +1630,7 @@ export class BlockNoteEditor<
1581
1630
  pluginState?: {
1582
1631
  deleteTriggerCharacter?: boolean;
1583
1632
  ignoreQueryLength?: boolean;
1584
- }
1633
+ },
1585
1634
  ) {
1586
1635
  if (!this.prosemirrorView) {
1587
1636
  return;
@@ -10,7 +10,9 @@ import { createDropFileExtension } from "../api/clipboard/fromClipboard/fileDrop
10
10
  import { createPasteFromClipboardExtension } from "../api/clipboard/fromClipboard/pasteExtension.js";
11
11
  import { createCopyToClipboardExtension } from "../api/clipboard/toClipboard/copyExtension.js";
12
12
  import { BackgroundColorExtension } from "../extensions/BackgroundColor/BackgroundColorExtension.js";
13
- import { createCollaborationExtensions } from "../extensions/Collaboration/createCollaborationExtensions.js";
13
+ import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
14
+ import { UndoPlugin } from "../extensions/Collaboration/UndoPlugin.js";
15
+ import { SyncPlugin } from "../extensions/Collaboration/SyncPlugin.js";
14
16
  import { CommentMark } from "../extensions/Comments/CommentMark.js";
15
17
  import { CommentsPlugin } from "../extensions/Comments/CommentsPlugin.js";
16
18
  import type { ThreadStore } from "../comments/index.js";
@@ -53,7 +55,7 @@ import type {
53
55
  type ExtensionOptions<
54
56
  BSchema extends BlockSchema,
55
57
  I extends InlineContentSchema,
56
- S extends StyleSchema
58
+ S extends StyleSchema,
57
59
  > = {
58
60
  editor: BlockNoteEditor<BSchema, I, S>;
59
61
  domAttributes: Partial<BlockNoteDOMAttributes>;
@@ -95,9 +97,9 @@ type ExtensionOptions<
95
97
  export const getBlockNoteExtensions = <
96
98
  BSchema extends BlockSchema,
97
99
  I extends InlineContentSchema,
98
- S extends StyleSchema
100
+ S extends StyleSchema,
99
101
  >(
100
- opts: ExtensionOptions<BSchema, I, S>
102
+ opts: ExtensionOptions<BSchema, I, S>,
101
103
  ) => {
102
104
  const ret: Record<string, BlockNoteExtension> = {};
103
105
  const tiptapExtensions = getTipTapExtensions(opts);
@@ -106,15 +108,24 @@ export const getBlockNoteExtensions = <
106
108
  ret[ext.name] = ext;
107
109
  }
108
110
 
111
+ if (opts.collaboration) {
112
+ ret["ySyncPlugin"] = new SyncPlugin(opts.collaboration.fragment);
113
+ ret["yUndoPlugin"] = new UndoPlugin();
114
+
115
+ if (opts.collaboration.provider?.awareness) {
116
+ ret["yCursorPlugin"] = new CursorPlugin(opts.collaboration);
117
+ }
118
+ }
119
+
109
120
  // Note: this is pretty hardcoded and will break when user provides plugins with same keys.
110
121
  // Define name on plugins instead and not make this a map?
111
122
  ret["formattingToolbar"] = new FormattingToolbarProsemirrorPlugin(
112
- opts.editor
123
+ opts.editor,
113
124
  );
114
125
  ret["linkToolbar"] = new LinkToolbarProsemirrorPlugin(opts.editor);
115
126
  ret["sideMenu"] = new SideMenuProsemirrorPlugin(
116
127
  opts.editor,
117
- opts.sideMenuDetection
128
+ opts.sideMenuDetection,
118
129
  );
119
130
  ret["suggestionMenus"] = new SuggestionMenuProseMirrorPlugin(opts.editor);
120
131
  ret["filePanel"] = new FilePanelProsemirrorPlugin(opts.editor as any);
@@ -144,7 +155,7 @@ export const getBlockNoteExtensions = <
144
155
  ret["comments"] = new CommentsPlugin(
145
156
  opts.editor,
146
157
  opts.comments.threadStore,
147
- CommentMark.name
158
+ CommentMark.name,
148
159
  );
149
160
  }
150
161
 
@@ -164,9 +175,9 @@ let LINKIFY_INITIALIZED = false;
164
175
  const getTipTapExtensions = <
165
176
  BSchema extends BlockSchema,
166
177
  I extends InlineContentSchema,
167
- S extends StyleSchema
178
+ S extends StyleSchema,
168
179
  >(
169
- opts: ExtensionOptions<BSchema, I, S>
180
+ opts: ExtensionOptions<BSchema, I, S>,
170
181
  ) => {
171
182
  const tiptapExtensions: AnyExtension[] = [
172
183
  extensions.ClipboardTextSerializer,
@@ -253,7 +264,7 @@ const getTipTapExtensions = <
253
264
  ext.configure({
254
265
  editor: opts.editor,
255
266
  domAttributes: opts.domAttributes,
256
- })
267
+ }),
257
268
  ),
258
269
  // the actual node itself
259
270
  blockSpec.implementation.node.configure({
@@ -271,7 +282,7 @@ const getTipTapExtensions = <
271
282
  prioritizeMarkdownOverHTML?: boolean;
272
283
  plainTextAsMarkdown?: boolean;
273
284
  }) => boolean | undefined;
274
- }) => context.defaultPasteHandler())
285
+ }) => context.defaultPasteHandler()),
275
286
  ),
276
287
  createDropFileExtension(opts.editor),
277
288
 
@@ -285,10 +296,8 @@ const getTipTapExtensions = <
285
296
 
286
297
  LINKIFY_INITIALIZED = true;
287
298
 
288
- if (opts.collaboration) {
289
- tiptapExtensions.push(...createCollaborationExtensions(opts.collaboration));
290
- } else {
291
- // disable history extension when collaboration is enabled as Yjs takes care of undo / redo
299
+ if (!opts.collaboration) {
300
+ // disable history extension when collaboration is enabled as y-prosemirror takes care of undo / redo
292
301
  tiptapExtensions.push(History);
293
302
  }
294
303