@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
110 lines (109 loc) • 5.57 kB
JavaScript
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details.
v3.2.1 */
import { c as customElement } from "../../chunks/runtime.js";
import { ref } from "lit-html/directives/ref.js";
import { html } from "lit";
import { LitElement, safeClassMap } from "@arcgis/lumina";
import { s as slotChangeGetAssignedElements, e as getSlotAssignedElements } from "../../chunks/dom.js";
import { css } from "@lit/reactive-element/css-tag.js";
const CSS = {
section: "section"
};
const SLOTS = {
titleGroup: "title-group"
};
const styles = css`:host{display:flex;flex-direction:column}:host([bordered]){box-shadow:inset 0 1px 0 var(--calcite-tab-border-color, var(--calcite-color-border-1));background-color:var(--calcite-tab-background-color, var(--calcite-color-foreground-1))}:host([bordered]) section{border-color:var(--calcite-tab-border-color, var(--calcite-color-border-1));border-style:solid}section{display:flex;flex-grow:1;overflow:hidden;border-width:1px;border-block-start-style:solid;border-block-start-color:var(--calcite-tab-border-color, var(--calcite-color-border-1))}:host([bordered][position=bottom]){box-shadow:inset 0 1px 0 var(--calcite-tab-border-color, var(--calcite-color-border-1)),inset 0 -1px 0 var(--calcite-tab-border-color, var(--calcite-color-border-1))}:host([bordered]:not([position=bottom])) ::slotted(calcite-tab-nav){margin-block-end:-1px}:host([position=bottom]){flex-direction:column-reverse}:host([position=bottom]) section{flex-direction:column-reverse;border-block-start-width:0px;border-block-end-width:1px}:host([bordered][scale=s]) section{padding:.75rem}:host([bordered][scale=m]) section{padding:.5rem}:host([bordered][scale=l]) section{padding:1rem}:host([position=bottom]:not([bordered])) section{border-block-end-style:solid;border-block-end-color:var(--calcite-tab-border-color, var(--calcite-color-border-1))}@media (forced-colors: active){:host([bordered]) section{border-block-start-width:0px;border-block-end-width:1px}:host([position=bottom][bordered]) section{border-block-start-width:1px;border-block-end-width:0px}}:host([hidden]){display:none}[hidden]{display:none}`;
class Tabs extends LitElement {
constructor() {
super();
this.tabs = [];
this.titles = [];
this.bordered = false;
this.layout = "inline";
this.position = "top";
this.scale = "m";
this.listen("calciteInternalTabNavSlotChange", this.calciteInternalTabNavSlotChangeHandler);
}
static {
this.properties = { tabs: [16, {}, { state: true }], titles: [16, {}, { state: true }], bordered: [5, {}, { type: Boolean }], layout: [3, {}, { reflect: true }], position: [3, {}, { reflect: true }], scale: [3, {}, { reflect: true }] };
}
static {
this.styles = styles;
}
connectedCallback() {
super.connectedCallback();
this.updateItems();
}
load() {
this.updateItems();
}
willUpdate(changes) {
if (changes.has("position") && (this.hasUpdated || this.position !== "top") || changes.has("scale") && (this.hasUpdated || this.scale !== "m")) {
this.updateItems();
}
if ((changes.has("titles") || changes.has("tabs")) && this.hasUpdated && this.titles?.length > 0 && this.tabs?.length > 0) {
this.updateAriaSettings();
this.updateItems();
}
}
calciteInternalTabNavSlotChangeHandler(event) {
event.stopPropagation();
if (event.detail.length !== this.titles.length) {
this.titles = event.detail;
}
}
defaultSlotChangeHandler(event) {
this.tabs = slotChangeGetAssignedElements(event, "calcite-tab");
}
async updateAriaSettings() {
await this.componentOnReady();
let tabIds;
let titleIds;
const tabs = getSlotAssignedElements(this.slotEl, "calcite-tab");
if (tabs.some((el) => el.tab) || this.titles.some((el) => el.tab)) {
tabIds = tabs.sort((a, b) => a.tab.localeCompare(b.tab)).map((el) => el.id);
titleIds = this.titles.sort((a, b) => a.tab.localeCompare(b.tab)).map((el) => el.id);
} else {
const tabDomIndexes = await Promise.all(tabs.map((el) => el.getTabIndex()));
const titleDomIndexes = await Promise.all(this.titles.map((el) => el.getTabIndex()));
tabIds = tabDomIndexes.reduce((ids, indexInDOM, registryIndex) => {
ids[indexInDOM] = tabs[registryIndex].id;
return ids;
}, []);
titleIds = titleDomIndexes.reduce((ids, indexInDOM, registryIndex) => {
ids[indexInDOM] = this.titles[registryIndex].id;
return ids;
}, []);
}
tabs.forEach((el) => el._updateAriaInfo(tabIds, titleIds));
this.titles.forEach((el) => el._updateAriaInfo(tabIds, titleIds));
}
updateItems() {
const { position, scale } = this;
const nav = this.el.querySelector("calcite-tab-nav");
if (nav) {
nav.position = position;
nav.scale = scale;
}
Array.from(this.el.querySelectorAll("calcite-tab")).forEach((tab) => {
if (tab.parentElement === this.el) {
tab.scale = scale;
}
});
Array.from(this.el.querySelectorAll("calcite-tab-nav > calcite-tab-title")).forEach((title) => {
title.position = position;
title.scale = scale;
});
}
setDefaultSlotRef(el) {
this.slotEl = el;
}
render() {
return html`<slot name=${SLOTS.titleGroup}></slot><section class=${safeClassMap(CSS.section)}><slot @slotchange=${this.defaultSlotChangeHandler} ${ref(this.setDefaultSlotRef)}></slot></section>`;
}
}
customElement("calcite-tabs", Tabs);
export {
Tabs
};