feat: do not delete frame children on frame delete (#9011)

This commit is contained in:
David Luzar 2025-01-14 21:08:25 +01:00 committed by GitHub
parent 46f42ef8d7
commit ae6bee3403
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 103 additions and 40 deletions

View file

@ -7,7 +7,7 @@ import { getNonDeletedElements } from "../element";
import type { ExcalidrawElement } from "../element/types";
import type { AppClassProperties, AppState } from "../types";
import { mutateElement, newElementWith } from "../element/mutateElement";
import { getElementsInGroup } from "../groups";
import { getElementsInGroup, selectGroupsForSelectedElements } from "../groups";
import { LinearElementEditor } from "../element/linearElementEditor";
import { fixBindingsAfterDeletion } from "../element/binding";
import {
@ -33,14 +33,15 @@ const deleteSelectedElements = (
).map((el) => el.id),
);
return {
elements: elements.map((el) => {
const selectedElementIds: Record<ExcalidrawElement["id"], true> = {};
let shouldSelectEditingGroup = true;
const nextElements = elements.map((el) => {
if (appState.selectedElementIds[el.id]) {
if (el.boundElements) {
el.boundElements.forEach((candidate) => {
const bound = app.scene
.getNonDeletedElementsMap()
.get(candidate.id);
const bound = app.scene.getNonDeletedElementsMap().get(candidate.id);
if (bound && isElbowArrow(bound)) {
mutateElement(bound, {
startBinding:
@ -48,9 +49,7 @@ const deleteSelectedElements = (
? null
: bound.startBinding,
endBinding:
el.id === bound.endBinding?.elementId
? null
: bound.endBinding,
el.id === bound.endBinding?.elementId ? null : bound.endBinding,
});
mutateElbowArrow(bound, elementsMap, bound.points);
}
@ -59,22 +58,74 @@ const deleteSelectedElements = (
return newElementWith(el, { isDeleted: true });
}
// if deleting a frame, remove the children from it and select them
if (el.frameId && framesToBeDeleted.has(el.frameId)) {
return newElementWith(el, { isDeleted: true });
shouldSelectEditingGroup = false;
selectedElementIds[el.id] = true;
return newElementWith(el, { frameId: null });
}
if (
isBoundToContainer(el) &&
appState.selectedElementIds[el.containerId]
) {
if (isBoundToContainer(el) && appState.selectedElementIds[el.containerId]) {
return newElementWith(el, { isDeleted: true });
}
return el;
}),
});
let nextEditingGroupId = appState.editingGroupId;
// select next eligible element in currently editing group or supergroup
if (shouldSelectEditingGroup && appState.editingGroupId) {
const elems = getElementsInGroup(
nextElements,
appState.editingGroupId,
).filter((el) => !el.isDeleted);
if (elems.length > 1) {
if (elems[0]) {
selectedElementIds[elems[0].id] = true;
}
} else {
nextEditingGroupId = null;
if (elems[0]) {
selectedElementIds[elems[0].id] = true;
}
const lastElementInGroup = elems[0];
if (lastElementInGroup) {
const editingGroupIdx = lastElementInGroup.groupIds.findIndex(
(groupId) => {
return groupId === appState.editingGroupId;
},
);
const superGroupId = lastElementInGroup.groupIds[editingGroupIdx + 1];
if (superGroupId) {
const elems = getElementsInGroup(nextElements, superGroupId).filter(
(el) => !el.isDeleted,
);
if (elems.length > 1) {
nextEditingGroupId = superGroupId;
elems.forEach((el) => {
selectedElementIds[el.id] = true;
});
}
}
}
}
}
return {
elements: nextElements,
appState: {
...appState,
selectedElementIds: {},
selectedGroupIds: {},
...selectGroupsForSelectedElements(
{
selectedElementIds,
editingGroupId: nextEditingGroupId,
},
nextElements,
appState,
null,
),
},
};
};

View file

@ -105,6 +105,10 @@ export const selectGroupsForSelectedElements = (function () {
const groupElementsIndex: Record<GroupId, string[]> = {};
const selectedElementIdsInGroups = elements.reduce(
(acc: Record<string, true>, element) => {
if (element.isDeleted) {
return acc;
}
const groupId = element.groupIds.find((id) => selectedGroupIds[id]);
if (groupId) {

View file

@ -4307,14 +4307,20 @@ History {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {
"editingGroupId": null,
"selectedElementIds": {
"id1": true,
},
"selectedGroupIds": {
"id4": false,
},
},
"inserted": {
"editingGroupId": "id4",
"selectedElementIds": {
"id0": true,
},
"selectedGroupIds": {},
},
},
},
@ -4337,14 +4343,16 @@ History {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {
"editingGroupId": null,
"selectedElementIds": {},
"selectedGroupIds": {},
},
"inserted": {
"editingGroupId": "id4",
"selectedElementIds": {
"id1": true,
},
"selectedGroupIds": {
"id4": false,
},
},
},
},