@vaadin/combo-box 25.3.0-beta2 → 25.3.0-beta3

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.
@@ -519,6 +519,16 @@
519
519
  "description": "A subset of items, filtered based on the user input. Filtered items\ncan be assigned directly to omit the internal filtering functionality.\nThe items can be of either `String` or `Object` type.",
520
520
  "attribute": "filtered-items"
521
521
  },
522
+ {
523
+ "kind": "field",
524
+ "name": "itemIdPath",
525
+ "privacy": "public",
526
+ "type": {
527
+ "text": "string"
528
+ },
529
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
530
+ "attribute": "item-id-path"
531
+ },
522
532
  {
523
533
  "kind": "field",
524
534
  "name": "itemLabelGenerator",
@@ -606,6 +616,11 @@
606
616
  "module": "src/vaadin-combo-box-base-mixin.js"
607
617
  }
608
618
  },
619
+ {
620
+ "kind": "method",
621
+ "name": "requestContentUpdate",
622
+ "description": "Requests an update for the content of items.\nWhile performing the update, it invokes the renderer (passed in the `renderer` property) once an item.\n\nIt is not guaranteed that the update happens immediately (synchronously) after it is requested."
623
+ },
609
624
  {
610
625
  "kind": "field",
611
626
  "name": "value",
@@ -654,6 +669,14 @@
654
669
  "description": "Filtering string the user has typed into the input field.",
655
670
  "fieldName": "filter"
656
671
  },
672
+ {
673
+ "name": "item-id-path",
674
+ "type": {
675
+ "text": "string"
676
+ },
677
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
678
+ "fieldName": "itemIdPath"
679
+ },
657
680
  {
658
681
  "name": "item-label-path",
659
682
  "type": {
@@ -882,8 +905,12 @@
882
905
  "type": {
883
906
  "text": "string"
884
907
  },
885
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
886
- "attribute": "item-id-path"
908
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
909
+ "attribute": "item-id-path",
910
+ "inheritedFrom": {
911
+ "name": "ComboBoxItemsMixin",
912
+ "module": "src/vaadin-combo-box-items-mixin.js"
913
+ }
887
914
  },
888
915
  {
889
916
  "kind": "field",
@@ -1029,7 +1056,11 @@
1029
1056
  {
1030
1057
  "kind": "method",
1031
1058
  "name": "requestContentUpdate",
1032
- "description": "Requests an update for the content of items.\nWhile performing the update, it invokes the renderer (passed in the `renderer` property) once an item.\n\nIt is not guaranteed that the update happens immediately (synchronously) after it is requested."
1059
+ "description": "Requests an update for the content of items.\nWhile performing the update, it invokes the renderer (passed in the `renderer` property) once an item.\n\nIt is not guaranteed that the update happens immediately (synchronously) after it is requested.",
1060
+ "inheritedFrom": {
1061
+ "name": "ComboBoxItemsMixin",
1062
+ "module": "src/vaadin-combo-box-items-mixin.js"
1063
+ }
1033
1064
  },
1034
1065
  {
1035
1066
  "kind": "field",
@@ -1176,8 +1207,12 @@
1176
1207
  "type": {
1177
1208
  "text": "string"
1178
1209
  },
1179
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
1180
- "fieldName": "itemIdPath"
1210
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
1211
+ "fieldName": "itemIdPath",
1212
+ "inheritedFrom": {
1213
+ "name": "ComboBoxItemsMixin",
1214
+ "module": "src/vaadin-combo-box-items-mixin.js"
1215
+ }
1181
1216
  },
1182
1217
  {
1183
1218
  "name": "item-label-path",
@@ -1569,16 +1604,6 @@
1569
1604
  "description": "A function used to generate CSS class names for dropdown\nitems based on the item. The return value should be the\ngenerated class name as a string, or multiple class names\nseparated by whitespace characters.",
1570
1605
  "attribute": "item-class-name-generator"
1571
1606
  },
1572
- {
1573
- "kind": "field",
1574
- "name": "itemIdPath",
1575
- "privacy": "public",
1576
- "type": {
1577
- "text": "string"
1578
- },
1579
- "description": "Path for the id of the item, used to detect whether the item is selected.",
1580
- "attribute": "item-id-path"
1581
- },
1582
1607
  {
1583
1608
  "kind": "field",
1584
1609
  "name": "items",
@@ -1699,14 +1724,6 @@
1699
1724
  "description": "Index of an item that has focus outline and is scrolled into view.\nThe actual focus still remains in the input field.",
1700
1725
  "fieldName": "focusedIndex"
1701
1726
  },
1702
- {
1703
- "name": "item-id-path",
1704
- "type": {
1705
- "text": "string"
1706
- },
1707
- "description": "Path for the id of the item, used to detect whether the item is selected.",
1708
- "fieldName": "itemIdPath"
1709
- },
1710
1727
  {
1711
1728
  "name": "items",
1712
1729
  "type": {
@@ -2062,11 +2079,11 @@
2062
2079
  "type": {
2063
2080
  "text": "string"
2064
2081
  },
2065
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
2082
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
2066
2083
  "attribute": "item-id-path",
2067
2084
  "inheritedFrom": {
2068
- "name": "ComboBoxMixin",
2069
- "module": "src/vaadin-combo-box-mixin.js"
2085
+ "name": "ComboBoxItemsMixin",
2086
+ "module": "src/vaadin-combo-box-items-mixin.js"
2070
2087
  }
2071
2088
  },
2072
2089
  {
@@ -2293,8 +2310,8 @@
2293
2310
  "name": "requestContentUpdate",
2294
2311
  "description": "Requests an update for the content of items.\nWhile performing the update, it invokes the renderer (passed in the `renderer` property) once an item.\n\nIt is not guaranteed that the update happens immediately (synchronously) after it is requested.",
2295
2312
  "inheritedFrom": {
2296
- "name": "ComboBoxMixin",
2297
- "module": "src/vaadin-combo-box-mixin.js"
2313
+ "name": "ComboBoxItemsMixin",
2314
+ "module": "src/vaadin-combo-box-items-mixin.js"
2298
2315
  }
2299
2316
  },
2300
2317
  {
@@ -2656,11 +2673,11 @@
2656
2673
  "type": {
2657
2674
  "text": "string"
2658
2675
  },
2659
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
2676
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
2660
2677
  "fieldName": "itemIdPath",
2661
2678
  "inheritedFrom": {
2662
- "name": "ComboBoxMixin",
2663
- "module": "src/vaadin-combo-box-mixin.js"
2679
+ "name": "ComboBoxItemsMixin",
2680
+ "module": "src/vaadin-combo-box-items-mixin.js"
2664
2681
  }
2665
2682
  },
2666
2683
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/combo-box",
3
- "version": "25.3.0-beta2",
3
+ "version": "25.3.0-beta3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -36,22 +36,22 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@open-wc/dedupe-mixin": "^1.3.0",
39
- "@vaadin/a11y-base": "25.3.0-beta2",
40
- "@vaadin/component-base": "25.3.0-beta2",
41
- "@vaadin/field-base": "25.3.0-beta2",
42
- "@vaadin/input-container": "25.3.0-beta2",
43
- "@vaadin/item": "25.3.0-beta2",
44
- "@vaadin/lit-renderer": "25.3.0-beta2",
45
- "@vaadin/overlay": "25.3.0-beta2",
46
- "@vaadin/vaadin-themable-mixin": "25.3.0-beta2",
39
+ "@vaadin/a11y-base": "25.3.0-beta3",
40
+ "@vaadin/component-base": "25.3.0-beta3",
41
+ "@vaadin/field-base": "25.3.0-beta3",
42
+ "@vaadin/input-container": "25.3.0-beta3",
43
+ "@vaadin/item": "25.3.0-beta3",
44
+ "@vaadin/lit-renderer": "25.3.0-beta3",
45
+ "@vaadin/overlay": "25.3.0-beta3",
46
+ "@vaadin/vaadin-themable-mixin": "25.3.0-beta3",
47
47
  "lit": "^3.0.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@vaadin/aura": "25.3.0-beta2",
51
- "@vaadin/chai-plugins": "25.3.0-beta2",
52
- "@vaadin/test-runner-commands": "25.3.0-beta2",
50
+ "@vaadin/aura": "25.3.0-beta3",
51
+ "@vaadin/chai-plugins": "25.3.0-beta3",
52
+ "@vaadin/test-runner-commands": "25.3.0-beta3",
53
53
  "@vaadin/testing-helpers": "^2.0.0",
54
- "@vaadin/vaadin-lumo-styles": "25.3.0-beta2",
54
+ "@vaadin/vaadin-lumo-styles": "25.3.0-beta3",
55
55
  "sinon": "^22.0.0"
56
56
  },
57
57
  "customElements": "custom-elements.json",
@@ -59,5 +59,5 @@
59
59
  "web-types.json",
60
60
  "web-types.lit.json"
61
61
  ],
62
- "gitHead": "d97ccbec217b60c39f3c8b2dd52473c79a48c8c1"
62
+ "gitHead": "1ea43188e1297f6898cbf9d3610b85a7a2cca6f0"
63
63
  }
