@vaadin/select 22.0.0-alpha9 → 22.0.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/README.md +32 -31
- package/package.json +15 -15
- package/src/vaadin-select-overlay.js +1 -1
- package/src/vaadin-select-value-button.js +1 -1
- package/src/vaadin-select.d.ts +17 -11
- package/src/vaadin-select.js +82 -43
- package/theme/lumo/vaadin-select-styles.js +15 -7
- package/theme/material/vaadin-select-styles.js +13 -4
package/README.md
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @vaadin/select
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
|
5
|
-
[API documentation ↗](https://vaadin.com/components/vaadin-select/html-api)
|
|
3
|
+
A web component for selecting a single value from a list of options presented in an overlay.
|
|
6
4
|
|
|
7
|
-
[
|
|
5
|
+
[Documentation + Live Demo ↗](https://vaadin.com/docs/latest/ds/components/select)
|
|
8
6
|
|
|
9
7
|
[](https://www.npmjs.com/package/@vaadin/vaadin-select)
|
|
10
|
-
[](https://vaadin.com/directory/component/vaadinvaadin-select)
|
|
11
8
|
[](https://discord.gg/PHmkCKC)
|
|
12
9
|
|
|
13
10
|
```html
|
|
14
|
-
<vaadin-select></vaadin-select>
|
|
11
|
+
<vaadin-select label="Sort by"></vaadin-select>
|
|
15
12
|
<script>
|
|
16
13
|
document.querySelector('vaadin-select').renderer = (root) => {
|
|
17
14
|
if (root.firstElementChild) {
|
|
@@ -19,55 +16,58 @@
|
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
// Note that innerHTML is only used for demo purposes here!
|
|
22
|
-
//
|
|
19
|
+
// Consider using Lit or another template library instead.
|
|
23
20
|
root.innerHTML = `
|
|
24
21
|
<vaadin-list-box>
|
|
25
|
-
<vaadin-item>
|
|
26
|
-
<vaadin-item>
|
|
27
|
-
<vaadin-item>
|
|
28
|
-
<
|
|
29
|
-
<vaadin-item
|
|
22
|
+
<vaadin-item value="recent">Most recent first</vaadin-item>
|
|
23
|
+
<vaadin-item value="rating-desc">Rating: high to low</vaadin-item>
|
|
24
|
+
<vaadin-item value="rating-asc">Rating: low to high</vaadin-item>
|
|
25
|
+
<vaadin-item value="price-desc">Price: high to low</vaadin-item>
|
|
26
|
+
<vaadin-item value="price-asc">Price: low to high</vaadin-item>
|
|
30
27
|
</vaadin-list-box>
|
|
31
28
|
`;
|
|
32
29
|
};
|
|
33
30
|
</script>
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
[<img src="https://raw.githubusercontent.com/vaadin/
|
|
33
|
+
[<img src="https://raw.githubusercontent.com/vaadin/web-components/master/packages/select/screenshot.png" width="231" alt="Screenshot of vaadin-select">](https://vaadin.com/docs/latest/ds/components/select)
|
|
37
34
|
|
|
38
35
|
## Installation
|
|
39
36
|
|
|
40
|
-
Install
|
|
37
|
+
Install the component:
|
|
41
38
|
|
|
42
39
|
```sh
|
|
43
|
-
npm i @vaadin/
|
|
40
|
+
npm i @vaadin/select
|
|
44
41
|
```
|
|
45
42
|
|
|
46
|
-
Once installed, import
|
|
43
|
+
Once installed, import the component in your application:
|
|
47
44
|
|
|
48
45
|
```js
|
|
49
|
-
import '@vaadin/
|
|
46
|
+
import '@vaadin/select';
|
|
50
47
|
```
|
|
51
48
|
|
|
52
|
-
##
|
|
49
|
+
## Themes
|
|
53
50
|
|
|
54
|
-
Vaadin components
|
|
51
|
+
Vaadin components come with two built-in [themes](https://vaadin.com/docs/latest/ds/customization/using-themes), Lumo and Material.
|
|
52
|
+
The [main entrypoint](https://github.com/vaadin/web-components/blob/master/packages/select/vaadin-select.js) of the package uses the Lumo theme.
|
|
55
53
|
|
|
56
|
-
To use the Material theme, import the
|
|
54
|
+
To use the Material theme, import the component from the `theme/material` folder:
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`theme/lumo/vaadin-select.js`
|
|
56
|
+
```js
|
|
57
|
+
import '@vaadin/select/theme/material/vaadin-select.js';
|
|
58
|
+
```
|
|
63
59
|
|
|
64
|
-
|
|
60
|
+
You can also import the Lumo version of the component explicitly:
|
|
65
61
|
|
|
66
|
-
|
|
62
|
+
```js
|
|
63
|
+
import '@vaadin/select/theme/lumo/vaadin-select.js';
|
|
64
|
+
```
|
|
67
65
|
|
|
68
|
-
-
|
|
66
|
+
Finally, you can import the un-themed component from the `src` folder to get a minimal starting point:
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
```js
|
|
69
|
+
import '@vaadin/select/src/vaadin-select.js';
|
|
70
|
+
```
|
|
71
71
|
|
|
72
72
|
## Contributing
|
|
73
73
|
|
|
@@ -77,4 +77,5 @@ Read the [contributing guide](https://vaadin.com/docs/latest/guide/contributing/
|
|
|
77
77
|
|
|
78
78
|
Apache License 2.0
|
|
79
79
|
|
|
80
|
-
Vaadin collects development time
|
|
80
|
+
Vaadin collects usage statistics at development time to improve this product.
|
|
81
|
+
For details and to opt-out, see https://github.com/vaadin/vaadin-usage-statistics.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/select",
|
|
3
|
-
"version": "22.0.0
|
|
3
|
+
"version": "22.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -34,24 +34,24 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@polymer/iron-media-query": "^3.0.0",
|
|
36
36
|
"@polymer/polymer": "^3.2.0",
|
|
37
|
-
"@vaadin/button": "22.0.0
|
|
38
|
-
"@vaadin/component-base": "22.0.0
|
|
39
|
-
"@vaadin/field-base": "22.0.0
|
|
40
|
-
"@vaadin/input-container": "22.0.0
|
|
41
|
-
"@vaadin/item": "22.0.0
|
|
42
|
-
"@vaadin/list-box": "22.0.0
|
|
43
|
-
"@vaadin/vaadin-list-mixin": "22.0.0
|
|
44
|
-
"@vaadin/vaadin-lumo-styles": "22.0.0
|
|
45
|
-
"@vaadin/vaadin-material-styles": "22.0.0
|
|
46
|
-
"@vaadin/vaadin-overlay": "22.0.0
|
|
47
|
-
"@vaadin/vaadin-themable-mixin": "22.0.0
|
|
37
|
+
"@vaadin/button": "^22.0.0",
|
|
38
|
+
"@vaadin/component-base": "^22.0.0",
|
|
39
|
+
"@vaadin/field-base": "^22.0.0",
|
|
40
|
+
"@vaadin/input-container": "^22.0.0",
|
|
41
|
+
"@vaadin/item": "^22.0.0",
|
|
42
|
+
"@vaadin/list-box": "^22.0.0",
|
|
43
|
+
"@vaadin/vaadin-list-mixin": "^22.0.0",
|
|
44
|
+
"@vaadin/vaadin-lumo-styles": "^22.0.0",
|
|
45
|
+
"@vaadin/vaadin-material-styles": "^22.0.0",
|
|
46
|
+
"@vaadin/vaadin-overlay": "^22.0.0",
|
|
47
|
+
"@vaadin/vaadin-themable-mixin": "^22.0.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@esm-bundle/chai": "^4.3.4",
|
|
51
|
-
"@vaadin/polymer-legacy-adapter": "22.0.0
|
|
52
|
-
"@vaadin/testing-helpers": "^0.3.
|
|
51
|
+
"@vaadin/polymer-legacy-adapter": "^22.0.0",
|
|
52
|
+
"@vaadin/testing-helpers": "^0.3.2",
|
|
53
53
|
"lit": "^2.0.0",
|
|
54
54
|
"sinon": "^9.2.0"
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "b668e9b1a975227fbe34beb70d1cd5b03dce2348"
|
|
57
57
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { OverlayElement } from '@vaadin/vaadin-overlay/src/vaadin-overlay.js';
|
|
7
|
-
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
8
7
|
import { PositionMixin } from '@vaadin/vaadin-overlay/src/vaadin-overlay-position-mixin.js';
|
|
8
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
9
9
|
|
|
10
10
|
registerStyles(
|
|
11
11
|
'vaadin-select-overlay',
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { Button } from '@vaadin/button/src/vaadin-button.js';
|
|
7
|
-
import {
|
|
7
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
8
8
|
|
|
9
9
|
registerStyles(
|
|
10
10
|
'vaadin-select-value-button',
|
package/src/vaadin-select.d.ts
CHANGED
|
@@ -92,23 +92,25 @@ export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMa
|
|
|
92
92
|
* `--vaadin-field-default-width` | Default width of the field | :host | `12em`
|
|
93
93
|
* `--vaadin-select-text-field-width` | Effective width of the field | `vaadin-select-overlay` |
|
|
94
94
|
*
|
|
95
|
-
*
|
|
95
|
+
* `<vaadin-select>` provides mostly the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
|
|
96
|
+
* See [`<vaadin-text-field>`](#/elements/vaadin-text-field) for the styling documentation.
|
|
96
97
|
*
|
|
97
|
-
*
|
|
98
|
+
*
|
|
99
|
+
* In addition to `<vaadin-text-field>` parts, the following parts are available for theming:
|
|
100
|
+
*
|
|
101
|
+
* Part name | Description
|
|
98
102
|
* ----------------|----------------
|
|
99
103
|
* `toggle-button` | The toggle button
|
|
100
104
|
*
|
|
101
|
-
*
|
|
105
|
+
* In addition to `<vaadin-text-field>` state attributes, the following state attributes are available for theming:
|
|
102
106
|
*
|
|
103
|
-
* Attribute
|
|
104
|
-
*
|
|
105
|
-
* `opened`
|
|
106
|
-
* `invalid` | Set when the element is invalid | :host
|
|
107
|
-
* `focused` | Set when the element is focused | :host
|
|
108
|
-
* `focus-ring` | Set when the element is keyboard focused | :host
|
|
109
|
-
* `readonly` | Set when the select is read only | :host
|
|
107
|
+
* Attribute | Description | Part name
|
|
108
|
+
* ----------|-----------------------------|-----------
|
|
109
|
+
* `opened` | Set when the select is open | :host
|
|
110
110
|
*
|
|
111
|
-
*
|
|
111
|
+
* There are two exceptions in terms of styling compared to `<vaadin-text-field>`:
|
|
112
|
+
* - the `clear-button` shadow DOM part does not exist in `<vaadin-select>`.
|
|
113
|
+
* - the `input-prevented` state attribute is not supported by `<vaadin-select>`.
|
|
112
114
|
*
|
|
113
115
|
* ### Internal components
|
|
114
116
|
*
|
|
@@ -116,10 +118,14 @@ export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMa
|
|
|
116
118
|
* components are themable:
|
|
117
119
|
*
|
|
118
120
|
* - `<vaadin-select-overlay>` - has the same API as [`<vaadin-overlay>`](#/elements/vaadin-overlay).
|
|
121
|
+
* - `<vaadin-select-value-button>` - has the same API as [`<vaadin-button>`](#/elements/vaadin-button).
|
|
122
|
+
* - [`<vaadin-input-container>`](#/elements/vaadin-input-container) - an internal element wrapping the button.
|
|
119
123
|
*
|
|
120
124
|
* Note: the `theme` attribute value set on `<vaadin-select>` is
|
|
121
125
|
* propagated to the internal components listed above.
|
|
122
126
|
*
|
|
127
|
+
* See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
|
|
128
|
+
*
|
|
123
129
|
* @fires {Event} change - Fired when the user commits a value change.
|
|
124
130
|
* @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
|
|
125
131
|
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
|
package/src/vaadin-select.js
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
|
|
7
6
|
import '@polymer/iron-media-query/iron-media-query.js';
|
|
7
|
+
import '@vaadin/input-container/src/vaadin-input-container.js';
|
|
8
|
+
import './vaadin-select-overlay.js';
|
|
9
|
+
import './vaadin-select-value-button.js';
|
|
10
|
+
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
8
11
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
9
12
|
import { SlotMixin } from '@vaadin/component-base/src/slot-mixin.js';
|
|
10
13
|
import { processTemplates } from '@vaadin/component-base/src/templates.js';
|
|
@@ -12,11 +15,7 @@ import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.
|
|
|
12
15
|
import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
|
|
13
16
|
import { fieldShared } from '@vaadin/field-base/src/styles/field-shared-styles.js';
|
|
14
17
|
import { inputFieldContainer } from '@vaadin/field-base/src/styles/input-field-container-styles.js';
|
|
15
|
-
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
16
|
-
import { registerStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
17
|
-
import '@vaadin/input-container/src/vaadin-input-container.js';
|
|
18
|
-
import './vaadin-select-overlay.js';
|
|
19
|
-
import './vaadin-select-value-button.js';
|
|
18
|
+
import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
20
19
|
|
|
21
20
|
registerStyles('vaadin-select', [fieldShared, inputFieldContainer], { moduleId: 'vaadin-select-styles' });
|
|
22
21
|
|
|
@@ -68,23 +67,25 @@ registerStyles('vaadin-select', [fieldShared, inputFieldContainer], { moduleId:
|
|
|
68
67
|
* `--vaadin-field-default-width` | Default width of the field | :host | `12em`
|
|
69
68
|
* `--vaadin-select-text-field-width` | Effective width of the field | `vaadin-select-overlay` |
|
|
70
69
|
*
|
|
71
|
-
*
|
|
70
|
+
* `<vaadin-select>` provides mostly the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
|
|
71
|
+
* See [`<vaadin-text-field>`](#/elements/vaadin-text-field) for the styling documentation.
|
|
72
|
+
*
|
|
72
73
|
*
|
|
73
|
-
*
|
|
74
|
+
* In addition to `<vaadin-text-field>` parts, the following parts are available for theming:
|
|
75
|
+
*
|
|
76
|
+
* Part name | Description
|
|
74
77
|
* ----------------|----------------
|
|
75
78
|
* `toggle-button` | The toggle button
|
|
76
79
|
*
|
|
77
|
-
*
|
|
80
|
+
* In addition to `<vaadin-text-field>` state attributes, the following state attributes are available for theming:
|
|
78
81
|
*
|
|
79
|
-
* Attribute
|
|
80
|
-
*
|
|
81
|
-
* `opened`
|
|
82
|
-
* `invalid` | Set when the element is invalid | :host
|
|
83
|
-
* `focused` | Set when the element is focused | :host
|
|
84
|
-
* `focus-ring` | Set when the element is keyboard focused | :host
|
|
85
|
-
* `readonly` | Set when the select is read only | :host
|
|
82
|
+
* Attribute | Description | Part name
|
|
83
|
+
* ----------|-----------------------------|-----------
|
|
84
|
+
* `opened` | Set when the select is open | :host
|
|
86
85
|
*
|
|
87
|
-
*
|
|
86
|
+
* There are two exceptions in terms of styling compared to `<vaadin-text-field>`:
|
|
87
|
+
* - the `clear-button` shadow DOM part does not exist in `<vaadin-select>`.
|
|
88
|
+
* - the `input-prevented` state attribute is not supported by `<vaadin-select>`.
|
|
88
89
|
*
|
|
89
90
|
* ### Internal components
|
|
90
91
|
*
|
|
@@ -92,10 +93,14 @@ registerStyles('vaadin-select', [fieldShared, inputFieldContainer], { moduleId:
|
|
|
92
93
|
* components are themable:
|
|
93
94
|
*
|
|
94
95
|
* - `<vaadin-select-overlay>` - has the same API as [`<vaadin-overlay>`](#/elements/vaadin-overlay).
|
|
96
|
+
* - `<vaadin-select-value-button>` - has the same API as [`<vaadin-button>`](#/elements/vaadin-button).
|
|
97
|
+
* - [`<vaadin-input-container>`](#/elements/vaadin-input-container) - an internal element wrapping the button.
|
|
95
98
|
*
|
|
96
99
|
* Note: the `theme` attribute value set on `<vaadin-select>` is
|
|
97
100
|
* propagated to the internal components listed above.
|
|
98
101
|
*
|
|
102
|
+
* See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
|
|
103
|
+
*
|
|
99
104
|
* @fires {Event} change - Fired when the user commits a value change.
|
|
100
105
|
* @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
|
|
101
106
|
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
|
|
@@ -123,7 +128,7 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
123
128
|
</style>
|
|
124
129
|
|
|
125
130
|
<div class="vaadin-select-container">
|
|
126
|
-
<div part="label">
|
|
131
|
+
<div part="label" on-click="_onClick">
|
|
127
132
|
<slot name="label"></slot>
|
|
128
133
|
<span part="required-indicator" aria-hidden="true" on-click="focus"></span>
|
|
129
134
|
</div>
|
|
@@ -338,8 +343,15 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
338
343
|
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
339
344
|
*/
|
|
340
345
|
requestContentUpdate() {
|
|
346
|
+
if (!this._overlayElement) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
341
350
|
this._overlayElement.requestContentUpdate();
|
|
342
351
|
|
|
352
|
+
// Ensure menu element is set
|
|
353
|
+
this._assignMenuElement();
|
|
354
|
+
|
|
343
355
|
if (this._menuElement && this._menuElement.items) {
|
|
344
356
|
this._updateSelectedItem(this.value, this._menuElement.items);
|
|
345
357
|
}
|
|
@@ -362,18 +374,19 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
362
374
|
|
|
363
375
|
/** @private */
|
|
364
376
|
_assignMenuElement() {
|
|
365
|
-
|
|
366
|
-
(element) => element.localName !== 'style'
|
|
367
|
-
);
|
|
377
|
+
const menuElement = this.__getMenuElement();
|
|
368
378
|
|
|
369
|
-
if (this.
|
|
370
|
-
this._menuElement
|
|
371
|
-
|
|
379
|
+
if (menuElement && menuElement !== this.__lastMenuElement) {
|
|
380
|
+
this._menuElement = menuElement;
|
|
381
|
+
menuElement.addEventListener('items-changed', () => {
|
|
382
|
+
this._items = menuElement.items;
|
|
372
383
|
this._items.forEach((item) => item.setAttribute('role', 'option'));
|
|
373
384
|
});
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
385
|
+
menuElement.addEventListener('selected-changed', () => this.__updateValueButton());
|
|
386
|
+
// Use capture phase to make it possible for `<vaadin-grid-pro-edit-select>`
|
|
387
|
+
// to override and handle the keydown event before the value change happens.
|
|
388
|
+
menuElement.addEventListener('keydown', (e) => this._onKeyDownInside(e), true);
|
|
389
|
+
menuElement.addEventListener(
|
|
377
390
|
'click',
|
|
378
391
|
() => {
|
|
379
392
|
this.__userInteraction = true;
|
|
@@ -382,10 +395,19 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
382
395
|
true
|
|
383
396
|
);
|
|
384
397
|
|
|
385
|
-
|
|
398
|
+
menuElement.setAttribute('role', 'listbox');
|
|
399
|
+
|
|
400
|
+
// Store the menu element reference
|
|
401
|
+
this.__lastMenuElement = menuElement;
|
|
386
402
|
}
|
|
387
403
|
}
|
|
388
404
|
|
|
405
|
+
/** @private */
|
|
406
|
+
__getMenuElement() {
|
|
407
|
+
const content = this._overlayElement && this._overlayElement.content;
|
|
408
|
+
return content ? Array.from(content.children).find((el) => el.localName !== 'style') : null;
|
|
409
|
+
}
|
|
410
|
+
|
|
389
411
|
/** @private */
|
|
390
412
|
_valueChanged(value, oldValue) {
|
|
391
413
|
this.toggleAttribute('has-value', Boolean(value));
|
|
@@ -397,12 +419,13 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
397
419
|
this.validate();
|
|
398
420
|
}
|
|
399
421
|
|
|
400
|
-
/**
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
422
|
+
/**
|
|
423
|
+
* Opens the overlay if the field is not read-only.
|
|
424
|
+
*
|
|
425
|
+
* @private
|
|
426
|
+
*/
|
|
427
|
+
_onClick() {
|
|
428
|
+
this.opened = !this.readonly;
|
|
406
429
|
}
|
|
407
430
|
|
|
408
431
|
/**
|
|
@@ -414,13 +437,16 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
414
437
|
if (/^(Enter|SpaceBar|\s|ArrowDown|Down|ArrowUp|Up)$/.test(e.key)) {
|
|
415
438
|
e.preventDefault();
|
|
416
439
|
this.opened = true;
|
|
417
|
-
} else if (/[
|
|
440
|
+
} else if (/[\p{L}\p{Nd}]/u.test(e.key) && e.key.length === 1) {
|
|
418
441
|
const selected = this._menuElement.selected;
|
|
419
442
|
const currentIdx = selected !== undefined ? selected : -1;
|
|
420
443
|
const newIdx = this._menuElement._searchKey(currentIdx, e.key);
|
|
421
444
|
if (newIdx >= 0) {
|
|
422
445
|
this.__userInteraction = true;
|
|
423
|
-
|
|
446
|
+
|
|
447
|
+
// Announce the value selected with the first letter shortcut
|
|
448
|
+
this._updateAriaLive(true);
|
|
449
|
+
this._menuElement.selected = newIdx;
|
|
424
450
|
}
|
|
425
451
|
}
|
|
426
452
|
}
|
|
@@ -439,6 +465,9 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
439
465
|
/** @private */
|
|
440
466
|
_openedChanged(opened, wasOpened) {
|
|
441
467
|
if (opened) {
|
|
468
|
+
// Avoid multiple announcements when a value gets selected from the dropdown
|
|
469
|
+
this._updateAriaLive(false);
|
|
470
|
+
|
|
442
471
|
if (!this._overlayElement || !this._menuElement || !this.focusElement || this.disabled || this.readonly) {
|
|
443
472
|
this.opened = false;
|
|
444
473
|
return;
|
|
@@ -460,13 +489,9 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
460
489
|
|
|
461
490
|
this._menuElement.focus();
|
|
462
491
|
} else if (wasOpened) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
this.focus();
|
|
467
|
-
if (this._openedWithFocusRing) {
|
|
468
|
-
this.setAttribute('focus-ring', '');
|
|
469
|
-
}
|
|
492
|
+
this.focus();
|
|
493
|
+
if (this._openedWithFocusRing) {
|
|
494
|
+
this.setAttribute('focus-ring', '');
|
|
470
495
|
}
|
|
471
496
|
this.validate();
|
|
472
497
|
}
|
|
@@ -486,6 +511,17 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
486
511
|
}
|
|
487
512
|
}
|
|
488
513
|
|
|
514
|
+
/** @private */
|
|
515
|
+
_updateAriaLive(ariaLive) {
|
|
516
|
+
if (this._valueButton) {
|
|
517
|
+
if (ariaLive) {
|
|
518
|
+
this._valueButton.setAttribute('aria-live', 'polite');
|
|
519
|
+
} else {
|
|
520
|
+
this._valueButton.removeAttribute('aria-live');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
489
525
|
/** @private */
|
|
490
526
|
__attachSelectedItem(selected) {
|
|
491
527
|
let labelItem;
|
|
@@ -532,10 +568,13 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
532
568
|
|
|
533
569
|
const selected = this._items[this._menuElement.selected];
|
|
534
570
|
|
|
571
|
+
this._valueButton.removeAttribute('placeholder');
|
|
572
|
+
|
|
535
573
|
if (!selected) {
|
|
536
574
|
if (this.placeholder) {
|
|
537
575
|
const item = this.__createItem(this.placeholder);
|
|
538
576
|
this.__appendItem(item);
|
|
577
|
+
this._valueButton.setAttribute('placeholder', '');
|
|
539
578
|
}
|
|
540
579
|
} else {
|
|
541
580
|
this.__attachSelectedItem(selected);
|
|
@@ -3,33 +3,37 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
7
6
|
import '@vaadin/vaadin-lumo-styles/sizing.js';
|
|
8
7
|
import '@vaadin/vaadin-lumo-styles/style.js';
|
|
9
8
|
import '@vaadin/vaadin-lumo-styles/font-icons.js';
|
|
10
|
-
import { menuOverlay } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js';
|
|
11
9
|
import { inputFieldShared } from '@vaadin/vaadin-lumo-styles/mixins/input-field-shared.js';
|
|
10
|
+
import { menuOverlay } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js';
|
|
11
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
12
12
|
|
|
13
13
|
const select = css`
|
|
14
14
|
:host(:not([theme*='align'])) ::slotted([slot='value']) {
|
|
15
15
|
text-align: start;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
[part='input-field'] {
|
|
19
|
+
cursor: var(--lumo-clickable-cursor);
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
[part='input-field'] ::slotted([slot='value']) {
|
|
19
23
|
font-weight: 500;
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
[part='input-field'] ::slotted([slot='value']:not([placeholder])) {
|
|
27
|
+
color: var(--lumo-body-text-color);
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
/* placeholder styles */
|
|
23
|
-
|
|
31
|
+
[part='input-field'] ::slotted([slot='value'][placeholder]) {
|
|
24
32
|
color: inherit;
|
|
25
33
|
transition: opacity 0.175s 0.1s;
|
|
26
34
|
opacity: 0.5;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
:host([has-value]) [part='input-field'] ::slotted([slot='value']) {
|
|
30
|
-
color: var(--lumo-body-text-color);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
37
|
[part='toggle-button']::before {
|
|
34
38
|
content: var(--lumo-icons-dropdown);
|
|
35
39
|
}
|
|
@@ -62,6 +66,10 @@ registerStyles(
|
|
|
62
66
|
:host([focus-ring]) {
|
|
63
67
|
box-shadow: none;
|
|
64
68
|
}
|
|
69
|
+
|
|
70
|
+
::slotted(vaadin-item:hover) {
|
|
71
|
+
background-color: transparent;
|
|
72
|
+
}
|
|
65
73
|
`,
|
|
66
74
|
{ moduleId: 'lumo-select-value-button' }
|
|
67
75
|
);
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
7
6
|
import '@vaadin/vaadin-material-styles/font-icons.js';
|
|
8
|
-
import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js';
|
|
9
7
|
import { inputFieldShared } from '@vaadin/vaadin-material-styles/mixins/input-field-shared.js';
|
|
8
|
+
import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js';
|
|
9
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
10
10
|
|
|
11
11
|
const select = css`
|
|
12
12
|
:host {
|
|
@@ -15,13 +15,13 @@ const select = css`
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/* placeholder styles */
|
|
18
|
-
:host
|
|
18
|
+
:host [part='input-field'] ::slotted([slot='value'][placeholder]) {
|
|
19
19
|
color: var(--material-disabled-text-color);
|
|
20
20
|
transition: opacity 0.175s 0.1s;
|
|
21
21
|
opacity: 1;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
:host
|
|
24
|
+
:host [part='input-field'] ::slotted([slot='value']) {
|
|
25
25
|
color: var(--material-body-text-color);
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -53,6 +53,15 @@ registerStyles(
|
|
|
53
53
|
:host::after {
|
|
54
54
|
display: none;
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
::slotted(vaadin-item) {
|
|
58
|
+
font: inherit;
|
|
59
|
+
padding: 4px 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
::slotted(vaadin-item:hover) {
|
|
63
|
+
background-color: transparent;
|
|
64
|
+
}
|
|
56
65
|
`,
|
|
57
66
|
{ moduleId: 'material-select-value-button' }
|
|
58
67
|
);
|