diff --git a/packages/element/tests/binding.test.tsx b/packages/element/tests/binding.test.tsx index e2495c52f9..85a613bf87 100644 --- a/packages/element/tests/binding.test.tsx +++ b/packages/element/tests/binding.test.tsx @@ -493,6 +493,7 @@ describe("binding for simple arrows", () => { expect(arrow.endBinding?.elementId).toBe(rectRight.id); mouse.downAt(-100, -100); + mouse.moveTo(0, 0); mouse.moveTo(650, 750); mouse.up(0, 0); diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 3683535c2a..36abd632b6 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -11463,13 +11463,10 @@ class App extends React.Component { ): void => { const selectionElement = this.state.selectionElement; const pointerCoords = pointerDownState.lastCoords; - const selectedElements = this.scene.getSelectedElements(this.state); - const onlyBindingElementSelected = - selectedElements?.length === 1 && isBindingElement(selectedElements[0]); if ( selectionElement && - this.state.activeTool.type !== "eraser" && - !onlyBindingElementSelected + pointerDownState.boxSelection.hasOccurred && + this.state.activeTool.type !== "eraser" ) { dragNewElement({ newElement: selectionElement, diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index 7ae3b5775f..b8467c20ab 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -1223,7 +1223,7 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 10, "x": -20, "y": -10, @@ -1431,14 +1431,14 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1505387817, + "versionNonce": 1604849351, "width": 20, "x": 20, "y": 30, @@ -1463,14 +1463,14 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 915032327, + "versionNonce": 493213705, "width": 20, "x": -10, "y": 0, @@ -1765,14 +1765,14 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1505387817, + "versionNonce": 1604849351, "width": 20, "x": 20, "y": 30, @@ -1797,14 +1797,14 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 915032327, + "versionNonce": 493213705, "width": 20, "x": -10, "y": 0, @@ -2108,7 +2108,7 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 10, "x": -20, "y": -10, @@ -2321,7 +2321,7 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1014066025, + "versionNonce": 1116226695, "width": 10, "x": -20, "y": -10, @@ -2567,7 +2567,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 10, "x": -20, "y": -10, @@ -2592,14 +2592,14 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "opacity": 100, "roughness": 1, "roundness": null, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 5, - "versionNonce": 1604849351, + "versionNonce": 400692809, "width": 10, "x": -10, "y": 0, @@ -2868,14 +2868,14 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 81784553, + "versionNonce": 915032327, "width": 20, "x": -10, "y": 0, @@ -2902,14 +2902,14 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "opacity": 100, "roughness": 1, "roundness": null, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 747212839, + "versionNonce": 81784553, "width": 20, "x": 20, "y": 30, @@ -3238,14 +3238,14 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "opacity": 60, "roughness": 2, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1359939303, + "versionNonce": 1402203177, "width": 20, "x": -10, "y": 0, @@ -3270,14 +3270,14 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "opacity": 60, "roughness": 2, "roundness": null, - "seed": 640725609, + "seed": 1898319239, "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 9, - "versionNonce": 908564423, + "versionNonce": 941653321, "width": 20, "x": 20, "y": 30, @@ -3732,14 +3732,14 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "opacity": 100, "roughness": 1, "roundness": null, - "seed": 400692809, + "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 81784553, + "versionNonce": 915032327, "width": 20, "x": 20, "y": 30, @@ -3764,14 +3764,14 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -4058,14 +4058,14 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "opacity": 100, "roughness": 1, "roundness": null, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 915032327, + "versionNonce": 493213705, "width": 20, "x": 20, "y": 30, @@ -4090,14 +4090,14 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -4387,14 +4387,14 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 5, - "versionNonce": 1006504105, + "versionNonce": 760410951, "width": 20, "x": -10, "y": 0, @@ -4419,14 +4419,14 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "opacity": 100, "roughness": 1, "roundness": null, - "seed": 400692809, + "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 5, - "versionNonce": 289600103, + "versionNonce": 1006504105, "width": 20, "x": 20, "y": 30, @@ -5675,14 +5675,14 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "opacity": 100, "roughness": 1, "roundness": null, - "seed": 453191, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1014066025, + "versionNonce": 1150084233, "width": 10, "x": -10, "y": 0, @@ -5707,14 +5707,14 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "opacity": 100, "roughness": 1, "roundness": null, - "seed": 1505387817, + "seed": 400692809, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 915032327, + "versionNonce": 23633383, "width": 10, "x": 12, "y": 0, @@ -6899,14 +6899,14 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "opacity": 100, "roughness": 1, "roundness": null, - "seed": 449462985, + "seed": 1278240551, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1723083209, + "versionNonce": 747212839, "width": 10, "x": -10, "y": 0, @@ -6933,14 +6933,14 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "opacity": 100, "roughness": 1, "roundness": null, - "seed": 400692809, + "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 760410951, + "versionNonce": 1723083209, "width": 10, "x": 12, "y": 0, @@ -9837,7 +9837,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] el "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 10, "x": -20, "y": -10, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index ecea596167..f5ab13c34f 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -13935,7 +13935,7 @@ exports[`regression tests > switches from group of selected elements to another "opacity": 100, "roughness": 1, "roundness": null, - "seed": 289600103, + "seed": 1006504105, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, diff --git a/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap index 5d5c701f0a..1414b24192 100644 --- a/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap @@ -41,8 +41,8 @@ exports[`select single element on the scene > arrow 1`] = ` "strokeWidth": 2, "type": "arrow", "updated": 1, - "version": 4, - "versionNonce": 2019559783, + "version": 5, + "versionNonce": 1116226695, "width": 30, "x": 10, "y": 10, @@ -88,8 +88,8 @@ exports[`select single element on the scene > arrow escape 1`] = ` "strokeWidth": 2, "type": "line", "updated": 1, - "version": 4, - "versionNonce": 2019559783, + "version": 5, + "versionNonce": 1116226695, "width": 30, "x": 10, "y": 10, @@ -120,8 +120,8 @@ exports[`select single element on the scene > diamond 1`] = ` "strokeWidth": 2, "type": "diamond", "updated": 1, - "version": 3, - "versionNonce": 401146281, + "version": 4, + "versionNonce": 2019559783, "width": 30, "x": 10, "y": 10, @@ -152,8 +152,8 @@ exports[`select single element on the scene > ellipse 1`] = ` "strokeWidth": 2, "type": "ellipse", "updated": 1, - "version": 3, - "versionNonce": 401146281, + "version": 4, + "versionNonce": 2019559783, "width": 30, "x": 10, "y": 10, @@ -184,8 +184,8 @@ exports[`select single element on the scene > rectangle 1`] = ` "strokeWidth": 2, "type": "rectangle", "updated": 1, - "version": 3, - "versionNonce": 401146281, + "version": 4, + "versionNonce": 2019559783, "width": 30, "x": 10, "y": 10, diff --git a/packages/excalidraw/tests/history.test.tsx b/packages/excalidraw/tests/history.test.tsx index 219b002777..d3c6e2d470 100644 --- a/packages/excalidraw/tests/history.test.tsx +++ b/packages/excalidraw/tests/history.test.tsx @@ -315,6 +315,7 @@ describe("history", () => { ]); mouse.downAt(0, 0); + mouse.moveTo(25, 25); mouse.moveTo(50, 50); mouse.upAt(50, 50); expect(API.getUndoStack().length).toBe(3); diff --git a/packages/excalidraw/tests/regressionTests.test.tsx b/packages/excalidraw/tests/regressionTests.test.tsx index f16606b6f2..d12a845d63 100644 --- a/packages/excalidraw/tests/regressionTests.test.tsx +++ b/packages/excalidraw/tests/regressionTests.test.tsx @@ -467,6 +467,7 @@ describe("regression tests", () => { mouse.reset(); mouse.down(); + mouse.move(-1000, -1000); mouse.restorePosition(...end); mouse.up(); @@ -517,6 +518,7 @@ describe("regression tests", () => { mouse.reset(); mouse.down(); + mouse.move(-1000, -1000); mouse.restorePosition(...end); mouse.up(); @@ -534,6 +536,7 @@ describe("regression tests", () => { mouse.moveTo(-10, -10); // the NW resizing handle is at [0, 0], so moving further mouse.down(); + mouse.move(-1000, -1000); mouse.restorePosition(...end); mouse.up(); diff --git a/packages/excalidraw/tests/selection.test.tsx b/packages/excalidraw/tests/selection.test.tsx index dde3c96e48..86be835f7b 100644 --- a/packages/excalidraw/tests/selection.test.tsx +++ b/packages/excalidraw/tests/selection.test.tsx @@ -65,6 +65,7 @@ describe("box-selection", () => { API.setElements([rect1, rect2]); mouse.downAt(175, -20); + mouse.move(-1000, -1000); mouse.moveTo(85, 70); mouse.up(); @@ -72,6 +73,7 @@ describe("box-selection", () => { Keyboard.withModifierKeys({ shift: true }, () => { mouse.downAt(75, -20); + mouse.move(-1000, -1000); mouse.moveTo(-15, 70); mouse.up(); }); @@ -93,6 +95,7 @@ describe("box-selection", () => { API.setElements([rect1]); mouse.downAt(75, -20); + mouse.move(-1000, -1000); mouse.moveTo(-15, 70); assertSelectedElements([rect1.id]); @@ -138,6 +141,7 @@ describe("inner box-selection", () => { API.setElements([rect1, rect2, rect3]); Keyboard.withModifierKeys({ ctrl: true }, () => { mouse.downAt(40, 40); + mouse.move(-1000, -1000); mouse.moveTo(290, 290); mouse.up(); @@ -175,6 +179,7 @@ describe("inner box-selection", () => { Keyboard.withModifierKeys({ ctrl: true }, () => { mouse.downAt(40, 40); + mouse.move(-1000, -1000); mouse.moveTo(rect2.x + rect2.width + 10, rect2.y + rect2.height + 10); mouse.up(); @@ -212,6 +217,7 @@ describe("inner box-selection", () => { API.setElements([rect1, rect2, rect3]); Keyboard.withModifierKeys({ ctrl: true }, () => { mouse.downAt(rect2.x - 20, rect2.y - 20); + mouse.move(-1000, -1000); mouse.moveTo(rect2.x + rect2.width + 10, rect2.y + rect2.height + 10); assertSelectedElements([rect2.id, rect3.id]); expect(h.state.selectedGroupIds).toEqual({ A: true }); @@ -253,9 +259,10 @@ describe("selection element", () => { const canvas = container.querySelector("canvas.interactive")!; fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 }); - expect(renderInteractiveScene).toHaveBeenCalledTimes(4); + expect(renderInteractiveScene).toHaveBeenCalledTimes(5); expect(renderStaticScene).toHaveBeenCalledTimes(3); const selectionElement = h.state.selectionElement!; expect(selectionElement).not.toBeNull(); @@ -275,10 +282,11 @@ describe("selection element", () => { const canvas = container.querySelector("canvas.interactive")!; fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(5); + expect(renderInteractiveScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(3); expect(h.state.selectionElement).toBeNull(); }); @@ -303,6 +311,7 @@ describe("select single element on the scene", () => { const tool = getByToolName("rectangle"); fireEvent.click(tool); fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { @@ -335,6 +344,7 @@ describe("select single element on the scene", () => { const tool = getByToolName("diamond"); fireEvent.click(tool); fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { @@ -367,6 +377,7 @@ describe("select single element on the scene", () => { const tool = getByToolName("ellipse"); fireEvent.click(tool); fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { @@ -399,6 +410,7 @@ describe("select single element on the scene", () => { const tool = getByToolName("arrow"); fireEvent.click(tool); fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { @@ -425,8 +437,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(10); + expect(renderStaticScene).toHaveBeenCalledTimes(8); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -443,6 +455,7 @@ describe("select single element on the scene", () => { const tool = getByToolName("line"); fireEvent.click(tool); fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); + fireEvent.pointerMove(canvas, { clientX: -1000, clientY: -1000 }); fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { @@ -469,8 +482,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(10); + expect(renderStaticScene).toHaveBeenCalledTimes(8); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -525,6 +538,7 @@ describe("selectedElementIds stability", () => { expect(h.state.selectedElementIds).toBe(selectedElementIds_1); mouse.downAt(-50, -50); + mouse.move(-1000, -1000); mouse.moveTo(50, 50); const selectedElementIds_2 = h.state.selectedElementIds;