Back to .net8.0 api/v4/InfinityQS ApiExplorerSettings Wafer Counter Color Sorting
302 lines
9.6 KiB
JavaScript
302 lines
9.6 KiB
JavaScript
//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
|