Skip to content

Commit d2a600c

Browse files
authored
fix(unique-id): do not attempt to append to y-sync plugin transactions (#2153)
1 parent 49af3da commit d2a600c

File tree

6 files changed

+90
-6
lines changed

6 files changed

+90
-6
lines changed

packages/core/src/editor/BlockNoteEditor.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
} from "../api/getBlockInfoFromPos.js";
66
import { BlockNoteEditor } from "./BlockNoteEditor.js";
77
import { BlockNoteExtension } from "./BlockNoteExtension.js";
8+
import * as Y from "yjs";
89

910
/**
1011
* @vitest-environment jsdom
@@ -146,3 +147,67 @@ it("onCreate event", () => {
146147
});
147148
expect(created).toBe(true);
148149
});
150+
151+
it("sets an initial block id when using Y.js", async () => {
152+
const doc = new Y.Doc();
153+
const fragment = doc.getXmlFragment("doc");
154+
let transactionCount = 0;
155+
const editor = BlockNoteEditor.create({
156+
collaboration: {
157+
fragment,
158+
user: { name: "Hello", color: "#FFFFFF" },
159+
provider: null,
160+
},
161+
_tiptapOptions: {
162+
onTransaction: () => {
163+
transactionCount++;
164+
},
165+
},
166+
});
167+
168+
editor.mount(document.createElement("div"));
169+
170+
expect(editor.prosemirrorState.doc.toJSON()).toMatchInlineSnapshot(`
171+
{
172+
"content": [
173+
{
174+
"content": [
175+
{
176+
"attrs": {
177+
"id": "initialBlockId",
178+
},
179+
"content": [
180+
{
181+
"attrs": {
182+
"backgroundColor": "default",
183+
"textAlignment": "left",
184+
"textColor": "default",
185+
},
186+
"type": "paragraph",
187+
},
188+
],
189+
"type": "blockContainer",
190+
},
191+
],
192+
"type": "blockGroup",
193+
},
194+
],
195+
"type": "doc",
196+
}
197+
`);
198+
expect(transactionCount).toBe(1);
199+
// The fragment should not be modified yet, since the editor's content is only the initial content
200+
expect(fragment.toJSON()).toMatchInlineSnapshot(`""`);
201+
202+
editor.replaceBlocks(editor.document, [
203+
{
204+
type: "paragraph",
205+
content: [{ text: "Hello", styles: {}, type: "text" }],
206+
},
207+
]);
208+
expect(transactionCount).toBe(2);
209+
// Only after a real modification is made, will the fragment be updated
210+
expect(fragment.toJSON()).toMatchInlineSnapshot(
211+
`"<blockgroup><blockcontainer id="0"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello</paragraph></blockcontainer><blockcontainer id="1"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>"`,
212+
);
213+
});

packages/core/src/editor/BlockNoteEditor.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,25 @@ export class BlockNoteEditor<
917917
);
918918
}
919919

920+
// When y-prosemirror creates an empty document, the `blockContainer` node is created with an `id` of `null`.
921+
// This causes the unique id extension to generate a new id for the initial block, which is not what we want
922+
// Since it will be randomly generated & cause there to be more updates to the ydoc
923+
// This is a hack to make it so that anytime `schema.doc.createAndFill` is called, the initial block id is already set to "initialBlockId"
924+
let cache: Node | undefined = undefined;
925+
const oldCreateAndFill = this.pmSchema.nodes.doc.createAndFill;
926+
this.pmSchema.nodes.doc.createAndFill = (...args: any) => {
927+
if (cache) {
928+
return cache;
929+
}
930+
const ret = oldCreateAndFill.apply(this.pmSchema.nodes.doc, args)!;
931+
932+
// create a copy that we can mutate (otherwise, assigning attrs is not safe and corrupts the pm state)
933+
const jsonNode = JSON.parse(JSON.stringify(ret.toJSON()));
934+
jsonNode.content[0].content[0].attrs.id = "initialBlockId";
935+
936+
cache = Node.fromJSON(this.pmSchema, jsonNode);
937+
return cache;
938+
};
920939
this.pmSchema.cached.blockNoteEditor = this;
921940

922941
// Initialize managers

packages/core/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"type": "text",
99
},
1010
],
11-
"id": "3",
11+
"id": "2",
1212
"props": {
1313
"backgroundColor": "default",
1414
"textAlignment": "left",
@@ -19,7 +19,7 @@
1919
{
2020
"children": [],
2121
"content": [],
22-
"id": "4",
22+
"id": "3",
2323
"props": {
2424
"backgroundColor": "default",
2525
"textAlignment": "left",

packages/core/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"type": "text",
99
},
1010
],
11-
"id": "1",
11+
"id": "0",
1212
"props": {
1313
"backgroundColor": "default",
1414
"textAlignment": "left",
@@ -19,7 +19,7 @@
1919
{
2020
"children": [],
2121
"content": [],
22-
"id": "2",
22+
"id": "1",
2323
"props": {
2424
"backgroundColor": "default",
2525
"textAlignment": "left",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<blockgroup><blockcontainer id="3"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello World</paragraph></blockcontainer><blockcontainer id="4"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>
1+
<blockgroup><blockcontainer id="2"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello World</paragraph></blockcontainer><blockcontainer id="3"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<blockgroup><blockcontainer id="1"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello</paragraph></blockcontainer><blockcontainer id="2"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>
1+
<blockgroup><blockcontainer id="0"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello</paragraph></blockcontainer><blockcontainer id="1"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>

0 commit comments

Comments
 (0)