@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,7 +1,9 @@
1
1
  import { EditorState, Plugin, PluginKey, PluginView } from "prosemirror-state";
2
2
  import { EditorView } from "prosemirror-view";
3
3
 
4
+ import { ySyncPluginKey } from "y-prosemirror";
4
5
  import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
6
+ import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
5
7
  import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
6
8
  import type {
7
9
  BlockFromConfig,
@@ -9,12 +11,10 @@ import type {
9
11
  InlineContentSchema,
10
12
  StyleSchema,
11
13
  } from "../../schema/index.js";
12
- import { EventEmitter } from "../../util/EventEmitter.js";
13
- import { ySyncPluginKey } from "y-prosemirror";
14
14
 
15
15
  export type FilePanelState<
16
16
  I extends InlineContentSchema,
17
- S extends StyleSchema
17
+ S extends StyleSchema,
18
18
  > = UiElementPosition & {
19
19
  // TODO: This typing is not quite right (children should be from BSchema)
20
20
  block: BlockFromConfig<FileBlockConfig, I, S>;
@@ -34,7 +34,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
34
34
  >,
35
35
  private readonly pluginKey: PluginKey<FilePanelState<I, S>>,
36
36
  private readonly pmView: EditorView,
37
- emitUpdate: (state: FilePanelState<I, S>) => void
37
+ emitUpdate: (state: FilePanelState<I, S>) => void,
38
38
  ) {
39
39
  this.emitUpdate = () => {
40
40
  if (!this.state) {
@@ -71,7 +71,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
71
71
  scrollHandler = () => {
72
72
  if (this.state?.show) {
73
73
  const blockElement = this.pmView.root.querySelector(
74
- `[data-node-type="blockContainer"][data-id="${this.state.block.id}"]`
74
+ `[data-node-type="blockContainer"][data-id="${this.state.block.id}"]`,
75
75
  );
76
76
  if (!blockElement) {
77
77
  return;
@@ -87,7 +87,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
87
87
 
88
88
  if (!this.state?.show && pluginState?.block && this.editor.isEditable) {
89
89
  const blockElement = this.pmView.root.querySelector(
90
- `[data-node-type="blockContainer"][data-id="${pluginState.block.id}"]`
90
+ `[data-node-type="blockContainer"][data-id="${pluginState.block.id}"]`,
91
91
  );
92
92
  if (!blockElement) {
93
93
  return;
@@ -132,66 +132,67 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
132
132
  }
133
133
 
134
134
  const filePanelPluginKey = new PluginKey<FilePanelState<any, any>>(
135
- "FilePanelPlugin"
135
+ "FilePanelPlugin",
136
136
  );
137
137
 
138
138
  export class FilePanelProsemirrorPlugin<
139
139
  I extends InlineContentSchema,
140
- S extends StyleSchema
141
- > extends EventEmitter<any> {
140
+ S extends StyleSchema,
141
+ > extends BlockNoteExtension {
142
142
  private view: FilePanelView<I, S> | undefined;
143
- public readonly plugin: Plugin;
144
143
 
145
144
  constructor(editor: BlockNoteEditor<Record<string, FileBlockConfig>, I, S>) {
146
145
  super();
147
- this.plugin = new Plugin<{
148
- block: BlockFromConfig<FileBlockConfig, I, S> | undefined;
149
- }>({
150
- key: filePanelPluginKey,
151
- view: (editorView) => {
152
- this.view = new FilePanelView<I, S>(
153
- editor,
154
- filePanelPluginKey,
155
- editorView,
156
- (state) => {
157
- this.emit("update", state);
158
- }
159
- );
160
- return this.view;
161
- },
162
- props: {
163
- handleKeyDown: (_view, event: KeyboardEvent) => {
164
- if (event.key === "Escape" && this.shown) {
165
- this.view?.closeMenu();
166
- return true;
167
- }
168
- return false;
146
+ this.addProsemirrorPlugin(
147
+ new Plugin<{
148
+ block: BlockFromConfig<FileBlockConfig, I, S> | undefined;
149
+ }>({
150
+ key: filePanelPluginKey,
151
+ view: (editorView) => {
152
+ this.view = new FilePanelView<I, S>(
153
+ editor,
154
+ filePanelPluginKey,
155
+ editorView,
156
+ (state) => {
157
+ this.emit("update", state);
158
+ },
159
+ );
160
+ return this.view;
169
161
  },
170
- },
171
- state: {
172
- init: () => {
173
- return {
174
- block: undefined,
175
- };
162
+ props: {
163
+ handleKeyDown: (_view, event: KeyboardEvent) => {
164
+ if (event.key === "Escape" && this.shown) {
165
+ this.view?.closeMenu();
166
+ return true;
167
+ }
168
+ return false;
169
+ },
176
170
  },
177
- apply: (transaction, prev) => {
178
- const state: FilePanelState<I, S> | undefined =
179
- transaction.getMeta(filePanelPluginKey);
180
-
181
- if (state) {
182
- return state;
183
- }
184
-
185
- if (
186
- !transaction.getMeta(ySyncPluginKey) &&
187
- (transaction.selectionSet || transaction.docChanged)
188
- ) {
189
- return { block: undefined };
190
- }
191
- return prev;
171
+ state: {
172
+ init: () => {
173
+ return {
174
+ block: undefined,
175
+ };
176
+ },
177
+ apply: (transaction, prev) => {
178
+ const state: FilePanelState<I, S> | undefined =
179
+ transaction.getMeta(filePanelPluginKey);
180
+
181
+ if (state) {
182
+ return state;
183
+ }
184
+
185
+ if (
186
+ !transaction.getMeta(ySyncPluginKey) &&
187
+ (transaction.selectionSet || transaction.docChanged)
188
+ ) {
189
+ return { block: undefined };
190
+ }
191
+ return prev;
192
+ },
192
193
  },
193
- },
194
- });
194
+ }),
195
+ );
195
196
  }
196
197
 
197
198
  public get shown() {
@@ -3,13 +3,13 @@ import { EditorState, Plugin, PluginKey, PluginView } from "prosemirror-state";
3
3
  import { EditorView } from "prosemirror-view";
4
4
 
5
5
  import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
6
+ import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
6
7
  import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
7
8
  import {
8
9
  BlockSchema,
9
10
  InlineContentSchema,
10
11
  StyleSchema,
11
12
  } from "../../schema/index.js";
12
- import { EventEmitter } from "../../util/EventEmitter.js";
13
13
 
14
14
  export type FormattingToolbarState = UiElementPosition;
15
15
 
@@ -25,7 +25,7 @@ export class FormattingToolbarView implements PluginView {
25
25
  state: EditorState;
26
26
  from: number;
27
27
  to: number;
28
- }) => boolean = ({ state, from, to }) => {
28
+ }) => boolean = ({ view, state, from, to }) => {
29
29
  const { doc, selection } = state;
30
30
  const { empty } = selection;
31
31
 
@@ -43,7 +43,16 @@ export class FormattingToolbarView implements PluginView {
43
43
  return false;
44
44
  }
45
45
 
46
- return !(empty || isEmptyTextBlock);
46
+ if (empty || isEmptyTextBlock) {
47
+ return false;
48
+ }
49
+
50
+ const focusedElement = document.activeElement;
51
+ if (!this.isElementWithinEditorWrapper(focusedElement) && view.editable) {
52
+ // editable editors must have focus for the toolbar to show
53
+ return false;
54
+ }
55
+ return true;
47
56
  };
48
57
 
49
58
  constructor(
@@ -53,12 +62,12 @@ export class FormattingToolbarView implements PluginView {
53
62
  StyleSchema
54
63
  >,
55
64
  private readonly pmView: EditorView,
56
- emitUpdate: (state: FormattingToolbarState) => void
65
+ emitUpdate: (state: FormattingToolbarState) => void,
57
66
  ) {
58
67
  this.emitUpdate = () => {
59
68
  if (!this.state) {
60
69
  throw new Error(
61
- "Attempting to update uninitialized formatting toolbar"
70
+ "Attempting to update uninitialized formatting toolbar",
62
71
  );
63
72
  }
64
73
 
@@ -96,7 +105,7 @@ export class FormattingToolbarView implements PluginView {
96
105
  (editorWrapper === (event.relatedTarget as Node) ||
97
106
  editorWrapper.contains(event.relatedTarget as Node) ||
98
107
  (event.relatedTarget as HTMLElement).matches(
99
- ".bn-ui-container, .bn-ui-container *"
108
+ ".bn-ui-container, .bn-ui-container *",
100
109
  ))
101
110
  ) {
102
111
  return;
@@ -108,8 +117,22 @@ export class FormattingToolbarView implements PluginView {
108
117
  }
109
118
  };
110
119
 
111
- viewMousedownHandler = () => {
112
- this.preventShow = true;
120
+ isElementWithinEditorWrapper = (element: Node | null) => {
121
+ if (!element) {
122
+ return false;
123
+ }
124
+ const editorWrapper = this.pmView.dom.parentElement;
125
+ if (!editorWrapper) {
126
+ return false;
127
+ }
128
+
129
+ return editorWrapper.contains(element);
130
+ };
131
+
132
+ viewMousedownHandler = (e: MouseEvent) => {
133
+ if (!this.isElementWithinEditorWrapper(e.target as Node)) {
134
+ this.preventShow = true;
135
+ }
113
136
  };
114
137
 
115
138
  mouseupHandler = () => {
@@ -172,12 +195,18 @@ export class FormattingToolbarView implements PluginView {
172
195
  // e.g. the download file button, should still be accessible. Therefore,
173
196
  // logic for hiding when the editor is non-editable is handled
174
197
  // individually in each button.
175
- this.state = {
198
+ const nextState = {
176
199
  show: true,
177
200
  referencePos: this.getSelectionBoundingBox(),
178
201
  };
179
202
 
180
- this.emitUpdate();
203
+ if (
204
+ nextState.show !== this.state?.show ||
205
+ nextState.referencePos.toJSON() !== this.state?.referencePos.toJSON()
206
+ ) {
207
+ this.state = nextState;
208
+ this.emitUpdate();
209
+ }
181
210
 
182
211
  return;
183
212
  }
@@ -233,33 +262,34 @@ export class FormattingToolbarView implements PluginView {
233
262
  }
234
263
 
235
264
  export const formattingToolbarPluginKey = new PluginKey(
236
- "FormattingToolbarPlugin"
265
+ "FormattingToolbarPlugin",
237
266
  );
238
267
 
239
- export class FormattingToolbarProsemirrorPlugin extends EventEmitter<any> {
268
+ export class FormattingToolbarProsemirrorPlugin extends BlockNoteExtension {
240
269
  private view: FormattingToolbarView | undefined;
241
- public readonly plugin: Plugin;
242
270
 
243
271
  constructor(editor: BlockNoteEditor<any, any, any>) {
244
272
  super();
245
- this.plugin = new Plugin({
246
- key: formattingToolbarPluginKey,
247
- view: (editorView) => {
248
- this.view = new FormattingToolbarView(editor, editorView, (state) => {
249
- this.emit("update", state);
250
- });
251
- return this.view;
252
- },
253
- props: {
254
- handleKeyDown: (_view, event: KeyboardEvent) => {
255
- if (event.key === "Escape" && this.shown) {
256
- this.view!.closeMenu();
257
- return true;
258
- }
259
- return false;
273
+ this.addProsemirrorPlugin(
274
+ new Plugin({
275
+ key: formattingToolbarPluginKey,
276
+ view: (editorView) => {
277
+ this.view = new FormattingToolbarView(editor, editorView, (state) => {
278
+ this.emit("update", state);
279
+ });
280
+ return this.view;
260
281
  },
261
- },
262
- });
282
+ props: {
283
+ handleKeyDown: (_view, event: KeyboardEvent) => {
284
+ if (event.key === "Escape" && this.shown) {
285
+ this.view!.closeMenu();
286
+ return true;
287
+ }
288
+ return false;
289
+ },
290
+ },
291
+ }),
292
+ );
263
293
  }
264
294
 
265
295
  public get shown() {
@@ -48,7 +48,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
48
48
  updateBlockCommand(blockInfo.bnBlock.beforePos, {
49
49
  type: "paragraph",
50
50
  props: {},
51
- })
51
+ }),
52
52
  );
53
53
  }
54
54
 
@@ -114,7 +114,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
114
114
 
115
115
  const prevBlockInfo = getPrevBlockInfo(
116
116
  state.doc,
117
- blockInfo.bnBlock.beforePos
117
+ blockInfo.bnBlock.beforePos,
118
118
  );
119
119
 
120
120
  if (prevBlockInfo) {
@@ -124,7 +124,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
124
124
 
125
125
  const parentBlockInfo = getParentBlockInfo(
126
126
  state.doc,
127
- blockInfo.bnBlock.beforePos
127
+ blockInfo.bnBlock.beforePos,
128
128
  );
129
129
 
130
130
  if (parentBlockInfo?.blockNoteType !== "column") {
@@ -135,7 +135,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
135
135
 
136
136
  const columnList = getParentBlockInfo(
137
137
  state.doc,
138
- column.bnBlock.beforePos
138
+ column.bnBlock.beforePos,
139
139
  );
140
140
  if (columnList?.blockNoteType !== "columnList") {
141
141
  throw new Error("parent of column is not a column list");
@@ -156,7 +156,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
156
156
  const blockToMove = state.doc.slice(
157
157
  blockInfo.bnBlock.beforePos,
158
158
  blockInfo.bnBlock.afterPos,
159
- false
159
+ false,
160
160
  );
161
161
 
162
162
  /*
@@ -180,8 +180,8 @@ export const KeyboardShortcutsExtension = Extension.create<{
180
180
  columnList.bnBlock.afterPos - 2,
181
181
  blockToMove,
182
182
  blockToMove.size, // append existing content to blockToMove
183
- false
184
- )
183
+ false,
184
+ ),
185
185
  );
186
186
  const pos = state.tr.doc.resolve(column.bnBlock.beforePos);
187
187
  state.tr.setSelection(TextSelection.between(pos, pos));
@@ -197,11 +197,11 @@ export const KeyboardShortcutsExtension = Extension.create<{
197
197
  column.bnBlock.beforePos - 1,
198
198
  blockToMove,
199
199
  0, // prepend existing content to blockToMove
200
- false
201
- )
200
+ false,
201
+ ),
202
202
  );
203
203
  const pos = state.tr.doc.resolve(
204
- state.tr.mapping.map(column.bnBlock.beforePos - 1)
204
+ state.tr.mapping.map(column.bnBlock.beforePos - 1),
205
205
  );
206
206
  state.tr.setSelection(TextSelection.between(pos, pos));
207
207
  }
@@ -210,43 +210,43 @@ export const KeyboardShortcutsExtension = Extension.create<{
210
210
  // delete column
211
211
  state.tr.delete(
212
212
  column.bnBlock.beforePos,
213
- column.bnBlock.afterPos
213
+ column.bnBlock.afterPos,
214
214
  );
215
215
 
216
216
  // move before columnlist
217
217
  state.tr.insert(
218
218
  columnList.bnBlock.beforePos,
219
- blockToMove.content
219
+ blockToMove.content,
220
220
  );
221
221
 
222
222
  const pos = state.tr.doc.resolve(
223
- columnList.bnBlock.beforePos
223
+ columnList.bnBlock.beforePos,
224
224
  );
225
225
  state.tr.setSelection(TextSelection.between(pos, pos));
226
226
  } else {
227
227
  // just delete the </column><column> closing and opening tags to merge the columns
228
228
  state.tr.delete(
229
229
  column.bnBlock.beforePos - 1,
230
- column.bnBlock.beforePos + 1
230
+ column.bnBlock.beforePos + 1,
231
231
  );
232
232
  }
233
233
  } else {
234
234
  // delete block
235
235
  state.tr.delete(
236
236
  blockInfo.bnBlock.beforePos,
237
- blockInfo.bnBlock.afterPos
237
+ blockInfo.bnBlock.afterPos,
238
238
  );
239
239
  if (isFirstColumn) {
240
240
  // move before columnlist
241
241
  state.tr.insert(
242
242
  columnList.bnBlock.beforePos - 1,
243
- blockToMove.content
243
+ blockToMove.content,
244
244
  );
245
245
  } else {
246
246
  // append block to previous column
247
247
  state.tr.insert(
248
248
  column.bnBlock.beforePos - 1,
249
- blockToMove.content
249
+ blockToMove.content,
250
250
  );
251
251
  }
252
252
  const pos = state.tr.doc.resolve(column.bnBlock.beforePos - 1);
@@ -272,7 +272,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
272
272
  if (blockEmpty) {
273
273
  const prevBlockInfo = getPrevBlockInfo(
274
274
  state.doc,
275
- blockInfo.bnBlock.beforePos
275
+ blockInfo.bnBlock.beforePos,
276
276
  );
277
277
  if (!prevBlockInfo || !prevBlockInfo.isBlockContainer) {
278
278
  return false;
@@ -291,7 +291,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
291
291
  const lastCellParagraphEndPos = lastCellEndPos - 1;
292
292
 
293
293
  chainedCommands = chainedCommands.setTextSelection(
294
- lastCellParagraphEndPos
294
+ lastCellParagraphEndPos,
295
295
  );
296
296
  } else if (
297
297
  prevBlockInfo.blockContent.node.type.spec.content === ""
@@ -301,7 +301,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
301
301
  prevBlockInfo.blockContent.node.nodeSize;
302
302
 
303
303
  chainedCommands = chainedCommands.setNodeSelection(
304
- nonEditableBlockContentStartPos
304
+ nonEditableBlockContentStartPos,
305
305
  );
306
306
  } else {
307
307
  const blockContentStartPos =
@@ -341,13 +341,13 @@ export const KeyboardShortcutsExtension = Extension.create<{
341
341
 
342
342
  const prevBlockInfo = getPrevBlockInfo(
343
343
  state.doc,
344
- blockInfo.bnBlock.beforePos
344
+ blockInfo.bnBlock.beforePos,
345
345
  );
346
346
 
347
347
  if (prevBlockInfo && selectionAtBlockStart && selectionEmpty) {
348
348
  const bottomBlock = getBottomNestedBlockInfo(
349
349
  state.doc,
350
- prevBlockInfo
350
+ prevBlockInfo,
351
351
  );
352
352
 
353
353
  if (!bottomBlock.isBlockContainer) {
@@ -368,7 +368,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
368
368
  from: blockInfo.bnBlock.beforePos,
369
369
  to: blockInfo.bnBlock.afterPos,
370
370
  },
371
- bottomBlock.bnBlock.afterPos
371
+ bottomBlock.bnBlock.afterPos,
372
372
  )
373
373
  .deleteRange({
374
374
  from: bottomBlock.bnBlock.beforePos,
@@ -521,7 +521,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
521
521
  .insert(newBlockInsertionPos, newBlock)
522
522
  .scrollIntoView();
523
523
  state.tr.setSelection(
524
- new TextSelection(state.doc.resolve(newBlockContentPos))
524
+ new TextSelection(state.doc.resolve(newBlockContentPos)),
525
525
  );
526
526
  }
527
527
 
@@ -551,8 +551,8 @@ export const KeyboardShortcutsExtension = Extension.create<{
551
551
  splitBlockCommand(
552
552
  state.selection.from,
553
553
  selectionAtBlockStart,
554
- selectionAtBlockStart
555
- )
554
+ selectionAtBlockStart,
555
+ ),
556
556
  )
557
557
  .run();
558
558
 
@@ -4,15 +4,15 @@ import { EditorView } from "@tiptap/pm/view";
4
4
  import { Mark } from "prosemirror-model";
5
5
  import { EditorState, Plugin, PluginKey, PluginView } from "prosemirror-state";
6
6
 
7
+ import { getPmSchema } from "../../api/pmUtil.js";
7
8
  import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
9
+ import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
8
10
  import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
9
11
  import {
10
12
  BlockSchema,
11
13
  InlineContentSchema,
12
14
  StyleSchema,
13
15
  } from "../../schema/index.js";
14
- import { EventEmitter } from "../../util/EventEmitter.js";
15
- import { getPmSchema } from "../../api/pmUtil.js";
16
16
 
17
17
  export type LinkToolbarState = UiElementPosition & {
18
18
  // The hovered link's URL, and the text it's displayed with in the
@@ -41,7 +41,7 @@ class LinkToolbarView implements PluginView {
41
41
  constructor(
42
42
  private readonly editor: BlockNoteEditor<any, any, any>,
43
43
  private readonly pmView: EditorView,
44
- emitUpdate: (state: LinkToolbarState) => void
44
+ emitUpdate: (state: LinkToolbarState) => void,
45
45
  ) {
46
46
  this.emitUpdate = () => {
47
47
  if (!this.state) {
@@ -70,7 +70,7 @@ class LinkToolbarView implements PluginView {
70
70
  this.pmView.root.addEventListener(
71
71
  "click",
72
72
  this.clickHandler as EventListener,
73
- true
73
+ true,
74
74
  );
75
75
 
76
76
  // Setting capture=true ensures that any parent container of the editor that
@@ -146,7 +146,7 @@ class LinkToolbarView implements PluginView {
146
146
  this.state.referencePos = posToDOMRect(
147
147
  this.pmView,
148
148
  this.linkMarkRange!.from,
149
- this.linkMarkRange!.to
149
+ this.linkMarkRange!.to,
150
150
  );
151
151
  this.emitUpdate();
152
152
  }
@@ -160,7 +160,7 @@ class LinkToolbarView implements PluginView {
160
160
  tr.addMark(
161
161
  this.linkMarkRange!.from,
162
162
  this.linkMarkRange!.from + text.length,
163
- pmSchema.mark("link", { href: url })
163
+ pmSchema.mark("link", { href: url }),
164
164
  );
165
165
  });
166
166
  this.pmView.focus();
@@ -177,9 +177,9 @@ class LinkToolbarView implements PluginView {
177
177
  .removeMark(
178
178
  this.linkMarkRange!.from,
179
179
  this.linkMarkRange!.to,
180
- this.linkMark!.type
180
+ this.linkMark!.type,
181
181
  )
182
- .setMeta("preventAutolink", true)
182
+ .setMeta("preventAutolink", true),
183
183
  );
184
184
  this.pmView.focus();
185
185
 
@@ -226,7 +226,7 @@ class LinkToolbarView implements PluginView {
226
226
  getMarkRange(
227
227
  this.pmView.state.selection.$from,
228
228
  mark.type,
229
- mark.attrs
229
+ mark.attrs,
230
230
  ) || undefined;
231
231
 
232
232
  break;
@@ -251,12 +251,12 @@ class LinkToolbarView implements PluginView {
251
251
  referencePos: posToDOMRect(
252
252
  this.pmView,
253
253
  this.linkMarkRange!.from,
254
- this.linkMarkRange!.to
254
+ this.linkMarkRange!.to,
255
255
  ),
256
256
  url: this.linkMark!.attrs.href,
257
257
  text: this.pmView.state.doc.textBetween(
258
258
  this.linkMarkRange!.from,
259
- this.linkMarkRange!.to
259
+ this.linkMarkRange!.to,
260
260
  ),
261
261
  };
262
262
  this.emitUpdate();
@@ -290,7 +290,7 @@ class LinkToolbarView implements PluginView {
290
290
  this.pmView.root.removeEventListener(
291
291
  "click",
292
292
  this.clickHandler as EventListener,
293
- true
293
+ true,
294
294
  );
295
295
  }
296
296
  }
@@ -300,31 +300,32 @@ export const linkToolbarPluginKey = new PluginKey("LinkToolbarPlugin");
300
300
  export class LinkToolbarProsemirrorPlugin<
301
301
  BSchema extends BlockSchema,
302
302
  I extends InlineContentSchema,
303
- S extends StyleSchema
304
- > extends EventEmitter<any> {
303
+ S extends StyleSchema,
304
+ > extends BlockNoteExtension {
305
305
  private view: LinkToolbarView | undefined;
306
- public readonly plugin: Plugin;
307
306
 
308
307
  constructor(editor: BlockNoteEditor<BSchema, I, S>) {
309
308
  super();
310
- this.plugin = new Plugin({
311
- key: linkToolbarPluginKey,
312
- view: (editorView) => {
313
- this.view = new LinkToolbarView(editor, editorView, (state) => {
314
- this.emit("update", state);
315
- });
316
- return this.view;
317
- },
318
- props: {
319
- handleKeyDown: (_view, event: KeyboardEvent) => {
320
- if (event.key === "Escape" && this.shown) {
321
- this.view!.closeMenu();
322
- return true;
323
- }
324
- return false;
309
+ this.addProsemirrorPlugin(
310
+ new Plugin({
311
+ key: linkToolbarPluginKey,
312
+ view: (editorView) => {
313
+ this.view = new LinkToolbarView(editor, editorView, (state) => {
314
+ this.emit("update", state);
315
+ });
316
+ return this.view;
325
317
  },
326
- },
327
- });
318
+ props: {
319
+ handleKeyDown: (_view, event: KeyboardEvent) => {
320
+ if (event.key === "Escape" && this.shown) {
321
+ this.view!.closeMenu();
322
+ return true;
323
+ }
324
+ return false;
325
+ },
326
+ },
327
+ }),
328
+ );
328
329
  }
329
330
 
330
331
  public onUpdate(callback: (state: LinkToolbarState) => void) {