Skip to content

Commit c766956

Browse files
committed
feat: pausing & resuming of a ydoc
1 parent 86df775 commit c766956

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>
@@ -474,7 +483,7 @@ export class BlockNoteEditor<
474483

475484
private readonly showSelectionPlugin: ShowSelectionPlugin;
476485

477-
private readonly cursorPlugin: CursorPlugin;
486+
private cursorPlugin: CursorPlugin;
478487

479488
/**
480489
* 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<
934943
};
935944
}
936945

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

0 commit comments

Comments
 (0)