From ffcb67b21f3693821b0202bf54707bcee21a8ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20Tolm=C3=A1cs?= Date: Mon, 16 Feb 2026 22:25:28 +0100 Subject: [PATCH] fix: Inside-inside bound arrow endpoint drag trigger focus point editor (#10771) fix: Inside-inside binding arrow endpoint drag trigger focus point editor Signed-off-by: Mark Tolmacs --- packages/element/src/arrows/focus.ts | 30 ++++++++++++++----- .../excalidraw/renderer/interactiveScene.ts | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/element/src/arrows/focus.ts b/packages/element/src/arrows/focus.ts index ae02793f72..e0abd75f66 100644 --- a/packages/element/src/arrows/focus.ts +++ b/packages/element/src/arrows/focus.ts @@ -42,6 +42,7 @@ export const isFocusPointVisible = ( isBindingEnabled: AppState["isBindingEnabled"]; zoom: AppState["zoom"]; }, + startOrEnd: "start" | "end", ignoreOverlap = false, ): boolean => { // No focus point management for elbow arrows, because elbow arrows @@ -76,14 +77,25 @@ export const isFocusPointVisible = ( } } - // Check if the focus point is within the element's shape bounds - return hitElementItself({ - element: bindableElement, + const arrowPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates( + arrow, + startOrEnd === "end" ? arrow.points.length - 1 : 0, elementsMap, - point: focusPoint, - threshold: getBindingGap(bindableElement, arrow), - overrideShouldTestInside: true, - }); + ); + + // Check if the focus point is within the element's shape bounds + // Endpoint dragging takes precedence + return ( + pointDistance(focusPoint, arrowPoint) >= + (FOCUS_POINT_SIZE * 1.5) / appState.zoom.value && + hitElementItself({ + element: bindableElement, + elementsMap, + point: focusPoint, + threshold: getBindingGap(bindableElement, arrow), + overrideShouldTestInside: true, + }) + ); }; // Updates the arrow endpoints in "orbit" configuration @@ -353,6 +365,7 @@ export const handleFocusPointPointerDown = ( bindableElement, elementsMap, appState, + "start", ) && pointDistance(pointerPos, focusPoint) <= hitThreshold ) { @@ -387,6 +400,7 @@ export const handleFocusPointPointerDown = ( bindableElement, elementsMap, appState, + "end", ) && pointDistance(pointerPos, focusPoint) <= hitThreshold ) { @@ -501,6 +515,7 @@ export const handleFocusPointHover = ( bindableElement, elementsMap, appState, + "start", ) && pointDistance(pointerPos, focusPoint) <= hitThreshold ) { @@ -529,6 +544,7 @@ export const handleFocusPointHover = ( bindableElement, elementsMap, appState, + "end", ) && pointDistance(pointerPos, focusPoint) <= hitThreshold ) { diff --git a/packages/excalidraw/renderer/interactiveScene.ts b/packages/excalidraw/renderer/interactiveScene.ts index 85b4a9a369..fd243eee3b 100644 --- a/packages/excalidraw/renderer/interactiveScene.ts +++ b/packages/excalidraw/renderer/interactiveScene.ts @@ -1269,6 +1269,7 @@ const renderFocusPointIndicator = ({ bindableElement, elementsMap, appState, + type, ) ) { return;