@blocknote/core 0.42.3 → 0.44.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 (200) hide show
  1. package/dist/BlockNoteExtension-BWw0r8Gy.cjs +2 -0
  2. package/dist/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -0
  3. package/dist/BlockNoteExtension-C2X7LW-V.js +25 -0
  4. package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -0
  5. package/dist/BlockNoteSchema-B4gm-Qco.cjs +2 -0
  6. package/dist/BlockNoteSchema-B4gm-Qco.cjs.map +1 -0
  7. package/dist/BlockNoteSchema-C-l154WP.js +270 -0
  8. package/dist/BlockNoteSchema-C-l154WP.js.map +1 -0
  9. package/dist/EventEmitter-CLwfmbqG.cjs +2 -0
  10. package/dist/EventEmitter-CLwfmbqG.cjs.map +1 -0
  11. package/dist/EventEmitter-CjSwpTbz.js +27 -0
  12. package/dist/EventEmitter-CjSwpTbz.js.map +1 -0
  13. package/dist/ShowSelection-BW37oJ6h.cjs +2 -0
  14. package/dist/ShowSelection-BW37oJ6h.cjs.map +1 -0
  15. package/dist/ShowSelection-Dz-NEase.js +43 -0
  16. package/dist/ShowSelection-Dz-NEase.js.map +1 -0
  17. package/dist/TrailingNode-B_zPMWxw.js +2098 -0
  18. package/dist/TrailingNode-B_zPMWxw.js.map +1 -0
  19. package/dist/TrailingNode-CRHrgOnK.cjs +2 -0
  20. package/dist/TrailingNode-CRHrgOnK.cjs.map +1 -0
  21. package/dist/{blockToNode-DIfPWLH8.js → blockToNode-DBNbhwwC.js} +33 -33
  22. package/dist/blockToNode-DBNbhwwC.js.map +1 -0
  23. package/dist/blockToNode-w7H99R6p.cjs.map +1 -1
  24. package/dist/blocknote.cjs +4 -4
  25. package/dist/blocknote.cjs.map +1 -1
  26. package/dist/blocknote.js +2496 -5686
  27. package/dist/blocknote.js.map +1 -1
  28. package/dist/blocks.cjs +1 -1
  29. package/dist/blocks.js +71 -70
  30. package/dist/blocks.js.map +1 -1
  31. package/dist/comments.cjs +1 -1
  32. package/dist/comments.cjs.map +1 -1
  33. package/dist/comments.js +451 -137
  34. package/dist/comments.js.map +1 -1
  35. package/dist/defaultBlocks-DLJ4Q1_J.cjs +6 -0
  36. package/dist/defaultBlocks-DLJ4Q1_J.cjs.map +1 -0
  37. package/dist/{BlockNoteSchema-Bi-eeHal.js → defaultBlocks-DgA_mtQV.js} +974 -1027
  38. package/dist/defaultBlocks-DgA_mtQV.js.map +1 -0
  39. package/dist/extensions.cjs +2 -0
  40. package/dist/extensions.cjs.map +1 -0
  41. package/dist/extensions.js +57 -0
  42. package/dist/extensions.js.map +1 -0
  43. package/dist/tsconfig.tsbuildinfo +1 -1
  44. package/dist/webpack-stats.json +1 -1
  45. package/dist/yjs.js +1 -1
  46. package/package.json +9 -3
  47. package/src/api/nodeConversions/blockToNode.ts +1 -1
  48. package/src/api/nodeConversions/nodeToBlock.ts +1 -1
  49. package/src/blocks/Code/block.ts +4 -4
  50. package/src/blocks/Divider/block.ts +2 -2
  51. package/src/blocks/File/helpers/render/createAddFileButton.ts +7 -5
  52. package/src/blocks/Heading/block.ts +23 -20
  53. package/src/blocks/ListItem/BulletListItem/block.ts +2 -2
  54. package/src/blocks/ListItem/CheckListItem/block.ts +2 -2
  55. package/src/blocks/ListItem/NumberedListItem/block.ts +3 -3
  56. package/src/blocks/ListItem/ToggleListItem/block.ts +2 -2
  57. package/src/blocks/PageBreak/getPageBreakSlashMenuItems.ts +2 -2
  58. package/src/blocks/Paragraph/block.ts +2 -2
  59. package/src/blocks/Quote/block.ts +2 -2
  60. package/src/blocks/Table/block.ts +4 -3
  61. package/src/blocks/ToggleWrapper/createToggleWrapper.ts +2 -1
  62. package/src/comments/extension.ts +353 -0
  63. package/src/comments/index.ts +2 -1
  64. package/src/comments/types.ts +8 -0
  65. package/src/{extensions/Comments → comments}/userstore/UserStore.ts +2 -2
  66. package/src/editor/BlockNoteEditor.test.ts +2 -23
  67. package/src/editor/BlockNoteEditor.ts +60 -453
  68. package/src/editor/BlockNoteExtension.test.ts +103 -0
  69. package/src/editor/BlockNoteExtension.ts +174 -56
  70. package/src/editor/managers/EventManager.ts +64 -35
  71. package/src/editor/managers/ExtensionManager/extensions.ts +214 -0
  72. package/src/editor/managers/ExtensionManager/index.ts +514 -0
  73. package/src/editor/managers/ExtensionManager/symbol.ts +6 -0
  74. package/src/editor/managers/SelectionManager.ts +5 -1
  75. package/src/editor/managers/StateManager.ts +29 -17
  76. package/src/editor/managers/index.ts +1 -5
  77. package/src/extensions/BlockChange/{BlockChangePlugin.ts → BlockChange.ts} +27 -29
  78. package/src/extensions/Collaboration/{ForkYDocPlugin.test.ts → ForkYDoc.test.ts} +6 -5
  79. package/src/extensions/Collaboration/ForkYDoc.ts +158 -0
  80. package/src/extensions/Collaboration/YCursorPlugin.ts +183 -0
  81. package/src/extensions/Collaboration/YSync.ts +16 -0
  82. package/src/extensions/Collaboration/YUndo.ts +12 -0
  83. package/src/extensions/Collaboration/schemaMigration/SchemaMigration.ts +59 -0
  84. package/src/extensions/DropCursor/DropCursor.ts +26 -0
  85. package/src/extensions/FilePanel/FilePanel.ts +41 -0
  86. package/src/extensions/FormattingToolbar/FormattingToolbar.ts +119 -0
  87. package/src/extensions/History/History.ts +11 -0
  88. package/src/extensions/LinkToolbar/LinkToolbar.ts +121 -0
  89. package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.ts +74 -0
  90. package/src/extensions/Placeholder/Placeholder.ts +148 -0
  91. package/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.ts → PreviousBlockType.ts} +9 -13
  92. package/src/extensions/ShowSelection/{ShowSelectionPlugin.ts → ShowSelection.ts} +27 -33
  93. package/src/extensions/SideMenu/{SideMenuPlugin.ts → SideMenu.ts} +63 -83
  94. package/src/extensions/SuggestionMenu/{SuggestionPlugin.ts → SuggestionMenu.ts} +71 -77
  95. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +29 -44
  96. package/src/extensions/TableHandles/{TableHandlesPlugin.ts → TableHandles.ts} +416 -437
  97. package/src/extensions/TrailingNode/{TrailingNodeExtension.ts → TrailingNode.ts} +8 -17
  98. package/src/extensions/index.ts +24 -0
  99. package/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.ts +1 -1
  100. package/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.ts +21 -16
  101. package/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.ts +1 -1
  102. package/src/extensions/tiptap-extensions/index.ts +31 -0
  103. package/src/index.ts +1 -13
  104. package/src/schema/blocks/createSpec.ts +14 -11
  105. package/src/schema/blocks/internal.ts +2 -2
  106. package/src/schema/blocks/types.ts +8 -5
  107. package/src/schema/schema.ts +11 -36
  108. package/src/util/topo-sort.ts +46 -0
  109. package/types/src/comments/extension.d.ts +70 -0
  110. package/types/src/comments/index.d.ts +2 -1
  111. package/types/src/comments/types.d.ts +8 -0
  112. package/types/src/{extensions/Comments → comments}/userstore/UserStore.d.ts +2 -2
  113. package/types/src/editor/BlockNoteEditor.d.ts +34 -105
  114. package/types/src/editor/BlockNoteExtension.d.ts +87 -22
  115. package/types/src/editor/managers/EventManager.d.ts +25 -16
  116. package/types/src/editor/managers/ExtensionManager/extensions.d.ts +8 -0
  117. package/types/src/editor/managers/ExtensionManager/index.d.ts +83 -0
  118. package/types/src/editor/managers/ExtensionManager/symbol.d.ts +5 -0
  119. package/types/src/editor/managers/StateManager.d.ts +1 -12
  120. package/types/src/editor/managers/index.d.ts +1 -2
  121. package/types/src/extensions/BlockChange/BlockChange.d.ts +16 -0
  122. package/types/src/extensions/Collaboration/ForkYDoc.d.ts +34 -0
  123. package/types/src/extensions/Collaboration/ForkYDoc.test.d.ts +1 -0
  124. package/types/src/extensions/Collaboration/YCursorPlugin.d.ts +24 -0
  125. package/types/src/extensions/Collaboration/YSync.d.ts +8 -0
  126. package/types/src/extensions/Collaboration/YUndo.d.ts +12 -0
  127. package/types/src/extensions/Collaboration/schemaMigration/SchemaMigration.d.ts +8 -0
  128. package/types/src/extensions/DropCursor/DropCursor.d.ts +5 -0
  129. package/types/src/extensions/FilePanel/FilePanel.d.ts +11 -0
  130. package/types/src/extensions/FormattingToolbar/FormattingToolbar.d.ts +9 -0
  131. package/types/src/extensions/History/History.d.ts +6 -0
  132. package/types/src/extensions/LinkToolbar/LinkToolbar.d.ts +24 -0
  133. package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.d.ts +5 -0
  134. package/types/src/extensions/Placeholder/Placeholder.d.ts +6 -0
  135. package/types/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.d.ts → PreviousBlockType.d.ts} +9 -5
  136. package/types/src/extensions/ShowSelection/ShowSelection.d.ts +21 -0
  137. package/types/src/extensions/SideMenu/{SideMenuPlugin.d.ts → SideMenu.d.ts} +11 -15
  138. package/types/src/extensions/SuggestionMenu/SuggestionMenu.d.ts +54 -0
  139. package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +1 -1
  140. package/types/src/extensions/TableHandles/{TableHandlesPlugin.d.ts → TableHandles.d.ts} +28 -31
  141. package/types/src/extensions/TrailingNode/TrailingNode.d.ts +8 -0
  142. package/types/src/extensions/index.d.ts +24 -0
  143. package/types/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.d.ts +1 -1
  144. package/types/src/extensions/tiptap-extensions/index.d.ts +11 -0
  145. package/types/src/index.d.ts +1 -13
  146. package/types/src/schema/blocks/createSpec.d.ts +4 -4
  147. package/types/src/schema/blocks/internal.d.ts +2 -2
  148. package/types/src/schema/blocks/types.d.ts +5 -5
  149. package/types/src/util/topo-sort.d.ts +8 -0
  150. package/dist/BlockNoteSchema-Bi-eeHal.js.map +0 -1
  151. package/dist/BlockNoteSchema-DjDaA2C3.cjs +0 -6
  152. package/dist/BlockNoteSchema-DjDaA2C3.cjs.map +0 -1
  153. package/dist/blockToNode-DIfPWLH8.js.map +0 -1
  154. package/src/comments/models/User.ts +0 -8
  155. package/src/editor/BlockNoteExtensions.ts +0 -325
  156. package/src/editor/managers/CollaborationManager.ts +0 -212
  157. package/src/editor/managers/ExtensionManager.ts +0 -130
  158. package/src/extensions/Collaboration/CursorPlugin.ts +0 -189
  159. package/src/extensions/Collaboration/ForkYDocPlugin.ts +0 -192
  160. package/src/extensions/Collaboration/SyncPlugin.ts +0 -18
  161. package/src/extensions/Collaboration/UndoPlugin.ts +0 -18
  162. package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +0 -59
  163. package/src/extensions/Comments/CommentsPlugin.ts +0 -392
  164. package/src/extensions/FilePanel/FilePanelPlugin.ts +0 -206
  165. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +0 -363
  166. package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +0 -380
  167. package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +0 -75
  168. package/src/extensions/Placeholder/PlaceholderPlugin.ts +0 -147
  169. package/types/src/comments/models/User.d.ts +0 -8
  170. package/types/src/editor/BlockNoteExtensions.d.ts +0 -43
  171. package/types/src/editor/managers/CollaborationManager.d.ts +0 -115
  172. package/types/src/editor/managers/ExtensionManager.d.ts +0 -68
  173. package/types/src/extensions/BlockChange/BlockChangePlugin.d.ts +0 -15
  174. package/types/src/extensions/Collaboration/CursorPlugin.d.ts +0 -37
  175. package/types/src/extensions/Collaboration/ForkYDocPlugin.d.ts +0 -41
  176. package/types/src/extensions/Collaboration/SyncPlugin.d.ts +0 -7
  177. package/types/src/extensions/Collaboration/UndoPlugin.d.ts +0 -9
  178. package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +0 -7
  179. package/types/src/extensions/Comments/CommentsPlugin.d.ts +0 -66
  180. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +0 -31
  181. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +0 -41
  182. package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +0 -42
  183. package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +0 -5
  184. package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +0 -6
  185. package/types/src/extensions/ShowSelection/ShowSelectionPlugin.d.ts +0 -15
  186. package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +0 -31
  187. package/types/src/extensions/TrailingNode/TrailingNodeExtension.d.ts +0 -13
  188. /package/src/{extensions/Comments/CommentMark.ts → comments/mark.ts} +0 -0
  189. /package/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.ts +0 -0
  190. /package/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.ts +0 -0
  191. /package/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.ts +0 -0
  192. /package/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.ts +0 -0
  193. /package/types/src/{extensions/Comments/CommentMark.d.ts → comments/mark.d.ts} +0 -0
  194. /package/types/src/{extensions/Collaboration/ForkYDocPlugin.test.d.ts → editor/BlockNoteExtension.test.d.ts} +0 -0
  195. /package/types/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.d.ts +0 -0
  196. /package/types/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.d.ts +0 -0
  197. /package/types/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.d.ts +0 -0
  198. /package/types/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.d.ts +0 -0
  199. /package/types/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.d.ts +0 -0
  200. /package/types/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.d.ts +0 -0
