@vaadin/combo-box 24.4.0-dev.b3e1d14600 → 24.5.0-alpha1

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.
Files changed (49) hide show
  1. package/README.md +0 -1
  2. package/package.json +16 -14
  3. package/src/lit/renderer-directives.d.ts +1 -1
  4. package/src/lit/renderer-directives.js +1 -1
  5. package/src/vaadin-combo-box-data-provider-mixin.d.ts +1 -1
  6. package/src/vaadin-combo-box-data-provider-mixin.js +116 -120
  7. package/src/vaadin-combo-box-item-mixin.d.ts +1 -1
  8. package/src/vaadin-combo-box-item-mixin.js +2 -2
  9. package/src/vaadin-combo-box-item.d.ts +1 -1
  10. package/src/vaadin-combo-box-item.js +1 -1
  11. package/src/vaadin-combo-box-light-mixin.d.ts +26 -0
  12. package/src/vaadin-combo-box-light-mixin.js +140 -0
  13. package/src/vaadin-combo-box-light.d.ts +3 -8
  14. package/src/vaadin-combo-box-light.js +4 -128
  15. package/src/vaadin-combo-box-mixin.d.ts +9 -1
  16. package/src/vaadin-combo-box-mixin.js +112 -33
  17. package/src/vaadin-combo-box-overlay-mixin.d.ts +1 -1
  18. package/src/vaadin-combo-box-overlay-mixin.js +1 -1
  19. package/src/vaadin-combo-box-overlay.d.ts +1 -1
  20. package/src/vaadin-combo-box-overlay.js +1 -1
  21. package/src/vaadin-combo-box-placeholder.js +1 -1
  22. package/src/vaadin-combo-box-scroller-mixin.d.ts +1 -1
  23. package/src/vaadin-combo-box-scroller-mixin.js +65 -16
  24. package/src/vaadin-combo-box-scroller.d.ts +1 -1
  25. package/src/vaadin-combo-box-scroller.js +1 -1
  26. package/src/vaadin-combo-box.d.ts +1 -1
  27. package/src/vaadin-combo-box.js +1 -1
  28. package/src/vaadin-lit-combo-box-item.js +50 -0
  29. package/src/vaadin-lit-combo-box-light.js +58 -0
  30. package/src/vaadin-lit-combo-box-overlay.js +76 -0
  31. package/src/vaadin-lit-combo-box-scroller.js +59 -0
  32. package/src/vaadin-lit-combo-box.js +170 -0
  33. package/theme/lumo/vaadin-combo-box-item-styles.d.ts +5 -0
  34. package/theme/lumo/vaadin-combo-box-item-styles.js +2 -4
  35. package/theme/lumo/vaadin-combo-box-light.d.ts +3 -0
  36. package/theme/lumo/vaadin-combo-box-overlay-styles.d.ts +6 -0
  37. package/theme/lumo/vaadin-combo-box-styles.d.ts +2 -0
  38. package/theme/lumo/vaadin-combo-box.d.ts +4 -0
  39. package/theme/lumo/vaadin-lit-combo-box-light.d.ts +3 -0
  40. package/theme/lumo/vaadin-lit-combo-box-light.js +3 -0
  41. package/theme/lumo/vaadin-lit-combo-box.d.ts +4 -0
  42. package/theme/lumo/vaadin-lit-combo-box.js +4 -0
  43. package/theme/material/vaadin-combo-box-item-styles.d.ts +5 -0
  44. package/theme/material/vaadin-combo-box-light.d.ts +3 -0
  45. package/theme/material/vaadin-combo-box-overlay-styles.d.ts +4 -0
  46. package/theme/material/vaadin-combo-box-styles.d.ts +3 -0
  47. package/theme/material/vaadin-combo-box.d.ts +4 -0
  48. package/web-types.json +1210 -0
  49. package/web-types.lit.json +587 -0
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
@@ -11,6 +11,7 @@ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.j
11
11
  import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
12
  import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
