Repository navigation
Conversation
`replaceExtension` (behind `registerExtension`) collected ProseMirror plugins only from the instances `addExtension` returned. `addExtension` also registers the extensions declared in `blockNoteExtensions`, but it returns just the parent, so their plugins were never installed. `CollaborationExtension` keeps all of its plugins (YSync, YCursor, YUndo, ...) in sub-extensions, so registering it on an existing editor installed nothing and edits never reached the Y.XmlFragment. Collect every extension added in the call and order them by the same dependency priority used when the editor is created. The order matters: y-prosemirror's cursor plugin reads the sync plugin's state in `init`, so registration throws if YCursor ends up before YSync. Closes TypeCellOS#3175
|
@adarshsm is attempting to deploy a commit to the TypeCell Team on Vercel. A member of the Team first needs to authorize it. |
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/diagram-block
@blocknote/mantine
@blocknote/math-block
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-email-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
@blocknote/xl-typst-exporter
commit: |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #3175.
editor.registerExtension(CollaborationExtension(...))on an editor that already exists installed no Yjs plugins, so local edits never reached theY.XmlFragment. This fixes runtime registration (registerExtension/replaceExtension) to install the plugins of the sub-extensions an extension declares inblockNoteExtensions.Rationale
replaceExtensionbuiltpluginsToAddfrom the return values ofaddExtension.addExtensionregisters the parent and then recursively registers itsblockNoteExtensionsintothis.extensions, but it returns only the parent. So the sub-extensions were recorded as registered while their ProseMirror plugins were never installed.CollaborationExtensionhas no plugins of its own. YSync, YCursor, YUndo, ForkYDoc and the others all come fromblockNoteExtensions, so registering it at runtime installed nothing. When the extension is passed toBlockNoteEditor.createit works, becausegetTiptapExtensionswalks all ofthis.extensions.Changes
replaceExtensionnow collects every extension the call added (the parent plus its sub-extensions) by diffingthis.extensionsbefore and after the add phase.getTiptapExtensionsuses, so sub-extensions come before their parent andrunsBeforeis respected, just as at editor creation. The priority computation moved into a small privategetExtensionPriority()that both paths share.The ordering is required. y-prosemirror's cursor plugin reads the sync plugin's state in its
init. Collecting the sub-extensions in declaration order (YCursor is declared before YSync) makesregisterExtensionthrow fromcursor-plugin.jsinit. With the priority order, the plugins go in asy-sync,yjs-cursor,y-undo, the same order as at editor creation.Impact
blockNoteExtensions, such as the onesForkYDocpasses toreplaceExtension, the set of plugins added is the same as before. They're now sorted by priority, with ties kept in the given order sinceArray.prototype.sortis stable. That's the order they'd get at editor creation.Testing
ExtensionManager.test.tsgets a new runtime-registration test. A parent with a plugin-bearing sub-extension is registered viaeditor.registerExtension, and the test asserts that the sub's plugin is installed and comes before the parent's.yjs/extensions/index.test.ts. It creates an editor without collaboration, registersCollaborationExtension(with an awareness provider, so the cursor plugin is included), edits, and asserts the fragment contains the edit.main(expected -1 not to be -1, andexpected '' to contain 'hello') and pass with this change.@blocknote/coresuite: 885 passed, 9 skipped.vp lintandvp fmt --checkare clean on the touched files.Checklist
Additional Notes
This PR doesn't change one related gap: extensions registered at runtime never get their
mount()called, because mounting only happens in theeditor.onMounthandler. For collaboration this only affects YCursor's "show the label on activity" listener. Cursors and sync work without it, and flat registration (the workaround in the issue) has the same limitation. I can follow up separately if you'd like runtime registration to mount extensions on an already-mounted editor.🤖 Generated with Claude Code