@momentum-design/components 0.92.1 → 0.92.3
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/browser/index.js +303 -297
- package/dist/browser/index.js.map +4 -4
- package/dist/components/menubar/menubar.component.d.ts +2 -1
- package/dist/components/menubar/menubar.component.js +23 -2
- package/dist/components/menusection/menusection.component.d.ts +9 -0
- package/dist/components/menusection/menusection.component.js +15 -1
- package/dist/components/menusection/menusection.constants.d.ts +4 -1
- package/dist/components/menusection/menusection.constants.js +4 -1
- package/dist/components/popover/popover.component.d.ts +35 -4
- package/dist/components/popover/popover.component.js +50 -5
- package/dist/components/popover/popover.constants.d.ts +3 -1
- package/dist/components/popover/popover.constants.js +3 -1
- package/dist/components/popover/popover.events.d.ts +12 -0
- package/dist/components/popover/popover.events.js +16 -0
- package/dist/components/popover/popover.utils.js +1 -1
- package/dist/components/select/select.component.d.ts +32 -37
- package/dist/components/select/select.component.js +132 -148
- package/dist/components/select/select.constants.d.ts +2 -1
- package/dist/components/select/select.constants.js +2 -1
- package/dist/components/select/select.styles.js +20 -17
- package/dist/components/select/select.types.d.ts +3 -1
- package/dist/components/selectlistbox/index.d.ts +7 -0
- package/dist/components/selectlistbox/index.js +4 -0
- package/dist/components/selectlistbox/selectlistbox.component.d.ts +18 -0
- package/dist/components/selectlistbox/selectlistbox.component.js +24 -0
- package/dist/components/selectlistbox/selectlistbox.constants.d.ts +2 -0
- package/dist/components/selectlistbox/selectlistbox.constants.js +3 -0
- package/dist/components/selectlistbox/selectlistbox.types.d.ts +3 -0
- package/dist/components/selectlistbox/selectlistbox.types.js +1 -0
- package/dist/custom-elements.json +1323 -1009
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/select/index.d.ts +2 -0
- package/dist/react/select/index.js +2 -0
- package/dist/react/selectlistbox/index.d.ts +15 -0
- package/dist/react/selectlistbox/index.js +24 -0
- package/package.json +1 -1
@@ -10,6 +10,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
10
10
|
import { html, nothing } from 'lit';
|
11
11
|
import { property, query, queryAssignedElements, state } from 'lit/decorators.js';
|
12
12
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
13
|
+
import { live } from 'lit/directives/live.js';
|
13
14
|
import { KEYS } from '../../utils/keys';
|
14
15
|
import { DataAriaLabelMixin } from '../../utils/mixins/DataAriaLabelMixin';
|
15
16
|
import { FormInternalsMixin } from '../../utils/mixins/FormInternalsMixin';
|
@@ -20,7 +21,7 @@ import { TAG_NAME as OPTION_GROUP_TAG_NAME } from '../optgroup/optgroup.constant
|
|
20
21
|
import { TAG_NAME as OPTION_TAG_NAME } from '../option/option.constants';
|
21
22
|
import { POPOVER_PLACEMENT } from '../popover/popover.constants';
|
22
23
|
import { TYPE, VALID_TEXT_TAGS } from '../text/text.constants';
|
23
|
-
import { ARROW_ICON, TRIGGER_ID } from './select.constants';
|
24
|
+
import { ARROW_ICON, LISTBOX_ID, TRIGGER_ID } from './select.constants';
|
24
25
|
import styles from './select.styles';
|
25
26
|
/**
|
26
27
|
* The mdc-select component is a dropdown selection control that allows users to pick an option from a predefined list.
|
@@ -30,6 +31,8 @@ import styles from './select.styles';
|
|
30
31
|
*
|
31
32
|
* To set a default option, use the `selected` attribute on the `mdc-option` element.
|
32
33
|
*
|
34
|
+
* **Note:** Make sure to add `mdc-selectlistbox` as a child of `mdc-select` and wrap options/optgroup in it to ensure proper accessibility functionality. Read more about it in SelectListBox documentation.
|
35
|
+
*
|
33
36
|
* @dependency mdc-button
|
34
37
|
* @dependency mdc-icon
|
35
38
|
* @dependency mdc-popover
|
@@ -60,23 +63,43 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
60
63
|
* @default auto
|
61
64
|
*/
|
62
65
|
this.height = 'auto';
|
66
|
+
/**
|
67
|
+
* The placeholder text which will be shown on the text if provided.
|
68
|
+
*/
|
69
|
+
this.placement = POPOVER_PLACEMENT.BOTTOM_START;
|
63
70
|
/** @internal */
|
64
71
|
this.baseIconName = ARROW_ICON.ARROW_DOWN;
|
65
72
|
/** @internal */
|
66
73
|
this.selectedValue = '';
|
67
74
|
/** @internal */
|
68
75
|
this.displayPopover = false;
|
69
|
-
/** @internal */
|
70
|
-
this.activeDescendant = '';
|
71
76
|
}
|
72
77
|
/**
|
73
|
-
*
|
78
|
+
* Modifies the listbox wrapper to ensure it has the correct attributes
|
79
|
+
* and IDs for accessibility.
|
80
|
+
*
|
81
|
+
* Once [ariaOwnsElements](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/ariaOwnsElements) is supported in browsers,
|
82
|
+
* this an be removed and mdc-option can be used directly in the select component with a listbox in a different
|
83
|
+
* shadow root and aria-owns attribute to connect them.
|
84
|
+
*/
|
85
|
+
modifyListBoxWrapper() {
|
86
|
+
const slottedListBox = this.slottedListboxes[0];
|
87
|
+
if (!slottedListBox) {
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
slottedListBox.setAttribute('id', LISTBOX_ID);
|
91
|
+
slottedListBox.setAttribute('aria-label', this.dataAriaLabel || '');
|
92
|
+
slottedListBox.setAttribute('aria-labelledby', TRIGGER_ID);
|
93
|
+
}
|
94
|
+
/**
|
95
|
+
* A helper function which returns a flattened array of all valid options from within the slotted listbox.
|
74
96
|
* It takes care of the edge cases where the option is either a direct child or a
|
75
97
|
* child of an option group.
|
76
98
|
*/
|
77
99
|
getAllValidOptions() {
|
78
100
|
var _a;
|
79
|
-
|
101
|
+
const optionsList = Array.from(((_a = this.slottedListboxes[0]) === null || _a === void 0 ? void 0 : _a.children) || []);
|
102
|
+
return ((optionsList === null || optionsList === void 0 ? void 0 : optionsList.map(option => {
|
80
103
|
if (option.tagName.toLowerCase() === OPTION_TAG_NAME) {
|
81
104
|
return option;
|
82
105
|
}
|
@@ -86,15 +109,6 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
86
109
|
return [];
|
87
110
|
}).flat()) || []);
|
88
111
|
}
|
89
|
-
handlePopoverOpen() {
|
90
|
-
this.displayPopover = true;
|
91
|
-
this.baseIconName = ARROW_ICON.ARROW_UP;
|
92
|
-
this.updateActivedescendant();
|
93
|
-
}
|
94
|
-
handlePopoverClose() {
|
95
|
-
this.displayPopover = false;
|
96
|
-
this.baseIconName = ARROW_ICON.ARROW_DOWN;
|
97
|
-
}
|
98
112
|
/**
|
99
113
|
* Updates the tabindex and selected attribute of the options.
|
100
114
|
* If selectedOption is provided, it will be set as the selected option.
|
@@ -164,11 +178,8 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
164
178
|
else {
|
165
179
|
this.inputElement.setCustomValidity('');
|
166
180
|
}
|
167
|
-
this.setValidity();
|
168
|
-
}
|
169
|
-
else {
|
170
|
-
this.internals.setValidity({});
|
171
181
|
}
|
182
|
+
this.setValidity();
|
172
183
|
}
|
173
184
|
/**
|
174
185
|
* @internal
|
@@ -180,6 +191,7 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
180
191
|
this.selectedIcon = null;
|
181
192
|
this.internals.setFormValue(this.selectedValue);
|
182
193
|
this.updateTabIndexForAllOptions();
|
194
|
+
this.requestUpdate();
|
183
195
|
}
|
184
196
|
/** @internal */
|
185
197
|
formStateRestoreCallback(state) {
|
@@ -253,6 +265,18 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
253
265
|
break;
|
254
266
|
}
|
255
267
|
}
|
268
|
+
handleClickCombobox(event) {
|
269
|
+
if (this.disabled || this.softDisabled || this.readonly) {
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
if (this.displayPopover) {
|
273
|
+
this.closePopover();
|
274
|
+
}
|
275
|
+
else {
|
276
|
+
this.openPopover();
|
277
|
+
}
|
278
|
+
event.stopPropagation();
|
279
|
+
}
|
256
280
|
/**
|
257
281
|
* Handles the keydown event on the select element when the popover is closed.
|
258
282
|
* The options are as follows:
|
@@ -262,15 +286,23 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
262
286
|
* - END: Opens the popover and sets focus and tabindex on the last option.
|
263
287
|
* @param event - The keyboard event.
|
264
288
|
*/
|
265
|
-
|
289
|
+
handleKeydownCombobox(event) {
|
290
|
+
if (this.disabled || this.softDisabled || this.readonly) {
|
291
|
+
return;
|
292
|
+
}
|
266
293
|
switch (event.key) {
|
267
294
|
case KEYS.ARROW_DOWN:
|
268
295
|
case KEYS.ARROW_UP:
|
296
|
+
this.openPopover();
|
297
|
+
// Prevent the default browser behavior of scrolling down
|
298
|
+
event.preventDefault();
|
299
|
+
break;
|
269
300
|
case KEYS.ENTER:
|
270
301
|
case KEYS.SPACE:
|
271
302
|
this.openPopover();
|
272
303
|
// Prevent the default browser behavior of scrolling down
|
273
304
|
event.preventDefault();
|
305
|
+
event.stopPropagation();
|
274
306
|
break;
|
275
307
|
case KEYS.HOME:
|
276
308
|
this.openPopover();
|
@@ -332,24 +364,7 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
332
364
|
}
|
333
365
|
return -1;
|
334
366
|
}
|
335
|
-
updateActivedescendant(target) {
|
336
|
-
var _a, _b, _c, _d, _e;
|
337
|
-
const options = this.getAllValidOptions();
|
338
|
-
if (target) {
|
339
|
-
const currentIndex = options.findIndex(option => option === target);
|
340
|
-
this.activeDescendant = (_b = (_a = options[currentIndex]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '';
|
341
|
-
}
|
342
|
-
else {
|
343
|
-
// If no target is provided, find the option with tabindex="0" or the first option
|
344
|
-
const focusedOption = options.find(option => option.getAttribute('tabindex') === '0');
|
345
|
-
this.activeDescendant = (_e = (_c = focusedOption === null || focusedOption === void 0 ? void 0 : focusedOption.id) !== null && _c !== void 0 ? _c : (_d = options[0]) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : '';
|
346
|
-
}
|
347
|
-
}
|
348
|
-
resetActivedescendant() {
|
349
|
-
this.activeDescendant = '';
|
350
|
-
}
|
351
367
|
setFocusAndTabIndex(newIndex) {
|
352
|
-
var _a;
|
353
368
|
const options = this.getAllValidOptions();
|
354
369
|
const targetOption = options[newIndex];
|
355
370
|
if (targetOption) {
|
@@ -358,30 +373,24 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
358
373
|
const newTabindex = newIndex === index ? '0' : '-1';
|
359
374
|
node === null || node === void 0 ? void 0 : node.setAttribute('tabindex', newTabindex);
|
360
375
|
});
|
361
|
-
// Update activeDescendant after changing focus
|
362
|
-
this.activeDescendant = (_a = targetOption.id) !== null && _a !== void 0 ? _a : '';
|
363
376
|
}
|
364
377
|
}
|
365
378
|
openPopover() {
|
366
|
-
var _a, _b;
|
367
379
|
this.displayPopover = true;
|
368
|
-
|
369
|
-
const options = this.getAllValidOptions();
|
370
|
-
const selectedOption = options.find(option => option.hasAttribute('selected'));
|
371
|
-
const focusedOption = options.find(option => option.getAttribute('tabindex') === '0');
|
372
|
-
// Set activeDescendant to the selected/focused option or first option
|
373
|
-
this.activeDescendant = (_b = (_a = (selectedOption || focusedOption || options[0])) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '';
|
380
|
+
this.baseIconName = ARROW_ICON.ARROW_UP;
|
374
381
|
}
|
375
382
|
closePopover() {
|
376
383
|
this.displayPopover = false;
|
377
|
-
this.
|
384
|
+
this.baseIconName = ARROW_ICON.ARROW_DOWN;
|
378
385
|
}
|
379
386
|
/**
|
380
387
|
* Handles the first updated lifecycle event.
|
381
388
|
* If an option is selected, use that as the value.
|
382
389
|
* If not, use the placeholder if it exists, otherwise use the first option.
|
383
390
|
*/
|
384
|
-
firstUpdated() {
|
391
|
+
async firstUpdated() {
|
392
|
+
await this.updateComplete;
|
393
|
+
this.modifyListBoxWrapper();
|
385
394
|
const options = this.getAllValidOptions();
|
386
395
|
const selectedOptionIndex = options.findIndex(option => option === null || option === void 0 ? void 0 : option.hasAttribute('selected'));
|
387
396
|
if (selectedOptionIndex !== -1) {
|
@@ -399,122 +408,75 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
399
408
|
this.manageRequired();
|
400
409
|
}
|
401
410
|
}
|
402
|
-
/**
|
403
|
-
* Generates the native select element.
|
404
|
-
* The native select element is not rendered directly and is not visible on the UI.
|
405
|
-
* It's rendered only on the DOM for accessibility purposes.
|
406
|
-
* Instead, the overlay uses the native select element to generate the list of options.
|
407
|
-
* @returns A TemplateResult representing the native select element.
|
408
|
-
*/
|
409
|
-
getNativeSelect() {
|
410
|
-
return html `
|
411
|
-
<select
|
412
|
-
part="native-select"
|
413
|
-
id="${this.id}"
|
414
|
-
tabindex="-1"
|
415
|
-
aria-hidden="true"
|
416
|
-
name="${this.name}"
|
417
|
-
size="1"
|
418
|
-
.value="${this.selectedValue}"
|
419
|
-
?autofocus="${this.autofocus}"
|
420
|
-
?disabled="${this.disabled}"
|
421
|
-
?required="${this.required}"
|
422
|
-
@mousedown="${(event) => event.preventDefault()}"
|
423
|
-
>
|
424
|
-
${this.getOptionsContentFromSlot()}
|
425
|
-
</select>
|
426
|
-
`;
|
427
|
-
}
|
428
|
-
/**
|
429
|
-
* This method maps over all valid options and constructs their corresponding
|
430
|
-
* HTML `<option>` elements. The attributes such as `value`, `label`, `disabled`,
|
431
|
-
* and `selected` are extracted from the respective option elements.
|
432
|
-
* If the attribute is not present, a default value or fallback is used.
|
433
|
-
* The content of each `<option>` is set to the text content of the option element.
|
434
|
-
* @returns An array of `TemplateResult` representing the option elements.
|
435
|
-
*/
|
436
|
-
getOptionsContentFromSlot() {
|
437
|
-
return this.getAllValidOptions().map(option => {
|
438
|
-
var _a, _b;
|
439
|
-
return html `
|
440
|
-
<option
|
441
|
-
part="native-select"
|
442
|
-
value="${(_a = option.getAttribute('value')) !== null && _a !== void 0 ? _a : ''}"
|
443
|
-
label="${(_b = option.getAttribute('label')) !== null && _b !== void 0 ? _b : ''}"
|
444
|
-
?disabled="${!!option.hasAttribute('disabled')}"
|
445
|
-
?selected="${!!option.hasAttribute('selected')}"
|
446
|
-
>
|
447
|
-
${option.textContent}
|
448
|
-
</option>
|
449
|
-
`;
|
450
|
-
});
|
451
|
-
}
|
452
|
-
/**
|
453
|
-
* Generates the content for the popover associated with the select component.
|
454
|
-
* If the component is disabled or readonly, returns `nothing`.
|
455
|
-
* Otherwise, returns a `TemplateResult` that renders a popover with various configurations
|
456
|
-
* such as visibility, interaction, and event handlers.
|
457
|
-
* The popover acts as a dropdown list with options, allowing user interaction.
|
458
|
-
*/
|
459
|
-
getPopoverContent() {
|
460
|
-
if (this.disabled || this.readonly) {
|
461
|
-
return nothing;
|
462
|
-
}
|
463
|
-
return html `
|
464
|
-
<mdc-popover
|
465
|
-
id="options-popover"
|
466
|
-
triggerid="${TRIGGER_ID}"
|
467
|
-
@keydown="${this.handlePopoverOnOpen}"
|
468
|
-
interactive
|
469
|
-
?visible="${this.displayPopover}"
|
470
|
-
hide-on-outside-click
|
471
|
-
hide-on-escape
|
472
|
-
focus-back-to-trigger
|
473
|
-
focus-trap
|
474
|
-
role="${ROLE.LISTBOX}"
|
475
|
-
placement="${POPOVER_PLACEMENT.BOTTOM_START}"
|
476
|
-
@shown="${this.handlePopoverOpen}"
|
477
|
-
@hidden="${this.handlePopoverClose}"
|
478
|
-
style="--mdc-popover-max-width: 100%; --mdc-popover-max-height: ${this.height};"
|
479
|
-
>
|
480
|
-
<slot @click="${this.handleOptionsClick}"></slot>
|
481
|
-
</mdc-popover>
|
482
|
-
`;
|
483
|
-
}
|
484
411
|
updated(changedProperties) {
|
485
412
|
super.updated(changedProperties);
|
486
|
-
if (changedProperties.has('disabled') ||
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
if (changedProperties.has('displayPopover')) {
|
491
|
-
if (this.displayPopover) {
|
492
|
-
this.openPopover();
|
493
|
-
}
|
494
|
-
else {
|
413
|
+
if (changedProperties.has('disabled') ||
|
414
|
+
changedProperties.has('softDisabled') ||
|
415
|
+
changedProperties.has('readonly')) {
|
416
|
+
if (this.disabled || this.softDisabled || this.readonly) {
|
495
417
|
this.closePopover();
|
496
418
|
}
|
497
419
|
}
|
420
|
+
if (changedProperties.has('dataAriaLabel')) {
|
421
|
+
this.modifyListBoxWrapper();
|
422
|
+
}
|
423
|
+
}
|
424
|
+
handleOnChange() {
|
425
|
+
this.selectedValue = this.inputElement.value;
|
426
|
+
this.internals.setFormValue(this.selectedValue);
|
498
427
|
}
|
499
428
|
render() {
|
500
429
|
var _a, _b;
|
501
430
|
return html `
|
502
431
|
${this.renderLabel()}
|
503
432
|
<div part="container">
|
433
|
+
<select
|
434
|
+
part="native-select"
|
435
|
+
id="${this.id}"
|
436
|
+
tabindex="-1"
|
437
|
+
aria-hidden="true"
|
438
|
+
name="${this.name}"
|
439
|
+
size="1"
|
440
|
+
.value="${live(this.selectedValue)}"
|
441
|
+
?autofocus="${this.autofocus}"
|
442
|
+
?disabled="${this.disabled}"
|
443
|
+
?required="${this.required}"
|
444
|
+
aria-disabled="${ifDefined(this.disabled || this.softDisabled)}"
|
445
|
+
@change="${this.handleOnChange}"
|
446
|
+
@mousedown="${(event) => event.preventDefault()}"
|
447
|
+
>
|
448
|
+
${this.getAllValidOptions().map(option => {
|
449
|
+
var _a, _b;
|
450
|
+
return html `
|
451
|
+
<option
|
452
|
+
part="native-select"
|
453
|
+
value="${(_a = option.getAttribute('value')) !== null && _a !== void 0 ? _a : ''}"
|
454
|
+
label="${(_b = option.getAttribute('label')) !== null && _b !== void 0 ? _b : ''}"
|
455
|
+
?disabled="${!!option.hasAttribute('disabled')}"
|
456
|
+
?selected="${!!option.hasAttribute('selected')}"
|
457
|
+
>
|
458
|
+
${option.textContent}
|
459
|
+
</option>
|
460
|
+
`;
|
461
|
+
})}
|
462
|
+
</select>
|
504
463
|
<div
|
505
464
|
id="${TRIGGER_ID}"
|
506
465
|
part="base-container"
|
507
|
-
@
|
466
|
+
@click="${this.handleClickCombobox}"
|
467
|
+
@keydown="${this.handleKeydownCombobox}"
|
508
468
|
tabindex="${this.disabled ? '-1' : '0'}"
|
509
469
|
class="${this.disabled ? '' : 'mdc-focus-ring'}"
|
510
470
|
role="${ROLE.COMBOBOX}"
|
511
|
-
aria-
|
512
|
-
aria-controls="${ifDefined(this.displayPopover ? 'options-popover' : undefined)}"
|
471
|
+
aria-controls="${LISTBOX_ID}"
|
513
472
|
aria-label="${(_a = this.dataAriaLabel) !== null && _a !== void 0 ? _a : ''}"
|
514
473
|
aria-labelledby="${this.label ? FORMFIELD_DEFAULTS.HEADING_ID : ''}"
|
515
474
|
aria-expanded="${this.displayPopover ? 'true' : 'false'}"
|
475
|
+
aria-haspopup="${ROLE.LISTBOX}"
|
516
476
|
aria-required="${this.required ? 'true' : 'false'}"
|
517
477
|
aria-invalid="${this.helpTextType === VALIDATION.ERROR ? 'true' : 'false'}"
|
478
|
+
aria-disabled="${ifDefined(this.disabled || this.softDisabled)}"
|
479
|
+
aria-readonly="${ifDefined(this.readonly)}"
|
518
480
|
>
|
519
481
|
${this.selectedIcon
|
520
482
|
? html `<mdc-icon length-unit="rem" size="1" name="${this.selectedIcon}" part="selected-icon"></mdc-icon>`
|
@@ -530,7 +492,25 @@ class Select extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
|
|
530
492
|
<mdc-icon size="1" length-unit="rem" name="${this.baseIconName}"></mdc-icon>
|
531
493
|
</div>
|
532
494
|
</div>
|
533
|
-
|
495
|
+
<mdc-popover
|
496
|
+
trigger="manual"
|
497
|
+
triggerid="${TRIGGER_ID}"
|
498
|
+
@keydown="${this.handlePopoverOnOpen}"
|
499
|
+
interactive
|
500
|
+
?visible="${this.displayPopover}"
|
501
|
+
role=""
|
502
|
+
hide-on-outside-click
|
503
|
+
hide-on-escape
|
504
|
+
focus-back-to-trigger
|
505
|
+
focus-trap
|
506
|
+
size
|
507
|
+
placement="${this.placement}"
|
508
|
+
@closebyescape="${this.closePopover}"
|
509
|
+
@closebyoutsideclick="${this.closePopover}"
|
510
|
+
style="--mdc-popover-max-width: 100%; --mdc-popover-max-height: ${this.height};"
|
511
|
+
>
|
512
|
+
<slot @click="${this.handleOptionsClick}"></slot>
|
513
|
+
</mdc-popover>
|
534
514
|
</div>
|
535
515
|
${this.renderHelperText()}
|
536
516
|
`;
|
@@ -550,9 +530,17 @@ __decorate([
|
|
550
530
|
__metadata("design:type", Object)
|
551
531
|
], Select.prototype, "height", void 0);
|
552
532
|
__decorate([
|
553
|
-
|
533
|
+
property({ type: String, reflect: true }),
|
534
|
+
__metadata("design:type", String)
|
535
|
+
], Select.prototype, "placement", void 0);
|
536
|
+
__decorate([
|
537
|
+
property({ type: Boolean, attribute: 'soft-disabled' }),
|
538
|
+
__metadata("design:type", Boolean)
|
539
|
+
], Select.prototype, "softDisabled", void 0);
|
540
|
+
__decorate([
|
541
|
+
queryAssignedElements({ selector: 'mdc-selectlistbox' }),
|
554
542
|
__metadata("design:type", Array)
|
555
|
-
], Select.prototype, "
|
543
|
+
], Select.prototype, "slottedListboxes", void 0);
|
556
544
|
__decorate([
|
557
545
|
state(),
|
558
546
|
__metadata("design:type", String)
|
@@ -573,10 +561,6 @@ __decorate([
|
|
573
561
|
state(),
|
574
562
|
__metadata("design:type", Object)
|
575
563
|
], Select.prototype, "displayPopover", void 0);
|
576
|
-
__decorate([
|
577
|
-
state(),
|
578
|
-
__metadata("design:type", Object)
|
579
|
-
], Select.prototype, "activeDescendant", void 0);
|
580
564
|
__decorate([
|
581
565
|
query('select'),
|
582
566
|
__metadata("design:type", HTMLInputElement)
|
@@ -4,4 +4,5 @@ declare const ARROW_ICON: {
|
|
4
4
|
readonly ARROW_DOWN: "arrow-down-bold";
|
5
5
|
};
|
6
6
|
declare const TRIGGER_ID = "select-base-triggerid";
|
7
|
-
|
7
|
+
declare const LISTBOX_ID = "select-listbox";
|
8
|
+
export { ARROW_ICON, TAG_NAME, TRIGGER_ID, LISTBOX_ID };
|
@@ -70,14 +70,25 @@ const styles = css `
|
|
70
70
|
display: flex;
|
71
71
|
padding: 2px;
|
72
72
|
}
|
73
|
-
:host([readonly])::part(icon-container) {
|
74
|
-
color: var(--mdc-select-disabled-text-color);
|
75
|
-
}
|
76
73
|
:host::part(popover-content) {
|
77
74
|
min-width: auto;
|
78
|
-
overflow:
|
75
|
+
overflow-y: auto;
|
76
|
+
}
|
77
|
+
|
78
|
+
/* Help text border colors */
|
79
|
+
:host([help-text-type='success'])::part(base-container) {
|
80
|
+
border-color: var(--mdc-select-success-border-color);
|
81
|
+
}
|
82
|
+
:host([help-text-type='error'])::part(base-container) {
|
83
|
+
border-color: var(--mdc-select-error-border-color);
|
84
|
+
}
|
85
|
+
:host([help-text-type='warning'])::part(base-container) {
|
86
|
+
border-color: var(--mdc-select-warning-border-color);
|
79
87
|
}
|
88
|
+
|
89
|
+
/* Disabled, readonly, soft-disabled */
|
80
90
|
:host([disabled])::part(base-container),
|
91
|
+
:host([soft-disabled])::part(base-container),
|
81
92
|
:host([readonly])::part(base-container),
|
82
93
|
:host([help-text-type='success'][disabled])::part(base-container),
|
83
94
|
:host([help-text-type='error'][disabled])::part(base-container),
|
@@ -88,24 +99,16 @@ const styles = css `
|
|
88
99
|
border-color: var(--mdc-select-disabled-border-color);
|
89
100
|
background: var(--mdc-select-disabled-background-color);
|
90
101
|
}
|
91
|
-
:host([disabled]:hover)::part(base-container),
|
92
|
-
:host([readonly]:hover)::part(base-container) {
|
93
|
-
background-color: unset;
|
94
|
-
}
|
95
102
|
:host([readonly])::part(base-text) {
|
96
103
|
color: var(--mdc-select-selected-text-color);
|
97
104
|
}
|
98
|
-
:host([disabled])::part(base-text)
|
105
|
+
:host([disabled])::part(base-text),
|
106
|
+
:host([soft-disabled])::part(base-text) {
|
99
107
|
color: var(--mdc-select-disabled-text-color);
|
100
108
|
}
|
101
|
-
:host([
|
102
|
-
|
103
|
-
|
104
|
-
:host([help-text-type='error'])::part(base-container) {
|
105
|
-
border-color: var(--mdc-select-error-border-color);
|
106
|
-
}
|
107
|
-
:host([help-text-type='warning'])::part(base-container) {
|
108
|
-
border-color: var(--mdc-select-warning-border-color);
|
109
|
+
:host([soft-disabled])::part(icon-container),
|
110
|
+
:host([readonly])::part(icon-container) {
|
111
|
+
color: var(--mdc-select-disabled-text-color);
|
109
112
|
}
|
110
113
|
`;
|
111
114
|
export default [styles, ...hostFocusRingStyles(true)];
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import type { ValueOf } from '../../utils/types';
|
2
|
+
import type { PopoverPlacement } from '../popover/popover.types';
|
2
3
|
import { ARROW_ICON } from './select.constants';
|
3
4
|
interface Events {
|
4
5
|
onClickEvent: MouseEvent;
|
@@ -7,5 +8,6 @@ interface Events {
|
|
7
8
|
onKeyDownEvent: KeyboardEvent;
|
8
9
|
onFocusEvent: FocusEvent;
|
9
10
|
}
|
11
|
+
type Placement = Extract<PopoverPlacement, 'bottom-start' | 'top-start'>;
|
10
12
|
type ArrowIcon = ValueOf<typeof ARROW_ICON>;
|
11
|
-
export type { Events, ArrowIcon };
|
13
|
+
export type { Events, ArrowIcon, Placement };
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Component } from '../../models';
|
2
|
+
/**
|
3
|
+
* Selectlistbox component as Light DOM component to act as a simple wrapper
|
4
|
+
* for mdc-option components to ensure accessibility and proper role assignment.
|
5
|
+
*
|
6
|
+
* Once [ariaOwnsElements](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/ariaOwnsElements) is supported in browsers, this component can be removed
|
7
|
+
* and mdc-option can be used directly in the select component with a listbox in a different
|
8
|
+
* shadow root and aria-owns attribute to connect them.
|
9
|
+
*
|
10
|
+
* @tagname mdc-selectlistbox
|
11
|
+
*
|
12
|
+
* @slot default - This is a default/unnamed slot, which can be used to insert mdc-option components.
|
13
|
+
*/
|
14
|
+
declare class Selectlistbox extends Component {
|
15
|
+
role: "listbox";
|
16
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment;
|
17
|
+
}
|
18
|
+
export default Selectlistbox;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Component } from '../../models';
|
2
|
+
import { ROLE } from '../../utils/roles';
|
3
|
+
/**
|
4
|
+
* Selectlistbox component as Light DOM component to act as a simple wrapper
|
5
|
+
* for mdc-option components to ensure accessibility and proper role assignment.
|
6
|
+
*
|
7
|
+
* Once [ariaOwnsElements](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/ariaOwnsElements) is supported in browsers, this component can be removed
|
8
|
+
* and mdc-option can be used directly in the select component with a listbox in a different
|
9
|
+
* shadow root and aria-owns attribute to connect them.
|
10
|
+
*
|
11
|
+
* @tagname mdc-selectlistbox
|
12
|
+
*
|
13
|
+
* @slot default - This is a default/unnamed slot, which can be used to insert mdc-option components.
|
14
|
+
*/
|
15
|
+
class Selectlistbox extends Component {
|
16
|
+
constructor() {
|
17
|
+
super(...arguments);
|
18
|
+
this.role = ROLE.LISTBOX;
|
19
|
+
}
|
20
|
+
createRenderRoot() {
|
21
|
+
return this;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
export default Selectlistbox;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|