@@ -170,6 +170,24 @@ export const ComboBoxBaseMixin = (superClass) =>
170
170
  }
171
171
  }
172
172
 
173
+ /** @protected */
174
+ updated(props) {
175
+ super.updated(props);
176
+
177
+ // Note: `loading` is only declared by components that support a data provider.
178
+ if (props.has('opened') || props.has('_dropdownItems') || props.has('loading')) {
179
+ // Close the overlay if there are no items to display.
180
+ // See https://github.com/vaadin/vaadin-combo-box/pull/964
181
+ this._overlayOpened = this.opened && (!!this.loading || this._hasDropdownItems);
182
+ }
183
+
184
+ // Update the scroller only once the overlay is actually opened, so that the
185
+ // virtualizer does not measure and render items while the overlay is hidden.
186
+ if (['_overlayOpened', '_dropdownItems', '_focusedIndex', '_theme'].some((prop) => props.has(prop))) {
187
+ this._updateScroller();
188
+ }
189
+ }
190
+
173
191
  /** @protected */
174
192
  disconnectedCallback() {
175
193
  super.disconnectedCallback();
@@ -248,6 +266,29 @@ export const ComboBoxBaseMixin = (superClass) =>
248
266
  this.appendChild(scroller);
249
267
  }
250
268
 
269
+ /**
270
+ * Update the scroller to reflect the dropdown items, the focused item
271
+ * and whether the overlay is opened.
272
+ * @protected
273
+ */
274
+ _updateScroller() {
275
+ const opened = this._overlayOpened;
276
+
277
+ if (opened) {
278
+ this._scroller.style.maxHeight =
279
+ getComputedStyle(this).getPropertyValue(`--${this._tagNamePrefix}-overlay-max-height`) || '65vh';
280
+ }
281
+
282
+ const isClosing = this.hasAttribute('closing');
283
+
284
+ this._scroller.setProperties({
285
+ items: opened || isClosing ? this._dropdownItems : [],
286
+ opened,
287
+ focusedIndex: this._focusedIndex,
288
+ theme: this._theme,
289
+ });
290
+ }
291
+
251
292
  /**
252
293
  * @type {boolean}
253
294
  * @protected
@@ -446,6 +487,18 @@ export const ComboBoxBaseMixin = (superClass) =>
446
487
  return item ? item.toString() : '';
447
488
  }
448
489
 
490
+ /**
491
+ * Returns true when both items refer to the same item.
492
+ * Override to provide logic for item id path.
493
+ * @param {unknown} item
494
+ * @param {unknown} other
495
+ * @return {boolean}
496
+ * @protected
497
+ */
498
+ _isSameItem(item, other) {
499
+ return item === other;
500
+ }
501
+
449
502
  /** @private */
