@laserware/hoverboard
Version:
Better context menus for Electron.
152 lines (136 loc) • 4.18 kB
text/typescript
import {
CheckboxMenuItem,
type CheckboxMenuItemOptions,
} from "./CheckboxMenuItem.js";
import type { ContextMenuItem } from "./ContextMenuItem.js";
import {
NormalMenuItem,
type NormalMenuItemOptions,
} from "./NormalMenuItem.js";
import { RadioMenuItem, type RadioMenuItemOptions } from "./RadioMenuItem.js";
import { RoleMenuItem, type RoleMenuItemOptions } from "./RoleMenuItem.js";
import {
SeparatorMenuItem,
type SeparatorMenuItemOptions,
} from "./SeparatorMenuItem.js";
import { ShareMenuItem, type ShareMenuItemOptions } from "./ShareMenuItem.js";
import {
SubmenuMenuItem,
type SubmenuMenuItemOptions,
} from "./SubmenuMenuItem.js";
export type MenuBuilderFunction = (builder: MenuBuilder) => MenuBuilder;
/**
* Used to build a context menu with a builder function, rather than specifying
* an array of menu items.
*
* @internal
*/
export class MenuBuilder {
readonly #items: ContextMenuItem[] = [];
/** Items in the context menu. */
public get items(): ContextMenuItem[] {
return this.#items;
}
/**
* Adds the specified `item` to the context menu.
*
* @param item Context menu item to add.
*/
public add(item: ContextMenuItem): this {
this.#items.push(item);
return this;
}
/**
* Iterates over the specified `values` and calls the `onValue` callback to
* add menu items to the menu.
*
* This is useful for adding multiple submenu items in a builder function.
*
* @param values Array of values of any type to iterate over.
* @param onValue Callback called for each value.
*
* @example
* const menu = contextMenu((builder) =>
* builder.submenu(
* {
* id: "submenu",
* label: "Radio Options",
* sublabel: "This is a sublabel",
* },
* (builder) =>
* builder.map(["1", "2", "3"], (value) =>
* builder.radio({
* label: `Option ${value}`,
* checked: activeOption === value,
* click() {
* console.log(`Clicked ${value}`);
* },
* }),
* ),
* ),
* );
*/
public map<T>(values: T[], onValue: (value: T) => any): this {
for (const value of values) {
onValue(value);
}
return this;
}
/** Adds a checkbox menu item to the menu with the specified options. */
public checkbox(options: CheckboxMenuItemOptions): this {
this.#items.push(new CheckboxMenuItem(options));
return this;
}
/** Adds a normal menu item to the menu with the specified options. */
public normal(options: NormalMenuItemOptions): this {
this.#items.push(new NormalMenuItem(options));
return this;
}
/** Adds a radio menu item to the menu with the specified options. */
public radio(options: RadioMenuItemOptions): this {
this.#items.push(new RadioMenuItem(options));
return this;
}
/** Adds a role menu item to the menu with the specified options. */
public role(options: RoleMenuItemOptions): this {
this.#items.push(new RoleMenuItem(options));
return this;
}
/** Adds a separator menu item to the menu. */
public separator(options?: SeparatorMenuItemOptions): this {
this.#items.push(new SeparatorMenuItem(options));
return this;
}
/**
* Adds a Share Menu item to the menu.
*
* @platforms macOS
*/
public shareMenu(options: ShareMenuItemOptions): this {
this.#items.push(new ShareMenuItem(options));
return this;
}
/**
* Adds a submenu menu item to the context menu with the specified `options`
* and containing the specified `items`.
*/
public submenu(
options: SubmenuMenuItemOptions,
items: ContextMenuItem[],
): this;
/**
* Adds a submenu menu item to the context menu with the specified `options`
* and items added with the specified `build` function.
*/
public submenu(
options: SubmenuMenuItemOptions,
build: MenuBuilderFunction,
): this;
public submenu(
options: SubmenuMenuItemOptions,
init: ContextMenuItem[] | MenuBuilderFunction,
): this {
this.#items.push(new SubmenuMenuItem(options, init as any));
return this;
}
}