Skip to content

Arrow bend translation#770

Open
trangdoan982 wants to merge 1 commit intomainfrom
cursor/ENG-1366-arrow-bend-translation-59c6
Open

Arrow bend translation#770
trangdoan982 wants to merge 1 commit intomainfrom
cursor/ENG-1366-arrow-bend-translation-59c6

Conversation

@trangdoan982
Copy link
Collaborator

@trangdoan982 trangdoan982 commented Feb 12, 2026

Fixes DiscourseRelationShape's onTranslate to prevent unexpected bend changes when moving multiple selected shapes.

Previously, when both ends of a DiscourseRelationShape were bound, its onTranslate method would always convert translation into bend changes. This was incorrect when the relation was moved as part of a larger selection of shapes (e.g., nodes and the connecting arrow). The change ensures that bend changes only occur if only the relation shape is selected, allowing for simple translation when moved with other shapes, aligning with tldraw's native arrow behavior.


Linear Issue: ENG-1366

Open in Cursor Open in Web


Open with Devin

- Check if only the relation shape is selected before applying bend changes
- When multiple shapes are selected together, perform simple translation
- Preserves existing behavior when dragging arrow alone (bend changes allowed)
- Aligns with tldraw native arrow behavior for group movements

Co-authored-by: Trang Doan <trangdoan982@users.noreply.github.com>
@cursor
Copy link

cursor bot commented Feb 12, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@linear
Copy link

linear bot commented Feb 12, 2026

@supabase
Copy link

supabase bot commented Feb 12, 2026

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@trangdoan982 trangdoan982 marked this pull request as ready for review February 13, 2026 17:11
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +477 to +483
// Check if other shapes are also being translated
const selectedShapeIds = this.editor.getSelectedShapeIds();
const onlyRelationSelected = selectedShapeIds.length === 1 && selectedShapeIds[0] === shape.id;

// If both ends are bound AND only the relation is selected, convert translation to bend changes
// If other shapes are also selected, do a simple translation instead
if (bindings.start && bindings.end && onlyRelationSelected) {
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 Missing early return in onTranslate causes bindings to be removed when multi-selecting bound arrows with their nodes

When a DiscourseRelationShape with both ends bound is translated as part of a multi-shape selection (e.g., the arrow plus its two bound nodes), the arrow's bindings are incorrectly modified or removed.

Root Cause: onTranslateStart always sets translation data for both-ends-bound case, but onTranslate now falls through to wrong code path

In onTranslateStart (line 606), when both ends are bound, the method always stores shapeAtTranslationStart data and returns early — regardless of whether the bound shapes are also selected:

// Line 606-622
if (bindings.start && bindings.end) {
  shapeAtTranslationStart.set(shape, { ... });
  return; // Always returns here
}

This check at line 606 runs before the check at line 630 that would normally detect that bound shapes are in the selection and return without setting shapeAtTranslationStart.

Then in onTranslate, the new PR code at line 483 checks onlyRelationSelected. When other shapes are also selected, onlyRelationSelected is false, so the bend-change block is skipped. Execution falls through to the "normal translation behavior" code path (lines 535-591).

This normal path iterates over atTranslationStart.terminalBindings and for each terminal:

  1. Calculates newPagePoint = terminalBinding.pagePosition + pageDelta * 0.5 (line 547-549)
  2. Calls getShapeAtPoint(newPagePoint) to find the target (line 551)
  3. If the target isn't found at that point, calls removeArrowBinding() (line 585-589)

When the bound nodes are also being translated (moving by the full pageDelta), searching at pagePosition + pageDelta * 0.5 (only half the delta) will likely miss the target shapes. This causes removeArrowBinding to fire, breaking the arrow connections.

Impact: Selecting and moving a group of connected nodes and arrows together will disconnect the arrows from their nodes, which is the opposite of the intended fix.

Suggested change
// Check if other shapes are also being translated
const selectedShapeIds = this.editor.getSelectedShapeIds();
const onlyRelationSelected = selectedShapeIds.length === 1 && selectedShapeIds[0] === shape.id;
// If both ends are bound AND only the relation is selected, convert translation to bend changes
// If other shapes are also selected, do a simple translation instead
if (bindings.start && bindings.end && onlyRelationSelected) {
// Check if other shapes are also being translated
const selectedShapeIds = this.editor.getSelectedShapeIds();
const onlyRelationSelected = selectedShapeIds.length === 1 && selectedShapeIds[0] === shape.id;
// If both ends are bound AND only the relation is selected, convert translation to bend changes
// If other shapes are also selected, allow simple translation (tldraw handles moving bound shapes)
if (bindings.start && bindings.end) {
if (!onlyRelationSelected) return;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

2 participants