Skip to content

Commit 71a7e1b

Browse files
authored
chore: tsify menu (electron#24358)
1 parent 2a3437e commit 71a7e1b

File tree

8 files changed

+156
-131
lines changed

8 files changed

+156
-131
lines changed

docs/api/menu.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ Appends the `menuItem` to the menu.
9696

9797
* `id` String
9898

99-
Returns `MenuItem` the item with the specified `id`
99+
Returns `MenuItem | null` the item with the specified `id`
100100

101101
#### `menu.insert(pos, menuItem)`
102102

filenames.auto.gni

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,10 @@ auto_filenames = {
201201
"lib/browser/api/global-shortcut.ts",
202202
"lib/browser/api/in-app-purchase.ts",
203203
"lib/browser/api/ipc-main.ts",
204-
"lib/browser/api/menu-item-roles.js",
205-
"lib/browser/api/menu-item.js",
206-
"lib/browser/api/menu-utils.js",
207-
"lib/browser/api/menu.js",
204+
"lib/browser/api/menu-item-roles.ts",
205+
"lib/browser/api/menu-item.ts",
206+
"lib/browser/api/menu-utils.ts",
207+
"lib/browser/api/menu.ts",
208208
"lib/browser/api/message-channel.ts",
209209
"lib/browser/api/module-list.ts",
210210
"lib/browser/api/native-theme.ts",

lib/browser/api/menu-item-roles.js renamed to lib/browser/api/menu-item-roles.ts

Lines changed: 62 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,56 @@
1-
'use strict';
2-
3-
const { app } = require('electron');
1+
import { app, BrowserWindow, WebContents, MenuItemConstructorOptions } from 'electron';
42

53
const isMac = process.platform === 'darwin';
64
const isWindows = process.platform === 'win32';
75
const isLinux = process.platform === 'linux';
86

9-
const roles = {
7+
type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' |
8+
'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' |
9+
'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu'
10+
interface Role {
11+
label: string;
12+
accelerator?: string;
13+
windowMethod?: ((window: BrowserWindow) => void);
14+
webContentsMethod?: ((webContents: WebContents) => void);
15+
appMethod?: () => void;
16+
registerAccelerator?: boolean;
17+
nonNativeMacOSRole?: boolean;
18+
submenu?: MenuItemConstructorOptions[];
19+
}
20+
21+
export const roleList: Record<RoleId, Role> = {
1022
about: {
1123
get label () {
1224
return isLinux ? 'About' : `About ${app.name}`;
1325
},
14-
...(isWindows && { appMethod: 'showAboutPanel' })
26+
...(isWindows && { appMethod: () => app.showAboutPanel() })
1527
},
1628
close: {
1729
label: isMac ? 'Close Window' : 'Close',
1830
accelerator: 'CommandOrControl+W',
19-
windowMethod: 'close'
31+
windowMethod: w => w.close()
2032
},
2133
copy: {
2234
label: 'Copy',
2335
accelerator: 'CommandOrControl+C',
24-
webContentsMethod: 'copy',
36+
webContentsMethod: wc => wc.copy(),
2537
registerAccelerator: false
2638
},
2739
cut: {
2840
label: 'Cut',
2941
accelerator: 'CommandOrControl+X',
30-
webContentsMethod: 'cut',
42+
webContentsMethod: wc => wc.cut(),
3143
registerAccelerator: false
3244
},
3345
delete: {
3446
label: 'Delete',
35-
webContentsMethod: 'delete'
47+
webContentsMethod: wc => wc.delete()
3648
},
3749
forcereload: {
3850
label: 'Force Reload',
3951
accelerator: 'Shift+CmdOrCtrl+R',
4052
nonNativeMacOSRole: true,
41-
windowMethod: (window) => {
53+
windowMethod: (window: BrowserWindow) => {
4254
window.webContents.reloadIgnoringCache();
4355
}
4456
},
@@ -61,18 +73,18 @@ const roles = {
6173
minimize: {
6274
label: 'Minimize',
6375
accelerator: 'CommandOrControl+M',
64-
windowMethod: 'minimize'
76+
windowMethod: w => w.minimize()
6577
},
6678
paste: {
6779
label: 'Paste',
6880
accelerator: 'CommandOrControl+V',
69-
webContentsMethod: 'paste',
81+
webContentsMethod: wc => wc.paste(),
7082
registerAccelerator: false
7183
},
7284
pasteandmatchstyle: {
7385
label: 'Paste and Match Style',
7486
accelerator: isMac ? 'Cmd+Option+Shift+V' : 'Shift+CommandOrControl+V',
75-
webContentsMethod: 'pasteAndMatchStyle',
87+
webContentsMethod: wc => wc.pasteAndMatchStyle(),
7688
registerAccelerator: false
7789
},
7890
quit: {
@@ -84,31 +96,31 @@ const roles = {
8496
}
8597
},
8698
accelerator: isWindows ? undefined : 'CommandOrControl+Q',
87-
appMethod: 'quit'
99+
appMethod: () => app.quit()
88100
},
89101
redo: {
90102
label: 'Redo',
91103
accelerator: isWindows ? 'Control+Y' : 'Shift+CommandOrControl+Z',
92-
webContentsMethod: 'redo'
104+
webContentsMethod: wc => wc.redo()
93105
},
94106
reload: {
95107
label: 'Reload',
96108
accelerator: 'CmdOrCtrl+R',
97109
nonNativeMacOSRole: true,
98-
windowMethod: 'reload'
110+
windowMethod: w => w.reload()
99111
},
100112
resetzoom: {
101113
label: 'Actual Size',
102114
accelerator: 'CommandOrControl+0',
103115
nonNativeMacOSRole: true,
104-
webContentsMethod: (webContents) => {
116+
webContentsMethod: (webContents: WebContents) => {
105117
webContents.zoomLevel = 0;
106118
}
107119
},
108120
selectall: {
109121
label: 'Select All',
110122
accelerator: 'CommandOrControl+A',
111-
webContentsMethod: 'selectAll'
123+
webContentsMethod: wc => wc.selectAll()
112124
},
113125
services: {
114126
label: 'Services'
@@ -129,19 +141,19 @@ const roles = {
129141
label: 'Toggle Developer Tools',
130142
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
131143
nonNativeMacOSRole: true,
132-
windowMethod: 'toggleDevTools'
144+
windowMethod: w => w.webContents.toggleDevTools()
133145
},
134146
togglefullscreen: {
135147
label: 'Toggle Full Screen',
136148
accelerator: isMac ? 'Control+Command+F' : 'F11',
137-
windowMethod: (window) => {
149+
windowMethod: (window: BrowserWindow) => {
138150
window.setFullScreen(!window.isFullScreen());
139151
}
140152
},
141153
undo: {
142154
label: 'Undo',
143155
accelerator: 'CommandOrControl+Z',
144-
webContentsMethod: 'undo'
156+
webContentsMethod: wc => wc.undo()
145157
},
146158
unhide: {
147159
label: 'Show All'
@@ -156,15 +168,15 @@ const roles = {
156168
label: 'Zoom In',
157169
accelerator: 'CommandOrControl+Plus',
158170
nonNativeMacOSRole: true,
159-
webContentsMethod: (webContents) => {
171+
webContentsMethod: (webContents: WebContents) => {
160172
webContents.zoomLevel += 0.5;
161173
}
162174
},
163175
zoomout: {
164176
label: 'Zoom Out',
165177
accelerator: 'CommandOrControl+-',
166178
nonNativeMacOSRole: true,
167-
webContentsMethod: (webContents) => {
179+
webContentsMethod: (webContents: WebContents) => {
168180
webContents.zoomLevel -= 0.5;
169181
}
170182
},
@@ -214,11 +226,11 @@ const roles = {
214226
{ role: 'stopSpeaking' }
215227
]
216228
}
217-
] : [
229+
] as MenuItemConstructorOptions[] : [
218230
{ role: 'delete' },
219231
{ type: 'separator' },
220232
{ role: 'selectAll' }
221-
])
233+
] as MenuItemConstructorOptions[])
222234
]
223235
},
224236
// View submenu
@@ -245,76 +257,66 @@ const roles = {
245257
...(isMac ? [
246258
{ type: 'separator' },
247259
{ role: 'front' }
248-
] : [
260+
] as MenuItemConstructorOptions[] : [
249261
{ role: 'close' }
250-
])
262+
] as MenuItemConstructorOptions[])
251263
]
252264
}
253265
};
254266

