@blocknote/core 0.30.0 → 0.31.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 (245) hide show
  1. package/dist/blocknote.cjs +9 -9
  2. package/dist/blocknote.cjs.map +1 -1
  3. package/dist/blocknote.js +2771 -2245
  4. package/dist/blocknote.js.map +1 -1
  5. package/dist/comments.cjs.map +1 -1
  6. package/dist/comments.js.map +1 -1
  7. package/dist/{en-D4taoCs4.cjs → en-BXVKCwYt.cjs} +2 -2
  8. package/dist/en-BXVKCwYt.cjs.map +1 -0
  9. package/dist/{en-B7ycW7c8.js → en-qGo6sk9V.js} +2 -3
  10. package/dist/en-qGo6sk9V.js.map +1 -0
  11. package/dist/locales.cjs +1 -1
  12. package/dist/locales.cjs.map +1 -1
  13. package/dist/locales.js +20 -39
  14. package/dist/locales.js.map +1 -1
  15. package/dist/style.css +1 -1
  16. package/dist/webpack-stats.json +1 -1
  17. package/package.json +8 -7
  18. package/src/api/README.md +1 -1
  19. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.test.ts +19 -14
  20. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +7 -8
  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/moveBlocks.test.ts +14 -14
  24. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts +16 -16
  25. package/src/api/blockManipulation/commands/nestBlock/nestBlock.ts +8 -8
  26. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.test.ts +12 -12
  27. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +8 -8
  28. package/src/api/blockManipulation/commands/splitBlock/splitBlock.test.ts +10 -10
  29. package/src/api/blockManipulation/commands/splitBlock/splitBlock.ts +2 -2
  30. package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +2816 -0
  31. package/src/api/blockManipulation/commands/updateBlock/updateBlock.test.ts +200 -42
  32. package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +104 -34
  33. package/src/api/blockManipulation/getBlock/getBlock.ts +9 -9
  34. package/src/api/blockManipulation/insertContentAt.ts +1 -1
  35. package/src/api/blockManipulation/selections/selection.ts +59 -12
  36. package/src/api/blockManipulation/selections/{textCursorPosition/textCursorPosition.ts → textCursorPosition.ts} +13 -13
  37. package/src/api/blockManipulation/tables/tables.test.ts +106 -106
  38. package/src/api/blockManipulation/tables/tables.ts +35 -35
  39. package/src/api/clipboard/fromClipboard/fileDropExtension.ts +2 -2
  40. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +9 -9
  41. package/src/api/clipboard/fromClipboard/handleVSCodePaste.ts +3 -3
  42. package/src/api/clipboard/fromClipboard/pasteExtension.ts +3 -3
  43. package/src/api/clipboard/toClipboard/copyExtension.ts +22 -22
  44. package/src/api/exporters/html/externalHTMLExporter.ts +6 -6
  45. package/src/api/exporters/html/internalHTMLSerializer.ts +3 -3
  46. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +16 -16
  47. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +14 -14
  48. package/src/api/exporters/markdown/markdownExporter.ts +3 -3
  49. package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +3 -3
  50. package/src/api/getBlockInfoFromPos.ts +6 -6
  51. package/src/api/nodeConversions/blockToNode.ts +31 -28
  52. package/src/api/nodeConversions/fragmentToBlocks.ts +1 -1
  53. package/src/api/nodeConversions/nodeToBlock.ts +240 -41
  54. package/src/api/nodeUtil.test.ts +16 -16
  55. package/src/api/nodeUtil.ts +10 -10
  56. package/src/api/parsers/html/parseHTML.ts +1 -1
  57. package/src/api/parsers/html/util/nestedLists.ts +2 -2
  58. package/src/api/parsers/markdown/parseMarkdown.ts +1 -1
  59. package/src/api/pmUtil.ts +7 -7
  60. package/src/api/positionMapping.test.ts +3 -3
  61. package/src/api/positionMapping.ts +5 -5
  62. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +4 -4
  63. package/src/blocks/CodeBlockContent/CodeBlockContent.ts +18 -18
  64. package/src/blocks/FileBlockContent/FileBlockContent.ts +2 -2
  65. package/src/blocks/FileBlockContent/helpers/parse/parseFigureElement.ts +2 -2
  66. package/src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts +6 -6
  67. package/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts +2 -2
  68. package/src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.ts +1 -1
  69. package/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts +7 -7
  70. package/src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.ts +1 -1
  71. package/src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.ts +1 -1
  72. package/src/blocks/FileBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts +2 -2
  73. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +6 -6
  74. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +4 -4
  75. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +4 -4
  76. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +10 -10
  77. package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +1 -1
  78. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +1 -1
  79. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +4 -4
  80. package/src/blocks/ListItemBlockContent/getListItemContent.ts +5 -5
  81. package/src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts +1 -1
  82. package/src/blocks/PageBreakBlockContent/getPageBreakSlashMenuItems.ts +3 -3
  83. package/src/blocks/PageBreakBlockContent/schema.ts +2 -2
  84. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +3 -3
  85. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +4 -4
  86. package/src/blocks/README.md +1 -1
  87. package/src/blocks/TableBlockContent/TableBlockContent.ts +37 -7
  88. package/src/blocks/TableBlockContent/TableExtension.ts +3 -3
  89. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +4 -4
  90. package/src/blocks/defaultBlockHelpers.ts +8 -8
  91. package/src/blocks/defaultBlockTypeGuards.ts +16 -16
  92. package/src/blocks/defaultBlocks.ts +3 -3
  93. package/src/comments/threadstore/DefaultThreadStoreAuth.ts +3 -3
  94. package/src/comments/threadstore/ThreadStore.ts +1 -1
  95. package/src/comments/threadstore/TipTapThreadStore.ts +10 -10
  96. package/src/comments/threadstore/yjs/RESTYjsThreadStore.ts +4 -4
  97. package/src/comments/threadstore/yjs/YjsThreadStore.test.ts +2 -2
  98. package/src/comments/threadstore/yjs/YjsThreadStore.ts +14 -14
  99. package/src/comments/threadstore/yjs/YjsThreadStoreBase.ts +1 -1
  100. package/src/comments/threadstore/yjs/yjsHelpers.ts +6 -6
  101. package/src/editor/Block.css +35 -1
  102. package/src/editor/BlockNoteEditor.test.ts +10 -3
  103. package/src/editor/BlockNoteEditor.ts +95 -38
  104. package/src/editor/BlockNoteExtension.ts +26 -0
  105. package/src/editor/BlockNoteExtensions.ts +38 -22
  106. package/src/editor/BlockNoteSchema.ts +4 -4
  107. package/src/editor/BlockNoteTipTapEditor.ts +33 -12
  108. package/src/editor/README.md +1 -1
  109. package/src/editor/cursorPositionTypes.ts +1 -1
  110. package/src/editor/editor.css +15 -3
  111. package/src/editor/selectionTypes.ts +1 -1
  112. package/src/editor/transformPasted.ts +2 -2
  113. package/src/exporter/Exporter.ts +5 -5
  114. package/src/exporter/mapping.ts +7 -7
  115. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +1 -1
  116. package/src/extensions/Collaboration/CursorPlugin.ts +15 -9
  117. package/src/extensions/Collaboration/ForkYDocPlugin.test.ts +166 -0
  118. package/src/extensions/Collaboration/ForkYDocPlugin.ts +174 -0
  119. package/src/extensions/Collaboration/SyncPlugin.ts +7 -4
  120. package/src/extensions/Collaboration/UndoPlugin.ts +7 -4
  121. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json +30 -0
  122. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json +30 -0
  123. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-forked.html +1 -0
  124. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap.html +1 -0
  125. package/src/extensions/Comments/CommentsPlugin.ts +80 -75
  126. package/src/extensions/Comments/userstore/UserStore.ts +2 -2
  127. package/src/extensions/FilePanel/FilePanelPlugin.ts +56 -55
  128. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +60 -30
  129. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +26 -26
  130. package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +33 -32
  131. package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +45 -42
  132. package/src/extensions/Placeholder/PlaceholderPlugin.ts +113 -110
  133. package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +179 -170
  134. package/src/extensions/README.md +1 -1
  135. package/src/extensions/ShowSelection/ShowSelectionPlugin.ts +22 -19
  136. package/src/extensions/SideMenu/MultipleNodeSelection.ts +1 -1
  137. package/src/extensions/SideMenu/SideMenuPlugin.ts +49 -48
  138. package/src/extensions/SideMenu/dragging.ts +8 -8
  139. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +176 -176
  140. package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +2 -2
  141. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +16 -16
  142. package/src/extensions/Suggestions/SuggestionMarks.ts +175 -0
  143. package/src/extensions/TableHandles/TableHandlesPlugin.ts +199 -195
  144. package/src/extensions/TrailingNode/TrailingNodeExtension.ts +1 -1
  145. package/src/extensions/UniqueID/UniqueID.ts +6 -6
  146. package/src/extensions/getDraggableBlockFromElement.ts +1 -1
  147. package/src/fonts/inter.css +18 -9
  148. package/src/i18n/locales/ar.ts +0 -1
  149. package/src/i18n/locales/de.ts +0 -1
  150. package/src/i18n/locales/en.ts +0 -1
  151. package/src/i18n/locales/es.ts +0 -1
  152. package/src/i18n/locales/fr.ts +0 -1
  153. package/src/i18n/locales/hr.ts +0 -1
  154. package/src/i18n/locales/is.ts +0 -1
  155. package/src/i18n/locales/it.ts +0 -1
  156. package/src/i18n/locales/ja.ts +0 -1
  157. package/src/i18n/locales/ko.ts +0 -1
  158. package/src/i18n/locales/nl.ts +0 -1
  159. package/src/i18n/locales/no.ts +0 -1
  160. package/src/i18n/locales/pl.ts +0 -1
  161. package/src/i18n/locales/pt.ts +0 -1
  162. package/src/i18n/locales/ru.ts +0 -1
  163. package/src/i18n/locales/sk.ts +0 -1
  164. package/src/i18n/locales/uk.ts +0 -1
  165. package/src/i18n/locales/vi.ts +0 -1
  166. package/src/i18n/locales/zh-tw.ts +0 -1
  167. package/src/i18n/locales/zh.ts +0 -1
  168. package/src/index.ts +18 -8
  169. package/src/locales.ts +1 -1
  170. package/src/pm-nodes/BlockContainer.ts +1 -1
  171. package/src/pm-nodes/BlockGroup.ts +2 -2
  172. package/src/pm-nodes/Doc.ts +5 -4
  173. package/src/schema/README.md +1 -1
  174. package/src/schema/blocks/createSpec.ts +14 -14
  175. package/src/schema/blocks/internal.ts +17 -17
  176. package/src/schema/blocks/types.ts +25 -25
  177. package/src/schema/inlineContent/createSpec.ts +16 -20
  178. package/src/schema/inlineContent/internal.ts +9 -9
  179. package/src/schema/inlineContent/types.ts +26 -26
  180. package/src/schema/propTypes.ts +8 -8
  181. package/src/schema/styles/createSpec.ts +2 -2
  182. package/src/schema/styles/internal.ts +7 -7
  183. package/src/schema/styles/types.ts +2 -2
  184. package/src/util/EventEmitter.ts +4 -4
  185. package/src/util/README.md +1 -1
  186. package/src/util/combineByGroup.ts +1 -1
  187. package/src/util/table.ts +33 -30
  188. package/types/src/api/blockManipulation/commands/insertBlocks/insertBlocks.d.ts +1 -1
  189. package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.d.ts +4 -0
  190. package/types/src/api/blockManipulation/commands/removeBlocks/removeBlocks.test.d.ts +1 -0
  191. package/types/src/api/blockManipulation/commands/updateBlock/updateBlock.d.ts +3 -1
  192. package/types/src/api/blockManipulation/selections/selection.d.ts +10 -0
  193. package/types/src/api/blockManipulation/selections/textCursorPosition.d.ts +5 -0
  194. package/types/src/api/blockManipulation/transactions.test.d.ts +0 -0
  195. package/types/src/api/clipboard/clipboardExternal.test.d.ts +1 -0
  196. package/types/src/api/clipboard/clipboardInternal.test.d.ts +1 -0
  197. package/types/src/api/clipboard/testUtil.d.ts +541 -0
  198. package/types/src/api/exporters/html/htmlConversion.test.d.ts +1 -0
  199. package/types/src/api/exporters/markdown/markdownExporter.test.d.ts +1 -0
  200. package/types/src/api/nodeConversions/nodeConversions.test.d.ts +1 -0
  201. package/types/src/api/nodeConversions/nodeToBlock.d.ts +39 -2
  202. package/types/src/api/parsers/html/parseHTML.test.d.ts +1 -0
  203. package/types/src/api/parsers/markdown/parseMarkdown.test.d.ts +1 -0
  204. package/types/src/api/pmUtil.d.ts +3 -3
  205. package/types/src/api/testUtil/cases/customBlocks.d.ts +670 -0
  206. package/types/src/api/testUtil/cases/customInlineContent.d.ts +558 -0
  207. package/types/src/api/testUtil/cases/customStyles.d.ts +552 -0
  208. package/types/src/api/testUtil/cases/defaultSchema.d.ts +4 -0
  209. package/types/src/api/testUtil/index.d.ts +14 -0
  210. package/types/src/api/testUtil/partialBlockTestUtil.d.ts +9 -0
  211. package/types/src/api/testUtil/paste.d.ts +2 -0
  212. package/types/src/blocks/CodeBlockContent/defaultSupportedLanguages.d.ts +6 -0
  213. package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +9 -1
  214. package/types/src/editor/BlockNoteEditor.d.ts +58 -10
  215. package/types/src/editor/BlockNoteExtension.d.ts +9 -0
  216. package/types/src/editor/BlockNoteExtensions.d.ts +2 -2
  217. package/types/src/editor/BlockNoteTipTapEditor.d.ts +2 -2
  218. package/types/src/extensions/Collaboration/CursorPlugin.d.ts +3 -3
  219. package/types/src/extensions/Collaboration/ForkYDocPlugin.d.ts +41 -0
  220. package/types/src/extensions/Collaboration/ForkYDocPlugin.test.d.ts +1 -0
  221. package/types/src/extensions/Collaboration/SyncPlugin.d.ts +3 -3
  222. package/types/src/extensions/Collaboration/UndoPlugin.d.ts +3 -3
  223. package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +17 -0
  224. package/types/src/extensions/Comments/CommentsPlugin.d.ts +2 -4
  225. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +3 -4
  226. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +5 -5
  227. package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +3 -4
  228. package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +2 -3
  229. package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +2 -3
  230. package/types/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.d.ts +2 -3
  231. package/types/src/extensions/ShowSelection/ShowSelectionPlugin.d.ts +2 -3
  232. package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +3 -4
  233. package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +2 -4
  234. package/types/src/extensions/Suggestions/SuggestionMarks.d.ts +4 -0
  235. package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +5 -6
  236. package/types/src/i18n/locales/en.d.ts +0 -1
  237. package/types/src/i18n/locales/sk.d.ts +0 -1
  238. package/types/src/index.d.ts +15 -8
  239. package/dist/en-B7ycW7c8.js.map +0 -1
  240. package/dist/en-D4taoCs4.cjs.map +0 -1
  241. package/dist/tsconfig.tsbuildinfo +0 -1
  242. package/src/api/blockManipulation/selections/__snapshots__/selection.test.ts.snap +0 -844
  243. package/src/api/blockManipulation/selections/selection.test.ts +0 -72
  244. package/src/api/blockManipulation/selections/textCursorPosition/__snapshots__/textCursorPosition.test.ts.snap +0 -316
  245. package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.ts +0 -74
