@vaadin/combo-box 25.3.2 → 25.4.0-alpha2

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.
@@ -155,6 +155,10 @@
155
155
  }
156
156
  ],
157
157
  "mixins": [
158
+ {
159
+ "name": "ComboBoxHighlightMixin",
160
+ "module": "src/vaadin-combo-box-highlight-mixin.js"
161
+ },
158
162
  {
159
163
  "name": "KeyboardMixin",
160
164
  "package": "@vaadin/a11y-base/src/keyboard-mixin.js"
@@ -306,6 +310,40 @@
306
310
  }
307
311
  ]
308
312
  },
313
+ {
314
+ "kind": "javascript-module",
315
+ "path": "src/vaadin-combo-box-highlight-mixin.js",
316
+ "declarations": [
317
+ {
318
+ "kind": "mixin",
319
+ "description": "A mixin that tracks which element of a combo box has the keyboard highlight\nwhile the DOM focus stays in the input. Only one element is highlighted at\na time.\n\nThe state is one of:\n\n- `{ type: 'none' }`: nothing is highlighted.\n- `{ type: 'item', index }`: the dropdown item at `index`.\n\nMixins applied on top can add more types by calling `_setHighlightState()`.",
320
+ "name": "ComboBoxHighlightMixin",
321
+ "members": [],
322
+ "attributes": [],
323
+ "parameters": [
324
+ {
325
+ "name": "superClass"
326
+ }
327
+ ],
328
+ "mixins": [
329
+ {
330
+ "name": "dedupeMixin",
331
+ "package": "@open-wc/dedupe-mixin"
332
+ }
333
+ ]
334
+ }
335
+ ],
336
+ "exports": [
337
+ {
338
+ "kind": "js",
339
+ "name": "ComboBoxHighlightMixin",
340
+ "declaration": {
341
+ "name": "ComboBoxHighlightMixin",
342
+ "module": "src/vaadin-combo-box-highlight-mixin.js"
343
+ }
344
+ }
345
+ ]
346
+ },
309
347
  {
310
348
  "kind": "javascript-module",
311
349
  "path": "src/vaadin-combo-box-item-mixin.js",
@@ -1781,7 +1819,7 @@
1781
1819
  "declarations": [
1782
1820
  {
1783
1821
  "kind": "class",
1784
- "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`](#/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\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`](#/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`](#/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>`](#/elements/vaadin-item).\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
1822
+ "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`](#/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\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`](#/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`](#/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-height` |\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-aside-gap` |\n| `--vaadin-input-field-label-aside-text-align` |\n| `--vaadin-input-field-label-aside-width` |\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>`](#/elements/vaadin-item).\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
1785
1823
  "name": "ComboBox",
1786
1824
  "members": [
1787
1825
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/combo-box",
3
- "version": "25.3.2",
3
+ "version": "25.4.0-alpha2",
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.2",
40
- "@vaadin/component-base": "~25.3.2",
41
- "@vaadin/field-base": "~25.3.2",
42
- "@vaadin/input-container": "~25.3.2",
43
- "@vaadin/item": "~25.3.2",
44
- "@vaadin/lit-renderer": "~25.3.2",
45
- "@vaadin/overlay": "~25.3.2",
46
- "@vaadin/vaadin-themable-mixin": "~25.3.2",
39
+ "@vaadin/a11y-base": "25.4.0-alpha2",
40
+ "@vaadin/component-base": "25.4.0-alpha2",
41
+ "@vaadin/field-base": "25.4.0-alpha2",
42
+ "@vaadin/input-container": "25.4.0-alpha2",
43
+ "@vaadin/item": "25.4.0-alpha2",
44
+ "@vaadin/lit-renderer": "25.4.0-alpha2",
45
+ "@vaadin/overlay": "25.4.0-alpha2",
46
+ "@vaadin/vaadin-themable-mixin": "25.4.0-alpha2",
47
47
  "lit": "^3.0.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@vaadin/aura": "~25.3.2",
51
- "@vaadin/chai-plugins": "~25.3.2",
52
- "@vaadin/test-runner-commands": "~25.3.2",
50
+ "@vaadin/aura": "25.4.0-alpha2",
51
+ "@vaadin/chai-plugins": "25.4.0-alpha2",
52
+ "@vaadin/test-runner-commands": "25.4.0-alpha2",
53
53
  "@vaadin/testing-helpers": "^2.0.0",
54
- "@vaadin/vaadin-lumo-styles": "~25.3.2",
54
+ "@vaadin/vaadin-lumo-styles": "25.4.0-alpha2",
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": "3f75254a3f77da3977cb79a77f549f37b8a5d54e"
62
+ "gitHead": "213f8b55112558d2f976d8730fe44370ca868333"
63
63
  }
@@ -9,10 +9,12 @@ import type { FocusMixinClass } from '@vaadin/a11y-base/src/focus-mixin.js';
9
9
  import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js';
10
10
  import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
11
11
  import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
12
+ import type { ComboBoxHighlightMixinClass } from './vaadin-combo-box-highlight-mixin.js';
12
13
 
13
14
  export declare function ComboBoxBaseMixin<T extends Constructor<HTMLElement>>(
14
15
  base: T,
15
16
  ): Constructor<ComboBoxBaseMixinClass> &
17
+ Constructor<ComboBoxHighlightMixinClass> &
16
18
  Constructor<DisabledMixinClass> &
17
19
  Constructor<FocusMixinClass> &
18
20
  Constructor<InputMixinClass> &
@@ -10,10 +10,13 @@ import { KeyboardMixin } from '@vaadin/a11y-base/src/keyboard-mixin.js';
10
10
  import { isTouch } from '@vaadin/component-base/src/browser-utils.js';
11
11
  import { setOrRemoveAttribute } from '@vaadin/component-base/src/dom-utils.js';
12
12
  import { InputMixin } from '@vaadin/field-base/src/input-mixin.js';
13
+ import { ComboBoxHighlightMixin } from './vaadin-combo-box-highlight-mixin.js';
13
14
  import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
14
15
 
15
16
  export const ComboBoxBaseMixin = (superClass) =>
16
- class ComboBoxMixinBaseClass extends KeyboardMixin(InputMixin(DisabledMixin(FocusMixin(superClass)))) {
17
+ class ComboBoxMixinBaseClass extends ComboBoxHighlightMixin(
18
+ KeyboardMixin(InputMixin(DisabledMixin(FocusMixin(superClass)))),
19
+ ) {
17
20
  static get properties() {
18
21
  return {
19
22
  /**
@@ -46,16 +49,6 @@ export const ComboBoxBaseMixin = (superClass) =>
46
49
  reflectToAttribute: true,
47
50
  },
48
51
 
49
- /**
50
- * @protected
51
- */
52
- _focusedIndex: {
53
- type: Number,
54
- observer: '_focusedIndexChanged',
55
- value: -1,
56
- sync: true,
57
- },
58
-
59
52
  /**
60
53
  * @type {!HTMLElement | undefined}
61
54
  * @protected
@@ -183,9 +176,15 @@ export const ComboBoxBaseMixin = (superClass) =>
183
176
 
184
177
  // Update the scroller only once the overlay is actually opened, so that the
185
178
  // virtualizer does not measure and render items while the overlay is hidden.
186
- if (['_overlayOpened', '_dropdownItems', '_focusedIndex', '_theme'].some((prop) => props.has(prop))) {
179
+ if (['_overlayOpened', '_dropdownItems', '_highlightState', '_theme'].some((prop) => props.has(prop))) {
187
180
  this._updateScroller();
188
181
  }
182
+
183
+ // An item can be highlighted while the overlay is closed, e.g. when filtering
184
+ // on input. Reference it once the overlay is opened.
185
+ if (props.has('_highlightState') || (props.has('_overlayOpened') && this._overlayOpened)) {
186
+ this._updateActiveDescendant();
187
+ }
189
188
  }
190
189
 
191
190
  /** @protected */
@@ -284,7 +283,7 @@ export const ComboBoxBaseMixin = (superClass) =>
284
283
  this._scroller.setProperties({
285
284
  items: opened || isClosing ? this._dropdownItems : [],
286
285
  opened,
287
- focusedIndex: this._focusedIndex,
286
+ focusedIndex: this._highlightedItemIndex,
288
287
  theme: this._theme,
289
288
  });
290
289
  }
@@ -306,26 +305,19 @@ export const ComboBoxBaseMixin = (superClass) =>
306
305
  }
307
306
  }
308
307
 
309
- /** @private */
310
- _focusedIndexChanged(index, oldIndex) {
311
- if (oldIndex === undefined) {
312
- return;
313
- }
314
- this._updateActiveDescendant(index);
315
- }
316
-
317
308
  /** @protected */
318
309
  _isInputFocused() {
319
310
  return this.inputElement && isElementFocused(this.inputElement);
320
311
  }
321
312
 
322
- /** @private */
323
- _updateActiveDescendant(index) {
313
+ /** @protected */
314
+ _updateActiveDescendant() {
324
315
  const input = this.inputElement;
325
316
  if (!input) {
326
317
  return;
327
318
  }
328
319
 
320
+ const index = this._highlightedItemIndex;
329
321
  const item = this._getItemElements().find((el) => el.index === index);
330
322
  setOrRemoveAttribute(input, 'aria-activedescendant', item?.id);
331
323
  }
@@ -502,11 +494,8 @@ export const ComboBoxBaseMixin = (superClass) =>
502
494
  /** @private */
503
495
  _onArrowDown() {
504
496
  if (this.opened) {
505
- const items = this._dropdownItems;
506
- if (items) {
507
- this._focusedIndex = Math.min(items.length - 1, this._focusedIndex + 1);
508
- this._prefillFocusedItemLabel();
509
- }
497
+ this._highlightNextItem();
498
+ this._prefillFocusedItemLabel();
510
499
  } else {
511
500
  this.open();
512
501
  }
@@ -515,15 +504,7 @@ export const ComboBoxBaseMixin = (superClass) =>
515
504
  /** @private */
516
505
  _onArrowUp() {
517
506
  if (this.opened) {
518
- if (this._focusedIndex > -1) {
519
- this._focusedIndex = Math.max(0, this._focusedIndex - 1);
520
- } else {
521
- const items = this._dropdownItems;
522
- if (items) {
523
- this._focusedIndex = items.length - 1;
524
- }
525
- }
526
-
507
+ this._highlightPrevItem();
527
508
  this._prefillFocusedItemLabel();
528
509
  } else {
529
510
  this.open();
@@ -532,9 +513,8 @@ export const ComboBoxBaseMixin = (superClass) =>
532
513
 
533
514
  /** @private */
534
515
  _prefillFocusedItemLabel() {
535
- if (this._focusedIndex > -1) {
536
- const focusedItem = this._dropdownItems[this._focusedIndex];
537
- this._inputElementValue = this._getItemLabel(focusedItem);
516
+ if (this._hasHighlightedItem) {
517
+ this._inputElementValue = this._getItemLabel(this._highlightedItem);
538
518
  this._markAllSelectionRange();
539
519
  }
540
520
  }
@@ -633,16 +613,16 @@ export const ComboBoxBaseMixin = (superClass) =>
633
613
  // The overlay is open or
634
614
  // The input value has changed but the change hasn't been committed, so cancel it.
635
615
  e.stopPropagation();
636
- this._focusedIndex = -1;
616
+ this._clearItemHighlight();
637
617
  this._onEscapeCancel();
638
618
  } else if (this.opened) {
639
619
  // Auto-open is enabled
640
620
  // The overlay is open
641
621
  e.stopPropagation();
642
622
 
643
- if (this._focusedIndex > -1) {
623
+ if (this._hasHighlightedItem) {
644
624
  // An item is focused, revert the input to the filtered value
645
- this._focusedIndex = -1;
625
+ this._clearItemHighlight();
646
626
  this._revertInputValue();
647
627
  } else {
648
628
  // No item is focused, cancel the change and close the overlay
@@ -766,7 +746,7 @@ export const ComboBoxBaseMixin = (superClass) =>
766
746
  }
767
747
 
768
748
  if (this.opened) {
769
- this._focusedIndex = this._dropdownItems.indexOf(e.detail.item);
749
+ this._highlightItem(e.detail.item);
770
750
  this.close();
771
751
  }
772
752
  }
@@ -47,7 +47,7 @@ export const ComboBoxFocusIndexMixin = (superClass) =>
47
47
  // wins. Rendering rows around `index` also lets placeholder rows fire
48
48
  // `index-requested`, loading any missing pages via the data-provider
49
49
  // chain.
50
- this._focusedIndex = index;
50
+ this._highlightItemAt(index);
51
51
  this._scrollIntoView(index, true);
52
52
 
53
53
  // A page-load may have kicked in during the scroll (placeholder
@@ -61,7 +61,7 @@ export const ComboBoxFocusIndexMixin = (superClass) =>
61
61
  delete this.__pendingFocusIndex;
62
62
  requestAnimationFrame(() => {
63
63
  if (this.isConnected) {
64
- this._updateActiveDescendant(index);
64
+ this._updateActiveDescendant();
65
65
  }
66
66
  });
67
67
  }
@@ -0,0 +1,18 @@
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
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+
8
+ /**
9
+ * A mixin that tracks which element of a combo box has the keyboard highlight
10
+ * while the DOM focus stays in the input. Only one element is highlighted at
11
+ * a time.
12
+ */
13
+ export declare function ComboBoxHighlightMixin<T extends Constructor<HTMLElement>>(
14
+ base: T,
15
+ ): Constructor<ComboBoxHighlightMixinClass> & T;
16
+
17
+ // Nothing to declare, all state and methods are considered internal
18
+ export declare class ComboBoxHighlightMixinClass {}
@@ -0,0 +1,109 @@
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
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
7
+
8
+ /**
9
+ * A mixin that tracks which element of a combo box has the keyboard highlight
10
+ * while the DOM focus stays in the input. Only one element is highlighted at
11
+ * a time.
12
+ *
13
+ * The state is one of:
14
+ *
15
+ * - `{ type: 'none' }`: nothing is highlighted.
16
+ * - `{ type: 'item', index }`: the dropdown item at `index`.
17
+ *
18
+ * Mixins applied on top can add more types by calling `_setHighlightState()`.
19
+ */
20
+ const ComboBoxHighlightMixinImplementation = (superClass) =>
21
+ class ComboBoxHighlightMixinClass extends superClass {
22
+ static get properties() {
23
+ return {
24
+ /**
25
+ * The element that currently has the keyboard highlight.
26
+ * @protected
27
+ */
28
+ _highlightState: {
29
+ type: Object,
30
+ value: () => ({ type: 'none' }),
31
+ sync: true,
32
+ },
33
+ };
34
+ }
35
+
36
+ /** @protected */
37
+ get _hasHighlightedItem() {
38
+ return this._highlightState.type === 'item';
39
+ }
40
+
41
+ /** @protected */
42
+ get _highlightedItemIndex() {
43
+ return this._hasHighlightedItem ? this._highlightState.index : -1;
44
+ }
45
+
46
+ /** @protected */
47
+ get _highlightedItem() {
48
+ return this._hasHighlightedItem ? this._dropdownItems?.[this._highlightState.index] : undefined;
49
+ }
50
+
51
+ /** @protected */
52
+ _highlightNextItem() {
53
+ const items = this._dropdownItems;
54
+ if (items) {
55
+ this._highlightItemAt(Math.min(items.length - 1, this._highlightedItemIndex + 1));
56
+ }
57
+ }
58
+
59
+ /** @protected */
60
+ _highlightPrevItem() {
61
+ const items = this._dropdownItems;
62
+ if (items) {
63
+ this._highlightItemAt(
64
+ this._hasHighlightedItem ? Math.max(0, this._highlightState.index - 1) : items.length - 1,
65
+ );
66
+ }
67
+ }
68
+
69
+ /** @protected */
70
+ _highlightItem(item) {
71
+ const items = this._dropdownItems;
72
+ this._highlightItemAt(items ? items.indexOf(item) : -1);
73
+ }
74
+
75
+ /** @protected */
76
+ _highlightItemAt(index) {
77
+ if (index > -1) {
78
+ this._setHighlightState({ type: 'item', index });
79
+ } else {
80
+ this._clearItemHighlight();
81
+ }
82
+ }
83
+
84
+ /**
85
+ * @protected
86
+ */
87
+ _clearItemHighlight() {
88
+ if (this._hasHighlightedItem) {
89
+ this._clearHighlight();
90
+ }
91
+ }
92
+
93
+ /** @protected */
94
+ _clearHighlight() {
95
+ this._setHighlightState({ type: 'none' });
96
+ }
97
+
98
+ /**
99
+ * @protected
100
+ */
101
+ _setHighlightState(state) {
102
+ const oldState = this._highlightState;
103
+ if (state.type !== oldState.type || state.index !== oldState.index) {
104
+ this._highlightState = state;
105
+ }
106
+ }
107
+ };
108
+
109
+ export const ComboBoxHighlightMixin = dedupeMixin(ComboBoxHighlightMixinImplementation);
@@ -205,8 +205,8 @@ export const ComboBoxItemsMixin = (superClass) =>
205
205
  }
206
206
 
207
207
  /**
208
- * Override an event listener from `ComboBoxBaseMixin` to handle
209
- * batched setting of both `opened` and `filter` properties.
208
+ * Override an event listener from `ComboBoxBaseMixin` to update
209
+ * the filter and open the dropdown on user input.
210
210
  * @param {!Event} event
211
211
  * @protected
212
212
  * @override
@@ -214,25 +214,18 @@ export const ComboBoxItemsMixin = (superClass) =>
214
214
  _onInput(event) {
215
215
  const filter = this._inputElementValue;
216
216
 
217
- // When opening dropdown on user input, both `opened` and `filter` properties are set.
218
- // Perform a batched property update instead of relying on sync property observers.
219
- // This is necessary to avoid an extra data-provider request for loading first page.
220
- const props = {};
221
-
222
217
  if (this.filter === filter) {
223
218
  // Filter and input value might get out of sync, while keyboard navigating for example.
224
219
  // Afterwards, input value might be changed to the same value as used in filtering.
225
220
  // In situation like these, we need to make sure all the filter changes handlers are run.
226
221
  this._filterChanged(this.filter);
227
222
  } else {
228
- props.filter = filter;
223
+ this.filter = filter;
229
224
  }
230
225
 
231
226
  if (!this.opened && !this._isClearButton(event) && !this.autoOpenDisabled) {
232
- props.opened = true;
227
+ this.opened = true;
233
228
  }
234
-
235
- this.setProperties(props);
236
229
  }
237
230
 
238
231
  /**
@@ -246,8 +239,8 @@ export const ComboBoxItemsMixin = (superClass) =>
246
239
  _onOpened() {
247
240
  super._onOpened();
248
241
 
249
- if (this.filter && this._focusedIndex === -1) {
250
- this._focusedIndex = this.__getItemIndexByFilter(this._dropdownItems);
242
+ if (this.filter && !this._hasHighlightedItem) {
243
+ this._highlightItemAt(this.__getItemIndexByFilter(this._dropdownItems));
251
244
  }
252
245
  }
253
246
 
@@ -309,7 +302,7 @@ export const ComboBoxItemsMixin = (superClass) =>
309
302
  // Scroll to the top of the list whenever the filter changes.
310
303
  this._scrollIntoView(0);
311
304
 
312
- this._focusedIndex = -1;
305
+ this._clearItemHighlight();
313
306
 
314
307
  if (this.items) {
315
308
  this.filteredItems = this._filterItems(this.items, filter);
@@ -348,37 +341,31 @@ export const ComboBoxItemsMixin = (superClass) =>
348
341
  * @protected
349
342
  */
350
343
  _setDropdownItems(newItems) {
351
- const oldItems = this._dropdownItems;
344
+ const highlightedItem = this._highlightedItem;
352
345
  this._dropdownItems = newItems;
353
346
 
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;
347
+ this.__restoreItemHighlight(highlightedItem);
348
+ }
349
+
350
+ /**
351
+ * Highlights the given item again if it is still among the dropdown
352
+ * items, which keeps the highlight in place when more items are
353
+ * loading. Otherwise the item matching the filter is highlighted, or none.
354
+ * @private
355
+ */
356
+ __restoreItemHighlight(item) {
357
+ const items = this._dropdownItems;
358
358
 
359
- // When both the previously-focused entry and the new entry at the
359
+ // When both the previously highlighted entry and the new entry at the
360
360
  // same index are placeholders (e.g. the Flow connector mid-scroll
361
- // re-pushing `_setDropdownItems`), preserve `_focusedIndex` until
361
+ // re-pushing `_setDropdownItems`), preserve the highlight until
362
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
- ) {
363
+ if (item instanceof ComboBoxPlaceholder && items[this._highlightedItemIndex] instanceof ComboBoxPlaceholder) {
368
364
  return;
369
365
  }
370
366
 
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
- }
367
+ const index = this.__getItemIndexByValue(items, this._getItemValue(item));
368
+ this._highlightItemAt(index > -1 ? index : this.__getItemIndexByFilter(items));
382
369
  }
383
370
 
384
371
  /** @private */
@@ -146,7 +146,7 @@ export const ComboBoxMixin = (superClass) =>
146
146
  */
147
147
  _hasValidInputValue() {
148
148
  const hasInvalidOption =
149
- this._focusedIndex < 0 &&
149
+ !this._hasHighlightedItem &&
150
150
  this._inputElementValue !== '' &&
151
151
  this._getItemLabel(this.selectedItem) !== this._inputElementValue;
152
152
 
@@ -236,14 +236,14 @@ export const ComboBoxMixin = (superClass) =>
236
236
  * @override
237
237
  */
238
238
  _commitValue() {
239
- if (this._focusedIndex > -1) {
240
- const focusedItem = this._dropdownItems[this._focusedIndex];
239
+ if (this._hasHighlightedItem) {
240
+ const focusedItem = this._highlightedItem;
241
241
  if (this.selectedItem !== focusedItem) {
242
242
  this.selectedItem = focusedItem;
243
243
  }
244
244
  // Make sure input field is updated in case value doesn't change (i.e. FOO -> foo)
245
245
  this._inputElementValue = this._getItemLabel(this.selectedItem);
246
- this._focusedIndex = -1;
246
+ this._clearItemHighlight();
247
247
  } else if (this._inputElementValue === '' || this._inputElementValue === undefined) {
248
248
  this.selectedItem = null;
249
249
 
@@ -284,6 +284,11 @@ export const ComboBoxScrollerMixin = (superClass) =>
284
284
  }
285
285
 
286
286
  this.requestContentUpdate();
287
+
288
+ // The focused index can change while closed, when scrolling to it is skipped
289
+ if (this.focusedIndex >= 0 && !this.loading) {
290
+ this.scrollIntoView(this.focusedIndex);
291
+ }
287
292
  return;
288
293
  }
289
294
 
@@ -223,10 +223,14 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
223
223
  * | `--vaadin-input-field-error-font-weight` |
224
224
  * | `--vaadin-input-field-error-line-height` |
225
225
  * | `--vaadin-input-field-gap` |
226
+ * | `--vaadin-input-field-height` |
226
227
  * | `--vaadin-input-field-helper-color` |
227
228
  * | `--vaadin-input-field-helper-font-size` |
228
229
  * | `--vaadin-input-field-helper-font-weight` |
229
230
  * | `--vaadin-input-field-helper-line-height` |
231
+ * | `--vaadin-input-field-label-aside-gap` |
232
+ * | `--vaadin-input-field-label-aside-text-align` |
233
+ * | `--vaadin-input-field-label-aside-width` |
230
234
  * | `--vaadin-input-field-label-color` |
231
235
  * | `--vaadin-input-field-label-font-size` |
232
236
  * | `--vaadin-input-field-label-font-weight` |
@@ -155,10 +155,14 @@ import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
155
155
  * | `--vaadin-input-field-error-font-weight` |
156
156
  * | `--vaadin-input-field-error-line-height` |
157
157
  * | `--vaadin-input-field-gap` |
158
+ * | `--vaadin-input-field-height` |
158
159
  * | `--vaadin-input-field-helper-color` |
159
160
  * | `--vaadin-input-field-helper-font-size` |
160
161
  * | `--vaadin-input-field-helper-font-weight` |
161
162
  * | `--vaadin-input-field-helper-line-height` |
163
+ * | `--vaadin-input-field-label-aside-gap` |
164
+ * | `--vaadin-input-field-label-aside-text-align` |
165
+ * | `--vaadin-input-field-label-aside-width` |
162
166
  * | `--vaadin-input-field-label-color` |
163
167
  * | `--vaadin-input-field-label-font-size` |
164
168
  * | `--vaadin-input-field-label-font-weight` |
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.2",
4
+ "version": "25.4.0-alpha2",
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.2/#/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.2/#/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.2/#/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.2/#/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.4.0-alpha2/#/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.4.0-alpha2/#/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.4.0-alpha2/#/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-height` |\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-aside-gap` |\n| `--vaadin-input-field-label-aside-text-align` |\n| `--vaadin-input-field-label-aside-width` |\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.4.0-alpha2/#/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",
@@ -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.2",
4
+ "version": "25.4.0-alpha2",
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.2/#/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.2/#/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.2/#/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.2/#/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.4.0-alpha2/#/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.4.0-alpha2/#/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.4.0-alpha2/#/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-height` |\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-aside-gap` |\n| `--vaadin-input-field-label-aside-text-align` |\n| `--vaadin-input-field-label-aside-width` |\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.4.0-alpha2/#/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
  {