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.

276 lines 10.8 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; }; import { html, LitElement, nothing } from 'lit'; import { eventOptions, property, queryAssignedElements, state, } from 'lit/decorators.js'; import { cache } from 'lit/directives/cache.js'; import { createRef, ref } from 'lit/directives/ref.js'; import { styleMap } from 'lit/directives/style-map.js'; import { addThemingController } from '../../theming/theming-controller.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 { createResizeObserverController } from '../common/controllers/resize-observer.js'; import { watch } from '../common/decorators/watch.js'; import { registerComponent } from '../common/definitions/register.js'; import { EventEmitterMixin } from '../common/mixins/event-emitter.js'; import { partMap } from '../common/part-map.js'; import { findElementFromEventPath, first, getRoot, isEmpty, isLTR, isString, last, scrollIntoView, wrap, } from '../common/util.js'; import IgcTabComponent from './tab.js'; import { createTabHelpers, getTabHeader } from './tab-dom.js'; import { styles as shared } from './themes/shared/tabs/tabs.common.css.js'; import { styles } from './themes/tabs.base.css.js'; import { all } from './themes/tabs-themes.js'; class IgcTabsComponent extends EventEmitterMixin(LitElement) { static register() { registerComponent(IgcTabsComponent, IgcTabComponent, IgcIconButtonComponent); } get _enabledTabs() { return this._tabs.filter((tab) => !tab.disabled); } get tabs() { return this._tabs; } get selected() { if (this._activeTab) { return this._activeTab.label || this._activeTab.id; } return ''; } _alignmentChanged() { this._domHelpers.setIndicator(this._activeTab); } constructor() { super(); this._resizeController = createResizeObserverController(this, { callback: this._resizeCallback, options: { box: 'border-box' }, target: null, }); this._headerRef = createRef(); this._indicatorRef = createRef(); this._domHelpers = createTabHelpers(this, this._headerRef, this._indicatorRef); this.alignment = 'start'; this.activation = 'auto'; addThemingController(this, all); addKeybindings(this, { ref: this._headerRef, skip: this._skipKeyboard, bindingDefaults: { preventDefault: true }, }) .set(arrowLeft, () => this._handleArrowKeys(isLTR(this) ? -1 : 1)) .set(arrowRight, () => this._handleArrowKeys(isLTR(this) ? 1 : -1)) .set(homeKey, this._handleHomeKey) .set(endKey, this._handleEndKey) .setActivateHandler(this._handleActivationKeys, { preventDefault: false, }); createMutationController(this, { callback: this._mutationCallback, config: { attributeFilter: ['selected'], childList: true, subtree: true, }, filter: [IgcTabComponent.tagName], }); } async firstUpdated() { await this.updateComplete; const selectedTab = this._tabs.findLast((tab) => tab.selected) ?? first(this._enabledTabs); this._domHelpers.setStyleProperties(); this._domHelpers.setScrollButtonState(); this._setSelectedTab(selectedTab, false); this._resizeController.observe(this._headerRef.value); } connectedCallback() { super.connectedCallback(); this.role = 'tablist'; } updated() { if (this._domHelpers.isLeftToRightChanged) { this._domHelpers.setIndicator(this._activeTab); } } _resizeCallback() { this._domHelpers.setStyleProperties(); this._domHelpers.setScrollButtonState(); this._domHelpers.setIndicator(this._activeTab); } _mutationCallback(parameters) { this._selectedAttributeChanged(parameters); this._handleTabsRemoved(parameters); this._handleTabsAdded(parameters); this._domHelpers.setStyleProperties(); this._domHelpers.setScrollButtonState(); this._domHelpers.setIndicator(this._activeTab); } _selectedAttributeChanged({ changes, }) { const selected = changes.attributes.find(({ node: tab }) => this._tabs.includes(tab) && tab.selected)?.node; this._setSelectedTab(selected, false); } _handleTabsAdded({ changes, }) { if (!isEmpty(changes.added)) { const lastAdded = changes.added.findLast((change) => change.target.closest(this.tagName) === this && change.node.selected)?.node; this._setSelectedTab(lastAdded, false); } } _handleTabsRemoved({ changes, }) { if (!isEmpty(changes.removed)) { let nextSelectedTab = null; const removed = changes.removed.filter((change) => change.target.closest(this.tagName) === this); for (const each of removed) { if (each.node.selected && each.node === this._activeTab) { nextSelectedTab = first(this._enabledTabs); break; } } if (nextSelectedTab) { this._setSelectedTab(nextSelectedTab, false); } } } _getClosestActiveTabIndex() { const active = getRoot(this).activeElement; const tab = active ? active.closest(IgcTabComponent.tagName) : null; return tab ? this._enabledTabs.indexOf(tab) : -1; } _setSelectedTab(tab, shouldEmit = true) { if (!tab || tab === this._activeTab) { return; } if (this._activeTab) { this._activeTab.selected = false; } tab.selected = true; this._activeTab = tab; scrollIntoView(getTabHeader(tab)); this._domHelpers.setIndicator(this._activeTab); if (shouldEmit) { this.emitEvent('igcChange', { detail: this._activeTab }); } } _keyboardActivateTab(tab) { const header = getTabHeader(tab); this._domHelpers.setScrollSnap(); scrollIntoView(header); header.focus({ preventScroll: true }); if (this.activation === 'auto') { this._setSelectedTab(tab); } } _skipKeyboard(node, event) { return !(this._isEventFromTabHeader(event) && this._tabs.includes(node.closest(IgcTabComponent.tagName))); } _isEventFromTabHeader(event) { return findElementFromEventPath('[part~="tab-header"]', event); } _handleArrowKeys(delta) { const tabs = this._enabledTabs; this._keyboardActivateTab(tabs[wrap(0, tabs.length - 1, this._getClosestActiveTabIndex() + delta)]); } _handleHomeKey() { this._keyboardActivateTab(first(this._enabledTabs)); } _handleEndKey() { this._keyboardActivateTab(last(this._enabledTabs)); } _handleActivationKeys() { const tabs = this._enabledTabs; const index = this._getClosestActiveTabIndex(); if (index > -1) { this._setSelectedTab(tabs[index], false); this._keyboardActivateTab(tabs[index]); } } _handleClick(event) { if (!this._isEventFromTabHeader(event)) { return; } const tab = findElementFromEventPath(IgcTabComponent.tagName, event); if (!(tab && this._tabs.includes(tab)) || tab?.disabled) { return; } this._domHelpers.setScrollSnap(); getTabHeader(tab).focus(); this._setSelectedTab(tab); } _handleScroll() { this._domHelpers.setScrollButtonState(); } select(ref) { const tab = isString(ref) ? this._tabs.find((t) => t.id === ref) : ref; if (tab) { this._setSelectedTab(tab, false); } } _renderScrollButton(direction) { const isStart = direction === 'start'; const { start, end } = this._domHelpers.scrollButtonsDisabled; return html `${cache(this._domHelpers.hasScrollButtons ? html ` <igc-icon-button tabindex="-1" variant="flat" collection="default" part="${direction}-scroll-button" exportparts="icon" name=${isStart ? 'prev' : 'next'} ?disabled=${isStart ? start : end} @click=${() => this._domHelpers.scrollTabs(direction)} > </igc-icon-button> ` : nothing)}`; } render() { return html ` <div ${ref(this._headerRef)} part="tabs" style=${styleMap(this._domHelpers.styleProperties)} @scroll=${this._handleScroll} > <div part=${partMap({ inner: true, scrollable: this._domHelpers.hasScrollButtons, })} > ${this._renderScrollButton('start')} <slot @click=${this._handleClick}></slot> ${this._renderScrollButton('end')} <div part="selected-indicator"> <span ${ref(this._indicatorRef)}></span> </div> </div> </div> `; } } IgcTabsComponent.tagName = 'igc-tabs'; IgcTabsComponent.styles = [styles, shared]; export default IgcTabsComponent; __decorate([ queryAssignedElements({ selector: IgcTabComponent.tagName }) ], IgcTabsComponent.prototype, "_tabs", 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, "_alignmentChanged", null); __decorate([ eventOptions({ passive: true }) ], IgcTabsComponent.prototype, "_handleScroll", null); //# sourceMappingURL=tabs.js.map