@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.
- package/dist/BlockNoteExtension-BWw0r8Gy.cjs +2 -0
- package/dist/BlockNoteExtension-BWw0r8Gy.cjs.map +1 -0
- package/dist/BlockNoteExtension-C2X7LW-V.js +25 -0
- package/dist/BlockNoteExtension-C2X7LW-V.js.map +1 -0
- package/dist/BlockNoteSchema-B4gm-Qco.cjs +2 -0
- package/dist/BlockNoteSchema-B4gm-Qco.cjs.map +1 -0
- package/dist/BlockNoteSchema-C-l154WP.js +270 -0
- package/dist/BlockNoteSchema-C-l154WP.js.map +1 -0
- package/dist/EventEmitter-CLwfmbqG.cjs +2 -0
- package/dist/EventEmitter-CLwfmbqG.cjs.map +1 -0
- package/dist/EventEmitter-CjSwpTbz.js +27 -0
- package/dist/EventEmitter-CjSwpTbz.js.map +1 -0
- package/dist/ShowSelection-BW37oJ6h.cjs +2 -0
- package/dist/ShowSelection-BW37oJ6h.cjs.map +1 -0
- package/dist/ShowSelection-Dz-NEase.js +43 -0
- package/dist/ShowSelection-Dz-NEase.js.map +1 -0
- package/dist/TrailingNode-B_zPMWxw.js +2098 -0
- package/dist/TrailingNode-B_zPMWxw.js.map +1 -0
- package/dist/TrailingNode-CRHrgOnK.cjs +2 -0
- package/dist/TrailingNode-CRHrgOnK.cjs.map +1 -0
- package/dist/{blockToNode-DIfPWLH8.js → blockToNode-DBNbhwwC.js} +33 -33
- package/dist/blockToNode-DBNbhwwC.js.map +1 -0
- package/dist/blockToNode-w7H99R6p.cjs.map +1 -1
- package/dist/blocknote.cjs +4 -4
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +2496 -5686
- package/dist/blocknote.js.map +1 -1
- package/dist/blocks.cjs +1 -1
- package/dist/blocks.js +71 -70
- package/dist/blocks.js.map +1 -1
- package/dist/comments.cjs +1 -1
- package/dist/comments.cjs.map +1 -1
- package/dist/comments.js +451 -137
- package/dist/comments.js.map +1 -1
- package/dist/defaultBlocks-DLJ4Q1_J.cjs +6 -0
- package/dist/defaultBlocks-DLJ4Q1_J.cjs.map +1 -0
- package/dist/{BlockNoteSchema-Bi-eeHal.js → defaultBlocks-DgA_mtQV.js} +974 -1027
- package/dist/defaultBlocks-DgA_mtQV.js.map +1 -0
- package/dist/extensions.cjs +2 -0
- package/dist/extensions.cjs.map +1 -0
- package/dist/extensions.js +57 -0
- package/dist/extensions.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/dist/yjs.js +1 -1
- package/package.json +9 -3
- package/src/api/nodeConversions/blockToNode.ts +1 -1
- package/src/api/nodeConversions/nodeToBlock.ts +1 -1
- package/src/blocks/Code/block.ts +4 -4
- package/src/blocks/Divider/block.ts +2 -2
- package/src/blocks/File/helpers/render/createAddFileButton.ts +7 -5
- package/src/blocks/Heading/block.ts +23 -20
- package/src/blocks/ListItem/BulletListItem/block.ts +2 -2
- package/src/blocks/ListItem/CheckListItem/block.ts +2 -2
- package/src/blocks/ListItem/NumberedListItem/block.ts +3 -3
- package/src/blocks/ListItem/ToggleListItem/block.ts +2 -2
- package/src/blocks/PageBreak/getPageBreakSlashMenuItems.ts +2 -2
- package/src/blocks/Paragraph/block.ts +2 -2
- package/src/blocks/Quote/block.ts +2 -2
- package/src/blocks/Table/block.ts +4 -3
- package/src/blocks/ToggleWrapper/createToggleWrapper.ts +2 -1
- package/src/comments/extension.ts +353 -0
- package/src/comments/index.ts +2 -1
- package/src/comments/types.ts +8 -0
- package/src/{extensions/Comments → comments}/userstore/UserStore.ts +2 -2
- package/src/editor/BlockNoteEditor.test.ts +2 -23
- package/src/editor/BlockNoteEditor.ts +60 -453
- package/src/editor/BlockNoteExtension.test.ts +103 -0
- package/src/editor/BlockNoteExtension.ts +174 -56
- package/src/editor/managers/EventManager.ts +64 -35
- package/src/editor/managers/ExtensionManager/extensions.ts +214 -0
- package/src/editor/managers/ExtensionManager/index.ts +514 -0
- package/src/editor/managers/ExtensionManager/symbol.ts +6 -0
- package/src/editor/managers/SelectionManager.ts +5 -1
- package/src/editor/managers/StateManager.ts +29 -17
- package/src/editor/managers/index.ts +1 -5
- package/src/extensions/BlockChange/{BlockChangePlugin.ts → BlockChange.ts} +27 -29
- package/src/extensions/Collaboration/{ForkYDocPlugin.test.ts → ForkYDoc.test.ts} +6 -5
- package/src/extensions/Collaboration/ForkYDoc.ts +158 -0
- package/src/extensions/Collaboration/YCursorPlugin.ts +183 -0
- package/src/extensions/Collaboration/YSync.ts +16 -0
- package/src/extensions/Collaboration/YUndo.ts +12 -0
- package/src/extensions/Collaboration/schemaMigration/SchemaMigration.ts +59 -0
- package/src/extensions/DropCursor/DropCursor.ts +26 -0
- package/src/extensions/FilePanel/FilePanel.ts +41 -0
- package/src/extensions/FormattingToolbar/FormattingToolbar.ts +119 -0
- package/src/extensions/History/History.ts +11 -0
- package/src/extensions/LinkToolbar/LinkToolbar.ts +121 -0
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.ts +74 -0
- package/src/extensions/Placeholder/Placeholder.ts +148 -0
- package/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.ts → PreviousBlockType.ts} +9 -13
- package/src/extensions/ShowSelection/{ShowSelectionPlugin.ts → ShowSelection.ts} +27 -33
- package/src/extensions/SideMenu/{SideMenuPlugin.ts → SideMenu.ts} +63 -83
- package/src/extensions/SuggestionMenu/{SuggestionPlugin.ts → SuggestionMenu.ts} +71 -77
- package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +29 -44
- package/src/extensions/TableHandles/{TableHandlesPlugin.ts → TableHandles.ts} +416 -437
- package/src/extensions/TrailingNode/{TrailingNodeExtension.ts → TrailingNode.ts} +8 -17
- package/src/extensions/index.ts +24 -0
- package/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.ts +1 -1
- package/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.ts +21 -16
- package/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.ts +1 -1
- package/src/extensions/tiptap-extensions/index.ts +31 -0
- package/src/index.ts +1 -13
- package/src/schema/blocks/createSpec.ts +14 -11
- package/src/schema/blocks/internal.ts +2 -2
- package/src/schema/blocks/types.ts +8 -5
- package/src/schema/schema.ts +11 -36
- package/src/util/topo-sort.ts +46 -0
- package/types/src/comments/extension.d.ts +70 -0
- package/types/src/comments/index.d.ts +2 -1
- package/types/src/comments/types.d.ts +8 -0
- package/types/src/{extensions/Comments → comments}/userstore/UserStore.d.ts +2 -2
- package/types/src/editor/BlockNoteEditor.d.ts +34 -105
- package/types/src/editor/BlockNoteExtension.d.ts +87 -22
- package/types/src/editor/managers/EventManager.d.ts +25 -16
- package/types/src/editor/managers/ExtensionManager/extensions.d.ts +8 -0
- package/types/src/editor/managers/ExtensionManager/index.d.ts +83 -0
- package/types/src/editor/managers/ExtensionManager/symbol.d.ts +5 -0
- package/types/src/editor/managers/StateManager.d.ts +1 -12
- package/types/src/editor/managers/index.d.ts +1 -2
- package/types/src/extensions/BlockChange/BlockChange.d.ts +16 -0
- package/types/src/extensions/Collaboration/ForkYDoc.d.ts +34 -0
- package/types/src/extensions/Collaboration/ForkYDoc.test.d.ts +1 -0
- package/types/src/extensions/Collaboration/YCursorPlugin.d.ts +24 -0
- package/types/src/extensions/Collaboration/YSync.d.ts +8 -0
- package/types/src/extensions/Collaboration/YUndo.d.ts +12 -0
- package/types/src/extensions/Collaboration/schemaMigration/SchemaMigration.d.ts +8 -0
- package/types/src/extensions/DropCursor/DropCursor.d.ts +5 -0
- package/types/src/extensions/FilePanel/FilePanel.d.ts +11 -0
- package/types/src/extensions/FormattingToolbar/FormattingToolbar.d.ts +9 -0
- package/types/src/extensions/History/History.d.ts +6 -0
- package/types/src/extensions/LinkToolbar/LinkToolbar.d.ts +24 -0
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboard.d.ts +5 -0
- package/types/src/extensions/Placeholder/Placeholder.d.ts +6 -0
- package/types/src/extensions/PreviousBlockType/{PreviousBlockTypePlugin.d.ts → PreviousBlockType.d.ts} +9 -5
- package/types/src/extensions/ShowSelection/ShowSelection.d.ts +21 -0
- package/types/src/extensions/SideMenu/{SideMenuPlugin.d.ts → SideMenu.d.ts} +11 -15
- package/types/src/extensions/SuggestionMenu/SuggestionMenu.d.ts +54 -0
- package/types/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.d.ts +1 -1
- package/types/src/extensions/TableHandles/{TableHandlesPlugin.d.ts → TableHandles.d.ts} +28 -31
- package/types/src/extensions/TrailingNode/TrailingNode.d.ts +8 -0
- package/types/src/extensions/index.d.ts +24 -0
- package/types/src/extensions/{KeyboardShortcuts → tiptap-extensions/KeyboardShortcuts}/KeyboardShortcutsExtension.d.ts +1 -1
- package/types/src/extensions/tiptap-extensions/index.d.ts +11 -0
- package/types/src/index.d.ts +1 -13
- package/types/src/schema/blocks/createSpec.d.ts +4 -4
- package/types/src/schema/blocks/internal.d.ts +2 -2
- package/types/src/schema/blocks/types.d.ts +5 -5
- package/types/src/util/topo-sort.d.ts +8 -0
- package/dist/BlockNoteSchema-Bi-eeHal.js.map +0 -1
- package/dist/BlockNoteSchema-DjDaA2C3.cjs +0 -6
- package/dist/BlockNoteSchema-DjDaA2C3.cjs.map +0 -1
- package/dist/blockToNode-DIfPWLH8.js.map +0 -1
- package/src/comments/models/User.ts +0 -8
- package/src/editor/BlockNoteExtensions.ts +0 -325
- package/src/editor/managers/CollaborationManager.ts +0 -212
- package/src/editor/managers/ExtensionManager.ts +0 -130
- package/src/extensions/Collaboration/CursorPlugin.ts +0 -189
- package/src/extensions/Collaboration/ForkYDocPlugin.ts +0 -192
- package/src/extensions/Collaboration/SyncPlugin.ts +0 -18
- package/src/extensions/Collaboration/UndoPlugin.ts +0 -18
- package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +0 -59
- package/src/extensions/Comments/CommentsPlugin.ts +0 -392
- package/src/extensions/FilePanel/FilePanelPlugin.ts +0 -206
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +0 -363
- package/src/extensions/LinkToolbar/LinkToolbarPlugin.ts +0 -380
- package/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts +0 -75
- package/src/extensions/Placeholder/PlaceholderPlugin.ts +0 -147
- package/types/src/comments/models/User.d.ts +0 -8
- package/types/src/editor/BlockNoteExtensions.d.ts +0 -43
- package/types/src/editor/managers/CollaborationManager.d.ts +0 -115
- package/types/src/editor/managers/ExtensionManager.d.ts +0 -68
- package/types/src/extensions/BlockChange/BlockChangePlugin.d.ts +0 -15
- package/types/src/extensions/Collaboration/CursorPlugin.d.ts +0 -37
- package/types/src/extensions/Collaboration/ForkYDocPlugin.d.ts +0 -41
- package/types/src/extensions/Collaboration/SyncPlugin.d.ts +0 -7
- package/types/src/extensions/Collaboration/UndoPlugin.d.ts +0 -9
- package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +0 -7
- package/types/src/extensions/Comments/CommentsPlugin.d.ts +0 -66
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +0 -31
- package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +0 -41
- package/types/src/extensions/LinkToolbar/LinkToolbarPlugin.d.ts +0 -42
- package/types/src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.d.ts +0 -5
- package/types/src/extensions/Placeholder/PlaceholderPlugin.d.ts +0 -6
- package/types/src/extensions/ShowSelection/ShowSelectionPlugin.d.ts +0 -15
- package/types/src/extensions/SuggestionMenu/SuggestionPlugin.d.ts +0 -31
- package/types/src/extensions/TrailingNode/TrailingNodeExtension.d.ts +0 -13
- /package/src/{extensions/Comments/CommentMark.ts → comments/mark.ts} +0 -0
- /package/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.ts +0 -0
- /package/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.ts +0 -0
- /package/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.ts +0 -0
- /package/src/extensions/{UniqueID → tiptap-extensions/UniqueID}/UniqueID.ts +0 -0
- /package/types/src/{extensions/Comments/CommentMark.d.ts → comments/mark.d.ts} +0 -0
- /package/types/src/{extensions/Collaboration/ForkYDocPlugin.test.d.ts → editor/BlockNoteExtension.test.d.ts} +0 -0
- /package/types/src/extensions/{BackgroundColor → tiptap-extensions/BackgroundColor}/BackgroundColorExtension.d.ts +0 -0
- /package/types/src/extensions/{HardBreak → tiptap-extensions/HardBreak}/HardBreak.d.ts +0 -0
- /package/types/src/extensions/{Suggestions → tiptap-extensions/Suggestions}/SuggestionMarks.d.ts +0 -0
- /package/types/src/extensions/{TextAlignment → tiptap-extensions/TextAlignment}/TextAlignmentExtension.d.ts +0 -0
- /package/types/src/extensions/{TextColor → tiptap-extensions/TextColor}/TextColorExtension.d.ts +0 -0
- /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,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 {};
|