Skip to content

Commit 54cbf59

Browse files
fix(api/menu): fix submenus when created using an object in items field in the object passed to Menu/Submenu.new (#11441)
* fix(api/menu): fix submenus when created using an object in `items` field in the object passed to `Menu/Submenu.new` closes #11435 also closes #11422 as I included the docs in this PR * Update .changes/js-submenu-in-options.md * Update packages/api/src/menu/base.ts --------- Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
1 parent ce864ce commit 54cbf59

10 files changed

Lines changed: 53 additions & 22 deletions

File tree

.changes/js-submenu-in-options.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tauri-apps/api": "patch:bug"
3+
---
4+
5+
Fix submenu created as a menu item instead of a submenu when created by using an object in the `items` field in the options object passed to `Menu.new` or `Submenu.new`.

crates/tauri/scripts/bundle.global.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/tauri/src/menu/builders/menu.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ use crate::{image::Image, menu::*, Manager, Runtime};
66

77
/// A builder type for [`Menu`]
88
///
9+
/// ## Platform-specific:
10+
///
11+
/// - **macOS**: if using [`MenuBuilder`] for the global menubar, it can only contain [`Submenu`]s
12+
///
913
/// # Example
1014
///
1115
/// ```no_run

crates/tauri/src/menu/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ macro_rules! gen_wrappers {
147147
gen_wrappers!(
148148
/// A type that is either a menu bar on the window
149149
/// on Windows and Linux or as a global menu in the menubar on macOS.
150+
///
151+
/// ## Platform-specific:
152+
///
153+
/// - **macOS**: if using [`Menu`] for the global menubar, it can only contain [`Submenu`]s
150154
Menu(MenuInner),
151155
/// A menu item inside a [`Menu`] or [`Submenu`] and contains only text.
152156
MenuItem(MenuItemInner, MenuItem),

crates/tauri/src/menu/plugin.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,13 @@ impl PredefinedMenuItemPayload {
300300

301301
#[derive(Deserialize)]
302302
#[serde(untagged)]
303+
// Note, order matters for untagged enum deserialization
303304
enum MenuItemPayloadKind {
304305
ExistingItem((ResourceId, ItemKind)),
305306
Predefined(PredefinedMenuItemPayload),
306307
Check(CheckMenuItemPayload),
307-
Submenu(SubmenuPayload),
308308
Icon(IconMenuItemPayload),
309+
Submenu(SubmenuPayload),
309310
MenuItem(MenuItemPayload),
310311
}
311312

packages/api/src/menu/base.ts

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ function injectChannel(
2626
| PredefinedMenuItemOptions
2727
| CheckMenuItemOptions
2828
):
29-
| MenuItemOptions
3029
| SubmenuOptions
31-
| IconMenuItemOptions
3230
| PredefinedMenuItemOptions
33-
| (CheckMenuItemOptions & { handler?: Channel<string> }) {
31+
| ((MenuItemOptions | IconMenuItemOptions | CheckMenuItemOptions) & {
32+
handler?: Channel<string>
33+
}) {
3434
if ('items' in i) {
3535
i.items = i.items?.map((item) =>
3636
'rid' in item ? item : injectChannel(item)
@@ -49,31 +49,29 @@ export async function newMenu(
4949
opts?: unknown
5050
): Promise<[number, string]> {
5151
const handler = new Channel<string>()
52-
let items: null | Array<
53-
| [number, string]
54-
| MenuItemOptions
55-
| SubmenuOptions
56-
| IconMenuItemOptions
57-
| PredefinedMenuItemOptions
58-
| CheckMenuItemOptions
59-
> = null
52+
6053
if (opts && typeof opts === 'object') {
6154
if ('action' in opts && opts.action) {
6255
handler.onmessage = opts.action as () => void
6356
delete opts.action
6457
}
6558

6659
if ('items' in opts && opts.items) {
67-
items = (
68-
opts.items as Array<
60+
function prepareItem(
61+
i:
6962
| { rid: number; kind: string }
7063
| MenuItemOptions
7164
| SubmenuOptions
7265
| IconMenuItemOptions
7366
| PredefinedMenuItemOptions
7467
| CheckMenuItemOptions
75-
>
76-
).map((i) => {
68+
):
69+
| [number, string]
70+
| SubmenuOptions
71+
| PredefinedMenuItemOptions
72+
| MenuItemOptions
73+
| IconMenuItemOptions
74+
| CheckMenuItemOptions {
7775
if ('rid' in i) {
7876
return [i.rid, i.kind]
7977
}
@@ -86,14 +84,22 @@ export async function newMenu(
8684
i.icon = transformImage(i.icon)
8785
}
8886

87+
if ('items' in i && i.items) {
88+
// @ts-expect-error the `prepareItem` return doesn't exactly match
89+
// this is fine, because the difference is in `[number, string]` variant
90+
i.items = i.items.map(prepareItem)
91+
}
92+
8993
return injectChannel(i)
90-
})
94+
}
95+
96+
opts.items = (opts.items as []).map(prepareItem)
9197
}
9298
}
9399

94100
return invoke('plugin:menu|new', {
95101
kind,
96-
options: opts ? { ...opts, items } : undefined,
102+
options: opts,
97103
handler
98104
})
99105
}

packages/api/src/menu/iconMenuItem.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ export enum NativeIcon {
133133
export interface IconMenuItemOptions extends MenuItemOptions {
134134
/**
135135
* Icon to be used for the new icon menu item.
136+
*
137+
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
138+
* To enable it, change your Cargo.toml file:
139+
* ```toml
140+
* [dependencies]
141+
* tauri = { version = "...", features = ["...", "image-png"] }
142+
* ```
136143
*/
137144
icon?: NativeIcon | string | Image | Uint8Array | ArrayBuffer | number[]
138145
}

packages/api/src/menu/menu.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ export interface MenuOptions {
6868

6969
/** A type that is either a menu bar on the window
7070
* on Windows and Linux or as a global menu in the menubar on macOS.
71+
*
72+
* #### Platform-specific:
73+
*
74+
* - **macOS**: if using {@linkcode Menu} for the global menubar, it can only contain {@linkcode Submenu}s.
7175
*/
7276
export class Menu extends MenuItemBase {
7377
/** @ignore */

packages/api/src/tray.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export interface TrayIconOptions {
7979
/**
8080
* The tray icon which could be icon bytes or path to the icon file.
8181
*
82-
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
82+
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
8383
* To enable it, change your Cargo.toml file:
8484
* ```toml
8585
* [dependencies]
@@ -196,7 +196,7 @@ export class TrayIcon extends Resource {
196196
/**
197197
* Sets a new tray icon. If `null` is provided, it will remove the icon.
198198
*
199-
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
199+
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
200200
* To enable it, change your Cargo.toml file:
201201
* ```toml
202202
* [dependencies]

packages/api/src/window.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,7 @@ class Window {
14631463
* await getCurrentWindow().setIcon('/tauri/awesome.png');
14641464
* ```
14651465
*
1466-
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
1466+
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
14671467
* To enable it, change your Cargo.toml file:
14681468
* ```toml
14691469
* [dependencies]

0 commit comments

Comments
 (0)