Skip to content

Commit 24e3700

Browse files
huntiemeta-codesync[bot]
authored andcommitted
Integrate app menu with DevTools features, add icons (#57421)
Summary: Pull Request resolved: #57421 UX polish: Refine RNDT desktop app with new menu items mapping to key features inside the DevTools UI, and add menu item icons (macOS 26+). **New/changed menu items** - **[New] File > Reload App** - Unify cmd+R logic — explicitly bound to "Reload App". - **[New] File > Reload DevTools** - opt+R — reinstates above - Note: Reloading and force-reloading the debugger-frontend's UI can also be done with cmd+R and cmd+shift+R *from a DevTools-on-DevTools window*. - **[New] File > QuickOpen…** - **[New] View > Command Palette…** - **[Changed] View > Toggle Developer Tools** - Shown in debug builds only. Delete Reload and Force Reload items here (per above). - **[New] Help > Keyboard Shortcuts** - Simplify Edit menu options. **Notes** - Icons are configured on macOS 26+ only, and we've left the `{role: '<name>'}` icon templates alone (should be managed upstream in Electron, although today these icons are missing in some cases). See electron/electron#50609, electron/electron#48909. Changelog: [General][Changed] - **React Native DevTools**: Expose new options in the app menu Reviewed By: motiz88 Differential Revision: D94527813 fbshipit-source-id: e56a83c620efd2a2b41e3e7645a0fe987148de46
1 parent 7d7bcbe commit 24e3700

3 files changed

Lines changed: 149 additions & 29 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
const {BrowserWindow, Menu, app, nativeImage, shell} =
12+
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
13+
require('electron') as any;
14+
15+
const {isMacOSAtLeast} = require('./utils');
16+
17+
export function configureAppMenu(): void {
18+
const template = [
19+
...(process.platform === 'darwin' ? [{role: 'appMenu'}] : []),
20+
{
21+
label: 'File',
22+
submenu: [
23+
{
24+
label: 'Reload App',
25+
accelerator:
26+
process.platform === 'darwin' ? 'Command+R' : 'Control+R',
27+
click: () => invokeCommand('inspector-main.reload'),
28+
},
29+
{
30+
label: 'Reload DevTools',
31+
accelerator: process.platform === 'darwin' ? 'Option+R' : 'Alt+R',
32+
click: () => BrowserWindow.getFocusedWindow()?.webContents.reload(),
33+
},
34+
{type: 'separator'},
35+
{
36+
label: 'Quick Open…',
37+
...menuSymbol('doc.text.magnifyingglass'),
38+
accelerator:
39+
process.platform === 'darwin' ? 'Command+P' : 'Control+P',
40+
click: () => invokeCommand('quick-open.show'),
41+
},
42+
{type: 'separator'},
43+
{role: 'close'},
44+
],
45+
},
46+
{
47+
label: 'Edit',
48+
submenu: [
49+
{role: 'undo'},
50+
{role: 'redo'},
51+
{type: 'separator'},
52+
{role: 'cut'},
53+
{role: 'copy'},
54+
{role: 'paste'},
55+
{role: 'selectAll'},
56+
],
57+
},
58+
{
59+
label: 'View',
60+
submenu: [
61+
{
62+
label: 'Command Palette…',
63+
...menuSymbol('filemenu.and.selection'),
64+
accelerator:
65+
process.platform === 'darwin'
66+
? 'Command+Shift+P'
67+
: 'Control+Shift+P',
68+
click: () => invokeCommand('quick-open.show-command-menu'),
69+
},
70+
// Enable Developer Tools only in development
71+
...(!app.isPackaged
72+
? [{type: 'separator'}, {role: 'toggleDevTools'}]
73+
: []),
74+
{type: 'separator'},
75+
{role: 'resetZoom'},
76+
{role: 'zoomIn'},
77+
{role: 'zoomOut'},
78+
{type: 'separator'},
79+
{role: 'togglefullscreen'},
80+
],
81+
},
82+
{role: 'windowMenu'},
83+
{
84+
role: 'help',
85+
submenu: [
86+
{
87+
label: 'Keyboard Shortcuts',
88+
...menuSymbol('keyboard'),
89+
click: () => invokeCommand('settings.shortcuts'),
90+
},
91+
{type: 'separator'},
92+
{
93+
label: 'React Native Website',
94+
click: () => shell.openExternal('https://reactnative.dev'),
95+
},
96+
{
97+
label: 'Release Notes',
98+
click: () =>
99+
shell.openExternal(
100+
'https://github.com/facebook/react-native/releases',
101+
),
102+
},
103+
],
104+
},
105+
];
106+
const menu = Menu.buildFromTemplate(template);
107+
Menu.setApplicationMenu(menu);
108+
}
109+
110+
function menuSymbol(symbolName: string): {icon?: unknown} {
111+
if (!isMacOSAtLeast(26)) {
112+
return {};
113+
}
114+
return {
115+
icon: nativeImage.createMenuSymbol(symbolName),
116+
};
117+
}
118+
119+
function invokeCommand(commandId: string): void {
120+
const win = BrowserWindow.getFocusedWindow();
121+
win?.webContents.executeJavaScript(
122+
`(async () => {
123+
const UI = await import('./ui/legacy/legacy.js');
124+
return UI.ActionRegistry.ActionRegistry.instance()
125+
.getAction(${JSON.stringify(commandId)})?.execute();
126+
})()`,
127+
true,
128+
);
129+
}

packages/debugger-shell/src/electron/MainInstanceEntryPoint.js

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
* @format
99
*/
1010

11+
import {configureAppMenu} from './AppMenu.js';
1112
import SettingsStore from './SettingsStore.js';
1213

1314
const path = require('path');
1415
const util = require('util');
1516

1617
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
17-
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
18+
const {BrowserWindow, app, shell, ipcMain} = require('electron') as any;
1819

1920
const appSettings = new SettingsStore();
2021
const windowMetadata = new WeakMap<
@@ -102,34 +103,6 @@ function handleLaunchArgs(argv: string[]) {
102103
frontendWindow.focus();
103104
}
104105

105-
function configureAppMenu() {
106-
const template = [
107-
...(process.platform === 'darwin' ? [{role: 'appMenu'}] : []),
108-
{role: 'fileMenu'},
109-
{role: 'editMenu'},
110-
{role: 'viewMenu'},
111-
{role: 'windowMenu'},
112-
{
113-
role: 'help',
114-
submenu: [
115-
{
116-
label: 'React Native Website',
117-
click: () => shell.openExternal('https://reactnative.dev'),
118-
},
119-
{
120-
label: 'Release Notes',
121-
click: () =>
122-
shell.openExternal(
123-
'https://github.com/facebook/react-native/releases',
124-
),
125-
},
126-
],
127-
},
128-
];
129-
const menu = Menu.buildFromTemplate(template);
130-
Menu.setApplicationMenu(menu);
131-
}
132-
133106
function getSavedWindowPosition(
134107
windowKey: string,
135108
): ?{width: number, height: number, x?: number, y?: number} {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
/** Equivalent of Swift's `if #available(macOS 26, *)`. */
12+
export function isMacOSAtLeast(major: number): boolean {
13+
return (
14+
process.platform === 'darwin' &&
15+
// $FlowFixMe[prop-missing]
16+
Number.parseInt(process.getSystemVersion().split('.')[0], 10) >= major
17+
);
18+
}

0 commit comments

Comments
 (0)