450
503
  _onArrowDown() {
451
504
  if (this.opened) {
@@ -120,10 +120,8 @@ export const ComboBoxDataProviderMixin = (superClass) =>
120
120
  if (this.__previousDataProviderFilter !== filter) {
121
121
  this.__previousDataProviderFilter = filter;
122
122
 
123
- this.__keepOverlayOpened = true;
124
- this.size = undefined;
123
+ this.__dataProviderController.rootCache.size = undefined;
125
124
  this.clearCache();
126
- this.__keepOverlayOpened = false;
127
125
  }
128
126
  }
129
127
 
@@ -152,7 +150,7 @@ export const ComboBoxDataProviderMixin = (superClass) =>
152
150
 
153
151
  /** @private */
154
152
  __onDataProviderPageRequested() {
155
- this.loading = true;
153
+ this.__synchronizeControllerState();
156
154
  }
157
155
 
158
156
  /** @private */
@@ -179,14 +177,18 @@ export const ComboBoxDataProviderMixin = (superClass) =>
179
177
 
180
178
  this.__dataProviderController.clearCache();
181
179
 
182
- this.__synchronizeControllerState();
183
-
180
+ // Request the first page before synchronizing the component state.
181
+ // Otherwise the component would observe an intermediate state where
182
+ // the items are empty but no request is pending, which would close
183
+ // the overlay and re-open it right away.
184
184
  if (this._shouldFetchData()) {
185
185
  this._forceNextRequest = false;
186
186
  this.__dataProviderController.loadFirstPage();
187
187
  } else {
188
188
  this._forceNextRequest = true;
189
189
  }
190
+
191
+ this.__synchronizeControllerState();
190
192
  }
191
193
 
192
194
  /**
@@ -240,9 +242,13 @@ export const ComboBoxDataProviderMixin = (superClass) =>
240
242
  // will be requested in the `ready()` callback.
241
243
  if (this.__dataProviderInitialized && this.dataProvider) {
242
244
  const { rootCache } = this.__dataProviderController;
243
- this.size = rootCache.size;
244
- this.filteredItems = rootCache.items;
245
- this.loading = this.__dataProviderController.isLoading();
245
+ // Apply all properties in one update so that observers depending on
246
+ // several of them never see a partially synchronized state.
247
+ this.setProperties({
248
+ size: rootCache.size,
249
+ filteredItems: rootCache.items,
250
+ loading: this.__dataProviderController.isLoading(),
251
+ });
246
252
  }
247
253
  }
248
254
 
@@ -60,6 +60,15 @@ export declare class ComboBoxItemsMixinClass<TItem> {
60
60
  */
61
61
  itemValuePath: string;
62
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
+
63
72
  /**
64
73
  * Controls which item is automatically set to be selected, for
65
74
  * example on Enter, when the typed filter only partially matches
@@ -85,4 +94,12 @@ export declare class ComboBoxItemsMixinClass<TItem> {
85
94
  * @attr {none|first-match|only-match} partial-match-mode
86
95
  */
87
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;
88
105
  }
@@ -112,6 +112,18 @@ export const ComboBoxItemsMixin = (superClass) =>
112
112
  sync: true,
113
113
  },
114
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
+
115
127
  /**
116
128
  * Controls which item is automatically set to be selected, for
117
129
  * example on Enter, when the typed filter only partially matches
@@ -159,6 +171,39 @@ export const ComboBoxItemsMixin = (superClass) =>
159
171
  }
160
172
  }
161
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
+
162
207
  /**
163
208
  * Override an event listener from `ComboBoxBaseMixin` to handle
164
209
  * batched setting of both `opened` and `filter` properties.
@@ -232,6 +277,26 @@ export const ComboBoxItemsMixin = (superClass) =>
232
277
  return value;
233
278
  }
234
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
+
235
300
  /** @private */
236
301
  _itemLabelPathChanged(itemLabelPath) {
237
302
  if (typeof itemLabelPath !== 'string') {
@@ -276,12 +341,44 @@ export const ComboBoxItemsMixin = (superClass) =>
276
341
  }
277
342
 
278
343
  /**
279
- * Provide items to be rendered in the dropdown.
280
- * Override to provide actual implementation.
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
281
348
  * @protected
282
349
  */
283
- _setDropdownItems() {
284
- // To be implemented
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
+ }
285
382
  }
286
383
 
287
384
  /** @private */
@@ -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', 'itemIdPath', 'itemClassNameGenerator', 'renderer', 'selectedItem'].forEach((prop) => {
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.
@@ -499,20 +420,14 @@ export const ComboBoxMixin = (superClass) =>
499
420
  }
500
421
 
501
422
  /**
502
- * Provide items to be rendered in the dropdown.
503
- * Override this method to show custom items.
423
+ * Override method from `ComboBoxItemsMixin` to sync `selectedItem`
424
+ * based on `value` once a new set of items is available.
504
425
  *
505
426
  * @protected
506
427
  * @override
507
428
  */
