Fix BubbleMenu and FloatingMenu not supporting option updates after initialization#7445
Fix BubbleMenu and FloatingMenu not supporting option updates after initialization#7445
Conversation
The BubbleMenu component now properly updates when props change after the initial render. Previously, options like scrollTarget were only applied during plugin construction and never updated afterward. Changes: - Add updateOptions method to BubbleMenuView class that handles dynamic option updates including scrollTarget listener management - Extend transaction handler to support 'updateOptions' metadata - Add useEffect in React component to dispatch option updates when props change, avoiding full plugin re-registration This allows users to dynamically pass configuration options retrieved via useEffect (e.g., scrollTarget from a DOM ref) without needing workarounds like conditional rendering. https://claude.ai/code/session_01RbvqtygmL8dKaCCSHPPUdS
Apply the same fix from BubbleMenu to FloatingMenu for consistency. Previously, FloatingMenu would re-register the entire plugin when props changed. Now it uses the same updateOptions transaction pattern. https://claude.ai/code/session_01RbvqtygmL8dKaCCSHPPUdS
🦋 Changeset detectedLatest commit: 91f38be The changes in this PR will be included in the next version bump. This PR includes changesets to release 72 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
✅ Deploy Preview for tiptap-embed ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR ensures that React BubbleMenu and FloatingMenu components correctly react to prop changes after initialization, particularly for Floating UI options like scrollTarget, without repeatedly re-registering ProseMirror plugins.
Changes:
- Refactors React
BubbleMenuandFloatingMenuto register their plugins once per editor instance, tracking props via refs and dispatchingupdateOptionsplugin metadata when React props change. - Adds
updateOptionshandling toBubbleMenuViewandFloatingMenuView, including dynamic scroll listener management whenoptions.scrollTargetchanges. - Documents the behavior change in a new changeset, issuing patch bumps for
@tiptap/extension-bubble-menu,@tiptap/extension-floating-menu, and@tiptap/react.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react/src/menus/FloatingMenu.tsx | Registers the floating menu plugin once per editor, tracks plugin options in a ref, and dispatches 'floatingMenu' / type: 'updateOptions' transactions when React props change. |
| packages/react/src/menus/BubbleMenu.tsx | Mirrors the floating menu ref/effect pattern for the bubble menu, including getReferencedVirtualElement, and dispatches 'bubbleMenu' / type: 'updateOptions' transactions. |
| packages/extension-floating-menu/src/floating-menu-plugin.ts | Extends FloatingMenuView to handle updateOptions meta, updating delays, appendTo, shouldShow, and options (including scroll listener migration on scrollTarget change). |
| packages/extension-bubble-menu/src/bubble-menu-plugin.ts | Extends BubbleMenuView similarly with an updateOptions method and transaction handler, updating relevant fields and moving the scroll listener when options.scrollTarget changes. |
| .changeset/fix-bubble-menu-props-update.md | Adds a changeset describing the fix so that the affected packages get patch releases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@tiptap/extension-character-count
@tiptap/extension-dropcursor
@tiptap/extension-gapcursor
@tiptap/extension-focus
@tiptap/extension-history
@tiptap/extension-list-keymap
@tiptap/extension-list-item
@tiptap/extension-placeholder
@tiptap/extension-table-cell
@tiptap/extension-table-header
@tiptap/extension-table-row
@tiptap/extension-task-item
@tiptap/extension-task-list
@tiptap/core
@tiptap/extension-audio
@tiptap/extension-blockquote
@tiptap/extension-bold
@tiptap/extension-bubble-menu
@tiptap/extension-bullet-list
@tiptap/extension-code
@tiptap/extension-collaboration
@tiptap/extension-code-block-lowlight
@tiptap/extension-code-block
@tiptap/extension-color
@tiptap/extension-collaboration-caret
@tiptap/extension-details
@tiptap/extension-document
@tiptap/extension-drag-handle
@tiptap/extension-drag-handle-react
@tiptap/extension-drag-handle-vue-2
@tiptap/extension-drag-handle-vue-3
@tiptap/extension-file-handler
@tiptap/extension-emoji
@tiptap/extension-floating-menu
@tiptap/extension-font-family
@tiptap/extension-heading
@tiptap/extension-hard-break
@tiptap/extension-highlight
@tiptap/extension-horizontal-rule
@tiptap/extension-image
@tiptap/extension-invisible-characters
@tiptap/extension-italic
@tiptap/extension-link
@tiptap/extension-list
@tiptap/extension-mathematics
@tiptap/extension-mention
@tiptap/extension-ordered-list
@tiptap/extension-node-range
@tiptap/extension-paragraph
@tiptap/extension-subscript
@tiptap/extension-strike
@tiptap/extension-table-of-contents
@tiptap/extension-table
@tiptap/extension-superscript
@tiptap/extension-text
@tiptap/extension-text-align
@tiptap/extension-text-style
@tiptap/extension-typography
@tiptap/extension-twitch
@tiptap/extension-underline
@tiptap/extension-unique-id
@tiptap/extension-youtube
@tiptap/extensions
@tiptap/markdown
@tiptap/html
@tiptap/react
@tiptap/starter-kit
@tiptap/pm
@tiptap/static-renderer
@tiptap/suggestion
@tiptap/vue-2
@tiptap/vue-3
commit: |
Address Copilot review feedback: the previous implementation only updated scrollTarget when a new value was explicitly defined, preventing users from resetting it back to the default window behavior. Now when options.scrollTarget is undefined/null, it correctly defaults to window, allowing proper reset of the scroll listener. https://claude.ai/code/session_01RbvqtygmL8dKaCCSHPPUdS
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Changes Overview
Fixes the BubbleMenu and FloatingMenu components to properly update when props change after initial render. Previously, options like
scrollTargetpassed viauseEffectwere never applied because the plugins were only configured during construction.Implementation Approach
Instead of re-registering the entire plugin when props change (which caused regressions in previous attempts), this PR:
updateOptionsmethod to bothBubbleMenuViewandFloatingMenuView- Handles dynamic option updates including proper scroll listener management whenscrollTargetchangesupdateOptionsmetadata type alongside existingupdatePositionThis approach keeps both menus consistent and avoids the performance issues that caused the previous fix to be reverted.
Testing Done
Verification Steps
scrollTargetpassed viauseEffect:shouldShow,updateDelay, etc. updates the plugin without re-registrationAdditional Notes
Regarding non-memoized props: This implementation dispatches update transactions when props change (by reference). Unlike the previous reverted fix, this does NOT re-register the plugin - it only calls
updateOptions. For optimal performance, users should memoize function/object props, but non-memoized props will not cause the severe regression seen before (nounregisterPlugin/registerPlugincycle).Bonus improvement for FloatingMenu: Previously, FloatingMenu re-registered the entire plugin on any prop change. This PR also fixes that behavior to match the new BubbleMenu pattern.
Checklist
Related Issues
Fixes #6963