@vscode-elements/elements 1.16.1 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +1178 -565
- package/dist/bundled.js +731 -638
- package/dist/includes/VscElement.d.ts.map +1 -1
- package/dist/includes/VscElement.js +3 -1
- package/dist/includes/VscElement.js.map +1 -1
- package/dist/includes/vscode-select/OptionListController.d.ts +61 -0
- package/dist/includes/vscode-select/OptionListController.d.ts.map +1 -0
- package/dist/includes/vscode-select/OptionListController.js +373 -0
- package/dist/includes/vscode-select/OptionListController.js.map +1 -0
- package/dist/includes/vscode-select/helpers.d.ts +2 -2
- package/dist/includes/vscode-select/helpers.js.map +1 -1
- package/dist/includes/vscode-select/styles.d.ts.map +1 -1
- package/dist/includes/vscode-select/styles.js +28 -26
- package/dist/includes/vscode-select/styles.js.map +1 -1
- package/dist/includes/vscode-select/template-elements.d.ts +1 -0
- package/dist/includes/vscode-select/template-elements.d.ts.map +1 -1
- package/dist/includes/vscode-select/template-elements.js +14 -1
- package/dist/includes/vscode-select/template-elements.js.map +1 -1
- package/dist/includes/vscode-select/types.d.ts +11 -7
- package/dist/includes/vscode-select/types.d.ts.map +1 -1
- package/dist/includes/vscode-select/types.js.map +1 -1
- package/dist/includes/vscode-select/vscode-select-base.d.ts +26 -31
- package/dist/includes/vscode-select/vscode-select-base.d.ts.map +1 -1
- package/dist/includes/vscode-select/vscode-select-base.js +228 -325
- package/dist/includes/vscode-select/vscode-select-base.js.map +1 -1
- package/dist/vscode-button/vscode-button.styles.js +1 -1
- package/dist/vscode-button/vscode-button.styles.js.map +1 -1
- package/dist/vscode-button-group/vscode-button-group.styles.d.ts.map +1 -1
- package/dist/vscode-button-group/vscode-button-group.styles.js +2 -0
- package/dist/vscode-button-group/vscode-button-group.styles.js.map +1 -1
- package/dist/vscode-icon/vscode-icon.d.ts.map +1 -1
- package/dist/vscode-icon/vscode-icon.js +1 -0
- package/dist/vscode-icon/vscode-icon.js.map +1 -1
- package/dist/vscode-label/vscode-label.d.ts.map +1 -1
- package/dist/vscode-label/vscode-label.js +9 -7
- package/dist/vscode-label/vscode-label.js.map +1 -1
- package/dist/vscode-multi-select/vscode-multi-select.d.ts +9 -1
- package/dist/vscode-multi-select/vscode-multi-select.d.ts.map +1 -1
- package/dist/vscode-multi-select/vscode-multi-select.js +126 -66
- package/dist/vscode-multi-select/vscode-multi-select.js.map +1 -1
- package/dist/vscode-scrollable/vscode-scrollable.d.ts +57 -13
- package/dist/vscode-scrollable/vscode-scrollable.d.ts.map +1 -1
- package/dist/vscode-scrollable/vscode-scrollable.js +187 -82
- package/dist/vscode-scrollable/vscode-scrollable.js.map +1 -1
- package/dist/vscode-single-select/vscode-single-select.d.ts +4 -4
- package/dist/vscode-single-select/vscode-single-select.d.ts.map +1 -1
- package/dist/vscode-single-select/vscode-single-select.js +140 -74
- package/dist/vscode-single-select/vscode-single-select.js.map +1 -1
- package/package.json +7 -5
- package/vscode.css-custom-data.json +1 -5
- package/vscode.html-custom-data.json +51 -5
|
@@ -5,20 +5,34 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html, render, nothing } from 'lit';
|
|
8
|
-
import { property,
|
|
8
|
+
import { property, queryAssignedElements, state } from 'lit/decorators.js';
|
|
9
9
|
import { classMap } from 'lit/directives/class-map.js';
|
|
10
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
10
11
|
import { repeat } from 'lit/directives/repeat.js';
|
|
12
|
+
import { when } from 'lit/directives/when.js';
|
|
11
13
|
import '../../vscode-button/index.js';
|
|
12
14
|
import '../../vscode-option/index.js';
|
|
13
|
-
import {
|
|
15
|
+
import { stylePropertyMap } from '../style-property-map.js';
|
|
14
16
|
import { VscElement } from '../VscElement.js';
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
import { filterOptionsByPattern, highlightRanges } from './helpers.js';
|
|
18
|
+
import { OptionListController } from './OptionListController.js';
|
|
19
|
+
import { checkIcon } from './template-elements.js';
|
|
20
|
+
import '../../vscode-scrollable/vscode-scrollable.js';
|
|
21
|
+
export const VISIBLE_OPTS = 10;
|
|
22
|
+
export const OPT_HEIGHT = 22;
|
|
18
23
|
/**
|
|
19
24
|
* @cssprop --dropdown-z-index - workaround for dropdown z-index issues
|
|
20
25
|
*/
|
|
21
26
|
export class VscodeSelectBase extends VscElement {
|
|
27
|
+
/**
|
|
28
|
+
* Options can be filtered by typing into a text input field.
|
|
29
|
+
*/
|
|
30
|
+
set combobox(enabled) {
|
|
31
|
+
this._opts.comboboxMode = enabled;
|
|
32
|
+
}
|
|
33
|
+
get combobox() {
|
|
34
|
+
return this._opts.comboboxMode;
|
|
35
|
+
}
|
|
22
36
|
/**
|
|
23
37
|
* The element cannot be used and is not focusable.
|
|
24
38
|
*/
|
|
@@ -55,26 +69,31 @@ export class VscodeSelectBase extends VscElement {
|
|
|
55
69
|
'startsWith',
|
|
56
70
|
'startsWithPerTerm',
|
|
57
71
|
];
|
|
72
|
+
let fm;
|
|
58
73
|
if (validValues.includes(val)) {
|
|
59
|
-
this._filter = val;
|
|
74
|
+
// this._filter = val as FilterMethod;
|
|
75
|
+
fm = val;
|
|
60
76
|
}
|
|
61
77
|
else {
|
|
62
|
-
this._filter = 'fuzzy';
|
|
78
|
+
// this._filter = 'fuzzy';
|
|
79
|
+
// eslint-disable-next-line no-console
|
|
63
80
|
console.warn(`[VSCode Webview Elements] Invalid filter: "${val}", fallback to default. Valid values are: "contains", "fuzzy", "startsWith", "startsWithPerm".`, this);
|
|
81
|
+
fm = 'fuzzy';
|
|
64
82
|
}
|
|
83
|
+
this._opts.filterMethod = fm;
|
|
65
84
|
}
|
|
66
85
|
get filter() {
|
|
67
|
-
return this.
|
|
86
|
+
return this._opts.filterMethod;
|
|
68
87
|
}
|
|
69
88
|
/**
|
|
70
89
|
* @attr [options=[]]
|
|
71
90
|
* @type {Option[]}
|
|
72
91
|
*/
|
|
73
92
|
set options(opts) {
|
|
74
|
-
this.
|
|
93
|
+
this._opts.populate(opts);
|
|
75
94
|
}
|
|
76
95
|
get options() {
|
|
77
|
-
return this.
|
|
96
|
+
return this._opts.options.map(({ label, value, description, selected, disabled }) => ({
|
|
78
97
|
label,
|
|
79
98
|
value,
|
|
80
99
|
description,
|
|
@@ -84,13 +103,12 @@ export class VscodeSelectBase extends VscElement {
|
|
|
84
103
|
}
|
|
85
104
|
constructor() {
|
|
86
105
|
super();
|
|
87
|
-
/** @internal */
|
|
88
|
-
this.ariaExpanded = 'false';
|
|
89
106
|
this.creatable = false;
|
|
90
107
|
/**
|
|
91
|
-
*
|
|
108
|
+
* Accessible label for screen readers. When a `<vscode-label>` is connected
|
|
109
|
+
* to the component, it will be filled automatically.
|
|
92
110
|
*/
|
|
93
|
-
this.
|
|
111
|
+
this.label = '';
|
|
94
112
|
/**
|
|
95
113
|
* Sets the invalid state manually.
|
|
96
114
|
*/
|
|
@@ -107,29 +125,17 @@ export class VscodeSelectBase extends VscElement {
|
|
|
107
125
|
* Position of the options list when visible.
|
|
108
126
|
*/
|
|
109
127
|
this.position = 'below';
|
|
110
|
-
|
|
111
|
-
this.tabIndex = 0;
|
|
128
|
+
this._opts = new OptionListController(this);
|
|
112
129
|
this._firstUpdateCompleted = false;
|
|
113
|
-
this._activeIndex = -1;
|
|
114
130
|
this._currentDescription = '';
|
|
115
131
|
this._filter = 'fuzzy';
|
|
116
|
-
this._filterPattern = '';
|
|
117
|
-
this._selectedIndex = -1;
|
|
118
132
|
this._selectedIndexes = [];
|
|
119
133
|
this._options = [];
|
|
120
134
|
this._value = '';
|
|
121
135
|
this._values = [];
|
|
122
|
-
this._listScrollTop = 0;
|
|
123
136
|
this._isPlaceholderOptionActive = false;
|
|
124
137
|
this._isBeingFiltered = false;
|
|
125
|
-
|
|
126
|
-
this._multiple = false;
|
|
127
|
-
/**
|
|
128
|
-
* @internal
|
|
129
|
-
* Quick-searchable map for searching a value in the options list.
|
|
130
|
-
* Keys are the options values, values are the option indexes.
|
|
131
|
-
*/
|
|
132
|
-
this._valueOptionIndexMap = {};
|
|
138
|
+
this._optionListScrollPos = 0;
|
|
133
139
|
this._isHoverForbidden = false;
|
|
134
140
|
this._disabled = false;
|
|
135
141
|
this._originalTabIndex = undefined;
|
|
@@ -137,14 +143,16 @@ export class VscodeSelectBase extends VscElement {
|
|
|
137
143
|
const path = event.composedPath();
|
|
138
144
|
const found = path.findIndex((et) => et === this);
|
|
139
145
|
if (found === -1) {
|
|
140
|
-
this.
|
|
141
|
-
window.removeEventListener('click', this._onClickOutside);
|
|
146
|
+
this.open = false;
|
|
142
147
|
}
|
|
143
148
|
};
|
|
144
149
|
this._onMouseMove = () => {
|
|
145
150
|
this._isHoverForbidden = false;
|
|
146
151
|
window.removeEventListener('mousemove', this._onMouseMove);
|
|
147
152
|
};
|
|
153
|
+
this._onOptionListScroll = (ev) => {
|
|
154
|
+
this._optionListScrollPos = ev.detail;
|
|
155
|
+
};
|
|
148
156
|
this._onComponentKeyDown = (event) => {
|
|
149
157
|
if ([' ', 'ArrowUp', 'ArrowDown', 'Escape'].includes(event.key)) {
|
|
150
158
|
event.stopPropagation();
|
|
@@ -157,7 +165,7 @@ export class VscodeSelectBase extends VscElement {
|
|
|
157
165
|
this._onSpaceKeyDown();
|
|
158
166
|
}
|
|
159
167
|
if (event.key === 'Escape') {
|
|
160
|
-
this.
|
|
168
|
+
this._onEscapeKeyDown();
|
|
161
169
|
}
|
|
162
170
|
if (event.key === 'ArrowUp') {
|
|
163
171
|
this._onArrowUpKeyDown();
|
|
@@ -183,6 +191,7 @@ export class VscodeSelectBase extends VscElement {
|
|
|
183
191
|
this.addEventListener('keydown', this._onComponentKeyDown);
|
|
184
192
|
this.addEventListener('focus', this._onComponentFocus);
|
|
185
193
|
this.addEventListener('blur', this._onComponentBlur);
|
|
194
|
+
this._setAutoFocus();
|
|
186
195
|
}
|
|
187
196
|
disconnectedCallback() {
|
|
188
197
|
super.disconnectedCallback();
|
|
@@ -198,32 +207,59 @@ export class VscodeSelectBase extends VscElement {
|
|
|
198
207
|
this._manageRequired();
|
|
199
208
|
}
|
|
200
209
|
}
|
|
210
|
+
update(changedProperties) {
|
|
211
|
+
super.update(changedProperties);
|
|
212
|
+
if (changedProperties.has('open')) {
|
|
213
|
+
if (this.open) {
|
|
214
|
+
this._opts.activateDefault();
|
|
215
|
+
this._scrollActiveElementToTop();
|
|
216
|
+
window.addEventListener('click', this._onClickOutside);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
window.removeEventListener('click', this._onClickOutside);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
201
223
|
get _filteredOptions() {
|
|
202
|
-
if (!this.combobox || this.
|
|
224
|
+
if (!this.combobox || this._opts.filterPattern === '') {
|
|
203
225
|
return this._options;
|
|
204
226
|
}
|
|
205
|
-
return filterOptionsByPattern(this._options, this.
|
|
227
|
+
return filterOptionsByPattern(this._options, this._opts.filterPattern, this._filter);
|
|
206
228
|
}
|
|
207
|
-
|
|
208
|
-
|
|
229
|
+
_setAutoFocus() {
|
|
230
|
+
if (this.hasAttribute('autofocus')) {
|
|
231
|
+
if (this.tabIndex < 0) {
|
|
232
|
+
this.tabIndex = 0;
|
|
233
|
+
}
|
|
234
|
+
if (this.combobox) {
|
|
235
|
+
this.updateComplete.then(() => {
|
|
236
|
+
this.shadowRoot
|
|
237
|
+
?.querySelector('.combobox-input')
|
|
238
|
+
.focus();
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
this.updateComplete.then(() => {
|
|
243
|
+
this.shadowRoot
|
|
244
|
+
?.querySelector('.select-face')
|
|
245
|
+
.focus();
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
209
249
|
}
|
|
210
250
|
get _isSuggestedOptionVisible() {
|
|
211
251
|
if (!(this.combobox && this.creatable)) {
|
|
212
252
|
return false;
|
|
213
253
|
}
|
|
214
|
-
const filterPatternExistsAsOption =
|
|
215
|
-
const filtered = this.
|
|
254
|
+
const filterPatternExistsAsOption = this._opts.getOptionByValue(this._opts.filterPattern) !== null;
|
|
255
|
+
const filtered = this._opts.filterPattern.length > 0;
|
|
216
256
|
return !filterPatternExistsAsOption && filtered;
|
|
217
257
|
}
|
|
218
258
|
_manageRequired() { }
|
|
219
259
|
_setStateFromSlottedElements() {
|
|
220
|
-
const options = [];
|
|
221
|
-
let nextIndex = 0;
|
|
222
260
|
const optionElements = this._assignedOptions ?? [];
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
this._valueOptionIndexMap = {};
|
|
226
|
-
optionElements.forEach((el, i) => {
|
|
261
|
+
this._opts.clear();
|
|
262
|
+
optionElements.forEach((el) => {
|
|
227
263
|
const { innerText, description, disabled } = el;
|
|
228
264
|
const value = typeof el.value === 'string' ? el.value : innerText.trim();
|
|
229
265
|
const selected = el.selected ?? false;
|
|
@@ -232,93 +268,61 @@ export class VscodeSelectBase extends VscElement {
|
|
|
232
268
|
value,
|
|
233
269
|
description,
|
|
234
270
|
selected,
|
|
235
|
-
index: nextIndex,
|
|
236
271
|
disabled,
|
|
237
272
|
};
|
|
238
|
-
|
|
239
|
-
if (selected && !this._multiple) {
|
|
240
|
-
this._activeIndex = i;
|
|
241
|
-
}
|
|
242
|
-
if (selected) {
|
|
243
|
-
selectedIndexes.push(options.length - 1);
|
|
244
|
-
values.push(value);
|
|
245
|
-
}
|
|
246
|
-
this._valueOptionIndexMap[op.value] = op.index;
|
|
273
|
+
this._opts.add(op);
|
|
247
274
|
});
|
|
248
|
-
this._options = options;
|
|
249
|
-
if (selectedIndexes.length > 0) {
|
|
250
|
-
this._selectedIndex = selectedIndexes[0];
|
|
251
|
-
this._selectedIndexes = selectedIndexes;
|
|
252
|
-
this._value = values[0];
|
|
253
|
-
this._values = values;
|
|
254
|
-
}
|
|
255
|
-
if (!this._multiple && !this.combobox && selectedIndexes.length === 0) {
|
|
256
|
-
this._selectedIndex = this._options.length > 0 ? 0 : -1;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async _toggleDropdown(visible) {
|
|
260
|
-
this.open = visible;
|
|
261
|
-
this.ariaExpanded = String(visible);
|
|
262
|
-
if (visible && !this._multiple) {
|
|
263
|
-
this._activeIndex = this._selectedIndex;
|
|
264
|
-
}
|
|
265
|
-
if (visible && !this._multiple && !this.combobox) {
|
|
266
|
-
this._activeIndex = this._selectedIndex;
|
|
267
|
-
if (this._activeIndex > VISIBLE_OPTS - 1) {
|
|
268
|
-
await this.updateComplete;
|
|
269
|
-
this._listElement.scrollTop = Math.floor(this._activeIndex * OPT_HEIGHT);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (visible) {
|
|
273
|
-
window.addEventListener('click', this._onClickOutside);
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
window.removeEventListener('click', this._onClickOutside);
|
|
277
|
-
}
|
|
278
275
|
}
|
|
279
276
|
_createSuggestedOption() {
|
|
280
|
-
const nextSelectedIndex = this.
|
|
277
|
+
const nextSelectedIndex = this._opts.numOptions;
|
|
281
278
|
const op = document.createElement('vscode-option');
|
|
282
|
-
op.value = this.
|
|
283
|
-
render(this.
|
|
279
|
+
op.value = this._opts.filterPattern;
|
|
280
|
+
render(this._opts.filterPattern, op);
|
|
284
281
|
this.appendChild(op);
|
|
285
282
|
return nextSelectedIndex;
|
|
286
283
|
}
|
|
287
284
|
_dispatchChangeEvent() {
|
|
288
|
-
if (!this._multiple) {
|
|
289
|
-
/** @deprecated */
|
|
290
|
-
this.dispatchEvent(new CustomEvent('vsc-change', {
|
|
291
|
-
detail: {
|
|
292
|
-
selectedIndex: this._selectedIndex,
|
|
293
|
-
value: this._value,
|
|
294
|
-
},
|
|
295
|
-
}));
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
/** @deprecated */
|
|
299
|
-
this.dispatchEvent(new CustomEvent('vsc-change', {
|
|
300
|
-
detail: {
|
|
301
|
-
selectedIndexes: this._selectedIndexes,
|
|
302
|
-
value: this._values,
|
|
303
|
-
},
|
|
304
|
-
}));
|
|
305
|
-
}
|
|
306
285
|
this.dispatchEvent(new Event('change'));
|
|
307
286
|
this.dispatchEvent(new Event('input'));
|
|
308
287
|
}
|
|
309
288
|
async _createAndSelectSuggestedOption() { }
|
|
310
|
-
_onFaceClick() {
|
|
311
|
-
this._toggleDropdown(!this.open);
|
|
312
|
-
if (this._multiple) {
|
|
313
|
-
this._activeIndex = 0;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
289
|
_toggleComboboxDropdown() {
|
|
317
|
-
this.
|
|
318
|
-
this.
|
|
319
|
-
|
|
320
|
-
|
|
290
|
+
this._opts.filterPattern = '';
|
|
291
|
+
this.open = !this.open;
|
|
292
|
+
}
|
|
293
|
+
_scrollActiveElementToTop() {
|
|
294
|
+
this._optionListScrollPos = Math.floor(this._opts.relativeActiveIndex * OPT_HEIGHT);
|
|
295
|
+
}
|
|
296
|
+
async _adjustOptionListScrollPos(direction, optionIndex) {
|
|
297
|
+
let numOpts = this._opts.numOfVisibleOptions;
|
|
298
|
+
const suggestedOptionVisible = this._isSuggestedOptionVisible;
|
|
299
|
+
if (suggestedOptionVisible) {
|
|
300
|
+
numOpts += 1;
|
|
301
|
+
}
|
|
302
|
+
if (numOpts <= VISIBLE_OPTS) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
this._isHoverForbidden = true;
|
|
306
|
+
window.addEventListener('mousemove', this._onMouseMove);
|
|
307
|
+
const ulScrollTop = this._optionListScrollPos;
|
|
308
|
+
const liPosY = optionIndex * OPT_HEIGHT;
|
|
309
|
+
const fullyVisible = liPosY >= ulScrollTop &&
|
|
310
|
+
liPosY <= ulScrollTop + VISIBLE_OPTS * OPT_HEIGHT - OPT_HEIGHT;
|
|
311
|
+
if (direction === 'down') {
|
|
312
|
+
if (!fullyVisible) {
|
|
313
|
+
this._optionListScrollPos =
|
|
314
|
+
optionIndex * OPT_HEIGHT - (VISIBLE_OPTS - 1) * OPT_HEIGHT;
|
|
315
|
+
}
|
|
321
316
|
}
|
|
317
|
+
if (direction === 'up') {
|
|
318
|
+
if (!fullyVisible) {
|
|
319
|
+
this._optionListScrollPos = Math.floor(this._opts.relativeActiveIndex * OPT_HEIGHT);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//#region event handlers
|
|
324
|
+
_onFaceClick() {
|
|
325
|
+
this.open = !this.open;
|
|
322
326
|
}
|
|
323
327
|
_onComboboxButtonClick() {
|
|
324
328
|
this._toggleComboboxDropdown();
|
|
@@ -338,11 +342,11 @@ export class VscodeSelectBase extends VscElement {
|
|
|
338
342
|
}
|
|
339
343
|
if (el.matches('.placeholder')) {
|
|
340
344
|
this._isPlaceholderOptionActive = true;
|
|
341
|
-
this.
|
|
345
|
+
this._opts.activeIndex = -1;
|
|
342
346
|
}
|
|
343
347
|
else {
|
|
344
348
|
this._isPlaceholderOptionActive = false;
|
|
345
|
-
this.
|
|
349
|
+
this._opts.activeIndex = +el.dataset.index;
|
|
346
350
|
}
|
|
347
351
|
}
|
|
348
352
|
_onPlaceholderOptionMouseOut() {
|
|
@@ -363,143 +367,70 @@ export class VscodeSelectBase extends VscElement {
|
|
|
363
367
|
if (clickedOnAcceptButton) {
|
|
364
368
|
return;
|
|
365
369
|
}
|
|
366
|
-
const list = this.combobox ? this._filteredOptions : this._options;
|
|
367
|
-
const showDropdownNext = !this.open;
|
|
368
|
-
this._toggleDropdown(showDropdownNext);
|
|
369
|
-
if (!this._multiple &&
|
|
370
|
-
!showDropdownNext &&
|
|
371
|
-
this._selectedIndex !== this._activeIndex) {
|
|
372
|
-
this._selectedIndex =
|
|
373
|
-
this._activeIndex > -1 ? list[this._activeIndex].index : -1;
|
|
374
|
-
this._value =
|
|
375
|
-
this._selectedIndex > -1
|
|
376
|
-
? this._options[this._selectedIndex].value
|
|
377
|
-
: '';
|
|
378
|
-
this._dispatchChangeEvent();
|
|
379
|
-
}
|
|
380
|
-
if (this.combobox) {
|
|
381
|
-
if (this._isPlaceholderOptionActive) {
|
|
382
|
-
this._createAndSelectSuggestedOption();
|
|
383
|
-
}
|
|
384
|
-
else {
|
|
385
|
-
if (!this._multiple && !showDropdownNext) {
|
|
386
|
-
this._selectedIndex =
|
|
387
|
-
this._activeIndex > -1
|
|
388
|
-
? this._filteredOptions[this._activeIndex].index
|
|
389
|
-
: -1;
|
|
390
|
-
}
|
|
391
|
-
if (!this._multiple && showDropdownNext) {
|
|
392
|
-
this.updateComplete.then(() => {
|
|
393
|
-
this._scrollActiveElementToTop();
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
if (this._multiple && showDropdownNext) {
|
|
399
|
-
this._activeIndex = 0;
|
|
400
|
-
}
|
|
401
370
|
}
|
|
402
371
|
_onSpaceKeyDown() {
|
|
403
372
|
if (!this.open) {
|
|
404
|
-
this.
|
|
373
|
+
this.open = true;
|
|
405
374
|
return;
|
|
406
375
|
}
|
|
407
|
-
if (this.open && this._multiple && this._activeIndex > -1) {
|
|
408
|
-
const opts = this.combobox ? this._filteredOptions : this._options;
|
|
409
|
-
const selectedOption = opts[this._activeIndex];
|
|
410
|
-
const nextSelectedIndexes = [];
|
|
411
|
-
this._options[selectedOption.index].selected = !selectedOption.selected;
|
|
412
|
-
opts.forEach(({ index }) => {
|
|
413
|
-
const { selected } = this._options[index];
|
|
414
|
-
if (selected) {
|
|
415
|
-
nextSelectedIndexes.push(index);
|
|
416
|
-
}
|
|
417
|
-
});
|
|
418
|
-
this._selectedIndexes = nextSelectedIndexes;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
_scrollActiveElementToTop() {
|
|
422
|
-
this._listElement.scrollTop = Math.floor(this._activeIndex * OPT_HEIGHT);
|
|
423
|
-
}
|
|
424
|
-
async _adjustOptionListScrollPos(direction, optionIndex) {
|
|
425
|
-
let numOpts = this.combobox
|
|
426
|
-
? this._filteredOptions.length
|
|
427
|
-
: this._options.length;
|
|
428
|
-
const suggestedOptionVisible = this._isSuggestedOptionVisible;
|
|
429
|
-
if (suggestedOptionVisible) {
|
|
430
|
-
numOpts += 1;
|
|
431
|
-
}
|
|
432
|
-
if (numOpts <= VISIBLE_OPTS) {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
this._isHoverForbidden = true;
|
|
436
|
-
window.addEventListener('mousemove', this._onMouseMove);
|
|
437
|
-
const ulScrollTop = this._listElement.scrollTop;
|
|
438
|
-
const liPosY = optionIndex * OPT_HEIGHT;
|
|
439
|
-
const fullyVisible = liPosY >= ulScrollTop &&
|
|
440
|
-
liPosY <= ulScrollTop + VISIBLE_OPTS * OPT_HEIGHT - OPT_HEIGHT;
|
|
441
|
-
if (direction === 'down') {
|
|
442
|
-
if (!fullyVisible) {
|
|
443
|
-
this._listElement.scrollTop =
|
|
444
|
-
optionIndex * OPT_HEIGHT - (VISIBLE_OPTS - 1) * OPT_HEIGHT;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
if (direction === 'up') {
|
|
448
|
-
if (!fullyVisible) {
|
|
449
|
-
this._listElement.scrollTop = Math.floor(this._activeIndex * OPT_HEIGHT);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
376
|
}
|
|
453
377
|
_onArrowUpKeyDown() {
|
|
454
378
|
if (this.open) {
|
|
455
|
-
if (this.
|
|
379
|
+
if (this._opts.activeIndex <= 0 && !(this.combobox && this.creatable)) {
|
|
456
380
|
return;
|
|
457
381
|
}
|
|
458
382
|
if (this._isPlaceholderOptionActive) {
|
|
459
|
-
const optionIndex = this.
|
|
460
|
-
this.
|
|
383
|
+
const optionIndex = this._opts.numOfVisibleOptions - 1;
|
|
384
|
+
this._opts.activeIndex = optionIndex;
|
|
461
385
|
this._isPlaceholderOptionActive = false;
|
|
462
386
|
}
|
|
463
387
|
else {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
388
|
+
const prevOp = this._opts.prev();
|
|
389
|
+
if (prevOp !== null) {
|
|
390
|
+
this._opts.activeIndex = prevOp?.index ?? -1;
|
|
391
|
+
const prevSelectableIndex = prevOp?.filteredIndex ?? -1;
|
|
392
|
+
if (prevSelectableIndex > -1) {
|
|
393
|
+
this._adjustOptionListScrollPos('up', prevSelectableIndex);
|
|
394
|
+
}
|
|
471
395
|
}
|
|
472
396
|
}
|
|
473
397
|
}
|
|
398
|
+
else {
|
|
399
|
+
this.open = true;
|
|
400
|
+
this._opts.activateDefault();
|
|
401
|
+
}
|
|
474
402
|
}
|
|
475
403
|
_onArrowDownKeyDown() {
|
|
476
|
-
let numOpts = this.
|
|
477
|
-
? this._filteredOptions.length
|
|
478
|
-
: this._options.length;
|
|
479
|
-
const currentOptions = this.combobox
|
|
480
|
-
? this._filteredOptions
|
|
481
|
-
: this._options;
|
|
404
|
+
let numOpts = this._opts.numOfVisibleOptions;
|
|
482
405
|
const suggestedOptionVisible = this._isSuggestedOptionVisible;
|
|
483
406
|
if (suggestedOptionVisible) {
|
|
484
407
|
numOpts += 1;
|
|
485
408
|
}
|
|
486
409
|
if (this.open) {
|
|
487
|
-
if (this._isPlaceholderOptionActive && this.
|
|
410
|
+
if (this._isPlaceholderOptionActive && this._opts.activeIndex === -1) {
|
|
488
411
|
return;
|
|
489
412
|
}
|
|
490
|
-
|
|
413
|
+
const nextOp = this._opts.next();
|
|
414
|
+
if (suggestedOptionVisible && nextOp === null) {
|
|
491
415
|
this._isPlaceholderOptionActive = true;
|
|
492
416
|
this._adjustOptionListScrollPos('down', numOpts - 1);
|
|
493
|
-
this.
|
|
417
|
+
this._opts.activeIndex = -1;
|
|
494
418
|
}
|
|
495
|
-
else if (
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
this._adjustOptionListScrollPos('down',
|
|
419
|
+
else if (nextOp !== null) {
|
|
420
|
+
const nextSelectableIndex = nextOp?.filteredIndex ?? -1;
|
|
421
|
+
this._opts.activeIndex = nextOp?.index ?? -1;
|
|
422
|
+
if (nextSelectableIndex > -1) {
|
|
423
|
+
this._adjustOptionListScrollPos('down', nextSelectableIndex);
|
|
500
424
|
}
|
|
501
425
|
}
|
|
502
426
|
}
|
|
427
|
+
else {
|
|
428
|
+
this.open = true;
|
|
429
|
+
this._opts.activateDefault();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
_onEscapeKeyDown() {
|
|
433
|
+
this.open = false;
|
|
503
434
|
}
|
|
504
435
|
_onSlotChange() {
|
|
505
436
|
this._setStateFromSlottedElements();
|
|
@@ -508,61 +439,83 @@ export class VscodeSelectBase extends VscElement {
|
|
|
508
439
|
_onComboboxInputFocus(ev) {
|
|
509
440
|
ev.target.select();
|
|
510
441
|
this._isBeingFiltered = false;
|
|
511
|
-
this.
|
|
442
|
+
this._opts.filterPattern = '';
|
|
512
443
|
}
|
|
513
444
|
_onComboboxInputBlur() {
|
|
514
445
|
this._isBeingFiltered = false;
|
|
515
446
|
}
|
|
516
447
|
_onComboboxInputInput(ev) {
|
|
517
448
|
this._isBeingFiltered = true;
|
|
518
|
-
this.
|
|
519
|
-
this.
|
|
520
|
-
this.
|
|
449
|
+
this._opts.filterPattern = ev.target.value;
|
|
450
|
+
this._opts.activeIndex = -1;
|
|
451
|
+
this.open = true;
|
|
521
452
|
}
|
|
522
453
|
_onComboboxInputClick() {
|
|
523
|
-
this._isBeingFiltered = this.
|
|
524
|
-
this.
|
|
454
|
+
this._isBeingFiltered = this._opts.filterPattern !== '';
|
|
455
|
+
this.open = true;
|
|
456
|
+
}
|
|
457
|
+
_onComboboxInputSpaceKeyDown(ev) {
|
|
458
|
+
if (ev.key === ' ') {
|
|
459
|
+
ev.stopPropagation();
|
|
460
|
+
}
|
|
525
461
|
}
|
|
526
462
|
_onOptionClick(_ev) {
|
|
527
463
|
this._isBeingFiltered = false;
|
|
528
464
|
return;
|
|
529
465
|
}
|
|
466
|
+
//#endregion
|
|
467
|
+
//#region render functions
|
|
468
|
+
_renderCheckbox(checked, label) {
|
|
469
|
+
const checkboxClasses = {
|
|
470
|
+
'checkbox-icon': true,
|
|
471
|
+
checked,
|
|
472
|
+
};
|
|
473
|
+
return html `<span class=${classMap(checkboxClasses)}>${checkIcon}</span
|
|
474
|
+
><span class="option-label">${label}</span>`;
|
|
475
|
+
}
|
|
530
476
|
_renderOptions() {
|
|
531
|
-
const list = this.
|
|
477
|
+
const list = this._opts.options;
|
|
532
478
|
return html `
|
|
533
479
|
<ul
|
|
480
|
+
aria-label=${ifDefined(this.label ?? undefined)}
|
|
481
|
+
aria-multiselectable=${ifDefined(this._opts.multiSelect ? 'true' : undefined)}
|
|
534
482
|
class="options"
|
|
483
|
+
id="select-listbox"
|
|
484
|
+
role="listbox"
|
|
485
|
+
tabindex="-1"
|
|
535
486
|
@click=${this._onOptionClick}
|
|
536
487
|
@mouseover=${this._onOptionMouseOver}
|
|
537
488
|
>
|
|
538
489
|
${repeat(list, (op) => op.index, (op, index) => {
|
|
490
|
+
if (!op.visible) {
|
|
491
|
+
return nothing;
|
|
492
|
+
}
|
|
493
|
+
const active = op.index === this._opts.activeIndex && !op.disabled;
|
|
494
|
+
const selected = this._opts.getIsIndexSelected(op.index);
|
|
539
495
|
const optionClasses = {
|
|
540
|
-
active
|
|
496
|
+
active,
|
|
541
497
|
disabled: op.disabled,
|
|
542
498
|
option: true,
|
|
543
|
-
selected
|
|
544
|
-
};
|
|
545
|
-
const checkboxClasses = {
|
|
546
|
-
'checkbox-icon': true,
|
|
547
|
-
checked: op.selected,
|
|
499
|
+
selected,
|
|
548
500
|
};
|
|
549
501
|
const labelText = (op.ranges?.length ?? 0 > 0)
|
|
550
502
|
? highlightRanges(op.label, op.ranges ?? [])
|
|
551
503
|
: op.label;
|
|
552
504
|
return html `
|
|
553
505
|
<li
|
|
506
|
+
aria-selected=${selected ? 'true' : 'false'}
|
|
554
507
|
class=${classMap(optionClasses)}
|
|
555
508
|
data-index=${op.index}
|
|
556
509
|
data-filtered-index=${index}
|
|
510
|
+
id=${`op-${op.index}`}
|
|
511
|
+
role="option"
|
|
512
|
+
tabindex="-1"
|
|
557
513
|
>
|
|
558
|
-
${this.
|
|
559
|
-
? html `<span class=${classMap(checkboxClasses)}></span
|
|
560
|
-
><span class="option-label">${labelText}</span>`
|
|
561
|
-
: labelText}
|
|
514
|
+
${when(this._opts.multiSelect, () => this._renderCheckbox(selected, labelText), () => labelText)}
|
|
562
515
|
</li>
|
|
563
516
|
`;
|
|
564
517
|
})}
|
|
565
|
-
${this._renderPlaceholderOption(
|
|
518
|
+
${this._renderPlaceholderOption(this._opts.numOfVisibleOptions < 1)}
|
|
566
519
|
</ul>
|
|
567
520
|
`;
|
|
568
521
|
}
|
|
@@ -570,10 +523,11 @@ export class VscodeSelectBase extends VscElement {
|
|
|
570
523
|
if (!this.combobox) {
|
|
571
524
|
return nothing;
|
|
572
525
|
}
|
|
573
|
-
|
|
526
|
+
const foundOption = this._opts.getOptionByLabel(this._opts.filterPattern);
|
|
527
|
+
if (foundOption) {
|
|
574
528
|
return nothing;
|
|
575
529
|
}
|
|
576
|
-
if (this.creatable && this.
|
|
530
|
+
if (this.creatable && this._opts.filterPattern.length > 0) {
|
|
577
531
|
return html `<li
|
|
578
532
|
class=${classMap({
|
|
579
533
|
option: true,
|
|
@@ -582,7 +536,7 @@ export class VscodeSelectBase extends VscElement {
|
|
|
582
536
|
})}
|
|
583
537
|
@mouseout=${this._onPlaceholderOptionMouseOut}
|
|
584
538
|
>
|
|
585
|
-
Add "${this.
|
|
539
|
+
Add "${this._opts.filterPattern}"
|
|
586
540
|
</li>`;
|
|
587
541
|
}
|
|
588
542
|
else {
|
|
@@ -594,10 +548,11 @@ export class VscodeSelectBase extends VscElement {
|
|
|
594
548
|
}
|
|
595
549
|
}
|
|
596
550
|
_renderDescription() {
|
|
597
|
-
|
|
551
|
+
const op = this._opts.getActiveOption();
|
|
552
|
+
if (!op) {
|
|
598
553
|
return nothing;
|
|
599
554
|
}
|
|
600
|
-
const { description } =
|
|
555
|
+
const { description } = op;
|
|
601
556
|
return description
|
|
602
557
|
? html `<div class="description">${description}</div>`
|
|
603
558
|
: nothing;
|
|
@@ -605,89 +560,52 @@ export class VscodeSelectBase extends VscElement {
|
|
|
605
560
|
_renderSelectFace() {
|
|
606
561
|
return html `${nothing}`;
|
|
607
562
|
}
|
|
608
|
-
_renderMultiSelectLabel() {
|
|
609
|
-
switch (this._selectedIndexes.length) {
|
|
610
|
-
case 0:
|
|
611
|
-
return html `<span class="select-face-badge no-item"
|
|
612
|
-
>No items selected</span
|
|
613
|
-
>`;
|
|
614
|
-
case 1:
|
|
615
|
-
return html `<span class="select-face-badge">1 item selected</span>`;
|
|
616
|
-
default:
|
|
617
|
-
return html `<span class="select-face-badge"
|
|
618
|
-
>${this._selectedIndexes.length} items selected</span
|
|
619
|
-
>`;
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
563
|
_renderComboboxFace() {
|
|
623
|
-
|
|
624
|
-
if (this._isBeingFiltered) {
|
|
625
|
-
inputVal = this._filterPattern;
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
inputVal =
|
|
629
|
-
this._selectedIndex > -1
|
|
630
|
-
? (this._options[this._selectedIndex]?.label ?? '')
|
|
631
|
-
: '';
|
|
632
|
-
}
|
|
633
|
-
return html `
|
|
634
|
-
<div class="combobox-face face">
|
|
635
|
-
${this._multiple ? this._renderMultiSelectLabel() : nothing}
|
|
636
|
-
<input
|
|
637
|
-
class="combobox-input"
|
|
638
|
-
spellcheck="false"
|
|
639
|
-
type="text"
|
|
640
|
-
autocomplete="off"
|
|
641
|
-
.value=${inputVal}
|
|
642
|
-
@focus=${this._onComboboxInputFocus}
|
|
643
|
-
@blur=${this._onComboboxInputBlur}
|
|
644
|
-
@input=${this._onComboboxInputInput}
|
|
645
|
-
@click=${this._onComboboxInputClick}
|
|
646
|
-
>
|
|
647
|
-
<button
|
|
648
|
-
class="combobox-button"
|
|
649
|
-
type="button"
|
|
650
|
-
@click=${this._onComboboxButtonClick}
|
|
651
|
-
@keydown=${this._onComboboxButtonKeyDown}
|
|
652
|
-
>
|
|
653
|
-
${chevronDownIcon}
|
|
654
|
-
</button>
|
|
655
|
-
</div>
|
|
656
|
-
`;
|
|
564
|
+
return html `${nothing}`;
|
|
657
565
|
}
|
|
658
566
|
_renderDropdownControls() {
|
|
659
567
|
return html `${nothing}`;
|
|
660
568
|
}
|
|
661
569
|
_renderDropdown() {
|
|
662
|
-
const classes =
|
|
570
|
+
const classes = {
|
|
663
571
|
dropdown: true,
|
|
664
|
-
multiple: this.
|
|
665
|
-
|
|
572
|
+
multiple: this._opts.multiSelect,
|
|
573
|
+
open: this.open,
|
|
574
|
+
};
|
|
575
|
+
const visibleOptions = this._isSuggestedOptionVisible || this._opts.numOfVisibleOptions === 0
|
|
576
|
+
? this._opts.numOfVisibleOptions + 1
|
|
577
|
+
: this._opts.numOfVisibleOptions;
|
|
578
|
+
const scrollPaneHeight = Math.min(visibleOptions * OPT_HEIGHT, VISIBLE_OPTS * OPT_HEIGHT);
|
|
666
579
|
return html `
|
|
667
|
-
<div class=${classes}>
|
|
580
|
+
<div class=${classMap(classes)}>
|
|
668
581
|
${this.position === 'above' ? this._renderDescription() : nothing}
|
|
669
|
-
|
|
582
|
+
<vscode-scrollable
|
|
583
|
+
always-visible
|
|
584
|
+
class="scrollable"
|
|
585
|
+
min-thumb-size="40"
|
|
586
|
+
tabindex="-1"
|
|
587
|
+
@vsc-scrollable-scroll=${this._onOptionListScroll}
|
|
588
|
+
.scrollPos=${this._optionListScrollPos}
|
|
589
|
+
.style=${stylePropertyMap({
|
|
590
|
+
height: `${scrollPaneHeight}px`,
|
|
591
|
+
})}
|
|
592
|
+
>
|
|
593
|
+
${this._renderOptions()} ${this._renderDropdownControls()}
|
|
594
|
+
</vscode-scrollable>
|
|
670
595
|
${this.position === 'below' ? this._renderDescription() : nothing}
|
|
671
596
|
</div>
|
|
672
597
|
`;
|
|
673
598
|
}
|
|
674
|
-
render() {
|
|
675
|
-
return html `
|
|
676
|
-
<slot class="main-slot" @slotchange=${this._onSlotChange}></slot>
|
|
677
|
-
${this.combobox ? this._renderComboboxFace() : this._renderSelectFace()}
|
|
678
|
-
${this.open ? this._renderDropdown() : nothing}
|
|
679
|
-
`;
|
|
680
|
-
}
|
|
681
599
|
}
|
|
682
|
-
__decorate([
|
|
683
|
-
property({ type: String, reflect: true, attribute: 'aria-expanded' })
|
|
684
|
-
], VscodeSelectBase.prototype, "ariaExpanded", void 0);
|
|
685
600
|
__decorate([
|
|
686
601
|
property({ type: Boolean, reflect: true })
|
|
687
602
|
], VscodeSelectBase.prototype, "creatable", void 0);
|
|
688
603
|
__decorate([
|
|
689
604
|
property({ type: Boolean, reflect: true })
|
|
690
|
-
], VscodeSelectBase.prototype, "combobox",
|
|
605
|
+
], VscodeSelectBase.prototype, "combobox", null);
|
|
606
|
+
__decorate([
|
|
607
|
+
property({ reflect: true })
|
|
608
|
+
], VscodeSelectBase.prototype, "label", void 0);
|
|
691
609
|
__decorate([
|
|
692
610
|
property({ type: Boolean, reflect: true })
|
|
693
611
|
], VscodeSelectBase.prototype, "disabled", null);
|
|
@@ -709,18 +627,12 @@ __decorate([
|
|
|
709
627
|
__decorate([
|
|
710
628
|
property({ reflect: true })
|
|
711
629
|
], VscodeSelectBase.prototype, "position", void 0);
|
|
712
|
-
__decorate([
|
|
713
|
-
property({ type: Number, attribute: true, reflect: true })
|
|
714
|
-
], VscodeSelectBase.prototype, "tabIndex", void 0);
|
|
715
630
|
__decorate([
|
|
716
631
|
queryAssignedElements({
|
|
717
632
|
flatten: true,
|
|
718
633
|
selector: 'vscode-option',
|
|
719
634
|
})
|
|
720
635
|
], VscodeSelectBase.prototype, "_assignedOptions", void 0);
|
|
721
|
-
__decorate([
|
|
722
|
-
state()
|
|
723
|
-
], VscodeSelectBase.prototype, "_activeIndex", void 0);
|
|
724
636
|
__decorate([
|
|
725
637
|
state()
|
|
726
638
|
], VscodeSelectBase.prototype, "_currentDescription", void 0);
|
|
@@ -730,12 +642,6 @@ __decorate([
|
|
|
730
642
|
__decorate([
|
|
731
643
|
state()
|
|
732
644
|
], VscodeSelectBase.prototype, "_filteredOptions", null);
|
|
733
|
-
__decorate([
|
|
734
|
-
state()
|
|
735
|
-
], VscodeSelectBase.prototype, "_filterPattern", void 0);
|
|
736
|
-
__decorate([
|
|
737
|
-
state()
|
|
738
|
-
], VscodeSelectBase.prototype, "_selectedIndex", void 0);
|
|
739
645
|
__decorate([
|
|
740
646
|
state()
|
|
741
647
|
], VscodeSelectBase.prototype, "_selectedIndexes", void 0);
|
|
@@ -748,9 +654,6 @@ __decorate([
|
|
|
748
654
|
__decorate([
|
|
749
655
|
state()
|
|
750
656
|
], VscodeSelectBase.prototype, "_values", void 0);
|
|
751
|
-
__decorate([
|
|
752
|
-
state()
|
|
753
|
-
], VscodeSelectBase.prototype, "_listScrollTop", void 0);
|
|
754
657
|
__decorate([
|
|
755
658
|
state()
|
|
756
659
|
], VscodeSelectBase.prototype, "_isPlaceholderOptionActive", void 0);
|
|
@@ -758,6 +661,6 @@ __decorate([
|
|
|
758
661
|
state()
|
|
759
662
|
], VscodeSelectBase.prototype, "_isBeingFiltered", void 0);
|
|
760
663
|
__decorate([
|
|
761
|
-
|
|
762
|
-
], VscodeSelectBase.prototype, "
|
|
664
|
+
state()
|
|
665
|
+
], VscodeSelectBase.prototype, "_optionListScrollPos", void 0);
|
|
763
666
|
//# sourceMappingURL=vscode-select-base.js.map
|