@@ -1,380 +0,0 @@
1
- import { getMarkRange, posToDOMRect, Range } from "@tiptap/core";
2
-
3
- import { EditorView } from "@tiptap/pm/view";
4
- import { Mark } from "prosemirror-model";
5
- import { EditorState, Plugin, PluginKey, PluginView } from "prosemirror-state";
6
-
7
- import { getPmSchema } from "../../api/pmUtil.js";
8
- import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
9
- import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
10
- import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
11
- import {
12
- BlockSchema,
13
- InlineContentSchema,
14
- StyleSchema,
15
- } from "../../schema/index.js";
16
-
17
- export type LinkToolbarState = UiElementPosition & {
18
- // The hovered link's URL, and the text it's displayed with in the
19
- // editor.
20
- url: string;
21
- text: string;
22
- };
23
-
24
- class LinkToolbarView implements PluginView {
25
- public state?: LinkToolbarState;
26
- public emitUpdate: () => void;
27
-
28
- menuUpdateTimer: ReturnType<typeof setTimeout> | undefined;
29
- startMenuUpdateTimer: () => void;
30
- stopMenuUpdateTimer: () => void;
31
-
32
- mouseHoveredLinkMark: Mark | undefined;
33
- mouseHoveredLinkMarkRange: Range | undefined;
34
-
35
- keyboardHoveredLinkMark: Mark | undefined;
36
- keyboardHoveredLinkMarkRange: Range | undefined;
37
-
38
- linkMark: Mark | undefined;
39
- linkMarkRange: Range | undefined;
40
-
41
- constructor(
42
- private readonly editor: BlockNoteEditor<any, any, any>,
43
- private readonly pmView: EditorView,
44
- emitUpdate: (state: LinkToolbarState) => void,
45
- ) {
46
- this.emitUpdate = () => {
47
- if (!this.state) {
48
- throw new Error("Attempting to update uninitialized link toolbar");
49
- }
50
-
51
- emitUpdate(this.state);
52
- };
53
-
54
- this.startMenuUpdateTimer = () => {
55
- this.menuUpdateTimer = setTimeout(() => {
56
- this.update(this.pmView, undefined, true);
57
- }, 250);
58
- };
59
-
60
- this.stopMenuUpdateTimer = () => {
61
- if (this.menuUpdateTimer) {
62
- clearTimeout(this.menuUpdateTimer);
63
- this.menuUpdateTimer = undefined;
64
- }
65
-
66
- return false;
67
- };
68
-
69
- this.pmView.dom.addEventListener("mouseover", this.mouseOverHandler);
70
- this.pmView.root.addEventListener(
71
- "click",
72
- this.clickHandler as EventListener,
73
- true,
74
- );
75
-
76
- // Setting capture=true ensures that any parent container of the editor that
77
- // gets scrolled will trigger the scroll event. Scroll events do not bubble
78
- // and so won't propagate to the document by default.
79
- this.pmView.root.addEventListener("scroll", this.scrollHandler, true);
80
- }
81
-
82
- mouseOverHandler = (event: MouseEvent) => {
83
- // Resets the link mark currently hovered by the mouse cursor.
84
- this.mouseHoveredLinkMark = undefined;
85
- this.mouseHoveredLinkMarkRange = undefined;
86
-
87
- this.stopMenuUpdateTimer();
88
-
89
- if (
90
- event.target instanceof HTMLAnchorElement &&
91
- event.target.nodeName === "A"
92
- ) {
93
- // Finds link mark at the hovered element's position to update mouseHoveredLinkMark and
94
- // mouseHoveredLinkMarkRange.
95
- const hoveredLinkElement = event.target;
96
- const posInHoveredLinkMark =
97
- this.pmView.posAtDOM(hoveredLinkElement, 0) + 1;
98
- const resolvedPosInHoveredLinkMark =
99
- this.pmView.state.doc.resolve(posInHoveredLinkMark);
100
- const marksAtPos = resolvedPosInHoveredLinkMark.marks();
101
-
102
- for (const mark of marksAtPos) {
103
- if (
104
- mark.type.name === this.pmView.state.schema.mark("link").type.name
105
- ) {
106
- this.mouseHoveredLinkMark = mark;
107
- this.mouseHoveredLinkMarkRange =
108
- getMarkRange(resolvedPosInHoveredLinkMark, mark.type, mark.attrs) ||
109
- undefined;
110
-
111
- break;
112
- }
113
- }
114
- }
115
-
116
- this.startMenuUpdateTimer();
117
-
118
- return false;
119
- };
120
-
121
- clickHandler = (event: MouseEvent) => {
122
- const editorWrapper = this.pmView.dom.parentElement!;
123
-
124
- if (
125
- // Toolbar is open.
126
- this.linkMark &&
127
- // An element is clicked.
128
- event &&
129
- event.target &&
130
- // The clicked element is not the editor.
131
- !(
132
- editorWrapper === (event.target as Node) ||
133
- editorWrapper.contains(event.target as Node)
134
- )
135
- ) {
136
- if (this.state?.show) {
137
- this.state.show = false;
138
- this.emitUpdate();
139
- }
140
- }
141
- };
142
-
143
- scrollHandler = () => {
144
- if (this.linkMark !== undefined) {
145
- if (this.state?.show) {
146
- this.state.referencePos = posToDOMRect(
147
- this.pmView,
148
- this.linkMarkRange!.from,
149
- this.linkMarkRange!.to,
150
- );
151
- this.emitUpdate();
152
- }
153
- }
154
- };
155
-
156
- editLink(url: string, text: string) {
157
- this.editor.transact((tr) => {
158
- const pmSchema = getPmSchema(tr);
159
- tr.insertText(text, this.linkMarkRange!.from, this.linkMarkRange!.to);
160
- tr.addMark(
161
- this.linkMarkRange!.from,
162
- this.linkMarkRange!.from + text.length,
163
- pmSchema.mark("link", { href: url }),
164
- );
165
- });
166
- this.pmView.focus();
167
-
168
- if (this.state?.show) {
169
- this.state.show = false;
170
- this.emitUpdate();
171
- }
172
- }
173
-
174
- deleteLink() {
175
- this.editor.transact((tr) =>
176
- tr
177
- .removeMark(
178
- this.linkMarkRange!.from,
179
- this.linkMarkRange!.to,
180
- this.linkMark!.type,
181
- )
182
- .setMeta("preventAutolink", true),
183
- );
184
- this.pmView.focus();
185
-
186
- if (this.state?.show) {
187
- this.state.show = false;
188
- this.emitUpdate();
189
- }
190
- }
191
-
192
- update(view: EditorView, oldState?: EditorState, fromMouseOver = false) {
193
- const { state } = view;
194
-
195
- const isSame =
196
- oldState &&
197
- oldState.selection.from === state.selection.from &&
198
- oldState.selection.to === state.selection.to;
199
-
200
- if (isSame || !this.pmView.hasFocus()) {
201
- return;
202
- }
203
-
204
- // Saves the currently hovered link mark before it's updated.
205
- const prevLinkMark = this.linkMark;
206
-
207
- // Resets the currently hovered link mark.
208
- this.linkMark = undefined;
209
- this.linkMarkRange = undefined;
210
-
211
- // Resets the link mark currently hovered by the keyboard cursor.
212
- this.keyboardHoveredLinkMark = undefined;
213
- this.keyboardHoveredLinkMarkRange = undefined;
214
-
215
- // Finds link mark at the editor selection's position to update keyboardHoveredLinkMark and
216
- // keyboardHoveredLinkMarkRange.
217
- if (this.pmView.state.selection.empty) {
218
- const marksAtPos = this.pmView.state.selection.$from.marks();
219
-
220
- for (const mark of marksAtPos) {
221
- if (
222
- mark.type.name === this.pmView.state.schema.mark("link").type.name
223
- ) {
224
- this.keyboardHoveredLinkMark = mark;
225
- this.keyboardHoveredLinkMarkRange =
226
- getMarkRange(
227
- this.pmView.state.selection.$from,
228
- mark.type,
229
- mark.attrs,
230
- ) || undefined;
231
-
232
- break;
233
- }
234
- }
235
- }
236
-
237
- if (this.mouseHoveredLinkMark && fromMouseOver) {
238
- this.linkMark = this.mouseHoveredLinkMark;
239
- this.linkMarkRange = this.mouseHoveredLinkMarkRange;
240
- }
241
-
242
- // Keyboard cursor position takes precedence over mouse hovered link.
243
- if (this.keyboardHoveredLinkMark) {
244
- this.linkMark = this.keyboardHoveredLinkMark;
245
- this.linkMarkRange = this.keyboardHoveredLinkMarkRange;
246
- }
247
-
248
- if (this.linkMark && this.editor.isEditable) {
249
- this.state = {
250
- show: true,
251
- referencePos: posToDOMRect(
252
- this.pmView,
253
- this.linkMarkRange!.from,
254
- this.linkMarkRange!.to,
255
- ),
256
- url: this.linkMark!.attrs.href,
257
- text: this.pmView.state.doc.textBetween(
258
- this.linkMarkRange!.from,
259
- this.linkMarkRange!.to,
260
- ),
261
- };
262
- this.emitUpdate();
263
-
264
- return;
265
- }
266
-
267
- // Hides menu.
268
- if (
269
- this.state?.show &&
270
- prevLinkMark &&
271
- (!this.linkMark || !this.editor.isEditable)
272
- ) {
273
- this.state.show = false;
274
- this.emitUpdate();
275
-
276
- return;
277
- }
278
- }
279
-
280
- closeMenu = () => {
281
- if (this.state?.show) {
282
- this.state.show = false;
283
- this.emitUpdate();
284
- }
285
- };
286
-
287
- destroy() {
288
- this.pmView.dom.removeEventListener("mouseover", this.mouseOverHandler);
289
- this.pmView.root.removeEventListener("scroll", this.scrollHandler, true);
290
- this.pmView.root.removeEventListener(
291
- "click",
292
- this.clickHandler as EventListener,
293
- true,
294
- );
295
- }
296
- }
297
-
298
- export const linkToolbarPluginKey = new PluginKey("LinkToolbarPlugin");
299
-
300
- export class LinkToolbarProsemirrorPlugin<
301
- BSchema extends BlockSchema,
302
- I extends InlineContentSchema,
303
- S extends StyleSchema,
304
- > extends BlockNoteExtension {
305
- public static key() {
306
- return "linkToolbar";
307
- }
308
-
309
- private view: LinkToolbarView | undefined;
310
-
311
- constructor(editor: BlockNoteEditor<BSchema, I, S>) {
312
- super();
313
- this.addProsemirrorPlugin(
314
- new Plugin({
315
- key: linkToolbarPluginKey,
316
- view: (editorView) => {
317
- this.view = new LinkToolbarView(editor, editorView, (state) => {
318
- this.emit("update", state);
319
- });
320
- return this.view;
321
- },
322
- props: {
323
- handleKeyDown: (_view, event: KeyboardEvent) => {
324
- if (event.key === "Escape" && this.shown) {
325
- this.view!.closeMenu();
326
- return true;
327
- }
328
- return false;
329
- },
330
- },
331
- }),
332
- );
333
- }
334
-
335
- public onUpdate(callback: (state: LinkToolbarState) => void) {
336
- return this.on("update", callback);
337
- }
338
-
339
- /**
340
- * Edit the currently hovered link.
341
- */
342
- public editLink = (url: string, text: string) => {
343
- this.view!.editLink(url, text);
344
- };
345
-
346
- /**
347
- * Delete the currently hovered link.
348
- */
349
- public deleteLink = () => {
350
- this.view!.deleteLink();
351
- };
352
-
353
- /**
354
- * When hovering on/off links using the mouse cursor, the link toolbar will
355
- * open & close with a delay.
356
- *
357
- * This function starts the delay timer, and should be used for when the mouse
358
- * cursor enters the link toolbar.
359
- */
360
- public startHideTimer = () => {
361
- this.view!.startMenuUpdateTimer();
362
- };
363
-
364
- /**
365
- * When hovering on/off links using the mouse cursor, the link toolbar will
366
- * open & close with a delay.
367
- *
368
- * This function stops the delay timer, and should be used for when the mouse
369
- * cursor exits the link toolbar.
370
- */
371
- public stopHideTimer = () => {
372
- this.view!.stopMenuUpdateTimer();
373
- };
374
-
375
- public get shown() {
376
- return this.view?.state?.show || false;
377
- }
378
-
379
- public closeMenu = () => this.view!.closeMenu();
380
- }
@@ -1,75 +0,0 @@
1
- import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
2
- import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
3
-
4
- const PLUGIN_KEY = new PluginKey("node-selection-keyboard");
5
- // By default, typing with a node selection active will cause ProseMirror to
6
- // replace the node with one that contains editable content. This plugin blocks
7
- // this behaviour without also blocking things like keyboard shortcuts:
8
- //
9
- // - Lets through key presses that do not include alphanumeric characters. This
10
- // includes things like backspace/delete/home/end/etc.
11
- // - Lets through any key presses that include ctrl/meta keys. These will be
12
- // shortcuts of some kind like ctrl+C/mod+C.
13
- // - Special case for Enter key which creates a new paragraph block below and
14
- // sets the selection to it. This is just to bring the UX closer to Notion
15
- //
16
- // While a more elegant solution would probably process transactions instead of
17
- // keystrokes, this brings us most of the way to Notion's UX without much added
18
- // complexity.
19
- export class NodeSelectionKeyboardPlugin extends BlockNoteExtension {
20
- public static key() {
21
- return "nodeSelectionKeyboard";
22
- }
23
-
24
- constructor() {
25
- super();
26
- this.addProsemirrorPlugin(
27
- new Plugin({
28
- key: PLUGIN_KEY,
29
- props: {
30
- handleKeyDown: (view, event) => {
31
- // Checks for node selection
32
- if ("node" in view.state.selection) {
33
- // Checks if key press uses ctrl/meta modifier
34
- if (event.ctrlKey || event.metaKey) {
35
- return false;
36
- }
37
- // Checks if key press is alphanumeric
38
- if (event.key.length === 1) {
39
- event.preventDefault();
40
-
41
- return true;
42
- }
43
- // Checks if key press is Enter
44
- if (
45
- event.key === "Enter" &&
46
- !event.shiftKey &&
47
- !event.altKey &&
48
- !event.ctrlKey &&
49
- !event.metaKey
50
- ) {
51
- const tr = view.state.tr;
52
- view.dispatch(
53
- tr
54
- .insert(
55
- view.state.tr.selection.$to.after(),
56
- view.state.schema.nodes["paragraph"].createChecked(),
57
- )
58
- .setSelection(
59
- new TextSelection(
60
- tr.doc.resolve(view.state.tr.selection.$to.after() + 1),
61
- ),
62
- ),
63
- );
64
-
65
- return true;
66
- }
67
- }
68
-
69
- return false;
70
- },
71
- },
72
- }),
73
- );
74
- }
75
- }
@@ -1,147 +0,0 @@
1
- import { Plugin, PluginKey } from "prosemirror-state";
2
- import { Decoration, DecorationSet } from "prosemirror-view";
3
- import { v4 } from "uuid";
4
- import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
5
- import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
6
-
7
- const PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);
8
-
9
- export class PlaceholderPlugin extends BlockNoteExtension {
10
- public static key() {
11
- return "placeholder";
12
- }
13
-
14
- constructor(
15
- editor: BlockNoteEditor<any, any, any>,
16
- placeholders: Record<
17
- string | "default" | "emptyDocument",
18
- string | undefined
19
- >,
20
- ) {
21
- super();
22
- this.addProsemirrorPlugin(
23
- new Plugin({
24
- key: PLUGIN_KEY,
25
- view: (view) => {
26
- const uniqueEditorSelector = `placeholder-selector-${v4()}`;
27
- view.dom.classList.add(uniqueEditorSelector);
28
- const styleEl = document.createElement("style");
29
-
30
- const nonce = editor._tiptapEditor.options.injectNonce;
31
- if (nonce) {
32
- styleEl.setAttribute("nonce", nonce);
33
- }
34
-
35
- if (view.root instanceof window.ShadowRoot) {
36
- view.root.append(styleEl);
37
- } else {
38
- view.root.head.appendChild(styleEl);
39
- }
40
-
41
- const styleSheet = styleEl.sheet!;
42
-
43
- const getSelector = (additionalSelectors = "") =>
44
- `.${uniqueEditorSelector} .bn-block-content${additionalSelectors} .bn-inline-content:has(> .ProseMirror-trailingBreak:only-child):before`;
45
-
46
- try {
47
- // FIXME: the names "default" and "emptyDocument" are hardcoded
48
- const {
49
- default: defaultPlaceholder,
50
- emptyDocument: emptyPlaceholder,
51
- ...rest
52
- } = placeholders;
53
-
54
- // add block specific placeholders
55
- for (const [blockType, placeholder] of Object.entries(rest)) {
56
- const blockTypeSelector = `[data-content-type="${blockType}"]`;
57
-
58
- styleSheet.insertRule(
59
- `${getSelector(blockTypeSelector)} { content: ${JSON.stringify(
60
- placeholder,
61
- )}; }`,
62
- );
63
- }
64
-
65
- const onlyBlockSelector = `[data-is-only-empty-block]`;
66
- const mustBeFocusedSelector = `[data-is-empty-and-focused]`;
67
-
68
- // placeholder for when there's only one empty block
69
- styleSheet.insertRule(
70
- `${getSelector(onlyBlockSelector)} { content: ${JSON.stringify(
71
- emptyPlaceholder,
72
- )}; }`,
73
- );
74
-
75
- // placeholder for default blocks, only when the cursor is in the block (mustBeFocused)
76
- styleSheet.insertRule(
77
- `${getSelector(mustBeFocusedSelector)} { content: ${JSON.stringify(
78
- defaultPlaceholder,
79
- )}; }`,
80
- );
81
- } catch (e) {
82
- // eslint-disable-next-line no-console
83
- console.warn(
84
- `Failed to insert placeholder CSS rule - this is likely due to the browser not supporting certain CSS pseudo-element selectors (:has, :only-child:, or :before)`,
85
- e,
86
- );
87
- }
88
-
89
- return {
90
- destroy: () => {
91
- if (view.root instanceof window.ShadowRoot) {
92
- view.root.removeChild(styleEl);
93
- } else {
94
- view.root.head.removeChild(styleEl);
95
- }
96
- },
97
- };
98
- },
99
- props: {
100
- decorations: (state) => {
101
- const { doc, selection } = state;
102
-
103
- if (!editor.isEditable) {
104
- return;
105
- }
106
-
107
- if (!selection.empty) {
108
- return;
109
- }
110
-
111
- // Don't show placeholder when the cursor is inside a code block
112
- if (selection.$from.parent.type.spec.code) {
113
- return;
114
- }
115
-
116
- const decs = [];
117
-
118
- // decoration for when there's only one empty block
119
- // positions are hardcoded for now
120
- if (state.doc.content.size === 6) {
121
- decs.push(
122
- Decoration.node(2, 4, {
123
- "data-is-only-empty-block": "true",
124
- }),
125
- );
126
- }
127
-
128
- const $pos = selection.$anchor;
129
- const node = $pos.parent;
130
-
131
- if (node.content.size === 0) {
132
- const before = $pos.before();
133
-
134
- decs.push(
135
- Decoration.node(before, before + node.nodeSize, {
136
- "data-is-empty-and-focused": "true",
137
- }),
138
- );
139
- }
140
-
141
- return DecorationSet.create(doc, decs);
142
- },
143
- },
144
- }),
145
- );
146
- }
147
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * A collaborator of the document.
3
- */
4
- export type User = {
5
- id: string;
6
- username: string;
7
- avatarUrl: string;
8
- };
@@ -1,43 +0,0 @@
1
- import { Plugin } from "prosemirror-state";
2
- import * as Y from "yjs";
3
- import type { ThreadStore, User } from "../comments/index.js";
4
- import { BlockNoteDOMAttributes, BlockSchema, BlockSpecs, InlineContentSchema, InlineContentSpecs, StyleSchema, StyleSpecs } from "../schema/index.js";
5
- import type { BlockNoteEditor, BlockNoteEditorOptions, SupportedExtension } from "./BlockNoteEditor.js";
6
- import { BlockNoteSchema } from "../blocks/BlockNoteSchema.js";
7
- type ExtensionOptions<BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema> = {
8
- editor: BlockNoteEditor<BSchema, I, S>;
9
- domAttributes: Partial<BlockNoteDOMAttributes>;
10
- blockSpecs: BlockSpecs;
11
- inlineContentSpecs: InlineContentSpecs;
12
- styleSpecs: StyleSpecs;
13
- trailingBlock: boolean | undefined;
14
- collaboration?: {
15
- fragment: Y.XmlFragment;
16
- user: {
17
- name: string;
18
- color: string;
19
- [key: string]: string;
20
- };
21
- provider: any;
22
- renderCursor?: (user: any) => HTMLElement;
23
- showCursorLabels?: "always" | "activity";
24
- };
25
- disableExtensions: string[] | undefined;
26
- setIdAttribute?: boolean;
27
- animations: boolean;
28
- tableHandles: boolean;
29
- dropCursor: (opts: any) => Plugin;
30
- placeholders: Record<string | "default" | "emptyDocument", string | undefined>;
31
- tabBehavior?: "prefer-navigate-ui" | "prefer-indent";
32
- comments?: {
33
- schema?: BlockNoteSchema<any, any, any>;
34
- threadStore: ThreadStore;
35
- resolveUsers?: (userIds: string[]) => Promise<User[]>;
36
- };
37
- pasteHandler: BlockNoteEditorOptions<any, any, any>["pasteHandler"];
38
- };
39
- /**
40
- * Get all the Tiptap extensions BlockNote is configured with by default
41
- */
42
- export declare const getBlockNoteExtensions: <BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema>(opts: ExtensionOptions<BSchema, I, S>) => Record<string, SupportedExtension>;
43
- export {};