Path: blob/main/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as DOM from '../../../base/browser/dom.js';6import { StandardKeyboardEvent } from '../../../base/browser/keyboardEvent.js';7import { ActionViewItem, BaseActionViewItem } from '../../../base/browser/ui/actionbar/actionViewItems.js';8import { DropdownMenuActionViewItem } from '../../../base/browser/ui/dropdown/dropdownActionViewItem.js';9import { IAction, IActionRunner } from '../../../base/common/actions.js';10import { Event } from '../../../base/common/event.js';11import { KeyCode } from '../../../base/common/keyCodes.js';12import { ResolvedKeybinding } from '../../../base/common/keybindings.js';13import { MenuEntryActionViewItem } from './menuEntryActionViewItem.js';14import { MenuItemAction } from '../common/actions.js';15import { IContextKeyService } from '../../contextkey/common/contextkey.js';16import { IKeybindingService } from '../../keybinding/common/keybinding.js';17import { INotificationService } from '../../notification/common/notification.js';18import { IThemeService } from '../../theme/common/themeService.js';19import { IContextMenuService } from '../../contextview/browser/contextView.js';20import { IAccessibilityService } from '../../accessibility/common/accessibility.js';21import { IHoverDelegate } from '../../../base/browser/ui/hover/hoverDelegate.js';2223export interface IDropdownWithPrimaryActionViewItemOptions {24actionRunner?: IActionRunner;25getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined;26hoverDelegate?: IHoverDelegate;27menuAsChild?: boolean;28skipTelemetry?: boolean;29}3031export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem {32protected readonly _primaryAction: ActionViewItem;33private _dropdown: DropdownMenuActionViewItem;34private _container: HTMLElement | null = null;35private _dropdownContainer: HTMLElement | null = null;3637get onDidChangeDropdownVisibility(): Event<boolean> {38return this._dropdown.onDidChangeVisibility;39}4041constructor(42primaryAction: MenuItemAction,43dropdownAction: IAction,44dropdownMenuActions: readonly IAction[],45className: string,46private readonly _options: IDropdownWithPrimaryActionViewItemOptions | undefined,47@IContextMenuService private readonly _contextMenuProvider: IContextMenuService,48@IKeybindingService _keybindingService: IKeybindingService,49@INotificationService _notificationService: INotificationService,50@IContextKeyService _contextKeyService: IContextKeyService,51@IThemeService _themeService: IThemeService,52@IAccessibilityService _accessibilityService: IAccessibilityService53) {54super(null, primaryAction, { hoverDelegate: _options?.hoverDelegate });55this._primaryAction = new MenuEntryActionViewItem(primaryAction, { hoverDelegate: _options?.hoverDelegate }, _keybindingService, _notificationService, _contextKeyService, _themeService, _contextMenuProvider, _accessibilityService);56if (_options?.actionRunner) {57this._primaryAction.actionRunner = _options.actionRunner;58}5960this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, {61menuAsChild: _options?.menuAsChild ?? true,62classNames: className ? ['codicon', 'codicon-chevron-down', className] : ['codicon', 'codicon-chevron-down'],63actionRunner: this._options?.actionRunner,64keybindingProvider: this._options?.getKeyBinding ?? (action => _keybindingService.lookupKeybinding(action.id)),65hoverDelegate: _options?.hoverDelegate,66skipTelemetry: _options?.skipTelemetry,67});68}6970override set actionRunner(actionRunner: IActionRunner) {71super.actionRunner = actionRunner;7273this._primaryAction.actionRunner = actionRunner;74this._dropdown.actionRunner = actionRunner;75}7677override get actionRunner(): IActionRunner {78return super.actionRunner;79}8081override setActionContext(newContext: unknown): void {82super.setActionContext(newContext);83this._primaryAction.setActionContext(newContext);84this._dropdown.setActionContext(newContext);85}8687override render(container: HTMLElement): void {88this._container = container;89super.render(this._container);90this._container.classList.add('monaco-dropdown-with-primary');91const primaryContainer = DOM.$('.action-container');92primaryContainer.role = 'button';93primaryContainer.ariaDisabled = String(!this.action.enabled);94this._primaryAction.render(DOM.append(this._container, primaryContainer));95this._dropdownContainer = DOM.$('.dropdown-action-container');96this._dropdown.render(DOM.append(this._container, this._dropdownContainer));97this._register(DOM.addDisposableListener(primaryContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {98if (!this.action.enabled) {99return;100}101const event = new StandardKeyboardEvent(e);102if (event.equals(KeyCode.RightArrow)) {103this._primaryAction.element!.tabIndex = -1;104this._dropdown.focus();105event.stopPropagation();106}107}));108this._register(DOM.addDisposableListener(this._dropdownContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {109if (!this.action.enabled) {110return;111}112const event = new StandardKeyboardEvent(e);113if (event.equals(KeyCode.LeftArrow)) {114this._primaryAction.element!.tabIndex = 0;115this._dropdown.setFocusable(false);116this._primaryAction.element?.focus();117event.stopPropagation();118}119}));120121this.updateEnabled();122}123124override focus(fromRight?: boolean): void {125if (fromRight) {126this._dropdown.focus();127} else {128this._primaryAction.element!.tabIndex = 0;129this._primaryAction.element!.focus();130}131}132133override blur(): void {134this._primaryAction.element!.tabIndex = -1;135this._dropdown.blur();136this._container!.blur();137}138139override setFocusable(focusable: boolean): void {140if (focusable) {141this._primaryAction.element!.tabIndex = 0;142} else {143this._primaryAction.element!.tabIndex = -1;144this._dropdown.setFocusable(false);145}146}147148protected override updateEnabled(): void {149const disabled = !this.action.enabled;150this.element?.classList.toggle('disabled', disabled);151}152153update(dropdownAction: IAction, dropdownMenuActions: IAction[], dropdownIcon?: string): void {154this._dropdown.dispose();155this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, {156menuAsChild: this._options?.menuAsChild ?? true,157classNames: ['codicon', dropdownIcon || 'codicon-chevron-down'],158actionRunner: this._options?.actionRunner,159hoverDelegate: this._options?.hoverDelegate,160keybindingProvider: this._options?.getKeyBinding161});162if (this._dropdownContainer) {163this._dropdown.render(this._dropdownContainer);164}165}166167showDropdown(): void {168this._dropdown.show();169}170171override dispose() {172this._primaryAction.dispose();173this._dropdown.dispose();174super.dispose();175}176}177178179