diff --git a/docs/api/menu.md b/docs/api/menu.md index cd9e177ae0..486054a224 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -96,7 +96,7 @@ Appends the `menuItem` to the menu. * `id` String -Returns `MenuItem` the item with the specified `id` +Returns `MenuItem | null` the item with the specified `id` #### `menu.insert(pos, menuItem)` diff --git a/filenames.auto.gni b/filenames.auto.gni index 375d77e82a..e5c977ac90 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -201,10 +201,10 @@ auto_filenames = { "lib/browser/api/global-shortcut.ts", "lib/browser/api/in-app-purchase.ts", "lib/browser/api/ipc-main.ts", - "lib/browser/api/menu-item-roles.js", - "lib/browser/api/menu-item.js", - "lib/browser/api/menu-utils.js", - "lib/browser/api/menu.js", + "lib/browser/api/menu-item-roles.ts", + "lib/browser/api/menu-item.ts", + "lib/browser/api/menu-utils.ts", + "lib/browser/api/menu.ts", "lib/browser/api/message-channel.ts", "lib/browser/api/module-list.ts", "lib/browser/api/native-theme.ts", diff --git a/lib/browser/api/menu-item-roles.js b/lib/browser/api/menu-item-roles.ts similarity index 63% rename from lib/browser/api/menu-item-roles.js rename to lib/browser/api/menu-item-roles.ts index 3b2bd73259..189a728b75 100644 --- a/lib/browser/api/menu-item-roles.js +++ b/lib/browser/api/menu-item-roles.ts @@ -1,44 +1,56 @@ -'use strict'; - -const { app } = require('electron'); +import { app, BrowserWindow, WebContents, MenuItemConstructorOptions } from 'electron'; const isMac = process.platform === 'darwin'; const isWindows = process.platform === 'win32'; const isLinux = process.platform === 'linux'; -const roles = { +type RoleId = 'about' | 'close' | 'copy' | 'cut' | 'delete' | 'forcereload' | 'front' | 'help' | 'hide' | 'hideothers' | 'minimize' | + 'paste' | 'pasteandmatchstyle' | 'quit' | 'redo' | 'reload' | 'resetzoom' | 'selectall' | 'services' | 'recentdocuments' | 'clearrecentdocuments' | 'startspeaking' | 'stopspeaking' | + 'toggledevtools' | 'togglefullscreen' | 'undo' | 'unhide' | 'window' | 'zoom' | 'zoomin' | 'zoomout' | 'appmenu' | 'filemenu' | 'editmenu' | 'viewmenu' | 'windowmenu' +interface Role { + label: string; + accelerator?: string; + windowMethod?: ((window: BrowserWindow) => void); + webContentsMethod?: ((webContents: WebContents) => void); + appMethod?: () => void; + registerAccelerator?: boolean; + nonNativeMacOSRole?: boolean; + submenu?: MenuItemConstructorOptions[]; +} + +export const roleList: Record = { about: { get label () { return isLinux ? 'About' : `About ${app.name}`; }, - ...(isWindows && { appMethod: 'showAboutPanel' }) + ...(isWindows && { appMethod: () => app.showAboutPanel() }) }, close: { label: isMac ? 'Close Window' : 'Close', accelerator: 'CommandOrControl+W', - windowMethod: 'close' + windowMethod: w => w.close() }, copy: { label: 'Copy', accelerator: 'CommandOrControl+C', - webContentsMethod: 'copy', + webContentsMethod: wc => wc.copy(), registerAccelerator: false }, cut: { label: 'Cut', accelerator: 'CommandOrControl+X', - webContentsMethod: 'cut', + webContentsMethod: wc => wc.cut(), registerAccelerator: false }, delete: { label: 'Delete', - webContentsMethod: 'delete' + webContentsMethod: wc => wc.delete() }, forcereload: { label: 'Force Reload', accelerator: 'Shift+CmdOrCtrl+R', nonNativeMacOSRole: true, - windowMethod: (window) => { + windowMethod: (window: BrowserWindow) => { window.webContents.reloadIgnoringCache(); } }, @@ -61,18 +73,18 @@ const roles = { minimize: { label: 'Minimize', accelerator: 'CommandOrControl+M', - windowMethod: 'minimize' + windowMethod: w => w.minimize() }, paste: { label: 'Paste', accelerator: 'CommandOrControl+V', - webContentsMethod: 'paste', + webContentsMethod: wc => wc.paste(), registerAccelerator: false }, pasteandmatchstyle: { label: 'Paste and Match Style', accelerator: isMac ? 'Cmd+Option+Shift+V' : 'Shift+CommandOrControl+V', - webContentsMethod: 'pasteAndMatchStyle', + webContentsMethod: wc => wc.pasteAndMatchStyle(), registerAccelerator: false }, quit: { @@ -84,31 +96,31 @@ const roles = { } }, accelerator: isWindows ? undefined : 'CommandOrControl+Q', - appMethod: 'quit' + appMethod: () => app.quit() }, redo: { label: 'Redo', accelerator: isWindows ? 'Control+Y' : 'Shift+CommandOrControl+Z', - webContentsMethod: 'redo' + webContentsMethod: wc => wc.redo() }, reload: { label: 'Reload', accelerator: 'CmdOrCtrl+R', nonNativeMacOSRole: true, - windowMethod: 'reload' + windowMethod: w => w.reload() }, resetzoom: { label: 'Actual Size', accelerator: 'CommandOrControl+0', nonNativeMacOSRole: true, - webContentsMethod: (webContents) => { + webContentsMethod: (webContents: WebContents) => { webContents.zoomLevel = 0; } }, selectall: { label: 'Select All', accelerator: 'CommandOrControl+A', - webContentsMethod: 'selectAll' + webContentsMethod: wc => wc.selectAll() }, services: { label: 'Services' @@ -129,19 +141,19 @@ const roles = { label: 'Toggle Developer Tools', accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I', nonNativeMacOSRole: true, - windowMethod: 'toggleDevTools' + windowMethod: w => w.webContents.toggleDevTools() }, togglefullscreen: { label: 'Toggle Full Screen', accelerator: isMac ? 'Control+Command+F' : 'F11', - windowMethod: (window) => { + windowMethod: (window: BrowserWindow) => { window.setFullScreen(!window.isFullScreen()); } }, undo: { label: 'Undo', accelerator: 'CommandOrControl+Z', - webContentsMethod: 'undo' + webContentsMethod: wc => wc.undo() }, unhide: { label: 'Show All' @@ -156,7 +168,7 @@ const roles = { label: 'Zoom In', accelerator: 'CommandOrControl+Plus', nonNativeMacOSRole: true, - webContentsMethod: (webContents) => { + webContentsMethod: (webContents: WebContents) => { webContents.zoomLevel += 0.5; } }, @@ -164,7 +176,7 @@ const roles = { label: 'Zoom Out', accelerator: 'CommandOrControl+-', nonNativeMacOSRole: true, - webContentsMethod: (webContents) => { + webContentsMethod: (webContents: WebContents) => { webContents.zoomLevel -= 0.5; } }, @@ -214,11 +226,11 @@ const roles = { { role: 'stopSpeaking' } ] } - ] : [ + ] as MenuItemConstructorOptions[] : [ { role: 'delete' }, { type: 'separator' }, { role: 'selectAll' } - ]) + ] as MenuItemConstructorOptions[]) ] }, // View submenu @@ -245,40 +257,38 @@ const roles = { ...(isMac ? [ { type: 'separator' }, { role: 'front' } - ] : [ + ] as MenuItemConstructorOptions[] : [ { role: 'close' } - ]) + ] as MenuItemConstructorOptions[]) ] } }; -exports.roleList = roles; - -const canExecuteRole = (role) => { - if (!Object.prototype.hasOwnProperty.call(roles, role)) return false; +const canExecuteRole = (role: keyof typeof roleList) => { + if (!Object.prototype.hasOwnProperty.call(roleList, role)) return false; if (!isMac) return true; // macOS handles all roles natively except for a few - return roles[role].nonNativeMacOSRole; + return roleList[role].nonNativeMacOSRole; }; -exports.getDefaultLabel = (role) => { - return Object.prototype.hasOwnProperty.call(roles, role) ? roles[role].label : ''; -}; +export function getDefaultLabel (role: RoleId) { + return Object.prototype.hasOwnProperty.call(roleList, role) ? roleList[role].label : ''; +} -exports.getDefaultAccelerator = (role) => { - if (Object.prototype.hasOwnProperty.call(roles, role)) return roles[role].accelerator; -}; +export function getDefaultAccelerator (role: RoleId) { + if (Object.prototype.hasOwnProperty.call(roleList, role)) return roleList[role].accelerator; +} -exports.shouldRegisterAccelerator = (role) => { - const hasRoleRegister = Object.prototype.hasOwnProperty.call(roles, role) && roles[role].registerAccelerator !== undefined; - return hasRoleRegister ? roles[role].registerAccelerator : true; -}; +export function shouldRegisterAccelerator (role: RoleId) { + const hasRoleRegister = Object.prototype.hasOwnProperty.call(roleList, role) && roleList[role].registerAccelerator !== undefined; + return hasRoleRegister ? roleList[role].registerAccelerator : true; +} -exports.getDefaultSubmenu = (role) => { - if (!Object.prototype.hasOwnProperty.call(roles, role)) return; +export function getDefaultSubmenu (role: RoleId) { + if (!Object.prototype.hasOwnProperty.call(roleList, role)) return; - let { submenu } = roles[role]; + let { submenu } = roleList[role]; // remove null items from within the submenu if (Array.isArray(submenu)) { @@ -286,35 +296,27 @@ exports.getDefaultSubmenu = (role) => { } return submenu; -}; +} -exports.execute = (role, focusedWindow, focusedWebContents) => { +export function execute (role: RoleId, focusedWindow: BrowserWindow, focusedWebContents: WebContents) { if (!canExecuteRole(role)) return false; - const { appMethod, webContentsMethod, windowMethod } = roles[role]; + const { appMethod, webContentsMethod, windowMethod } = roleList[role]; if (appMethod) { - app[appMethod](); + appMethod(); return true; } if (windowMethod && focusedWindow != null) { - if (typeof windowMethod === 'function') { - windowMethod(focusedWindow); - } else { - focusedWindow[windowMethod](); - } + windowMethod(focusedWindow); return true; } if (webContentsMethod && focusedWebContents != null) { - if (typeof webContentsMethod === 'function') { - webContentsMethod(focusedWebContents); - } else { - focusedWebContents[webContentsMethod](); - } + webContentsMethod(focusedWebContents); return true; } return false; -}; +} diff --git a/lib/browser/api/menu-item.js b/lib/browser/api/menu-item.ts similarity index 84% rename from lib/browser/api/menu-item.js rename to lib/browser/api/menu-item.ts index 171f2ead06..123cb79cca 100644 --- a/lib/browser/api/menu-item.js +++ b/lib/browser/api/menu-item.ts @@ -1,12 +1,9 @@ -'use strict'; - -const roles = require('@electron/internal/browser/api/menu-item-roles'); +import * as roles from './menu-item-roles'; +import { Menu, Event, BrowserWindow, WebContents } from 'electron'; let nextCommandId = 0; -const MenuItem = function (options) { - const { Menu } = require('electron'); - +const MenuItem = function (this: any, options: any) { // Preserve extra fields specified by user for (const key in options) { if (!(key in this)) this[key] = options[key]; @@ -47,7 +44,7 @@ const MenuItem = function (options) { this.overrideReadOnlyProperty('commandId', ++nextCommandId); const click = options.click; - this.click = (event, focusedWindow, focusedWebContents) => { + this.click = (event: Event, focusedWindow: BrowserWindow, focusedWebContents: WebContents) => { // Manually flip the checked flags when clicked. if (this.type === 'checkbox' || this.type === 'radio') { this.checked = !this.checked; @@ -69,13 +66,13 @@ MenuItem.prototype.getDefaultRoleAccelerator = function () { return roles.getDefaultAccelerator(this.role); }; -MenuItem.prototype.overrideProperty = function (name, defaultValue = null) { +MenuItem.prototype.overrideProperty = function (name: string, defaultValue: any = null) { if (this[name] == null) { this[name] = defaultValue; } }; -MenuItem.prototype.overrideReadOnlyProperty = function (name, defaultValue) { +MenuItem.prototype.overrideReadOnlyProperty = function (name: string, defaultValue: any) { this.overrideProperty(name, defaultValue); Object.defineProperty(this, name, { enumerable: true, diff --git a/lib/browser/api/menu-utils.js b/lib/browser/api/menu-utils.ts similarity index 77% rename from lib/browser/api/menu-utils.js rename to lib/browser/api/menu-utils.ts index 493f04c19c..2bd83ace38 100644 --- a/lib/browser/api/menu-utils.js +++ b/lib/browser/api/menu-utils.ts @@ -1,6 +1,4 @@ -'use strict'; - -function splitArray (arr, predicate) { +function splitArray (arr: T[], predicate: (x: T) => boolean) { const result = arr.reduce((multi, item) => { const current = multi[multi.length - 1]; if (predicate(item)) { @@ -9,7 +7,7 @@ function splitArray (arr, predicate) { current.push(item); } return multi; - }, [[]]); + }, [[]] as T[][]); if (result[result.length - 1].length === 0) { return result.slice(0, result.length - 1); @@ -17,7 +15,7 @@ function splitArray (arr, predicate) { return result; } -function joinArrays (arrays, joinIDs) { +function joinArrays (arrays: any[][], joinIDs: any[]) { return arrays.reduce((joined, arr, i) => { if (i > 0 && arr.length) { if (joinIDs.length > 0) { @@ -31,14 +29,14 @@ function joinArrays (arrays, joinIDs) { }, []); } -function pushOntoMultiMap (map, key, value) { +function pushOntoMultiMap (map: Map, key: K, value: V) { if (!map.has(key)) { map.set(key, []); } - map.get(key).push(value); + map.get(key)!.push(value); } -function indexOfGroupContainingID (groups, id, ignoreGroup) { +function indexOfGroupContainingID (groups: {id?: T}[][], id: T, ignoreGroup: {id?: T}[]) { return groups.findIndex( candidateGroup => candidateGroup !== ignoreGroup && @@ -50,11 +48,11 @@ function indexOfGroupContainingID (groups, id, ignoreGroup) { // Sort nodes topologically using a depth-first approach. Encountered cycles // are broken. -function sortTopologically (originalOrder, edgesById) { - const sorted = []; - const marked = new Set(); +function sortTopologically (originalOrder: T[], edgesById: Map) { + const sorted = [] as T[]; + const marked = new Set(); - const visit = (mark) => { + const visit = (mark: T) => { if (marked.has(mark)) return; marked.add(mark); const edges = edgesById.get(mark); @@ -68,7 +66,7 @@ function sortTopologically (originalOrder, edgesById) { return sorted; } -function attemptToMergeAGroup (groups) { +function attemptToMergeAGroup (groups: {before?: T[], after?: T[], id?: T}[][]) { for (let i = 0; i < groups.length; i++) { const group = groups[i]; for (const item of group) { @@ -87,7 +85,7 @@ function attemptToMergeAGroup (groups) { return false; } -function mergeGroups (groups) { +function mergeGroups (groups: {before?: T[], after?: T[], id?: T}[][]) { let merged = true; while (merged) { merged = attemptToMergeAGroup(groups); @@ -95,7 +93,7 @@ function mergeGroups (groups) { return groups; } -function sortItemsInGroup (group) { +function sortItemsInGroup (group: {before?: T[], after?: T[], id?: T}[]) { const originalOrder = group.map((node, i) => i); const edges = new Map(); const idToIndex = new Map(group.map((item, i) => [item.id, i])); @@ -123,7 +121,7 @@ function sortItemsInGroup (group) { return sortedNodes.map(i => group[i]); } -function findEdgesInGroup (groups, i, edges) { +function findEdgesInGroup (groups: {beforeGroupContaining?: T[], afterGroupContaining?: T[], id?: T}[][], i: number, edges: Map) { const group = groups[i]; for (const item of group) { if (item.beforeGroupContaining) { @@ -147,7 +145,7 @@ function findEdgesInGroup (groups, i, edges) { } } -function sortGroups (groups) { +function sortGroups (groups: {id?: T}[][]) { const originalOrder = groups.map((item, i) => i); const edges = new Map(); @@ -159,8 +157,8 @@ function sortGroups (groups) { return sortedGroupIndexes.map(i => groups[i]); } -function sortMenuItems (menuItems) { - const isSeparator = (item) => item.type === 'separator'; +export function sortMenuItems (menuItems: {type?: string, id?: string}[]) { + const isSeparator = (item: {type?: string}) => item.type === 'separator'; const separators = menuItems.filter(i => i.type === 'separator'); // Split the items into their implicit groups based upon separators. @@ -172,5 +170,3 @@ function sortMenuItems (menuItems) { const joined = joinArrays(sortedGroups, separators); return joined; } - -module.exports = { sortMenuItems }; diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.ts similarity index 81% rename from lib/browser/api/menu.js rename to lib/browser/api/menu.ts index 81bc3c7784..adf2f75701 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.ts @@ -1,13 +1,11 @@ -'use strict'; +import { BaseWindow, MenuItem, webContents, Menu as MenuType, BrowserWindow, MenuItemConstructorOptions } from 'electron'; +import { sortMenuItems } from './menu-utils'; -const { BaseWindow, MenuItem, webContents } = require('electron'); -const { sortMenuItems } = require('@electron/internal/browser/api/menu-utils'); -const EventEmitter = require('events').EventEmitter; const v8Util = process._linkedBinding('electron_common_v8_util'); const bindings = process._linkedBinding('electron_browser_menu'); -const { Menu } = bindings; -let applicationMenu = null; +const { Menu } = bindings as { Menu: typeof MenuType }; +let applicationMenu: MenuType | null = null; let groupIdIndex = 0; /* Instance Methods */ @@ -19,17 +17,17 @@ Menu.prototype._init = function () { }; Menu.prototype._isCommandIdChecked = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].checked : undefined; + return this.commandsMap[id] ? this.commandsMap[id].checked : false; }; Menu.prototype._isCommandIdEnabled = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].enabled : undefined; + return this.commandsMap[id] ? this.commandsMap[id].enabled : false; }; Menu.prototype._shouldCommandIdWorkWhenHidden = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].acceleratorWorksWhenHidden : undefined; + return this.commandsMap[id] ? !!this.commandsMap[id].acceleratorWorksWhenHidden : false; }; Menu.prototype._isCommandIdVisible = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].visible : undefined; + return this.commandsMap[id] ? this.commandsMap[id].visible : false; }; Menu.prototype._getAcceleratorForCommandId = function (id, useDefaultAccelerator) { @@ -40,13 +38,14 @@ Menu.prototype._getAcceleratorForCommandId = function (id, useDefaultAccelerator }; Menu.prototype._shouldRegisterAcceleratorForCommandId = function (id) { - return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : undefined; + return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : false; }; Menu.prototype._executeCommand = function (event, id) { const command = this.commandsMap[id]; if (!command) return; - command.click(event, BaseWindow.getFocusedWindow(), webContents.getFocusedWebContents()); + const focusedWindow = BaseWindow.getFocusedWindow(); + command.click(event, focusedWindow instanceof BrowserWindow ? focusedWindow : undefined, webContents.getFocusedWebContents()); }; Menu.prototype._menuWillShow = function () { @@ -73,17 +72,17 @@ Menu.prototype.popup = function (options = {}) { // find which window to use const wins = BaseWindow.getAllWindows(); - if (!wins || wins.indexOf(window) === -1) { - window = BaseWindow.getFocusedWindow(); + if (!wins || wins.indexOf(window as any) === -1) { + window = BaseWindow.getFocusedWindow() as any; if (!window && wins && wins.length > 0) { - window = wins[0]; + window = wins[0] as any; } if (!window) { throw new Error('Cannot open Menu without a BaseWindow present'); } } - this.popupAt(window, x, y, positioningItem, callback); + this.popupAt(window as unknown as BaseWindow, x, y, positioningItem, callback); return { browserWindow: window, x, y, position: positioningItem }; }; @@ -102,8 +101,9 @@ Menu.prototype.getMenuItemById = function (id) { let found = items.find(item => item.id === id) || null; for (let i = 0; !found && i < items.length; i++) { - if (items[i].submenu) { - found = items[i].submenu.getMenuItemById(id); + const { submenu } = items[i]; + if (submenu) { + found = submenu.getMenuItemById(id); } } return found; @@ -155,7 +155,7 @@ Menu.getApplicationMenu = () => applicationMenu; Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder; // set application menu with a preexisting menu -Menu.setApplicationMenu = function (menu) { +Menu.setApplicationMenu = function (menu: MenuType) { if (menu && menu.constructor !== Menu) { throw new TypeError('Invalid menu'); } @@ -200,7 +200,7 @@ Menu.buildFromTemplate = function (template) { /* Helper Functions */ // validate the template against having the wrong attribute -function areValidTemplateItems (template) { +function areValidTemplateItems (template: (MenuItemConstructorOptions | MenuItem)[]) { return template.every(item => item != null && typeof item === 'object' && @@ -209,7 +209,7 @@ function areValidTemplateItems (template) { item.type === 'separator')); } -function sortTemplate (template) { +function sortTemplate (template: (MenuItemConstructorOptions | MenuItem)[]) { const sorted = sortMenuItems(template); for (const item of sorted) { if (Array.isArray(item.submenu)) { @@ -220,15 +220,15 @@ function sortTemplate (template) { } // Search between separators to find a radio menu item and return its group id -function generateGroupId (items, pos) { +function generateGroupId (items: (MenuItemConstructorOptions | MenuItem)[], pos: number) { if (pos > 0) { for (let idx = pos - 1; idx >= 0; idx--) { - if (items[idx].type === 'radio') return items[idx].groupId; + if (items[idx].type === 'radio') return (items[idx] as any).groupId; if (items[idx].type === 'separator') break; } } else if (pos < items.length) { for (let idx = pos; idx <= items.length - 1; idx++) { - if (items[idx].type === 'radio') return items[idx].groupId; + if (items[idx].type === 'radio') return (items[idx] as any).groupId; if (items[idx].type === 'separator') break; } } @@ -236,7 +236,7 @@ function generateGroupId (items, pos) { return groupIdIndex; } -function removeExtraSeparators (items) { +function removeExtraSeparators (items: (MenuItemConstructorOptions | MenuItem)[]) { // fold adjacent separators together let ret = items.filter((e, idx, arr) => { if (e.visible === false) return true; @@ -252,7 +252,7 @@ function removeExtraSeparators (items) { return ret; } -function insertItemByType (item, pos) { +function insertItemByType (this: MenuType, item: MenuItem, pos: number) { const types = { normal: () => this.insertItem(pos, item.commandId, item.label), checkbox: () => this.insertCheckItem(pos, item.commandId, item.label), diff --git a/spec-main/ambient.d.ts b/spec-main/ambient.d.ts index 9a5ecee2c2..eb6e1b1a55 100644 --- a/spec-main/ambient.d.ts +++ b/spec-main/ambient.d.ts @@ -1,16 +1,6 @@ declare let standardScheme: string; declare namespace Electron { - interface Menu { - _executeCommand(event: any, id: number): void; - _menuWillShow(): void; - getAcceleratorTextAt(index: number): string; - } - - interface MenuItem { - getDefaultRoleAccelerator(): Accelerator | undefined; - } - interface WebContents { getOwnerBrowserWindow(): BrowserWindow; getWebPreferences(): any; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 00be2ab3d0..699ebbe5f8 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -107,6 +107,45 @@ declare namespace Electron { length(): number; } + interface Menu { + _init(): void; + _isCommandIdChecked(id: string): boolean; + _isCommandIdEnabled(id: string): boolean; + _shouldCommandIdWorkWhenHidden(id: string): boolean; + _isCommandIdVisible(id: string): boolean; + _getAcceleratorForCommandId(id: string, useDefaultAccelerator: boolean): Accelerator | undefined; + _shouldRegisterAcceleratorForCommandId(id: string): boolean; + _callMenuWillShow(): void; + _executeCommand(event: any, id: number): void; + _menuWillShow(): void; + commandsMap: Record; + groupsMap: Record; + getItemCount(): number; + popupAt(window: BaseWindow, x: number, y: number, positioning: number, callback: () => void): void; + closePopupAt(id: number): void; + setSublabel(index: number, label: string): void; + setToolTip(index: number, tooltip: string): void; + setIcon(index: number, image: string | NativeImage): void; + setRole(index: number, role: string): void; + insertItem(index: number, commandId: number, label: string): void; + insertCheckItem(index: number, commandId: number, label: string): void; + insertRadioItem(index: number, commandId: number, label: string, groupId: number): void; + insertSeparator(index: number): void; + insertSubMenu(index: number, commandId: number, label: string, submenu?: Menu): void; + delegate?: any; + getAcceleratorTextAt(index: number): string; + } + + interface MenuItem { + overrideReadOnlyProperty(property: string, value: any): void; + groupId: number; + getDefaultRoleAccelerator(): Accelerator | undefined; + acceleratorWorksWhenHidden?: boolean; + } + + const deprecate: ElectronInternal.DeprecationUtil; namespace Main { @@ -123,6 +162,7 @@ declare namespace Electron { static getAllWindows(): BaseWindow[]; isFocused(): boolean; static getFocusedWindow(): BaseWindow | undefined; + setMenu(menu: Menu): void; } class WebContentsView { constructor(options: BrowserWindowConstructorOptions)