@vaadin/multi-select-combo-box 24.6.0-alpha9 → 24.6.0-rc1

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 (26) hide show
  1. package/package.json +16 -15
  2. package/src/vaadin-lit-multi-select-combo-box-chip.js +79 -0
  3. package/src/vaadin-lit-multi-select-combo-box-container.js +66 -0
  4. package/src/vaadin-lit-multi-select-combo-box-internal.js +56 -0
  5. package/src/vaadin-lit-multi-select-combo-box-item.js +50 -0
  6. package/src/vaadin-lit-multi-select-combo-box-overlay.js +64 -0
  7. package/src/vaadin-lit-multi-select-combo-box-scroller.js +96 -0
  8. package/src/vaadin-lit-multi-select-combo-box.d.ts +1 -0
  9. package/src/vaadin-lit-multi-select-combo-box.js +146 -0
  10. package/src/vaadin-multi-select-combo-box-chip.js +6 -27
  11. package/src/vaadin-multi-select-combo-box-internal-mixin.js +425 -0
  12. package/src/vaadin-multi-select-combo-box-internal.js +3 -399
  13. package/src/vaadin-multi-select-combo-box-mixin.d.ts +253 -0
  14. package/src/vaadin-multi-select-combo-box-mixin.js +1150 -0
  15. package/src/vaadin-multi-select-combo-box-styles.d.ts +10 -0
  16. package/src/vaadin-multi-select-combo-box-styles.js +73 -0
  17. package/src/vaadin-multi-select-combo-box.d.ts +5 -213
  18. package/src/vaadin-multi-select-combo-box.js +5 -1139
  19. package/theme/lumo/vaadin-lit-multi-select-combo-box.d.ts +3 -0
  20. package/theme/lumo/vaadin-lit-multi-select-combo-box.js +3 -0
  21. package/theme/material/vaadin-lit-multi-select-combo-box.d.ts +3 -0
  22. package/theme/material/vaadin-lit-multi-select-combo-box.js +3 -0
  23. package/vaadin-lit-multi-select-combo-box.d.ts +1 -0
  24. package/vaadin-lit-multi-select-combo-box.js +2 -0
  25. package/web-types.json +5 -5
  26. package/web-types.lit.json +8 -8
