@ni/nimble-components 24.1.6 → 24.1.8
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/dist/all-components-bundle.js +501 -61
- package/dist/all-components-bundle.js.map +1 -1
- package/dist/all-components-bundle.min.js +7375 -7353
- package/dist/all-components-bundle.min.js.map +1 -1
- package/dist/esm/combobox/index.d.ts +172 -20
- package/dist/esm/combobox/index.js +453 -44
- package/dist/esm/combobox/index.js.map +1 -1
- package/dist/esm/combobox/models/combobox-form-associated.d.ts +16 -0
- package/dist/esm/combobox/models/combobox-form-associated.js +19 -0
- package/dist/esm/combobox/models/combobox-form-associated.js.map +1 -0
- package/dist/esm/src/combobox/index.d.ts +172 -20
- package/dist/esm/src/combobox/models/combobox-form-associated.d.ts +16 -0
- package/dist/esm/src/table-column/date-text/index.d.ts +25 -1
- package/dist/esm/src/table-column/duration-text/index.d.ts +26 -2
- package/dist/esm/src/table-column/number-text/index.d.ts +25 -1
- package/dist/esm/src/table-column/text/index.d.ts +25 -1
- package/dist/esm/src/table-column/text-base/index.d.ts +10 -9
- package/dist/esm/table-column/date-text/index.d.ts +25 -1
- package/dist/esm/table-column/date-text/index.js +2 -2
- package/dist/esm/table-column/date-text/index.js.map +1 -1
- package/dist/esm/table-column/duration-text/index.d.ts +26 -2
- package/dist/esm/table-column/duration-text/index.js +2 -2
- package/dist/esm/table-column/duration-text/index.js.map +1 -1
- package/dist/esm/table-column/number-text/index.d.ts +25 -1
- package/dist/esm/table-column/number-text/index.js +2 -2
- package/dist/esm/table-column/number-text/index.js.map +1 -1
- package/dist/esm/table-column/text/index.d.ts +25 -1
- package/dist/esm/table-column/text/index.js +2 -2
- package/dist/esm/table-column/text/index.js.map +1 -1
- package/dist/esm/table-column/text-base/index.d.ts +10 -9
- package/dist/esm/table-column/text-base/index.js +6 -2
- package/dist/esm/table-column/text-base/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { attr, html, observable, ref } from '@microsoft/fast-element';
|
|
3
|
-
import { DesignSystem,
|
|
4
|
-
import { keyArrowDown, keyArrowUp, keyEnter, keySpace } from '@microsoft/fast-web-utilities';
|
|
2
|
+
import { DOM, Observable, attr, html, observable, ref } from '@microsoft/fast-element';
|
|
3
|
+
import { DesignSystem, ComboboxAutocomplete, SelectPosition, DelegatesARIACombobox, applyMixins, StartEnd } from '@microsoft/fast-foundation';
|
|
4
|
+
import { keyArrowDown, keyArrowUp, keyEnter, keyEscape, keySpace, keyTab, limit, uniqueId } from '@microsoft/fast-web-utilities';
|
|
5
5
|
import { toggleButtonTag } from '../toggle-button';
|
|
6
6
|
import { errorTextTemplate } from '../patterns/error/template';
|
|
7
7
|
import { iconArrowExpanderDownTag } from '../icons/arrow-expander-down';
|
|
@@ -9,65 +9,156 @@ import { iconExclamationMarkTag } from '../icons/exclamation-mark';
|
|
|
9
9
|
import { styles } from './styles';
|
|
10
10
|
import { DropdownAppearance } from '../patterns/dropdown/types';
|
|
11
11
|
import { template } from './template';
|
|
12
|
+
import { FormAssociatedCombobox } from './models/combobox-form-associated';
|
|
12
13
|
/**
|
|
13
14
|
* A nimble-styed HTML combobox
|
|
14
15
|
*/
|
|
15
|
-
export class Combobox extends
|
|
16
|
+
export class Combobox extends FormAssociatedCombobox {
|
|
16
17
|
constructor() {
|
|
17
18
|
super(...arguments);
|
|
18
19
|
this.appearance = DropdownAppearance.underline;
|
|
19
20
|
this.errorVisible = false;
|
|
21
|
+
/**
|
|
22
|
+
* The open attribute.
|
|
23
|
+
*/
|
|
24
|
+
this.open = false;
|
|
25
|
+
/**
|
|
26
|
+
* The collection of currently filtered options.
|
|
27
|
+
*/
|
|
28
|
+
this.filteredOptions = [];
|
|
20
29
|
/** @internal */
|
|
21
30
|
this.hasOverflow = false;
|
|
31
|
+
/**
|
|
32
|
+
* The unique id for the internal listbox element.
|
|
33
|
+
*
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
this.listboxId = uniqueId('listbox-');
|
|
37
|
+
/**
|
|
38
|
+
* The max height for the listbox when opened.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
this.maxHeight = 0;
|
|
22
43
|
this.valueUpdatedByInput = false;
|
|
44
|
+
this._value = '';
|
|
45
|
+
this.filter = '';
|
|
46
|
+
/**
|
|
47
|
+
* The initial state of the position attribute.
|
|
48
|
+
*/
|
|
49
|
+
this.forcedPosition = false;
|
|
23
50
|
}
|
|
24
51
|
get value() {
|
|
25
|
-
|
|
52
|
+
Observable.track(this, 'value');
|
|
53
|
+
return this._value;
|
|
26
54
|
}
|
|
27
|
-
// This override is to work around an issue in FAST where an old filter value
|
|
28
|
-
// is used after programmatically setting the value property.
|
|
29
|
-
// See: https://github.com/microsoft/fast/issues/6749
|
|
30
55
|
set value(next) {
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
const prev = `${this._value}`;
|
|
57
|
+
let updatedValue = next;
|
|
58
|
+
if (this.$fastController.isConnected && this.options) {
|
|
59
|
+
const selectedIndex = this.options.findIndex(el => el.text.toLowerCase() === next.toLowerCase());
|
|
60
|
+
const prevSelectedValue = this.options[this.selectedIndex]?.text;
|
|
61
|
+
const nextSelectedValue = this.options[selectedIndex]?.text;
|
|
62
|
+
this.selectedIndex = prevSelectedValue !== nextSelectedValue
|
|
63
|
+
? selectedIndex
|
|
64
|
+
: this.selectedIndex;
|
|
65
|
+
updatedValue = this.firstSelectedOption?.text || next;
|
|
66
|
+
}
|
|
67
|
+
if (prev !== updatedValue) {
|
|
68
|
+
this._value = updatedValue;
|
|
69
|
+
super.valueChanged(prev, updatedValue);
|
|
70
|
+
Observable.notify(this, 'value');
|
|
71
|
+
}
|
|
33
72
|
// Can remove when following resolved: https://github.com/microsoft/fast/issues/6749
|
|
34
|
-
|
|
35
|
-
this['filter'] = next;
|
|
73
|
+
this.filter = next;
|
|
36
74
|
this.filterOptions();
|
|
37
75
|
this.selectedIndex = this.options
|
|
38
76
|
.map(option => option.text)
|
|
39
77
|
.indexOf(this.value);
|
|
40
78
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The list of options.
|
|
81
|
+
*
|
|
82
|
+
* Overrides `Listbox.options`.
|
|
83
|
+
*/
|
|
84
|
+
get options() {
|
|
85
|
+
Observable.track(this, 'options');
|
|
86
|
+
return this.filteredOptions?.length
|
|
87
|
+
? this.filteredOptions
|
|
88
|
+
: this._options;
|
|
89
|
+
}
|
|
90
|
+
set options(value) {
|
|
91
|
+
this._options = value;
|
|
92
|
+
Observable.notify(this, 'options');
|
|
93
|
+
}
|
|
94
|
+
get isAutocompleteInline() {
|
|
95
|
+
return (this.autocomplete === ComboboxAutocomplete.inline
|
|
96
|
+
|| this.isAutocompleteBoth);
|
|
97
|
+
}
|
|
98
|
+
get isAutocompleteList() {
|
|
99
|
+
return (this.autocomplete === ComboboxAutocomplete.list
|
|
100
|
+
|| this.isAutocompleteBoth);
|
|
101
|
+
}
|
|
102
|
+
get isAutocompleteBoth() {
|
|
103
|
+
return this.autocomplete === ComboboxAutocomplete.both;
|
|
49
104
|
}
|
|
50
|
-
// Workaround for https://github.com/microsoft/fast/issues/5773
|
|
51
105
|
slottedOptionsChanged(prev, next) {
|
|
106
|
+
// Workaround for https://github.com/microsoft/fast/issues/5773
|
|
52
107
|
const value = this.value;
|
|
53
108
|
super.slottedOptionsChanged(prev, next);
|
|
109
|
+
this.updateValue();
|
|
54
110
|
if (value) {
|
|
55
111
|
this.value = value;
|
|
56
112
|
}
|
|
57
113
|
}
|
|
58
114
|
connectedCallback() {
|
|
59
115
|
super.connectedCallback();
|
|
60
|
-
|
|
116
|
+
this.forcedPosition = !!this.positionAttribute;
|
|
117
|
+
if (this.value) {
|
|
118
|
+
this.initialValue = this.value;
|
|
119
|
+
}
|
|
61
120
|
this.setPositioning();
|
|
62
121
|
this.updateInputAriaLabel();
|
|
63
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* @internal
|
|
125
|
+
*/
|
|
126
|
+
clickHandler(e) {
|
|
127
|
+
if (this.disabled) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
if (this.open) {
|
|
131
|
+
const captured = e.target.closest('option,[role=option]');
|
|
132
|
+
if (!captured || captured.disabled) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
this.selectedOptions = [captured];
|
|
136
|
+
this.control.value = captured.text;
|
|
137
|
+
this.clearSelectionRange();
|
|
138
|
+
this.updateValue(true);
|
|
139
|
+
}
|
|
140
|
+
this.open = !this.open;
|
|
141
|
+
if (this.open) {
|
|
142
|
+
this.control.focus();
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* @internal
|
|
148
|
+
*/
|
|
64
149
|
toggleButtonClickHandler(e) {
|
|
65
150
|
e.stopImmediatePropagation();
|
|
66
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
67
155
|
toggleButtonChangeHandler(e) {
|
|
68
156
|
this.open = this.dropdownButton.checked;
|
|
69
157
|
e.stopImmediatePropagation();
|
|
70
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
71
162
|
toggleButtonKeyDownHandler(e) {
|
|
72
163
|
switch (e.key) {
|
|
73
164
|
case keyArrowUp:
|
|
@@ -81,20 +172,57 @@ export class Combobox extends FoundationCombobox {
|
|
|
81
172
|
return true;
|
|
82
173
|
}
|
|
83
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* @internal
|
|
177
|
+
*/
|
|
84
178
|
filterOptions() {
|
|
85
|
-
|
|
179
|
+
if (!this.autocomplete
|
|
180
|
+
|| this.autocomplete === ComboboxAutocomplete.none) {
|
|
181
|
+
this.filter = '';
|
|
182
|
+
}
|
|
183
|
+
const filter = this.filter.toLowerCase();
|
|
184
|
+
this.filteredOptions = this._options.filter(o => o.text.toLowerCase().startsWith(filter));
|
|
185
|
+
if (this.isAutocompleteList) {
|
|
186
|
+
if (!this.filteredOptions.length && !filter) {
|
|
187
|
+
this.filteredOptions = this._options;
|
|
188
|
+
}
|
|
189
|
+
this._options.forEach(o => {
|
|
190
|
+
o.visuallyHidden = !this.filteredOptions.includes(o);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
86
193
|
const enabledOptions = this.filteredOptions.filter(o => !o.disabled);
|
|
87
194
|
this.filteredOptions = enabledOptions;
|
|
88
195
|
}
|
|
89
196
|
/**
|
|
90
|
-
*
|
|
91
|
-
* For now, we will update the value ourselves while a user types in text. Note that there is other
|
|
92
|
-
* implementation related to this (like the 'keydownEventHandler') needed to create the complete set
|
|
93
|
-
* of desired behavior described in the issue noted above.
|
|
197
|
+
* @internal
|
|
94
198
|
*/
|
|
95
|
-
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
96
199
|
inputHandler(e) {
|
|
97
|
-
|
|
200
|
+
this.filter = this.control.value;
|
|
201
|
+
this.filterOptions();
|
|
202
|
+
if (!this.isAutocompleteInline) {
|
|
203
|
+
this.selectedIndex = this.options
|
|
204
|
+
.map(option => option.text)
|
|
205
|
+
.indexOf(this.control.value);
|
|
206
|
+
}
|
|
207
|
+
if (!(e.inputType.includes('deleteContent') || !this.filter.length)) {
|
|
208
|
+
if (this.isAutocompleteList && !this.open) {
|
|
209
|
+
this.open = true;
|
|
210
|
+
}
|
|
211
|
+
if (this.isAutocompleteInline) {
|
|
212
|
+
if (this.filteredOptions.length) {
|
|
213
|
+
this.selectedOptions = [this.filteredOptions[0]];
|
|
214
|
+
this.selectedIndex = this.options.indexOf(this.firstSelectedOption);
|
|
215
|
+
this.setInlineSelection();
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
this.selectedIndex = -1;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// This is a workaround for the issue described here: https://github.com/microsoft/fast/issues/6267
|
|
223
|
+
// For now, we will update the value ourselves while a user types in text. Note that there is other
|
|
224
|
+
// implementation related to this (like the 'keydownEventHandler') needed to create the complete set
|
|
225
|
+
// of desired behavior described in the issue noted above.
|
|
98
226
|
if (!this.valueUpdatedByInput) {
|
|
99
227
|
this.valueBeforeTextUpdate = this.value;
|
|
100
228
|
}
|
|
@@ -104,47 +232,260 @@ export class Combobox extends FoundationCombobox {
|
|
|
104
232
|
this.focusAndScrollOptionIntoView();
|
|
105
233
|
}
|
|
106
234
|
this.value = this.control.value;
|
|
107
|
-
return
|
|
235
|
+
return true;
|
|
108
236
|
}
|
|
109
|
-
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
110
237
|
keydownHandler(e) {
|
|
111
|
-
const returnValue = super.keydownHandler(e);
|
|
112
238
|
if (e.ctrlKey || e.altKey) {
|
|
113
|
-
return
|
|
239
|
+
return true;
|
|
114
240
|
}
|
|
115
241
|
switch (e.key) {
|
|
116
242
|
case keyEnter:
|
|
243
|
+
this.syncValue();
|
|
244
|
+
if (this.isAutocompleteInline) {
|
|
245
|
+
this.filter = this.value;
|
|
246
|
+
}
|
|
247
|
+
this.open = false;
|
|
248
|
+
this.clearSelectionRange();
|
|
117
249
|
this.emitChangeIfValueUpdated();
|
|
118
250
|
break;
|
|
251
|
+
case keyEscape:
|
|
252
|
+
if (!this.isAutocompleteInline) {
|
|
253
|
+
this.selectedIndex = -1;
|
|
254
|
+
}
|
|
255
|
+
if (this.open) {
|
|
256
|
+
this.open = false;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
this.value = '';
|
|
260
|
+
this.control.value = '';
|
|
261
|
+
this.filter = '';
|
|
262
|
+
this.filterOptions();
|
|
263
|
+
break;
|
|
264
|
+
case keyTab:
|
|
265
|
+
this.setInputToSelection();
|
|
266
|
+
if (!this.open) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
e.preventDefault();
|
|
270
|
+
this.open = false;
|
|
271
|
+
break;
|
|
119
272
|
case keyArrowDown:
|
|
120
273
|
case keyArrowUp:
|
|
274
|
+
this.filterOptions();
|
|
275
|
+
if (!this.open) {
|
|
276
|
+
this.open = true;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
if (this.filteredOptions.length > 0) {
|
|
280
|
+
super.keydownHandler(e);
|
|
281
|
+
}
|
|
282
|
+
if (this.isAutocompleteInline) {
|
|
283
|
+
this.setInlineSelection();
|
|
284
|
+
}
|
|
121
285
|
if (this.open && this.valueUpdatedByInput) {
|
|
122
286
|
this.valueUpdatedByInput = false;
|
|
123
287
|
}
|
|
124
288
|
break;
|
|
125
289
|
default:
|
|
126
|
-
return
|
|
290
|
+
return true;
|
|
127
291
|
}
|
|
128
|
-
return
|
|
292
|
+
return true;
|
|
129
293
|
}
|
|
130
|
-
|
|
294
|
+
/**
|
|
295
|
+
* @internal
|
|
296
|
+
*/
|
|
297
|
+
keyupHandler(e) {
|
|
298
|
+
const key = e.key;
|
|
299
|
+
switch (key) {
|
|
300
|
+
case 'ArrowLeft':
|
|
301
|
+
case 'ArrowRight':
|
|
302
|
+
case 'Backspace':
|
|
303
|
+
case 'Delete':
|
|
304
|
+
case 'Home':
|
|
305
|
+
case 'End': {
|
|
306
|
+
this.filter = this.control.value;
|
|
307
|
+
this.selectedIndex = -1;
|
|
308
|
+
this.filterOptions();
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
default: {
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* @internal
|
|
319
|
+
*/
|
|
131
320
|
focusoutHandler(e) {
|
|
132
|
-
|
|
321
|
+
this.syncValue();
|
|
322
|
+
if (this.open) {
|
|
323
|
+
const focusTarget = e.relatedTarget;
|
|
324
|
+
if (this.isSameNode(focusTarget)) {
|
|
325
|
+
this.focus();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
133
328
|
this.open = false;
|
|
134
329
|
this.emitChangeIfValueUpdated();
|
|
135
|
-
return
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Reset the element to its first selectable option when its parent form is reset.
|
|
334
|
+
*
|
|
335
|
+
* @internal
|
|
336
|
+
*/
|
|
337
|
+
formResetCallback() {
|
|
338
|
+
super.formResetCallback();
|
|
339
|
+
this.setDefaultSelectedOption();
|
|
340
|
+
this.updateValue();
|
|
341
|
+
}
|
|
342
|
+
/** {@inheritDoc (FormAssociated:interface).validate} */
|
|
343
|
+
validate() {
|
|
344
|
+
super.validate(this.control);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Set the default selected options at initialization or reset.
|
|
348
|
+
*
|
|
349
|
+
* @internal
|
|
350
|
+
* @remarks
|
|
351
|
+
* Overrides `Listbox.setDefaultSelectedOption`
|
|
352
|
+
*/
|
|
353
|
+
setDefaultSelectedOption() {
|
|
354
|
+
if (this.$fastController.isConnected && this.options) {
|
|
355
|
+
const selectedIndex = this.options.findIndex(el => el.getAttribute('selected') !== null || el.selected);
|
|
356
|
+
this.selectedIndex = selectedIndex;
|
|
357
|
+
if (!this.dirtyValue && this.firstSelectedOption) {
|
|
358
|
+
this.value = this.firstSelectedOption.text;
|
|
359
|
+
}
|
|
360
|
+
this.setSelectedOptions();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* @internal
|
|
365
|
+
*/
|
|
366
|
+
selectedIndexChanged(prev, next) {
|
|
367
|
+
if (this.$fastController.isConnected) {
|
|
368
|
+
const pinnedSelectedIndex = limit(-1, this.options.length - 1, next);
|
|
369
|
+
// we only want to call the super method when the selectedIndex is in range
|
|
370
|
+
if (pinnedSelectedIndex !== this.selectedIndex) {
|
|
371
|
+
this.selectedIndex = pinnedSelectedIndex;
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
super.selectedIndexChanged(prev, pinnedSelectedIndex);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Synchronize the `aria-disabled` property when the `disabled` property changes.
|
|
379
|
+
*
|
|
380
|
+
* @internal
|
|
381
|
+
*/
|
|
382
|
+
disabledChanged(prev, next) {
|
|
383
|
+
if (super.disabledChanged) {
|
|
384
|
+
super.disabledChanged(prev, next);
|
|
385
|
+
}
|
|
386
|
+
this.ariaDisabled = this.disabled ? 'true' : 'false';
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Move focus to the previous selectable option.
|
|
390
|
+
*
|
|
391
|
+
* @internal
|
|
392
|
+
* @remarks
|
|
393
|
+
* Overrides `Listbox.selectPreviousOption`
|
|
394
|
+
*/
|
|
395
|
+
selectPreviousOption() {
|
|
396
|
+
if (!this.disabled && this.selectedIndex >= 0) {
|
|
397
|
+
this.selectedIndex -= 1;
|
|
398
|
+
}
|
|
136
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* @internal
|
|
402
|
+
*/
|
|
403
|
+
setPositioning() {
|
|
404
|
+
// Workaround for https://github.com/microsoft/fast/issues/5123
|
|
405
|
+
if (!this.$fastController.isConnected) {
|
|
406
|
+
// Don't call setPositioning() until we're connected,
|
|
407
|
+
// since this.forcedPosition isn't initialized yet.
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const currentBox = this.getBoundingClientRect();
|
|
411
|
+
const viewportHeight = window.innerHeight;
|
|
412
|
+
const availableBottom = viewportHeight - currentBox.bottom;
|
|
413
|
+
if (this.forcedPosition) {
|
|
414
|
+
this.position = this.positionAttribute;
|
|
415
|
+
}
|
|
416
|
+
else if (currentBox.top > availableBottom) {
|
|
417
|
+
this.position = SelectPosition.above;
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
this.position = SelectPosition.below;
|
|
421
|
+
}
|
|
422
|
+
this.positionAttribute = this.forcedPosition
|
|
423
|
+
? this.positionAttribute
|
|
424
|
+
: this.position;
|
|
425
|
+
this.maxHeight = this.position === SelectPosition.above
|
|
426
|
+
? Math.trunc(currentBox.top)
|
|
427
|
+
: Math.trunc(availableBottom);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Focus the control and scroll the first selected option into view.
|
|
431
|
+
*
|
|
432
|
+
* @internal
|
|
433
|
+
* @remarks
|
|
434
|
+
* Overrides: `Listbox.focusAndScrollOptionIntoView`
|
|
435
|
+
*/
|
|
137
436
|
focusAndScrollOptionIntoView() {
|
|
138
437
|
if (this.open) {
|
|
139
|
-
|
|
438
|
+
if (this.contains(document.activeElement)) {
|
|
439
|
+
this.control.focus();
|
|
440
|
+
if (this.firstSelectedOption) {
|
|
441
|
+
requestAnimationFrame(() => {
|
|
442
|
+
this.firstSelectedOption?.scrollIntoView({
|
|
443
|
+
block: 'nearest'
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
140
448
|
}
|
|
141
449
|
}
|
|
142
450
|
openChanged() {
|
|
143
|
-
|
|
451
|
+
if (this.open) {
|
|
452
|
+
this.ariaControls = this.listboxId;
|
|
453
|
+
this.ariaExpanded = 'true';
|
|
454
|
+
this.setPositioning();
|
|
455
|
+
this.focusAndScrollOptionIntoView();
|
|
456
|
+
// focus is directed to the element when `open` is changed programmatically
|
|
457
|
+
DOM.queueUpdate(() => this.focus());
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
this.ariaControls = '';
|
|
461
|
+
this.ariaExpanded = 'false';
|
|
462
|
+
}
|
|
144
463
|
if (this.dropdownButton) {
|
|
145
464
|
this.dropdownButton.checked = this.open;
|
|
146
465
|
}
|
|
147
466
|
}
|
|
467
|
+
placeholderChanged() {
|
|
468
|
+
if (this.proxy instanceof HTMLInputElement) {
|
|
469
|
+
this.proxy.placeholder = this.placeholder ?? '';
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Ensure that the entire list of options is used when setting the selected property.
|
|
474
|
+
* @internal
|
|
475
|
+
* @remarks
|
|
476
|
+
* Overrides: `Listbox.selectedOptionsChanged`
|
|
477
|
+
*/
|
|
478
|
+
selectedOptionsChanged(_, next) {
|
|
479
|
+
if (this.$fastController.isConnected) {
|
|
480
|
+
this._options.forEach(o => {
|
|
481
|
+
o.selected = next.includes(o);
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
positionChanged(_, next) {
|
|
486
|
+
this.positionAttribute = next;
|
|
487
|
+
this.setPositioning();
|
|
488
|
+
}
|
|
148
489
|
regionChanged(_prev, _next) {
|
|
149
490
|
if (this.region && this.controlWrapper) {
|
|
150
491
|
this.region.anchorElement = this.controlWrapper;
|
|
@@ -162,6 +503,49 @@ export class Combobox extends FoundationCombobox {
|
|
|
162
503
|
maxHeightChanged() {
|
|
163
504
|
this.updateListboxMaxHeightCssVariable();
|
|
164
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Sets the value and to match the first selected option.
|
|
508
|
+
*/
|
|
509
|
+
updateValue(shouldEmit) {
|
|
510
|
+
if (this.$fastController.isConnected) {
|
|
511
|
+
this.value = this.firstSelectedOption?.text || this.control.value;
|
|
512
|
+
this.control.value = this.value;
|
|
513
|
+
}
|
|
514
|
+
if (shouldEmit) {
|
|
515
|
+
this.$emit('change');
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Focus and set the content of the control based on the first selected option.
|
|
520
|
+
*/
|
|
521
|
+
setInputToSelection() {
|
|
522
|
+
if (this.firstSelectedOption) {
|
|
523
|
+
this.control.value = this.firstSelectedOption.text;
|
|
524
|
+
this.control.focus();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Focus, set and select the content of the control based on the first selected option.
|
|
529
|
+
*/
|
|
530
|
+
setInlineSelection() {
|
|
531
|
+
if (this.firstSelectedOption) {
|
|
532
|
+
this.setInputToSelection();
|
|
533
|
+
this.control.setSelectionRange(this.filter.length, this.control.value.length, 'backward');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
clearSelectionRange() {
|
|
537
|
+
const controlValueLength = this.control.value.length;
|
|
538
|
+
this.control.setSelectionRange(controlValueLength, controlValueLength);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Determines if a value update should involve emitting a change event, then updates the value.
|
|
542
|
+
*/
|
|
543
|
+
syncValue() {
|
|
544
|
+
const newValue = this.selectedIndex > -1
|
|
545
|
+
? this.firstSelectedOption?.text
|
|
546
|
+
: this.control.value;
|
|
547
|
+
this.updateValue(this.value !== newValue);
|
|
548
|
+
}
|
|
165
549
|
updateListboxMaxHeightCssVariable() {
|
|
166
550
|
if (this.listbox) {
|
|
167
551
|
this.listbox.style.setProperty('--ni-private-select-max-height', `${this.maxHeight}px`);
|
|
@@ -198,27 +582,51 @@ export class Combobox extends FoundationCombobox {
|
|
|
198
582
|
__decorate([
|
|
199
583
|
attr
|
|
200
584
|
], Combobox.prototype, "appearance", void 0);
|
|
201
|
-
__decorate([
|
|
202
|
-
observable
|
|
203
|
-
], Combobox.prototype, "dropdownButton", void 0);
|
|
204
585
|
__decorate([
|
|
205
586
|
attr({ attribute: 'error-text' })
|
|
206
587
|
], Combobox.prototype, "errorText", void 0);
|
|
207
588
|
__decorate([
|
|
208
589
|
attr({ attribute: 'error-visible', mode: 'boolean' })
|
|
209
590
|
], Combobox.prototype, "errorVisible", void 0);
|
|
591
|
+
__decorate([
|
|
592
|
+
attr({ attribute: 'autocomplete', mode: 'fromView' })
|
|
593
|
+
], Combobox.prototype, "autocomplete", void 0);
|
|
594
|
+
__decorate([
|
|
595
|
+
attr({ attribute: 'position' })
|
|
596
|
+
], Combobox.prototype, "positionAttribute", void 0);
|
|
597
|
+
__decorate([
|
|
598
|
+
attr({ attribute: 'open', mode: 'boolean' })
|
|
599
|
+
], Combobox.prototype, "open", void 0);
|
|
600
|
+
__decorate([
|
|
601
|
+
attr
|
|
602
|
+
], Combobox.prototype, "placeholder", void 0);
|
|
603
|
+
__decorate([
|
|
604
|
+
observable
|
|
605
|
+
], Combobox.prototype, "position", void 0);
|
|
210
606
|
__decorate([
|
|
211
607
|
observable
|
|
212
608
|
], Combobox.prototype, "region", void 0);
|
|
213
609
|
__decorate([
|
|
214
610
|
observable
|
|
215
611
|
], Combobox.prototype, "controlWrapper", void 0);
|
|
612
|
+
__decorate([
|
|
613
|
+
observable
|
|
614
|
+
], Combobox.prototype, "control", void 0);
|
|
615
|
+
__decorate([
|
|
616
|
+
observable
|
|
617
|
+
], Combobox.prototype, "listbox", void 0);
|
|
618
|
+
__decorate([
|
|
619
|
+
observable
|
|
620
|
+
], Combobox.prototype, "dropdownButton", void 0);
|
|
216
621
|
__decorate([
|
|
217
622
|
observable
|
|
218
623
|
], Combobox.prototype, "hasOverflow", void 0);
|
|
624
|
+
__decorate([
|
|
625
|
+
observable
|
|
626
|
+
], Combobox.prototype, "maxHeight", void 0);
|
|
219
627
|
const nimbleCombobox = Combobox.compose({
|
|
220
628
|
baseName: 'combobox',
|
|
221
|
-
baseClass:
|
|
629
|
+
baseClass: FormAssociatedCombobox,
|
|
222
630
|
template,
|
|
223
631
|
styles,
|
|
224
632
|
shadowOptions: {
|
|
@@ -256,6 +664,7 @@ const nimbleCombobox = Combobox.compose({
|
|
|
256
664
|
${errorTextTemplate}
|
|
257
665
|
`
|
|
258
666
|
});
|
|
667
|
+
applyMixins(Combobox, StartEnd, DelegatesARIACombobox);
|
|
259
668
|
DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleCombobox());
|
|
260
669
|
export const comboboxTag = 'nimble-combobox';
|
|
261
670
|
//# sourceMappingURL=index.js.map
|