fix: keep orig elem in place on alt-duplication (#9403)

* fix: keep orig elem in place on alt-duplication

* clarify comment

* fix: incorrect selection on duplicating labeled containers

* fix: duplicating within group outside frame should remove from group
This commit is contained in:
David Luzar 2025-04-17 16:08:07 +02:00 committed by GitHub
parent 0cf36d6b30
commit a5d6939826
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 603 additions and 579 deletions

View file

@ -1,40 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`duplicate element on move when ALT is clicked > rectangle 5`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"boundElements": null,
"customData": undefined,
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 50,
"id": "id2",
"index": "Zz",
"isDeleted": false,
"link": null,
"locked": false,
"opacity": 100,
"roughness": 1,
"roundness": {
"type": 3,
},
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "rectangle",
"updated": 1,
"version": 6,
"versionNonce": 1604849351,
"width": 30,
"x": 30,
"y": 20,
}
`;
exports[`duplicate element on move when ALT is clicked > rectangle 6`] = `
{
"angle": 0,
"backgroundColor": "transparent",
@ -54,13 +20,47 @@ exports[`duplicate element on move when ALT is clicked > rectangle 6`] = `
"roundness": {
"type": 3,
},
"seed": 1505387817,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "rectangle",
"updated": 1,
"version": 6,
"version": 5,
"versionNonce": 1505387817,
"width": 30,
"x": 30,
"y": 20,
}
`;
exports[`duplicate element on move when ALT is clicked > rectangle 6`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"boundElements": null,
"customData": undefined,
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 50,
"id": "id2",
"index": "a1",
"isDeleted": false,
"link": null,
"locked": false,
"opacity": 100,
"roughness": 1,
"roundness": {
"type": 3,
},
"seed": 1604849351,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "rectangle",
"updated": 1,
"version": 7,
"versionNonce": 915032327,
"width": 30,
"x": -10,

View file

@ -2038,7 +2038,7 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
"scrolledOutside": false,
"searchMatches": [],
"selectedElementIds": {
"id0": true,
"id2": true,
},
"selectedElementsAreBeingDragged": false,
"selectedGroupIds": {},
@ -2128,8 +2128,16 @@ History {
HistoryEntry {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {},
"inserted": {},
"deleted": {
"selectedElementIds": {
"id2": true,
},
},
"inserted": {
"selectedElementIds": {
"id0": true,
},
},
},
},
"elementsChange": ElementsChange {
@ -2145,7 +2153,7 @@ History {
"frameId": null,
"groupIds": [],
"height": 10,
"index": "Zz",
"index": "a1",
"isDeleted": false,
"link": null,
"locked": false,
@ -2159,26 +2167,15 @@ History {
"strokeWidth": 2,
"type": "rectangle",
"width": 10,
"x": 10,
"y": 10,
"x": 20,
"y": 20,
},
"inserted": {
"isDeleted": true,
},
},
},
"updated": Map {
"id0" => Delta {
"deleted": {
"x": 20,
"y": 20,
},
"inserted": {
"x": 10,
"y": 10,
},
},
},
"updated": Map {},
},
},
],
@ -10378,13 +10375,13 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
"scrolledOutside": false,
"searchMatches": [],
"selectedElementIds": {
"id0": true,
"id1": true,
"id2": true,
"id6": true,
"id8": true,
"id9": true,
},
"selectedElementsAreBeingDragged": false,
"selectedGroupIds": {
"id4": true,
"id7": true,
},
"selectedLinearElement": null,
"selectionElement": null,
@ -10648,8 +10645,26 @@ History {
HistoryEntry {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {},
"inserted": {},
"deleted": {
"selectedElementIds": {
"id6": true,
"id8": true,
"id9": true,
},
"selectedGroupIds": {
"id7": true,
},
},
"inserted": {
"selectedElementIds": {
"id0": true,
"id1": true,
"id2": true,
},
"selectedGroupIds": {
"id4": true,
},
},
},
},
"elementsChange": ElementsChange {
@ -10667,7 +10682,7 @@ History {
"id7",
],
"height": 10,
"index": "Zx",
"index": "a3",
"isDeleted": false,
"link": null,
"locked": false,
@ -10681,8 +10696,8 @@ History {
"strokeWidth": 2,
"type": "rectangle",
"width": 10,
"x": 10,
"y": 10,
"x": 20,
"y": 20,
},
"inserted": {
"isDeleted": true,
@ -10700,7 +10715,7 @@ History {
"id7",
],
"height": 10,
"index": "Zy",
"index": "a4",
"isDeleted": false,
"link": null,
"locked": false,
@ -10714,8 +10729,8 @@ History {
"strokeWidth": 2,
"type": "rectangle",
"width": 10,
"x": 30,
"y": 10,
"x": 40,
"y": 20,
},
"inserted": {
"isDeleted": true,
@ -10733,7 +10748,7 @@ History {
"id7",
],
"height": 10,
"index": "Zz",
"index": "a5",
"isDeleted": false,
"link": null,
"locked": false,
@ -10747,46 +10762,15 @@ History {
"strokeWidth": 2,
"type": "rectangle",
"width": 10,
"x": 50,
"y": 10,
"x": 60,
"y": 20,
},
"inserted": {
"isDeleted": true,
},
},
},
"updated": Map {
"id0" => Delta {
"deleted": {
"x": 20,
"y": 20,
},
"inserted": {
"x": 10,
"y": 10,
},
},
"id1" => Delta {
"deleted": {
"x": 40,
"y": 20,
},
"inserted": {
"x": 30,
"y": 10,
},
},
"id2" => Delta {
"deleted": {
"x": 60,
"y": 20,
},
"inserted": {
"x": 50,
"y": 10,
},
},
},
"updated": Map {},
},
},
],

View file

@ -307,6 +307,41 @@ describe("pasting & frames", () => {
});
});
it("should remove element from frame when pasted outside", async () => {
const frame = API.createElement({
type: "frame",
width: 100,
height: 100,
x: 0,
y: 0,
});
const rect = API.createElement({
type: "rectangle",
frameId: frame.id,
x: 10,
y: 10,
width: 50,
height: 50,
});
API.setElements([frame]);
const clipboardJSON = await serializeAsClipboardJSON({
elements: [rect],
files: null,
});
mouse.moveTo(150, 150);
pasteWithCtrlCmdV(clipboardJSON);
await waitFor(() => {
expect(h.elements.length).toBe(2);
expect(h.elements[1].type).toBe(rect.type);
expect(h.elements[1].frameId).toBe(null);
});
});
it("should filter out elements not overlapping frame", async () => {
const frame = API.createElement({
type: "frame",

View file

@ -218,7 +218,7 @@ describe("Cropping and other features", async () => {
initialHeight / 2,
]);
Keyboard.keyDown(KEYS.ESCAPE);
const duplicatedImage = duplicateElement(null, new Map(), image, {});
const duplicatedImage = duplicateElement(null, new Map(), image);
act(() => {
h.app.scene.insertElement(duplicatedImage);
});