@vaadin/multi-select-combo-box 23.2.0-dev.8a7678b70 → 23.3.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.
package/README.md CHANGED
@@ -1,18 +1,20 @@
1
1
  # @vaadin/multi-select-combo-box
2
2
 
3
- > ⚠️ Work in progress, please do not use this component yet.
4
-
5
3
  A web component that wraps `<vaadin-combo-box>` and allows selecting multiple items.
6
4
 
5
+ [Documentation + Live Demo ↗](https://vaadin.com/docs/latest/components/multi-select-combo-box)
6
+
7
7
  ```html
8
- <vaadin-multi-select-combo-box id="fruit"></vaadin-multi-select-combo-box>
8
+ <vaadin-multi-select-combo-box style="width: 300px"></vaadin-multi-select-combo-box>
9
9
  <script>
10
- const comboBox = document.querySelector('#fruit');
10
+ const comboBox = document.querySelector('vaadin-multi-select-combo-box');
11
11
  comboBox.items = ['apple', 'banana', 'lemon', 'orange'];
12
- comboBox.selectedItems = ['lemon', 'orange'];
12
+ comboBox.selectedItems = ['apple', 'banana'];
13
13
  </script>
14
14
  ```
15
15
 
16
+ [<img src="https://raw.githubusercontent.com/vaadin/web-components/master/packages/multi-select-combo-box/screenshot.png" width="300" alt="Screenshot of vaadin-multi-select-combo-box">](https://vaadin.com/docs/latest/components/multi-select-combo-box)
17
+
16
18
  ## Installation
17
19
 
18
20
  Install the component:
@@ -29,7 +31,7 @@ import '@vaadin/multi-select-combo-box';
29
31
 
30
32
  ## Themes
31
33
 
32
- Vaadin components come with two built-in [themes](https://vaadin.com/docs/latest/ds/customization/using-themes), Lumo and Material.
34
+ Vaadin components come with two built-in [themes](https://vaadin.com/docs/latest/styling), Lumo and Material.
33
35
  The [main entrypoint](https://github.com/vaadin/web-components/blob/master/packages/multi-select-combo-box/vaadin-multi-select-combo-box.js) of the package uses the Lumo theme.
34
36
 
35
37
  To use the Material theme, import the component from the `theme/material` folder:
@@ -52,7 +54,7 @@ import '@vaadin/multi-select-combo-box/src/vaadin-multi-select-combo-box.js';
52
54
 
53
55
  ## Contributing
54
56
 
55
- Read the [contributing guide](https://vaadin.com/docs/latest/guide/contributing/overview) to learn about our development process, how to propose bugfixes and improvements, and how to test your changes to Vaadin components.
57
+ Read the [contributing guide](https://vaadin.com/docs/latest/contributing/overview) to learn about our development process, how to propose bugfixes and improvements, and how to test your changes to Vaadin components.
56
58
 
57
59
  ## License
58
60
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/multi-select-combo-box",
3
- "version": "23.2.0-dev.8a7678b70",
3
+ "version": "23.3.0-alpha1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -19,12 +19,14 @@
19
19
  "main": "vaadin-multi-select-combo-box.js",
20
20
  "module": "vaadin-multi-select-combo-box.js",
21
21
  "files": [
22
- "lit.js",
23
22
  "lit.d.ts",
23
+ "lit.js",
24
24
  "src",
25
25
  "theme",
26
26
  "vaadin-*.d.ts",
27
- "vaadin-*.js"
27
+ "vaadin-*.js",
28
+ "web-types.json",
29
+ "web-types.lit.json"
28
30
  ],
29
31
  "keywords": [
30
32
  "Vaadin",
@@ -35,19 +37,23 @@
35
37
  ],
36
38
  "dependencies": {
37
39
  "@polymer/polymer": "^3.0.0",
38
- "@vaadin/combo-box": "23.2.0-dev.8a7678b70",
39
- "@vaadin/component-base": "23.2.0-dev.8a7678b70",
40
- "@vaadin/field-base": "23.2.0-dev.8a7678b70",
41
- "@vaadin/input-container": "23.2.0-dev.8a7678b70",
42
- "@vaadin/lit-renderer": "23.2.0-dev.8a7678b70",
43
- "@vaadin/vaadin-lumo-styles": "23.2.0-dev.8a7678b70",
44
- "@vaadin/vaadin-material-styles": "23.2.0-dev.8a7678b70",
45
- "@vaadin/vaadin-themable-mixin": "23.2.0-dev.8a7678b70"
40
+ "@vaadin/combo-box": "23.3.0-alpha1",
41
+ "@vaadin/component-base": "23.3.0-alpha1",
42
+ "@vaadin/field-base": "23.3.0-alpha1",
43
+ "@vaadin/input-container": "23.3.0-alpha1",
44
+ "@vaadin/lit-renderer": "23.3.0-alpha1",
45
+ "@vaadin/vaadin-lumo-styles": "23.3.0-alpha1",
46
+ "@vaadin/vaadin-material-styles": "23.3.0-alpha1",
47
+ "@vaadin/vaadin-themable-mixin": "23.3.0-alpha1"
46
48
  },
47
49
  "devDependencies": {
48
50
  "@esm-bundle/chai": "^4.3.4",
49
51
  "@vaadin/testing-helpers": "^0.3.2",
50
52
  "sinon": "^13.0.2"
51
53
  },
52
- "gitHead": "85b403f96d8282f262322b56c0ff4289f843d02a"
54
+ "web-types": [
55
+ "web-types.json",
56
+ "web-types.lit.json"
57
+ ],
58
+ "gitHead": "beabc527d4b1274eb798ff701d406fed45cfe638"
53
59
  }
@@ -3,11 +3,11 @@
3
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
- import { TemplateResult } from 'lit';
7
- import { DirectiveResult } from 'lit/directive.js';
8
- import { ComboBoxItemModel } from '@vaadin/combo-box/src/vaadin-combo-box.js';
6
+ import type { TemplateResult } from 'lit';
7
+ import type { DirectiveResult } from 'lit/directive.js';
8
+ import type { ComboBoxItemModel } from '@vaadin/combo-box/src/vaadin-combo-box.js';
9
9
  import { LitRendererDirective } from '@vaadin/lit-renderer';
10
- import { MultiSelectComboBox } from '../vaadin-multi-select-combo-box.js';
10
+ import type { MultiSelectComboBox } from '../vaadin-multi-select-combo-box.js';
11
11
 
12
12
  export type MultiSelectComboBoxLitRenderer<TItem> = (
13
13
  item: TItem,
@@ -18,7 +18,7 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
18
18
  * `label` | Element containing the label
19
19
  * `remove-button` | Remove button
20
20
  *
21
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
21
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
22
22
  *
23
23
  * @extends HTMLElement
24
24
  * @private
@@ -38,7 +38,6 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
38
38
 
39
39
  <vaadin-multi-select-combo-box-overlay
40
40
  id="overlay"
41
- hidden$="[[_isOverlayHidden(filteredItems, loading)]]"
42
41
  opened="[[_overlayOpened]]"
43
42
  loading$="[[loading]]"
44
43
  theme$="[[_theme]]"
@@ -87,6 +86,15 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
87
86
  value: () => [],
88
87
  },
89
88
 
89
+ /**
90
+ * Last input value entered by the user before value is updated.
91
+ * Used to store `filter` property value before clearing it.
92
+ */
93
+ lastFilter: {
94
+ type: String,
95
+ notify: true,
96
+ },
97
+
90
98
  _target: {
91
99
  type: Object,
92
100
  },
@@ -195,6 +203,18 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
195
203
  super._closeOrCommit();
196
204
  }
197
205
 
206
+ /**
207
+ * @protected
208
+ * @override
209
+ */
210
+ _commitValue() {
211
+ // Store filter value for checking if user input is matching
212
+ // an item which is already selected, to not un-select it.
213
+ this.lastFilter = this.filter;
214
+
215
+ super._commitValue();
216
+ }
217
+
198
218
  /**
199
219
  * Override method inherited from the combo-box
200
220
  * to not update focused item when readonly.
@@ -23,7 +23,7 @@ import { ComboBoxItem } from '@vaadin/combo-box/src/vaadin-combo-box-item.js';
23
23
  * `selected` | Set when the item is selected | :host
24
24
  * `focused` | Set when the item is focused | :host
25
25
  *
26
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
26
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
27
27
  *
28
28
  * @extends ComboBoxItem
29
29
  * @private
@@ -3,26 +3,28 @@
3
3
  * Copyright (c) 2021 - 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 {
6
+ import type {
7
7
  ComboBoxDataProvider,
8
8
  ComboBoxDefaultItem,
9
9
  ComboBoxItemModel,
10
10
  } from '@vaadin/combo-box/src/vaadin-combo-box.js';
11
- import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
12
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
13
- import { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
14
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
15
- import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
16
- import { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.js';
17
- import { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
18
- import { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
19
- import { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
20
- import { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
21
- import { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
22
- import { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
23
- import { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
24
- import { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
25
- import { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
12
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
13
+ import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
14
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
15
+ import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
16
+ import type { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.js';
17
+ import type { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
18
+ import type { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
19
+ import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
20
+ import type { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
21
+ import type { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
22
+ import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
23
+ import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
24
+ import type { SlotStylesMixinClass } from '@vaadin/field-base/src/slot-styles-mixin.js';
25
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
26
+ import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
27
+ import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
26
28
 
27
29
  export type MultiSelectComboBoxRenderer<TItem> = (
28
30
  root: HTMLElement,
@@ -65,6 +67,11 @@ export type MultiSelectComboBoxInvalidChangedEvent = CustomEvent<{ value: boolea
65
67
  */
66
68
  export type MultiSelectComboBoxSelectedItemsChangedEvent<TItem> = CustomEvent<{ value: TItem[] }>;
67
69
 
70
+ /**
71
+ * Fired whenever the field is validated.
72
+ */
73
+ export type MultiSelectComboBoxValidatedEvent = CustomEvent<{ valid: boolean }>;
74
+
68
75
  export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap {
69
76
  change: MultiSelectComboBoxChangeEvent<TItem>;
70
77
 
@@ -75,6 +82,8 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
75
82
  'invalid-changed': MultiSelectComboBoxInvalidChangedEvent;
76
83
 
77
84
  'selected-items-changed': MultiSelectComboBoxSelectedItemsChangedEvent<TItem>;
85
+
86
+ validated: MultiSelectComboBoxValidatedEvent;
78
87
  }
79
88
 
80
89
  /**
@@ -131,6 +140,7 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
131
140
  * Custom property | Description | Default
132
141
  * -----------------------------------------------------|----------------------------|--------
133
142
  * `--vaadin-field-default-width` | Default width of the field | `12em`
143
+ * `--vaadin-multi-select-combo-box-overlay-width` | Width of the overlay | `auto`
134
144
  * `--vaadin-multi-select-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
135
145
  * `--vaadin-multi-select-combo-box-input-min-width` | Min width of the input | `4em`
136
146
  *
@@ -146,13 +156,14 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
146
156
  * Note: the `theme` attribute value set on `<vaadin-multi-select-combo-box>` is
147
157
  * propagated to these components.
148
158
  *
149
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
159
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
150
160
  *
151
161
  * @fires {Event} change - Fired when the user commits a value change.
152
162
  * @fires {CustomEvent} custom-value-set - Fired when the user sets a custom value.
153
163
  * @fires {CustomEvent} filter-changed - Fired when the `filter` property changes.
154
164
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
155
165
  * @fires {CustomEvent} selected-items-changed - Fired when the `selectedItems` property changes.
166
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
156
167
  */
157
168
  declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLElement {
158
169
  /**
@@ -294,6 +305,11 @@ declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLEleme
294
305
  */
295
306
  clearCache(): void;
296
307
 
308
+ /**
309
+ * Clears the selected items.
310
+ */
311
+ clear(): void;
312
+
297
313
  /**
298
314
  * Requests an update for the content of items.
299
315
  * While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
@@ -305,21 +321,22 @@ declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLEleme
305
321
  addEventListener<K extends keyof MultiSelectComboBoxEventMap<TItem>>(
306
322
  type: K,
307
323
  listener: (this: MultiSelectComboBox<TItem>, ev: MultiSelectComboBoxEventMap<TItem>[K]) => void,
308
- options?: boolean | AddEventListenerOptions,
324
+ options?: AddEventListenerOptions | boolean,
309
325
  ): void;
310
326
 
311
327
  removeEventListener<K extends keyof MultiSelectComboBoxEventMap<TItem>>(
312
328
  type: K,
313
329
  listener: (this: MultiSelectComboBox<TItem>, ev: MultiSelectComboBoxEventMap<TItem>[K]) => void,
314
- options?: boolean | EventListenerOptions,
330
+ options?: EventListenerOptions | boolean,
315
331
  ): void;
316
332
  }
317
333
 
318
334
  interface MultiSelectComboBox
319
335
  extends ValidateMixinClass,
336
+ SlotStylesMixinClass,
320
337
  LabelMixinClass,
321
338
  KeyboardMixinClass,
322
- InputMixinClass,
339
+ Omit<InputMixinClass, 'value'>,
323
340
  InputControlMixinClass,
324
341
  InputConstraintsMixinClass,
325
342
  FocusMixinClass,
@@ -329,6 +346,7 @@ interface MultiSelectComboBox
329
346
  DelegateFocusMixinClass,
330
347
  ResizeMixinClass,
331
348
  ThemableMixinClass,
349
+ ThemePropertyMixinClass,
332
350
  ElementMixinClass,
333
351
  ControllerMixinClass {}
334
352
 
@@ -11,6 +11,7 @@ import { announce } from '@vaadin/component-base/src/a11y-announcer.js';
11
11
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
12
12
  import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
13
13
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
14
+ import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
14
15
  import { InputControlMixin } from '@vaadin/field-base/src/input-control-mixin.js';
15
16
  import { InputController } from '@vaadin/field-base/src/input-controller.js';
16
17
  import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-controller.js';
@@ -31,10 +32,6 @@ const multiSelectComboBox = css`
31
32
  align-items: center;
32
33
  }
33
34
 
34
- :host([has-value]) ::slotted(input:placeholder-shown) {
35
- color: transparent !important;
36
- }
37
-
38
35
  ::slotted(input) {
39
36
  box-sizing: border-box;
40
37
  flex: 1 0 var(--input-min-width);
@@ -109,6 +106,7 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
109
106
  * Custom property | Description | Default
110
107
  * -----------------------------------------------------|----------------------------|--------
111
108
  * `--vaadin-field-default-width` | Default width of the field | `12em`
109
+ * `--vaadin-multi-select-combo-box-overlay-width` | Width of the overlay | `auto`
112
110
  * `--vaadin-multi-select-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
113
111
  * `--vaadin-multi-select-combo-box-input-min-width` | Min width of the input | `4em`
114
112
  *
@@ -124,13 +122,14 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
124
122
  * Note: the `theme` attribute value set on `<vaadin-multi-select-combo-box>` is
125
123
  * propagated to these components.
126
124
  *
127
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
125
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
128
126
  *
129
127
  * @fires {Event} change - Fired when the user commits a value change.
130
128
  * @fires {CustomEvent} custom-value-set - Fired when the user sets a custom value.
131
129
  * @fires {CustomEvent} filter-changed - Fired when the `filter` property changes.
132
130
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
133
131
  * @fires {CustomEvent} selected-items-changed - Fired when the `selectedItems` property changes.
132
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
134
133
  *
135
134
  * @extends HTMLElement
136
135
  * @mixes ElementMixin
@@ -163,6 +162,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
163
162
  allow-custom-value="[[allowCustomValue]]"
164
163
  data-provider="[[dataProvider]]"
165
164
  filter="{{filter}}"
165
+ last-filter="{{_lastFilter}}"
166
166
  loading="{{loading}}"
167
167
  size="{{size}}"
168
168
  filtered-items="[[__effectiveFilteredItems]]"
@@ -195,7 +195,13 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
195
195
  ></vaadin-multi-select-combo-box-chip>
196
196
  <div id="chips" part="chips" slot="prefix"></div>
197
197
  <slot name="input"></slot>
198
- <div id="clearButton" part="clear-button" slot="suffix" aria-hidden="true"></div>
198
+ <div
199
+ id="clearButton"
200
+ part="clear-button"
201
+ slot="suffix"
202
+ on-touchend="_onClearButtonTouchend"
203
+ aria-hidden="true"
204
+ ></div>
199
205
  <div id="toggleButton" class="toggle-button" part="toggle-button" slot="suffix" aria-hidden="true"></div>
200
206
  </vaadin-multi-select-combo-box-container>
201
207
  </vaadin-multi-select-combo-box-internal>
@@ -208,6 +214,8 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
208
214
  <slot name="error-message"></slot>
209
215
  </div>
210
216
  </div>
217
+
218
+ <slot name="tooltip"></slot>
211
219
  `;
212
220
  }
213
221
 
@@ -423,6 +431,11 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
423
431
  */
424
432
  filteredItems: Array,
425
433
 
434
+ /** @private */
435
+ value: {
436
+ type: String,
437
+ },
438
+
426
439
  /** @private */
427
440
  __effectiveItems: {
428
441
  type: Array,
@@ -435,12 +448,6 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
435
448
  computed: '__computeEffectiveFilteredItems(items, filteredItems, selectedItems, readonly)',
436
449
  },
437
450
 
438
- /** @protected */
439
- _hasValue: {
440
- type: Boolean,
441
- value: false,
442
- },
443
-
444
451
  /** @private */
445
452
  _overflowItems: {
446
453
  type: Array,
@@ -453,6 +460,11 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
453
460
  value: -1,
454
461
  observer: '_focusedChipIndexChanged',
455
462
  },
463
+
464
+ /** @private */
465
+ _lastFilter: {
466
+ type: String,
467
+ },
456
468
  };
457
469
  }
458
470
 
@@ -460,6 +472,19 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
460
472
  return ['_selectedItemsChanged(selectedItems, selectedItems.*)'];
461
473
  }
462
474
 
475
+ /** @protected */
476
+ get slotStyles() {
477
+ const tag = this.localName;
478
+ return [
479
+ ...super.slotStyles,
480
+ `
481
+ ${tag}[has-value] input::placeholder {
482
+ color: transparent !important;
483
+ }
484
+ `,
485
+ ];
486
+ }
487
+
463
488
  /**
464
489
  * Used by `InputControlMixin` as a reference to the clear button element.
465
490
  * @protected
@@ -488,6 +513,10 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
488
513
  );
489
514
  this.addController(new LabelledInputController(this.inputElement, this._labelController));
490
515
 
516
+ this._tooltipController = new TooltipController(this);
517
+ this.addController(this._tooltipController);
518
+ this._tooltipController.setShouldShow((target) => !target.opened);
519
+
491
520
  this._inputField = this.shadowRoot.querySelector('[part="input-field"]');
492
521
  this.__updateChips();
493
522
 
@@ -502,6 +531,15 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
502
531
  return this.required && !this.readonly ? this._hasValue : true;
503
532
  }
504
533
 
534
+ /**
535
+ * Clears the selected items.
536
+ */
537
+ clear() {
538
+ this.__updateSelection([]);
539
+
540
+ announce(this.i18n.cleared);
541
+ }
542
+
505
543
  /**
506
544
  * Clears the cached pages and reloads data from data provider when needed.
507
545
  */
@@ -561,21 +599,6 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
561
599
  this._focusedChipIndex = -1;
562
600
  this.validate();
563
601
  }
564
-
565
- // Propagate focused attribute to internal combo box
566
- if (this.$ && this.$.comboBox) {
567
- this.$.comboBox.toggleAttribute('focused', focused);
568
- }
569
- }
570
-
571
- /**
572
- * Override method inherited from `InputMixin`
573
- * to keep attribute after clearing the input.
574
- * @protected
575
- * @override
576
- */
577
- _toggleHasValue() {
578
- super._toggleHasValue(this._hasValue);
579
602
  }
580
603
 
581
604
  /**
@@ -664,9 +687,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
664
687
 
665
688
  /** @private */
666
689
  _selectedItemsChanged(selectedItems) {
667
- this._hasValue = Boolean(selectedItems && selectedItems.length);
668
-
669
- this._toggleHasValue();
690
+ this._toggleHasValue(this._hasValue);
670
691
 
671
692
  // Use placeholder for announcing items
672
693
  if (this._hasValue) {
@@ -755,7 +776,8 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
755
776
  const itemsCopy = [...this.selectedItems];
756
777
  itemsCopy.splice(itemsCopy.indexOf(item), 1);
757
778
  this.__updateSelection(itemsCopy);
758
- this.__announceItem(item, false, itemsCopy.length);
779
+ const itemLabel = this._getItemLabel(item);
780
+ this.__announceItem(itemLabel, false, itemsCopy.length);
759
781
  }
760
782
 
761
783
  /** @private */
@@ -768,8 +790,9 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
768
790
  let isSelected = false;
769
791
 
770
792
  if (index !== -1) {
793
+ const lastFilter = this._lastFilter;
771
794
  // Do not unselect when manually typing and committing an already selected item.
772
- if (this.filter.toLowerCase() === itemLabel.toLowerCase()) {
795
+ if (lastFilter && lastFilter.toLowerCase() === itemLabel.toLowerCase()) {
773
796
  this.__clearFilter();
774
797
  return;
775
798
  }
@@ -877,6 +900,14 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
877
900
  this._overflowItems = items;
878
901
  }
879
902
 
903
+ /** @private */
904
+ _onClearButtonTouchend(event) {
905
+ // Cancel the following click and focus events
906
+ event.preventDefault();
907
+
908
+ this.clear();
909
+ }
910
+
880
911
  /**
881
912
  * Override method inherited from `InputControlMixin` and clear items.
882
913
  * @protected
@@ -885,9 +916,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
885
916
  _onClearButtonClick(event) {
886
917
  event.stopPropagation();
887
918
 
888
- this.__updateSelection([]);
889
-
890
- announce(this.i18n.cleared);
919
+ this.clear();
891
920
  }
892
921
 
893
922
  /**
@@ -1092,6 +1121,17 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
1092
1121
  __computeEffectiveFilteredItems(items, filteredItems, selectedItems, readonly) {
1093
1122
  return !items && readonly ? selectedItems : filteredItems;
1094
1123
  }
1124
+
1125
+ /**
1126
+ * Override a method from `InputMixin` to
1127
+ * compute the presence of value based on `selectedItems`.
1128
+ *
1129
+ * @protected
1130
+ * @override
1131
+ */
1132
+ get _hasValue() {
1133
+ return this.selectedItems && this.selectedItems.length > 0;
1134
+ }
1095
1135
  }
1096
1136
 
1097
1137
  customElements.define(MultiSelectComboBox.is, MultiSelectComboBox);