@blocknote/core 0.27.2 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/dist/blocknote.cjs +10 -10
  2. package/dist/blocknote.cjs.map +1 -1
  3. package/dist/blocknote.js +3032 -3118
  4. package/dist/blocknote.js.map +1 -1
  5. package/dist/locales.cjs +1 -1
  6. package/dist/locales.cjs.map +1 -1
  7. package/dist/locales.js +10 -10
  8. package/dist/locales.js.map +1 -1
  9. package/dist/tsconfig.tsbuildinfo +1 -1
  10. package/dist/webpack-stats.json +1 -1
  11. package/package.json +2 -2
  12. package/src/api/__snapshots__/blocks-deleted-nested-deep.json +26 -0
  13. package/src/api/__snapshots__/blocks-deleted-nested.json +68 -0
  14. package/src/api/__snapshots__/blocks-deleted.json +26 -0
  15. package/src/api/__snapshots__/blocks-inserted-nested.json +62 -0
  16. package/src/api/__snapshots__/blocks-inserted.json +20 -0
  17. package/src/api/__snapshots__/blocks-updated-content-inserted.json +42 -0
  18. package/src/api/__snapshots__/blocks-updated-multiple-insert.json +50 -0
  19. package/src/api/__snapshots__/blocks-updated-multiple.json +82 -0
  20. package/src/api/__snapshots__/blocks-updated-nested-deep.json +42 -0
  21. package/src/api/__snapshots__/blocks-updated-nested-multiple.json +118 -0
  22. package/src/api/__snapshots__/blocks-updated-nested.json +78 -0
  23. package/src/api/__snapshots__/blocks-updated-single.json +42 -0
  24. package/src/api/__snapshots__/blocks-updated.json +42 -0
  25. package/src/api/blockManipulation/__snapshots__/transactions.test.ts.snap +34 -0
  26. package/src/api/blockManipulation/commands/insertBlocks/__snapshots__/insertBlocks.test.ts.snap +312 -0
  27. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.test.ts +127 -94
  28. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +19 -37
  29. package/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts +8 -6
  30. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.ts +25 -31
  31. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts +93 -91
  32. package/src/api/blockManipulation/commands/nestBlock/nestBlock.ts +16 -20
  33. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.test.ts +14 -1
  34. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +18 -56
  35. package/src/api/blockManipulation/commands/splitBlock/splitBlock.test.ts +52 -46
  36. package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +1051 -0
  37. package/src/api/blockManipulation/commands/updateBlock/updateBlock.test.ts +247 -154
  38. package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +109 -142
  39. package/src/api/blockManipulation/getBlock/getBlock.ts +23 -48
  40. package/src/api/blockManipulation/insertContentAt.ts +4 -17
  41. package/src/api/blockManipulation/selections/selection.test.ts +32 -16
  42. package/src/api/blockManipulation/selections/selection.ts +25 -51
  43. package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.ts +35 -14
  44. package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts +34 -65
  45. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +8 -10
  46. package/src/api/clipboard/toClipboard/copyExtension.ts +7 -7
  47. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +7 -16
  48. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +3 -17
  49. package/src/api/getBlockInfoFromPos.ts +13 -1
  50. package/src/api/nodeConversions/blockToNode.ts +21 -10
  51. package/src/api/nodeConversions/fragmentToBlocks.ts +5 -18
  52. package/src/api/nodeConversions/nodeToBlock.ts +11 -8
  53. package/src/api/nodeUtil.test.ts +228 -0
  54. package/src/api/nodeUtil.ts +235 -2
  55. package/src/api/parsers/html/parseHTML.ts +2 -10
  56. package/src/api/parsers/markdown/parseMarkdown.ts +2 -8
  57. package/src/api/pmUtil.ts +54 -0
  58. package/src/api/positionMapping.test.ts +370 -0
  59. package/src/api/positionMapping.ts +114 -0
  60. package/src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts +2 -2
  61. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +9 -13
  62. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +5 -9
  63. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +19 -31
  64. package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +10 -8
  65. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +9 -13
  66. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +1 -1
  67. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +5 -9
  68. package/src/blocks/defaultBlockHelpers.ts +1 -1
  69. package/src/editor/BlockNoteEditor.test.ts +1 -1
  70. package/src/editor/BlockNoteEditor.ts +259 -130
  71. package/src/editor/BlockNoteTipTapEditor.ts +91 -8
  72. package/src/extensions/Comments/CommentsPlugin.ts +32 -34
  73. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +4 -8
  74. package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +12 -13
  75. package/src/extensions/ShowSelection/ShowSelectionPlugin.ts +1 -3
  76. package/src/extensions/SideMenu/MultipleNodeSelection.ts +3 -1
  77. package/src/extensions/SideMenu/dragging.ts +1 -1
  78. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +38 -25
  79. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +8 -8
  80. package/src/extensions/TableHandles/TableHandlesPlugin.ts +150 -136
  81. package/src/i18n/locales/de.ts +10 -10
  82. package/src/index.ts +4 -3
  83. package/src/schema/inlineContent/createSpec.ts +1 -5
  84. package/types/src/api/blockManipulation/commands/insertBlocks/insertBlocks.d.ts +2 -2
  85. package/types/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.d.ts +4 -8
  86. package/types/src/api/blockManipulation/commands/updateBlock/updateBlock.d.ts +9 -10
  87. package/types/src/api/blockManipulation/getBlock/getBlock.d.ts +7 -7
  88. package/types/src/api/blockManipulation/insertContentAt.d.ts +5 -3
  89. package/types/src/api/blockManipulation/selections/selection.d.ts +3 -3
  90. package/types/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.d.ts +5 -5
  91. package/types/src/api/getBlockInfoFromPos.d.ts +8 -1
  92. package/types/src/api/nodeConversions/blockToNode.d.ts +3 -3
  93. package/types/src/api/nodeConversions/fragmentToBlocks.d.ts +1 -2
  94. package/types/src/api/nodeConversions/nodeToBlock.d.ts +2 -2
  95. package/types/src/api/nodeUtil.d.ts +67 -1
  96. package/types/src/api/parsers/html/parseHTML.d.ts +1 -1
  97. package/types/src/api/parsers/markdown/parseMarkdown.d.ts +1 -1
  98. package/types/src/api/pmUtil.d.ts +12 -0
  99. package/types/src/api/positionMapping.d.ts +25 -0
  100. package/types/src/editor/BlockNoteEditor.d.ts +72 -10
  101. package/types/src/editor/BlockNoteTipTapEditor.d.ts +15 -2
  102. package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +1 -1
  103. package/types/src/index.d.ts +1 -2
  104. package/src/api/blockManipulation/commands/removeBlocks/__snapshots__/removeBlocks.test.ts.snap +0 -1859
  105. package/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.ts +0 -40
  106. package/src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts +0 -20
  107. package/src/api/clipboard/__snapshots__/external/pasteEndOfParagraph.html +0 -138
  108. package/src/api/clipboard/__snapshots__/external/pasteEndOfParagraphText.html +0 -138
  109. package/src/api/clipboard/__snapshots__/external/pasteImage.html +0 -153
  110. package/src/api/clipboard/__snapshots__/external/pasteParagraphInCustomBlock.html +0 -138
  111. package/src/api/clipboard/__snapshots__/external/pasteTable.html +0 -233
  112. package/src/api/clipboard/__snapshots__/external/pasteTableInExistingTable.html +0 -216
  113. package/src/api/clipboard/__snapshots__/internal/basicBlocks.html +0 -1
  114. package/src/api/clipboard/__snapshots__/internal/basicBlocksWithProps.html +0 -1
  115. package/src/api/clipboard/__snapshots__/internal/childToParent.html +0 -1
  116. package/src/api/clipboard/__snapshots__/internal/childrenToNextParent.html +0 -1
  117. package/src/api/clipboard/__snapshots__/internal/childrenToNextParentsChildren.html +0 -1
  118. package/src/api/clipboard/__snapshots__/internal/image.html +0 -1
  119. package/src/api/clipboard/__snapshots__/internal/multipleChildren.html +0 -1
  120. package/src/api/clipboard/__snapshots__/internal/multipleStyledText.html +0 -1
  121. package/src/api/clipboard/__snapshots__/internal/nestedImage.html +0 -1
  122. package/src/api/clipboard/__snapshots__/internal/paragraphInCustomBlock.html +0 -1
  123. package/src/api/clipboard/__snapshots__/internal/partialChildToParent.html +0 -1
  124. package/src/api/clipboard/__snapshots__/internal/styledText.html +0 -1
  125. package/src/api/clipboard/__snapshots__/internal/tableAllCells.html +0 -1
  126. package/src/api/clipboard/__snapshots__/internal/tableCell.html +0 -1
  127. package/src/api/clipboard/__snapshots__/internal/tableCellText.html +0 -1
  128. package/src/api/clipboard/__snapshots__/internal/tableRow.html +0 -1
  129. package/src/api/clipboard/__snapshots__/internal/unstyledText.html +0 -1
  130. package/src/api/clipboard/clipboardExternal.test.ts +0 -161
  131. package/src/api/clipboard/clipboardInternal.test.ts +0 -435
  132. package/src/api/clipboard/testUtil.ts +0 -27
  133. package/src/api/exporters/html/__snapshots__/codeBlock/contains-newlines/external.html +0 -1
  134. package/src/api/exporters/html/__snapshots__/codeBlock/contains-newlines/internal.html +0 -3
  135. package/src/api/exporters/html/__snapshots__/codeBlock/defaultLanguage/external.html +0 -1
  136. package/src/api/exporters/html/__snapshots__/codeBlock/defaultLanguage/internal.html +0 -1
  137. package/src/api/exporters/html/__snapshots__/codeBlock/empty/external.html +0 -1
  138. package/src/api/exporters/html/__snapshots__/codeBlock/empty/internal.html +0 -1
  139. package/src/api/exporters/html/__snapshots__/codeBlock/python/external.html +0 -1
  140. package/src/api/exporters/html/__snapshots__/codeBlock/python/internal.html +0 -1
  141. package/src/api/exporters/html/__snapshots__/complex/misc/external.html +0 -1
  142. package/src/api/exporters/html/__snapshots__/complex/misc/internal.html +0 -1
  143. package/src/api/exporters/html/__snapshots__/customBlock/basic/external.html +0 -1
  144. package/src/api/exporters/html/__snapshots__/customBlock/basic/internal.html +0 -1
  145. package/src/api/exporters/html/__snapshots__/customParagraph/basic/external.html +0 -1
  146. package/src/api/exporters/html/__snapshots__/customParagraph/basic/internal.html +0 -1
  147. package/src/api/exporters/html/__snapshots__/customParagraph/lineBreaks/external.html +0 -1
  148. package/src/api/exporters/html/__snapshots__/customParagraph/lineBreaks/internal.html +0 -1
  149. package/src/api/exporters/html/__snapshots__/customParagraph/nested/external.html +0 -1
  150. package/src/api/exporters/html/__snapshots__/customParagraph/nested/internal.html +0 -1
  151. package/src/api/exporters/html/__snapshots__/customParagraph/styled/external.html +0 -1
  152. package/src/api/exporters/html/__snapshots__/customParagraph/styled/internal.html +0 -1
  153. package/src/api/exporters/html/__snapshots__/file/basic/external.html +0 -1
  154. package/src/api/exporters/html/__snapshots__/file/basic/internal.html +0 -1
  155. package/src/api/exporters/html/__snapshots__/file/button/external.html +0 -1
  156. package/src/api/exporters/html/__snapshots__/file/button/internal.html +0 -1
  157. package/src/api/exporters/html/__snapshots__/file/nested/external.html +0 -1
  158. package/src/api/exporters/html/__snapshots__/file/nested/internal.html +0 -1
  159. package/src/api/exporters/html/__snapshots__/file/noCaption/external.html +0 -1
  160. package/src/api/exporters/html/__snapshots__/file/noCaption/internal.html +0 -1
  161. package/src/api/exporters/html/__snapshots__/file/noName/external.html +0 -1
  162. package/src/api/exporters/html/__snapshots__/file/noName/internal.html +0 -1
  163. package/src/api/exporters/html/__snapshots__/fontSize/basic/external.html +0 -1
  164. package/src/api/exporters/html/__snapshots__/fontSize/basic/internal.html +0 -1
  165. package/src/api/exporters/html/__snapshots__/hardbreak/basic/external.html +0 -1
  166. package/src/api/exporters/html/__snapshots__/hardbreak/basic/internal.html +0 -1
  167. package/src/api/exporters/html/__snapshots__/hardbreak/between-links/external.html +0 -1
  168. package/src/api/exporters/html/__snapshots__/hardbreak/between-links/internal.html +0 -1
  169. package/src/api/exporters/html/__snapshots__/hardbreak/end/external.html +0 -1
  170. package/src/api/exporters/html/__snapshots__/hardbreak/end/internal.html +0 -1
  171. package/src/api/exporters/html/__snapshots__/hardbreak/link/external.html +0 -1
  172. package/src/api/exporters/html/__snapshots__/hardbreak/link/internal.html +0 -1
  173. package/src/api/exporters/html/__snapshots__/hardbreak/multiple/external.html +0 -1
  174. package/src/api/exporters/html/__snapshots__/hardbreak/multiple/internal.html +0 -1
  175. package/src/api/exporters/html/__snapshots__/hardbreak/only/external.html +0 -1
  176. package/src/api/exporters/html/__snapshots__/hardbreak/only/internal.html +0 -1
  177. package/src/api/exporters/html/__snapshots__/hardbreak/start/external.html +0 -1
  178. package/src/api/exporters/html/__snapshots__/hardbreak/start/internal.html +0 -1
  179. package/src/api/exporters/html/__snapshots__/hardbreak/styles/external.html +0 -1
  180. package/src/api/exporters/html/__snapshots__/hardbreak/styles/internal.html +0 -1
  181. package/src/api/exporters/html/__snapshots__/image/basic/external.html +0 -1
  182. package/src/api/exporters/html/__snapshots__/image/basic/internal.html +0 -1
  183. package/src/api/exporters/html/__snapshots__/image/button/external.html +0 -1
  184. package/src/api/exporters/html/__snapshots__/image/button/internal.html +0 -1
  185. package/src/api/exporters/html/__snapshots__/image/nested/external.html +0 -1
  186. package/src/api/exporters/html/__snapshots__/image/nested/internal.html +0 -1
  187. package/src/api/exporters/html/__snapshots__/image/noCaption/external.html +0 -1
  188. package/src/api/exporters/html/__snapshots__/image/noCaption/internal.html +0 -1
  189. package/src/api/exporters/html/__snapshots__/image/noName/external.html +0 -1
  190. package/src/api/exporters/html/__snapshots__/image/noName/internal.html +0 -1
  191. package/src/api/exporters/html/__snapshots__/image/noPreview/external.html +0 -1
  192. package/src/api/exporters/html/__snapshots__/image/noPreview/internal.html +0 -1
  193. package/src/api/exporters/html/__snapshots__/link/adjacent/external.html +0 -1
  194. package/src/api/exporters/html/__snapshots__/link/adjacent/internal.html +0 -1
  195. package/src/api/exporters/html/__snapshots__/link/basic/external.html +0 -1
  196. package/src/api/exporters/html/__snapshots__/link/basic/internal.html +0 -1
  197. package/src/api/exporters/html/__snapshots__/link/styled/external.html +0 -1
  198. package/src/api/exporters/html/__snapshots__/link/styled/internal.html +0 -1
  199. package/src/api/exporters/html/__snapshots__/lists/basic/external.html +0 -1
  200. package/src/api/exporters/html/__snapshots__/lists/basic/internal.html +0 -1
  201. package/src/api/exporters/html/__snapshots__/lists/nested/external.html +0 -1
  202. package/src/api/exporters/html/__snapshots__/lists/nested/internal.html +0 -1
  203. package/src/api/exporters/html/__snapshots__/mention/basic/external.html +0 -1
  204. package/src/api/exporters/html/__snapshots__/mention/basic/internal.html +0 -1
  205. package/src/api/exporters/html/__snapshots__/pageBreak/basic/external.html +0 -1
  206. package/src/api/exporters/html/__snapshots__/pageBreak/basic/internal.html +0 -1
  207. package/src/api/exporters/html/__snapshots__/paragraph/basic/external.html +0 -1
  208. package/src/api/exporters/html/__snapshots__/paragraph/basic/internal.html +0 -1
  209. package/src/api/exporters/html/__snapshots__/paragraph/empty/external.html +0 -1
  210. package/src/api/exporters/html/__snapshots__/paragraph/empty/internal.html +0 -1
  211. package/src/api/exporters/html/__snapshots__/paragraph/lineBreaks/external.html +0 -1
  212. package/src/api/exporters/html/__snapshots__/paragraph/lineBreaks/internal.html +0 -1
  213. package/src/api/exporters/html/__snapshots__/paragraph/nested/external.html +0 -1
  214. package/src/api/exporters/html/__snapshots__/paragraph/nested/internal.html +0 -1
  215. package/src/api/exporters/html/__snapshots__/paragraph/styled/external.html +0 -1
  216. package/src/api/exporters/html/__snapshots__/paragraph/styled/internal.html +0 -1
  217. package/src/api/exporters/html/__snapshots__/paste/parse-basic-block-types.json +0 -140
  218. package/src/api/exporters/html/__snapshots__/paste/parse-deep-nested-content.json +0 -240
  219. package/src/api/exporters/html/__snapshots__/paste/parse-div-with-inline-content.json +0 -91
  220. package/src/api/exporters/html/__snapshots__/paste/parse-divs.json +0 -19
  221. package/src/api/exporters/html/__snapshots__/paste/parse-fake-image-caption.json +0 -31
  222. package/src/api/exporters/html/__snapshots__/paste/parse-mixed-nested-lists.json +0 -70
  223. package/src/api/exporters/html/__snapshots__/paste/parse-nested-lists-with-paragraphs.json +0 -70
  224. package/src/api/exporters/html/__snapshots__/paste/parse-nested-lists.json +0 -70
  225. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/basic/external.html +0 -1
  226. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/basic/internal.html +0 -1
  227. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/nested/external.html +0 -1
  228. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/nested/internal.html +0 -1
  229. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/styled/external.html +0 -1
  230. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/styled/internal.html +0 -1
  231. package/src/api/exporters/html/__snapshots__/simpleFile/basic/external.html +0 -1
  232. package/src/api/exporters/html/__snapshots__/simpleFile/basic/internal.html +0 -1
  233. package/src/api/exporters/html/__snapshots__/simpleFile/button/external.html +0 -1
  234. package/src/api/exporters/html/__snapshots__/simpleFile/button/internal.html +0 -1
  235. package/src/api/exporters/html/__snapshots__/simpleFile/nested/external.html +0 -1
  236. package/src/api/exporters/html/__snapshots__/simpleFile/nested/internal.html +0 -1
  237. package/src/api/exporters/html/__snapshots__/simpleImage/basic/external.html +0 -1
  238. package/src/api/exporters/html/__snapshots__/simpleImage/basic/internal.html +0 -1
  239. package/src/api/exporters/html/__snapshots__/simpleImage/button/external.html +0 -1
  240. package/src/api/exporters/html/__snapshots__/simpleImage/button/internal.html +0 -1
  241. package/src/api/exporters/html/__snapshots__/simpleImage/nested/external.html +0 -1
  242. package/src/api/exporters/html/__snapshots__/simpleImage/nested/internal.html +0 -1
  243. package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/external.html +0 -1
  244. package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/internal.html +0 -1
  245. package/src/api/exporters/html/__snapshots__/simpleImage/noName/external.html +0 -1
  246. package/src/api/exporters/html/__snapshots__/simpleImage/noName/internal.html +0 -1
  247. package/src/api/exporters/html/__snapshots__/simpleImage/noPreview/external.html +0 -1
  248. package/src/api/exporters/html/__snapshots__/simpleImage/noPreview/internal.html +0 -1
  249. package/src/api/exporters/html/__snapshots__/small/basic/external.html +0 -1
  250. package/src/api/exporters/html/__snapshots__/small/basic/internal.html +0 -1
  251. package/src/api/exporters/html/__snapshots__/table/allColWidths/external.html +0 -1
  252. package/src/api/exporters/html/__snapshots__/table/allColWidths/internal.html +0 -1
  253. package/src/api/exporters/html/__snapshots__/table/basic/external.html +0 -1
  254. package/src/api/exporters/html/__snapshots__/table/basic/internal.html +0 -1
  255. package/src/api/exporters/html/__snapshots__/table/headerCols/external.html +0 -1
  256. package/src/api/exporters/html/__snapshots__/table/headerCols/internal.html +0 -1
  257. package/src/api/exporters/html/__snapshots__/table/headerRows/external.html +0 -1
  258. package/src/api/exporters/html/__snapshots__/table/headerRows/internal.html +0 -1
  259. package/src/api/exporters/html/__snapshots__/table/headersRows/external.html +0 -1
  260. package/src/api/exporters/html/__snapshots__/table/headersRows/internal.html +0 -1
  261. package/src/api/exporters/html/__snapshots__/table/mixedCellColors/external.html +0 -1
  262. package/src/api/exporters/html/__snapshots__/table/mixedCellColors/internal.html +0 -1
  263. package/src/api/exporters/html/__snapshots__/table/mixedColWidths/external.html +0 -1
  264. package/src/api/exporters/html/__snapshots__/table/mixedColWidths/internal.html +0 -1
  265. package/src/api/exporters/html/__snapshots__/table/mixedRowspansAndColspans/external.html +0 -1
  266. package/src/api/exporters/html/__snapshots__/table/mixedRowspansAndColspans/internal.html +0 -1
  267. package/src/api/exporters/html/__snapshots__/tag/basic/external.html +0 -1
  268. package/src/api/exporters/html/__snapshots__/tag/basic/internal.html +0 -1
  269. package/src/api/exporters/html/htmlConversion.test.ts +0 -110
  270. package/src/api/exporters/markdown/__snapshots__/codeBlock/contains-newlines/markdown.md +0 -4
  271. package/src/api/exporters/markdown/__snapshots__/codeBlock/defaultLanguage/markdown.md +0 -3
  272. package/src/api/exporters/markdown/__snapshots__/codeBlock/empty/markdown.md +0 -2
  273. package/src/api/exporters/markdown/__snapshots__/codeBlock/python/markdown.md +0 -3
  274. package/src/api/exporters/markdown/__snapshots__/complex/misc/markdown.md +0 -5
  275. package/src/api/exporters/markdown/__snapshots__/customBlock/basic/markdown.md +0 -5
  276. package/src/api/exporters/markdown/__snapshots__/customParagraph/basic/markdown.md +0 -1
  277. package/src/api/exporters/markdown/__snapshots__/customParagraph/lineBreaks/markdown.md +0 -1
  278. package/src/api/exporters/markdown/__snapshots__/customParagraph/nested/markdown.md +0 -5
  279. package/src/api/exporters/markdown/__snapshots__/customParagraph/styled/markdown.md +0 -1
  280. package/src/api/exporters/markdown/__snapshots__/file/basic/markdown.md +0 -3
  281. package/src/api/exporters/markdown/__snapshots__/file/button/markdown.md +0 -1
  282. package/src/api/exporters/markdown/__snapshots__/file/nested/markdown.md +0 -7
  283. package/src/api/exporters/markdown/__snapshots__/file/noCaption/markdown.md +0 -1
  284. package/src/api/exporters/markdown/__snapshots__/file/noName/markdown.md +0 -3
  285. package/src/api/exporters/markdown/__snapshots__/fontSize/basic/markdown.md +0 -1
  286. package/src/api/exporters/markdown/__snapshots__/hardbreak/basic/markdown.md +0 -2
  287. package/src/api/exporters/markdown/__snapshots__/hardbreak/between-links/markdown.md +0 -2
  288. package/src/api/exporters/markdown/__snapshots__/hardbreak/end/markdown.md +0 -1
  289. package/src/api/exporters/markdown/__snapshots__/hardbreak/link/markdown.md +0 -2
  290. package/src/api/exporters/markdown/__snapshots__/hardbreak/multiple/markdown.md +0 -3
  291. package/src/api/exporters/markdown/__snapshots__/hardbreak/only/markdown.md +0 -0
  292. package/src/api/exporters/markdown/__snapshots__/hardbreak/start/markdown.md +0 -1
  293. package/src/api/exporters/markdown/__snapshots__/hardbreak/styles/markdown.md +0 -2
  294. package/src/api/exporters/markdown/__snapshots__/image/basic/markdown.md +0 -3
  295. package/src/api/exporters/markdown/__snapshots__/image/button/markdown.md +0 -1
  296. package/src/api/exporters/markdown/__snapshots__/image/nested/markdown.md +0 -7
  297. package/src/api/exporters/markdown/__snapshots__/image/noCaption/markdown.md +0 -1
  298. package/src/api/exporters/markdown/__snapshots__/image/noName/markdown.md +0 -3
  299. package/src/api/exporters/markdown/__snapshots__/image/noPreview/markdown.md +0 -3
  300. package/src/api/exporters/markdown/__snapshots__/link/adjacent/markdown.md +0 -1
  301. package/src/api/exporters/markdown/__snapshots__/link/basic/markdown.md +0 -1
  302. package/src/api/exporters/markdown/__snapshots__/link/styled/markdown.md +0 -1
  303. package/src/api/exporters/markdown/__snapshots__/lists/basic/markdown.md +0 -10
  304. package/src/api/exporters/markdown/__snapshots__/lists/nested/markdown.md +0 -10
  305. package/src/api/exporters/markdown/__snapshots__/mention/basic/markdown.md +0 -1
  306. package/src/api/exporters/markdown/__snapshots__/pageBreak/basic/markdown.md +0 -0
  307. package/src/api/exporters/markdown/__snapshots__/paragraph/basic/markdown.md +0 -1
  308. package/src/api/exporters/markdown/__snapshots__/paragraph/empty/markdown.md +0 -0
  309. package/src/api/exporters/markdown/__snapshots__/paragraph/lineBreaks/markdown.md +0 -2
  310. package/src/api/exporters/markdown/__snapshots__/paragraph/nested/markdown.md +0 -5
  311. package/src/api/exporters/markdown/__snapshots__/paragraph/styled/markdown.md +0 -1
  312. package/src/api/exporters/markdown/__snapshots__/simpleCustomParagraph/basic/markdown.md +0 -1
  313. package/src/api/exporters/markdown/__snapshots__/simpleCustomParagraph/nested/markdown.md +0 -5
  314. package/src/api/exporters/markdown/__snapshots__/simpleCustomParagraph/styled/markdown.md +0 -1
  315. package/src/api/exporters/markdown/__snapshots__/simpleFile/basic/markdown.md +0 -3
  316. package/src/api/exporters/markdown/__snapshots__/simpleFile/button/markdown.md +0 -1
  317. package/src/api/exporters/markdown/__snapshots__/simpleFile/nested/markdown.md +0 -7
  318. package/src/api/exporters/markdown/__snapshots__/simpleImage/basic/markdown.md +0 -3
  319. package/src/api/exporters/markdown/__snapshots__/simpleImage/button/markdown.md +0 -1
  320. package/src/api/exporters/markdown/__snapshots__/simpleImage/nested/markdown.md +0 -7
  321. package/src/api/exporters/markdown/__snapshots__/simpleImage/noCaption/markdown.md +0 -1
  322. package/src/api/exporters/markdown/__snapshots__/simpleImage/noName/markdown.md +0 -3
  323. package/src/api/exporters/markdown/__snapshots__/simpleImage/noPreview/markdown.md +0 -3
  324. package/src/api/exporters/markdown/__snapshots__/small/basic/markdown.md +0 -1
  325. package/src/api/exporters/markdown/__snapshots__/table/allColWidths/markdown.md +0 -5
  326. package/src/api/exporters/markdown/__snapshots__/table/basic/markdown.md +0 -5
  327. package/src/api/exporters/markdown/__snapshots__/table/headerCols/markdown.md +0 -4
  328. package/src/api/exporters/markdown/__snapshots__/table/headerRows/markdown.md +0 -4
  329. package/src/api/exporters/markdown/__snapshots__/table/mixedCellColors/markdown.md +0 -5
  330. package/src/api/exporters/markdown/__snapshots__/table/mixedColWidths/markdown.md +0 -5
  331. package/src/api/exporters/markdown/__snapshots__/table/mixedRowspansAndColspans/markdown.md +0 -5
  332. package/src/api/exporters/markdown/__snapshots__/tag/basic/markdown.md +0 -1
  333. package/src/api/exporters/markdown/markdownExporter.test.ts +0 -86
  334. package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +0 -3473
  335. package/src/api/nodeConversions/nodeConversions.test.ts +0 -83
  336. package/src/api/parsers/html/__snapshots__/list-test.json +0 -177
  337. package/src/api/parsers/html/__snapshots__/parse-2-tables.json +0 -129
  338. package/src/api/parsers/html/__snapshots__/parse-basic-block-types.json +0 -142
  339. package/src/api/parsers/html/__snapshots__/parse-codeblocks.json +0 -62
  340. package/src/api/parsers/html/__snapshots__/parse-div-with-inline-content.json +0 -91
  341. package/src/api/parsers/html/__snapshots__/parse-divs.json +0 -121
  342. package/src/api/parsers/html/__snapshots__/parse-fake-image-caption.json +0 -33
  343. package/src/api/parsers/html/__snapshots__/parse-image-in-paragraph.json +0 -16
  344. package/src/api/parsers/html/__snapshots__/parse-mixed-nested-lists.json +0 -265
  345. package/src/api/parsers/html/__snapshots__/parse-nested-lists-with-paragraphs.json +0 -265
  346. package/src/api/parsers/html/__snapshots__/parse-nested-lists.json +0 -265
  347. package/src/api/parsers/html/__snapshots__/parse-notion-html.json +0 -565
  348. package/src/api/parsers/html/__snapshots__/parse-two-divs.json +0 -36
  349. package/src/api/parsers/html/parseHTML.test.ts +0 -563
  350. package/src/api/parsers/markdown/__snapshots__/complex.json +0 -353
  351. package/src/api/parsers/markdown/__snapshots__/issue-226-1.json +0 -71
  352. package/src/api/parsers/markdown/__snapshots__/issue-226-2.json +0 -144
  353. package/src/api/parsers/markdown/__snapshots__/nested.json +0 -72
  354. package/src/api/parsers/markdown/__snapshots__/non-nested.json +0 -71
  355. package/src/api/parsers/markdown/__snapshots__/pasted/complex.json +0 -319
  356. package/src/api/parsers/markdown/__snapshots__/pasted/issue-226-1.json +0 -81
  357. package/src/api/parsers/markdown/__snapshots__/pasted/issue-226-2.json +0 -165
  358. package/src/api/parsers/markdown/__snapshots__/pasted/nested.json +0 -81
  359. package/src/api/parsers/markdown/__snapshots__/pasted/non-nested.json +0 -81
  360. package/src/api/parsers/markdown/__snapshots__/pasted/styled.json +0 -61
  361. package/src/api/parsers/markdown/__snapshots__/pasted/whitespace bold.json +0 -42
  362. package/src/api/parsers/markdown/__snapshots__/styled.json +0 -58
  363. package/src/api/parsers/markdown/__snapshots__/whitespace bold.json +0 -19
  364. package/src/api/parsers/markdown/parseMarkdown.test.ts +0 -135
  365. package/src/api/testUtil/cases/customBlocks.ts +0 -342
  366. package/src/api/testUtil/cases/customInlineContent.ts +0 -113
  367. package/src/api/testUtil/cases/customStyles.ts +0 -102
  368. package/src/api/testUtil/cases/defaultSchema.ts +0 -1493
  369. package/src/api/testUtil/index.ts +0 -19
  370. package/src/api/testUtil/partialBlockTestUtil.ts +0 -198
  371. package/src/api/testUtil/paste.ts +0 -46
  372. package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.d.ts +0 -4
  373. package/types/src/api/clipboard/clipboardInternal.test.d.ts +0 -1
  374. package/types/src/api/clipboard/testUtil.d.ts +0 -541
  375. package/types/src/api/exporters/html/htmlConversion.test.d.ts +0 -1
  376. package/types/src/api/exporters/markdown/markdownExporter.test.d.ts +0 -1
  377. package/types/src/api/nodeConversions/nodeConversions.test.d.ts +0 -1
  378. package/types/src/api/parsers/html/parseHTML.test.d.ts +0 -1
  379. package/types/src/api/parsers/markdown/parseMarkdown.test.d.ts +0 -1
  380. package/types/src/api/testUtil/cases/customBlocks.d.ts +0 -670
  381. package/types/src/api/testUtil/cases/customInlineContent.d.ts +0 -558
  382. package/types/src/api/testUtil/cases/customStyles.d.ts +0 -552
  383. package/types/src/api/testUtil/cases/defaultSchema.d.ts +0 -4
  384. package/types/src/api/testUtil/index.d.ts +0 -14
  385. package/types/src/api/testUtil/partialBlockTestUtil.d.ts +0 -9
  386. package/types/src/api/testUtil/paste.d.ts +0 -2
  387. /package/types/src/api/{blockManipulation/commands/removeBlocks/removeBlocks.test.d.ts → nodeUtil.test.d.ts} +0 -0
  388. /package/types/src/api/{clipboard/clipboardExternal.test.d.ts → positionMapping.test.d.ts} +0 -0
