@everymatrix/general-input 1.28.7 → 1.28.8
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/dist/cjs/checkbox-group-input_10.cjs.entry.js +12517 -13047
- package/dist/components/active-mixin.js +6 -6
- package/dist/components/checkbox-group-input2.js +307 -260
- package/dist/components/date-input2.js +2206 -3449
- package/dist/components/field-mixin.js +2512 -2226
- package/dist/components/input-field-shared-styles.js +211 -308
- package/dist/components/password-input2.js +72 -119
- package/dist/components/pattern-mixin.js +85 -0
- package/dist/components/vaadin-button.js +73 -102
- package/dist/components/vaadin-combo-box.js +808 -991
- package/dist/components/virtual-keyboard-controller.js +1768 -1111
- package/dist/esm/checkbox-group-input_10.entry.js +12517 -13047
- package/dist/general-input/general-input.esm.js +1 -1
- package/dist/general-input/p-6958a2a8.entry.js +3581 -0
- package/package.json +1 -1
- package/dist/general-input/p-765941e7.entry.js +0 -3646
- /package/dist/types/Users/{adrian.pripon/Documents/Work → sebastian.strulea/Documents/work}/widgets-stencil/packages/general-input/.stencil/packages/general-input/stencil.config.d.ts +0 -0
|
@@ -1,111 +1,11 @@
|
|
|
1
|
-
import { i, r as registerStyles,
|
|
2
|
-
import {
|
|
3
|
-
import { i as inputFieldShared, e as isSafari,
|
|
4
|
-
|
|
5
|
-
const item = i`
|
|
6
|
-
:host {
|
|
7
|
-
display: flex;
|
|
8
|
-
align-items: center;
|
|
9
|
-
box-sizing: border-box;
|
|
10
|
-
font-family: var(--lumo-font-family);
|
|
11
|
-
font-size: var(--lumo-font-size-m);
|
|
12
|
-
line-height: var(--lumo-line-height-xs);
|
|
13
|
-
padding: 0.5em calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4) 0.5em
|
|
14
|
-
var(--_lumo-list-box-item-padding-left, calc(var(--lumo-border-radius-m) / 4));
|
|
15
|
-
min-height: var(--lumo-size-m);
|
|
16
|
-
outline: none;
|
|
17
|
-
border-radius: var(--lumo-border-radius-m);
|
|
18
|
-
cursor: var(--lumo-clickable-cursor);
|
|
19
|
-
-webkit-font-smoothing: antialiased;
|
|
20
|
-
-moz-osx-font-smoothing: grayscale;
|
|
21
|
-
-webkit-tap-highlight-color: var(--lumo-primary-color-10pct);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/* Checkmark */
|
|
25
|
-
[part='checkmark']::before {
|
|
26
|
-
display: var(--_lumo-item-selected-icon-display, none);
|
|
27
|
-
content: var(--lumo-icons-checkmark);
|
|
28
|
-
font-family: lumo-icons;
|
|
29
|
-
font-size: var(--lumo-icon-size-m);
|
|
30
|
-
line-height: 1;
|
|
31
|
-
font-weight: normal;
|
|
32
|
-
width: 1em;
|
|
33
|
-
height: 1em;
|
|
34
|
-
margin: calc((1 - var(--lumo-line-height-xs)) * var(--lumo-font-size-m) / 2) 0;
|
|
35
|
-
color: var(--lumo-primary-text-color);
|
|
36
|
-
flex: none;
|
|
37
|
-
opacity: 0;
|
|
38
|
-
transition: transform 0.2s cubic-bezier(0.12, 0.32, 0.54, 2), opacity 0.1s;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
:host([selected]) [part='checkmark']::before {
|
|
42
|
-
opacity: 1;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
:host([active]:not([selected])) [part='checkmark']::before {
|
|
46
|
-
transform: scale(0.8);
|
|
47
|
-
opacity: 0;
|
|
48
|
-
transition-duration: 0s;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
[part='content'] {
|
|
52
|
-
flex: auto;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/* Disabled */
|
|
56
|
-
:host([disabled]) {
|
|
57
|
-
color: var(--lumo-disabled-text-color);
|
|
58
|
-
cursor: default;
|
|
59
|
-
pointer-events: none;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/* TODO a workaround until we have "focus-follows-mouse". After that, use the hover style for focus-ring as well */
|
|
63
|
-
@media (any-hover: hover) {
|
|
64
|
-
:host(:hover:not([disabled])) {
|
|
65
|
-
background-color: var(--lumo-primary-color-10pct);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
:host([focus-ring]:not([disabled])) {
|
|
69
|
-
box-shadow: inset 0 0 0 2px var(--lumo-primary-color-50pct);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/* RTL specific styles */
|
|
74
|
-
:host([dir='rtl']) {
|
|
75
|
-
padding-left: calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4);
|
|
76
|
-
padding-right: var(--_lumo-list-box-item-padding-left, calc(var(--lumo-border-radius-m) / 4));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/* Slotted icons */
|
|
80
|
-
:host ::slotted(vaadin-icon) {
|
|
81
|
-
width: var(--lumo-icon-size-m);
|
|
82
|
-
height: var(--lumo-icon-size-m);
|
|
83
|
-
}
|
|
84
|
-
`;
|
|
85
|
-
|
|
86
|
-
registerStyles('vaadin-item', item, { moduleId: 'lumo-item' });
|
|
87
|
-
|
|
88
|
-
const comboBoxItem = i`
|
|
89
|
-
:host {
|
|
90
|
-
transition: background-color 100ms;
|
|
91
|
-
overflow: hidden;
|
|
92
|
-
--_lumo-item-selected-icon-display: block;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
@media (any-hover: hover) {
|
|
96
|
-
:host([focused]:not([disabled])) {
|
|
97
|
-
box-shadow: inset 0 0 0 2px var(--lumo-primary-color-50pct);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
`;
|
|
101
|
-
|
|
102
|
-
registerStyles('vaadin-combo-box-item', [item, comboBoxItem], {
|
|
103
|
-
moduleId: 'lumo-combo-box-item',
|
|
104
|
-
});
|
|
1
|
+
import { i, r as registerStyles, T as ThemableMixin, A as DirMixin, P as PolymerElement, h as html, n as microTask, O as idlePeriod, Q as animationFrame, R as flush, y as Debouncer, U as enqueueDebouncer, z as timeOut, W as generateUniqueId, C as ControllerMixin, K as KeyboardMixin, I as InputMixin, a as DisabledMixin, b as isElementFocused, e as InputController, f as LabelledInputController, g as TooltipController, E as ElementMixin } from './field-mixin.js';
|
|
2
|
+
import { o as overlay, d as menuOverlayCore, P as PositionMixin, O as Overlay, V as VirtualKeyboardController } from './virtual-keyboard-controller.js';
|
|
3
|
+
import { i as inputFieldShared, e as isSafari, f as isTouch, c as InputControlMixin, d as inputFieldShared$1 } from './input-field-shared-styles.js';
|
|
4
|
+
import { P as PatternMixin } from './pattern-mixin.js';
|
|
105
5
|
|
|
106
6
|
/**
|
|
107
7
|
* @license
|
|
108
|
-
* Copyright (c) 2022
|
|
8
|
+
* Copyright (c) 2022 Vaadin Ltd.
|
|
109
9
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
110
10
|
*/
|
|
111
11
|
|
|
@@ -156,6 +56,14 @@ const comboBoxOverlay = i`
|
|
|
156
56
|
padding: 0;
|
|
157
57
|
}
|
|
158
58
|
|
|
59
|
+
:host {
|
|
60
|
+
--_vaadin-combo-box-items-container-border-width: var(--lumo-space-xs);
|
|
61
|
+
--_vaadin-combo-box-items-container-border-style: solid;
|
|
62
|
+
--_vaadin-combo-box-items-container-border-color: transparent;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Loading state */
|
|
66
|
+
|
|
159
67
|
/* When items are empty, the spinner needs some room */
|
|
160
68
|
:host(:not([closing])) [part~='content'] {
|
|
161
69
|
min-height: calc(2 * var(--lumo-space-s) + var(--lumo-icon-size-s));
|
|
@@ -172,9 +80,7 @@ const comboBoxOverlay = i`
|
|
|
172
80
|
:host([bottom-aligned]) [part~='overlay'] {
|
|
173
81
|
margin-bottom: var(--lumo-space-xs);
|
|
174
82
|
}
|
|
175
|
-
`;
|
|
176
83
|
|
|
177
|
-
const comboBoxLoader = i`
|
|
178
84
|
[part~='loader'] {
|
|
179
85
|
position: absolute;
|
|
180
86
|
z-index: 1;
|
|
@@ -186,6 +92,8 @@ const comboBoxLoader = i`
|
|
|
186
92
|
margin-inline-end: 0;
|
|
187
93
|
}
|
|
188
94
|
|
|
95
|
+
/* RTL specific styles */
|
|
96
|
+
|
|
189
97
|
:host([dir='rtl']) [part~='loader'] {
|
|
190
98
|
left: auto;
|
|
191
99
|
margin-left: 0;
|
|
@@ -195,182 +103,127 @@ const comboBoxLoader = i`
|
|
|
195
103
|
}
|
|
196
104
|
`;
|
|
197
105
|
|
|
198
|
-
registerStyles(
|
|
199
|
-
'
|
|
200
|
-
|
|
201
|
-
overlay,
|
|
202
|
-
menuOverlayCore,
|
|
203
|
-
comboBoxOverlay,
|
|
204
|
-
loader,
|
|
205
|
-
comboBoxLoader,
|
|
206
|
-
i`
|
|
207
|
-
:host {
|
|
208
|
-
--_vaadin-combo-box-items-container-border-width: var(--lumo-space-xs);
|
|
209
|
-
--_vaadin-combo-box-items-container-border-style: solid;
|
|
210
|
-
}
|
|
211
|
-
`,
|
|
212
|
-
],
|
|
213
|
-
{ moduleId: 'lumo-combo-box-overlay' },
|
|
214
|
-
);
|
|
106
|
+
registerStyles('vaadin-combo-box-overlay', [overlay, menuOverlayCore, comboBoxOverlay, loader], {
|
|
107
|
+
moduleId: 'lumo-combo-box-overlay',
|
|
108
|
+
});
|
|
215
109
|
|
|
216
|
-
const
|
|
110
|
+
const item = i`
|
|
217
111
|
:host {
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
box-sizing: border-box;
|
|
115
|
+
font-family: var(--lumo-font-family);
|
|
116
|
+
font-size: var(--lumo-font-size-m);
|
|
117
|
+
line-height: var(--lumo-line-height-xs);
|
|
118
|
+
padding: 0.5em calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4) 0.5em
|
|
119
|
+
var(--_lumo-list-box-item-padding-left, calc(var(--lumo-border-radius-m) / 4));
|
|
120
|
+
min-height: var(--lumo-size-m);
|
|
218
121
|
outline: none;
|
|
122
|
+
border-radius: var(--lumo-border-radius-m);
|
|
123
|
+
cursor: var(--lumo-clickable-cursor);
|
|
124
|
+
-webkit-font-smoothing: antialiased;
|
|
125
|
+
-moz-osx-font-smoothing: grayscale;
|
|
126
|
+
-webkit-tap-highlight-color: var(--lumo-primary-color-10pct);
|
|
219
127
|
}
|
|
220
128
|
|
|
221
|
-
|
|
222
|
-
|
|
129
|
+
/* Checkmark */
|
|
130
|
+
[part='checkmark']::before {
|
|
131
|
+
display: var(--_lumo-item-selected-icon-display, none);
|
|
132
|
+
content: var(--lumo-icons-checkmark);
|
|
133
|
+
font-family: lumo-icons;
|
|
134
|
+
font-size: var(--lumo-icon-size-m);
|
|
135
|
+
line-height: 1;
|
|
136
|
+
font-weight: normal;
|
|
137
|
+
width: 1em;
|
|
138
|
+
height: 1em;
|
|
139
|
+
margin: calc((1 - var(--lumo-line-height-xs)) * var(--lumo-font-size-m) / 2) 0;
|
|
140
|
+
color: var(--lumo-primary-text-color);
|
|
141
|
+
flex: none;
|
|
142
|
+
opacity: 0;
|
|
143
|
+
transition: transform 0.2s cubic-bezier(0.12, 0.32, 0.54, 2), opacity 0.1s;
|
|
223
144
|
}
|
|
224
|
-
`;
|
|
225
145
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
* @license
|
|
230
|
-
* Copyright (c) 2015 - 2023 Vaadin Ltd.
|
|
231
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
232
|
-
*/
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* @polymerMixin
|
|
236
|
-
*/
|
|
237
|
-
const ComboBoxItemMixin = (superClass) =>
|
|
238
|
-
class ComboBoxItemMixinClass extends superClass {
|
|
239
|
-
static get properties() {
|
|
240
|
-
return {
|
|
241
|
-
/**
|
|
242
|
-
* The index of the item.
|
|
243
|
-
*/
|
|
244
|
-
index: {
|
|
245
|
-
type: Number,
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* The item to render.
|
|
250
|
-
*/
|
|
251
|
-
item: {
|
|
252
|
-
type: Object,
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* The text to render in the item.
|
|
257
|
-
*/
|
|
258
|
-
label: {
|
|
259
|
-
type: String,
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* True when item is selected.
|
|
264
|
-
*/
|
|
265
|
-
selected: {
|
|
266
|
-
type: Boolean,
|
|
267
|
-
value: false,
|
|
268
|
-
reflectToAttribute: true,
|
|
269
|
-
},
|
|
146
|
+
:host([selected]) [part='checkmark']::before {
|
|
147
|
+
opacity: 1;
|
|
148
|
+
}
|
|
270
149
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
value: false,
|
|
277
|
-
reflectToAttribute: true,
|
|
278
|
-
},
|
|
150
|
+
:host([active]:not([selected])) [part='checkmark']::before {
|
|
151
|
+
transform: scale(0.8);
|
|
152
|
+
opacity: 0;
|
|
153
|
+
transition-duration: 0s;
|
|
154
|
+
}
|
|
279
155
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
renderer: {
|
|
284
|
-
type: Function,
|
|
285
|
-
},
|
|
286
|
-
};
|
|
287
|
-
}
|
|
156
|
+
[part='content'] {
|
|
157
|
+
flex: auto;
|
|
158
|
+
}
|
|
288
159
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
160
|
+
/* Disabled */
|
|
161
|
+
:host([disabled]) {
|
|
162
|
+
color: var(--lumo-disabled-text-color);
|
|
163
|
+
cursor: default;
|
|
164
|
+
pointer-events: none;
|
|
165
|
+
}
|
|
292
166
|
|
|
293
|
-
|
|
294
|
-
|
|
167
|
+
/* TODO a workaround until we have "focus-follows-mouse". After that, use the hover style for focus-ring as well */
|
|
168
|
+
@media (any-hover: hover) {
|
|
169
|
+
:host(:hover:not([disabled])) {
|
|
170
|
+
background-color: var(--lumo-primary-color-10pct);
|
|
295
171
|
}
|
|
296
172
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// The element is being hidden (by virtualizer). Mark one of the __rendererOrItemChanged
|
|
300
|
-
// dependencies as undefined to make sure it's called when the element is shown again
|
|
301
|
-
// and assigned properties with possibly identical values as before hiding.
|
|
302
|
-
this.index = undefined;
|
|
303
|
-
} else {
|
|
304
|
-
super.attributeChangedCallback(name, oldValue, newValue);
|
|
305
|
-
}
|
|
173
|
+
:host([focus-ring]:not([disabled])) {
|
|
174
|
+
box-shadow: inset 0 0 0 2px var(--lumo-primary-color-50pct);
|
|
306
175
|
}
|
|
176
|
+
}
|
|
307
177
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
178
|
+
/* RTL specific styles */
|
|
179
|
+
:host([dir='rtl']) {
|
|
180
|
+
padding-left: calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4);
|
|
181
|
+
padding-right: var(--_lumo-list-box-item-padding-left, calc(var(--lumo-border-radius-m) / 4));
|
|
182
|
+
}
|
|
313
183
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
184
|
+
/* Slotted icons */
|
|
185
|
+
:host ::slotted(vaadin-icon),
|
|
186
|
+
:host ::slotted(iron-icon) {
|
|
187
|
+
width: var(--lumo-icon-size-m);
|
|
188
|
+
height: var(--lumo-icon-size-m);
|
|
189
|
+
}
|
|
190
|
+
`;
|
|
319
191
|
|
|
320
|
-
|
|
321
|
-
* Requests an update for the content of the item.
|
|
322
|
-
* While performing the update, it invokes the renderer passed in the `renderer` property.
|
|
323
|
-
*
|
|
324
|
-
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
325
|
-
*/
|
|
326
|
-
requestContentUpdate() {
|
|
327
|
-
if (!this.renderer) {
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
192
|
+
registerStyles('vaadin-item', item, { moduleId: 'lumo-item' });
|
|
330
193
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
194
|
+
const comboBoxItem = i`
|
|
195
|
+
:host {
|
|
196
|
+
transition: background-color 100ms;
|
|
197
|
+
overflow: hidden;
|
|
198
|
+
--_lumo-item-selected-icon-display: block;
|
|
199
|
+
}
|
|
337
200
|
|
|
338
|
-
|
|
201
|
+
@media (any-hover: hover) {
|
|
202
|
+
:host([focused]:not([disabled])) {
|
|
203
|
+
box-shadow: inset 0 0 0 2px var(--lumo-primary-color-50pct);
|
|
339
204
|
}
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
340
207
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
if (this._oldRenderer !== renderer) {
|
|
348
|
-
this.innerHTML = '';
|
|
349
|
-
// Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
|
|
350
|
-
// When clearing the rendered content, this part needs to be manually disposed of.
|
|
351
|
-
// Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
|
|
352
|
-
delete this._$litPart$;
|
|
353
|
-
}
|
|
208
|
+
registerStyles('vaadin-combo-box-item', [item, comboBoxItem], {
|
|
209
|
+
moduleId: 'lumo-combo-box-item',
|
|
210
|
+
});
|
|
354
211
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
212
|
+
const comboBox = i`
|
|
213
|
+
:host {
|
|
214
|
+
outline: none;
|
|
215
|
+
}
|
|
360
216
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
217
|
+
[part='toggle-button']::before {
|
|
218
|
+
content: var(--lumo-icons-dropdown);
|
|
219
|
+
}
|
|
220
|
+
`;
|
|
366
221
|
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
};
|
|
222
|
+
registerStyles('vaadin-combo-box', [inputFieldShared, comboBox], { moduleId: 'lumo-combo-box' });
|
|
370
223
|
|
|
371
224
|
/**
|
|
372
225
|
* @license
|
|
373
|
-
* Copyright (c) 2015 -
|
|
226
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
374
227
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
375
228
|
*/
|
|
376
229
|
|
|
@@ -393,15 +246,13 @@ const ComboBoxItemMixin = (superClass) =>
|
|
|
393
246
|
* `selected` | Set when the item is selected
|
|
394
247
|
* `focused` | Set when the item is focused
|
|
395
248
|
*
|
|
396
|
-
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
|
|
249
|
+
* See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
|
|
397
250
|
*
|
|
398
|
-
* @customElement
|
|
399
|
-
* @mixes ComboBoxItemMixin
|
|
400
251
|
* @mixes ThemableMixin
|
|
401
252
|
* @mixes DirMixin
|
|
402
253
|
* @private
|
|
403
254
|
*/
|
|
404
|
-
class ComboBoxItem extends
|
|
255
|
+
class ComboBoxItem extends ThemableMixin(DirMixin(PolymerElement)) {
|
|
405
256
|
static get template() {
|
|
406
257
|
return html`
|
|
407
258
|
<style>
|
|
@@ -423,142 +274,217 @@ class ComboBoxItem extends ComboBoxItemMixin(ThemableMixin(DirMixin(PolymerEleme
|
|
|
423
274
|
static get is() {
|
|
424
275
|
return 'vaadin-combo-box-item';
|
|
425
276
|
}
|
|
426
|
-
}
|
|
427
277
|
|
|
428
|
-
|
|
278
|
+
static get properties() {
|
|
279
|
+
return {
|
|
280
|
+
/**
|
|
281
|
+
* The index of the item
|
|
282
|
+
*/
|
|
283
|
+
index: Number,
|
|
429
284
|
|
|
430
|
-
/**
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
285
|
+
/**
|
|
286
|
+
* The item to render
|
|
287
|
+
* @type {(String|Object)}
|
|
288
|
+
*/
|
|
289
|
+
item: Object,
|
|
435
290
|
|
|
436
|
-
/**
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const ComboBoxOverlayMixin = (superClass) =>
|
|
441
|
-
class ComboBoxOverlayMixin extends PositionMixin(superClass) {
|
|
442
|
-
static get observers() {
|
|
443
|
-
return ['_setOverlayWidth(positionTarget, opened)'];
|
|
444
|
-
}
|
|
291
|
+
/**
|
|
292
|
+
* The text label corresponding to the item
|
|
293
|
+
*/
|
|
294
|
+
label: String,
|
|
445
295
|
|
|
446
|
-
|
|
447
|
-
|
|
296
|
+
/**
|
|
297
|
+
* True when item is selected
|
|
298
|
+
*/
|
|
299
|
+
selected: {
|
|
300
|
+
type: Boolean,
|
|
301
|
+
value: false,
|
|
302
|
+
reflectToAttribute: true,
|
|
303
|
+
},
|
|
448
304
|
|
|
449
|
-
|
|
450
|
-
|
|
305
|
+
/**
|
|
306
|
+
* True when item is focused
|
|
307
|
+
*/
|
|
308
|
+
focused: {
|
|
309
|
+
type: Boolean,
|
|
310
|
+
value: false,
|
|
311
|
+
reflectToAttribute: true,
|
|
312
|
+
},
|
|
451
313
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
314
|
+
/**
|
|
315
|
+
* Custom function for rendering the content of the `<vaadin-combo-box-item>` propagated from the combo box element.
|
|
316
|
+
*/
|
|
317
|
+
renderer: Function,
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Saved instance of a custom renderer function.
|
|
321
|
+
*/
|
|
322
|
+
_oldRenderer: Function,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
455
325
|
|
|
456
|
-
|
|
326
|
+
static get observers() {
|
|
327
|
+
return ['__rendererOrItemChanged(renderer, index, item.*, selected, focused)', '__updateLabel(label, renderer)'];
|
|
328
|
+
}
|
|
457
329
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
330
|
+
connectedCallback() {
|
|
331
|
+
super.connectedCallback();
|
|
332
|
+
|
|
333
|
+
this._comboBox = this.parentNode.comboBox;
|
|
334
|
+
|
|
335
|
+
const hostDir = this._comboBox.getAttribute('dir');
|
|
336
|
+
if (hostDir) {
|
|
337
|
+
this.setAttribute('dir', hostDir);
|
|
462
338
|
}
|
|
339
|
+
}
|
|
463
340
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const eventPath = event.composedPath();
|
|
474
|
-
return !eventPath.includes(this.positionTarget) && !eventPath.includes(this);
|
|
341
|
+
/**
|
|
342
|
+
* Requests an update for the content of the item.
|
|
343
|
+
* While performing the update, it invokes the renderer passed in the `renderer` property.
|
|
344
|
+
*
|
|
345
|
+
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
346
|
+
*/
|
|
347
|
+
requestContentUpdate() {
|
|
348
|
+
if (!this.renderer) {
|
|
349
|
+
return;
|
|
475
350
|
}
|
|
476
351
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
352
|
+
const model = {
|
|
353
|
+
index: this.index,
|
|
354
|
+
item: this.item,
|
|
355
|
+
focused: this.focused,
|
|
356
|
+
selected: this.selected,
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
this.renderer(this, this._comboBox, model);
|
|
360
|
+
}
|
|
482
361
|
|
|
483
|
-
|
|
362
|
+
/** @private */
|
|
363
|
+
__rendererOrItemChanged(renderer, index, item) {
|
|
364
|
+
if (item === undefined || index === undefined) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
484
367
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
368
|
+
if (this._oldRenderer !== renderer) {
|
|
369
|
+
this.innerHTML = '';
|
|
370
|
+
// Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
|
|
371
|
+
// When clearing the rendered content, this part needs to be manually disposed of.
|
|
372
|
+
// Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
|
|
373
|
+
delete this._$litPart$;
|
|
374
|
+
}
|
|
490
375
|
|
|
491
|
-
|
|
492
|
-
|
|
376
|
+
if (renderer) {
|
|
377
|
+
this._oldRenderer = renderer;
|
|
378
|
+
this.requestContentUpdate();
|
|
493
379
|
}
|
|
494
|
-
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** @private */
|
|
383
|
+
__updateLabel(label, renderer) {
|
|
384
|
+
if (renderer) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
this.textContent = label;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
customElements.define(ComboBoxItem.is, ComboBoxItem);
|
|
495
393
|
|
|
496
394
|
/**
|
|
497
395
|
* @license
|
|
498
|
-
* Copyright (c) 2015 -
|
|
396
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
499
397
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
500
398
|
*/
|
|
501
399
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
400
|
+
registerStyles(
|
|
401
|
+
'vaadin-combo-box-overlay',
|
|
402
|
+
i`
|
|
403
|
+
#overlay {
|
|
404
|
+
width: var(--vaadin-combo-box-overlay-width, var(--_vaadin-combo-box-overlay-default-width, auto));
|
|
405
|
+
}
|
|
506
406
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
407
|
+
[part='content'] {
|
|
408
|
+
display: flex;
|
|
409
|
+
flex-direction: column;
|
|
410
|
+
height: 100%;
|
|
411
|
+
}
|
|
412
|
+
`,
|
|
413
|
+
{ moduleId: 'vaadin-combo-box-overlay-styles' },
|
|
414
|
+
);
|
|
513
415
|
|
|
514
|
-
|
|
515
|
-
moduleId: 'vaadin-combo-box-overlay-styles',
|
|
516
|
-
});
|
|
416
|
+
let memoizedTemplate;
|
|
517
417
|
|
|
518
418
|
/**
|
|
519
419
|
* An element used internally by `<vaadin-combo-box>`. Not intended to be used separately.
|
|
520
420
|
*
|
|
521
|
-
* @
|
|
522
|
-
* @extends HTMLElement
|
|
523
|
-
* @mixes ComboBoxOverlayMixin
|
|
524
|
-
* @mixes DirMixin
|
|
525
|
-
* @mixes OverlayMixin
|
|
526
|
-
* @mixes ThemableMixin
|
|
421
|
+
* @extends Overlay
|
|
527
422
|
* @private
|
|
528
423
|
*/
|
|
529
|
-
class ComboBoxOverlay extends
|
|
424
|
+
class ComboBoxOverlay extends PositionMixin(Overlay) {
|
|
530
425
|
static get is() {
|
|
531
426
|
return 'vaadin-combo-box-overlay';
|
|
532
427
|
}
|
|
533
428
|
|
|
534
429
|
static get template() {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
430
|
+
if (!memoizedTemplate) {
|
|
431
|
+
memoizedTemplate = super.template.cloneNode(true);
|
|
432
|
+
memoizedTemplate.content.querySelector('[part~="overlay"]').removeAttribute('tabindex');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return memoizedTemplate;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
static get observers() {
|
|
439
|
+
return ['_setOverlayWidth(positionTarget, opened)'];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
connectedCallback() {
|
|
443
|
+
super.connectedCallback();
|
|
444
|
+
|
|
445
|
+
const comboBox = this._comboBox;
|
|
446
|
+
|
|
447
|
+
const hostDir = comboBox && comboBox.getAttribute('dir');
|
|
448
|
+
if (hostDir) {
|
|
449
|
+
this.setAttribute('dir', hostDir);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
ready() {
|
|
454
|
+
super.ready();
|
|
455
|
+
const loader = document.createElement('div');
|
|
456
|
+
loader.setAttribute('part', 'loader');
|
|
457
|
+
const content = this.shadowRoot.querySelector('[part~="content"]');
|
|
458
|
+
content.parentNode.insertBefore(loader, content);
|
|
459
|
+
this.requiredVerticalSpace = 200;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
_outsideClickListener(event) {
|
|
463
|
+
const eventPath = event.composedPath();
|
|
464
|
+
if (!eventPath.includes(this.positionTarget) && !eventPath.includes(this)) {
|
|
465
|
+
this.close();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
_setOverlayWidth(positionTarget, opened) {
|
|
470
|
+
if (positionTarget && opened) {
|
|
471
|
+
const propPrefix = this.localName;
|
|
472
|
+
this.style.setProperty(`--_${propPrefix}-default-width`, `${positionTarget.clientWidth}px`);
|
|
473
|
+
|
|
474
|
+
const customWidth = getComputedStyle(this._comboBox).getPropertyValue(`--${propPrefix}-width`);
|
|
475
|
+
|
|
476
|
+
if (customWidth === '') {
|
|
477
|
+
this.style.removeProperty(`--${propPrefix}-width`);
|
|
478
|
+
} else {
|
|
479
|
+
this.style.setProperty(`--${propPrefix}-width`, customWidth);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
this._updatePosition();
|
|
483
|
+
}
|
|
542
484
|
}
|
|
543
485
|
}
|
|
544
486
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* @license
|
|
549
|
-
* Copyright (c) 2023 Vaadin Ltd.
|
|
550
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
551
|
-
*/
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Convenience method for reading a value from a path.
|
|
555
|
-
*
|
|
556
|
-
* @param {string} path
|
|
557
|
-
* @param {object} object
|
|
558
|
-
*/
|
|
559
|
-
function get(path, object) {
|
|
560
|
-
return path.split('.').reduce((obj, property) => (obj ? obj[property] : undefined), object);
|
|
561
|
-
}
|
|
487
|
+
customElements.define(ComboBoxOverlay.is, ComboBoxOverlay);
|
|
562
488
|
|
|
563
489
|
/**
|
|
564
490
|
* @license
|
|
@@ -570,7 +496,7 @@ function get(path, object) {
|
|
|
570
496
|
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
571
497
|
*/
|
|
572
498
|
|
|
573
|
-
const IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/
|
|
499
|
+
const IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
|
|
574
500
|
const IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
|
|
575
501
|
const DEFAULT_PHYSICAL_COUNT = 3;
|
|
576
502
|
|
|
@@ -1060,12 +986,9 @@ const ironList = {
|
|
|
1060
986
|
this._physicalIndexForKey = {};
|
|
1061
987
|
this._firstVisibleIndexVal = null;
|
|
1062
988
|
this._lastVisibleIndexVal = null;
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
if (!this._physicalSizes) {
|
|
1067
|
-
this._physicalSizes = [];
|
|
1068
|
-
}
|
|
989
|
+
this._physicalCount = this._physicalCount || 0;
|
|
990
|
+
this._physicalItems = this._physicalItems || [];
|
|
991
|
+
this._physicalSizes = this._physicalSizes || [];
|
|
1069
992
|
this._physicalStart = 0;
|
|
1070
993
|
if (this._scrollTop > this._scrollOffset) {
|
|
1071
994
|
this._resetScrollPosition(0);
|
|
@@ -1174,21 +1097,16 @@ const ironList = {
|
|
|
1174
1097
|
* @param {boolean=} forceUpdate If true, updates the height no matter what.
|
|
1175
1098
|
*/
|
|
1176
1099
|
_updateScrollerSize(forceUpdate) {
|
|
1177
|
-
|
|
1100
|
+
this._estScrollHeight =
|
|
1178
1101
|
this._physicalBottom +
|
|
1179
1102
|
Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
|
|
1180
1103
|
|
|
1181
|
-
this.
|
|
1182
|
-
|
|
1104
|
+
forceUpdate = forceUpdate || this._scrollHeight === 0;
|
|
1105
|
+
forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
|
|
1183
1106
|
// Amortize height adjustment, so it won't trigger large repaints too often.
|
|
1184
|
-
if (
|
|
1185
|
-
|
|
1186
|
-
this._scrollHeight
|
|
1187
|
-
this._scrollPosition >= estScrollHeight - this._physicalSize ||
|
|
1188
|
-
Math.abs(estScrollHeight - this._scrollHeight) >= this._viewportHeight
|
|
1189
|
-
) {
|
|
1190
|
-
this.$.items.style.height = `${estScrollHeight}px`;
|
|
1191
|
-
this._scrollHeight = estScrollHeight;
|
|
1107
|
+
if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._viewportHeight) {
|
|
1108
|
+
this.$.items.style.height = `${this._estScrollHeight}px`;
|
|
1109
|
+
this._scrollHeight = this._estScrollHeight;
|
|
1192
1110
|
}
|
|
1193
1111
|
},
|
|
1194
1112
|
|
|
@@ -1284,9 +1202,7 @@ const ironList = {
|
|
|
1284
1202
|
},
|
|
1285
1203
|
|
|
1286
1204
|
_debounce(name, cb, asyncModule) {
|
|
1287
|
-
|
|
1288
|
-
this._debouncers = {};
|
|
1289
|
-
}
|
|
1205
|
+
this._debouncers = this._debouncers || {};
|
|
1290
1206
|
this._debouncers[name] = Debouncer.debounce(this._debouncers[name], asyncModule, cb.bind(this));
|
|
1291
1207
|
enqueueDebouncer(this._debouncers[name]);
|
|
1292
1208
|
},
|
|
@@ -1294,7 +1210,7 @@ const ironList = {
|
|
|
1294
1210
|
|
|
1295
1211
|
/**
|
|
1296
1212
|
* @license
|
|
1297
|
-
* Copyright (c) 2021 -
|
|
1213
|
+
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
1298
1214
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1299
1215
|
*/
|
|
1300
1216
|
|
|
@@ -1424,15 +1340,11 @@ class IronListAdapter {
|
|
|
1424
1340
|
}
|
|
1425
1341
|
|
|
1426
1342
|
update(startIndex = 0, endIndex = this.size - 1) {
|
|
1427
|
-
const updatedElements = [];
|
|
1428
1343
|
this.__getVisibleElements().forEach((el) => {
|
|
1429
1344
|
if (el.__virtualIndex >= startIndex && el.__virtualIndex <= endIndex) {
|
|
1430
1345
|
this.__updateElement(el, el.__virtualIndex, true);
|
|
1431
|
-
updatedElements.push(el);
|
|
1432
1346
|
}
|
|
1433
1347
|
});
|
|
1434
|
-
|
|
1435
|
-
this.__afterElementsUpdated(updatedElements);
|
|
1436
1348
|
}
|
|
1437
1349
|
|
|
1438
1350
|
/**
|
|
@@ -1495,40 +1407,28 @@ class IronListAdapter {
|
|
|
1495
1407
|
this.updateElement(el, index);
|
|
1496
1408
|
el.__lastUpdatedIndex = index;
|
|
1497
1409
|
}
|
|
1498
|
-
}
|
|
1499
1410
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
} else {
|
|
1522
|
-
// Add element height to the queue
|
|
1523
|
-
this.__elementHeightQueue.push(elementHeight);
|
|
1524
|
-
this.__elementHeightQueue.shift();
|
|
1525
|
-
|
|
1526
|
-
// Calculate new placeholder height based on the average of the defined values in the
|
|
1527
|
-
// element height queue
|
|
1528
|
-
const filteredHeights = this.__elementHeightQueue.filter((h) => h !== undefined);
|
|
1529
|
-
this.__placeholderHeight = Math.round(filteredHeights.reduce((a, b) => a + b, 0) / filteredHeights.length);
|
|
1530
|
-
}
|
|
1531
|
-
});
|
|
1411
|
+
const elementHeight = el.offsetHeight;
|
|
1412
|
+
if (elementHeight === 0) {
|
|
1413
|
+
// If the elements have 0 height after update (for example due to lazy rendering),
|
|
1414
|
+
// it results in iron-list requesting to create an unlimited count of elements.
|
|
1415
|
+
// Assign a temporary placeholder sizing to elements that would otherwise end up having
|
|
1416
|
+
// no height.
|
|
1417
|
+
el.style.paddingTop = `${this.__placeholderHeight}px`;
|
|
1418
|
+
|
|
1419
|
+
// Manually schedule the resize handler to make sure the placeholder padding is
|
|
1420
|
+
// cleared in case the resize observer never triggers.
|
|
1421
|
+
requestAnimationFrame(() => this._resizeHandler());
|
|
1422
|
+
} else {
|
|
1423
|
+
// Add element height to the queue
|
|
1424
|
+
this.__elementHeightQueue.push(elementHeight);
|
|
1425
|
+
this.__elementHeightQueue.shift();
|
|
1426
|
+
|
|
1427
|
+
// Calcualte new placeholder height based on the average of the defined values in the
|
|
1428
|
+
// element height queue
|
|
1429
|
+
const filteredHeights = this.__elementHeightQueue.filter((h) => h !== undefined);
|
|
1430
|
+
this.__placeholderHeight = Math.round(filteredHeights.reduce((a, b) => a + b, 0) / filteredHeights.length);
|
|
1431
|
+
}
|
|
1532
1432
|
}
|
|
1533
1433
|
|
|
1534
1434
|
__getIndexScrollOffset(index) {
|
|
@@ -1553,37 +1453,42 @@ class IronListAdapter {
|
|
|
1553
1453
|
this._debouncers._increasePoolIfNeeded.cancel();
|
|
1554
1454
|
}
|
|
1555
1455
|
|
|
1456
|
+
// Prevent element update while the scroll position is being restored
|
|
1457
|
+
this.__preventElementUpdates = true;
|
|
1458
|
+
|
|
1459
|
+
// Record the scroll position before changing the size
|
|
1460
|
+
let fvi; // First visible index
|
|
1461
|
+
let fviOffsetBefore; // Scroll offset of the first visible index
|
|
1462
|
+
if (size > 0) {
|
|
1463
|
+
fvi = this.adjustedFirstVisibleIndex;
|
|
1464
|
+
fviOffsetBefore = this.__getIndexScrollOffset(fvi);
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1556
1467
|
// Change the size
|
|
1557
1468
|
this.__size = size;
|
|
1558
1469
|
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
// Already initialized, just update _virtualCount
|
|
1569
|
-
this._updateScrollerSize();
|
|
1570
|
-
this._virtualCount = this.items.length;
|
|
1571
|
-
this._render();
|
|
1572
|
-
}
|
|
1470
|
+
this._itemsChanged({
|
|
1471
|
+
path: 'items',
|
|
1472
|
+
});
|
|
1473
|
+
flush();
|
|
1474
|
+
|
|
1475
|
+
// Try to restore the scroll position if the new size is larger than 0
|
|
1476
|
+
if (size > 0) {
|
|
1477
|
+
fvi = Math.min(fvi, size - 1);
|
|
1478
|
+
this.scrollToIndex(fvi);
|
|
1573
1479
|
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
this._assignModels();
|
|
1480
|
+
const fviOffsetAfter = this.__getIndexScrollOffset(fvi);
|
|
1481
|
+
if (fviOffsetBefore !== undefined && fviOffsetAfter !== undefined) {
|
|
1482
|
+
this._scrollTop += fviOffsetBefore - fviOffsetAfter;
|
|
1483
|
+
}
|
|
1579
1484
|
}
|
|
1580
1485
|
|
|
1581
1486
|
if (!this.elementsContainer.children.length) {
|
|
1582
1487
|
requestAnimationFrame(() => this._resizeHandler());
|
|
1583
1488
|
}
|
|
1584
1489
|
|
|
1585
|
-
|
|
1586
|
-
//
|
|
1490
|
+
this.__preventElementUpdates = false;
|
|
1491
|
+
// Schedule and flush a resize handler
|
|
1587
1492
|
this._resizeHandler();
|
|
1588
1493
|
flush();
|
|
1589
1494
|
}
|
|
@@ -1648,20 +1553,16 @@ class IronListAdapter {
|
|
|
1648
1553
|
|
|
1649
1554
|
/** @private */
|
|
1650
1555
|
_assignModels(itemSet) {
|
|
1651
|
-
const updatedElements = [];
|
|
1652
1556
|
this._iterateItems((pidx, vidx) => {
|
|
1653
1557
|
const el = this._physicalItems[pidx];
|
|
1654
1558
|
el.hidden = vidx >= this.size;
|
|
1655
1559
|
if (!el.hidden) {
|
|
1656
1560
|
el.__virtualIndex = vidx + (this._vidxOffset || 0);
|
|
1657
1561
|
this.__updateElement(el, el.__virtualIndex);
|
|
1658
|
-
updatedElements.push(el);
|
|
1659
1562
|
} else {
|
|
1660
1563
|
delete el.__lastUpdatedIndex;
|
|
1661
1564
|
}
|
|
1662
1565
|
}, itemSet);
|
|
1663
|
-
|
|
1664
|
-
this.__afterElementsUpdated(updatedElements);
|
|
1665
1566
|
}
|
|
1666
1567
|
|
|
1667
1568
|
/** @private */
|
|
@@ -1790,9 +1691,7 @@ class IronListAdapter {
|
|
|
1790
1691
|
deltaY *= this._scrollPageHeight;
|
|
1791
1692
|
}
|
|
1792
1693
|
|
|
1793
|
-
|
|
1794
|
-
this._deltaYAcc = 0;
|
|
1795
|
-
}
|
|
1694
|
+
this._deltaYAcc = this._deltaYAcc || 0;
|
|
1796
1695
|
|
|
1797
1696
|
if (this._wheelAnimationFrame) {
|
|
1798
1697
|
// Accumulate wheel delta while a frame is being processed
|
|
@@ -1865,29 +1764,6 @@ class IronListAdapter {
|
|
|
1865
1764
|
);
|
|
1866
1765
|
}
|
|
1867
1766
|
|
|
1868
|
-
/**
|
|
1869
|
-
* Increases the pool size.
|
|
1870
|
-
* @override
|
|
1871
|
-
*/
|
|
1872
|
-
_increasePoolIfNeeded(count) {
|
|
1873
|
-
if (this._physicalCount > 2 && count) {
|
|
1874
|
-
// The iron-list logic has already created some physical items and
|
|
1875
|
-
// has decided to create more. Since each item creation round is
|
|
1876
|
-
// expensive, let's try to create the remaining items in one go.
|
|
1877
|
-
|
|
1878
|
-
// Calculate the total item count that would be needed to fill the viewport
|
|
1879
|
-
// plus the buffer assuming rest of the items to be of the average size
|
|
1880
|
-
// of the items already created.
|
|
1881
|
-
const totalItemCount = Math.ceil(this._optPhysicalSize / this._physicalAverage);
|
|
1882
|
-
const missingItemCount = totalItemCount - this._physicalCount;
|
|
1883
|
-
// Create the remaining items in one go. Use a maximum of 100 items
|
|
1884
|
-
// as a safety measure.
|
|
1885
|
-
super._increasePoolIfNeeded(Math.max(count, Math.min(100, missingItemCount)));
|
|
1886
|
-
} else {
|
|
1887
|
-
super._increasePoolIfNeeded(count);
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
1767
|
/**
|
|
1892
1768
|
* @returns {Number|undefined} - The browser's default font-size in pixels
|
|
1893
1769
|
* @private
|
|
@@ -2017,24 +1893,6 @@ class Virtualizer {
|
|
|
2017
1893
|
this.__adapter = new IronListAdapter(config);
|
|
2018
1894
|
}
|
|
2019
1895
|
|
|
2020
|
-
/**
|
|
2021
|
-
* Gets the index of the first visible item in the viewport.
|
|
2022
|
-
*
|
|
2023
|
-
* @return {number}
|
|
2024
|
-
*/
|
|
2025
|
-
get firstVisibleIndex() {
|
|
2026
|
-
return this.__adapter.adjustedFirstVisibleIndex;
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
/**
|
|
2030
|
-
* Gets the index of the last visible item in the viewport.
|
|
2031
|
-
*
|
|
2032
|
-
* @return {number}
|
|
2033
|
-
*/
|
|
2034
|
-
get lastVisibleIndex() {
|
|
2035
|
-
return this.__adapter.adjustedLastVisibleIndex;
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
1896
|
/**
|
|
2039
1897
|
* The size of the virtualizer
|
|
2040
1898
|
* @return {number | undefined} The size of the virtualizer
|
|
@@ -2082,11 +1940,29 @@ class Virtualizer {
|
|
|
2082
1940
|
flush() {
|
|
2083
1941
|
this.__adapter.flush();
|
|
2084
1942
|
}
|
|
1943
|
+
|
|
1944
|
+
/**
|
|
1945
|
+
* Gets the index of the first visible item in the viewport.
|
|
1946
|
+
*
|
|
1947
|
+
* @return {number}
|
|
1948
|
+
*/
|
|
1949
|
+
get firstVisibleIndex() {
|
|
1950
|
+
return this.__adapter.adjustedFirstVisibleIndex;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
/**
|
|
1954
|
+
* Gets the index of the last visible item in the viewport.
|
|
1955
|
+
*
|
|
1956
|
+
* @return {number}
|
|
1957
|
+
*/
|
|
1958
|
+
get lastVisibleIndex() {
|
|
1959
|
+
return this.__adapter.adjustedLastVisibleIndex;
|
|
1960
|
+
}
|
|
2085
1961
|
}
|
|
2086
1962
|
|
|
2087
1963
|
/**
|
|
2088
1964
|
* @license
|
|
2089
|
-
* Copyright (c) 2015 -
|
|
1965
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
2090
1966
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2091
1967
|
*/
|
|
2092
1968
|
|
|
@@ -2103,454 +1979,394 @@ const ComboBoxPlaceholder = class ComboBoxPlaceholder {
|
|
|
2103
1979
|
|
|
2104
1980
|
/**
|
|
2105
1981
|
* @license
|
|
2106
|
-
* Copyright (c) 2015 -
|
|
1982
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
2107
1983
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2108
1984
|
*/
|
|
2109
1985
|
|
|
2110
1986
|
/**
|
|
2111
|
-
*
|
|
1987
|
+
* Element for internal use only.
|
|
1988
|
+
*
|
|
1989
|
+
* @extends HTMLElement
|
|
1990
|
+
* @private
|
|
2112
1991
|
*/
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
/**
|
|
2118
|
-
* A full set of items to filter the visible options from.
|
|
2119
|
-
* Set to an empty array when combo-box is not opened.
|
|
2120
|
-
*/
|
|
2121
|
-
items: {
|
|
2122
|
-
type: Array,
|
|
2123
|
-
observer: '__itemsChanged',
|
|
2124
|
-
},
|
|
2125
|
-
|
|
2126
|
-
/**
|
|
2127
|
-
* Index of an item that has focus outline and is scrolled into view.
|
|
2128
|
-
* The actual focus still remains in the input field.
|
|
2129
|
-
*/
|
|
2130
|
-
focusedIndex: {
|
|
2131
|
-
type: Number,
|
|
2132
|
-
observer: '__focusedIndexChanged',
|
|
2133
|
-
},
|
|
2134
|
-
|
|
2135
|
-
/**
|
|
2136
|
-
* Set to true while combo-box fetches new page from the data provider.
|
|
2137
|
-
*/
|
|
2138
|
-
loading: {
|
|
2139
|
-
type: Boolean,
|
|
2140
|
-
observer: '__loadingChanged',
|
|
2141
|
-
},
|
|
2142
|
-
|
|
2143
|
-
/**
|
|
2144
|
-
* Whether the combo-box is currently opened or not. If set to false,
|
|
2145
|
-
* calling `scrollIntoView` does not have any effect.
|
|
2146
|
-
*/
|
|
2147
|
-
opened: {
|
|
2148
|
-
type: Boolean,
|
|
2149
|
-
observer: '__openedChanged',
|
|
2150
|
-
},
|
|
1992
|
+
class ComboBoxScroller extends PolymerElement {
|
|
1993
|
+
static get is() {
|
|
1994
|
+
return 'vaadin-combo-box-scroller';
|
|
1995
|
+
}
|
|
2151
1996
|
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
1997
|
+
static get template() {
|
|
1998
|
+
return html`
|
|
1999
|
+
<style>
|
|
2000
|
+
:host {
|
|
2001
|
+
display: block;
|
|
2002
|
+
min-height: 1px;
|
|
2003
|
+
overflow: auto;
|
|
2159
2004
|
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
*/
|
|
2163
|
-
itemIdPath: {
|
|
2164
|
-
type: String,
|
|
2165
|
-
},
|
|
2005
|
+
/* Fixes item background from getting on top of scrollbars on Safari */
|
|
2006
|
+
transform: translate3d(0, 0, 0);
|
|
2166
2007
|
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
*/
|
|
2170
|
-
owner: {
|
|
2171
|
-
type: Object,
|
|
2172
|
-
},
|
|
2008
|
+
/* Enable momentum scrolling on iOS */
|
|
2009
|
+
-webkit-overflow-scrolling: touch;
|
|
2173
2010
|
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
getItemLabel: {
|
|
2178
|
-
type: Object,
|
|
2179
|
-
},
|
|
2011
|
+
/* Fixes scrollbar disappearing when 'Show scroll bars: Always' enabled in Safari */
|
|
2012
|
+
box-shadow: 0 0 0 white;
|
|
2013
|
+
}
|
|
2180
2014
|
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2015
|
+
#selector {
|
|
2016
|
+
border-width: var(--_vaadin-combo-box-items-container-border-width);
|
|
2017
|
+
border-style: var(--_vaadin-combo-box-items-container-border-style);
|
|
2018
|
+
border-color: var(--_vaadin-combo-box-items-container-border-color);
|
|
2019
|
+
position: relative;
|
|
2020
|
+
}
|
|
2021
|
+
</style>
|
|
2022
|
+
<div id="selector">
|
|
2023
|
+
<slot></slot>
|
|
2024
|
+
</div>
|
|
2025
|
+
`;
|
|
2026
|
+
}
|
|
2188
2027
|
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2028
|
+
static get properties() {
|
|
2029
|
+
return {
|
|
2030
|
+
/**
|
|
2031
|
+
* A full set of items to filter the visible options from.
|
|
2032
|
+
* Set to an empty array when combo-box is not opened.
|
|
2033
|
+
*/
|
|
2034
|
+
items: {
|
|
2035
|
+
type: Array,
|
|
2036
|
+
observer: '__itemsChanged',
|
|
2037
|
+
},
|
|
2197
2038
|
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2039
|
+
/**
|
|
2040
|
+
* Index of an item that has focus outline and is scrolled into view.
|
|
2041
|
+
* The actual focus still remains in the input field.
|
|
2042
|
+
*/
|
|
2043
|
+
focusedIndex: {
|
|
2044
|
+
type: Number,
|
|
2045
|
+
observer: '__focusedIndexChanged',
|
|
2046
|
+
},
|
|
2202
2047
|
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
})
|
|
2211
|
-
.reduce((sum, v) => {
|
|
2212
|
-
return sum + v;
|
|
2213
|
-
});
|
|
2214
|
-
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Set to true while combo-box fetches new page from the data provider.
|
|
2050
|
+
*/
|
|
2051
|
+
loading: {
|
|
2052
|
+
type: Boolean,
|
|
2053
|
+
observer: '__loadingChanged',
|
|
2054
|
+
},
|
|
2215
2055
|
|
|
2216
|
-
|
|
2217
|
-
|
|
2056
|
+
/**
|
|
2057
|
+
* Whether the combo-box is currently opened or not. If set to false,
|
|
2058
|
+
* calling `scrollIntoView` does not have any effect.
|
|
2059
|
+
*/
|
|
2060
|
+
opened: {
|
|
2061
|
+
type: Boolean,
|
|
2062
|
+
observer: '__openedChanged',
|
|
2063
|
+
},
|
|
2218
2064
|
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2065
|
+
/**
|
|
2066
|
+
* The selected item from the `items` array.
|
|
2067
|
+
*/
|
|
2068
|
+
selectedItem: {
|
|
2069
|
+
type: Object,
|
|
2070
|
+
observer: '__selectedItemChanged',
|
|
2071
|
+
},
|
|
2222
2072
|
|
|
2223
|
-
|
|
2073
|
+
/**
|
|
2074
|
+
* Path for the id of the item, used to detect whether the item is selected.
|
|
2075
|
+
*/
|
|
2076
|
+
itemIdPath: {
|
|
2077
|
+
type: String,
|
|
2078
|
+
},
|
|
2224
2079
|
|
|
2225
|
-
|
|
2226
|
-
|
|
2080
|
+
/**
|
|
2081
|
+
* Reference to the combo-box, used by the item elements.
|
|
2082
|
+
*/
|
|
2083
|
+
comboBox: {
|
|
2084
|
+
type: Object,
|
|
2085
|
+
},
|
|
2227
2086
|
|
|
2228
|
-
|
|
2229
|
-
|
|
2087
|
+
/**
|
|
2088
|
+
* Function used to set a label for every combo-box item.
|
|
2089
|
+
*/
|
|
2090
|
+
getItemLabel: {
|
|
2091
|
+
type: Object,
|
|
2092
|
+
},
|
|
2230
2093
|
|
|
2231
|
-
|
|
2094
|
+
/**
|
|
2095
|
+
* Function used to render the content of every combo-box item.
|
|
2096
|
+
*/
|
|
2097
|
+
renderer: {
|
|
2098
|
+
type: Object,
|
|
2099
|
+
observer: '__rendererChanged',
|
|
2100
|
+
},
|
|
2232
2101
|
|
|
2233
|
-
|
|
2102
|
+
/**
|
|
2103
|
+
* Used to propagate the `theme` attribute from the host element.
|
|
2104
|
+
*/
|
|
2105
|
+
theme: {
|
|
2106
|
+
type: String,
|
|
2107
|
+
},
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
2234
2110
|
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
scrollTarget: this,
|
|
2240
|
-
scrollContainer: this.$.selector,
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2111
|
+
constructor() {
|
|
2112
|
+
super();
|
|
2113
|
+
this.__boundOnItemClick = this.__onItemClick.bind(this);
|
|
2114
|
+
}
|
|
2243
2115
|
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
requestContentUpdate() {
|
|
2248
|
-
if (this.__virtualizer) {
|
|
2249
|
-
this.__virtualizer.update();
|
|
2250
|
-
}
|
|
2116
|
+
__openedChanged(opened) {
|
|
2117
|
+
if (opened) {
|
|
2118
|
+
this.requestContentUpdate();
|
|
2251
2119
|
}
|
|
2120
|
+
}
|
|
2252
2121
|
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
* @param {number} index
|
|
2257
|
-
*/
|
|
2258
|
-
scrollIntoView(index) {
|
|
2259
|
-
if (!(this.opened && index >= 0)) {
|
|
2260
|
-
return;
|
|
2261
|
-
}
|
|
2262
|
-
|
|
2263
|
-
const visibleItemsCount = this._visibleItemsCount();
|
|
2122
|
+
/** @protected */
|
|
2123
|
+
ready() {
|
|
2124
|
+
super.ready();
|
|
2264
2125
|
|
|
2265
|
-
|
|
2126
|
+
// Ensure every instance has unique ID
|
|
2127
|
+
this.id = `${this.localName}-${generateUniqueId()}`;
|
|
2266
2128
|
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
// First scroll to target (will be at the top of the scroller) to make sure it's rendered.
|
|
2270
|
-
this.__virtualizer.scrollToIndex(index);
|
|
2271
|
-
// Then calculate the index for the following scroll (to get the target to bottom of the scroller).
|
|
2272
|
-
targetIndex = index - visibleItemsCount + 1;
|
|
2273
|
-
} else if (index > this.__virtualizer.firstVisibleIndex) {
|
|
2274
|
-
// The item is already visible, scrolling is unnecessary per se. But we need to trigger iron-list to set
|
|
2275
|
-
// the correct scrollTop on the scrollTarget. Scrolling to firstVisibleIndex.
|
|
2276
|
-
targetIndex = this.__virtualizer.firstVisibleIndex;
|
|
2277
|
-
}
|
|
2278
|
-
this.__virtualizer.scrollToIndex(Math.max(0, targetIndex));
|
|
2129
|
+
// Allow extensions to customize tag name for the items
|
|
2130
|
+
this.__hostTagName = this.constructor.is.replace('-scroller', '');
|
|
2279
2131
|
|
|
2280
|
-
|
|
2281
|
-
const lastPhysicalItem = [...this.children].find(
|
|
2282
|
-
(el) => !el.hidden && el.index === this.__virtualizer.lastVisibleIndex,
|
|
2283
|
-
);
|
|
2284
|
-
if (!lastPhysicalItem || index !== lastPhysicalItem.index) {
|
|
2285
|
-
return;
|
|
2286
|
-
}
|
|
2287
|
-
const lastPhysicalItemRect = lastPhysicalItem.getBoundingClientRect();
|
|
2288
|
-
const scrollerRect = this.getBoundingClientRect();
|
|
2289
|
-
const scrollTopAdjust = lastPhysicalItemRect.bottom - scrollerRect.bottom + this._viewportTotalPaddingBottom;
|
|
2290
|
-
if (scrollTopAdjust > 0) {
|
|
2291
|
-
this.scrollTop += scrollTopAdjust;
|
|
2292
|
-
}
|
|
2293
|
-
}
|
|
2132
|
+
this.setAttribute('role', 'listbox');
|
|
2294
2133
|
|
|
2295
|
-
|
|
2296
|
-
* @param {string | object} item
|
|
2297
|
-
* @param {string | object} selectedItem
|
|
2298
|
-
* @param {string} itemIdPath
|
|
2299
|
-
* @protected
|
|
2300
|
-
*/
|
|
2301
|
-
_isItemSelected(item, selectedItem, itemIdPath) {
|
|
2302
|
-
if (item instanceof ComboBoxPlaceholder) {
|
|
2303
|
-
return false;
|
|
2304
|
-
} else if (itemIdPath && item !== undefined && selectedItem !== undefined) {
|
|
2305
|
-
return get(itemIdPath, item) === get(itemIdPath, selectedItem);
|
|
2306
|
-
}
|
|
2307
|
-
return item === selectedItem;
|
|
2308
|
-
}
|
|
2134
|
+
this.addEventListener('click', (e) => e.stopPropagation());
|
|
2309
2135
|
|
|
2310
|
-
|
|
2311
|
-
__itemsChanged(items) {
|
|
2312
|
-
if (this.__virtualizer && items) {
|
|
2313
|
-
this.__virtualizer.size = items.length;
|
|
2314
|
-
this.__virtualizer.flush();
|
|
2315
|
-
this.requestContentUpdate();
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2136
|
+
this.__patchWheelOverScrolling();
|
|
2318
2137
|
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
this.
|
|
2322
|
-
|
|
2138
|
+
this.__virtualizer = new Virtualizer({
|
|
2139
|
+
createElements: this.__createElements.bind(this),
|
|
2140
|
+
updateElement: this.__updateElement.bind(this),
|
|
2141
|
+
elementsContainer: this,
|
|
2142
|
+
scrollTarget: this,
|
|
2143
|
+
scrollContainer: this.$.selector,
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2323
2146
|
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
this.requestContentUpdate();
|
|
2328
|
-
}
|
|
2147
|
+
requestContentUpdate() {
|
|
2148
|
+
if (this.__virtualizer) {
|
|
2149
|
+
this.__virtualizer.update();
|
|
2329
2150
|
}
|
|
2151
|
+
}
|
|
2330
2152
|
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2153
|
+
scrollIntoView(index) {
|
|
2154
|
+
if (!(this.opened && index >= 0)) {
|
|
2155
|
+
return;
|
|
2334
2156
|
}
|
|
2335
2157
|
|
|
2336
|
-
|
|
2337
|
-
__focusedIndexChanged(index, oldIndex) {
|
|
2338
|
-
if (index !== oldIndex) {
|
|
2339
|
-
this.requestContentUpdate();
|
|
2340
|
-
}
|
|
2158
|
+
const visibleItemsCount = this._visibleItemsCount();
|
|
2341
2159
|
|
|
2342
|
-
|
|
2343
|
-
// when requesting next page from the data provider on scroll.
|
|
2344
|
-
if (index >= 0 && !this.loading) {
|
|
2345
|
-
this.scrollIntoView(index);
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2160
|
+
let targetIndex = index;
|
|
2348
2161
|
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2162
|
+
if (index > this.__virtualizer.lastVisibleIndex - 1) {
|
|
2163
|
+
// Index is below the bottom, scrolling down. Make the item appear at the bottom.
|
|
2164
|
+
// First scroll to target (will be at the top of the scroller) to make sure it's rendered.
|
|
2165
|
+
this.__virtualizer.scrollToIndex(index);
|
|
2166
|
+
// Then calculate the index for the following scroll (to get the target to bottom of the scroller).
|
|
2167
|
+
targetIndex = index - visibleItemsCount + 1;
|
|
2168
|
+
} else if (index > this.__virtualizer.firstVisibleIndex) {
|
|
2169
|
+
// The item is already visible, scrolling is unnecessary per se. But we need to trigger iron-list to set
|
|
2170
|
+
// the correct scrollTop on the scrollTarget. Scrolling to firstVisibleIndex.
|
|
2171
|
+
targetIndex = this.__virtualizer.firstVisibleIndex;
|
|
2354
2172
|
}
|
|
2173
|
+
this.__virtualizer.scrollToIndex(Math.max(0, targetIndex));
|
|
2355
2174
|
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
item.tabIndex = '-1';
|
|
2363
|
-
item.style.width = '100%';
|
|
2364
|
-
return item;
|
|
2365
|
-
});
|
|
2175
|
+
// Sometimes the item is partly below the bottom edge, detect and adjust.
|
|
2176
|
+
const lastPhysicalItem = [...this.children].find(
|
|
2177
|
+
(el) => !el.hidden && el.index === this.__virtualizer.lastVisibleIndex,
|
|
2178
|
+
);
|
|
2179
|
+
if (!lastPhysicalItem || index !== lastPhysicalItem.index) {
|
|
2180
|
+
return;
|
|
2366
2181
|
}
|
|
2182
|
+
const lastPhysicalItemRect = lastPhysicalItem.getBoundingClientRect();
|
|
2183
|
+
const scrollerRect = this.getBoundingClientRect();
|
|
2184
|
+
const scrollTopAdjust = lastPhysicalItemRect.bottom - scrollerRect.bottom + this._viewportTotalPaddingBottom;
|
|
2185
|
+
if (scrollTopAdjust > 0) {
|
|
2186
|
+
this.scrollTop += scrollTopAdjust;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2367
2189
|
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
*/
|
|
2373
|
-
_updateElement(el, index) {
|
|
2374
|
-
const item = this.items[index];
|
|
2375
|
-
const focusedIndex = this.focusedIndex;
|
|
2376
|
-
const selected = this._isItemSelected(item, this.selectedItem, this.itemIdPath);
|
|
2377
|
-
|
|
2378
|
-
el.setProperties({
|
|
2379
|
-
item,
|
|
2380
|
-
index,
|
|
2381
|
-
label: this.getItemLabel(item),
|
|
2382
|
-
selected,
|
|
2383
|
-
renderer: this.renderer,
|
|
2384
|
-
focused: !this.loading && focusedIndex === index,
|
|
2385
|
-
});
|
|
2386
|
-
|
|
2387
|
-
el.id = `${this.__hostTagName}-item-${index}`;
|
|
2388
|
-
el.setAttribute('role', index !== undefined ? 'option' : false);
|
|
2389
|
-
el.setAttribute('aria-selected', selected.toString());
|
|
2390
|
-
el.setAttribute('aria-posinset', index + 1);
|
|
2391
|
-
el.setAttribute('aria-setsize', this.items.length);
|
|
2190
|
+
/** @private */
|
|
2191
|
+
__getAriaRole(itemIndex) {
|
|
2192
|
+
return itemIndex !== undefined ? 'option' : false;
|
|
2193
|
+
}
|
|
2392
2194
|
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
}
|
|
2195
|
+
/** @private */
|
|
2196
|
+
__isItemFocused(focusedIndex, itemIndex) {
|
|
2197
|
+
return !this.loading && focusedIndex === itemIndex;
|
|
2198
|
+
}
|
|
2398
2199
|
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2200
|
+
/** @protected */
|
|
2201
|
+
_isItemSelected(item, selectedItem, itemIdPath) {
|
|
2202
|
+
if (item instanceof ComboBoxPlaceholder) {
|
|
2203
|
+
return false;
|
|
2204
|
+
} else if (itemIdPath && item !== undefined && selectedItem !== undefined) {
|
|
2205
|
+
return this.get(itemIdPath, item) === this.get(itemIdPath, selectedItem);
|
|
2402
2206
|
}
|
|
2207
|
+
return item === selectedItem;
|
|
2208
|
+
}
|
|
2403
2209
|
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2210
|
+
/** @private */
|
|
2211
|
+
__itemsChanged(items) {
|
|
2212
|
+
if (this.__virtualizer && items) {
|
|
2213
|
+
this.__virtualizer.size = items.length;
|
|
2214
|
+
this.__virtualizer.flush();
|
|
2215
|
+
this.requestContentUpdate();
|
|
2407
2216
|
}
|
|
2217
|
+
}
|
|
2408
2218
|
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
* @private
|
|
2414
|
-
*/
|
|
2415
|
-
__patchWheelOverScrolling() {
|
|
2416
|
-
this.$.selector.addEventListener('wheel', (e) => {
|
|
2417
|
-
const scrolledToTop = this.scrollTop === 0;
|
|
2418
|
-
const scrolledToBottom = this.scrollHeight - this.scrollTop - this.clientHeight <= 1;
|
|
2419
|
-
if (scrolledToTop && e.deltaY < 0) {
|
|
2420
|
-
e.preventDefault();
|
|
2421
|
-
} else if (scrolledToBottom && e.deltaY > 0) {
|
|
2422
|
-
e.preventDefault();
|
|
2423
|
-
}
|
|
2424
|
-
});
|
|
2425
|
-
}
|
|
2219
|
+
/** @private */
|
|
2220
|
+
__loadingChanged() {
|
|
2221
|
+
this.requestContentUpdate();
|
|
2222
|
+
}
|
|
2426
2223
|
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
* The event is dispatched asynchronously to prevent an immediate page request and therefore
|
|
2432
|
-
* a possible infinite recursion in case the data provider implements page request cancelation logic
|
|
2433
|
-
* by invoking data provider page callbacks with an empty array.
|
|
2434
|
-
* The infinite recursion may occur otherwise since invoking a data provider page callback with an empty array
|
|
2435
|
-
* triggers a synchronous scroller update and, if the callback corresponds to the currently visible page,
|
|
2436
|
-
* the scroller will synchronously request the page again which may lead to looping in the end.
|
|
2437
|
-
* That was the case for the Flow counterpart:
|
|
2438
|
-
* https://github.com/vaadin/flow-components/issues/3553#issuecomment-1239344828
|
|
2439
|
-
* @private
|
|
2440
|
-
*/
|
|
2441
|
-
__requestItemByIndex(index) {
|
|
2442
|
-
requestAnimationFrame(() => {
|
|
2443
|
-
this.dispatchEvent(
|
|
2444
|
-
new CustomEvent('index-requested', {
|
|
2445
|
-
detail: {
|
|
2446
|
-
index,
|
|
2447
|
-
currentScrollerPos: this._oldScrollerPosition,
|
|
2448
|
-
},
|
|
2449
|
-
}),
|
|
2450
|
-
);
|
|
2451
|
-
});
|
|
2452
|
-
}
|
|
2224
|
+
/** @private */
|
|
2225
|
+
__selectedItemChanged() {
|
|
2226
|
+
this.requestContentUpdate();
|
|
2227
|
+
}
|
|
2453
2228
|
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
this.
|
|
2458
|
-
const hasItems = this.__virtualizer.size > 0;
|
|
2459
|
-
return hasItems ? this.__virtualizer.lastVisibleIndex - this.__virtualizer.firstVisibleIndex + 1 : 0;
|
|
2229
|
+
/** @private */
|
|
2230
|
+
__focusedIndexChanged(index, oldIndex) {
|
|
2231
|
+
if (index !== oldIndex) {
|
|
2232
|
+
this.requestContentUpdate();
|
|
2460
2233
|
}
|
|
2461
|
-
};
|
|
2462
2234
|
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2235
|
+
// Do not jump back to the previously focused item while loading
|
|
2236
|
+
// when requesting next page from the data provider on scroll.
|
|
2237
|
+
if (index >= 0 && !this.loading) {
|
|
2238
|
+
this.scrollIntoView(index);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2468
2241
|
|
|
2469
|
-
/**
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
* @mixes ComboBoxScrollerMixin
|
|
2475
|
-
* @private
|
|
2476
|
-
*/
|
|
2477
|
-
class ComboBoxScroller extends ComboBoxScrollerMixin(PolymerElement) {
|
|
2478
|
-
static get is() {
|
|
2479
|
-
return 'vaadin-combo-box-scroller';
|
|
2242
|
+
/** @private */
|
|
2243
|
+
__rendererChanged(renderer, oldRenderer) {
|
|
2244
|
+
if (renderer || oldRenderer) {
|
|
2245
|
+
this.requestContentUpdate();
|
|
2246
|
+
}
|
|
2480
2247
|
}
|
|
2481
2248
|
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2249
|
+
/** @private */
|
|
2250
|
+
__createElements(count) {
|
|
2251
|
+
return [...Array(count)].map(() => {
|
|
2252
|
+
const item = document.createElement(`${this.__hostTagName}-item`);
|
|
2253
|
+
item.addEventListener('click', this.__boundOnItemClick);
|
|
2254
|
+
// Negative tabindex prevents the item content from being focused.
|
|
2255
|
+
item.tabIndex = '-1';
|
|
2256
|
+
item.style.width = '100%';
|
|
2257
|
+
return item;
|
|
2258
|
+
});
|
|
2259
|
+
}
|
|
2489
2260
|
|
|
2490
|
-
|
|
2491
|
-
|
|
2261
|
+
/** @private */
|
|
2262
|
+
__updateElement(el, index) {
|
|
2263
|
+
const item = this.items[index];
|
|
2264
|
+
const focusedIndex = this.focusedIndex;
|
|
2265
|
+
const selected = this._isItemSelected(item, this.selectedItem, this.itemIdPath);
|
|
2266
|
+
|
|
2267
|
+
el.setProperties({
|
|
2268
|
+
item,
|
|
2269
|
+
index,
|
|
2270
|
+
label: this.getItemLabel(item),
|
|
2271
|
+
selected,
|
|
2272
|
+
renderer: this.renderer,
|
|
2273
|
+
focused: this.__isItemFocused(focusedIndex, index),
|
|
2274
|
+
});
|
|
2492
2275
|
|
|
2493
|
-
|
|
2494
|
-
|
|
2276
|
+
el.id = `${this.__hostTagName}-item-${index}`;
|
|
2277
|
+
el.setAttribute('role', this.__getAriaRole(index));
|
|
2278
|
+
el.setAttribute('aria-selected', selected.toString());
|
|
2279
|
+
el.setAttribute('aria-posinset', index + 1);
|
|
2280
|
+
el.setAttribute('aria-setsize', this.items.length);
|
|
2495
2281
|
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2282
|
+
if (this.theme) {
|
|
2283
|
+
el.setAttribute('theme', this.theme);
|
|
2284
|
+
} else {
|
|
2285
|
+
el.removeAttribute('theme');
|
|
2286
|
+
}
|
|
2499
2287
|
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
border-color: var(--_vaadin-combo-box-items-container-border-color, transparent);
|
|
2504
|
-
position: relative;
|
|
2505
|
-
}
|
|
2506
|
-
</style>
|
|
2507
|
-
<div id="selector">
|
|
2508
|
-
<slot></slot>
|
|
2509
|
-
</div>
|
|
2510
|
-
`;
|
|
2288
|
+
if (item instanceof ComboBoxPlaceholder) {
|
|
2289
|
+
this.__requestItemByIndex(index);
|
|
2290
|
+
}
|
|
2511
2291
|
}
|
|
2512
|
-
}
|
|
2513
2292
|
|
|
2514
|
-
|
|
2293
|
+
/** @private */
|
|
2294
|
+
__onItemClick(e) {
|
|
2295
|
+
this.dispatchEvent(new CustomEvent('selection-changed', { detail: { item: e.currentTarget.item } }));
|
|
2296
|
+
}
|
|
2515
2297
|
|
|
2516
|
-
/**
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2298
|
+
/**
|
|
2299
|
+
* We want to prevent the kinetic scrolling energy from being transferred from the overlay contents over to the parent.
|
|
2300
|
+
* Further improvement ideas: after the contents have been scrolled to the top or bottom and scrolling has stopped, it could allow
|
|
2301
|
+
* scrolling the parent similarly to touch scrolling.
|
|
2302
|
+
*/
|
|
2303
|
+
__patchWheelOverScrolling() {
|
|
2304
|
+
this.$.selector.addEventListener('wheel', (e) => {
|
|
2305
|
+
const scrolledToTop = this.scrollTop === 0;
|
|
2306
|
+
const scrolledToBottom = this.scrollHeight - this.scrollTop - this.clientHeight <= 1;
|
|
2307
|
+
if (scrolledToTop && e.deltaY < 0) {
|
|
2308
|
+
e.preventDefault();
|
|
2309
|
+
} else if (scrolledToBottom && e.deltaY > 0) {
|
|
2310
|
+
e.preventDefault();
|
|
2311
|
+
}
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2521
2314
|
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
/**
|
|
2533
|
-
* A regular expression that the value is checked against.
|
|
2534
|
-
* The pattern must match the entire value, not just some subset.
|
|
2535
|
-
*/
|
|
2536
|
-
pattern: {
|
|
2537
|
-
type: String,
|
|
2538
|
-
},
|
|
2539
|
-
};
|
|
2315
|
+
get _viewportTotalPaddingBottom() {
|
|
2316
|
+
if (this._cachedViewportTotalPaddingBottom === undefined) {
|
|
2317
|
+
const itemsStyle = window.getComputedStyle(this.$.selector);
|
|
2318
|
+
this._cachedViewportTotalPaddingBottom = [itemsStyle.paddingBottom, itemsStyle.borderBottomWidth]
|
|
2319
|
+
.map((v) => {
|
|
2320
|
+
return parseInt(v, 10);
|
|
2321
|
+
})
|
|
2322
|
+
.reduce((sum, v) => {
|
|
2323
|
+
return sum + v;
|
|
2324
|
+
});
|
|
2540
2325
|
}
|
|
2541
2326
|
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
}
|
|
2327
|
+
return this._cachedViewportTotalPaddingBottom;
|
|
2328
|
+
}
|
|
2545
2329
|
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2330
|
+
/**
|
|
2331
|
+
* Dispatches an `index-requested` event for the given index to notify
|
|
2332
|
+
* the data provider that it should start loading the page containing the requested index.
|
|
2333
|
+
*
|
|
2334
|
+
* The event is dispatched asynchronously to prevent an immediate page request and therefore
|
|
2335
|
+
* a possible infinite recursion in case the data provider implements page request cancelation logic
|
|
2336
|
+
* by invoking data provider page callbacks with an empty array.
|
|
2337
|
+
* The infinite recursion may occur otherwise since invoking a data provider page callback with an empty array
|
|
2338
|
+
* triggers a synchronous scroller update and, if the callback corresponds to the currently visible page,
|
|
2339
|
+
* the scroller will synchronously request the page again which may lead to looping in the end.
|
|
2340
|
+
* That was the case for the Flow counterpart:
|
|
2341
|
+
* https://github.com/vaadin/flow-components/issues/3553#issuecomment-1239344828
|
|
2342
|
+
*/
|
|
2343
|
+
__requestItemByIndex(index) {
|
|
2344
|
+
requestAnimationFrame(() => {
|
|
2345
|
+
this.dispatchEvent(
|
|
2346
|
+
new CustomEvent('index-requested', {
|
|
2347
|
+
detail: {
|
|
2348
|
+
index,
|
|
2349
|
+
currentScrollerPos: this._oldScrollerPosition,
|
|
2350
|
+
},
|
|
2351
|
+
}),
|
|
2352
|
+
);
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
/** @private */
|
|
2357
|
+
_visibleItemsCount() {
|
|
2358
|
+
// Ensure items are positioned
|
|
2359
|
+
this.__virtualizer.scrollToIndex(this.__virtualizer.firstVisibleIndex);
|
|
2360
|
+
const hasItems = this.__virtualizer.size > 0;
|
|
2361
|
+
return hasItems ? this.__virtualizer.lastVisibleIndex - this.__virtualizer.firstVisibleIndex + 1 : 0;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
customElements.define(ComboBoxScroller.is, ComboBoxScroller);
|
|
2550
2366
|
|
|
2551
2367
|
/**
|
|
2552
2368
|
* @license
|
|
2553
|
-
* Copyright (c) 2015 -
|
|
2369
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
2554
2370
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2555
2371
|
*/
|
|
2556
2372
|
|
|
@@ -2860,18 +2676,20 @@ const ComboBoxDataProviderMixin = (superClass) =>
|
|
|
2860
2676
|
_flushPendingRequests(size) {
|
|
2861
2677
|
if (this._pendingRequests) {
|
|
2862
2678
|
const lastPage = Math.ceil(size / this.pageSize);
|
|
2863
|
-
Object.
|
|
2864
|
-
|
|
2865
|
-
|
|
2679
|
+
const pendingRequestsKeys = Object.keys(this._pendingRequests);
|
|
2680
|
+
for (let reqIdx = 0; reqIdx < pendingRequestsKeys.length; reqIdx++) {
|
|
2681
|
+
const page = parseInt(pendingRequestsKeys[reqIdx]);
|
|
2682
|
+
if (page >= lastPage) {
|
|
2683
|
+
this._pendingRequests[page]([], size);
|
|
2866
2684
|
}
|
|
2867
|
-
}
|
|
2685
|
+
}
|
|
2868
2686
|
}
|
|
2869
2687
|
}
|
|
2870
2688
|
};
|
|
2871
2689
|
|
|
2872
2690
|
/**
|
|
2873
2691
|
* @license
|
|
2874
|
-
* Copyright (c) 2021 -
|
|
2692
|
+
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
2875
2693
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2876
2694
|
*/
|
|
2877
2695
|
|
|
@@ -2896,7 +2714,7 @@ function processTemplates(component) {
|
|
|
2896
2714
|
|
|
2897
2715
|
/**
|
|
2898
2716
|
* @license
|
|
2899
|
-
* Copyright (c) 2015 -
|
|
2717
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
2900
2718
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2901
2719
|
*/
|
|
2902
2720
|
|
|
@@ -2930,19 +2748,10 @@ function findItemIndex(items, callback) {
|
|
|
2930
2748
|
|
|
2931
2749
|
/**
|
|
2932
2750
|
* @polymerMixin
|
|
2933
|
-
* @mixes ControllerMixin
|
|
2934
|
-
* @mixes ValidateMixin
|
|
2935
|
-
* @mixes DisabledMixin
|
|
2936
|
-
* @mixes InputMixin
|
|
2937
|
-
* @mixes KeyboardMixin
|
|
2938
|
-
* @mixes FocusMixin
|
|
2939
|
-
* @mixes OverlayClassMixin
|
|
2940
2751
|
* @param {function(new:HTMLElement)} subclass
|
|
2941
2752
|
*/
|
|
2942
2753
|
const ComboBoxMixin = (subclass) =>
|
|
2943
|
-
class
|
|
2944
|
-
ControllerMixin(ValidateMixin(FocusMixin(KeyboardMixin(InputMixin(DisabledMixin(subclass)))))),
|
|
2945
|
-
) {
|
|
2754
|
+
class VaadinComboBoxMixinElement extends ControllerMixin(KeyboardMixin(InputMixin(DisabledMixin(subclass)))) {
|
|
2946
2755
|
static get properties() {
|
|
2947
2756
|
return {
|
|
2948
2757
|
/**
|
|
@@ -3117,14 +2926,6 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3117
2926
|
observer: '_toggleElementChanged',
|
|
3118
2927
|
},
|
|
3119
2928
|
|
|
3120
|
-
/**
|
|
3121
|
-
* Set of items to be rendered in the dropdown.
|
|
3122
|
-
* @protected
|
|
3123
|
-
*/
|
|
3124
|
-
_dropdownItems: {
|
|
3125
|
-
type: Array,
|
|
3126
|
-
},
|
|
3127
|
-
|
|
3128
2929
|
/** @private */
|
|
3129
2930
|
_closeOnBlurIsPrevented: Boolean,
|
|
3130
2931
|
|
|
@@ -3142,13 +2943,14 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3142
2943
|
static get observers() {
|
|
3143
2944
|
return [
|
|
3144
2945
|
'_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
|
|
3145
|
-
'_openedOrItemsChanged(opened,
|
|
3146
|
-
'_updateScroller(_scroller,
|
|
2946
|
+
'_openedOrItemsChanged(opened, filteredItems, loading)',
|
|
2947
|
+
'_updateScroller(_scroller, filteredItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
|
|
3147
2948
|
];
|
|
3148
2949
|
}
|
|
3149
2950
|
|
|
3150
2951
|
constructor() {
|
|
3151
2952
|
super();
|
|
2953
|
+
this._boundOnFocusout = this._onFocusout.bind(this);
|
|
3152
2954
|
this._boundOverlaySelectedItemChanged = this._overlaySelectedItemChanged.bind(this);
|
|
3153
2955
|
this._boundOnClearButtonMouseDown = this.__onClearButtonMouseDown.bind(this);
|
|
3154
2956
|
this._boundOnClick = this._onClick.bind(this);
|
|
@@ -3165,6 +2967,24 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3165
2967
|
return 'vaadin-combo-box';
|
|
3166
2968
|
}
|
|
3167
2969
|
|
|
2970
|
+
/**
|
|
2971
|
+
* @return {string | undefined}
|
|
2972
|
+
* @protected
|
|
2973
|
+
*/
|
|
2974
|
+
get _inputElementValue() {
|
|
2975
|
+
return this.inputElement ? this.inputElement[this._propertyForValue] : undefined;
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
/**
|
|
2979
|
+
* @param {string} value
|
|
2980
|
+
* @protected
|
|
2981
|
+
*/
|
|
2982
|
+
set _inputElementValue(value) {
|
|
2983
|
+
if (this.inputElement) {
|
|
2984
|
+
this.inputElement[this._propertyForValue] = value;
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
|
|
3168
2988
|
/**
|
|
3169
2989
|
* Get a reference to the native `<input>` element.
|
|
3170
2990
|
* Override to provide a custom input.
|
|
@@ -3215,6 +3035,8 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3215
3035
|
this._initOverlay();
|
|
3216
3036
|
this._initScroller();
|
|
3217
3037
|
|
|
3038
|
+
this.addEventListener('focusout', this._boundOnFocusout);
|
|
3039
|
+
|
|
3218
3040
|
this._lastCommittedValue = this.value;
|
|
3219
3041
|
|
|
3220
3042
|
this.addEventListener('click', this._boundOnClick);
|
|
@@ -3222,7 +3044,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3222
3044
|
|
|
3223
3045
|
const bringToFrontListener = () => {
|
|
3224
3046
|
requestAnimationFrame(() => {
|
|
3225
|
-
this.
|
|
3047
|
+
this.$.overlay.bringToFront();
|
|
3226
3048
|
});
|
|
3227
3049
|
};
|
|
3228
3050
|
|
|
@@ -3313,8 +3135,6 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3313
3135
|
overlay.addEventListener('opened-changed', (e) => {
|
|
3314
3136
|
this._overlayOpened = e.detail.value;
|
|
3315
3137
|
});
|
|
3316
|
-
|
|
3317
|
-
this._overlayElement = overlay;
|
|
3318
3138
|
}
|
|
3319
3139
|
|
|
3320
3140
|
/**
|
|
@@ -3326,7 +3146,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3326
3146
|
_initScroller(host) {
|
|
3327
3147
|
const scrollerTag = `${this._tagNamePrefix}-scroller`;
|
|
3328
3148
|
|
|
3329
|
-
const overlay = this
|
|
3149
|
+
const overlay = this.$.overlay;
|
|
3330
3150
|
|
|
3331
3151
|
overlay.renderer = (root) => {
|
|
3332
3152
|
if (!root.firstChild) {
|
|
@@ -3339,7 +3159,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3339
3159
|
|
|
3340
3160
|
const scroller = overlay.querySelector(scrollerTag);
|
|
3341
3161
|
|
|
3342
|
-
scroller.
|
|
3162
|
+
scroller.comboBox = host || this;
|
|
3343
3163
|
scroller.getItemLabel = this._getItemLabel.bind(this);
|
|
3344
3164
|
scroller.addEventListener('selection-changed', this._boundOverlaySelectedItemChanged);
|
|
3345
3165
|
|
|
@@ -3382,7 +3202,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3382
3202
|
this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-opened', { bubbles: true, composed: true }));
|
|
3383
3203
|
|
|
3384
3204
|
this._onOpened();
|
|
3385
|
-
} else if (wasOpened && this.
|
|
3205
|
+
} else if (wasOpened && this.filteredItems && this.filteredItems.length) {
|
|
3386
3206
|
this.close();
|
|
3387
3207
|
|
|
3388
3208
|
this.dispatchEvent(new CustomEvent('vaadin-combo-box-dropdown-closed', { bubbles: true, composed: true }));
|
|
@@ -3434,7 +3254,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3434
3254
|
}
|
|
3435
3255
|
}
|
|
3436
3256
|
|
|
3437
|
-
this.
|
|
3257
|
+
this.$.overlay.restoreFocusOnClose = true;
|
|
3438
3258
|
} else {
|
|
3439
3259
|
this._onClosed();
|
|
3440
3260
|
if (this._openedWithFocusRing && this._isInputFocused()) {
|
|
@@ -3468,19 +3288,13 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3468
3288
|
return event.composedPath()[0] === this.clearElement;
|
|
3469
3289
|
}
|
|
3470
3290
|
|
|
3471
|
-
/** @private */
|
|
3472
|
-
__onClearButtonMouseDown(event) {
|
|
3473
|
-
event.preventDefault(); // Prevent native focusout event
|
|
3474
|
-
this.inputElement.focus();
|
|
3475
|
-
}
|
|
3476
|
-
|
|
3477
3291
|
/**
|
|
3478
3292
|
* @param {Event} event
|
|
3479
3293
|
* @protected
|
|
3480
3294
|
*/
|
|
3481
|
-
|
|
3295
|
+
_handleClearButtonClick(event) {
|
|
3482
3296
|
event.preventDefault();
|
|
3483
|
-
this.
|
|
3297
|
+
this._clear();
|
|
3484
3298
|
|
|
3485
3299
|
// De-select dropdown item
|
|
3486
3300
|
if (this.opened) {
|
|
@@ -3516,13 +3330,15 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3516
3330
|
}
|
|
3517
3331
|
|
|
3518
3332
|
/** @private */
|
|
3519
|
-
_onClick(
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
this.
|
|
3333
|
+
_onClick(e) {
|
|
3334
|
+
const path = e.composedPath();
|
|
3335
|
+
|
|
3336
|
+
if (this._isClearButton(e)) {
|
|
3337
|
+
this._handleClearButtonClick(e);
|
|
3338
|
+
} else if (path.indexOf(this._toggleElement) > -1) {
|
|
3339
|
+
this._onToggleButtonClick(e);
|
|
3524
3340
|
} else {
|
|
3525
|
-
this._onHostClick(
|
|
3341
|
+
this._onHostClick(e);
|
|
3526
3342
|
}
|
|
3527
3343
|
}
|
|
3528
3344
|
|
|
@@ -3537,7 +3353,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3537
3353
|
super._onKeyDown(e);
|
|
3538
3354
|
|
|
3539
3355
|
if (e.key === 'Tab') {
|
|
3540
|
-
this.
|
|
3356
|
+
this.$.overlay.restoreFocusOnClose = false;
|
|
3541
3357
|
} else if (e.key === 'ArrowDown') {
|
|
3542
3358
|
this._onArrowDown();
|
|
3543
3359
|
|
|
@@ -3553,7 +3369,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3553
3369
|
|
|
3554
3370
|
/** @private */
|
|
3555
3371
|
_getItemLabel(item) {
|
|
3556
|
-
let label = item && this.itemLabelPath ? get(this.itemLabelPath, item) : undefined;
|
|
3372
|
+
let label = item && this.itemLabelPath ? this.get(this.itemLabelPath, item) : undefined;
|
|
3557
3373
|
if (label === undefined || label === null) {
|
|
3558
3374
|
label = item ? item.toString() : '';
|
|
3559
3375
|
}
|
|
@@ -3562,7 +3378,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3562
3378
|
|
|
3563
3379
|
/** @private */
|
|
3564
3380
|
_getItemValue(item) {
|
|
3565
|
-
let value = item && this.itemValuePath ? get(this.itemValuePath, item) : undefined;
|
|
3381
|
+
let value = item && this.itemValuePath ? this.get(this.itemValuePath, item) : undefined;
|
|
3566
3382
|
if (value === undefined) {
|
|
3567
3383
|
value = item ? item.toString() : '';
|
|
3568
3384
|
}
|
|
@@ -3572,7 +3388,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3572
3388
|
/** @private */
|
|
3573
3389
|
_onArrowDown() {
|
|
3574
3390
|
if (this.opened) {
|
|
3575
|
-
const items = this.
|
|
3391
|
+
const items = this.filteredItems;
|
|
3576
3392
|
if (items) {
|
|
3577
3393
|
this._focusedIndex = Math.min(items.length - 1, this._focusedIndex + 1);
|
|
3578
3394
|
this._prefillFocusedItemLabel();
|
|
@@ -3588,7 +3404,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3588
3404
|
if (this._focusedIndex > -1) {
|
|
3589
3405
|
this._focusedIndex = Math.max(0, this._focusedIndex - 1);
|
|
3590
3406
|
} else {
|
|
3591
|
-
const items = this.
|
|
3407
|
+
const items = this.filteredItems;
|
|
3592
3408
|
if (items) {
|
|
3593
3409
|
this._focusedIndex = items.length - 1;
|
|
3594
3410
|
}
|
|
@@ -3603,7 +3419,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3603
3419
|
/** @private */
|
|
3604
3420
|
_prefillFocusedItemLabel() {
|
|
3605
3421
|
if (this._focusedIndex > -1) {
|
|
3606
|
-
const focusedItem = this.
|
|
3422
|
+
const focusedItem = this.filteredItems[this._focusedIndex];
|
|
3607
3423
|
this._inputElementValue = this._getItemLabel(focusedItem);
|
|
3608
3424
|
this._markAllSelectionRange();
|
|
3609
3425
|
}
|
|
@@ -3700,7 +3516,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3700
3516
|
} else if (this.clearButtonVisible && !this.opened && !!this.value) {
|
|
3701
3517
|
e.stopPropagation();
|
|
3702
3518
|
// The clear button is visible and the overlay is closed, so clear the value.
|
|
3703
|
-
this.
|
|
3519
|
+
this._clear();
|
|
3704
3520
|
}
|
|
3705
3521
|
} else if (this.opened) {
|
|
3706
3522
|
// Auto-open is enabled
|
|
@@ -3718,7 +3534,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3718
3534
|
} else if (this.clearButtonVisible && !!this.value) {
|
|
3719
3535
|
e.stopPropagation();
|
|
3720
3536
|
// The clear button is visible and the overlay is closed, so clear the value.
|
|
3721
|
-
this.
|
|
3537
|
+
this._clear();
|
|
3722
3538
|
}
|
|
3723
3539
|
}
|
|
3724
3540
|
|
|
@@ -3740,7 +3556,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3740
3556
|
* Clears the current value.
|
|
3741
3557
|
* @protected
|
|
3742
3558
|
*/
|
|
3743
|
-
|
|
3559
|
+
_clear() {
|
|
3744
3560
|
this.selectedItem = null;
|
|
3745
3561
|
|
|
3746
3562
|
if (this.allowCustomValue) {
|
|
@@ -3776,7 +3592,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3776
3592
|
/** @private */
|
|
3777
3593
|
_commitValue() {
|
|
3778
3594
|
if (this._focusedIndex > -1) {
|
|
3779
|
-
const focusedItem = this.
|
|
3595
|
+
const focusedItem = this.filteredItems[this._focusedIndex];
|
|
3780
3596
|
if (this.selectedItem !== focusedItem) {
|
|
3781
3597
|
this.selectedItem = focusedItem;
|
|
3782
3598
|
}
|
|
@@ -3791,7 +3607,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3791
3607
|
}
|
|
3792
3608
|
} else {
|
|
3793
3609
|
// Try to find an item which label matches the input value.
|
|
3794
|
-
const items = [
|
|
3610
|
+
const items = [...(this.filteredItems || []), this.selectedItem];
|
|
3795
3611
|
const itemMatchingInputValue = items[this.__getItemIndexByLabel(items, this._inputElementValue)];
|
|
3796
3612
|
|
|
3797
3613
|
if (
|
|
@@ -3832,6 +3648,14 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3832
3648
|
this.filter = '';
|
|
3833
3649
|
}
|
|
3834
3650
|
|
|
3651
|
+
/**
|
|
3652
|
+
* @return {string}
|
|
3653
|
+
* @protected
|
|
3654
|
+
*/
|
|
3655
|
+
get _propertyForValue() {
|
|
3656
|
+
return 'value';
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3835
3659
|
/**
|
|
3836
3660
|
* Override an event listener from `InputMixin`.
|
|
3837
3661
|
* @param {!Event} event
|
|
@@ -3978,12 +3802,6 @@ const ComboBoxMixin = (subclass) =>
|
|
|
3978
3802
|
|
|
3979
3803
|
/** @private */
|
|
3980
3804
|
_detectAndDispatchChange() {
|
|
3981
|
-
// Do not validate when focusout is caused by document
|
|
3982
|
-
// losing focus, which happens on browser tab switch.
|
|
3983
|
-
if (document.hasFocus()) {
|
|
3984
|
-
this.validate();
|
|
3985
|
-
}
|
|
3986
|
-
|
|
3987
3805
|
if (this.value !== this._lastCommittedValue) {
|
|
3988
3806
|
this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
|
|
3989
3807
|
this._lastCommittedValue = this.value;
|
|
@@ -4006,8 +3824,6 @@ const ComboBoxMixin = (subclass) =>
|
|
|
4006
3824
|
|
|
4007
3825
|
/** @private */
|
|
4008
3826
|
_filteredItemsChanged(filteredItems, oldFilteredItems) {
|
|
4009
|
-
this._setDropdownItems(filteredItems);
|
|
4010
|
-
|
|
4011
3827
|
// Store the currently focused item if any. The focused index preserves
|
|
4012
3828
|
// in the case when more filtered items are loading but it is reset
|
|
4013
3829
|
// when the user types in a filter query.
|
|
@@ -4068,16 +3884,6 @@ const ComboBoxMixin = (subclass) =>
|
|
|
4068
3884
|
}
|
|
4069
3885
|
}
|
|
4070
3886
|
|
|
4071
|
-
/**
|
|
4072
|
-
* Provide items to be rendered in the dropdown.
|
|
4073
|
-
* Override this method to show custom items.
|
|
4074
|
-
*
|
|
4075
|
-
* @protected
|
|
4076
|
-
*/
|
|
4077
|
-
_setDropdownItems(items) {
|
|
4078
|
-
this._dropdownItems = items;
|
|
4079
|
-
}
|
|
4080
|
-
|
|
4081
3887
|
/** @private */
|
|
4082
3888
|
_getItemElements() {
|
|
4083
3889
|
return Array.from(this._scroller.querySelectorAll(`${this._tagNamePrefix}-item`));
|
|
@@ -4138,53 +3944,35 @@ const ComboBoxMixin = (subclass) =>
|
|
|
4138
3944
|
}
|
|
4139
3945
|
}
|
|
4140
3946
|
|
|
4141
|
-
/**
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
* @param {boolean} focused
|
|
4146
|
-
* @protected
|
|
4147
|
-
* @override
|
|
4148
|
-
*/
|
|
4149
|
-
_setFocused(focused) {
|
|
4150
|
-
super._setFocused(focused);
|
|
4151
|
-
|
|
4152
|
-
if (!focused && !this.readonly && !this._closeOnBlurIsPrevented) {
|
|
4153
|
-
// User's logic in `custom-value-set` event listener might cause input to blur,
|
|
4154
|
-
// which will result in attempting to commit the same custom value once again.
|
|
4155
|
-
if (!this.opened && this.allowCustomValue && this._inputElementValue === this._lastCustomValue) {
|
|
4156
|
-
delete this._lastCustomValue;
|
|
4157
|
-
return;
|
|
4158
|
-
}
|
|
4159
|
-
|
|
4160
|
-
this._closeOrCommit();
|
|
4161
|
-
}
|
|
3947
|
+
/** @private */
|
|
3948
|
+
__onClearButtonMouseDown(event) {
|
|
3949
|
+
event.preventDefault(); // Prevent native focusout event
|
|
3950
|
+
this.inputElement.focus();
|
|
4162
3951
|
}
|
|
4163
3952
|
|
|
4164
|
-
/**
|
|
4165
|
-
|
|
4166
|
-
* state when focus moves to the overlay.
|
|
4167
|
-
*
|
|
4168
|
-
* @param {FocusEvent} event
|
|
4169
|
-
* @return {boolean}
|
|
4170
|
-
* @protected
|
|
4171
|
-
* @override
|
|
4172
|
-
*/
|
|
4173
|
-
_shouldRemoveFocus(event) {
|
|
3953
|
+
/** @private */
|
|
3954
|
+
_onFocusout(event) {
|
|
4174
3955
|
// VoiceOver on iOS fires `focusout` event when moving focus to the item in the dropdown.
|
|
4175
3956
|
// Do not focus the input in this case, because it would break announcement for the item.
|
|
4176
3957
|
if (event.relatedTarget && event.relatedTarget.localName === `${this._tagNamePrefix}-item`) {
|
|
4177
|
-
return
|
|
3958
|
+
return;
|
|
4178
3959
|
}
|
|
4179
3960
|
|
|
4180
|
-
//
|
|
4181
|
-
|
|
4182
|
-
if (event.relatedTarget === this._overlayElement) {
|
|
3961
|
+
// Fixes the problem with `focusout` happening when clicking on the scroll bar on Edge
|
|
3962
|
+
if (event.relatedTarget === this.$.overlay) {
|
|
4183
3963
|
event.composedPath()[0].focus();
|
|
4184
|
-
return
|
|
3964
|
+
return;
|
|
4185
3965
|
}
|
|
3966
|
+
if (!this.readonly && !this._closeOnBlurIsPrevented) {
|
|
3967
|
+
// User's logic in `custom-value-set` event listener might cause input to blur,
|
|
3968
|
+
// which will result in attempting to commit the same custom value once again.
|
|
3969
|
+
if (!this.opened && this.allowCustomValue && this._inputElementValue === this._lastCustomValue) {
|
|
3970
|
+
delete this._lastCustomValue;
|
|
3971
|
+
return;
|
|
3972
|
+
}
|
|
4186
3973
|
|
|
4187
|
-
|
|
3974
|
+
this._closeOrCommit();
|
|
3975
|
+
}
|
|
4188
3976
|
}
|
|
4189
3977
|
|
|
4190
3978
|
/** @private */
|
|
@@ -4194,7 +3982,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
4194
3982
|
}
|
|
4195
3983
|
|
|
4196
3984
|
event.preventDefault();
|
|
4197
|
-
this.
|
|
3985
|
+
this._clear();
|
|
4198
3986
|
}
|
|
4199
3987
|
|
|
4200
3988
|
/**
|
|
@@ -4240,7 +4028,7 @@ const ComboBoxMixin = (subclass) =>
|
|
|
4240
4028
|
|
|
4241
4029
|
/**
|
|
4242
4030
|
* @license
|
|
4243
|
-
* Copyright (c) 2015 -
|
|
4031
|
+
* Copyright (c) 2015 - 2022 Vaadin Ltd.
|
|
4244
4032
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
4245
4033
|
*/
|
|
4246
4034
|
|
|
@@ -4360,7 +4148,7 @@ registerStyles('vaadin-combo-box', inputFieldShared$1, { moduleId: 'vaadin-combo
|
|
|
4360
4148
|
* Note: the `theme` attribute value set on `<vaadin-combo-box>` is
|
|
4361
4149
|
* propagated to the internal components listed above.
|
|
4362
4150
|
*
|
|
4363
|
-
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
|
|
4151
|
+
* See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
|
|
4364
4152
|
*
|
|
4365
4153
|
* @fires {Event} change - Fired when the user commits a value change.
|
|
4366
4154
|
* @fires {CustomEvent} custom-value-set - Fired when the user sets a custom value.
|
|
@@ -4371,7 +4159,6 @@ registerStyles('vaadin-combo-box', inputFieldShared$1, { moduleId: 'vaadin-combo
|
|
|
4371
4159
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
4372
4160
|
* @fires {CustomEvent} validated - Fired whenever the field is validated.
|
|
4373
4161
|
*
|
|
4374
|
-
* @customElement
|
|
4375
4162
|
* @extends HTMLElement
|
|
4376
4163
|
* @mixes ElementMixin
|
|
4377
4164
|
* @mixes ThemableMixin
|
|
@@ -4474,7 +4261,6 @@ class ComboBox extends ComboBoxDataProviderMixin(
|
|
|
4474
4261
|
this._tooltipController = new TooltipController(this);
|
|
4475
4262
|
this.addController(this._tooltipController);
|
|
4476
4263
|
this._tooltipController.setPosition('top');
|
|
4477
|
-
this._tooltipController.setAriaTarget(this.inputElement);
|
|
4478
4264
|
this._tooltipController.setShouldShow((target) => !target.opened);
|
|
4479
4265
|
|
|
4480
4266
|
this._positionTarget = this.shadowRoot.querySelector('[part="input-field"]');
|
|
@@ -4482,17 +4268,48 @@ class ComboBox extends ComboBoxDataProviderMixin(
|
|
|
4482
4268
|
}
|
|
4483
4269
|
|
|
4484
4270
|
/**
|
|
4485
|
-
* Override
|
|
4486
|
-
*
|
|
4487
|
-
*
|
|
4488
|
-
*
|
|
4271
|
+
* Override method inherited from `FocusMixin` to validate on blur.
|
|
4272
|
+
* @param {boolean} focused
|
|
4273
|
+
* @protected
|
|
4274
|
+
* @override
|
|
4275
|
+
*/
|
|
4276
|
+
_setFocused(focused) {
|
|
4277
|
+
super._setFocused(focused);
|
|
4278
|
+
|
|
4279
|
+
if (!focused) {
|
|
4280
|
+
this.validate();
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4284
|
+
/**
|
|
4285
|
+
* Override method inherited from `FocusMixin` to not remove focused
|
|
4286
|
+
* state when focus moves to the overlay.
|
|
4287
|
+
* @param {FocusEvent} event
|
|
4288
|
+
* @return {boolean}
|
|
4289
|
+
* @protected
|
|
4290
|
+
* @override
|
|
4291
|
+
*/
|
|
4292
|
+
_shouldRemoveFocus(event) {
|
|
4293
|
+
// Do not blur when focus moves to the overlay
|
|
4294
|
+
if (event.relatedTarget === this.$.overlay) {
|
|
4295
|
+
event.composedPath()[0].focus();
|
|
4296
|
+
return false;
|
|
4297
|
+
}
|
|
4298
|
+
|
|
4299
|
+
return true;
|
|
4300
|
+
}
|
|
4301
|
+
|
|
4302
|
+
/**
|
|
4303
|
+
* Override method inherited from `InputControlMixin` to handle clear
|
|
4304
|
+
* button click and stop event from propagating to the host element.
|
|
4489
4305
|
* @param {Event} event
|
|
4490
4306
|
* @protected
|
|
4491
4307
|
* @override
|
|
4492
4308
|
*/
|
|
4493
4309
|
_onClearButtonClick(event) {
|
|
4494
4310
|
event.stopPropagation();
|
|
4495
|
-
|
|
4311
|
+
|
|
4312
|
+
this._handleClearButtonClick(event);
|
|
4496
4313
|
}
|
|
4497
4314
|
|
|
4498
4315
|
/**
|
|
@@ -4509,4 +4326,4 @@ class ComboBox extends ComboBoxDataProviderMixin(
|
|
|
4509
4326
|
}
|
|
4510
4327
|
}
|
|
4511
4328
|
|
|
4512
|
-
|
|
4329
|
+
customElements.define(ComboBox.is, ComboBox);
|