@blocknote/core 0.19.2 → 0.21.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 (220) hide show
  1. package/dist/blocknote.js +2035 -1758
  2. package/dist/blocknote.js.map +1 -1
  3. package/dist/blocknote.umd.cjs +6 -6
  4. package/dist/blocknote.umd.cjs.map +1 -1
  5. package/dist/src/api/blockManipulation/commands/insertBlocks/insertBlocks.js +6 -3
  6. package/dist/src/api/blockManipulation/commands/insertBlocks/insertBlocks.js.map +1 -1
  7. package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.js +219 -0
  8. package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.js.map +1 -0
  9. package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.js +175 -0
  10. package/dist/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.js.map +1 -0
  11. package/dist/src/api/blockManipulation/commands/splitBlock/splitBlock.test.js +4 -1
  12. package/dist/src/api/blockManipulation/commands/splitBlock/splitBlock.test.js.map +1 -1
  13. package/dist/src/api/blockManipulation/commands/updateBlock/updateBlock.js +6 -3
  14. package/dist/src/api/blockManipulation/commands/updateBlock/updateBlock.js.map +1 -1
  15. package/dist/src/api/blockManipulation/getBlock/getBlock.js +56 -0
  16. package/dist/src/api/blockManipulation/getBlock/getBlock.js.map +1 -0
  17. package/dist/src/api/blockManipulation/selections/selection.js +149 -0
  18. package/dist/src/api/blockManipulation/selections/selection.js.map +1 -0
  19. package/dist/src/api/blockManipulation/selections/selection.test.js +39 -0
  20. package/dist/src/api/blockManipulation/selections/selection.test.js.map +1 -0
  21. package/dist/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.js +3 -0
  22. package/dist/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.js.map +1 -1
  23. package/dist/src/api/clipboard/clipboard.test.js +6 -3
  24. package/dist/src/api/clipboard/clipboard.test.js.map +1 -1
  25. package/dist/src/api/clipboard/fromClipboard/handleFileInsertion.js +1 -1
  26. package/dist/src/api/clipboard/fromClipboard/handleFileInsertion.js.map +1 -1
  27. package/dist/src/api/clipboard/fromClipboard/handleVSCodePaste.js +2 -3
  28. package/dist/src/api/clipboard/fromClipboard/handleVSCodePaste.js.map +1 -1
  29. package/dist/src/api/clipboard/fromClipboard/pasteExtension.js +5 -5
  30. package/dist/src/api/clipboard/fromClipboard/pasteExtension.js.map +1 -1
  31. package/dist/src/api/clipboard/toClipboard/copyExtension.js +4 -2
  32. package/dist/src/api/clipboard/toClipboard/copyExtension.js.map +1 -1
  33. package/dist/src/api/nodeUtil.js +1 -1
  34. package/dist/src/api/nodeUtil.js.map +1 -1
  35. package/dist/src/api/parsers/markdown/parseMarkdown.test.js +4 -1
  36. package/dist/src/api/parsers/markdown/parseMarkdown.test.js.map +1 -1
  37. package/dist/src/blocks/AudioBlockContent/AudioBlockContent.js +14 -7
  38. package/dist/src/blocks/AudioBlockContent/AudioBlockContent.js.map +1 -1
  39. package/dist/src/blocks/AudioBlockContent/{audioBlockHelpers.js → parseAudioElement.js} +1 -1
  40. package/dist/src/blocks/AudioBlockContent/parseAudioElement.js.map +1 -0
  41. package/dist/src/blocks/FileBlockContent/FileBlockContent.js +5 -4
  42. package/dist/src/blocks/FileBlockContent/FileBlockContent.js.map +1 -1
  43. package/dist/src/blocks/FileBlockContent/helpers/parse/parseEmbedElement.js +5 -0
  44. package/dist/src/blocks/FileBlockContent/helpers/parse/parseEmbedElement.js.map +1 -0
  45. package/dist/src/blocks/FileBlockContent/helpers/parse/parseFigureElement.js +10 -0
  46. package/dist/src/blocks/FileBlockContent/helpers/parse/parseFigureElement.js.map +1 -0
  47. package/dist/src/blocks/FileBlockContent/helpers/render/createAddFileButton.js +39 -0
  48. package/dist/src/blocks/FileBlockContent/helpers/render/createAddFileButton.js.map +1 -0
  49. package/dist/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.js +51 -0
  50. package/dist/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.js.map +1 -0
  51. package/dist/src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.js +17 -0
  52. package/dist/src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.js.map +1 -0
  53. package/dist/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.js +147 -0
  54. package/dist/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.js.map +1 -0
  55. package/dist/src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js +9 -0
  56. package/dist/src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js.map +1 -0
  57. package/dist/src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js +11 -0
  58. package/dist/src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js.map +1 -0
  59. package/dist/src/blocks/ImageBlockContent/ImageBlockContent.js +17 -9
  60. package/dist/src/blocks/ImageBlockContent/ImageBlockContent.js.map +1 -1
  61. package/dist/src/blocks/ImageBlockContent/{imageBlockHelpers.js → parseImageElement.js} +1 -1
  62. package/dist/src/blocks/ImageBlockContent/parseImageElement.js.map +1 -0
  63. package/dist/src/blocks/TableBlockContent/TableExtension.js +8 -1
  64. package/dist/src/blocks/TableBlockContent/TableExtension.js.map +1 -1
  65. package/dist/src/blocks/VideoBlockContent/VideoBlockContent.js +18 -7
  66. package/dist/src/blocks/VideoBlockContent/VideoBlockContent.js.map +1 -1
  67. package/dist/src/blocks/VideoBlockContent/{videoBlockHelpers.js → parseVideoElement.js} +1 -1
  68. package/dist/src/blocks/VideoBlockContent/parseVideoElement.js.map +1 -0
  69. package/dist/src/editor/BlockNoteEditor.js +64 -62
  70. package/dist/src/editor/BlockNoteEditor.js.map +1 -1
  71. package/dist/src/editor/BlockNoteExtensions.js +5 -8
  72. package/dist/src/editor/BlockNoteExtensions.js.map +1 -1
  73. package/dist/src/extensions/FormattingToolbar/FormattingToolbarPlugin.js +4 -2
  74. package/dist/src/extensions/FormattingToolbar/FormattingToolbarPlugin.js.map +1 -1
  75. package/dist/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js +10 -8
  76. package/dist/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js.map +1 -1
  77. package/dist/src/extensions/LinkToolbar/LinkToolbarPlugin.js +7 -3
  78. package/dist/src/extensions/LinkToolbar/LinkToolbarPlugin.js.map +1 -1
  79. package/dist/src/extensions/LinkToolbar/protocols.js +14 -0
  80. package/dist/src/extensions/LinkToolbar/protocols.js.map +1 -0
  81. package/dist/src/extensions/Placeholder/PlaceholderPlugin.js +19 -13
  82. package/dist/src/extensions/Placeholder/PlaceholderPlugin.js.map +1 -1
  83. package/dist/src/extensions/SideMenu/SideMenuPlugin.js +5 -1
  84. package/dist/src/extensions/SideMenu/SideMenuPlugin.js.map +1 -1
  85. package/dist/src/extensions/SideMenu/dragging.js +8 -1
  86. package/dist/src/extensions/SideMenu/dragging.js.map +1 -1
  87. package/dist/src/extensions/SuggestionMenu/SuggestionPlugin.js +3 -3
  88. package/dist/src/extensions/SuggestionMenu/SuggestionPlugin.js.map +1 -1
  89. package/dist/src/extensions/TableHandles/TableHandlesPlugin.js +37 -11
  90. package/dist/src/extensions/TableHandles/TableHandlesPlugin.js.map +1 -1
  91. package/dist/src/i18n/locales/ru.js +1 -1
  92. package/dist/src/index.js +9 -2
  93. package/dist/src/index.js.map +1 -1
  94. package/dist/src/schema/inlineContent/createSpec.js +1 -1
  95. package/dist/src/schema/inlineContent/createSpec.js.map +1 -1
  96. package/dist/style.css +1 -1
  97. package/dist/tsconfig.tsbuildinfo +1 -1
  98. package/dist/webpack-stats.json +1 -1
  99. package/package.json +3 -3
  100. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +6 -6
  101. package/src/api/blockManipulation/commands/moveBlocks/__snapshots__/moveBlocks.test.ts.snap +9506 -0
  102. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.test.ts +295 -0
  103. package/src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts +336 -0
  104. package/src/api/blockManipulation/commands/splitBlock/splitBlock.test.ts +5 -1
  105. package/src/api/blockManipulation/commands/updateBlock/updateBlock.ts +11 -3
  106. package/src/api/blockManipulation/getBlock/getBlock.ts +141 -0
  107. package/src/api/blockManipulation/selections/__snapshots__/selection.test.ts.snap +660 -0
  108. package/src/api/blockManipulation/selections/selection.test.ts +56 -0
  109. package/src/api/blockManipulation/selections/selection.ts +244 -0
  110. package/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts +4 -0
  111. package/src/api/clipboard/__snapshots__/tableAllCells.html +1 -1
  112. package/src/api/clipboard/__snapshots__/tableCell.html +1 -1
  113. package/src/api/clipboard/__snapshots__/tableRow.html +1 -1
  114. package/src/api/clipboard/clipboard.test.ts +7 -3
  115. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +1 -1
  116. package/src/api/clipboard/fromClipboard/handleVSCodePaste.ts +7 -14
  117. package/src/api/clipboard/fromClipboard/pasteExtension.ts +6 -6
  118. package/src/api/clipboard/toClipboard/copyExtension.ts +7 -2
  119. package/src/api/exporters/html/__snapshots__/file/basic/internal.html +1 -1
  120. package/src/api/exporters/html/__snapshots__/file/nested/internal.html +1 -1
  121. package/src/api/exporters/html/__snapshots__/file/noCaption/internal.html +1 -1
  122. package/src/api/exporters/html/__snapshots__/file/noName/internal.html +1 -1
  123. package/src/api/exporters/html/__snapshots__/image/basic/internal.html +1 -1
  124. package/src/api/exporters/html/__snapshots__/image/nested/internal.html +1 -1
  125. package/src/api/exporters/html/__snapshots__/image/noCaption/internal.html +1 -1
  126. package/src/api/exporters/html/__snapshots__/image/noName/internal.html +1 -1
  127. package/src/api/exporters/html/__snapshots__/image/noPreview/internal.html +1 -1
  128. package/src/api/exporters/html/__snapshots__/simpleImage/basic/external.html +1 -1
  129. package/src/api/exporters/html/__snapshots__/simpleImage/basic/internal.html +1 -1
  130. package/src/api/exporters/html/__snapshots__/simpleImage/nested/external.html +1 -1
  131. package/src/api/exporters/html/__snapshots__/simpleImage/nested/internal.html +1 -1
  132. package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/external.html +1 -1
  133. package/src/api/exporters/html/__snapshots__/simpleImage/noCaption/internal.html +1 -1
  134. package/src/api/exporters/html/__snapshots__/simpleImage/noName/external.html +1 -1
  135. package/src/api/exporters/html/__snapshots__/simpleImage/noName/internal.html +1 -1
  136. package/src/api/exporters/html/__snapshots__/simpleImage/noPreview/external.html +1 -1
  137. package/src/api/exporters/html/__snapshots__/simpleImage/noPreview/internal.html +1 -1
  138. package/src/api/exporters/markdown/__snapshots__/simpleImage/basic/markdown.md +1 -1
  139. package/src/api/exporters/markdown/__snapshots__/simpleImage/nested/markdown.md +2 -2
  140. package/src/api/exporters/markdown/__snapshots__/simpleImage/noCaption/markdown.md +1 -1
  141. package/src/api/exporters/markdown/__snapshots__/simpleImage/noName/markdown.md +1 -1
  142. package/src/api/nodeUtil.ts +2 -2
  143. package/src/api/parsers/markdown/parseMarkdown.test.ts +5 -7
  144. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +13 -14
  145. package/src/blocks/FileBlockContent/FileBlockContent.ts +5 -12
  146. package/src/blocks/FileBlockContent/helpers/parse/parseEmbedElement.ts +5 -0
  147. package/src/blocks/FileBlockContent/helpers/parse/parseFigureElement.ts +16 -0
  148. package/src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts +63 -0
  149. package/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts +80 -0
  150. package/src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.ts +24 -0
  151. package/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts +204 -0
  152. package/src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.ts +13 -0
  153. package/src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.ts +15 -0
  154. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +20 -28
  155. package/src/blocks/TableBlockContent/TableExtension.ts +12 -1
  156. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +20 -27
  157. package/src/editor/Block.css +35 -51
  158. package/src/editor/BlockNoteEditor.ts +101 -92
  159. package/src/editor/BlockNoteExtensions.ts +9 -8
  160. package/src/editor/editor.css +1 -0
  161. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +4 -2
  162. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +11 -8
  163. package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +11 -4
  164. package/src/extensions/LinkToolbar/protocols.ts +13 -0
  165. package/src/extensions/Placeholder/PlaceholderPlugin.ts +29 -21
  166. package/src/extensions/SideMenu/SideMenuPlugin.ts +5 -1
  167. package/src/extensions/SideMenu/dragging.ts +8 -1
  168. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +3 -6
  169. package/src/extensions/TableHandles/TableHandlesPlugin.ts +49 -12
  170. package/src/i18n/locales/ru.ts +1 -1
  171. package/src/index.ts +9 -2
  172. package/src/schema/inlineContent/createSpec.ts +2 -2
  173. package/types/src/api/blockManipulation/commands/moveBlocks/moveBlocks.d.ts +15 -0
  174. package/types/src/api/blockManipulation/getBlock/getBlock.d.ts +7 -0
  175. package/types/src/api/blockManipulation/selections/selection.d.ts +5 -0
  176. package/types/src/api/blockManipulation/selections/selection.test.d.ts +1 -0
  177. package/types/src/api/clipboard/fromClipboard/handleVSCodePaste.d.ts +2 -3
  178. package/types/src/api/clipboard/fromClipboard/pasteExtension.d.ts +1 -3
  179. package/types/src/api/nodeUtil.d.ts +1 -1
  180. package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +2 -5
  181. package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +2 -5
  182. package/types/src/blocks/FileBlockContent/helpers/parse/parseEmbedElement.d.ts +3 -0
  183. package/types/src/blocks/FileBlockContent/helpers/parse/parseFigureElement.d.ts +4 -0
  184. package/types/src/blocks/FileBlockContent/helpers/render/createAddFileButton.d.ts +6 -0
  185. package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +9 -0
  186. package/types/src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.d.ts +6 -0
  187. package/types/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.d.ts +9 -0
  188. package/types/src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.d.ts +3 -0
  189. package/types/src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.d.ts +3 -0
  190. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +2 -5
  191. package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +2 -5
  192. package/types/src/editor/BlockNoteEditor.d.ts +60 -14
  193. package/types/src/editor/BlockNoteExtensions.d.ts +1 -0
  194. package/types/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.d.ts +1 -0
  195. package/types/src/extensions/LinkToolbar/protocols.d.ts +2 -0
  196. package/types/src/index.d.ts +9 -2
  197. package/types/src/pm-nodes/BlockContainer.d.ts +2 -2
  198. package/types/src/pm-nodes/BlockGroup.d.ts +2 -2
  199. package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.js +0 -116
  200. package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.js.map +0 -1
  201. package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.test.js +0 -110
  202. package/dist/src/api/blockManipulation/commands/moveBlock/moveBlock.test.js.map +0 -1
  203. package/dist/src/blocks/AudioBlockContent/audioBlockHelpers.js.map +0 -1
  204. package/dist/src/blocks/FileBlockContent/fileBlockHelpers.js +0 -317
  205. package/dist/src/blocks/FileBlockContent/fileBlockHelpers.js.map +0 -1
  206. package/dist/src/blocks/ImageBlockContent/imageBlockHelpers.js.map +0 -1
  207. package/dist/src/blocks/VideoBlockContent/videoBlockHelpers.js.map +0 -1
  208. package/src/api/blockManipulation/commands/moveBlock/__snapshots__/moveBlock.test.ts.snap +0 -3799
  209. package/src/api/blockManipulation/commands/moveBlock/moveBlock.test.ts +0 -196
  210. package/src/api/blockManipulation/commands/moveBlock/moveBlock.ts +0 -176
  211. package/src/blocks/FileBlockContent/fileBlockHelpers.ts +0 -456
  212. package/types/src/api/blockManipulation/commands/moveBlock/moveBlock.d.ts +0 -5
  213. package/types/src/blocks/FileBlockContent/fileBlockHelpers.d.ts +0 -41
  214. /package/src/blocks/AudioBlockContent/{audioBlockHelpers.ts → parseAudioElement.ts} +0 -0
  215. /package/src/blocks/ImageBlockContent/{imageBlockHelpers.ts → parseImageElement.ts} +0 -0
  216. /package/src/blocks/VideoBlockContent/{videoBlockHelpers.ts → parseVideoElement.ts} +0 -0
  217. /package/types/src/api/blockManipulation/commands/{moveBlock/moveBlock.test.d.ts → moveBlocks/moveBlocks.test.d.ts} +0 -0
  218. /package/types/src/blocks/AudioBlockContent/{audioBlockHelpers.d.ts → parseAudioElement.d.ts} +0 -0
  219. /package/types/src/blocks/ImageBlockContent/{imageBlockHelpers.d.ts → parseImageElement.d.ts} +0 -0
  220. /package/types/src/blocks/VideoBlockContent/{videoBlockHelpers.d.ts → parseVideoElement.d.ts} +0 -0
