UNPKG

@jupyterlab/ui-components

Version:

JupyterLab - UI components written in React

190 lines 6.18 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { Signal } from '@lumino/signaling'; import { h } from '@lumino/virtualdom'; import { ContextMenu, Menu } from '@lumino/widgets'; import { LabIconStyle } from '../../style'; import { classes } from '../../utils'; import { caretRightIcon, checkIcon } from '../iconimports'; const submenuIcon = caretRightIcon.bindprops({ stylesheet: 'menuItem' }); /** * An object which implements a universal context menu. * Tweaked to use inline svg icons */ export class ContextMenuSvg extends ContextMenu { /** * Construct a new context menu. * * @param options - The options for initializing the menu. */ constructor(options) { super(options); this._isDisposed = false; this._opened = new Signal(this); // override the vanilla .menu this.menu = new MenuSvg(options); } /** * Test whether the context menu is disposed. */ get isDisposed() { return this._isDisposed; } /** * A signal fired when the context menu is opened. */ get opened() { return this._opened; } /** * Dispose of the resources held by the context menu. */ dispose() { if (this._isDisposed) { return; } this._isDisposed = true; this.menu.dispose(); Signal.disconnectSender(this); } /** * Open the context menu in response to a `'contextmenu'` event. * * @param event - The `'contextmenu'` event of interest. * * @returns `true` if the menu was opened, or `false` if no items * matched the event and the menu was not opened. * * #### Notes * This method will populate the context menu with items which match * the propagation path of the event, then open the menu at the mouse * position indicated by the event. */ open(event) { if (this._isDisposed) { return false; } const hasItems = super.open(event); if (hasItems) { this._opened.emit(); } return hasItems; } } /** * a widget which displays items as a canonical menu. * Tweaked to use inline svg icons */ export class MenuSvg extends Menu { /** * construct a new menu. Overrides the default renderer * * @param options - The options for initializing the tab bar. */ constructor(options) { options.renderer = options.renderer || MenuSvg.defaultRenderer; super(options); this.addClass('jp-ThemedContainer'); } /** * insert a menu item into the menu at the specified index. Replaces the * default renderer for submenus * * @param index - The index at which to insert the item. * * @param options - The options for creating the menu item. * * @returns The menu item added to the menu. * * #### Notes * The index will be clamped to the bounds of the items. */ insertItem(index, options) { if (options.submenu) { MenuSvg.overrideDefaultRenderer(options.submenu); } return super.insertItem(index, options); } } (function (MenuSvg) { function overrideDefaultRenderer(menu) { // override renderer, if needed if (menu.renderer === Menu.defaultRenderer) { // cast away readonly on menu.renderer menu.renderer = MenuSvg.defaultRenderer; } // ensure correct renderer on any submenus that get added in the future const originalInsertItem = menu.insertItem.bind(menu); menu.insertItem = (index, options) => { if (options.submenu) { MenuSvg.overrideDefaultRenderer(options.submenu); } return originalInsertItem(index, options); }; // recurse through submenus for (const item of menu._items) { if (item.submenu) { overrideDefaultRenderer(item.submenu); } } } MenuSvg.overrideDefaultRenderer = overrideDefaultRenderer; /** * a modified implementation of the Menu Renderer */ class Renderer extends Menu.Renderer { /** * Render the icon element for a menu item. * * @param data - The data to use for rendering the icon. * * @returns A virtual element representing the item icon. */ renderIcon(data) { const className = this.createIconClass(data); if (data.item.isToggled) { // check mark icon takes precedence return h.div({ className }, checkIcon, data.item.iconLabel); } // if data.item.icon is undefined, it will be ignored return h.div({ className }, data.item.icon, data.item.iconLabel); } /** * Create the class name for the menu item icon. * * @param data - The data to use for the class name. * * @returns The full class name for the item icon. */ createIconClass(data) { let name = 'lm-Menu-itemIcon'; if (data.item.type === 'separator') { return classes(data.item.iconClass, name); } else { return classes(LabIconStyle.styleClass({ stylesheet: 'menuItem' }), data.item.iconClass, name); } } /** * Render the submenu icon element for a menu item. * * @param data - The data to use for rendering the submenu icon. * * @returns A virtual element representing the submenu icon. */ renderSubmenu(data) { const className = 'lm-Menu-itemSubmenuIcon'; if (data.item.type === 'submenu') { return h.div({ className }, submenuIcon); } else { return h.div({ className }); } } } MenuSvg.Renderer = Renderer; MenuSvg.defaultRenderer = new Renderer(); })(MenuSvg || (MenuSvg = {})); //# sourceMappingURL=menusvg.js.map