@vaadin/vaadin-combo-box
Advanced tools
Comparing version 22.0.0-alpha4 to 22.0.0-alpha5
{ | ||
"name": "@vaadin/vaadin-combo-box", | ||
"version": "22.0.0-alpha4", | ||
"version": "22.0.0-alpha5", | ||
"description": "Web Component for displaying a list of items with filtering", | ||
@@ -28,13 +28,13 @@ "main": "vaadin-combo-box.js", | ||
"@polymer/iron-a11y-announcer": "^3.0.0", | ||
"@polymer/iron-list": "^3.0.0", | ||
"@polymer/iron-resizable-behavior": "^3.0.0", | ||
"@polymer/polymer": "^3.0.0", | ||
"@vaadin/vaadin-control-state-mixin": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-element-mixin": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-item": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-lumo-styles": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-material-styles": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-overlay": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-text-field": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-themable-mixin": "^22.0.0-alpha4" | ||
"@vaadin/vaadin-control-state-mixin": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-element-mixin": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-item": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-lumo-styles": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-material-styles": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-overlay": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-text-field": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-themable-mixin": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-virtual-list": "^22.0.0-alpha5" | ||
}, | ||
@@ -46,4 +46,4 @@ "devDependencies": { | ||
"@vaadin/testing-helpers": "^0.2.1", | ||
"@vaadin/vaadin-dialog": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-template-renderer": "^22.0.0-alpha4", | ||
"@vaadin/vaadin-dialog": "^22.0.0-alpha5", | ||
"@vaadin/vaadin-template-renderer": "^22.0.0-alpha5", | ||
"lit": "^2.0.0-rc.1", | ||
@@ -55,3 +55,3 @@ "sinon": "^9.2.0" | ||
}, | ||
"gitHead": "86c025abd605d5a4a3c0ae36eb07c34704cee1f2" | ||
"gitHead": "012f658db6f81375be8889f63ee15e3f660fe9ec" | ||
} |
@@ -201,6 +201,2 @@ /** | ||
} | ||
if (page === 0 && this.__repositionOverlayDebouncer && items.length > (this.__maxRenderedItems || 0)) { | ||
setTimeout(() => this.__repositionOverlayDebouncer.flush()); | ||
this.__maxRenderedItems = items.length; | ||
} | ||
} | ||
@@ -207,0 +203,0 @@ }; |
@@ -7,3 +7,3 @@ /** | ||
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js'; | ||
import '@polymer/iron-list/iron-list.js'; | ||
import { Virtualizer } from '@vaadin/vaadin-virtual-list/src/virtualizer.js'; | ||
import './vaadin-combo-box-item.js'; | ||
@@ -53,21 +53,12 @@ import './vaadin-combo-box-dropdown.js'; | ||
} | ||
#selector { | ||
border-width: var(--_vaadin-combo-box-items-container-border-width); | ||
border-style: var(--_vaadin-combo-box-items-container-border-style); | ||
border-color: var(--_vaadin-combo-box-items-container-border-color); | ||
} | ||
</style> | ||
<div id="scroller" on-click="_stopPropagation"> | ||
<iron-list id="selector" role="listbox" items="[[_getItems(opened, _items)]]" scroll-target="[[_scroller]]"> | ||
<template> | ||
<vaadin-combo-box-item | ||
on-click="_onItemClick" | ||
index="[[__requestItemByIndex(item, index, _resetScrolling)]]" | ||
item="[[item]]" | ||
label="[[getItemLabel(item, _itemLabelPath)]]" | ||
selected="[[_isItemSelected(item, _selectedItem, _itemIdPath)]]" | ||
renderer="[[renderer]]" | ||
role$="[[_getAriaRole(index)]]" | ||
aria-selected$="[[_getAriaSelected(_focusedIndex,index)]]" | ||
focused="[[_isItemFocused(_focusedIndex,index)]]" | ||
tabindex="-1" | ||
theme$="[[theme]]" | ||
></vaadin-combo-box-item> | ||
</template> | ||
</iron-list> | ||
<div id="scroller" on-click="_stopPropagation" style="min-height: 1px"> | ||
<div id="selector" role="listbox"></div> | ||
</div> | ||
@@ -122,22 +113,2 @@ </template> | ||
/** | ||
* Used to recognize if the filter changed, so to skip the | ||
* scrolling restore. If true, then scroll to 0 position. Restore | ||
* the previous position otherwise. | ||
*/ | ||
filterChanged: { | ||
type: Boolean, | ||
value: false | ||
}, | ||
/** | ||
* Used to recognize scroller reset after new items have been set | ||
* to iron-list and to ignore unwanted pages load. If 'true', then | ||
* skip loading of the pages until it becomes 'false'. | ||
*/ | ||
_resetScrolling: { | ||
type: Boolean, | ||
value: false | ||
}, | ||
_selectedItem: { | ||
@@ -176,9 +147,5 @@ type: Object | ||
/** | ||
* Stores the scroller position before updating the 'items', in | ||
* order to restore it immediately after 'items' have been updated | ||
*/ | ||
_oldScrollerPosition: { | ||
type: Number, | ||
value: 0 | ||
__effectiveItems: { | ||
computed: '_getItems(opened, _items)', | ||
observer: '__effectiveItemsChanged' | ||
} | ||
@@ -189,5 +156,48 @@ }; | ||
static get observers() { | ||
return ['_loadingChanged(loading)', '_openedChanged(opened, _items, loading)', '_restoreScrollerPosition(_items)']; | ||
return [ | ||
'_loadingChanged(loading)', | ||
'_openedChanged(opened, _items, loading)', | ||
'__updateAllItems(_selectedItem, renderer)' | ||
]; | ||
} | ||
constructor() { | ||
super(); | ||
this.__boundOnItemClick = this._onItemClick.bind(this); | ||
} | ||
__effectiveItemsChanged(effectiveItems) { | ||
if (this.__virtualizer && effectiveItems) { | ||
this.__virtualizer.size = effectiveItems.length; | ||
this.__virtualizer.flush(); | ||
} | ||
} | ||
__createElements(count) { | ||
return [...Array(count)].map(() => { | ||
const item = document.createElement('vaadin-combo-box-item'); | ||
item.addEventListener('click', this.__boundOnItemClick); | ||
item.tabIndex = '-1'; | ||
item.style.width = '100%'; | ||
return item; | ||
}); | ||
} | ||
__updateElement(el, index) { | ||
const item = this.__effectiveItems[index]; | ||
el.setProperties({ | ||
item, | ||
index: this.__requestItemByIndex(item, index), | ||
label: this.getItemLabel(item, this._itemLabelPath), | ||
selected: this._isItemSelected(item, this._selectedItem, this._itemIdPath), | ||
renderer: this.renderer, | ||
focused: this._isItemFocused(this._focusedIndex, index) | ||
}); | ||
el.setAttribute('role', this._getAriaRole(index)); | ||
el.setAttribute('aria-selected', this._getAriaSelected(this._focusedIndex, index)); | ||
el.setAttribute('theme', this.theme); | ||
} | ||
_fireTouchAction(sourceEvent) { | ||
@@ -203,17 +213,2 @@ this.dispatchEvent( | ||
if (opened) { | ||
if (this._isNotEmpty(items) && this._selector && !this.filterChanged) { | ||
// iron-list triggers the scroller's reset after items update, and | ||
// this is not appropriate for undefined size lazy loading. | ||
// see https://github.com/vaadin/vaadin-combo-box-flow/issues/386 | ||
// We store iron-list scrolling position in order to restore | ||
// it later on after the items have been updated. | ||
const currentScrollerPosition = this._selector.firstVisibleIndex; | ||
if (currentScrollerPosition !== 0) { | ||
this._oldScrollerPosition = currentScrollerPosition; | ||
this._resetScrolling = true; | ||
} | ||
} | ||
// Let the position to be restored in the future calls unless it's not | ||
// caused by filtering | ||
this.filterChanged = false; | ||
return items; | ||
@@ -224,17 +219,2 @@ } | ||
_restoreScrollerPosition(items) { | ||
if (this._isNotEmpty(items) && this._selector && this._oldScrollerPosition !== 0) { | ||
// new items size might be less than old scrolling position | ||
this._scrollIntoView(Math.min(items.length - 1, this._oldScrollerPosition)); | ||
this._resetScrolling = false; | ||
// reset position to 0 again in order to properly handle the filter | ||
// cases (scroll to 0 after typing the filter) | ||
this._oldScrollerPosition = 0; | ||
} | ||
} | ||
_isNotEmpty(items) { | ||
return !this._isEmpty(items); | ||
} | ||
_isEmpty(items) { | ||
@@ -256,3 +236,3 @@ return !items || !items.length; | ||
} | ||
this.$.dropdown.opened = !!(opened && (loading || this._isNotEmpty(items))); | ||
this.$.dropdown.opened = !!(opened && (loading || !this._isEmpty(items))); | ||
this.$.dropdown.__emptyItems = false; | ||
@@ -276,2 +256,9 @@ } | ||
this.$.dropdown.$.overlay.addEventListener('mousedown', (e) => e.preventDefault()); | ||
this.__virtualizer = new Virtualizer({ | ||
createElements: this.__createElements.bind(this), | ||
updateElement: this.__updateElement.bind(this), | ||
scrollTarget: this._scroller, | ||
scrollContainer: this._selector | ||
}); | ||
} | ||
@@ -284,6 +271,6 @@ | ||
if (loading) { | ||
this.$.dropdown.$.overlay.setAttribute('loading', ''); | ||
} else { | ||
this.$.dropdown.$.overlay.removeAttribute('loading'); | ||
this.$.dropdown.$.overlay.toggleAttribute('loading', loading); | ||
if (!loading && this.__virtualizer) { | ||
setTimeout(() => this.__virtualizer.update()); | ||
} | ||
@@ -293,3 +280,3 @@ } | ||
_setOverlayHeight() { | ||
if (!this.opened || !this.positionTarget) { | ||
if (!this.__virtualizer || !this.opened || !this.positionTarget) { | ||
return; | ||
@@ -307,7 +294,2 @@ } | ||
this.$.dropdown.$.overlay.style.maxHeight = maxHeight; | ||
// we need to set height for iron-list to make its `firstVisibleIndex` work correctly. | ||
this._selector.style.maxHeight = maxHeight; | ||
this.updateViewportBoundaries(); | ||
} | ||
@@ -342,3 +324,3 @@ | ||
_onItemClick(e) { | ||
this.dispatchEvent(new CustomEvent('selection-changed', { detail: { item: e.model.item } })); | ||
this.dispatchEvent(new CustomEvent('selection-changed', { detail: { item: e.currentTarget.item } })); | ||
} | ||
@@ -368,4 +350,4 @@ | ||
*/ | ||
__requestItemByIndex(item, index, resetScrolling) { | ||
if (item instanceof ComboBoxPlaceholder && index !== undefined && !resetScrolling) { | ||
__requestItemByIndex(item, index) { | ||
if (item instanceof ComboBoxPlaceholder && index !== undefined) { | ||
this.dispatchEvent( | ||
@@ -411,3 +393,3 @@ new CustomEvent('index-requested', { detail: { index, currentScrollerPos: this._oldScrollerPosition } }) | ||
_scrollIntoView(index) { | ||
if (!(this.opened && index >= 0)) { | ||
if (!this.__virtualizer || !(this.opened && index >= 0)) { | ||
return; | ||
@@ -419,24 +401,25 @@ } | ||
if (index > this._selector.lastVisibleIndex - 1) { | ||
if (index > this.__virtualizer.lastVisibleIndex - 1) { | ||
// Index is below the bottom, scrolling down. Make the item appear at the bottom. | ||
// First scroll to target (will be at the top of the scroller) to make sure it's rendered. | ||
this._selector.scrollToIndex(index); | ||
this.__virtualizer.scrollToIndex(index); | ||
// Then calculate the index for the following scroll (to get the target to bottom of the scroller). | ||
targetIndex = index - visibleItemsCount + 1; | ||
} else if (index > this._selector.firstVisibleIndex) { | ||
} else if (index > this.__virtualizer.firstVisibleIndex) { | ||
// The item is already visible, scrolling is unnecessary per se. But we need to trigger iron-list to set | ||
// the correct scrollTop on the scrollTarget. Scrolling to firstVisibleIndex. | ||
targetIndex = this._selector.firstVisibleIndex; | ||
targetIndex = this.__virtualizer.firstVisibleIndex; | ||
} | ||
this._selector.scrollToIndex(Math.max(0, targetIndex)); | ||
this.__virtualizer.scrollToIndex(Math.max(0, targetIndex)); | ||
// Sometimes the item is partly below the bottom edge, detect and adjust. | ||
const pidx = this._selector._getPhysicalIndex(index), | ||
physicalItem = this._selector._physicalItems[pidx]; | ||
if (!physicalItem) { | ||
const lastPhysicalItem = [...this._selector.children].find( | ||
(el) => !el.hidden && el.index === this.__virtualizer.lastVisibleIndex | ||
); | ||
if (!lastPhysicalItem || index !== lastPhysicalItem.index) { | ||
return; | ||
} | ||
const physicalItemRect = physicalItem.getBoundingClientRect(), | ||
scrollerRect = this._scroller.getBoundingClientRect(), | ||
scrollTopAdjust = physicalItemRect.bottom - scrollerRect.bottom + this._viewportTotalPaddingBottom; | ||
const lastPhysicalItemRect = lastPhysicalItem.getBoundingClientRect(); | ||
const scrollerRect = this._scroller.getBoundingClientRect(); | ||
const scrollTopAdjust = lastPhysicalItemRect.bottom - scrollerRect.bottom + this._viewportTotalPaddingBottom; | ||
if (scrollTopAdjust > 0) { | ||
@@ -447,4 +430,6 @@ this._scroller.scrollTop += scrollTopAdjust; | ||
ensureItemsRendered() { | ||
this._selector._render(); | ||
__updateAllItems() { | ||
if (this.__virtualizer) { | ||
this.__virtualizer.update(); | ||
} | ||
} | ||
@@ -464,8 +449,6 @@ | ||
_patchWheelOverScrolling() { | ||
const selector = this._selector; | ||
selector.addEventListener('wheel', (e) => { | ||
const scroller = selector._scroller || selector.scrollTarget; | ||
this._selector.addEventListener('wheel', (e) => { | ||
const scroller = this._scroller; | ||
const scrolledToTop = scroller.scrollTop === 0; | ||
const scrolledToBottom = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight <= 1; | ||
if (scrolledToTop && e.deltaY < 0) { | ||
@@ -479,10 +462,5 @@ e.preventDefault(); | ||
updateViewportBoundaries() { | ||
this._cachedViewportTotalPaddingBottom = undefined; | ||
this._selector.updateViewportBoundaries(); | ||
} | ||
get _viewportTotalPaddingBottom() { | ||
if (this._cachedViewportTotalPaddingBottom === undefined) { | ||
const itemsStyle = window.getComputedStyle(this._selector.$.items); | ||
const itemsStyle = window.getComputedStyle(this._selector); | ||
this._cachedViewportTotalPaddingBottom = [itemsStyle.paddingBottom, itemsStyle.borderBottomWidth] | ||
@@ -502,6 +480,5 @@ .map((v) => { | ||
// Ensure items are positioned | ||
this._selector.scrollToIndex(this._selector.firstVisibleIndex); | ||
// Ensure viewport boundaries are up-to-date | ||
this.updateViewportBoundaries(); | ||
return this._selector.lastVisibleIndex - this._selector.firstVisibleIndex + 1; | ||
this.__virtualizer.scrollToIndex(this.__virtualizer.firstVisibleIndex); | ||
const hasItems = this.__virtualizer.size > 0; | ||
return hasItems ? this.__virtualizer.lastVisibleIndex - this.__virtualizer.firstVisibleIndex + 1 : 0; | ||
} | ||
@@ -508,0 +485,0 @@ |
@@ -6,5 +6,2 @@ /** | ||
*/ | ||
import { timeOut } from '@polymer/polymer/lib/utils/async.js'; | ||
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js'; | ||
import { flush } from '@polymer/polymer/lib/utils/flush.js'; | ||
import { IronA11yAnnouncer } from '@polymer/iron-a11y-announcer/iron-a11y-announcer.js'; | ||
@@ -603,19 +600,2 @@ import { processTemplates } from '@vaadin/vaadin-element-mixin/templates.js'; | ||
_onOpened() { | ||
// Pre P2 iron-list used a debouncer to render. Now that we synchronously render items, | ||
// we need to flush the DOM to make sure it doesn't get flushed in the middle of _render call | ||
// because that will cause problems to say the least. | ||
flush(); | ||
// With iron-list v1.3.9, calling `notifyResize()` no longer renders | ||
// the items synchronously. It is required to have the items rendered | ||
// before we update the overlay and the list positions and sizes. | ||
this.$.overlay.ensureItemsRendered(); | ||
this.$.overlay._selector.toggleScrollListener(true); | ||
// Ensure metrics are up-to-date | ||
this.$.overlay.updateViewportBoundaries(); | ||
// Force iron-list to create reusable nodes. Otherwise it will only start | ||
// doing that in scroll listener, which might affect performance. | ||
// See https://github.com/vaadin/vaadin-combo-box/pull/776 | ||
this.$.overlay._selector._increasePoolIfNeeded(); | ||
setTimeout(() => this._resizeDropdown(), 1); | ||
@@ -747,5 +727,4 @@ // Defer scroll position adjustment to improve performance. | ||
// Notify the dropdown about filter changing, so to let it skip the | ||
// scrolling restore | ||
this.$.overlay.filterChanged = true; | ||
// Scroll to the top of the list whenever the filter changes. | ||
this.$.overlay._scrollIntoView(0); | ||
@@ -911,6 +890,2 @@ if (this.items) { | ||
: this._indexOfValue(this.value, this.filteredItems); | ||
if (this.opened) { | ||
this._repositionOverlay(); | ||
} | ||
} | ||
@@ -957,37 +932,6 @@ } | ||
/** @private */ | ||
_repositionOverlay() { | ||
// async needed to reposition correctly after filtering | ||
// (especially when aligned on top of input) | ||
this.__repositionOverlayDebouncer = Debouncer.debounce( | ||
this.__repositionOverlayDebouncer, | ||
// Long debounce: sizing updates invoke multiple styling rounds, | ||
// which might affect performance, especially in old browsers. | ||
// See https://github.com/vaadin/vaadin-combo-box/pull/800 | ||
timeOut.after(500), | ||
() => { | ||
const selector = this.$.overlay._selector; | ||
if (!selector._isClientFull()) { | ||
// Due to the mismatch of the Y position of the item rendered | ||
// at the top of the scrolling list with some specific scroll | ||
// position values (2324, 3486, 6972, 60972, 95757 etc.) | ||
// iron-list loops the increasing of the pool and adds | ||
// too many items to the DOM. | ||
// Adjusting scroll position to equal the current scrollTop value | ||
// to avoid looping. | ||
selector._resetScrollPosition(selector._physicalTop); | ||
} | ||
this._resizeDropdown(); | ||
this.$.overlay.updateViewportBoundaries(); | ||
this.$.overlay.ensureItemsRendered(); | ||
selector.notifyResize(); | ||
flush(); | ||
} | ||
); | ||
} | ||
/** @private */ | ||
_indexOfValue(value, items) { | ||
if (items && this._isValidValue(value)) { | ||
for (let i = 0; i < items.length; i++) { | ||
if (this._getItemValue(items[i]) === value) { | ||
if (items[i] !== this.__placeHolder && this._getItemValue(items[i]) === value) { | ||
return i; | ||
@@ -994,0 +938,0 @@ } |
@@ -5,84 +5,82 @@ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; | ||
import '@vaadin/vaadin-lumo-styles/style.js'; | ||
import { overlay } from '@vaadin/vaadin-lumo-styles/mixins/overlay.js'; | ||
import '@vaadin/vaadin-overlay/theme/lumo/vaadin-overlay.js'; | ||
import '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js'; | ||
import { menuOverlayCore } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js'; | ||
registerStyles( | ||
'vaadin-combo-box-overlay', | ||
css` | ||
[part='content'] { | ||
padding: 0; | ||
} | ||
const comboBoxOverlay = css` | ||
[part='content'] { | ||
padding: 0; | ||
} | ||
:host { | ||
/* TODO: using a legacy mixin (unsupported) */ | ||
--iron-list-items-container: { | ||
border-width: var(--lumo-space-xs); | ||
border-style: solid; | ||
border-color: transparent; | ||
} | ||
} | ||
:host { | ||
--_vaadin-combo-box-items-container-border-width: var(--lumo-space-xs); | ||
--_vaadin-combo-box-items-container-border-style: solid; | ||
--_vaadin-combo-box-items-container-border-color: transparent; | ||
} | ||
/* Loading state */ | ||
/* Loading state */ | ||
/* When items are empty, the spinner needs some room */ | ||
:host(:not([closing])) [part~='content'] { | ||
min-height: calc(2 * var(--lumo-space-s) + var(--lumo-icon-size-s)); | ||
} | ||
/* When items are empty, the spinner needs some room */ | ||
:host(:not([closing])) [part~='content'] { | ||
min-height: calc(2 * var(--lumo-space-s) + var(--lumo-icon-size-s)); | ||
} | ||
[part~='overlay'] { | ||
position: relative; | ||
} | ||
[part~='overlay'] { | ||
position: relative; | ||
} | ||
:host([loading]) [part~='loader'] { | ||
box-sizing: border-box; | ||
width: var(--lumo-icon-size-s); | ||
height: var(--lumo-icon-size-s); | ||
position: absolute; | ||
z-index: 1; | ||
left: var(--lumo-space-s); | ||
right: var(--lumo-space-s); | ||
top: var(--lumo-space-s); | ||
margin-left: auto; | ||
margin-inline-start: auto; | ||
margin-inline-end: 0; | ||
border: 2px solid transparent; | ||
border-color: var(--lumo-primary-color-50pct) var(--lumo-primary-color-50pct) var(--lumo-primary-color) | ||
var(--lumo-primary-color); | ||
border-radius: calc(0.5 * var(--lumo-icon-size-s)); | ||
:host([loading]) [part~='loader'] { | ||
box-sizing: border-box; | ||
width: var(--lumo-icon-size-s); | ||
height: var(--lumo-icon-size-s); | ||
position: absolute; | ||
z-index: 1; | ||
left: var(--lumo-space-s); | ||
right: var(--lumo-space-s); | ||
top: var(--lumo-space-s); | ||
margin-left: auto; | ||
margin-inline-start: auto; | ||
margin-inline-end: 0; | ||
border: 2px solid transparent; | ||
border-color: var(--lumo-primary-color-50pct) var(--lumo-primary-color-50pct) var(--lumo-primary-color) | ||
var(--lumo-primary-color); | ||
border-radius: calc(0.5 * var(--lumo-icon-size-s)); | ||
opacity: 0; | ||
animation: 1s linear infinite lumo-combo-box-loader-rotate, 0.3s 0.1s lumo-combo-box-loader-fade-in both; | ||
pointer-events: none; | ||
} | ||
@keyframes lumo-combo-box-loader-fade-in { | ||
0% { | ||
opacity: 0; | ||
animation: 1s linear infinite lumo-combo-box-loader-rotate, 0.3s 0.1s lumo-combo-box-loader-fade-in both; | ||
pointer-events: none; | ||
} | ||
@keyframes lumo-combo-box-loader-fade-in { | ||
0% { | ||
opacity: 0; | ||
} | ||
100% { | ||
opacity: 1; | ||
} | ||
} | ||
100% { | ||
opacity: 1; | ||
} | ||
@keyframes lumo-combo-box-loader-rotate { | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
@keyframes lumo-combo-box-loader-rotate { | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
/* RTL specific styles */ | ||
/* RTL specific styles */ | ||
:host([loading][dir='rtl']) [part~='loader'] { | ||
left: auto; | ||
margin-left: 0; | ||
margin-right: auto; | ||
margin-inline-start: 0; | ||
margin-inline-end: auto; | ||
} | ||
`, | ||
{ moduleId: 'lumo-combo-box-overlay', include: ['lumo-overlay', 'lumo-menu-overlay-core'] } | ||
); | ||
:host([loading][dir='rtl']) [part~='loader'] { | ||
left: auto; | ||
margin-left: 0; | ||
margin-right: auto; | ||
margin-inline-start: 0; | ||
margin-inline-end: auto; | ||
} | ||
`; | ||
registerStyles('vaadin-combo-box-overlay', [overlay, menuOverlayCore, comboBoxOverlay], { | ||
moduleId: 'lumo-combo-box-overlay' | ||
}); |
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; | ||
import { item } from '@vaadin/vaadin-item/theme/lumo/vaadin-item-styles.js'; | ||
import '@vaadin/vaadin-lumo-styles/color.js'; | ||
import '@vaadin/vaadin-lumo-styles/spacing.js'; | ||
import '@vaadin/vaadin-lumo-styles/style.js'; | ||
import '@vaadin/vaadin-item/theme/lumo/vaadin-item.js'; | ||
/* TODO partly duplicated from vaadin-list-box styles. Should find a way to make it DRY */ | ||
registerStyles( | ||
'vaadin-combo-box-item', | ||
css` | ||
:host { | ||
cursor: default; | ||
-webkit-tap-highlight-color: var(--lumo-primary-color-10pct); | ||
padding-left: calc(var(--lumo-border-radius-m) / 4); | ||
padding-right: calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4); | ||
transition: background-color 100ms; | ||
border-radius: var(--lumo-border-radius-m); | ||
overflow: hidden; | ||
--_lumo-item-selected-icon-display: block; | ||
} | ||
const comboBoxItem = css` | ||
:host { | ||
cursor: default; | ||
-webkit-tap-highlight-color: var(--lumo-primary-color-10pct); | ||
padding-left: calc(var(--lumo-border-radius-m) / 4); | ||
padding-right: calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4); | ||
transition: background-color 100ms; | ||
border-radius: var(--lumo-border-radius-m); | ||
overflow: hidden; | ||
--_lumo-item-selected-icon-display: block; | ||
} | ||
:host(:hover) { | ||
background-color: var(--lumo-primary-color-10pct); | ||
} | ||
:host([focused]:not([disabled])) { | ||
box-shadow: inset 0 0 0 2px var(--lumo-primary-color-50pct); | ||
} | ||
@media (pointer: coarse) { | ||
:host(:hover) { | ||
background-color: var(--lumo-primary-color-10pct); | ||
background-color: transparent; | ||
} | ||
:host([focused]:not([disabled])) { | ||
box-shadow: inset 0 0 0 2px var(--lumo-primary-color-50pct); | ||
box-shadow: none; | ||
} | ||
} | ||
@media (pointer: coarse) { | ||
:host(:hover) { | ||
background-color: transparent; | ||
} | ||
/* RTL specific styles */ | ||
:host([dir='rtl']) { | ||
padding-right: calc(var(--lumo-border-radius-m) / 4); | ||
padding-left: calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4); | ||
} | ||
`; | ||
:host([focused]:not([disabled])) { | ||
box-shadow: none; | ||
} | ||
} | ||
/* RTL specific styles */ | ||
:host([dir='rtl']) { | ||
padding-right: calc(var(--lumo-border-radius-m) / 4); | ||
padding-left: calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4); | ||
} | ||
`, | ||
{ moduleId: 'lumo-combo-box-item', include: ['lumo-item'] } | ||
); | ||
registerStyles('vaadin-combo-box-item', [item, comboBoxItem], { | ||
moduleId: 'lumo-combo-box-item' | ||
}); |
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; | ||
import '@vaadin/vaadin-lumo-styles/font-icons.js'; | ||
import '@vaadin/vaadin-lumo-styles/mixins/field-button.js'; | ||
import { fieldButton } from '@vaadin/vaadin-lumo-styles/mixins/field-button.js'; | ||
import '@vaadin/vaadin-text-field/theme/lumo/vaadin-text-field.js'; | ||
registerStyles( | ||
'vaadin-combo-box', | ||
css` | ||
:host { | ||
outline: none; | ||
} | ||
const comboBox = css` | ||
:host { | ||
outline: none; | ||
} | ||
[part='toggle-button']::before { | ||
content: var(--lumo-icons-dropdown); | ||
} | ||
`, | ||
{ moduleId: 'lumo-combo-box', include: ['lumo-field-button'] } | ||
); | ||
[part='toggle-button']::before { | ||
content: var(--lumo-icons-dropdown); | ||
} | ||
`; | ||
registerStyles('vaadin-combo-box', [fieldButton, comboBox], { moduleId: 'lumo-combo-box' }); |
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; | ||
import '@vaadin/vaadin-material-styles/color.js'; | ||
import '@vaadin/vaadin-material-styles/mixins/menu-overlay.js'; | ||
import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js'; | ||
registerStyles( | ||
'vaadin-combo-box-overlay', | ||
css` | ||
:host { | ||
/* TODO using a legacy mixin (unsupported) */ | ||
--iron-list-items-container: { | ||
border-width: 8px 0; | ||
border-style: solid; | ||
border-color: transparent; | ||
} | ||
} | ||
const comboBoxOverlay = css` | ||
:host { | ||
--_vaadin-combo-box-items-container-border-width: 8px 0; | ||
--_vaadin-combo-box-items-container-border-style: solid; | ||
--_vaadin-combo-box-items-container-border-color: transparent; | ||
} | ||
[part='overlay'] { | ||
position: relative; | ||
overflow: visible; | ||
border-top-left-radius: 0; | ||
border-top-right-radius: 0; | ||
} | ||
[part='overlay'] { | ||
position: relative; | ||
overflow: visible; | ||
border-top-left-radius: 0; | ||
border-top-right-radius: 0; | ||
} | ||
[part='content'] { | ||
padding: 0; | ||
} | ||
[part='content'] { | ||
padding: 0; | ||
} | ||
:host([loading]) [part='loader'] { | ||
height: 2px; | ||
position: absolute; | ||
z-index: 1; | ||
top: -2px; | ||
left: 0; | ||
right: 0; | ||
background: var(--material-background-color) | ||
linear-gradient( | ||
90deg, | ||
transparent 0%, | ||
transparent 20%, | ||
var(--material-primary-color) 20%, | ||
var(--material-primary-color) 40%, | ||
transparent 40%, | ||
transparent 60%, | ||
var(--material-primary-color) 60%, | ||
var(--material-primary-color) 80%, | ||
transparent 80%, | ||
transparent 100% | ||
) | ||
0 0 / 400% 100% repeat-x; | ||
:host([loading]) [part='loader'] { | ||
height: 2px; | ||
position: absolute; | ||
z-index: 1; | ||
top: -2px; | ||
left: 0; | ||
right: 0; | ||
background: var(--material-background-color) | ||
linear-gradient( | ||
90deg, | ||
transparent 0%, | ||
transparent 20%, | ||
var(--material-primary-color) 20%, | ||
var(--material-primary-color) 40%, | ||
transparent 40%, | ||
transparent 60%, | ||
var(--material-primary-color) 60%, | ||
var(--material-primary-color) 80%, | ||
transparent 80%, | ||
transparent 100% | ||
) | ||
0 0 / 400% 100% repeat-x; | ||
opacity: 0; | ||
animation: 3s linear infinite material-combo-box-loader-progress, 0.3s 0.1s both material-combo-box-loader-fade-in; | ||
} | ||
[part='loader']::before { | ||
content: ''; | ||
display: block; | ||
height: 100%; | ||
opacity: 0.16; | ||
background: var(--material-primary-color); | ||
} | ||
@keyframes material-combo-box-loader-fade-in { | ||
0% { | ||
opacity: 0; | ||
animation: 3s linear infinite material-combo-box-loader-progress, 0.3s 0.1s both material-combo-box-loader-fade-in; | ||
} | ||
[part='loader']::before { | ||
content: ''; | ||
display: block; | ||
height: 100%; | ||
opacity: 0.16; | ||
background: var(--material-primary-color); | ||
100% { | ||
opacity: 1; | ||
} | ||
} | ||
@keyframes material-combo-box-loader-fade-in { | ||
0% { | ||
opacity: 0; | ||
} | ||
@keyframes material-combo-box-loader-progress { | ||
0% { | ||
background-position: 0 0; | ||
background-size: 300% 100%; | ||
} | ||
100% { | ||
opacity: 1; | ||
} | ||
33% { | ||
background-position: -100% 0; | ||
background-size: 400% 100%; | ||
} | ||
@keyframes material-combo-box-loader-progress { | ||
0% { | ||
background-position: 0 0; | ||
background-size: 300% 100%; | ||
} | ||
67% { | ||
background-position: -200% 0; | ||
background-size: 250% 100%; | ||
} | ||
33% { | ||
background-position: -100% 0; | ||
background-size: 400% 100%; | ||
} | ||
100% { | ||
background-position: -300% 0; | ||
background-size: 300% 100%; | ||
} | ||
} | ||
67% { | ||
background-position: -200% 0; | ||
background-size: 250% 100%; | ||
} | ||
/* RTL specific styles */ | ||
100% { | ||
background-position: -300% 0; | ||
background-size: 300% 100%; | ||
} | ||
@keyframes material-combo-box-loader-progress-rtl { | ||
0% { | ||
background-position: 100% 0; | ||
background-size: 300% 100%; | ||
} | ||
/* RTL specific styles */ | ||
33% { | ||
background-position: 200% 0; | ||
background-size: 400% 100%; | ||
} | ||
@keyframes material-combo-box-loader-progress-rtl { | ||
0% { | ||
background-position: 100% 0; | ||
background-size: 300% 100%; | ||
} | ||
67% { | ||
background-position: 300% 0; | ||
background-size: 250% 100%; | ||
} | ||
33% { | ||
background-position: 200% 0; | ||
background-size: 400% 100%; | ||
} | ||
100% { | ||
background-position: 400% 0; | ||
background-size: 300% 100%; | ||
} | ||
} | ||
67% { | ||
background-position: 300% 0; | ||
background-size: 250% 100%; | ||
} | ||
:host([loading][dir='rtl']) [part='loader'] { | ||
animation: 3s linear infinite material-combo-box-loader-progress-rtl, | ||
0.3s 0.1s both material-combo-box-loader-fade-in; | ||
} | ||
`; | ||
100% { | ||
background-position: 400% 0; | ||
background-size: 300% 100%; | ||
} | ||
} | ||
:host([loading][dir='rtl']) [part='loader'] { | ||
animation: 3s linear infinite material-combo-box-loader-progress-rtl, | ||
0.3s 0.1s both material-combo-box-loader-fade-in; | ||
} | ||
`, | ||
{ moduleId: 'material-combo-box-overlay', include: ['material-menu-overlay'] } | ||
); | ||
registerStyles('vaadin-combo-box-overlay', [menuOverlay, comboBoxOverlay], { | ||
moduleId: 'material-combo-box-overlay' | ||
}); |
@@ -5,32 +5,32 @@ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; | ||
import '@vaadin/vaadin-material-styles/typography.js'; | ||
import '@vaadin/vaadin-item/theme/material/vaadin-item.js'; | ||
import { item } from '@vaadin/vaadin-item/theme/material/vaadin-item-styles.js'; | ||
registerStyles( | ||
'vaadin-combo-box-item', | ||
css` | ||
:host { | ||
cursor: pointer; | ||
-webkit-tap-highlight-color: transparent; | ||
padding: 4px 10px; | ||
min-height: 36px; | ||
font-size: var(--material-small-font-size); | ||
--_material-item-selected-icon-display: block; | ||
} | ||
const comboBoxItem = css` | ||
:host { | ||
cursor: pointer; | ||
-webkit-tap-highlight-color: transparent; | ||
padding: 4px 10px; | ||
min-height: 36px; | ||
font-size: var(--material-small-font-size); | ||
--_material-item-selected-icon-display: block; | ||
} | ||
:host(:hover) { | ||
background-color: var(--material-secondary-background-color); | ||
} | ||
:host(:hover) { | ||
background-color: var(--material-secondary-background-color); | ||
} | ||
:host([focused]) { | ||
background-color: var(--material-divider-color); | ||
} | ||
@media (pointer: coarse) { | ||
:host(:hover), | ||
:host([focused]) { | ||
background-color: var(--material-divider-color); | ||
background-color: transparent; | ||
} | ||
} | ||
`; | ||
@media (pointer: coarse) { | ||
:host(:hover), | ||
:host([focused]) { | ||
background-color: transparent; | ||
} | ||
} | ||
`, | ||
{ moduleId: 'material-combo-box-item', include: ['material-item'] } | ||
); | ||
registerStyles('vaadin-combo-box-item', [item, comboBoxItem], { | ||
moduleId: 'material-combo-box-item' | ||
}); |
@@ -5,22 +5,20 @@ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js'; | ||
import '@vaadin/vaadin-material-styles/font-icons.js'; | ||
import '@vaadin/vaadin-material-styles/mixins/field-button.js'; | ||
import { fieldButton } from '@vaadin/vaadin-material-styles/mixins/field-button.js'; | ||
registerStyles( | ||
'vaadin-combo-box', | ||
css` | ||
:host { | ||
display: inline-flex; | ||
outline: none; | ||
-webkit-tap-highlight-color: transparent; | ||
} | ||
const comboBox = css` | ||
:host { | ||
display: inline-flex; | ||
outline: none; | ||
-webkit-tap-highlight-color: transparent; | ||
} | ||
[part='toggle-button']::before { | ||
content: var(--material-icons-dropdown); | ||
} | ||
[part='toggle-button']::before { | ||
content: var(--material-icons-dropdown); | ||
} | ||
:host([opened]) [part='toggle-button'] { | ||
transform: rotate(180deg); | ||
} | ||
`, | ||
{ moduleId: 'material-combo-box', include: ['material-field-button'] } | ||
); | ||
:host([opened]) [part='toggle-button'] { | ||
transform: rotate(180deg); | ||
} | ||
`; | ||
registerStyles('vaadin-combo-box', [fieldButton, comboBox], { moduleId: 'material-combo-box' }); |
134392
3467
+ Added@vaadin/vaadin-virtual-list@22.1.0(transitive)
+ Added@vaadin/virtual-list@22.1.0(transitive)
- Removed@polymer/iron-list@^3.0.0
- Removed@polymer/iron-a11y-keys-behavior@3.0.1(transitive)
- Removed@polymer/iron-list@3.1.0(transitive)
- Removed@polymer/iron-scroll-target-behavior@3.0.1(transitive)