fix: adding partial group to frame (#9014)

* prevent new frame from including partial groups

* separate wrapped partial group
This commit is contained in:
Ryan Di 2025-01-23 07:26:12 +08:00 committed by GitHub
parent dd1b45a25a
commit 0bf234fcc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 70 additions and 3 deletions

View file

@ -12,6 +12,8 @@ import { frameToolIcon } from "../components/icons";
import { StoreAction } from "../store"; import { StoreAction } from "../store";
import { getSelectedElements } from "../scene"; import { getSelectedElements } from "../scene";
import { newFrameElement } from "../element/newElement"; import { newFrameElement } from "../element/newElement";
import { getElementsInGroup } from "../groups";
import { mutateElement } from "../element/mutateElement";
const isSingleFrameSelected = ( const isSingleFrameSelected = (
appState: UIAppState, appState: UIAppState,
@ -174,6 +176,26 @@ export const actionWrapSelectionInFrame = register({
height: y2 - y1 + PADDING * 2, height: y2 - y1 + PADDING * 2,
}); });
// for a selected partial group, we want to remove it from the remainder of the group
if (appState.editingGroupId) {
const elementsInGroup = getElementsInGroup(
selectedElements,
appState.editingGroupId,
);
for (const elementInGroup of elementsInGroup) {
const index = elementInGroup.groupIds.indexOf(appState.editingGroupId);
mutateElement(
elementInGroup,
{
groupIds: elementInGroup.groupIds.slice(0, index),
},
false,
);
}
}
const nextElements = addElementsToFrame( const nextElements = addElementsToFrame(
[...app.scene.getElementsIncludingDeleted(), frame], [...app.scene.getElementsIncludingDeleted(), frame],
selectedElements, selectedElements,

View file

@ -369,12 +369,57 @@ export const getElementsInNewFrame = (
frame: ExcalidrawFrameLikeElement, frame: ExcalidrawFrameLikeElement,
elementsMap: ElementsMap, elementsMap: ElementsMap,
) => { ) => {
return omitGroupsContainingFrameLikes( return omitPartialGroups(
elements, omitGroupsContainingFrameLikes(
getElementsCompletelyInFrame(elements, frame, elementsMap), elements,
getElementsCompletelyInFrame(elements, frame, elementsMap),
),
frame,
elementsMap,
); );
}; };
export const omitPartialGroups = (
elements: ExcalidrawElement[],
frame: ExcalidrawFrameLikeElement,
allElementsMap: ElementsMap,
) => {
const elementsToReturn = [];
const checkedGroups = new Map<string, boolean>();
for (const element of elements) {
let shouldOmit = false;
if (element.groupIds.length > 0) {
// if some partial group should be omitted, then all elements in that group should be omitted
if (element.groupIds.some((gid) => checkedGroups.get(gid))) {
shouldOmit = true;
} else {
const allElementsInGroup = new Set(
element.groupIds.flatMap((gid) =>
getElementsInGroup(allElementsMap, gid),
),
);
shouldOmit = !elementsAreInFrameBounds(
Array.from(allElementsInGroup),
frame,
allElementsMap,
);
}
element.groupIds.forEach((gid) => {
checkedGroups.set(gid, shouldOmit);
});
}
if (!shouldOmit) {
elementsToReturn.push(element);
}
}
return elementsToReturn;
};
export const getContainingFrame = ( export const getContainingFrame = (
element: ExcalidrawElement, element: ExcalidrawElement,
elementsMap: ElementsMap, elementsMap: ElementsMap,