|
1 | 1 | import { AnyExtension, Extension, extensions } from "@tiptap/core"; |
2 | | -import { Awareness } from "y-protocols/awareness"; |
3 | | - |
4 | | -import type { BlockNoteEditor, BlockNoteExtension } from "./BlockNoteEditor.js"; |
5 | | - |
6 | | -import Collaboration from "@tiptap/extension-collaboration"; |
7 | | -import CollaborationCursor from "@tiptap/extension-collaboration-cursor"; |
8 | 2 | import { Gapcursor } from "@tiptap/extension-gapcursor"; |
9 | 3 | import { HardBreak } from "@tiptap/extension-hard-break"; |
10 | 4 | import { History } from "@tiptap/extension-history"; |
11 | 5 | import { Link } from "@tiptap/extension-link"; |
12 | 6 | import { Text } from "@tiptap/extension-text"; |
13 | 7 | import { Plugin } from "prosemirror-state"; |
14 | 8 | import * as Y from "yjs"; |
| 9 | + |
| 10 | +import type { BlockNoteEditor, BlockNoteExtension } from "./BlockNoteEditor.js"; |
15 | 11 | import { createDropFileExtension } from "../api/clipboard/fromClipboard/fileDropExtension.js"; |
16 | 12 | import { createPasteFromClipboardExtension } from "../api/clipboard/fromClipboard/pasteExtension.js"; |
17 | 13 | import { createCopyToClipboardExtension } from "../api/clipboard/toClipboard/copyExtension.js"; |
@@ -44,6 +40,7 @@ import { |
44 | 40 | StyleSchema, |
45 | 41 | StyleSpecs, |
46 | 42 | } from "../schema/index.js"; |
| 43 | +import { createCollaborationExtensions } from "../extensions/Collaboration/createCollaborationExtensions.js"; |
47 | 44 |
|
48 | 45 | type ExtensionOptions< |
49 | 46 | BSchema extends BlockSchema, |
@@ -247,128 +244,7 @@ const getTipTapExtensions = < |
247 | 244 | ]; |
248 | 245 |
|
249 | 246 | if (opts.collaboration) { |
250 | | - tiptapExtensions.push( |
251 | | - Collaboration.configure({ |
252 | | - fragment: opts.collaboration.fragment, |
253 | | - }) |
254 | | - ); |
255 | | - |
256 | | - const awareness = opts.collaboration?.provider.awareness as Awareness; |
257 | | - |
258 | | - if (awareness) { |
259 | | - const cursors = new Map< |
260 | | - number, |
261 | | - { element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined } |
262 | | - >(); |
263 | | - |
264 | | - if (opts.collaboration.showCursorLabels !== "always") { |
265 | | - awareness.on( |
266 | | - "change", |
267 | | - ({ |
268 | | - updated, |
269 | | - }: { |
270 | | - added: Array<number>; |
271 | | - updated: Array<number>; |
272 | | - removed: Array<number>; |
273 | | - }) => { |
274 | | - for (const clientID of updated) { |
275 | | - const cursor = cursors.get(clientID); |
276 | | - |
277 | | - if (cursor) { |
278 | | - cursor.element.setAttribute("data-active", ""); |
279 | | - |
280 | | - if (cursor.hideTimeout) { |
281 | | - clearTimeout(cursor.hideTimeout); |
282 | | - } |
283 | | - |
284 | | - cursors.set(clientID, { |
285 | | - element: cursor.element, |
286 | | - hideTimeout: setTimeout(() => { |
287 | | - cursor.element.removeAttribute("data-active"); |
288 | | - }, 2000), |
289 | | - }); |
290 | | - } |
291 | | - } |
292 | | - } |
293 | | - ); |
294 | | - } |
295 | | - |
296 | | - const createCursor = (clientID: number, name: string, color: string) => { |
297 | | - const cursorElement = document.createElement("span"); |
298 | | - |
299 | | - cursorElement.classList.add("collaboration-cursor__caret"); |
300 | | - cursorElement.setAttribute("style", `border-color: ${color}`); |
301 | | - if (opts.collaboration?.showCursorLabels === "always") { |
302 | | - cursorElement.setAttribute("data-active", ""); |
303 | | - } |
304 | | - |
305 | | - const labelElement = document.createElement("span"); |
306 | | - |
307 | | - labelElement.classList.add("collaboration-cursor__label"); |
308 | | - labelElement.setAttribute("style", `background-color: ${color}`); |
309 | | - labelElement.insertBefore(document.createTextNode(name), null); |
310 | | - |
311 | | - cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space |
312 | | - cursorElement.insertBefore(labelElement, null); |
313 | | - cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space |
314 | | - |
315 | | - cursors.set(clientID, { |
316 | | - element: cursorElement, |
317 | | - hideTimeout: undefined, |
318 | | - }); |
319 | | - |
320 | | - if (opts.collaboration?.showCursorLabels !== "always") { |
321 | | - cursorElement.addEventListener("mouseenter", () => { |
322 | | - const cursor = cursors.get(clientID)!; |
323 | | - cursor.element.setAttribute("data-active", ""); |
324 | | - |
325 | | - if (cursor.hideTimeout) { |
326 | | - clearTimeout(cursor.hideTimeout); |
327 | | - cursors.set(clientID, { |
328 | | - element: cursor.element, |
329 | | - hideTimeout: undefined, |
330 | | - }); |
331 | | - } |
332 | | - }); |
333 | | - |
334 | | - cursorElement.addEventListener("mouseleave", () => { |
335 | | - const cursor = cursors.get(clientID)!; |
336 | | - |
337 | | - cursors.set(clientID, { |
338 | | - element: cursor.element, |
339 | | - hideTimeout: setTimeout(() => { |
340 | | - cursor.element.removeAttribute("data-active"); |
341 | | - }, 2000), |
342 | | - }); |
343 | | - }); |
344 | | - } |
345 | | - |
346 | | - return cursors.get(clientID)!; |
347 | | - }; |
348 | | - |
349 | | - const defaultRender = (user: { color: string; name: string }) => { |
350 | | - const clientState = [...awareness.getStates().entries()].find( |
351 | | - (state) => state[1].user === user |
352 | | - ); |
353 | | - |
354 | | - if (!clientState) { |
355 | | - throw new Error("Could not find client state for user"); |
356 | | - } |
357 | | - |
358 | | - const clientID = clientState[0]; |
359 | | - |
360 | | - return ( |
361 | | - cursors.get(clientID) || createCursor(clientID, user.name, user.color) |
362 | | - ).element; |
363 | | - }; |
364 | | - tiptapExtensions.push( |
365 | | - CollaborationCursor.configure({ |
366 | | - user: opts.collaboration.user, |
367 | | - render: opts.collaboration.renderCursor || defaultRender, |
368 | | - provider: opts.collaboration.provider, |
369 | | - }) |
370 | | - ); |
371 | | - } |
| 247 | + tiptapExtensions.push(...createCollaborationExtensions(opts.collaboration)); |
372 | 248 | } else { |
373 | 249 | // disable history extension when collaboration is enabled as Yjs takes care of undo / redo |
374 | 250 | tiptapExtensions.push(History); |
|
0 commit comments