@blocknote/core 0.37.0 → 0.39.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 (271) hide show
  1. package/dist/BlockNoteSchema-DmZ6UQfY.cjs +11 -0
  2. package/dist/BlockNoteSchema-DmZ6UQfY.cjs.map +1 -0
  3. package/dist/BlockNoteSchema-oR047ACf.js +4275 -0
  4. package/dist/BlockNoteSchema-oR047ACf.js.map +1 -0
  5. package/dist/blocknote.cjs +4 -12
  6. package/dist/blocknote.cjs.map +1 -1
  7. package/dist/blocknote.js +3311 -7230
  8. package/dist/blocknote.js.map +1 -1
  9. package/dist/blocks.cjs +2 -0
  10. package/dist/blocks.cjs.map +1 -0
  11. package/dist/blocks.js +71 -0
  12. package/dist/blocks.js.map +1 -0
  13. package/dist/{en-CvDoFvhc.js → en-Bq3Es3Np.js} +6 -12
  14. package/dist/en-Bq3Es3Np.js.map +1 -0
  15. package/dist/en-D3B48eJ7.cjs +2 -0
  16. package/dist/en-D3B48eJ7.cjs.map +1 -0
  17. package/dist/locales.cjs +1 -1
  18. package/dist/locales.cjs.map +1 -1
  19. package/dist/locales.js +109 -229
  20. package/dist/locales.js.map +1 -1
  21. package/dist/style.css +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -0
  23. package/dist/webpack-stats.json +1 -1
  24. package/package.json +25 -22
  25. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +1 -1
  26. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +2 -2
  27. package/src/api/blockManipulation/commands/splitBlock/splitBlock.ts +34 -25
  28. package/src/api/blockManipulation/setupTestEnv.ts +0 -1
  29. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +4 -8
  30. package/src/api/clipboard/toClipboard/copyExtension.ts +1 -3
  31. package/src/api/exporters/html/externalHTMLExporter.ts +0 -1
  32. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +128 -28
  33. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +101 -41
  34. package/src/api/exporters/markdown/markdownExporter.ts +13 -22
  35. package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +2 -12
  36. package/src/api/parsers/html/parseHTML.ts +3 -2
  37. package/src/api/parsers/html/util/nestedLists.test.ts +8 -8
  38. package/src/api/parsers/markdown/parseMarkdown.ts +17 -14
  39. package/src/api/pmUtil.ts +1 -1
  40. package/src/api/positionMapping.test.ts +197 -33
  41. package/src/api/positionMapping.ts +4 -6
  42. package/src/blocks/Audio/block.ts +174 -0
  43. package/src/blocks/BlockNoteSchema.ts +59 -0
  44. package/src/blocks/Code/block.ts +303 -0
  45. package/src/blocks/Code/shiki.ts +73 -0
  46. package/src/blocks/File/block.ts +98 -0
  47. package/src/blocks/{FileBlockContent → File}/helpers/render/createAddFileButton.ts +8 -4
  48. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileBlockWrapper.ts +16 -13
  49. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.ts +15 -2
  50. package/src/blocks/{FileBlockContent → File}/helpers/render/createResizableFileBlockWrapper.ts +63 -19
  51. package/src/blocks/Heading/block.ts +138 -0
  52. package/src/blocks/Image/block.ts +190 -0
  53. package/src/blocks/ListItem/BulletListItem/block.ts +116 -0
  54. package/src/blocks/ListItem/CheckListItem/block.ts +175 -0
  55. package/src/blocks/ListItem/NumberedListItem/IndexingPlugin.ts +173 -0
  56. package/src/blocks/ListItem/NumberedListItem/block.ts +133 -0
  57. package/src/blocks/ListItem/ToggleListItem/block.ts +78 -0
  58. package/src/blocks/PageBreak/block.ts +72 -0
  59. package/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.ts +9 -7
  60. package/src/blocks/Paragraph/block.ts +80 -0
  61. package/src/blocks/Quote/block.ts +90 -0
  62. package/src/blocks/{TableBlockContent/TableBlockContent.ts → Table/block.ts} +169 -51
  63. package/src/blocks/ToggleWrapper/createToggleWrapper.ts +1 -1
  64. package/src/blocks/Video/block.ts +143 -0
  65. package/src/blocks/defaultBlockHelpers.ts +2 -2
  66. package/src/blocks/defaultBlockTypeGuards.ts +143 -174
  67. package/src/blocks/defaultBlocks.ts +107 -35
  68. package/src/blocks/defaultProps.ts +145 -4
  69. package/src/blocks/index.ts +26 -0
  70. package/src/blocks/utils/listItemEnterHandler.ts +42 -0
  71. package/src/editor/Block.css +54 -18
  72. package/src/editor/BlockNoteEditor.ts +265 -230
  73. package/src/editor/BlockNoteExtension.ts +92 -0
  74. package/src/editor/BlockNoteExtensions.ts +20 -16
  75. package/src/editor/defaultColors.ts +2 -2
  76. package/src/exporter/Exporter.ts +1 -1
  77. package/src/exporter/mapping.ts +1 -1
  78. package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +3 -20
  79. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +6 -8
  80. package/src/extensions/BlockChange/BlockChangePlugin.ts +2 -1
  81. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json +2 -2
  82. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json +2 -2
  83. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-forked.html +1 -1
  84. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap.html +1 -1
  85. package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +52 -0
  86. package/src/extensions/Collaboration/schemaMigration/migrationRules/index.ts +4 -0
  87. package/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.ts +4 -0
  88. package/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts +78 -0
  89. package/src/extensions/Comments/CommentsPlugin.ts +2 -0
  90. package/src/extensions/FilePanel/FilePanelPlugin.ts +5 -10
  91. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +1 -1
  92. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +4 -3
  93. package/src/extensions/Placeholder/PlaceholderPlugin.ts +2 -2
  94. package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +1 -23
  95. package/src/extensions/SideMenu/SideMenuPlugin.ts +0 -2
  96. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +0 -5
  97. package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +6 -2
  98. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +24 -17
  99. package/src/extensions/TableHandles/TableHandlesPlugin.ts +2 -2
  100. package/src/extensions/TextAlignment/TextAlignmentExtension.ts +5 -11
  101. package/src/extensions/TextColor/TextColorExtension.ts +3 -17
  102. package/src/extensions/TextColor/TextColorMark.ts +4 -9
  103. package/src/extensions/UniqueID/UniqueID.ts +6 -13
  104. package/src/i18n/locales/ar.ts +6 -12
  105. package/src/i18n/locales/de.ts +6 -12
  106. package/src/i18n/locales/en.ts +6 -12
  107. package/src/i18n/locales/es.ts +6 -12
  108. package/src/i18n/locales/fr.ts +6 -12
  109. package/src/i18n/locales/he.ts +6 -12
  110. package/src/i18n/locales/hr.ts +6 -12
  111. package/src/i18n/locales/is.ts +6 -12
  112. package/src/i18n/locales/it.ts +6 -12
  113. package/src/i18n/locales/ja.ts +6 -12
  114. package/src/i18n/locales/ko.ts +6 -12
  115. package/src/i18n/locales/nl.ts +6 -12
  116. package/src/i18n/locales/no.ts +6 -12
  117. package/src/i18n/locales/pl.ts +6 -12
  118. package/src/i18n/locales/pt.ts +6 -12
  119. package/src/i18n/locales/ru.ts +6 -12
  120. package/src/i18n/locales/sk.ts +6 -12
  121. package/src/i18n/locales/uk.ts +6 -12
  122. package/src/i18n/locales/vi.ts +6 -12
  123. package/src/i18n/locales/zh-tw.ts +6 -12
  124. package/src/i18n/locales/zh.ts +6 -12
  125. package/src/index.ts +2 -29
  126. package/src/schema/blocks/createSpec.ts +342 -169
  127. package/src/schema/blocks/internal.ts +77 -138
  128. package/src/schema/blocks/types.ts +264 -94
  129. package/src/schema/index.ts +1 -0
  130. package/src/schema/inlineContent/createSpec.ts +99 -21
  131. package/src/schema/inlineContent/internal.ts +16 -7
  132. package/src/schema/inlineContent/types.ts +24 -2
  133. package/src/schema/propTypes.ts +15 -9
  134. package/src/schema/schema.ts +209 -0
  135. package/src/schema/styles/createSpec.ts +79 -31
  136. package/src/schema/styles/internal.ts +61 -2
  137. package/src/schema/styles/types.ts +17 -3
  138. package/src/util/topo-sort.test.ts +125 -0
  139. package/src/util/topo-sort.ts +160 -0
  140. package/types/src/api/blockManipulation/commands/splitBlock/splitBlock.d.ts +2 -1
  141. package/types/src/api/blockManipulation/selections/selection.d.ts +1 -1
  142. package/types/src/api/blockManipulation/setupTestEnv.d.ts +29 -543
  143. package/types/src/api/exporters/html/util/serializeBlocksExternalHTML.d.ts +1 -1
  144. package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +1 -1
  145. package/types/src/api/exporters/markdown/markdownExporter.d.ts +1 -1
  146. package/types/src/api/parsers/html/parseHTML.d.ts +1 -1
  147. package/types/src/api/parsers/markdown/parseMarkdown.d.ts +2 -2
  148. package/types/src/api/pmUtil.d.ts +1 -1
  149. package/types/src/blocks/Audio/block.d.ts +58 -0
  150. package/types/src/blocks/BlockNoteSchema.d.ts +18 -0
  151. package/types/src/blocks/{CodeBlockContent/CodeBlockContent.d.ts → Code/block.d.ts} +25 -26
  152. package/types/src/blocks/Code/shiki.d.ts +4 -0
  153. package/types/src/blocks/File/block.d.ts +37 -0
  154. package/types/src/blocks/File/helpers/render/createAddFileButton.d.ts +6 -0
  155. package/types/src/blocks/File/helpers/render/createFileBlockWrapper.d.ts +25 -0
  156. package/types/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.d.ts +6 -2
  157. package/types/src/blocks/File/helpers/render/createResizableFileBlockWrapper.d.ts +31 -0
  158. package/types/src/blocks/Heading/block.d.ts +71 -0
  159. package/types/src/blocks/Image/block.d.ts +102 -0
  160. package/types/src/blocks/ListItem/BulletListItem/block.d.ts +25 -0
  161. package/types/src/blocks/ListItem/CheckListItem/block.d.ts +33 -0
  162. package/types/src/blocks/ListItem/NumberedListItem/IndexingPlugin.d.ts +8 -0
  163. package/types/src/blocks/ListItem/NumberedListItem/block.d.ts +33 -0
  164. package/types/src/blocks/ListItem/ToggleListItem/block.d.ts +25 -0
  165. package/types/src/blocks/PageBreak/block.d.ts +11 -0
  166. package/types/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.d.ts +4 -2
  167. package/types/src/blocks/Paragraph/block.d.ts +25 -0
  168. package/types/src/blocks/Quote/block.d.ts +17 -0
  169. package/types/src/blocks/Table/block.d.ts +21 -0
  170. package/types/src/blocks/Video/block.d.ts +67 -0
  171. package/types/src/blocks/defaultBlockHelpers.d.ts +1 -1
  172. package/types/src/blocks/defaultBlockTypeGuards.d.ts +15 -36
  173. package/types/src/blocks/defaultBlocks.d.ts +221 -1060
  174. package/types/src/blocks/defaultProps.d.ts +17 -1
  175. package/types/src/blocks/index.d.ts +24 -0
  176. package/types/src/blocks/utils/listItemEnterHandler.d.ts +2 -0
  177. package/types/src/editor/BlockNoteEditor.d.ts +39 -75
  178. package/types/src/editor/BlockNoteExtension.d.ts +67 -0
  179. package/types/src/editor/BlockNoteExtensions.d.ts +2 -0
  180. package/types/src/editor/defaultColors.d.ts +8 -76
  181. package/types/src/exporter/Exporter.d.ts +1 -1
  182. package/types/src/exporter/mapping.d.ts +1 -1
  183. package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +4 -1
  184. package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +7 -0
  185. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/index.d.ts +3 -0
  186. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.d.ts +3 -0
  187. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.d.ts +2 -0
  188. package/types/src/extensions/Comments/CommentsPlugin.d.ts +3 -1
  189. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +4 -4
  190. package/types/src/extensions/TextColor/TextColorMark.d.ts +4 -1
  191. package/types/src/i18n/locales/en.d.ts +1 -12
  192. package/types/src/i18n/locales/sk.d.ts +1 -12
  193. package/types/src/index.d.ts +2 -26
  194. package/types/src/schema/blocks/createSpec.d.ts +16 -36
  195. package/types/src/schema/blocks/internal.d.ts +11 -33
  196. package/types/src/schema/blocks/types.d.ts +181 -57
  197. package/types/src/schema/index.d.ts +1 -0
  198. package/types/src/schema/inlineContent/createSpec.d.ts +36 -2
  199. package/types/src/schema/inlineContent/internal.d.ts +7 -15
  200. package/types/src/schema/inlineContent/types.d.ts +15 -1
  201. package/types/src/schema/propTypes.d.ts +4 -4
  202. package/types/src/schema/schema.d.ts +40 -0
  203. package/types/src/schema/styles/createSpec.d.ts +6 -4
  204. package/types/src/schema/styles/internal.d.ts +6 -3
  205. package/types/src/schema/styles/types.d.ts +11 -2
  206. package/types/src/util/topo-sort.d.ts +18 -0
  207. package/types/src/util/topo-sort.test.d.ts +1 -0
  208. package/dist/en-CvDoFvhc.js.map +0 -1
  209. package/dist/en-ub2yVBX0.cjs +0 -2
  210. package/dist/en-ub2yVBX0.cjs.map +0 -1
  211. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +0 -145
  212. package/src/blocks/CodeBlockContent/CodeBlockContent.ts +0 -445
  213. package/src/blocks/FileBlockContent/FileBlockContent.ts +0 -100
  214. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +0 -159
  215. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +0 -160
  216. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +0 -134
  217. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +0 -299
  218. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +0 -86
  219. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +0 -172
  220. package/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.ts +0 -104
  221. package/src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts +0 -49
  222. package/src/blocks/PageBreakBlockContent/schema.ts +0 -40
  223. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +0 -78
  224. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +0 -121
  225. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +0 -159
  226. package/src/editor/BlockNoteSchema.ts +0 -107
  227. package/src/editor/BlockNoteTipTapEditor.ts +0 -335
  228. package/src/util/esmDependencies.ts +0 -51
  229. package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +0 -99
  230. package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +0 -90
  231. package/types/src/blocks/FileBlockContent/helpers/render/createAddFileButton.d.ts +0 -6
  232. package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +0 -9
  233. package/types/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.d.ts +0 -9
  234. package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +0 -67
  235. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +0 -131
  236. package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +0 -46
  237. package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +0 -55
  238. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +0 -2
  239. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +0 -58
  240. package/types/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.d.ts +0 -46
  241. package/types/src/blocks/PageBreakBlockContent/PageBreakBlockContent.d.ts +0 -31
  242. package/types/src/blocks/PageBreakBlockContent/schema.d.ts +0 -86
  243. package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +0 -52
  244. package/types/src/blocks/QuoteBlockContent/QuoteBlockContent.d.ts +0 -52
  245. package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +0 -39
  246. package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +0 -131
  247. package/types/src/editor/BlockNoteSchema.d.ts +0 -34
  248. package/types/src/editor/BlockNoteTipTapEditor.d.ts +0 -43
  249. package/types/src/util/esmDependencies.d.ts +0 -24
  250. /package/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.ts +0 -0
  251. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.ts +0 -0
  252. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.ts +0 -0
  253. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.ts +0 -0
  254. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.ts +0 -0
  255. /package/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.ts +0 -0
  256. /package/src/blocks/{ImageBlockContent → Image}/parseImageElement.ts +0 -0
  257. /package/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.ts +0 -0
  258. /package/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.ts +0 -0
  259. /package/src/blocks/{TableBlockContent → Table}/TableExtension.ts +0 -0
  260. /package/src/blocks/{VideoBlockContent → Video}/parseVideoElement.ts +0 -0
  261. /package/types/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.d.ts +0 -0
  262. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.d.ts +0 -0
  263. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.d.ts +0 -0
  264. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.d.ts +0 -0
  265. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.d.ts +0 -0
  266. /package/types/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +0 -0
  267. /package/types/src/blocks/{ImageBlockContent → Image}/parseImageElement.d.ts +0 -0
  268. /package/types/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.d.ts +0 -0
  269. /package/types/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.d.ts +0 -0
  270. /package/types/src/blocks/{TableBlockContent → Table}/TableExtension.d.ts +0 -0
  271. /package/types/src/blocks/{VideoBlockContent → Video}/parseVideoElement.d.ts +0 -0