@@ -0,0 +1,370 @@
1
+ import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
2
+ import * as Y from "yjs";
3
+ import { BlockNoteEditor } from "../editor/BlockNoteEditor.js";
4
+ import { trackPosition } from "./positionMapping.js";
5
+
6
+ describe("PositionStorage with local editor", () => {
7
+ let editor: BlockNoteEditor;
8
+
9
+ beforeEach(() => {
10
+ editor = BlockNoteEditor.create();
11
+ editor.mount(document.createElement("div"));
12
+ });
13
+
14
+ afterEach(() => {
15
+ editor.mount(undefined);
16
+ editor._tiptapEditor.destroy();
17
+ });
18
+
19
+ describe("mount and unmount", () => {
20
+ it("should register transaction handler on creation", () => {
21
+ editor._tiptapEditor.on = vi.fn();
22
+ trackPosition(editor, 0);
23
+
24
+ expect(editor._tiptapEditor.on).toHaveBeenCalledWith(
25
+ "transaction",
26
+ expect.any(Function)
27
+ );
28
+ });
29
+ });
30
+
31
+ describe("set and get positions", () => {
32
+ it("should store and retrieve positions without Y.js", () => {
33
+ const getPos = trackPosition(editor, 10);
34
+
35
+ expect(getPos()).toBe(10);
36
+ });
37
+
38
+ it("should handle right side positions", () => {
39
+ const getPos = trackPosition(editor, 10, "right");
40
+
41
+ expect(getPos()).toBe(10);
42
+ });
43
+ });
44
+
45
+ it("should update mapping for local transactions before the position", () => {
46
+ // Set initial content
47
+ editor.insertBlocks(
48
+ [
49
+ {
50
+ id: "1",
51
+ type: "paragraph",
52
+ content: [
53
+ {
54
+ type: "text",
55
+ text: "Hello World",
56
+ styles: {},
57
+ },
58
+ ],
59
+ },
60
+ ],
61
+ editor.document[0],
62
+ "before"
63
+ );
64
+
65
+ // Start tracking
66
+ const getPos = trackPosition(editor, 10);
67
+
68
+ // Move the cursor to the start of the document
69
+ editor.setTextCursorPosition(editor.document[0], "start");
70
+
71
+ // Insert text at the start of the document
72
+ editor.insertInlineContent([
73
+ {
74
+ type: "text",
75
+ text: "Test",
76
+ styles: {},
77
+ },
78
+ ]);
79
+
80
+ // Position should be updated according to mapping
81
+ expect(getPos()).toBe(14);
82
+ });
83
+
84
+ it("should not update mapping for local transactions after the position", () => {
85
+ // Set initial content
86
+ editor.insertBlocks(
87
+ [
88
+ {
89
+ id: "1",
90
+ type: "paragraph",
91
+ content: [
92
+ {
93
+ type: "text",
94
+ text: "Hello World",
95
+ styles: {},
96
+ },
97
+ ],
98
+ },
99
+ ],
100
+ editor.document[0],
101
+ "before"
102
+ );
103
+ // Start tracking
104
+ const getPos = trackPosition(editor, 10);
105
+
106
+ // Move the cursor to the end of the document
107
+ editor.setTextCursorPosition(editor.document[0], "end");
108
+
109
+ // Insert text at the end of the document
110
+ editor.insertInlineContent([
111
+ {
112
+ type: "text",
113
+ text: "Test",
114
+ styles: {},
115
+ },
116
+ ]);
117
+
118
+ // Position should not be updated
119
+ expect(getPos()).toBe(10);
120
+ });
121
+
122
+ it("should track positions on each side", () => {
123
+ editor.replaceBlocks(editor.document, [
124
+ {
125
+ type: "paragraph",
126
+ content: "Hello World",
127
+ },
128
+ ]);
129
+
130
+ // Store position at "Hello| World"
131
+ const getCursorPos = trackPosition(editor, 6);
132
+ const getStartPos = trackPosition(editor, 3);
133
+ const getStartRightPos = trackPosition(editor, 3, "right");
134
+ const getPosAfterPos = trackPosition(editor, 4);
135
+ const getPosAfterRightPos = trackPosition(editor, 4, "right");
136
+ // Insert text at the beginning
137
+ editor._tiptapEditor.commands.insertContentAt(3, "Test ");
138
+
139
+ // Position should be updated
140
+ expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
141
+ expect(getStartPos()).toBe(3); // 3
142
+ expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
143
+ expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
144
+ expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
145
+ });
146
+
147
+ it("should handle multiple transactions", () => {
148
+ editor.replaceBlocks(editor.document, [
149
+ {
150
+ type: "paragraph",
151
+ content: "Hello World",
152
+ },
153
+ ]);
154
+
155
+ // Store position at "Hello| World"
156
+ const getCursorPos = trackPosition(editor, 6);
157
+ const getStartPos = trackPosition(editor, 3);
158
+ const getStartRightPos = trackPosition(editor, 3, "right");
159
+ const getPosAfterPos = trackPosition(editor, 4);
160
+ const getPosAfterRightPos = trackPosition(editor, 4, "right");
161
+
162
+ // Insert text at the beginning
163
+ editor._tiptapEditor.commands.insertContentAt(3, "T");
164
+ editor._tiptapEditor.commands.insertContentAt(4, "e");
165
+ editor._tiptapEditor.commands.insertContentAt(5, "s");
166
+ editor._tiptapEditor.commands.insertContentAt(6, "t");
167
+ editor._tiptapEditor.commands.insertContentAt(7, " ");
168
+
169
+ // Position should be updated
170
+ expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
171
+ expect(getStartPos()).toBe(3); // 3
172
+ expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
173
+ expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
174
+ expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
175
+ });
176
+ });
177
+
178
+ describe("PositionStorage with remote editor", () => {
179
+ // Function to sync two documents
180
+ function syncDocs(sourceDoc: Y.Doc, targetDoc: Y.Doc) {
181
+ // Create update message from source
182
+ const update = Y.encodeStateAsUpdate(sourceDoc);
183
+
184
+ // Apply update to target
185
+ Y.applyUpdate(targetDoc, update);
186
+ }
187
+
188
+ // Set up two-way sync
189
+ function setupTwoWaySync(doc1: Y.Doc, doc2: Y.Doc) {
190
+ // Sync initial states
191
+ syncDocs(doc1, doc2);
192
+ syncDocs(doc2, doc1);
193
+
194
+ // Set up observers for future changes
195
+ doc1.on("update", (update: Uint8Array) => {
196
+ Y.applyUpdate(doc2, update);
197
+ });
198
+
199
+ doc2.on("update", (update: Uint8Array) => {
200
+ Y.applyUpdate(doc1, update);
201
+ });
202
+ }
203
+
204
+ describe("remote editor", () => {
205
+ let localEditor: BlockNoteEditor;
206
+ let remoteEditor: BlockNoteEditor;
207
+ let ydoc: Y.Doc;
208
+ let remoteYdoc: Y.Doc;
209
+
210
+ beforeEach(() => {
211
+ ydoc = new Y.Doc();
212
+ remoteYdoc = new Y.Doc();
213
+ // Create a mock editor
214
+ localEditor = BlockNoteEditor.create({
215
+ collaboration: {
216
+ fragment: ydoc.getXmlFragment("doc"),
217
+ user: { color: "#ff0000", name: "Local User" },
218
+ provider: undefined,
219
+ },
220
+ });
221
+ const div = document.createElement("div");
222
+ localEditor.mount(div);
223
+
224
+ remoteEditor = BlockNoteEditor.create({
225
+ collaboration: {
226
+ fragment: remoteYdoc.getXmlFragment("doc"),
227
+ user: { color: "#ff0000", name: "Remote User" },
228
+ provider: undefined,
229
+ },
230
+ });
231
+
232
+ const remoteDiv = document.createElement("div");
233
+ remoteEditor.mount(remoteDiv);
234
+ setupTwoWaySync(ydoc, remoteYdoc);
235
+ });
236
+
237
+ afterEach(() => {
238
+ ydoc.destroy();
239
+ remoteYdoc.destroy();
240
+ localEditor.mount(undefined);
241
+ localEditor._tiptapEditor.destroy();
242
+ remoteEditor.mount(undefined);
243
+ remoteEditor._tiptapEditor.destroy();
244
+ });
245
+
246
+ it("should update the local position when collaborating", () => {
247
+ localEditor.replaceBlocks(localEditor.document, [
248
+ {
249
+ type: "paragraph",
250
+ content: "Hello World",
251
+ },
252
+ ]);
253
+
254
+ // Store position at "Hello| World"
255
+ const getCursorPos = trackPosition(localEditor, 6);
256
+ // Store position at "|Hello World"
257
+ const getStartPos = trackPosition(localEditor, 3);
258
+ // Store position at "|Hello World" (but on the right side)
259
+ const getStartRightPos = trackPosition(localEditor, 3, "right");
260
+ // Store position at "H|ello World"
261
+ const getPosAfterPos = trackPosition(localEditor, 4);
262
+ // Store position at "H|ello World" (but on the right side)
263
+ const getPosAfterRightPos = trackPosition(localEditor, 4, "right");
264
+
265
+ // Insert text at the beginning
266
+ localEditor._tiptapEditor.commands.insertContentAt(3, "Test ");
267
+
268
+ // Position should be updated
269
+ expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
270
+ expect(getStartPos()).toBe(3); // 3
271
+ expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
272
+ expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
273
+ expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
274
+ });
275
+
276
+ it("should handle multiple transactions when collaborating", () => {
277
+ localEditor.replaceBlocks(localEditor.document, [
278
+ {
279
+ type: "paragraph",
280
+ content: "Hello World",
281
+ },
282
+ ]);
283
+
284
+ // Store position at "Hello| World"
285
+ const getCursorPos = trackPosition(localEditor, 6);
286
+ // Store position at "|Hello World"
287
+ const getStartPos = trackPosition(localEditor, 3);
288
+ // Store position at "|Hello World" (but on the right side)
289
+ const getStartRightPos = trackPosition(localEditor, 3, "right");
290
+ // Store position at "H|ello World"
291
+ const getPosAfterPos = trackPosition(localEditor, 4);
292
+ // Store position at "H|ello World" (but on the right side)
293
+ const getPosAfterRightPos = trackPosition(localEditor, 4, "right");
294
+
295
+ // Insert text at the beginning
296
+ localEditor._tiptapEditor.commands.insertContentAt(3, "T");
297
+ localEditor._tiptapEditor.commands.insertContentAt(4, "e");
298
+ localEditor._tiptapEditor.commands.insertContentAt(5, "s");
299
+ localEditor._tiptapEditor.commands.insertContentAt(6, "t");
300
+ localEditor._tiptapEditor.commands.insertContentAt(7, " ");
301
+
302
+ // Position should be updated
303
+ expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
304
+ expect(getStartPos()).toBe(3); // 3
305
+ expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
306
+ expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
307
+ expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
308
+ });
309
+
310
+ it("should update the local position from a remote transaction", () => {
311
+ remoteEditor.replaceBlocks(remoteEditor.document, [
312
+ {
313
+ type: "paragraph",
314
+ content: "Hello World",
315
+ },
316
+ ]);
317
+
318
+ // Store position at "Hello| World"
319
+ const getCursorPos = trackPosition(localEditor, 6);
320
+ // Store position at "|Hello World"
321
+ const getStartPos = trackPosition(localEditor, 3);
322
+ // Store position at "|Hello World" (but on the right side)
323
+ const getStartRightPos = trackPosition(localEditor, 3, "right");
324
+ // Store position at "H|ello World"
325
+ const getPosAfterPos = trackPosition(localEditor, 4);
326
+ // Store position at "H|ello World" (but on the right side)
327
+ const getPosAfterRightPos = trackPosition(localEditor, 4, "right");
328
+
329
+ // Insert text at the beginning
330
+ localEditor._tiptapEditor.commands.insertContentAt(3, "Test ");
331
+
332
+ // Position should be updated
333
+ expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
334
+ expect(getStartPos()).toBe(3); // 3
335
+ expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
336
+ expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
337
+ expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
338
+ });
339
+
340
+ it("should update the remote position from a remote transaction", () => {
341
+ remoteEditor.replaceBlocks(remoteEditor.document, [
342
+ {
343
+ type: "paragraph",
344
+ content: "Hello World",
345
+ },
346
+ ]);
347
+
348
+ // Store position at "Hello| World"
349
+ const getCursorPos = trackPosition(remoteEditor, 6);
350
+ // Store position at "|Hello World"
351
+ const getStartPos = trackPosition(remoteEditor, 3);
352
+ // Store position at "|Hello World" (but on the right side)
353
+ const getStartRightPos = trackPosition(remoteEditor, 3, "right");
354
+ // Store position at "H|ello World"
355
+ const getPosAfterPos = trackPosition(remoteEditor, 4);
356
+ // Store position at "H|ello World" (but on the right side)
357
+ const getPosAfterRightPos = trackPosition(remoteEditor, 4, "right");
358
+
359
+ // Insert text at the beginning
360
+ localEditor._tiptapEditor.commands.insertContentAt(3, "Test ");
361
+
362
+ // Position should be updated
363
+ expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
364
+ expect(getStartPos()).toBe(3); // 3
365
+ expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
366
+ expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
367
+ expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
368
+ });
369
+ });
370
+ });
@@ -0,0 +1,114 @@
1
+ import { Mapping } from "prosemirror-transform";
2
+ import {
3
+ absolutePositionToRelativePosition,
4
+ relativePositionToAbsolutePosition,
5
+ ySyncPluginKey,
6
+ } from "y-prosemirror";
7
+ import type { BlockNoteEditor } from "../editor/BlockNoteEditor.js";
8
+ import * as Y from "yjs";
9
+ import type { ProsemirrorBinding } from "y-prosemirror";
10
+
11
+ /**
12
+ * This is used to track a mapping for each editor. The mapping stores the mappings for each transaction since the first transaction that was tracked.
13
+ */
14
+ const editorToMapping = new Map<BlockNoteEditor<any, any, any>, Mapping>();
15
+
16
+ /**
17
+ * This initializes a single mapping for an editor instance.
18
+ */
19
+ function getMapping(editor: BlockNoteEditor<any, any, any>) {
20
+ if (editorToMapping.has(editor)) {
21
+ // Mapping already initialized, so we don't need to do anything
22
+ return editorToMapping.get(editor)!;
23
+ }
24
+ const mapping = new Mapping();
25
+ editor._tiptapEditor.on("transaction", ({ transaction }) => {
26
+ mapping.appendMapping(transaction.mapping);
27
+ });
28
+ editor._tiptapEditor.on("destroy", () => {
29
+ // Cleanup the mapping when the editor is destroyed
30
+ editorToMapping.delete(editor);
31
+ });
32
+
33
+ // There only is one mapping per editor, so we can just set it
34
+ editorToMapping.set(editor, mapping);
35
+
36
+ return mapping;
37
+ }
38
+
39
+ /**
40
+ * This is used to keep track of positions of elements in the editor.
41
+ * It is needed because y-prosemirror's sync plugin can disrupt normal prosemirror position mapping.
42
+ *
43
+ * It is specifically made to be able to be used whether the editor is being used in a collaboratively, or single user, providing the same API.
44
+ *
45
+ * @param editor The editor to track the position of.
46
+ * @param position The position to track.
47
+ * @param side The side of the position to track. "left" is the default. "right" would move with the change if the change is in the right direction.
48
+ * @returns A function that returns the position of the element.
49
+ */
50
+ export function trackPosition(
51
+ /**
52
+ * The editor to track the position of.
53
+ */
54
+ editor: BlockNoteEditor<any, any, any>,
55
+ /**
56
+ * The position to track.
57
+ */
58
+ position: number,
59
+ /**
60
+ * This is the side of the position to track. "left" is the default. "right" would move with the change if the change is in the right direction.
61
+ */
62
+ side: "left" | "right" = "left"
63
+ ): () => number {
64
+ const ySyncPluginState = ySyncPluginKey.getState(
65
+ editor._tiptapEditor.state
66
+ ) as {
67
+ doc: Y.Doc;
68
+ binding: ProsemirrorBinding;
69
+ };
70
+
71
+ if (!ySyncPluginState) {
72
+ // No y-prosemirror sync plugin, so we need to track the mapping manually
73
+ // This will initialize the mapping for this editor, if needed
74
+ const mapping = getMapping(editor);
75
+
76
+ // This is the start point of tracking the mapping
77
+ const trackedMapLength = mapping.maps.length;
78
+
79
+ return () => {
80
+ const pos = mapping
81
+ // Only read the history of the mapping that we care about
82
+ .slice(trackedMapLength)
83
+ .map(position, side === "left" ? -1 : 1);
84
+
85
+ return pos;
86
+ };
87
+ }
88
+
89
+ const relativePosition = absolutePositionToRelativePosition(
90
+ // Track the position after the position if we are on the right side
91
+ position + (side === "right" ? 1 : 0),
92
+ ySyncPluginState.binding.type,
93
+ ySyncPluginState.binding.mapping
94
+ );
95
+
96
+ return () => {
97
+ const curYSyncPluginState = ySyncPluginKey.getState(
98
+ editor._tiptapEditor.state
99
+ ) as typeof ySyncPluginState;
100
+ const pos = relativePositionToAbsolutePosition(
101
+ curYSyncPluginState.doc,
102
+ curYSyncPluginState.binding.type,
103
+ relativePosition,
104
+ curYSyncPluginState.binding.mapping
105
+ );
106
+
107
+ // This can happen if the element is garbage collected
108
+ if (pos === null) {
109
+ throw new Error("Position not found, cannot track positions");
110
+ }
111
+
112
+ return pos + (side === "right" ? -1 : 0);
113
+ };
114
+ }
@@ -32,8 +32,8 @@ export const createAddFileButton = (
32
32
  };
