@vaadin/combo-box 24.2.0-alpha1 → 24.2.0-alpha11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/combo-box",
3
- "version": "24.2.0-alpha1",
3
+ "version": "24.2.0-alpha11",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -38,21 +38,21 @@
38
38
  "dependencies": {
39
39
  "@open-wc/dedupe-mixin": "^1.3.0",
40
40
  "@polymer/polymer": "^3.0.0",
41
- "@vaadin/a11y-base": "24.2.0-alpha1",
42
- "@vaadin/component-base": "24.2.0-alpha1",
43
- "@vaadin/field-base": "24.2.0-alpha1",
44
- "@vaadin/input-container": "24.2.0-alpha1",
45
- "@vaadin/item": "24.2.0-alpha1",
46
- "@vaadin/lit-renderer": "24.2.0-alpha1",
47
- "@vaadin/overlay": "24.2.0-alpha1",
48
- "@vaadin/vaadin-lumo-styles": "24.2.0-alpha1",
49
- "@vaadin/vaadin-material-styles": "24.2.0-alpha1",
50
- "@vaadin/vaadin-themable-mixin": "24.2.0-alpha1"
41
+ "@vaadin/a11y-base": "24.2.0-alpha11",
42
+ "@vaadin/component-base": "24.2.0-alpha11",
43
+ "@vaadin/field-base": "24.2.0-alpha11",
44
+ "@vaadin/input-container": "24.2.0-alpha11",
45
+ "@vaadin/item": "24.2.0-alpha11",
46
+ "@vaadin/lit-renderer": "24.2.0-alpha11",
47
+ "@vaadin/overlay": "24.2.0-alpha11",
48
+ "@vaadin/vaadin-lumo-styles": "24.2.0-alpha11",
49
+ "@vaadin/vaadin-material-styles": "24.2.0-alpha11",
50
+ "@vaadin/vaadin-themable-mixin": "24.2.0-alpha11"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@esm-bundle/chai": "^4.3.4",
54
- "@vaadin/testing-helpers": "^0.4.2",
55
- "@vaadin/text-field": "24.2.0-alpha1",
54
+ "@vaadin/testing-helpers": "^0.5.0",
55
+ "@vaadin/text-field": "24.2.0-alpha11",
56
56
  "lit": "^2.0.0",
57
57
  "sinon": "^13.0.2"
58
58
  },
@@ -60,5 +60,5 @@
60
60
  "web-types.json",
61
61
  "web-types.lit.json"
62
62
  ],
63
- "gitHead": "0dbb118320203ab6c0c07450a3e718815367589f"
63
+ "gitHead": "a958207d5f6a09ca0e2dcf9f62194b3f92c8766a"
64
64
  }
@@ -3,8 +3,8 @@
3
3
  * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import type { TemplateResult } from 'lit';
7
6
  import type { DirectiveResult } from 'lit/directive.js';
7
+ import type { LitRendererResult } from '@vaadin/lit-renderer';
8
8
  import { LitRendererDirective } from '@vaadin/lit-renderer';
9
9
  import type { ComboBox, ComboBoxItemModel } from '../vaadin-combo-box.js';
10
10
 
@@ -12,7 +12,7 @@ export type ComboBoxLitRenderer<TItem> = (
12
12
  item: TItem,
13
13
  model: ComboBoxItemModel<TItem>,
14
14
  comboBox: ComboBox<TItem>,
15
- ) => TemplateResult;
15
+ ) => LitRendererResult;
16
16
 
17
17
  export class ComboBoxRendererDirective<TItem> extends LitRendererDirective<ComboBox, ComboBoxLitRenderer<TItem>> {
18
18
  /**
@@ -4,6 +4,7 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
7
+ import type { FocusMixinClass } from '@vaadin/a11y-base/src/focus-mixin.js';
7
8
  import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js';
8
9
  import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
9
10
  import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
@@ -40,6 +41,11 @@ export type ComboBoxLightOpenedChangedEvent = CustomEvent<{ value: boolean }>;
40
41
  */
41
42
  export type ComboBoxLightInvalidChangedEvent = CustomEvent<{ value: boolean }>;
42
43
 
44
+ /**
45
+ * Fired when the `dirty` property changes.
46
+ */
47
+ export type ComboBoxLightDirtyChangedEvent = CustomEvent<{ value: boolean }>;
48
+
43
49
  /**
44
50
  * Fired when the `value` property changes.
45
51
  */
@@ -71,6 +77,8 @@ export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
71
77
 
72
78
  'invalid-changed': ComboBoxLightInvalidChangedEvent;
73
79
 
80
+ 'dirty-changed': ComboBoxLightDirtyChangedEvent;
81
+
74
82
  'value-changed': ComboBoxLightValueChangedEvent;
75
83
 
76
84
  'selected-item-changed': ComboBoxLightSelectedItemChangedEvent<TItem>;
@@ -121,6 +129,7 @@ export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
121
129
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
122
130
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
123
131
  * @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
132
+ * @fires {CustomEvent} dirty-changed - Fired when the `dirty` property changes.
124
133
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
125
134
  * @fires {CustomEvent} validated - Fired whenever the field is validated.
126
135
  */
@@ -152,6 +161,7 @@ interface ComboBoxLight<TItem = ComboBoxDefaultItem>
152
161
  InputMixinClass,
153
162
  DisabledMixinClass,
154
163
  ThemableMixinClass,
164
+ FocusMixinClass,
155
165
  ThemePropertyMixinClass,
156
166
  ValidateMixinClass {}
157
167
 
@@ -180,7 +180,7 @@ class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixi
180
180
  * @return {boolean}
181
181
  */
182
182
  checkValidity() {
183
- if (this.inputElement.validate) {
183
+ if (this.inputElement && this.inputElement.validate) {
184
184
  return this.inputElement.validate();
185
185
  }
186
186
  return super.checkValidity();
@@ -195,32 +195,20 @@ class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixi
195
195
  );
196
196
  }
197
197
 
198
- /**
199
- * @param {!Event} event
200
- * @protected
201
- */
202
- _onChange(event) {
203
- super._onChange(event);
204
-
205
- if (this._isClearButton(event)) {
206
- this._onClearAction();
207
- }
208
- }
209
-
210
198
  /**
211
199
  * @protected
212
200
  * @override
213
201
  */
214
- _onFocusout(event) {
202
+ _shouldRemoveFocus(event) {
215
203
  const isBlurringControlButtons = event.target === this._toggleElement || event.target === this.clearElement;
216
204
  const isFocusingInputElement = event.relatedTarget && event.relatedTarget === this._nativeInput;
217
205
 
218
206
  // prevent closing the overlay when moving focus from clear or toggle buttons to the internal input
219
207
  if (isBlurringControlButtons && isFocusingInputElement) {
220
- return;
208
+ return false;
221
209
  }
222
210
 
223
- super._onFocusout(event);
211
+ return super._shouldRemoveFocus(event);
224
212
  }
225
213
  }
226
214
 
@@ -5,9 +5,11 @@
5
5
  */
6
6
  import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
  import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
8
+ import type { FocusMixinClass } from '@vaadin/a11y-base/src/focus-mixin.js';
8
9
  import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js';
9
10
  import type { OverlayClassMixinClass } from '@vaadin/component-base/src/overlay-class-mixin.js';
10
11
  import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
12
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
11
13
  import type { ComboBox } from './vaadin-combo-box.js';
12
14
  import type { ComboBoxDefaultItem, ComboBoxItemModel, ComboBoxItemRenderer } from './vaadin-combo-box-item-mixin.js';
13
15
 
@@ -19,9 +21,11 @@ export declare function ComboBoxMixin<TItem, T extends Constructor<HTMLElement>>
19
21
  base: T,
20
22
  ): Constructor<ComboBoxMixinClass<TItem>> &
