@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 +9 -9
- package/src/vaadin-multi-select-combo-box-dropdown.js +9 -0
- package/src/vaadin-multi-select-combo-box-internal.js +97 -1
- package/src/vaadin-multi-select-combo-box-scroller.js +1 -2
- package/src/vaadin-multi-select-combo-box.d.ts +27 -3
- package/src/vaadin-multi-select-combo-box.js +62 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/multi-select-combo-box",
|
|
3
|
-
"version": "23.1.
|
|
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.
|
|
37
|
-
"@vaadin/component-base": "23.1.
|
|
38
|
-
"@vaadin/field-base": "23.1.
|
|
39
|
-
"@vaadin/input-container": "23.1.
|
|
40
|
-
"@vaadin/vaadin-lumo-styles": "23.1.
|
|
41
|
-
"@vaadin/vaadin-material-styles": "23.1.
|
|
42
|
-
"@vaadin/vaadin-themable-mixin": "23.1.
|
|
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": "
|
|
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.
|
|
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
|
-
|
|
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 {
|
|
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:
|
|
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
|
|
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 (
|
|
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
|