docs: add Menu
module tutorials (#47761)
* docs: add `Menu` module tutorials * link API docs to new tutorials * removed unreferenced fiddles * add wording for new types * fix import sort errors * delete accelerator.md * fixes Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Erick Zhao <ezhao@slack-corp.com>
This commit is contained in:
parent
e2689400aa
commit
280f643862
39 changed files with 1240 additions and 1472 deletions
|
@ -21,7 +21,9 @@
|
|||
"ul",
|
||||
"unknown",
|
||||
"Tabs",
|
||||
"TabItem"
|
||||
"TabItem",
|
||||
"DocCardList",
|
||||
"kbd"
|
||||
]
|
||||
},
|
||||
"no-newline-in-links": true
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
# Accelerator
|
||||
|
||||
> Define keyboard shortcuts.
|
||||
|
||||
Accelerators are strings that can contain multiple modifiers and a single key code,
|
||||
combined by the `+` character, and are used to define keyboard shortcuts
|
||||
throughout your application. Accelerators are case insensitive.
|
||||
|
||||
Examples:
|
||||
|
||||
* `CommandOrControl+A`
|
||||
* `CommandOrControl+Shift+Z`
|
||||
|
||||
Shortcuts are registered with the [`globalShortcut`](global-shortcut.md) module
|
||||
using the [`register`](global-shortcut.md#globalshortcutregisteraccelerator-callback)
|
||||
method, i.e.
|
||||
|
||||
```js
|
||||
const { app, globalShortcut } = require('electron')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
// Register a 'CommandOrControl+Y' shortcut listener.
|
||||
globalShortcut.register('CommandOrControl+Y', () => {
|
||||
// Do stuff when Y and either Command/Control is pressed.
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Platform notice
|
||||
|
||||
On Linux and Windows, the `Command` key does not have any effect so
|
||||
use `CommandOrControl` which represents `Command` on macOS and `Control` on
|
||||
Linux and Windows to define some accelerators.
|
||||
|
||||
Use `Alt` instead of `Option`. The `Option` key only exists on macOS, whereas
|
||||
the `Alt` key is available on all platforms.
|
||||
|
||||
The `Super` (or `Meta`) key is mapped to the `Windows` key on Windows and Linux and
|
||||
`Cmd` on macOS.
|
||||
|
||||
## Available modifiers
|
||||
|
||||
* `Command` (or `Cmd` for short)
|
||||
* `Control` (or `Ctrl` for short)
|
||||
* `CommandOrControl` (or `CmdOrCtrl` for short)
|
||||
* `Alt`
|
||||
* `Option`
|
||||
* `AltGr`
|
||||
* `Shift`
|
||||
* `Super`
|
||||
* `Meta`
|
||||
|
||||
## Available key codes
|
||||
|
||||
* `0` to `9`
|
||||
* `A` to `Z`
|
||||
* `F1` to `F24`
|
||||
* Various Punctuation: `)`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `:`, `;`, `:`, `+`, `=`, `<`, `,`, `_`, `-`, `>`, `.`, `?`, `/`, `~`, `` ` ``, `{`, `]`, `[`, `|`, `\`, `}`, `"`
|
||||
* `Plus`
|
||||
* `Space`
|
||||
* `Tab`
|
||||
* `Capslock`
|
||||
* `Numlock`
|
||||
* `Scrolllock`
|
||||
* `Backspace`
|
||||
* `Delete`
|
||||
* `Insert`
|
||||
* `Return` (or `Enter` as alias)
|
||||
* `Up`, `Down`, `Left` and `Right`
|
||||
* `Home` and `End`
|
||||
* `PageUp` and `PageDown`
|
||||
* `Escape` (or `Esc` for short)
|
||||
* `VolumeUp`, `VolumeDown` and `VolumeMute`
|
||||
* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause`
|
||||
* `PrintScreen`
|
||||
* NumPad Keys
|
||||
* `num0` - `num9`
|
||||
* `numdec` - decimal key
|
||||
* `numadd` - numpad `+` key
|
||||
* `numsub` - numpad `-` key
|
||||
* `nummult` - numpad `*` key
|
||||
* `numdiv` - numpad `÷` key
|
|
@ -5,13 +5,8 @@
|
|||
Process: [Main](../glossary.md#main-process)<br />
|
||||
_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._
|
||||
|
||||
The following example shows how to bounce your icon on the dock.
|
||||
|
||||
```js
|
||||
const { app } = require('electron')
|
||||
|
||||
app.dock?.bounce()
|
||||
```
|
||||
> [!TIP]
|
||||
> See also: [A detailed guide about how to implement Dock menus](../tutorial/macos-dock.md).
|
||||
|
||||
### Instance Methods
|
||||
|
||||
|
@ -50,6 +45,9 @@ Bounces the Downloads stack if the filePath is inside the Downloads folder.
|
|||
|
||||
Sets the string to be displayed in the dock’s badging area.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You need to ensure that your application has the permission to display notifications for this method to work.
|
||||
|
||||
#### `dock.getBadge()` _macOS_
|
||||
|
||||
Returns `string` - The badge string of the dock.
|
||||
|
|
|
@ -46,13 +46,16 @@ app.on('will-quit', () => {
|
|||
})
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> See also: [A detailed guide on Keyboard Shortcuts](../tutorial/keyboard-shortcuts.md).
|
||||
|
||||
## Methods
|
||||
|
||||
The `globalShortcut` module has the following methods:
|
||||
|
||||
### `globalShortcut.register(accelerator, callback)`
|
||||
|
||||
* `accelerator` [Accelerator](accelerator.md)
|
||||
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
|
||||
* `callback` Function
|
||||
|
||||
Returns `boolean` - Whether or not the shortcut was registered successfully.
|
||||
|
@ -74,7 +77,7 @@ the app has been authorized as a [trusted accessibility client](https://develope
|
|||
|
||||
### `globalShortcut.registerAll(accelerators, callback)`
|
||||
|
||||
* `accelerators` [Accelerator](accelerator.md)[] - an array of [Accelerator](accelerator.md)s.
|
||||
* `accelerators` string[] - An array of [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcuts.
|
||||
* `callback` Function
|
||||
|
||||
Registers a global shortcut of all `accelerator` items in `accelerators`. The `callback` is called when any of the registered shortcuts are pressed by the user.
|
||||
|
@ -93,7 +96,7 @@ the app has been authorized as a [trusted accessibility client](https://develope
|
|||
|
||||
### `globalShortcut.isRegistered(accelerator)`
|
||||
|
||||
* `accelerator` [Accelerator](accelerator.md)
|
||||
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
|
||||
|
||||
Returns `boolean` - Whether this application has registered `accelerator`.
|
||||
|
||||
|
@ -103,7 +106,7 @@ don't want applications to fight for global shortcuts.
|
|||
|
||||
### `globalShortcut.unregister(accelerator)`
|
||||
|
||||
* `accelerator` [Accelerator](accelerator.md)
|
||||
* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut.
|
||||
|
||||
Unregisters the global shortcut of `accelerator`.
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ See [`Menu`](menu.md) for examples.
|
|||
* `window` [BaseWindow](base-window.md) | undefined - This will not be defined if no window is open.
|
||||
* `event` [KeyboardEvent](structures/keyboard-event.md)
|
||||
* `role` string (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, `zoomOut`, `toggleSpellChecker`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideOthers`, `unhide`, `quit`, `showSubstitutions`, `toggleSmartQuotes`, `toggleSmartDashes`, `toggleTextReplacement`, `startSpeaking`, `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, `selectPreviousTab`, `showAllTabs`, `mergeAllWindows`, `clearRecentDocuments`, `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when specified the
|
||||
`click` property will be ignored. See [roles](#roles).
|
||||
`click` property will be ignored. See [roles](../tutorial/menus.md#roles).
|
||||
* `type` string (optional)
|
||||
* `normal`
|
||||
* `separator`
|
||||
|
@ -31,7 +31,7 @@ See [`Menu`](menu.md) for examples.
|
|||
* `label` string (optional)
|
||||
* `sublabel` string (optional) _macOS_ - Available in macOS >= 14.4
|
||||
* `toolTip` string (optional) _macOS_ - Hover text for this menu item.
|
||||
* `accelerator` [Accelerator](accelerator.md) (optional)
|
||||
* `accelerator` string (optional) - An [Accelerator](../tutorial/keyboard-shortcuts.md#accelerators) string.
|
||||
* `icon` ([NativeImage](native-image.md) | string) (optional)
|
||||
* `enabled` boolean (optional) - If false, the menu item will be greyed out and
|
||||
unclickable.
|
||||
|
@ -64,88 +64,13 @@ See [`Menu`](menu.md) for examples.
|
|||
> [!NOTE]
|
||||
> `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development.
|
||||
|
||||
### Roles
|
||||
|
||||
Roles allow menu items to have predefined behaviors.
|
||||
|
||||
It is best to specify `role` for any menu item that matches a standard role,
|
||||
rather than trying to manually implement the behavior in a `click` function.
|
||||
The built-in `role` behavior will give the best native experience.
|
||||
|
||||
The `label` and `accelerator` values are optional when using a `role` and will
|
||||
default to appropriate values for each platform.
|
||||
|
||||
Every menu item must have either a `role`, `label`, or in the case of a separator
|
||||
a `type`.
|
||||
|
||||
The `role` property can have following values:
|
||||
|
||||
* `undo`
|
||||
* `about` - Trigger a native about panel (custom message box on Window, which does not provide its own).
|
||||
* `redo`
|
||||
* `cut`
|
||||
* `copy`
|
||||
* `paste`
|
||||
* `pasteAndMatchStyle`
|
||||
* `selectAll`
|
||||
* `delete`
|
||||
* `minimize` - Minimize current window.
|
||||
* `close` - Close current window.
|
||||
* `quit` - Quit the application.
|
||||
* `reload` - Reload the current window.
|
||||
* `forceReload` - Reload the current window ignoring the cache.
|
||||
* `toggleDevTools` - Toggle developer tools in the current window.
|
||||
* `togglefullscreen` - Toggle full screen mode on the current window.
|
||||
* `resetZoom` - Reset the focused page's zoom level to the original size.
|
||||
* `zoomIn` - Zoom in the focused page by 10%.
|
||||
* `zoomOut` - Zoom out the focused page by 10%.
|
||||
* `toggleSpellChecker` - Enable/disable builtin spell checker.
|
||||
* `fileMenu` - Whole default "File" menu (Close / Quit)
|
||||
* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.).
|
||||
* `viewMenu` - Whole default "View" menu (Reload, Toggle Developer Tools, etc.)
|
||||
* `windowMenu` - Whole default "Window" menu (Minimize, Zoom, etc.).
|
||||
|
||||
The following additional roles are available on _macOS_:
|
||||
|
||||
* `appMenu` - Whole default "App" menu (About, Services, etc.)
|
||||
* `hide` - Map to the `hide` action.
|
||||
* `hideOthers` - Map to the `hideOtherApplications` action.
|
||||
* `unhide` - Map to the `unhideAllApplications` action.
|
||||
* `showSubstitutions` - Map to the `orderFrontSubstitutionsPanel` action.
|
||||
* `toggleSmartQuotes` - Map to the `toggleAutomaticQuoteSubstitution` action.
|
||||
* `toggleSmartDashes` - Map to the `toggleAutomaticDashSubstitution` action.
|
||||
* `toggleTextReplacement` - Map to the `toggleAutomaticTextReplacement` action.
|
||||
* `startSpeaking` - Map to the `startSpeaking` action.
|
||||
* `stopSpeaking` - Map to the `stopSpeaking` action.
|
||||
* `front` - Map to the `arrangeInFront` action.
|
||||
* `zoom` - Map to the `performZoom` action.
|
||||
* `toggleTabBar` - Map to the `toggleTabBar` action.
|
||||
* `selectNextTab` - Map to the `selectNextTab` action.
|
||||
* `selectPreviousTab` - Map to the `selectPreviousTab` action.
|
||||
* `showAllTabs` - Map to the `showAllTabs` action.
|
||||
* `mergeAllWindows` - Map to the `mergeAllWindows` action.
|
||||
* `moveTabToNewWindow` - Map to the `moveTabToNewWindow` action.
|
||||
* `window` - The submenu is a "Window" menu.
|
||||
* `help` - The submenu is a "Help" menu.
|
||||
* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu. This is only intended for use in the Application Menu and is _not_ the same as the "Services" submenu used in context menus in macOS apps, which is not implemented in Electron.
|
||||
* `recentDocuments` - The submenu is an "Open Recent" menu.
|
||||
* `clearRecentDocuments` - Map to the `clearRecentDocuments` action.
|
||||
* `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share.
|
||||
|
||||
When specifying a `role` on macOS, `label` and `accelerator` are the only
|
||||
options that will affect the menu item. All other options will be ignored.
|
||||
Lowercase `role`, e.g. `toggledevtools`, is still supported.
|
||||
|
||||
> [!NOTE]
|
||||
> The `enabled` and `visibility` properties are not available for top-level menu items in the tray on macOS.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `MenuItem`:
|
||||
|
||||
#### `menuItem.id`
|
||||
|
||||
A `string` indicating the item's unique id, this property can be
|
||||
A `string` indicating the item's unique id. This property can be
|
||||
dynamically changed.
|
||||
|
||||
#### `menuItem.label`
|
||||
|
@ -203,17 +128,17 @@ A `string` indicating the item's hover text.
|
|||
|
||||
#### `menuItem.enabled`
|
||||
|
||||
A `boolean` indicating whether the item is enabled, this property can be
|
||||
A `boolean` indicating whether the item is enabled. This property can be
|
||||
dynamically changed.
|
||||
|
||||
#### `menuItem.visible`
|
||||
|
||||
A `boolean` indicating whether the item is visible, this property can be
|
||||
A `boolean` indicating whether the item is visible. This property can be
|
||||
dynamically changed.
|
||||
|
||||
#### `menuItem.checked`
|
||||
|
||||
A `boolean` indicating whether the item is checked, this property can be
|
||||
A `boolean` indicating whether the item is checked. This property can be
|
||||
dynamically changed.
|
||||
|
||||
A `checkbox` menu item will toggle the `checked` property on and off when
|
||||
|
@ -244,5 +169,3 @@ A `number` indicating an item's sequential unique id.
|
|||
#### `menuItem.menu`
|
||||
|
||||
A `Menu` that the item is a part of.
|
||||
|
||||
[ShareMenu]: https://developer.apple.com/design/human-interface-guidelines/macos/extensions/share-extensions/
|
||||
|
|
339
docs/api/menu.md
339
docs/api/menu.md
|
@ -6,6 +6,9 @@
|
|||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
> [!TIP]
|
||||
> See also: [A detailed guide about how to implement menus in your application](../tutorial/menus.md).
|
||||
|
||||
> [!WARNING]
|
||||
> Electron's built-in classes cannot be subclassed in user code.
|
||||
> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules).
|
||||
|
@ -20,7 +23,7 @@ The `Menu` class has the following static methods:
|
|||
|
||||
#### `Menu.setApplicationMenu(menu)`
|
||||
|
||||
* `menu` Menu | null
|
||||
- `menu` Menu | null
|
||||
|
||||
Sets `menu` as the application menu on macOS. On Windows and Linux, the
|
||||
`menu` will be set as each window's top menu.
|
||||
|
@ -51,18 +54,18 @@ Returns `Menu | null` - The application menu, if set, or `null`, if not set.
|
|||
|
||||
#### `Menu.sendActionToFirstResponder(action)` _macOS_
|
||||
|
||||
* `action` string
|
||||
- `action` string
|
||||
|
||||
Sends the `action` to the first responder of application. This is used for
|
||||
emulating default macOS menu behaviors. Usually you would use the
|
||||
[`role`](menu-item.md#roles) property of a [`MenuItem`](menu-item.md).
|
||||
[`role`](../tutorial/menus.md#roles) property of a [`MenuItem`](menu-item.md).
|
||||
|
||||
See the [macOS Cocoa Event Handling Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html#//apple_ref/doc/uid/10000060i-CH3-SW7)
|
||||
for more information on macOS' native actions.
|
||||
|
||||
#### `Menu.buildFromTemplate(template)`
|
||||
|
||||
* `template` (MenuItemConstructorOptions | MenuItem)[]
|
||||
- `template` (MenuItemConstructorOptions | MenuItem)[]
|
||||
|
||||
Returns `Menu`
|
||||
|
||||
|
@ -77,47 +80,50 @@ The `menu` object has the following instance methods:
|
|||
|
||||
#### `menu.popup([options])`
|
||||
|
||||
* `options` Object (optional)
|
||||
* `window` [BaseWindow](base-window.md) (optional) - Default is the focused window.
|
||||
* `frame` [WebFrameMain](web-frame-main.md) (optional) - Provide the relevant frame
|
||||
- `options` Object (optional)
|
||||
- `window` [BaseWindow](base-window.md) (optional) - Default is the focused window.
|
||||
- `frame` [WebFrameMain](web-frame-main.md) (optional) - Provide the relevant frame
|
||||
if you want certain OS-level features such as Writing Tools on macOS to function correctly. Typically, this should be `params.frame` from the [`context-menu` event](web-contents.md#event-context-menu) on a WebContents, or the [`focusedFrame` property](web-contents.md#contentsfocusedframe-readonly) of a WebContents.
|
||||
* `x` number (optional) - Default is the current mouse cursor position.
|
||||
- `x` number (optional) - Default is the current mouse cursor position.
|
||||
Must be declared if `y` is declared.
|
||||
* `y` number (optional) - Default is the current mouse cursor position.
|
||||
- `y` number (optional) - Default is the current mouse cursor position.
|
||||
Must be declared if `x` is declared.
|
||||
* `positioningItem` number (optional) _macOS_ - The index of the menu item to
|
||||
- `positioningItem` number (optional) _macOS_ - The index of the menu item to
|
||||
be positioned under the mouse cursor at the specified coordinates. Default
|
||||
is -1.
|
||||
* `sourceType` string (optional) _Windows_ _Linux_ - This should map to the `menuSourceType`
|
||||
- `sourceType` string (optional) _Windows_ _Linux_ - This should map to the `menuSourceType`
|
||||
provided by the `context-menu` event. It is not recommended to set this value manually,
|
||||
only provide values you receive from other APIs or leave it `undefined`.
|
||||
Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`.
|
||||
* `callback` Function (optional) - Called when menu is closed.
|
||||
- `callback` Function (optional) - Called when menu is closed.
|
||||
|
||||
Pops up this menu as a context menu in the [`BaseWindow`](base-window.md).
|
||||
|
||||
> [!TIP]
|
||||
> For more details, see the [Context Menu](../tutorial/context-menu.md) guide.
|
||||
|
||||
#### `menu.closePopup([window])`
|
||||
|
||||
* `window` [BaseWindow](base-window.md) (optional) - Default is the focused window.
|
||||
- `window` [BaseWindow](base-window.md) (optional) - Default is the focused window.
|
||||
|
||||
Closes the context menu in the `window`.
|
||||
|
||||
#### `menu.append(menuItem)`
|
||||
|
||||
* `menuItem` [MenuItem](menu-item.md)
|
||||
- `menuItem` [MenuItem](menu-item.md)
|
||||
|
||||
Appends the `menuItem` to the menu.
|
||||
|
||||
#### `menu.getMenuItemById(id)`
|
||||
|
||||
* `id` string
|
||||
- `id` string
|
||||
|
||||
Returns `MenuItem | null` the item with the specified `id`
|
||||
|
||||
#### `menu.insert(pos, menuItem)`
|
||||
|
||||
* `pos` Integer
|
||||
* `menuItem` [MenuItem](menu-item.md)
|
||||
- `pos` Integer
|
||||
- `menuItem` [MenuItem](menu-item.md)
|
||||
|
||||
Inserts the `menuItem` to the `pos` position of the menu.
|
||||
|
||||
|
@ -133,7 +139,7 @@ Objects created with `new Menu` or returned by `Menu.buildFromTemplate` emit the
|
|||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
- `event` Event
|
||||
|
||||
Emitted when `menu.popup()` is called.
|
||||
|
||||
|
@ -141,7 +147,7 @@ Emitted when `menu.popup()` is called.
|
|||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
- `event` Event
|
||||
|
||||
Emitted when a popup is closed either manually or with `menu.closePopup()`.
|
||||
|
||||
|
@ -153,296 +159,5 @@ Emitted when a popup is closed either manually or with `menu.closePopup()`.
|
|||
|
||||
A `MenuItem[]` array containing the menu's items.
|
||||
|
||||
Each `Menu` consists of multiple [`MenuItem`](menu-item.md)s and each `MenuItem`
|
||||
can have a submenu.
|
||||
|
||||
## Examples
|
||||
|
||||
An example of creating the application menu with the simple template API:
|
||||
|
||||
```js @ts-expect-error=[107]
|
||||
const { app, Menu } = require('electron')
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
|
||||
const template = [
|
||||
// { role: 'appMenu' }
|
||||
...(isMac
|
||||
? [{
|
||||
label: app.name,
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
}]
|
||||
: []),
|
||||
// { role: 'fileMenu' }
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
isMac ? { role: 'close' } : { role: 'quit' }
|
||||
]
|
||||
},
|
||||
// { role: 'editMenu' }
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
...(isMac
|
||||
? [
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startSpeaking' },
|
||||
{ role: 'stopSpeaking' }
|
||||
]
|
||||
}
|
||||
]
|
||||
: [
|
||||
{ role: 'delete' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'selectAll' }
|
||||
])
|
||||
]
|
||||
},
|
||||
// { role: 'viewMenu' }
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forceReload' },
|
||||
{ role: 'toggleDevTools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// { role: 'windowMenu' }
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
...(isMac
|
||||
? [
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'window' }
|
||||
]
|
||||
: [
|
||||
{ role: 'close' }
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: async () => {
|
||||
const { shell } = require('electron')
|
||||
await shell.openExternal('https://electronjs.org')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
```
|
||||
|
||||
### Render process
|
||||
|
||||
To create menus initiated by the renderer process, send the required
|
||||
information to the main process using IPC and have the main process display the
|
||||
menu on behalf of the renderer.
|
||||
|
||||
Below is an example of showing a menu when the user right clicks the page:
|
||||
|
||||
```js @ts-expect-error=[21]
|
||||
// renderer
|
||||
window.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
ipcRenderer.send('show-context-menu')
|
||||
})
|
||||
|
||||
ipcRenderer.on('context-menu-command', (e, command) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// main
|
||||
ipcMain.on('show-context-menu', (event) => {
|
||||
const template = [
|
||||
{
|
||||
label: 'Menu Item 1',
|
||||
click: () => { event.sender.send('context-menu-command', 'menu-item-1') }
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: 'Menu Item 2', type: 'checkbox', checked: true }
|
||||
]
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) })
|
||||
})
|
||||
```
|
||||
|
||||
## Notes on macOS Application Menu
|
||||
|
||||
macOS has a completely different style of application menu from Windows and
|
||||
Linux. Here are some notes on making your app's menu more native-like.
|
||||
|
||||
### Standard Menus
|
||||
|
||||
On macOS there are many system-defined standard menus, like the [`Services`](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) and
|
||||
`Windows` menus. To make your menu a standard menu, you should set your menu's
|
||||
`role` to one of the following and Electron will recognize them and make them
|
||||
become standard menus:
|
||||
|
||||
* `window`
|
||||
* `help`
|
||||
* `services`
|
||||
|
||||
### Standard Menu Item Actions
|
||||
|
||||
macOS has provided standard actions for some menu items, like `About xxx`,
|
||||
`Hide xxx`, and `Hide Others`. To set the action of a menu item to a standard
|
||||
action, you should set the `role` attribute of the menu item.
|
||||
|
||||
### Main Menu's Name
|
||||
|
||||
On macOS the label of the application menu's first item is always your app's
|
||||
name, no matter what label you set. To change it, modify your app bundle's
|
||||
`Info.plist` file. See
|
||||
[About Information Property List Files][AboutInformationPropertyListFiles]
|
||||
for more information.
|
||||
|
||||
### Menu Sublabels
|
||||
|
||||
Menu sublabels, or [subtitles](https://developer.apple.com/documentation/appkit/nsmenuitem/subtitle?language=objc), can be added to menu items using the `sublabel` option. Below is an example based on the renderer example above:
|
||||
|
||||
```js @ts-expect-error=[12]
|
||||
// main
|
||||
ipcMain.on('show-context-menu', (event) => {
|
||||
const template = [
|
||||
{
|
||||
label: 'Menu Item 1',
|
||||
sublabel: 'Subtitle 1',
|
||||
click: () => { event.sender.send('context-menu-command', 'menu-item-1') }
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ label: 'Menu Item 2', sublabel: 'Subtitle 2', type: 'checkbox', checked: true }
|
||||
]
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) })
|
||||
})
|
||||
```
|
||||
|
||||
## Setting Menu for Specific Browser Window (_Linux_ _Windows_)
|
||||
|
||||
The [`setMenu` method][setMenu] of browser windows can set the menu of certain
|
||||
browser windows.
|
||||
|
||||
## Menu Item Position
|
||||
|
||||
You can make use of `before`, `after`, `beforeGroupContaining`, `afterGroupContaining` and `id` to control how the item will be placed when building a menu with `Menu.buildFromTemplate`.
|
||||
|
||||
* `before` - Inserts this item before the item with the specified id. If the
|
||||
referenced item doesn't exist the item will be inserted at the end of
|
||||
the menu. Also implies that the menu item in question should be placed in the same “group” as the item.
|
||||
* `after` - Inserts this item after the item with the specified id. If the
|
||||
referenced item doesn't exist the item will be inserted at the end of
|
||||
the menu. Also implies that the menu item in question should be placed in the same “group” as the item.
|
||||
* `beforeGroupContaining` - Provides a means for a single context menu to declare
|
||||
the placement of their containing group before the containing group of the item with the specified id.
|
||||
* `afterGroupContaining` - Provides a means for a single context menu to declare
|
||||
the placement of their containing group after the containing group of the item with the specified id.
|
||||
|
||||
By default, items will be inserted in the order they exist in the template unless one of the specified positioning keywords is used.
|
||||
|
||||
### Examples
|
||||
|
||||
Template:
|
||||
|
||||
```js
|
||||
[
|
||||
{ id: '1', label: 'one' },
|
||||
{ id: '2', label: 'two' },
|
||||
{ id: '3', label: 'three' },
|
||||
{ id: '4', label: 'four' }
|
||||
]
|
||||
```
|
||||
|
||||
Menu:
|
||||
|
||||
```sh
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
|
||||
Template:
|
||||
|
||||
```js
|
||||
[
|
||||
{ id: '1', label: 'one' },
|
||||
{ type: 'separator' },
|
||||
{ id: '3', label: 'three', beforeGroupContaining: ['1'] },
|
||||
{ id: '4', label: 'four', afterGroupContaining: ['2'] },
|
||||
{ type: 'separator' },
|
||||
{ id: '2', label: 'two' }
|
||||
]
|
||||
```
|
||||
|
||||
Menu:
|
||||
|
||||
```sh
|
||||
- 3
|
||||
- 4
|
||||
- ---
|
||||
- 1
|
||||
- ---
|
||||
- 2
|
||||
```
|
||||
|
||||
Template:
|
||||
|
||||
```js
|
||||
[
|
||||
{ id: '1', label: 'one', after: ['3'] },
|
||||
{ id: '2', label: 'two', before: ['1'] },
|
||||
{ id: '3', label: 'three' }
|
||||
]
|
||||
```
|
||||
|
||||
Menu:
|
||||
|
||||
```sh
|
||||
- ---
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
```
|
||||
|
||||
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
|
||||
[setMenu]: browser-window.md#winsetmenumenu-linux-windows
|
||||
Each `Menu` consists of multiple [`MenuItem`](menu-item.md) instances and each `MenuItem`
|
||||
can nest a `Menu` into its `submenu` property.
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
* `type` string - The type of the event, can be `rawKeyDown`, `keyDown`, `keyUp` or `char`.
|
||||
* `keyCode` string - The character that will be sent
|
||||
as the keyboard event. Should only use the valid key codes in
|
||||
[Accelerator](../accelerator.md).
|
||||
as the keyboard event. Should only use valid [Accelerator](../../tutorial/keyboard-shortcuts.md#accelerators)
|
||||
key codes.
|
||||
|
|
|
@ -8,7 +8,7 @@ Process: [Main](../glossary.md#main-process)
|
|||
|
||||
`Tray` is an [EventEmitter][event-emitter].
|
||||
|
||||
```js
|
||||
```js title='Creating a basic tray menu'
|
||||
const { app, Menu, Tray } = require('electron')
|
||||
|
||||
let tray = null
|
||||
|
@ -25,6 +25,9 @@ app.whenReady().then(() => {
|
|||
})
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> See also: [A detailed guide about how to implement Tray menus](../tutorial/tray.md).
|
||||
|
||||
> [!WARNING]
|
||||
> Electron's built-in classes cannot be subclassed in user code.
|
||||
> For more information, see [the FAQ](../faq.md#class-inheritance-does-not-work-with-electron-built-in-modules).
|
||||
|
@ -329,3 +332,47 @@ The `bounds` of this tray icon as `Object`.
|
|||
Returns `boolean` - Whether the tray icon is destroyed.
|
||||
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
|
||||
## Platform considerations
|
||||
|
||||
### Linux
|
||||
|
||||
* Tray icon uses [StatusNotifierItem](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/)
|
||||
by default, when it is not available in user's desktop environment the
|
||||
`GtkStatusIcon` will be used instead.
|
||||
* The `click` event is emitted when the tray icon receives activation from
|
||||
user, however the StatusNotifierItem spec does not specify which action would
|
||||
cause an activation, for some environments it is left mouse click, but for
|
||||
some it might be double left mouse click.
|
||||
* In order for changes made to individual `MenuItem`s to take effect,
|
||||
you have to call `setContextMenu` again. For example:
|
||||
|
||||
```js
|
||||
const { app, Menu, Tray } = require('electron')
|
||||
|
||||
let appIcon = null
|
||||
app.whenReady().then(() => {
|
||||
appIcon = new Tray('/path/to/my/icon')
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Item1', type: 'radio' },
|
||||
{ label: 'Item2', type: 'radio' }
|
||||
])
|
||||
|
||||
// Make a change to the context menu
|
||||
contextMenu.items[1].checked = false
|
||||
|
||||
// Call this again for Linux because we modified the context menu
|
||||
appIcon.setContextMenu(contextMenu)
|
||||
})
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos).
|
||||
* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi.
|
||||
* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image.
|
||||
* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons.
|
||||
|
||||
### Windows
|
||||
|
||||
* It is recommended to use `ICO` icons to get best visual effects.
|
||||
|
|
|
@ -67,7 +67,7 @@ Sets the maximum and minimum pinch-to-zoom level.
|
|||
> [!NOTE]
|
||||
> Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom shortcuts are
|
||||
> controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem roles in the application
|
||||
> Menu. To disable shortcuts, manually [define the Menu](./menu.md#examples) and omit zoom roles
|
||||
> Menu. To disable shortcuts, manually [define the Menu](../tutorial/menus.md) and omit zoom roles
|
||||
> from the definition.
|
||||
|
||||
### `webFrame.setSpellCheckProvider(language, provider)`
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>Hit Alt+Ctrl+I on Windows or Opt+Cmd+I on Mac to see a message printed to the console.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,28 +0,0 @@
|
|||
const { app, BrowserWindow, globalShortcut } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
globalShortcut.register('Alt+CommandOrControl+I', () => {
|
||||
console.log('Electron loves global shortcuts!')
|
||||
})
|
||||
}).then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>Hit Alt+Shift+I on Windows, or Opt+Cmd+I on mac to see a message printed to the console.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,36 +0,0 @@
|
|||
const { app, BrowserWindow, Menu, MenuItem } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({
|
||||
label: 'Electron',
|
||||
submenu: [{
|
||||
role: 'help',
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+I' : 'Alt+Shift+I',
|
||||
click: () => { console.log('Electron rocks!') }
|
||||
}]
|
||||
}))
|
||||
|
||||
Menu.setApplicationMenu(menu)
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>Right click the dock icon to see the custom menu options.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,40 +0,0 @@
|
|||
const { app, BrowserWindow, Menu } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const dockMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'New Window',
|
||||
click () { console.log('New Window') }
|
||||
}, {
|
||||
label: 'New Window with Settings',
|
||||
submenu: [
|
||||
{ label: 'Basic' },
|
||||
{ label: 'Pro' }
|
||||
]
|
||||
},
|
||||
{ label: 'New Command...' }
|
||||
])
|
||||
|
||||
app.whenReady().then(() => {
|
||||
app.dock?.setMenu(dockMenu)
|
||||
}).then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
14
docs/fiddles/menus/context-menu/dom/index.html
Normal file
14
docs/fiddles/menus/context-menu/dom/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Context Menu Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Context Menu Demo</h1>
|
||||
<!-- highlight-next-line -->
|
||||
<textarea id="editable"></textarea>
|
||||
</body>
|
||||
</html>
|
39
docs/fiddles/menus/context-menu/dom/main.js
Normal file
39
docs/fiddles/menus/context-menu/dom/main.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, Menu } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{ role: 'copy' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'paste' },
|
||||
{ role: 'selectall' }
|
||||
])
|
||||
|
||||
// highlight-start
|
||||
ipcMain.on('context-menu', (event) => {
|
||||
menu.popup({
|
||||
window: BrowserWindow.fromWebContents(event.sender)
|
||||
})
|
||||
})
|
||||
// highlight-end
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
11
docs/fiddles/menus/context-menu/dom/preload.js
Normal file
11
docs/fiddles/menus/context-menu/dom/preload.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const { ipcRenderer } = require('electron/renderer')
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const textarea = document.getElementById('editable')
|
||||
// highlight-start
|
||||
textarea.addEventListener('contextmenu', (event) => {
|
||||
event.preventDefault()
|
||||
ipcRenderer.send('context-menu')
|
||||
})
|
||||
// highlight-end
|
||||
})
|
14
docs/fiddles/menus/context-menu/web-contents/index.html
Normal file
14
docs/fiddles/menus/context-menu/web-contents/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Context Menu Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Context Menu Demo</h1>
|
||||
<!-- highlight-next-line -->
|
||||
<textarea></textarea>
|
||||
</body>
|
||||
</html>
|
32
docs/fiddles/menus/context-menu/web-contents/main.js
Normal file
32
docs/fiddles/menus/context-menu/web-contents/main.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const { app, BrowserWindow, Menu } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow()
|
||||
// highlight-start
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{ role: 'copy' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'paste' },
|
||||
{ role: 'selectall' }
|
||||
])
|
||||
win.webContents.on('context-menu', (_event, params) => {
|
||||
// only show the context menu if the element is editable
|
||||
if (params.isEditable) {
|
||||
menu.popup()
|
||||
}
|
||||
})
|
||||
// highlight-end
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
|
@ -1,124 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Customize Menus</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h1>Customize Menus</h1>
|
||||
|
||||
<h3>
|
||||
The <code>Menu</code> and <code>MenuItem</code> modules can be used to
|
||||
create custom native menus.
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
There are two kinds of menus: the application (top) menu and context
|
||||
(right-click) menu.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://www.electronjs.org/docs/latest/api/menu"
|
||||
>full API documentation<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Create an application menu</h2>
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
The <code>Menu</code> and <code>MenuItem</code> modules allow you to
|
||||
customize your application menu. If you don't set any menu, Electron
|
||||
will generate a minimal menu for your app by default.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you click the 'View' option in the application menu and then the
|
||||
'App Menu Demo', you'll see an information box displayed.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Know operating system menu differences.</strong>
|
||||
<p>
|
||||
When designing an app for multiple operating systems it's
|
||||
important to be mindful of the ways application menu conventions
|
||||
differ on each operating system.
|
||||
</p>
|
||||
<p>
|
||||
For instance, on Windows, accelerators are set with an
|
||||
<code>&</code>. Naming conventions also vary, like between
|
||||
"Settings" or "Preferences". Below are resources for learning
|
||||
operating system specific standards.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://developer.apple.com/design/human-interface-guidelines/the-menu-bar"
|
||||
>macOS<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://learn.microsoft.com/en-us/windows/apps/design/controls/menus-and-context-menus"
|
||||
>Windows<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://developer.gnome.org/hig/patterns/controls/menus.html"
|
||||
>Linux<span
|
||||
>(opens in new window)</span
|
||||
></a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Create a context menu</h2>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<button id="context-menu">View Demo</button>
|
||||
</div>
|
||||
<p>
|
||||
A context, or right-click, menu can be created with the
|
||||
<code>Menu</code> and <code>MenuItem</code> modules as well. You can
|
||||
right-click anywhere in this app or click the demo button to see an
|
||||
example context menu.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this demo we use the <code>ipcRenderer</code> module to show the
|
||||
context menu when explicitly calling it from the renderer process.
|
||||
</p>
|
||||
<p>
|
||||
See the full
|
||||
<a
|
||||
href="https://www.electronjs.org/docs/latest/api/web-contents/#event-context-menu"
|
||||
>context-menu event documentation</a
|
||||
>
|
||||
for all the available properties.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,368 +0,0 @@
|
|||
// Modules to control application life and create native browser window
|
||||
const {
|
||||
BrowserWindow,
|
||||
Menu,
|
||||
MenuItem,
|
||||
ipcMain,
|
||||
app,
|
||||
shell,
|
||||
dialog,
|
||||
autoUpdater
|
||||
} = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({ label: 'Hello' }))
|
||||
menu.append(new MenuItem({ type: 'separator' }))
|
||||
menu.append(
|
||||
new MenuItem({ label: 'Electron', type: 'checkbox', checked: true })
|
||||
)
|
||||
|
||||
const template = [
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'CmdOrCtrl+Z',
|
||||
role: 'undo'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+CmdOrCtrl+Z',
|
||||
role: 'redo'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'CmdOrCtrl+X',
|
||||
role: 'cut'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'CmdOrCtrl+C',
|
||||
role: 'copy'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
role: 'paste'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
role: 'selectall'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click: (item, focusedWindow) => {
|
||||
if (focusedWindow) {
|
||||
// on reload, start fresh and close any old
|
||||
// open secondary windows
|
||||
if (focusedWindow.id === 1) {
|
||||
for (const win of BrowserWindow.getAllWindows()) {
|
||||
if (win.id > 1) win.close()
|
||||
}
|
||||
}
|
||||
focusedWindow.reload()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: (() => {
|
||||
if (process.platform === 'darwin') {
|
||||
return 'Ctrl+Command+F'
|
||||
} else {
|
||||
return 'F11'
|
||||
}
|
||||
})(),
|
||||
click: (item, focusedWindow) => {
|
||||
if (focusedWindow) {
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: (() => {
|
||||
if (process.platform === 'darwin') {
|
||||
return 'Alt+Command+I'
|
||||
} else {
|
||||
return 'Ctrl+Shift+I'
|
||||
}
|
||||
})(),
|
||||
click: (item, focusedWindow) => {
|
||||
if (focusedWindow) {
|
||||
focusedWindow.webContents.toggleDevTools()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'App Menu Demo',
|
||||
click: function (item, focusedWindow) {
|
||||
if (focusedWindow) {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Application Menu Demo',
|
||||
buttons: ['Ok'],
|
||||
message:
|
||||
'This demo is for the Menu section, showing how to create a clickable menu item in the application menu.'
|
||||
}
|
||||
dialog.showMessageBox(focusedWindow, options, function () {})
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'CmdOrCtrl+M',
|
||||
role: 'minimize'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'CmdOrCtrl+W',
|
||||
role: 'close'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Reopen Window',
|
||||
accelerator: 'CmdOrCtrl+Shift+T',
|
||||
enabled: false,
|
||||
key: 'reopenMenuItem',
|
||||
click: () => {
|
||||
app.emit('activate')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: () => {
|
||||
shell.openExternal('https://electronjs.org')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
function addUpdateMenuItems (items, position) {
|
||||
if (process.mas) return
|
||||
|
||||
const version = app.getVersion()
|
||||
const updateItems = [
|
||||
{
|
||||
label: `Version ${version}`,
|
||||
enabled: false
|
||||
},
|
||||
{
|
||||
label: 'Checking for Update',
|
||||
enabled: false,
|
||||
key: 'checkingForUpdate'
|
||||
},
|
||||
{
|
||||
label: 'Check for Update',
|
||||
visible: false,
|
||||
key: 'checkForUpdate',
|
||||
click: () => {
|
||||
autoUpdater.checkForUpdates()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Restart and Install Update',
|
||||
enabled: true,
|
||||
visible: false,
|
||||
key: 'restartToUpdate',
|
||||
click: () => {
|
||||
autoUpdater.quitAndInstall()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
items.splice.apply(items, [position, 0].concat(updateItems))
|
||||
}
|
||||
|
||||
function findReopenMenuItem () {
|
||||
const menu = Menu.getApplicationMenu()
|
||||
if (!menu) return
|
||||
|
||||
let reopenMenuItem
|
||||
for (const item of menu.items) {
|
||||
if (item.submenu) {
|
||||
for (const subitem of item.submenu.items) {
|
||||
if (subitem.key === 'reopenMenuItem') {
|
||||
reopenMenuItem = subitem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reopenMenuItem
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
const name = app.getName()
|
||||
template.unshift({
|
||||
label: name,
|
||||
submenu: [
|
||||
{
|
||||
label: `About ${name}`,
|
||||
role: 'about'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Services',
|
||||
role: 'services',
|
||||
submenu: []
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: `Hide ${name}`,
|
||||
accelerator: 'Command+H',
|
||||
role: 'hide'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Alt+H',
|
||||
role: 'hideothers'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
role: 'unhide'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: () => {
|
||||
app.quit()
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Window menu.
|
||||
template[3].submenu.push(
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Bring All to Front',
|
||||
role: 'front'
|
||||
}
|
||||
)
|
||||
|
||||
addUpdateMenuItems(template[0].submenu, 1)
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const helpMenu = template[template.length - 1].submenu
|
||||
addUpdateMenuItems(helpMenu, 0)
|
||||
}
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
|
||||
// Open external links in the default browser
|
||||
mainWindow.webContents.on('will-navigate', (event, url) => {
|
||||
event.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
})
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
const reopenMenuItem = findReopenMenuItem()
|
||||
if (reopenMenuItem) reopenMenuItem.enabled = true
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('browser-window-created', (event, win) => {
|
||||
const reopenMenuItem = findReopenMenuItem()
|
||||
if (reopenMenuItem) reopenMenuItem.enabled = false
|
||||
|
||||
win.webContents.on('context-menu', (e, params) => {
|
||||
menu.popup(win, params.x, params.y)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('show-context-menu', event => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender)
|
||||
menu.popup(win)
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
|
@ -1,5 +0,0 @@
|
|||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
showContextMenu: () => ipcRenderer.send('show-context-menu')
|
||||
})
|
|
@ -1,6 +0,0 @@
|
|||
// Tell main process to show the menu when demo button is clicked
|
||||
const contextMenuBtn = document.getElementById('context-menu')
|
||||
|
||||
contextMenuBtn.addEventListener('click', () => {
|
||||
window.electronAPI.showContextMenu()
|
||||
})
|
18
docs/fiddles/menus/dock-menu/index.html
Normal file
18
docs/fiddles/menus/dock-menu/index.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Dock Menu Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Dock Menu Demo</h1>
|
||||
<ul>
|
||||
<li>Create new BrowserWindow instances via the "New Window" option</li>
|
||||
<li>Close all BrowserWindow instances via the "Close All Windows" option</li>
|
||||
<li>Read the docs via the "Show Electron Docs" option</li>
|
||||
</ul>
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
46
docs/fiddles/menus/dock-menu/main.js
Normal file
46
docs/fiddles/menus/dock-menu/main.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
const { app, BrowserWindow, Menu } = require('electron/main')
|
||||
const { shell } = require('electron/common')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow()
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
function closeAllWindows () {
|
||||
const wins = BrowserWindow.getAllWindows()
|
||||
for (const win of wins) {
|
||||
win.close()
|
||||
}
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
const dockMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'New Window',
|
||||
click: () => { createWindow() }
|
||||
},
|
||||
{
|
||||
label: 'Close All Windows',
|
||||
click: () => { closeAllWindows() }
|
||||
},
|
||||
{
|
||||
label: 'Open Electron Docs',
|
||||
click: () => {
|
||||
shell.openExternal('https://electronjs.org/docs')
|
||||
}
|
||||
}
|
||||
// add more menu options to the array
|
||||
])
|
||||
|
||||
app.dock.setMenu(dockMenu)
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
1
docs/fiddles/menus/dock-menu/renderer.js
Normal file
1
docs/fiddles/menus/dock-menu/renderer.js
Normal file
|
@ -0,0 +1 @@
|
|||
document.title = `${document.title} - ${new Date()}`
|
19
docs/fiddles/menus/tray-menu/index.html
Normal file
19
docs/fiddles/menus/tray-menu/index.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Tray Menu Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tray Menu Demo</h1>
|
||||
<p>This app will stay running even after all windows are closed.</p>
|
||||
<ul>
|
||||
<li>Use the "Open App" menu item to focus the main window (or open one if it does not exist).</li>
|
||||
<li>Change between red and green Tray icons with the "Set Green Icon" checkbox.</li>
|
||||
<li>Give the Tray icon a title using the "Set Title" checkbox.</li>
|
||||
<li>Quit the app using the "Quit" menu item.</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
60
docs/fiddles/menus/tray-menu/main.js
Normal file
60
docs/fiddles/menus/tray-menu/main.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
const { app, BrowserWindow, Menu, Tray } = require('electron/main')
|
||||
const { nativeImage } = require('electron/common')
|
||||
|
||||
// save a reference to the Tray object globally to avoid garbage collection
|
||||
let tray = null
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow()
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
// The Tray object can only be instantiated after the 'ready' event is fired
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
const red = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACTSURBVHgBpZKBCYAgEEV/TeAIjuIIbdQIuUGt0CS1gW1iZ2jIVaTnhw+Cvs8/OYDJA4Y8kR3ZR2/kmazxJbpUEfQ/Dm/UG7wVwHkjlQdMFfDdJMFaACebnjJGyDWgcnZu1/lrCrl6NCoEHJBrDwEr5NrT6ko/UV8xdLAC2N49mlc5CylpYh8wCwqrvbBGLoKGvz8Bfq0QPWEUo/EAAAAASUVORK5CYII=')
|
||||
const green = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACOSURBVHgBpZLRDYAgEEOrEzgCozCCGzkCbKArOIlugJvgoRAUNcLRpvGH19TkgFQWkqIohhK8UEaKwKcsOg/+WR1vX+AlA74u6q4FqgCOSzwsGHCwbKliAF89Cv89tWmOT4VaVMoVbOBrdQUz+FrD6XItzh4LzYB1HFJ9yrEkZ4l+wvcid9pTssh4UKbPd+4vED2Nd54iAAAAAElFTkSuQmCC')
|
||||
|
||||
tray = new Tray(red)
|
||||
tray.setToolTip('Tray Icon Demo')
|
||||
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Open App',
|
||||
click: () => {
|
||||
const wins = BrowserWindow.getAllWindows()
|
||||
if (wins.length === 0) {
|
||||
createWindow()
|
||||
} else {
|
||||
wins[0].focus()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Set Green Icon',
|
||||
type: 'checkbox',
|
||||
click: ({ checked }) => {
|
||||
checked ? tray.setImage(green) : tray.setImage(red)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Set Title',
|
||||
type: 'checkbox',
|
||||
click: ({ checked }) => {
|
||||
checked ? tray.setTitle('Title') : tray.setTitle('')
|
||||
}
|
||||
},
|
||||
{ role: 'quit' }
|
||||
])
|
||||
|
||||
tray.setContextMenu(contextMenu)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
// This will prevent the app from closing when windows close
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
|
@ -1,47 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Tray</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1>Tray</h1>
|
||||
<h3>
|
||||
The <code>tray</code> module allows you to create an icon in the
|
||||
operating system's notification area.
|
||||
</h3>
|
||||
<p>This icon can also have a context menu attached.</p>
|
||||
|
||||
<p>
|
||||
Open the
|
||||
<a href="https://www.electronjs.org/docs/latest/api/tray">
|
||||
full API documentation
|
||||
</a>
|
||||
in your browser.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h2>ProTip</h2>
|
||||
<strong>Tray support in Linux.</strong>
|
||||
<p>
|
||||
On Linux distributions that only have app indicator support, users
|
||||
will need to install <code>libappindicator1</code> to make the
|
||||
tray icon work. See the
|
||||
<a href="https://www.electronjs.org/docs/latest/api/tray">
|
||||
full API documentation
|
||||
</a>
|
||||
for more details about using Tray on Linux.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,18 +0,0 @@
|
|||
const { app, Tray, Menu, nativeImage } = require('electron/main')
|
||||
|
||||
let tray
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAACsZJREFUWAmtWFlsXFcZ/u82++Jt7IyT2Em6ZFHTpAtWIzspEgjEUhA8VNAiIYEQUvuABBIUwUMkQIVKPCIoEiABLShISEBbhFJwIGRpIKRpbNeJ7bh2HHvssR3PPnPnLnzfmRlju6EQqUc+c++c8y/fv54z1uQOh+/7Glh0TD59TE/TND7lnfa4/64OKsM071QoeZpA/y9WWvk/B4XCC06TUC+Xyw8HTXNQ1+Ww6PpOrMebewXxvBueJ6/XHOdMJBL5J9Y97m2R0SS/wweE6JxkGx5dilWr1S/7dXsEa2o4+LyFmcFcaL5zbX3Y9gh5hpeWYpSB9XV5/H678V89BGYDXnHJlCsWn4gHrGc1K9CXxferOdvPOOKUfF8cH7nUyCtklQZXih/VNNlmirk3GdBSoIcRswW7/vVkLPYi5W2Uze8bh7J+4wLfh4dViFx5/nmrUi7/MhGNvrCkBfpeWqnW/7BUdadqntQ8zwr6vhUV34xpYnDynWvcmwQNaclDXsqgLMqkocPDw7fNx7d5qIX+/PmJxKGD6VdDkeh7ztyqOFfrokGCEWiiZ1mp0uITnuKAosaT7+pNxMYTyefutcQfbA+b1XLpH5fnF97/yD335Fu6mqTqsclDINBVmI4fDxw80KPAvJSt1MZtMcLiGxYUu83p4UkgnJZlqcl3LAj3WnTkIS9lUBYNPJjueVWgg7qocyOgliFqjZsg8gq5tRdiieQTf1gq15Y8CUbRZtyWOzZwc8lEqS3PTCtgqd13ieO68BQ2uNl64tXAewktrFuX2mPdkWAxn3sxnmx7sqUTJGqso8MGS9tbXFz8DMH8bblUX3T9QARVi8RV8qljfcJy0zRlaf6mzHEuzEtmekqCoZB4rqp0OmudHtUnlEWZlE0d1EWd1N3EozourcO65pw4eTIZQTW9VazJtbqvw9XwKVFQMsKDBuNhtp4uvGGFI+IDgKnpMjYyIis3ZsQMBIR7pONsIaMsyqRs6ohY1rPUSd3EQFDqo+kdZ3Fh4aupbdu+99uFQr2A1CBs4uEAjZjIFUMHi4dVxMXzCdCXQj4vBrwVCofl0ulTcv/DAxJJJBUPc8mpoyI2JDw7bFyT+ifTcSubyXytJ51+roWBxwG9Q73WWjZ7eSUU3//nXM0NI+x0PBGrTSgsLS9JFuFxHFrvSqIrJV279gi6tjiVspTza3JjZhY+0CQZj0mlWJSeHTslCro6eFqymCcVVN77kkGjs1p4sy2VOoSlOrFwT+XR+PjkgGaZ+ycKVbRTYUdVrmaImCvzk1dlFCEJdHRJ284+ie/ol0h7p7jFvExcvCCXzp2Rqem3pAMAiqWS6JGYhFI9Mjo6KjevXVUyKEuFHrKpY6JQ8TXT3D8+OTkAHBw6o6LCFo9ag3o4JtlCyTHEt5AxKvS6YUi5kJeZG3Py0NAxlLcJ9xti+K7Mjo/JfGZRuvv6Ze+9+yWEhDZAvzg3JyhX2d6/S7q6e+TimdOS7ElLKBZDwqvmj6rztayr1fVI1IoXi4PAcYZY1tPEEO1wEVlXgRFBDcmIXTqJsS+XyhKLJ5A/OpIVXXptWUYv/UvaenfIocEhMQ2EzHHErlXFCgQl3paU1eVl6QAY8sQTCSmVihKJx1V/ogvgIYF/pACdcMBhqONoHhF88/2d+bojyA6cRvje2IdFjoSjUSnBS8hgyS9lZOzKFdmPxO3o6gQIGzwuDn1dVSCtCKPy1pZXlATXqUsVYMLRmKo87vP4Y1ioqwCdCegmMYx3W/VPn8RrSDwwIMMbcEjkYo29JZVOy+ybI7K4eksODx1VSqvligpReSVLgySM/FI5h2q062jNyL3s7FtoAyGJIlx1225UmwJF6aJRJ3XzHXO9bWvsJa3jQFlBJkz6iuXdu32HzM7MyP0PPNgAU6ko4Qzp6b+flr8MD9OYJg9CwtzL5+T65ITs2bsP3mGxN/ZbBcOn0sk20gAkLQ+huXpFi8vkoY9AoyDjxTR1mbo6Ltt275HpN0dlNxQE40mVM8Ajjxx9VAGhAvQR1akZFCq799ADysMuQqOxh2FNmamEaz51ItGLfFD9+oUJoZkLowHoFA2mljUacqOMflKuVmHpfmnfvlMuvXZeStmMBIMhcWEdjgFJtrUjXI0KchAuAg0ilxLJNoRVBxhIBm0TjjKAuqjTqTs3CQZ6QUUMGFW7eiWMUg6w+yo8YMW7DqtqlZLkUDV2ISfd29KyDwk9MjYmMyOXxQIIKuShqo4VGFNBEgeDQYqVam5N5tEePFQgURIUBCsd1EWd1XrtDUUMLARD9bKaK5ytQ2Gb75g8WMiEP6VkfnZGevv6UF1vSBW5E0PFDAweFRvlfun8WVmamhDNrkmweQ0pwaPt6M4m8mgKTTFXqcrV0ZH1FKBg6qAu6qTuJiCV1Cp2Q0NDr9Uq5Ym+oMEDlSewsoRwrVBEaij7AJ4s7zrOpumxEdm15y6558GHJVe1Zezy6zJx6aJkpq5JFB4z6zVZmBiX1VWUP0IY4CFMYcpQdZ3xqIs6oftCE5DHKwd0q/tzOV8svdDb3nk8VnG9qmgQC0ZURz8Ur91alXgSByZ6ES9kZZTr/PR16UOCh+7dq0CWyyXJ4xqCQ0nKt9YQSlPue2gAeYZzD7yNLk0wmqAreb2WYSxAJ8Dget64wxtEBlDaqVOn/K5dB67t6+t5MhoMJuc8w8UPKiQ9CQR9JK5czhZAQxPt7TKF3OiAIisUViAD2Lg5d0P2HDgoKeRaW0enyqVwBJcO5fFG5dqa7h406qaeX8384uTZL5w9+UqxhYHFp0YLIYA9ddfu3T+4UJF6Rg+YAc9D0+RoIGP1ULhpWspr10evyK7+ftWTrk9PS/++A9KZSm26cih2mMOErem6n/ZsZwA2TM/MPHXs2LEftnSTbh0Q36mIIbx44cLvOnu3f+xUwbWLmoHTCUlF6g2jBQo/GnFrnGNqSHdvr+rIKGMW1KahwEBdzHft98aNwMr8zd8/NDDwccihc0hLi3GubRjY0Bm6H19fPvnZI4c/fHd7PJ2peXYZ+WQ26JufZELjQ6lbAQtnWre0d3apY8TFIdtAo+Qri6mupsB49lBMC+QXF0YefObZT8j0eKWlswVjEyCCOXHihPGb575VCvVuf3lvetsH9rXF0rla3cnhpoIGjgsUPhR3I4TMKYJQV1Z6WO02aEjHa5mNe3OPW3OPRHVrbXFh9Ocvv/KR1372owx1Pf3005uc35Ddgtd8rsf06IdS5777zZ+mUqmPzjm6TPpmvayZOq4LyATeCzkanmiy4qEuC/yXiO8CSMRzvLs1x9phepLNZl868sy3Pyen/5hd1/EfRvWmuvSWNeaRS/RkPDI4+NjE1NSXEoXlpaNB1zqo20abi59/vu/UfM2pie7WUDVq8l3wTwnskeZ+zTbIQ17KoCzKpGzq2KqX32/roRbh8ePHdUzl0s9/5Rv9n/7go19MxCKfCkZiu3V06wrO5gocxL7Dgd/IEobEMH6rejg+auXidL5Y/vWv/vTX53/y/e/MkGajTH7fOt4RUJOY1df4RdtY6ICFRzqTySOhUOA+3Ai3o31H1ZbnlXBruFmt2iMrudy5xx9//BzWV7nXDBGN2xpjbt/5oGUEdhtO3iD47xZOvm8a5CHvpsV38wsUaMwBWsz3rbK5xr0mzdv2t9Jv/f5vhsF4J+Q63IUAAAAASUVORK5CYII=')
|
||||
tray = new Tray(icon)
|
||||
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Item1', type: 'radio' },
|
||||
{ label: 'Item2', type: 'radio' },
|
||||
{ label: 'Item3', type: 'radio', checked: true },
|
||||
{ label: 'Item4', type: 'radio' }
|
||||
])
|
||||
|
||||
tray.setToolTip('This is my application.')
|
||||
tray.setContextMenu(contextMenu)
|
||||
})
|
208
docs/tutorial/application-menu.md
Normal file
208
docs/tutorial/application-menu.md
Normal file
|
@ -0,0 +1,208 @@
|
|||
---
|
||||
title: Application Menu
|
||||
description: Customize the main application menu for your Electron app
|
||||
slug: application-menu
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Application Menu
|
||||
|
||||
Each Electron app has a single top-level application menu.
|
||||
|
||||
* On macOS, this menu is shown in the system [menu bar](https://support.apple.com/en-ca/guide/mac-help/mchlp1446/mac).
|
||||
* On Windows and Linux, this menu is shown at the top of each [BaseWindow](../api/base-window.md).
|
||||
|
||||
## Building application menus
|
||||
|
||||
The application menu can be set by passing a [Menu](../api/menu.md) instance into the
|
||||
[`Menu.setApplicationMenu`](../api/menu.md#menusetapplicationmenumenu) static function.
|
||||
|
||||
When building an application menu in Electron, each top-level array menu item **must be a submenu**.
|
||||
|
||||
Electron will set a default menu for your app if this API is never called. Below is an example of
|
||||
that default menu being created manually using shorthand [`MenuItem` roles](./menus.md#roles).
|
||||
|
||||
```js title='Manually creating the default menu' @ts-expect-error=[107]
|
||||
const { shell } = require('electron/common')
|
||||
const { app, Menu } = require('electron/main')
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
const template = [
|
||||
// { role: 'appMenu' }
|
||||
...(isMac
|
||||
? [{
|
||||
label: app.name,
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
}]
|
||||
: []),
|
||||
// { role: 'fileMenu' }
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
isMac ? { role: 'close' } : { role: 'quit' }
|
||||
]
|
||||
},
|
||||
// { role: 'editMenu' }
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
...(isMac
|
||||
? [
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startSpeaking' },
|
||||
{ role: 'stopSpeaking' }
|
||||
]
|
||||
}
|
||||
]
|
||||
: [
|
||||
{ role: 'delete' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'selectAll' }
|
||||
])
|
||||
]
|
||||
},
|
||||
// { role: 'viewMenu' }
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forceReload' },
|
||||
{ role: 'toggleDevTools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// { role: 'windowMenu' }
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
...(isMac
|
||||
? [
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'window' }
|
||||
]
|
||||
: [
|
||||
{ role: 'close' }
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: async () => {
|
||||
const { shell } = require('electron')
|
||||
await shell.openExternal('https://electronjs.org')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> On macOS, the first submenu of the application menu will **always** have your application's name
|
||||
> as its label. In general, you can populate this submenu by conditionally adding a menu item with
|
||||
> the `appMenu` role.
|
||||
|
||||
> [!TIP]
|
||||
> For additional descriptions of available roles, see the [`MenuItem` roles](./menus.md#roles)
|
||||
> section of the general Menus guide.
|
||||
|
||||
### Using standard OS menu roles
|
||||
|
||||
Defining each submenu explicitly can get very verbose. If you want to re-use default submenus
|
||||
in your app, you can use various submenu-related roles provided by Electron.
|
||||
|
||||
```js title='Using default roles for each submenu' @ts-expect-error=[26]
|
||||
const { shell } = require('electron/common')
|
||||
const { app, Menu } = require('electron/main')
|
||||
|
||||
const template = [
|
||||
...(process.platform === 'darwin'
|
||||
? [{ role: 'appMenu' }]
|
||||
: []),
|
||||
{ role: 'fileMenu' },
|
||||
{ role: 'editMenu' },
|
||||
{ role: 'viewMenu' },
|
||||
{ role: 'windowMenu' },
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: async () => {
|
||||
const { shell } = require('electron')
|
||||
await shell.openExternal('https://electronjs.org')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> On macOS, the `help` role defines a top-level Help submenu that has a search bar for
|
||||
> other menu items. It requires items to be added to its `submenu` to function.
|
||||
|
||||
## Setting window-specific application menus _Linux_ _Windows_
|
||||
|
||||
Since the root application menu exists on each `BaseWindow` on Windows and Linux, you can override
|
||||
it with a window-specific `Menu` instance via the [`win.setMenu`](../api/browser-window.md#winsetmenumenu-linux-windows) method.
|
||||
|
||||
```js title='Override a window's menu'
|
||||
const { BrowserWindow, Menu } = require('electron/main')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'my custom menu',
|
||||
submenu: [
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' }
|
||||
]
|
||||
}
|
||||
])
|
||||
win.setMenu(menu)
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> You can remove a specific window's application menu by calling the
|
||||
> [`win.removeMenu`](../api/base-window.md#winremovemenu-linux-windows) API.
|
69
docs/tutorial/context-menu.md
Normal file
69
docs/tutorial/context-menu.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: Context Menu
|
||||
description: Configure cross-platform native OS menus with the Menu API.
|
||||
slug: context-menu
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Context Menu
|
||||
|
||||
Context menus are pop-up menus that appear when right-clicking (or pressing a shortcut
|
||||
such as <kbd>Shift</kbd> + <kbd>F10</kbd> on Windows) somewhere in an app's interface.
|
||||
|
||||
No context menu will appear by default in Electron. However, context menus can be created by using
|
||||
the [`menu.popup`](../api/menu.md#menupopupoptions) function on an instance of the
|
||||
[Menu](../api/menu.md) class. You will need to listen for specific context menu events and set up
|
||||
the trigger for `menu.popup` manually.
|
||||
|
||||
There are two ways of listening for context menu events in Electron: either via the main process
|
||||
through [webContents](../api/web-contents.md) or in the renderer process via the
|
||||
[`contextmenu`](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event) web event.
|
||||
|
||||
## Using the `context-menu` event (main)
|
||||
|
||||
Whenever a right-click is detected within the bounds of a specific `WebContents` instance, a
|
||||
[`context-menu`](../api/web-contents.md#event-context-menu) event is triggered. The `params` object
|
||||
passed to the listener provides an extensive list of attributes to distinguish which type of element
|
||||
is receiving the event.
|
||||
|
||||
For example, if you want to provide a context menu for links, check for the `linkURL` parameter.
|
||||
If you want to check for editable elements such as `<textarea/>`, check for the `isEditable` parameter.
|
||||
|
||||
```fiddle docs/fiddles/menus/context-menu/web-contents
|
||||
```
|
||||
|
||||
## Using the `contextmenu` event (renderer)
|
||||
|
||||
Alternatively, you can also listen to the [`contextmenu`](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event)
|
||||
event available on DOM elements in the renderer process and call the `menu.popup` function via IPC.
|
||||
|
||||
> [!TIP]
|
||||
> To learn more about IPC basics in Electron, see the [Inter-Process Communication](./ipc.md) guide.
|
||||
|
||||
```fiddle docs/fiddles/menus/context-menu/dom|focus=preload.js
|
||||
```
|
||||
|
||||
## Additional macOS menu items (e.g. Writing Tools)
|
||||
|
||||
On macOS, the [Writing Tools](https://support.apple.com/en-ca/guide/mac-help/mchldcd6c260/15.0/mac/15.0),
|
||||
[AutoFill](https://support.apple.com/en-mz/guide/safari/ibrwf71ba236/mac), and
|
||||
[Services](https://support.apple.com/en-ca/guide/mac-help/mchlp1012/mac) menu items
|
||||
are disabled by default for context menus in Electron. To enable these features, pass the
|
||||
[WebFrameMain](../api/web-frame-main.md) associated to the target `webContents` to the `frame`
|
||||
parameter in `menu.popup`.
|
||||
|
||||
```js title='Associating a frame to the context menu'
|
||||
const { BrowserWindow, Menu } = require('electron/main')
|
||||
|
||||
const menu = Menu.buildFromTemplate([{ role: 'editMenu' }])
|
||||
const win = new BrowserWindow()
|
||||
win.webContents.on('context-menu', (_event, params) => {
|
||||
// Whether the context is editable.
|
||||
if (params.isEditable) {
|
||||
menu.popup({
|
||||
// highlight-next-line
|
||||
frame: params.frame
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
|
@ -1,127 +1,170 @@
|
|||
---
|
||||
title: "Keyboard Shortcuts"
|
||||
description: "Define accelerator strings for local and global keyboard shortcuts"
|
||||
slug: keyboard-shortcuts
|
||||
hide_title: false
|
||||
---
|
||||
|
||||
# Keyboard Shortcuts
|
||||
|
||||
## Overview
|
||||
## Accelerators
|
||||
|
||||
This feature allows you to configure local and global keyboard shortcuts
|
||||
for your Electron application.
|
||||
Accelerators are strings that can be used to represent keyboard shortcuts throughout your Electron.
|
||||
These strings can contain multiple modifiers keys and a single key code joined by the `+` character.
|
||||
|
||||
## Example
|
||||
> [!NOTE]
|
||||
> Accelerators are **case-insensitive**.
|
||||
|
||||
### Local Shortcuts
|
||||
### Available modifiers
|
||||
|
||||
Local keyboard shortcuts are triggered only when the application is focused.
|
||||
To configure a local keyboard shortcut, you need to specify an [`accelerator`][]
|
||||
property when creating a [MenuItem][] within the [Menu][] module.
|
||||
* `Command` (or `Cmd` for short)
|
||||
* `Control` (or `Ctrl` for short)
|
||||
* `CommandOrControl` (or `CmdOrCtrl` for short)
|
||||
* `Alt`
|
||||
* `Option`
|
||||
* `AltGr`
|
||||
* `Shift`
|
||||
* `Super` (or `Meta` as alias)
|
||||
|
||||
Starting with a working application from the
|
||||
[tutorial starter code][tutorial-starter-code], update the `main.js` to be:
|
||||
### Available key codes
|
||||
|
||||
```fiddle docs/fiddles/features/keyboard-shortcuts/local
|
||||
const { app, BrowserWindow, Menu, MenuItem } = require('electron/main')
|
||||
* `0` to `9`
|
||||
* `A` to `Z`
|
||||
* `F1` to `F24`
|
||||
* Various Punctuation: `)`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `:`, `;`, `:`, `+`, `=`, `<`, `,`, `_`, `-`, `>`, `.`, `?`, `/`, `~`, `` ` ``, `{`, `]`, `[`, `|`, `\`, `}`, `"`
|
||||
* `Plus`
|
||||
* `Space`
|
||||
* `Tab`
|
||||
* `Capslock`
|
||||
* `Numlock`
|
||||
* `Scrolllock`
|
||||
* `Backspace`
|
||||
* `Delete`
|
||||
* `Insert`
|
||||
* `Return` (or `Enter` as alias)
|
||||
* `Up`, `Down`, `Left` and `Right`
|
||||
* `Home` and `End`
|
||||
* `PageUp` and `PageDown`
|
||||
* `Escape` (or `Esc` for short)
|
||||
* `VolumeUp`, `VolumeDown` and `VolumeMute`
|
||||
* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause`
|
||||
* `PrintScreen`
|
||||
* NumPad Keys
|
||||
* `num0` - `num9`
|
||||
* `numdec` - decimal key
|
||||
* `numadd` - numpad `+` key
|
||||
* `numsub` - numpad `-` key
|
||||
* `nummult` - numpad `*` key
|
||||
* `numdiv` - numpad `÷` key
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
### Cross-platform modifiers
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
Many modifier accelerators map to different keys between operating systems.
|
||||
|
||||
| Modifier | macOS | Windows and Linux |
|
||||
|------------------|-------------|----------------------|
|
||||
|`CommandOrControl`| Command (⌘) | Control |
|
||||
|`Command` | Command (⌘) | N/A |
|
||||
|`Control` | Control (^) | Control |
|
||||
|`Alt` | Option (⌥) | Alt |
|
||||
|`Option` | Option (⌥) | N/A |
|
||||
|`Super` (`Meta`) | Command (⌘) | Windows (⊞) |
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> * On Linux and Windows, the `Command` modifier does not have any effect. In general, you should use
|
||||
> the `CommandOrControl` modifier instead, which represents <kbd>⌘ Cmd</kbd> on macOS and <kbd>Ctrl</kbd>
|
||||
> on Linux and Windows.
|
||||
> * Use `Alt` instead of `Option`. The <kbd>⌥ Opt</kbd> key only exists on macOS, whereas the `Alt` will
|
||||
> map to the appropriate modifier on all platforms.
|
||||
|
||||
#### Examples
|
||||
|
||||
Here are some examples of cross-platform Electron accelerators for common editing operations:
|
||||
|
||||
* Copy: `CommandOrControl+C`
|
||||
* Paste: `CommandOrControl+V`
|
||||
* Undo: `CommandOrControl+Z`
|
||||
* Redo: `CommandOrControl+Shift+Z`
|
||||
|
||||
## Local shortcuts
|
||||
|
||||
**Local** keyboard shortcuts are triggered only when the application is focused. These shortcuts
|
||||
map to specific menu items within the app's main [application menu](./application-menu.md).
|
||||
|
||||
To define a local keyboard shortcut, you need to configure the `accelerator` property when creating
|
||||
a [MenuItem](../api/menu-item.md). Then, the `click` event associated to that menu item will trigger
|
||||
upon using that accelerator.
|
||||
|
||||
```js title='Opening a dialog via accelerator (local)'
|
||||
const { dialog, Menu, MenuItem } = require('electron/main')
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({
|
||||
label: 'Electron',
|
||||
submenu: [{
|
||||
role: 'help',
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+I' : 'Alt+Shift+I',
|
||||
click: () => { console.log('Electron rocks!') }
|
||||
}]
|
||||
}))
|
||||
|
||||
Menu.setApplicationMenu(menu)
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
> NOTE: In the code above, you can see that the accelerator differs based on the
|
||||
user's operating system. For MacOS, it is `Alt+Cmd+I`, whereas for Linux and
|
||||
Windows, it is `Alt+Shift+I`.
|
||||
|
||||
After launching the Electron application, you should see the application menu
|
||||
along with the local shortcut you just defined:
|
||||
|
||||

|
||||
|
||||
If you click `Help` or press the defined accelerator and then open the terminal
|
||||
that you ran your Electron application from, you will see the message that was
|
||||
generated after triggering the `click` event: "Electron rocks!".
|
||||
|
||||
### Global Shortcuts
|
||||
|
||||
To configure a global keyboard shortcut, you need to use the [globalShortcut][]
|
||||
module to detect keyboard events even when the application does not have
|
||||
keyboard focus.
|
||||
|
||||
Starting with a working application from the
|
||||
[tutorial starter code][tutorial-starter-code], update the `main.js` to be:
|
||||
|
||||
```fiddle docs/fiddles/features/keyboard-shortcuts/global
|
||||
const { app, BrowserWindow, globalShortcut } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
// The first submenu needs to be the app menu on macOS
|
||||
if (process.platform === 'darwin') {
|
||||
const appMenu = new MenuItem({ role: 'appMenu' })
|
||||
menu.append(appMenu)
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
globalShortcut.register('Alt+CommandOrControl+I', () => {
|
||||
console.log('Electron loves global shortcuts!')
|
||||
})
|
||||
}).then(createWindow)
|
||||
// highlight-start
|
||||
const submenu = Menu.buildFromTemplate([{
|
||||
label: 'Open a Dialog',
|
||||
click: () => dialog.showMessageBox({ message: 'Hello World!' }),
|
||||
accelerator: 'CommandOrControl+Alt+R'
|
||||
}])
|
||||
menu.append(new MenuItem({ label: 'Custom Menu', submenu }))
|
||||
// highlight-end
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
Menu.setApplicationMenu(menu)
|
||||
```
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
In the above example, a native "Hello World" dialog will open when pressing <kbd>⌘ Cmd</kbd>+<kbd>⌥ Opt</kbd>+<kbd>R</kbd>
|
||||
on macOS or <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>R</kbd> on other platforms.
|
||||
|
||||
> [!TIP]
|
||||
> Accelerators can work even when menu items are hidden. On macOS, this feature can be disabled by
|
||||
> setting `acceleratorWorksWhenHidden: false` when building a `MenuItem`.
|
||||
|
||||
> [!TIP]
|
||||
> On Windows and Linux, the `registerAccelerator` property of the `MenuItem` can be set to `false`
|
||||
> so that the accelerator is visible in the system menu but not enabled.
|
||||
|
||||
## Global shortcuts
|
||||
|
||||
**Global** keyboard shortcuts work even when your app is out of focus. To configure a global keyboard
|
||||
shortcut, you can use the [`globalShortcut.register`](../api/global-shortcut.md#globalshortcutregisteraccelerator-callback)
|
||||
function to specify shortcuts.
|
||||
|
||||
```js title='Opening a dialog via accelerator (global)'
|
||||
const { dialog, globalShortcut } = require('electron/main')
|
||||
|
||||
globalShortcut.register('CommandOrControl+Alt+R', () => {
|
||||
dialog.showMessageBox({ message: 'Hello World!' })
|
||||
})
|
||||
```
|
||||
|
||||
> NOTE: In the code above, the `CommandOrControl` combination uses `Command`
|
||||
on macOS and `Control` on Windows/Linux.
|
||||
To later unregister a shortcut, you can use the [`globalShortcut.unregisterAccelerator`](../api/global-shortcut.md#globalshortcutunregisteraccelerator)
|
||||
function.
|
||||
|
||||
After launching the Electron application, if you press the defined key
|
||||
combination then open the terminal that you ran your Electron application from,
|
||||
you will see that Electron loves global shortcuts!
|
||||
```js title='Opening a dialog via accelerator (global)'
|
||||
const { globalShortcut } = require('electron/main')
|
||||
|
||||
### Shortcuts within a BrowserWindow
|
||||
globalShortcut.unregister('CommandOrControl+Alt+R')
|
||||
```
|
||||
|
||||
#### Using web APIs
|
||||
> [!WARNING]
|
||||
> On macOS, there's a long-standing bug with `globalShortcut` that prevents it from working with
|
||||
> keyboard layouts other than QWERTY ([electron/electron#19747](https://github.com/electron/electron/issues/19747)).
|
||||
|
||||
If you want to handle keyboard shortcuts within a [BrowserWindow][], you can
|
||||
listen for the `keyup` and `keydown` [DOM events][dom-events] inside the
|
||||
renderer process using the [addEventListener() API][addEventListener-api].
|
||||
## Shortcuts within a window
|
||||
|
||||
### In the renderer process
|
||||
|
||||
If you want to handle keyboard shortcuts within a [BaseWindow](../api/base-window.md), you can
|
||||
listen for the [`keyup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/keyup_event) and
|
||||
[`keydown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event) DOM Events inside
|
||||
the renderer process using the [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) API.
|
||||
|
||||
```fiddle docs/fiddles/features/keyboard-shortcuts/web-apis|focus=renderer.js
|
||||
function handleKeyPress (event) {
|
||||
|
@ -141,18 +184,14 @@ window.addEventListener('keyup', handleKeyPress, true)
|
|||
#### Intercepting events in the main process
|
||||
|
||||
The [`before-input-event`](../api/web-contents.md#event-before-input-event) event
|
||||
is emitted before dispatching `keydown` and `keyup` events in the page. It can
|
||||
is emitted before dispatching `keydown` and `keyup` events in the renderer process. It can
|
||||
be used to catch and handle custom shortcuts that are not visible in the menu.
|
||||
|
||||
Starting with a working application from the
|
||||
[tutorial starter code][tutorial-starter-code], update the `main.js` file with the
|
||||
following lines:
|
||||
|
||||
```fiddle docs/fiddles/features/keyboard-shortcuts/interception-from-main
|
||||
```js title='Intercepting the Ctrl+I event from the main process'
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.loadFile('index.html')
|
||||
win.webContents.on('before-input-event', (event, input) => {
|
||||
|
@ -163,49 +202,3 @@ app.whenReady().then(() => {
|
|||
})
|
||||
})
|
||||
```
|
||||
|
||||
After launching the Electron application, if you open the terminal that you ran
|
||||
your Electron application from and press `Ctrl+I` key combination, you will
|
||||
see that this key combination was successfully intercepted.
|
||||
|
||||
#### Using third-party libraries
|
||||
|
||||
If you don't want to do manual shortcut parsing, there are libraries that do
|
||||
advanced key detection, such as [mousetrap][]. Below are examples of usage of the
|
||||
`mousetrap` running in the Renderer process:
|
||||
|
||||
```js @ts-nocheck
|
||||
Mousetrap.bind('4', () => { console.log('4') })
|
||||
Mousetrap.bind('?', () => { console.log('show shortcuts!') })
|
||||
Mousetrap.bind('esc', () => { console.log('escape') }, 'keyup')
|
||||
|
||||
// combinations
|
||||
Mousetrap.bind('command+shift+k', () => { console.log('command shift k') })
|
||||
|
||||
// map multiple combinations to the same callback
|
||||
Mousetrap.bind(['command+k', 'ctrl+k'], () => {
|
||||
console.log('command k or control k')
|
||||
|
||||
// return false to prevent default behavior and stop event from bubbling
|
||||
return false
|
||||
})
|
||||
|
||||
// gmail style sequences
|
||||
Mousetrap.bind('g i', () => { console.log('go to inbox') })
|
||||
Mousetrap.bind('* a', () => { console.log('select all') })
|
||||
|
||||
// konami code!
|
||||
Mousetrap.bind('up up down down left right left right b a enter', () => {
|
||||
console.log('konami code')
|
||||
})
|
||||
```
|
||||
|
||||
[Menu]: ../api/menu.md
|
||||
[MenuItem]: ../api/menu-item.md
|
||||
[globalShortcut]: ../api/global-shortcut.md
|
||||
[`accelerator`]: ../api/accelerator.md
|
||||
[BrowserWindow]: ../api/browser-window.md
|
||||
[mousetrap]: https://github.com/ccampbell/mousetrap
|
||||
[dom-events]: https://developer.mozilla.org/en-US/docs/Web/Events
|
||||
[addEventListener-api]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
|
||||
[tutorial-starter-code]: tutorial-2-first-app.md#final-starter-code
|
||||
|
|
|
@ -1,76 +1,73 @@
|
|||
---
|
||||
title: Dock
|
||||
description: Configure your application's Dock presence on macOS.
|
||||
title: Dock Menu
|
||||
description: Configure your app's Dock presence on macOS.
|
||||
slug: macos-dock
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Dock
|
||||
# Dock Menu
|
||||
|
||||
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
|
||||
API exists to create a custom dock menu, but Electron also uses the app dock
|
||||
icon as the entry point for cross-platform features like
|
||||
[recent documents][recent-documents] and [application progress][progress-bar].
|
||||
On macOS, the [Dock](https://support.apple.com/en-ca/guide/mac-help/mh35859/mac) is an interface
|
||||
element that displays open and frequently-used apps. While opened or pinned, each app has its own
|
||||
icon in the Dock.
|
||||
|
||||
The custom dock is commonly used to add shortcuts to tasks the user wouldn't
|
||||
want to open the whole app window for.
|
||||
> [!NOTE]
|
||||
> On macOS, the Dock is the entry point for certain cross-platform features like
|
||||
> [Recent Documents](./recent-documents.md) and [Application Progress](./progress-bar.md).
|
||||
> Read those guides for more details.
|
||||
|
||||
**Dock menu of Terminal.app:**
|
||||
## Dock API
|
||||
|
||||
![Dock Menu][dock-menu-image]
|
||||
All functionality for the Dock is exposed via the [Dock](../api/dock.md) class exposed via
|
||||
[`app.dock`](../api/app.md#appdock-macos-readonly) property. There is a single `Dock` instance per
|
||||
Electron application, and this property only exists on macOS.
|
||||
|
||||
To set your custom dock menu, you need to use the
|
||||
[`app.dock.setMenu`](../api/dock.md#docksetmenumenu-macos) API,
|
||||
which is only available on macOS.
|
||||
One of the main uses for your app's Dock icon is to expose additional app menus. The Dock menu is
|
||||
triggered by right-clicking or <kbd>Ctrl</kbd>-clicking the app icon. By default, the app's Dock menu
|
||||
will come with system-provided window management utilities, including the ability to show all windows,
|
||||
hide the app, and switch betweeen different open windows.
|
||||
|
||||
```fiddle docs/fiddles/features/macos-dock-menu
|
||||
To set an app-defined custom Dock menu, pass any [Menu](../api/menu.md) instance into the
|
||||
[`dock.setMenu`](../api/dock.md#docksetmenumenu-macos) API.
|
||||
|
||||
> [!TIP]
|
||||
> For best practices to make your Dock menu feel more native, see Apple's
|
||||
> [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/dock-menus)
|
||||
> page on Dock menus.
|
||||
|
||||
## Attaching a context menu
|
||||
|
||||
```js title='Setting a Dock menu'
|
||||
const { app, BrowserWindow, Menu } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const dockMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'New Window',
|
||||
click () { console.log('New Window') }
|
||||
}, {
|
||||
label: 'New Window with Settings',
|
||||
submenu: [
|
||||
{ label: 'Basic' },
|
||||
{ label: 'Pro' }
|
||||
]
|
||||
},
|
||||
{ label: 'New Command...' }
|
||||
])
|
||||
|
||||
// dock.setMenu only works after the 'ready' event is fired
|
||||
app.whenReady().then(() => {
|
||||
const dockMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'New Window',
|
||||
click: () => { const win = new BrowserWindow() }
|
||||
}
|
||||
// add more menu options to the array
|
||||
])
|
||||
|
||||
// Dock is undefined on platforms outside of macOS
|
||||
// highlight-next-line
|
||||
app.dock?.setMenu(dockMenu)
|
||||
}).then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
After launching the Electron application, right click the application icon.
|
||||
You should see the custom menu you just defined:
|
||||
> [!NOTE]
|
||||
> Unlike with regular [context menus](./context-menu.md), Dock context menus don't need to be
|
||||
> manually instrumented using the `menu.popup` API. Instead, the Dock object handles click events
|
||||
> for you.
|
||||
|
||||

|
||||
> [!TIP]
|
||||
> To learn more about crafting menus in Electron, see the [Menus](./menus.md#building-menus) guide.
|
||||
|
||||
[dock-menu-image]: https://cloud.githubusercontent.com/assets/639601/5069962/6032658a-6e9c-11e4-9953-aa84006bdfff.png
|
||||
[recent-documents]: ./recent-documents.md
|
||||
[progress-bar]: ./progress-bar.md
|
||||
## Runnable Fiddle demo
|
||||
|
||||
Below is a runnable example of how you can use the Dock menu to create and close windows in your
|
||||
Electron app.
|
||||
|
||||
```fiddle docs/fiddles/menus/dock-menu
|
||||
```
|
||||
|
|
348
docs/tutorial/menus.md
Normal file
348
docs/tutorial/menus.md
Normal file
|
@ -0,0 +1,348 @@
|
|||
---
|
||||
title: Menus
|
||||
description: Configure cross-platform native OS menus with the Menu API.
|
||||
slug: menus
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
# Menus
|
||||
|
||||
Electron's [Menu](../api/menu.md) class provides a standardized way to create cross-platform native
|
||||
menus throughout your application.
|
||||
|
||||
## Available menus in Electron
|
||||
|
||||
The same menu API is used for multiple use cases:
|
||||
|
||||
* The **application menu** is the top-level menu for your application. Each app only has a single
|
||||
application menu at a time.
|
||||
* **Context menus** are triggered by the user when right-clicking on a portion of your app's
|
||||
interface.
|
||||
* The **tray menu** is a special context menu triggered when right-clicking on your app's [Tray](../api/tray.md)
|
||||
instance.
|
||||
* On macOS, the **dock menu** is a special context menu triggered when right-clicking on your app's
|
||||
icon in the system [Dock](https://support.apple.com/en-ca/guide/mac-help/mh35859/mac).
|
||||
|
||||
To learn more about the various kinds of native menus you can create and how to specify keyboard
|
||||
shortcuts, see the individual guides in this section:
|
||||
|
||||
<DocCardList />
|
||||
|
||||
## Building menus
|
||||
|
||||
Each `Menu` instance is composed of an array of [MenuItem](../api/menu-item.md) objects accessible via
|
||||
the `menu.items` instance property. Menus can be nested by setting the `item.submenu` property to
|
||||
another menu.
|
||||
|
||||
There are two ways to build a menu: either by directly calling [`menu.append`](../api/menu.md#menuappendmenuitem)
|
||||
or by using the static [`Menu.buildFromTemplate`](../api/menu.md#menubuildfromtemplatetemplate)
|
||||
helper function.
|
||||
|
||||
The helper function reduces boilerplate by allowing you to pass a collection of `MenuItem`
|
||||
constructor options (or instantiated `MenuItem` instances) in a single array rather than having to
|
||||
append each item in a separate function call.
|
||||
|
||||
Below is an example of a minimal application menu:
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="constructor" label="Constructor">
|
||||
```js title='menu.js'
|
||||
const submenu = new Menu()
|
||||
submenu.append(new MenuItem({ label: 'Hello' }))
|
||||
submenu.append(new MenuItem({ type: 'separator' }))
|
||||
submenu.append(new MenuItem({ label: 'Electron', type: 'checkbox', checked: true }))
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({ label: 'Menu', submenu }))
|
||||
Menu.setApplicationMenu(menu)
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="template" label="Template Helper">
|
||||
```js title='menu.js'
|
||||
const menu = Menu.buildFromTemplate([{
|
||||
label: 'Menu',
|
||||
submenu: [
|
||||
{ label: 'Hello' },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Electron', type: 'checkbox', checked: true }
|
||||
]
|
||||
}])
|
||||
Menu.setApplicationMenu(menu)
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
> [!IMPORTANT]
|
||||
> All menu items (except for the `separator` type) must have a label. Labels can either be manually
|
||||
> defined using the `label` property or inherited from the item's `role`.
|
||||
|
||||
### Types
|
||||
|
||||
A menu item's type grants it a particular appearance and functionality. Some types are
|
||||
automatically assigned based on other constructor options:
|
||||
|
||||
* By default, menu items have the `normal` type.
|
||||
* Menu items that contain the `submenu` property will be assigned the `submenu` type.
|
||||
|
||||
Other available types, when specified, give special additional properties to the menu item:
|
||||
|
||||
* `checkbox` - toggles the `checked` property whenever the menu item is clicked
|
||||
* `radio` - toggles the `checked` property and turns off that property for all adjacent `radio` items
|
||||
* `palette` - creates a [Palette](https://developer.apple.com/documentation/appkit/nsmenu/presentationstyle-swift.enum/palette)
|
||||
submenu, which aligns items horizontally (available on macOS 14 and above)
|
||||
* `header` - creates a section header, which can convey groupings with labels (available on macOS 14 and above)
|
||||
|
||||
> [!TIP]
|
||||
> Adjacent `radio` items are at the same level of submenu and not divided by a separator.
|
||||
>
|
||||
> ```js
|
||||
> [
|
||||
> { type: 'radio', label: 'Adjacent 1' },
|
||||
> { type: 'radio', label: 'Adjacent 2' },
|
||||
> { type: 'separator' },
|
||||
> { type: 'radio', label: 'Non-adjacent' } // unaffected by the others
|
||||
> ]
|
||||
> ```
|
||||
|
||||
### Roles
|
||||
|
||||
Roles give `normal` type menu items predefined behaviors.
|
||||
|
||||
We recommend specifying the `role` attribute for any menu item that matches a standard role
|
||||
rather than trying to manually implement the behavior in a `click` function.
|
||||
The built-in `role` behavior will give the best native experience.
|
||||
|
||||
The `label` and `accelerator` values are optional when using a `role` and will
|
||||
default to appropriate values for each platform.
|
||||
|
||||
> [!TIP]
|
||||
> Role strings are **case-insensitive**. For example, `toggleDevTools`, `toggledevtools`, and
|
||||
> `TOGGLEDEVTOOLS` are all equivalent roles when defining menu items.
|
||||
|
||||
#### Edit roles
|
||||
|
||||
* `undo`
|
||||
* `redo`
|
||||
* `cut`
|
||||
* `copy`
|
||||
* `paste`
|
||||
* `pasteAndMatchStyle`
|
||||
* `selectAll`
|
||||
* `delete`
|
||||
|
||||
#### Window roles
|
||||
|
||||
* `about` - Trigger a native about panel (custom message box on Window, which does not provide its own).
|
||||
* `minimize` - Minimize current window.
|
||||
* `close` - Close current window.
|
||||
* `quit` - Quit the application.
|
||||
* `reload` - Reload the current window.
|
||||
* `forceReload` - Reload the current window ignoring the cache.
|
||||
* `toggleDevTools` - Toggle developer tools in the current window.
|
||||
* `togglefullscreen` - Toggle full screen mode on the current window.
|
||||
* `resetZoom` - Reset the focused page's zoom level to the original size.
|
||||
* `zoomIn` - Zoom in the focused page by 10%.
|
||||
* `zoomOut` - Zoom out the focused page by 10%.
|
||||
* `toggleSpellChecker` - Enable/disable built-in spellchecker.
|
||||
|
||||
#### Default menu roles
|
||||
|
||||
* `fileMenu` - The submenu is a "File" menu (Close / Quit)
|
||||
* `editMenu` - The submenu is an "Edit" menu (Undo, Copy, etc.)
|
||||
* `viewMenu` - The submenu is a "View" menu (Reload, Toggle Developer Tools, etc.)
|
||||
* `windowMenu` - The submenu is a "Window" menu (Minimize, Zoom, etc.)
|
||||
|
||||
#### macOS-only roles
|
||||
|
||||
macOS has a number of platform-specific menu roles available. Many of these map to underlying
|
||||
[AppKit](https://developer.apple.com/documentation/appkit) APIs.
|
||||
|
||||
##### App management roles
|
||||
|
||||
* `hide` - Map to the [`hide`](https://developer.apple.com/documentation/appkit/nsapplication/hide(_:)) action.
|
||||
* `hideOthers` - Map to the [`hideOtherApplications`](https://developer.apple.com/documentation/appkit/nsapplication/hideotherapplications(_:)) action.
|
||||
* `unhide` - Map to the [`unhideAllApplications`](https://developer.apple.com/documentation/appkit/nsapplication/unhideallapplications(_:)) action.
|
||||
* `front` - Map to the [`arrangeInFront`](https://developer.apple.com/documentation/appkit/nsapplication/arrangeinfront(_:)) action.
|
||||
* `zoom` - Map to the [`performZoom`](https://developer.apple.com/documentation/appkit/nswindow/performzoom(_:)) action.
|
||||
|
||||
##### Edit roles
|
||||
|
||||
* `showSubstitutions` - Map to the [`orderFrontSubstitutionsPanel`](https://developer.apple.com/documentation/appkit/nstextview/orderfrontsubstitutionspanel(_:)) action.
|
||||
* `toggleSmartQuotes` - Map to the [`toggleAutomaticQuoteSubstitution`](https://developer.apple.com/documentation/appkit/nstextview/toggleautomaticquotesubstitution(_:)) action.
|
||||
* `toggleSmartDashes` - Map to the [`toggleAutomaticDashSubstitution`](https://developer.apple.com/documentation/appkit/nstextview/toggleautomaticdashsubstitution(_:)) action.
|
||||
* `toggleTextReplacement` - Map to the [`toggleAutomaticTextReplacement`](https://developer.apple.com/documentation/appkit/nstextview/toggleautomatictextreplacement(_:)) action.
|
||||
|
||||
##### Speech roles
|
||||
|
||||
* `startSpeaking` - Map to the [`startSpeaking`](https://developer.apple.com/documentation/appkit/nstextview/startspeaking(_:)) action.
|
||||
* `stopSpeaking` - Map to the [`stopSpeaking`](https://developer.apple.com/documentation/appkit/nstextview/stopspeaking(_:)) action.
|
||||
|
||||
##### Native tab roles
|
||||
|
||||
* `toggleTabBar` - Map to the [`toggleTabBar`](https://developer.apple.com/documentation/appkit/nswindow/toggletabbar(_:)) action.
|
||||
* `selectNextTab` - Map to the [`selectNextTab`](https://developer.apple.com/documentation/appkit/nswindow/selectnexttab(_:)) action.
|
||||
* `selectPreviousTab` - Map to the [`selectPreviousTab`](https://developer.apple.com/documentation/appkit/nswindow/selectprevioustab(_:)) action.
|
||||
<!-- * `showAllTabs` - Map to the `showAllTabs` action. -->
|
||||
* `mergeAllWindows` - Map to the [`mergeAllWindows`](https://developer.apple.com/documentation/appkit/nswindow/mergeallwindows(_:)) action.
|
||||
* `moveTabToNewWindow` - Map to the [`moveTabToNewWindow`](https://developer.apple.com/documentation/appkit/nswindow/movetabtonewwindow(_:)) action.
|
||||
|
||||
##### Default menu roles
|
||||
|
||||
* `appMenu` - Whole default "App" menu (About, Services, etc.)
|
||||
* `services` - The submenu is a ["Services"](https://developer.apple.com/documentation/appkit/nsapplication/1428608-servicesmenu?language=objc) menu.
|
||||
* `window` - The submenu is a "Window" menu.
|
||||
* `help` - The submenu is a "Help" menu.
|
||||
|
||||
##### Other menu roles
|
||||
|
||||
* `recentDocuments` - The submenu is an "Open Recent" menu.
|
||||
* `clearRecentDocuments` - Map to the [`clearRecentDocuments`](https://developer.apple.com/documentation/appkit/nsdocumentcontroller/clearrecentdocuments(_:)) action.
|
||||
* `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> When specifying a `role` on macOS, `label` and `accelerator` are the only
|
||||
> options that will affect the menu item. All other options will be ignored.
|
||||
|
||||
### Accelerators
|
||||
|
||||
The `accelerator` property allows you to define accelerator strings to map menu items to keyboard
|
||||
shortcuts. For more details, see the [Keyboard Shortcuts](./keyboard-shortcuts.md) guide.
|
||||
|
||||
## Advanced configuration
|
||||
|
||||
### Programmatic item positioning
|
||||
|
||||
You can make use of the `before`, `after`, `beforeGroupContaining`, `afterGroupContaining` and `id` attributes
|
||||
to control how menu items will be placed when building a menu with `Menu.buildFromTemplate`.
|
||||
|
||||
* `before` - Inserts this item before the item with the specified id. If the
|
||||
referenced item doesn't exist, the item will be inserted at the end of
|
||||
the menu. Also implies that the menu item in question should be placed in the same “group” as the item.
|
||||
* `after` - Inserts this item after the item with the specified id. If the
|
||||
referenced item doesn't exist, the item will be inserted at the end of
|
||||
the menu. Also implies that the menu item in question should be placed in the same “group” as the item.
|
||||
* `beforeGroupContaining` - Provides a means for a single context menu to declare
|
||||
the placement of their containing group before the containing group of the item with the specified id.
|
||||
* `afterGroupContaining` - Provides a means for a single context menu to declare
|
||||
the placement of their containing group after the containing group of the item with the specified id.
|
||||
|
||||
By default, items will be inserted in the order they exist in the template unless one of the specified
|
||||
positioning keywords is used.
|
||||
|
||||
#### Examples
|
||||
|
||||
Template:
|
||||
|
||||
```js
|
||||
[
|
||||
{ id: '1', label: 'one' },
|
||||
{ id: '2', label: 'two' },
|
||||
{ id: '3', label: 'three' },
|
||||
{ id: '4', label: 'four' }
|
||||
]
|
||||
```
|
||||
|
||||
Menu:
|
||||
|
||||
```plaintext
|
||||
- one
|
||||
- two
|
||||
- three
|
||||
- four
|
||||
```
|
||||
|
||||
Template:
|
||||
|
||||
```js
|
||||
[
|
||||
{ id: '1', label: 'one' },
|
||||
{ type: 'separator' },
|
||||
{ id: '3', label: 'three', beforeGroupContaining: ['1'] },
|
||||
{ id: '4', label: 'four', afterGroupContaining: ['2'] },
|
||||
{ type: 'separator' },
|
||||
{ id: '2', label: 'two' }
|
||||
]
|
||||
```
|
||||
|
||||
Menu:
|
||||
|
||||
```plaintext
|
||||
- three
|
||||
- four
|
||||
- ---
|
||||
- one
|
||||
- ---
|
||||
- two
|
||||
```
|
||||
|
||||
Template:
|
||||
|
||||
```js
|
||||
[
|
||||
{ id: '1', label: 'one', after: ['3'] },
|
||||
{ id: '2', label: 'two', before: ['1'] },
|
||||
{ id: '3', label: 'three' }
|
||||
]
|
||||
```
|
||||
|
||||
Menu:
|
||||
|
||||
```plaintext
|
||||
- ---
|
||||
- three
|
||||
- two
|
||||
- one
|
||||
```
|
||||
|
||||
### Icons
|
||||
|
||||
To add visual aid to your menus, you can use the `icon` property to assign images to individual
|
||||
`MenuItem` instances.
|
||||
|
||||
```js title='Adding a little green circle to a menu item'
|
||||
const { nativeImage } = require('electron/common')
|
||||
const { MenuItem } = require('electron/main')
|
||||
|
||||
// highlight-next-line
|
||||
const green = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACOSURBVHgBpZLRDYAgEEOrEzgCozCCGzkCbKArOIlugJvgoRAUNcLRpvGH19TkgFQWkqIohhK8UEaKwKcsOg/+WR1vX+AlA74u6q4FqgCOSzwsGHCwbKliAF89Cv89tWmOT4VaVMoVbOBrdQUz+FrD6XItzh4LzYB1HFJ9yrEkZ4l+wvcid9pTssh4UKbPd+4vED2Nd54iAAAAAElFTkSuQmCC')
|
||||
|
||||
const item = new MenuItem({
|
||||
label: 'Green Circle',
|
||||
// highlight-next-line
|
||||
icon: green
|
||||
})
|
||||
```
|
||||
|
||||
### Sublabels _macOS_
|
||||
|
||||
You can add sublabels (also known as [subtitles](https://developer.apple.com/documentation/appkit/nsmenuitem/subtitle))
|
||||
to menu items using the `sublabel` option on macOS 14.4 and above.
|
||||
|
||||
```js title='Adding descriptions via sublabel'
|
||||
const { MenuItem } = require('electron/main')
|
||||
|
||||
const item = new MenuItem({
|
||||
label: 'Log Message',
|
||||
// highlight-next-line
|
||||
sublabel: 'This will use the console.log utility',
|
||||
click: () => { console.log('Logging via menu...') }
|
||||
})
|
||||
```
|
||||
|
||||
### Tooltips _macOS_
|
||||
|
||||
Tooltips are informational indicators that appear when you hover over a menu item. You can set menu
|
||||
item tooltips on macOS using the `toolTip` option.
|
||||
|
||||
```js title='Adding additional information via tooltip'
|
||||
const { MenuItem } = require('electron/main')
|
||||
|
||||
const item = new MenuItem({
|
||||
label: 'Hover Over Me',
|
||||
// highlight-next-line
|
||||
toolTip: 'This is additional info that appears on hover'
|
||||
})
|
||||
```
|
|
@ -1,83 +1,86 @@
|
|||
---
|
||||
title: Tray
|
||||
description: This guide will take you through the process of creating
|
||||
a Tray icon with its own context menu to the system's notification area.
|
||||
title: Tray Menu
|
||||
description: Create a Tray icon with its own menu in the system's notification area.
|
||||
slug: tray
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Tray
|
||||
# Tray Menu
|
||||
|
||||
## Overview
|
||||
This guide will take you through the process of creating an icon with its own context menu to the
|
||||
system tray.
|
||||
|
||||
<!-- ✍ Update this section if you want to provide more details -->
|
||||
* On macOS, the icon will be located on the top right corner of your screen in the
|
||||
[menu bar extras](https://developer.apple.com/design/human-interface-guidelines/the-menu-bar#Menu-bar-extras)
|
||||
area.
|
||||
* On Windows, the icon will be located in the [notification area](https://learn.microsoft.com/en-us/windows/win32/shell/notification-area)
|
||||
at the end of the taskbar.
|
||||
* On Linux, the location of the Tray will differ based on your desktop environment.
|
||||
|
||||
This guide will take you through the process of creating a
|
||||
[Tray](../api/tray.md) icon with
|
||||
its own context menu to the system's notification area.
|
||||
## Creating a Tray icon
|
||||
|
||||
On MacOS and Ubuntu, the Tray will be located on the top
|
||||
right corner of your screen, adjacent to your battery and wifi icons.
|
||||
On Windows, the Tray will usually be located in the bottom right corner.
|
||||
The tray icon for your Electron app needs to be created programmatically with an instance of
|
||||
the [Tray](../api/tray.md#new-trayimage-guid) class. The class constructor requires a single
|
||||
instance of a [NativeImage](../api/native-image.md#class-nativeimage) or a path to a compatible icon
|
||||
file.
|
||||
|
||||
## Example
|
||||
> [!NOTE]
|
||||
> File formats vary per operating system. For more details, see the
|
||||
> [Platform Considerations](../api/tray.md#platform-considerations) section of the Tray API documentation.
|
||||
|
||||
### main.js
|
||||
## Minimizing to tray
|
||||
|
||||
First we must import `app`, `Tray`, `Menu`, `nativeImage` from `electron`.
|
||||
In order to keep the app and the system tray icon alive even when all windows are closed, you need to
|
||||
have a listener for the [`window-all-closed`](../api/app.md#event-window-all-closed) event on the
|
||||
`app` module. The base Electron templates generally listen for this event but quit the app on
|
||||
Windows and Linux to emulate standard OS behavior.
|
||||
|
||||
```js
|
||||
const { app, Tray, Menu, nativeImage } = require('electron')
|
||||
```
|
||||
|
||||
Next we will create our Tray. To do this, we will use a
|
||||
[`NativeImage`](../api/native-image.md) icon,
|
||||
which can be created through any one of these
|
||||
[methods](../api/native-image.md#methods).
|
||||
Note that we wrap our Tray creation code within an
|
||||
[`app.whenReady`](../api/app.md#appwhenready)
|
||||
as we will need to wait for our electron app to finish initializing.
|
||||
|
||||
```js title='main.js'
|
||||
let tray
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const icon = nativeImage.createFromPath('path/to/asset.png')
|
||||
tray = new Tray(icon)
|
||||
|
||||
// note: your contextMenu, Tooltip and Title code will go here!
|
||||
```js title='Setting up minimize to tray'
|
||||
app.on('window-all-closed', () => {
|
||||
// having this listener active will prevent the app from quitting.
|
||||
})
|
||||
```
|
||||
|
||||
Great! Now we can start attaching a context menu to our Tray, like so:
|
||||
## Attaching a context menu
|
||||
|
||||
```js @ts-expect-error=[8]
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: 'Item1', type: 'radio' },
|
||||
{ label: 'Item2', type: 'radio' },
|
||||
{ label: 'Item3', type: 'radio', checked: true },
|
||||
{ label: 'Item4', type: 'radio' }
|
||||
])
|
||||
You can attach a context menu to the Tray object by passing in a [Menu](../api/menu.md) instance
|
||||
into the [`tray.setContextMenu`](../api/tray.md#traysetcontextmenumenu) function.
|
||||
|
||||
tray.setContextMenu(contextMenu)
|
||||
> [!NOTE]
|
||||
> Unlike with regular [context menus](./context-menu.md), Tray context menus don't need to be
|
||||
> manually instrumented using the `menu.popup` API. Instead, the Tray object handles click events
|
||||
> for you (although various click-related events exist on the API for advanced use cases).
|
||||
|
||||
```js title='Creating a Tray menu that can quit the app'
|
||||
const { nativeImage } = require('electron/common')
|
||||
const { app, Tray, Menu } = require('electron/main')
|
||||
|
||||
// save a reference to the Tray object globally to avoid garbage collection
|
||||
let tray
|
||||
|
||||
// 16x16 red circle data URL
|
||||
const icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACTSURBVHgBpZKBCYAgEEV/TeAIjuIIbdQIuUGt0CS1gW1iZ2jIVaTnhw+Cvs8/OYDJA4Y8kR3ZR2/kmazxJbpUEfQ/Dm/UG7wVwHkjlQdMFfDdJMFaACebnjJGyDWgcnZu1/lrCrl6NCoEHJBrDwEr5NrT6ko/UV8xdLAC2N49mlc5CylpYh8wCwqrvbBGLoKGvz8Bfq0QPWEUo/EAAAAASUVORK5CYII=')
|
||||
|
||||
// The Tray can only be instantiated after the 'ready' event is fired
|
||||
app.whenReady().then(() => {
|
||||
tray = new Tray(icon)
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ role: 'quit' }
|
||||
])
|
||||
tray.setContextMenu(contextMenu)
|
||||
})
|
||||
```
|
||||
|
||||
The code above will create 4 separate radio-type items in the context menu.
|
||||
To read more about constructing native menus, click
|
||||
[here](../api/menu.md#menubuildfromtemplatetemplate).
|
||||
> [!TIP]
|
||||
> To learn more about crafting menus in Electron, see the [Menus](./menus.md#building-menus) guide.
|
||||
|
||||
Finally, let's give our tray a tooltip and a title.
|
||||
> [!WARNING]
|
||||
> The `enabled` and `visibility` properties are not available for top-level menu items in the tray on macOS.
|
||||
|
||||
```js @ts-type={tray:Electron.Tray}
|
||||
tray.setToolTip('This is my application')
|
||||
tray.setTitle('This is my title')
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
After you start your electron app, you should see the Tray residing
|
||||
in either the top or bottom right of your screen, depending on your
|
||||
operating system.
|
||||
|
||||
```fiddle docs/fiddles/native-ui/tray
|
||||
## Runnable Fiddle demo
|
||||
|
||||
Below is a runnable example of attaching various menu items to the Tray's context menu that help
|
||||
control app state and interact with the Tray API itself.
|
||||
|
||||
```fiddle docs/fiddles/menus/tray-menu
|
||||
```
|
||||
|
|
|
@ -14,7 +14,6 @@ Windows, and Linux.
|
|||
> supports composing many web views. `BaseWindow` can be used interchangeably with `BrowserWindow`
|
||||
> in the examples of the documents in this section.
|
||||
|
||||
<!-- markdownlint-disable-next-line MD033 -->
|
||||
<DocCardList />
|
||||
|
||||
[`BaseWindow`]: ../api/base-window.md
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# THIS FILE IS AUTO-GENERATED, PLEASE DO NOT EDIT BY HAND
|
||||
auto_filenames = {
|
||||
api_docs = [
|
||||
"docs/api/accelerator.md",
|
||||
"docs/api/app.md",
|
||||
"docs/api/auto-updater.md",
|
||||
"docs/api/base-window.md",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue