Core framework for building cloud and desktop IDE applications using modern web technologies with TypeScript and dependency injection.
—
Theia's menu system provides hierarchical menu management with dynamic contributions, context menus, and command integration for building comprehensive application interfaces.
Central registry for menu structure and menu items.
/**
* Registry for menu models and actions
*/
interface MenuModelRegistry {
/**
* Register menu action
* @param menuPath - Path to menu location
* @param item - Menu action to register
* @returns Disposable to unregister
*/
registerMenuAction(menuPath: MenuPath, item: MenuAction): Disposable;
/**
* Register submenu
* @param menuPath - Path to parent menu
* @param label - Submenu label
* @returns Menu path for the new submenu
*/
registerSubmenu(menuPath: MenuPath, label: string): MenuPath;
/**
* Get menu model for path
* @param menuPath - Menu path
* @returns Menu model
*/
getMenu(menuPath: MenuPath): CompositeMenuNode;
/**
* Get all menu paths
* @returns Array of menu paths
*/
getMenuPaths(): MenuPath[];
}
/**
* Service token for MenuModelRegistry
*/
const MenuModelRegistry: symbol;Hierarchical menu location identifiers.
/**
* Menu path array for identifying menu locations
*/
type MenuPath = string[];
/**
* Common menu paths
*/
namespace MenuPaths {
/** File menu */
const File: MenuPath;
/** Edit menu */
const Edit: MenuPath;
/** View menu */
const View: MenuPath;
/** Help menu */
const Help: MenuPath;
}Individual menu items that execute commands.
/**
* Menu action definition
*/
interface MenuAction {
/** Command to execute */
commandId: string;
/** Display label (overrides command label) */
label?: string;
/** Icon CSS class */
icon?: string;
/** Menu item order/priority */
order?: string;
/** Alt text for accessibility */
alt?: string;
/** When clause for conditional display */
when?: string;
/** Group for menu organization */
group?: string;
}Usage Example:
import { injectable, inject } from "@theia/core";
import { MenuModelRegistry, MenuAction } from "@theia/core/lib/common";
@injectable()
export class MyMenuContribution {
constructor(
@inject(MenuModelRegistry)
private readonly menus: MenuModelRegistry
) {}
registerMenus(): void {
// Register action in File menu
const openAction: MenuAction = {
commandId: 'my-extension.open-file',
label: 'Open Special File',
icon: 'fa fa-file-o',
order: '1',
group: 'file'
};
this.menus.registerMenuAction(['file'], openAction);
// Create submenu
const mySubmenu = this.menus.registerSubmenu(['view'], 'My Extension');
// Add actions to submenu
this.menus.registerMenuAction(mySubmenu, {
commandId: 'my-extension.show-panel',
label: 'Show Panel',
order: '1'
});
this.menus.registerMenuAction(mySubmenu, {
commandId: 'my-extension.settings',
label: 'Settings',
order: '2'
});
}
}Menu structure representation.
/**
* Base menu node interface
*/
interface MenuNode {
/** Node identifier */
readonly id: string;
/** Display label */
readonly label?: string;
/** Icon CSS class */
readonly icon?: string;
/** Sort string for ordering */
readonly sortString?: string;
/** When clause for visibility */
readonly when?: string;
}
/**
* Composite menu node containing child nodes
*/
interface CompositeMenuNode extends MenuNode {
/** Child menu nodes */
readonly children: MenuNode[];
/** True if node has children */
readonly hasChildren: boolean;
}
/**
* Action menu node that executes commands
*/
interface ActionMenuNode extends MenuNode {
/** Command to execute */
readonly command: string;
/** Command arguments */
readonly args?: any[];
/** Alt text */
readonly alt?: string;
}Dynamic context menus for widgets and UI elements.
/**
* Context menu renderer interface
*/
interface ContextMenuRenderer {
/**
* Render context menu
* @param menuPath - Menu path
* @param anchor - Anchor element or coordinates
* @param onHide - Callback when menu hides
*/
render(
menuPath: MenuPath,
anchor: Element | { x: number; y: number },
onHide?: () => void
): Promise<void>;
}
/**
* Service token for ContextMenuRenderer
*/
const ContextMenuRenderer: symbol;Usage Example:
import { inject, injectable } from "@theia/core";
import { ContextMenuRenderer } from "@theia/core/lib/browser";
@injectable()
export class MyWidget {
constructor(
@inject(ContextMenuRenderer)
private readonly contextMenuRenderer: ContextMenuRenderer
) {}
private handleContextMenu(event: MouseEvent): void {
event.preventDefault();
// Render context menu at mouse position
this.contextMenuRenderer.render(
['my-widget-context'],
{ x: event.clientX, y: event.clientY }
);
}
private setupContextMenu(): void {
// Register context menu items
this.menus.registerMenuAction(['my-widget-context'], {
commandId: 'my-widget.copy',
label: 'Copy',
order: '1'
});
this.menus.registerMenuAction(['my-widget-context'], {
commandId: 'my-widget.paste',
label: 'Paste',
order: '2'
});
}
}Extension point for contributing menus.
/**
* Menu contribution interface
*/
interface MenuContribution {
/**
* Register menus
* @param menus - Menu model registry
*/
registerMenus(menus: MenuModelRegistry): void;
}
/**
* Service token for MenuContribution
*/
const MenuContribution: symbol;Menus that appear based on context conditions.
// Register conditional menu action
this.menus.registerMenuAction(['edit'], {
commandId: 'editor.action.rename',
label: 'Rename Symbol',
when: 'editorHasRenameProvider && editorTextFocus'
});Organize menu items into logical groups with separators.
// Actions in same group appear together
this.menus.registerMenuAction(['file'], {
commandId: 'file.new',
group: 'new',
order: '1'
});
this.menus.registerMenuAction(['file'], {
commandId: 'file.open',
group: 'new',
order: '2'
});
// Different group creates separator
this.menus.registerMenuAction(['file'], {
commandId: 'file.save',
group: 'save',
order: '1'
});/**
* Menu-related type definitions
*/
type MenuItemRole = 'normal' | 'separator' | 'submenu';
interface MenuOptions {
role?: MenuItemRole;
type?: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio';
checked?: boolean;
enabled?: boolean;
visible?: boolean;
}
type MenuCallback = () => void;Install with Tessl CLI
npx tessl i tessl/npm-theia--core