@@ -1,5 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
 
3
+ import { getBlockInfo } from "../../../getBlockInfoFromPos.js";
4
+ import { getNodeById } from "../../../nodeUtil.js";
3
5
  import { setupTestEnv } from "../../setupTestEnv.js";
4
6
  import { updateBlock } from "./updateBlock.js";
5
7
 
@@ -13,7 +15,7 @@ describe("Test updateBlock typing", () => {
13
15
  {
14
16
  // @ts-expect-error invalid type
15
17
  type: "non-existing",
16
- }
18
+ },
17
19
  );
18
20
  } catch (e) {
19
21
  // ID doesn't exist, which is fine - this is a compile-time check
@@ -30,7 +32,7 @@ describe("Test updateBlock typing", () => {
30
32
  // @ts-expect-error invalid type
31
33
  level: 1,
32
34
  },
33
- }
35
+ },
34
36
  );
35
37
  } catch (e) {
36
38
  // ID doesn't exist, which is fine - this is a compile-time check
@@ -43,7 +45,7 @@ describe("Test updateBlock typing", () => {
43
45
  props: {
44
46
  level: 1,
45
47
  },
46
- }
48
+ },
47
49
  );
48
50
  } catch (e) {
49
51
  // ID doesn't exist, which is fine - this is a compile-time check
@@ -57,8 +59,8 @@ describe("Test updateBlock", () => {
57
59
  getEditor().transact((tr) =>
58
60
  updateBlock(tr, "heading-with-everything", {
59
61
  id: "new-id",
60
- })
61
- )
62
+ }),
63
+ ),
62
64
  ).toMatchSnapshot();
