@vaadin/multi-select-combo-box 23.1.0-rc3 → 23.1.2

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/multi-select-combo-box",
3
- "version": "23.1.0-rc3",
3
+ "version": "23.1.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -33,18 +33,18 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "@polymer/polymer": "^3.0.0",
36
- "@vaadin/combo-box": "23.1.0-rc3",
37
- "@vaadin/component-base": "23.1.0-rc3",
38
- "@vaadin/field-base": "23.1.0-rc3",
39
- "@vaadin/input-container": "23.1.0-rc3",
40
- "@vaadin/vaadin-lumo-styles": "23.1.0-rc3",
41
- "@vaadin/vaadin-material-styles": "23.1.0-rc3",
42
- "@vaadin/vaadin-themable-mixin": "23.1.0-rc3"
36
+ "@vaadin/combo-box": "^23.1.2",
37
+ "@vaadin/component-base": "^23.1.2",
38
+ "@vaadin/field-base": "^23.1.2",
39
+ "@vaadin/input-container": "^23.1.2",
40
+ "@vaadin/vaadin-lumo-styles": "^23.1.2",
41
+ "@vaadin/vaadin-material-styles": "^23.1.2",
42
+ "@vaadin/vaadin-themable-mixin": "^23.1.2"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@esm-bundle/chai": "^4.3.4",
46
46
  "@vaadin/testing-helpers": "^0.3.2",
47
47
  "sinon": "^13.0.2"
48
48
  },
49
- "gitHead": "49c312fbe0228adb559296d45655bbfd4eac6235"
49
+ "gitHead": "6fb205c6e9a761feadfb779dd5d7af96d3102e56"
50
50
  }
