Skip to content

Commit 3eab6e7

Browse files
committed
feat: pausing & resuming of a ydoc
1 parent 7de3a4b commit 3eab6e7

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

examples/07-collaboration/01-partykit/App.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,21 @@ export default function App() {
3030
});
3131

3232
// Renders the editor instance.
33-
return <BlockNoteView editor={editor} />;
33+
return (
34+
<>
35+
<button
36+
onClick={() => {
37+
editor.pauseYjsSync();
38+
}}>
39+
Pause
40+
</button>
41+
<button
42+
onClick={() => {
43+
editor.resumeYjsSync();
44+
}}>
45+
Play
46+
</button>
47+
<BlockNoteView editor={editor} />
48+
</>
49+
);
3450
}

packages/core/src/editor/BlockNoteEditor.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import {
9393
import { Dictionary } from "../i18n/dictionary.js";
9494
import { en } from "../i18n/locales/index.js";
9595

96+
import { redo, undo } from "@tiptap/pm/history";
9697
import {
9798
TextSelection,
9899
type Command,
@@ -101,8 +102,14 @@ import {
101102
} from "@tiptap/pm/state";
102103
import { dropCursor } from "prosemirror-dropcursor";
103104
import { EditorView } from "prosemirror-view";
104-
import { undoCommand, redoCommand, ySyncPluginKey } from "y-prosemirror";
105-
import { undo, redo } from "@tiptap/pm/history";
105+
import {
106+
redoCommand,
107+
undoCommand,
108+
yCursorPluginKey,
109+
ySyncPlugin,
110+
ySyncPluginKey,
111+
yUndoPluginKey,
112+
} from "y-prosemirror";
106113
import { createInternalHTMLSerializer } from "../api/exporters/html/internalHTMLSerializer.js";
107114
import { inlineContentToNodes } from "../api/nodeConversions/blockToNode.js";
108115
import { nodeToBlock } from "../api/nodeConversions/nodeToBlock.js";
@@ -113,9 +120,11 @@ import {
113120
import { nestedListsToBlockNoteStructure } from "../api/parsers/html/util/nestedLists.js";
114121
import { CodeBlockOptions } from "../blocks/CodeBlockContent/CodeBlockContent.js";
115122
import type { ThreadStore, User } from "../comments/index.js";
123+
import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
116124
import "../style.css";
117125
import { EventEmitter } from "../util/EventEmitter.js";
118-
import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
126+
import { SyncPlugin } from "../extensions/Collaboration/SyncPlugin.js";
127+
import { UndoPlugin } from "../extensions/Collaboration/UndoPlugin.js";
119128

120129
export type BlockNoteExtensionFactory = (
121130
editor: BlockNoteEditor<any, any, any>,
@@ -473,7 +482,7 @@ export class BlockNoteEditor<
473482

474483
private readonly showSelectionPlugin: ShowSelectionPlugin;
475484

476-
private readonly cursorPlugin: CursorPlugin;
485+
private cursorPlugin: CursorPlugin;
477486

478487
/**
479488
* The `uploadFile` method is what the editor uses when files need to be uploaded (for example when selecting an image to upload).
@@ -933,6 +942,46 @@ export class BlockNoteEditor<
933942
};
934943
}
935944

945+
private yjsState:
946+
| {
947+
prevFragment: Y.XmlFragment;
948+
nextFragment: Y.XmlFragment;
949+
}
950+
| undefined;
951+
952+
public pauseYjsSync() {
953+
const prevFragment = this.options.collaboration?.fragment;
954+
955+
if (!prevFragment) {
956+
throw new Error("No Yjs document found");
957+
}
958+
const nextFragment = prevFragment.clone();
959+
const doc = new Y.Doc();
960+
nextFragment._integrate(doc, nextFragment._item!);
961+
962+
this.yjsState = {
963+
prevFragment,
964+
nextFragment,
965+
};
966+
this._tiptapEditor.unregisterPlugin(yCursorPluginKey);
967+
this._tiptapEditor.unregisterPlugin(yUndoPluginKey);
968+
this._tiptapEditor.unregisterPlugin(ySyncPluginKey);
969+
this._tiptapEditor.registerPlugin(ySyncPlugin(nextFragment));
970+
}
971+
972+
public resumeYjsSync() {
973+
if (!this.yjsState) {
974+
throw new Error("No Yjs document found");
975+
}
976+
this._tiptapEditor.unregisterPlugin(ySyncPluginKey);
977+
this._tiptapEditor.registerPlugin(
978+
new SyncPlugin(this.yjsState.prevFragment).plugin
979+
);
980+
this.cursorPlugin = new CursorPlugin(this.options.collaboration!);
981+
this._tiptapEditor.registerPlugin(this.cursorPlugin.plugin);
982+
this._tiptapEditor.registerPlugin(new UndoPlugin().plugin);
983+
}
984+
936985
/**
937986
* @deprecated, use `editor.document` instead
938987
*/

0 commit comments

Comments
 (0)