@universal-material/web
Version:
Material web components
158 lines (157 loc) • 5.6 kB
JavaScript
import { __decorate } from "tslib";
import { html, LitElement, render } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { map } from 'lit/directives/map.js';
import { when } from 'lit/directives/when.js';
import { styles } from './overflow-menu.styles.js';
let OverflowMenu = class OverflowMenu extends LitElement {
static { this.styles = styles; }
#resizeObserver;
#items;
#collapsedItems;
#anchor;
set anchor(value) {
this.#anchor = value;
this.#invalidate();
this.#resizeObserver.disconnect();
this.#resizeObserver.observe(this.anchor);
}
get anchor() {
return this.#anchor ?? this;
}
#menuItemsContainer;
#updateMenusTimeout;
constructor() {
super();
this.#resizeObserver = new ResizeObserver(() => this.#invalidate());
this.#items = [];
this.#collapsedItems = [];
this._renderMenu = false;
this.#anchor = null;
this.#menuItemsContainer = document.createElement('div');
this.#updateMenusTimeout = 0;
this.#menuItemsContainer.slot = 'menu-items';
setTimeout(() => this.appendChild(this.#menuItemsContainer));
}
connectedCallback() {
super.connectedCallback();
this.anchor = this.anchor;
}
disconnectedCallback() {
super.disconnectedCallback();
this.#resizeObserver.disconnect();
}
#invalidate() {
this.#updateMenuToggleVisibility();
this.#updateMenuItems();
}
#updateMenuToggleVisibility() {
let collapsedCount = 0;
let hasAlwaysCollapsedItems = false;
for (const item of this.#items) {
hasAlwaysCollapsedItems = hasAlwaysCollapsedItems || item.collapse === 'always';
if (this.#isNotCollapsedMenuItem(item)) {
continue;
}
collapsedCount++;
}
const firstItem = this.#items[0];
const renderMenu = hasAlwaysCollapsedItems || !!firstItem && (this._renderMenu
? collapsedCount > 1
: collapsedCount > 0);
if (this._renderMenu !== renderMenu) {
this._renderMenu = renderMenu;
}
}
#updateMenuItems() {
if (!this._renderMenu) {
this.#collapsedItems.length = 0;
return;
}
clearTimeout(this.#updateMenusTimeout);
this.#updateMenusTimeout = setTimeout(() => {
const previousCollapsedLength = this.#collapsedItems.length;
this.#collapsedItems.length = 0;
for (const item of this.#items) {
if (this.#isNotCollapsedMenuItem(item)) {
continue;
}
this.#collapsedItems.push(item);
}
if (previousCollapsedLength !== this.#collapsedItems.length) {
this.requestUpdate();
}
}, 100);
}
#isNotCollapsedMenuItem(item) {
return item.offsetTop === this.offsetTop && item.collapse !== 'always';
}
#handleSlotChange(e) {
const slot = e.target;
this.#items = slot
.assignedElements()
.filter(el => el.tagName === 'U-OVERFLOW-MENU-ITEM')
.reverse();
this.#invalidate();
}
render() {
this._renderMenuItems();
const classes = { 'show-menu': this._renderMenu };
return html `
<div class="container ${classMap(classes)}">
<div class="items-set">
<div class="empty-space"></div>
<slot @slotchange="${this.#handleSlotChange}"></slot>
</div>
${when(this._renderMenu, () => html `
<div class="inner-menu">
<u-icon-button @click=${{ handleEvent: () => this.menu?.toggle() }}>
<slot name="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 -960 960 960" width="1em"
fill="currentColor">
<path
d="M480-160q-33 0-56.5-23.5T400-240q0-33 23.5-56.5T480-320q33 0 56.5 23.5T560-240q0
33-23.5 56.5T480-160Zm0-240q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0
33-23.5 56.5T480-400Zm0-240q-33 0-56.5-23.5T400-720q0-33 23.5-56.5T480-800q33 0 56.5 23.5T560-720q0 33-23.5 56.5T480-640Z"/>
</svg>
</slot>
</u-icon-button>
<u-menu anchor-corner="end-end">
<slot name="menu-items"></slot>
</u-menu>
</div>
`)}
</div>
`;
}
_renderMenuItems() {
const menuItems = html `
${map(this.#collapsedItems, item => {
const nodes = item.childNodes.values();
return html `
<u-menu-item @click=${{ handleEvent: () => item.click() }}>
<div slot="leading-icon">
${map(nodes, node => node.cloneNode(true))}
</div>
${item.label}
</u-menu-item>
`;
})}`;
render(menuItems, this.#menuItemsContainer);
}
};
__decorate([
state()
], OverflowMenu.prototype, "_renderMenu", void 0);
__decorate([
query('u-menu')
], OverflowMenu.prototype, "menu", void 0);
__decorate([
property()
], OverflowMenu.prototype, "anchor", null);
OverflowMenu = __decorate([
customElement('u-overflow-menu')
], OverflowMenu);
export { OverflowMenu };
//# sourceMappingURL=overflow-menu.js.map