Skip to content

fix: prevent intermittent image duplication during internal drag-and-drop#2350

Draft
christianhg wants to merge 1 commit intomainfrom
fix/dnd-image-duplication
Draft

fix: prevent intermittent image duplication during internal drag-and-drop#2350
christianhg wants to merge 1 commit intomainfrom
fix/dnd-image-duplication

Conversation

@christianhg
Copy link
Member

Problem

Clients report intermittent block duplication when drag-and-dropping images internally.

Root Cause

A race condition between two drop event handlers:

  1. React onDrop on the editor element — reads internalDrag from the actor context to determine dragOrigin, then sends the drag.drop behavior event
  2. Window drop listener on document — sends {type: 'drop'} to the actor, which transitions the machine from dragging internallyidle and clears internalDrag

If the window listener fires before React's onDrop reads internalDrag, dragOrigin is undefined. This causes the fallback drag.drop behavior to fire (the one for external drops), which deserializes and inserts the block without deleting the original — resulting in duplication.

Fix

  • Remove the window-level drop listener
  • Send {type: 'drop'} from handleDrop after the behavior event, ensuring internalDrag is always available when the behavior event is processed

The window-level dragend listener is kept — it's needed for drags that end outside the editor (e.g., user drags a block and drops it on the desktop).

@vercel
Copy link

vercel bot commented Mar 11, 2026

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

Project Deployment Actions Updated (UTC)
portable-text-editor-documentation Ready Ready Preview, Comment Mar 11, 2026 6:37pm
portable-text-example-basic Ready Ready Preview, Comment Mar 11, 2026 6:37pm
portable-text-playground Ready Ready Preview, Comment Mar 11, 2026 6:37pm

Request Review

@github-actions
Copy link
Contributor

github-actions bot commented Mar 11, 2026

📦 Bundle Stats — @portabletext/editor

Compared against main (d58ddc7b)

@portabletext/editor

Metric Value vs main (d58ddc7)
Internal (raw) 779.1 KB -145 B, -0.0%
Internal (gzip) 145.2 KB -22 B, -0.0%
Bundled (raw) 1.39 MB -145 B, -0.0%
Bundled (gzip) 308.1 KB -22 B, -0.0%
Import time 92ms -2ms, -2.2%

@portabletext/editor/behaviors

Metric Value vs main (d58ddc7)
Internal (raw) 467 B -
Internal (gzip) 207 B -
Bundled (raw) 424 B -
Bundled (gzip) 171 B -
Import time 6ms -0ms, -5.2%

@portabletext/editor/plugins

Metric Value vs main (d58ddc7)
Internal (raw) 2.5 KB -
Internal (gzip) 910 B -
Bundled (raw) 2.3 KB -
Bundled (gzip) 839 B -
Import time 11ms -0ms, -2.8%

@portabletext/editor/selectors

Metric Value vs main (d58ddc7)
Internal (raw) 60.2 KB -
Internal (gzip) 9.4 KB -
Bundled (raw) 56.7 KB -
Bundled (gzip) 8.6 KB -
Import time 10ms -0ms, -2.7%

@portabletext/editor/utils

Metric Value vs main (d58ddc7)
Internal (raw) 24.2 KB -
Internal (gzip) 4.7 KB -
Bundled (raw) 22.2 KB -
Bundled (gzip) 4.4 KB -
Import time 9ms -0ms, -3.2%
Details
  • Import time regressions over 10% are flagged with ⚠️
  • Treemap artifacts are attached to the CI run for detailed size analysis
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

@changeset-bot
Copy link

changeset-bot bot commented Mar 11, 2026

🦋 Changeset detected

Latest commit: 05698a4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@portabletext/editor Patch
@portabletext/plugin-character-pair-decorator Patch
@portabletext/plugin-emoji-picker Patch
@portabletext/plugin-input-rule Patch
@portabletext/plugin-markdown-shortcuts Patch
@portabletext/plugin-one-line Patch
@portabletext/plugin-paste-link Patch
@portabletext/plugin-sdk-value Patch
@portabletext/plugin-typeahead-picker Patch
@portabletext/plugin-typography Patch
@portabletext/toolbar Patch

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

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.

1 participant