From 81a26b67de394696cd20d0afeda990c2436a01d8 Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Wed, 13 Aug 2025 17:55:57 +0200 Subject: [PATCH] fix: Elbow arrow fixes --- packages/element/src/binding.ts | 1 + packages/element/tests/elbowArrow.test.tsx | 12 ++-- packages/excalidraw/components/App.tsx | 72 +++++++++------------- 3 files changed, 35 insertions(+), 50 deletions(-) diff --git a/packages/element/src/binding.ts b/packages/element/src/binding.ts index 054c1a4389..39f3948269 100644 --- a/packages/element/src/binding.ts +++ b/packages/element/src/binding.ts @@ -145,6 +145,7 @@ export const bindOrUnbindBindingElement = ( ...opts, }, ); + bindOrUnbindBindingElementEdge(arrow, start, "start", scene); bindOrUnbindBindingElementEdge(arrow, end, "end", scene); if (!isElbowArrow(arrow) && (start.focusPoint || end.focusPoint)) { diff --git a/packages/element/tests/elbowArrow.test.tsx b/packages/element/tests/elbowArrow.test.tsx index 131b3defa1..25ef2b2ac0 100644 --- a/packages/element/tests/elbowArrow.test.tsx +++ b/packages/element/tests/elbowArrow.test.tsx @@ -155,8 +155,8 @@ describe("elbow arrow routing", () => { expect(arrow.width).toEqual(90); expect(arrow.height).toEqual(200); }); + it("can generate proper points for bound elbow arrow", () => { - const scene = new Scene(); const rectangle1 = API.createElement({ type: "rectangle", x: -150, @@ -180,17 +180,15 @@ describe("elbow arrow routing", () => { height: 200, points: [pointFrom(0, 0), pointFrom(90, 200)], }) as ExcalidrawElbowArrowElement; - scene.insertElement(rectangle1); - scene.insertElement(rectangle2); - scene.insertElement(arrow); + API.setElements([rectangle1, rectangle2, arrow]); - bindBindingElement(arrow, rectangle1, "orbit", "start", scene); - bindBindingElement(arrow, rectangle2, "orbit", "end", scene); + bindBindingElement(arrow, rectangle1, "orbit", "start", h.scene); + bindBindingElement(arrow, rectangle2, "orbit", "end", h.scene); expect(arrow.startBinding).not.toBe(null); expect(arrow.endBinding).not.toBe(null); - h.app.scene.mutateElement(arrow, { + h.scene.mutateElement(arrow, { points: [pointFrom(0, 0), pointFrom(90, 200)], }); diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 5218ba799d..d10096d4b5 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -769,6 +769,27 @@ class App extends React.Component { this.actionManager.registerAction(createRedoAction(this.history)); } + // setState: React.Component["setState"] = ( + // state, + // callback?, + // ) => { + // let newState: Parameters[0] = null; + // if (typeof state === "function") { + // newState = state(this.state, this.props) as Pick< + // AppState, + // keyof AppState + // >; + // } else { + // newState = state as Pick; + // } + + // if (newState && Object.hasOwn(newState, "selectedLinearElement")) { + // console.trace(!!newState.selectedLinearElement); + // } + + // super.setState(newState, callback); + // }; + updateEditorAtom = ( atom: WritableAtom, ...args: Args @@ -2519,47 +2540,6 @@ class App extends React.Component { return this.setState(...args); }, }, - watchState: { - configurable: true, - value: ( - callback: - | (( - prevState: Parameters, - nextState: Parameters | null, - ) => void) - | undefined, - ) => { - if (callback) { - (window as any).__originalSetState = this.setState; - this.setState = new Proxy(this.setState, { - apply: (target, thisArg, [state, cb]) => { - const prevState = thisArg.state; - let newState: Parameters | null = null; - - // Log state change for debugging - if (typeof state === "function") { - newState = state(prevState, this.props); - } else if (state) { - newState = state; - } - - try { - callback(prevState, newState); - } catch (error) { - console.warn("Error in watchState callback:", error); - } - - if (newState) { - target.bind(thisArg)(newState as any, cb); - } - }, - }); - } else if ((window as any).__originalSetState) { - this.setState = (window as any).__originalSetState; - delete (window as any).__originalSetState; - } - }, - }, app: { configurable: true, value: this, @@ -8160,7 +8140,13 @@ class App extends React.Component { lastCommittedPoint: multiElement.points[multiElement.points.length - 1], }); - this.actionManager.executeAction(actionFinalize); + this.actionManager.executeAction(actionFinalize, "ui", { + event: event.nativeEvent, + sceneCoords: { + x: pointerDownState.origin.x, + y: pointerDownState.origin.y, + }, + }); return; } @@ -8347,7 +8333,7 @@ class App extends React.Component { this.setState((prevState) => { let linearElementEditor = null; let nextSelectedElementIds = prevState.selectedElementIds; - if (isSimpleArrow(element)) { + if (isBindingElement(element)) { const linearElement = new LinearElementEditor( element, this.scene.getNonDeletedElementsMap(),