Skip to content

fix: prevent table row drag from moving an extra adjacent row#2703

Merged
nperez0111 merged 1 commit intoTypeCellOS:mainfrom
LimChaeJune:fix/duplicate_invocation_dragHandle
May 4, 2026
Merged

fix: prevent table row drag from moving an extra adjacent row#2703
nperez0111 merged 1 commit intoTypeCellOS:mainfrom
LimChaeJune:fix/duplicate_invocation_dragHandle

Conversation

@LimChaeJune
Copy link
Copy Markdown
Contributor

@LimChaeJune LimChaeJune commented May 4, 2026

Summary

Fixes a bug where dragging a single table row could move an extra adjacent row when the drop lands outside .bn-block-group (e.g. into the side menu gutter). Closes #2691.

Rationale

SideMenuView.dispatchSyntheticEvent re-dispatches drop events as synthetic so ProseMirror can handle drops that fall outside the editor bounds. Both SideMenuView and TableHandlesView listen for drop on pmView.root. SideMenuView's handlers already guard against the synthetic event, but TableHandlesView.dropHandler does not — so a single user gesture invokes dropHandler twice (once for the synthetic, once for the original). Between the two calls, ProseMirror commits the row move and refreshes state.block, causing the second call to drag the now-shifted neighbor along with the original target.

The fix clears state.draggingState once dropHandler has the values it needs, making the handler idempotent. This avoids leaking knowledge of SideMenuView's synthetic-event convention into TableHandlesView and protects against any future path that re-enters dropHandler for the same gesture.

Changes

  • packages/core/src/extensions/TableHandles/TableHandles.ts: After destructuring draggingState from this.state, clear this.state.draggingState = undefined. The re-dispatched drop now short-circuits at the existing draggingState === undefined early return.
  • tests/src/end-to-end/tables/tables.test.ts: Added a Playwright regression test that drags row 2 of a 5-row table onto the side-menu gutter (blockGroup.x - 50) and asserts the resulting row order.

Impact

  • TableHandles row/column drag: Behavior unchanged for normal in-bounds drops. Out-of-bounds drops (side gutter, below table padding) now move only the dragged row instead of also dragging an adjacent one.
  • dragEnd still sets draggingState = undefined, which is now a no-op after dropHandler ran but stays correct for drag cancellations that never reach dropHandler.

Testing

  • Regression test: New Playwright test drags row 2 of a 5-row table onto the side-menu gutter and asserts the row order is ["R1", "R3", "R4", "R5", "R2"]. Fails without the fix with ["R1", "R4", "R5", "R2", "R3"] (the exact bug pattern from Table row drag moves two rows instead of one due to duplicate dropHandler invocation #2691). Passes on chromium and webkit; firefox is skipped following the existing dragdrop test convention.
  • Manual: Verified the original repro in the BlockNote demo no longer triggers after the fix.

Screenshots/Video

Before
duplicateRows

After
화면 기록 2026-05-04 오후 3 43 22

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

the bug is intermittent in real use because it only triggers when the drop coordinate falls outside .bn-block-group. The regression test pins the drop to the side gutter to make this deterministic.

Summary by CodeRabbit

Bug Fixes

  • Fixed table row drag-and-drop behavior to prevent unintended row movements during drag operations, ensuring only the selected row is repositioned as intended.
  • Added regression test coverage to verify correct row drag behavior and confirm that only the intended row moves during drag operations.

When a row drag is dropped outside `.bn-block-group` (e.g. into the
side menu gutter), `SideMenuView.dispatchSyntheticEvent` re-dispatches
the drop with `synthetic = true` so ProseMirror can handle a coordinate
inside the editor. The synthetic event AND the original drop both bubble
to `pmView.root`, so `TableHandlesView.dropHandler` runs twice for one
user gesture; ProseMirror commits the row move on the first call, and
the second call moves the now-shifted adjacent row.

Make `dropHandler` idempotent by clearing `state.draggingState` once the
move logic has the values it needs. The re-dispatched drop hits the
existing early return for `draggingState === undefined` and no longer
runs the move twice.

Adds a Playwright regression test that drags a row to the side menu
gutter (the user-facing reproduction in issue TypeCellOS#2691) and asserts only
the dragged row moves.

Closes TypeCellOS#2691
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

@LimChaeJune is attempting to deploy a commit to the TypeCell Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a124081-90ca-4dd7-a0c5-cf96e85a5346

📥 Commits

Reviewing files that changed from the base of the PR and between f6717b3 and 4cc161e.

📒 Files selected for processing (2)
  • packages/core/src/extensions/TableHandles/TableHandles.ts
  • tests/src/end-to-end/tables/tables.test.ts

📝 Walkthrough

Walkthrough

The PR fixes a bug where dragging a table row moved two rows instead of one. The dropHandler in TableHandles now clears draggingState early to prevent duplicate invocations from both synthetic and original drop events. A regression test verifies that only the dragged row moves.

Changes

Table Row Drag Fix

Layer / File(s) Summary
State Clearing
packages/core/src/extensions/TableHandles/TableHandles.ts
dropHandler now sets this.state.draggingState = undefined immediately after guard checks, before move logic executes, preventing duplicate handler invocations from re-dispatched synthetic drop events.
Regression Test
tests/src/end-to-end/tables/tables.test.ts
New test "Row drag should move only the dragged row" (Firefox-skipped) replaces the editor with a 5-row × 1-column table, performs a row-handle drag-drop into the side-menu gutter, and asserts via DOM text that only the dragged row is repositioned (["R1", "R3", "R4", "R5", "R2"]).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • nperez0111

Poem

🐰 A row that danced with double boots,
Now settles in its proper spot—
One drag, one place, no phantom moves,
The test confirms what bugs have wrought! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: preventing duplicate row moves during table row drag operations.
Description check ✅ Passed The PR description covers all required template sections with detailed rationale, changes, impact, testing, and screenshots demonstrating the fix.
Linked Issues check ✅ Passed The PR directly addresses all coding requirements from issue #2691: preventing duplicate dropHandler invocations through idempotent handler design and adding a regression test.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the duplicate row drag bug; no unrelated modifications were introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 4, 2026

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@2703

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@2703

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@2703

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@2703

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@2703

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@2703

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@2703

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@2703

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@2703

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@2703

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@2703

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@2703

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@2703

commit: 4cc161e

@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

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

Project Deployment Actions Updated (UTC)
blocknote Ready Ready Preview May 4, 2026 0:15am

Request Review

Copy link
Copy Markdown
Contributor

@nperez0111 nperez0111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @LimChaeJune this fixes the issue well!

@nperez0111 nperez0111 merged commit 73f4827 into TypeCellOS:main May 4, 2026
22 of 23 checks passed
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.

Table row drag moves two rows instead of one due to duplicate dropHandler invocation

2 participants