monaco-editor-core
Version:
A browser based code editor
424 lines • 18.7 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as dom from '../../../base/browser/dom.js';
import { ActionBar } from '../../../base/browser/ui/actionbar/actionbar.js';
import { disposableTimeout } from '../../../base/common/async.js';
import { Disposable, DisposableStore, MutableDisposable } from '../../../base/common/lifecycle.js';
import './actionWidget.css';
import { localize, localize2 } from '../../../nls.js';
import { acceptSelectedActionCommand, ActionList, previewSelectedActionCommand } from './actionList.js';
import { Action2, registerAction2 } from '../../actions/common/actions.js';
import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../contextkey/common/contextkey.js';
import { IContextViewService } from '../../contextview/browser/contextView.js';
import { registerSingleton } from '../../instantiation/common/extensions.js';
import { createDecorator, IInstantiationService } from '../../instantiation/common/instantiation.js';
import { inputActiveOptionBackground, registerColor } from '../../theme/common/colorRegistry.js';
registerColor('actionBar.toggledBackground', inputActiveOptionBackground, localize(1744, 'Background color for toggled action items in action bar.'));
const ACTION_WIDGET_CLOSE_START_OPACITY_VARIABLE = '--action-widget-close-start-opacity';
const ACTION_WIDGET_CLOSE_START_TRANSFORM_VARIABLE = '--action-widget-close-start-transform';
const ActionWidgetContextKeys = {
Visible: new RawContextKey('codeActionMenuVisible', false, localize(1745, "Whether the action widget list is visible")),
FilterFocused: new RawContextKey('codeActionMenuFilterFocused', false, localize(1746, "Whether the action widget filter input is focused")),
};
export const IActionWidgetService = createDecorator('actionWidgetService');
let ActionWidgetService = class ActionWidgetService extends Disposable {
get isVisible() {
return ActionWidgetContextKeys.Visible.getValue(this._contextKeyService) || false;
}
constructor(_contextViewService, _contextKeyService, _instantiationService) {
super();
this._contextViewService = _contextViewService;
this._contextKeyService = _contextKeyService;
this._instantiationService = _instantiationService;
this._list = this._register(new MutableDisposable());
this._closeAnimation = this._register(new MutableDisposable());
}
show(user, supportsPreview, items, delegate, anchor, container, actionBarActions, accessibilityProvider, listOptions) {
const visibleContext = ActionWidgetContextKeys.Visible.bindTo(this._contextKeyService);
const list = this._instantiationService.createInstance(ActionList, user, supportsPreview, items, delegate, accessibilityProvider, listOptions, anchor);
this._contextViewService.showContextView({
getAnchor: () => anchor,
render: (container) => {
visibleContext.set(true);
return this._renderWidget(container, list, actionBarActions ?? [], listOptions);
},
onHide: (didCancel) => {
visibleContext.reset();
this._onWidgetClosed(didCancel);
},
get anchorPosition() { return list.anchorPosition; },
focus: () => list.focus(),
}, container, false);
}
acceptSelected(preview) {
this._list.value?.acceptSelected(preview);
}
focusPrevious() {
this._list?.value?.focusPrevious();
}
focusNext() {
this._list?.value?.focusNext();
}
collapseSection() {
this._list?.value?.collapseFocusedSection();
}
expandSection() {
this._list?.value?.expandFocusedSection();
}
toggleSection() {
return this._list?.value?.toggleFocusedSection() ?? false;
}
clearFilter() {
return this._list?.value?.clearFilter() ?? false;
}
hide(didCancel) {
const list = this._list.value;
const widget = this._widgetElement;
if (!list || this._closingList === list) {
return;
}
const closeAnimation = list.closeAnimation;
if (!widget || !closeAnimation || closeAnimation.duration <= 0 || !this._hasRequiredAncestorClasses(widget, closeAnimation.requiredAncestorClasses)) {
this._closingList = list;
list.hide(didCancel);
return;
}
this._closingList = list;
const computedStyle = dom.getWindow(widget).getComputedStyle(widget);
widget.style.setProperty(ACTION_WIDGET_CLOSE_START_OPACITY_VARIABLE, computedStyle.opacity);
widget.style.setProperty(ACTION_WIDGET_CLOSE_START_TRANSFORM_VARIABLE, computedStyle.transform);
widget.classList.add(closeAnimation.className);
list.hide(didCancel, false);
this._closeAnimation.value = disposableTimeout(() => {
if (this._list.value === list) {
this._contextViewService.hideContextView(didCancel);
}
}, closeAnimation.duration);
}
clear() {
this._closeAnimation.clear();
this._closingList = undefined;
this._widgetElement?.style.removeProperty(ACTION_WIDGET_CLOSE_START_OPACITY_VARIABLE);
this._widgetElement?.style.removeProperty(ACTION_WIDGET_CLOSE_START_TRANSFORM_VARIABLE);
this._widgetElement = undefined;
this._list.clear();
}
_renderWidget(element, list, actionBarActions, listOptions) {
const widget = document.createElement('div');
widget.classList.add('action-widget');
const widgetClassNames = list.widgetClassName?.split(/\s+/).filter(Boolean);
if (widgetClassNames?.length) {
widget.classList.add(...widgetClassNames);
}
element.appendChild(widget);
this._widgetElement = widget;
this._list.value = list;
if (this._list.value) {
if (this._list.value.headerContainer) {
widget.appendChild(this._list.value.headerContainer);
}
if (this._list.value.filterContainer) {
widget.appendChild(this._list.value.filterContainer);
}
widget.appendChild(this._list.value.domNode);
if (this._list.value.footerContainer) {
widget.appendChild(this._list.value.footerContainer);
}
}
else {
throw new Error('List has no value');
}
const renderDisposables = new DisposableStore();
if (listOptions?.filterAsCombobox) {
renderDisposables.add(dom.addStandardDisposableListener(widget, 'keydown', e => {
if (e.keyCode === 9 /* KeyCode.Escape */ && !e.browserEvent.isComposing) {
dom.EventHelper.stop(e, true);
this.hide(true);
}
}));
}
// Clicking the header banner must not move focus out of the list, which
// would blur the widget and dismiss it.
const headerContainer = this._list.value.headerContainer;
if (headerContainer) {
renderDisposables.add(dom.addDisposableGenericMouseDownListener(headerContainer, e => e.preventDefault()));
}
let suppressBlurHideUntil = 0;
renderDisposables.add(dom.addDisposableGenericMouseDownListener(widget, () => {
suppressBlurHideUntil = Date.now() + 1000;
}));
// Invisible div to block mouse interaction in the rest of the UI
const menuBlock = document.createElement('div');
const block = element.appendChild(menuBlock);
block.classList.add('context-view-block');
renderDisposables.add(dom.addDisposableGenericMouseDownListener(block, e => e.stopPropagation()));
// Action bar
let actionBarWidth = 0;
if (actionBarActions.length) {
const actionBar = this._createActionBar('.action-widget-action-bar', actionBarActions);
if (actionBar) {
widget.appendChild(actionBar.getContainer().parentElement);
renderDisposables.add(actionBar);
actionBarWidth = actionBar.getContainer().offsetWidth;
}
}
const width = this._list.value?.layout(actionBarWidth);
widget.style.width = `${width}px`;
// Track filter input focus state
const filterFocusedContext = ActionWidgetContextKeys.FilterFocused.bindTo(this._contextKeyService);
renderDisposables.add({ dispose: () => filterFocusedContext.reset() });
if (this._list.value?.filterInput) {
const filterInput = this._list.value.filterInput;
renderDisposables.add(dom.addDisposableListener(filterInput, 'focus', () => filterFocusedContext.set(true)));
renderDisposables.add(dom.addDisposableListener(filterInput, 'blur', () => filterFocusedContext.set(false)));
}
const focusTracker = renderDisposables.add(dom.trackFocus(element));
const pendingBlurHide = renderDisposables.add(new MutableDisposable());
renderDisposables.add(focusTracker.onDidFocus(() => pendingBlurHide.clear()));
renderDisposables.add(focusTracker.onDidBlur(() => {
const runBlurHide = () => {
const remainingSuppression = suppressBlurHideUntil - Date.now();
if (remainingSuppression > 0) {
pendingBlurHide.value = disposableTimeout(runBlurHide, remainingSuppression);
return;
}
// Don't hide if focus moved to a hover or submenu that belongs to this action widget
const activeElement = dom.getActiveElement();
if (activeElement && (element.contains(activeElement) || activeElement.closest('.action-widget-hover') || activeElement.closest('.action-list-submenu-panel'))) {
return;
}
this.hide(true);
};
pendingBlurHide.value = disposableTimeout(runBlurHide, 75);
}));
return renderDisposables;
}
_createActionBar(className, actions) {
if (!actions.length) {
return undefined;
}
const container = dom.$(className);
const actionBar = new ActionBar(container);
actionBar.push(actions, { icon: false, label: true });
return actionBar;
}
_hasRequiredAncestorClasses(element, classNames) {
if (!classNames?.length) {
return true;
}
for (let candidate = element; candidate; candidate = candidate.parentElement) {
if (classNames.every(className => candidate.classList.contains(className))) {
return true;
}
}
return false;
}
_onWidgetClosed(didCancel) {
if (this._closingList === this._list.value) {
this.clear();
return;
}
this._closeAnimation.clear();
this._closingList = undefined;
this._widgetElement = undefined;
this._list.value?.hide(didCancel);
}
};
ActionWidgetService = __decorate([
__param(0, IContextViewService),
__param(1, IContextKeyService),
__param(2, IInstantiationService)
], ActionWidgetService);
export { ActionWidgetService };
registerSingleton(IActionWidgetService, ActionWidgetService, 1 /* InstantiationType.Delayed */);
const weight = 100 /* KeybindingWeight.EditorContrib */ + 1000;
registerAction2(class extends Action2 {
constructor() {
super({
id: 'hideCodeActionWidget',
title: localize2(1747, "Hide action widget"),
precondition: ActionWidgetContextKeys.Visible,
keybinding: {
weight,
primary: 9 /* KeyCode.Escape */,
secondary: [1024 /* KeyMod.Shift */ | 9 /* KeyCode.Escape */]
},
});
}
run(accessor) {
accessor.get(IActionWidgetService).hide(true);
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'clearFilterCodeActionWidget',
title: localize2(1748, "Clear action widget filter"),
precondition: ContextKeyExpr.and(ActionWidgetContextKeys.Visible, ActionWidgetContextKeys.FilterFocused),
keybinding: {
weight: weight + 1,
primary: 9 /* KeyCode.Escape */,
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
if (!widgetService.clearFilter()) {
widgetService.hide(true);
}
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'selectPrevCodeAction',
title: localize2(1749, "Select previous action"),
precondition: ActionWidgetContextKeys.Visible,
keybinding: {
weight,
primary: 16 /* KeyCode.UpArrow */,
secondary: [2048 /* KeyMod.CtrlCmd */ | 16 /* KeyCode.UpArrow */],
mac: { primary: 16 /* KeyCode.UpArrow */, secondary: [2048 /* KeyMod.CtrlCmd */ | 16 /* KeyCode.UpArrow */, 256 /* KeyMod.WinCtrl */ | 46 /* KeyCode.KeyP */] },
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
widgetService.focusPrevious();
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'selectNextCodeAction',
title: localize2(1750, "Select next action"),
precondition: ActionWidgetContextKeys.Visible,
keybinding: {
weight,
primary: 18 /* KeyCode.DownArrow */,
secondary: [2048 /* KeyMod.CtrlCmd */ | 18 /* KeyCode.DownArrow */],
mac: { primary: 18 /* KeyCode.DownArrow */, secondary: [2048 /* KeyMod.CtrlCmd */ | 18 /* KeyCode.DownArrow */, 256 /* KeyMod.WinCtrl */ | 44 /* KeyCode.KeyN */] }
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
widgetService.focusNext();
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'collapseSectionCodeAction',
title: localize2(1751, "Collapse section"),
precondition: ContextKeyExpr.and(ActionWidgetContextKeys.Visible, ActionWidgetContextKeys.FilterFocused.negate()),
keybinding: {
weight,
primary: 15 /* KeyCode.LeftArrow */,
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
widgetService.collapseSection();
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'expandSectionCodeAction',
title: localize2(1752, "Expand section"),
precondition: ContextKeyExpr.and(ActionWidgetContextKeys.Visible, ActionWidgetContextKeys.FilterFocused.negate()),
keybinding: {
weight,
primary: 17 /* KeyCode.RightArrow */,
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
widgetService.expandSection();
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'toggleSectionCodeAction',
title: localize2(1753, "Toggle section"),
precondition: ContextKeyExpr.and(ActionWidgetContextKeys.Visible, ActionWidgetContextKeys.FilterFocused.negate()),
keybinding: {
weight,
primary: 10 /* KeyCode.Space */,
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
if (!widgetService.toggleSection()) {
widgetService.acceptSelected();
}
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: acceptSelectedActionCommand,
title: localize2(1754, "Accept selected action"),
precondition: ActionWidgetContextKeys.Visible,
keybinding: {
weight,
primary: 3 /* KeyCode.Enter */,
secondary: [2048 /* KeyMod.CtrlCmd */ | 89 /* KeyCode.Period */],
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
widgetService.acceptSelected();
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: previewSelectedActionCommand,
title: localize2(1755, "Preview selected action"),
precondition: ActionWidgetContextKeys.Visible,
keybinding: {
weight,
primary: 2048 /* KeyMod.CtrlCmd */ | 3 /* KeyCode.Enter */,
}
});
}
run(accessor) {
const widgetService = accessor.get(IActionWidgetService);
if (widgetService instanceof ActionWidgetService) {
widgetService.acceptSelected(true);
}
}
});
//# sourceMappingURL=actionWidget.js.map