diff --git a/packages/excalidraw/actions/actionDeleteSelected.tsx b/packages/excalidraw/actions/actionDeleteSelected.tsx index 49292c10e9..16970b1434 100644 --- a/packages/excalidraw/actions/actionDeleteSelected.tsx +++ b/packages/excalidraw/actions/actionDeleteSelected.tsx @@ -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,48 +33,99 @@ const deleteSelectedElements = ( ).map((el) => el.id), ); - return { - elements: elements.map((el) => { - if (appState.selectedElementIds[el.id]) { - if (el.boundElements) { - el.boundElements.forEach((candidate) => { - const bound = app.scene - .getNonDeletedElementsMap() - .get(candidate.id); - if (bound && isElbowArrow(bound)) { - mutateElement(bound, { - startBinding: - el.id === bound.startBinding?.elementId - ? null - : bound.startBinding, - endBinding: - el.id === bound.endBinding?.elementId - ? null - : bound.endBinding, - }); - mutateElbowArrow(bound, elementsMap, bound.points); - } - }); + const selectedElementIds: Record = {}; + + 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); + if (bound && isElbowArrow(bound)) { + mutateElement(bound, { + startBinding: + el.id === bound.startBinding?.elementId + ? null + : bound.startBinding, + endBinding: + el.id === bound.endBinding?.elementId ? null : bound.endBinding, + }); + mutateElbowArrow(bound, elementsMap, bound.points); + } + }); + } + return newElementWith(el, { isDeleted: true }); + } + + // if deleting a frame, remove the children from it and select them + if (el.frameId && framesToBeDeleted.has(el.frameId)) { + shouldSelectEditingGroup = false; + selectedElementIds[el.id] = true; + return newElementWith(el, { frameId: null }); + } + + 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 newElementWith(el, { isDeleted: true }); } + } + } - if (el.frameId && framesToBeDeleted.has(el.frameId)) { - return newElementWith(el, { isDeleted: true }); - } - - if ( - isBoundToContainer(el) && - appState.selectedElementIds[el.containerId] - ) { - return newElementWith(el, { isDeleted: true }); - } - return el; - }), + return { + elements: nextElements, appState: { ...appState, - selectedElementIds: {}, - selectedGroupIds: {}, + ...selectGroupsForSelectedElements( + { + selectedElementIds, + editingGroupId: nextEditingGroupId, + }, + nextElements, + appState, + null, + ), }, }; }; diff --git a/packages/excalidraw/groups.ts b/packages/excalidraw/groups.ts index 87b64f591d..5a4e606f71 100644 --- a/packages/excalidraw/groups.ts +++ b/packages/excalidraw/groups.ts @@ -105,6 +105,10 @@ export const selectGroupsForSelectedElements = (function () { const groupElementsIndex: Record = {}; const selectedElementIdsInGroups = elements.reduce( (acc: Record, element) => { + if (element.isDeleted) { + return acc; + } + const groupId = element.groupIds.find((id) => selectedGroupIds[id]); if (groupId) { diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 8d357b8fb0..75795b251e 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -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, + }, }, }, },