63
65
  expect(getEditor().document).toMatchSnapshot();
64
66
  });
@@ -68,8 +70,8 @@ describe("Test updateBlock", () => {
68
70
  getEditor().transact((tr) =>
69
71
  updateBlock(tr, "heading-with-everything", {
70
72
  type: "paragraph",
71
- })
72
- )
73
+ }),
74
+ ),
73
75
  ).toMatchSnapshot();
74
76
 
75
77
  expect(getEditor().document).toMatchSnapshot();
@@ -82,8 +84,8 @@ describe("Test updateBlock", () => {
82
84
  props: {
83
85
  level: 3,
84
86
  },
85
- })
86
- )
87
+ }),
88
+ ),
87
89
  ).toMatchSnapshot();
88
90
 
89
91
  expect(getEditor().document).toMatchSnapshot();
@@ -99,8 +101,8 @@ describe("Test updateBlock", () => {
99
101
  textAlignment: "right",
100
102
  textColor: "blue",
101
103
  },
102
- })
103
- )
104
+ }),
105
+ ),
104
106
  ).toMatchSnapshot();
105
107
 
106
108
  expect(getEditor().document).toMatchSnapshot();
@@ -113,8 +115,8 @@ describe("Test updateBlock", () => {
113
115
  props: {
114
116
  level: undefined,
115
117
  },
116
- })
117
- )
118
+ }),
119
+ ),
118
120
  ).toMatchSnapshot();
