mirror of
https://github.com/coder/code-server.git
synced 2026-05-06 12:31:58 +02:00
Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
32
lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.css
Normal file
32
lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.css
Normal file
@@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-select-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/** Actions */
|
||||
|
||||
.monaco-action-bar .action-item.select-container {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .monaco-select-box {
|
||||
cursor: pointer;
|
||||
min-width: 110px;
|
||||
min-height: 18px;
|
||||
padding: 2px 23px 2px 8px;
|
||||
}
|
||||
|
||||
.mac .monaco-action-bar .action-item .monaco-select-box {
|
||||
font-size: 11px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
132
lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.ts
Normal file
132
lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./selectBox';
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
import { IContentActionHandler } from 'vs/base/browser/formattedTextRenderer';
|
||||
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IListStyles } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { SelectBoxNative } from 'vs/base/browser/ui/selectBox/selectBoxNative';
|
||||
import { SelectBoxList } from 'vs/base/browser/ui/selectBox/selectBoxCustom';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
|
||||
// Public SelectBox interface - Calls routed to appropriate select implementation class
|
||||
|
||||
export interface ISelectBoxDelegate extends IDisposable {
|
||||
|
||||
// Public SelectBox Interface
|
||||
readonly onDidSelect: Event<ISelectData>;
|
||||
setOptions(options: ISelectOptionItem[], selected?: number): void;
|
||||
select(index: number): void;
|
||||
setAriaLabel(label: string): void;
|
||||
focus(): void;
|
||||
blur(): void;
|
||||
|
||||
// Delegated Widget interface
|
||||
render(container: HTMLElement): void;
|
||||
style(styles: ISelectBoxStyles): void;
|
||||
applyStyles(): void;
|
||||
}
|
||||
|
||||
export interface ISelectBoxOptions {
|
||||
useCustomDrawn?: boolean;
|
||||
ariaLabel?: string;
|
||||
minBottomMargin?: number;
|
||||
optionsAsChildren?: boolean;
|
||||
}
|
||||
|
||||
// Utilize optionItem interface to capture all option parameters
|
||||
export interface ISelectOptionItem {
|
||||
text: string;
|
||||
decoratorRight?: string;
|
||||
description?: string;
|
||||
descriptionIsMarkdown?: boolean;
|
||||
descriptionMarkdownActionHandler?: IContentActionHandler;
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ISelectBoxStyles extends IListStyles {
|
||||
selectBackground?: Color;
|
||||
selectListBackground?: Color;
|
||||
selectForeground?: Color;
|
||||
decoratorRightForeground?: Color;
|
||||
selectBorder?: Color;
|
||||
selectListBorder?: Color;
|
||||
focusBorder?: Color;
|
||||
}
|
||||
|
||||
export const defaultStyles = {
|
||||
selectBackground: Color.fromHex('#3C3C3C'),
|
||||
selectForeground: Color.fromHex('#F0F0F0'),
|
||||
selectBorder: Color.fromHex('#3C3C3C')
|
||||
};
|
||||
|
||||
export interface ISelectData {
|
||||
selected: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export class SelectBox extends Widget implements ISelectBoxDelegate {
|
||||
private selectBoxDelegate: ISelectBoxDelegate;
|
||||
|
||||
constructor(options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles = deepClone(defaultStyles), selectBoxOptions?: ISelectBoxOptions) {
|
||||
super();
|
||||
|
||||
// Default to native SelectBox for OSX unless overridden
|
||||
if (isMacintosh && !selectBoxOptions?.useCustomDrawn) {
|
||||
this.selectBoxDelegate = new SelectBoxNative(options, selected, styles, selectBoxOptions);
|
||||
} else {
|
||||
this.selectBoxDelegate = new SelectBoxList(options, selected, contextViewProvider, styles, selectBoxOptions);
|
||||
}
|
||||
|
||||
this._register(this.selectBoxDelegate);
|
||||
}
|
||||
|
||||
// Public SelectBox Methods - routed through delegate interface
|
||||
|
||||
public get onDidSelect(): Event<ISelectData> {
|
||||
return this.selectBoxDelegate.onDidSelect;
|
||||
}
|
||||
|
||||
public setOptions(options: ISelectOptionItem[], selected?: number): void {
|
||||
this.selectBoxDelegate.setOptions(options, selected);
|
||||
}
|
||||
|
||||
public select(index: number): void {
|
||||
this.selectBoxDelegate.select(index);
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
this.selectBoxDelegate.setAriaLabel(label);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.selectBoxDelegate.focus();
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
this.selectBoxDelegate.blur();
|
||||
}
|
||||
|
||||
// Public Widget Methods - routed through delegate interface
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
this.selectBoxDelegate.render(container);
|
||||
}
|
||||
|
||||
public style(styles: ISelectBoxStyles): void {
|
||||
this.selectBoxDelegate.style(styles);
|
||||
}
|
||||
|
||||
public applyStyles(): void {
|
||||
this.selectBoxDelegate.applyStyles();
|
||||
}
|
||||
}
|
||||
114
lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.css
Normal file
114
lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.css
Normal file
@@ -0,0 +1,114 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Use custom CSS vars to expose padding into parent select for padding calculation */
|
||||
.monaco-select-box-dropdown-padding {
|
||||
--dropdown-padding-top: 1px;
|
||||
--dropdown-padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.hc-black .monaco-select-box-dropdown-padding {
|
||||
--dropdown-padding-top: 3px;
|
||||
--dropdown-padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container {
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a:focus {
|
||||
outline: 1px solid -webkit-focus-ring-color;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown code {
|
||||
line-height: 15px; /** For some reason, this is needed, otherwise <code> will take up 20px height */
|
||||
font-family: var(--monaco-monospace-font);
|
||||
}
|
||||
|
||||
|
||||
.monaco-select-box-dropdown-container.visible {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
width: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-list-container {
|
||||
flex: 0 0 auto;
|
||||
align-self: flex-start;
|
||||
padding-top: var(--dropdown-padding-top);
|
||||
padding-bottom: var(--dropdown-padding-bottom);
|
||||
padding-left: 1px;
|
||||
padding-right: 1px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-details-pane {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.hc-black .monaco-select-box-dropdown-container > .select-box-dropdown-list-container {
|
||||
padding-top: var(--dropdown-padding-top);
|
||||
padding-bottom: var(--dropdown-padding-bottom);
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row > .option-text {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding-left: 3.5px;
|
||||
white-space: nowrap;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row > .option-decorator-right {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
/* Accepted CSS hiding technique for accessibility reader text */
|
||||
/* https://webaim.org/techniques/css/invisiblecontent/ */
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row > .visually-hidden {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
top: auto;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-container-width-control {
|
||||
flex: 1 1 auto;
|
||||
align-self: flex-start;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-container-width-control > .width-control-div {
|
||||
overflow: hidden;
|
||||
max-height: 0px;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-dropdown-container-width-control > .width-control-div > .option-text-width-control {
|
||||
padding-left: 4px;
|
||||
padding-right: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
1032
lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
Normal file
1032
lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
Normal file
File diff suppressed because it is too large
Load Diff
180
lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxNative.ts
Normal file
180
lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxNative.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxStyles, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { Gesture, EventType } from 'vs/base/browser/touch';
|
||||
|
||||
export class SelectBoxNative extends Disposable implements ISelectBoxDelegate {
|
||||
|
||||
private selectElement: HTMLSelectElement;
|
||||
private selectBoxOptions: ISelectBoxOptions;
|
||||
private options: ISelectOptionItem[];
|
||||
private selected = 0;
|
||||
private readonly _onDidSelect: Emitter<ISelectData>;
|
||||
private styles: ISelectBoxStyles;
|
||||
|
||||
constructor(options: ISelectOptionItem[], selected: number, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) {
|
||||
super();
|
||||
this.selectBoxOptions = selectBoxOptions || Object.create(null);
|
||||
|
||||
this.options = [];
|
||||
|
||||
this.selectElement = document.createElement('select');
|
||||
|
||||
this.selectElement.className = 'monaco-select-box';
|
||||
|
||||
if (typeof this.selectBoxOptions.ariaLabel === 'string') {
|
||||
this.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel);
|
||||
}
|
||||
|
||||
this._onDidSelect = this._register(new Emitter<ISelectData>());
|
||||
|
||||
this.styles = styles;
|
||||
|
||||
this.registerListeners();
|
||||
this.setOptions(options, selected);
|
||||
}
|
||||
|
||||
private registerListeners() {
|
||||
this._register(Gesture.addTarget(this.selectElement));
|
||||
[EventType.Tap].forEach(eventType => {
|
||||
this._register(dom.addDisposableListener(this.selectElement, eventType, (e) => {
|
||||
this.selectElement.focus();
|
||||
}));
|
||||
});
|
||||
|
||||
this._register(dom.addStandardDisposableListener(this.selectElement, 'click', (e) => {
|
||||
dom.EventHelper.stop(e, true);
|
||||
}));
|
||||
|
||||
this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => {
|
||||
this.selectElement.title = e.target.value;
|
||||
this._onDidSelect.fire({
|
||||
index: e.target.selectedIndex,
|
||||
selected: e.target.value
|
||||
});
|
||||
}));
|
||||
|
||||
this._register(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => {
|
||||
let showSelect = false;
|
||||
|
||||
if (isMacintosh) {
|
||||
if (e.keyCode === KeyCode.DownArrow || e.keyCode === KeyCode.UpArrow || e.keyCode === KeyCode.Space) {
|
||||
showSelect = true;
|
||||
}
|
||||
} else {
|
||||
if (e.keyCode === KeyCode.DownArrow && e.altKey || e.keyCode === KeyCode.Space || e.keyCode === KeyCode.Enter) {
|
||||
showSelect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (showSelect) {
|
||||
// Space, Enter, is used to expand select box, do not propagate it (prevent action bar action run)
|
||||
e.stopPropagation();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public get onDidSelect(): Event<ISelectData> {
|
||||
return this._onDidSelect.event;
|
||||
}
|
||||
|
||||
public setOptions(options: ISelectOptionItem[], selected?: number): void {
|
||||
|
||||
if (!this.options || !arrays.equals(this.options, options)) {
|
||||
this.options = options;
|
||||
this.selectElement.options.length = 0;
|
||||
|
||||
this.options.forEach((option, index) => {
|
||||
this.selectElement.add(this.createOption(option.text, index, option.isDisabled));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (selected !== undefined) {
|
||||
this.select(selected);
|
||||
}
|
||||
}
|
||||
|
||||
public select(index: number): void {
|
||||
if (this.options.length === 0) {
|
||||
this.selected = 0;
|
||||
} else if (index >= 0 && index < this.options.length) {
|
||||
this.selected = index;
|
||||
} else if (index > this.options.length - 1) {
|
||||
// Adjust index to end of list
|
||||
// This could make client out of sync with the select
|
||||
this.select(this.options.length - 1);
|
||||
} else if (this.selected < 0) {
|
||||
this.selected = 0;
|
||||
}
|
||||
|
||||
this.selectElement.selectedIndex = this.selected;
|
||||
if ((this.selected < this.options.length) && typeof this.options[this.selected].text === 'string') {
|
||||
this.selectElement.title = this.options[this.selected].text;
|
||||
} else {
|
||||
this.selectElement.title = '';
|
||||
}
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
this.selectBoxOptions.ariaLabel = label;
|
||||
this.selectElement.setAttribute('aria-label', label);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
if (this.selectElement) {
|
||||
this.selectElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
if (this.selectElement) {
|
||||
this.selectElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
container.classList.add('select-container');
|
||||
container.appendChild(this.selectElement);
|
||||
this.setOptions(this.options, this.selected);
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
public style(styles: ISelectBoxStyles): void {
|
||||
this.styles = styles;
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
public applyStyles(): void {
|
||||
|
||||
// Style native select
|
||||
if (this.selectElement) {
|
||||
const background = this.styles.selectBackground ? this.styles.selectBackground.toString() : '';
|
||||
const foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : '';
|
||||
const border = this.styles.selectBorder ? this.styles.selectBorder.toString() : '';
|
||||
|
||||
this.selectElement.style.backgroundColor = background;
|
||||
this.selectElement.style.color = foreground;
|
||||
this.selectElement.style.borderColor = border;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private createOption(value: string, index: number, disabled?: boolean): HTMLOptionElement {
|
||||
const option = document.createElement('option');
|
||||
option.value = value;
|
||||
option.text = value;
|
||||
option.disabled = !!disabled;
|
||||
|
||||
return option;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user