listbox and select box (#23504)

* listbox

* select box

* fix tests

* one more test
This commit is contained in:
Alan Ren
2023-06-28 11:20:31 -07:00
committed by GitHub
parent e52aa01cf0
commit 6dc1b9b905
31 changed files with 159 additions and 414 deletions

View File

@@ -3,8 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SelectBox, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
import { Color } from 'vs/base/common/color';
import { SelectBox, ISelectOptionItem, ISelectBoxStyles } from 'vs/base/browser/ui/selectBox/selectBox';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import * as dom from 'vs/base/browser/dom';
@@ -12,40 +11,26 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { Emitter } from 'vs/base/common/event';
import { renderFormattedText, renderText, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer';
import { defaultSelectBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
const $ = dom.$;
export interface IListBoxStyles {
selectBackground?: Color;
selectForeground?: Color;
selectBorder?: Color;
inputValidationInfoBorder?: Color;
inputValidationInfoBackground?: Color;
inputValidationWarningBorder?: Color;
inputValidationWarningBackground?: Color;
inputValidationErrorBorder?: Color;
inputValidationErrorBackground?: Color;
export interface IListBoxStyles extends ISelectBoxStyles {
inputValidationInfoBorder: string | undefined;
inputValidationInfoBackground: string | undefined;
inputValidationWarningBorder: string | undefined;
inputValidationWarningBackground: string | undefined;
inputValidationErrorBorder: string | undefined;
inputValidationErrorBackground: string | undefined;
}
export interface IListBoxOptions extends Partial<IListBoxStyles> {
items: ISelectOptionItem[];
}
/*
* Extends SelectBox to allow multiple selection and adding/remove items dynamically
*/
export class ListBox extends SelectBox {
// private enabledSelectBackground?: Color;
// private enabledSelectForeground?: Color;
// private enabledSelectBorder?: Color;
// private disabledSelectBackground?: Color;
// private disabledSelectForeground?: Color;
// private disabledSelectBorder?: Color;
private inputValidationInfoBorder?: Color;
private inputValidationInfoBackground?: Color;
private inputValidationWarningBorder?: Color;
private inputValidationWarningBackground?: Color;
private inputValidationErrorBorder?: Color;
private inputValidationErrorBackground?: Color;
private message?: IMessage;
private contextViewProvider: IContextViewProvider;
private isValid: boolean;
@@ -53,11 +38,10 @@ export class ListBox extends SelectBox {
private _onKeyDown = new Emitter<StandardKeyboardEvent>();
public readonly onKeyDown = this._onKeyDown.event;
constructor(
private options: ISelectOptionItem[],
constructor(private readonly options: IListBoxOptions,
contextViewProvider: IContextViewProvider) {
super(options, 0, contextViewProvider, defaultSelectBoxStyles);
super(options.items, 0, contextViewProvider, <ISelectBoxStyles>options);
this.contextViewProvider = contextViewProvider;
this.isValid = true;
this.selectElement.multiple = true;
@@ -78,53 +62,20 @@ export class ListBox extends SelectBox {
this.selectElement.focus();
}));
// this.enabledSelectBackground = this.selectBackground;
// this.enabledSelectForeground = this.selectForeground;
// this.enabledSelectBorder = this.selectBorder;
//this.disabledSelectBackground = Color.transparent;
// this.inputValidationInfoBorder = defaultOpts.inputValidationInfoBorder;
// this.inputValidationInfoBackground = defaultOpts.inputValidationInfoBackground;
// this.inputValidationWarningBorder = defaultOpts.inputValidationWarningBorder;
// this.inputValidationWarningBackground = defaultOpts.inputValidationWarningBackground;
// this.inputValidationErrorBorder = defaultOpts.inputValidationErrorBorder;
// this.inputValidationErrorBackground = defaultOpts.inputValidationErrorBackground;
this.onblur(this.selectElement, () => this.onBlur());
this.onfocus(this.selectElement, () => this.onFocus());
}
// {{SQL CARBON TODO}} - apply styles
public style(styles: IListBoxStyles): void {
// let superStyle: ISelectBoxStyles = {
// selectBackground: styles.selectBackground,
// selectForeground: styles.selectForeground,
// selectBorder: styles.selectBorder
// };
// super.style(superStyle);
// this.enabledSelectBackground = this.selectBackground;
// this.enabledSelectForeground = this.selectForeground;
// this.enabledSelectBorder = this.selectBorder;
// this.inputValidationInfoBackground = styles.inputValidationInfoBackground;
// this.inputValidationInfoBorder = styles.inputValidationInfoBorder;
// this.inputValidationWarningBackground = styles.inputValidationWarningBackground;
// this.inputValidationWarningBorder = styles.inputValidationWarningBorder;
// this.inputValidationErrorBackground = styles.inputValidationErrorBackground;
// this.inputValidationErrorBorder = styles.inputValidationErrorBorder;
}
public setValidation(isValid: boolean, message?: IMessage): void {
this.isValid = isValid;
this.message = message;
// {{SQL CARBON TODO}} - apply styles
// if (this.isValid) {
// this.selectElement.style.border = `1px solid ${this.selectBorder}`;
// } else if (this.message) {
// const styles = this.stylesForType(this.message.type);
// this.selectElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
// }
if (this.isValid) {
this.selectElement.style.border = `1px solid ${this.options.selectBorder}`;
} else if (this.message) {
const styles = this.stylesForType(this.message.type);
this.selectElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
}
}
public get isContentValid(): boolean {
@@ -153,9 +104,9 @@ export class ListBox extends SelectBox {
for (let i = 0; i < indexes.length; i++) {
this.selectElement.remove(indexes[i]);
this.options.splice(indexes[i], 1);
this.options.items.splice(indexes[i], 1);
}
super.setOptions(this.options);
super.setOptions(this.options.items);
}
public add(option: string): void {
@@ -163,29 +114,21 @@ export class ListBox extends SelectBox {
this.selectElement.add(optionObj);
// make sure that base options are updated since that is used in selection not selectElement
this.options.push(optionObj);
super.setOptions(this.options);
this.options.items.push(optionObj);
super.setOptions(this.options.items);
}
public override setOptions(options: ISelectOptionItem[], selected?: number): void {
this.options = options;
this.options.items = options;
super.setOptions(options, selected);
}
public enable(): void {
this.selectElement.disabled = false;
// this.selectBackground = this.enabledSelectBackground;
// this.selectForeground = this.enabledSelectForeground;
// this.selectBorder = this.enabledSelectBorder;
// this.applyStyles();
}
public disable(): void {
this.selectElement.disabled = true;
// this.selectBackground = this.disabledSelectBackground;
// this.selectForeground = this.disabledSelectForeground;
// this.selectBorder = this.disabledSelectBorder;
// this.applyStyles();
}
public onBlur(): void {
@@ -227,7 +170,7 @@ export class ListBox extends SelectBox {
spanElement.classList.add(this.classForType(this.message.type));
const styles = this.stylesForType(this.message.type);
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';
spanElement.style.backgroundColor = styles.background ? styles.background : '';
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
dom.append(div, spanElement);
@@ -247,11 +190,11 @@ export class ListBox extends SelectBox {
}
}
private stylesForType(type?: MessageType): { border?: Color; background?: Color } {
private stylesForType(type?: MessageType): { border: string | undefined; background: string | undefined } {
switch (type) {
case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground };
case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground };
default: return { border: this.inputValidationErrorBorder, background: this.inputValidationErrorBackground };
case MessageType.INFO: return { border: this.options.inputValidationInfoBorder, background: this.options.inputValidationInfoBackground };
case MessageType.WARNING: return { border: this.options.inputValidationWarningBorder, background: this.options.inputValidationWarningBackground };
default: return { border: this.options.inputValidationErrorBorder, background: this.options.inputValidationErrorBackground };
}
}
}

View File

@@ -6,7 +6,6 @@
import 'vs/css!./media/selectBox';
import { SelectBox as vsSelectBox, ISelectBoxStyles as vsISelectBoxStyles, ISelectBoxOptions, ISelectOptionItem, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
import { Color } from 'vs/base/common/color';
import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import * as dom from 'vs/base/browser/dom';
import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
@@ -18,7 +17,6 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { SelectBoxList } from 'vs/base/browser/ui/selectBox/selectBoxCustom';
import { Event, Emitter } from 'vs/base/common/event';
import { AdsWidget } from 'sql/base/browser/ui/adsWidget';
import { defaultSelectBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
const $ = dom.$;
@@ -28,17 +26,12 @@ export interface SelectOptionItemSQL extends ISelectOptionItem {
}
export interface ISelectBoxStyles extends vsISelectBoxStyles {
disabledSelectBackground?: Color;
disabledSelectForeground?: Color;
inputValidationInfoBorder?: Color;
inputValidationInfoBackground?: Color;
inputinputValidationInfoForeground?: Color;
inputValidationWarningBorder?: Color;
inputValidationWarningBackground?: Color;
inputValidationWarningForeground?: Color;
inputValidationErrorBorder?: Color;
inputValidationErrorBackground?: Color;
inputValidationErrorForeground?: Color;
inputValidationInfoBorder: string | undefined;
inputValidationInfoBackground: string | undefined;
inputValidationWarningBorder: string | undefined;
inputValidationWarningBackground: string | undefined;
inputValidationErrorBorder: string | undefined;
inputValidationErrorBackground: string | undefined;
}
export class SelectBox extends vsSelectBox implements AdsWidget {
@@ -46,32 +39,16 @@ export class SelectBox extends vsSelectBox implements AdsWidget {
private _dialogOptions: SelectOptionItemSQL[];
private _selectedOption: string;
private _selectBoxOptions?: ISelectBoxOptions;
// private enabledSelectBackground?: Color;
// private enabledSelectForeground?: Color;
// private enabledSelectBorder?: Color;
// private disabledSelectBackground?: Color;
// private disabledSelectForeground?: Color;
// private disabledSelectBorder?: Color;
private contextViewProvider: IContextViewProvider;
private message?: IMessage;
private _onDidSelect: Emitter<ISelectData>;
private _onDidFocus: Emitter<void>;
private inputValidationInfoBorder?: Color;
private inputValidationInfoBackground?: Color;
private inputValidationInfoForeground?: Color;
private inputValidationWarningBorder?: Color;
private inputValidationWarningBackground?: Color;
private inputValidationWarningForeground?: Color;
private inputValidationErrorBorder?: Color;
private inputValidationErrorBackground?: Color;
private inputValidationErrorForeground?: Color;
private element?: HTMLElement;
constructor(options: SelectOptionItemSQL[] | string[], selectedOption: string, contextViewProvider: IContextViewProvider, container?: HTMLElement, selectBoxOptions?: ISelectBoxOptions, id?: string) {
constructor(options: SelectOptionItemSQL[] | string[], selectedOption: string, private readonly _styles: ISelectBoxStyles, contextViewProvider: IContextViewProvider, container?: HTMLElement, selectBoxOptions?: ISelectBoxOptions, id?: string) {
let optionItems: SelectOptionItemSQL[] = SelectBox.createOptions(options);
super(optionItems, 0, contextViewProvider, defaultSelectBoxStyles, selectBoxOptions);
super(optionItems, 0, contextViewProvider, _styles, selectBoxOptions);
this._onDidSelect = new Emitter<ISelectData>();
this._onDidFocus = new Emitter<void>();
@@ -89,13 +66,6 @@ export class SelectBox extends vsSelectBox implements AdsWidget {
this._onDidSelect.fire(newSelect);
}));
// {{SQL CARBON TODO}} - fix styles
// this.enabledSelectBackground = this.selectBackground;
// this.enabledSelectForeground = this.selectForeground;
// this.enabledSelectBorder = this.selectBorder;
// this.disabledSelectBackground = Color.transparent;
// this.disabledSelectForeground = undefined;
// this.disabledSelectBorder = undefined;
this.contextViewProvider = contextViewProvider;
if (container) {
this.element = dom.append(container, $('.monaco-selectbox.idle'));
@@ -180,24 +150,6 @@ export class SelectBox extends vsSelectBox implements AdsWidget {
this._dialogOptions = options;
}
public style(styles: ISelectBoxStyles): void {
// this.enabledSelectBackground = this.selectBackground;
// this.enabledSelectForeground = this.selectForeground;
// this.enabledSelectBorder = this.selectBorder;
// this.disabledSelectBackground = styles.disabledSelectBackground;
// this.disabledSelectForeground = styles.disabledSelectForeground;
this.inputValidationInfoBorder = styles.inputValidationInfoBorder;
this.inputValidationInfoBackground = styles.inputValidationInfoBackground;
this.inputValidationInfoForeground = styles.inputinputValidationInfoForeground;
this.inputValidationWarningBorder = styles.inputValidationWarningBorder;
this.inputValidationWarningBackground = styles.inputValidationWarningBackground;
this.inputValidationWarningForeground = styles.inputValidationWarningForeground;
this.inputValidationErrorBorder = styles.inputValidationErrorBorder;
this.inputValidationErrorBackground = styles.inputValidationErrorBackground;
this.inputValidationErrorForeground = styles.inputValidationErrorForeground;
//this.applyStyles();
}
public selectWithOptionName(optionName?: string, selectFirstByDefault: boolean = true, forceSelectionEvent: boolean = false): void {
let option: number | undefined;
if (optionName !== undefined) {
@@ -245,18 +197,10 @@ export class SelectBox extends vsSelectBox implements AdsWidget {
public enable(): void {
this.selectElement.disabled = false;
// this.selectBackground = this.enabledSelectBackground;
// this.selectForeground = this.enabledSelectForeground;
// this.selectBorder = this.enabledSelectBorder;
//this.applyStyles();
}
public disable(): void {
this.selectElement.disabled = true;
// this.selectBackground = this.disabledSelectBackground;
// this.selectForeground = this.disabledSelectForeground;
// this.selectBorder = this.disabledSelectBorder;
//this.applyStyles();
}
public getAriaLabel(): string {
@@ -323,7 +267,7 @@ export class SelectBox extends vsSelectBox implements AdsWidget {
spanElement.classList.add(this.classForType(message.type));
const styles = this.stylesForType(message.type);
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';
spanElement.style.backgroundColor = styles.background ? styles.background : '';
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
dom.append(div, spanElement);
@@ -363,11 +307,11 @@ export class SelectBox extends vsSelectBox implements AdsWidget {
}
}
private stylesForType(type: MessageType | undefined): { border: Color | undefined; background: Color | undefined; foreground: Color | undefined } {
private stylesForType(type: MessageType | undefined): { border: string | undefined; background: string | undefined; } {
switch (type) {
case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground, foreground: this.inputValidationInfoForeground };
case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground, foreground: this.inputValidationWarningForeground };
default: return { border: this.inputValidationErrorBorder, background: this.inputValidationErrorBackground, foreground: this.inputValidationErrorForeground };
case MessageType.INFO: return { border: this._styles.inputValidationInfoBorder, background: this._styles.inputValidationInfoBackground };
case MessageType.WARNING: return { border: this._styles.inputValidationWarningBorder, background: this._styles.inputValidationWarningBackground };
default: return { border: this._styles.inputValidationErrorBorder, background: this._styles.inputValidationErrorBackground };
}
}

View File

@@ -12,7 +12,7 @@ import { Dropdown, IEditableDropdownStyles } from 'sql/base/browser/ui/editableD
import { Disposable } from 'vs/base/common/lifecycle';
import { defaultInputBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
import { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';
import { ISelectBoxStyles } from 'vs/base/browser/ui/selectBox/selectBox';
import { ISelectBoxStyles } from 'sql/base/browser/ui/selectBox/selectBox';
const InverseKeyCodeMap: { [k: string]: number } = Object.fromEntries(Object.entries(EVENT_KEY_CODE_MAP).map(([key, value]) => [value, Number(key)]));
@@ -169,7 +169,7 @@ export class TableCellEditorFactory {
await this.commitEdit();
});
} else {
this._component = new SelectBox([], undefined, self._contextViewProvider);
this._component = new SelectBox([], undefined, self._options.selectBoxStyles, self._contextViewProvider);
this._component.render(container);
this._component.selectElem.style.height = '100%';
this._component.onDidSelect(async () => {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { SelectBox, SelectOptionItemSQL } from 'sql/base/browser/ui/selectBox/selectBox';
import { ISelectBoxStyles, SelectBox, SelectOptionItemSQL } from 'sql/base/browser/ui/selectBox/selectBox';
import { deepClone, equals } from 'vs/base/common/objects';
const options: SelectOptionItemSQL[] = [
@@ -15,13 +15,13 @@ const options: SelectOptionItemSQL[] = [
suite('Select Box tests', () => {
test('default value', () => {
const sb = new SelectBox(options, options[1].value, undefined!, undefined!, undefined!);
const sb = new SelectBox(options, options[1].value, <ISelectBoxStyles>{}, undefined!, undefined!, undefined!);
assert(sb.value === options[1].value);
});
test('values change', () => {
const sb = new SelectBox(options, options[1].value, undefined!, undefined!, undefined!);
const sb = new SelectBox(options, options[1].value, <ISelectBoxStyles>{}, undefined!, undefined!, undefined!);
const newOptions = deepClone(options);
{
const moreOptions: SelectOptionItemSQL[] = [
@@ -37,7 +37,7 @@ suite('Select Box tests', () => {
});
test('the selected option changes', () => {
const sb = new SelectBox(options, options[1].value, undefined!, undefined!, undefined!);
const sb = new SelectBox(options, options[1].value, <ISelectBoxStyles>{}, undefined!, undefined!, undefined!);
sb.onSelect({
index: 0,
@@ -50,7 +50,7 @@ suite('Select Box tests', () => {
test('values get auto populated', () => {
const newOptions = deepClone(options).map(s => { return { text: s.text, value: s.text }; });
const sb = new SelectBox(newOptions, undefined!, undefined!, undefined!, undefined!);
const sb = new SelectBox(newOptions, undefined!, <ISelectBoxStyles>{}, undefined!, undefined!, undefined!);
assert(equals(sb.values, newOptions.map(s => s.text)));
});