@@ -33,6 +33,15 @@ class MultiSelectComboBoxDropdown extends ComboBoxDropdown {
33
33
  ></vaadin-multi-select-combo-box-overlay>
34
34
  `;
35
35
  }
36
+
37
+ /** @protected */
38
+ ready() {
39
+ super.ready();
40
+
41
+ // Set owner for using by item renderers
42
+ const comboBox = this.getRootNode().host;
43
+ this._scroller.comboBox = comboBox.getRootNode().host;
44
+ }
36
45
  }
37
46
 
38
47
  customElements.define(MultiSelectComboBoxDropdown.is, MultiSelectComboBoxDropdown);
@@ -50,6 +50,24 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
50
50
 
51
51
  static get properties() {
52
52
  return {
53
+ /**
54
+ * A subset of items, filtered based on the user input.
55
+ */
56
+ filteredItems: {
57
+ type: Array,
58
+ notify: true,
59
+ },
60
+
61
+ /**
62
+ * When set to `true`, "loading" attribute is set
63
+ * on the host and the overlay element.
64
+ * @type {boolean}
65
+ */
66
+ loading: {
67
+ type: Boolean,
68
+ notify: true,
69
+ },
70
+
53
71
  /**
54
72
  * Total number of items.
55
73
  * @type {number | undefined}
@@ -59,12 +77,34 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
59
77
  notify: true,
60
78
  },
61
79
 
80
+ /**
81
+ * Selected items to render in the dropdown
82
+ * when the component is read-only.
83
+ */
84
+ selectedItems: {
85
+ type: Array,
86
+ value: () => [],
87
+ },
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
+
62
98
  _target: {
63
99
  type: Object,
64
100
  },
65
101
  };
66
102
  }
67
103
 
104
+ static get observers() {
105
+ return ['_readonlyItemsChanged(readonly, selectedItems)'];
106
+ }
107
+
68
108
  /**
69
109
  * Reference to the clear button element.
70
110
  * @protected
@@ -80,7 +120,7 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
80
120
  * @override
81
121
  */
82
122
  open() {
83
- if (!this.disabled && !(this.readonly && this._getOverlayItems().length === 0)) {
123
+ if (!this.disabled && !(this.readonly && this.selectedItems.length === 0)) {
84
124
  this.opened = true;
85
125
  }
86
126
  }
@@ -152,6 +192,18 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
152
192
  super._closeOrCommit();
153
193
  }
154
194
 
195
+ /**
196
+ * @protected
197
+ * @override
198
+ */
199
+ _commitValue() {
200
+ // Store filter value for checking if user input is matching
201
+ // an item which is already selected, to not un-select it.
202
+ this.lastFilter = this.filter;
203
+
204
+ super._commitValue();
205
+ }
206
+
155
207
  /**
156
208
  * Override method inherited from the combo-box
157
209
  * to not update focused item when readonly.
@@ -246,6 +298,50 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
246
298
  );
247
299
  }
248
300
  }
301
+
302
+ /**
303
+ * Override method inherited from the combo-box
304
+ * to render only selected items when read-only,
305
+ * even if a different set of items is provided.
306
+ *
307
+ * @protected
308
+ * @override
309
+ */
310
+ _setOverlayItems(items) {
311
+ const effectiveItems = this.readonly ? this.selectedItems : items;
312
+ super._setOverlayItems(effectiveItems);
313
+ }
314
+
315
+ /**
316
+ * Override method inherited from the combo-box
317
+ * to not request data provider when read-only.
318
+ *
319
+ * @param {number}
320
+ * @return {boolean}
321
+ * @protected
322
+ * @override
323
+ */
324
+ _shouldLoadPage(page) {
325
+ if (this.readonly) {
326
+ return false;
327
+ }
328
+
329
+ return super._shouldLoadPage(page);
330
+ }
331
+
332
+ /** @private */
333
+ _readonlyItemsChanged(readonly, selectedItems) {
334
+ if (readonly && selectedItems) {
335
+ this.__savedItems = this._getOverlayItems();
336
+ this._setOverlayItems(selectedItems);
337
+ }
338
+
339
+ // Restore the original dropdown items
340
+ if (readonly === false && this.__savedItems) {
341
+ this._setOverlayItems(this.__savedItems);
342
+ this.__savedItems = null;
343
+ }
344
+ }
249
345
  }
250
346
 
251
347
  customElements.define(MultiSelectComboBoxInternal.is, MultiSelectComboBoxInternal);
@@ -40,8 +40,7 @@ class MultiSelectComboBoxScroller extends ComboBoxScroller {
40
40
  return false;
41
41
  }
42
42
 
43
- const host = this.comboBox.getRootNode().host;
44
- return host._findIndex(item, host.selectedItems, itemIdPath) > -1;
43
+ return this.comboBox._findIndex(item, this.comboBox.selectedItems, itemIdPath) > -1;
45
44
  }
46
45
 
47
46
  /** @private */
@@ -3,7 +3,11 @@
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 { ComboBoxDataProvider, ComboBoxDefaultItem, ComboBoxRenderer } from '@vaadin/combo-box/src/vaadin-combo-box.js';
6
+ import {
7
+ ComboBoxDataProvider,
8
+ ComboBoxDefaultItem,
9
+ ComboBoxItemModel,
10
+ } from '@vaadin/combo-box/src/vaadin-combo-box.js';
7
11
  import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
8
12
  import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
9
13
  import { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
@@ -20,6 +24,12 @@ import { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
20
24
  import { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
21
25
  import { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
22
26
 
27
+ export type MultiSelectComboBoxRenderer<TItem> = (
28
+ root: HTMLElement,
29
+ comboBox: MultiSelectComboBox<TItem>,
30
+ model: ComboBoxItemModel<TItem>,
31
+ ) => void;
32
+
23
33
  export interface MultiSelectComboBoxI18n {
24
34
  cleared: string;
25
35
  focused: string;
@@ -112,6 +122,7 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
112
122
  * `invalid` | Set when the element is invalid
113
123
  * `focused` | Set when the element is focused
114
124
  * `focus-ring` | Set when the element is keyboard focused
125
+ * `loading` | Set when loading items from the data provider
115
126
  * `opened` | Set when the dropdown is open
116
127
  * `readonly` | Set to a readonly element
117
128
  *
@@ -231,6 +242,11 @@ declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLEleme
231
242
  */
232
243
  i18n: MultiSelectComboBoxI18n;
233
244
 
245
+ /**
246
+ * True when loading items from the data provider, false otherwise.
247
+ */
248
+ loading: boolean;
249
+
234
250
  /**
235
251
  * True if the dropdown is open, false otherwise.
236
252
  */
@@ -254,13 +270,13 @@ declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLEleme
254
270
  * Receives three arguments:
255
271
  *
256
272
  * - `root` The `<vaadin-multi-select-combo-box-item>` internal container DOM element.
257
- * - `comboBox` The reference to the `<vaadin-combo-box>` element.
273
+ * - `comboBox` The reference to the `<vaadin-multi-select-combo-box>` element.
258
274
  * - `model` The object with the properties related with the rendered
259
275
  * item, contains:
260
276
  * - `model.index` The index of the rendered item.
261
277
  * - `model.item` The item.
262
278
  */
263
- renderer: ComboBoxRenderer<TItem> | null | undefined;
279
+ renderer: MultiSelectComboBoxRenderer<TItem> | null | undefined;
264
280
 
265
281
  /**
266
282
  * The list of selected items.
@@ -278,6 +294,14 @@ declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLEleme
278
294
  */
279
295
  clearCache(): void;
280
296
 
297
+ /**
298
+ * Requests an update for the content of items.
299
+ * While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
300
+ *
301
+ * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
302
+ */
303
+ requestContentUpdate(): void;
304
+
281
305
  addEventListener<K extends keyof MultiSelectComboBoxEventMap<TItem>>(
282
306
  type: K,
283
307
  listener: (this: MultiSelectComboBox<TItem>, ev: MultiSelectComboBoxEventMap<TItem>[K]) => void,
@@ -100,6 +100,7 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
100
100
  * `invalid` | Set when the element is invalid
101
101
  * `focused` | Set when the element is focused
102
102
  * `focus-ring` | Set when the element is keyboard focused
103
+ * `loading` | Set when loading items from the data provider
103
104
  * `opened` | Set when the dropdown is open
104
105
  * `readonly` | Set to a readonly element
105
106
  *
@@ -162,14 +163,18 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
162
163
  allow-custom-value="[[allowCustomValue]]"
163
164
  data-provider="[[dataProvider]]"
164
165
  filter="{{filter}}"
166
+ last-filter="{{_lastFilter}}"
167
+ loading="{{loading}}"
165
168
  size="{{size}}"
166
169
  filtered-items="[[filteredItems]]"
170
+ selected-items="[[selectedItems]]"
167
171
  opened="{{opened}}"
168
172
  renderer="[[renderer]]"
169
173
  theme$="[[_theme]]"
170
174
  on-combo-box-item-selected="_onComboBoxItemSelected"
171
175
  on-change="_onComboBoxChange"
172
176
  on-custom-value-set="_onCustomValueSet"
177
+ on-filtered-items-changed="_onFilteredItemsChanged"
173
178
  >
174
179
  <vaadin-multi-select-combo-box-container
175
180
  part="input-field"
@@ -298,6 +303,15 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
298
303
  },
299
304
  },
300
305
 
306
+ /**
307
+ * True when loading items from the data provider, false otherwise.
308
+ */
309
+ loading: {
310
+ type: Boolean,
311
+ value: false,
312
+ reflectToAttribute: true,
313
+ },
314
+
301
315
  /**
302
316
  * When present, it specifies that the field is read-only.
303
317
  */
@@ -359,7 +373,6 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
359
373
  */
360
374
  dataProvider: {
361
375
  type: Object,
362
- observer: '_dataProviderChanged',
363
376
  },
364
377
 
365
378
  /**
@@ -387,7 +400,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
387
400
  * Receives three arguments:
388
401
  *
389
402
  * - `root` The `<vaadin-multi-select-combo-box-item>` internal container DOM element.
390
- * - `comboBox` The reference to the `<vaadin-combo-box>` element.
403
+ * - `comboBox` The reference to the `<vaadin-multi-select-combo-box>` element.
391
404
  * - `model` The object with the properties related with the rendered
392
405
  * item, contains:
393
406
  * - `model.index` The index of the rendered item.
@@ -429,6 +442,11 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
429
442
  value: -1,
430
443
  observer: '_focusedChipIndexChanged',
431
444
  },
445
+
446
+ /** @private */
447
+ _lastFilter: {
448
+ type: String,
449
+ },
432
450
  };
433
451
  }
434
452
 
@@ -487,6 +505,18 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
487
505
  }
488
506
  }
489
507
 
508
+ /**
509
+ * Requests an update for the content of items.
510
+ * While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
511
+ *
512
+ * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
513
+ */
514
+ requestContentUpdate() {
515
+ if (this.$ && this.$.comboBox) {
516
+ this.$.comboBox.requestContentUpdate();
517
+ }
518
+ }
519
+
490
520
  /**
491
521
  * Override method inherited from `DisabledMixin` to forward disabled to chips.
492
522
  * @protected
@@ -582,15 +612,23 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
582
612
  }
583
613
  }
584
614
 
615
+ /**
616
+ * Implement two-way binding for the `filteredItems` property
617
+ * that can be set on the internal combo-box element.
618
+ *
619
+ * @param {CustomEvent} event
620
+ * @private
621
+ */
622
+ _onFilteredItemsChanged(event) {
623
+ const { value } = event.detail;
624
+ if (Array.isArray(value) || value == null) {
625
+ this.filteredItems = value;
626
+ }
627
+ }
628
+
585
629
  /** @private */
586
630
  _readonlyChanged(readonly, oldReadonly) {
587
- if (readonly) {
588
- this.__savedItems = this.$.comboBox._getOverlayItems();
589
- this.$.comboBox._setOverlayItems(Array.from(this.selectedItems));
590
- this.__updateChips();
591
- } else if (oldReadonly) {
592
- this.$.comboBox._setOverlayItems(this.__savedItems);
593
- this.__savedItems = null;
631
+ if (readonly || oldReadonly) {
594
632
  this.__updateChips();
595
633
  }
596
634
  }
@@ -637,12 +675,8 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
637
675
  // Re-render chips
638
676
  this.__updateChips();
639
677
 
640
- if (this.readonly) {
641
- this.$.comboBox._setOverlayItems(selectedItems);
642
- }
643
-
644
678
  // Update selected for dropdown items
645
- this.$.comboBox.requestContentUpdate();
679
+ this.requestContentUpdate();
646
680
  }
647
681
 
648
682
  /** @private */
@@ -728,8 +762,9 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
728
762
  let isSelected = false;
729
763
 
730
764
  if (index !== -1) {
765
+ const lastFilter = this._lastFilter;
731
766
  // Do not unselect when manually typing and committing an already selected item.
732
- if (this.filter.toLowerCase() === itemLabel.toLowerCase()) {
767
+ if (lastFilter && lastFilter.toLowerCase() === itemLabel.toLowerCase()) {
733
768
  this.__clearFilter();
734
769
  return;
735
770
  }
@@ -850,6 +885,18 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
850
885
  announce(this.i18n.cleared);
851
886
  }
852
887
 
888
+ /**
889
+ * Override an event listener from `InputControlMixin` to
890
+ * stop the change event re-targeted from the input.
891
+ *
892
+ * @param {!Event} event
893
+ * @protected
894
+ * @override
895
+ */
896
+ _onChange(event) {
897
+ event.stopPropagation();
898
+ }
899
+
853
900
  /**
854
901
  * Override an event listener from `KeyboardMixin`.
855
902
  * Do not call `super` in order to override clear