119
121
 
120
122
  expect(getEditor().document).toMatchSnapshot();
@@ -130,8 +132,8 @@ describe("Test updateBlock", () => {
130
132
  textAlignment: undefined,
131
133
  textColor: undefined,
132
134
  },
133
- })
134
- )
135
+ }),
136
+ ),
135
137
  ).toMatchSnapshot();
136
138
 
137
139
  expect(getEditor().document).toMatchSnapshot();
@@ -142,8 +144,8 @@ describe("Test updateBlock", () => {
142
144
  getEditor().transact((tr) =>
143
145
  updateBlock(tr, "heading-with-everything", {
144
146
  content: "New content",
145
- })
146
- )
147
+ }),
148
+ ),
147
149
  ).toMatchSnapshot();
148
150
 
149
151
  expect(getEditor().document).toMatchSnapshot();
@@ -166,13 +168,169 @@ describe("Test updateBlock", () => {
166
168
  styles: { backgroundColor: "blue" },
167
169
  },
168
170
  ],
169
- })
170
- )
171
+ }),
172
+ ),
171
173
  ).toMatchSnapshot();
172
174
 
173
175
  expect(getEditor().document).toMatchSnapshot();
174
176
  });
175
177
 
178
+ it("Update partial (offset start)", () => {
179
+ const info = getBlockInfo(
180
+ getNodeById("heading-with-everything", getEditor().prosemirrorState.doc)!,
181
+ );
182
+
183
+ if (!info.isBlockContainer) {
184
+ throw new Error("heading-with-everything is not a block container");
185
+ }
186
+
187
+ getEditor().transact((tr) =>
188
+ updateBlock(
189
+ tr,
190
+ "heading-with-everything",
191
+ {
192
+ content: [
193
+ {
194
+ type: "text",
195
+ text: "without styles",
196
+ styles: {},
197
+ },
198
+ ],
199
+ },
200
+ info.blockContent.beforePos + 9,
201
+ ),
202
+ );
203
+
204
+ expect(getEditor().document).toMatchSnapshot();
205
+ });
206
+
207
+ it("Update partial (offset start + end)", () => {
208
+ const info = getBlockInfo(
209
+ getNodeById("heading-with-everything", getEditor().prosemirrorState.doc)!,
210
+ );
211
+
212
+ if (!info.isBlockContainer) {
213
+ throw new Error("heading-with-everything is not a block container");
214
+ }
215
+
216
+ getEditor().transact((tr) =>
217
+ updateBlock(
218
+ tr,
219
+ "heading-with-everything",
220
+ {
221
+ content: [
222
+ {
223
+ type: "text",
224
+ text: "without styles and ",
225
+ styles: {},
226
+ },
227
+ ],
228
+ },
229
+ info.blockContent.beforePos + 9,
230
+ info.blockContent.beforePos + 9,
231
+ ),
232
+ );
233
+
234
+ expect(getEditor().document).toMatchSnapshot();
235
+ });
236
+
237
+ it("Update partial (props + offset end)", () => {
238
+ const info = getBlockInfo(
239
+ getNodeById("heading-with-everything", getEditor().prosemirrorState.doc)!,
240
+ );
241
+
242
+ if (!info.isBlockContainer) {
243
+ throw new Error("heading-with-everything is not a block container");
244
+ }
245
+
246
+ getEditor().transact((tr) => {
247
+ updateBlock(
248
+ tr,
249
+ "heading-with-everything",
250
+ {
251
+ props: {
252
+ level: 1,
253
+ },
254
+ content: [
255
+ {
256
+ type: "text",
257
+ text: "Title",
258
+ styles: {},
259
+ },
260
+ ],
261
+ },
262
+ undefined,
263
+ info.blockContent.beforePos + 8,
264
+ );
265
+ });
266
+
267
+ expect(getEditor().document).toMatchSnapshot();
268
+ });
269
+
270
+ it("Update partial (table cell)", () => {
271
+ const info = getBlockInfo(
272
+ getNodeById("table-0", getEditor().prosemirrorState.doc)!,
273
+ );
274
+
275
+ if (!info.isBlockContainer) {
276
+ throw new Error("table-0 is not a block container");
277
+ }
278
+
279
+ const cell = info.blockContent.node.resolve(2);
280
+
281
+ getEditor().transact((tr) =>
282
+ updateBlock(
283
+ tr,
284
+ "table-0",
285
+ {
286
+ type: "table",
287
+ content: {
288
+ type: "tableContent",
289
+ rows: [{ cells: ["updated cell 1"] }],
290
+ },
291
+ },
292
+ info.blockContent.beforePos + 2,
293
+ info.blockContent.beforePos + 2 + cell.node().nodeSize,
294
+ ),
295
+ );
296
+
297
+ expect(getEditor().document).toMatchSnapshot();
298
+ });
299
+
300
+ it("Update partial (table row)", () => {
301
+ const info = getBlockInfo(
302
+ getNodeById("table-0", getEditor().prosemirrorState.doc)!,
303
+ );
304
+
305
+ if (!info.isBlockContainer) {
306
+ throw new Error("table-0 is not a block container");
307
+ }
308
+
309
+ const cell = info.blockContent.node.resolve(1);
310
+
311
+ getEditor().transact((tr) =>
312
+ updateBlock(
313
+ tr,
314
+ "table-0",
315
+ {
316
+ type: "table",
317
+ content: {
318
+ type: "tableContent",
319
+ rows: [
320
+ {
321
+ cells: ["updated cell 1", "updated cell 2", "updated cell 3"],
322
+ },
323
+ ],
324
+ },
325
+ },
326
+ info.blockContent.beforePos + 1,
327
+ info.blockContent.beforePos + 1 + cell.node().nodeSize,
328
+ ),
329
+ );
330
+
331
+ expect(getEditor().document).toMatchSnapshot();
332
+ });
333
+
176
334
  it("Update children", () => {
177
335
  expect(
178
336
  getEditor().transact((tr) =>
@@ -191,8 +349,8 @@ describe("Test updateBlock", () => {
191
349
  ],
192
350
  },
193
351
  ],
194
- })
195
- )
352
+ }),
353
+ ),
196
354
  ).toMatchSnapshot();