255-
exports.roleList = roles;
256-
257-
const canExecuteRole = (role) => {
258-
if (!Object.prototype.hasOwnProperty.call(roles, role)) return false;
267+
const canExecuteRole = (role: keyof typeof roleList) => {
268+
if (!Object.prototype.hasOwnProperty.call(roleList, role)) return false;
259269
if (!isMac) return true;
260270

261271
// macOS handles all roles natively except for a few
262-
return roles[role].nonNativeMacOSRole;
272+
return roleList[role].nonNativeMacOSRole;
263273
};
264274

265-
exports.getDefaultLabel = (role) => {
266-
return Object.prototype.hasOwnProperty.call(roles, role) ? roles[role].label : '';
267-
};
275+
export function getDefaultLabel (role: RoleId) {
276+
return Object.prototype.hasOwnProperty.call(roleList, role) ? roleList[role].label : '';
277+
}
268278

269-
exports.getDefaultAccelerator = (role) => {
270-
if (Object.prototype.hasOwnProperty.call(roles, role)) return roles[role].accelerator;
271-
};
279+
export function getDefaultAccelerator (role: RoleId) {
280+
if (Object.prototype.hasOwnProperty.call(roleList, role)) return roleList[role].accelerator;
281+
}
272282

273-
exports.shouldRegisterAccelerator = (role) => {
274-
const hasRoleRegister = Object.prototype.hasOwnProperty.call(roles, role) && roles[role].registerAccelerator !== undefined;
275-
return hasRoleRegister ? roles[role].registerAccelerator : true;
276-
};
283+
export function shouldRegisterAccelerator (role: RoleId) {
284+
const hasRoleRegister = Object.prototype.hasOwnProperty.call(roleList, role) && roleList[role].registerAccelerator !== undefined;
285+
return hasRoleRegister ? roleList[role].registerAccelerator : true;
286+
}
277287

278-
exports.getDefaultSubmenu = (role) => {
279-
if (!Object.prototype.hasOwnProperty.call(roles, role)) return;
288+
export function getDefaultSubmenu (role: RoleId) {
289+
if (!Object.prototype.hasOwnProperty.call(roleList, role)) return;
280290

281-
let { submenu } = roles[role];
291+
let { submenu } = roleList[role];
282292

283293
// remove null items from within the submenu
284294
if (Array.isArray(submenu)) {
285295
submenu = submenu.filter((item) => item != null);
286296
}
287297

288298
return submenu;
289-
};
299+
}
290300

291-
exports.execute = (role, focusedWindow, focusedWebContents) => {
301+
export function execute (role: RoleId, focusedWindow: BrowserWindow, focusedWebContents: WebContents) {
292302
if (!canExecuteRole(role)) return false;
293303

294-
const { appMethod, webContentsMethod, windowMethod } = roles[role];
304+
const { appMethod, webContentsMethod, windowMethod } = roleList[role];
295305

296306
if (appMethod) {
297-
app[appMethod]();
307+
appMethod();
298308
return true;
299309
}
300310

301311
if (windowMethod && focusedWindow != null) {
302-
if (typeof windowMethod === 'function') {
303-
windowMethod(focusedWindow);
304-
} else {
305-
focusedWindow[windowMethod]();
306-
}
312+
windowMethod(focusedWindow);
307313
return true;
308314
}
309315

310316
if (webContentsMethod && focusedWebContents != null) {
311-
if (typeof webContentsMethod === 'function') {
312-
webContentsMethod(focusedWebContents);
313-
} else {
314-
focusedWebContents[webContentsMethod]();
315-
}
317+
webContentsMethod(focusedWebContents);
316318
return true;
317319
}
318320

319321
return false;
320-
};
322+
}

lib/browser/api/menu-item.js renamed to lib/browser/api/menu-item.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
'use strict';
2-
3-
const roles = require('@electron/internal/browser/api/menu-item-roles');
1+
import * as roles from './menu-item-roles';
2+
import { Menu, Event, BrowserWindow, WebContents } from 'electron';
43

54
let nextCommandId = 0;
65

7-
const MenuItem = function (options) {
8-
const { Menu } = require('electron');
9-
6+
const MenuItem = function (this: any, options: any) {
107
// Preserve extra fields specified by user
118
for (const key in options) {
129
if (!(key in this)) this[key] = options[key];
@@ -47,7 +44,7 @@ const MenuItem = function (options) {
4744
this.overrideReadOnlyProperty('commandId', ++nextCommandId);
4845

4946
const click = options.click;
50-
this.click = (event, focusedWindow, focusedWebContents) => {
47+
this.click = (event: Event, focusedWindow: BrowserWindow, focusedWebContents: WebContents) => {
5148
// Manually flip the checked flags when clicked.
5249
if (this.type === 'checkbox' || this.type === 'radio') {
5350
this.checked = !this.checked;
@@ -69,13 +66,13 @@ MenuItem.prototype.getDefaultRoleAccelerator = function () {
6966
return roles.getDefaultAccelerator(this.role);
7067
};
7168

72-
MenuItem.prototype.overrideProperty = function (name, defaultValue = null) {
69+
MenuItem.prototype.overrideProperty = function (name: string, defaultValue: any = null) {
7370
if (this[name] == null) {
7471
this[name] = defaultValue;
7572
}
7673
};
7774

78-
MenuItem.prototype.overrideReadOnlyProperty = function (name, defaultValue) {
75+
MenuItem.prototype.overrideReadOnlyProperty = function (name: string, defaultValue: any) {
7976
this.overrideProperty(name, defaultValue);
8077
Object.defineProperty(this, name, {
8178
enumerable: true,

0 commit comments

Comments
 (0)