@@ -16,13 +16,11 @@ async function parseMarkdownAndCompareSnapshots(
16
16
  snapshotPath
17
17
  );
18
18
 
19
- doPaste(
20
- editor._tiptapEditor.view,
21
- md,
22
- null,
23
- true,
24
- new ClipboardEvent("paste")
25
- );
19
+ if (!editor.prosemirrorView) {
20
+ throw new Error("Editor view not initialized.");
21
+ }
22
+
23
+ doPaste(editor.prosemirrorView, md, null, true, new ClipboardEvent("paste"));
26
24
 
27
25
  const pastedSnapshotPath = "./__snapshots__/pasted/" + snapshotName + ".json";
28
26
  expect(JSON.stringify(editor.document, undefined, 2)).toMatchFileSnapshot(
@@ -8,14 +8,11 @@ import {
8
8
  } from "../../schema/index.js";
9
9
  import { defaultProps } from "../defaultProps.js";
10
10
 
11
- import {
12
- createFigureWithCaption,
13
- createFileAndCaptionWrapper,
14
- createFileBlockWrapper,
15
- createLinkWithCaption,
16
- parseFigureElement,
17
- } from "../FileBlockContent/fileBlockHelpers.js";
18
- import { parseAudioElement } from "./audioBlockHelpers.js";
11
+ import { parseFigureElement } from "../FileBlockContent/helpers/parse/parseFigureElement.js";
12
+ import { createFileBlockWrapper } from "../FileBlockContent/helpers/render/createFileBlockWrapper.js";
13
+ import { createFigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js";
14
+ import { createLinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js";
15
+ import { parseAudioElement } from "./parseAudioElement.js";
19
16
 
20
17
  export const FILE_AUDIO_ICON_SVG =
21
18
  '<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>';
@@ -57,19 +54,21 @@ export const audioRender = (
57
54
 
58
55
  const audio = document.createElement("audio");
59
56
  audio.className = "bn-audio";
60
- editor.resolveFileUrl(block.props.url).then((downloadUrl) => {
61
- audio.src = downloadUrl;
62
- });
57
+ if (editor.resolveFileUrl) {
58
+ editor.resolveFileUrl(block.props.url).then((downloadUrl) => {
59
+ audio.src = downloadUrl;
60
+ });
61
+ } else {
62
+ audio.src = block.props.url;
63
+ }
63
64
  audio.controls = true;
64
65
  audio.contentEditable = "false";
65
66
  audio.draggable = false;
66
67
 
67
- const element = createFileAndCaptionWrapper(block, audio);
68
-
69
68
  return createFileBlockWrapper(
70
69
  block,
71
70
  editor,
72
- element,
71
+ { dom: audio },
73
72
  editor.dictionary.file_blocks.audio.add_button_text,
74
73
  icon.firstElementChild as HTMLElement
75
74
  );
@@ -6,14 +6,10 @@ import {
6
6
  createBlockSpec,
7
7
  } from "../../schema/index.js";
8
8
  import { defaultProps } from "../defaultProps.js";
9
- import {
10
- createDefaultFilePreview,
11
- createFileAndCaptionWrapper,
12
- createFileBlockWrapper,
13
- createLinkWithCaption,
14
- parseEmbedElement,
15
- parseFigureElement,
16
- } from "./fileBlockHelpers.js";
9
+ import { parseEmbedElement } from "./helpers/parse/parseEmbedElement.js";
10
+ import { parseFigureElement } from "./helpers/parse/parseFigureElement.js";
11
+ import { createFileBlockWrapper } from "./helpers/render/createFileBlockWrapper.js";
12
+ import { createLinkWithCaption } from "./helpers/toExternalHTML/createLinkWithCaption.js";
17
13
 
18
14
  export const filePropSchema = {
19
15
  backgroundColor: defaultProps.backgroundColor,
@@ -42,10 +38,7 @@ export const fileRender = (
42
38
  block: BlockFromConfig<typeof fileBlockConfig, any, any>,
43
39
  editor: BlockNoteEditor<any, any, any>
44
40
  ) => {
45
- const file = createDefaultFilePreview(block).dom;
46
- const element = createFileAndCaptionWrapper(block, file);
47
-
48
- return createFileBlockWrapper(block, editor, element);
41
+ return createFileBlockWrapper(block, editor);
49
42
  };
50
43
 
51
44
  export const fileParse = (element: HTMLElement) => {
@@ -0,0 +1,5 @@
1
+ export const parseEmbedElement = (embedElement: HTMLEmbedElement) => {
2
+ const url = embedElement.src || undefined;
3
+
4
+ return { url };
5
+ };
@@ -0,0 +1,16 @@
1
+ export const parseFigureElement = (
2
+ figureElement: HTMLElement,
3
+ targetTag: string
4
+ ) => {
5
+ const targetElement = figureElement.querySelector(
6
+ targetTag
7
+ ) as HTMLElement | null;
8
+ if (!targetElement) {
9
+ return undefined;
10
+ }
11
+
12
+ const captionElement = figureElement.querySelector("figcaption");
13
+ const caption = captionElement?.textContent ?? undefined;
14
+
15
+ return { targetElement, caption };
16
+ };
@@ -0,0 +1,63 @@
1
+ import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
2
+ import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js";
3
+
4
+ export const createAddFileButton = (
5
+ block: BlockFromConfig<FileBlockConfig, any, any>,
6
+ editor: BlockNoteEditor<any, any, any>,
7
+ buttonText?: string,
8
+ buttonIcon?: HTMLElement
9
+ ) => {
10
+ const addFileButton = document.createElement("div");
11
+ addFileButton.className = "bn-add-file-button";
12
+
13
+ const addFileButtonIcon = document.createElement("div");
14
+ addFileButtonIcon.className = "bn-add-file-button-icon";
15
+ if (buttonIcon) {
16
+ addFileButtonIcon.appendChild(buttonIcon);
17
+ } else {
18
+ addFileButtonIcon.innerHTML =
19
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8ZM10 4V9H5V20H19V4H10Z"></path></svg>';
20
+ }
21
+ addFileButton.appendChild(addFileButtonIcon);
22
+
23
+ const addFileButtonText = document.createElement("p");
24
+ addFileButtonText.className = "bn-add-file-button-text";
25
+ addFileButtonText.innerHTML =
26
+ buttonText || editor.dictionary.file_blocks.file.add_button_text;
27
+ addFileButton.appendChild(addFileButtonText);
28
+
29
+ // Prevents focus from moving to the button.
30
+ const addFileButtonMouseDownHandler = (event: MouseEvent) => {
31
+ event.preventDefault();
32
+ };
33
+ // Opens the file toolbar.
34
+ const addFileButtonClickHandler = () => {
35
+ editor.dispatch(
36
+ editor._tiptapEditor.state.tr.setMeta(editor.filePanel!.plugin, {
37
+ block: block,
38
+ })
39
+ );
40
+ };
41
+ addFileButton.addEventListener(
42
+ "mousedown",
43
+ addFileButtonMouseDownHandler,
44
+ true
45
+ );
46
+ addFileButton.addEventListener("click", addFileButtonClickHandler, true);
47
+
48
+ return {
49
+ dom: addFileButton,
50
+ destroy: () => {
51
+ addFileButton.removeEventListener(
52
+ "mousedown",
53
+ addFileButtonMouseDownHandler,
54
+ true
55
+ );
56
+ addFileButton.removeEventListener(
57
+ "click",
58
+ addFileButtonClickHandler,
59
+ true
60
+ );
61
+ },
62
+ };
63
+ };
@@ -0,0 +1,80 @@
1
+ import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
2
+ import {
3
+ BlockFromConfig,
4
+ BlockSchemaWithBlock,
5
+ FileBlockConfig,
6
+ } from "../../../../schema/index.js";
7
+ import { createAddFileButton } from "./createAddFileButton.js";
8
+ import { createFileNameWithIcon } from "./createFileNameWithIcon.js";
9
+
10
+ export const createFileBlockWrapper = (
11
+ block: BlockFromConfig<FileBlockConfig, any, any>,
12
+ editor: BlockNoteEditor<
13
+ BlockSchemaWithBlock<FileBlockConfig["type"], FileBlockConfig>,
14
+ any,
15
+ any
16
+ >,
17
+ element?: { dom: HTMLElement; destroy?: () => void },
18
+ buttonText?: string,
19
+ buttonIcon?: HTMLElement
20
+ ) => {
21
+ const wrapper = document.createElement("div");
22
+ wrapper.className = "bn-file-block-content-wrapper";
23
+
24
+ // Show the add file button if the file has not been uploaded yet. Change to
25
+ // show a loader if a file upload for the block begins.
26
+ if (block.props.url === "") {
27
+ const addFileButton = createAddFileButton(
28
+ block,
29
+ editor,
30
+ buttonText,
31
+ buttonIcon
32
+ );
33
+ wrapper.appendChild(addFileButton.dom);
34
+
35
+ const destroyUploadStartHandler = editor.onUploadStart((blockId) => {
36
+ if (blockId === block.id) {
37
+ wrapper.removeChild(addFileButton.dom);
38
+
39
+ const loading = document.createElement("div");
40
+ loading.className = "bn-file-loading-preview";
41
+ loading.textContent = "Loading...";
42
+ wrapper.appendChild(loading);
43
+ }
44
+ });
45
+
46
+ return {
47
+ dom: wrapper,
48
+ destroy: () => {
49
+ destroyUploadStartHandler();
50
+ addFileButton.destroy();
51
+ },
52
+ };
53
+ }
54
+
55
+ const ret: { dom: HTMLElement; destroy?: () => void } = { dom: wrapper };
56
+
57
+ // Show the file preview, or the file name and icon.
58
+ if (block.props.showPreview === false || !element) {
59
+ // Show file name and icon.
60
+ const fileNameWithIcon = createFileNameWithIcon(block);
61
+ wrapper.appendChild(fileNameWithIcon.dom);
62
+
63
+ ret.destroy = () => {
64
+ fileNameWithIcon.destroy?.();
65
+ };
66
+ } else {
67
+ // Show file preview.
68
+ wrapper.appendChild(element.dom);
69
+ }
70
+
71
+ // Show the caption if there is one.
72
+ if (block.props.caption) {
73
+ const caption = document.createElement("p");
74
+ caption.className = "bn-file-caption";
75
+ caption.textContent = block.props.caption;
76
+ wrapper.appendChild(caption);
77
+ }
78
+
79
+ return ret;
80
+ };
@@ -0,0 +1,24 @@
1
+ import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js";
2
+
3
+ export const FILE_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8ZM10 4V9H5V20H19V4H10Z"></path></svg>`;
4
+
5
+ export const createFileNameWithIcon = (
6
+ block: BlockFromConfig<FileBlockConfig, any, any>
7
+ ): { dom: HTMLElement; destroy?: () => void } => {
8
+ const file = document.createElement("div");
9
+ file.className = "bn-file-name-with-icon";
10
+
11
+ const icon = document.createElement("div");
12
+ icon.className = "bn-file-icon";
13
+ icon.innerHTML = FILE_ICON_SVG;
14
+ file.appendChild(icon);
15
+
16
+ const fileName = document.createElement("p");
17
+ fileName.className = "bn-file-name";
18
+ fileName.textContent = block.props.name;
19
+ file.appendChild(fileName);
20
+
21
+ return {
22
+ dom: file,
23
+ };
24
+ };
@@ -0,0 +1,204 @@
1
+ import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
2
+ import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js";
3
+ import { createFileBlockWrapper } from "./createFileBlockWrapper.js";
4
+
5
+ export const createResizableFileBlockWrapper = (
6
+ block: BlockFromConfig<FileBlockConfig, any, any>,
7
+ editor: BlockNoteEditor<any, any, any>,
8
+ element: { dom: HTMLElement; destroy?: () => void },
9
+ resizeHandlesContainerElement: HTMLElement,
10
+ buttonText: string,
11
+ buttonIcon: HTMLElement
12
+ ): { dom: HTMLElement; destroy: () => void } => {
13
+ const { dom, destroy } = createFileBlockWrapper(
14
+ block,
15
+ editor,
16
+ element,
17
+ buttonText,
18
+ buttonIcon
19
+ );
20
+ const wrapper = dom;
21
+ if (block.props.url && block.props.showPreview) {
22
+ wrapper.style.width = `${block.props.previewWidth}px`;
23
+ }
24
+
25
+ const leftResizeHandle = document.createElement("div");
26
+ leftResizeHandle.className = "bn-resize-handle";
27
+ leftResizeHandle.style.left = "4px";
28
+ const rightResizeHandle = document.createElement("div");
29
+ rightResizeHandle.className = "bn-resize-handle";
30
+ rightResizeHandle.style.right = "4px";
31
+
32
+ // Temporary parameters set when the user begins resizing the element, used to
33
+ // calculate the new width of the element.
34
+ let resizeParams:
35
+ | {
36
+ handleUsed: "left" | "right";
37
+ initialWidth: number;
38
+ initialClientX: number;
39
+ }
40
+ | undefined;
41
+ let width = block.props.previewWidth! as number;
42
+
43
+ // Updates the element width with an updated width depending on the cursor X
44
+ // offset from when the resize began, and which resize handle is being used.
45
+ const windowMouseMoveHandler = (event: MouseEvent) => {
46
+ if (!resizeParams) {
47
+ if (
48
+ !editor.isEditable &&
49
+ resizeHandlesContainerElement.contains(leftResizeHandle) &&
50
+ resizeHandlesContainerElement.contains(rightResizeHandle)
51
+ ) {
52
+ resizeHandlesContainerElement.removeChild(leftResizeHandle);
53
+ resizeHandlesContainerElement.removeChild(rightResizeHandle);
54
+ }
55
+
56
+ return;
57
+ }
58
+
59
+ let newWidth: number;
60
+
61
+ if (block.props.textAlignment === "center") {
62
+ if (resizeParams.handleUsed === "left") {
63
+ newWidth =
64
+ resizeParams.initialWidth +
65
+ (resizeParams.initialClientX - event.clientX) * 2;
66
+ } else {
67
+ newWidth =
68
+ resizeParams.initialWidth +
69
+ (event.clientX - resizeParams.initialClientX) * 2;
70
+ }
71
+ } else {
72
+ if (resizeParams.handleUsed === "left") {
73
+ newWidth =
74
+ resizeParams.initialWidth +
75
+ resizeParams.initialClientX -
76
+ event.clientX;
77
+ } else {
78
+ newWidth =
79
+ resizeParams.initialWidth +
80
+ event.clientX -
81
+ resizeParams.initialClientX;
82
+ }
83
+ }
84
+
85
+ // Min element width in px.
86
+ const minWidth = 64;
87
+
88
+ // Ensures the element is not wider than the editor and not narrower than a
89
+ // predetermined minimum width.
90
+ width = Math.max(newWidth, minWidth);
91
+ wrapper.style.width = `${width}px`;
92
+ };
93
+ // Stops mouse movements from resizing the element and updates the block's
94
+ // `width` prop to the new value.
95
+ const windowMouseUpHandler = (event: MouseEvent) => {
96
+ // Hides the drag handles if the cursor is no longer over the element.
97
+ if (
98
+ (!event.target ||
99
+ !wrapper.contains(event.target as Node) ||
100
+ !editor.isEditable) &&
101
+ resizeHandlesContainerElement.contains(leftResizeHandle) &&
102
+ resizeHandlesContainerElement.contains(rightResizeHandle)
103
+ ) {
104
+ resizeHandlesContainerElement.removeChild(leftResizeHandle);
105
+ resizeHandlesContainerElement.removeChild(rightResizeHandle);
106
+ }
107
+
108
+ if (!resizeParams) {
109
+ return;
110
+ }
111
+
112
+ resizeParams = undefined;
113
+
114
+ editor.updateBlock(block, {
115
+ props: {
116
+ previewWidth: width,
117
+ },
118
+ });
119
+ };
120
+
121
+ // Shows the resize handles when hovering over the wrapper with the cursor.
122
+ const wrapperMouseEnterHandler = () => {
123
+ if (editor.isEditable) {
124
+ resizeHandlesContainerElement.appendChild(leftResizeHandle);
125
+ resizeHandlesContainerElement.appendChild(rightResizeHandle);
126
+ }
127
+ };
128
+ // Hides the resize handles when the cursor leaves the wrapper, unless the
129
+ // cursor moves to one of the resize handles.
130
+ const wrapperMouseLeaveHandler = (event: MouseEvent) => {
131
+ if (
132
+ event.relatedTarget === leftResizeHandle ||
133
+ event.relatedTarget === rightResizeHandle
134
+ ) {
135
+ return;
136
+ }
137
+
138
+ if (resizeParams) {
139
+ return;
140
+ }
141
+
142
+ if (
143
+ editor.isEditable &&
144
+ resizeHandlesContainerElement.contains(leftResizeHandle) &&
145
+ resizeHandlesContainerElement.contains(rightResizeHandle)
146
+ ) {
147
+ resizeHandlesContainerElement.removeChild(leftResizeHandle);
148
+ resizeHandlesContainerElement.removeChild(rightResizeHandle);
149
+ }
150
+ };
151
+
152
+ // Sets the resize params, allowing the user to begin resizing the element by
153
+ // moving the cursor left or right.
154
+ const leftResizeHandleMouseDownHandler = (event: MouseEvent) => {
155
+ event.preventDefault();
156
+
157
+ resizeParams = {
158
+ handleUsed: "left",
159
+ initialWidth: wrapper.clientWidth,
160
+ initialClientX: event.clientX,
161
+ };
162
+ };
163
+ const rightResizeHandleMouseDownHandler = (event: MouseEvent) => {
164
+ event.preventDefault();
165
+
166
+ resizeParams = {
167
+ handleUsed: "right",
168
+ initialWidth: wrapper.clientWidth,
169
+ initialClientX: event.clientX,
170
+ };
171
+ };
172
+
173
+ window.addEventListener("mousemove", windowMouseMoveHandler);
174
+ window.addEventListener("mouseup", windowMouseUpHandler);
175
+ wrapper.addEventListener("mouseenter", wrapperMouseEnterHandler);
176
+ wrapper.addEventListener("mouseleave", wrapperMouseLeaveHandler);
177
+ leftResizeHandle.addEventListener(
178
+ "mousedown",
179
+ leftResizeHandleMouseDownHandler
180
+ );
181
+ rightResizeHandle.addEventListener(
182
+ "mousedown",
183
+ rightResizeHandleMouseDownHandler
184
+ );
185
+
186
+ return {
187
+ dom: wrapper,
188
+ destroy: () => {
189
+ destroy?.();
190
+ window.removeEventListener("mousemove", windowMouseMoveHandler);
191
+ window.removeEventListener("mouseup", windowMouseUpHandler);
192
+ wrapper.removeEventListener("mouseenter", wrapperMouseEnterHandler);
193
+ wrapper.removeEventListener("mouseleave", wrapperMouseLeaveHandler);
194
+ leftResizeHandle.removeEventListener(
195
+ "mousedown",
196
+ leftResizeHandleMouseDownHandler
197
+ );
198
+ rightResizeHandle.removeEventListener(
199
+ "mousedown",
200
+ rightResizeHandleMouseDownHandler
201
+ );
202
+ },
203
+ };
204
+ };
@@ -0,0 +1,13 @@
1
+ export const createFigureWithCaption = (
2
+ element: HTMLElement,
3
+ caption: string
4
+ ) => {
5
+ const figure = document.createElement("figure");
6
+ const captionElement = document.createElement("figcaption");
7
+ captionElement.textContent = caption;
8
+
9
+ figure.appendChild(element);
10
+ figure.appendChild(captionElement);
11
+
12
+ return { dom: figure };
13
+ };
@@ -0,0 +1,15 @@
1
+ export const createLinkWithCaption = (
2
+ element: HTMLElement,
3
+ caption: string
4
+ ) => {
5
+ const wrapper = document.createElement("div");
6
+ const fileCaption = document.createElement("p");
7
+ fileCaption.textContent = caption;
8
+
9
+ wrapper.appendChild(element);
10
+ wrapper.appendChild(fileCaption);
11
+
12
+ return {
13
+ dom: wrapper,
14
+ };
15
+ };
@@ -7,15 +7,11 @@ import {
7
7
  PropSchema,
8
8
  } from "../../schema/index.js";
9
9
  import { defaultProps } from "../defaultProps.js";
10
- import {
11
- createFigureWithCaption,
12
- createFileAndCaptionWrapper,
13
- createFileBlockWrapper,
14
- createLinkWithCaption,
15
- createResizeHandlesWrapper,
16
- parseFigureElement,
17
- } from "../FileBlockContent/fileBlockHelpers.js";
18
- import { parseImageElement } from "./imageBlockHelpers.js";
10
+ import { parseFigureElement } from "../FileBlockContent/helpers/parse/parseFigureElement.js";
11
+ import { createFigureWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.js";
12
+ import { createLinkWithCaption } from "../FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.js";
13
+ import { createResizableFileBlockWrapper } from "../FileBlockContent/helpers/render/createResizableFileBlockWrapper.js";
14
+ import { parseImageElement } from "./parseImageElement.js";
19
15
 
20
16
  export const FILE_IMAGE_ICON_SVG =
21
17
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5 11.1005L7 9.1005L12.5 14.6005L16 11.1005L19 14.1005V5H5V11.1005ZM4 3H20C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3ZM15.5 10C14.6716 10 14 9.32843 14 8.5C14 7.67157 14.6716 7 15.5 7C16.3284 7 17 7.67157 17 8.5C17 9.32843 16.3284 10 15.5 10Z"></path></svg>';
@@ -60,33 +56,29 @@ export const imageRender = (
60
56
  const icon = document.createElement("div");
61
57
  icon.innerHTML = FILE_IMAGE_ICON_SVG;
62
58
 
59
+ const imageWrapper = document.createElement("div");
60
+ imageWrapper.className = "bn-visual-media-wrapper";
61
+
63
62
  const image = document.createElement("img");
64
63
  image.className = "bn-visual-media";
65
- editor.resolveFileUrl(block.props.url).then((downloadUrl) => {
66
- image.src = downloadUrl;
67
- });
64
+ if (editor.resolveFileUrl) {
65
+ editor.resolveFileUrl(block.props.url).then((downloadUrl) => {
66
+ image.src = downloadUrl;
67
+ });
68
+ } else {
69
+ image.src = block.props.url;
70
+ }
71
+
68
72
  image.alt = block.props.name || block.props.caption || "BlockNote image";
69
73
  image.contentEditable = "false";
70
74
  image.draggable = false;
71
- image.width = Math.min(
72
- block.props.previewWidth,
73
- editor.domElement.firstElementChild!.clientWidth
74
- );
75
-
76
- const file = createResizeHandlesWrapper(
77
- block,
78
- editor,
79
- image,
80
- () => image.width,
81
- (width) => (image.width = width)
82
- );
83
-
84
- const element = createFileAndCaptionWrapper(block, file.dom);
75
+ imageWrapper.appendChild(image);
85
76
 
86
- return createFileBlockWrapper(
77
+ return createResizableFileBlockWrapper(
87
78
  block,
88
79
  editor,
89
- element,
80
+ { dom: imageWrapper },
81
+ imageWrapper,
90
82
  editor.dictionary.file_blocks.image.add_button_text,
91
83
  icon.firstElementChild as HTMLElement
92
84
  );
@@ -1,5 +1,5 @@
1
1
  import { callOrReturn, Extension, getExtensionField } from "@tiptap/core";
2
- import { columnResizing, tableEditing } from "prosemirror-tables";
2
+ import { columnResizing, goToNextCell, tableEditing } from "prosemirror-tables";
3
3
 
4
4
  export const RESIZE_MIN_WIDTH = 35;
5
5
  export const EMPTY_CELL_WIDTH = 120;
@@ -53,6 +53,17 @@ export const TableExtension = Extension.create({
53
53
  selectionIsInTableParagraphNode
54
54
  );
55
55
  },
56
+ // Enables navigating cells using the tab key.
57
+ Tab: () => {
58
+ return this.editor.commands.command(({ state, dispatch, view }) =>
59
+ goToNextCell(1)(state, dispatch, view)
60
+ );
61
+ },
62
+ "Shift-Tab": () => {
63
+ return this.editor.commands.command(({ state, dispatch, view }) =>
64
+ goToNextCell(-1)(state, dispatch, view)
65
+ );
66
+ },
56
67
  };
57
68
  },
58
69