197
355
 
198
356
  expect(getEditor().document).toMatchSnapshot();
@@ -236,8 +394,8 @@ describe("Test updateBlock", () => {
236
394
  ],
237
395
  },
238
396
  ],
239
- })
240
- )
397
+ }),
398
+ ),
241
399
  ).toMatchSnapshot();
242
400
 
243
401
  expect(getEditor().document).toMatchSnapshot();
@@ -248,7 +406,7 @@ describe("Test updateBlock", () => {
248
406
  getEditor().transact((tr) =>
249
407
  updateBlock(tr, "paragraph-0", {
250
408
  type: "table",
251
- })
409
+ }),
252
410
  );
253
411
  }).toThrow();
254
412
  });
@@ -258,8 +416,8 @@ describe("Test updateBlock", () => {
258
416
  getEditor().transact((tr) =>
259
417
  updateBlock(tr, "table-0", {
260
418
  type: "paragraph",
261
- })
262
- )
419
+ }),
420
+ ),
263
421
  ).toMatchSnapshot();
264
422
 
265
423
  expect(getEditor().document).toMatchSnapshot();
@@ -284,8 +442,8 @@ describe("Test updateBlock", () => {
284
442
  },
285
443
  ],
286
444
  },
287
- })
288
- )
445
+ }),
446
+ ),
289
447
  ).toMatchSnapshot();
