fix(nodeview): ensure NodeView re-renders on position changes without…#7566
fix(nodeview): ensure NodeView re-renders on position changes without…#7566
Conversation
✅ Deploy Preview for tiptap-embed ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
🦋 Changeset detectedLatest commit: ba1ed8b 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 |
There was a problem hiding this comment.
Pull request overview
Fixes NodeView renderer behavior across React/Vue so NodeViews can re-render when their document position changes without a corresponding node/decorations reference change (e.g., sibling reordering), and updates the DragHandle demo to make verification easier.
Changes:
- Track per-NodeView
currentPosand listen toeditor.on('update')to rAF-batch position checks and force a re-render whengetPos()changes. - Update the
update()fast-path to keepcurrentPosin sync (and attempt to re-render on position-only changes). - Update the DragHandleWithNodeViews React demo to render multiple recommendation nodes and display each NodeView’s
pos.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/vue-3/src/VueNodeViewRenderer.ts | Adds currentPos tracking + editor update listener to trigger rerenders on position shifts. |
| packages/vue-2/src/VueNodeViewRenderer.ts | Same as Vue 3, adapted to Vue 2 renderer behavior. |
| packages/react/src/ReactNodeViewRenderer.tsx | Same as Vue versions, with React memo/shallow-compare considerations. |
| demos/src/Extensions/DragHandleWithNodeViews/React/index.jsx | Demo content updated to multiple nodes and clearer instructions. |
| demos/src/Extensions/DragHandleWithNodeViews/React/extensions/recommendation/views/RecommendationView.jsx | Displays pos via getPos() to validate rerendering. |
| .changeset/fix-nodeview-position-updates.md | Adds patch changeset for @tiptap/react, @tiptap/vue-2, @tiptap/vue-3. |
@tiptap/extension-character-count
@tiptap/extension-dropcursor
@tiptap/extension-history
@tiptap/extension-focus
@tiptap/extension-gapcursor
@tiptap/extension-placeholder
@tiptap/extension-list-item
@tiptap/extension-list-keymap
@tiptap/extension-table-header
@tiptap/extension-table-cell
@tiptap/extension-table-row
@tiptap/extension-task-list
@tiptap/extension-task-item
@tiptap/core
@tiptap/extension-audio
@tiptap/extension-blockquote
@tiptap/extension-bold
@tiptap/extension-bubble-menu
@tiptap/extension-bullet-list
@tiptap/extension-code-block
@tiptap/extension-code
@tiptap/extension-code-block-lowlight
@tiptap/extension-collaboration
@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-emoji
@tiptap/extension-file-handler
@tiptap/extension-floating-menu
@tiptap/extension-font-family
@tiptap/extension-hard-break
@tiptap/extension-highlight
@tiptap/extension-heading
@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-node-range
@tiptap/extension-ordered-list
@tiptap/extension-paragraph
@tiptap/extension-subscript
@tiptap/extension-strike
@tiptap/extension-superscript
@tiptap/extension-table
@tiptap/extension-table-of-contents
@tiptap/extension-text
@tiptap/extension-text-align
@tiptap/extension-text-style
@tiptap/extension-twitch
@tiptap/extension-typography
@tiptap/extension-unique-id
@tiptap/extension-underline
@tiptap/extension-youtube
@tiptap/extensions
@tiptap/html
@tiptap/markdown
@tiptap/react
@tiptap/starter-kit
@tiptap/pm
@tiptap/static-renderer
@tiptap/suggestion
@tiptap/vue-2
@tiptap/vue-3
commit: |
…rop functionality
• Detect position-only document moves and force NodeView re-renders by tracking node positions and passing fresh getPos references to renderers. • Centralize per-editor position-check registry in @tiptap/core (nodeViewPositionRegistry) to avoid per-NodeView listeners and duplicate rAFs. • Update React, Vue 3 and Vue 2 NodeView renderers to use the shared registry and guard against renderer-init races. • Inline Vue demo styles and use optional chaining for editor teardown in the Vue demo. This is a bugfix (patch): fixes cases where NodeViews wouldn’t update when their position changed within a parent node.,
…itionUpdateRegistries
…/tiptap into fix/nodeview-position-updates
Changes Overview
Implementation Approach
currentPostracking and aneditor.on('update')listener that:getPos()tocurrentPos,renderer.updateProps({ getPos: () => this.getPos() })(fresh function ref to bypass memo/shallow-equality).update()early-return optimization but updated it to also updatecurrentPossohandleEditorUpdateis cheap when ProseMirror already handled the node.posand give eachRecommendationnode a uniquedata-idand start with five nodes to make verification easy.updateoption path unchanged.Testing Done
pos:.posand the sibling nodes’ displayedposimmediately (validated interactively).Verification Steps
pnpm dev # open http://localhost:3000 -> Extensions -> DragHandleWithNodeViewspos:updates immediately.pos:immediately (no need to edit/focus them).pnpm lint pnpm build pnpm test:run # optional; runs existing Cypress testsAdditional Notes
selectionUpdatepattern. For documents with very large numbers of NodeViews this is O(N) per frame in the worst case; batching keeps it practical for normal use.updatecallbacks are unaffected (the customupdatepath runs