Skip to content

Commit b8f0451

Browse files
authored
Do not close context menu when clicking on checkbox items (#4690)
1 parent 4a807b6 commit b8f0451

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

newIDE/app/src/UI/Menu/ContextMenu.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Fade from '@material-ui/core/Fade';
88
import ElectronMenuImplementation from './ElectronMenuImplementation';
99
import MaterialUIMenuImplementation from './MaterialUIMenuImplementation';
1010
import optionalRequire from '../../Utils/OptionalRequire';
11+
import useForceUpdate from '../../Utils/UseForceUpdate';
1112
const electron = optionalRequire('electron');
1213

1314
export type ContextMenuInterface = {|
@@ -28,6 +29,7 @@ const MaterialUIContextMenu = React.forwardRef<
2829
]);
2930
const [openMenu, setOpenMenu] = React.useState<boolean>(false);
3031
const [buildOptions, setBuildOptions] = React.useState<any>({});
32+
const forceUpdate = useForceUpdate();
3133

3234
const menuImplementation = new MaterialUIMenuImplementation({
3335
onClose: () => setOpenMenu(false),
@@ -58,7 +60,8 @@ const MaterialUIContextMenu = React.forwardRef<
5860
{...menuImplementation.getMenuProps()}
5961
>
6062
{menuImplementation.buildFromTemplate(
61-
props.buildMenuTemplate(i18n, buildOptions)
63+
props.buildMenuTemplate(i18n, buildOptions),
64+
forceUpdate
6265
)}
6366
</Menu>
6467
)}

newIDE/app/src/UI/Menu/ElectronMenuImplementation.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
1+
// @flow
12
import optionalRequire from '../../Utils/OptionalRequire';
3+
import {
4+
type MenuItemTemplate,
5+
type ContextMenuImplementation,
6+
} from './Menu.flow';
27
const electron = optionalRequire('electron');
38
const remote = optionalRequire('@electron/remote');
49

510
/**
611
* Wraps an Electron Menu
712
*/
8-
export default class ElectronMenuImplementation {
9-
buildFromTemplate(template) {
13+
export default class ElectronMenuImplementation
14+
implements ContextMenuImplementation {
15+
menuTemplate: Array<MenuItemTemplate>;
16+
menu: any; // TODO: Is it necessary to store the menu in a class variable?
17+
18+
buildFromTemplate(template: Array<MenuItemTemplate>) {
1019
this.menuTemplate = template;
1120
return undefined;
1221
}
1322

14-
showMenu(dimensions) {
23+
showMenu(dimensions: {|
24+
left: number,
25+
top: number,
26+
width: number,
27+
height: number,
28+
|}) {
1529
if (!electron) return;
1630

1731
const { Menu } = remote;

newIDE/app/src/UI/Menu/MaterialUIMenuImplementation.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import Divider from '@material-ui/core/Divider';
1111
import Fade from '@material-ui/core/Fade';
1212
import makeStyles from '@material-ui/styles/makeStyles';
1313
import { adaptAcceleratorString } from '../AcceleratorString';
14-
import { type MenuItemTemplate } from './Menu.flow';
14+
import {
15+
type MenuItemTemplate,
16+
type ContextMenuImplementation,
17+
} from './Menu.flow';
1518

1619
const useStyles = makeStyles({
1720
backdropRootForMouse: {
@@ -185,13 +188,17 @@ const SubMenuItem = ({ item, buildFromTemplate }) => {
185188
* - checked (when `type` is 'checkbox')
186189
* - submenu
187190
*/
188-
export default class MaterialUIMenuImplementation {
191+
export default class MaterialUIMenuImplementation
192+
implements ContextMenuImplementation {
189193
_onClose: () => void;
190194
constructor({ onClose }: {| onClose: () => void |}) {
191195
this._onClose = onClose;
192196
}
193197

194-
buildFromTemplate(template: Array<MenuItemTemplate>) {
198+
buildFromTemplate(
199+
template: Array<MenuItemTemplate>,
200+
forceUpdate?: () => void
201+
) {
195202
return template
196203
.map((item, id) => {
197204
if (item.visible === false) return null;
@@ -215,13 +222,20 @@ export default class MaterialUIMenuImplementation {
215222
// $FlowFixMe - existence should be inferred by Flow.
216223
item.enabled === false
217224
}
218-
onClick={() => {
225+
onClick={async () => {
219226
if (item.enabled === false) {
220227
return;
221228
}
222229

223230
if (item.click) {
224-
item.click();
231+
await item.click();
232+
if (item.type === 'checkbox') {
233+
// In case the item click function changes something that React does not detect,
234+
// for instance a change in the project/layout C++ object, the menu must be
235+
// manually updated to display the change.
236+
if (forceUpdate) forceUpdate();
237+
return;
238+
}
225239
}
226240
this._onClose();
227241
}}
@@ -238,7 +252,9 @@ export default class MaterialUIMenuImplementation {
238252
<SubMenuItem
239253
key={'submenu' + item.label}
240254
item={item}
241-
buildFromTemplate={template => this.buildFromTemplate(template)}
255+
buildFromTemplate={template =>
256+
this.buildFromTemplate(template, forceUpdate)
257+
}
242258
/>
243259
);
244260
} else {

newIDE/app/src/UI/Menu/Menu.flow.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// @flow
22

3+
import { type Node as ReactNode } from 'react';
4+
35
/**
46
* The type describing a menu item supported both as in an Electron
57
* menu and as a material-ui menu (for the web-app).
@@ -33,6 +35,19 @@ export type MenuItemTemplate =
3335
type: 'separator',
3436
|};
3537

38+
export interface ContextMenuImplementation {
39+
buildFromTemplate(
40+
template: Array<MenuItemTemplate>,
41+
forceUpdate?: () => void
42+
): ?ReactNode;
43+
showMenu(dimensions: {|
44+
left: number,
45+
top: number,
46+
width: number,
47+
height: number,
48+
|}): void;
49+
}
50+
3651
/**
3752
* The type describing a menu item without any function for the clicks.
3853
* Instead, `onClickSendEvent` or `onClickOpenLink` are plain strings

0 commit comments

Comments
 (0)