@@ -0,0 +1,425 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { ComboBoxDataProviderMixin } from '@vaadin/combo-box/src/vaadin-combo-box-data-provider-mixin.js';
7
+ import { ComboBoxMixin } from '@vaadin/combo-box/src/vaadin-combo-box-mixin.js';
8
+ import { ComboBoxPlaceholder } from '@vaadin/combo-box/src/vaadin-combo-box-placeholder.js';
9
+
10
+ /**
11
+ * @polymerMixin
12
+ * @mixes ComboBoxDataProviderMixin
13
+ * @mixes ComboBoxMixin
14
+ */
15
+ export const MultiSelectComboBoxInternalMixin = (superClass) =>
16
+ class MultiSelectComboBoxInternalMixinClass extends ComboBoxDataProviderMixin(ComboBoxMixin(superClass)) {
17
+ static get properties() {
18
+ return {
19
+ /**
20
+ * A subset of items, filtered based on the user input.
21
+ */
22
+ filteredItems: {
23
+ type: Array,
24
+ notify: true,
25
+ sync: true,
26
+ },
27
+
28
+ /**
29
+ * When true, filter string isn't cleared after selecting an item.
30
+ */
31
+ keepFilter: {
32
+ type: Boolean,
33
+ value: false,
34
+ },
35
+
36
+ /**
37
+ * When set to `true`, "loading" attribute is set
38
+ * on the host and the overlay element.
39
+ * @type {boolean}
40
+ */
41
+ loading: {
42
+ type: Boolean,
43
+ notify: true,
44
+ sync: true,
45
+ },
46
+
47
+ /**
48
+ * Total number of items.
49
+ * @type {number | undefined}
50
+ */
51
+ size: {
52
+ type: Number,
53
+ notify: true,
54
+ observer: '_sizeChanged',
55
+ sync: true,
56
+ },
57
+
58
+ /**
59
+ * Selected items to render in the dropdown
60
+ * when the component is read-only.
61
+ */
62
+ selectedItems: {
63
+ type: Array,
64
+ value: () => [],
65
+ },
66
+
67
+ /**
68
+ * Set to true to group selected items at the top of the overlay.
69
+ * @attr {boolean} selected-items-on-top
70
+ */
71
+ selectedItemsOnTop: {
72
+ type: Boolean,
73
+ value: false,
74
+ sync: true,
75
+ },
76
+
77
+ /**
78
+ * Last input value entered by the user before value is updated.
79
+ * Used to store `filter` property value before clearing it.
80
+ */
81
+ lastFilter: {
82
+ type: String,
83
+ notify: true,
84
+ sync: true,
85
+ },
86
+
87
+ /**
88
+ * A subset of items to be shown at the top of the overlay.
89
+ */
90
+ topGroup: {
91
+ type: Array,
92
+ observer: '_topGroupChanged',
93
+ sync: true,
94
+ },
95
+
96
+ _target: {
97
+ type: Object,
98
+ },
99
+ };
100
+ }
101
+
102
+ static get observers() {
103
+ return ['_readonlyChanged(readonly)'];
104
+ }
105
+
106
+ /**
107
+ * Reference to the clear button element.
108
+ * @protected
109
+ * @return {!HTMLElement}
110
+ */
111
+ get clearElement() {
112
+ return this.querySelector('[part="clear-button"]');
113
+ }
114
+
115
+ /**
116
+ * Tag name prefix used by scroller and items.
117
+ * @protected
118
+ * @return {string}
119
+ */
120
+ get _tagNamePrefix() {
121
+ return 'vaadin-multi-select-combo-box';
122
+ }
123
+
124
+ /**
125
+ * Override method inherited from the combo-box
126
+ * to allow opening dropdown when readonly.
127
+ * @override
128
+ */
129
+ open() {
130
+ if (!this.disabled && !(this.readonly && this.selectedItems.length === 0)) {
131
+ this.opened = true;
132
+ }
133
+ }
134
+
135
+ /** @protected */
136
+ ready() {
137
+ super.ready();
138
+
139
+ this._target = this;
140
+ this._toggleElement = this.querySelector('.toggle-button');
141
+ }
142
+
143
+ /** @protected */
144
+ async _updateOverlayWidth() {
145
+ if (!this.$ && this.updateComplete) {
146
+ await this.updateComplete;
147
+ }
148
+
149
+ this.$.overlay._updateOverlayWidth();
150
+ }
151
+
152
+ /** @private */
153
+ _readonlyChanged() {
154
+ this._setDropdownItems(this.filteredItems);
155
+ }
156
+
157
+ /**
158
+ * Override combo-box method to group selected
159
+ * items at the top of the overlay.
160
+ *
161
+ * @protected
162
+ * @override
163
+ */
164
+ _setDropdownItems(items) {
165
+ if (this.readonly) {
166
+ super._setDropdownItems(this.selectedItems);
167
+ return;
168
+ }
169
+
170
+ if (this.filter || !this.selectedItemsOnTop) {
171
+ super._setDropdownItems(items);
172
+ return;
173
+ }
174
+
175
+ if (items && items.length && this.topGroup && this.topGroup.length) {
176
+ // Filter out items included to the top group.
177
+ const filteredItems = items.filter(
178
+ (item) => this._comboBox._findIndex(item, this.topGroup, this.itemIdPath) === -1,
179
+ );
180
+
181
+ super._setDropdownItems(this.topGroup.concat(filteredItems));
182
+ return;
183
+ }
184
+
185
+ super._setDropdownItems(items);
186
+ }
187
+
188
+ /** @private */
189
+ _topGroupChanged(topGroup) {
190
+ if (topGroup) {
191
+ this._setDropdownItems(this.filteredItems);
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Override combo-box method to set correct owner for using by item renderers.
197
+ * This needs to be done before the scroller gets added to the DOM to ensure
198
+ * Lit directive works in case when combo-box is opened using attribute.
199
+ *
200
+ * @protected
201
+ * @override
202
+ */
203
+ _initScroller() {
204
+ const comboBox = this.getRootNode().host;
205
+
206
+ this._comboBox = comboBox;
207
+
208
+ super._initScroller(comboBox);
209
+ }
210
+
211
+ /**
212
+ * Override Enter handler to keep overlay open
213
+ * when item is selected or unselected.
214
+ * @param {!Event} event
215
+ * @protected
216
+ * @override
217
+ */
218
+ _onEnter(event) {
219
+ if (this.opened) {
220
+ // Do not submit the surrounding form.
221
+ event.preventDefault();
222
+ // Do not trigger global listeners.
223
+ event.stopPropagation();
224
+
225
+ if (this.readonly) {
226
+ this.close();
227
+ } else if (this._hasValidInputValue()) {
228
+ // Keep selected item focused after committing on Enter.
229
+ const focusedItem = this._dropdownItems[this._focusedIndex];
230
+ this._commitValue();
231
+ this._focusedIndex = this._dropdownItems.indexOf(focusedItem);
232
+ }
233
+
234
+ return;
235
+ }
236
+
237
+ super._onEnter(event);
238
+ }
239
+
240
+ /**
241
+ * Override Escape handler to not clear
242
+ * selected items when readonly.
243
+ * @param {!Event} event
244
+ * @protected
245
+ * @override
246
+ */
247
+ _onEscape(event) {
248
+ if (this.readonly) {
249
+ event.stopPropagation();
250
+ if (this.opened) {
251
+ this.close();
252
+ }
253
+ return;
254
+ }
255
+
256
+ super._onEscape(event);
257
+ }
258
+
259
+ /**
260
+ * Override from combo-box to ignore requests to clear the filter if the
261
+ * keepFilter option is enabled. Exceptions are when the dropdown is closed,
262
+ * so the filter is still cleared on cancel and focus out.
263
+ * @protected
264
+ * @override
265
+ */
266
+ _clearFilter() {
267
+ if (!this.keepFilter || !this.opened) {
268
+ super._clearFilter();
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Override method from combo-box to always clear the filter when reverting
274
+ * the input value, regardless of the keepFilter option.
275
+ * @override
276
+ * @protected
277
+ */
278
+ _revertInputValueToValue() {
279
+ super._revertInputValueToValue();
280
+ this.filter = '';
281
+ }
282
+
283
+ /**
284
+ * @protected
285
+ * @override
286
+ */
287
+ _commitValue() {
288
+ // Store filter value for checking if user input is matching
289
+ // an item which is already selected, to not un-select it.
290
+ this.lastFilter = this.filter;
291
+
292
+ super._commitValue();
293
+ }
294
+
295
+ /**
296
+ * Override method inherited from the combo-box
297
+ * to not update focused item when readonly.
298
+ * @protected
299
+ * @override
300
+ */
301
+ _onArrowDown() {
302
+ if (!this.readonly) {
303
+ super._onArrowDown();
304
+ } else if (!this.opened) {
305
+ this.open();
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Override method inherited from the combo-box
311
+ * to not update focused item when readonly.
312
+ * @protected
313
+ * @override
314
+ */
315
+ _onArrowUp() {
316
+ if (!this.readonly) {
317
+ super._onArrowUp();
318
+ } else if (!this.opened) {
319
+ this.open();
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Override method inherited from the combo-box
325
+ * to close dropdown on blur when readonly.
326
+ * @param {boolean} focused
327
+ * @protected
328
+ * @override
329
+ */
330
+ _setFocused(focused) {
331
+ // Disable combo-box logic that updates selectedItem
332
+ // based on the overlay focused index on input blur
333
+ if (!focused) {
334
+ this._ignoreCommitValue = true;
335
+ }
336
+
337
+ super._setFocused(focused);
338
+
339
+ if (!focused && this.readonly && !this._closeOnBlurIsPrevented) {
340
+ this.close();
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Override method inherited from the combo-box
346
+ * to not commit an already selected item again
347
+ * on blur, which would result in un-selecting.
348
+ * @protected
349
+ * @override
350
+ */
351
+ _detectAndDispatchChange() {
352
+ if (this._ignoreCommitValue) {
353
+ this._ignoreCommitValue = false;
354
+
355
+ // Reset internal combo-box state
356
+ this.selectedItem = null;
357
+ this._inputElementValue = '';
358
+ return;
359
+ }
360
+
361
+ super._detectAndDispatchChange();
362
+ }
363
+
364
+ /**
365
+ * @param {CustomEvent} event
366
+ * @protected
367
+ * @override
368
+ */
369
+ _overlaySelectedItemChanged(event) {
370
+ event.stopPropagation();
371
+
372
+ // Do not un-select on click when readonly
373
+ if (this.readonly) {
374
+ return;
375
+ }
376
+
377
+ if (event.detail.item instanceof ComboBoxPlaceholder) {
378
+ return;
379
+ }
380
+
381
+ if (this.opened) {
382
+ // Store filter value for checking if user input is matching
383
+ // an item which is already selected, to not un-select it.
384
+ this.lastFilter = this.filter;
385
+
386
+ this.dispatchEvent(
387
+ new CustomEvent('combo-box-item-selected', {
388
+ detail: {
389
+ item: event.detail.item,
390
+ },
391
+ }),
392
+ );
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Override method inherited from the combo-box
398
+ * to not request data provider when read-only.
399
+ *
400
+ * @protected
401
+ * @override
402
+ */
403
+ _shouldFetchData() {
404
+ if (this.readonly) {
405
+ return false;
406
+ }
407
+
408
+ return super._shouldFetchData();
409
+ }
410
+
411
+ /**
412
+ * Override method inherited from the combo-box
413
+ * to not clear the data provider cache when read-only.
414
+ *
415
+ * @protected
416
+ * @override
417
+ */
418
+ clearCache() {
419
+ if (this.readonly) {
420
+ return;
421
+ }
422
+
423
+ super.clearCache();
424
+ }
425
+ };