@vaadin/select 22.0.2 → 23.0.0-alpha4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/select",
3
- "version": "22.0.2",
3
+ "version": "23.0.0-alpha4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -18,6 +18,7 @@
18
18
  },
19
19
  "main": "vaadin-select.js",
20
20
  "module": "vaadin-select.js",
21
+ "type": "module",
21
22
  "files": [
22
23
  "src",
23
24
  "theme",
@@ -34,24 +35,24 @@
34
35
  "dependencies": {
35
36
  "@polymer/iron-media-query": "^3.0.0",
36
37
  "@polymer/polymer": "^3.2.0",
37
- "@vaadin/button": "^22.0.2",
38
- "@vaadin/component-base": "^22.0.2",
39
- "@vaadin/field-base": "^22.0.2",
40
- "@vaadin/input-container": "^22.0.2",
41
- "@vaadin/item": "^22.0.2",
42
- "@vaadin/list-box": "^22.0.2",
43
- "@vaadin/vaadin-list-mixin": "^22.0.2",
44
- "@vaadin/vaadin-lumo-styles": "^22.0.2",
45
- "@vaadin/vaadin-material-styles": "^22.0.2",
46
- "@vaadin/vaadin-overlay": "^22.0.2",
47
- "@vaadin/vaadin-themable-mixin": "^22.0.2"
38
+ "@vaadin/button": "23.0.0-alpha4",
39
+ "@vaadin/component-base": "23.0.0-alpha4",
40
+ "@vaadin/field-base": "23.0.0-alpha4",
41
+ "@vaadin/input-container": "23.0.0-alpha4",
42
+ "@vaadin/item": "23.0.0-alpha4",
43
+ "@vaadin/list-box": "23.0.0-alpha4",
44
+ "@vaadin/vaadin-list-mixin": "23.0.0-alpha4",
45
+ "@vaadin/vaadin-lumo-styles": "23.0.0-alpha4",
46
+ "@vaadin/vaadin-material-styles": "23.0.0-alpha4",
47
+ "@vaadin/vaadin-overlay": "23.0.0-alpha4",
48
+ "@vaadin/vaadin-themable-mixin": "23.0.0-alpha4"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@esm-bundle/chai": "^4.3.4",
51
- "@vaadin/polymer-legacy-adapter": "^22.0.2",
52
+ "@vaadin/polymer-legacy-adapter": "23.0.0-alpha4",
52
53
  "@vaadin/testing-helpers": "^0.3.2",
53
54
  "lit": "^2.0.0",
54
55
  "sinon": "^9.2.0"
55
56
  },
56
- "gitHead": "df21370c4a655a38eac11f79686021ab3b0887ad"
57
+ "gitHead": "81e2deee5147bb7c1f4884760f4598613306f1fb"
57
58
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { Item } from '@vaadin/item/src/vaadin-item.js';
7
+
8
+ /**
9
+ * An element used internally by `<vaadin-select>`. Not intended to be used separately.
10
+ *
11
+ * @extends Item
12
+ * @protected
13
+ */
14
+ class SelectItem extends Item {
15
+ static get is() {
16
+ return 'vaadin-select-item';
17
+ }
18
+ }
19
+
20
+ customElements.define(SelectItem.is, SelectItem);
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { ListBox } from '@vaadin/list-box/src/vaadin-list-box.js';
7
+
8
+ /**
9
+ * An element used internally by `<vaadin-select>`. Not intended to be used separately.
10
+ *
11
+ * @extends ListBox
12
+ * @protected
13
+ */
14
+ class SelectListBox extends ListBox {
15
+ static get is() {
16
+ return 'vaadin-select-list-box';
17
+ }
18
+ }
19
+
20
+ customElements.define(SelectListBox.is, SelectListBox);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
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';
@@ -28,6 +28,21 @@ class SelectOverlay extends PositionMixin(OverlayElement) {
28
28
  static get is() {
29
29
  return 'vaadin-select-overlay';
30
30
  }
31
+
32
+ requestContentUpdate() {
33
+ super.requestContentUpdate();
34
+
35
+ if (this.owner) {
36
+ // Ensure menuElement reference is correct.
37
+ const menuElement = this._getMenuElement();
38
+ this.owner._assignMenuElement(menuElement);
39
+ }
40
+ }
41
+
42
+ /** @protected */
43
+ _getMenuElement() {
44
+ return Array.from(this.children).find((el) => el.localName !== 'style');
45
+ }
31
46
  }
32
47
 
33
48
  customElements.define(SelectOverlay.is, SelectOverlay);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
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';
@@ -14,14 +14,14 @@ registerStyles(
14
14
  min-width: 0;
15
15
  }
16
16
 
17
- ::slotted(vaadin-item) {
17
+ ::slotted(:not([slot])) {
18
18
  padding-left: 0;
19
19
  padding-right: 0;
20
20
  flex: auto;
21
21
  }
22
22
 
23
23
  /* placeholder styles */
24
- ::slotted(:not([selected])) {
24
+ ::slotted(:not([slot]):not([selected])) {
25
25
  line-height: normal;
26
26
  }
27
27
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
@@ -9,6 +9,19 @@ import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.
9
9
  import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
10
10
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
11
 
12
+ export interface SelectItem {
13
+ label?: string;
14
+ component?: string;
15
+ disabled?: boolean;
16
+ }
17
+
18
+ /**
19
+ * Fired when the user commits a value change.
20
+ */
21
+ export type SelectChangeEvent = Event & {
22
+ target: Select;
23
+ };
24
+
12
25
  /**
13
26
  * Function for rendering the content of the `<vaadin-select>`.
14
27
  * Receives two arguments:
@@ -42,22 +55,41 @@ export interface SelectCustomEventMap {
42
55
  'value-changed': SelectValueChangedEvent;
43
56
  }
44
57
 
45
- export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMap {}
58
+ export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMap {
59
+ change: SelectChangeEvent;
60
+ }
46
61
 
47
62
  /**
48
63
  * `<vaadin-select>` is a Web Component for selecting values from a list of items.
49
64
  *
65
+ * ### Items
66
+ *
67
+ * Use the `items` property to define possible options for the select:
68
+ *
69
+ * ```html
70
+ * <vaadin-select id="select"></vaadin-select>
71
+ * ```
72
+ * ```js
73
+ * const select = document.querySelector('#select');
74
+ * select.items = [
75
+ * { label: 'Most recent first', value: 'recent' },
76
+ * { component: 'hr' },
77
+ * { label: 'Rating: low to high', value: 'rating-asc' },
78
+ * { label: 'Rating: high to low', value: 'rating-desc' },
79
+ * { component: 'hr' },
80
+ * { label: 'Price: low to high', value: 'price-asc', disabled: true },
81
+ * { label: 'Price: high to low', value: 'price-desc', disabled: true }
82
+ * ];
83
+ * ```
84
+ *
50
85
  * ### Rendering
51
86
  *
52
- * The content of the select can be populated by using the renderer callback function.
87
+ * Alternatively, the content of the select can be populated by using the renderer callback function.
53
88
  *
54
89
  * The renderer function provides `root`, `select` arguments.
55
90
  * Generate DOM content, append it to the `root` element and control the state
56
91
  * of the host element by accessing `select`.
57
92
  *
58
- * ```html
59
- * <vaadin-select id="select"></vaadin-select>
60
- * ```
61
93
  * ```js
62
94
  * const select = document.querySelector('#select');
63
95
  * select.renderer = function(root, select) {
@@ -132,6 +164,29 @@ export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMa
132
164
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
133
165
  */
134
166
  declare class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(ThemableMixin(HTMLElement))))) {
167
+ /**
168
+ * An array containing items that will be rendered as the options of the select.
169
+ *
170
+ * #### Example
171
+ * ```js
172
+ * select.items = [
173
+ * { label: 'Most recent first', value: 'recent' },
174
+ * { component: 'hr' },
175
+ * { label: 'Rating: low to high', value: 'rating-asc' },
176
+ * { label: 'Rating: high to low', value: 'rating-desc' },
177
+ * { component: 'hr' },
178
+ * { label: 'Price: low to high', value: 'price-asc', disabled: true },
179
+ * { label: 'Price: high to low', value: 'price-desc', disabled: true }
180
+ * ];
181
+ * ```
182
+ *
183
+ * Note: each item is rendered by default as the internal `<vaadin-select-item>` that is an extension of `<vaadin-item>`.
184
+ * To render the item with a custom component, provide a tag name by the `component` property.
185
+ *
186
+ * @type {!Array<!SelectItem>}
187
+ */
188
+ items: SelectItem[] | null | undefined;
189
+
135
190
  /**
136
191
  * Set when the select is open
137
192
  */
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import '@polymer/iron-media-query/iron-media-query.js';
7
7
  import '@vaadin/input-container/src/vaadin-input-container.js';
8
+ import './vaadin-select-item.js';
9
+ import './vaadin-select-list-box.js';
8
10
  import './vaadin-select-overlay.js';
9
11
  import './vaadin-select-value-button.js';
10
12
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
@@ -22,17 +24,34 @@ registerStyles('vaadin-select', [fieldShared, inputFieldContainer], { moduleId:
22
24
  /**
23
25
  * `<vaadin-select>` is a Web Component for selecting values from a list of items.
24
26
  *
27
+ * ### Items
28
+ *
29
+ * Use the `items` property to define possible options for the select:
30
+ *
31
+ * ```html
32
+ * <vaadin-select id="select"></vaadin-select>
33
+ * ```
34
+ * ```js
35
+ * const select = document.querySelector('#select');
36
+ * select.items = [
37
+ * { label: 'Most recent first', value: 'recent' },
38
+ * { component: 'hr' },
39
+ * { label: 'Rating: low to high', value: 'rating-asc' },
40
+ * { label: 'Rating: high to low', value: 'rating-desc' },
41
+ * { component: 'hr' },
42
+ * { label: 'Price: low to high', value: 'price-asc', disabled: true },
43
+ * { label: 'Price: high to low', value: 'price-desc', disabled: true }
44
+ * ];
45
+ * ```
46
+ *
25
47
  * ### Rendering
26
48
  *
27
- * The content of the select can be populated by using the renderer callback function.
49
+ * Alternatively, the content of the select can be populated by using the renderer callback function.
28
50
  *
29
51
  * The renderer function provides `root`, `select` arguments.
30
52
  * Generate DOM content, append it to the `root` element and control the state
31
53
  * of the host element by accessing `select`.
32
54
  *
33
- * ```html
34
- * <vaadin-select id="select"></vaadin-select>
35
- * ```
36
55
  * ```js
37
56
  * const select = document.querySelector('#select');
38
57
  * select.renderer = function(root, select) {
@@ -169,6 +188,32 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
169
188
 
170
189
  static get properties() {
171
190
  return {
191
+ /**
192
+ * An array containing items that will be rendered as the options of the select.
193
+ *
194
+ * #### Example
195
+ * ```js
196
+ * select.items = [
197
+ * { label: 'Most recent first', value: 'recent' },
198
+ * { component: 'hr' },
199
+ * { label: 'Rating: low to high', value: 'rating-asc' },
200
+ * { label: 'Rating: high to low', value: 'rating-desc' },
201
+ * { component: 'hr' },
202
+ * { label: 'Price: low to high', value: 'price-asc', disabled: true },
203
+ * { label: 'Price: high to low', value: 'price-desc', disabled: true }
204
+ * ];
205
+ * ```
206
+ *
207
+ * Note: each item is rendered by default as the internal `<vaadin-select-item>` that is an extension of `<vaadin-item>`.
208
+ * To render the item with a custom component, provide a tag name by the `component` property.
209
+ *
210
+ * @type {!Array<!SelectItem>}
211
+ */
212
+ items: {
213
+ type: Array,
214
+ observer: '__itemsChanged'
215
+ },
216
+
172
217
  /**
173
218
  * Set when the select is open
174
219
  * @type {boolean}
@@ -349,33 +394,42 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
349
394
 
350
395
  this._overlayElement.requestContentUpdate();
351
396
 
352
- // Ensure menu element is set
353
- this._assignMenuElement();
354
-
355
397
  if (this._menuElement && this._menuElement.items) {
356
398
  this._updateSelectedItem(this.value, this._menuElement.items);
357
399
  }
358
400
  }
359
401
 
360
- /** @private */
402
+ /**
403
+ * @param {SelectRenderer | undefined | null} renderer
404
+ * @param {SelectOverlay | undefined} overlay
405
+ * @private
406
+ */
361
407
  _rendererChanged(renderer, overlay) {
362
408
  if (!overlay) {
363
409
  return;
364
410
  }
365
411
 
366
- overlay.setProperties({ owner: this, renderer });
412
+ overlay.setProperties({ owner: this, renderer: renderer || this.__defaultRenderer });
367
413
 
368
414
  this.requestContentUpdate();
415
+ }
369
416
 
370
- if (renderer) {
371
- this._assignMenuElement();
417
+ /**
418
+ * @param {SelectItem[] | undefined | null} newItems
419
+ * @param {SelectItem[] | undefined | null} oldItems
420
+ * @private
421
+ */
422
+ __itemsChanged(newItems, oldItems) {
423
+ if (newItems || oldItems) {
424
+ this.requestContentUpdate();
372
425
  }
373
426
  }
374
427
 
375
- /** @private */
376
- _assignMenuElement() {
377
- const menuElement = this.__getMenuElement();
378
-
428
+ /**
429
+ * @param {HTMLElement} menuElement
430
+ * @protected
431
+ */
432
+ _assignMenuElement(menuElement) {
379
433
  if (menuElement && menuElement !== this.__lastMenuElement) {
380
434
  this._menuElement = menuElement;
381
435
  menuElement.addEventListener('items-changed', () => {
@@ -402,12 +456,6 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
402
456
  }
403
457
  }
404
458
 
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
-
411
459
  /** @private */
412
460
  _valueChanged(value, oldValue) {
413
461
  this.toggleAttribute('has-value', Boolean(value));
@@ -528,7 +576,7 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
528
576
 
529
577
  const label = selected.getAttribute('label');
530
578
  if (label) {
531
- labelItem = this.__createItem(label);
579
+ labelItem = this.__createItemElement({ label });
532
580
  } else {
533
581
  labelItem = selected.cloneNode(true);
534
582
  }
@@ -536,26 +584,40 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
536
584
  // store reference to the original item
537
585
  labelItem._sourceItem = selected;
538
586
 
539
- this.__appendItem(labelItem);
587
+ this.__appendValueItemElement(labelItem);
540
588
 
541
589
  // ensure the item gets proper styles
542
590
  labelItem.selected = true;
543
591
  }
544
592
 
545
- /** @private */
546
- __createItem(text) {
547
- const item = document.createElement('vaadin-item');
548
- item.textContent = text;
549
- return item;
593
+ /**
594
+ * @param {!SelectItem} item
595
+ * @private
596
+ */
597
+ __createItemElement(item) {
598
+ const itemElement = document.createElement(item.component || 'vaadin-select-item');
599
+ if (item.label) {
600
+ itemElement.textContent = item.label;
601
+ }
602
+ if (item.value) {
603
+ itemElement.value = item.value;
604
+ }
605
+ if (item.disabled) {
606
+ itemElement.disabled = item.disabled;
607
+ }
608
+ return itemElement;
550
609
  }
551
610
 
552
- /** @private */
553
- __appendItem(item) {
554
- item.removeAttribute('tabindex');
555
- item.removeAttribute('role');
556
- item.setAttribute('id', this._fieldId);
611
+ /**
612
+ * @param {!HTMLElement} itemElement
613
+ * @private
614
+ */
615
+ __appendValueItemElement(itemElement) {
616
+ itemElement.removeAttribute('tabindex');
617
+ itemElement.removeAttribute('role');
618
+ itemElement.setAttribute('id', this._fieldId);
557
619
 
558
- this._valueButton.appendChild(item);
620
+ this._valueButton.appendChild(itemElement);
559
621
  }
560
622
 
561
623
  /** @private */
@@ -572,8 +634,8 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
572
634
 
573
635
  if (!selected) {
574
636
  if (this.placeholder) {
575
- const item = this.__createItem(this.placeholder);
576
- this.__appendItem(item);
637
+ const item = this.__createItemElement({ label: this.placeholder });
638
+ this.__appendValueItemElement(item);
577
639
  this._valueButton.setAttribute('placeholder', '');
578
640
  }
579
641
  } else {
@@ -640,6 +702,30 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
640
702
  return !(this.invalid = !(this.disabled || !this.required || this.value));
641
703
  }
642
704
 
705
+ /**
706
+ * Renders items when they are provided by the `items` property and clears the content otherwise.
707
+ * @param {!HTMLElement} root
708
+ * @param {!Select} _select
709
+ * @private
710
+ */
711
+ __defaultRenderer(root, _select) {
712
+ if (!this.items || this.items.length === 0) {
713
+ root.textContent = '';
714
+ return;
715
+ }
716
+
717
+ let listBox = root.firstElementChild;
718
+ if (!listBox) {
719
+ listBox = document.createElement('vaadin-select-list-box');
720
+ root.appendChild(listBox);
721
+ }
722
+
723
+ listBox.textContent = '';
724
+ this.items.forEach((item) => {
725
+ listBox.appendChild(this.__createItemElement(item));
726
+ });
727
+ }
728
+
643
729
  /**
644
730
  * Fired when the user commits a value change.
645
731
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import '@vaadin/vaadin-lumo-styles/sizing.js';
@@ -67,7 +67,7 @@ registerStyles(
67
67
  box-shadow: none;
68
68
  }
69
69
 
70
- ::slotted(vaadin-item:hover) {
70
+ ::slotted(:not([slot]):hover) {
71
71
  background-color: transparent;
72
72
  }
73
73
  `,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import '@vaadin/button/theme/lumo/vaadin-button.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import '@vaadin/vaadin-material-styles/font-icons.js';
@@ -54,12 +54,12 @@ registerStyles(
54
54
  display: none;
55
55
  }
56
56
 
57
- ::slotted(vaadin-item) {
57
+ ::slotted(:not([slot])) {
58
58
  font: inherit;
59
59
  padding: 4px 0;
60
60
  }
61
61
 
62
- ::slotted(vaadin-item:hover) {
62
+ ::slotted(:not([slot]):hover) {
63
63
  background-color: transparent;
64
64
  }
65
65
  `,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2021 Vaadin Ltd.
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import '@vaadin/button/theme/material/vaadin-button.js';