@vaadin/combo-box 23.2.0-alpha1 → 23.2.0-alpha4
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 +20 -14
- package/src/lit/renderer-directives.d.ts +3 -3
- package/src/vaadin-combo-box-data-provider-mixin.d.ts +3 -3
- package/src/vaadin-combo-box-data-provider-mixin.js +29 -31
- package/src/vaadin-combo-box-light.d.ts +19 -10
- package/src/vaadin-combo-box-light.js +4 -1
- package/src/vaadin-combo-box-mixin.d.ts +8 -24
- package/src/vaadin-combo-box-mixin.js +57 -67
- package/src/vaadin-combo-box-scroller.js +1 -1
- package/src/vaadin-combo-box.d.ts +29 -20
- package/src/vaadin-combo-box.js +2 -0
- package/web-types.json +1054 -0
- package/web-types.lit.json +496 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/combo-box",
|
|
3
|
-
"version": "23.2.0-
|
|
3
|
+
"version": "23.2.0-alpha4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"src",
|
|
25
25
|
"theme",
|
|
26
26
|
"vaadin-*.d.ts",
|
|
27
|
-
"vaadin-*.js"
|
|
27
|
+
"vaadin-*.js",
|
|
28
|
+
"web-types.json",
|
|
29
|
+
"web-types.lit.json"
|
|
28
30
|
],
|
|
29
31
|
"keywords": [
|
|
30
32
|
"Vaadin",
|
|
@@ -36,23 +38,27 @@
|
|
|
36
38
|
"dependencies": {
|
|
37
39
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
38
40
|
"@polymer/polymer": "^3.0.0",
|
|
39
|
-
"@vaadin/component-base": "23.2.0-
|
|
40
|
-
"@vaadin/field-base": "23.2.0-
|
|
41
|
-
"@vaadin/input-container": "23.2.0-
|
|
42
|
-
"@vaadin/item": "23.2.0-
|
|
43
|
-
"@vaadin/lit-renderer": "23.2.0-
|
|
44
|
-
"@vaadin/vaadin-lumo-styles": "23.2.0-
|
|
45
|
-
"@vaadin/vaadin-material-styles": "23.2.0-
|
|
46
|
-
"@vaadin/vaadin-overlay": "23.2.0-
|
|
47
|
-
"@vaadin/vaadin-themable-mixin": "23.2.0-
|
|
41
|
+
"@vaadin/component-base": "23.2.0-alpha4",
|
|
42
|
+
"@vaadin/field-base": "23.2.0-alpha4",
|
|
43
|
+
"@vaadin/input-container": "23.2.0-alpha4",
|
|
44
|
+
"@vaadin/item": "23.2.0-alpha4",
|
|
45
|
+
"@vaadin/lit-renderer": "23.2.0-alpha4",
|
|
46
|
+
"@vaadin/vaadin-lumo-styles": "23.2.0-alpha4",
|
|
47
|
+
"@vaadin/vaadin-material-styles": "23.2.0-alpha4",
|
|
48
|
+
"@vaadin/vaadin-overlay": "23.2.0-alpha4",
|
|
49
|
+
"@vaadin/vaadin-themable-mixin": "23.2.0-alpha4"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
50
52
|
"@esm-bundle/chai": "^4.3.4",
|
|
51
|
-
"@vaadin/polymer-legacy-adapter": "23.2.0-
|
|
53
|
+
"@vaadin/polymer-legacy-adapter": "23.2.0-alpha4",
|
|
52
54
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
53
|
-
"@vaadin/text-field": "23.2.0-
|
|
55
|
+
"@vaadin/text-field": "23.2.0-alpha4",
|
|
54
56
|
"lit": "^2.0.0",
|
|
55
57
|
"sinon": "^13.0.2"
|
|
56
58
|
},
|
|
57
|
-
"
|
|
59
|
+
"web-types": [
|
|
60
|
+
"web-types.json",
|
|
61
|
+
"web-types.lit.json"
|
|
62
|
+
],
|
|
63
|
+
"gitHead": "cbf5f1d0f38ac9b81c65cf9ef5660182e176e598"
|
|
58
64
|
}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Copyright (c) 2017 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { TemplateResult } from 'lit';
|
|
7
|
-
import { DirectiveResult } from 'lit/directive.js';
|
|
6
|
+
import type { TemplateResult } from 'lit';
|
|
7
|
+
import type { DirectiveResult } from 'lit/directive.js';
|
|
8
8
|
import { LitRendererDirective } from '@vaadin/lit-renderer';
|
|
9
|
-
import { ComboBox, ComboBoxItemModel } from '../vaadin-combo-box.js';
|
|
9
|
+
import type { ComboBox, ComboBoxItemModel } from '../vaadin-combo-box.js';
|
|
10
10
|
|
|
11
11
|
export type ComboBoxLitRenderer<TItem> = (
|
|
12
12
|
item: TItem,
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
6
|
+
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
7
|
|
|
8
|
-
export type ComboBoxDataProviderCallback<TItem> = (items: TItem[], size
|
|
8
|
+
export type ComboBoxDataProviderCallback<TItem> = (items: TItem[], size?: number) => void;
|
|
9
9
|
|
|
10
10
|
export interface ComboBoxDataProviderParams {
|
|
11
11
|
page: number;
|
|
@@ -20,7 +20,7 @@ export type ComboBoxDataProvider<TItem> = (
|
|
|
20
20
|
|
|
21
21
|
export declare function ComboBoxDataProviderMixin<TItem, T extends Constructor<HTMLElement>>(
|
|
22
22
|
base: T,
|
|
23
|
-
):
|
|
23
|
+
): Constructor<ComboBoxDataProviderMixinClass<TItem>> & T;
|
|
24
24
|
|
|
25
25
|
export declare class ComboBoxDataProviderMixinClass<TItem> {
|
|
26
26
|
/**
|
|
@@ -62,13 +62,17 @@ export const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
62
62
|
__placeHolder: {
|
|
63
63
|
value: new ComboBoxPlaceholder(),
|
|
64
64
|
},
|
|
65
|
+
|
|
66
|
+
/** @private */
|
|
67
|
+
__previousDataProviderFilter: {
|
|
68
|
+
type: String,
|
|
69
|
+
},
|
|
65
70
|
};
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
static get observers() {
|
|
69
74
|
return [
|
|
70
|
-
'_dataProviderFilterChanged(filter
|
|
71
|
-
'_dataProviderClearFilter(dataProvider, opened, value)',
|
|
75
|
+
'_dataProviderFilterChanged(filter)',
|
|
72
76
|
'_warnDataProviderValue(dataProvider, value)',
|
|
73
77
|
'_ensureFirstPage(opened)',
|
|
74
78
|
];
|
|
@@ -77,7 +81,6 @@ export const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
77
81
|
/** @protected */
|
|
78
82
|
ready() {
|
|
79
83
|
super.ready();
|
|
80
|
-
this.clearCache();
|
|
81
84
|
this._scroller.addEventListener('index-requested', (e) => {
|
|
82
85
|
const index = e.detail.index;
|
|
83
86
|
const currentScrollerPos = e.detail.currentScrollerPos;
|
|
@@ -101,38 +104,25 @@ export const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
/** @private */
|
|
104
|
-
_dataProviderFilterChanged() {
|
|
105
|
-
if (
|
|
107
|
+
_dataProviderFilterChanged(filter) {
|
|
108
|
+
if (this.__previousDataProviderFilter === undefined && filter === '') {
|
|
109
|
+
this.__previousDataProviderFilter = filter;
|
|
106
110
|
return;
|
|
107
111
|
}
|
|
108
112
|
|
|
109
|
-
this.
|
|
110
|
-
|
|
113
|
+
if (this.__previousDataProviderFilter !== filter) {
|
|
114
|
+
this.__previousDataProviderFilter = filter;
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
116
|
+
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
|
+
this.size = undefined;
|
|
120
123
|
|
|
121
|
-
|
|
122
|
-
_refreshData(clearFilter) {
|
|
123
|
-
// Immediately mark as loading if this refresh leads to re-fetching pages
|
|
124
|
-
// This prevents some issues with the properties below triggering
|
|
125
|
-
// observers that also rely on the loading state
|
|
126
|
-
this.loading = this._shouldFetchData();
|
|
127
|
-
// Reset size and internal loading state
|
|
128
|
-
this.size = undefined;
|
|
129
|
-
this._pendingRequests = {};
|
|
130
|
-
// Clear filter if requested
|
|
131
|
-
if (clearFilter) {
|
|
132
|
-
this.filter = '';
|
|
124
|
+
this.clearCache();
|
|
133
125
|
}
|
|
134
|
-
// Clear cached pages, and reload current page if we need the data
|
|
135
|
-
this.clearCache();
|
|
136
126
|
}
|
|
137
127
|
|
|
138
128
|
/** @private */
|
|
@@ -196,10 +186,13 @@ export const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
196
186
|
filteredItems.splice(params.page * params.pageSize, items.length, ...items);
|
|
197
187
|
this.filteredItems = filteredItems;
|
|
198
188
|
|
|
199
|
-
if (!this.opened && !this.
|
|
189
|
+
if (!this.opened && !this._isInputFocused()) {
|
|
200
190
|
this._commitValue();
|
|
201
191
|
}
|
|
202
|
-
|
|
192
|
+
|
|
193
|
+
if (size !== undefined) {
|
|
194
|
+
this.size = size;
|
|
195
|
+
}
|
|
203
196
|
|
|
204
197
|
delete this._pendingRequests[page];
|
|
205
198
|
|
|
@@ -229,13 +222,16 @@ export const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
229
222
|
if (!this.dataProvider) {
|
|
230
223
|
return;
|
|
231
224
|
}
|
|
225
|
+
|
|
232
226
|
this._pendingRequests = {};
|
|
233
227
|
const filteredItems = [];
|
|
234
228
|
for (let i = 0; i < (this.size || 0); i++) {
|
|
235
229
|
filteredItems.push(this.__placeHolder);
|
|
236
230
|
}
|
|
237
231
|
this.filteredItems = filteredItems;
|
|
232
|
+
|
|
238
233
|
if (this._shouldFetchData()) {
|
|
234
|
+
this._forceNextRequest = false;
|
|
239
235
|
this._loadPage(0);
|
|
240
236
|
} else {
|
|
241
237
|
this._forceNextRequest = true;
|
|
@@ -269,6 +265,8 @@ export const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
269
265
|
this._ensureItemsOrDataProvider(() => {
|
|
270
266
|
this.dataProvider = oldDataProvider;
|
|
271
267
|
});
|
|
268
|
+
|
|
269
|
+
this.clearCache();
|
|
272
270
|
}
|
|
273
271
|
|
|
274
272
|
/** @private */
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
|
|
7
|
-
import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
8
|
-
import { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { ComboBoxDefaultItem } from './vaadin-combo-box-mixin.js';
|
|
6
|
+
import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
|
|
7
|
+
import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
8
|
+
import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
|
|
9
|
+
import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
|
|
10
|
+
import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
11
|
+
import type { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
|
|
12
|
+
import type { ComboBoxDefaultItem, ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
|
|
13
13
|
export {
|
|
14
14
|
ComboBoxDataProvider,
|
|
15
15
|
ComboBoxDataProviderCallback,
|
|
@@ -54,6 +54,11 @@ export type ComboBoxLightFilterChangedEvent = CustomEvent<{ value: string }>;
|
|
|
54
54
|
*/
|
|
55
55
|
export type ComboBoxLightSelectedItemChangedEvent<TItem> = CustomEvent<{ value: TItem | null | undefined }>;
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Fired whenever the field is validated.
|
|
59
|
+
*/
|
|
60
|
+
export type ComboBoxLightValidatedEvent = CustomEvent<{ valid: boolean }>;
|
|
61
|
+
|
|
57
62
|
export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
|
|
58
63
|
change: ComboBoxLightChangeEvent<TItem>;
|
|
59
64
|
|
|
@@ -68,6 +73,8 @@ export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
|
|
|
68
73
|
'value-changed': ComboBoxLightValueChangedEvent;
|
|
69
74
|
|
|
70
75
|
'selected-item-changed': ComboBoxLightSelectedItemChangedEvent<TItem>;
|
|
76
|
+
|
|
77
|
+
validated: ComboBoxLightValidatedEvent;
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
/**
|
|
@@ -114,6 +121,7 @@ export interface ComboBoxLightEventMap<TItem> extends HTMLElementEventMap {
|
|
|
114
121
|
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
|
|
115
122
|
* @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
|
|
116
123
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
124
|
+
* @fires {CustomEvent} validated - Fired whenever the field is validated.
|
|
117
125
|
*/
|
|
118
126
|
declare class ComboBoxLight<TItem = ComboBoxDefaultItem> extends HTMLElement {
|
|
119
127
|
/**
|
|
@@ -126,13 +134,13 @@ declare class ComboBoxLight<TItem = ComboBoxDefaultItem> extends HTMLElement {
|
|
|
126
134
|
addEventListener<K extends keyof ComboBoxLightEventMap<TItem>>(
|
|
127
135
|
type: K,
|
|
128
136
|
listener: (this: ComboBoxLight<TItem>, ev: ComboBoxLightEventMap<TItem>[K]) => void,
|
|
129
|
-
options?:
|
|
137
|
+
options?: AddEventListenerOptions | boolean,
|
|
130
138
|
): void;
|
|
131
139
|
|
|
132
140
|
removeEventListener<K extends keyof ComboBoxLightEventMap<TItem>>(
|
|
133
141
|
type: K,
|
|
134
142
|
listener: (this: ComboBoxLight<TItem>, ev: ComboBoxLightEventMap<TItem>[K]) => void,
|
|
135
|
-
options?:
|
|
143
|
+
options?: EventListenerOptions | boolean,
|
|
136
144
|
): void;
|
|
137
145
|
}
|
|
138
146
|
|
|
@@ -142,7 +150,8 @@ interface ComboBoxLight<TItem = ComboBoxDefaultItem>
|
|
|
142
150
|
KeyboardMixinClass,
|
|
143
151
|
InputMixinClass,
|
|
144
152
|
DisabledMixinClass,
|
|
145
|
-
ThemableMixinClass
|
|
153
|
+
ThemableMixinClass,
|
|
154
|
+
ValidateMixinClass {}
|
|
146
155
|
|
|
147
156
|
declare global {
|
|
148
157
|
interface HTMLElementTagNameMap {
|
|
@@ -8,6 +8,7 @@ import './vaadin-combo-box-overlay.js';
|
|
|
8
8
|
import './vaadin-combo-box-scroller.js';
|
|
9
9
|
import { dashToCamelCase } from '@polymer/polymer/lib/utils/case-map.js';
|
|
10
10
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
11
|
+
import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
|
|
11
12
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
12
13
|
import { ComboBoxDataProviderMixin } from './vaadin-combo-box-data-provider-mixin.js';
|
|
13
14
|
import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
|
|
@@ -56,13 +57,15 @@ import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
|
|
|
56
57
|
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
|
|
57
58
|
* @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
|
|
58
59
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
60
|
+
* @fires {CustomEvent} validated - Fired whenever the field is validated.
|
|
59
61
|
*
|
|
60
62
|
* @extends HTMLElement
|
|
61
63
|
* @mixes ComboBoxDataProviderMixin
|
|
62
64
|
* @mixes ComboBoxMixin
|
|
63
65
|
* @mixes ThemableMixin
|
|
66
|
+
* @mixes ValidateMixin
|
|
64
67
|
*/
|
|
65
|
-
class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ThemableMixin(PolymerElement))) {
|
|
68
|
+
class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixin(ThemableMixin(PolymerElement)))) {
|
|
66
69
|
static get is() {
|
|
67
70
|
return 'vaadin-combo-box-light';
|
|
68
71
|
}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
-
import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
|
|
8
|
-
import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
9
|
-
import { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
|
|
10
|
-
import { ComboBox } from './vaadin-combo-box.js';
|
|
6
|
+
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
+
import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
|
|
8
|
+
import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
9
|
+
import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
|
|
10
|
+
import type { ComboBox } from './vaadin-combo-box.js';
|
|
11
11
|
|
|
12
12
|
export type ComboBoxDefaultItem = any;
|
|
13
13
|
|
|
@@ -24,11 +24,11 @@ export type ComboBoxRenderer<TItem> = (
|
|
|
24
24
|
|
|
25
25
|
export declare function ComboBoxMixin<TItem, T extends Constructor<HTMLElement>>(
|
|
26
26
|
base: T,
|
|
27
|
-
):
|
|
28
|
-
Constructor<ComboBoxMixinClass<TItem>> &
|
|
27
|
+
): Constructor<ComboBoxMixinClass<TItem>> &
|
|
29
28
|
Constructor<DisabledMixinClass> &
|
|
30
29
|
Constructor<InputMixinClass> &
|
|
31
|
-
Constructor<KeyboardMixinClass
|
|
30
|
+
Constructor<KeyboardMixinClass> &
|
|
31
|
+
T;
|
|
32
32
|
|
|
33
33
|
export declare class ComboBoxMixinClass<TItem> {
|
|
34
34
|
/**
|
|
@@ -138,11 +138,6 @@ export declare class ComboBoxMixinClass<TItem> {
|
|
|
138
138
|
*/
|
|
139
139
|
itemIdPath: string | null | undefined;
|
|
140
140
|
|
|
141
|
-
/**
|
|
142
|
-
* Set to true if the value is invalid.
|
|
143
|
-
*/
|
|
144
|
-
invalid: boolean;
|
|
145
|
-
|
|
146
141
|
protected readonly _propertyForValue: string;
|
|
147
142
|
|
|
148
143
|
protected _inputElementValue: string | undefined;
|
|
@@ -170,16 +165,5 @@ export declare class ComboBoxMixinClass<TItem> {
|
|
|
170
165
|
*/
|
|
171
166
|
close(): void;
|
|
172
167
|
|
|
173
|
-
/**
|
|
174
|
-
* Returns true if `value` is valid, and sets the `invalid` flag appropriately.
|
|
175
|
-
*/
|
|
176
|
-
validate(): boolean;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Returns true if the current input value satisfies all constraints (if any).
|
|
180
|
-
* You can override this method for custom validations.
|
|
181
|
-
*/
|
|
182
|
-
checkValidity(): boolean;
|
|
183
|
-
|
|
184
168
|
protected _revertInputValue(): void;
|
|
185
169
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { isTouch } from '@vaadin/component-base/src/browser-utils.js';
|
|
7
7
|
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
8
8
|
import { DisabledMixin } from '@vaadin/component-base/src/disabled-mixin.js';
|
|
9
|
+
import { isElementFocused } from '@vaadin/component-base/src/focus-utils.js';
|
|
9
10
|
import { KeyboardMixin } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
10
11
|
import { processTemplates } from '@vaadin/component-base/src/templates.js';
|
|
11
12
|
import { InputMixin } from '@vaadin/field-base/src/input-mixin.js';
|
|
@@ -236,7 +237,6 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
236
237
|
|
|
237
238
|
static get observers() {
|
|
238
239
|
return [
|
|
239
|
-
'_filterChanged(filter, itemValuePath, itemLabelPath)',
|
|
240
240
|
'_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
|
|
241
241
|
'_openedOrItemsChanged(opened, filteredItems, loading)',
|
|
242
242
|
'_updateScroller(_scroller, filteredItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
|
|
@@ -382,6 +382,25 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
382
382
|
this.opened = false;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Override Polymer lifecycle callback to handle `filter` property change after
|
|
387
|
+
* the observer for `opened` property is triggered. This is needed when opening
|
|
388
|
+
* combo-box on user input to ensure the focused index is set correctly.
|
|
389
|
+
*
|
|
390
|
+
* @param {!Object} currentProps Current accessor values
|
|
391
|
+
* @param {?Object} changedProps Properties changed since the last call
|
|
392
|
+
* @param {?Object} oldProps Previous values for each changed property
|
|
393
|
+
* @protected
|
|
394
|
+
* @override
|
|
395
|
+
*/
|
|
396
|
+
_propertiesChanged(currentProps, changedProps, oldProps) {
|
|
397
|
+
super._propertiesChanged(currentProps, changedProps, oldProps);
|
|
398
|
+
|
|
399
|
+
if (changedProps.filter !== undefined) {
|
|
400
|
+
this._filterChanged(changedProps.filter);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
385
404
|
/** @private */
|
|
386
405
|
_initOverlay() {
|
|
387
406
|
const overlay = this.$.overlay;
|
|
@@ -395,11 +414,6 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
395
414
|
// Prevent blurring the input when clicking inside the overlay
|
|
396
415
|
overlay.addEventListener('mousedown', (e) => e.preventDefault());
|
|
397
416
|
|
|
398
|
-
// Preventing the default modal behavior of the overlay on input click
|
|
399
|
-
overlay.addEventListener('vaadin-overlay-outside-click', (e) => {
|
|
400
|
-
e.preventDefault();
|
|
401
|
-
});
|
|
402
|
-
|
|
403
417
|
// Manual two-way binding for the overlay "opened" property
|
|
404
418
|
overlay.addEventListener('opened-changed', (e) => {
|
|
405
419
|
this._overlayOpened = e.detail.value;
|
|
@@ -442,6 +456,11 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
442
456
|
// eslint-disable-next-line max-params
|
|
443
457
|
_updateScroller(scroller, items, opened, loading, selectedItem, itemIdPath, focusedIndex, renderer, theme) {
|
|
444
458
|
if (scroller) {
|
|
459
|
+
if (opened) {
|
|
460
|
+
scroller.style.maxHeight =
|
|
461
|
+
getComputedStyle(this).getPropertyValue(`--${this._tagNamePrefix}-overlay-max-height`) || '65vh';
|
|
462
|
+
}
|
|
463
|
+
|
|
445
464
|
scroller.setProperties({
|
|
446
465
|
items: opened ? items : [],
|
|
447
466
|
opened,
|
|
@@ -488,6 +507,11 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
488
507
|
this._updateActiveDescendant(index);
|
|
489
508
|
}
|
|
490
509
|
|
|
510
|
+
/** @protected */
|
|
511
|
+
_isInputFocused() {
|
|
512
|
+
return this.inputElement && isElementFocused(this.inputElement);
|
|
513
|
+
}
|
|
514
|
+
|
|
491
515
|
/** @private */
|
|
492
516
|
_updateActiveDescendant(index) {
|
|
493
517
|
const input = this.inputElement;
|
|
@@ -514,14 +538,14 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
514
538
|
this._openedWithFocusRing = this.hasAttribute('focus-ring');
|
|
515
539
|
// For touch devices, we don't want to popup virtual keyboard
|
|
516
540
|
// unless input element is explicitly focused by the user.
|
|
517
|
-
if (!this.
|
|
541
|
+
if (!this._isInputFocused() && !isTouch) {
|
|
518
542
|
this.focus();
|
|
519
543
|
}
|
|
520
544
|
|
|
521
545
|
this.$.overlay.restoreFocusOnClose = true;
|
|
522
546
|
} else {
|
|
523
547
|
this._onClosed();
|
|
524
|
-
if (this._openedWithFocusRing && this.
|
|
548
|
+
if (this._openedWithFocusRing && this._isInputFocused()) {
|
|
525
549
|
this.setAttribute('focus-ring', '');
|
|
526
550
|
}
|
|
527
551
|
}
|
|
@@ -595,8 +619,6 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
595
619
|
|
|
596
620
|
/** @private */
|
|
597
621
|
_onClick(e) {
|
|
598
|
-
this._closeOnBlurIsPrevented = true;
|
|
599
|
-
|
|
600
622
|
const path = e.composedPath();
|
|
601
623
|
|
|
602
624
|
if (this._isClearButton(e)) {
|
|
@@ -606,8 +628,6 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
606
628
|
} else {
|
|
607
629
|
this._onHostClick(e);
|
|
608
630
|
}
|
|
609
|
-
|
|
610
|
-
this._closeOnBlurIsPrevented = false;
|
|
611
631
|
}
|
|
612
632
|
|
|
613
633
|
/**
|
|
@@ -623,16 +643,12 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
623
643
|
if (e.key === 'Tab') {
|
|
624
644
|
this.$.overlay.restoreFocusOnClose = false;
|
|
625
645
|
} else if (e.key === 'ArrowDown') {
|
|
626
|
-
this._closeOnBlurIsPrevented = true;
|
|
627
646
|
this._onArrowDown();
|
|
628
|
-
this._closeOnBlurIsPrevented = false;
|
|
629
647
|
|
|
630
648
|
// Prevent caret from moving
|
|
631
649
|
e.preventDefault();
|
|
632
650
|
} else if (e.key === 'ArrowUp') {
|
|
633
|
-
this._closeOnBlurIsPrevented = true;
|
|
634
651
|
this._onArrowUp();
|
|
635
|
-
this._closeOnBlurIsPrevented = false;
|
|
636
652
|
|
|
637
653
|
// Prevent caret from moving
|
|
638
654
|
e.preventDefault();
|
|
@@ -703,8 +719,7 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
703
719
|
// and there's no need to modify the selection range if the input isn't focused anyway.
|
|
704
720
|
// This affects Safari. When the overlay is open, and then hitting tab, browser should focus
|
|
705
721
|
// the next focusable element instead of the combo-box itself.
|
|
706
|
-
|
|
707
|
-
if (this.hasAttribute('focused')) {
|
|
722
|
+
if (this._isInputFocused() && this.inputElement.setSelectionRange) {
|
|
708
723
|
this.inputElement.setSelectionRange(start, end);
|
|
709
724
|
}
|
|
710
725
|
}
|
|
@@ -814,7 +829,7 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
814
829
|
toggleElement.addEventListener('mousedown', (e) => e.preventDefault());
|
|
815
830
|
// Unfocus previously focused element if focus is not inside combo box (on touch devices)
|
|
816
831
|
toggleElement.addEventListener('click', () => {
|
|
817
|
-
if (isTouch && !this.
|
|
832
|
+
if (isTouch && !this._isInputFocused()) {
|
|
818
833
|
document.activeElement.blur();
|
|
819
834
|
}
|
|
820
835
|
});
|
|
@@ -849,10 +864,6 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
849
864
|
_onOpened() {
|
|
850
865
|
// Defer scroll position adjustment to improve performance.
|
|
851
866
|
requestAnimationFrame(() => {
|
|
852
|
-
// When opened is set as attribute, this logic needs to be delayed until scroller is created.
|
|
853
|
-
this._scroller.style.maxHeight =
|
|
854
|
-
getComputedStyle(this).getPropertyValue(`--${this._tagNamePrefix}-overlay-max-height`) || '65vh';
|
|
855
|
-
|
|
856
867
|
this._scrollIntoView(this._focusedIndex);
|
|
857
868
|
|
|
858
869
|
// Set attribute after the items are rendered when overlay is opened for the first time.
|
|
@@ -925,9 +936,7 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
925
936
|
|
|
926
937
|
this._clearSelectionRange();
|
|
927
938
|
|
|
928
|
-
|
|
929
|
-
this.filter = '';
|
|
930
|
-
}
|
|
939
|
+
this.filter = '';
|
|
931
940
|
}
|
|
932
941
|
|
|
933
942
|
/**
|
|
@@ -945,19 +954,27 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
945
954
|
* @override
|
|
946
955
|
*/
|
|
947
956
|
_onInput(event) {
|
|
948
|
-
|
|
949
|
-
this.open();
|
|
950
|
-
}
|
|
957
|
+
const filter = this._inputElementValue;
|
|
951
958
|
|
|
952
|
-
|
|
953
|
-
|
|
959
|
+
// When opening dropdown on user input, both `opened` and `filter` properties are set.
|
|
960
|
+
// Perform a batched property update instead of relying on sync property observers.
|
|
961
|
+
// This is necessary to avoid an extra data-provider request for loading first page.
|
|
962
|
+
const props = {};
|
|
963
|
+
|
|
964
|
+
if (this.filter === filter) {
|
|
954
965
|
// Filter and input value might get out of sync, while keyboard navigating for example.
|
|
955
966
|
// Afterwards, input value might be changed to the same value as used in filtering.
|
|
956
967
|
// In situation like these, we need to make sure all the filter changes handlers are run.
|
|
957
|
-
this._filterChanged(this.filter
|
|
968
|
+
this._filterChanged(this.filter);
|
|
958
969
|
} else {
|
|
959
|
-
|
|
970
|
+
props.filter = filter;
|
|
960
971
|
}
|
|
972
|
+
|
|
973
|
+
if (!this.opened && !this._isClearButton(event) && !this.autoOpenDisabled) {
|
|
974
|
+
props.opened = true;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
this.setProperties(props);
|
|
961
978
|
}
|
|
962
979
|
|
|
963
980
|
/**
|
|
@@ -980,11 +997,7 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
980
997
|
}
|
|
981
998
|
|
|
982
999
|
/** @private */
|
|
983
|
-
_filterChanged(filter
|
|
984
|
-
if (filter === undefined) {
|
|
985
|
-
return;
|
|
986
|
-
}
|
|
987
|
-
|
|
1000
|
+
_filterChanged(filter) {
|
|
988
1001
|
// Scroll to the top of the list whenever the filter changes.
|
|
989
1002
|
this._scrollIntoView(0);
|
|
990
1003
|
|
|
@@ -1063,14 +1076,11 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
1063
1076
|
}
|
|
1064
1077
|
|
|
1065
1078
|
if (isValidValue(value)) {
|
|
1066
|
-
let item;
|
|
1067
1079
|
if (this._getItemValue(this.selectedItem) !== value) {
|
|
1068
1080
|
this._selectItemForValue(value);
|
|
1069
|
-
} else {
|
|
1070
|
-
item = this.selectedItem;
|
|
1071
1081
|
}
|
|
1072
1082
|
|
|
1073
|
-
if (!
|
|
1083
|
+
if (!this.selectedItem && this.allowCustomValue) {
|
|
1074
1084
|
this._inputElementValue = value;
|
|
1075
1085
|
}
|
|
1076
1086
|
|
|
@@ -1078,6 +1088,9 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
1078
1088
|
} else {
|
|
1079
1089
|
this.selectedItem = null;
|
|
1080
1090
|
}
|
|
1091
|
+
|
|
1092
|
+
this.filter = '';
|
|
1093
|
+
|
|
1081
1094
|
// In the next _detectAndDispatchChange() call, the change detection should pass
|
|
1082
1095
|
this._lastCommittedValue = undefined;
|
|
1083
1096
|
}
|
|
@@ -1276,35 +1289,12 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
1276
1289
|
this._clear();
|
|
1277
1290
|
}
|
|
1278
1291
|
|
|
1279
|
-
/**
|
|
1280
|
-
* Returns true if `value` is valid, and sets the `invalid` flag appropriately.
|
|
1281
|
-
*
|
|
1282
|
-
* @return {boolean} True if the value is valid and sets the `invalid` flag appropriately
|
|
1283
|
-
*/
|
|
1284
|
-
validate() {
|
|
1285
|
-
return !(this.invalid = !this.checkValidity());
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
/**
|
|
1289
|
-
* Returns true if the current input value satisfies all constraints (if any).
|
|
1290
|
-
* You can override this method for custom validations.
|
|
1291
|
-
*
|
|
1292
|
-
* @return {boolean}
|
|
1293
|
-
*/
|
|
1294
|
-
checkValidity() {
|
|
1295
|
-
if (super.checkValidity) {
|
|
1296
|
-
return super.checkValidity();
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
return !this.required || !!this.value;
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
1292
|
/**
|
|
1303
1293
|
* Fired when the value changes.
|
|
1304
1294
|
*
|
|
1305
1295
|
* @event value-changed
|
|
1306
1296
|
* @param {Object} detail
|
|
1307
|
-
*
|
|
1297
|
+
* @param {String} detail.value the combobox value
|
|
1308
1298
|
*/
|
|
1309
1299
|
|
|
1310
1300
|
/**
|
|
@@ -1312,7 +1302,7 @@ export const ComboBoxMixin = (subclass) =>
|
|
|
1312
1302
|
*
|
|
1313
1303
|
* @event selected-item-changed
|
|
1314
1304
|
* @param {Object} detail
|
|
1315
|
-
*
|
|
1305
|
+
* @param {Object|String} detail.value the selected item. Type is the same as the type of `items`.
|
|
1316
1306
|
*/
|
|
1317
1307
|
|
|
1318
1308
|
/**
|