@vaadin/combo-box 24.4.0-alpha8 → 24.4.0-beta1

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/README.md CHANGED
@@ -5,7 +5,6 @@ A web component for choosing a value from a filterable list of options presented
5
5
  [Documentation + Live Demo ↗](https://vaadin.com/docs/latest/components/combo-box)
6
6
 
7
7
  [![npm version](https://badgen.net/npm/v/@vaadin/combo-box)](https://www.npmjs.com/package/@vaadin/combo-box)
8
- [![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC)
9
8
 
10
9
  ```html
11
10
  <vaadin-combo-box
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/combo-box",
3
- "version": "24.4.0-alpha8",
3
+ "version": "24.4.0-beta1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -26,7 +26,9 @@
26
26
  "vaadin-*.d.ts",
27
27
  "vaadin-*.js",
28
28
  "web-types.json",
29
- "web-types.lit.json"
29
+ "web-types.lit.json",
30
+ "!vaadin-lit-*.d.ts",
31
+ "!vaadin-lit-*.js"
30
32
  ],
31
33
  "keywords": [
32
34
  "Vaadin",
@@ -38,21 +40,21 @@
38
40
  "dependencies": {
39
41
  "@open-wc/dedupe-mixin": "^1.3.0",
40
42
  "@polymer/polymer": "^3.0.0",
41
- "@vaadin/a11y-base": "24.4.0-alpha8",
42
- "@vaadin/component-base": "24.4.0-alpha8",
43
- "@vaadin/field-base": "24.4.0-alpha8",
44
- "@vaadin/input-container": "24.4.0-alpha8",
45
- "@vaadin/item": "24.4.0-alpha8",
46
- "@vaadin/lit-renderer": "24.4.0-alpha8",
47
- "@vaadin/overlay": "24.4.0-alpha8",
48
- "@vaadin/vaadin-lumo-styles": "24.4.0-alpha8",
49
- "@vaadin/vaadin-material-styles": "24.4.0-alpha8",
50
- "@vaadin/vaadin-themable-mixin": "24.4.0-alpha8"
43
+ "@vaadin/a11y-base": "24.4.0-beta1",
44
+ "@vaadin/component-base": "24.4.0-beta1",
45
+ "@vaadin/field-base": "24.4.0-beta1",
46
+ "@vaadin/input-container": "24.4.0-beta1",
47
+ "@vaadin/item": "24.4.0-beta1",
48
+ "@vaadin/lit-renderer": "24.4.0-beta1",
49
+ "@vaadin/overlay": "24.4.0-beta1",
50
+ "@vaadin/vaadin-lumo-styles": "24.4.0-beta1",
51
+ "@vaadin/vaadin-material-styles": "24.4.0-beta1",
52
+ "@vaadin/vaadin-themable-mixin": "24.4.0-beta1"
51
53
  },
52
54
  "devDependencies": {
53
55
  "@esm-bundle/chai": "^4.3.4",
54
56
  "@vaadin/testing-helpers": "^0.6.0",
55
- "@vaadin/text-field": "24.4.0-alpha8",
57
+ "@vaadin/text-field": "24.4.0-beta1",
56
58
  "lit": "^3.0.0",
57
59
  "sinon": "^13.0.2"
58
60
  },
@@ -60,5 +62,5 @@
60
62
  "web-types.json",
61
63
  "web-types.lit.json"
62
64
  ],
63
- "gitHead": "a26ec541cd39218eb2af1fe5f627c9ddd9f2df69"
65
+ "gitHead": "504787f741d677467ae93ca7cd31d84489366a9c"
64
66
  }
@@ -21,6 +21,7 @@ export const ComboBoxDataProviderMixin = (superClass) =>
21
21
  type: Number,
22
22
  value: 50,
23
23
  observer: '_pageSizeChanged',
24
+ sync: true,
24
25
  },
25
26
 
26
27
  /**
@@ -30,6 +31,7 @@ export const ComboBoxDataProviderMixin = (superClass) =>
30
31
  size: {
31
32
  type: Number,
32
33
  observer: '_sizeChanged',
34
+ sync: true,
33
35
  },
34
36
 
35
37
  /**
@@ -49,6 +51,7 @@ export const ComboBoxDataProviderMixin = (superClass) =>
49
51
  dataProvider: {
50
52
  type: Object,
51
53
  observer: '_dataProviderChanged',
54
+ sync: true,
52
55
  },
53
56
 
54
57
  /** @private */
@@ -82,18 +85,11 @@ export const ComboBoxDataProviderMixin = (superClass) =>
82
85
  ready() {
83
86
  super.ready();
84
87
  this._scroller.addEventListener('index-requested', (e) => {
85
- const index = e.detail.index;
86
- const currentScrollerPos = e.detail.currentScrollerPos;
87
- const allowedIndexRange = Math.floor(this.pageSize * 1.5);
88
-
89
- // Ignores the indexes, which are being re-sent during scrolling reset,
90
- // if the corresponding page is around the current scroller position.
91
- // Otherwise, there might be a last pages duplicates, which cause the
92
- // loading indicator hanging and blank items
93
- if (this._shouldSkipIndex(index, allowedIndexRange, currentScrollerPos)) {
88
+ if (!this._shouldFetchData()) {
94
89
  return;
95
90
  }
96
91
 
92
+ const index = e.detail.index;
97
93
  if (index !== undefined) {
98
94
  const page = this._getPageForIndex(index);
99
95
  if (this._shouldLoadPage(page)) {
@@ -113,19 +109,15 @@ export const ComboBoxDataProviderMixin = (superClass) =>
113
109
  if (this.__previousDataProviderFilter !== filter) {
114
110
  this.__previousDataProviderFilter = filter;
115
111
 
112
+ this.__keepOverlayOpened = true;
116
113
  this._pendingRequests = {};
117
- // Immediately mark as loading if this refresh leads to re-fetching pages
118
- // This prevents some issues with the properties below triggering
119
- // observers that also rely on the loading state
120
- this.loading = this._shouldFetchData();
121
- // Reset size and internal loading state
122
114
  this.size = undefined;
123
-
124
115
  this.clearCache();
116
+ this.__keepOverlayOpened = false;
125
117
  }
126
118
  }
127
119
 
128
- /** @private */
120
+ /** @protected */
129
121
  _shouldFetchData() {
130
122
  if (!this.dataProvider) {
131
123
  return false;
@@ -136,23 +128,18 @@ export const ComboBoxDataProviderMixin = (superClass) =>
136
128
 
137
129
  /** @private */
138
130
  _ensureFirstPage(opened) {
131
+ if (!this._shouldFetchData()) {
132
+ return;
133
+ }
134
+
139
135
  if (opened && this._shouldLoadPage(0)) {
140
136
  this._loadPage(0);
141
137
  }
142
138
  }
143
139
 
144
- /** @private */
145
- _shouldSkipIndex(index, allowedIndexRange, currentScrollerPos) {
146
- return (
147
- currentScrollerPos !== 0 &&
148
- index >= currentScrollerPos - allowedIndexRange &&
149
- index <= currentScrollerPos + allowedIndexRange
150
- );
151
- }
152
-
153
140
  /** @private */
154
141
  _shouldLoadPage(page) {
155
- if (!this.filteredItems || this._forceNextRequest) {
142
+ if (this._forceNextRequest) {
156
143
  this._forceNextRequest = false;
157
144
  return true;
158
145
  }
@@ -60,7 +60,7 @@ export const ComboBoxItemMixin = (superClass) =>
60
60
  }
61
61
 
62
62
  static get observers() {
63
- return ['__rendererOrItemChanged(renderer, index, item.*, selected, focused)', '__updateLabel(label, renderer)'];
63
+ return ['__rendererOrItemChanged(renderer, index, item, selected, focused)', '__updateLabel(label, renderer)'];
64
64
  }
65
65
 
66
66
  static get observedAttributes() {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2015 - 2024 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
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
8
+ import type { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
9
+ import type { ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
10
+
11
+ export declare function ComboBoxLightMixin<TItem, T extends Constructor<HTMLElement>>(
12
+ base: T,
13
+ ): Constructor<ComboBoxDataProviderMixinClass<TItem>> &
14
+ Constructor<ComboBoxLightMixinClass> &
15
+ Constructor<ComboBoxMixinClass<TItem>> &
16
+ Constructor<ValidateMixinClass> &
17
+ T;
18
+
19
+ export declare class ComboBoxLightMixinClass {
20
+ /**
21
+ * Name of the two-way data-bindable property representing the
22
+ * value of the custom input field.
23
+ * @attr {string} attr-for-value
24
+ */
25
+ attrForValue: string;
26
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2015 - 2024 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { dashToCamelCase } from '@polymer/polymer/lib/utils/case-map.js';
7
+ import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
8
+ import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
9
+ import { ComboBoxDataProviderMixin } from './vaadin-combo-box-data-provider-mixin.js';
10
+ import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
11
+
12
+ /**
13
+ * @polymerMixin
14
+ * @mixes ComboBoxDataProviderMixin
15
+ * @mixes ComboBoxMixin
16
+ * @mixes ValidateMixin
17
+ */
18
+ export const ComboBoxLightMixin = (superClass) =>
19
+ class ComboBoxLightMixinClass extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixin(superClass))) {
20
+ static get properties() {
21
+ return {
22
+ /**
23
+ * Name of the two-way data-bindable property representing the
24
+ * value of the custom input field.
25
+ * @attr {string} attr-for-value
26
+ * @type {string}
27
+ */
28
+ attrForValue: {
29
+ type: String,
30
+ value: 'value',
31
+ },
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Used by `InputControlMixin` as a reference to the clear button element.
37
+ * @protected
38
+ * @return {!HTMLElement}
39
+ */
40
+ get clearElement() {
41
+ return this.querySelector('.clear-button');
42
+ }
43
+
44
+ /**
45
+ * Override this getter from `InputMixin` to allow using
46
+ * an arbitrary property name instead of `value`
47
+ * for accessing the input element's value.
48
+ *
49
+ * @protected
50
+ * @override
51
+ * @return {string}
52
+ */
53
+ get _inputElementValueProperty() {
54
+ return dashToCamelCase(this.attrForValue);
55
+ }
56
+
57
+ /**
58
+ * @protected
59
+ * @override
60
+ * @return {HTMLInputElement | undefined}
61
+ */
62
+ get _nativeInput() {
63
+ const input = this.inputElement;
64
+
65
+ if (input) {
66
+ // Support `<input class="input">`
67
+ if (input instanceof HTMLInputElement) {
68
+ return input;
69
+ }
70
+
71
+ // Support `<input>` in light DOM (e.g. `vaadin-text-field`)
72
+ const slottedInput = input.querySelector('input');
73
+ if (slottedInput) {
74
+ return slottedInput;
75
+ }
76
+
77
+ if (input.shadowRoot) {
78
+ // Support `<input>` in Shadow DOM (e.g. `mwc-textfield`)
79
+ const shadowInput = input.shadowRoot.querySelector('input');
80
+ if (shadowInput) {
81
+ return shadowInput;
82
+ }
83
+ }
84
+ }
85
+
86
+ return undefined;
87
+ }
88
+
89
+ /** @protected */
90
+ ready() {
91
+ super.ready();
92
+
93
+ this._toggleElement = this.querySelector('.toggle-button');
94
+
95
+ // Wait until the slotted input DOM is ready
96
+ afterNextRender(this, () => {
97
+ this._setInputElement(this.querySelector('vaadin-text-field,.input'));
98
+ this._revertInputValue();
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Returns true if the current input value satisfies all constraints (if any).
104
+ * @return {boolean}
105
+ */
106
+ checkValidity() {
107
+ if (this.inputElement && this.inputElement.validate) {
108
+ return this.inputElement.validate();
109
+ }
110
+ return super.checkValidity();
111
+ }
112
+
113
+ /**
114
+ * @protected
115
+ * @override
116
+ */
117
+ _isClearButton(event) {
118
+ return (
119
+ super._isClearButton(event) ||
120
+ (event.type === 'input' && !event.isTrusted) || // Fake input event dispatched by clear button
121
+ event.composedPath()[0].getAttribute('part') === 'clear-button'
122
+ );
123
+ }
124
+
125
+ /**
126
+ * @protected
127
+ * @override
128
+ */
129
+ _shouldRemoveFocus(event) {
130
+ const isBlurringControlButtons = event.target === this._toggleElement || event.target === this.clearElement;
131
+ const isFocusingInputElement = event.relatedTarget && event.relatedTarget === this._nativeInput;
132
+
133
+ // prevent closing the overlay when moving focus from clear or toggle buttons to the internal input
134
+ if (isBlurringControlButtons && isFocusingInputElement) {
135
+ return false;
136
+ }
137
+
138
+ return super._shouldRemoveFocus(event);
139
+ }
140
+ };
@@ -11,6 +11,7 @@ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.j
11
11
  import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
12
  import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
13
13
  import type { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
14
+ import type { ComboBoxLightMixinClass } from './vaadin-combo-box-light-mixin.js';
14
15
  import type { ComboBoxDefaultItem, ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
15
16
  export {
16
17
  ComboBoxDataProvider,
@@ -126,13 +127,6 @@ export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
126
127
  * @fires {CustomEvent} validated - Fired whenever the field is validated.
127
128
  */
128
129
  declare class ComboBoxLight<TItem = ComboBoxDefaultItem> extends HTMLElement {
129
- /**
130
- * Name of the two-way data-bindable property representing the
131
- * value of the custom input field.
132
- * @attr {string} attr-for-value
133
- */
134
- attrForValue: string;
135
-
136
130
  addEventListener<K extends keyof ComboBoxLightEventMap<TItem>>(
137
131
  type: K,
138
132
  listener: (this: ComboBoxLight<TItem>, ev: ComboBoxLightEventMap<TItem>[K]) => void,
@@ -148,6 +142,7 @@ declare class ComboBoxLight<TItem = ComboBoxDefaultItem> extends HTMLElement {
148
142
 
149
143
  interface ComboBoxLight<TItem = ComboBoxDefaultItem>
150
144
  extends ComboBoxDataProviderMixinClass<TItem>,
145
+ ComboBoxLightMixinClass,
151
146
  ComboBoxMixinClass<TItem>,
152
147
  KeyboardMixinClass,
153
148
  InputMixinClass,
@@ -6,14 +6,10 @@
6
6
  import './vaadin-combo-box-item.js';
7
7
  import './vaadin-combo-box-overlay.js';
8
8
  import './vaadin-combo-box-scroller.js';
9
- import { dashToCamelCase } from '@polymer/polymer/lib/utils/case-map.js';
10
- import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
11
9
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
12
10
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
13
- import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
14
11
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
15
- import { ComboBoxDataProviderMixin } from './vaadin-combo-box-data-provider-mixin.js';
16
- import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
12
+ import { ComboBoxLightMixin } from './vaadin-combo-box-light-mixin.js';
17
13
 
18
14
  /**
19
15
  * `<vaadin-combo-box-light>` is a customizable version of the `<vaadin-combo-box>` providing
@@ -63,12 +59,10 @@ import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
63
59
  *
64
60
  * @customElement
65
61
  * @extends HTMLElement
66
- * @mixes ComboBoxDataProviderMixin
67
- * @mixes ComboBoxMixin
62
+ * @mixes ComboBoxLightMixin
68
63
  * @mixes ThemableMixin
69
- * @mixes ValidateMixin
70
64
  */
71
- class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixin(ThemableMixin(PolymerElement)))) {
65
+ class ComboBoxLight extends ComboBoxLightMixin(ThemableMixin(PolymerElement)) {
72
66
  static get is() {
73
67
  return 'vaadin-combo-box-light';
74
68
  }
@@ -94,124 +88,6 @@ class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixi
94
88
  ></vaadin-combo-box-overlay>
95
89
  `;
96
90
  }
97
-
98
- static get properties() {
99
- return {
100
- /**
101
- * Name of the two-way data-bindable property representing the
102
- * value of the custom input field.
103
- * @attr {string} attr-for-value
104
- * @type {string}
105
- */
106
- attrForValue: {
107
- type: String,
108
- value: 'value',
109
- },
110
- };
111
- }
112
-
113
- /**
114
- * Used by `InputControlMixin` as a reference to the clear button element.
115
- * @protected
116
- * @return {!HTMLElement}
117
- */
118
- get clearElement() {
119
- return this.querySelector('.clear-button');
120
- }
121
-
122
- /**
123
- * Override this getter from `InputMixin` to allow using
124
- * an arbitrary property name instead of `value`
125
- * for accessing the input element's value.
126
- *
127
- * @protected
128
- * @override
129
- * @return {string}
130
- */
131
- get _inputElementValueProperty() {
132
- return dashToCamelCase(this.attrForValue);
133
- }
134
-
135
- /**
136
- * @protected
137
- * @override
138
- * @return {HTMLInputElement | undefined}
139
- */
140
- get _nativeInput() {
141
- const input = this.inputElement;
142
-
143
- if (input) {
144
- // Support `<input class="input">`
145
- if (input instanceof HTMLInputElement) {
146
- return input;
147
- }
148
-
149
- // Support `<input>` in light DOM (e.g. `vaadin-text-field`)
150
- const slottedInput = input.querySelector('input');
151
- if (slottedInput) {
152
- return slottedInput;
153
- }
154
-
155
- if (input.shadowRoot) {
156
- // Support `<input>` in Shadow DOM (e.g. `mwc-textfield`)
157
- const shadowInput = input.shadowRoot.querySelector('input');
158
- if (shadowInput) {
159
- return shadowInput;
160
- }
161
- }
162
- }
163
-
164
- return undefined;
165
- }
166
-
167
- /** @protected */
168
- ready() {
169
- super.ready();
170
-
171
- this._toggleElement = this.querySelector('.toggle-button');
172
-
173
- // Wait until the slotted input DOM is ready
174
- afterNextRender(this, () => {
175
- this._setInputElement(this.querySelector('vaadin-text-field,.input'));
176
- this._revertInputValue();
177
- });
178
- }
179
-
180
- /**
181
- * Returns true if the current input value satisfies all constraints (if any).
182
- * @return {boolean}
183
- */
184
- checkValidity() {
185
- if (this.inputElement && this.inputElement.validate) {
186
- return this.inputElement.validate();
187
- }
188
- return super.checkValidity();
189
- }
190
-
191
- /** @protected */
192
- _isClearButton(event) {
193
- return (
194
- super._isClearButton(event) ||
195
- (event.type === 'input' && !event.isTrusted) || // Fake input event dispatched by clear button
196
- event.composedPath()[0].getAttribute('part') === 'clear-button'
197
- );
198
- }
199
-
200
- /**
201
- * @protected
202
- * @override
203
- */
204
- _shouldRemoveFocus(event) {
205
- const isBlurringControlButtons = event.target === this._toggleElement || event.target === this.clearElement;
206
- const isFocusingInputElement = event.relatedTarget && event.relatedTarget === this._nativeInput;
207
-
208
- // prevent closing the overlay when moving focus from clear or toggle buttons to the internal input
209
- if (isBlurringControlButtons && isFocusingInputElement) {
210
- return false;
211
- }
212
-
213
- return super._shouldRemoveFocus(event);
214
- }
215
91
  }
216
92
 
217
93
  defineCustomElement(ComboBoxLight);