@vaadin/combo-box 25.3.0-dev.1fa5a51482 → 25.3.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.
- package/custom-elements.json +149 -36
- package/package.json +14 -14
- package/src/vaadin-combo-box-base-mixin.js +55 -12
- package/src/vaadin-combo-box-data-provider-mixin.js +15 -9
- package/src/vaadin-combo-box-focus-index-mixin.js +5 -0
- package/src/vaadin-combo-box-item-mixin.js +1 -1
- package/src/vaadin-combo-box-item.js +3 -3
- package/src/vaadin-combo-box-items-mixin.d.ts +45 -0
- package/src/vaadin-combo-box-items-mixin.js +167 -4
- package/src/vaadin-combo-box-mixin.d.ts +0 -17
- package/src/vaadin-combo-box-mixin.js +7 -114
- package/src/vaadin-combo-box-overlay-mixin.js +10 -13
- package/src/vaadin-combo-box-overlay.js +3 -1
- package/src/vaadin-combo-box-placeholder.d.ts +20 -0
- package/src/vaadin-combo-box-scroller-mixin.d.ts +1 -6
- package/src/vaadin-combo-box-scroller-mixin.js +7 -19
- package/src/vaadin-combo-box-scroller.js +3 -1
- package/src/vaadin-combo-box.d.ts +43 -8
- package/src/vaadin-combo-box.js +42 -8
- package/web-types.json +44 -8
- package/web-types.lit.json +19 -5
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
7
|
import type { ComboBoxBaseMixinClass } from './vaadin-combo-box-base-mixin.js';
|
|
8
8
|
|
|
9
|
+
export type ComboBoxPartialMatchMode = 'first-match' | 'none' | 'only-match';
|
|
10
|
+
|
|
9
11
|
export declare function ComboBoxItemsMixin<TItem, T extends Constructor<HTMLElement>>(
|
|
10
12
|
base: T,
|
|
11
13
|
): Constructor<ComboBoxBaseMixinClass> & Constructor<ComboBoxItemsMixinClass<TItem>> & T;
|
|
@@ -57,4 +59,47 @@ export declare class ComboBoxItemsMixinClass<TItem> {
|
|
|
57
59
|
* @attr {string} item-value-path
|
|
58
60
|
*/
|
|
59
61
|
itemValuePath: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Path for the id of the item. If `items` is an array of objects,
|
|
65
|
+
* the `itemIdPath` is used to compare and identify the same item
|
|
66
|
+
* in the selection and in `filteredItems` (items given by the
|
|
67
|
+
* `dataProvider` callback).
|
|
68
|
+
* @attr {string} item-id-path
|
|
69
|
+
*/
|
|
70
|
+
itemIdPath: string | null | undefined;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Controls which item is automatically set to be selected, for
|
|
74
|
+
* example on Enter, when the typed filter only partially matches
|
|
75
|
+
* its label. The item that will be selected is highlighted in the
|
|
76
|
+
* dropdown while typing:
|
|
77
|
+
*
|
|
78
|
+
* - `none` (default): an item is automatically set to be selected only when the filter matches its label exactly.
|
|
79
|
+
* - `first-match`: the first item in the filtered results is automatically set to be selected.
|
|
80
|
+
* - `only-match`: the item is automatically set to be selected when filtering narrows the results to a single item.
|
|
81
|
+
*
|
|
82
|
+
* In general, an exact match is always set to be selected and takes
|
|
83
|
+
* precedence over partial matches, regardless of the mode.
|
|
84
|
+
*
|
|
85
|
+
* A partial match is only applied while the dropdown is open. For
|
|
86
|
+
* example, when auto-open is disabled with `autoOpenDisabled`, typing
|
|
87
|
+
* does not highlight a match or set it to be selected until the
|
|
88
|
+
* dropdown is opened.
|
|
89
|
+
*
|
|
90
|
+
* This feature cannot be used together with custom values, because a
|
|
91
|
+
* partial match is also a valid custom value. A partial match is not
|
|
92
|
+
* applied when custom values are allowed with `allowCustomValue`.
|
|
93
|
+
*
|
|
94
|
+
* @attr {none|first-match|only-match} partial-match-mode
|
|
95
|
+
*/
|
|
96
|
+
partialMatchMode: ComboBoxPartialMatchMode;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Requests an update for the content of items.
|
|
100
|
+
* While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
|
|
101
|
+
*
|
|
102
|
+
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
103
|
+
*/
|
|
104
|
+
requestContentUpdate(): void;
|
|
60
105
|
}
|
|
@@ -111,6 +111,47 @@ export const ComboBoxItemsMixin = (superClass) =>
|
|
|
111
111
|
value: 'value',
|
|
112
112
|
sync: true,
|
|
113
113
|
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Path for the id of the item. If `items` is an array of objects,
|
|
117
|
+
* the `itemIdPath` is used to compare and identify the same item
|
|
118
|
+
* in the selection and in `filteredItems` (items given by the
|
|
119
|
+
* `dataProvider` callback).
|
|
120
|
+
* @attr {string} item-id-path
|
|
121
|
+
*/
|
|
122
|
+
itemIdPath: {
|
|
123
|
+
type: String,
|
|
124
|
+
sync: true,
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Controls which item is automatically set to be selected, for
|
|
129
|
+
* example on Enter, when the typed filter only partially matches
|
|
130
|
+
* its label. The item that will be selected is highlighted in the
|
|
131
|
+
* dropdown while typing:
|
|
132
|
+
*
|
|
133
|
+
* - `none` (default): an item is automatically set to be selected only when the filter matches its label exactly.
|
|
134
|
+
* - `first-match`: the first item in the filtered results is automatically set to be selected.
|
|
135
|
+
* - `only-match`: the item is automatically set to be selected when filtering narrows the results to a single item.
|
|
136
|
+
*
|
|
137
|
+
* In general, an exact match is always set to be selected and takes
|
|
138
|
+
* precedence over partial matches, regardless of the mode.
|
|
139
|
+
*
|
|
140
|
+
* A partial match is only applied while the dropdown is open. For
|
|
141
|
+
* example, when auto-open is disabled with `autoOpenDisabled`, typing
|
|
142
|
+
* does not highlight a match or set it to be selected until the
|
|
143
|
+
* dropdown is opened.
|
|
144
|
+
*
|
|
145
|
+
* This feature cannot be used together with custom values, because a
|
|
146
|
+
* partial match is also a valid custom value. A partial match is not
|
|
147
|
+
* applied when custom values are allowed with `allowCustomValue`.
|
|
148
|
+
*
|
|
149
|
+
* @attr {none|first-match|only-match} partial-match-mode
|
|
150
|
+
*/
|
|
151
|
+
partialMatchMode: {
|
|
152
|
+
type: String,
|
|
153
|
+
value: 'none',
|
|
154
|
+
},
|
|
114
155
|
};
|
|
115
156
|
}
|
|
116
157
|
|
|
@@ -130,6 +171,39 @@ export const ComboBoxItemsMixin = (superClass) =>
|
|
|
130
171
|
}
|
|
131
172
|
}
|
|
132
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Requests an update for the content of items.
|
|
176
|
+
* While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
|
|
177
|
+
*
|
|
178
|
+
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
179
|
+
*/
|
|
180
|
+
requestContentUpdate() {
|
|
181
|
+
if (!this._scroller) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this._scroller.requestContentUpdate();
|
|
186
|
+
|
|
187
|
+
this._getItemElements().forEach((item) => {
|
|
188
|
+
item.requestContentUpdate();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Override method from `ComboBoxBaseMixin` to deselect
|
|
194
|
+
* dropdown item by requesting content update on clear.
|
|
195
|
+
* @param {Event} event
|
|
196
|
+
* @protected
|
|
197
|
+
* @override
|
|
198
|
+
*/
|
|
199
|
+
_onClearButtonClick(event) {
|
|
200
|
+
super._onClearButtonClick(event);
|
|
201
|
+
|
|
202
|
+
if (this.opened) {
|
|
203
|
+
this.requestContentUpdate();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
133
207
|
/**
|
|
134
208
|
* Override an event listener from `ComboBoxBaseMixin` to handle
|
|
135
209
|
* batched setting of both `opened` and `filter` properties.
|
|
@@ -161,6 +235,22 @@ export const ComboBoxItemsMixin = (superClass) =>
|
|
|
161
235
|
this.setProperties(props);
|
|
162
236
|
}
|
|
163
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Override method from `ComboBoxBaseMixin` to focus the item matching
|
|
240
|
+
* the filter when the dropdown is opened after typing, which is possible
|
|
241
|
+
* when `autoOpenDisabled` is enabled.
|
|
242
|
+
*
|
|
243
|
+
* @protected
|
|
244
|
+
* @override
|
|
245
|
+
*/
|
|
246
|
+
_onOpened() {
|
|
247
|
+
super._onOpened();
|
|
248
|
+
|
|
249
|
+
if (this.filter && this._focusedIndex === -1) {
|
|
250
|
+
this._focusedIndex = this.__getItemIndexByFilter(this._dropdownItems);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
164
254
|
/**
|
|
165
255
|
* Override method from `ComboBoxBaseMixin` to handle item label path.
|
|
166
256
|
* @protected
|
|
@@ -187,6 +277,26 @@ export const ComboBoxItemsMixin = (superClass) =>
|
|
|
187
277
|
return value;
|
|
188
278
|
}
|
|
189
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Override method from `ComboBoxBaseMixin` to compare object items
|
|
282
|
+
* by the value at `itemIdPath` instead of by identity.
|
|
283
|
+
* @param {unknown} item
|
|
284
|
+
* @param {unknown} other
|
|
285
|
+
* @return {boolean}
|
|
286
|
+
* @protected
|
|
287
|
+
* @override
|
|
288
|
+
*/
|
|
289
|
+
_isSameItem(item, other) {
|
|
290
|
+
if (this.itemIdPath && item && other) {
|
|
291
|
+
const id = get(this.itemIdPath, item);
|
|
292
|
+
if (id !== undefined) {
|
|
293
|
+
return id === get(this.itemIdPath, other);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return super._isSameItem(item, other);
|
|
298
|
+
}
|
|
299
|
+
|
|
190
300
|
/** @private */
|
|
191
301
|
_itemLabelPathChanged(itemLabelPath) {
|
|
192
302
|
if (typeof itemLabelPath !== 'string') {
|
|
@@ -231,12 +341,44 @@ export const ComboBoxItemsMixin = (superClass) =>
|
|
|
231
341
|
}
|
|
232
342
|
|
|
233
343
|
/**
|
|
234
|
-
* Provide items to be rendered in the dropdown.
|
|
235
|
-
*
|
|
344
|
+
* Provide items to be rendered in the dropdown. Override this method
|
|
345
|
+
* to change the items to render, e.g. to show custom items.
|
|
346
|
+
*
|
|
347
|
+
* @param {Array} newItems
|
|
236
348
|
* @protected
|
|
237
349
|
*/
|
|
238
|
-
_setDropdownItems() {
|
|
239
|
-
|
|
350
|
+
_setDropdownItems(newItems) {
|
|
351
|
+
const oldItems = this._dropdownItems;
|
|
352
|
+
this._dropdownItems = newItems;
|
|
353
|
+
|
|
354
|
+
// Store the currently focused item if any. The focused index preserves
|
|
355
|
+
// in the case when more filtered items are loading but it is reset
|
|
356
|
+
// when the user types in a filter query.
|
|
357
|
+
const focusedItem = oldItems ? oldItems[this._focusedIndex] : null;
|
|
358
|
+
|
|
359
|
+
// When both the previously-focused entry and the new entry at the
|
|
360
|
+
// same index are placeholders (e.g. the Flow connector mid-scroll
|
|
361
|
+
// re-pushing `_setDropdownItems`), preserve `_focusedIndex` until
|
|
362
|
+
// a follow-up call lands a real item at that position.
|
|
363
|
+
if (
|
|
364
|
+
oldItems &&
|
|
365
|
+
oldItems[this._focusedIndex] instanceof ComboBoxPlaceholder &&
|
|
366
|
+
newItems[this._focusedIndex] instanceof ComboBoxPlaceholder
|
|
367
|
+
) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Try to first set focus on the item that had been focused before `newItems` were updated
|
|
372
|
+
// if it is still present in the `newItems` array. Otherwise, set the focused index
|
|
373
|
+
// depending on the selected item or the filter query.
|
|
374
|
+
const focusedItemIndex = this.__getItemIndexByValue(newItems, this._getItemValue(focusedItem));
|
|
375
|
+
if (focusedItemIndex > -1) {
|
|
376
|
+
this._focusedIndex = focusedItemIndex;
|
|
377
|
+
} else {
|
|
378
|
+
// When the user filled in something that is different from the current value = filtering is enabled,
|
|
379
|
+
// set the focused index to the item that matches the filter query.
|
|
380
|
+
this._focusedIndex = this.__getItemIndexByFilter(newItems);
|
|
381
|
+
}
|
|
240
382
|
}
|
|
241
383
|
|
|
242
384
|
/** @private */
|
|
@@ -282,4 +424,25 @@ export const ComboBoxItemsMixin = (superClass) =>
|
|
|
282
424
|
return this._getItemLabel(item).toString().toLowerCase() === label.toString().toLowerCase();
|
|
283
425
|
});
|
|
284
426
|
}
|
|
427
|
+
|
|
428
|
+
/** @private */
|
|
429
|
+
__getItemIndexByFilter(items) {
|
|
430
|
+
// An item whose label matches the filter exactly takes precedence.
|
|
431
|
+
const exactMatchIndex = this.__getItemIndexByLabel(items, this.filter);
|
|
432
|
+
if (exactMatchIndex > -1) {
|
|
433
|
+
return exactMatchIndex;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (!this.opened || !items || items.length === 0 || !this.filter || this.allowCustomValue) {
|
|
437
|
+
return -1;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (this.partialMatchMode === 'first-match' || (this.partialMatchMode === 'only-match' && items.length === 1)) {
|
|
441
|
+
// Skip an item that is not yet loaded. Once the item is loaded,
|
|
442
|
+
// the focused index is updated again.
|
|
443
|
+
return items[0] instanceof ComboBoxPlaceholder ? -1 : 0;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return -1;
|
|
447
|
+
}
|
|
285
448
|
};
|
|
@@ -78,21 +78,4 @@ export declare class ComboBoxMixinClass<TItem> {
|
|
|
78
78
|
* The selected item from the `items` array.
|
|
79
79
|
*/
|
|
80
80
|
selectedItem: TItem | null | undefined;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Path for the id of the item. If `items` is an array of objects,
|
|
84
|
-
* the `itemIdPath` is used to compare and identify the same item
|
|
85
|
-
* in `selectedItem` and `filteredItems` (items given by the
|
|
86
|
-
* `dataProvider` callback).
|
|
87
|
-
* @attr {string} item-id-path
|
|
88
|
-
*/
|
|
89
|
-
itemIdPath: string | null | undefined;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Requests an update for the content of items.
|
|
93
|
-
* While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
|
|
94
|
-
*
|
|
95
|
-
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
96
|
-
*/
|
|
97
|
-
requestContentUpdate(): void;
|
|
98
81
|
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
|
|
7
7
|
import { ComboBoxItemsMixin } from './vaadin-combo-box-items-mixin.js';
|
|
8
|
-
import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Checks if the value is supported as an item value in this control.
|
|
@@ -79,33 +78,11 @@ export const ComboBoxMixin = (superClass) =>
|
|
|
79
78
|
itemClassNameGenerator: {
|
|
80
79
|
type: Object,
|
|
81
80
|
},
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Path for the id of the item. If `items` is an array of objects,
|
|
85
|
-
* the `itemIdPath` is used to compare and identify the same item
|
|
86
|
-
* in `selectedItem` and `filteredItems` (items given by the
|
|
87
|
-
* `dataProvider` callback).
|
|
88
|
-
* @attr {string} item-id-path
|
|
89
|
-
*/
|
|
90
|
-
itemIdPath: {
|
|
91
|
-
type: String,
|
|
92
|
-
sync: true,
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
/** @private */
|
|
96
|
-
__keepOverlayOpened: {
|
|
97
|
-
type: Boolean,
|
|
98
|
-
sync: true,
|
|
99
|
-
},
|
|
100
81
|
};
|
|
101
82
|
}
|
|
102
83
|
|
|
103
84
|
static get observers() {
|
|
104
|
-
return [
|
|
105
|
-
'_openedOrItemsChanged(opened, _dropdownItems, loading, __keepOverlayOpened)',
|
|
106
|
-
'_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
|
|
107
|
-
'_updateScroller(opened, _dropdownItems, _focusedIndex, _theme)',
|
|
108
|
-
];
|
|
85
|
+
return ['_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)'];
|
|
109
86
|
}
|
|
110
87
|
|
|
111
88
|
/** @protected */
|
|
@@ -121,24 +98,6 @@ export const ComboBoxMixin = (superClass) =>
|
|
|
121
98
|
this._lastCommittedValue = this.value;
|
|
122
99
|
}
|
|
123
100
|
|
|
124
|
-
/**
|
|
125
|
-
* Requests an update for the content of items.
|
|
126
|
-
* While performing the update, it invokes the renderer (passed in the `renderer` property) once an item.
|
|
127
|
-
*
|
|
128
|
-
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
129
|
-
*/
|
|
130
|
-
requestContentUpdate() {
|
|
131
|
-
if (!this._scroller) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
this._scroller.requestContentUpdate();
|
|
136
|
-
|
|
137
|
-
this._getItemElements().forEach((item) => {
|
|
138
|
-
item.requestContentUpdate();
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
101
|
/**
|
|
143
102
|
* @param {Object} props
|
|
144
103
|
* @protected
|
|
@@ -146,51 +105,13 @@ export const ComboBoxMixin = (superClass) =>
|
|
|
146
105
|
updated(props) {
|
|
147
106
|
super.updated(props);
|
|
148
107
|
|
|
149
|
-
['loading', '
|
|
108
|
+
['loading', 'itemClassNameGenerator', 'renderer', 'selectedItem'].forEach((prop) => {
|
|
150
109
|
if (props.has(prop)) {
|
|
151
110
|
this._scroller[prop] = this[prop];
|
|
152
111
|
}
|
|
153
112
|
});
|
|
154
113
|
}
|
|
155
114
|
|
|
156
|
-
/** @private */
|
|
157
|
-
_updateScroller(opened, items, focusedIndex, theme) {
|
|
158
|
-
if (opened) {
|
|
159
|
-
this._scroller.style.maxHeight =
|
|
160
|
-
getComputedStyle(this).getPropertyValue(`--${this._tagNamePrefix}-overlay-max-height`) || '65vh';
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const isClosing = this.hasAttribute('closing');
|
|
164
|
-
|
|
165
|
-
this._scroller.setProperties({
|
|
166
|
-
items: opened || isClosing ? items : [],
|
|
167
|
-
opened,
|
|
168
|
-
focusedIndex,
|
|
169
|
-
theme,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** @private */
|
|
174
|
-
_openedOrItemsChanged(opened, items, loading, keepOverlayOpened) {
|
|
175
|
-
// Close the overlay if there are no items to display.
|
|
176
|
-
// See https://github.com/vaadin/vaadin-combo-box/pull/964
|
|
177
|
-
this._overlayOpened = opened && (keepOverlayOpened || loading || !!items?.length);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Override method from `ComboBoxBaseMixin` to deselect
|
|
182
|
-
* dropdown item by requesting content update on clear.
|
|
183
|
-
* @param {Event} event
|
|
184
|
-
* @protected
|
|
185
|
-
*/
|
|
186
|
-
_onClearButtonClick(event) {
|
|
187
|
-
super._onClearButtonClick(event);
|
|
188
|
-
|
|
189
|
-
if (this.opened) {
|
|
190
|
-
this.requestContentUpdate();
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
115
|
/**
|
|
195
116
|
* Override method inherited from `InputMixin`
|
|
196
117
|
* to revert the input value to value.
|
|
@@ -281,6 +202,8 @@ export const ComboBoxMixin = (superClass) =>
|
|
|
281
202
|
* @override
|
|
282
203
|
*/
|
|
283
204
|
_onOpened() {
|
|
205
|
+
super._onOpened();
|
|
206
|
+
|
|
284
207
|
this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-opened', { bubbles: true, composed: true }));
|
|
285
208
|
|
|
286
209
|
// _detectAndDispatchChange() should not consider value changes done before opening
|
|
@@ -497,20 +420,14 @@ export const ComboBoxMixin = (superClass) =>
|
|
|
497
420
|
}
|
|
498
421
|
|
|
499
422
|
/**
|
|
500
|
-
*
|
|
501
|
-
*
|
|
423
|
+
* Override method from `ComboBoxItemsMixin` to sync `selectedItem`
|
|
424
|
+
* based on `value` once a new set of items is available.
|
|
502
425
|
*
|
|
503
426
|
* @protected
|
|
504
427
|
* @override
|
|
505
428
|
*/
|
|
506
429
|
_setDropdownItems(newItems) {
|
|
507
|
-
|
|
508
|
-
this._dropdownItems = newItems;
|
|
509
|
-
|
|
510
|
-
// Store the currently focused item if any. The focused index preserves
|
|
511
|
-
// in the case when more filtered items are loading but it is reset
|
|
512
|
-
// when the user types in a filter query.
|
|
513
|
-
const focusedItem = oldItems ? oldItems[this._focusedIndex] : null;
|
|
430
|
+
super._setDropdownItems(newItems);
|
|
514
431
|
|
|
515
432
|
// Try to sync `selectedItem` based on `value` once a new set of `filteredItems` is available
|
|
516
433
|
// (as a result of external filtering or when they have been loaded by the data provider).
|
|
@@ -520,30 +437,6 @@ export const ComboBoxMixin = (superClass) =>
|
|
|
520
437
|
if ((this.selectedItem === null || this.selectedItem === undefined) && valueIndex >= 0) {
|
|
521
438
|
this.selectedItem = newItems[valueIndex];
|
|
522
439
|
}
|
|
523
|
-
|
|
524
|
-
// When both the previously-focused entry and the new entry at the
|
|
525
|
-
// same index are placeholders (e.g. the Flow connector mid-scroll
|
|
526
|
-
// re-pushing `_setDropdownItems`), preserve `_focusedIndex` until
|
|
527
|
-
// a follow-up call lands a real item at that position.
|
|
528
|
-
if (
|
|
529
|
-
oldItems &&
|
|
530
|
-
oldItems[this._focusedIndex] instanceof ComboBoxPlaceholder &&
|
|
531
|
-
newItems[this._focusedIndex] instanceof ComboBoxPlaceholder
|
|
532
|
-
) {
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Try to first set focus on the item that had been focused before `newItems` were updated
|
|
537
|
-
// if it is still present in the `newItems` array. Otherwise, set the focused index
|
|
538
|
-
// depending on the selected item or the filter query.
|
|
539
|
-
const focusedItemIndex = this.__getItemIndexByValue(newItems, this._getItemValue(focusedItem));
|
|
540
|
-
if (focusedItemIndex > -1) {
|
|
541
|
-
this._focusedIndex = focusedItemIndex;
|
|
542
|
-
} else {
|
|
543
|
-
// When the user filled in something that is different from the current value = filtering is enabled,
|
|
544
|
-
// set the focused index to the item that matches the filter query.
|
|
545
|
-
this._focusedIndex = this.__getItemIndexByLabel(newItems, this.filter);
|
|
546
|
-
}
|
|
547
440
|
}
|
|
548
441
|
|
|
549
442
|
/**
|
|
@@ -8,16 +8,22 @@ import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin
|
|
|
8
8
|
|
|
9
9
|
export const ComboBoxOverlayMixin = (superClass) =>
|
|
10
10
|
class ComboBoxOverlayMixin extends PositionMixin(superClass) {
|
|
11
|
-
static get observers() {
|
|
12
|
-
return ['_setOverlayWidth(positionTarget, opened)'];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
constructor() {
|
|
16
12
|
super();
|
|
17
13
|
|
|
18
14
|
this.requiredVerticalSpace = 200;
|
|
19
15
|
}
|
|
20
16
|
|
|
17
|
+
/** @protected */
|
|
18
|
+
willUpdate(props) {
|
|
19
|
+
super.willUpdate(props);
|
|
20
|
+
|
|
21
|
+
// Update width here so that `PositionMixin` uses correct width in `updated()`.
|
|
22
|
+
if ((props.has('opened') || props.has('positionTarget')) && this.opened && this.positionTarget) {
|
|
23
|
+
this._updateOverlayWidth();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
/**
|
|
22
28
|
* Override method inherited from `Overlay`
|
|
23
29
|
* to not close on position target click.
|
|
@@ -49,13 +55,4 @@ export const ComboBoxOverlayMixin = (superClass) =>
|
|
|
49
55
|
_updateOverlayWidth() {
|
|
50
56
|
this.style.setProperty(`--_${this.localName}-default-width`, `${this.positionTarget.offsetWidth}px`);
|
|
51
57
|
}
|
|
52
|
-
|
|
53
|
-
/** @private */
|
|
54
|
-
_setOverlayWidth(positionTarget, opened) {
|
|
55
|
-
if (positionTarget && opened) {
|
|
56
|
-
this._updateOverlayWidth();
|
|
57
|
-
|
|
58
|
-
this._updatePosition();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
58
|
};
|
|
@@ -22,7 +22,7 @@ import { ComboBoxOverlayMixin } from './vaadin-combo-box-overlay-mixin.js';
|
|
|
22
22
|
* @extends HTMLElement
|
|
23
23
|
* @private
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
class ComboBoxOverlay extends ComboBoxOverlayMixin(
|
|
26
26
|
OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))),
|
|
27
27
|
) {
|
|
28
28
|
static get is() {
|
|
@@ -45,3 +45,5 @@ export class ComboBoxOverlay extends ComboBoxOverlayMixin(
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
defineCustomElement(ComboBoxOverlay);
|
|
48
|
+
|
|
49
|
+
export { ComboBoxOverlay };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2015 - 2026 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Placeholder object class representing items being loaded.
|
|
9
|
+
*
|
|
10
|
+
* @private
|
|
11
|
+
*/
|
|
12
|
+
declare class ComboBoxPlaceholder {
|
|
13
|
+
// Nominal brand: keeps structurally similar values from being assignable
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-private-class-members
|
|
15
|
+
private __comboBoxPlaceholder: true;
|
|
16
|
+
|
|
17
|
+
toString(): string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { ComboBoxPlaceholder };
|
|
@@ -17,11 +17,6 @@ export declare class ComboBoxScrollerMixinClass<TItem, TOwner> {
|
|
|
17
17
|
*/
|
|
18
18
|
focusedIndex: number;
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* Path for the id of the item, used to detect whether the item is selected.
|
|
22
|
-
*/
|
|
23
|
-
itemIdPath: string | null | undefined;
|
|
24
|
-
|
|
25
20
|
/**
|
|
26
21
|
* A full set of items to filter the visible options from.
|
|
27
22
|
* Set to an empty array when combo-box is not opened.
|
|
@@ -78,7 +73,7 @@ export declare class ComboBoxScrollerMixinClass<TItem, TOwner> {
|
|
|
78
73
|
*/
|
|
79
74
|
scrollIntoView(index: number, alignToCenter?: boolean): void;
|
|
80
75
|
|
|
81
|
-
protected _isItemSelected(item: TItem, selectedItem: TItem
|
|
76
|
+
protected _isItemSelected(item: TItem, selectedItem: TItem): boolean;
|
|
82
77
|
|
|
83
78
|
protected _updateElement(el: HTMLElement, index: number): void;
|
|
84
79
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2015 - 2026 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 { setOrRemoveAttribute } from '@vaadin/component-base/src/dom-utils.js';
|
|
7
7
|
import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
|
|
8
8
|
import { Virtualizer } from '@vaadin/component-base/src/virtualizer.js';
|
|
9
9
|
import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
|
|
@@ -71,13 +71,6 @@ export const ComboBoxScrollerMixin = (superClass) =>
|
|
|
71
71
|
observer: '__itemClassNameGeneratorChanged',
|
|
72
72
|
},
|
|
73
73
|
|
|
74
|
-
/**
|
|
75
|
-
* Path for the id of the item, used to detect whether the item is selected.
|
|
76
|
-
*/
|
|
77
|
-
itemIdPath: {
|
|
78
|
-
type: String,
|
|
79
|
-
},
|
|
80
|
-
|
|
81
74
|
/**
|
|
82
75
|
* Reference to the owner (combo-box owner), used by the item elements.
|
|
83
76
|
*/
|
|
@@ -243,16 +236,15 @@ export const ComboBoxScrollerMixin = (superClass) =>
|
|
|
243
236
|
/**
|
|
244
237
|
* @param {string | object} item
|
|
245
238
|
* @param {string | object} selectedItem
|
|
246
|
-
* @
|
|
239
|
+
* @return {boolean}
|
|
247
240
|
* @protected
|
|
248
241
|
*/
|
|
249
|
-
_isItemSelected(item, selectedItem
|
|
242
|
+
_isItemSelected(item, selectedItem) {
|
|
250
243
|
if (item instanceof ComboBoxPlaceholder) {
|
|
251
244
|
return false;
|
|
252
|
-
} else if (itemIdPath && item !== undefined && selectedItem !== undefined) {
|
|
253
|
-
return get(itemIdPath, item) === get(itemIdPath, selectedItem);
|
|
254
245
|
}
|
|
255
|
-
|
|
246
|
+
|
|
247
|
+
return this.owner._isSameItem(item, selectedItem);
|
|
256
248
|
}
|
|
257
249
|
|
|
258
250
|
/** @private */
|
|
@@ -366,7 +358,7 @@ export const ComboBoxScrollerMixin = (superClass) =>
|
|
|
366
358
|
_updateElement(el, index) {
|
|
367
359
|
const item = this.items[index];
|
|
368
360
|
const focusedIndex = this.focusedIndex;
|
|
369
|
-
const selected = this._isItemSelected(item, this.selectedItem
|
|
361
|
+
const selected = this._isItemSelected(item, this.selectedItem);
|
|
370
362
|
|
|
371
363
|
el.setProperties({
|
|
372
364
|
item,
|
|
@@ -389,11 +381,7 @@ export const ComboBoxScrollerMixin = (superClass) =>
|
|
|
389
381
|
el.setAttribute('aria-posinset', index + 1);
|
|
390
382
|
el.setAttribute('aria-setsize', this.items.length);
|
|
391
383
|
|
|
392
|
-
|
|
393
|
-
el.setAttribute('theme', this.theme);
|
|
394
|
-
} else {
|
|
395
|
-
el.removeAttribute('theme');
|
|
396
|
-
}
|
|
384
|
+
setOrRemoveAttribute(el, 'theme', this.theme);
|
|
397
385
|
|
|
398
386
|
if (item instanceof ComboBoxPlaceholder) {
|
|
399
387
|
this.__requestItemByIndex(index);
|
|
@@ -16,7 +16,7 @@ import { ComboBoxScrollerMixin } from './vaadin-combo-box-scroller-mixin.js';
|
|
|
16
16
|
* @extends HTMLElement
|
|
17
17
|
* @private
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
class ComboBoxScroller extends ComboBoxScrollerMixin(PolylitMixin(LitElement)) {
|
|
20
20
|
static get is() {
|
|
21
21
|
return 'vaadin-combo-box-scroller';
|
|
22
22
|
}
|
|
@@ -36,3 +36,5 @@ export class ComboBoxScroller extends ComboBoxScrollerMixin(PolylitMixin(LitElem
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
defineCustomElement(ComboBoxScroller);
|
|
39
|
+
|
|
40
|
+
export { ComboBoxScroller };
|