290
448
 
291
449
  expect(getEditor().document).toMatchSnapshot();
@@ -297,8 +455,8 @@ describe("Test updateBlock", () => {
297
455
  updateBlock(tr, "table-0", {
298
456
  type: "paragraph",
299
457
  content: "Paragraph",
300
- })
301
- )
458
+ }),
459
+ ),
302
460
  ).toMatchSnapshot();
303
461
 
304
462
  expect(getEditor().document).toMatchSnapshot();
@@ -309,8 +467,8 @@ describe("Test updateBlock", () => {
309
467
  getEditor().transact((tr) =>
310
468
  updateBlock(tr, "paragraph-0", {
311
469
  type: "image",
312
- })
313
- )
470
+ }),
471
+ ),
314
472
  ).toMatchSnapshot();
315
473
 
316
474
  expect(getEditor().document).toMatchSnapshot();
@@ -321,8 +479,8 @@ describe("Test updateBlock", () => {
321
479
  getEditor().transact((tr) =>
322
480
  updateBlock(tr, "image-0", {
323
481
  type: "paragraph",
324
- })
325
- )
482
+ }),
483
+ ),
326
484
  ).toMatchSnapshot();
327
485
 
328
486
  expect(getEditor().document).toMatchSnapshot();
@@ -334,8 +492,8 @@ describe("Test updateBlock", () => {
334
492
  updateBlock(tr, "image-0", {
335
493
  type: "paragraph",
336
494
  content: "Paragraph",
337
- })
338
- )
495
+ }),
496
+ ),
339
497
  ).toMatchSnapshot();
340
498
 
341
499
  expect(getEditor().document).toMatchSnapshot();
@@ -346,8 +504,8 @@ describe("Test updateBlock", () => {
346
504
  getEditor().transact((tr) =>
347
505
  updateBlock(tr, "image-0", {
348
506
  type: "table",
349
- })
350
- )
507
+ }),
508
+ ),
351
509
  ).toMatchSnapshot();
352
510
 
353
511
  expect(getEditor().document).toMatchSnapshot();
@@ -399,8 +557,8 @@ describe("Test updateBlock", () => {
399
557
  },
400
558
  ],
401
559
  },
402
- })
403
- )
560
+ }),
561
+ ),
404
562
  ).toMatchSnapshot();
405
563
 
406
564
  expect(getEditor().document).toMatchSnapshot();
@@ -411,8 +569,8 @@ describe("Test updateBlock", () => {
411
569
  getEditor().transact((tr) =>
412
570
  updateBlock(tr, "table-0", {
413
571
  type: "image",
414
- })
415
- )
572
+ }),
573
+ ),
416
574
  ).toMatchSnapshot();
417
575
 
418
576
  expect(getEditor().document).toMatchSnapshot();
@@ -6,7 +6,7 @@ import {
6
6
  } from "prosemirror-model";
7
7
  import type { Transaction } from "prosemirror-state";
8
8
 
9
- import { ReplaceStep } from "prosemirror-transform";
9
+ import { ReplaceStep, Transform } from "prosemirror-transform";
10
10
  import type { Block, PartialBlock } from "../../../../blocks/defaultBlocks.js";
