Skip to content

Conversation

@nperez0111
Copy link
Contributor

@nperez0111 nperez0111 commented Nov 4, 2025

Summary

This is because of a bug that we've had for a while, but I was never able to trace down.

Rationale

  • We set an initial block id for the initial content (always "initialBlockId" when collaboration is detected)
  • y-sync replaces the document with what it "sees" in the Y.XmlFragment we gave it
    • This causes a transaction to replace the initial content (replacing it with an empty document with a blockContainer containing an id of null when using schema.doc.createAndFill())
    • The unique id plugin sees this & attempts to correct the missing id, issuing a new transaction
    • This means there is now a write to the Y.XmlFragment\

This write can happen independently to the provider actually synchronizing the content.
Meaning, that the Y.XmlFragment and tr.doc are out of sync when y-prosemirror attempts to restore the selection.

This is ultimately because y-prosemirror is listening to the Y.Doc after it already is accepting the change. Which is totally valid, but ProseMirror doesn't offer a great way to keep these values in-sync.

Changes

The fix here is stop the unique ID appended transaction from even having to amend the id being null, but monkey patching schema.doc.createAndFill to create a doc node which has a valid id (set arbitrarily to initialBlockId).

Impact

This reinstates a bug fix that we had prior to the migration of Tiptap V3, in Tiptap V3 isEmpty takes a different code path, so it is not needed for that check any longer. This allows us to have a perfectly valid document when initialized from an empty Y.XmlFragment immediately.

Testing

I've manually verified that there is no longer a race condition where the selection fails to be restored because the document is smaller than the position it chose to restore to.

Screenshots/Video

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature

Additional Notes

@vercel
Copy link

vercel bot commented Nov 4, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
blocknote Ready Ready Preview Nov 5, 2025 0:20am
blocknote-website Ready Ready Preview Nov 5, 2025 0:20am

This is because of a bug that we've had for a while, but I was never able to trace down.

- We set an initial block id for the initial content (always "initialBlockId" when collaboration is detected)
- `y-sync` replaces the document with what it "sees" in the `Y.XmlFragment` we gave it
	- This causes a transaction to replace the initial content (replacing it with an empty document with a `blockContainer` containing an id of `null`)
	- The unique id plugin sees this & attempts to correct the missing id, issuing a new transaction
	- This means there is now a write to the `Y.XmlFragment`\

This write can happen independently to the provider actually synchronizing the content.
Meaning, that the `Y.XmlFragment` and `tr.doc` are out of sync when `y-prosemirror` attempts to [restore the selection](https://github.com/yjs/y-prosemirror/blob/ef35266d660c3cd76a491fde243b0c6bee25d585/src/plugins/sync-plugin.js#L634).

This is ultimately because `y-prosemirror` is listening to the Y.Doc _after_ it already is accepting the change. Which is totally valid, but ProseMirror doesn't offer a great way to keep these values in-sync.

The fix here is to just stop the unique-id extension from attempting to amend any `y-prosemirror` transactions. Ultimately, the remote editor should have already written the correct ID (since to the remote editor, it was the local editor - therefore, the unique-id extension should have run).
@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 5, 2025

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/ariakit@2153

@blocknote/code-block

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/code-block@2153

@blocknote/core

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/core@2153

@blocknote/mantine

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/mantine@2153

@blocknote/react

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/react@2153

@blocknote/server-util

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/server-util@2153

@blocknote/shadcn

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/shadcn@2153

@blocknote/xl-ai

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-ai@2153

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-docx-exporter@2153

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-email-exporter@2153

@blocknote/xl-multi-column

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-multi-column@2153

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-odt-exporter@2153

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/TypeCellOS/BlockNote/@blocknote/xl-pdf-exporter@2153

commit: 6ce83dd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants