|
|
|
@ -117,7 +117,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#list {
|
|
|
|
|
#popup {
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
transition: opacity 0ms;
|
|
|
|
|
opacity: 0;
|
|
|
|
@ -126,12 +126,12 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
height: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#list[open] {
|
|
|
|
|
#popup[open] {
|
|
|
|
|
pointer-events: all;
|
|
|
|
|
transition: opacity 180ms;
|
|
|
|
|
opacity: 1;
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
background: #FAFAFA;
|
|
|
|
|
background: var(--tp-dropdown-popup-bg, #FAFAFA);
|
|
|
|
|
height: auto;
|
|
|
|
|
box-shadow: var(--shadow-2dp);
|
|
|
|
|
}
|
|
|
|
@ -148,17 +148,19 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
div[role="option"]:hover {
|
|
|
|
|
background: #E0F7FA;
|
|
|
|
|
background: var(--tp-dropdown-hovered-item-bg, #E0F7FA);
|
|
|
|
|
color: var(--tp-dropdown-hovered-item-color, inherit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
div[role="option"]:focus {
|
|
|
|
|
background: #EEEEEE;
|
|
|
|
|
background: var(--tp-dropdown-focused-item-bg, #EEEEEE);
|
|
|
|
|
color: var(--tp-dropdown-focused-item-color, inherit);
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
div[role="option"][selected] {
|
|
|
|
|
background: #4FC3F7;
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
background: var(--tp-dropdown-selected-item-bg, #4FC3F7);
|
|
|
|
|
color: var(--tp-dropdown-selected-item-color, #FFFFFF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
div[role="option"]:first-of-type {
|
|
|
|
@ -200,7 +202,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
|
|
|
|
|
@media all and (min-width: 0) and (max-width: 480px) {
|
|
|
|
|
|
|
|
|
|
:host(:not([not-responsive])) #list {
|
|
|
|
|
:host(:not([not-responsive])) #popup {
|
|
|
|
|
top: 40px !important;
|
|
|
|
|
bottom: 40px !important;
|
|
|
|
|
left: 40px !important;
|
|
|
|
@ -214,7 +216,6 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
|
|
|
|
|
:host(:not([not-responsive])) #itemList {
|
|
|
|
|
max-height: none !important;
|
|
|
|
|
display: flex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:host(:not([not-responsive])) #filter {
|
|
|
|
@ -235,7 +236,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
const { label, isOpen, errorMessage, filterPlaceholder, extensible, filterable, items} = this;
|
|
|
|
|
const { label, isOpen, errorMessage, filterPlaceholder, extensible, filterable, items } = this;
|
|
|
|
|
|
|
|
|
|
return html`
|
|
|
|
|
<tp-media-query query="(min-width: 0) and (max-width: 480px)" @media-query-update=${this._queryUpdated}></tp-media-query>
|
|
|
|
@ -248,7 +249,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
<tp-icon id="toggleIcon" ?open="${isOpen}" .icon=${TpDropdown.selectorIcon}></tp-icon>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="list" ?open="${isOpen}">
|
|
|
|
|
<div id="popup" ?open="${isOpen}" part="popup">
|
|
|
|
|
${filterable ? html`
|
|
|
|
|
<tp-input part="filter" exportparts="wrap:filterWrap" id="filter" .value=${this._filterTerm || ''} @input=${e => this._filterTerm = e.target.value} .inert=${!isOpen} ?hidden=${!(filterable || extensible)}>
|
|
|
|
|
<input type="text" placeholder=${filterPlaceholder}>
|
|
|
|
@ -284,6 +285,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
autoExtend: { type: Boolean, },
|
|
|
|
|
focused: { type: Boolean, reflect: true, },
|
|
|
|
|
readonly: { type: Boolean, reflect: true },
|
|
|
|
|
invalid: { type: Boolean, reflect: true },
|
|
|
|
|
/*
|
|
|
|
|
* Stores the first known value of the `value` property that is not falsy.
|
|
|
|
|
* If `items` changes and no longer holds the originally selected item,
|
|
|
|
@ -349,7 +351,11 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
this._itemsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
if (changes.has('isOpen')) {
|
|
|
|
|
this.dispatchEvent(new CustomEvent('is-open-changed', { detail: this.isOpen, bubbles: true, composed: true }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return super.shouldUpdate(changes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updated(changes) {
|
|
|
|
@ -522,6 +528,12 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
this.label = this.items[idx].label;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.isOpen) {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.focus();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.isOpen = false;
|
|
|
|
|
window.removeEventListener('resize', this._boundSetListPosition);
|
|
|
|
|
document.removeEventListener('scroll', this._boundSetListPosition);
|
|
|
|
@ -549,8 +561,8 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
|
|
|
|
|
var spaceBottom = winHeight - rect.top - rect.height - filterHeight;
|
|
|
|
|
this.$.itemList.style.maxHeight = (spaceBottom - 20) + 'px';
|
|
|
|
|
this.$.list.style.maxWidth = rect.width + 'px';
|
|
|
|
|
this.$.list.style.minWidth = rect.width + 'px';
|
|
|
|
|
this.$.popup.style.maxWidth = rect.width + 'px';
|
|
|
|
|
this.$.popup.style.minWidth = rect.width + 'px';
|
|
|
|
|
|
|
|
|
|
var useTopLayout = spaceBottom < 150;
|
|
|
|
|
|
|
|
|
@ -558,7 +570,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
this.$.itemList.style.maxHeight = (rect.top - 20) + 'px';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._posFixed(this, this.$.list, {
|
|
|
|
|
this._posFixed(this, this.$.popup, {
|
|
|
|
|
spacing: 0,
|
|
|
|
|
valign: useTopLayout ? 'top' : 'bottom',
|
|
|
|
|
halign: 'left'
|
|
|
|
@ -568,7 +580,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
var lastItem = this.$.itemList.querySelector('div[role="option"]:last-of-type');
|
|
|
|
|
if (lastItem) {
|
|
|
|
|
this.$.list.style.maxHeight = lastItem.getBoundingClientRect().top + 'px';
|
|
|
|
|
this.$.popup.style.maxHeight = lastItem.getBoundingClientRect().top + 'px';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -673,6 +685,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
}, 20);
|
|
|
|
|
} else {
|
|
|
|
|
this.value = itemEl.value;
|
|
|
|
|
this.dispatchEvent(new CustomEvent('selection-changed', { detail: this.value, bubbles: true, composed: true }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rootTarget = e.composedPath()[0];
|
|
|
|
@ -693,7 +706,6 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
if (this.isOpen) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.close();
|
|
|
|
|
this.focus();
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -782,7 +794,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
var label = this.$.filter.value;
|
|
|
|
|
if (label !== '') {
|
|
|
|
|
if (!this._selectByLabel(label)) {
|
|
|
|
|
this.fire('add-item', { label: label });
|
|
|
|
|
this.dispatchEvent(new CustomEvent('add-item', { detail: { label }, bubbles: true, composed: true }));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -792,7 +804,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
if (Array.isArray(this.items)) {
|
|
|
|
|
for (var i = 0, li = this.items.length; i < li; ++i) {
|
|
|
|
|
if (String(this.items[i].label).toLowerCase() === String(label)) {
|
|
|
|
|
this.value = this.items[i].id;
|
|
|
|
|
this.value = this.items[i].value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -806,6 +818,7 @@ class TpDropdown extends BaseElement {
|
|
|
|
|
|
|
|
|
|
if (item) {
|
|
|
|
|
this.value = item.value;
|
|
|
|
|
this.dispatchEvent(new CustomEvent('selection-changed', { detail: this.value, bubbles: true, composed: true }));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|