UNPKG

igniteui-webcomponents

Version:

Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.

330 lines 12.7 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var IgcTabsComponent_1; import { LitElement, html, nothing } from 'lit'; import { eventOptions, property, query, queryAssignedElements, state, } from 'lit/decorators.js'; import { createRef, ref } from 'lit/directives/ref.js'; import { themes } from '../../theming/theming-decorator.js'; import IgcIconButtonComponent from '../button/icon-button.js'; import { addKeybindings, arrowLeft, arrowRight, endKey, homeKey, } from '../common/controllers/key-bindings.js'; import { createMutationController, } from '../common/controllers/mutation-observer.js'; import { blazorAdditionalDependencies } from '../common/decorators/blazorAdditionalDependencies.js'; import { watch } from '../common/decorators/watch.js'; import { registerComponent } from '../common/definitions/register.js'; import { EventEmitterMixin } from '../common/mixins/event-emitter.js'; import { createCounter, getOffset, isLTR, wrap } from '../common/util.js'; import IgcTabPanelComponent from './tab-panel.js'; import IgcTabComponent from './tab.js'; import { styles as shared } from './themes/shared/tabs/tabs.common.css.js'; import { all } from './themes/tabs-themes.js'; import { styles } from './themes/tabs.base.css.js'; let IgcTabsComponent = IgcTabsComponent_1 = class IgcTabsComponent extends EventEmitterMixin(LitElement) { static register() { registerComponent(IgcTabsComponent_1, IgcTabComponent, IgcTabPanelComponent, IgcIconButtonComponent); } get _closestActiveTabIndex() { const root = this.getRootNode(); const tabs = this.enabledTabs; const tab = root.activeElement ? root.activeElement.closest(IgcTabComponent.tagName) : null; return tabs.indexOf(tab); } _mutationCallback({ changes: { attributes, added, removed }, }) { const ownAttributes = attributes.filter((tab) => tab.closest(this.tagName) === this); const ownAdded = added.filter(({ target }) => target.closest(this.tagName) === this); const ownRemoved = removed.filter(({ target }) => target.closest(this.tagName) === this); this.setSelectedTab(ownAttributes.find((tab) => tab.selected)); if (ownRemoved.length || ownAdded.length) { for (const { node: tab } of ownRemoved) { this.resizeObserver?.unobserve(tab); if (tab.selected && tab === this.activeTab) { this.activeTab = undefined; } } for (const { node: tab } of ownAdded) { this.resizeObserver?.observe(tab); if (tab.selected) { this.setSelectedTab(tab); } } this.syncAttributes(); } this.updateSelectedTab(); this.activeTab?.scrollIntoView({ block: 'nearest' }); this.alignIndicator(); } get enabledTabs() { return this.tabs.filter((tab) => !tab.disabled); } get selected() { return this.activeTab?.panel ?? ''; } alignIndicator() { const styles = { visibility: this.activeTab ? 'visible' : 'hidden', transitionDuration: '0.3s', }; if (this.activeTab && this.wrapper) { Object.assign(styles, { width: `${this.activeTab.offsetWidth}px`, transform: `translate(${isLTR(this) ? getOffset(this.activeTab, this.wrapper).left : getOffset(this.activeTab, this.wrapper).right}px)`, }); } Object.assign(this.selectedIndicator?.style ?? {}, styles); } constructor() { super(); this.headerRef = createRef(); this.showScrollButtons = false; this.disableStartScrollButton = true; this.disableEndScrollButton = false; this.alignment = 'start'; this.activation = 'auto'; addKeybindings(this, { ref: this.headerRef, bindingDefaults: { preventDefault: true }, }) .set(arrowLeft, this.onArrowLeft) .set(arrowRight, this.onArrowRight) .set(homeKey, this.onHomeKey) .set(endKey, this.onEndKey) .setActivateHandler(this.onActivationKey); createMutationController(this, { callback: this._mutationCallback, config: { attributeFilter: ['selected'], childList: true, subtree: true, }, filter: [IgcTabComponent.tagName], }); } async firstUpdated() { this.showScrollButtons = this.container.scrollWidth > this.container.clientWidth; await this.updateComplete; this.syncAttributes(); this.setupObserver(); this.setSelectedTab(this.tabs.filter((tab) => tab.selected).at(-1) ?? this.enabledTabs.at(0)); this.updateSelectedTab(); } disconnectedCallback() { this.resizeObserver?.disconnect(); super.disconnectedCallback(); } updateButtonsOnResize() { this.showScrollButtons = false; this.performUpdate(); this.showScrollButtons = this.container.scrollWidth > this.container.clientWidth; this.updateScrollButtons(); } updateScrollButtons() { const { scrollLeft, offsetWidth } = this.container; const { scrollWidth } = this.wrapper; this.disableEndScrollButton = scrollWidth <= Math.abs(scrollLeft) + offsetWidth; this.disableStartScrollButton = scrollLeft === 0; } setupObserver() { this.resizeObserver = new ResizeObserver(() => { this.updateButtonsOnResize(); this.alignIndicator(); }); [this.container, this.wrapper, ...this.tabs].forEach((element) => this.resizeObserver.observe(element)); } updateSelectedTab() { this.tabs.forEach((tab) => { tab.selected = tab === this.activeTab; }); this.panels.forEach((panel) => { panel.hidden = panel.id !== this.activeTab?.panel; }); } syncAttributes() { const prefix = this.id ? `${this.id}-` : ''; this.tabs.forEach((tab, index) => { if (!tab.panel) { tab.panel = this.panels.at(index)?.id ?? `${prefix}tab-${IgcTabsComponent_1.increment()}`; } this.panels .find((panel) => panel.id === tab.panel) ?.setAttribute('aria-labelledby', tab.id); }); } setSelectedTab(tab) { if (!tab || tab === this.activeTab) { return; } if (this.activeTab) { this.activeTab.selected = false; } this.activeTab = tab; this.activeTab.selected = true; } scrollByTabOffset(direction) { const { scrollLeft, offsetWidth } = this.container; const LTR = isLTR(this); const next = direction === 'end'; const pivot = Math.abs(next ? offsetWidth + scrollLeft : scrollLeft); let amount = this.tabs .map((tab) => ({ start: LTR ? getOffset(tab, this.wrapper).left : Math.abs(getOffset(tab, this.wrapper).right), width: tab.offsetWidth, })) .filter((offset) => next ? offset.start + offset.width > pivot : offset.start < pivot) .at(next ? 0 : -1).width; amount *= next ? 1 : -1; this.container.scrollBy({ left: LTR ? amount : -amount }); } handleClick(event) { const target = event.target; const tab = target.closest('igc-tab'); if (!(tab && this.contains(tab)) || tab.disabled) { return; } tab.focus(); this.setSelectedTab(tab); this.emitEvent('igcChange', { detail: tab }); } _scrollToAndFocus(tab) { tab.scrollIntoView({ behavior: 'auto', block: 'nearest' }); tab.focus(); } _kbActivateTab(tab) { this._scrollToAndFocus(tab); if (this.activation === 'auto') { this.setSelectedTab(tab); this.emitEvent('igcChange', { detail: tab }); } } onArrowLeft() { const tabs = this.enabledTabs; const delta = isLTR(this) ? -1 : 1; this._kbActivateTab(tabs[wrap(0, tabs.length - 1, this._closestActiveTabIndex + delta)]); } onArrowRight() { const tabs = this.enabledTabs; const delta = isLTR(this) ? 1 : -1; this._kbActivateTab(tabs[wrap(0, tabs.length - 1, this._closestActiveTabIndex + delta)]); } onHomeKey() { this._kbActivateTab(this.enabledTabs.at(0)); } onEndKey() { this._kbActivateTab(this.enabledTabs.at(-1)); } onActivationKey() { const tabs = this.enabledTabs; const index = this._closestActiveTabIndex; this.setSelectedTab(tabs[index]); this._kbActivateTab(tabs[index]); } handleScroll() { this.updateScrollButtons(); } select(name) { this.setSelectedTab(this.tabs.find((el) => el.panel === name)); } renderScrollButton(direction) { const start = direction === 'start'; return this.showScrollButtons ? html `<igc-icon-button tabindex="-1" aria-hidden="true" variant="flat" collection="default" part="${direction}-scroll-button" exportparts="icon" name="${start ? 'prev' : 'next'}" .disabled=${start ? this.disableStartScrollButton : this.disableEndScrollButton} @click=${() => this.scrollByTabOffset(direction)} ></igc-icon-button>` : nothing; } render() { return html ` <div part="headers"> ${this.renderScrollButton('start')} <div part="headers-content" @scroll=${this.handleScroll}> <div part="headers-wrapper"> <div ${ref(this.headerRef)} part="headers-scroll" role="tablist" @click=${this.handleClick} > <slot></slot> </div> <div part="selected-indicator"></div> </div> </div> ${this.renderScrollButton('end')} </div> <div part="content"> <slot name="panel"></slot> </div> `; } }; IgcTabsComponent.tagName = 'igc-tabs'; IgcTabsComponent.styles = [styles, shared]; IgcTabsComponent.increment = createCounter(); __decorate([ queryAssignedElements({ selector: IgcTabComponent.tagName }) ], IgcTabsComponent.prototype, "tabs", void 0); __decorate([ queryAssignedElements({ slot: 'panel' }) ], IgcTabsComponent.prototype, "panels", void 0); __decorate([ query('[part="headers-wrapper"]') ], IgcTabsComponent.prototype, "wrapper", void 0); __decorate([ query('[part="headers-content"]') ], IgcTabsComponent.prototype, "container", void 0); __decorate([ query('[part="selected-indicator"]') ], IgcTabsComponent.prototype, "selectedIndicator", void 0); __decorate([ state() ], IgcTabsComponent.prototype, "showScrollButtons", void 0); __decorate([ state() ], IgcTabsComponent.prototype, "disableStartScrollButton", void 0); __decorate([ state() ], IgcTabsComponent.prototype, "disableEndScrollButton", void 0); __decorate([ state() ], IgcTabsComponent.prototype, "activeTab", void 0); __decorate([ property({ reflect: true }) ], IgcTabsComponent.prototype, "alignment", void 0); __decorate([ property() ], IgcTabsComponent.prototype, "activation", void 0); __decorate([ watch('alignment', { waitUntilFirstUpdate: true }) ], IgcTabsComponent.prototype, "alignIndicator", null); __decorate([ eventOptions({ passive: true }) ], IgcTabsComponent.prototype, "handleScroll", null); IgcTabsComponent = IgcTabsComponent_1 = __decorate([ themes(all), blazorAdditionalDependencies('IgcTabComponent, IgcTabPanelComponent') ], IgcTabsComponent); export default IgcTabsComponent; //# sourceMappingURL=tabs.js.map