@@ -1,23 +1,29 @@
1
- import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
1
+ import { describe, expect, it, vi } from "vitest";
2
2
  import * as Y from "yjs";
3
3
  import { BlockNoteEditor } from "../editor/BlockNoteEditor.js";
4
4
  import { trackPosition } from "./positionMapping.js";
5
5
 
6
6
  describe("PositionStorage with local editor", () => {
7
- let editor: BlockNoteEditor;
7
+ describe("mount and unmount", () => {
8
+ it("should register transaction handler on creation", () => {
9
+ const editor = BlockNoteEditor.create();
10
+ editor.mount(document.createElement("div"));
8
11
 
9
- beforeEach(() => {
10
- editor = BlockNoteEditor.create();
11
- editor.mount(document.createElement("div"));
12
- });
12
+ editor._tiptapEditor.on = vi.fn();
13
+ trackPosition(editor, 0);
13
14
 
14
- afterEach(() => {
15
- editor.mount(undefined);
16
- editor._tiptapEditor.destroy();
17
- });
15
+ expect(editor._tiptapEditor.on).toHaveBeenCalledWith(
16
+ "transaction",
17
+ expect.any(Function),
18
+ );
19
+
20
+ editor._tiptapEditor.destroy();
21
+ });
22
+
23
+ it("should register transaction handler on creation & mount", () => {
24
+ const editor = BlockNoteEditor.create();
25
+ // editor.mount(document.createElement("div"));
18
26
 
19
- describe("mount and unmount", () => {
20
- it("should register transaction handler on creation", () => {
21
27
  editor._tiptapEditor.on = vi.fn();
22
28
  trackPosition(editor, 0);
23
29
 
@@ -25,24 +31,82 @@ describe("PositionStorage with local editor", () => {
25
31
  "transaction",
26
32
  expect.any(Function),
27
33
  );
34
+
35
+ editor._tiptapEditor.destroy();
28
36
  });
29
37
  });
30
38
 
31
39
  describe("set and get positions", () => {
32
40
  it("should store and retrieve positions without Y.js", () => {
41
+ const editor = BlockNoteEditor.create();
42
+ editor.mount(document.createElement("div"));
43
+
33
44
  const getPos = trackPosition(editor, 10);
34
45
 
35
46
  expect(getPos()).toBe(10);
47
+
48
+ editor._tiptapEditor.destroy();
36
49
  });
37
50
 
38
51
  it("should handle right side positions", () => {
52
+ const editor = BlockNoteEditor.create();
53
+ editor.mount(document.createElement("div"));
54
+
39
55
  const getPos = trackPosition(editor, 10, "right");
40
56
 
41
57
  expect(getPos()).toBe(10);
58
+
59
+ editor._tiptapEditor.destroy();
42
60
  });
43
61
  });
44
62
 
45
63
  it("should update mapping for local transactions before the position", () => {
64
+ const editor = BlockNoteEditor.create();
65
+ editor.mount(document.createElement("div"));
66
+
67
+ // Set initial content
68
+ editor.insertBlocks(
69
+ [
70
+ {
71
+ id: "1",
72
+ type: "paragraph",
73
+ content: [
74
+ {
75
+ type: "text",
76
+ text: "Hello World",
77
+ styles: {},
78
+ },
79
+ ],
80
+ },
81
+ ],
82
+ editor.document[0],
83
+ "before",
84
+ );
85
+
86
+ // Start tracking
87
+ const getPos = trackPosition(editor, 10);
88
+
89
+ // Move the cursor to the start of the document
90
+ editor.setTextCursorPosition(editor.document[0], "start");
91
+
92
+ // Insert text at the start of the document
93
+ editor.insertInlineContent([
94
+ {
95
+ type: "text",
96
+ text: "Test",
97
+ styles: {},
98
+ },
99
+ ]);
100
+
101
+ // Position should be updated according to mapping
102
+ expect(getPos()).toBe(14);
103
+
104
+ editor._tiptapEditor.destroy();
105
+ });
106
+
107
+ it("should update mapping for local transactions before the position (unmounted)", () => {
108
+ const editor = BlockNoteEditor.create();
109
+
46
110
  // Set initial content
47
111
  editor.insertBlocks(
48
112
  [
@@ -79,9 +143,14 @@ describe("PositionStorage with local editor", () => {
79
143
 
80
144
  // Position should be updated according to mapping
81
145
  expect(getPos()).toBe(14);
146
+
147
+ editor._tiptapEditor.destroy();
82
148
  });
83
149
 
84
150
  it("should not update mapping for local transactions after the position", () => {
151
+ const editor = BlockNoteEditor.create();
152
+ editor.mount(document.createElement("div"));
153
+
85
154
  // Set initial content
86
155
  editor.insertBlocks(
87
156
  [
@@ -117,9 +186,14 @@ describe("PositionStorage with local editor", () => {
117
186
 
118
187
  // Position should not be updated
119
188
  expect(getPos()).toBe(10);
189
+
190
+ editor._tiptapEditor.destroy();
120
191
  });
121
192
 
122
193
  it("should track positions on each side", () => {
194
+ const editor = BlockNoteEditor.create();
195
+ editor.mount(document.createElement("div"));
196
+
123
197
  editor.replaceBlocks(editor.document, [
124
198
  {
125
199
  type: "paragraph",
@@ -142,9 +216,14 @@ describe("PositionStorage with local editor", () => {
142
216
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
143
217
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
144
218
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
219
+
220
+ editor._tiptapEditor.destroy();
145
221
  });
146
222
 
147
223
  it("should handle multiple transactions", () => {
224
+ const editor = BlockNoteEditor.create();
225
+ editor.mount(document.createElement("div"));
226
+
148
227
  editor.replaceBlocks(editor.document, [
149
228
  {
150
229
  type: "paragraph",
@@ -172,6 +251,8 @@ describe("PositionStorage with local editor", () => {
172
251
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
173
252
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
174
253
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
254
+
255
+ editor._tiptapEditor.destroy();
175
256
  });
176
257
  });
177
258
 
@@ -202,16 +283,12 @@ describe("PositionStorage with remote editor", () => {
202
283
  }
203
284
 
204
285
  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();
286
+ it("should update the local position when collaborating", () => {
287
+ const ydoc = new Y.Doc();
288
+ const remoteYdoc = new Y.Doc();
289
+
213
290
  // Create a mock editor
214
- localEditor = BlockNoteEditor.create({
291
+ const localEditor = BlockNoteEditor.create({
215
292
  collaboration: {
216
293
  fragment: ydoc.getXmlFragment("doc"),
217
294
  user: { color: "#ff0000", name: "Local User" },
@@ -221,7 +298,7 @@ describe("PositionStorage with remote editor", () => {
221
298
  const div = document.createElement("div");
222
299
  localEditor.mount(div);
223
300
 
224
- remoteEditor = BlockNoteEditor.create({
301
+ const remoteEditor = BlockNoteEditor.create({
225
302
  collaboration: {
226
303
  fragment: remoteYdoc.getXmlFragment("doc"),
227
304
  user: { color: "#ff0000", name: "Remote User" },
@@ -232,18 +309,7 @@ describe("PositionStorage with remote editor", () => {
232
309
  const remoteDiv = document.createElement("div");
233
310
  remoteEditor.mount(remoteDiv);
234
311
  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
312
 
246
- it("should update the local position when collaborating", () => {
247
313
  localEditor.replaceBlocks(localEditor.document, [
248
314
  {
249
315
  type: "paragraph",
@@ -271,9 +337,40 @@ describe("PositionStorage with remote editor", () => {
271
337
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
272
338
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
273
339
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
340
+
341
+ ydoc.destroy();
342
+ remoteYdoc.destroy();
343
+ localEditor._tiptapEditor.destroy();
344
+ remoteEditor._tiptapEditor.destroy();
274
345
  });
275
346
 
276
347
  it("should handle multiple transactions when collaborating", () => {
348
+ const ydoc = new Y.Doc();
349
+ const remoteYdoc = new Y.Doc();
350
+
351
+ // Create a mock editor
352
+ const localEditor = BlockNoteEditor.create({
353
+ collaboration: {
354
+ fragment: ydoc.getXmlFragment("doc"),
355
+ user: { color: "#ff0000", name: "Local User" },
356
+ provider: undefined,
357
+ },
358
+ });
359
+ const div = document.createElement("div");
360
+ localEditor.mount(div);
361
+
362
+ const remoteEditor = BlockNoteEditor.create({
363
+ collaboration: {
364
+ fragment: remoteYdoc.getXmlFragment("doc"),
365
+ user: { color: "#ff0000", name: "Remote User" },
366
+ provider: undefined,
367
+ },
368
+ });
369
+
370
+ const remoteDiv = document.createElement("div");
371
+ remoteEditor.mount(remoteDiv);
372
+ setupTwoWaySync(ydoc, remoteYdoc);
373
+
277
374
  localEditor.replaceBlocks(localEditor.document, [
278
375
  {
279
376
  type: "paragraph",
@@ -305,9 +402,40 @@ describe("PositionStorage with remote editor", () => {
305
402
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
306
403
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
307
404
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
405
+
406
+ ydoc.destroy();
407
+ remoteYdoc.destroy();
408
+ localEditor._tiptapEditor.destroy();
409
+ remoteEditor._tiptapEditor.destroy();
308
410
  });
309
411
 
310
412
  it("should update the local position from a remote transaction", () => {
413
+ const ydoc = new Y.Doc();
414
+ const remoteYdoc = new Y.Doc();
415
+
416
+ // Create a mock editor
417
+ const localEditor = BlockNoteEditor.create({
418
+ collaboration: {
419
+ fragment: ydoc.getXmlFragment("doc"),
420
+ user: { color: "#ff0000", name: "Local User" },
421
+ provider: undefined,
422
+ },
423
+ });
424
+ const div = document.createElement("div");
425
+ localEditor.mount(div);
426
+
427
+ const remoteEditor = BlockNoteEditor.create({
428
+ collaboration: {
429
+ fragment: remoteYdoc.getXmlFragment("doc"),
430
+ user: { color: "#ff0000", name: "Remote User" },
431
+ provider: undefined,
432
+ },
433
+ });
434
+
435
+ const remoteDiv = document.createElement("div");
436
+ remoteEditor.mount(remoteDiv);
437
+ setupTwoWaySync(ydoc, remoteYdoc);
438
+
311
439
  remoteEditor.replaceBlocks(remoteEditor.document, [
312
440
  {
313
441
  type: "paragraph",
@@ -335,9 +463,40 @@ describe("PositionStorage with remote editor", () => {
335
463
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
336
464
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
337
465
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
466
+
467
+ ydoc.destroy();
468
+ remoteYdoc.destroy();
469
+ localEditor._tiptapEditor.destroy();
470
+ remoteEditor._tiptapEditor.destroy();
338
471
  });
339
472
 
340
473
  it("should update the remote position from a remote transaction", () => {
474
+ const ydoc = new Y.Doc();
475
+ const remoteYdoc = new Y.Doc();
476
+
477
+ // Create a mock editor
478
+ const localEditor = BlockNoteEditor.create({
479
+ collaboration: {
480
+ fragment: ydoc.getXmlFragment("doc"),
481
+ user: { color: "#ff0000", name: "Local User" },
482
+ provider: undefined,
483
+ },
484
+ });
485
+ const div = document.createElement("div");
486
+ localEditor.mount(div);
487
+
488
+ const remoteEditor = BlockNoteEditor.create({
489
+ collaboration: {
490
+ fragment: remoteYdoc.getXmlFragment("doc"),
491
+ user: { color: "#ff0000", name: "Remote User" },
492
+ provider: undefined,
493
+ },
494
+ });
495
+
496
+ const remoteDiv = document.createElement("div");
497
+ remoteEditor.mount(remoteDiv);
498
+ setupTwoWaySync(ydoc, remoteYdoc);
499
+
341
500
  remoteEditor.replaceBlocks(remoteEditor.document, [
342
501
  {
343
502
  type: "paragraph",
@@ -365,6 +524,11 @@ describe("PositionStorage with remote editor", () => {
365
524
  expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
366
525
  expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
367
526
  expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
527
+
528
+ ydoc.destroy();
529
+ remoteYdoc.destroy();
530
+ localEditor._tiptapEditor.destroy();
531
+ remoteEditor._tiptapEditor.destroy();
368
532
  });
369
533
  });
370
534
  });
@@ -61,9 +61,7 @@ export function trackPosition(
61
61
  */
62
62
  side: "left" | "right" = "left",
63
63
  ): () => number {
64
- const ySyncPluginState = ySyncPluginKey.getState(
65
- editor._tiptapEditor.state,
66
- ) as {
64
+ const ySyncPluginState = ySyncPluginKey.getState(editor.prosemirrorState) as {
67
65
  doc: Y.Doc;
68
66
  binding: ProsemirrorBinding;
69
67
  };
@@ -88,14 +86,14 @@ export function trackPosition(
88
86
 
89
87
  const relativePosition = absolutePositionToRelativePosition(
90
88
  // Track the position after the position if we are on the right side
91
- position + (side === "right" ? 1 : 0),
89
+ position + (side === "right" ? 1 : -1),
92
90
  ySyncPluginState.binding.type,
93
91
  ySyncPluginState.binding.mapping,
94
92
  );
95
93
 
96
94
  return () => {
97
95
  const curYSyncPluginState = ySyncPluginKey.getState(
98
- editor._tiptapEditor.state,
96
+ editor.prosemirrorState,
99
97
  ) as typeof ySyncPluginState;
100
98
  const pos = relativePositionToAbsolutePosition(
101
99
  curYSyncPluginState.doc,
@@ -109,6 +107,6 @@ export function trackPosition(
109
107
  throw new Error("Position not found, cannot track positions");
110
108
  }
111
109
 
112
- return pos + (side === "right" ? -1 : 0);
110
+ return pos + (side === "right" ? -1 : 1);
113
111
  };
114
112
  }
@@ -0,0 +1,174 @@
1
+ import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
2
+ import {
3
+ BlockFromConfig,
4
+ createBlockConfig,
5
+ createBlockSpec,
6
+ } from "../../schema/index.js";
7
+ import { defaultProps, parseDefaultProps } from "../defaultProps.js";
8
+ import { parseFigureElement } from "../File/helpers/parse/parseFigureElement.js";
9
+ import { createFileBlockWrapper } from "../File/helpers/render/createFileBlockWrapper.js";
10
+ import { createFigureWithCaption } from "../File/helpers/toExternalHTML/createFigureWithCaption.js";
11
+ import { createLinkWithCaption } from "../File/helpers/toExternalHTML/createLinkWithCaption.js";
12
+ import { parseAudioElement } from "./parseAudioElement.js";
13
+
14
+ export const FILE_AUDIO_ICON_SVG =
15
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M2 16.0001H5.88889L11.1834 20.3319C11.2727 20.405 11.3846 20.4449 11.5 20.4449C11.7761 20.4449 12 20.2211 12 19.9449V4.05519C12 3.93977 11.9601 3.8279 11.887 3.73857C11.7121 3.52485 11.3971 3.49335 11.1834 3.66821L5.88889 8.00007H2C1.44772 8.00007 1 8.44778 1 9.00007V15.0001C1 15.5524 1.44772 16.0001 2 16.0001ZM23 12C23 15.292 21.5539 18.2463 19.2622 20.2622L17.8445 18.8444C19.7758 17.1937 21 14.7398 21 12C21 9.26016 19.7758 6.80629 17.8445 5.15557L19.2622 3.73779C21.5539 5.75368 23 8.70795 23 12ZM18 12C18 10.0883 17.106 8.38548 15.7133 7.28673L14.2842 8.71584C15.3213 9.43855 16 10.64 16 12C16 13.36 15.3213 14.5614 14.2842 15.2841L15.7133 16.7132C17.106 15.6145 18 13.9116 18 12Z"></path></svg>';
16
+
17
+ export interface AudioOptions {
18
+ icon?: string;
19
+ }
20
+
21
+ export type AudioBlockConfig = ReturnType<typeof createAudioBlockConfig>;
22
+
23
+ export const createAudioBlockConfig = createBlockConfig(
24
+ (_ctx: AudioOptions) =>
25
+ ({
26
+ type: "audio" as const,
27
+ propSchema: {
28
+ backgroundColor: defaultProps.backgroundColor,
29
+ // File name.
30
+ name: {
31
+ default: "" as const,
32
+ },
33
+ // File url.
34
+ url: {
35
+ default: "" as const,
36
+ },
37
+ // File caption.
38
+ caption: {
39
+ default: "" as const,
40
+ },
41
+
42
+ showPreview: {
43
+ default: true,
44
+ },
45
+ },
46
+ content: "none",
47
+ }) as const,
48
+ );
49
+
50
+ export const audioParse =
51
+ (_config: AudioOptions = {}) =>
52
+ (element: HTMLElement) => {
53
+ if (element.tagName === "AUDIO") {
54
+ // Ignore if parent figure has already been parsed.
55
+ if (element.closest("figure")) {
56
+ return undefined;
57
+ }
58
+
59
+ const { backgroundColor } = parseDefaultProps(element);
60
+
61
+ return {
62
+ ...parseAudioElement(element as HTMLAudioElement),
63
+ backgroundColor,
64
+ };
65
+ }
66
+
67
+ if (element.tagName === "FIGURE") {
68
+ const parsedFigure = parseFigureElement(element, "audio");
69
+ if (!parsedFigure) {
70
+ return undefined;
71
+ }
72
+
73
+ const { targetElement, caption } = parsedFigure;
74
+
75
+ const { backgroundColor } = parseDefaultProps(element);
76
+
77
+ return {
78
+ ...parseAudioElement(targetElement as HTMLAudioElement),
79
+ backgroundColor,
80
+ caption,
81
+ };
82
+ }
83
+
84
+ return undefined;
85
+ };
86
+
87
+ export const audioRender =
88
+ (config: AudioOptions = {}) =>
89
+ (
90
+ block: BlockFromConfig<ReturnType<typeof createAudioBlockConfig>, any, any>,
91
+ editor: BlockNoteEditor<
92
+ Record<"audio", ReturnType<typeof createAudioBlockConfig>>,
93
+ any,
94
+ any
95
+ >,
96
+ ) => {
97
+ const icon = document.createElement("div");
98
+ icon.innerHTML = config.icon ?? FILE_AUDIO_ICON_SVG;
99
+
100
+ const audio = document.createElement("audio");
101
+ audio.className = "bn-audio";
102
+ if (editor.resolveFileUrl) {
103
+ editor.resolveFileUrl(block.props.url).then((downloadUrl) => {
104
+ audio.src = downloadUrl;
105
+ });
106
+ } else {
107
+ audio.src = block.props.url;
108
+ }
109
+ audio.controls = true;
110
+ audio.contentEditable = "false";
111
+ audio.draggable = false;
112
+
113
+ return createFileBlockWrapper(
114
+ block,
115
+ editor,
116
+ { dom: audio },
117
+ icon.firstElementChild as HTMLElement,
118
+ );
119
+ };
120
+
121
+ export const audioToExternalHTML =
122
+ (_config: AudioOptions = {}) =>
123
+ (
124
+ block: BlockFromConfig<ReturnType<typeof createAudioBlockConfig>, any, any>,
125
+ _editor: BlockNoteEditor<
126
+ Record<"audio", ReturnType<typeof createAudioBlockConfig>>,
127
+ any,
128
+ any
129
+ >,
130
+ ) => {
131
+ if (!block.props.url) {
132
+ const div = document.createElement("p");
133
+ div.textContent = "Add audio";
134
+
135
+ return {
136
+ dom: div,
137
+ };
138
+ }
139
+
140
+ let audio;
141
+ if (block.props.showPreview) {
142
+ audio = document.createElement("audio");
143
+ audio.src = block.props.url;
144
+ } else {
145
+ audio = document.createElement("a");
146
+ audio.href = block.props.url;
147
+ audio.textContent = block.props.name || block.props.url;
148
+ }
149
+
150
+ if (block.props.caption) {
151
+ if (block.props.showPreview) {
152
+ return createFigureWithCaption(audio, block.props.caption);
153
+ } else {
154
+ return createLinkWithCaption(audio, block.props.caption);
155
+ }
156
+ }
157
+
158
+ return {
159
+ dom: audio,
160
+ };
161
+ };
162
+
163
+ export const createAudioBlockSpec = createBlockSpec(
164
+ createAudioBlockConfig,
165
+ (config) => ({
166
+ meta: {
167
+ fileBlockAccept: ["audio/*"],
168
+ },
169
+ parse: audioParse(config),
170
+ render: audioRender(config),
171
+ toExternalHTML: audioToExternalHTML(config),
172
+ runsBefore: ["file"],
173
+ }),
174
+ );
@@ -0,0 +1,59 @@
1
+ import {
2
+ BlockSchema,
3
+ BlockSchemaFromSpecs,
4
+ BlockSpecs,
5
+ CustomBlockNoteSchema,
6
+ InlineContentSchema,
7
+ InlineContentSchemaFromSpecs,
8
+ InlineContentSpecs,
9
+ StyleSchema,
10
+ StyleSchemaFromSpecs,
11
+ StyleSpecs,
12
+ } from "../schema/index.js";
13
+ import {
14
+ defaultBlockSpecs,
15
+ defaultInlineContentSpecs,
16
+ defaultStyleSpecs,
17
+ } from "./defaultBlocks.js";
18
+
19
+ export class BlockNoteSchema<
20
+ BSchema extends BlockSchema,
21
+ ISchema extends InlineContentSchema,
22
+ SSchema extends StyleSchema,
23
+ > extends CustomBlockNoteSchema<BSchema, ISchema, SSchema> {
24
+ public static create<
25
+ BSpecs extends BlockSpecs | undefined = undefined,
26
+ ISpecs extends InlineContentSpecs | undefined = undefined,
27
+ SSpecs extends StyleSpecs | undefined = undefined,
28
+ >(options?: {
29
+ /**
30
+ * A list of custom block types that should be available in the editor.
31
+ */
32
+ blockSpecs?: BSpecs;
33
+ /**
34
+ * A list of custom InlineContent types that should be available in the editor.
35
+ */
36
+ inlineContentSpecs?: ISpecs;
37
+ /**
38
+ * A list of custom Styles that should be available in the editor.
39
+ */
40
+ styleSpecs?: SSpecs;
41
+ }): BlockNoteSchema<
42
+ BSpecs extends undefined
43
+ ? BlockSchemaFromSpecs<typeof defaultBlockSpecs>
44
+ : BlockSchemaFromSpecs<NonNullable<BSpecs>>,
45
+ ISpecs extends undefined
46
+ ? InlineContentSchemaFromSpecs<typeof defaultInlineContentSpecs>
47
+ : InlineContentSchemaFromSpecs<NonNullable<ISpecs>>,
48
+ SSpecs extends undefined
49
+ ? StyleSchemaFromSpecs<typeof defaultStyleSpecs>
50
+ : StyleSchemaFromSpecs<NonNullable<SSpecs>>
51
+ > {
52
+ return new BlockNoteSchema<any, any, any>({
53
+ blockSpecs: options?.blockSpecs ?? defaultBlockSpecs,
54
+ inlineContentSpecs:
55
+ options?.inlineContentSpecs ?? defaultInlineContentSpecs,
56
+ styleSpecs: options?.styleSpecs ?? defaultStyleSpecs,
57
+ });
58
+ }
59
+ }