508
429
  _setDropdownItems(newItems) {
509
- const oldItems = this._dropdownItems;
510
- this._dropdownItems = newItems;
511
-
512
- // Store the currently focused item if any. The focused index preserves
513
- // in the case when more filtered items are loading but it is reset
514
- // when the user types in a filter query.
515
- const focusedItem = oldItems ? oldItems[this._focusedIndex] : null;
430
+ super._setDropdownItems(newItems);
516
431
 
517
432
  // Try to sync `selectedItem` based on `value` once a new set of `filteredItems` is available
518
433
  // (as a result of external filtering or when they have been loaded by the data provider).
@@ -522,30 +437,6 @@ export const ComboBoxMixin = (superClass) =>
522
437
  if ((this.selectedItem === null || this.selectedItem === undefined) && valueIndex >= 0) {
523
438
  this.selectedItem = newItems[valueIndex];
524
439
  }
525
-
526
- // When both the previously-focused entry and the new entry at the
527
- // same index are placeholders (e.g. the Flow connector mid-scroll
528
- // re-pushing `_setDropdownItems`), preserve `_focusedIndex` until
529
- // a follow-up call lands a real item at that position.
530
- if (
531
- oldItems &&
532
- oldItems[this._focusedIndex] instanceof ComboBoxPlaceholder &&
533
- newItems[this._focusedIndex] instanceof ComboBoxPlaceholder
534
- ) {
535
- return;
536
- }
537
-
538
- // Try to first set focus on the item that had been focused before `newItems` were updated
539
- // if it is still present in the `newItems` array. Otherwise, set the focused index
540
- // depending on the selected item or the filter query.
541
- const focusedItemIndex = this.__getItemIndexByValue(newItems, this._getItemValue(focusedItem));
542
- if (focusedItemIndex > -1) {
543
- this._focusedIndex = focusedItemIndex;
544
- } else {
545
- // When the user filled in something that is different from the current value = filtering is enabled,
546
- // set the focused index to the item that matches the filter query.
547
- this._focusedIndex = this.__getItemIndexByFilter(newItems);
548
- }
549
440
  }
550
441
 
551
442
  /**
@@ -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, itemIdPath: string | null | undefined): void;
76
+ protected _isItemSelected(item: TItem, selectedItem: TItem): boolean;
82
77
 
83
78
  protected _updateElement(el: HTMLElement, index: number): void;
84
79
  }
@@ -4,7 +4,6 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { setOrRemoveAttribute } from '@vaadin/component-base/src/dom-utils.js';
7
- import { get } from '@vaadin/component-base/src/path-utils.js';
8
7
  import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
9
8
  import { Virtualizer } from '@vaadin/component-base/src/virtualizer.js';
10
9
  import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
@@ -72,13 +71,6 @@ export const ComboBoxScrollerMixin = (superClass) =>
72
71
  observer: '__itemClassNameGeneratorChanged',
73
72
  },
74
73
 
75
- /**
76
- * Path for the id of the item, used to detect whether the item is selected.
77
- */
78
- itemIdPath: {
79
- type: String,
80
- },
81
-
82
74
  /**
83
75
  * Reference to the owner (combo-box owner), used by the item elements.
84
76
  */
@@ -244,16 +236,15 @@ export const ComboBoxScrollerMixin = (superClass) =>
244
236
  /**
245
237
  * @param {string | object} item
246
238
  * @param {string | object} selectedItem
247
- * @param {string} itemIdPath
239
+ * @return {boolean}
248
240
  * @protected
249
241
  */
