@vaadin/combo-box 23.1.2 → 23.2.0-alpha3

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.
@@ -52,9 +52,7 @@ export class ComboBoxOverlay extends PositionMixin(OverlayElement) {
52
52
  connectedCallback() {
53
53
  super.connectedCallback();
54
54
 
55
- const dropdown = this.__dataHost;
56
- const comboBox = dropdown && dropdown.getRootNode().host;
57
- this._comboBox = comboBox;
55
+ const comboBox = this._comboBox;
58
56
 
59
57
  const hostDir = comboBox && comboBox.getAttribute('dir');
60
58
  if (hostDir) {
@@ -4,6 +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 { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
7
+ import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
7
8
  import { Virtualizer } from '@vaadin/component-base/src/virtualizer.js';
8
9
  import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
9
10
 
@@ -90,6 +91,7 @@ export class ComboBoxScroller extends PolymerElement {
90
91
  */
91
92
  selectedItem: {
92
93
  type: Object,
94
+ observer: '__selectedItemChanged',
93
95
  },
94
96
 
95
97
  /**
@@ -145,6 +147,9 @@ export class ComboBoxScroller extends PolymerElement {
145
147
  ready() {
146
148
  super.ready();
147
149
 
150
+ // Ensure every instance has unique ID
151
+ this.id = `${this.localName}-${generateUniqueId()}`;
152
+
148
153
  // Allow extensions to customize tag name for the items
149
154
  this.__hostTagName = this.constructor.is.replace('-scroller', '');
150
155
 
@@ -218,7 +223,7 @@ export class ComboBoxScroller extends PolymerElement {
218
223
 
219
224
  /** @private */
220
225
  __isItemFocused(focusedIndex, itemIndex) {
221
- return focusedIndex === itemIndex;
226
+ return !this.loading && focusedIndex === itemIndex;
222
227
  }
223
228
 
224
229
  /** @private */
@@ -243,12 +248,19 @@ export class ComboBoxScroller extends PolymerElement {
243
248
  }
244
249
 
245
250
  /** @private */
246
- __loadingChanged(loading) {
247
- if (this.__virtualizer && !loading) {
251
+ __loadingChanged() {
252
+ if (this.__virtualizer) {
248
253
  setTimeout(() => this.requestContentUpdate());
249
254
  }
250
255
  }
251
256
 
257
+ /** @private */
258
+ __selectedItemChanged() {
259
+ if (this.__virtualizer) {
260
+ this.requestContentUpdate();
261
+ }
262
+ }
263
+
252
264
  /** @private */
253
265
  __focusedIndexChanged(index, oldIndex) {
254
266
  if (!this.__virtualizer) {
@@ -3,24 +3,24 @@
3
3
  * Copyright (c) 2015 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
9
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
- import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
- import { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
12
- import { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
13
- import { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
14
- import { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
15
- import { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
16
- import { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
17
- import { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
18
- import { PatternMixinClass } from '@vaadin/field-base/src/pattern-mixin.js';
19
- import { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
20
- import { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
21
- import { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
22
- import { ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
23
- import { ComboBoxDefaultItem } from './vaadin-combo-box-mixin.js';
6
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
9
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
+ import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
+ import type { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
12
+ import type { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
13
+ import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
14
+ import type { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
15
+ import type { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
16
+ import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
17
+ import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
18
+ import type { PatternMixinClass } from '@vaadin/field-base/src/pattern-mixin.js';
19
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
20
+ import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
21
+ import type { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
22
+ import type { ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
23
+ import type { ComboBoxDefaultItem } from './vaadin-combo-box-mixin.js';
24
24
  export {
25
25
  ComboBoxDataProvider,
26
26
  ComboBoxDataProviderCallback,
@@ -65,6 +65,11 @@ export type ComboBoxFilterChangedEvent = CustomEvent<{ value: string }>;
65
65
  */
66
66
  export type ComboBoxSelectedItemChangedEvent<TItem> = CustomEvent<{ value: TItem | null | undefined }>;
67
67
 
68
+ /**
69
+ * Fired whenever the field is validated.
70
+ */
71
+ export type ComboBoxValidatedEvent = CustomEvent<{ valid: boolean }>;
72
+
68
73
  export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
69
74
  change: ComboBoxChangeEvent<TItem>;
70
75
 
@@ -79,6 +84,8 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
79
84
  'value-changed': ComboBoxValueChangedEvent;
80
85
 
81
86
  'selected-item-changed': ComboBoxSelectedItemChangedEvent<TItem>;
87
+
88
+ validated: ComboBoxValidatedEvent;
82
89
  }
83
90
 
84
91
  /**
@@ -165,6 +172,7 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
165
172
  * Custom property | Description | Default
166
173
  * ----------------------------------------|----------------------------|---------
167
174
  * `--vaadin-field-default-width` | Default width of the field | `12em`
175
+ * `--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`
168
176
  * `--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
169
177
  *
170
178
  * `<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
@@ -207,6 +215,7 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
207
215
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
208
216
  * @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
209
217
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
218
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
210
219
  */
211
220
  declare class ComboBox<TItem = ComboBoxDefaultItem> extends HTMLElement {
212
221
  addEventListener<K extends keyof ComboBoxEventMap<TItem>>(
@@ -4,7 +4,9 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import '@vaadin/input-container/src/vaadin-input-container.js';
7
- import './vaadin-combo-box-dropdown.js';
7
+ import './vaadin-combo-box-item.js';
8
+ import './vaadin-combo-box-overlay.js';
9
+ import './vaadin-combo-box-scroller.js';
8
10
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
9
11
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
12
  import { InputControlMixin } from '@vaadin/field-base/src/input-control-mixin.js';
@@ -102,6 +104,7 @@ registerStyles('vaadin-combo-box', inputFieldShared, { moduleId: 'vaadin-combo-b
102
104
  * Custom property | Description | Default
103
105
  * ----------------------------------------|----------------------------|---------
104
106
  * `--vaadin-field-default-width` | Default width of the field | `12em`
107
+ * `--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`
105
108
  * `--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
106
109
  *
107
110
  * `<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
@@ -144,6 +147,7 @@ registerStyles('vaadin-combo-box', inputFieldShared, { moduleId: 'vaadin-combo-b
144
147
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
145
148
  * @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
146
149
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
150
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
147
151
  *
148
152
  * @extends HTMLElement
149
153
  * @mixes ElementMixin
@@ -196,19 +200,16 @@ class ComboBox extends ComboBoxDataProviderMixin(
196
200
  </div>
197
201
  </div>
198
202
 
199
- <vaadin-combo-box-dropdown
200
- id="dropdown"
201
- opened="[[opened]]"
202
- renderer="[[renderer]]"
203
+ <vaadin-combo-box-overlay
204
+ id="overlay"
205
+ hidden$="[[_isOverlayHidden(filteredItems, loading)]]"
206
+ opened="[[_overlayOpened]]"
207
+ loading$="[[loading]]"
208
+ theme$="[[_theme]]"
203
209
  position-target="[[_positionTarget]]"
204
- restore-focus-on-close="[[__restoreFocusOnClose]]"
210
+ no-vertical-overlap
205
211
  restore-focus-node="[[inputElement]]"
206
- _focused-index="[[_focusedIndex]]"
207
- _item-id-path="[[itemIdPath]]"
208
- _item-label-path="[[itemLabelPath]]"
209
- loading="[[loading]]"
210
- theme="[[_theme]]"
211
- ></vaadin-combo-box-dropdown>
212
+ ></vaadin-combo-box-overlay>
212
213
  `;
213
214
  }
214
215
 
@@ -273,7 +274,7 @@ class ComboBox extends ComboBoxDataProviderMixin(
273
274
  */
274
275
  _shouldRemoveFocus(event) {
275
276
  // Do not blur when focus moves to the overlay
276
- if (event.relatedTarget === this.$.dropdown.$.overlay) {
277
+ if (event.relatedTarget === this.$.overlay) {
277
278
  event.composedPath()[0].focus();
278
279
  return false;
279
280
  }
@@ -1,287 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2015 - 2022 Vaadin Ltd.
4
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
- */
6
- import './vaadin-combo-box-item.js';
7
- import './vaadin-combo-box-overlay.js';
8
- import './vaadin-combo-box-scroller.js';
9
- import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
10
-
11
- /**
12
- * Element for internal use only.
13
- *
14
- * @extends HTMLElement
15
- * @private
16
- */
17
- export class ComboBoxDropdown extends PolymerElement {
18
- static get is() {
19
- return 'vaadin-combo-box-dropdown';
20
- }
21
-
22
- static get template() {
23
- return html`
24
- <vaadin-combo-box-overlay
25
- id="overlay"
26
- hidden$="[[_isOverlayHidden(_items.*, loading)]]"
27
- loading$="[[loading]]"
28
- opened="{{_overlayOpened}}"
29
- theme$="[[theme]]"
30
- position-target="[[positionTarget]]"
31
- no-vertical-overlap
32
- restore-focus-on-close="[[restoreFocusOnClose]]"
33
- restore-focus-node="[[restoreFocusNode]]"
34
- ></vaadin-combo-box-overlay>
35
- `;
36
- }
37
-
38
- static get properties() {
39
- return {
40
- /**
41
- * True if the combo-box has been activate by the user.
42
- * The actual opened state depends on whether the dropdown has items.
43
- */
44
- opened: Boolean,
45
-
46
- /**
47
- * The element to position/align the dropdown by.
48
- */
49
- positionTarget: {
50
- type: Object,
51
- },
52
-
53
- /**
54
- * Custom function for rendering the content of the `<vaadin-combo-box-item>` propagated from the combo box element.
55
- */
56
- renderer: Function,
57
-
58
- /**
59
- * `true` when new items are being loaded.
60
- */
61
- loading: {
62
- type: Boolean,
63
- value: false,
64
- reflectToAttribute: true,
65
- },
66
-
67
- /**
68
- * Used to propagate the `theme` attribute from the host element.
69
- */
70
- theme: String,
71
-
72
- _selectedItem: {
73
- type: Object,
74
- },
75
-
76
- _items: {
77
- type: Array,
78
- },
79
-
80
- _focusedIndex: {
81
- type: Number,
82
- value: -1,
83
- },
84
-
85
- focusedItem: {
86
- type: String,
87
- computed: '_getFocusedItem(_focusedIndex)',
88
- },
89
-
90
- _itemLabelPath: {
91
- type: String,
92
- value: 'label',
93
- },
94
-
95
- _itemValuePath: {
96
- type: String,
97
- value: 'value',
98
- },
99
-
100
- _scroller: Object,
101
-
102
- _itemIdPath: String,
103
-
104
- _overlayOpened: {
105
- type: Boolean,
106
- observer: '_openedChanged',
107
- },
108
- };
109
- }
110
-
111
- static get observers() {
112
- return [
113
- '_openedOrItemsChanged(opened, _items, loading)',
114
- '__updateScroller(_scroller, _items, opened, loading, _selectedItem, _itemIdPath, _focusedIndex, renderer, theme)',
115
- ];
116
- }
117
-
118
- constructor() {
119
- super();
120
-
121
- // Ensure every instance has unique ID
122
- const uniqueId = (ComboBoxDropdown._uniqueId = 1 + ComboBoxDropdown._uniqueId || 0);
123
- this.scrollerId = `${this.localName}-scroller-${uniqueId}`;
124
- }
125
-
126
- ready() {
127
- super.ready();
128
-
129
- // Allow extensions to customize tag name for the items
130
- this.__hostTagName = this.constructor.is.replace('-dropdown', '');
131
-
132
- const overlay = this.$.overlay;
133
- const scrollerTag = `${this.__hostTagName}-scroller`;
134
-
135
- overlay.renderer = (root) => {
136
- if (!root.firstChild) {
137
- const scroller = document.createElement(scrollerTag);
138
- root.appendChild(scroller);
139
- }
140
- };
141
-
142
- // Ensure the scroller is rendered
143
- overlay.requestContentUpdate();
144
-
145
- this._scroller = overlay.content.querySelector(scrollerTag);
146
- this._scroller.id = this.scrollerId;
147
-
148
- this._scroller.getItemLabel = this.getItemLabel.bind(this);
149
- this._scroller.comboBox = this.getRootNode().host;
150
-
151
- this._scroller.addEventListener('selection-changed', (e) => this._forwardScrollerEvent(e));
152
- this._scroller.addEventListener('index-requested', (e) => this._forwardScrollerEvent(e));
153
-
154
- overlay.addEventListener('touchend', (e) => this._fireTouchAction(e));
155
- overlay.addEventListener('touchmove', (e) => this._fireTouchAction(e));
156
-
157
- // Prevent blurring the input when clicking inside the overlay.
158
- overlay.addEventListener('mousedown', (e) => e.preventDefault());
159
-
160
- // Preventing the default modal behaviour of the overlay on input clicking
161
- overlay.addEventListener('vaadin-overlay-outside-click', (e) => {
162
- e.preventDefault();
163
- });
164
- }
165
-
166
- disconnectedCallback() {
167
- super.disconnectedCallback();
168
-
169
- // Making sure the overlay is closed and removed from DOM after detaching the dropdown.
170
- this._overlayOpened = false;
171
- }
172
-
173
- _fireTouchAction(sourceEvent) {
174
- this.dispatchEvent(
175
- new CustomEvent('vaadin-overlay-touch-action', {
176
- detail: { sourceEvent },
177
- }),
178
- );
179
- }
180
-
181
- _forwardScrollerEvent(event) {
182
- this.dispatchEvent(new CustomEvent(event.type, { detail: event.detail }));
183
- }
184
-
185
- _openedChanged(opened, wasOpened) {
186
- if (opened) {
187
- this._scroller.style.maxHeight =
188
- getComputedStyle(this).getPropertyValue(`--${this.__hostTagName}-overlay-max-height`) || '65vh';
189
-
190
- this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-opened', { bubbles: true, composed: true }));
191
- } else if (wasOpened && !this.__emptyItems) {
192
- this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-closed', { bubbles: true, composed: true }));
193
- }
194
- }
195
-
196
- _openedOrItemsChanged(opened, items, loading) {
197
- // See https://github.com/vaadin/vaadin-combo-box/pull/964
198
- const hasItems = items && items.length;
199
- if (!hasItems) {
200
- this.__emptyItems = true;
201
- }
202
- this._overlayOpened = !!(opened && (loading || hasItems));
203
- this.__emptyItems = false;
204
- }
205
-
206
- _getFocusedItem(focusedIndex) {
207
- if (focusedIndex >= 0) {
208
- return this._items[focusedIndex];
209
- }
210
- }
211
-
212
- /**
213
- * Gets the index of the item with the provided label.
214
- * @return {number}
215
- */
216
- indexOfLabel(label) {
217
- if (this._items && label) {
218
- for (let i = 0; i < this._items.length; i++) {
219
- if (this.getItemLabel(this._items[i]).toString().toLowerCase() === label.toString().toLowerCase()) {
220
- return i;
221
- }
222
- }
223
- }
224
-
225
- return -1;
226
- }
227
-
228
- /**
229
- * Gets the label string for the item based on the `_itemLabelPath`.
230
- * @return {string}
231
- */
232
- getItemLabel(item, itemLabelPath) {
233
- itemLabelPath = itemLabelPath || this._itemLabelPath;
234
- let label = item && itemLabelPath ? this.get(itemLabelPath, item) : undefined;
235
- if (label === undefined || label === null) {
236
- label = item ? item.toString() : '';
237
- }
238
- return label;
239
- }
240
-
241
- _scrollIntoView(index) {
242
- if (!this._scroller) {
243
- return;
244
- }
245
- this._scroller.scrollIntoView(index);
246
- }
247
-
248
- adjustScrollPosition() {
249
- if (this.opened && this._items) {
250
- this._scrollIntoView(this._focusedIndex);
251
- }
252
- }
253
-
254
- // eslint-disable-next-line max-params
255
- __updateScroller(scroller, items, opened, loading, selectedItem, itemIdPath, focusedIndex, renderer, theme) {
256
- if (scroller) {
257
- scroller.setProperties({
258
- items: opened ? items : [],
259
- opened,
260
- loading,
261
- selectedItem,
262
- itemIdPath,
263
- focusedIndex,
264
- renderer,
265
- theme,
266
- });
267
- }
268
- }
269
-
270
- _isOverlayHidden() {
271
- return !this.loading && !(this._items && this._items.length);
272
- }
273
-
274
- /**
275
- * Fired after the `vaadin-combo-box-dropdown` opens.
276
- *
277
- * @event vaadin-combo-box-dropdown-opened
278
- */
279
-
280
- /**
281
- * Fired after the `vaadin-combo-box-dropdown` closes.
282
- *
283
- * @event vaadin-combo-box-dropdown-closed
284
- */
285
- }
286
-
287
- customElements.define(ComboBoxDropdown.is, ComboBoxDropdown);