Group / ungroup should not always be present in the context menu (#1890)

Co-authored-by: rene_mbp <harryloveslearning@googlemail.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Rene 2020-07-09 22:32:27 +02:00 committed by GitHub
parent 5664de0459
commit 51a8ab65f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 593 additions and 0 deletions

View File

@ -90,6 +90,8 @@ export const actionGroup = register({
},
contextMenuOrder: 4,
contextItemLabel: "labels.group",
contextItemPredicate: (elements, appState) =>
getSelectedElements(getNonDeletedElements(elements), appState).length > 1,
keyTest: (event) => {
return (
!event.shiftKey &&
@ -136,4 +138,6 @@ export const actionUngroup = register({
},
contextMenuOrder: 5,
contextItemLabel: "labels.ungroup",
contextItemPredicate: (elements, appState) =>
getSelectedGroupIds(appState).length > 0,
});

View File

@ -82,6 +82,14 @@ export class ActionManager implements ActionsManagerInterface {
return Object.values(this.actions)
.filter(actionFilter)
.filter((action) => "contextItemLabel" in action)
.filter((action) =>
action.contextItemPredicate
? action.contextItemPredicate(
this.getElementsIncludingDeleted(),
this.getAppState(),
)
: true,
)
.sort(
(a, b) =>
(a.contextMenuOrder !== undefined ? a.contextMenuOrder : 999) -

View File

@ -81,6 +81,10 @@ export interface Action {
) => boolean;
contextItemLabel?: string;
contextMenuOrder?: number;
contextItemPredicate?: (
elements: readonly ExcalidrawElement[],
appState: AppState,
) => boolean;
}
export interface ActionsManagerInterface {

View File

@ -15375,6 +15375,496 @@ exports[`regression tests shift-click to multiselect, then drag: [end of test] n
exports[`regression tests shift-click to multiselect, then drag: [end of test] number of renders 1`] = `17`;
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] appState 1`] = `
Object {
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
"currentItemFontFamily": 1,
"currentItemFontSize": 20,
"currentItemOpacity": 100,
"currentItemRoughness": 1,
"currentItemStrokeColor": "#000000",
"currentItemStrokeStyle": "solid",
"currentItemStrokeWidth": 1,
"currentItemTextAlign": "left",
"cursorButton": "up",
"cursorX": 0,
"cursorY": 0,
"draggingElement": null,
"editingElement": null,
"editingGroupId": null,
"editingLinearElement": null,
"elementLocked": false,
"elementType": "selection",
"errorMessage": null,
"exportBackground": true,
"gridSize": null,
"height": 768,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"openMenu": null,
"previousSelectedElementIds": Object {
"id0": true,
"id2": true,
},
"resizingElement": null,
"scrollX": 0,
"scrollY": 0,
"scrolledOutside": false,
"selectedElementIds": Object {
"id0": true,
"id1": true,
"id2": true,
"id3": true,
},
"selectedGroupIds": Object {},
"selectionElement": null,
"shouldAddWatermark": false,
"shouldCacheIgnoreZoom": false,
"showShortcutsDialog": false,
"username": "",
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
"zoom": 1,
}
`;
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] element 0 1`] = `
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 1278240551,
"width": 10,
"x": 10,
"y": 10,
}
`;
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] element 1 1`] = `
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id1",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 449462985,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 453191,
"width": 10,
"x": 30,
"y": 10,
}
`;
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] history 1`] = `
Object {
"recording": false,
"redoStack": Array [],
"stateHistory": Array [
Object {
"appState": Object {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": Object {
"id0": true,
},
"viewBackgroundColor": "#ffffff",
},
"elements": Array [
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 1278240551,
"width": 10,
"x": 10,
"y": 10,
},
],
},
Object {
"appState": Object {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": Object {
"id1": true,
},
"viewBackgroundColor": "#ffffff",
},
"elements": Array [
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 1278240551,
"width": 10,
"x": 10,
"y": 10,
},
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id1",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 449462985,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 453191,
"width": 10,
"x": 30,
"y": 10,
},
],
},
],
}
`;
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of elements 1`] = `2`;
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of renders 1`] = `15`;
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] appState 1`] = `
Object {
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
"currentItemFontFamily": 1,
"currentItemFontSize": 20,
"currentItemOpacity": 100,
"currentItemRoughness": 1,
"currentItemStrokeColor": "#000000",
"currentItemStrokeStyle": "solid",
"currentItemStrokeWidth": 1,
"currentItemTextAlign": "left",
"cursorButton": "up",
"cursorX": 0,
"cursorY": 0,
"draggingElement": null,
"editingElement": null,
"editingGroupId": null,
"editingLinearElement": null,
"elementLocked": false,
"elementType": "selection",
"errorMessage": null,
"exportBackground": true,
"gridSize": null,
"height": 768,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"openMenu": null,
"previousSelectedElementIds": Object {
"id0": true,
"id2": true,
},
"resizingElement": null,
"scrollX": 0,
"scrollY": 0,
"scrolledOutside": false,
"selectedElementIds": Object {
"id0": true,
"id1": true,
"id2": true,
"id3": true,
},
"selectedGroupIds": Object {
"id4": true,
},
"selectionElement": null,
"shouldAddWatermark": false,
"shouldCacheIgnoreZoom": false,
"showShortcutsDialog": false,
"username": "",
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
"zoom": 1,
}
`;
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] element 0 1`] = `
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [
"id4",
],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 3,
"versionNonce": 1150084233,
"width": 10,
"x": 10,
"y": 10,
}
`;
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] element 1 1`] = `
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [
"id4",
],
"height": 10,
"id": "id1",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 449462985,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 3,
"versionNonce": 1116226695,
"width": 10,
"x": 30,
"y": 10,
}
`;
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] history 1`] = `
Object {
"recording": false,
"redoStack": Array [],
"stateHistory": Array [
Object {
"appState": Object {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": Object {
"id0": true,
},
"viewBackgroundColor": "#ffffff",
},
"elements": Array [
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 1278240551,
"width": 10,
"x": 10,
"y": 10,
},
],
},
Object {
"appState": Object {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": Object {
"id1": true,
},
"viewBackgroundColor": "#ffffff",
},
"elements": Array [
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 1278240551,
"width": 10,
"x": 10,
"y": 10,
},
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [],
"height": 10,
"id": "id1",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 449462985,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 2,
"versionNonce": 453191,
"width": 10,
"x": 30,
"y": 10,
},
],
},
Object {
"appState": Object {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": Object {
"id0": true,
"id1": true,
"id2": true,
"id3": true,
},
"viewBackgroundColor": "#ffffff",
},
"elements": Array [
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [
"id4",
],
"height": 10,
"id": "id0",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 337897,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 3,
"versionNonce": 1150084233,
"width": 10,
"x": 10,
"y": 10,
},
Object {
"angle": 0,
"backgroundColor": "transparent",
"fillStyle": "hachure",
"groupIds": Array [
"id4",
],
"height": 10,
"id": "id1",
"isDeleted": false,
"opacity": 100,
"roughness": 1,
"seed": 449462985,
"strokeColor": "#000000",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"version": 3,
"versionNonce": 1116226695,
"width": 10,
"x": 30,
"y": 10,
},
],
},
],
}
`;
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of elements 1`] = `2`;
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of renders 1`] = `16`;
exports[`regression tests shows context menu for canvas: [end of test] appState 1`] = `
Object {
"collaborators": Map {},

View File

@ -878,6 +878,93 @@ describe("regression tests", () => {
mouse.down(10, 10);
mouse.up(20, 20);
fireEvent.contextMenu(canvas, { button: 2, clientX: 1, clientY: 1 });
const contextMenu = document.querySelector(".context-menu");
const options = contextMenu?.querySelectorAll(".context-menu-option");
const expectedOptions = [
"Copy styles",
"Paste styles",
"Delete",
"Send backward",
"Bring forward",
"Send to back",
"Bring to front",
"Duplicate",
];
expect(contextMenu).not.toBeNull();
expect(contextMenu?.children.length).toBe(8);
options?.forEach((opt, i) => {
expect(opt.textContent).toBe(expectedOptions[i]);
});
});
it("shows 'Group selection' in context menu for multiple selected elements", () => {
fireEvent.change(document.querySelector(".dropdown-select__language")!, {
target: { value: "en" },
});
clickTool("rectangle");
mouse.down(10, 10);
mouse.up(10, 10);
clickTool("rectangle");
mouse.down(10, -10);
mouse.up(10, 10);
mouse.reset();
mouse.click(10, 10);
withModifierKeys({ shift: true }, () => {
mouse.click(20, 0);
});
fireEvent.contextMenu(canvas, { button: 2, clientX: 1, clientY: 1 });
const contextMenu = document.querySelector(".context-menu");
const options = contextMenu?.querySelectorAll(".context-menu-option");
const expectedOptions = [
"Copy styles",
"Paste styles",
"Delete",
"Group selection",
"Send backward",
"Bring forward",
"Send to back",
"Bring to front",
"Duplicate",
];
expect(contextMenu).not.toBeNull();
expect(contextMenu?.children.length).toBe(9);
options?.forEach((opt, i) => {
expect(opt.textContent).toBe(expectedOptions[i]);
});
});
it("shows 'Ungroup selection' in context menu for group inside selected elements", () => {
fireEvent.change(document.querySelector(".dropdown-select__language")!, {
target: { value: "en" },
});
clickTool("rectangle");
mouse.down(10, 10);
mouse.up(10, 10);
clickTool("rectangle");
mouse.down(10, -10);
mouse.up(10, 10);
mouse.reset();
mouse.click(10, 10);
withModifierKeys({ shift: true }, () => {
mouse.click(20, 0);
});
withModifierKeys({ ctrl: true }, () => {
keyPress("g");
});
fireEvent.contextMenu(canvas, { button: 2, clientX: 1, clientY: 1 });
const contextMenu = document.querySelector(".context-menu");
const options = contextMenu?.querySelectorAll(".context-menu-option");
const expectedOptions = [