250
- _isItemSelected(item, selectedItem, itemIdPath) {
242
+ _isItemSelected(item, selectedItem) {
251
243
  if (item instanceof ComboBoxPlaceholder) {
252
244
  return false;
253
- } else if (itemIdPath && item !== undefined && selectedItem !== undefined) {
254
- return get(itemIdPath, item) === get(itemIdPath, selectedItem);
255
245
  }
256
- return item === selectedItem;
246
+
247
+ return this.owner._isSameItem(item, selectedItem);
257
248
  }
258
249
 
259
250
  /** @private */
@@ -367,7 +358,7 @@ export const ComboBoxScrollerMixin = (superClass) =>
367
358
  _updateElement(el, index) {
368
359
  const item = this.items[index];
369
360
  const focusedIndex = this.focusedIndex;
370
- const selected = this._isItemSelected(item, this.selectedItem, this.itemIdPath);
361
+ const selected = this._isItemSelected(item, this.selectedItem);
371
362
 
372
363
  el.setProperties({
373
364
  item,
package/web-types.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/combo-box",
4
- "version": "25.3.0-beta2",
4
+ "version": "25.3.0-beta3",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
10
  "name": "vaadin-combo-box",
11
- "description": "`<vaadin-combo-box>` is a web component for choosing a value from a filterable list of options\npresented in a dropdown overlay. The options can be provided as a list of strings or objects\nby setting [`items`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-combo-box#property-items) property on the element.\n\n```html\n<vaadin-combo-box id=\"combo-box\"></vaadin-combo-box>\n```\n```js\ndocument.querySelector('#combo-box').items = ['apple', 'orange', 'banana'];\n```\n\nWhen the selected `value` is changed, a `value-changed` event is triggered.\n\n### Item rendering\n\nTo customize the content of the `<vaadin-combo-box-item>` elements placed in the dropdown, use\n[`renderer`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-combo-box#property-renderer) property which accepts a function.\nThe renderer function is called with `root`, `comboBox`, and `model` as arguments.\n\nGenerate DOM content by using `model` object properties if needed, and append it to the `root`\nelement. The `comboBox` reference is provided to access the combo-box element state. Do not\nset combo-box properties in a `renderer` function.\n\n```js\nconst comboBox = document.querySelector('#combo-box');\ncomboBox.items = [{'label': 'Hydrogen', 'value': 'H'}];\ncomboBox.renderer = (root, comboBox, model) => {\n const item = model.item;\n root.innerHTML = `${model.index}: ${item.label} <b>${item.value}</b>`;\n};\n```\n\nRenderer is called on the opening of the combo-box and each time the related model is updated.\nBefore creating new content, it is recommended to check if there is already an existing DOM\nelement in `root` from a previous renderer call for reusing it. Even though combo-box uses\ninfinite scrolling, reducing DOM operations might improve performance.\n\nThe following properties are available in the `model` argument:\n\nProperty | Type | Description\n-----------|------------------|-------------\n`index` | Number | Index of the item in the `items` array\n`item` | String or Object | The item reference\n`selected` | Boolean | True when item is selected\n`focused` | Boolean | True when item is focused\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively use the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-combo-box#property-dataProvider) function property.\nThe `<vaadin-combo-box>` calls this function lazily, only when it needs more data\nto be displayed.\n\n__Note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```js\ncomboBox.dataProvider = async (params, callback) => {\n const API = 'https://demo.vaadin.com/demo-data/1.0/filtered-countries';\n const { filter, page, pageSize } = params;\n const index = page * pageSize;\n\n const res = await fetch(`${API}?index=${index}&count=${pageSize}&filter=${filter}`);\n if (res.ok) {\n const { result, size } = await res.json();\n callback(result, size);\n }\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The label element\n`input-field` | The element that wraps prefix, value and buttons\n`field-button` | Set on both clear and toggle buttons\n`clear-button` | The clear button\n`error-message` | The error message element\n`helper-text` | The helper text element wrapper\n`required-indicator` | The `required` state indicator element\n`toggle-button` | The toggle button\n`overlay` | The overlay container\n`content` | The overlay content\n`loader` | The loading indicator shown while loading items\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|---------------------------------\n`disabled` | Set when the element is disabled\n`has-value` | Set when the element has a value\n`has-label` | Set when the element has a label\n`has-helper` | Set when the element has helper text or slot\n`has-error-message` | Set when the element has an error message\n`has-tooltip` | Set when the element has a slotted tooltip\n`invalid` | Set when the element is invalid\n`focused` | Set when the element is focused\n`focus-ring` | Set when the element is keyboard focused\n`readonly` | Set when the element is readonly\n`opened` | Set when the overlay is opened\n`loading` | Set when loading items from the data provider\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:--------------------------------------------------|\n| `--vaadin-combo-box-overlay-max-height` |\n| `--vaadin-combo-box-overlay-width` |\n| `--vaadin-field-default-width` |\n| `--vaadin-input-field-background` |\n| `--vaadin-input-field-border-color` |\n| `--vaadin-input-field-border-radius` |\n| `--vaadin-input-field-border-width` |\n| `--vaadin-input-field-bottom-end-radius` |\n| `--vaadin-input-field-bottom-start-radius` |\n| `--vaadin-input-field-button-text-color` |\n| `--vaadin-input-field-container-gap` |\n| `--vaadin-input-field-disabled-background` |\n| `--vaadin-input-field-disabled-text-color` |\n| `--vaadin-input-field-error-color` |\n| `--vaadin-input-field-error-font-size` |\n| `--vaadin-input-field-error-font-weight` |\n| `--vaadin-input-field-error-line-height` |\n| `--vaadin-input-field-gap` |\n| `--vaadin-input-field-helper-color` |\n| `--vaadin-input-field-helper-font-size` |\n| `--vaadin-input-field-helper-font-weight` |\n| `--vaadin-input-field-helper-line-height` |\n| `--vaadin-input-field-label-color` |\n| `--vaadin-input-field-label-font-size` |\n| `--vaadin-input-field-label-font-weight` |\n| `--vaadin-input-field-label-line-height` |\n| `--vaadin-input-field-padding` |\n| `--vaadin-input-field-placeholder-color` |\n| `--vaadin-input-field-required-indicator` |\n| `--vaadin-input-field-required-indicator-color` |\n| `--vaadin-input-field-top-end-radius` |\n| `--vaadin-input-field-top-start-radius` |\n| `--vaadin-input-field-value-color` |\n| `--vaadin-input-field-value-font-size` |\n| `--vaadin-input-field-value-font-weight` |\n| `--vaadin-input-field-value-line-height` |\n| `--vaadin-item-overlay-padding` |\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-item).\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
11
+ "description": "`<vaadin-combo-box>` is a web component for choosing a value from a filterable list of options\npresented in a dropdown overlay. The options can be provided as a list of strings or objects\nby setting [`items`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-combo-box#property-items) property on the element.\n\n```html\n<vaadin-combo-box id=\"combo-box\"></vaadin-combo-box>\n```\n```js\ndocument.querySelector('#combo-box').items = ['apple', 'orange', 'banana'];\n```\n\nWhen the selected `value` is changed, a `value-changed` event is triggered.\n\n### Item rendering\n\nTo customize the content of the `<vaadin-combo-box-item>` elements placed in the dropdown, use\n[`renderer`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-combo-box#property-renderer) property which accepts a function.\nThe renderer function is called with `root`, `comboBox`, and `model` as arguments.\n\nGenerate DOM content by using `model` object properties if needed, and append it to the `root`\nelement. The `comboBox` reference is provided to access the combo-box element state. Do not\nset combo-box properties in a `renderer` function.\n\n```js\nconst comboBox = document.querySelector('#combo-box');\ncomboBox.items = [{'label': 'Hydrogen', 'value': 'H'}];\ncomboBox.renderer = (root, comboBox, model) => {\n const item = model.item;\n root.innerHTML = `${model.index}: ${item.label} <b>${item.value}</b>`;\n};\n```\n\nRenderer is called on the opening of the combo-box and each time the related model is updated.\nBefore creating new content, it is recommended to check if there is already an existing DOM\nelement in `root` from a previous renderer call for reusing it. Even though combo-box uses\ninfinite scrolling, reducing DOM operations might improve performance.\n\nThe following properties are available in the `model` argument:\n\nProperty | Type | Description\n-----------|------------------|-------------\n`index` | Number | Index of the item in the `items` array\n`item` | String or Object | The item reference\n`selected` | Boolean | True when item is selected\n`focused` | Boolean | True when item is focused\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively use the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-combo-box#property-dataProvider) function property.\nThe `<vaadin-combo-box>` calls this function lazily, only when it needs more data\nto be displayed.\n\n__Note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```js\ncomboBox.dataProvider = async (params, callback) => {\n const API = 'https://demo.vaadin.com/demo-data/1.0/filtered-countries';\n const { filter, page, pageSize } = params;\n const index = page * pageSize;\n\n const res = await fetch(`${API}?index=${index}&count=${pageSize}&filter=${filter}`);\n if (res.ok) {\n const { result, size } = await res.json();\n callback(result, size);\n }\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The label element\n`input-field` | The element that wraps prefix, value and buttons\n`field-button` | Set on both clear and toggle buttons\n`clear-button` | The clear button\n`error-message` | The error message element\n`helper-text` | The helper text element wrapper\n`required-indicator` | The `required` state indicator element\n`toggle-button` | The toggle button\n`overlay` | The overlay container\n`content` | The overlay content\n`loader` | The loading indicator shown while loading items\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|---------------------------------\n`disabled` | Set when the element is disabled\n`has-value` | Set when the element has a value\n`has-label` | Set when the element has a label\n`has-helper` | Set when the element has helper text or slot\n`has-error-message` | Set when the element has an error message\n`has-tooltip` | Set when the element has a slotted tooltip\n`invalid` | Set when the element is invalid\n`focused` | Set when the element is focused\n`focus-ring` | Set when the element is keyboard focused\n`readonly` | Set when the element is readonly\n`opened` | Set when the overlay is opened\n`loading` | Set when loading items from the data provider\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:--------------------------------------------------|\n| `--vaadin-combo-box-overlay-max-height` |\n| `--vaadin-combo-box-overlay-width` |\n| `--vaadin-field-default-width` |\n| `--vaadin-input-field-background` |\n| `--vaadin-input-field-border-color` |\n| `--vaadin-input-field-border-radius` |\n| `--vaadin-input-field-border-width` |\n| `--vaadin-input-field-bottom-end-radius` |\n| `--vaadin-input-field-bottom-start-radius` |\n| `--vaadin-input-field-button-text-color` |\n| `--vaadin-input-field-container-gap` |\n| `--vaadin-input-field-disabled-background` |\n| `--vaadin-input-field-disabled-text-color` |\n| `--vaadin-input-field-error-color` |\n| `--vaadin-input-field-error-font-size` |\n| `--vaadin-input-field-error-font-weight` |\n| `--vaadin-input-field-error-line-height` |\n| `--vaadin-input-field-gap` |\n| `--vaadin-input-field-helper-color` |\n| `--vaadin-input-field-helper-font-size` |\n| `--vaadin-input-field-helper-font-weight` |\n| `--vaadin-input-field-helper-line-height` |\n| `--vaadin-input-field-label-color` |\n| `--vaadin-input-field-label-font-size` |\n| `--vaadin-input-field-label-font-weight` |\n| `--vaadin-input-field-label-line-height` |\n| `--vaadin-input-field-padding` |\n| `--vaadin-input-field-placeholder-color` |\n| `--vaadin-input-field-required-indicator` |\n| `--vaadin-input-field-required-indicator-color` |\n| `--vaadin-input-field-top-end-radius` |\n| `--vaadin-input-field-top-start-radius` |\n| `--vaadin-input-field-value-color` |\n| `--vaadin-input-field-value-font-size` |\n| `--vaadin-input-field-value-font-weight` |\n| `--vaadin-input-field-value-line-height` |\n| `--vaadin-item-overlay-padding` |\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-item).\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
12
12
  "attributes": [
13
13
  {
14
14
  "name": "accessible-description-ref",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  {
140
140
  "name": "item-id-path",
141
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
141
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
142
142
  "value": {
143
143
  "type": [
144
144
  "string"
@@ -459,7 +459,7 @@
459
459
  },
460
460
  {
461
461
  "name": "itemIdPath",
462
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
462
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
463
463
  "value": {
464
464
  "type": [
465
465
  "string"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/combo-box",
4
- "version": "25.3.0-beta2",
4
+ "version": "25.3.0-beta3",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -16,7 +16,7 @@
16
16
  "elements": [
17
17
  {
18
18
  "name": "vaadin-combo-box",
19
- "description": "`<vaadin-combo-box>` is a web component for choosing a value from a filterable list of options\npresented in a dropdown overlay. The options can be provided as a list of strings or objects\nby setting [`items`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-combo-box#property-items) property on the element.\n\n```html\n<vaadin-combo-box id=\"combo-box\"></vaadin-combo-box>\n```\n```js\ndocument.querySelector('#combo-box').items = ['apple', 'orange', 'banana'];\n```\n\nWhen the selected `value` is changed, a `value-changed` event is triggered.\n\n### Item rendering\n\nTo customize the content of the `<vaadin-combo-box-item>` elements placed in the dropdown, use\n[`renderer`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-combo-box#property-renderer) property which accepts a function.\nThe renderer function is called with `root`, `comboBox`, and `model` as arguments.\n\nGenerate DOM content by using `model` object properties if needed, and append it to the `root`\nelement. The `comboBox` reference is provided to access the combo-box element state. Do not\nset combo-box properties in a `renderer` function.\n\n```js\nconst comboBox = document.querySelector('#combo-box');\ncomboBox.items = [{'label': 'Hydrogen', 'value': 'H'}];\ncomboBox.renderer = (root, comboBox, model) => {\n const item = model.item;\n root.innerHTML = `${model.index}: ${item.label} <b>${item.value}</b>`;\n};\n```\n\nRenderer is called on the opening of the combo-box and each time the related model is updated.\nBefore creating new content, it is recommended to check if there is already an existing DOM\nelement in `root` from a previous renderer call for reusing it. Even though combo-box uses\ninfinite scrolling, reducing DOM operations might improve performance.\n\nThe following properties are available in the `model` argument:\n\nProperty | Type | Description\n-----------|------------------|-------------\n`index` | Number | Index of the item in the `items` array\n`item` | String or Object | The item reference\n`selected` | Boolean | True when item is selected\n`focused` | Boolean | True when item is focused\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively use the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-combo-box#property-dataProvider) function property.\nThe `<vaadin-combo-box>` calls this function lazily, only when it needs more data\nto be displayed.\n\n__Note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```js\ncomboBox.dataProvider = async (params, callback) => {\n const API = 'https://demo.vaadin.com/demo-data/1.0/filtered-countries';\n const { filter, page, pageSize } = params;\n const index = page * pageSize;\n\n const res = await fetch(`${API}?index=${index}&count=${pageSize}&filter=${filter}`);\n if (res.ok) {\n const { result, size } = await res.json();\n callback(result, size);\n }\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The label element\n`input-field` | The element that wraps prefix, value and buttons\n`field-button` | Set on both clear and toggle buttons\n`clear-button` | The clear button\n`error-message` | The error message element\n`helper-text` | The helper text element wrapper\n`required-indicator` | The `required` state indicator element\n`toggle-button` | The toggle button\n`overlay` | The overlay container\n`content` | The overlay content\n`loader` | The loading indicator shown while loading items\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|---------------------------------\n`disabled` | Set when the element is disabled\n`has-value` | Set when the element has a value\n`has-label` | Set when the element has a label\n`has-helper` | Set when the element has helper text or slot\n`has-error-message` | Set when the element has an error message\n`has-tooltip` | Set when the element has a slotted tooltip\n`invalid` | Set when the element is invalid\n`focused` | Set when the element is focused\n`focus-ring` | Set when the element is keyboard focused\n`readonly` | Set when the element is readonly\n`opened` | Set when the overlay is opened\n`loading` | Set when loading items from the data provider\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:--------------------------------------------------|\n| `--vaadin-combo-box-overlay-max-height` |\n| `--vaadin-combo-box-overlay-width` |\n| `--vaadin-field-default-width` |\n| `--vaadin-input-field-background` |\n| `--vaadin-input-field-border-color` |\n| `--vaadin-input-field-border-radius` |\n| `--vaadin-input-field-border-width` |\n| `--vaadin-input-field-bottom-end-radius` |\n| `--vaadin-input-field-bottom-start-radius` |\n| `--vaadin-input-field-button-text-color` |\n| `--vaadin-input-field-container-gap` |\n| `--vaadin-input-field-disabled-background` |\n| `--vaadin-input-field-disabled-text-color` |\n| `--vaadin-input-field-error-color` |\n| `--vaadin-input-field-error-font-size` |\n| `--vaadin-input-field-error-font-weight` |\n| `--vaadin-input-field-error-line-height` |\n| `--vaadin-input-field-gap` |\n| `--vaadin-input-field-helper-color` |\n| `--vaadin-input-field-helper-font-size` |\n| `--vaadin-input-field-helper-font-weight` |\n| `--vaadin-input-field-helper-line-height` |\n| `--vaadin-input-field-label-color` |\n| `--vaadin-input-field-label-font-size` |\n| `--vaadin-input-field-label-font-weight` |\n| `--vaadin-input-field-label-line-height` |\n| `--vaadin-input-field-padding` |\n| `--vaadin-input-field-placeholder-color` |\n| `--vaadin-input-field-required-indicator` |\n| `--vaadin-input-field-required-indicator-color` |\n| `--vaadin-input-field-top-end-radius` |\n| `--vaadin-input-field-top-start-radius` |\n| `--vaadin-input-field-value-color` |\n| `--vaadin-input-field-value-font-size` |\n| `--vaadin-input-field-value-font-weight` |\n| `--vaadin-input-field-value-line-height` |\n| `--vaadin-item-overlay-padding` |\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta2/#/elements/vaadin-item).\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
19
+ "description": "`<vaadin-combo-box>` is a web component for choosing a value from a filterable list of options\npresented in a dropdown overlay. The options can be provided as a list of strings or objects\nby setting [`items`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-combo-box#property-items) property on the element.\n\n```html\n<vaadin-combo-box id=\"combo-box\"></vaadin-combo-box>\n```\n```js\ndocument.querySelector('#combo-box').items = ['apple', 'orange', 'banana'];\n```\n\nWhen the selected `value` is changed, a `value-changed` event is triggered.\n\n### Item rendering\n\nTo customize the content of the `<vaadin-combo-box-item>` elements placed in the dropdown, use\n[`renderer`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-combo-box#property-renderer) property which accepts a function.\nThe renderer function is called with `root`, `comboBox`, and `model` as arguments.\n\nGenerate DOM content by using `model` object properties if needed, and append it to the `root`\nelement. The `comboBox` reference is provided to access the combo-box element state. Do not\nset combo-box properties in a `renderer` function.\n\n```js\nconst comboBox = document.querySelector('#combo-box');\ncomboBox.items = [{'label': 'Hydrogen', 'value': 'H'}];\ncomboBox.renderer = (root, comboBox, model) => {\n const item = model.item;\n root.innerHTML = `${model.index}: ${item.label} <b>${item.value}</b>`;\n};\n```\n\nRenderer is called on the opening of the combo-box and each time the related model is updated.\nBefore creating new content, it is recommended to check if there is already an existing DOM\nelement in `root` from a previous renderer call for reusing it. Even though combo-box uses\ninfinite scrolling, reducing DOM operations might improve performance.\n\nThe following properties are available in the `model` argument:\n\nProperty | Type | Description\n-----------|------------------|-------------\n`index` | Number | Index of the item in the `items` array\n`item` | String or Object | The item reference\n`selected` | Boolean | True when item is selected\n`focused` | Boolean | True when item is focused\n\n### Lazy Loading with Function Data Provider\n\nIn addition to assigning an array to the items property, you can alternatively use the\n[`dataProvider`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-combo-box#property-dataProvider) function property.\nThe `<vaadin-combo-box>` calls this function lazily, only when it needs more data\nto be displayed.\n\n__Note that when using function data providers, the total number of items\nneeds to be set manually. The total number of items can be returned\nin the second argument of the data provider callback:__\n\n```js\ncomboBox.dataProvider = async (params, callback) => {\n const API = 'https://demo.vaadin.com/demo-data/1.0/filtered-countries';\n const { filter, page, pageSize } = params;\n const index = page * pageSize;\n\n const res = await fetch(`${API}?index=${index}&count=${pageSize}&filter=${filter}`);\n if (res.ok) {\n const { result, size } = await res.json();\n callback(result, size);\n }\n};\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n---------------------|----------------\n`label` | The label element\n`input-field` | The element that wraps prefix, value and buttons\n`field-button` | Set on both clear and toggle buttons\n`clear-button` | The clear button\n`error-message` | The error message element\n`helper-text` | The helper text element wrapper\n`required-indicator` | The `required` state indicator element\n`toggle-button` | The toggle button\n`overlay` | The overlay container\n`content` | The overlay content\n`loader` | The loading indicator shown while loading items\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------------|---------------------------------\n`disabled` | Set when the element is disabled\n`has-value` | Set when the element has a value\n`has-label` | Set when the element has a label\n`has-helper` | Set when the element has helper text or slot\n`has-error-message` | Set when the element has an error message\n`has-tooltip` | Set when the element has a slotted tooltip\n`invalid` | Set when the element is invalid\n`focused` | Set when the element is focused\n`focus-ring` | Set when the element is keyboard focused\n`readonly` | Set when the element is readonly\n`opened` | Set when the overlay is opened\n`loading` | Set when loading items from the data provider\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property |\n:--------------------------------------------------|\n| `--vaadin-combo-box-overlay-max-height` |\n| `--vaadin-combo-box-overlay-width` |\n| `--vaadin-field-default-width` |\n| `--vaadin-input-field-background` |\n| `--vaadin-input-field-border-color` |\n| `--vaadin-input-field-border-radius` |\n| `--vaadin-input-field-border-width` |\n| `--vaadin-input-field-bottom-end-radius` |\n| `--vaadin-input-field-bottom-start-radius` |\n| `--vaadin-input-field-button-text-color` |\n| `--vaadin-input-field-container-gap` |\n| `--vaadin-input-field-disabled-background` |\n| `--vaadin-input-field-disabled-text-color` |\n| `--vaadin-input-field-error-color` |\n| `--vaadin-input-field-error-font-size` |\n| `--vaadin-input-field-error-font-weight` |\n| `--vaadin-input-field-error-line-height` |\n| `--vaadin-input-field-gap` |\n| `--vaadin-input-field-helper-color` |\n| `--vaadin-input-field-helper-font-size` |\n| `--vaadin-input-field-helper-font-weight` |\n| `--vaadin-input-field-helper-line-height` |\n| `--vaadin-input-field-label-color` |\n| `--vaadin-input-field-label-font-size` |\n| `--vaadin-input-field-label-font-weight` |\n| `--vaadin-input-field-label-line-height` |\n| `--vaadin-input-field-padding` |\n| `--vaadin-input-field-placeholder-color` |\n| `--vaadin-input-field-required-indicator` |\n| `--vaadin-input-field-required-indicator-color` |\n| `--vaadin-input-field-top-end-radius` |\n| `--vaadin-input-field-top-start-radius` |\n| `--vaadin-input-field-value-color` |\n| `--vaadin-input-field-value-font-size` |\n| `--vaadin-input-field-value-font-weight` |\n| `--vaadin-input-field-value-line-height` |\n| `--vaadin-item-overlay-padding` |\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/25.3.0-beta3/#/elements/vaadin-item).\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
20
20
  "extension": true,
21
21
  "attributes": [
22
22
  {
@@ -140,7 +140,7 @@
140
140
  },
141
141
  {
142
142
  "name": ".itemIdPath",
143
- "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin `selectedItem` and `filteredItems` (items given by the\n`dataProvider` callback).",
143
+ "description": "Path for the id of the item. If `items` is an array of objects,\nthe `itemIdPath` is used to compare and identify the same item\nin the selection and in `filteredItems` (items given by the\n`dataProvider` callback).",
144
144
  "value": {
145
145
  "kind": "expression"
146
146
  }