diff --git a/packages/element/src/binding.ts b/packages/element/src/binding.ts index 2ad190927..9118d11dc 100644 --- a/packages/element/src/binding.ts +++ b/packages/element/src/binding.ts @@ -128,6 +128,7 @@ export const bindOrUnbindBindingElement = ( appState, { ...opts, + finalize: true, }, ); @@ -396,7 +397,7 @@ const bindingStrategyForSimpleArrowEndpointDragging = ( elements: readonly Ordered[], globalBindMode: AppState["bindMode"], arrow: NonDeleted, - shiftKey?: boolean, + finalize?: boolean, ): { current: BindingStrategy; other: BindingStrategy } => { let current: BindingStrategy = { mode: undefined }; let other: BindingStrategy = { mode: undefined }; @@ -461,7 +462,7 @@ const bindingStrategyForSimpleArrowEndpointDragging = ( // The opposite binding is on the binding gap of the same element if (oppositeBinding.mode === "orbit") { current = { element: hit, mode: "orbit", focusPoint: point }; - other = { mode: null }; + other = { mode: finalize ? null : undefined }; return { current, other: isMultiPoint ? { mode: undefined } : other }; } @@ -517,6 +518,7 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = ( opts?: { newArrow?: boolean; shiftKey?: boolean; + finalize?: boolean; }, ): { start: BindingStrategy; end: BindingStrategy } => { const globalBindMode = appState.bindMode || "orbit"; @@ -600,7 +602,7 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = ( elements, globalBindMode, arrow, - opts?.shiftKey, + opts?.finalize, ); return { start: current, end: other }; @@ -623,7 +625,7 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = ( elements, globalBindMode, arrow, - opts?.shiftKey, + opts?.finalize, ); return { start: other, end: current }; diff --git a/packages/element/src/linearElementEditor.ts b/packages/element/src/linearElementEditor.ts index 394db8670..b8cc3eb5a 100644 --- a/packages/element/src/linearElementEditor.ts +++ b/packages/element/src/linearElementEditor.ts @@ -2215,6 +2215,21 @@ const pointDraggingUpdates = ( ? lineSegment(start.focusPoint, end.focusPoint) : undefined; + // Needed to handle a special case where an existing arrow is dragged over + // the same element it is bound to on the other side + const startIsDraggingOverEndElement = + element.endBinding && + nextArrow.startBinding && + app.state.bindMode === "inside" && + endIsDragged && + nextArrow.startBinding.elementId === element.endBinding.elementId; + const endIsDraggingOverStartElement = + element.startBinding && + nextArrow.endBinding && + app.state.bindMode === "inside" && + startIsDragged && + element.startBinding.elementId === nextArrow.endBinding.elementId; + // We need to update the non-dragged point too if bound, // so we look up the old binding to trigger updateBoundPoint const endBindable = nextArrow.endBinding @@ -2223,16 +2238,17 @@ const pointDraggingUpdates = ( nextArrow.endBinding.elementId, )! as ExcalidrawBindableElement) : null; - const endLocalPoint = endBindable - ? updateBoundPoint( - nextArrow, - "endBinding", - nextArrow.endBinding, - endBindable, - elementsMap, - customIntersector, - ) || nextArrow.points[nextArrow.points.length - 1] - : nextArrow.points[nextArrow.points.length - 1]; + const endLocalPoint = + endBindable && !endIsDraggingOverStartElement + ? updateBoundPoint( + nextArrow, + "endBinding", + nextArrow.endBinding, + endBindable, + elementsMap, + customIntersector, + ) || nextArrow.points[nextArrow.points.length - 1] + : nextArrow.points[nextArrow.points.length - 1]; // We need to keep the simulated next arrow up-to-date, because // updateBoundPoint looks at the opposite point @@ -2247,16 +2263,17 @@ const pointDraggingUpdates = ( )! as ExcalidrawBindableElement) : null; - const startLocalPoint = startBindable - ? updateBoundPoint( - nextArrow, - "startBinding", - nextArrow.startBinding, - startBindable, - elementsMap, - customIntersector, - ) || nextArrow.points[0] - : nextArrow.points[0]; + const startLocalPoint = + startBindable && startIsDraggingOverEndElement + ? updateBoundPoint( + nextArrow, + "startBinding", + nextArrow.startBinding, + startBindable, + elementsMap, + customIntersector, + ) || nextArrow.points[0] + : nextArrow.points[0]; const endChanged = pointDistance(