UNPKG

sussudio

Version:

An unofficial VS Code Internal API

167 lines (166 loc) 7.49 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as nls from "../../../../nls.mjs"; import { $, addDisposableListener, append, EventType, h } from "../../dom.mjs"; import { StandardKeyboardEvent } from "../../keyboardEvent.mjs"; import { ActionViewItem, BaseActionViewItem } from "../actionbar/actionViewItems.mjs"; import { DropdownMenu } from "./dropdown.mjs"; import { Action } from "../../../common/actions.mjs"; import { Codicon } from "../../../common/codicons.mjs"; import { Emitter } from "../../../common/event.mjs"; import "../../../../css!./dropdown.mjs"; export class DropdownMenuActionViewItem extends BaseActionViewItem { menuActionsOrProvider; dropdownMenu; contextMenuProvider; actionItem = null; _onDidChangeVisibility = this._register(new Emitter()); onDidChangeVisibility = this._onDidChangeVisibility.event; options; constructor(action, menuActionsOrProvider, contextMenuProvider, options = Object.create(null)) { super(null, action, options); this.menuActionsOrProvider = menuActionsOrProvider; this.contextMenuProvider = contextMenuProvider; this.options = options; if (this.options.actionRunner) { this.actionRunner = this.options.actionRunner; } } render(container) { this.actionItem = container; const labelRenderer = (el) => { this.element = append(el, $('a.action-label')); let classNames = []; if (typeof this.options.classNames === 'string') { classNames = this.options.classNames.split(/\s+/g).filter(s => !!s); } else if (this.options.classNames) { classNames = this.options.classNames; } // todo@aeschli: remove codicon, should come through `this.options.classNames` if (!classNames.find(c => c === 'icon')) { classNames.push('codicon'); } this.element.classList.add(...classNames); this.element.setAttribute('role', 'button'); this.element.setAttribute('aria-haspopup', 'true'); this.element.setAttribute('aria-expanded', 'false'); this.element.title = this._action.label || ''; this.element.ariaLabel = this._action.label || ''; return null; }; const isActionsArray = Array.isArray(this.menuActionsOrProvider); const options = { contextMenuProvider: this.contextMenuProvider, labelRenderer: labelRenderer, menuAsChild: this.options.menuAsChild, actions: isActionsArray ? this.menuActionsOrProvider : undefined, actionProvider: isActionsArray ? undefined : this.menuActionsOrProvider }; this.dropdownMenu = this._register(new DropdownMenu(container, options)); this._register(this.dropdownMenu.onDidChangeVisibility(visible => { this.element?.setAttribute('aria-expanded', `${visible}`); this._onDidChangeVisibility.fire(visible); })); this.dropdownMenu.menuOptions = { actionViewItemProvider: this.options.actionViewItemProvider, actionRunner: this.actionRunner, getKeyBinding: this.options.keybindingProvider, context: this._context }; if (this.options.anchorAlignmentProvider) { const that = this; this.dropdownMenu.menuOptions = { ...this.dropdownMenu.menuOptions, get anchorAlignment() { return that.options.anchorAlignmentProvider(); } }; } this.updateTooltip(); this.updateEnabled(); } getTooltip() { let title = null; if (this.action.tooltip) { title = this.action.tooltip; } else if (this.action.label) { title = this.action.label; } return title ?? undefined; } setActionContext(newContext) { super.setActionContext(newContext); if (this.dropdownMenu) { if (this.dropdownMenu.menuOptions) { this.dropdownMenu.menuOptions.context = newContext; } else { this.dropdownMenu.menuOptions = { context: newContext }; } } } show() { this.dropdownMenu?.show(); } updateEnabled() { const disabled = !this.action.enabled; this.actionItem?.classList.toggle('disabled', disabled); this.element?.classList.toggle('disabled', disabled); } } export class ActionWithDropdownActionViewItem extends ActionViewItem { contextMenuProvider; dropdownMenuActionViewItem; constructor(context, action, options, contextMenuProvider) { super(context, action, options); this.contextMenuProvider = contextMenuProvider; } render(container) { super.render(container); if (this.element) { this.element.classList.add('action-dropdown-item'); const menuActionsProvider = { getActions: () => { const actionsProvider = this.options.menuActionsOrProvider; return Array.isArray(actionsProvider) ? actionsProvider : actionsProvider.getActions(); // TODO: microsoft/TypeScript#42768 } }; const menuActionClassNames = this.options.menuActionClassNames || []; const separator = h('div.action-dropdown-item-separator', [h('div', {})]).root; separator.classList.toggle('prominent', menuActionClassNames.includes('prominent')); append(this.element, separator); this.dropdownMenuActionViewItem = new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', nls.localize('moreActions', "More Actions..."))), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...Codicon.dropDownButton.classNamesArray, ...menuActionClassNames] }); this.dropdownMenuActionViewItem.render(this.element); this._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => { const event = new StandardKeyboardEvent(e); let handled = false; if (this.dropdownMenuActionViewItem?.isFocused() && event.equals(15 /* KeyCode.LeftArrow */)) { handled = true; this.dropdownMenuActionViewItem?.blur(); this.focus(); } else if (this.isFocused() && event.equals(17 /* KeyCode.RightArrow */)) { handled = true; this.blur(); this.dropdownMenuActionViewItem?.focus(); } if (handled) { event.preventDefault(); event.stopPropagation(); } })); } } blur() { super.blur(); this.dropdownMenuActionViewItem?.blur(); } setFocusable(focusable) { super.setFocusable(focusable); this.dropdownMenuActionViewItem?.setFocusable(focusable); } }