@blocknote/core 0.42.2 → 0.43.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-CbSavEwr.js +270 -0
- package/dist/BlockNoteSchema-CbSavEwr.js.map +1 -0
- package/dist/BlockNoteSchema-D8TyvlfU.cjs +2 -0
- package/dist/BlockNoteSchema-D8TyvlfU.cjs.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-BUhuMJrB.js +2096 -0
- package/dist/TrailingNode-BUhuMJrB.js.map +1 -0
- package/dist/TrailingNode-CaT_wbho.cjs +2 -0
- package/dist/TrailingNode-CaT_wbho.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 +2401 -5592
- 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/{BlockNoteSchema-Bi-eeHal.js → defaultBlocks-BJtxTOM2.js} +991 -1047
- package/dist/defaultBlocks-BJtxTOM2.js.map +1 -0
- package/dist/defaultBlocks-BxFclIGP.cjs +6 -0
- package/dist/defaultBlocks-BxFclIGP.cjs.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 +12 -6
- 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 +66 -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,189 +0,0 @@
|
|
|
1
|
-
import { defaultSelectionBuilder, yCursorPlugin } from "y-prosemirror";
|
|
2
|
-
import { Awareness } from "y-protocols/awareness.js";
|
|
3
|
-
import * as Y from "yjs";
|
|
4
|
-
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
|
|
5
|
-
|
|
6
|
-
export type CollaborationUser = {
|
|
7
|
-
name: string;
|
|
8
|
-
color: string;
|
|
9
|
-
[key: string]: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export class CursorPlugin extends BlockNoteExtension {
|
|
13
|
-
public static key() {
|
|
14
|
-
return "yCursorPlugin";
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
private provider: { awareness: Awareness };
|
|
18
|
-
private recentlyUpdatedCursors: Map<
|
|
19
|
-
number,
|
|
20
|
-
{ element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined }
|
|
21
|
-
>;
|
|
22
|
-
constructor(
|
|
23
|
-
private collaboration: {
|
|
24
|
-
fragment: Y.XmlFragment;
|
|
25
|
-
user: CollaborationUser;
|
|
26
|
-
provider: { awareness: Awareness };
|
|
27
|
-
renderCursor?: (user: CollaborationUser) => HTMLElement;
|
|
28
|
-
showCursorLabels?: "always" | "activity";
|
|
29
|
-
},
|
|
30
|
-
) {
|
|
31
|
-
super();
|
|
32
|
-
this.provider = collaboration.provider;
|
|
33
|
-
this.recentlyUpdatedCursors = new Map();
|
|
34
|
-
|
|
35
|
-
this.provider.awareness.setLocalStateField("user", collaboration.user);
|
|
36
|
-
|
|
37
|
-
if (collaboration.showCursorLabels !== "always") {
|
|
38
|
-
this.provider.awareness.on(
|
|
39
|
-
"change",
|
|
40
|
-
({
|
|
41
|
-
updated,
|
|
42
|
-
}: {
|
|
43
|
-
added: Array<number>;
|
|
44
|
-
updated: Array<number>;
|
|
45
|
-
removed: Array<number>;
|
|
46
|
-
}) => {
|
|
47
|
-
for (const clientID of updated) {
|
|
48
|
-
const cursor = this.recentlyUpdatedCursors.get(clientID);
|
|
49
|
-
|
|
50
|
-
if (cursor) {
|
|
51
|
-
cursor.element.setAttribute("data-active", "");
|
|
52
|
-
|
|
53
|
-
if (cursor.hideTimeout) {
|
|
54
|
-
clearTimeout(cursor.hideTimeout);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
this.recentlyUpdatedCursors.set(clientID, {
|
|
58
|
-
element: cursor.element,
|
|
59
|
-
hideTimeout: setTimeout(() => {
|
|
60
|
-
cursor.element.removeAttribute("data-active");
|
|
61
|
-
}, 2000),
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
this.addProsemirrorPlugin(
|
|
70
|
-
yCursorPlugin(this.provider.awareness, {
|
|
71
|
-
selectionBuilder: defaultSelectionBuilder,
|
|
72
|
-
cursorBuilder: this.renderCursor,
|
|
73
|
-
}),
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public get priority() {
|
|
78
|
-
return 999;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private renderCursor = (user: CollaborationUser, clientID: number) => {
|
|
82
|
-
let cursorData = this.recentlyUpdatedCursors.get(clientID);
|
|
83
|
-
|
|
84
|
-
if (!cursorData) {
|
|
85
|
-
const cursorElement = (
|
|
86
|
-
this.collaboration.renderCursor ?? CursorPlugin.defaultCursorRender
|
|
87
|
-
)(user);
|
|
88
|
-
|
|
89
|
-
if (this.collaboration.showCursorLabels !== "always") {
|
|
90
|
-
cursorElement.addEventListener("mouseenter", () => {
|
|
91
|
-
const cursor = this.recentlyUpdatedCursors.get(clientID)!;
|
|
92
|
-
cursor.element.setAttribute("data-active", "");
|
|
93
|
-
|
|
94
|
-
if (cursor.hideTimeout) {
|
|
95
|
-
clearTimeout(cursor.hideTimeout);
|
|
96
|
-
this.recentlyUpdatedCursors.set(clientID, {
|
|
97
|
-
element: cursor.element,
|
|
98
|
-
hideTimeout: undefined,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
cursorElement.addEventListener("mouseleave", () => {
|
|
104
|
-
const cursor = this.recentlyUpdatedCursors.get(clientID)!;
|
|
105
|
-
|
|
106
|
-
this.recentlyUpdatedCursors.set(clientID, {
|
|
107
|
-
element: cursor.element,
|
|
108
|
-
hideTimeout: setTimeout(() => {
|
|
109
|
-
cursor.element.removeAttribute("data-active");
|
|
110
|
-
}, 2000),
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
cursorData = {
|
|
116
|
-
element: cursorElement,
|
|
117
|
-
hideTimeout: undefined,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
this.recentlyUpdatedCursors.set(clientID, cursorData);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return cursorData.element;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
public updateUser = (user: {
|
|
127
|
-
name: string;
|
|
128
|
-
color: string;
|
|
129
|
-
[key: string]: string;
|
|
130
|
-
}) => {
|
|
131
|
-
this.provider.awareness.setLocalStateField("user", user);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Determine whether the foreground color should be white or black based on a provided background color
|
|
136
|
-
* Inspired by: https://stackoverflow.com/a/3943023
|
|
137
|
-
*
|
|
138
|
-
*/
|
|
139
|
-
public static isDarkColor(bgColor: string): boolean {
|
|
140
|
-
const color = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor;
|
|
141
|
-
const r = parseInt(color.substring(0, 2), 16); // hexToR
|
|
142
|
-
const g = parseInt(color.substring(2, 4), 16); // hexToG
|
|
143
|
-
const b = parseInt(color.substring(4, 6), 16); // hexToB
|
|
144
|
-
const uicolors = [r / 255, g / 255, b / 255];
|
|
145
|
-
const c = uicolors.map((col) => {
|
|
146
|
-
if (col <= 0.03928) {
|
|
147
|
-
return col / 12.92;
|
|
148
|
-
}
|
|
149
|
-
return Math.pow((col + 0.055) / 1.055, 2.4);
|
|
150
|
-
});
|
|
151
|
-
const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
|
|
152
|
-
return L <= 0.179;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
public static defaultCursorRender = (user: CollaborationUser) => {
|
|
156
|
-
const cursorElement = document.createElement("span");
|
|
157
|
-
|
|
158
|
-
cursorElement.classList.add("bn-collaboration-cursor__base");
|
|
159
|
-
|
|
160
|
-
const caretElement = document.createElement("span");
|
|
161
|
-
caretElement.setAttribute("contentedEditable", "false");
|
|
162
|
-
caretElement.classList.add("bn-collaboration-cursor__caret");
|
|
163
|
-
caretElement.setAttribute(
|
|
164
|
-
"style",
|
|
165
|
-
`background-color: ${user.color}; color: ${
|
|
166
|
-
CursorPlugin.isDarkColor(user.color) ? "white" : "black"
|
|
167
|
-
}`,
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const labelElement = document.createElement("span");
|
|
171
|
-
|
|
172
|
-
labelElement.classList.add("bn-collaboration-cursor__label");
|
|
173
|
-
labelElement.setAttribute(
|
|
174
|
-
"style",
|
|
175
|
-
`background-color: ${user.color}; color: ${
|
|
176
|
-
CursorPlugin.isDarkColor(user.color) ? "white" : "black"
|
|
177
|
-
}`,
|
|
178
|
-
);
|
|
179
|
-
labelElement.insertBefore(document.createTextNode(user.name), null);
|
|
180
|
-
|
|
181
|
-
caretElement.insertBefore(labelElement, null);
|
|
182
|
-
|
|
183
|
-
cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space
|
|
184
|
-
cursorElement.insertBefore(caretElement, null);
|
|
185
|
-
cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space
|
|
186
|
-
|
|
187
|
-
return cursorElement;
|
|
188
|
-
};
|
|
189
|
-
}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import * as Y from "yjs";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
yCursorPluginKey,
|
|
5
|
-
ySyncPluginKey,
|
|
6
|
-
yUndoPluginKey,
|
|
7
|
-
} from "y-prosemirror";
|
|
8
|
-
import { CursorPlugin } from "./CursorPlugin.js";
|
|
9
|
-
import { SyncPlugin } from "./SyncPlugin.js";
|
|
10
|
-
import { UndoPlugin } from "./UndoPlugin.js";
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
BlockNoteEditor,
|
|
14
|
-
BlockNoteEditorOptions,
|
|
15
|
-
} from "../../editor/BlockNoteEditor.js";
|
|
16
|
-
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
|
|
17
|
-
|
|
18
|
-
export class ForkYDocPlugin extends BlockNoteExtension<{
|
|
19
|
-
forked: boolean;
|
|
20
|
-
}> {
|
|
21
|
-
public static key() {
|
|
22
|
-
return "ForkYDocPlugin";
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
private editor: BlockNoteEditor<any, any, any>;
|
|
26
|
-
private collaboration: BlockNoteEditorOptions<any, any, any>["collaboration"];
|
|
27
|
-
|
|
28
|
-
constructor({
|
|
29
|
-
editor,
|
|
30
|
-
collaboration,
|
|
31
|
-
}: {
|
|
32
|
-
editor: BlockNoteEditor<any, any, any>;
|
|
33
|
-
collaboration: BlockNoteEditorOptions<any, any, any>["collaboration"];
|
|
34
|
-
}) {
|
|
35
|
-
super(editor);
|
|
36
|
-
this.editor = editor;
|
|
37
|
-
this.collaboration = collaboration;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* To find a fragment in another ydoc, we need to search for it.
|
|
42
|
-
*/
|
|
43
|
-
private findTypeInOtherYdoc<T extends Y.AbstractType<any>>(
|
|
44
|
-
ytype: T,
|
|
45
|
-
otherYdoc: Y.Doc,
|
|
46
|
-
): T {
|
|
47
|
-
const ydoc = ytype.doc!;
|
|
48
|
-
if (ytype._item === null) {
|
|
49
|
-
/**
|
|
50
|
-
* If is a root type, we need to find the root key in the original ydoc
|
|
51
|
-
* and use it to get the type in the other ydoc.
|
|
52
|
-
*/
|
|
53
|
-
const rootKey = Array.from(ydoc.share.keys()).find(
|
|
54
|
-
(key) => ydoc.share.get(key) === ytype,
|
|
55
|
-
);
|
|
56
|
-
if (rootKey == null) {
|
|
57
|
-
throw new Error("type does not exist in other ydoc");
|
|
58
|
-
}
|
|
59
|
-
return otherYdoc.get(rootKey, ytype.constructor as new () => T) as T;
|
|
60
|
-
} else {
|
|
61
|
-
/**
|
|
62
|
-
* If it is a sub type, we use the item id to find the history type.
|
|
63
|
-
*/
|
|
64
|
-
const ytypeItem = ytype._item;
|
|
65
|
-
const otherStructs =
|
|
66
|
-
otherYdoc.store.clients.get(ytypeItem.id.client) ?? [];
|
|
67
|
-
const itemIndex = Y.findIndexSS(otherStructs, ytypeItem.id.clock);
|
|
68
|
-
const otherItem = otherStructs[itemIndex] as Y.Item;
|
|
69
|
-
const otherContent = otherItem.content as Y.ContentType;
|
|
70
|
-
return otherContent.type as T;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Whether the editor is editing a forked document,
|
|
76
|
-
* preserving a reference to the original document and the forked document.
|
|
77
|
-
*/
|
|
78
|
-
public get isForkedFromRemote() {
|
|
79
|
-
return this.forkedState !== undefined;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Stores whether the editor is editing a forked document,
|
|
84
|
-
* preserving a reference to the original document and the forked document.
|
|
85
|
-
*/
|
|
86
|
-
private forkedState:
|
|
87
|
-
| {
|
|
88
|
-
originalFragment: Y.XmlFragment;
|
|
89
|
-
undoStack: Y.UndoManager["undoStack"];
|
|
90
|
-
forkedFragment: Y.XmlFragment;
|
|
91
|
-
}
|
|
92
|
-
| undefined;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Fork the Y.js document from syncing to the remote,
|
|
96
|
-
* allowing modifications to the document without affecting the remote.
|
|
97
|
-
* These changes can later be rolled back or applied to the remote.
|
|
98
|
-
*/
|
|
99
|
-
public fork() {
|
|
100
|
-
if (this.isForkedFromRemote) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const originalFragment = this.collaboration?.fragment;
|
|
105
|
-
|
|
106
|
-
if (!originalFragment) {
|
|
107
|
-
throw new Error("No fragment to fork from");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const doc = new Y.Doc();
|
|
111
|
-
// Copy the original document to a new Yjs document
|
|
112
|
-
Y.applyUpdate(doc, Y.encodeStateAsUpdate(originalFragment.doc!));
|
|
113
|
-
|
|
114
|
-
// Find the forked fragment in the new Yjs document
|
|
115
|
-
const forkedFragment = this.findTypeInOtherYdoc(originalFragment, doc);
|
|
116
|
-
|
|
117
|
-
this.forkedState = {
|
|
118
|
-
undoStack: yUndoPluginKey.getState(this.editor.prosemirrorState)!
|
|
119
|
-
.undoManager.undoStack,
|
|
120
|
-
originalFragment,
|
|
121
|
-
forkedFragment,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Need to reset all the yjs plugins
|
|
125
|
-
this.editor._tiptapEditor.unregisterPlugin([
|
|
126
|
-
yCursorPluginKey,
|
|
127
|
-
yUndoPluginKey,
|
|
128
|
-
ySyncPluginKey,
|
|
129
|
-
]);
|
|
130
|
-
// Register them again, based on the new forked fragment
|
|
131
|
-
this.editor._tiptapEditor.registerPlugin(
|
|
132
|
-
new SyncPlugin(forkedFragment).plugins[0],
|
|
133
|
-
);
|
|
134
|
-
this.editor._tiptapEditor.registerPlugin(
|
|
135
|
-
new UndoPlugin({ editor: this.editor }).plugins[0],
|
|
136
|
-
);
|
|
137
|
-
// No need to register the cursor plugin again, it's a local fork
|
|
138
|
-
this.emit("forked", true);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Resume syncing the Y.js document to the remote
|
|
143
|
-
* If `keepChanges` is true, any changes that have been made to the forked document will be applied to the original document.
|
|
144
|
-
* Otherwise, the original document will be restored and the changes will be discarded.
|
|
145
|
-
*/
|
|
146
|
-
public merge({ keepChanges }: { keepChanges: boolean }) {
|
|
147
|
-
if (!this.forkedState) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
// Remove the forked fragment's plugins
|
|
151
|
-
this.editor._tiptapEditor.unregisterPlugin(ySyncPluginKey);
|
|
152
|
-
this.editor._tiptapEditor.unregisterPlugin(yUndoPluginKey);
|
|
153
|
-
|
|
154
|
-
const { originalFragment, forkedFragment, undoStack } = this.forkedState;
|
|
155
|
-
this.editor.extensions["ySyncPlugin"] = new SyncPlugin(originalFragment);
|
|
156
|
-
this.editor.extensions["yCursorPlugin"] = new CursorPlugin(
|
|
157
|
-
this.collaboration!,
|
|
158
|
-
);
|
|
159
|
-
this.editor.extensions["yUndoPlugin"] = new UndoPlugin({
|
|
160
|
-
editor: this.editor,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Register the plugins again, based on the original fragment
|
|
164
|
-
this.editor._tiptapEditor.registerPlugin(
|
|
165
|
-
this.editor.extensions["ySyncPlugin"].plugins[0],
|
|
166
|
-
);
|
|
167
|
-
this.editor._tiptapEditor.registerPlugin(
|
|
168
|
-
this.editor.extensions["yCursorPlugin"].plugins[0],
|
|
169
|
-
);
|
|
170
|
-
this.editor._tiptapEditor.registerPlugin(
|
|
171
|
-
this.editor.extensions["yUndoPlugin"].plugins[0],
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
// Reset the undo stack to the original undo stack
|
|
175
|
-
yUndoPluginKey.getState(
|
|
176
|
-
this.editor.prosemirrorState,
|
|
177
|
-
)!.undoManager.undoStack = undoStack;
|
|
178
|
-
|
|
179
|
-
if (keepChanges) {
|
|
180
|
-
// Apply any changes that have been made to the fork, onto the original doc
|
|
181
|
-
const update = Y.encodeStateAsUpdate(
|
|
182
|
-
forkedFragment.doc!,
|
|
183
|
-
Y.encodeStateVector(originalFragment.doc!),
|
|
184
|
-
);
|
|
185
|
-
// Applying this change will add to the undo stack, allowing it to be undone normally
|
|
186
|
-
Y.applyUpdate(originalFragment.doc!, update, this.editor);
|
|
187
|
-
}
|
|
188
|
-
// Reset the forked state
|
|
189
|
-
this.forkedState = undefined;
|
|
190
|
-
this.emit("forked", false);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ySyncPlugin } from "y-prosemirror";
|
|
2
|
-
import type * as Y from "yjs";
|
|
3
|
-
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
|
|
4
|
-
|
|
5
|
-
export class SyncPlugin extends BlockNoteExtension {
|
|
6
|
-
public static key() {
|
|
7
|
-
return "ySyncPlugin";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
constructor(fragment: Y.XmlFragment) {
|
|
11
|
-
super();
|
|
12
|
-
this.addProsemirrorPlugin(ySyncPlugin(fragment));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public get priority() {
|
|
16
|
-
return 1001;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { yUndoPlugin } from "y-prosemirror";
|
|
2
|
-
import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
|
|
3
|
-
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
|
|
4
|
-
|
|
5
|
-
export class UndoPlugin extends BlockNoteExtension {
|
|
6
|
-
public static key() {
|
|
7
|
-
return "yUndoPlugin";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
constructor({ editor }: { editor: BlockNoteEditor<any, any, any> }) {
|
|
11
|
-
super();
|
|
12
|
-
this.addProsemirrorPlugin(yUndoPlugin({ trackedOrigins: [editor] }));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public get priority() {
|
|
16
|
-
return 1000;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
2
|
-
import * as Y from "yjs";
|
|
3
|
-
|
|
4
|
-
import { BlockNoteExtension } from "../../../editor/BlockNoteExtension.js";
|
|
5
|
-
import migrationRules from "./migrationRules/index.js";
|
|
6
|
-
|
|
7
|
-
// This plugin allows us to update collaboration YDocs whenever BlockNote's
|
|
8
|
-
// underlying ProseMirror schema changes. The plugin reads the current Yjs
|
|
9
|
-
// fragment and dispatches additional transactions to the ProseMirror state, in
|
|
10
|
-
// case things are found in the fragment that don't adhere to the editor schema
|
|
11
|
-
// and need to be fixed. These fixes are defined as `MigrationRule`s within the
|
|
12
|
-
// `migrationRules` directory.
|
|
13
|
-
export class SchemaMigrationPlugin extends BlockNoteExtension {
|
|
14
|
-
private migrationDone = false;
|
|
15
|
-
|
|
16
|
-
public static key() {
|
|
17
|
-
return "schemaMigrationPlugin";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
constructor(fragment: Y.XmlFragment) {
|
|
21
|
-
const pluginKey = new PluginKey(SchemaMigrationPlugin.key());
|
|
22
|
-
|
|
23
|
-
super();
|
|
24
|
-
this.addProsemirrorPlugin(
|
|
25
|
-
new Plugin({
|
|
26
|
-
key: pluginKey,
|
|
27
|
-
appendTransaction: (transactions, _oldState, newState) => {
|
|
28
|
-
if (this.migrationDone) {
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
// If any of the transactions are not due to a yjs sync, we don't need to run the migration
|
|
34
|
-
!transactions.some((tr) => tr.getMeta("y-sync$")) ||
|
|
35
|
-
// If none of the transactions result in a document change, we don't need to run the migration
|
|
36
|
-
transactions.every((tr) => !tr.docChanged) ||
|
|
37
|
-
// If the fragment is still empty, we can't run the migration (since it has not yet been applied to the Y.Doc)
|
|
38
|
-
!fragment.firstChild
|
|
39
|
-
) {
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const tr = newState.tr;
|
|
44
|
-
for (const migrationRule of migrationRules) {
|
|
45
|
-
migrationRule(fragment, tr);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.migrationDone = true;
|
|
49
|
-
|
|
50
|
-
if (!tr.docChanged) {
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return tr;
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|