From f40b70ec87ef04b7f9ababfcaf6a6e77268596b5 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Thu, 24 Apr 2025 17:39:43 +0200 Subject: [PATCH 1/7] feat: re-implement Y.js collaboration as BlockNote plugins --- packages/core/package.json | 2 - packages/core/src/editor/BlockNoteEditor.ts | 11 +- .../core/src/editor/BlockNoteExtensions.ts | 19 ++- .../extensions/Collaboration/CursorPlugin.ts | 152 ++++++++++++++++++ .../extensions/Collaboration/SyncPlugin.ts | 15 ++ .../extensions/Collaboration/UndoPlugin.ts | 14 ++ .../createCollaborationExtensions.ts | 147 ----------------- .../KeyboardShortcutsExtension.ts | 3 + pnpm-lock.yaml | 6 - 9 files changed, 207 insertions(+), 162 deletions(-) create mode 100644 packages/core/src/extensions/Collaboration/CursorPlugin.ts create mode 100644 packages/core/src/extensions/Collaboration/SyncPlugin.ts create mode 100644 packages/core/src/extensions/Collaboration/UndoPlugin.ts delete mode 100644 packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts diff --git a/packages/core/package.json b/packages/core/package.json index 8f26e5234..3b52f591b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -77,8 +77,6 @@ "@tiptap/core": "^2.11.5", "@tiptap/extension-bold": "^2.11.5", "@tiptap/extension-code": "^2.11.5", - "@tiptap/extension-collaboration": "^2.11.5", - "@tiptap/extension-collaboration-cursor": "^2.11.5", "@tiptap/extension-gapcursor": "^2.11.5", "@tiptap/extension-history": "^2.11.5", "@tiptap/extension-horizontal-rule": "^2.11.5", diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index f79362f90..715ef60b5 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -115,6 +115,7 @@ import { CodeBlockOptions } from "../blocks/CodeBlockContent/CodeBlockContent.js import type { ThreadStore, User } from "../comments/index.js"; import "../style.css"; import { EventEmitter } from "../util/EventEmitter.js"; +import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js"; export type BlockNoteExtensionFactory = ( editor: BlockNoteEditor @@ -124,6 +125,7 @@ export type BlockNoteExtension = | AnyExtension | { plugin: Plugin; + priority?: number; }; export type BlockCache< @@ -472,6 +474,8 @@ export class BlockNoteEditor< private readonly showSelectionPlugin: ShowSelectionPlugin; + private readonly cursorPlugin: CursorPlugin; + /** * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload). * This method should set when creating the editor as this is application-specific. @@ -622,6 +626,7 @@ export class BlockNoteEditor< this.tableHandles = this.extensions["tableHandles"] as any; this.comments = this.extensions["comments"] as any; this.showSelectionPlugin = this.extensions["showSelection"] as any; + this.cursorPlugin = this.extensions["yCursorPlugin"] as any; if (newOptions.uploadFile) { const uploadFile = newOptions.uploadFile; @@ -643,7 +648,7 @@ export class BlockNoteEditor< this.headless = newOptions._headless; const collaborationEnabled = - "collaboration" in this.extensions || + "ySyncPlugin" in this.extensions || "liveblocksExtension" in this.extensions; if (collaborationEnabled && newOptions.initialContent) { @@ -696,6 +701,7 @@ export class BlockNoteEditor< // "blocknote" extensions (prosemirror plugins) return Extension.create({ name: key, + priority: ext.priority, addProseMirrorPlugins: () => [ext.plugin], }); }), @@ -1488,7 +1494,8 @@ export class BlockNoteEditor< "Cannot update collaboration user info when collaboration is disabled." ); } - this._tiptapEditor.commands.updateUser(user); + + this.cursorPlugin.updateUser(user); } /** diff --git a/packages/core/src/editor/BlockNoteExtensions.ts b/packages/core/src/editor/BlockNoteExtensions.ts index 932ca9128..b0c5db73b 100644 --- a/packages/core/src/editor/BlockNoteExtensions.ts +++ b/packages/core/src/editor/BlockNoteExtensions.ts @@ -10,7 +10,9 @@ import { createDropFileExtension } from "../api/clipboard/fromClipboard/fileDrop import { createPasteFromClipboardExtension } from "../api/clipboard/fromClipboard/pasteExtension.js"; import { createCopyToClipboardExtension } from "../api/clipboard/toClipboard/copyExtension.js"; import { BackgroundColorExtension } from "../extensions/BackgroundColor/BackgroundColorExtension.js"; -import { createCollaborationExtensions } from "../extensions/Collaboration/createCollaborationExtensions.js"; +import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js"; +import { UndoPlugin } from "../extensions/Collaboration/UndoPlugin.js"; +import { SyncPlugin } from "../extensions/Collaboration/SyncPlugin.js"; import { CommentMark } from "../extensions/Comments/CommentMark.js"; import { CommentsPlugin } from "../extensions/Comments/CommentsPlugin.js"; import type { ThreadStore } from "../comments/index.js"; @@ -106,6 +108,15 @@ export const getBlockNoteExtensions = < ret[ext.name] = ext; } + if (opts.collaboration) { + ret["ySyncPlugin"] = new SyncPlugin(opts.collaboration.fragment); + ret["yUndoPlugin"] = new UndoPlugin(); + + if (opts.collaboration.provider?.awareness) { + ret["yCursorPlugin"] = new CursorPlugin(opts.collaboration); + } + } + // Note: this is pretty hardcoded and will break when user provides plugins with same keys. // Define name on plugins instead and not make this a map? ret["formattingToolbar"] = new FormattingToolbarProsemirrorPlugin( @@ -285,10 +296,8 @@ const getTipTapExtensions = < LINKIFY_INITIALIZED = true; - if (opts.collaboration) { - tiptapExtensions.push(...createCollaborationExtensions(opts.collaboration)); - } else { - // disable history extension when collaboration is enabled as Yjs takes care of undo / redo + if (!opts.collaboration) { + // disable history extension when collaboration is enabled as y-prosemirror takes care of undo / redo tiptapExtensions.push(History); } diff --git a/packages/core/src/extensions/Collaboration/CursorPlugin.ts b/packages/core/src/extensions/Collaboration/CursorPlugin.ts new file mode 100644 index 000000000..d6acf74c8 --- /dev/null +++ b/packages/core/src/extensions/Collaboration/CursorPlugin.ts @@ -0,0 +1,152 @@ +import { Plugin } from "prosemirror-state"; +import { defaultSelectionBuilder, yCursorPlugin } from "y-prosemirror"; +import { Awareness } from "y-protocols/awareness.js"; +import * as Y from "yjs"; + +export type CollaborationUser = { + name: string; + color: string; + [key: string]: string; +}; + +export class CursorPlugin { + public plugin: Plugin; + private provider: { awareness: Awareness }; + private recentlyUpdatedCursors: Map< + number, + { element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined } + >; + constructor( + private collaboration: { + fragment: Y.XmlFragment; + user: CollaborationUser; + provider: { awareness: Awareness }; + renderCursor?: (user: CollaborationUser) => HTMLElement; + showCursorLabels?: "always" | "activity"; + } + ) { + this.provider = collaboration.provider; + this.recentlyUpdatedCursors = new Map(); + + this.provider.awareness.setLocalStateField("user", collaboration.user); + + if (collaboration.showCursorLabels !== "always") { + this.provider.awareness.on( + "change", + ({ + updated, + }: { + added: Array; + updated: Array; + removed: Array; + }) => { + for (const clientID of updated) { + const cursor = this.recentlyUpdatedCursors.get(clientID); + + if (cursor) { + cursor.element.setAttribute("data-active", ""); + + if (cursor.hideTimeout) { + clearTimeout(cursor.hideTimeout); + } + + this.recentlyUpdatedCursors.set(clientID, { + element: cursor.element, + hideTimeout: setTimeout(() => { + cursor.element.removeAttribute("data-active"); + }, 2000), + }); + } + } + } + ); + } + + this.plugin = yCursorPlugin(this.provider.awareness, { + selectionBuilder: defaultSelectionBuilder, + cursorBuilder: this.renderCursor, + }); + } + + public get priority() { + return 999; + } + + private renderCursor = (user: CollaborationUser, clientID: number) => { + let cursorData = this.recentlyUpdatedCursors.get(clientID); + + if (!cursorData) { + const cursorElement = ( + this.collaboration.renderCursor ?? CursorPlugin.defaultCursorRender + )(user); + + if (this.collaboration.showCursorLabels !== "always") { + cursorElement.addEventListener("mouseenter", () => { + const cursor = this.recentlyUpdatedCursors.get(clientID)!; + cursor.element.setAttribute("data-active", ""); + + if (cursor.hideTimeout) { + clearTimeout(cursor.hideTimeout); + this.recentlyUpdatedCursors.set(clientID, { + element: cursor.element, + hideTimeout: undefined, + }); + } + }); + + cursorElement.addEventListener("mouseleave", () => { + const cursor = this.recentlyUpdatedCursors.get(clientID)!; + + this.recentlyUpdatedCursors.set(clientID, { + element: cursor.element, + hideTimeout: setTimeout(() => { + cursor.element.removeAttribute("data-active"); + }, 2000), + }); + }); + } + + cursorData = { + element: cursorElement, + hideTimeout: undefined, + }; + + this.recentlyUpdatedCursors.set(clientID, cursorData); + } + + return cursorData.element; + }; + + public updateUser = (user: { + name: string; + color: string; + [key: string]: string; + }) => { + this.provider.awareness.setLocalStateField("user", user); + }; + + public static defaultCursorRender = (user: CollaborationUser) => { + const cursorElement = document.createElement("span"); + + cursorElement.classList.add("bn-collaboration-cursor__base"); + + const caretElement = document.createElement("span"); + caretElement.setAttribute("contentedEditable", "false"); + caretElement.classList.add("bn-collaboration-cursor__caret"); + caretElement.setAttribute("style", `background-color: ${user.color}`); + + const labelElement = document.createElement("span"); + + labelElement.classList.add("bn-collaboration-cursor__label"); + labelElement.setAttribute("style", `background-color: ${user.color}`); + labelElement.insertBefore(document.createTextNode(user.name), null); + + caretElement.insertBefore(labelElement, null); + + cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space + cursorElement.insertBefore(caretElement, null); + cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space + + return cursorElement; + }; +} diff --git a/packages/core/src/extensions/Collaboration/SyncPlugin.ts b/packages/core/src/extensions/Collaboration/SyncPlugin.ts new file mode 100644 index 000000000..00e3cc700 --- /dev/null +++ b/packages/core/src/extensions/Collaboration/SyncPlugin.ts @@ -0,0 +1,15 @@ +import { Plugin } from "prosemirror-state"; +import { ySyncPlugin } from "y-prosemirror"; +import type * as Y from "yjs"; + +export class SyncPlugin { + public plugin: Plugin; + + constructor(fragment: Y.XmlFragment) { + this.plugin = ySyncPlugin(fragment); + } + + public get priority() { + return 1001; + } +} diff --git a/packages/core/src/extensions/Collaboration/UndoPlugin.ts b/packages/core/src/extensions/Collaboration/UndoPlugin.ts new file mode 100644 index 000000000..87d39ee5e --- /dev/null +++ b/packages/core/src/extensions/Collaboration/UndoPlugin.ts @@ -0,0 +1,14 @@ +import { Plugin } from "prosemirror-state"; +import { yUndoPlugin } from "y-prosemirror"; + +export class UndoPlugin { + public plugin: Plugin; + + constructor() { + this.plugin = yUndoPlugin(); + } + + public get priority() { + return 1000; + } +} diff --git a/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts b/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts deleted file mode 100644 index 919c3029f..000000000 --- a/packages/core/src/extensions/Collaboration/createCollaborationExtensions.ts +++ /dev/null @@ -1,147 +0,0 @@ -import Collaboration from "@tiptap/extension-collaboration"; -import CollaborationCursor from "@tiptap/extension-collaboration-cursor"; -import { Awareness } from "y-protocols/awareness"; -import * as Y from "yjs"; - -export const createCollaborationExtensions = (collaboration: { - fragment: Y.XmlFragment; - user: { - name: string; - color: string; - [key: string]: string; - }; - provider: any; - renderCursor?: (user: any) => HTMLElement; - showCursorLabels?: "always" | "activity"; -}) => { - const tiptapExtensions = []; - - tiptapExtensions.push( - Collaboration.configure({ - fragment: collaboration.fragment, - }) - ); - - const awareness = collaboration.provider?.awareness as Awareness | undefined; - - if (awareness) { - const cursors = new Map< - number, - { element: HTMLElement; hideTimeout: NodeJS.Timeout | undefined } - >(); - - if (collaboration.showCursorLabels !== "always") { - awareness.on( - "change", - ({ - updated, - }: { - added: Array; - updated: Array; - removed: Array; - }) => { - for (const clientID of updated) { - const cursor = cursors.get(clientID); - - if (cursor) { - cursor.element.setAttribute("data-active", ""); - - if (cursor.hideTimeout) { - clearTimeout(cursor.hideTimeout); - } - - cursors.set(clientID, { - element: cursor.element, - hideTimeout: setTimeout(() => { - cursor.element.removeAttribute("data-active"); - }, 2000), - }); - } - } - } - ); - } - - const renderCursor = (user: { name: string; color: string }) => { - const cursorElement = document.createElement("span"); - - cursorElement.classList.add("bn-collaboration-cursor__base"); - - const caretElement = document.createElement("span"); - caretElement.setAttribute("contentedEditable", "false"); - caretElement.classList.add("bn-collaboration-cursor__caret"); - caretElement.setAttribute("style", `background-color: ${user.color}`); - - const labelElement = document.createElement("span"); - - labelElement.classList.add("bn-collaboration-cursor__label"); - labelElement.setAttribute("style", `background-color: ${user.color}`); - labelElement.insertBefore(document.createTextNode(user.name), null); - - caretElement.insertBefore(labelElement, null); - - cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space - cursorElement.insertBefore(caretElement, null); - cursorElement.insertBefore(document.createTextNode("\u2060"), null); // Non-breaking space - - return cursorElement; - }; - - const render = ( - user: { color: string; name: string }, - clientID: number - ) => { - let cursorData = cursors.get(clientID); - - if (!cursorData) { - const cursorElement = - collaboration?.renderCursor?.(user) || renderCursor(user); - - if (collaboration?.showCursorLabels !== "always") { - cursorElement.addEventListener("mouseenter", () => { - const cursor = cursors.get(clientID)!; - cursor.element.setAttribute("data-active", ""); - - if (cursor.hideTimeout) { - clearTimeout(cursor.hideTimeout); - cursors.set(clientID, { - element: cursor.element, - hideTimeout: undefined, - }); - } - }); - - cursorElement.addEventListener("mouseleave", () => { - const cursor = cursors.get(clientID)!; - - cursors.set(clientID, { - element: cursor.element, - hideTimeout: setTimeout(() => { - cursor.element.removeAttribute("data-active"); - }, 2000), - }); - }); - } - - cursorData = { - element: cursorElement, - hideTimeout: undefined, - }; - - cursors.set(clientID, cursorData); - } - - return cursorData.element; - }; - - tiptapExtensions.push( - CollaborationCursor.configure({ - user: collaboration.user, - render: render as any, // tiptap type not compatible with latest y-prosemirror - provider: collaboration.provider, - }) - ); - } - - return tiptapExtensions; -}; diff --git a/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts b/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts index 6bd69d978..d0abda0ab 100644 --- a/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +++ b/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts @@ -605,6 +605,9 @@ export const KeyboardShortcutsExtension = Extension.create<{ this.options.editor.moveBlocksDown(); return true; }, + "Mod-z": () => this.options.editor.undo(), + "Mod-y": () => this.options.editor.redo(), + "Shift-Mod-z": () => this.options.editor.redo(), }; }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a11febbcb..40aea4d70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2866,12 +2866,6 @@ importers: '@tiptap/extension-code': specifier: ^2.11.5 version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) - '@tiptap/extension-collaboration': - specifier: ^2.11.5 - version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)) - '@tiptap/extension-collaboration-cursor': - specifier: ^2.11.5 - version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)) '@tiptap/extension-gapcursor': specifier: ^2.11.5 version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) From 1fa5136b2026e2c3bc512a6ccb2dd108bfe1471a Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Thu, 24 Apr 2025 18:13:46 +0200 Subject: [PATCH 2/7] feat: pausing & resuming of a ydoc --- examples/07-collaboration/01-partykit/App.tsx | 18 +++++- packages/core/src/editor/BlockNoteEditor.ts | 57 +++++++++++++++++-- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/examples/07-collaboration/01-partykit/App.tsx b/examples/07-collaboration/01-partykit/App.tsx index cecfb6767..0f833568a 100644 --- a/examples/07-collaboration/01-partykit/App.tsx +++ b/examples/07-collaboration/01-partykit/App.tsx @@ -30,5 +30,21 @@ export default function App() { }); // Renders the editor instance. - return ; + return ( + <> + + + + + ); } diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index 715ef60b5..d69f80e6b 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -93,6 +93,7 @@ import { import { Dictionary } from "../i18n/dictionary.js"; import { en } from "../i18n/locales/index.js"; +import { redo, undo } from "@tiptap/pm/history"; import { TextSelection, type Command, @@ -101,8 +102,14 @@ import { } from "@tiptap/pm/state"; import { dropCursor } from "prosemirror-dropcursor"; import { EditorView } from "prosemirror-view"; -import { undoCommand, redoCommand, ySyncPluginKey } from "y-prosemirror"; -import { undo, redo } from "@tiptap/pm/history"; +import { + redoCommand, + undoCommand, + yCursorPluginKey, + ySyncPlugin, + ySyncPluginKey, + yUndoPluginKey, +} from "y-prosemirror"; import { createInternalHTMLSerializer } from "../api/exporters/html/internalHTMLSerializer.js"; import { inlineContentToNodes } from "../api/nodeConversions/blockToNode.js"; import { nodeToBlock } from "../api/nodeConversions/nodeToBlock.js"; @@ -113,9 +120,11 @@ import { import { nestedListsToBlockNoteStructure } from "../api/parsers/html/util/nestedLists.js"; import { CodeBlockOptions } from "../blocks/CodeBlockContent/CodeBlockContent.js"; import type { ThreadStore, User } from "../comments/index.js"; +import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js"; import "../style.css"; import { EventEmitter } from "../util/EventEmitter.js"; -import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js"; +import { SyncPlugin } from "../extensions/Collaboration/SyncPlugin.js"; +import { UndoPlugin } from "../extensions/Collaboration/UndoPlugin.js"; export type BlockNoteExtensionFactory = ( editor: BlockNoteEditor @@ -474,7 +483,7 @@ export class BlockNoteEditor< private readonly showSelectionPlugin: ShowSelectionPlugin; - private readonly cursorPlugin: CursorPlugin; + private cursorPlugin: CursorPlugin; /** * The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload). @@ -934,6 +943,46 @@ export class BlockNoteEditor< }; } + private yjsState: + | { + prevFragment: Y.XmlFragment; + nextFragment: Y.XmlFragment; + } + | undefined; + + public pauseYjsSync() { + const prevFragment = this.options.collaboration?.fragment; + + if (!prevFragment) { + throw new Error("No Yjs document found"); + } + const nextFragment = prevFragment.clone(); + const doc = new Y.Doc(); + nextFragment._integrate(doc, nextFragment._item!); + + this.yjsState = { + prevFragment, + nextFragment, + }; + this._tiptapEditor.unregisterPlugin(yCursorPluginKey); + this._tiptapEditor.unregisterPlugin(yUndoPluginKey); + this._tiptapEditor.unregisterPlugin(ySyncPluginKey); + this._tiptapEditor.registerPlugin(ySyncPlugin(nextFragment)); + } + + public resumeYjsSync() { + if (!this.yjsState) { + throw new Error("No Yjs document found"); + } + this._tiptapEditor.unregisterPlugin(ySyncPluginKey); + this._tiptapEditor.registerPlugin( + new SyncPlugin(this.yjsState.prevFragment).plugin + ); + this.cursorPlugin = new CursorPlugin(this.options.collaboration!); + this._tiptapEditor.registerPlugin(this.cursorPlugin.plugin); + this._tiptapEditor.registerPlugin(new UndoPlugin().plugin); + } + /** * @deprecated, use `editor.document` instead */ From 0c3b42a9999e2b7c5bc7af9674353977fc7cf321 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Thu, 24 Apr 2025 18:46:55 +0200 Subject: [PATCH 3/7] refactor: integrate the fragment properly --- packages/core/src/editor/BlockNoteEditor.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index d69f80e6b..20e326480 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -956,9 +956,10 @@ export class BlockNoteEditor< if (!prevFragment) { throw new Error("No Yjs document found"); } + const nextFragment = prevFragment.clone(); const doc = new Y.Doc(); - nextFragment._integrate(doc, nextFragment._item!); + doc.getMap().set("cpy", nextFragment); this.yjsState = { prevFragment, From 6e8ac433cddb57c61a8d45d2c1d679f13ad0297e Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Thu, 24 Apr 2025 19:24:15 +0200 Subject: [PATCH 4/7] feat: add accepting and rejecting changes --- examples/07-collaboration/01-partykit/App.tsx | 12 +++- packages/core/src/editor/BlockNoteEditor.ts | 61 +++++++++++++++++-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/examples/07-collaboration/01-partykit/App.tsx b/examples/07-collaboration/01-partykit/App.tsx index 0f833568a..0bdc8c407 100644 --- a/examples/07-collaboration/01-partykit/App.tsx +++ b/examples/07-collaboration/01-partykit/App.tsx @@ -36,13 +36,19 @@ export default function App() { onClick={() => { editor.pauseYjsSync(); }}> - Pause + Pause syncing + diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index 20e326480..ffc970bae 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -943,6 +943,44 @@ export class BlockNoteEditor< }; } + /** + * To find a fragment in another ydoc, we need to search for it. + */ + private findTypeInOtherYdoc>( + ytype: T, + otherYdoc: Y.Doc + ): T { + const ydoc = ytype.doc!; + if (ytype._item === null) { + /** + * If is a root type, we need to find the root key in the original ydoc + * and use it to get the type in the other ydoc. + */ + const rootKey = Array.from(ydoc.share.keys()).find( + (key) => ydoc.share.get(key) === ytype + ); + if (rootKey == null) { + throw new Error("type does not exist in other ydoc"); + } + return otherYdoc.get(rootKey, ytype.constructor as new () => T) as T; + } else { + /** + * If it is a sub type, we use the item id to find the history type. + */ + const ytypeItem = ytype._item; + const otherStructs = + otherYdoc.store.clients.get(ytypeItem.id.client) ?? []; + const itemIndex = Y.findIndexSS(otherStructs, ytypeItem.id.clock); + const otherItem = otherStructs[itemIndex] as Y.Item; + const otherContent = otherItem.content as Y.ContentType; + return otherContent.type as T; + } + } + + public get isRemoteSyncing() { + return this.yjsState !== undefined; + } + private yjsState: | { prevFragment: Y.XmlFragment; @@ -951,15 +989,22 @@ export class BlockNoteEditor< | undefined; public pauseYjsSync() { + if (this.isRemoteSyncing) { + return; + } + const prevFragment = this.options.collaboration?.fragment; if (!prevFragment) { throw new Error("No Yjs document found"); } - const nextFragment = prevFragment.clone(); + const update = Y.encodeStateAsUpdate(prevFragment.doc!); + const doc = new Y.Doc(); - doc.getMap().set("cpy", nextFragment); + Y.applyUpdate(doc, update); + + const nextFragment = this.findTypeInOtherYdoc(prevFragment, doc); this.yjsState = { prevFragment, @@ -971,17 +1016,21 @@ export class BlockNoteEditor< this._tiptapEditor.registerPlugin(ySyncPlugin(nextFragment)); } - public resumeYjsSync() { + public resumeYjsSync(mergeChanges = false) { if (!this.yjsState) { throw new Error("No Yjs document found"); } this._tiptapEditor.unregisterPlugin(ySyncPluginKey); - this._tiptapEditor.registerPlugin( - new SyncPlugin(this.yjsState.prevFragment).plugin - ); + const fragment = this.yjsState.prevFragment; + if (mergeChanges) { + const update = Y.encodeStateAsUpdate(this.yjsState.nextFragment.doc!); + Y.applyUpdate(fragment.doc!, update); + } + this._tiptapEditor.registerPlugin(new SyncPlugin(fragment).plugin); this.cursorPlugin = new CursorPlugin(this.options.collaboration!); this._tiptapEditor.registerPlugin(this.cursorPlugin.plugin); this._tiptapEditor.registerPlugin(new UndoPlugin().plugin); + this.yjsState = undefined; } /** From d1a045a17b668b7eaac6c636766a3197622a8076 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 25 Apr 2025 08:56:48 +0200 Subject: [PATCH 5/7] refactor: cleanup & naming --- examples/07-collaboration/01-partykit/App.tsx | 11 ++- packages/core/src/editor/BlockNoteEditor.ts | 91 +++++++++++++------ 2 files changed, 71 insertions(+), 31 deletions(-) diff --git a/examples/07-collaboration/01-partykit/App.tsx b/examples/07-collaboration/01-partykit/App.tsx index 0bdc8c407..5485fd519 100644 --- a/examples/07-collaboration/01-partykit/App.tsx +++ b/examples/07-collaboration/01-partykit/App.tsx @@ -4,6 +4,8 @@ import { BlockNoteView } from "@blocknote/mantine"; import "@blocknote/mantine/style.css"; import YPartyKitProvider from "y-partykit/provider"; import * as Y from "yjs"; +import { useEffect } from "react"; +import { useState } from "react"; // Sets up Yjs document and PartyKit Yjs provider. const doc = new Y.Doc(); @@ -28,13 +30,17 @@ export default function App() { }, }, }); + const [forked, setForked] = useState(false); + useEffect(() => { + editor.on("forked", setForked); + }, [editor]); // Renders the editor instance. return ( <> @@ -50,6 +56,9 @@ export default function App() { }}> Play (reject changes) +
+

Forked: {forked ? "Yes" : "No"}

+
); diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index ffc970bae..de8ec1e2f 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -106,7 +106,6 @@ import { redoCommand, undoCommand, yCursorPluginKey, - ySyncPlugin, ySyncPluginKey, yUndoPluginKey, } from "y-prosemirror"; @@ -404,6 +403,7 @@ export class BlockNoteEditor< SSchema extends StyleSchema = DefaultStyleSchema > extends EventEmitter<{ create: void; + forked: boolean; }> { /** * The underlying prosemirror schema @@ -977,60 +977,91 @@ export class BlockNoteEditor< } } - public get isRemoteSyncing() { - return this.yjsState !== undefined; + /** + * Whether the editor is editing a forked document, + * preserving a reference to the original document and the forked document. + */ + public get isForkedFromRemote() { + return this.forkedState !== undefined; } - private yjsState: + /** + * Stores whether the editor is editing a forked document, + * preserving a reference to the original document and the forked document. + */ + private forkedState: | { - prevFragment: Y.XmlFragment; - nextFragment: Y.XmlFragment; + originalFragment: Y.XmlFragment; + forkedFragment: Y.XmlFragment; } | undefined; - public pauseYjsSync() { - if (this.isRemoteSyncing) { + /** + * Fork the Y.js document from syncing to the remote, + * allowing modifications to the document without affecting the remote. + * These changes can later be rolled back or applied to the remote. + */ + public forkYjsSync() { + if (this.forkedState) { return; } - const prevFragment = this.options.collaboration?.fragment; + const originalFragment = this.options.collaboration?.fragment; - if (!prevFragment) { + if (!originalFragment) { throw new Error("No Yjs document found"); } - const update = Y.encodeStateAsUpdate(prevFragment.doc!); - const doc = new Y.Doc(); - Y.applyUpdate(doc, update); + // Copy the original document to a new Yjs document + Y.applyUpdate(doc, Y.encodeStateAsUpdate(originalFragment.doc!)); - const nextFragment = this.findTypeInOtherYdoc(prevFragment, doc); + // Find the forked fragment in the new Yjs document + const forkedFragment = this.findTypeInOtherYdoc(originalFragment, doc); - this.yjsState = { - prevFragment, - nextFragment, + this.forkedState = { + originalFragment, + forkedFragment, }; - this._tiptapEditor.unregisterPlugin(yCursorPluginKey); - this._tiptapEditor.unregisterPlugin(yUndoPluginKey); - this._tiptapEditor.unregisterPlugin(ySyncPluginKey); - this._tiptapEditor.registerPlugin(ySyncPlugin(nextFragment)); + + // Need to reset all the yjs plugins + [yCursorPluginKey, yUndoPluginKey, ySyncPluginKey].forEach((key) => { + this._tiptapEditor.unregisterPlugin(key); + }); + // Register them again, based on the new forked fragment + this._tiptapEditor.registerPlugin(new SyncPlugin(forkedFragment).plugin); + this._tiptapEditor.registerPlugin(new UndoPlugin().plugin); + // No need to register the cursor plugin again, it's a local fork + this.emit("forked", true); } - public resumeYjsSync(mergeChanges = false) { - if (!this.yjsState) { - throw new Error("No Yjs document found"); + /** + * Resume syncing the Y.js document to the remote + * If `keepChanges` is true, any changes that have been made to the forked document will be applied to the original document. + * Otherwise, the original document will be restored and the changes will be discarded. + */ + public resumeYjsSync(keepChanges = false) { + if (!this.forkedState) { + return; } + // Remove the forked fragment's plugins this._tiptapEditor.unregisterPlugin(ySyncPluginKey); - const fragment = this.yjsState.prevFragment; - if (mergeChanges) { - const update = Y.encodeStateAsUpdate(this.yjsState.nextFragment.doc!); - Y.applyUpdate(fragment.doc!, update); + this._tiptapEditor.unregisterPlugin(yUndoPluginKey); + + const { originalFragment, forkedFragment } = this.forkedState!; + if (keepChanges) { + // Apply any changes that have been made to the fork, onto the original doc + const update = Y.encodeStateAsUpdate(forkedFragment.doc!); + Y.applyUpdate(originalFragment.doc!, update); } - this._tiptapEditor.registerPlugin(new SyncPlugin(fragment).plugin); + // Register the plugins again, based on the original fragment + this._tiptapEditor.registerPlugin(new SyncPlugin(originalFragment).plugin); this.cursorPlugin = new CursorPlugin(this.options.collaboration!); this._tiptapEditor.registerPlugin(this.cursorPlugin.plugin); this._tiptapEditor.registerPlugin(new UndoPlugin().plugin); - this.yjsState = undefined; + // Reset the forked state + this.forkedState = undefined; + this.emit("forked", false); } /** From 50b415e11bb224ce6c311905a82935613ad01b84 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 25 Apr 2025 09:00:23 +0200 Subject: [PATCH 6/7] refactor: do not throw error on unneeded fork --- packages/core/src/editor/BlockNoteEditor.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index de8ec1e2f..cd8f46505 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -1009,7 +1009,8 @@ export class BlockNoteEditor< const originalFragment = this.options.collaboration?.fragment; if (!originalFragment) { - throw new Error("No Yjs document found"); + // No original fragment found, so no need to fork + return; } const doc = new Y.Doc(); From 5065c3ff4aa307c065b692b3fa26bfd996ccaa8b Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 2 May 2025 12:36:03 +0200 Subject: [PATCH 7/7] feat: wip on integrating y-diff --- examples/07-collaboration/01-partykit/App.tsx | 2 +- package.json | 5 +- packages/core/package.json | 4 +- packages/core/src/editor/BlockNoteEditor.ts | 11 ++ pnpm-lock.yaml | 177 ++++++++++++------ 5 files changed, 134 insertions(+), 65 deletions(-) diff --git a/examples/07-collaboration/01-partykit/App.tsx b/examples/07-collaboration/01-partykit/App.tsx index 5485fd519..f2304c7b5 100644 --- a/examples/07-collaboration/01-partykit/App.tsx +++ b/examples/07-collaboration/01-partykit/App.tsx @@ -12,7 +12,7 @@ const doc = new Y.Doc(); const provider = new YPartyKitProvider( "blocknote-dev.yousefed.partykit.dev", // Use a unique name as a "room" for your application. - "your-project-name", + "your-project-name-nick", doc ); diff --git a/package.json b/package.json index a4a34feee..159c30fb6 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,10 @@ "canvas", "esbuild", "nx" - ] + ], + "overrides": { + "yjs": "^14.0.0-0" + } }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808", "private": true, diff --git a/packages/core/package.json b/packages/core/package.json index 3b52f591b..844f2bb07 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -109,9 +109,9 @@ "remark-stringify": "^11.0.0", "unified": "^11.0.5", "uuid": "^8.3.2", - "y-prosemirror": "^1.3.4", + "y-prosemirror": "npm:@y/prosemirror@2.0.0-0", "y-protocols": "^1.0.6", - "yjs": "^13.6.15" + "yjs": "^14.0.0-0" }, "devDependencies": { "@types/emoji-mart": "^3.0.14", diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index cd8f46505..6af37ec18 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -1017,6 +1017,17 @@ export class BlockNoteEditor< // Copy the original document to a new Yjs document Y.applyUpdate(doc, Y.encodeStateAsUpdate(originalFragment.doc!)); + const update = Y.encodeStateAsUpdate(doc); + const blob = new Blob([update], { type: "application/octet-stream" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `${Date.now()}.update`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + // Find the forked fragment in the new Yjs document const forkedFragment = this.findTypeInOtherYdoc(originalFragment, doc); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40aea4d70..6ffca16b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + yjs: ^14.0.0-0 + importers: .: @@ -135,8 +138,8 @@ importers: specifier: ^0.0.25 version: 0.0.25 yjs: - specifier: ^13.6.15 - version: 13.6.24 + specifier: ^14.0.0-0 + version: 14.0.0-4 devDependencies: '@types/node': specifier: ^20 @@ -2400,8 +2403,8 @@ importers: specifier: ^0.0.25 version: 0.0.25 yjs: - specifier: ^13.6.15 - version: 13.6.24 + specifier: ^14.0.0-0 + version: 14.0.0-4 devDependencies: '@types/react': specifier: ^18.0.25 @@ -2441,10 +2444,10 @@ importers: version: 2.23.1(react@18.3.1) '@liveblocks/react-blocknote': specifier: ^2.23.1 - version: 2.23.1(a9fafa167a137f224b16cac05e678ac8) + version: 2.23.1(5ccc4b160c9122137e1878732f35766c) '@liveblocks/react-tiptap': specifier: ^2.23.1 - version: 2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@13.6.24)) + version: 2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@14.0.0-4)) '@liveblocks/react-ui': specifier: ^2.23.1 version: 2.23.1(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -2455,8 +2458,8 @@ importers: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) yjs: - specifier: ^13.6.15 - version: 13.6.24 + specifier: ^14.0.0-0 + version: 14.0.0-4 devDependencies: '@types/react': specifier: ^18.0.25 @@ -2490,7 +2493,7 @@ importers: version: link:../../../packages/shadcn '@y-sweet/react': specifier: ^0.6.3 - version: 0.6.4(react@18.3.1)(yjs@13.6.24) + version: 0.6.4(react@18.3.1)(yjs@14.0.0-4) react: specifier: ^18.3.1 version: 18.3.1 @@ -2533,7 +2536,7 @@ importers: version: 7.17.3(@mantine/hooks@7.17.3(react@18.3.1))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@y-sweet/react': specifier: ^0.6.3 - version: 0.6.4(react@18.3.1)(yjs@13.6.24) + version: 0.6.4(react@18.3.1)(yjs@14.0.0-4) react: specifier: ^18.3.1 version: 18.3.1 @@ -2576,7 +2579,7 @@ importers: version: 7.17.3(@mantine/hooks@7.17.3(react@18.3.1))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@y-sweet/react': specifier: ^0.6.3 - version: 0.6.4(react@18.3.1)(yjs@13.6.24) + version: 0.6.4(react@18.3.1)(yjs@14.0.0-4) react: specifier: ^18.3.1 version: 18.3.1 @@ -2963,14 +2966,14 @@ importers: specifier: ^8.3.2 version: 8.3.2 y-prosemirror: - specifier: ^1.3.4 - version: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24) + specifier: npm:@y/prosemirror@2.0.0-0 + version: '@y/prosemirror@2.0.0-0(@y/protocols@1.0.6-1(yjs@14.0.0-4))(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(yjs@14.0.0-4)' y-protocols: specifier: ^1.0.6 - version: 1.0.6(yjs@13.6.24) + version: 1.0.6(yjs@14.0.0-4) yjs: - specifier: ^13.6.15 - version: 13.6.24 + specifier: ^14.0.0-0 + version: 14.0.0-4 devDependencies: '@types/emoji-mart': specifier: ^3.0.14 @@ -3213,13 +3216,13 @@ importers: version: 18.3.1(react@18.3.1) y-prosemirror: specifier: ^1.3.4 - version: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24) + version: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4) y-protocols: specifier: ^1.0.6 - version: 1.0.6(yjs@13.6.24) + version: 1.0.6(yjs@14.0.0-4) yjs: - specifier: ^13.6.15 - version: 13.6.24 + specifier: ^14.0.0-0 + version: 14.0.0-4 devDependencies: '@types/jsdom': specifier: ^21.1.7 @@ -3672,10 +3675,10 @@ importers: version: 2.23.1(react@18.3.1) '@liveblocks/react-blocknote': specifier: ^2.23.1 - version: 2.23.1(a9fafa167a137f224b16cac05e678ac8) + version: 2.23.1(5ccc4b160c9122137e1878732f35766c) '@liveblocks/react-tiptap': specifier: ^2.23.1 - version: 2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@13.6.24)) + version: 2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@14.0.0-4)) '@liveblocks/react-ui': specifier: ^2.23.1 version: 2.23.1(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3723,7 +3726,7 @@ importers: version: 3.6.8(@uppy/core@3.13.1) '@y-sweet/react': specifier: ^0.6.3 - version: 0.6.4(react@18.3.1)(yjs@13.6.24) + version: 0.6.4(react@18.3.1)(yjs@14.0.0-4) autoprefixer: specifier: 10.4.21 version: 10.4.21(postcss@8.5.3) @@ -3746,8 +3749,8 @@ importers: specifier: ^0.0.25 version: 0.0.25 yjs: - specifier: ^13.6.15 - version: 13.6.24 + specifier: ^14.0.0-0 + version: 14.0.0-4 devDependencies: '@types/react': specifier: ^18.0.25 @@ -5559,7 +5562,7 @@ packages: '@liveblocks/yjs@2.23.1': resolution: {integrity: sha512-fGSWQ+SD7b0B/aY5rcqunH5MAudsxCtf+IXdIW9OR4czOcHLFeB9kJEgg1WcU8erfqevlEcIv3+VMjEn2dAiKA==} peerDependencies: - yjs: ^13.6.1 + yjs: ^14.0.0-0 '@mantine/core@7.17.3': resolution: {integrity: sha512-N/AfV5eMnfEMx9WzI7AU5pNFBEzAfT/KtE2XDKS+0ht6RifUmolIxyIvoGMYz2yUEsCBMJZqmBq33Rabf5W7Ug==} @@ -7827,17 +7830,33 @@ packages: '@y-sweet/client@0.6.4': resolution: {integrity: sha512-dRfnMulK9HJWzm1BnmViZP93FZ/RrXlIN3Uke3f9iIDDDFLPQs5YBDWZ4dc24Hd8/BnX/Xe/uZzDJcAvENx3fw==} peerDependencies: - yjs: ^13.0.0 + yjs: ^14.0.0-0 '@y-sweet/react@0.6.4': resolution: {integrity: sha512-FotyT2MN+wicBl3tHm7CrkJUQu2YFIkOQ7w6DAQTVs6/o+/8kuL7a2svKL15mMAR1TVary1GSCASyRix9VqUCA==} peerDependencies: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - yjs: ^13 + yjs: ^14.0.0-0 '@y-sweet/sdk@0.6.4': resolution: {integrity: sha512-px51qSbckGrucN83BM9jJyaBLLdYFT+zhvsootK+WW9t/9rQSQHQX54gdtF6M1kUktA4jOGfSiAXDzuTY0zYVg==} + '@y/prosemirror@2.0.0-0': + resolution: {integrity: sha512-k3FUjUWJpt+qT94q5HVp/2dxURMpwIIr8Dd3j1F1s5HIZI5oevm30cgoVlS6ys7zwdyAGZzfpL5SnFvTYfH6hw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + '@y/protocols': ^1.0.6-1 + prosemirror-model: ^1.7.1 + prosemirror-state: ^1.2.3 + prosemirror-view: ^1.9.10 + yjs: ^14.0.0-0 + + '@y/protocols@1.0.6-1': + resolution: {integrity: sha512-6hyVR4Azg+JVqeyCkPQMsg9BMpB7fgAldsIDwb5EqJTPLXkQuk/mqK/j0rvIZUuPvJjlYSDBIOQWNsy92iXQsQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^14.0.0-0 + '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -10181,6 +10200,11 @@ packages: engines: {node: '>=16'} hasBin: true + lib0@0.2.105: + resolution: {integrity: sha512-5vtbuBi2P43ZYOfVMV+TZYkWEa0J9kijXirzEgrPA+nJDQCtMx805/rqW4G1nXbM9IRIhwW+OyNNgcQdbhKfSw==} + engines: {node: '>=16'} + hasBin: true + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -12973,7 +12997,7 @@ packages: resolution: {integrity: sha512-9oCFRSPPzBK7/w5vOkJBaVCQZKHXB/v6SIT+WYhnJxlEC61juqG0hBrAf+y3gmSMLFLwICNH9nQ53uscuse6Hg==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} peerDependencies: - yjs: ^13.0.0 + yjs: ^14.0.0-0 y-partykit@0.0.25: resolution: {integrity: sha512-/EIL73TuYX6lYnxM4mb/kTTKllS1vNjBXk9KJXFwTXFrUqMo8hbJMqnE+glvBG2EDejEI06rk3jR50lpDB8Dqg==} @@ -12986,13 +13010,13 @@ packages: prosemirror-state: ^1.2.3 prosemirror-view: ^1.9.10 y-protocols: ^1.0.1 - yjs: ^13.5.38 + yjs: ^14.0.0-0 y-protocols@1.0.6: resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} peerDependencies: - yjs: ^13.0.0 + yjs: ^14.0.0-0 y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} @@ -13028,6 +13052,10 @@ packages: resolution: {integrity: sha512-xn/pYLTZa3uD1uDG8lpxfLRo5SR/rp0frdASOl2a71aYNvUXdWcLtVL91s2y7j+Q8ppmjZ9H3jsGVgoFMbT2VA==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} + yjs@14.0.0-4: + resolution: {integrity: sha512-HD0uhG537bS3Gy8DNoXy/DWdxMAAaJ+30myQ+jTSTtiJ7LfUflicgx6RweYQ4qjho1gSq9/s8v3ydt13Sip+YQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -15005,16 +15033,16 @@ snapshots: '@liveblocks/core@2.23.1': {} - '@liveblocks/react-blocknote@2.23.1(a9fafa167a137f224b16cac05e678ac8)': + '@liveblocks/react-blocknote@2.23.1(5ccc4b160c9122137e1878732f35766c)': dependencies: '@blocknote/core': link:packages/core '@blocknote/react': link:packages/react '@liveblocks/client': 2.23.1 '@liveblocks/core': 2.23.1 '@liveblocks/react': 2.23.1(react@18.3.1) - '@liveblocks/react-tiptap': 2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@13.6.24)) + '@liveblocks/react-tiptap': 2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@14.0.0-4)) '@liveblocks/react-ui': 2.23.1(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@liveblocks/yjs': 2.23.1(yjs@13.6.24) + '@liveblocks/yjs': 2.23.1(yjs@14.0.0-4) '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -15034,27 +15062,27 @@ snapshots: - y-protocols - yjs - '@liveblocks/react-tiptap@2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@13.6.24))': + '@liveblocks/react-tiptap@2.23.1(@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)))(@tiptap/pm@2.11.5)(@tiptap/react@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@tiptap/suggestion@2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(y-protocols@1.0.6(yjs@14.0.0-4))': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@liveblocks/client': 2.23.1 '@liveblocks/core': 2.23.1 '@liveblocks/react': 2.23.1(react@18.3.1) '@liveblocks/react-ui': 2.23.1(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@liveblocks/yjs': 2.23.1(yjs@13.6.24) + '@liveblocks/yjs': 2.23.1(yjs@14.0.0-4) '@radix-ui/react-select': 2.1.6(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-toggle': 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) - '@tiptap/extension-collaboration': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)) - '@tiptap/extension-collaboration-cursor': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24)) + '@tiptap/extension-collaboration': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)) + '@tiptap/extension-collaboration-cursor': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4)) '@tiptap/pm': 2.11.5 '@tiptap/react': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tiptap/suggestion': 2.11.7(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) cmdk: 1.1.1(@types/react-dom@18.3.5(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - y-prosemirror: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24) - yjs: 13.6.24 + y-prosemirror: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4) + yjs: 14.0.0-4 transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -15091,13 +15119,13 @@ snapshots: '@liveblocks/core': 2.23.1 react: 18.3.1 - '@liveblocks/yjs@2.23.1(yjs@13.6.24)': + '@liveblocks/yjs@2.23.1(yjs@14.0.0-4)': dependencies: '@liveblocks/client': 2.23.1 '@liveblocks/core': 2.23.1 js-base64: 3.7.7 - y-indexeddb: 9.0.12(yjs@13.6.24) - yjs: 13.6.24 + y-indexeddb: 9.0.12(yjs@14.0.0-4) + yjs: 14.0.0-4 '@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@18.3.1))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -16989,16 +17017,16 @@ snapshots: dependencies: '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) - '@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24))': + '@tiptap/extension-collaboration-cursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4))': dependencies: '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) - y-prosemirror: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24) + y-prosemirror: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4) - '@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24))': + '@tiptap/extension-collaboration@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4))': dependencies: '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) '@tiptap/pm': 2.11.5 - y-prosemirror: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24) + y-prosemirror: 1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4) '@tiptap/extension-floating-menu@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)': dependencies: @@ -17774,24 +17802,38 @@ snapshots: '@xtuc/long@4.2.2': {} - '@y-sweet/client@0.6.4(yjs@13.6.24)': + '@y-sweet/client@0.6.4(yjs@14.0.0-4)': dependencies: '@y-sweet/sdk': 0.6.4 - y-protocols: 1.0.6(yjs@13.6.24) - yjs: 13.6.24 + y-protocols: 1.0.6(yjs@14.0.0-4) + yjs: 14.0.0-4 - '@y-sweet/react@0.6.4(react@18.3.1)(yjs@13.6.24)': + '@y-sweet/react@0.6.4(react@18.3.1)(yjs@14.0.0-4)': dependencies: - '@y-sweet/client': 0.6.4(yjs@13.6.24) + '@y-sweet/client': 0.6.4(yjs@14.0.0-4) '@y-sweet/sdk': 0.6.4 react: 18.3.1 - y-protocols: 1.0.6(yjs@13.6.24) - yjs: 13.6.24 + y-protocols: 1.0.6(yjs@14.0.0-4) + yjs: 14.0.0-4 '@y-sweet/sdk@0.6.4': dependencies: '@types/node': 20.17.28 + '@y/prosemirror@2.0.0-0(@y/protocols@1.0.6-1(yjs@14.0.0-4))(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(yjs@14.0.0-4)': + dependencies: + '@y/protocols': 1.0.6-1(yjs@14.0.0-4) + lib0: 0.2.101 + prosemirror-model: 1.25.0 + prosemirror-state: 1.4.3 + prosemirror-view: 1.38.1 + yjs: 14.0.0-4 + + '@y/protocols@1.0.6-1(yjs@14.0.0-4)': + dependencies: + lib0: 0.2.101 + yjs: 14.0.0-4 + '@yarnpkg/lockfile@1.1.0': {} '@yarnpkg/parsers@3.0.2': @@ -20586,6 +20628,10 @@ snapshots: dependencies: isomorphic.js: 0.2.5 + lib0@0.2.105: + dependencies: + isomorphic.js: 0.2.5 + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -24287,33 +24333,38 @@ snapshots: xtend@4.0.2: {} - y-indexeddb@9.0.12(yjs@13.6.24): + y-indexeddb@9.0.12(yjs@14.0.0-4): dependencies: lib0: 0.2.101 - yjs: 13.6.24 + yjs: 14.0.0-4 y-partykit@0.0.25: dependencies: lib0: 0.2.101 lodash.debounce: 4.0.8 react: 18.3.1 - y-protocols: 1.0.6(yjs@13.6.24) - yjs: 13.6.24 + y-protocols: 1.0.6(yjs@14.0.0-4) + yjs: 14.0.0-4 - y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@13.6.24))(yjs@13.6.24): + y-prosemirror@1.3.4(prosemirror-model@1.25.0)(prosemirror-state@1.4.3)(prosemirror-view@1.38.1)(y-protocols@1.0.6(yjs@14.0.0-4))(yjs@14.0.0-4): dependencies: lib0: 0.2.101 prosemirror-model: 1.25.0 prosemirror-state: 1.4.3 prosemirror-view: 1.38.1 - y-protocols: 1.0.6(yjs@13.6.24) - yjs: 13.6.24 + y-protocols: 1.0.6(yjs@14.0.0-4) + yjs: 14.0.0-4 y-protocols@1.0.6(yjs@13.6.24): dependencies: lib0: 0.2.101 yjs: 13.6.24 + y-protocols@1.0.6(yjs@14.0.0-4): + dependencies: + lib0: 0.2.101 + yjs: 14.0.0-4 + y18n@5.0.8: {} yallist@2.1.2: {} @@ -24343,6 +24394,10 @@ snapshots: dependencies: lib0: 0.2.101 + yjs@14.0.0-4: + dependencies: + lib0: 0.2.105 + yocto-queue@0.1.0: {} yoga-layout@3.2.1: {}