11
11
  import type {
12
12
  BlockIdentifier,
@@ -28,13 +28,14 @@ import { nodeToBlock } from "../../../nodeConversions/nodeToBlock.js";
28
28
  import { getNodeById } from "../../../nodeUtil.js";
29
29
  import { getPmSchema } from "../../../pmUtil.js";
30
30
 
31
+ // for compatibility with tiptap. TODO: remove as we want to remove dependency on tiptap command interface
31
32
  export const updateBlockCommand = <
32
33
  BSchema extends BlockSchema,
33
34
  I extends InlineContentSchema,
34
- S extends StyleSchema
35
+ S extends StyleSchema,
35
36
  >(
36
37
  posBeforeBlock: number,
37
- block: PartialBlock<BSchema, I, S>
38
+ block: PartialBlock<BSchema, I, S>,
38
39
  ) => {
39
40
  return ({
40
41
  tr,
@@ -50,18 +51,29 @@ export const updateBlockCommand = <
50
51
  };
51
52
  };
52
53
 
53
- const updateBlockTr = <
54
+ export function updateBlockTr<
54
55
  BSchema extends BlockSchema,
55
56
  I extends InlineContentSchema,
56
- S extends StyleSchema
57
+ S extends StyleSchema,
57
58
  >(
58
- tr: Transaction,
59
+ tr: Transform,
59
60
  posBeforeBlock: number,
60
- block: PartialBlock<BSchema, I, S>
61
- ) => {
61
+ block: PartialBlock<BSchema, I, S>,
62
+ replaceFromPos?: number,
63
+ replaceToPos?: number,
64
+ ) {
62
65
  const blockInfo = getBlockInfoFromResolvedPos(tr.doc.resolve(posBeforeBlock));
63
66
 
64
67
  const pmSchema = getPmSchema(tr);
68
+
69
+ if (
70
+ replaceFromPos !== undefined &&
71
+ replaceToPos !== undefined &&
72
+ replaceFromPos > replaceToPos
73
+ ) {
74
+ throw new Error("Invalid replaceFromPos or replaceToPos");
75
+ }
76
+
65
77
  // Adds blockGroup node with child blocks if necessary.
66
78
 
67
79
  const oldNodeType = pmSchema.nodes[blockInfo.blockNoteType];
@@ -71,10 +83,32 @@ const updateBlockTr = <
71
83
  : pmSchema.nodes["blockContainer"];
72
84
 
73
85
  if (blockInfo.isBlockContainer && newNodeType.isInGroup("blockContent")) {
86
+ const replaceFromOffset =
87
+ replaceFromPos !== undefined &&
88
+ replaceFromPos > blockInfo.blockContent.beforePos &&
89
+ replaceFromPos < blockInfo.blockContent.afterPos
90
+ ? replaceFromPos - blockInfo.blockContent.beforePos - 1
91
+ : undefined;
92
+
93
+ const replaceToOffset =
94
+ replaceToPos !== undefined &&
95
+ replaceToPos > blockInfo.blockContent.beforePos &&
96
+ replaceToPos < blockInfo.blockContent.afterPos
97
+ ? replaceToPos - blockInfo.blockContent.beforePos - 1
98
+ : undefined;
99
+
74
100
  updateChildren(block, tr, blockInfo);
75
101
  // The code below determines the new content of the block.
76
102
  // or "keep" to keep as-is
77
- updateBlockContentNode(block, tr, oldNodeType, newNodeType, blockInfo);
103
+ updateBlockContentNode(
104
+ block,
105
+ tr,
106
+ oldNodeType,
107
+ newNodeType,
108
+ blockInfo,
109
+ replaceFromOffset,
110
+ replaceToOffset,
111
+ );
78
112
  } else if (!blockInfo.isBlockContainer && newNodeType.isInGroup("bnBlock")) {
79
113
  updateChildren(block, tr, blockInfo);
80
114
  // old node was a bnBlock type (like column or columnList) and new block as well
@@ -96,8 +130,8 @@ const updateBlockTr = <
96
130
  children: existingBlock.children, // if no children are passed in, use existing children
97
131
  ...block,
98
132
  },
99
- pmSchema
100
- )
133
+ pmSchema,
134
+ ),
101
135
  );
102
136
 
103
137
  return;
@@ -109,15 +143,15 @@ const updateBlockTr = <
109
143
  ...blockInfo.bnBlock.node.attrs,
110
144
  ...block.props,
111
145
  });
112
- };
146
+ }
113
147
 
114
148
  function updateBlockContentNode<
115
149
  BSchema extends BlockSchema,
116
150
  I extends InlineContentSchema,
