Browse Source

fix: CTRL/CMD & arrow point drag unbinds both sides (#6459) (#7877)

Márk Tolmács 1 year ago
parent
commit
a04676d423

+ 1 - 1
packages/excalidraw/components/App.tsx

@@ -8472,7 +8472,7 @@ class App extends React.Component<AppProps, AppState> {
               this,
             )
           : unbindLinearElements(
-              this.scene.getNonDeletedElements(),
+              this.scene.getSelectedElements(this.state),
               elementsMap,
             );
       }

+ 10 - 1
packages/excalidraw/element/binding.ts

@@ -293,7 +293,16 @@ export const unbindLinearElements = (
 ): void => {
   elements.forEach((element) => {
     if (isBindingElement(element)) {
-      bindOrUnbindLinearElement(element, null, null, elementsMap);
+      if (element.startBinding !== null && element.endBinding !== null) {
+        bindOrUnbindLinearElement(element, null, null, elementsMap);
+      } else {
+        bindOrUnbindLinearElement(
+          element,
+          element.startBinding ? "keep" : null,
+          element.endBinding ? "keep" : null,
+          elementsMap,
+        );
+      }
     }
   });
 };

+ 40 - 0
packages/excalidraw/tests/binding.test.tsx

@@ -369,4 +369,44 @@ describe("element binding", () => {
     expect(arrow2.startBinding?.elementId).toBe(container.id);
     expect(arrow2.endBinding?.elementId).toBe(rectangle1.id);
   });
+
+  // #6459
+  it("should unbind arrow only from the latest element", () => {
+    const rectLeft = UI.createElement("rectangle", {
+      x: 0,
+      width: 200,
+      height: 500,
+    });
+    const rectRight = UI.createElement("rectangle", {
+      x: 400,
+      width: 200,
+      height: 500,
+    });
+    const arrow = UI.createElement("arrow", {
+      x: 210,
+      y: 250,
+      width: 180,
+      height: 1,
+    });
+    expect(arrow.startBinding?.elementId).toBe(rectLeft.id);
+    expect(arrow.endBinding?.elementId).toBe(rectRight.id);
+
+    // Drag arrow off of bound rectangle range
+    const handles = getTransformHandles(
+      arrow,
+      h.state.zoom,
+      arrayToMap(h.elements),
+      "mouse",
+    ).se!;
+
+    Keyboard.keyDown(KEYS.CTRL_OR_CMD);
+    const elX = handles[0] + handles[2] / 2;
+    const elY = handles[1] + handles[3] / 2;
+    mouse.downAt(elX, elY);
+    mouse.moveTo(300, 400);
+    mouse.up();
+
+    expect(arrow.startBinding).not.toBe(null);
+    expect(arrow.endBinding).toBe(null);
+  });
 });