Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2

This commit is contained in:
ADS Merger
2020-04-23 02:50:35 +00:00
committed by Anthony Dresser
parent 3603f55d97
commit 7f1d8fc32f
659 changed files with 22709 additions and 12497 deletions

View File

@@ -822,6 +822,7 @@ export const EventType = {
MOUSE_OUT: 'mouseout',
MOUSE_ENTER: 'mouseenter',
MOUSE_LEAVE: 'mouseleave',
MOUSE_WHEEL: browser.isEdge ? 'mousewheel' : 'wheel',
POINTER_UP: 'pointerup',
POINTER_DOWN: 'pointerdown',
POINTER_MOVE: 'pointermove',

View File

@@ -197,8 +197,8 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
const renderedMarkdown = marked.parse(
markdown.supportThemeIcons
? markdownEscapeEscapedCodicons(markdown.value)
: markdown.value,
? markdownEscapeEscapedCodicons(markdown.value || '')
: (markdown.value || ''),
markedOptions
);

View File

@@ -80,15 +80,11 @@ export class StandardMouseEvent implements IMouseEvent {
}
public preventDefault(): void {
if (this.browserEvent.preventDefault) {
this.browserEvent.preventDefault();
}
this.browserEvent.preventDefault();
}
public stopPropagation(): void {
if (this.browserEvent.stopPropagation) {
this.browserEvent.stopPropagation();
}
this.browserEvent.stopPropagation();
}
}
@@ -208,17 +204,13 @@ export class StandardWheelEvent {
public preventDefault(): void {
if (this.browserEvent) {
if (this.browserEvent.preventDefault) {
this.browserEvent.preventDefault();
}
this.browserEvent.preventDefault();
}
}
public stopPropagation(): void {
if (this.browserEvent) {
if (this.browserEvent.stopPropagation) {
this.browserEvent.stopPropagation();
}
this.browserEvent.stopPropagation();
}
}
}

View File

