Skip to content

Commit

Permalink
fix(api/menu): fix submenus when created using an object in items f…
Browse files Browse the repository at this point in the history
…ield 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 <[email protected]>
  • Loading branch information
amrbashir and lucasfernog authored Oct 23, 2024
1 parent ce864ce commit 54cbf59
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 22 deletions.
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 `prepareItem` return doesn't exactly match
// 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

0 comments on commit 54cbf59

Please sign in to comment.