117
- S extends StyleSchema
151
+ S extends StyleSchema,
118
152
  >(
119
153
  block: PartialBlock<BSchema, I, S>,
120
- tr: Transaction,
154
+ tr: Transform,
121
155
  oldNodeType: NodeType,
122
156
  newNodeType: NodeType,
123
157
  blockInfo: {
@@ -125,7 +159,9 @@ function updateBlockContentNode<
125
159
  | { node: PMNode; beforePos: number; afterPos: number }
126
160
  | undefined;
127
161
  blockContent: { node: PMNode; beforePos: number; afterPos: number };
128
- }
162
+ },
163
+ replaceFromOffset?: number,
164
+ replaceToOffset?: number,
129
165
  ) {
130
166
  const pmSchema = getPmSchema(tr);
131
167
  let content: PMNode[] | "keep" = "keep";
@@ -137,7 +173,7 @@ function updateBlockContentNode<
137
173
  content = inlineContentToNodes(
138
174
  [block.content],
139
175
  pmSchema,
140
- newNodeType.name
176
+ newNodeType.name,
141
177
  );
142
178
  } else if (Array.isArray(block.content)) {
143
179
  // Adds a text node with the provided styles converted into marks to the content,
@@ -172,17 +208,43 @@ function updateBlockContentNode<
172
208
  // content is being replaced or not.
173
209
  if (content === "keep") {
174
210
  // use setNodeMarkup to only update the type and attributes
175
- tr.setNodeMarkup(
176
- blockInfo.blockContent.beforePos,
177
- block.type === undefined ? undefined : pmSchema.nodes[block.type],
178
- {
179
- ...blockInfo.blockContent.node.attrs,
180
- ...block.props,
181
- }
211
+ tr.setNodeMarkup(blockInfo.blockContent.beforePos, newNodeType, {
212
+ ...blockInfo.blockContent.node.attrs,
213
+ ...block.props,
214
+ });
215
+ } else if (replaceFromOffset !== undefined || replaceToOffset !== undefined) {
216
+ // first update markup of the containing node
217
+ tr.setNodeMarkup(blockInfo.blockContent.beforePos, newNodeType, {
218
+ ...blockInfo.blockContent.node.attrs,
219
+ ...block.props,
220
+ });
221
+
222
+ const start =
223
+ blockInfo.blockContent.beforePos + 1 + (replaceFromOffset ?? 0);
224
+ const end =
225
+ blockInfo.blockContent.beforePos +
226
+ 1 +
227
+ (replaceToOffset ?? blockInfo.blockContent.node.content.size);
228
+
229
+ // for content like table cells (where the blockcontent has nested PM nodes),
230
+ // we need to figure out the correct openStart and openEnd for the slice when replacing
231
+
232
+ const contentDepth = tr.doc.resolve(blockInfo.blockContent.beforePos).depth;
233
+ const startDepth = tr.doc.resolve(start).depth;
234
+ const endDepth = tr.doc.resolve(end).depth;
235
+
236
+ tr.replace(
237
+ start,
238
+ end,
239
+ new Slice(
240
+ Fragment.from(content),
241
+ startDepth - contentDepth - 1,
242
+ endDepth - contentDepth - 1,
243
+ ),
182
244
  );
183
245
  } else {
184
246
  // use replaceWith to replace the content and the block itself
185
- // also reset the selection since replacing the block content
247
+ // also reset the selection since replacing the block content
186
248
  // sets it to the next block.
187
249
  tr.replaceWith(
188
250
  blockInfo.blockContent.beforePos,
@@ -192,8 +254,8 @@ function updateBlockContentNode<
192
254
  ...blockInfo.blockContent.node.attrs,
193
255
  ...block.props,
194
256
  },
195
- content
196
- )
257
+ content,
258
+ ),
197
259
  );
198
260
  }
199
261
  }
@@ -201,8 +263,8 @@ function updateBlockContentNode<
201
263
  function updateChildren<
202
264
  BSchema extends BlockSchema,
203
265
  I extends InlineContentSchema,
204
- S extends StyleSchema
205
- >(block: PartialBlock<BSchema, I, S>, tr: Transaction, blockInfo: BlockInfo) {
266
+ S extends StyleSchema,
267
+ >(block: PartialBlock<BSchema, I, S>, tr: Transform, blockInfo: BlockInfo) {
206
268
  const pmSchema = getPmSchema(tr);
207
269
  if (block.children !== undefined && block.children.length > 0) {
208
270
  const childNodes = block.children.map((child) => {
@@ -218,8 +280,8 @@ function updateChildren<
218
280
  new ReplaceStep(
219
281
  blockInfo.childContainer.beforePos + 1,
220
282
  blockInfo.childContainer.afterPos - 1,
221
- new Slice(Fragment.from(childNodes), 0, 0)
222
- )
283
+ new Slice(Fragment.from(childNodes), 0, 0),
284
+ ),
223
285
  );
224
286
  } else {
225
287
  if (!blockInfo.isBlockContainer) {
@@ -228,7 +290,7 @@ function updateChildren<
228
290
  // Inserts a new blockGroup containing the child nodes created earlier.
229
291
  tr.insert(
230
292
  blockInfo.blockContent.afterPos,
231
- pmSchema.nodes["blockGroup"].createChecked({}, childNodes)
293
+ pmSchema.nodes["blockGroup"].createChecked({}, childNodes),
232
294
  );
233
295
  }
234
296
  }
@@ -237,11 +299,13 @@ function updateChildren<
237
299
  export function updateBlock<
238
300
  BSchema extends BlockSchema = any,
239
301
  I extends InlineContentSchema = any,
240
- S extends StyleSchema = any
302
+ S extends StyleSchema = any,
241
303
  >(
242
304
  tr: Transaction,
243
305
  blockToUpdate: BlockIdentifier,
244
- update: PartialBlock<BSchema, I, S>
306
+ update: PartialBlock<BSchema, I, S>,
307
+ replaceFromPos?: number,
308
+ replaceToPos?: number,
245
309
  ): Block<BSchema, I, S> {
246
310
  const id =
247
311
  typeof blockToUpdate === "string" ? blockToUpdate : blockToUpdate.id;
@@ -250,7 +314,13 @@ export function updateBlock<
250
314
  throw new Error(`Block with ID ${id} not found`);
251
315
  }
252
316
 
253
- updateBlockTr(tr, posInfo.posBeforeNode, update);
317
+ updateBlockTr(
318
+ tr,
319
+ posInfo.posBeforeNode,
320
+ update,
321
+ replaceFromPos,
322
+ replaceToPos,
323
+ );
254
324
 
255
325
  const blockContainerNode = tr.doc
256
326
  .resolve(posInfo.posBeforeNode + 1) // TODO: clean?