@vaadin/combo-box 23.2.0-dev.8a7678b70 → 23.2.0-rc1

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.
@@ -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)',
@@ -280,14 +280,26 @@ export const ComboBoxMixin = (subclass) =>
280
280
  }
281
281
  }
282
282
 
283
+ /**
284
+ * Get a reference to the native `<input>` element.
285
+ * Override to provide a custom input.
286
+ * @protected
287
+ * @return {HTMLInputElement | undefined}
288
+ */
289
+ get _nativeInput() {
290
+ return this.inputElement;
291
+ }
292
+
283
293
  /**
284
294
  * Override method inherited from `InputMixin`
285
295
  * to customize the input element.
286
296
  * @protected
287
297
  * @override
288
298
  */
289
- _inputElementChanged(input) {
290
- super._inputElementChanged(input);
299
+ _inputElementChanged(inputElement) {
300
+ super._inputElementChanged(inputElement);
301
+
302
+ const input = this._nativeInput;
291
303
 
292
304
  if (input) {
293
305
  input.autocomplete = 'off';
@@ -382,6 +394,25 @@ export const ComboBoxMixin = (subclass) =>
382
394
  this.opened = false;
383
395
  }
384
396
 
397
+ /**
398
+ * Override Polymer lifecycle callback to handle `filter` property change after
399
+ * the observer for `opened` property is triggered. This is needed when opening
400
+ * combo-box on user input to ensure the focused index is set correctly.
401
+ *
402
+ * @param {!Object} currentProps Current accessor values
403
+ * @param {?Object} changedProps Properties changed since the last call
404
+ * @param {?Object} oldProps Previous values for each changed property
405
+ * @protected
406
+ * @override
407
+ */
408
+ _propertiesChanged(currentProps, changedProps, oldProps) {
409
+ super._propertiesChanged(currentProps, changedProps, oldProps);
410
+
411
+ if (changedProps.filter !== undefined) {
412
+ this._filterChanged(changedProps.filter);
413
+ }
414
+ }
415
+
385
416
  /** @private */
386
417
  _initOverlay() {
387
418
  const overlay = this.$.overlay;
@@ -395,11 +426,6 @@ export const ComboBoxMixin = (subclass) =>
395
426
  // Prevent blurring the input when clicking inside the overlay
396
427
  overlay.addEventListener('mousedown', (e) => e.preventDefault());
397
428
 
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
429
  // Manual two-way binding for the overlay "opened" property
404
430
  overlay.addEventListener('opened-changed', (e) => {
405
431
  this._overlayOpened = e.detail.value;
@@ -424,9 +450,7 @@ export const ComboBoxMixin = (subclass) =>
424
450
  };
425
451
 
426
452
  // Ensure the scroller is rendered
427
- if (!this.opened) {
428
- overlay.requestContentUpdate();
429
- }
453
+ overlay.requestContentUpdate();
430
454
 
431
455
  const scroller = overlay.querySelector(scrollerTag);
432
456
 
@@ -460,11 +484,6 @@ export const ComboBoxMixin = (subclass) =>
460
484
  }
461
485
  }
462
486
 
463
- /** @protected */
464
- _isOverlayHidden(items, loading) {
465
- return !loading && !(items && items.length);
466
- }
467
-
468
487
  /** @private */
469
488
  _openedOrItemsChanged(opened, items, loading) {
470
489
  // Close the overlay if there are no items to display.
@@ -493,9 +512,14 @@ export const ComboBoxMixin = (subclass) =>
493
512
  this._updateActiveDescendant(index);
494
513
  }
495
514
 
515
+ /** @protected */
516
+ _isInputFocused() {
517
+ return this.inputElement && isElementFocused(this.inputElement);
518
+ }
519
+
496
520
  /** @private */
497
521
  _updateActiveDescendant(index) {
498
- const input = this.inputElement;
522
+ const input = this._nativeInput;
499
523
  if (!input) {
500
524
  return;
501
525
  }
@@ -519,19 +543,19 @@ export const ComboBoxMixin = (subclass) =>
519
543
  this._openedWithFocusRing = this.hasAttribute('focus-ring');
520
544
  // For touch devices, we don't want to popup virtual keyboard
521
545
  // unless input element is explicitly focused by the user.
522
- if (!this.hasAttribute('focused') && !isTouch) {
546
+ if (!this._isInputFocused() && !isTouch) {
523
547
  this.focus();
524
548
  }
525
549
 
526
550
  this.$.overlay.restoreFocusOnClose = true;
527
551
  } else {
528
552
  this._onClosed();
529
- if (this._openedWithFocusRing && this.hasAttribute('focused')) {
553
+ if (this._openedWithFocusRing && this._isInputFocused()) {
530
554
  this.setAttribute('focus-ring', '');
531
555
  }
532
556
  }
533
557
 
534
- const input = this.inputElement;
558
+ const input = this._nativeInput;
535
559
  if (input) {
536
560
  input.setAttribute('aria-expanded', !!opened);
537
561
 
@@ -600,8 +624,6 @@ export const ComboBoxMixin = (subclass) =>
600
624
 
601
625
  /** @private */
602
626
  _onClick(e) {
603
- this._closeOnBlurIsPrevented = true;
604
-
605
627
  const path = e.composedPath();
606
628
 
607
629
  if (this._isClearButton(e)) {
@@ -611,8 +633,6 @@ export const ComboBoxMixin = (subclass) =>
611
633
  } else {
612
634
  this._onHostClick(e);
613
635
  }
614
-
615
- this._closeOnBlurIsPrevented = false;
616
636
  }
617
637
 
618
638
  /**
@@ -628,16 +648,12 @@ export const ComboBoxMixin = (subclass) =>
628
648
  if (e.key === 'Tab') {
629
649
  this.$.overlay.restoreFocusOnClose = false;
630
650
  } else if (e.key === 'ArrowDown') {
631
- this._closeOnBlurIsPrevented = true;
632
651
  this._onArrowDown();
633
- this._closeOnBlurIsPrevented = false;
634
652
 
635
653
  // Prevent caret from moving
636
654
  e.preventDefault();
637
655
  } else if (e.key === 'ArrowUp') {
638
- this._closeOnBlurIsPrevented = true;
639
656
  this._onArrowUp();
640
- this._closeOnBlurIsPrevented = false;
641
657
 
642
658
  // Prevent caret from moving
643
659
  e.preventDefault();
@@ -708,8 +724,7 @@ export const ComboBoxMixin = (subclass) =>
708
724
  // and there's no need to modify the selection range if the input isn't focused anyway.
709
725
  // This affects Safari. When the overlay is open, and then hitting tab, browser should focus
710
726
  // the next focusable element instead of the combo-box itself.
711
- // Checking the focused property here is enough instead of checking the activeElement.
712
- if (this.hasAttribute('focused')) {
727
+ if (this._isInputFocused() && this.inputElement.setSelectionRange) {
713
728
  this.inputElement.setSelectionRange(start, end);
714
729
  }
715
730
  }
@@ -819,7 +834,7 @@ export const ComboBoxMixin = (subclass) =>
819
834
  toggleElement.addEventListener('mousedown', (e) => e.preventDefault());
820
835
  // Unfocus previously focused element if focus is not inside combo box (on touch devices)
821
836
  toggleElement.addEventListener('click', () => {
822
- if (isTouch && !this.hasAttribute('focused')) {
837
+ if (isTouch && !this._isInputFocused()) {
823
838
  document.activeElement.blur();
824
839
  }
825
840
  });
@@ -926,9 +941,7 @@ export const ComboBoxMixin = (subclass) =>
926
941
 
927
942
  this._clearSelectionRange();
928
943
 
929
- if (!this.dataProvider) {
930
- this.filter = '';
931
- }
944
+ this.filter = '';
932
945
  }
933
946
 
934
947
  /**
@@ -946,19 +959,27 @@ export const ComboBoxMixin = (subclass) =>
946
959
  * @override
947
960
  */
948
961
  _onInput(event) {
949
- if (!this.opened && !this._isClearButton(event) && !this.autoOpenDisabled) {
950
- this.open();
951
- }
962
+ const filter = this._inputElementValue;
963
+
964
+ // When opening dropdown on user input, both `opened` and `filter` properties are set.
965
+ // Perform a batched property update instead of relying on sync property observers.
966
+ // This is necessary to avoid an extra data-provider request for loading first page.
967
+ const props = {};
952
968
 
953
- const value = this._inputElementValue;
954
- if (this.filter === value) {
969
+ if (this.filter === filter) {
955
970
  // Filter and input value might get out of sync, while keyboard navigating for example.
956
971
  // Afterwards, input value might be changed to the same value as used in filtering.
957
972
  // In situation like these, we need to make sure all the filter changes handlers are run.
958
- this._filterChanged(this.filter, this.itemValuePath, this.itemLabelPath);
973
+ this._filterChanged(this.filter);
959
974
  } else {
960
- this.filter = value;
975
+ props.filter = filter;
961
976
  }
977
+
978
+ if (!this.opened && !this._isClearButton(event) && !this.autoOpenDisabled) {
979
+ props.opened = true;
980
+ }
981
+
982
+ this.setProperties(props);
962
983
  }
963
984
 
964
985
  /**
@@ -981,11 +1002,7 @@ export const ComboBoxMixin = (subclass) =>
981
1002
  }
982
1003
 
983
1004
  /** @private */
984
- _filterChanged(filter, _itemValuePath, _itemLabelPath) {
985
- if (filter === undefined) {
986
- return;
987
- }
988
-
1005
+ _filterChanged(filter) {
989
1006
  // Scroll to the top of the list whenever the filter changes.
990
1007
  this._scrollIntoView(0);
991
1008
 
@@ -1028,7 +1045,7 @@ export const ComboBoxMixin = (subclass) =>
1028
1045
  this.value = '';
1029
1046
  }
1030
1047
 
1031
- this._toggleHasValue(this.value !== '');
1048
+ this._toggleHasValue(this._hasValue);
1032
1049
  this._inputElementValue = this.value;
1033
1050
  }
1034
1051
  } else {
@@ -1064,21 +1081,21 @@ export const ComboBoxMixin = (subclass) =>
1064
1081
  }
1065
1082
 
1066
1083
  if (isValidValue(value)) {
1067
- let item;
1068
1084
  if (this._getItemValue(this.selectedItem) !== value) {
1069
1085
  this._selectItemForValue(value);
1070
- } else {
1071
- item = this.selectedItem;
1072
1086
  }
1073
1087
 
1074
- if (!item && this.allowCustomValue) {
1088
+ if (!this.selectedItem && this.allowCustomValue) {
1075
1089
  this._inputElementValue = value;
1076
1090
  }
1077
1091
 
1078
- this._toggleHasValue(this.value !== '');
1092
+ this._toggleHasValue(this._hasValue);
1079
1093
  } else {
1080
1094
  this.selectedItem = null;
1081
1095
  }
1096
+
1097
+ this.filter = '';
1098
+
1082
1099
  // In the next _detectAndDispatchChange() call, the change detection should pass
1083
1100
  this._lastCommittedValue = undefined;
1084
1101
  }
@@ -1236,9 +1253,6 @@ export const ComboBoxMixin = (subclass) =>
1236
1253
  if (this.opened) {
1237
1254
  this._focusedIndex = this.filteredItems.indexOf(e.detail.item);
1238
1255
  this.close();
1239
- } else if (this.selectedItem !== e.detail.item) {
1240
- this.selectedItem = e.detail.item;
1241
- this._detectAndDispatchChange();
1242
1256
  }
1243
1257
  }
1244
1258
 
@@ -1250,6 +1264,12 @@ export const ComboBoxMixin = (subclass) =>
1250
1264
 
1251
1265
  /** @private */
1252
1266
  _onFocusout(event) {
1267
+ // VoiceOver on iOS fires `focusout` event when moving focus to the item in the dropdown.
1268
+ // Do not focus the input in this case, because it would break announcement for the item.
1269
+ if (event.relatedTarget && event.relatedTarget.localName === `${this._tagNamePrefix}-item`) {
1270
+ return;
1271
+ }
1272
+
1253
1273
  // Fixes the problem with `focusout` happening when clicking on the scroll bar on Edge
1254
1274
  if (event.relatedTarget === this.$.overlay) {
1255
1275
  event.composedPath()[0].focus();
@@ -1277,35 +1297,12 @@ export const ComboBoxMixin = (subclass) =>
1277
1297
  this._clear();
1278
1298
  }
1279
1299
 
1280
- /**
1281
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
1282
- *
1283
- * @return {boolean} True if the value is valid and sets the `invalid` flag appropriately
1284
- */
1285
- validate() {
1286
- return !(this.invalid = !this.checkValidity());
1287
- }
1288
-
1289
- /**
1290
- * Returns true if the current input value satisfies all constraints (if any).
1291
- * You can override this method for custom validations.
1292
- *
1293
- * @return {boolean}
1294
- */
1295
- checkValidity() {
1296
- if (super.checkValidity) {
1297
- return super.checkValidity();
1298
- }
1299
-
1300
- return !this.required || !!this.value;
1301
- }
1302
-
1303
1300
  /**
1304
1301
  * Fired when the value changes.
1305
1302
  *
1306
1303
  * @event value-changed
1307
1304
  * @param {Object} detail
1308
- * @param {String} detail.value the combobox value
1305
+ * @param {String} detail.value the combobox value
1309
1306
  */
1310
1307
 
1311
1308
  /**
@@ -1313,7 +1310,7 @@ export const ComboBoxMixin = (subclass) =>
1313
1310
  *
1314
1311
  * @event selected-item-changed
1315
1312
  * @param {Object} detail
1316
- * @param {Object|String} detail.value the selected item. Type is the same as the type of `items`.
1313
+ * @param {Object|String} detail.value the selected item. Type is the same as the type of `items`.
1317
1314
  */
1318
1315
 
1319
1316
  /**
@@ -3,24 +3,25 @@
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 { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
7
- import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
- import { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
9
- import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
- import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
- import { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
12
- import { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
13
- import { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
14
- import { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
15
- import { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
16
- import { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
17
- import { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
18
- import { PatternMixinClass } from '@vaadin/field-base/src/pattern-mixin.js';
19
- import { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
20
- import { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
21
- import { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
22
- import { ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
23
- import { ComboBoxDefaultItem } from './vaadin-combo-box-mixin.js';
6
+ import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
7
+ import type { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
8
+ import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
9
+ import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
10
+ import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
11
+ import type { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
12
+ import type { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
13
+ import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
14
+ import type { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
15
+ import type { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
16
+ import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
17
+ import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
18
+ import type { PatternMixinClass } from '@vaadin/field-base/src/pattern-mixin.js';
19
+ import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
20
+ import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
21
+ import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
22
+ import type { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
23
+ import type { ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
24
+ import type { ComboBoxDefaultItem } from './vaadin-combo-box-mixin.js';
24
25
  export {
25
26
  ComboBoxDataProvider,
26
27
  ComboBoxDataProviderCallback,
@@ -65,6 +66,11 @@ export type ComboBoxFilterChangedEvent = CustomEvent<{ value: string }>;
65
66
  */
66
67
  export type ComboBoxSelectedItemChangedEvent<TItem> = CustomEvent<{ value: TItem | null | undefined }>;
67
68
 
69
+ /**
70
+ * Fired whenever the field is validated.
71
+ */
72
+ export type ComboBoxValidatedEvent = CustomEvent<{ valid: boolean }>;
73
+
68
74
  export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
69
75
  change: ComboBoxChangeEvent<TItem>;
70
76
 
@@ -79,6 +85,8 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
79
85
  'value-changed': ComboBoxValueChangedEvent;
80
86
 
81
87
  'selected-item-changed': ComboBoxSelectedItemChangedEvent<TItem>;
88
+
89
+ validated: ComboBoxValidatedEvent;
82
90
  }
83
91
 
84
92
  /**
@@ -165,6 +173,7 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
165
173
  * Custom property | Description | Default
166
174
  * ----------------------------------------|----------------------------|---------
167
175
  * `--vaadin-field-default-width` | Default width of the field | `12em`
176
+ * `--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`
168
177
  * `--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
169
178
  *
170
179
  * `<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
@@ -207,18 +216,19 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
207
216
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
208
217
  * @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
209
218
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
219
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
210
220
  */
211
221
  declare class ComboBox<TItem = ComboBoxDefaultItem> extends HTMLElement {
212
222
  addEventListener<K extends keyof ComboBoxEventMap<TItem>>(
213
223
  type: K,
214
224
  listener: (this: ComboBox<TItem>, ev: ComboBoxEventMap<TItem>[K]) => void,
215
- options?: boolean | AddEventListenerOptions,
225
+ options?: AddEventListenerOptions | boolean,
216
226
  ): void;
217
227
 
218
228
  removeEventListener<K extends keyof ComboBoxEventMap<TItem>>(
219
229
  type: K,
220
230
  listener: (this: ComboBox<TItem>, ev: ComboBoxEventMap<TItem>[K]) => void,
221
- options?: boolean | EventListenerOptions,
231
+ options?: EventListenerOptions | boolean,
222
232
  ): void;
223
233
  }
224
234
 
@@ -238,6 +248,7 @@ interface ComboBox<TItem = ComboBoxDefaultItem>
238
248
  DelegateStateMixinClass,
239
249
  DelegateFocusMixinClass,
240
250
  ThemableMixinClass,
251
+ ThemePropertyMixinClass,
241
252
  ElementMixinClass,
242
253
  ControllerMixinClass {}
243
254
 
@@ -104,6 +104,7 @@ registerStyles('vaadin-combo-box', inputFieldShared, { moduleId: 'vaadin-combo-b
104
104
  * Custom property | Description | Default
105
105
  * ----------------------------------------|----------------------------|---------
106
106
  * `--vaadin-field-default-width` | Default width of the field | `12em`
107
+ * `--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`
107
108
  * `--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
108
109
  *
109
110
  * `<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
@@ -146,6 +147,7 @@ registerStyles('vaadin-combo-box', inputFieldShared, { moduleId: 'vaadin-combo-b
146
147
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
147
148
  * @fires {CustomEvent} selected-item-changed - Fired when the `selectedItem` property changes.
148
149
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
150
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
149
151
  *
150
152
  * @extends HTMLElement
151
153
  * @mixes ElementMixin
@@ -200,7 +202,6 @@ class ComboBox extends ComboBoxDataProviderMixin(
200
202
 
201
203
  <vaadin-combo-box-overlay
202
204
  id="overlay"
203
- hidden$="[[_isOverlayHidden(filteredItems, loading)]]"
204
205
  opened="[[_overlayOpened]]"
205
206
  loading$="[[loading]]"
206
207
  theme$="[[_theme]]"
@@ -2,6 +2,7 @@ import '@vaadin/vaadin-lumo-styles/color.js';
2
2
  import '@vaadin/vaadin-lumo-styles/spacing.js';
3
3
  import '@vaadin/vaadin-lumo-styles/style.js';
4
4
  import '@vaadin/vaadin-overlay/theme/lumo/vaadin-overlay.js';
5
+ import { loader } from '@vaadin/vaadin-lumo-styles/mixins/loader.js';
5
6
  import { menuOverlayCore } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js';
6
7
  import { overlay } from '@vaadin/vaadin-lumo-styles/mixins/overlay.js';
7
8
  import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
@@ -36,10 +37,7 @@ const comboBoxOverlay = css`
36
37
  margin-bottom: var(--lumo-space-xs);
37
38
  }
38
39
 
39
- :host([loading]) [part~='loader'] {
40
- box-sizing: border-box;
41
- width: var(--lumo-icon-size-s);
42
- height: var(--lumo-icon-size-s);
40
+ [part~='loader'] {
43
41
  position: absolute;
44
42
  z-index: 1;
45
43
  left: var(--lumo-space-s);
@@ -48,38 +46,11 @@ const comboBoxOverlay = css`
48
46
  margin-left: auto;
49
47
  margin-inline-start: auto;
50
48
  margin-inline-end: 0;
51
- border: 2px solid transparent;
52
- border-color: var(--lumo-primary-color-50pct) var(--lumo-primary-color-50pct) var(--lumo-primary-color)
53
- var(--lumo-primary-color);
54
- border-radius: calc(0.5 * var(--lumo-icon-size-s));
55
- opacity: 0;
56
- animation: 1s linear infinite lumo-combo-box-loader-rotate, 0.3s 0.1s lumo-combo-box-loader-fade-in both;
57
- pointer-events: none;
58
- }
59
-
60
- @keyframes lumo-combo-box-loader-fade-in {
61
- 0% {
62
- opacity: 0;
63
- }
64
-
65
- 100% {
66
- opacity: 1;
67
- }
68
- }
69
-
70
- @keyframes lumo-combo-box-loader-rotate {
71
- 0% {
72
- transform: rotate(0deg);
73
- }
74
-
75
- 100% {
76
- transform: rotate(360deg);
77
- }
78
49
  }
79
50
 
80
51
  /* RTL specific styles */
81
52
 
82
- :host([loading][dir='rtl']) [part~='loader'] {
53
+ :host([dir='rtl']) [part~='loader'] {
83
54
  left: auto;
84
55
  margin-left: 0;
85
56
  margin-right: auto;
@@ -88,6 +59,6 @@ const comboBoxOverlay = css`
88
59
  }
89
60
  `;
90
61
 
91
- registerStyles('vaadin-combo-box-overlay', [overlay, menuOverlayCore, comboBoxOverlay], {
62
+ registerStyles('vaadin-combo-box-overlay', [overlay, menuOverlayCore, comboBoxOverlay, loader], {
92
63
  moduleId: 'lumo-combo-box-overlay',
93
64
  });
@@ -1,5 +1,6 @@
1
1
  import '@vaadin/vaadin-material-styles/color.js';
2
2
  import '@vaadin/vaadin-overlay/theme/material/vaadin-overlay.js';
3
+ import { loader } from '@vaadin/vaadin-material-styles/mixins/loader.js';
3
4
  import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js';
4
5
  import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
5
6
 
@@ -21,102 +22,15 @@ const comboBoxOverlay = css`
21
22
  padding: 0;
22
23
  }
23
24
 
24
- :host([loading]) [part='loader'] {
25
- height: 2px;
25
+ [part~='loader'] {
26
26
  position: absolute;
27
27
  z-index: 1;
28
28
  top: -2px;
29
29
  left: 0;
30
30
  right: 0;
31
- background: var(--material-background-color)
32
- linear-gradient(
33
- 90deg,
34
- transparent 0%,
35
- transparent 20%,
36
- var(--material-primary-color) 20%,
37
- var(--material-primary-color) 40%,
38
- transparent 40%,
39
- transparent 60%,
40
- var(--material-primary-color) 60%,
41
- var(--material-primary-color) 80%,
42
- transparent 80%,
43
- transparent 100%
44
- )
45
- 0 0 / 400% 100% repeat-x;
46
- opacity: 0;
47
- animation: 3s linear infinite material-combo-box-loader-progress, 0.3s 0.1s both material-combo-box-loader-fade-in;
48
- }
49
-
50
- [part='loader']::before {
51
- content: '';
52
- display: block;
53
- height: 100%;
54
- opacity: 0.16;
55
- background: var(--material-primary-color);
56
- }
57
-
58
- @keyframes material-combo-box-loader-fade-in {
59
- 0% {
60
- opacity: 0;
61
- }
62
-
63
- 100% {
64
- opacity: 1;
65
- }
66
- }
67
-
68
- @keyframes material-combo-box-loader-progress {
69
- 0% {
70
- background-position: 0 0;
71
- background-size: 300% 100%;
72
- }
73
-
74
- 33% {
75
- background-position: -100% 0;
76
- background-size: 400% 100%;
77
- }
78
-
79
- 67% {
80
- background-position: -200% 0;
81
- background-size: 250% 100%;
82
- }
83
-
84
- 100% {
85
- background-position: -300% 0;
86
- background-size: 300% 100%;
87
- }
88
- }
89
-
90
- /* RTL specific styles */
91
-
92
- @keyframes material-combo-box-loader-progress-rtl {
93
- 0% {
94
- background-position: 100% 0;
95
- background-size: 300% 100%;
96
- }
97
-
98
- 33% {
99
- background-position: 200% 0;
100
- background-size: 400% 100%;
101
- }
102
-
103
- 67% {
104
- background-position: 300% 0;
105
- background-size: 250% 100%;
106
- }
107
-
108
- 100% {
109
- background-position: 400% 0;
110
- background-size: 300% 100%;
111
- }
112
- }
113
-
114
- :host([loading][dir='rtl']) [part='loader'] {
115
- animation: 3s linear infinite material-combo-box-loader-progress-rtl,
116
- 0.3s 0.1s both material-combo-box-loader-fade-in;
117
31
  }
118
32
  `;
119
33
 
120
- registerStyles('vaadin-combo-box-overlay', [menuOverlay, comboBoxOverlay], {
34
+ registerStyles('vaadin-combo-box-overlay', [menuOverlay, comboBoxOverlay, loader], {
121
35
  moduleId: 'material-combo-box-overlay',
122
36
  });