@universal-material/web
Version:
Material web components
200 lines • 6.6 kB
JavaScript
import { __decorate } from "tslib";
import { html, LitElement } from 'lit';
import { customElement, property, query, queryAssignedElements, } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { styles as baseStyles } from '../shared/base.styles.js';
import { styles } from './tab-bar.styles.js';
import { UmTab } from './tab.js';
let UmTabBar = class UmTabBar extends LitElement {
static { this.styles = [baseStyles, styles]; }
#tabs;
#activeTab;
#resizeObserver;
get activeTabIndex() {
if (!this.activeTab) {
return -1;
}
return this.#tabs.indexOf(this.activeTab);
}
set activeTabIndex(index) {
this.activeTab = this.#tabs[index];
}
get activeTab() {
return this.#activeTab;
}
set activeTab(activeTab) {
if (!this.#tabs.length) {
this.#activeTab = null;
this._updateTabIndicator();
return;
}
if (!activeTab
|| this.#activeTab === activeTab
|| !this.#tabs.includes(activeTab)) {
return;
}
const previouslyActiveTab = this.#activeTab;
this.#activeTab = activeTab;
previouslyActiveTab?.requestUpdate();
activeTab.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
activeTab.requestUpdate();
this._updateTabIndicator();
}
attributeChangedCallback(name, _, __) {
if (name === 'variant') {
this._updateTabIndicator();
}
}
connectedCallback() {
super.connectedCallback();
this.#attach();
}
render() {
const classes = { secondary: this.variant === 'secondary' };
return html `
<div
class="scroll-indicator scroll-left active"
=${this.#scrollToLeft}>
<u-elevation></u-elevation>
<u-ripple></u-ripple>
<slot name="scroll-left">
<svg
xmlns="http://www.w3.org/2000/svg"
height="1em"
viewBox="0 -960 960 960"
width="1em"
fill="currentColor">
<path d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z" />
</svg>
</slot>
</div>
<div
class="container ${classMap(classes)}"
=${this.#handleContainerScrollEnd}>
<slot =${this.#handleSlotChange}></slot>
<div class="tab-indicator"></div>
</div>
<div
class="scroll-indicator scroll-right active"
=${this.#scrollToRight}>
<u-elevation></u-elevation>
<u-ripple></u-ripple>
<slot name="scroll-right">
<svg
xmlns="http://www.w3.org/2000/svg"
height="1em"
viewBox="0 -960 960 960"
width="1em"
fill="currentColor">
<path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z" />
</svg>
</slot>
</div>
`;
}
constructor() {
super();
this.#tabs = [];
this.#activeTab = null;
this.#resizeObserver = new ResizeObserver(() => {
this._setScrollIndicatorsActive();
this._updateTabIndicator();
});
this.variant = 'primary';
this.#handleSlotChange = (e) => {
const slot = e.target;
this.#tabs =
slot.assignedElements({ flatten: true }).filter(element => element instanceof UmTab);
for (const tab of this.#tabs) {
tab._bar = this;
}
if (this.activeTabIndex > -1) {
return;
}
this.activeTab = this.#tabs[0];
};
this.#handleContainerScrollEnd = () => {
this._setScrollIndicatorsActive();
};
this.#scrollToLeft = () => {
this._container.scrollBy({
left: this._container.offsetWidth / -2,
behavior: 'smooth',
});
};
this.#scrollToRight = () => {
this._container.scrollBy({
left: this._container.offsetWidth / 2,
behavior: 'smooth',
});
};
this.#resizeObserver.observe(this);
}
#handleSlotChange;
#handleContainerScrollEnd;
_updateTabIndicator() {
if (!this._tabIndicator) {
return;
}
if (!this.activeTab) {
this._tabIndicator.style.left = '0';
this._tabIndicator.style.width = '0';
return;
}
const tabStyles = getComputedStyle(this.activeTab);
const padding = this.variant === 'primary' ? parseInt(tabStyles.paddingInline, 10) : 0;
this._tabIndicator.style.left = `${this.activeTab.offsetLeft + padding}px`;
this._tabIndicator.style.width = `${this.activeTab.offsetWidth - padding * 2}px`;
}
#scrollToLeft;
#scrollToRight;
_setScrollIndicatorsActive() {
const scrollSafeMargin = 1;
const scrollLength = this._container.scrollWidth - this._container.offsetWidth;
const isRtl = getComputedStyle(this._container).direction === 'rtl';
const scrollStart = isRtl
? this._container.scrollLeft + scrollLength
: this._container.scrollLeft;
if (scrollStart - scrollSafeMargin <= 0) {
this._container.scrollBy(-1, 0);
this._scrollLeft.classList.remove('active');
}
else {
this._scrollLeft.classList.add('active');
}
if (scrollStart >= scrollLength - scrollSafeMargin) {
this._container.scrollBy(1, 0);
this._scrollRight.classList.remove('active');
}
else {
this._scrollRight.classList.add('active');
}
}
async #attach() {
await this.updateComplete;
this._setScrollIndicatorsActive();
}
};
__decorate([
property({ reflect: true })
], UmTabBar.prototype, "variant", void 0);
__decorate([
query('.scroll-left')
], UmTabBar.prototype, "_scrollLeft", void 0);
__decorate([
query('.scroll-right')
], UmTabBar.prototype, "_scrollRight", void 0);
__decorate([
query('.container')
], UmTabBar.prototype, "_container", void 0);
__decorate([
query('.tab-indicator')
], UmTabBar.prototype, "_tabIndicator", void 0);
__decorate([
queryAssignedElements({ flatten: true })
], UmTabBar.prototype, "assignedElements", void 0);
UmTabBar = __decorate([
customElement('u-tab-bar')
], UmTabBar);
export { UmTabBar };
//# sourceMappingURL=tab-bar.js.map