Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(api/menu): fix submenus when created using an object in items field in the object passed to Menu/Submenu.new #11441

Merged
merged 3 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/js-submenu-in-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tauri-apps/api": "patch:bug"
---

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`.
2 changes: 1 addition & 1 deletion crates/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions crates/tauri/src/menu/builders/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use crate::{image::Image, menu::*, Manager, Runtime};

/// A builder type for [`Menu`]
///
/// ## Platform-specific:
///
/// - **macOS**: if using [`MenuBuilder`] for the global menubar, it can only contain [`Submenu`]s
///
/// # Example
///
/// ```no_run
Expand Down
4 changes: 4 additions & 0 deletions crates/tauri/src/menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ macro_rules! gen_wrappers {
gen_wrappers!(
/// A type that is either a menu bar on the window
/// on Windows and Linux or as a global menu in the menubar on macOS.
///
/// ## Platform-specific:
///
/// - **macOS**: if using [`Menu`] for the global menubar, it can only contain [`Submenu`]s
Menu(MenuInner),
/// A menu item inside a [`Menu`] or [`Submenu`] and contains only text.
MenuItem(MenuItemInner, MenuItem),
Expand Down
3 changes: 2 additions & 1 deletion crates/tauri/src/menu/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,12 +300,13 @@ impl PredefinedMenuItemPayload {

#[derive(Deserialize)]
#[serde(untagged)]
// Note, order matters for untagged enum deserialization
enum MenuItemPayloadKind {
ExistingItem((ResourceId, ItemKind)),
Predefined(PredefinedMenuItemPayload),
Check(CheckMenuItemPayload),
Submenu(SubmenuPayload),
Icon(IconMenuItemPayload),
Submenu(SubmenuPayload),
MenuItem(MenuItemPayload),
}

Expand Down
40 changes: 23 additions & 17 deletions packages/api/src/menu/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ function injectChannel(
| PredefinedMenuItemOptions
| CheckMenuItemOptions
):
| MenuItemOptions
| SubmenuOptions
| IconMenuItemOptions
| PredefinedMenuItemOptions
| (CheckMenuItemOptions & { handler?: Channel<string> }) {
| ((MenuItemOptions | IconMenuItemOptions | CheckMenuItemOptions) & {
handler?: Channel<string>
}) {
if ('items' in i) {
i.items = i.items?.map((item) =>
'rid' in item ? item : injectChannel(item)
Expand All @@ -49,31 +49,29 @@ export async function newMenu(
opts?: unknown
): Promise<[number, string]> {
const handler = new Channel<string>()
let items: null | Array<
| [number, string]
| MenuItemOptions
| SubmenuOptions
| IconMenuItemOptions
| PredefinedMenuItemOptions
| CheckMenuItemOptions
> = null

if (opts && typeof opts === 'object') {
if ('action' in opts && opts.action) {
handler.onmessage = opts.action as () => void
delete opts.action
}

if ('items' in opts && opts.items) {
items = (
opts.items as Array<
function prepareItem(
i:
| { rid: number; kind: string }
| MenuItemOptions
| SubmenuOptions
| IconMenuItemOptions
| PredefinedMenuItemOptions
| CheckMenuItemOptions
>
).map((i) => {
):
| [number, string]
| SubmenuOptions
| PredefinedMenuItemOptions
| MenuItemOptions
| IconMenuItemOptions
| CheckMenuItemOptions {
if ('rid' in i) {
return [i.rid, i.kind]
}
Expand All @@ -86,14 +84,22 @@ export async function newMenu(
i.icon = transformImage(i.icon)
}

if ('items' in i && i.items) {
// @ts-expect-error the `perpareItem` return doesn't exactly match
lucasfernog marked this conversation as resolved.
Show resolved Hide resolved
// this is fine, because the difference is in `[number, string]` variant
i.items = i.items.map(prepareItem)
}

return injectChannel(i)
})
}

opts.items = (opts.items as []).map(prepareItem)
}
}

return invoke('plugin:menu|new', {
kind,
options: opts ? { ...opts, items } : undefined,
options: opts,
handler
})
}
Expand Down
7 changes: 7 additions & 0 deletions packages/api/src/menu/iconMenuItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ export enum NativeIcon {
export interface IconMenuItemOptions extends MenuItemOptions {
/**
* Icon to be used for the new icon menu item.
*
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
icon?: NativeIcon | string | Image | Uint8Array | ArrayBuffer | number[]
}
Expand Down
4 changes: 4 additions & 0 deletions packages/api/src/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export interface MenuOptions {

/** A type that is either a menu bar on the window
* on Windows and Linux or as a global menu in the menubar on macOS.
*
* #### Platform-specific:
*
* - **macOS**: if using {@linkcode Menu} for the global menubar, it can only contain {@linkcode Submenu}s.
*/
export class Menu extends MenuItemBase {
/** @ignore */
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/tray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export interface TrayIconOptions {
/**
* The tray icon which could be icon bytes or path to the icon file.
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
Expand Down Expand Up @@ -196,7 +196,7 @@ export class TrayIcon extends Resource {
/**
* Sets a new tray icon. If `null` is provided, it will remove the icon.
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,7 @@ class Window {
* await getCurrentWindow().setIcon('/tauri/awesome.png');
* ```
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
Expand Down
Loading