@@ -136,7 +136,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
if (platform.isMacintosh) {
// macOS: allow to trigger the button when holding Ctrl+key and pressing the
// main mouse button. This is for scenarios where e.g. some interaction forces
// main mouse button. This is for scenarios where e.g. some interaction forces
// the Ctrl+key to be pressed and hold but the user still wants to interact
// with the actions (for example quick access in quick navigation mode).
this._register(DOM.addDisposableListener(element, DOM.EventType.CONTEXT_MENU, e => {
@@ -276,7 +276,6 @@ export class ActionViewItem extends BaseActionViewItem {
this.label = DOM.append(this.element, DOM.$('a.action-label'));
}
if (this.label) {
if (this._action.id === Separator.ID) {
this.label.setAttribute('role', 'presentation'); // A separator is a presentation item

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./aria';
import * as nls from 'vs/nls';
import { isMacintosh } from 'vs/base/common/platform';
import * as dom from 'vs/base/browser/dom';
@@ -23,7 +22,8 @@ export function setARIAContainer(parent: HTMLElement) {
statusContainer = document.createElement('div');
statusContainer.className = 'monaco-status';
statusContainer.setAttribute('role', 'status');
statusContainer.setAttribute('role', 'complementary');
statusContainer.setAttribute('aria-live', 'polite');
statusContainer.setAttribute('aria-atomic', 'true');
ariaContainer.appendChild(statusContainer);
@@ -33,51 +33,30 @@ export function setARIAContainer(parent: HTMLElement) {
/**
* Given the provided message, will make sure that it is read as alert to screen readers.
*/
export function alert(msg: string, disableRepeat?: boolean): void {
insertMessage(alertContainer, msg, disableRepeat);
export function alert(msg: string): void {
insertMessage(alertContainer, msg);
}
/**
* Given the provided message, will make sure that it is read as status to screen readers.
*/
export function status(msg: string, disableRepeat?: boolean): void {
export function status(msg: string): void {
if (isMacintosh) {
alert(msg, disableRepeat); // VoiceOver does not seem to support status role
alert(msg); // VoiceOver does not seem to support status role
} else {
insertMessage(statusContainer, msg, disableRepeat);
insertMessage(statusContainer, msg);
}
}
let repeatedTimes = 0;
let prevText: string | undefined = undefined;
function insertMessage(target: HTMLElement, msg: string, disableRepeat?: boolean): void {
function insertMessage(target: HTMLElement, msg: string): void {
if (!ariaContainer) {
return;
}
// If the same message should be inserted that is already present, a screen reader would
// not announce this message because it matches the previous one. As a workaround, we
// alter the message with the number of occurences unless this is explicitly disabled
// via the disableRepeat flag.
if (!disableRepeat) {
if (prevText === msg) {
repeatedTimes++;
} else {
prevText = msg;
repeatedTimes = 0;
}
switch (repeatedTimes) {
case 0: break;
case 1: msg = nls.localize('repeated', "{0} (occurred again)", msg); break;
default: msg = nls.localize('repeatedNtimes', "{0} (occurred {1} times)", msg, repeatedTimes); break;
}
}
dom.clearNode(target);
target.textContent = msg;
// See https://www.paciellogroup.com/blog/2012/06/html5-accessibility-chops-aria-rolealert-browser-support/
target.style.visibility = 'hidden';
target.style.visibility = 'visible';
}
}

View File

@@ -25,7 +25,7 @@
outline: none;
}
.monaco-breadcrumbs .monaco-breadcrumb-item .codicon-chevron-right {
.monaco-breadcrumbs .monaco-breadcrumb-item .codicon-breadcrumb-separator {
color: inherit;
}

View File

@@ -11,6 +11,7 @@ import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
import 'vs/css!./breadcrumbsWidget';
export abstract class BreadcrumbsItem {
@@ -55,6 +56,8 @@ export interface IBreadcrumbsItemEvent {
payload: any;
}
const breadcrumbSeparatorIcon = registerIcon('breadcrumb-separator', Codicon.chevronRight);
export class BreadcrumbsWidget {
private readonly _disposables = new DisposableStore();
@@ -336,7 +339,7 @@ export class BreadcrumbsWidget {
container.tabIndex = -1;
container.setAttribute('role', 'listitem');
dom.addClasses(container, 'monaco-breadcrumb-item');
const iconContainer = dom.$('.codicon.codicon-chevron-right');
const iconContainer = dom.$(breadcrumbSeparatorIcon.cssSelector);
container.appendChild(iconContainer);
}

View File

@@ -10,12 +10,13 @@ import { Widget } from 'vs/base/browser/ui/widget';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import * as objects from 'vs/base/common/objects';
import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Codicon } from 'vs/base/common/codicons';
export interface ICheckboxOpts extends ICheckboxStyles {
readonly actionClassName?: string;
readonly icon?: Codicon;
readonly title: string;
readonly isChecked: boolean;
}
@@ -93,13 +94,23 @@ export class Checkbox extends Widget {
constructor(opts: ICheckboxOpts) {
super();
this._opts = objects.deepClone(opts);
objects.mixin(this._opts, defaultOpts, false);
this._opts = { ...defaultOpts, ...opts };
this._checked = this._opts.isChecked;
const classes = ['monaco-custom-checkbox'];
if (this._opts.icon) {
classes.push(this._opts.icon.classNames);
} else {
classes.push('codicon'); // todo@aeschli: remove once codicon fully adopted
}
if (this._opts.actionClassName) {
classes.push(this._opts.actionClassName);
}
classes.push(this._checked ? 'checked' : 'unchecked');
this.domNode = document.createElement('div');
this.domNode.title = this._opts.title;
this.domNode.className = 'monaco-custom-checkbox codicon ' + (this._opts.actionClassName || '') + ' ' + (this._checked ? 'checked' : 'unchecked');
this.domNode.className = classes.join(' ');
this.domNode.tabIndex = 0;
this.domNode.setAttribute('role', 'checkbox');
this.domNode.setAttribute('aria-checked', String(this._checked));
@@ -192,7 +203,7 @@ export class SimpleCheckbox extends Widget {
constructor(private title: string, private isChecked: boolean) {
super();
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, actionClassName: 'monaco-simple-checkbox codicon-check' });
this.checkbox = new Checkbox({ title: this.title, isChecked: this.isChecked, icon: Codicon.check, actionClassName: 'monaco-simple-checkbox' });
this.domNode = this.checkbox.domNode;

View File

@@ -1,427 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?a76e99e42eab7c1a55601640b708d820") format("truetype");
}
.codicon[class*='codicon-'] {
font: normal normal normal 16px/1 codicon;
display: inline-block;
text-decoration: none;
text-rendering: auto;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.codicon-add:before { content: "\ea60" }
.codicon-plus:before { content: "\ea60" }
.codicon-gist-new:before { content: "\ea60" }
.codicon-repo-create:before { content: "\ea60" }
.codicon-lightbulb:before { content: "\ea61" }
.codicon-light-bulb:before { content: "\ea61" }
.codicon-repo:before { content: "\ea62" }
.codicon-repo-delete:before { content: "\ea62" }
.codicon-gist-fork:before { content: "\ea63" }
.codicon-repo-forked:before { content: "\ea63" }
.codicon-git-pull-request:before { content: "\ea64" }
.codicon-git-pull-request-abandoned:before { content: "\ea64" }
.codicon-record-keys:before { content: "\ea65" }
.codicon-keyboard:before { content: "\ea65" }
.codicon-tag:before { content: "\ea66" }
.codicon-tag-add:before { content: "\ea66" }
.codicon-tag-remove:before { content: "\ea66" }
.codicon-person:before { content: "\ea67" }
.codicon-person-add:before { content: "\ea67" }
.codicon-person-follow:before { content: "\ea67" }
.codicon-person-outline:before { content: "\ea67" }
.codicon-person-filled:before { content: "\ea67" }
.codicon-git-branch:before { content: "\ea68" }
.codicon-git-branch-create:before { content: "\ea68" }
.codicon-git-branch-delete:before { content: "\ea68" }
.codicon-source-control:before { content: "\ea68" }
.codicon-mirror:before { content: "\ea69" }
.codicon-mirror-public:before { content: "\ea69" }
.codicon-star:before { content: "\ea6a" }
.codicon-star-add:before { content: "\ea6a" }
.codicon-star-delete:before { content: "\ea6a" }
.codicon-star-empty:before { content: "\ea6a" }
.codicon-comment:before { content: "\ea6b" }
.codicon-comment-add:before { content: "\ea6b" }
.codicon-alert:before { content: "\ea6c" }
.codicon-warning:before { content: "\ea6c" }
.codicon-search:before { content: "\ea6d" }
.codicon-search-save:before { content: "\ea6d" }
.codicon-log-out:before { content: "\ea6e" }
.codicon-sign-out:before { content: "\ea6e" }
.codicon-log-in:before { content: "\ea6f" }
.codicon-sign-in:before { content: "\ea6f" }
.codicon-eye:before { content: "\ea70" }
.codicon-eye-unwatch:before { content: "\ea70" }
.codicon-eye-watch:before { content: "\ea70" }
.codicon-circle-filled:before { content: "\ea71" }
.codicon-primitive-dot:before { content: "\ea71" }
.codicon-close-dirty:before { content: "\ea71" }
.codicon-debug-breakpoint:before { content: "\ea71" }
.codicon-debug-breakpoint-disabled:before { content: "\ea71" }
.codicon-debug-hint:before { content: "\ea71" }
.codicon-primitive-square:before { content: "\ea72" }
.codicon-edit:before { content: "\ea73" }
.codicon-pencil:before { content: "\ea73" }
.codicon-info:before { content: "\ea74" }
.codicon-issue-opened:before { content: "\ea74" }
.codicon-gist-private:before { content: "\ea75" }
.codicon-git-fork-private:before { content: "\ea75" }
.codicon-lock:before { content: "\ea75" }
.codicon-mirror-private:before { content: "\ea75" }
.codicon-close:before { content: "\ea76" }
.codicon-remove-close:before { content: "\ea76" }
.codicon-x:before { content: "\ea76" }
.codicon-repo-sync:before { content: "\ea77" }
.codicon-sync:before { content: "\ea77" }
.codicon-clone:before { content: "\ea78" }
.codicon-desktop-download:before { content: "\ea78" }
.codicon-beaker:before { content: "\ea79" }
.codicon-microscope:before { content: "\ea79" }
.codicon-vm:before { content: "\ea7a" }
.codicon-device-desktop:before { content: "\ea7a" }
.codicon-file:before { content: "\ea7b" }
.codicon-file-text:before { content: "\ea7b" }
.codicon-more:before { content: "\ea7c" }
.codicon-ellipsis:before { content: "\ea7c" }
.codicon-kebab-horizontal:before { content: "\ea7c" }
.codicon-mail-reply:before { content: "\ea7d" }
.codicon-reply:before { content: "\ea7d" }
.codicon-organization:before { content: "\ea7e" }
.codicon-organization-filled:before { content: "\ea7e" }
.codicon-organization-outline:before { content: "\ea7e" }
.codicon-new-file:before { content: "\ea7f" }
.codicon-file-add:before { content: "\ea7f" }
.codicon-new-folder:before { content: "\ea80" }
.codicon-file-directory-create:before { content: "\ea80" }
.codicon-trash:before { content: "\ea81" }
.codicon-trashcan:before { content: "\ea81" }
.codicon-history:before { content: "\ea82" }
.codicon-clock:before { content: "\ea82" }
.codicon-folder:before { content: "\ea83" }
.codicon-file-directory:before { content: "\ea83" }
.codicon-symbol-folder:before { content: "\ea83" }
.codicon-logo-github:before { content: "\ea84" }
.codicon-mark-github:before { content: "\ea84" }
.codicon-github:before { content: "\ea84" }
.codicon-terminal:before { content: "\ea85" }
.codicon-console:before { content: "\ea85" }
.codicon-repl:before { content: "\ea85" }
.codicon-zap:before { content: "\ea86" }
.codicon-symbol-event:before { content: "\ea86" }
.codicon-error:before { content: "\ea87" }
.codicon-stop:before { content: "\ea87" }
.codicon-variable:before { content: "\ea88" }
.codicon-symbol-variable:before { content: "\ea88" }
.codicon-array:before { content: "\ea8a" }
.codicon-symbol-array:before { content: "\ea8a" }
.codicon-symbol-module:before { content: "\ea8b" }
.codicon-symbol-package:before { content: "\ea8b" }
.codicon-symbol-namespace:before { content: "\ea8b" }
.codicon-symbol-object:before { content: "\ea8b" }
.codicon-symbol-method:before { content: "\ea8c" }
.codicon-symbol-function:before { content: "\ea8c" }
.codicon-symbol-constructor:before { content: "\ea8c" }
.codicon-symbol-boolean:before { content: "\ea8f" }
.codicon-symbol-null:before { content: "\ea8f" }
.codicon-symbol-numeric:before { content: "\ea90" }
.codicon-symbol-number:before { content: "\ea90" }
.codicon-symbol-structure:before { content: "\ea91" }
.codicon-symbol-struct:before { content: "\ea91" }
.codicon-symbol-parameter:before { content: "\ea92" }
.codicon-symbol-type-parameter:before { content: "\ea92" }
.codicon-symbol-key:before { content: "\ea93" }
.codicon-symbol-text:before { content: "\ea93" }
.codicon-symbol-reference:before { content: "\ea94" }
.codicon-go-to-file:before { content: "\ea94" }
.codicon-symbol-enum:before { content: "\ea95" }
.codicon-symbol-value:before { content: "\ea95" }
.codicon-symbol-ruler:before { content: "\ea96" }
.codicon-symbol-unit:before { content: "\ea96" }
.codicon-activate-breakpoints:before { content: "\ea97" }
.codicon-archive:before { content: "\ea98" }
.codicon-arrow-both:before { content: "\ea99" }
.codicon-arrow-down:before { content: "\ea9a" }
.codicon-arrow-left:before { content: "\ea9b" }
.codicon-arrow-right:before { content: "\ea9c" }
.codicon-arrow-small-down:before { content: "\ea9d" }
.codicon-arrow-small-left:before { content: "\ea9e" }
.codicon-arrow-small-right:before { content: "\ea9f" }
.codicon-arrow-small-up:before { content: "\eaa0" }
.codicon-arrow-up:before { content: "\eaa1" }
.codicon-bell:before { content: "\eaa2" }
.codicon-bold:before { content: "\eaa3" }
.codicon-book:before { content: "\eaa4" }
.codicon-bookmark:before { content: "\eaa5" }
.codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6" }
.codicon-debug-breakpoint-conditional:before { content: "\eaa7" }
.codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7" }
.codicon-debug-breakpoint-data-unverified:before { content: "\eaa8" }
.codicon-debug-breakpoint-data:before { content: "\eaa9" }
.codicon-debug-breakpoint-data-disabled:before { content: "\eaa9" }
.codicon-debug-breakpoint-log-unverified:before { content: "\eaaa" }
.codicon-debug-breakpoint-log:before { content: "\eaab" }
.codicon-debug-breakpoint-log-disabled:before { content: "\eaab" }
.codicon-briefcase:before { content: "\eaac" }
.codicon-broadcast:before { content: "\eaad" }
.codicon-browser:before { content: "\eaae" }
.codicon-bug:before { content: "\eaaf" }
.codicon-calendar:before { content: "\eab0" }
.codicon-case-sensitive:before { content: "\eab1" }
.codicon-check:before { content: "\eab2" }
.codicon-checklist:before { content: "\eab3" }
.codicon-chevron-down:before { content: "\eab4" }
.codicon-chevron-left:before { content: "\eab5" }
.codicon-chevron-right:before { content: "\eab6" }
.codicon-chevron-up:before { content: "\eab7" }
.codicon-chrome-close:before { content: "\eab8" }
.codicon-chrome-maximize:before { content: "\eab9" }
.codicon-chrome-minimize:before { content: "\eaba" }
.codicon-chrome-restore:before { content: "\eabb" }
.codicon-circle-outline:before { content: "\eabc" }
.codicon-debug-breakpoint-unverified:before { content: "\eabc" }
.codicon-circle-slash:before { content: "\eabd" }
.codicon-circuit-board:before { content: "\eabe" }
.codicon-clear-all:before { content: "\eabf" }
.codicon-clippy:before { content: "\eac0" }
.codicon-close-all:before { content: "\eac1" }
.codicon-cloud-download:before { content: "\eac2" }
.codicon-cloud-upload:before { content: "\eac3" }
.codicon-code:before { content: "\eac4" }
.codicon-collapse-all:before { content: "\eac5" }
.codicon-color-mode:before { content: "\eac6" }
.codicon-comment-discussion:before { content: "\eac7" }
.codicon-compare-changes:before { content: "\eac8" }
.codicon-credit-card:before { content: "\eac9" }
.codicon-dash:before { content: "\eacc" }
.codicon-dashboard:before { content: "\eacd" }
.codicon-database:before { content: "\eace" }
.codicon-debug-continue:before { content: "\eacf" }
.codicon-debug-disconnect:before { content: "\ead0" }
.codicon-debug-pause:before { content: "\ead1" }
.codicon-debug-restart:before { content: "\ead2" }
.codicon-debug-start:before { content: "\ead3" }
.codicon-debug-step-into:before { content: "\ead4" }
.codicon-debug-step-out:before { content: "\ead5" }
.codicon-debug-step-over:before { content: "\ead6" }
.codicon-debug-stop:before { content: "\ead7" }
.codicon-debug:before { content: "\ead8" }
.codicon-device-camera-video:before { content: "\ead9" }
.codicon-device-camera:before { content: "\eada" }
.codicon-device-mobile:before { content: "\eadb" }
.codicon-diff-added:before { content: "\eadc" }
.codicon-diff-ignored:before { content: "\eadd" }
.codicon-diff-modified:before { content: "\eade" }
.codicon-diff-removed:before { content: "\eadf" }
.codicon-diff-renamed:before { content: "\eae0" }
.codicon-diff:before { content: "\eae1" }
.codicon-discard:before { content: "\eae2" }
.codicon-editor-layout:before { content: "\eae3" }
.codicon-empty-window:before { content: "\eae4" }
.codicon-exclude:before { content: "\eae5" }
.codicon-extensions:before { content: "\eae6" }
.codicon-eye-closed:before { content: "\eae7" }
.codicon-file-binary:before { content: "\eae8" }
.codicon-file-code:before { content: "\eae9" }
.codicon-file-media:before { content: "\eaea" }
.codicon-file-pdf:before { content: "\eaeb" }
.codicon-file-submodule:before { content: "\eaec" }
.codicon-file-symlink-directory:before { content: "\eaed" }
.codicon-file-symlink-file:before { content: "\eaee" }
.codicon-file-zip:before { content: "\eaef" }
.codicon-files:before { content: "\eaf0" }
.codicon-filter:before { content: "\eaf1" }
.codicon-flame:before { content: "\eaf2" }
.codicon-fold-down:before { content: "\eaf3" }
.codicon-fold-up:before { content: "\eaf4" }
.codicon-fold:before { content: "\eaf5" }
.codicon-folder-active:before { content: "\eaf6" }
.codicon-folder-opened:before { content: "\eaf7" }
.codicon-gear:before { content: "\eaf8" }
.codicon-gift:before { content: "\eaf9" }
.codicon-gist-secret:before { content: "\eafa" }
.codicon-gist:before { content: "\eafb" }
.codicon-git-commit:before { content: "\eafc" }
.codicon-git-compare:before { content: "\eafd" }
.codicon-git-merge:before { content: "\eafe" }
.codicon-github-action:before { content: "\eaff" }
.codicon-github-alt:before { content: "\eb00" }
.codicon-globe:before { content: "\eb01" }
.codicon-grabber:before { content: "\eb02" }
.codicon-graph:before { content: "\eb03" }
.codicon-gripper:before { content: "\eb04" }
.codicon-heart:before { content: "\eb05" }
.codicon-home:before { content: "\eb06" }
.codicon-horizontal-rule:before { content: "\eb07" }
.codicon-hubot:before { content: "\eb08" }
.codicon-inbox:before { content: "\eb09" }
.codicon-issue-closed:before { content: "\eb0a" }
.codicon-issue-reopened:before { content: "\eb0b" }
.codicon-issues:before { content: "\eb0c" }
.codicon-italic:before { content: "\eb0d" }
.codicon-jersey:before { content: "\eb0e" }
.codicon-json:before { content: "\eb0f" }
.codicon-kebab-vertical:before { content: "\eb10" }
.codicon-key:before { content: "\eb11" }
.codicon-law:before { content: "\eb12" }
.codicon-lightbulb-autofix:before { content: "\eb13" }
.codicon-link-external:before { content: "\eb14" }
.codicon-link:before { content: "\eb15" }
.codicon-list-ordered:before { content: "\eb16" }
.codicon-list-unordered:before { content: "\eb17" }
.codicon-live-share:before { content: "\eb18" }
.codicon-loading:before { content: "\eb19" }
.codicon-location:before { content: "\eb1a" }
.codicon-mail-read:before { content: "\eb1b" }
.codicon-mail:before { content: "\eb1c" }
.codicon-markdown:before { content: "\eb1d" }
.codicon-megaphone:before { content: "\eb1e" }
.codicon-mention:before { content: "\eb1f" }
.codicon-milestone:before { content: "\eb20" }
.codicon-mortar-board:before { content: "\eb21" }
.codicon-move:before { content: "\eb22" }
.codicon-multiple-windows:before { content: "\eb23" }
.codicon-mute:before { content: "\eb24" }
.codicon-no-newline:before { content: "\eb25" }
.codicon-note:before { content: "\eb26" }
.codicon-octoface:before { content: "\eb27" }
.codicon-open-preview:before { content: "\eb28" }
.codicon-package:before { content: "\eb29" }
.codicon-paintcan:before { content: "\eb2a" }
.codicon-pin:before { content: "\eb2b" }
.codicon-play:before { content: "\eb2c" }
.codicon-run:before { content: "\eb2c" }
.codicon-plug:before { content: "\eb2d" }
.codicon-preserve-case:before { content: "\eb2e" }
.codicon-preview:before { content: "\eb2f" }
.codicon-project:before { content: "\eb30" }
.codicon-pulse:before { content: "\eb31" }
.codicon-question:before { content: "\eb32" }
.codicon-quote:before { content: "\eb33" }
.codicon-radio-tower:before { content: "\eb34" }
.codicon-reactions:before { content: "\eb35" }
.codicon-references:before { content: "\eb36" }
.codicon-refresh:before { content: "\eb37" }
.codicon-regex:before { content: "\eb38" }
.codicon-remote-explorer:before { content: "\eb39" }
.codicon-remote:before { content: "\eb3a" }
.codicon-remove:before { content: "\eb3b" }
.codicon-replace-all:before { content: "\eb3c" }
.codicon-replace:before { content: "\eb3d" }
.codicon-repo-clone:before { content: "\eb3e" }
.codicon-repo-force-push:before { content: "\eb3f" }
.codicon-repo-pull:before { content: "\eb40" }
.codicon-repo-push:before { content: "\eb41" }
.codicon-report:before { content: "\eb42" }
.codicon-request-changes:before { content: "\eb43" }
.codicon-rocket:before { content: "\eb44" }
.codicon-root-folder-opened:before { content: "\eb45" }
.codicon-root-folder:before { content: "\eb46" }
.codicon-rss:before { content: "\eb47" }
.codicon-ruby:before { content: "\eb48" }
.codicon-save-all:before { content: "\eb49" }
.codicon-save-as:before { content: "\eb4a" }
.codicon-save:before { content: "\eb4b" }
.codicon-screen-full:before { content: "\eb4c" }
.codicon-screen-normal:before { content: "\eb4d" }
.codicon-search-stop:before { content: "\eb4e" }
.codicon-server:before { content: "\eb50" }
.codicon-settings-gear:before { content: "\eb51" }
.codicon-settings:before { content: "\eb52" }
.codicon-shield:before { content: "\eb53" }
.codicon-smiley:before { content: "\eb54" }
.codicon-sort-precedence:before { content: "\eb55" }
.codicon-split-horizontal:before { content: "\eb56" }
.codicon-split-vertical:before { content: "\eb57" }
.codicon-squirrel:before { content: "\eb58" }
.codicon-star-full:before { content: "\eb59" }
.codicon-star-half:before { content: "\eb5a" }
.codicon-symbol-class:before { content: "\eb5b" }
.codicon-symbol-color:before { content: "\eb5c" }
.codicon-symbol-constant:before { content: "\eb5d" }
.codicon-symbol-enum-member:before { content: "\eb5e" }
.codicon-symbol-field:before { content: "\eb5f" }
.codicon-symbol-file:before { content: "\eb60" }
.codicon-symbol-interface:before { content: "\eb61" }
.codicon-symbol-keyword:before { content: "\eb62" }
.codicon-symbol-misc:before { content: "\eb63" }
.codicon-symbol-operator:before { content: "\eb64" }
.codicon-symbol-property:before { content: "\eb65" }
.codicon-wrench:before { content: "\eb65" }
.codicon-wrench-subaction:before { content: "\eb65" }
.codicon-symbol-snippet:before { content: "\eb66" }
.codicon-tasklist:before { content: "\eb67" }
.codicon-telescope:before { content: "\eb68" }
.codicon-text-size:before { content: "\eb69" }
.codicon-three-bars:before { content: "\eb6a" }
.codicon-thumbsdown:before { content: "\eb6b" }
.codicon-thumbsup:before { content: "\eb6c" }
.codicon-tools:before { content: "\eb6d" }
.codicon-triangle-down:before { content: "\eb6e" }
.codicon-triangle-left:before { content: "\eb6f" }
.codicon-triangle-right:before { content: "\eb70" }
.codicon-triangle-up:before { content: "\eb71" }
.codicon-twitter:before { content: "\eb72" }
.codicon-unfold:before { content: "\eb73" }
.codicon-unlock:before { content: "\eb74" }
.codicon-unmute:before { content: "\eb75" }
.codicon-unverified:before { content: "\eb76" }
.codicon-verified:before { content: "\eb77" }
.codicon-versions:before { content: "\eb78" }
.codicon-vm-active:before { content: "\eb79" }
.codicon-vm-outline:before { content: "\eb7a" }
.codicon-vm-running:before { content: "\eb7b" }
.codicon-watch:before { content: "\eb7c" }
.codicon-whitespace:before { content: "\eb7d" }
.codicon-whole-word:before { content: "\eb7e" }
.codicon-window:before { content: "\eb7f" }
.codicon-word-wrap:before { content: "\eb80" }
.codicon-zoom-in:before { content: "\eb81" }
.codicon-zoom-out:before { content: "\eb82" }
.codicon-list-filter:before { content: "\eb83" }
.codicon-list-flat:before { content: "\eb84" }
.codicon-list-selection:before { content: "\eb85" }
.codicon-selection:before { content: "\eb85" }
.codicon-list-tree:before { content: "\eb86" }
.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" }
.codicon-debug-breakpoint-function:before { content: "\eb88" }
.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" }
.codicon-debug-stackframe-active:before { content: "\eb89" }
.codicon-debug-stackframe-dot:before { content: "\eb8a" }
.codicon-debug-stackframe:before { content: "\eb8b" }
.codicon-debug-stackframe-focused:before { content: "\eb8b" }
.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" }
.codicon-symbol-string:before { content: "\eb8d" }
.codicon-debug-reverse-continue:before { content: "\eb8e" }
.codicon-debug-step-back:before { content: "\eb8f" }
.codicon-debug-restart-frame:before { content: "\eb90" }
.codicon-debug-alternate:before { content: "\eb91" }
.codicon-call-incoming:before { content: "\eb92" }
.codicon-call-outgoing:before { content: "\eb93" }
.codicon-menu:before { content: "\eb94" }
.codicon-expand-all:before { content: "\eb95" }
.codicon-feedback:before { content: "\eb96" }
.codicon-group-by-ref-type:before { content: "\eb97" }
.codicon-ungroup-by-ref-type:before { content: "\eb98" }
.codicon-account:before { content: "\eb99" }
.codicon-bell-dot:before { content: "\eb9a" }
.codicon-debug-console:before { content: "\eb9b" }
.codicon-library:before { content: "\eb9c" }
.codicon-output:before { content: "\eb9d" }
.codicon-run-all:before { content: "\eb9e" }
.codicon-sync-ignored:before { content: "\eb9f" }
.codicon-debug-alt-2:before { content: "\f101" }
.codicon-debug-alt:before { content: "\f102" }

View File

@@ -0,0 +1,24 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?5d4d76ab2ce5108968ad644d591a16a6") format("truetype");
}
.codicon[class*='codicon-'] {
font: normal normal normal 16px/1 codicon;
display: inline-block;
text-decoration: none;
text-rendering: auto;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
/* icon rules are dynamically created in codiconStyles */

View File

@@ -3,9 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./codicon/codicon';
import 'vs/css!./codicon/codicon-modifications';
import 'vs/css!./codicon/codicon-animations';
import { escape } from 'vs/base/common/strings';
import { renderCodicons } from 'vs/base/common/codicons';

View File

@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./codicon/codicon';
import 'vs/css!./codicon/codicon-modifications';
import 'vs/css!./codicon/codicon-animations';
import { Codicon, iconRegistry } from 'vs/base/common/codicons';
import { createStyleSheet } from 'vs/base/browser/dom';
import { RunOnceScheduler } from 'vs/base/common/async';
function initialize() {
let codiconStyleSheet = createStyleSheet();
codiconStyleSheet.id = 'codiconStyles';
function updateAll() {
const rules = [];
for (let c of iconRegistry.all) {
rules.push(formatRule(c));
}
codiconStyleSheet.innerHTML = rules.join('\n');
}
const delayer = new RunOnceScheduler(updateAll, 0);
iconRegistry.onDidRegister(() => delayer.schedule());
delayer.schedule();
}
function formatRule(c: Codicon) {
let def = c.definition;
while (def instanceof Codicon) {
def = def.definition;
}
return `.codicon-${c.id}:before { content: '${def.character}'; }`;
}
initialize();

View File

@@ -6,7 +6,7 @@
import 'vs/css!./dialog';
import * as nls from 'vs/nls';
import { Disposable } from 'vs/base/common/lifecycle';
import { $, hide, show, EventHelper, clearNode, removeClasses, addClass, addClasses, removeNode, isAncestor, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { $, hide, show, EventHelper, clearNode, removeClasses, addClasses, removeNode, isAncestor, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
@@ -17,6 +17,7 @@ import { Action } from 'vs/base/common/actions';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { isMacintosh, isLinux } from 'vs/base/common/platform';
import { SimpleCheckbox, ISimpleCheckboxStyles } from 'vs/base/browser/ui/checkbox/checkbox';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
export interface IDialogOptions {
cancelId?: number;
@@ -37,6 +38,9 @@ export interface IDialogStyles extends IButtonStyles, ISimpleCheckboxStyles {
dialogBackground?: Color;
dialogShadow?: Color;
dialogBorder?: Color;
errorIconForeground?: Color;
warningIconForeground?: Color;
infoIconForeground?: Color;
}
interface ButtonMapEntry {
@@ -44,6 +48,11 @@ interface ButtonMapEntry {
index: number;
}
const dialogErrorIcon = registerIcon('dialog-error', Codicon.error);
const dialogWarningIcon = registerIcon('dialog-warning', Codicon.warning);
const dialogInfoIcon = registerIcon('dialog-info', Codicon.info);
const dialogCloseIcon = registerIcon('dialog-close', Codicon.close);
export class Dialog extends Disposable {
private element: HTMLElement | undefined;
private shadowElement: HTMLElement | undefined;
@@ -202,30 +211,29 @@ export class Dialog extends Disposable {
}
}));
addClass(this.iconElement, 'codicon');
removeClasses(this.iconElement, 'codicon-alert', 'codicon-warning', 'codicon-info');
removeClasses(this.iconElement, dialogErrorIcon.classNames, dialogWarningIcon.classNames, dialogInfoIcon.classNames, Codicon.loading.classNames);
switch (this.options.type) {
case 'error':
addClass(this.iconElement, 'codicon-error');
addClasses(this.iconElement, dialogErrorIcon.classNames);
break;
case 'warning':
addClass(this.iconElement, 'codicon-warning');
addClasses(this.iconElement, dialogWarningIcon.classNames);
break;
case 'pending':
addClasses(this.iconElement, 'codicon-loading', 'codicon-animation-spin');
addClasses(this.iconElement, Codicon.loading.classNames, 'codicon-animation-spin');
break;
case 'none':
case 'info':
case 'question':
default:
addClass(this.iconElement, 'codicon-info');
addClasses(this.iconElement, dialogInfoIcon.classNames);
break;
}
const actionBar = new ActionBar(this.toolbarContainer, {});
const action = new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), 'codicon codicon-close', true, () => {
const action = new Action('dialog.close', nls.localize('dialogClose', "Close Dialog"), dialogCloseIcon.classNames, true, () => {
resolve({ button: this.options.cancelId || 0, checkboxChecked: this.checkbox ? this.checkbox.checked : undefined });
return Promise.resolve();
});
@@ -268,10 +276,28 @@ export class Dialog extends Disposable {
this.checkbox.style(style);
}
if (this.messageDetailElement) {
if (this.messageDetailElement && fgColor && bgColor) {
const messageDetailColor = Color.fromHex(fgColor).transparent(.9);
this.messageDetailElement.style.color = messageDetailColor.makeOpaque(Color.fromHex(bgColor)).toString();
}
if (this.iconElement) {
let color;
switch (this.options.type) {
case 'error':
color = style.errorIconForeground;
break;
case 'warning':
color = style.warningIconForeground;
break;
default:
color = style.infoIconForeground;
break;
}
if (color) {
this.iconElement.style.color = color.toString();
}
}
}
}

View File

@@ -295,7 +295,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
render(container: HTMLElement): void {
const labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {
this.element = append(el, $('a.action-label.codicon'));
this.element = append(el, $('a.action-label.codicon')); // todo@aeschli: remove codicon, should come through `this.clazz`
if (this.clazz) {
addClasses(this.element, this.clazz);
}

View File

@@ -6,6 +6,7 @@
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
import { Color } from 'vs/base/common/color';
import * as nls from 'vs/nls';
import { Codicon } from 'vs/base/common/codicons';
export interface IFindInputCheckboxOpts {
readonly appendTitle: string;
@@ -21,7 +22,7 @@ const NLS_REGEX_CHECKBOX_LABEL = nls.localize('regexDescription', "Use Regular E
export class CaseSensitiveCheckbox extends Checkbox {
constructor(opts: IFindInputCheckboxOpts) {
super({
actionClassName: 'codicon-case-sensitive',
icon: Codicon.caseSensitive,
title: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
inputActiveOptionBorder: opts.inputActiveOptionBorder,
@@ -33,7 +34,7 @@ export class CaseSensitiveCheckbox extends Checkbox {
export class WholeWordsCheckbox extends Checkbox {
constructor(opts: IFindInputCheckboxOpts) {
super({
actionClassName: 'codicon-whole-word',
icon: Codicon.wholeWord,
title: NLS_WHOLE_WORD_CHECKBOX_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
inputActiveOptionBorder: opts.inputActiveOptionBorder,
@@ -45,7 +46,7 @@ export class WholeWordsCheckbox extends Checkbox {
export class RegexCheckbox extends Checkbox {
constructor(opts: IFindInputCheckboxOpts) {
super({
actionClassName: 'codicon-regex',
icon: Codicon.regex,
title: NLS_REGEX_CHECKBOX_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
inputActiveOptionBorder: opts.inputActiveOptionBorder,

View File

@@ -17,6 +17,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { Color } from 'vs/base/common/color';
import { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
import { IFindInputCheckboxOpts } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
import { Codicon } from 'vs/base/common/codicons';
export interface IReplaceInputOptions extends IReplaceInputStyles {
readonly placeholder?: string;
@@ -42,7 +43,7 @@ export class PreserveCaseCheckbox extends Checkbox {
constructor(opts: IFindInputCheckboxOpts) {
super({
// TODO: does this need its own icon?
actionClassName: 'codicon-preserve-case',
icon: Codicon.preserveCase,
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
inputActiveOptionBorder: opts.inputActiveOptionBorder,

View File

@@ -594,7 +594,7 @@ export class InputBox extends Widget {
this.element.style.backgroundColor = background;
this.element.style.color = foreground;
this.input.style.backgroundColor = background;
this.input.style.backgroundColor = 'inherit';
this.input.style.color = foreground;
this.element.style.borderWidth = border ? '1px' : '';

View File

@@ -129,10 +129,6 @@
cursor: pointer;
}
.monaco-list-type-filter > .controls > .filter:checked::before {
content: "\eb83" !important; /* codicon-list-filter */
}
.monaco-list-type-filter > .controls > .filter {
margin-left: 4px;
}

View File

@@ -63,17 +63,6 @@ export interface IIdentityProvider<T> {
getId(element: T): { toString(): string; };
}
export enum ListAriaRootRole {
/** default list structure role */
LIST = 'list',
/** default tree structure role */
TREE = 'tree',
/** role='tree' can interfere with screenreaders reading nested elements inside the tree row. Use FORM in that case. */
FORM = 'form'
}
export interface IKeyboardNavigationLabelProvider<T> {
/**

View File

@@ -7,10 +7,11 @@ import 'vs/css!./list';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { range } from 'vs/base/common/arrays';
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent } from './list';
import { List, IListStyles, IListOptions } from './listWidget';
import { List, IListStyles, IListOptions, IListAccessibilityProvider } from './listWidget';
import { IPagedModel } from 'vs/base/common/paging';
import { Event } from 'vs/base/common/event';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
export interface IPagedRenderer<TElement, TTemplateData> extends IListRenderer<TElement, TTemplateData> {
renderPlaceholder(index: number, templateData: TTemplateData): void;
@@ -70,6 +71,54 @@ class PagedRenderer<TElement, TTemplateData> implements IListRenderer<number, IT
}
}
class PagedAccessibilityProvider<T> implements IListAccessibilityProvider<number> {
constructor(
private modelProvider: () => IPagedModel<T>,
private accessibilityProvider: IListAccessibilityProvider<T>
) { }
getWidgetAriaLabel(): string {
return this.accessibilityProvider.getWidgetAriaLabel();
}
getAriaLabel(index: number): string | null {
const model = this.modelProvider();
if (!model.isResolved(index)) {
return null;
}
return this.accessibilityProvider.getAriaLabel(model.get(index));
}
}
export interface IPagedListOptions<T> {
readonly enableKeyboardNavigation?: boolean;
readonly automaticKeyboardNavigation?: boolean;
readonly ariaLabel?: string;
readonly keyboardSupport?: boolean;
readonly multipleSelectionSupport?: boolean;
readonly accessibilityProvider?: IListAccessibilityProvider<T>;
// list view options
readonly useShadows?: boolean;
readonly verticalScrollMode?: ScrollbarVisibility;
readonly setRowLineHeight?: boolean;
readonly setRowHeight?: boolean;
readonly supportDynamicHeights?: boolean;
readonly mouseSupport?: boolean;
readonly horizontalScrolling?: boolean;
readonly additionalScrollHeight?: number;
}
function fromPagedListOptions<T>(modelProvider: () => IPagedModel<T>, options: IPagedListOptions<T>): IListOptions<number> {
return {
...options,
accessibilityProvider: options.accessibilityProvider && new PagedAccessibilityProvider(modelProvider, options.accessibilityProvider)
};
}
export class PagedList<T> implements IDisposable {
private list: List<number>;
@@ -80,10 +129,11 @@ export class PagedList<T> implements IDisposable {
container: HTMLElement,
virtualDelegate: IListVirtualDelegate<number>,
renderers: IPagedRenderer<T, any>[],
options: IListOptions<any> = {}
options: IPagedListOptions<T> = {}
) {
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model));
this.list = new List(user, container, virtualDelegate, pagedRenderers, options);
const modelProvider = () => this.model;
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, modelProvider));
this.list = new List(user, container, virtualDelegate, pagedRenderers, fromPagedListOptions(modelProvider, options));
}
getHTMLElement(): HTMLElement {

View File

@@ -41,11 +41,11 @@ export interface IListViewDragAndDrop<T> extends IListDragAndDrop<T> {
getDragElements(element: T): T[];
}
export interface IAriaProvider<T> {
getSetSize(element: T, index: number, listLength: number): number;
getPosInSet(element: T, index: number): number;
export interface IListViewAccessibilityProvider<T> {
getSetSize?(element: T, index: number, listLength: number): number;
getPosInSet?(element: T, index: number): number;
getRole?(element: T): string;
isChecked?(element: T): boolean;
isChecked?(element: T): boolean | undefined;
}
export interface IListViewOptions<T> {
@@ -57,7 +57,7 @@ export interface IListViewOptions<T> {
readonly supportDynamicHeights?: boolean;
readonly mouseSupport?: boolean;
readonly horizontalScrolling?: boolean;
readonly ariaProvider?: IAriaProvider<T>;
readonly accessibilityProvider?: IListViewAccessibilityProvider<T>;
readonly additionalScrollHeight?: number;
}
@@ -152,6 +152,40 @@ function equalsDragFeedback(f1: number[] | undefined, f2: number[] | undefined):
return f1 === f2;
}
class ListViewAccessibilityProvider<T> implements Required<IListViewAccessibilityProvider<T>> {
readonly getSetSize: (element: any, index: number, listLength: number) => number;
readonly getPosInSet: (element: any, index: number) => number;
readonly getRole: (element: T) => string;
readonly isChecked: (element: T) => boolean | undefined;
constructor(accessibilityProvider?: IListViewAccessibilityProvider<T>) {
if (accessibilityProvider?.getSetSize) {
this.getSetSize = accessibilityProvider.getSetSize.bind(accessibilityProvider);
} else {
this.getSetSize = (e, i, l) => l;
}
if (accessibilityProvider?.getPosInSet) {
this.getPosInSet = accessibilityProvider.getPosInSet.bind(accessibilityProvider);
} else {
this.getPosInSet = (e, i) => i + 1;
}
if (accessibilityProvider?.getRole) {
this.getRole = accessibilityProvider.getRole.bind(accessibilityProvider);
} else {
this.getRole = _ => 'listitem';
}
if (accessibilityProvider?.isChecked) {
this.isChecked = accessibilityProvider.isChecked.bind(accessibilityProvider);
} else {
this.isChecked = _ => undefined;
}
}
}
export class ListView<T> implements ISpliceable<T>, IDisposable {
private static InstanceCount = 0;
@@ -181,7 +215,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
private supportDynamicHeights: boolean;
private horizontalScrolling: boolean;
private additionalScrollHeight: number;
private ariaProvider: IAriaProvider<T>;
private accessibilityProvider: ListViewAccessibilityProvider<T>;
private scrollWidth: number | undefined;
private dnd: IListViewDragAndDrop<T>;
@@ -237,7 +271,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.additionalScrollHeight = typeof options.additionalScrollHeight === 'undefined' ? 0 : options.additionalScrollHeight;
this.ariaProvider = options.ariaProvider || { getSetSize: (e, i, length) => length, getPosInSet: (_, index) => index + 1 };
this.accessibilityProvider = new ListViewAccessibilityProvider(options.accessibilityProvider);
this.rowsContainer = document.createElement('div');
this.rowsContainer.className = 'monaco-list-rows';
@@ -611,11 +645,11 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
if (!item.row) {
item.row = this.cache.alloc(item.templateId);
const role = this.ariaProvider.getRole ? this.ariaProvider.getRole(item.element) : 'listitem';
const role = this.accessibilityProvider.getRole(item.element);
item.row!.domNode!.setAttribute('role', role);
const checked = this.ariaProvider.isChecked ? this.ariaProvider.isChecked(item.element) : undefined;
const checked = this.accessibilityProvider.isChecked(item.element);
if (typeof checked !== 'undefined') {
item.row!.domNode!.setAttribute('aria-checked', String(checked));
item.row!.domNode!.setAttribute('aria-checked', String(!!checked));
}
}
@@ -687,8 +721,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
item.row!.domNode!.setAttribute('data-index', `${index}`);
item.row!.domNode!.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false');
item.row!.domNode!.setAttribute('aria-setsize', String(this.ariaProvider.getSetSize(item.element, index, this.length)));
item.row!.domNode!.setAttribute('aria-posinset', String(this.ariaProvider.getPosInSet(item.element, index)));
item.row!.domNode!.setAttribute('aria-setsize', String(this.accessibilityProvider.getSetSize(item.element, index, this.length)));
item.row!.domNode!.setAttribute('aria-posinset', String(this.accessibilityProvider.getPosInSet(item.element, index)));
item.row!.domNode!.setAttribute('id', this.getElementDomId(index));
DOM.toggleClass(item.row!.domNode!, 'drop-target', item.dropTarget);

View File

@@ -16,8 +16,8 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { Event, Emitter, EventBufferer } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole, ListError, IKeyboardNavigationDelegate } from './list';
import { ListView, IListViewOptions, IListViewDragAndDrop, IAriaProvider } from './listView';
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListError, IKeyboardNavigationDelegate } from './list';
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider } from './listView';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
@@ -686,25 +686,11 @@ export interface IStyleController {
style(styles: IListStyles): void;
}
export interface IAccessibilityProvider<T> {
/**
* Given an element in the tree, return the ARIA label that should be associated with the
* item. This helps screen readers to provide a meaningful label for the currently focused
* tree element.
*
* Returning null will not disable ARIA for the element. Instead it is up to the screen reader
* to compute a meaningful label based on the contents of the element in the DOM
*
* See also: https://www.w3.org/TR/wai-aria/#aria-label
*/
export interface IListAccessibilityProvider<T> extends IListViewAccessibilityProvider<T> {
getAriaLabel(element: T): string | null;
/**
* https://www.w3.org/TR/wai-aria/#aria-level
*/
getWidgetAriaLabel(): string;
getWidgetRole?(): string;
getAriaLevel?(element: T): number | undefined;
onDidChangeActiveDescendant?: Event<void>;
getActiveDescendantId?(element: T): string | undefined;
}
@@ -836,14 +822,12 @@ export interface IListOptions<T> {
readonly automaticKeyboardNavigation?: boolean;
readonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider<T>;
readonly keyboardNavigationDelegate?: IKeyboardNavigationDelegate;
readonly ariaRole?: ListAriaRootRole | string;
readonly ariaLabel?: string;
readonly keyboardSupport?: boolean;
readonly multipleSelectionSupport?: boolean;
readonly multipleSelectionController?: IMultipleSelectionController<T>;
readonly openController?: IOpenController;
readonly styleController?: (suffix: string) => IStyleController;
readonly accessibilityProvider?: IAccessibilityProvider<T>;
readonly accessibilityProvider?: IListAccessibilityProvider<T>;
// list view options
readonly useShadows?: boolean;
@@ -853,7 +837,6 @@ export interface IListOptions<T> {
readonly supportDynamicHeights?: boolean;
readonly mouseSupport?: boolean;
readonly horizontalScrolling?: boolean;
readonly ariaProvider?: IAriaProvider<T>;
readonly additionalScrollHeight?: number;
}
@@ -894,7 +877,7 @@ const defaultStyles: IListStyles = {
treeIndentGuidesStroke: Color.fromHex('#a9a9a9')
};
const DefaultOptions = {
const DefaultOptions: IListOptions<any> = {
keyboardSupport: true,
mouseSupport: true,
multipleSelectionSupport: true,
@@ -903,8 +886,7 @@ const DefaultOptions = {
onDragStart(): void { },
onDragOver() { return false; },
drop() { }
},
ariaRootRole: ListAriaRootRole.LIST
}
};
// TODO@Joao: move these utils into a SortedArray class
@@ -1036,7 +1018,7 @@ class AccessibiltyRenderer<T> implements IListRenderer<T, HTMLElement> {
templateId: string = 'a18n';
constructor(private accessibilityProvider: IAccessibilityProvider<T>) { }
constructor(private accessibilityProvider: IListAccessibilityProvider<T>) { }
renderTemplate(container: HTMLElement): HTMLElement {
return container;
@@ -1123,7 +1105,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
private spliceable: ISpliceable<T>;
private styleController: IStyleController;
private typeLabelController?: TypeLabelController<T>;
private accessibilityProvider?: IAccessibilityProvider<T>;
private accessibilityProvider?: IListAccessibilityProvider<T>;
private _ariaLabel: string = '';
protected readonly disposables = new DisposableStore();
@@ -1202,7 +1185,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
renderers: IListRenderer<any /* TODO@joao */, any>[],
private _options: IListOptions<T> = DefaultOptions
) {
this.selection = new SelectionTrait(this._options.ariaRole !== 'listbox');
const role = this._options.accessibilityProvider && this._options.accessibilityProvider.getWidgetRole ? this._options.accessibilityProvider?.getWidgetRole() : 'list';
this.selection = new SelectionTrait(role !== 'listbox');
this.focus = new Trait('focused');
mixin(_options, defaultStyles, false);
@@ -1227,12 +1211,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
};
this.view = new ListView(container, virtualDelegate, renderers, viewOptions);
if (typeof _options.ariaRole !== 'string') {
this.view.domNode.setAttribute('role', ListAriaRootRole.LIST);
} else {
this.view.domNode.setAttribute('role', _options.ariaRole);
}
this.view.domNode.setAttribute('role', role);
if (_options.styleController) {
this.styleController = _options.styleController(this.view.domId);
@@ -1273,8 +1252,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
this.onDidChangeFocus(this._onFocusChange, this, this.disposables);
this.onDidChangeSelection(this._onSelectionChange, this, this.disposables);
if (_options.ariaLabel) {
this.view.domNode.setAttribute('aria-label', localize('aria list', "{0}. Use the navigation keys to navigate.", _options.ariaLabel));
if (this.accessibilityProvider) {
this.ariaLabel = this.accessibilityProvider.getWidgetAriaLabel();
}
if (_options.multipleSelectionSupport) {
this.view.domNode.setAttribute('aria-multiselectable', 'true');
@@ -1377,6 +1356,15 @@ export class List<T> implements ISpliceable<T>, IDisposable {
return this.view.lastVisibleIndex;
}
get ariaLabel(): string {
return this._ariaLabel;
}
set ariaLabel(value: string) {
this._ariaLabel = value;
this.view.domNode.setAttribute('aria-label', localize('aria list', "{0}. Use the navigation keys to navigate.", value));
}
domFocus(): void {
this.view.domNode.focus();
}

View File

@@ -171,6 +171,7 @@
.menubar.compact {
flex-shrink: 0;
overflow: visible; /* to avoid the compact menu to be repositioned when clicking */
}
.menubar.compact > .menubar-menu-button {
@@ -201,7 +202,7 @@
}
.menubar.compact .toolbar-toggle-more {
position: absolute;
position: relative;
left: 0px;
top: 0px;
cursor: pointer;

View File

@@ -1,3 +0,0 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 5.625H0V4.5H18V5.625ZM18 14.625H0V13.5H18V14.625ZM18 10.1162H0V9H18V10.1162Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 209 B

View File

@@ -19,11 +19,14 @@ import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
import { Event } from 'vs/base/common/event';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
import { stripCodicons } from 'vs/base/common/codicons';
import { Codicon, registerIcon, stripCodicons } from 'vs/base/common/codicons';
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
export const MENU_ESCAPED_MNEMONIC_REGEX = /(&amp;)?(&amp;)([^\s&])/g;
const menuSelectionIcon = registerIcon('menu-selection', Codicon.check);
const menuSubmenuIcon = registerIcon('menu-submenu', Codicon.chevronRight);
export enum Direction {
Right,
Left
@@ -423,7 +426,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
}
}
this.check = append(this.item, $('span.menu-item-check.codicon.codicon-check'));
this.check = append(this.item, $('span.menu-item-check' + menuSelectionIcon.cssSelector));
this.check.setAttribute('role', 'none');
this.label = append(this.item, $('span.action-label'));
@@ -670,7 +673,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
addClass(this.item, 'monaco-submenu-item');
this.item.setAttribute('aria-haspopup', 'true');
this.updateAriaExpanded('false');
this.submenuIndicator = append(this.item, $('span.submenu-indicator.codicon.codicon-chevron-right'));
this.submenuIndicator = append(this.item, $('span.submenu-indicator' + menuSubmenuIcon.cssSelector));
this.submenuIndicator.setAttribute('aria-hidden', 'true');
}

View File

@@ -22,9 +22,12 @@ import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode';
import { isMacintosh } from 'vs/base/common/platform';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
const $ = DOM.$;
const menuBarMoreIcon = registerIcon('menubar-more', Codicon.more);
export interface IMenuBarOptions {
enableMnemonics?: boolean;
disableAltFocus?: boolean;
@@ -313,7 +316,7 @@ export class MenuBar extends Disposable {
const label = this.options.compactMode !== undefined ? nls.localize('mAppMenu', 'Application Menu') : nls.localize('mMore', 'More');
const title = this.options.compactMode !== undefined ? label : undefined;
const buttonElement = $('div.menubar-menu-button', { 'role': 'menuitem', 'tabindex': -1, 'aria-label': label, 'title': title, 'aria-haspopup': true });
const titleElement = $('div.menubar-menu-title.toolbar-toggle-more.codicon.codicon-more', { 'role': 'none', 'aria-hidden': true });
const titleElement = $('div.menubar-menu-title.toolbar-toggle-more' + menuBarMoreIcon.cssSelector, { 'role': 'none', 'aria-hidden': true });
buttonElement.appendChild(titleElement);
this.container.appendChild(buttonElement);

View File

@@ -9,6 +9,11 @@ import { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/s
import { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
import { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';
import { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
const scrollbarButtonLeftIcon = registerIcon('scrollbar-button-left', Codicon.triangleLeft);
const scrollbarButtonRightIcon = registerIcon('scrollbar-button-right', Codicon.triangleRight);
export class HorizontalScrollbar extends AbstractScrollbar {
@@ -36,7 +41,8 @@ export class HorizontalScrollbar extends AbstractScrollbar {
let scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;
this._createArrow({
className: 'scra codicon codicon-triangle-left',
className: 'scra',
icon: scrollbarButtonLeftIcon,
top: scrollbarDelta,
left: arrowDelta,
bottom: undefined,
@@ -47,7 +53,8 @@ export class HorizontalScrollbar extends AbstractScrollbar {
});
this._createArrow({
className: 'scra codicon codicon-triangle-right',
className: 'scra',
icon: scrollbarButtonRightIcon,
top: scrollbarDelta,
left: undefined,
bottom: undefined,

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/scrollbars';
import { isEdge } from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
@@ -266,7 +265,7 @@ export abstract class AbstractScrollableElement extends Widget {
}
public setScrollDimensions(dimensions: INewScrollDimensions): void {
this._scrollable.setScrollDimensions(dimensions);
this._scrollable.setScrollDimensions(dimensions, false);
}
/**
@@ -336,7 +335,7 @@ export abstract class AbstractScrollableElement extends Widget {
this._onMouseWheel(new StandardWheelEvent(browserEvent));
};
this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdge ? 'mousewheel' : 'wheel', onMouseWheel, { passive: false }));
this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { passive: false }));
}
}

View File

@@ -7,6 +7,8 @@ import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveM
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { Widget } from 'vs/base/browser/ui/widget';
import { IntervalTimer, TimeoutTimer } from 'vs/base/common/async';
import { Codicon } from 'vs/base/common/codicons';
import { addClasses } from 'vs/base/browser/dom';
/**
* The arrow image size.
@@ -16,6 +18,7 @@ export const ARROW_IMG_SIZE = 11;
export interface ScrollbarArrowOptions {
onActivate: () => void;
className: string;
icon: Codicon;
bgWidth: number;
bgHeight: number;
@@ -59,6 +62,8 @@ export class ScrollbarArrow extends Widget {
this.domNode = document.createElement('div');
this.domNode.className = opts.className;
addClasses(this.domNode, opts.icon.classNames);
this.domNode.style.position = 'absolute';
this.domNode.style.width = ARROW_IMG_SIZE + 'px';
this.domNode.style.height = ARROW_IMG_SIZE + 'px';

View File

@@ -9,6 +9,10 @@ import { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/s
import { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
import { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';
import { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
const scrollbarButtonUpIcon = registerIcon('scrollbar-button-up', Codicon.triangleUp);
const scrollbarButtonDownIcon = registerIcon('scrollbar-button-down', Codicon.triangleDown);
export class VerticalScrollbar extends AbstractScrollbar {
@@ -37,7 +41,8 @@ export class VerticalScrollbar extends AbstractScrollbar {
let scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;
this._createArrow({
className: 'scra codicon codicon-triangle-up',
className: 'scra',
icon: scrollbarButtonUpIcon,
top: arrowDelta,
left: scrollbarDelta,
bottom: undefined,
@@ -48,7 +53,8 @@ export class VerticalScrollbar extends AbstractScrollbar {
});
this._createArrow({
className: 'scra codicon codicon-triangle-down',
className: 'scra',
icon: scrollbarButtonDownIcon,
top: undefined,
left: scrollbarDelta,
bottom: arrowDelta,

View File

@@ -20,6 +20,7 @@ import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxSty
import { isMacintosh } from 'vs/base/common/platform';
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
import { IContentActionHandler } from 'vs/base/browser/formattedTextRenderer';
import { localize } from 'vs/nls';
const $ = dom.$;
@@ -732,12 +733,20 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
this.listRenderer = new SelectListRenderer();
this.selectList = new List('SelectBoxCustom', this.selectDropDownListContainer, this, [this.listRenderer], {
ariaLabel: this.selectBoxOptions.ariaLabel,
useShadows: false,
verticalScrollMode: ScrollbarVisibility.Visible,
keyboardSupport: false,
mouseSupport: false
mouseSupport: false,
accessibilityProvider: {
getAriaLabel: (element) => element.text,
getWidgetAriaLabel: () => localize('selectBox', "Select Box"),
getRole: () => 'option',
getWidgetRole: () => 'listbox'
}
});
if (this.selectBoxOptions.ariaLabel) {
this.selectList.ariaLabel = this.selectBoxOptions.ariaLabel;
}
// SetUp list keyboard controller - control navigation, disabled items, focus
const onSelectDropDownKeyDown = Event.chain(domEvent(this.selectDropDownListContainer, 'keydown'))

View File

@@ -236,6 +236,7 @@ export abstract class Pane extends Disposable implements IView {
const height = this._orientation === Orientation.VERTICAL ? size - headerSize : this.orthogonalSize - headerSize;
if (this.isExpanded()) {
toggleClass(this.body, 'wide', width >= 600);
this.layoutBody(height, width);
this.expandedSize = size;
}

View File

@@ -12,9 +12,12 @@ import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { withNullAsUndefined } from 'vs/base/common/types';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
export const CONTEXT = 'context.toolbar';
const toolBarMoreIcon = registerIcon('toolbar-more', Codicon.more);
export interface IToolBarOptions {
orientation?: ActionsOrientation;
actionViewItemProvider?: IActionViewItemProvider;
@@ -65,7 +68,7 @@ export class ToolBar extends Disposable {
this.options.actionViewItemProvider,
this.actionRunner,
this.options.getKeyBinding,
'codicon-more',
toolBarMoreIcon.classNames,
this.options.anchorAlignmentProvider
);
this.toggleMenuActionViewItem.value.setActionContext(this.actionBar.context);

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/tree';
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/listWidget';
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate, ListAriaRootRole } from 'vs/base/browser/ui/list/list';
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list';
import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode, addClasses, removeClasses } from 'vs/base/browser/dom';
import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -26,6 +26,7 @@ import { values } from 'vs/base/common/map';
import { clamp } from 'vs/base/common/numbers';
import { ScrollEvent } from 'vs/base/common/scrollable';
import { SetMap } from 'vs/base/common/collections';
import { treeItemExpandedIcon, treeFilterOnTypeOnIcon, treeFilterOnTypeOffIcon, treeFilterClearIcon } from 'vs/base/browser/ui/tree/treeIcons';
class TreeElementsDragAndDropData<T, TFilterData, TContext> extends ElementsDragAndDropData<T, TContext> {
@@ -162,9 +163,30 @@ function asListOptions<T, TFilterData, TRef>(modelProvider: () => ITreeModel<T,
},
accessibilityProvider: options.accessibilityProvider && {
...options.accessibilityProvider,
getSetSize(node) {
const model = modelProvider();
const ref = model.getNodeLocation(node);
const parentRef = model.getParentNodeLocation(ref);
const parentNode = model.getNode(parentRef);
return parentNode.visibleChildrenCount;
},
getPosInSet(node) {
return node.visibleChildIndex + 1;
},
isChecked: options.accessibilityProvider && options.accessibilityProvider.isChecked ? (node) => {
return options.accessibilityProvider!.isChecked!(node.element);
} : undefined,
getRole: options.accessibilityProvider && options.accessibilityProvider.getRole ? (node) => {
return options.accessibilityProvider!.getRole!(node.element);
} : () => 'treeitem',
getAriaLabel(e) {
return options.accessibilityProvider!.getAriaLabel(e.element);
},
getWidgetAriaLabel() {
return options.accessibilityProvider!.getWidgetAriaLabel();
},
getWidgetRole: options.accessibilityProvider && options.accessibilityProvider.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',
getAriaLevel(node) {
return node.depth;
},
@@ -178,27 +200,7 @@ function asListOptions<T, TFilterData, TRef>(modelProvider: () => ITreeModel<T,
return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(node.element);
}
},
enableKeyboardNavigation: options.simpleKeyboardNavigation,
ariaProvider: {
getSetSize(node) {
const model = modelProvider();
const ref = model.getNodeLocation(node);
const parentRef = model.getParentNodeLocation(ref);
const parentNode = model.getNode(parentRef);
return parentNode.visibleChildrenCount;
},
getPosInSet(node) {
return node.visibleChildIndex + 1;
},
isChecked: options.ariaProvider && options.ariaProvider.isChecked ? (node) => {
return options.ariaProvider!.isChecked!(node.element);
} : undefined,
getRole: options.ariaProvider && options.ariaProvider.getRole ? (node) => {
return options.ariaProvider!.getRole!(node.element);
} : () => 'treeitem'
},
ariaRole: ListAriaRootRole.TREE
enableKeyboardNavigation: options.simpleKeyboardNavigation
};
}
@@ -404,10 +406,10 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
}
if (node.collapsible && (!this.hideTwistiesOfChildlessElements || node.visibleChildrenCount > 0)) {
addClasses(templateData.twistie, 'codicon', 'codicon-chevron-down', 'collapsible');
addClasses(templateData.twistie, treeItemExpandedIcon.classNames, 'collapsible');
toggleClass(templateData.twistie, 'collapsed', node.collapsed);
} else {
removeClasses(templateData.twistie, 'codicon', 'codicon-chevron-down', 'collapsible', 'collapsed');
removeClasses(templateData.twistie, treeItemExpandedIcon.classNames, 'collapsible', 'collapsed');
}
if (node.collapsible) {
@@ -645,14 +647,14 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
const controls = append(this.domNode, $('.controls'));
this._filterOnType = !!tree.options.filterOnType;
this.filterOnTypeDomNode = append(controls, $<HTMLInputElement>('input.filter.codicon.codicon-list-selection'));
this.filterOnTypeDomNode = append(controls, $<HTMLInputElement>('input.filter'));
this.filterOnTypeDomNode.type = 'checkbox';
this.filterOnTypeDomNode.checked = this._filterOnType;
this.filterOnTypeDomNode.tabIndex = -1;
this.updateFilterOnTypeTitle();
this.updateFilterOnTypeTitleAndIcon();
domEvent(this.filterOnTypeDomNode, 'input')(this.onDidChangeFilterOnType, this, this.disposables);
this.clearDomNode = append(controls, $<HTMLInputElement>('button.clear.codicon.codicon-close'));
this.clearDomNode = append(controls, $<HTMLInputElement>('button.clear' + treeFilterClearIcon.cssSelector));
this.clearDomNode.tabIndex = -1;
this.clearDomNode.title = localize('clear', "Clear");
@@ -858,13 +860,17 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
this.tree.refilter();
this.tree.domFocus();
this.render();
this.updateFilterOnTypeTitle();
this.updateFilterOnTypeTitleAndIcon();
}
private updateFilterOnTypeTitle(): void {
private updateFilterOnTypeTitleAndIcon(): void {
if (this.filterOnType) {
removeClasses(this.filterOnTypeDomNode, treeFilterOnTypeOffIcon.classNames);
addClasses(this.filterOnTypeDomNode, treeFilterOnTypeOnIcon.classNames);
this.filterOnTypeDomNode.title = localize('disable filter on type', "Disable Filter on Type");
} else {
removeClasses(this.filterOnTypeDomNode, treeFilterOnTypeOnIcon.classNames);
addClasses(this.filterOnTypeDomNode, treeFilterOnTypeOffIcon.classNames);
this.filterOnTypeDomNode.title = localize('enable filter on type', "Enable Filter on Type");
}
}
@@ -1445,6 +1451,14 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
return node.element;
}
get ariaLabel(): string {
return this.view.ariaLabel;
}
set ariaLabel(value: string) {
this.view.ariaLabel = value;
}
domFocus(): void {
this.view.domFocus();
}

View File

@@ -5,7 +5,7 @@
import { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';
import { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree';
import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole } from 'vs/base/browser/ui/list/list';
import { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list';
import { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper, ITreeFilter, TreeVisibility, TreeFilterResult } from 'vs/base/browser/ui/tree/tree';
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
@@ -15,12 +15,13 @@ import { Iterable } from 'vs/base/common/iterator';
import { IDragAndDropData } from 'vs/base/browser/dnd';
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
import { toggleClass } from 'vs/base/browser/dom';
import { removeClasses, addClasses } from 'vs/base/browser/dom';
import { values } from 'vs/base/common/map';
import { ScrollEvent } from 'vs/base/common/scrollable';
import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
import { IThemable } from 'vs/base/common/styler';
import { isFilterResult, getVisibleState } from 'vs/base/browser/ui/tree/indexTreeModel';
import { treeItemLoadingIcon } from 'vs/base/browser/ui/tree/treeIcons';
interface IAsyncDataTreeNode<TInput, T> {
element: TInput | T;
@@ -109,7 +110,11 @@ class AsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements IT
}
renderTwistie(element: IAsyncDataTreeNode<TInput, T>, twistieElement: HTMLElement): boolean {
toggleClass(twistieElement, 'codicon-loading', element.slow);
if (element.slow) {
addClasses(twistieElement, treeItemLoadingIcon.classNames);
} else {
removeClasses(twistieElement, treeItemLoadingIcon.classNames);
}
return false;
}
@@ -231,9 +236,21 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
},
accessibilityProvider: options.accessibilityProvider && {
...options.accessibilityProvider,
getPosInSet: undefined,
getSetSize: undefined,
getRole: options.accessibilityProvider!.getRole ? (el) => {
return options.accessibilityProvider!.getRole!(el.element as T);
} : () => 'treeitem',
isChecked: options.accessibilityProvider!.isChecked ? (e) => {
return !!(options.accessibilityProvider?.isChecked!(e.element as T));
} : undefined,
getAriaLabel(e) {
return options.accessibilityProvider!.getAriaLabel(e.element as T);
},
getWidgetAriaLabel() {
return options.accessibilityProvider!.getWidgetAriaLabel();
},
getWidgetRole: options.accessibilityProvider!.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',
getAriaLevel: options.accessibilityProvider!.getAriaLevel && (node => {
return options.accessibilityProvider!.getAriaLevel!(node.element as T);
}),
@@ -258,21 +275,6 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
e => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T)
)
),
ariaProvider: options.ariaProvider && {
getPosInSet(el, index) {
return options.ariaProvider!.getPosInSet(el.element as T, index);
},
getSetSize(el, index, listLength) {
return options.ariaProvider!.getSetSize(el.element as T, index, listLength);
},
getRole: options.ariaProvider!.getRole ? (el) => {
return options.ariaProvider!.getRole!(el.element as T);
} : () => 'treeitem',
isChecked: options.ariaProvider!.isChecked ? (e) => {
return !!(options.ariaProvider?.isChecked!(e.element as T));
} : undefined
},
ariaRole: ListAriaRootRole.TREE,
additionalScrollHeight: options.additionalScrollHeight
};
}
@@ -448,6 +450,14 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
return this.tree.lastVisibleElement!.element as T;
}
get ariaLabel(): string {
return this.tree.ariaLabel;
}
set ariaLabel(value: string) {
this.tree.ariaLabel = value;
}
domFocus(): void {
this.tree.domFocus();
}
@@ -1044,7 +1054,11 @@ class CompressibleAsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> i
}
renderTwistie(element: IAsyncDataTreeNode<TInput, T>, twistieElement: HTMLElement): boolean {
toggleClass(twistieElement, 'codicon-loading', element.slow);
if (element.slow) {
addClasses(twistieElement, treeItemLoadingIcon.classNames);
} else {
removeClasses(twistieElement, treeItemLoadingIcon.classNames);
}
return false;
}

View File

@@ -60,6 +60,6 @@
transform: rotate(-90deg);
}
.monaco-tl-twistie.codicon-loading::before {
.monaco-tl-twistie.codicon-tree-item-loading::before {
animation: codicon-spin 1.25s linear infinite;
}

View File

@@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Codicon, registerIcon } from 'vs/base/common/codicons';
export const treeItemExpandedIcon = registerIcon('tree-item-expanded', Codicon.chevronDown); // collapsed is done with rotation
export const treeFilterOnTypeOnIcon = registerIcon('tree-filter-on-type-on', Codicon.listFilter);
export const treeFilterOnTypeOffIcon = registerIcon('tree-filter-on-type-off', Codicon.listSelection);
export const treeFilterClearIcon = registerIcon('tree-filter-clear', Codicon.close);
export const treeItemLoadingIcon = registerIcon('tree-item-loading', Codicon.loading);