//ifxTabs.tsx import { h } from "@stencil/core"; export class IfxTabs { constructor() { this.tabs = []; this.orientation = "horizontal"; this.activeTabIndex = 0; this.internalOrientation = undefined; this.internalActiveTabIndex = 0; this.internalFocusedTabIndex = 0; this.tabRefs = []; this.tabHeaderRefs = []; this.disabledTabs = []; this.tabObjects = []; } setActiveAndFocusedTab(index) { this.internalActiveTabIndex = index; this.internalFocusedTabIndex = index; } activeTabIndexChanged(newValue, oldValue) { if (newValue !== oldValue) { this.setActiveAndFocusedTab(newValue); } } componentWillLoad() { this.internalOrientation = this.orientation.toLowerCase() === 'vertical' ? 'vertical' : 'horizontal'; if (this.internalActiveTabIndex !== this.activeTabIndex) { this.ifxTabChange.emit({ previousTab: this.internalActiveTabIndex, currentTab: this.activeTabIndex }); } ; // this.internalActiveTabIndex = this.activeTabIndex; this.internalFocusedTabIndex = this.internalActiveTabIndex; this.updateTabStyles(); this.onSlotChange(); } updateTabStyles() { this.tabHeaderRefs.forEach((tab, index) => { tab.classList.toggle('active', index === this.internalActiveTabIndex); tab.setAttribute('aria-selected', index === this.internalActiveTabIndex ? 'true' : 'false'); }); } // needed for smooth border transition reRenderBorder() { const borderElement = this.el.shadowRoot.querySelector('.active-border'); if (borderElement && this.tabHeaderRefs[this.internalActiveTabIndex]) { if (this.orientation === 'horizontal') { borderElement.style.left = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetLeft}px`; borderElement.style.width = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetWidth}px`; borderElement.style.top = ''; borderElement.style.height = ''; } else { borderElement.style.top = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetTop}px`; borderElement.style.height = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetHeight}px`; borderElement.style.left = ''; borderElement.style.width = ''; } } } // when a slot is removed / added onSlotChange() { const tabs = this.el.querySelectorAll('ifx-tab'); this.tabObjects = Array.from(tabs).map((tab) => { return { header: tab === null || tab === void 0 ? void 0 : tab.header, disabled: (tab === null || tab === void 0 ? void 0 : tab.disabled) === true }; }); this.tabRefs = Array.from(tabs); this.tabRefs.forEach((tab, index) => { tab.setAttribute('slot', `tab-${index}`); }); } setDefaultOrientation() { const validOrientations = ['horizontal', 'vertical']; const lowercaseOrientation = this.orientation.toLowerCase(); if (!validOrientations.includes(lowercaseOrientation)) { this.internalOrientation = 'horizontal'; } else this.internalOrientation = this.orientation; } componentDidLoad() { this.updateBorderAndFocus(); // Add keyboard event listeners for each tab header this.tabHeaderRefs.forEach((tab, index) => { tab.addEventListener('focus', this.onTabFocus(index)); }); } onTabFocus(index) { return () => { this.internalFocusedTabIndex = index; }; } disconnectedCallback() { // Remove keyboard event listeners when component is unmounted this.tabHeaderRefs.forEach((tab, index) => { tab.removeEventListener('focus', this.onTabFocus(index)); }); } componentDidUpdate() { this.updateBorderAndFocus(); } updateBorderAndFocus() { this.reRenderBorder(); this.updateTabFocusability(); } updateTabFocusability() { this.tabHeaderRefs.forEach((tab, index) => { tab.tabIndex = index === this.internalActiveTabIndex ? 0 : -1; }); } focusNextTab() { let nextIndex = this.internalFocusedTabIndex + 1; while (nextIndex < this.tabHeaderRefs.length && this.tabObjects[nextIndex].disabled) { nextIndex++; } if (nextIndex >= 0 && nextIndex < this.tabHeaderRefs.length) { this.internalFocusedTabIndex = nextIndex; this.tabHeaderRefs[nextIndex].focus(); } } focusPreviousTab() { let prevIndex = this.internalFocusedTabIndex - 1; while ((prevIndex >= 0) && (this.tabObjects[prevIndex].disabled)) { prevIndex--; } if ((prevIndex >= 0) && (prevIndex < this.tabHeaderRefs.length)) { this.internalFocusedTabIndex = prevIndex; this.tabHeaderRefs[prevIndex].focus(); } } getTabItemClass(index) { const isActive = index === this.internalActiveTabIndex && !this.tabObjects[index].disabled; const isDisabled = this.tabObjects[index].disabled; return `tab-item ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''}`; } handleClick(tab, index) { this.ifxTabChange.emit({ previousTab: this.internalActiveTabIndex, currentTab: index }); if (!tab.disabled) this.internalActiveTabIndex = index; } handleKeyDown(ev) { if (ev.key === 'Tab') { if (ev.shiftKey) { // Shift + Tab if (this.internalFocusedTabIndex === 0) { // Allow default behavior to move focus out of component return; } else { ev.preventDefault(); this.focusPreviousTab(); } } else { // Tab if (this.internalFocusedTabIndex === this.tabHeaderRefs.length - 1) { // Allow default behavior to move focus out of component return; } else { ev.preventDefault(); this.focusNextTab(); } } } else if (ev.key === 'Enter') { if (this.internalFocusedTabIndex !== -1 && !this.tabObjects[this.internalFocusedTabIndex].disabled) { const previouslyActiveTabIndex = this.internalActiveTabIndex; this.internalActiveTabIndex = this.internalFocusedTabIndex; this.ifxTabChange.emit({ previousTab: previouslyActiveTabIndex, currentTab: this.internalFocusedTabIndex }); } } } render() { var _a; return (h("div", { "aria-label": "navigation tabs", class: `tabs ${this.internalOrientation}` }, h("ul", { role: "tablist", class: "tabs-list" }, (_a = this.tabObjects) === null || _a === void 0 ? void 0 : _a.map((tab, index) => (h("li", { class: this.getTabItemClass(index), ref: (el) => (this.tabHeaderRefs[index] = el), tabindex: "0", onClick: () => this.handleClick(tab, index), "aria-selected": index === this.internalActiveTabIndex ? 'true' : 'false', "aria-disabled": tab.disabled ? 'true' : 'false', role: "tab" }, tab === null || tab === void 0 ? void 0 : tab.header))), h("div", { class: "active-border" })), h("div", { class: "tab-content" }, Array.from(this.tabObjects).map((_, index) => (h("div", { style: { display: index === this.internalActiveTabIndex ? 'block' : 'none' } }, h("slot", { name: `tab-${index}` }))))))); } static get is() { return "ifx-tabs"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["tabs.scss"] }; } static get styleUrls() { return { "$": ["tabs.css"] }; } static get properties() { return { "tabs": { "type": "unknown", "mutable": false, "complexType": { "original": "{ header: string, disabled?: boolean }[]", "resolved": "{ header: string; disabled?: boolean; }[]", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "defaultValue": "[]" }, "orientation": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "attribute": "orientation", "reflect": false, "defaultValue": "\"horizontal\"" }, "activeTabIndex": { "type": "number", "mutable": true, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "attribute": "active-tab-index", "reflect": false, "defaultValue": "0" } }; } static get states() { return { "internalOrientation": {}, "internalActiveTabIndex": {}, "internalFocusedTabIndex": {}, "tabRefs": {}, "tabHeaderRefs": {}, "disabledTabs": {}, "tabObjects": {} }; } static get events() { return [{ "method": "ifxTabChange", "name": "ifxTabChange", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }]; } static get elementRef() { return "el"; } static get watchers() { return [{ "propName": "activeTabIndex", "methodName": "activeTabIndexChanged" }]; } static get listeners() { return [{ "name": "slotchange", "method": "onSlotChange", "target": undefined, "capture": false, "passive": false }, { "name": "keydown", "method": "handleKeyDown", "target": undefined, "capture": false, "passive": false }]; } } //# sourceMappingURL=tabs.js.map