33
33
  // Opens the file toolbar.
34
34
  const addFileButtonClickHandler = () => {
35
- editor.dispatch(
36
- editor._tiptapEditor.state.tr.setMeta(editor.filePanel!.plugin, {
35
+ editor.transact((tr) =>
36
+ tr.setMeta(editor.filePanel!.plugin, {
37
37
  block: block,
38
38
  })
39
39
  );
@@ -41,16 +41,12 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({
41
41
 
42
42
  chain()
43
43
  .command(
44
- updateBlockCommand(
45
- this.options.editor,
46
- blockInfo.bnBlock.beforePos,
47
- {
48
- type: "heading",
49
- props: {
50
- level: level as any,
51
- },
52
- }
53
- )
44
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
45
+ type: "heading",
46
+ props: {
47
+ level: level as any,
48
+ },
49
+ })
54
50
  )
55
51
  // Removes the "#" character(s) used to set the heading.
56
52
  .deleteRange({ from: range.from, to: range.to })
@@ -74,7 +70,7 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({
74
70
 
75
71
  // call updateBlockCommand
76
72
  return this.editor.commands.command(
77
- updateBlockCommand(this.options.editor, blockInfo.bnBlock.beforePos, {
73
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
78
74
  type: "heading",
79
75
  props: {
80
76
  level: 1 as any,
@@ -92,7 +88,7 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({
92
88
  }
93
89
 
94
90
  return this.editor.commands.command(
95
- updateBlockCommand(this.options.editor, blockInfo.bnBlock.beforePos, {
91
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
96
92
  type: "heading",
97
93
  props: {
98
94
  level: 2 as any,
@@ -110,7 +106,7 @@ const HeadingBlockContent = createStronglyTypedTiptapNode({
110
106
  }
111
107
 
112
108
  return this.editor.commands.command(
113
- updateBlockCommand(this.options.editor, blockInfo.bnBlock.beforePos, {
109
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
114
110
  type: "heading",
115
111
  props: {
116
112
  level: 3 as any,
@@ -37,14 +37,10 @@ const BulletListItemBlockContent = createStronglyTypedTiptapNode({
37
37
 
38
38
  chain()
39
39
  .command(
40
- updateBlockCommand(
41
- this.options.editor,
42
- blockInfo.bnBlock.beforePos,
43
- {
44
- type: "bulletListItem",
45
- props: {},
46
- }
47
- )
40
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
41
+ type: "bulletListItem",
42
+ props: {},
43
+ })
48
44
  )
49
45
  // Removes the "-", "+", or "*" character used to set the list.
50
46
  .deleteRange({ from: range.from, to: range.to });
@@ -66,7 +62,7 @@ const BulletListItemBlockContent = createStronglyTypedTiptapNode({
66
62
  }
67
63
 
68
64
  return this.editor.commands.command(
69
- updateBlockCommand(this.options.editor, blockInfo.bnBlock.beforePos, {
65
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
70
66
  type: "bulletListItem",
71
67
  props: {},
72
68
  })
@@ -46,16 +46,12 @@ const checkListItemBlockContent = createStronglyTypedTiptapNode({
46
46
 
47
47
  chain()
48
48
  .command(
49
- updateBlockCommand(
50
- this.options.editor,
51
- blockInfo.bnBlock.beforePos,
52
- {
53
- type: "checkListItem",
54
- props: {
55
- checked: false as any,
56
- },
57
- }
58
- )
49
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
50
+ type: "checkListItem",
51
+ props: {
52
+ checked: false as any,
53
+ },
54
+ })
59
55
  )
60
56
  // Removes the characters used to set the list.
61
57
  .deleteRange({ from: range.from, to: range.to });
@@ -75,16 +71,12 @@ const checkListItemBlockContent = createStronglyTypedTiptapNode({
75
71
 
76
72
  chain()
77
73
  .command(
78
- updateBlockCommand(
79
- this.options.editor,
80
- blockInfo.bnBlock.beforePos,
81
- {
82
- type: "checkListItem",
83
- props: {
84
- checked: true as any,
85
- },
86
- }
87
- )
74
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
75
+ type: "checkListItem",
76
+ props: {
77
+ checked: true as any,
78
+ },
79
+ })
88
80
  )
89
81
  // Removes the characters used to set the list.
90
82
  .deleteRange({ from: range.from, to: range.to });
@@ -106,7 +98,7 @@ const checkListItemBlockContent = createStronglyTypedTiptapNode({
106
98
  }
107
99
 
108
100
  return this.editor.commands.command(
109
- updateBlockCommand(this.options.editor, blockInfo.bnBlock.beforePos, {
101
+ updateBlockCommand(blockInfo.bnBlock.beforePos, {
110
102
  type: "checkListItem",
111
103
  props: {},
112
104
  })
@@ -241,16 +233,12 @@ const checkListItemBlockContent = createStronglyTypedTiptapNode({
241
233
  }
242
234
 
243
235
  this.editor.commands.command(
244
- updateBlockCommand(
245
- this.options.editor,
246
- beforeBlockContainerPos.posBeforeNode,
247
- {
248
- type: "checkListItem",
249
- props: {
250
- checked: checkbox.checked as any,
251
- },
252
- }
253
- )
236
+ updateBlockCommand(beforeBlockContainerPos.posBeforeNode, {
237
+ type: "checkListItem",
238
+ props: {
239
+ checked: checkbox.checked as any,
240
+ },
241
+ })
254
242
  );
255
243
  }
256
244
  };