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