From 95f1c719c4b6e1ec7e0d47f1f34efdc7abae6d85 Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Mon, 22 Sep 2025 18:22:35 +0200 Subject: [PATCH] fix: False bind timeout indicator Signed-off-by: Mark Tolmacs --- packages/excalidraw/components/App.tsx | 82 ++++++++++++++------------ 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index c0a6cd8f40..1b4dcfbb5e 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -1099,6 +1099,7 @@ class App extends React.Component { isOverlapping = !!( startBounds && endBounds && + startElement.id !== endElement.id && doBoundsIntersect(startBounds, endBounds) ); } @@ -8517,48 +8518,55 @@ class App extends React.Component { this.state, { newArrow: true }, ); - - this.handleDelayedBindModeChange(element, boundElement); } - this.setState((prevState) => { - let linearElementEditor = null; - let nextSelectedElementIds = prevState.selectedElementIds; - if (isLinearElement(element)) { - linearElementEditor = new LinearElementEditor( - element, - this.scene.getNonDeletedElementsMap(), - ); + // NOTE: We need the flushSync here for the + // delayed bind mode change to see the right state + // (specifically the `newElement`) + flushSync(() => { + this.setState((prevState) => { + let linearElementEditor = null; + let nextSelectedElementIds = prevState.selectedElementIds; + if (isLinearElement(element)) { + linearElementEditor = new LinearElementEditor( + element, + this.scene.getNonDeletedElementsMap(), + ); - const endIdx = element.points.length - 1; - linearElementEditor = { - ...linearElementEditor, - selectedPointsIndices: [endIdx], - initialState: { - ...linearElementEditor.initialState, - lastClickedPoint: endIdx, - origin: pointFrom( - pointerDownState.origin.x, - pointerDownState.origin.y, - ), - }, + const endIdx = element.points.length - 1; + linearElementEditor = { + ...linearElementEditor, + selectedPointsIndices: [endIdx], + initialState: { + ...linearElementEditor.initialState, + lastClickedPoint: endIdx, + origin: pointFrom( + pointerDownState.origin.x, + pointerDownState.origin.y, + ), + }, + }; + } + + nextSelectedElementIds = !this.state.activeTool.locked + ? makeNextSelectedElementIds({ [element.id]: true }, prevState) + : prevState.selectedElementIds; + + return { + ...prevState, + bindMode: "orbit", + newElement: element, + startBoundElement: boundElement, + suggestedBinding: boundElement || null, + selectedElementIds: nextSelectedElementIds, + selectedLinearElement: linearElementEditor, }; - } - - nextSelectedElementIds = !this.state.activeTool.locked - ? makeNextSelectedElementIds({ [element.id]: true }, prevState) - : prevState.selectedElementIds; - - return { - ...prevState, - bindMode: "orbit", - newElement: element, - startBoundElement: boundElement, - suggestedBinding: boundElement || null, - selectedElementIds: nextSelectedElementIds, - selectedLinearElement: linearElementEditor, - }; + }); }); + + if (isBindingElement(element)) { + this.handleDelayedBindModeChange(element, boundElement); + } } };