diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts index 16b2065c405b4..6f87a277c59b8 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityContributions.ts @@ -31,6 +31,10 @@ import { IAccessibleViewService, IAccessibleContentProvider, IAccessibleViewOpti import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { AccessibilityHelpAction, AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions'; +import { IAction } from 'vs/base/common/actions'; +import { INotificationViewItem } from 'vs/workbench/common/notifications'; +import { ThemeIcon } from 'vs/base/common/themables'; +import { Codicon } from 'vs/base/common/codicons'; export class EditorAccessibilityHelpContribution extends Disposable { static ID: 'editorAccessibilityHelpContribution'; @@ -220,7 +224,8 @@ export class NotificationAccessibleViewContribution extends Disposable { options: { ariaLabel: localize('notification', "Notification Accessible View"), type: AccessibleViewType.View - } + }, + actions: getActionsFromNotification(notification) }); return true; } @@ -229,6 +234,33 @@ export class NotificationAccessibleViewContribution extends Disposable { } } +function getActionsFromNotification(notification: INotificationViewItem): IAction[] | undefined { + let actions = undefined; + if (notification.actions) { + actions = []; + if (notification.actions.primary) { + actions.push(...notification.actions.primary); + } + if (notification.actions.secondary) { + actions.push(...notification.actions.secondary); + } + } + if (actions) { + for (const action of actions) { + action.class = ThemeIcon.asClassName(Codicon.bell); + const initialAction = action.run; + action.run = () => { + initialAction(); + notification.close(); + }; + } + } + if (actions) { + actions.push({ id: 'clearNotification', label: localize('clearNotification', "Clear Notification"), tooltip: localize('clearNotification', "Clear Notification"), run: () => notification.close(), enabled: true, class: ThemeIcon.asClassName(Codicon.clearAll) }); + } + return actions; +} + export function alertFocusChange(index: number | undefined, length: number | undefined, type: 'next' | 'previous'): void { if (index === undefined || length === undefined) { return; diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts index 3d3ea56946a42..d8643ad5a3396 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibleView.ts @@ -20,8 +20,8 @@ import { AccessibilityHelpNLS } from 'vs/editor/common/standaloneStrings'; import { CodeActionController } from 'vs/editor/contrib/codeAction/browser/codeActionController'; import { localize } from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; -import { MenuId } from 'vs/platform/actions/common/actions'; +import { WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; +import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewDelegate, IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -34,6 +34,10 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { AccessibilityVerbositySettingId, accessibilityHelpIsShown, accessibleViewIsShown } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; +import { IAction } from 'vs/base/common/actions'; +import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { Codicon } from 'vs/base/common/codicons'; +import { ThemeIcon } from 'vs/base/common/themables'; const enum DIMENSIONS { MAX_WIDTH = 600 @@ -41,6 +45,12 @@ const enum DIMENSIONS { export interface IAccessibleContentProvider { verbositySettingKey: AccessibilityVerbositySettingId; + options: IAccessibleViewOptions; + /** + * Note that a Codicon class should be provided for each action. + * If not, a default will be used. + */ + actions?: IAction[]; provideContent(): string; onClose(): void; onKeyDown?(e: IKeyboardEvent): void; @@ -50,7 +60,6 @@ export interface IAccessibleContentProvider { * When the language is markdown, this is provided by default. */ getSymbols?(): IAccessibleViewSymbol[]; - options: IAccessibleViewOptions; } export const IAccessibleViewService = createDecorator('accessibleViewService'); @@ -63,7 +72,6 @@ export interface IAccessibleViewService { previous(): void; goToSymbol(): void; disableHint(): void; - focusToolbar(): void; /** * If the setting is enabled, provides the open accessible view hint as a localized string. * @param verbositySettingKey The setting key for the verbosity of the feature @@ -93,7 +101,7 @@ class AccessibleView extends Disposable { get editorWidget() { return this._editorWidget; } private _editorContainer: HTMLElement; private _currentProvider: IAccessibleContentProvider | undefined; - private readonly _toolbar: MenuWorkbenchToolBar; + private readonly _toolbar: WorkbenchToolBar; constructor( @IOpenerService private readonly _openerService: IOpenerService, @@ -104,7 +112,8 @@ class AccessibleView extends Disposable { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @IKeybindingService private readonly _keybindingService: IKeybindingService, - @ILayoutService private readonly _layoutService: ILayoutService + @ILayoutService private readonly _layoutService: ILayoutService, + @IMenuService private readonly _menuService: IMenuService ) { super(); this._accessiblityHelpIsShown = accessibilityHelpIsShown.bindTo(this._contextKeyService); @@ -114,7 +123,11 @@ class AccessibleView extends Disposable { const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { contributions: EditorExtensionsRegistry.getEditorContributions().filter(c => c.id !== CodeActionController.ID) }; - this._toolbar = this._register(_instantiationService.createInstance(MenuWorkbenchToolBar, this._editorContainer, MenuId.AccessibleView, { ariaLabel: localize('accessibleViewToolbar', "Accessible View Toolbar"), orientation: ActionsOrientation.HORIZONTAL })); + this._toolbar = this._register(_instantiationService.createInstance(WorkbenchToolBar, this._editorContainer, { ariaLabel: localize('accessibleViewToolbar', "Accessible View Toolbar"), orientation: ActionsOrientation.HORIZONTAL })); + this._toolbar.context = { viewId: 'accessibleView' }; + const toolbarElt = this._toolbar.getElement(); + toolbarElt.tabIndex = 0; + const editorOptions: IEditorConstructionOptions = { ...getSimpleEditorOptions(this._configurationService), lineDecorationsWidth: 6, @@ -313,8 +326,8 @@ class AccessibleView extends Disposable { this._editorWidget.updateOptions({ ariaLabel }); this._editorWidget.focus(); }); - this._toolbar.context = { viewId: 'accessibleView' }; - this._toolbar.getElement().tabIndex = 0; + this._updateToolbar(provider.actions); + const disposableStore = new DisposableStore(); disposableStore.add(this._editorWidget.onKeyUp((e) => provider.onKeyDown?.(e))); disposableStore.add(this._editorWidget.onKeyDown((e) => { @@ -342,8 +355,20 @@ class AccessibleView extends Disposable { return disposableStore; } - focusToolbar(): void { - this._toolbar.focus(); + private _updateToolbar(providedActions?: IAction[]): void { + this._toolbar.setActions([]); + const menuActions: IAction[] = []; + const toolbarMenu = this._register(this._menuService.createMenu(MenuId.AccessibleView, this._contextKeyService)); + createAndFillInActionBarActions(toolbarMenu, {}, menuActions); + if (providedActions) { + for (const providedAction of providedActions) { + providedAction.class = providedAction.class || ThemeIcon.asClassName(Codicon.primitiveSquare); + providedAction.checked = undefined; + } + this._toolbar.setActions([...providedActions, ...menuActions]); + } else { + this._toolbar.setActions(menuActions); + } } private _layout(): void { @@ -488,9 +513,6 @@ export class AccessibleViewService extends Disposable implements IAccessibleView showAccessibleViewHelp(): void { this._accessibleView?.showAccessibleViewHelp(); } - focusToolbar(): void { - this._accessibleView?.focusToolbar(); - } }