13
13
  import type { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
14
+ import type { ComboBoxLightMixinClass } from './vaadin-combo-box-light-mixin.js';
14
15
  import type { ComboBoxDefaultItem, ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
15
16
  export {
16
17
  ComboBoxDataProvider,
@@ -126,13 +127,6 @@ export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
126
127
  * @fires {CustomEvent} validated - Fired whenever the field is validated.
127
128
  */
128
129
  declare class ComboBoxLight<TItem = ComboBoxDefaultItem> extends HTMLElement {
129
- /**
130
- * Name of the two-way data-bindable property representing the
131
- * value of the custom input field.
132
- * @attr {string} attr-for-value
133
- */
134
- attrForValue: string;
135
-
136
130
  addEventListener<K extends keyof ComboBoxLightEventMap<TItem>>(
137
131
  type: K,
138
132
  listener: (this: ComboBoxLight<TItem>, ev: ComboBoxLightEventMap<TItem>[K]) => void,
@@ -148,6 +142,7 @@ declare class ComboBoxLight<TItem = ComboBoxDefaultItem> extends HTMLElement {
148
142
 
149
143
  interface ComboBoxLight<TItem = ComboBoxDefaultItem>
150
144
  extends ComboBoxDataProviderMixinClass<TItem>,
145
+ ComboBoxLightMixinClass,
151
146
  ComboBoxMixinClass<TItem>,
152
147
  KeyboardMixinClass,
153
148
  InputMixinClass,
@@ -1,19 +1,15 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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-combo-box-item.js';
7
7
  import './vaadin-combo-box-overlay.js';
8
8
  import './vaadin-combo-box-scroller.js';
9
- import { dashToCamelCase } from '@polymer/polymer/lib/utils/case-map.js';
10
- import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
11
9
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
12
10
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
13
- import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
14
11
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
15
- import { ComboBoxDataProviderMixin } from './vaadin-combo-box-data-provider-mixin.js';
16
- import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
12
+ import { ComboBoxLightMixin } from './vaadin-combo-box-light-mixin.js';
17
13
 
18
14
  /**
19
15
  * `<vaadin-combo-box-light>` is a customizable version of the `<vaadin-combo-box>` providing
@@ -63,12 +59,10 @@ import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
63
59
  *
64
60
  * @customElement
65
61
  * @extends HTMLElement
66
- * @mixes ComboBoxDataProviderMixin
67
- * @mixes ComboBoxMixin
62
+ * @mixes ComboBoxLightMixin
68
63
  * @mixes ThemableMixin
69
- * @mixes ValidateMixin
70
64
  */
71
- class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixin(ThemableMixin(PolymerElement)))) {
65
+ class ComboBoxLight extends ComboBoxLightMixin(ThemableMixin(PolymerElement)) {
72
66
  static get is() {
73
67
  return 'vaadin-combo-box-light';
74
68
  }
@@ -94,124 +88,6 @@ class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixi
94
88
  ></vaadin-combo-box-overlay>
95
89
  `;
96
90
  }
97
-
98
- static get properties() {
99
- return {
100
- /**
101
- * Name of the two-way data-bindable property representing the
102
- * value of the custom input field.
103
- * @attr {string} attr-for-value
104
- * @type {string}
105
- */
106
- attrForValue: {
107
- type: String,
108
- value: 'value',
109
- },
110
- };
111
- }
112
-
113
- /**
114
- * Used by `InputControlMixin` as a reference to the clear button element.
115
- * @protected
116
- * @return {!HTMLElement}
117
- */
118
- get clearElement() {
119
- return this.querySelector('.clear-button');
120
- }
121
-
122
- /**
123
- * Override this getter from `InputMixin` to allow using
124
- * an arbitrary property name instead of `value`
125
- * for accessing the input element's value.
126
- *
127
- * @protected
128
- * @override
129
- * @return {string}
130
- */
131
- get _inputElementValueProperty() {
132
- return dashToCamelCase(this.attrForValue);
133
- }
134
-
135
- /**
136
- * @protected
137
- * @override
138
- * @return {HTMLInputElement | undefined}
139
- */
140
- get _nativeInput() {
141
- const input = this.inputElement;
142
-
143
- if (input) {
144
- // Support `<input class="input">`
145
- if (input instanceof HTMLInputElement) {
146
- return input;
147
- }
148
-
149
- // Support `<input>` in light DOM (e.g. `vaadin-text-field`)
150
- const slottedInput = input.querySelector('input');
151
- if (slottedInput) {
152
- return slottedInput;
153
- }
154
-
155
- if (input.shadowRoot) {
156
- // Support `<input>` in Shadow DOM (e.g. `mwc-textfield`)
157
- const shadowInput = input.shadowRoot.querySelector('input');
158
- if (shadowInput) {
159
- return shadowInput;
160
- }
161
- }
162
- }
163
-
164
- return undefined;
165
- }
166
-
167
- /** @protected */
168
- ready() {
169
- super.ready();
170
-
171
- this._toggleElement = this.querySelector('.toggle-button');
172
-
173
- // Wait until the slotted input DOM is ready
174
- afterNextRender(this, () => {
175
- this._setInputElement(this.querySelector('vaadin-text-field,.input'));
176
- this._revertInputValue();
177
- });
178
- }
179
-
180
- /**
181
- * Returns true if the current input value satisfies all constraints (if any).
182
- * @return {boolean}
183
- */
184
- checkValidity() {
185
- if (this.inputElement && this.inputElement.validate) {
186
- return this.inputElement.validate();
187
- }
188
- return super.checkValidity();
189
- }
190
-
191
- /** @protected */
192
- _isClearButton(event) {
193
- return (
194
- super._isClearButton(event) ||
195
- (event.type === 'input' && !event.isTrusted) || // Fake input event dispatched by clear button
196
- event.composedPath()[0].getAttribute('part') === 'clear-button'
197
- );
198
- }
199
-
200
- /**
201
- * @protected
202
- * @override
203
- */
204
- _shouldRemoveFocus(event) {
205
- const isBlurringControlButtons = event.target === this._toggleElement || event.target === this.clearElement;
206
- const isFocusingInputElement = event.relatedTarget && event.relatedTarget === this._nativeInput;
207
-
208
- // prevent closing the overlay when moving focus from clear or toggle buttons to the internal input
209
- if (isBlurringControlButtons && isFocusingInputElement) {
210
- return false;
211
- }
212
-
213
- return super._shouldRemoveFocus(event);
214
- }
215
91
  }
216
92
 
217
93
  defineCustomElement(ComboBoxLight);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -64,6 +64,14 @@ export declare class ComboBoxMixinClass<TItem> {
64
64
  */
65
65
  items: TItem[] | undefined;
66
66
 
67
+ /**
68
+ * A function used to generate CSS class names for dropdown
69
+ * items based on the item. The return value should be the
70
+ * generated class name as a string, or multiple class names
71
+ * separated by whitespace characters.
72
+ */
73
+ itemClassNameGenerator: (item: TItem) => string;
74
+
67
75
  /**
68
76
  * If `true`, the user can input a value that is not present in the items list.
69
77
  * `value` property will be set to the input value in this case.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
@@ -71,6 +71,7 @@ export const ComboBoxMixin = (subclass) =>
71
71
  notify: true,
72
72
  value: false,
73
73
  reflectToAttribute: true,
74
+ sync: true,
74
75
  observer: '_openedChanged',
75
76
  },
76
77
 
@@ -80,6 +81,7 @@ export const ComboBoxMixin = (subclass) =>
80
81
  */
81
82
  autoOpenDisabled: {
82
83
  type: Boolean,
84
+ sync: true,
83
85
  },
84
86
 
85
87
  /**
@@ -104,7 +106,10 @@ export const ComboBoxMixin = (subclass) =>
104
106
  * - `model.item` The item.
105
107
  * @type {ComboBoxRenderer | undefined}
106
108
  */
107
- renderer: Function,
109
+ renderer: {
110
+ type: Object,
111
+ sync: true,
112
+ },
108
113
 
109
114
  /**
110
115
  * A full set of items to filter the visible options from.
@@ -113,6 +118,7 @@ export const ComboBoxMixin = (subclass) =>
113
118
  */
114
119
  items: {
115
120
  type: Array,
121
+ sync: true,
116
122
  observer: '_itemsChanged',
117
123
  },
118
124
 
@@ -138,6 +144,7 @@ export const ComboBoxMixin = (subclass) =>
138
144
  filteredItems: {
139
145
  type: Array,
140
146
  observer: '_filteredItemsChanged',
147
+ sync: true,
141
148
  },
142
149
 
143
150
  /**
@@ -154,6 +161,7 @@ export const ComboBoxMixin = (subclass) =>
154
161
  type: Boolean,
155
162
  value: false,
156
163
  reflectToAttribute: true,
164
+ sync: true,
157
165
  },
158
166
 
159
167
  /**
@@ -164,6 +172,7 @@ export const ComboBoxMixin = (subclass) =>
164
172
  type: Number,
165
173
  observer: '_focusedIndexChanged',
166
174
  value: -1,
175
+ sync: true,
167
176
  },
168
177
 
169
178
  /**
@@ -174,6 +183,7 @@ export const ComboBoxMixin = (subclass) =>
174
183
  type: String,
175
184
  value: '',
176
185
  notify: true,
186
+ sync: true,
177
187
  },
178
188
 
179
189
  /**
@@ -183,6 +193,17 @@ export const ComboBoxMixin = (subclass) =>
183
193
  selectedItem: {
184
194
  type: Object,
185
195
  notify: true,
196
+ sync: true,
197
+ },
198
+
199
+ /**
200
+ * A function used to generate CSS class names for dropdown
201
+ * items based on the item. The return value should be the
202
+ * generated class name as a string, or multiple class names
203
+ * separated by whitespace characters.
204
+ */
205
+ itemClassNameGenerator: {
206
+ type: Object,
186
207
  },
187
208
 
188
209
  /**
@@ -199,6 +220,7 @@ export const ComboBoxMixin = (subclass) =>
199
220
  type: String,
200
221
  value: 'label',
201
222
  observer: '_itemLabelPathChanged',
223
+ sync: true,
202
224
  },
203
225
 
204
226
  /**
@@ -214,6 +236,7 @@ export const ComboBoxMixin = (subclass) =>
214
236
  itemValuePath: {
215
237
  type: String,
216
238
  value: 'value',
239
+ sync: true,
217
240
  },
218
241
 
219
242
  /**
@@ -223,7 +246,10 @@ export const ComboBoxMixin = (subclass) =>
223
246
  * `dataProvider` callback).
224
247
  * @attr {string} item-id-path
225
248
  */
226
- itemIdPath: String,
249
+ itemIdPath: {
250
+ type: String,
251
+ sync: true,
252
+ },
227
253
 
228
254
  /**
229
255
  * @type {!HTMLElement | undefined}
@@ -240,27 +266,38 @@ export const ComboBoxMixin = (subclass) =>
240
266
  */
241
267
  _dropdownItems: {
242
268
  type: Array,
269
+ sync: true,
243
270
  },
244
271
 
245
272
  /** @private */
246
273
  _closeOnBlurIsPrevented: Boolean,
247
274
 
248
275
  /** @private */
249
- _scroller: Object,
276
+ _scroller: {
277
+ type: Object,
278
+ sync: true,
279
+ },
250
280
 
251
281
  /** @private */
252
282
  _overlayOpened: {
253
283
  type: Boolean,
284
+ sync: true,
254
285
  observer: '_overlayOpenedChanged',
255
286
  },
287
+
288
+ /** @private */
289
+ __keepOverlayOpened: {
290
+ type: Boolean,
291
+ sync: true,
292
+ },
256
293
  };
257
294
  }
258
295
 
259
296
  static get observers() {
260
297
  return [
261
298
  '_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
262
- '_openedOrItemsChanged(opened, _dropdownItems, loading, _keepOverlayOpened)',
263
- '_updateScroller(_scroller, _dropdownItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
299
+ '_openedOrItemsChanged(opened, _dropdownItems, loading, __keepOverlayOpened)',
300
+ '_updateScroller(_scroller, _dropdownItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, _theme, itemClassNameGenerator)',
264
301
  ];
265
302
  }
266
303
 
@@ -413,6 +450,18 @@ export const ComboBoxMixin = (subclass) =>
413
450
  }
414
451
  }
415
452
 
453
+ /**
454
+ * Override LitElement lifecycle callback to handle filter property change.
455
+ * @param {Object} props
456
+ */
457
+ updated(props) {
458
+ super.updated(props);
459
+
460
+ if (props.has('filter')) {
461
+ this._filterChanged(this.filter);
462
+ }
463
+ }
464
+
416
465
  /** @private */
417
466
  _initOverlay() {
418
467
  const overlay = this.$.overlay;
@@ -441,32 +490,41 @@ export const ComboBoxMixin = (subclass) =>
441
490
  * @protected
442
491
  */
443
492
  _initScroller(host) {
444
- const scrollerTag = `${this._tagNamePrefix}-scroller`;
493
+ const scroller = document.createElement(`${this._tagNamePrefix}-scroller`);
494
+
495
+ scroller.owner = host || this;
496
+ scroller.getItemLabel = this._getItemLabel.bind(this);
497
+ scroller.addEventListener('selection-changed', this._boundOverlaySelectedItemChanged);
445
498
 
446
499
  const overlay = this._overlayElement;
447
500
 
448
501
  overlay.renderer = (root) => {
449
- if (!root.firstChild) {
450
- root.appendChild(document.createElement(scrollerTag));
502
+ if (!root.innerHTML) {
503
+ root.appendChild(scroller);
451
504
  }
452
505
  };
453
506
 
454
507
  // Ensure the scroller is rendered
455
508
  overlay.requestContentUpdate();
456
509
 
457
- const scroller = overlay.querySelector(scrollerTag);
458
-
459
- scroller.owner = host || this;
460
- scroller.getItemLabel = this._getItemLabel.bind(this);
461
- scroller.addEventListener('selection-changed', this._boundOverlaySelectedItemChanged);
462
-
463
510
  // Trigger the observer to set properties
464
511
  this._scroller = scroller;
465
512
  }
466
513
 
467
514
  /** @private */
468
515
  // eslint-disable-next-line max-params
469
- _updateScroller(scroller, items, opened, loading, selectedItem, itemIdPath, focusedIndex, renderer, theme) {
516
+ _updateScroller(
517
+ scroller,
518
+ items,
519
+ opened,
520
+ loading,
521
+ selectedItem,
522
+ itemIdPath,
523
+ focusedIndex,
524
+ renderer,
525
+ theme,
526
+ itemClassNameGenerator,
527
+ ) {
470
528
  if (scroller) {
471
529
  if (opened) {
472
530
  scroller.style.maxHeight =
@@ -482,7 +540,19 @@ export const ComboBoxMixin = (subclass) =>
482
540
  focusedIndex,
483
541
  renderer,
484
542
  theme,
543
+ itemClassNameGenerator,
485
544
  });
545
+
546
+ // NOTE: in PolylitMixin, setProperties() waits for `hasUpdated` to be set.
547
+ // This means for the first opening, properties won't be set synchronously.
548
+ // Call `performUpdate()` in this case to mimic the Polymer version logic.
549
+ if (scroller.performUpdate && !scroller.hasUpdated) {
550
+ try {
551
+ scroller.performUpdate();
552
+ } catch (_) {
553
+ // Suppress errors in synchronous tests for pre-opened combo-box.
554
+ }
555
+ }
486
556
  }
487
557
  }
488
558
 
@@ -490,7 +560,7 @@ export const ComboBoxMixin = (subclass) =>
490
560
  _openedOrItemsChanged(opened, items, loading, keepOverlayOpened) {
491
561
  // Close the overlay if there are no items to display.
492
562
  // See https://github.com/vaadin/vaadin-combo-box/pull/964
493
- this._overlayOpened = !!(opened && (keepOverlayOpened || loading || (items && items.length)));
563
+ this._overlayOpened = opened && (keepOverlayOpened || loading || !!(items && items.length));
494
564
  }
495
565
 
496
566
  /** @private */
@@ -542,7 +612,6 @@ export const ComboBoxMixin = (subclass) =>
542
612
  }
543
613
 
544
614
  if (opened) {
545
- this._openedWithFocusRing = this.hasAttribute('focus-ring');
546
615
  // For touch devices, we don't want to popup virtual keyboard
547
616
  // unless input element is explicitly focused by the user.
548
617
  if (!this._isInputFocused() && !isTouch) {
@@ -554,9 +623,6 @@ export const ComboBoxMixin = (subclass) =>
554
623
  this._overlayElement.restoreFocusOnClose = true;
555
624
  } else {
556
625
  this._onClosed();
557
- if (this._openedWithFocusRing && this._isInputFocused()) {
558
- this.setAttribute('focus-ring', '');
559
- }
560
626
  }
561
627
 
562
628
  const input = this._nativeInput;
@@ -772,11 +838,7 @@ export const ComboBoxMixin = (subclass) =>
772
838
  // Do not commit value when custom values are disallowed and input value is not a valid option
773
839
  // also stop propagation of the event, otherwise the user could submit a form while the input
774
840
  // still contains an invalid value
775
- const hasInvalidOption =
776
- this._focusedIndex < 0 &&
777
- this._inputElementValue !== '' &&
778
- this._getItemLabel(this.selectedItem) !== this._inputElementValue;
779
- if (!this.allowCustomValue && hasInvalidOption) {
841
+ if (!this._hasValidInputValue()) {
780
842
  // Do not submit the surrounding form.
781
843
  e.preventDefault();
782
844
  // Do not trigger global listeners
@@ -796,6 +858,18 @@ export const ComboBoxMixin = (subclass) =>
796
858
  this._closeOrCommit();
797
859
  }
798
860
 
861
+ /**
862
+ * @protected
863
+ */
864
+ _hasValidInputValue() {
865
+ const hasInvalidOption =
866
+ this._focusedIndex < 0 &&
867
+ this._inputElementValue !== '' &&
868
+ this._getItemLabel(this.selectedItem) !== this._inputElementValue;
869
+
870
+ return this.allowCustomValue || !hasInvalidOption;
871
+ }
872
+
799
873
  /**
800
874
  * Override an event listener from `KeyboardMixin`.
801
875
  * Do not call `super` in order to override clear
@@ -867,6 +941,15 @@ export const ComboBoxMixin = (subclass) =>
867
941
  this._detectAndDispatchChange();
868
942
  }
869
943
 
944
+ /**
945
+ * Clears the current filter. Should be used instead of setting the property
946
+ * directly in order to allow overriding this in multi-select combo box.
947
+ * @protected
948
+ */
949
+ _clearFilter() {
950
+ this.filter = '';
951
+ }
952
+
870
953
  /**
871
954
  * Reverts back to original value.
872
955
  */
@@ -938,7 +1021,7 @@ export const ComboBoxMixin = (subclass) =>
938
1021
  this.value = this._getItemValue(itemMatchingInputValue);
939
1022
  } else {
940
1023
  // Revert the input value
941
- this._inputElementValue = this.selectedItem ? this._getItemLabel(this.selectedItem) : this.value || '';
1024
+ this._revertInputValueToValue();
942
1025
  }
943
1026
  }
944
1027
 
@@ -946,7 +1029,7 @@ export const ComboBoxMixin = (subclass) =>
946
1029
 
947
1030
  this._clearSelectionRange();
948
1031
 
949
- this.filter = '';
1032
+ this._clearFilter();
950
1033
  }
951
1034
 
952
1035
  /**
@@ -1087,7 +1170,7 @@ export const ComboBoxMixin = (subclass) =>
1087
1170
  this.selectedItem = null;
1088
1171
  }
1089
1172
 
1090
- this.filter = '';
1173
+ this._clearFilter();
1091
1174
 
1092
1175
  // In the next _detectAndDispatchChange() call, the change detection should pass
1093
1176
  this._lastCommittedValue = undefined;
@@ -1113,10 +1196,6 @@ export const ComboBoxMixin = (subclass) =>
1113
1196
  this.items = oldItems;
1114
1197
  });
1115
1198
 
1116
- if (this.dataProvider) {
1117
- return;
1118
- }
1119
-
1120
1199
  if (items) {
1121
1200
  this.filteredItems = items.slice(0);
1122
1201
  } else if (oldItems) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * Copyright (c) 2015 - 2023 Vaadin Ltd.
3
+ * Copyright (c) 2015 - 2024 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 type { Constructor } from '@open-wc/dedupe-mixin';