restore focus on escape (#13285)

* restore focus on escape

* obtain focus on action click

* comment

* comment 2

* simplify the implementation

* remove the toggle action completely

* remove the import

* implement aria requirements
This commit is contained in:
Alan Ren
2020-11-10 11:31:53 -08:00
committed by GitHub
parent fbe8e9d9f3
commit e076062d4f

View File

@@ -5,7 +5,6 @@
import 'vs/css!./media/dropdownList'; import 'vs/css!./media/dropdownList';
import { ToggleDropdownAction } from './actions';
import { DropdownDataSource, DropdownFilter, DropdownModel, DropdownRenderer, DropdownController } from './dropdownTree'; import { DropdownDataSource, DropdownFilter, DropdownModel, DropdownRenderer, DropdownController } from './dropdownTree';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
@@ -82,7 +81,6 @@ export class Dropdown extends Disposable {
private _input: InputBox; private _input: InputBox;
private _tree: ITree; private _tree: ITree;
private _options: IDropdownOptions; private _options: IDropdownOptions;
private _toggleAction: ToggleDropdownAction;
private _dataSource = new DropdownDataSource(); private _dataSource = new DropdownDataSource();
private _filter = new DropdownFilter(); private _filter = new DropdownFilter();
private _renderer = new DropdownRenderer(); private _renderer = new DropdownRenderer();
@@ -114,16 +112,10 @@ export class Dropdown extends Disposable {
this._el = DOM.append(container, DOM.$('.monaco-dropdown')); this._el = DOM.append(container, DOM.$('.monaco-dropdown'));
this._el.style.width = '100%'; this._el.style.width = '100%';
this._inputContainer = DOM.append(this._el, DOM.$('.dropdown-input')); this._inputContainer = DOM.append(this._el, DOM.$('.dropdown-input.select-container'));
this._inputContainer.style.width = '100%'; this._inputContainer.style.width = '100%';
this._treeContainer = DOM.$('.dropdown-tree'); this._treeContainer = DOM.$('.dropdown-tree');
this._toggleAction = new ToggleDropdownAction(() => {
this._showList();
this._tree.domFocus();
this._tree.focusFirst();
}, this._options.actionLabel);
this._input = new InputBox(this._inputContainer, contextViewService, { this._input = new InputBox(this._inputContainer, contextViewService, {
validationOptions: { validationOptions: {
// @SQLTODO // @SQLTODO
@@ -131,7 +123,6 @@ export class Dropdown extends Disposable {
validation: v => this._inputValidator(v) validation: v => this._inputValidator(v)
}, },
placeholder: this._options.placeholder, placeholder: this._options.placeholder,
actions: [this._toggleAction],
ariaLabel: this._options.ariaLabel ariaLabel: this._options.ariaLabel
}); });
@@ -139,6 +130,8 @@ export class Dropdown extends Disposable {
// in the text box - we already have tooltips for each item in the dropdown itself. // in the text box - we already have tooltips for each item in the dropdown itself.
this._input.inputElement.title = ''; this._input.inputElement.title = '';
this._inputContainer.setAttribute('role', 'combobox');
this._register(DOM.addDisposableListener(this._input.inputElement, DOM.EventType.CLICK, () => { this._register(DOM.addDisposableListener(this._input.inputElement, DOM.EventType.CLICK, () => {
this._showList(); this._showList();
})); }));
@@ -162,14 +155,14 @@ export class Dropdown extends Disposable {
if (this._treeContainer.parentElement) { if (this._treeContainer.parentElement) {
this._input.validate(); this._input.validate();
this._onBlur.fire(); this._onBlur.fire();
this.contextViewService.hideContextView(); this._hideList();
e.stopPropagation(); e.stopPropagation();
} }
break; break;
case KeyCode.Tab: case KeyCode.Tab:
this._input.validate(); this._input.validate();
this._onBlur.fire(); this._onBlur.fire();
this.contextViewService.hideContextView(); this._hideList();
e.stopPropagation(); e.stopPropagation();
break; break;
case KeyCode.DownArrow: case KeyCode.DownArrow:
@@ -205,12 +198,15 @@ export class Dropdown extends Disposable {
this.value = e.value; this.value = e.value;
this._onValueChange.fire(e.value); this._onValueChange.fire(e.value);
this._input.focus(); this._input.focus();
this.contextViewService.hideContextView(); this._hideList();
}); });
this._controller.onDropdownEscape(() => { this._controller.onDropdownEscape(() => {
this._hideList();
// have to put this in the setTimeout to make sure the focus can be set properly when the context menu is opened by pressing the DownArrow key
setTimeout(() => {
this._input.focus(); this._input.focus();
this.contextViewService.hideContextView(); }, 0);
}); });
this._input.onDidChange(e => { this._input.onDidChange(e => {
@@ -225,7 +221,7 @@ export class Dropdown extends Disposable {
}); });
this.onBlur(() => { this.onBlur(() => {
this.contextViewService.hideContextView(); this._hideList();
this._input.validate(); this._input.validate();
}); });
@@ -235,6 +231,7 @@ export class Dropdown extends Disposable {
private _showList(): void { private _showList(): void {
if (this._input.isEnabled()) { if (this._input.isEnabled()) {
this._inputContainer.setAttribute('aria-expanded', 'true');
this._onFocus.fire(); this._onFocus.fire();
this._filter.filterString = ''; this._filter.filterString = '';
this.contextViewService.showContextView({ this.contextViewService.showContextView({
@@ -250,10 +247,15 @@ export class Dropdown extends Disposable {
} }
}; };
} }
}); }, this._inputContainer);
} }
} }
private _hideList(): void {
this.contextViewService.hideContextView();
this._inputContainer.setAttribute('aria-expanded', 'false');
}
private _layoutTree(): void { private _layoutTree(): void {
if (this._dataSource && this._dataSource.options && this._dataSource.options.length > 0) { if (this._dataSource && this._dataSource.options && this._dataSource.options.length > 0) {
let filteredLength = this._dataSource.options.reduce((p, i) => { let filteredLength = this._dataSource.options.reduce((p, i) => {
@@ -320,7 +322,7 @@ export class Dropdown extends Disposable {
public blur() { public blur() {
this._input.blur(); this._input.blur();
this.contextViewService.hideContextView(); this._hideList();
} }
style(style: IListStyles & IInputBoxStyles & IDropdownStyles) { style(style: IListStyles & IInputBoxStyles & IDropdownStyles) {
@@ -350,7 +352,6 @@ export class Dropdown extends Disposable {
public set enabled(val: boolean) { public set enabled(val: boolean) {
this._input.setEnabled(val); this._input.setEnabled(val);
this._toggleAction.enabled = val;
} }
public get enabled(): boolean { public get enabled(): boolean {