21
23
  Constructor<DisabledMixinClass> &
24
+ Constructor<FocusMixinClass> &
22
25
  Constructor<InputMixinClass> &
23
26
  Constructor<KeyboardMixinClass> &
24
27
  Constructor<OverlayClassMixinClass> &
28
+ Constructor<ValidateMixinClass> &
25
29
  T;
26
30
 
27
31
  export declare class ComboBoxMixinClass<TItem> {
@@ -4,13 +4,16 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
7
+ import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
7
8
  import { isElementFocused } from '@vaadin/a11y-base/src/focus-utils.js';
8
9
  import { KeyboardMixin } from '@vaadin/a11y-base/src/keyboard-mixin.js';
9
10
  import { isTouch } from '@vaadin/component-base/src/browser-utils.js';
10
11
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
11
12
  import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js';
13
+ import { get } from '@vaadin/component-base/src/path-utils.js';
12
14
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
13
15
  import { InputMixin } from '@vaadin/field-base/src/input-mixin.js';
16
+ import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
14
17
  import { VirtualKeyboardController } from '@vaadin/field-base/src/virtual-keyboard-controller.js';
15
18
  import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
16
19
 
@@ -45,15 +48,17 @@ function findItemIndex(items, callback) {
45
48
  /**
46
49
  * @polymerMixin
47
50
  * @mixes ControllerMixin
51
+ * @mixes ValidateMixin
48
52
  * @mixes DisabledMixin
49
53
  * @mixes InputMixin
50
54
  * @mixes KeyboardMixin
55
+ * @mixes FocusMixin
51
56
  * @mixes OverlayClassMixin
52
57
  * @param {function(new:HTMLElement)} subclass
53
58
  */
54
59
  export const ComboBoxMixin = (subclass) =>
55
60
  class ComboBoxMixinClass extends OverlayClassMixin(
56
- ControllerMixin(KeyboardMixin(InputMixin(DisabledMixin(subclass)))),
61
+ ControllerMixin(ValidateMixin(FocusMixin(KeyboardMixin(InputMixin(DisabledMixin(subclass)))))),
57
62
  ) {
58
63
  static get properties() {
59
64
  return {
@@ -253,7 +258,6 @@ export const ComboBoxMixin = (subclass) =>
253
258
 
254
259
  constructor() {
255
260
  super();
256
- this._boundOnFocusout = this._onFocusout.bind(this);
257
261
  this._boundOverlaySelectedItemChanged = this._overlaySelectedItemChanged.bind(this);
258
262
  this._boundOnClearButtonMouseDown = this.__onClearButtonMouseDown.bind(this);
259
263
  this._boundOnClick = this._onClick.bind(this);
@@ -320,8 +324,6 @@ export const ComboBoxMixin = (subclass) =>
320
324
  this._initOverlay();
321
325
  this._initScroller();
322
326
 
323
- this.addEventListener('focusout', this._boundOnFocusout);
324
-
325
327
  this._lastCommittedValue = this.value;
326
328
 
327
329
  this.addEventListener('click', this._boundOnClick);
@@ -660,7 +662,7 @@ export const ComboBoxMixin = (subclass) =>
660
662
 
661
663
  /** @private */
662
664
  _getItemLabel(item) {
663
- let label = item && this.itemLabelPath ? this.get(this.itemLabelPath, item) : undefined;
665
+ let label = item && this.itemLabelPath ? get(this.itemLabelPath, item) : undefined;
664
666
  if (label === undefined || label === null) {
665
667
  label = item ? item.toString() : '';
666
668
  }
@@ -669,7 +671,7 @@ export const ComboBoxMixin = (subclass) =>
669
671
 
670
672
  /** @private */
671
673
  _getItemValue(item) {
672
- let value = item && this.itemValuePath ? this.get(this.itemValuePath, item) : undefined;
674
+ let value = item && this.itemValuePath ? get(this.itemValuePath, item) : undefined;
673
675
  if (value === undefined) {
674
676
  value = item ? item.toString() : '';
675
677
  }
@@ -869,14 +871,6 @@ export const ComboBoxMixin = (subclass) =>
869
871
 
870
872
  /** @private */
871
873
  _onOpened() {
872
- // Defer scroll position adjustment to improve performance.
873
- requestAnimationFrame(() => {
874
- this._scrollIntoView(this._focusedIndex);
875
-
876
- // Set attribute after the items are rendered when overlay is opened for the first time.
877
- this._updateActiveDescendant(this._focusedIndex);
878
- });
879
-
880
874
  // _detectAndDispatchChange() should not consider value changes done before opening
881
875
  this._lastCommittedValue = this.value;
882
876
  }
@@ -897,6 +891,7 @@ export const ComboBoxMixin = (subclass) =>
897
891
  }
898
892
  // Make sure input field is updated in case value doesn't change (i.e. FOO -> foo)
899
893
  this._inputElementValue = this._getItemLabel(this.selectedItem);
894
+ this._focusedIndex = -1;
900
895
  } else if (this._inputElementValue === '' || this._inputElementValue === undefined) {
901
896
  this.selectedItem = null;
902
897
 
@@ -1056,10 +1051,6 @@ export const ComboBoxMixin = (subclass) =>
1056
1051
  this._toggleHasValue(true);
1057
1052
  this._inputElementValue = this._getItemLabel(selectedItem);
1058
1053
  }
1059
-
1060
- if (this.filteredItems) {
1061
- this._focusedIndex = this.filteredItems.indexOf(selectedItem);
1062
- }
1063
1054
  }
1064
1055
 
1065
1056
  /**
@@ -1096,7 +1087,18 @@ export const ComboBoxMixin = (subclass) =>
1096
1087
 
1097
1088
  /** @private */
1098
1089
  _detectAndDispatchChange() {
1099
- if (this.value !== this._lastCommittedValue) {
1090
+ const isValueChanged = this.value !== this._lastCommittedValue;
1091
+ if (isValueChanged) {
1092
+ this.dirty = true;
1093
+ }
1094
+
1095
+ // Do not validate when focusout is caused by document
1096
+ // losing focus, which happens on browser tab switch.
1097
+ if (document.hasFocus()) {
1098
+ this.validate();
1099
+ }
1100
+
1101
+ if (isValueChanged) {
1100
1102
  this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
1101
1103
  this._lastCommittedValue = this.value;
1102
1104
  }
@@ -1138,18 +1140,6 @@ export const ComboBoxMixin = (subclass) =>
1138
1140
  const focusedItemIndex = this.__getItemIndexByValue(filteredItems, this._getItemValue(focusedItem));
1139
1141
  if (focusedItemIndex > -1) {
1140
1142
  this._focusedIndex = focusedItemIndex;
1141
- } else {
1142
- this.__setInitialFocusedIndex();
1143
- }
1144
- }
1145
-
1146
- /** @private */
1147
- __setInitialFocusedIndex() {
1148
- const inputValue = this._inputElementValue;
1149
- if (inputValue === undefined || inputValue === this._getItemLabel(this.selectedItem)) {
1150
- // When the input element value is the same as the current value or not defined,
1151
- // set the focused index to the item that matches the value.
1152
- this._focusedIndex = this.__getItemIndexByLabel(this.filteredItems, this._getItemLabel(this.selectedItem));
1153
1143
  } else {
1154
1144
  // When the user filled in something that is different from the current value = filtering is enabled,
1155
1145
  // set the focused index to the item that matches the filter query.
@@ -1250,20 +1240,18 @@ export const ComboBoxMixin = (subclass) =>
1250
1240
  }
1251
1241
  }
1252
1242
 
1253
- /** @private */
1254
- _onFocusout(event) {
1255
- // VoiceOver on iOS fires `focusout` event when moving focus to the item in the dropdown.
1256
- // Do not focus the input in this case, because it would break announcement for the item.
1257
- if (event.relatedTarget && event.relatedTarget.localName === `${this._tagNamePrefix}-item`) {
1258
- return;
1259
- }
1243
+ /**
1244
+ * Override method inherited from `FocusMixin`
1245
+ * to close the overlay on blur and commit the value.
1246
+ *
1247
+ * @param {boolean} focused
1248
+ * @protected
1249
+ * @override
1250
+ */
1251
+ _setFocused(focused) {
1252
+ super._setFocused(focused);
1260
1253
 
1261
- // Fixes the problem with `focusout` happening when clicking on the scroll bar on Edge
1262
- if (event.relatedTarget === this._overlayElement) {
1263
- event.composedPath()[0].focus();
1264
- return;
1265
- }
1266
- if (!this.readonly && !this._closeOnBlurIsPrevented) {
1254
+ if (!focused && !this.readonly && !this._closeOnBlurIsPrevented) {
1267
1255
  // User's logic in `custom-value-set` event listener might cause input to blur,
1268
1256
  // which will result in attempting to commit the same custom value once again.
1269
1257
  if (!this.opened && this.allowCustomValue && this._inputElementValue === this._lastCustomValue) {
@@ -1275,6 +1263,32 @@ export const ComboBoxMixin = (subclass) =>
1275
1263
  }
1276
1264
  }
1277
1265
 
1266
+ /**
1267
+ * Override method inherited from `FocusMixin` to not remove focused
1268
+ * state when focus moves to the overlay.
1269
+ *
1270
+ * @param {FocusEvent} event
1271
+ * @return {boolean}
1272
+ * @protected
1273
+ * @override
1274
+ */
1275
+ _shouldRemoveFocus(event) {
1276
+ // VoiceOver on iOS fires `focusout` event when moving focus to the item in the dropdown.
1277
+ // Do not focus the input in this case, because it would break announcement for the item.
1278
+ if (event.relatedTarget && event.relatedTarget.localName === `${this._tagNamePrefix}-item`) {
1279
+ return false;
1280
+ }
1281
+
1282
+ // Do not blur when focus moves to the overlay
1283
+ // Also, fixes the problem with `focusout` happening when clicking on the scroll bar on Edge
1284
+ if (event.relatedTarget === this._overlayElement) {
1285
+ event.composedPath()[0].focus();
1286
+ return false;
1287
+ }
1288
+
1289
+ return true;
1290
+ }
1291
+
1278
1292
  /** @private */
1279
1293
  _onTouchend(event) {
1280
1294
  if (!this.clearElement || event.composedPath()[0] !== this.clearElement) {
@@ -3,13 +3,15 @@
3
3
  * Copyright (c) 2015 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { Overlay } from '@vaadin/overlay/src/vaadin-overlay.js';
6
+ import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
7
+ import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
8
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
7
9
  import { ComboBoxOverlayMixin } from './vaadin-combo-box-overlay-mixin.js';
8
10
 
9
11
  /**
10
12
  * An element used internally by `<vaadin-combo-box>`. Not intended to be used separately.
11
13
  */
12
- declare class ComboBoxOverlay extends ComboBoxOverlayMixin(Overlay) {}
14
+ declare class ComboBoxOverlay extends ComboBoxOverlayMixin(OverlayMixin(DirMixin(ThemableMixin(HTMLElement)))) {}
13
15
 
14
16
  declare global {
15
17
  interface HTMLElementTagNameMap {
@@ -3,54 +3,52 @@
3
3
  * Copyright (c) 2015 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { Overlay } from '@vaadin/overlay/src/vaadin-overlay.js';
7
- import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
6
+ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
7
+ import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
8
+ import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
9
+ import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
10
+ import { css, registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
11
  import { ComboBoxOverlayMixin } from './vaadin-combo-box-overlay-mixin.js';
9
12
 
10
- registerStyles(
11
- 'vaadin-combo-box-overlay',
12
- css`
13
- #overlay {
14
- width: var(--vaadin-combo-box-overlay-width, var(--_vaadin-combo-box-overlay-default-width, auto));
15
- }
13
+ const comboBoxOverlayStyles = css`
14
+ #overlay {
15
+ width: var(--vaadin-combo-box-overlay-width, var(--_vaadin-combo-box-overlay-default-width, auto));
16
+ }
16
17
 
17
- [part='content'] {
18
- display: flex;
19
- flex-direction: column;
20
- height: 100%;
21
- }
22
- `,
23
- { moduleId: 'vaadin-combo-box-overlay-styles' },
24
- );
18
+ [part='content'] {
19
+ display: flex;
20
+ flex-direction: column;
21
+ height: 100%;
22
+ }
23
+ `;
25
24
 
26
- let memoizedTemplate;
25
+ registerStyles('vaadin-combo-box-overlay', [overlayStyles, comboBoxOverlayStyles], {
26
+ moduleId: 'vaadin-combo-box-overlay-styles',
27
+ });
27
28
 
28
29
  /**
29
30
  * An element used internally by `<vaadin-combo-box>`. Not intended to be used separately.
30
31
  *
31
- * @extends Overlay
32
+ * @extends HTMLElement
32
33
  * @mixes ComboBoxOverlayMixin
34
+ * @mixes DirMixin
35
+ * @mixes OverlayMixin
36
+ * @mixes ThemableMixin
33
37
  * @private
34
38
  */
35
- export class ComboBoxOverlay extends ComboBoxOverlayMixin(Overlay) {
39
+ export class ComboBoxOverlay extends ComboBoxOverlayMixin(OverlayMixin(DirMixin(ThemableMixin(PolymerElement)))) {
36
40
  static get is() {
37
41
  return 'vaadin-combo-box-overlay';
38
42
  }
39
43
 
40
44
  static get template() {
41
- if (!memoizedTemplate) {
42
- memoizedTemplate = super.template.cloneNode(true);
43
-
44
- const overlay = memoizedTemplate.content.querySelector('[part~="overlay"]');
45
- overlay.removeAttribute('tabindex');
46
-
47
- const loader = document.createElement('div');
48
- loader.setAttribute('part', 'loader');
49
-
50
- overlay.insertBefore(loader, overlay.firstElementChild);
51
- }
52
-
53
- return memoizedTemplate;
45
+ return html`
46
+ <div id="backdrop" part="backdrop" hidden></div>
47
+ <div part="overlay" id="overlay">
48
+ <div part="loader"></div>
49
+ <div part="content" id="content"><slot></slot></div>
50
+ </div>
51
+ `;
54
52
  }
55
53
  }
56
54
 
@@ -3,6 +3,7 @@
3
3
  * Copyright (c) 2015 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
+ import { get } from '@vaadin/component-base/src/path-utils.js';
6
7
  import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
7
8
  import { Virtualizer } from '@vaadin/component-base/src/virtualizer.js';
8
9
  import { ComboBoxPlaceholder } from './vaadin-combo-box-placeholder.js';
@@ -202,7 +203,7 @@ export const ComboBoxScrollerMixin = (superClass) =>
202
203
  if (item instanceof ComboBoxPlaceholder) {
203
204
  return false;
204
205
  } else if (itemIdPath && item !== undefined && selectedItem !== undefined) {
205
- return this.get(itemIdPath, item) === this.get(itemIdPath, selectedItem);
206
+ return get(itemIdPath, item) === get(itemIdPath, selectedItem);
206
207
  }
207
208
  return item === selectedItem;
208
209
  }
@@ -53,6 +53,11 @@ export type ComboBoxOpenedChangedEvent = CustomEvent<{ value: boolean }>;
53
53
  */
54
54
  export type ComboBoxInvalidChangedEvent = CustomEvent<{ value: boolean }>;
55
55
 
56
+ /**
57
+ * Fired when the `dirty` property changes.
58
+ */
59
+ export type ComboBoxDirtyChangedEvent = CustomEvent<{ value: boolean }>;
60
+
56
61
  /**
57
62
  * Fired when the `value` property changes.
58
63
  */
@@ -84,6 +89,8 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
84
89
 
85
90
  'invalid-changed': ComboBoxInvalidChangedEvent;
86
91
 
92
+ 'dirty-changed': ComboBoxDirtyChangedEvent;
93
+
87
94
  'value-changed': ComboBoxValueChangedEvent;
88
95
 
89
96
  'selected-item-changed': ComboBoxSelectedItemChangedEvent<TItem>;
@@ -212,6 +219,7 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
212
219
  * @fires {CustomEvent} filter-changed - Fired when the `filter` property changes.
213
220
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
214
221
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
222
+ * @fires {CustomEvent} dirty-changed - Fired when the `dirty` property changes.
215
223
  * @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
216
224
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
217
225
  * @fires {CustomEvent} validated - Fired whenever the field is validated.
@@ -248,44 +248,13 @@ class ComboBox extends ComboBoxDataProviderMixin(
248
248
  this._tooltipController = new TooltipController(this);
249
249
  this.addController(this._tooltipController);
250
250
  this._tooltipController.setPosition('top');
251
+ this._tooltipController.setAriaTarget(this.inputElement);
251
252
  this._tooltipController.setShouldShow((target) => !target.opened);
252
253
 
253
254
  this._positionTarget = this.shadowRoot.querySelector('[part="input-field"]');
254
255
  this._toggleElement = this.$.toggleButton;
255
256
  }
256
257
 
257
- /**
258
- * Override method inherited from `FocusMixin` to validate on blur.
259
- * @param {boolean} focused
260
- * @protected
261
- * @override
262
- */
263
- _setFocused(focused) {
264
- super._setFocused(focused);
265
-
266
- if (!focused) {
267
- this.validate();
268
- }
269
- }
270
-
271
- /**
272
- * Override method inherited from `FocusMixin` to not remove focused
273
- * state when focus moves to the overlay.
274
- * @param {FocusEvent} event
275
- * @return {boolean}
276
- * @protected
277
- * @override
278
- */
279
- _shouldRemoveFocus(event) {
280
- // Do not blur when focus moves to the overlay
281
- if (event.relatedTarget === this._overlayElement) {
282
- event.composedPath()[0].focus();
283
- return false;
284
- }
285
-
286
- return true;
287
- }
288
-
289
258
  /**
290
259
  * Override the method from `InputControlMixin`
291
260
  * to stop event propagation to prevent `ComboBoxMixin`
@@ -1,7 +1,6 @@
1
1
  import '@vaadin/vaadin-lumo-styles/color.js';
2
2
  import '@vaadin/vaadin-lumo-styles/spacing.js';
3
3
  import '@vaadin/vaadin-lumo-styles/style.js';
4
- import '@vaadin/overlay/theme/lumo/vaadin-overlay.js';
5
4
  import { loader } from '@vaadin/vaadin-lumo-styles/mixins/loader.js';
6
5
  import { menuOverlayCore } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js';
7
6
  import { overlay } from '@vaadin/vaadin-lumo-styles/mixins/overlay.js';
@@ -1,5 +1,4 @@
1
1
  import '@vaadin/vaadin-material-styles/color.js';
2
- import '@vaadin/overlay/theme/material/vaadin-overlay.js';
3
2
  import { loader } from '@vaadin/vaadin-material-styles/mixins/loader.js';
4
3
  import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js';
5
4
  import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/combo-box",
4
- "version": "24.2.0-alpha1",
4
+ "version": "24.2.0-alpha11",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -29,6 +29,28 @@
29
29
  ]
30
30
  }
31
31
  },
32
+ {
33
+ "name": "invalid",
34
+ "description": "Set to true when the field is invalid.",
35
+ "value": {
36
+ "type": [
37
+ "boolean",
38
+ "null",
39
+ "undefined"
40
+ ]
41
+ }
42
+ },
43
+ {
44
+ "name": "required",
45
+ "description": "Specifies that the user must fill in a value.",
46
+ "value": {
47
+ "type": [
48
+ "boolean",
49
+ "null",
50
+ "undefined"
51
+ ]
52
+ }
53
+ },
32
54
  {
33
55
  "name": "disabled",
34
56
  "description": "If true, the user cannot interact with this element.",
@@ -51,6 +73,17 @@
51
73
  ]
52
74
  }
53
75
  },
76
+ {
77
+ "name": "dirty",
78
+ "description": "Whether the field is dirty.\n\nThe field is automatically marked as dirty once the user triggers\nan `input` or `change` event. Additionally, the field can be manually\nmarked as dirty by setting the property to `true`.",
79
+ "value": {
80
+ "type": [
81
+ "boolean",
82
+ "null",
83
+ "undefined"
84
+ ]
85
+ }
86
+ },
54
87
  {
55
88
  "name": "overlay-class",
56
89
  "description": "A space-delimited list of CSS class names to set on the overlay element.\nThis property does not affect other CSS class names set manually via JS.\n\nNote, if the CSS class name was set with this property, clearing it will\nremove it from the overlay, even if the same class name was also added\nmanually, e.g. by using `classList.add()` in the `renderer` function.",
@@ -147,28 +180,6 @@
147
180
  ]
148
181
  }
149
182
  },
150
- {
151
- "name": "invalid",
152
- "description": "Set to true when the field is invalid.",
153
- "value": {
154
- "type": [
155
- "boolean",
156
- "null",
157
- "undefined"
158
- ]
159
- }
160
- },
161
- {
162
- "name": "required",
163
- "description": "Specifies that the user must fill in a value.",
164
- "value": {
165
- "type": [
166
- "boolean",
167
- "null",
168
- "undefined"
169
- ]
170
- }
171
- },
172
183
  {
173
184
  "name": "attr-for-value",
174
185
  "description": "Name of the two-way data-bindable property representing the\nvalue of the custom input field.",
@@ -221,6 +232,28 @@
221
232
  ]
222
233
  }
223
234
  },
235
+ {
236
+ "name": "invalid",
237
+ "description": "Set to true when the field is invalid.",
238
+ "value": {
239
+ "type": [
240
+ "boolean",
241
+ "null",
242
+ "undefined"
243
+ ]
244
+ }
245
+ },
246
+ {
247
+ "name": "required",
248
+ "description": "Specifies that the user must fill in a value.",
249
+ "value": {
250
+ "type": [
251
+ "boolean",
252
+ "null",
253
+ "undefined"
254
+ ]
255
+ }
256
+ },
224
257
  {
225
258
  "name": "disabled",
226
259
  "description": "If true, the user cannot interact with this element.",
@@ -243,6 +276,17 @@
243
276
  ]
244
277
  }
245
278
  },
279
+ {
280
+ "name": "dirty",
281
+ "description": "Whether the field is dirty.\n\nThe field is automatically marked as dirty once the user triggers\nan `input` or `change` event. Additionally, the field can be manually\nmarked as dirty by setting the property to `true`.",
282
+ "value": {
283
+ "type": [
284
+ "boolean",
285
+ "null",
286
+ "undefined"
287
+ ]
288
+ }
289
+ },
246
290
  {
247
291
  "name": "overlayClass",
248
292
  "description": "A space-delimited list of CSS class names to set on the overlay element.\nThis property does not affect other CSS class names set manually via JS.\n\nNote, if the CSS class name was set with this property, clearing it will\nremove it from the overlay, even if the same class name was also added\nmanually, e.g. by using `classList.add()` in the `renderer` function.",
@@ -382,28 +426,6 @@
382
426
  ]
383
427
  }
384
428
  },
385
- {
386
- "name": "invalid",
387
- "description": "Set to true when the field is invalid.",
388
- "value": {
389
- "type": [
390
- "boolean",
391
- "null",
392
- "undefined"
393
- ]
394
- }
395
- },
396
- {
397
- "name": "required",
398
- "description": "Specifies that the user must fill in a value.",
399
- "value": {
400
- "type": [
401
- "boolean",
402
- "null",
403
- "undefined"
404
- ]
405
- }
406
- },
407
429
  {
408
430
  "name": "attrForValue",
409
431
  "description": "Name of the two-way data-bindable property representing the\nvalue of the custom input field.",
@@ -415,6 +437,10 @@
415
437
  }
416
438
  ],
417
439
  "events": [
440
+ {
441
+ "name": "validated",
442
+ "description": "Fired whenever the field is validated."
443
+ },
418
444
  {
419
445
  "name": "change",
420
446
  "description": "Fired when value changes.\nTo comply with https://developer.mozilla.org/en-US/docs/Web/Events/change"
@@ -440,8 +466,12 @@
440
466
  "description": "Fired when the value changes."
441
467
  },
442
468
  {
443
- "name": "validated",
444
- "description": "Fired whenever the field is validated."
469
+ "name": "invalid-changed",
470
+ "description": "Fired when the `invalid` property changes."
471
+ },
472
+ {
473
+ "name": "dirty-changed",
474
+ "description": "Fired when the `dirty` property changes."
445
475
  },
446
476
  {
447
477
  "name": "opened-changed",
@@ -450,17 +480,13 @@
450
480
  {
451
481
  "name": "filter-changed",
452
482
  "description": "Fired when the `filter` property changes."
453
- },
454
- {
455
- "name": "invalid-changed",
456
- "description": "Fired when the `invalid` property changes."
457
483
  }
458
484
  ]
459
485
  }
460
486
  },
461
487
  {
462
488
  "name": "vaadin-combo-box",
463
- "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/24.2.0-alpha1/#/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/24.2.0-alpha1/#/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/24.2.0-alpha1/#/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 custom properties are available for styling:\n\nCustom property | Description | Default\n----------------------------------------|----------------------------|---------\n`--vaadin-field-default-width` | Default width of the field | `12em`\n`--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`\n`--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`\n\n`<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.\nSee [`<vaadin-text-field>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-text-field) for the styling documentation.\n\nIn addition to `<vaadin-text-field>` parts, the following parts are available for theming:\n\nPart name | Description\n----------------|----------------\n`toggle-button` | The toggle button\n\nIn addition to `<vaadin-text-field>` state attributes, the following state attributes are available for theming:\n\nAttribute | Description | Part name\n----------|-------------|------------\n`opened` | Set when the combo box dropdown is open | :host\n`loading` | Set when new items are expected | :host\n\nIf you want to replace the default `<input>` and its container with a custom implementation to get full control\nover the input field, consider using the [`<vaadin-combo-box-light>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-combo-box-light) element.\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-overlay>` - has the same API as [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-overlay).\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-item).\n- [`<vaadin-input-container>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-input-container) - an internal element wrapping the input.\n\nNote: the `theme` attribute value set on `<vaadin-combo-box>` is\npropagated to the internal components listed above.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
489
+ "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/24.2.0-alpha11/#/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/24.2.0-alpha11/#/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/24.2.0-alpha11/#/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 custom properties are available for styling:\n\nCustom property | Description | Default\n----------------------------------------|----------------------------|---------\n`--vaadin-field-default-width` | Default width of the field | `12em`\n`--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`\n`--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`\n\n`<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.\nSee [`<vaadin-text-field>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-text-field) for the styling documentation.\n\nIn addition to `<vaadin-text-field>` parts, the following parts are available for theming:\n\nPart name | Description\n----------------|----------------\n`toggle-button` | The toggle button\n\nIn addition to `<vaadin-text-field>` state attributes, the following state attributes are available for theming:\n\nAttribute | Description | Part name\n----------|-------------|------------\n`opened` | Set when the combo box dropdown is open | :host\n`loading` | Set when new items are expected | :host\n\nIf you want to replace the default `<input>` and its container with a custom implementation to get full control\nover the input field, consider using the [`<vaadin-combo-box-light>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-combo-box-light) element.\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-overlay>` - has the same API as [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-overlay).\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-item).\n- [`<vaadin-input-container>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-input-container) - an internal element wrapping the input.\n\nNote: the `theme` attribute value set on `<vaadin-combo-box>` is\npropagated to the internal components listed above.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
464
490
  "attributes": [
465
491
  {
466
492
  "name": "disabled",
@@ -572,6 +598,17 @@
572
598
  ]
573
599
  }
574
600
  },
601
+ {
602
+ "name": "dirty",
603
+ "description": "Whether the field is dirty.\n\nThe field is automatically marked as dirty once the user triggers\nan `input` or `change` event. Additionally, the field can be manually\nmarked as dirty by setting the property to `true`.",
604
+ "value": {
605
+ "type": [
606
+ "boolean",
607
+ "null",
608
+ "undefined"
609
+ ]
610
+ }
611
+ },
575
612
  {
576
613
  "name": "clear-button-visible",
577
614
  "description": "Set to true to display the clear icon which clears the input.\n\nIt is up to the component to choose where to place the clear icon:\nin the Shadow DOM or in the light DOM. In any way, a reference to\nthe clear icon element should be provided via the `clearElement` getter.",
@@ -888,6 +925,17 @@
888
925
  ]
889
926
  }
890
927
  },
928
+ {
929
+ "name": "dirty",
930
+ "description": "Whether the field is dirty.\n\nThe field is automatically marked as dirty once the user triggers\nan `input` or `change` event. Additionally, the field can be manually\nmarked as dirty by setting the property to `true`.",
931
+ "value": {
932
+ "type": [
933
+ "boolean",
934
+ "null",
935
+ "undefined"
936
+ ]
937
+ }
938
+ },
891
939
  {
892
940
  "name": "clearButtonVisible",
893
941
  "description": "Set to true to display the clear icon which clears the input.\n\nIt is up to the component to choose where to place the clear icon:\nin the Shadow DOM or in the light DOM. In any way, a reference to\nthe clear icon element should be provided via the `clearElement` getter.",
@@ -1171,6 +1219,10 @@
1171
1219
  "name": "invalid-changed",
1172
1220
  "description": "Fired when the `invalid` property changes."
1173
1221
  },
1222
+ {
1223
+ "name": "dirty-changed",
1224
+ "description": "Fired when the `dirty` property changes."
1225
+ },
1174
1226
  {
1175
1227
  "name": "opened-changed",
1176
1228
  "description": "Fired when the `opened` property changes."
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/combo-box",
4
- "version": "24.2.0-alpha1",
4
+ "version": "24.2.0-alpha11",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -19,6 +19,20 @@
19
19
  "description": "`<vaadin-combo-box-light>` is a customizable version of the `<vaadin-combo-box>` providing\nonly the dropdown functionality and leaving the input field definition to the user.\n\nThe element has the same API as `<vaadin-combo-box>`.\n\nTo create a custom input field, you need to add a child element which has a two-way\ndata-bindable property representing the input value. The property name is expected\nto be `value` by default. For example, you can use `<vaadin-text-field>` element:\n\n```html\n<vaadin-combo-box-light>\n <vaadin-text-field></vaadin-text-field>\n</vaadin-combo-box-light>\n```\n\nIf you are using custom input field that has other property for value,\nset `class=\"input\"` to enable corresponding logic, and use `attr-for-value`\nattribute to specify which property to use:\n\n```html\n<vaadin-combo-box-light attr-for-value=\"input-value\">\n <custom-input class=\"input\"></custom-input>\n</vaadin-combo-box-light>\n```\n\nYou can also pass custom toggle and clear buttons with corresponding classes:\n\n```html\n<vaadin-combo-box-light>\n <custom-input class=\"input\" attr-for-value=\"input-value\">\n <button slot=\"suffix\" class=\"clear-button\">Clear</button>\n <button slot=\"suffix\" class=\"toggle-button\">Toggle</button>\n </custom-input>\n</vaadin-combo-box-light>\n```",
20
20
  "extension": true,
21
21
  "attributes": [
22
+ {
23
+ "name": "?invalid",
24
+ "description": "Set to true when the field is invalid.",
25
+ "value": {
26
+ "kind": "expression"
27
+ }
28
+ },
29
+ {
30
+ "name": "?required",
31
+ "description": "Specifies that the user must fill in a value.",
32
+ "value": {
33
+ "kind": "expression"
34
+ }
35
+ },
22
36
  {
23
37
  "name": "?disabled",
24
38
  "description": "If true, the user cannot interact with this element.",
@@ -26,6 +40,13 @@
26
40
  "kind": "expression"
27
41
  }
28
42
  },
43
+ {
44
+ "name": "?dirty",
45
+ "description": "Whether the field is dirty.\n\nThe field is automatically marked as dirty once the user triggers\nan `input` or `change` event. Additionally, the field can be manually\nmarked as dirty by setting the property to `true`.",
46
+ "value": {
47
+ "kind": "expression"
48
+ }
49
+ },
29
50
  {
30
51
  "name": "?opened",
31
52
  "description": "True if the dropdown is open, false otherwise.",
@@ -61,20 +82,6 @@
61
82
  "kind": "expression"
62
83
  }
63
84
  },
64
- {
65
- "name": "?invalid",
66
- "description": "Set to true when the field is invalid.",
67
- "value": {
68
- "kind": "expression"
69
- }
70
- },
71
- {
72
- "name": "?required",
73
- "description": "Specifies that the user must fill in a value.",
74
- "value": {
75
- "kind": "expression"
76
- }
77
- },
78
85
  {
79
86
  "name": ".pageSize",
80
87
  "description": "Number of items fetched at a time from the dataprovider.",
@@ -173,6 +180,13 @@
173
180
  "kind": "expression"
174
181
  }
175
182
  },
183
+ {
184
+ "name": "@validated",
185
+ "description": "Fired whenever the field is validated.",
186
+ "value": {
187
+ "kind": "expression"
188
+ }
189
+ },
176
190
  {
177
191
  "name": "@change",
178
192
  "description": "Fired when value changes.\nTo comply with https://developer.mozilla.org/en-US/docs/Web/Events/change",
@@ -216,29 +230,29 @@
216
230
  }
217
231
  },
218
232
  {
219
- "name": "@validated",
220
- "description": "Fired whenever the field is validated.",
233
+ "name": "@invalid-changed",
234
+ "description": "Fired when the `invalid` property changes.",
221
235
  "value": {
222
236
  "kind": "expression"
223
237
  }
224
238
  },
225
239
  {
226
- "name": "@opened-changed",
227
- "description": "Fired when the `opened` property changes.",
240
+ "name": "@dirty-changed",
241
+ "description": "Fired when the `dirty` property changes.",
228
242
  "value": {
229
243
  "kind": "expression"
230
244
  }
231
245
  },
232
246
  {
233
- "name": "@filter-changed",
234
- "description": "Fired when the `filter` property changes.",
247
+ "name": "@opened-changed",
248
+ "description": "Fired when the `opened` property changes.",
235
249
  "value": {
236
250
  "kind": "expression"
237
251
  }
238
252
  },
239
253
  {
240
- "name": "@invalid-changed",
241
- "description": "Fired when the `invalid` property changes.",
254
+ "name": "@filter-changed",
255
+ "description": "Fired when the `filter` property changes.",
242
256
  "value": {
243
257
  "kind": "expression"
244
258
  }
@@ -247,7 +261,7 @@
247
261
  },
248
262
  {
249
263
  "name": "vaadin-combo-box",
250
- "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/24.2.0-alpha1/#/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/24.2.0-alpha1/#/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/24.2.0-alpha1/#/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 custom properties are available for styling:\n\nCustom property | Description | Default\n----------------------------------------|----------------------------|---------\n`--vaadin-field-default-width` | Default width of the field | `12em`\n`--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`\n`--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`\n\n`<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.\nSee [`<vaadin-text-field>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-text-field) for the styling documentation.\n\nIn addition to `<vaadin-text-field>` parts, the following parts are available for theming:\n\nPart name | Description\n----------------|----------------\n`toggle-button` | The toggle button\n\nIn addition to `<vaadin-text-field>` state attributes, the following state attributes are available for theming:\n\nAttribute | Description | Part name\n----------|-------------|------------\n`opened` | Set when the combo box dropdown is open | :host\n`loading` | Set when new items are expected | :host\n\nIf you want to replace the default `<input>` and its container with a custom implementation to get full control\nover the input field, consider using the [`<vaadin-combo-box-light>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-combo-box-light) element.\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-overlay>` - has the same API as [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-overlay).\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-item).\n- [`<vaadin-input-container>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha1/#/elements/vaadin-input-container) - an internal element wrapping the input.\n\nNote: the `theme` attribute value set on `<vaadin-combo-box>` is\npropagated to the internal components listed above.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
264
+ "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/24.2.0-alpha11/#/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/24.2.0-alpha11/#/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/24.2.0-alpha11/#/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 custom properties are available for styling:\n\nCustom property | Description | Default\n----------------------------------------|----------------------------|---------\n`--vaadin-field-default-width` | Default width of the field | `12em`\n`--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`\n`--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`\n\n`<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.\nSee [`<vaadin-text-field>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-text-field) for the styling documentation.\n\nIn addition to `<vaadin-text-field>` parts, the following parts are available for theming:\n\nPart name | Description\n----------------|----------------\n`toggle-button` | The toggle button\n\nIn addition to `<vaadin-text-field>` state attributes, the following state attributes are available for theming:\n\nAttribute | Description | Part name\n----------|-------------|------------\n`opened` | Set when the combo box dropdown is open | :host\n`loading` | Set when new items are expected | :host\n\nIf you want to replace the default `<input>` and its container with a custom implementation to get full control\nover the input field, consider using the [`<vaadin-combo-box-light>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-combo-box-light) element.\n\n### Internal components\n\nIn addition to `<vaadin-combo-box>` itself, the following internal\ncomponents are themable:\n\n- `<vaadin-combo-box-overlay>` - has the same API as [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-overlay).\n- `<vaadin-combo-box-item>` - has the same API as [`<vaadin-item>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-item).\n- [`<vaadin-input-container>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-alpha11/#/elements/vaadin-input-container) - an internal element wrapping the input.\n\nNote: the `theme` attribute value set on `<vaadin-combo-box>` is\npropagated to the internal components listed above.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
251
265
  "extension": true,
252
266
  "attributes": [
253
267
  {
@@ -278,6 +292,13 @@
278
292
  "kind": "expression"
279
293
  }
280
294
  },
295
+ {
296
+ "name": "?dirty",
297
+ "description": "Whether the field is dirty.\n\nThe field is automatically marked as dirty once the user triggers\nan `input` or `change` event. Additionally, the field can be manually\nmarked as dirty by setting the property to `true`.",
298
+ "value": {
299
+ "kind": "expression"
300
+ }
301
+ },
281
302
  {
282
303
  "name": "?clearButtonVisible",
283
304
  "description": "Set to true to display the clear icon which clears the input.\n\nIt is up to the component to choose where to place the clear icon:\nin the Shadow DOM or in the light DOM. In any way, a reference to\nthe clear icon element should be provided via the `clearElement` getter.",
@@ -551,6 +572,13 @@
551
572
  "kind": "expression"
552
573
  }
553
574
  },
575
+ {
576
+ "name": "@dirty-changed",
577
+ "description": "Fired when the `dirty` property changes.",
578
+ "value": {
579
+ "kind": "expression"
580
+ }
581
+ },
554
582
  {
555
583
  "name": "@opened-changed",
556
584
  "description": "Fired when the `opened` property changes.",