From d6f197f63f4b5ae691c626a16ad377a4b4fb2f5c Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Sun, 10 May 2026 00:29:44 +0200 Subject: [PATCH 1/3] feat: add trigger option to control tray event binding Introduces `Options.trigger` ('click' | 'right-click' | 'none') as the single source of truth for which tray event toggles the menubar window. Deprecates `showOnRightClick`, which is kept as a fallback when `trigger` is unset. `trigger: 'none'` skips the tray click bindings entirely, enabling the "one tray icon, multiple anchored windows" pattern: instantiate a secondary Menubar to reuse the tray-anchored positioning while driving visibility manually via `showWindow()` (e.g. from a context menu). The motivating use case was raised in upstream max-mapper/menubar#485 by @haydendonald as a `disableClick` boolean. An enum subsumes both that flag and `showOnRightClick`, avoids a double-negative API, and leaves room for future trigger types. --- src/Menubar.ts | 12 +++++++----- src/types.ts | 11 +++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Menubar.ts b/src/Menubar.ts index b97edc2f..7a1709f1 100644 --- a/src/Menubar.ts +++ b/src/Menubar.ts @@ -246,17 +246,19 @@ export class Menubar extends EventEmitter { trayImage = path.join(__dirname, '..', 'assets', 'IconTemplate.png'); // Default cat icon } - const defaultClickEvent = this._options.showOnRightClick - ? 'right-click' - : 'click'; + const trigger = + this._options.trigger ?? + (this._options.showOnRightClick ? 'right-click' : 'click'); this._tray = this._options.tray || new Tray(trayImage); // Type guards for TS not to complain if (!this.tray) { throw new Error('Tray has been initialized above'); } - this.tray.on(defaultClickEvent as Parameters[0], this.clicked); - this.tray.on('double-click', this.clicked); + if (trigger !== 'none') { + this.tray.on(trigger as Parameters[0], this.clicked); + this.tray.on('double-click', this.clicked); + } this.tray.setToolTip(this._options.tooltip); if (!this._options.windowPosition) { diff --git a/src/types.ts b/src/types.ts index cf37f654..2aa692f7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -71,8 +71,19 @@ export interface Options { showOnAllWorkspaces?: boolean; /** * Show the window on 'right-click' event instead of regular 'click'. + * @deprecated Use {@link Options.trigger} instead. Will be removed in the + * next major release. */ showOnRightClick?: boolean; + /** + * Tray event that toggles the menubar window. Set to `'none'` to disable + * automatic toggling — the window can still be shown by calling + * {@link Menubar.showWindow} directly. Useful when a single tray icon serves + * multiple windows. + * @default `'click'` (or `'right-click'` if the deprecated + * {@link Options.showOnRightClick} is `true`) + */ + trigger?: 'click' | 'right-click' | 'none'; /** * Menubar tray icon tooltip text. Calls [`tray.setTooltip`](https://electronjs.org/docs/api/tray#traysettooltiptooltip). */ From 45c3632564ddecb25406455d8fbb71c15af73d81 Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Sun, 10 May 2026 00:29:49 +0200 Subject: [PATCH 2/3] test: cover trigger option behavior and showOnRightClick fallback --- src/Menubar.spec.ts | 72 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/Menubar.spec.ts b/src/Menubar.spec.ts index be13a58f..d32c2140 100644 --- a/src/Menubar.spec.ts +++ b/src/Menubar.spec.ts @@ -101,3 +101,75 @@ describe('Menubar', () => { }); }); }); + +describe('Menubar trigger option', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + const trayEvents = (mb: Menubar): string[] => + (mb.tray.on as Mock).mock.calls.map(([event]) => event as string); + + const onReady = (mb: Menubar, assertions: () => void): Promise => + new Promise((resolve) => { + mb.on('ready', () => { + assertions(); + resolve(); + }); + }); + + it('defaults to binding `click` and `double-click`', () => { + const mb = new Menubar(app, { preloadWindow: true }); + return onReady(mb, () => { + expect(trayEvents(mb)).toEqual( + expect.arrayContaining(['click', 'double-click']), + ); + expect(trayEvents(mb)).not.toContain('right-click'); + }); + }); + + it('binds `right-click` when `trigger: "right-click"`', () => { + const mb = new Menubar(app, { + preloadWindow: true, + trigger: 'right-click', + }); + return onReady(mb, () => { + expect(trayEvents(mb)).toEqual( + expect.arrayContaining(['right-click', 'double-click']), + ); + expect(trayEvents(mb)).not.toContain('click'); + }); + }); + + it('binds nothing when `trigger: "none"`', () => { + const mb = new Menubar(app, { preloadWindow: true, trigger: 'none' }); + return onReady(mb, () => { + expect(trayEvents(mb)).not.toContain('click'); + expect(trayEvents(mb)).not.toContain('right-click'); + expect(trayEvents(mb)).not.toContain('double-click'); + }); + }); + + it('falls back to `showOnRightClick` when `trigger` is unset', () => { + const mb = new Menubar(app, { + preloadWindow: true, + showOnRightClick: true, + }); + return onReady(mb, () => { + expect(trayEvents(mb)).toContain('right-click'); + expect(trayEvents(mb)).not.toContain('click'); + }); + }); + + it('lets `trigger` win over the deprecated `showOnRightClick`', () => { + const mb = new Menubar(app, { + preloadWindow: true, + showOnRightClick: true, + trigger: 'click', + }); + return onReady(mb, () => { + expect(trayEvents(mb)).toContain('click'); + expect(trayEvents(mb)).not.toContain('right-click'); + }); + }); +}); From b71f52d68ff5b642c2840712150c455847670d61 Mon Sep 17 00:00:00 2001 From: Afonso Jorge Ramos Date: Sun, 10 May 2026 00:29:49 +0200 Subject: [PATCH 3/3] docs: document trigger option and showOnRightClick deprecation --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a933005..59c155c1 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ You can pass an optional options object into the `menubar({ ... })` function: - `showOnAllWorkspaces` (default true) - Makes the window available on all OS X workspaces. - `windowPosition` (default trayCenter and trayBottomCenter on Windows) - Sets the window position (x and y will still override this), check [positioner docs](https://github.com/jenslind/electron-positioner#docs) for valid values. - `showDockIcon` (default false) - Configure the visibility of the application dock icon. -- `showOnRightClick` (default false) - Show the window on 'right-click' event instead of regular 'click' +- `trigger` (default `'click'`) - Tray event that toggles the menubar window. One of `'click'`, `'right-click'`, or `'none'`. Use `'none'` to disable automatic toggling — useful when a single tray icon serves multiple windows. The window can still be shown by calling `mb.showWindow()` directly. +- `showOnRightClick` (default false) - **Deprecated**, use `trigger: 'right-click'` instead. Show the window on 'right-click' event instead of regular 'click'. See the reference [API docs](./docs/interfaces/_types_.options.md).