Archived
Template
1
Fork 0
This repository has been archived on 2024-09-04. You can view files and clone it, but cannot push or open issues or pull requests.
Contour/public/@shoelace-style/shoelace/cdn/chunks/chunk.UY44KMIY.js
2024-01-30 10:59:28 -05:00

350 lines
12 KiB
JavaScript

import {
tab_group_styles_default
} from "./chunk.EG6EOQHP.js";
import {
scrollIntoView
} from "./chunk.RK73WSZS.js";
import {
SlIconButton
} from "./chunk.Y77CZW56.js";
import {
LocalizeController
} from "./chunk.NH3SRVOC.js";
import {
e
} from "./chunk.UZVKBFXH.js";
import {
watch
} from "./chunk.FA5RT4K4.js";
import {
ShoelaceElement,
e as e2,
n,
r
} from "./chunk.SEXBCYCU.js";
import {
x
} from "./chunk.CXZZ2LVK.js";
import {
__decorateClass,
__spreadValues
} from "./chunk.KIILAQWQ.js";
// src/components/tab-group/tab-group.component.ts
var SlTabGroup = class extends ShoelaceElement {
constructor() {
super(...arguments);
this.localize = new LocalizeController(this);
this.tabs = [];
this.panels = [];
this.hasScrollControls = false;
this.placement = "top";
this.activation = "auto";
this.noScrollControls = false;
}
connectedCallback() {
const whenAllDefined = Promise.all([
customElements.whenDefined("sl-tab"),
customElements.whenDefined("sl-tab-panel")
]);
super.connectedCallback();
this.resizeObserver = new ResizeObserver(() => {
this.repositionIndicator();
this.updateScrollControls();
});
this.mutationObserver = new MutationObserver((mutations) => {
if (mutations.some((m) => !["aria-labelledby", "aria-controls"].includes(m.attributeName))) {
setTimeout(() => this.setAriaLabels());
}
if (mutations.some((m) => m.attributeName === "disabled")) {
this.syncTabsAndPanels();
}
});
this.updateComplete.then(() => {
this.syncTabsAndPanels();
this.mutationObserver.observe(this, { attributes: true, childList: true, subtree: true });
this.resizeObserver.observe(this.nav);
whenAllDefined.then(() => {
const intersectionObserver = new IntersectionObserver((entries, observer) => {
var _a;
if (entries[0].intersectionRatio > 0) {
this.setAriaLabels();
this.setActiveTab((_a = this.getActiveTab()) != null ? _a : this.tabs[0], { emitEvents: false });
observer.unobserve(entries[0].target);
}
});
intersectionObserver.observe(this.tabGroup);
});
});
}
disconnectedCallback() {
super.disconnectedCallback();
this.mutationObserver.disconnect();
this.resizeObserver.unobserve(this.nav);
}
getAllTabs(options = { includeDisabled: true }) {
const slot = this.shadowRoot.querySelector('slot[name="nav"]');
return [...slot.assignedElements()].filter((el) => {
return options.includeDisabled ? el.tagName.toLowerCase() === "sl-tab" : el.tagName.toLowerCase() === "sl-tab" && !el.disabled;
});
}
getAllPanels() {
return [...this.body.assignedElements()].filter((el) => el.tagName.toLowerCase() === "sl-tab-panel");
}
getActiveTab() {
return this.tabs.find((el) => el.active);
}
handleClick(event) {
const target = event.target;
const tab = target.closest("sl-tab");
const tabGroup = tab == null ? void 0 : tab.closest("sl-tab-group");
if (tabGroup !== this) {
return;
}
if (tab !== null) {
this.setActiveTab(tab, { scrollBehavior: "smooth" });
}
}
handleKeyDown(event) {
const target = event.target;
const tab = target.closest("sl-tab");
const tabGroup = tab == null ? void 0 : tab.closest("sl-tab-group");
if (tabGroup !== this) {
return;
}
if (["Enter", " "].includes(event.key)) {
if (tab !== null) {
this.setActiveTab(tab, { scrollBehavior: "smooth" });
event.preventDefault();
}
}
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
const activeEl = this.tabs.find((t) => t.matches(":focus"));
const isRtl = this.localize.dir() === "rtl";
if ((activeEl == null ? void 0 : activeEl.tagName.toLowerCase()) === "sl-tab") {
let index = this.tabs.indexOf(activeEl);
if (event.key === "Home") {
index = 0;
} else if (event.key === "End") {
index = this.tabs.length - 1;
} else if (["top", "bottom"].includes(this.placement) && event.key === (isRtl ? "ArrowRight" : "ArrowLeft") || ["start", "end"].includes(this.placement) && event.key === "ArrowUp") {
index--;
} else if (["top", "bottom"].includes(this.placement) && event.key === (isRtl ? "ArrowLeft" : "ArrowRight") || ["start", "end"].includes(this.placement) && event.key === "ArrowDown") {
index++;
}
if (index < 0) {
index = this.tabs.length - 1;
}
if (index > this.tabs.length - 1) {
index = 0;
}
this.tabs[index].focus({ preventScroll: true });
if (this.activation === "auto") {
this.setActiveTab(this.tabs[index], { scrollBehavior: "smooth" });
}
if (["top", "bottom"].includes(this.placement)) {
scrollIntoView(this.tabs[index], this.nav, "horizontal");
}
event.preventDefault();
}
}
}
handleScrollToStart() {
this.nav.scroll({
left: this.localize.dir() === "rtl" ? this.nav.scrollLeft + this.nav.clientWidth : this.nav.scrollLeft - this.nav.clientWidth,
behavior: "smooth"
});
}
handleScrollToEnd() {
this.nav.scroll({
left: this.localize.dir() === "rtl" ? this.nav.scrollLeft - this.nav.clientWidth : this.nav.scrollLeft + this.nav.clientWidth,
behavior: "smooth"
});
}
setActiveTab(tab, options) {
options = __spreadValues({
emitEvents: true,
scrollBehavior: "auto"
}, options);
if (tab !== this.activeTab && !tab.disabled) {
const previousTab = this.activeTab;
this.activeTab = tab;
this.tabs.forEach((el) => el.active = el === this.activeTab);
this.panels.forEach((el) => {
var _a;
return el.active = el.name === ((_a = this.activeTab) == null ? void 0 : _a.panel);
});
this.syncIndicator();
if (["top", "bottom"].includes(this.placement)) {
scrollIntoView(this.activeTab, this.nav, "horizontal", options.scrollBehavior);
}
if (options.emitEvents) {
if (previousTab) {
this.emit("sl-tab-hide", { detail: { name: previousTab.panel } });
}
this.emit("sl-tab-show", { detail: { name: this.activeTab.panel } });
}
}
}
setAriaLabels() {
this.tabs.forEach((tab) => {
const panel = this.panels.find((el) => el.name === tab.panel);
if (panel) {
tab.setAttribute("aria-controls", panel.getAttribute("id"));
panel.setAttribute("aria-labelledby", tab.getAttribute("id"));
}
});
}
repositionIndicator() {
const currentTab = this.getActiveTab();
if (!currentTab) {
return;
}
const width = currentTab.clientWidth;
const height = currentTab.clientHeight;
const isRtl = this.localize.dir() === "rtl";
const allTabs = this.getAllTabs();
const precedingTabs = allTabs.slice(0, allTabs.indexOf(currentTab));
const offset = precedingTabs.reduce(
(previous, current) => ({
left: previous.left + current.clientWidth,
top: previous.top + current.clientHeight
}),
{ left: 0, top: 0 }
);
switch (this.placement) {
case "top":
case "bottom":
this.indicator.style.width = `${width}px`;
this.indicator.style.height = "auto";
this.indicator.style.translate = isRtl ? `${-1 * offset.left}px` : `${offset.left}px`;
break;
case "start":
case "end":
this.indicator.style.width = "auto";
this.indicator.style.height = `${height}px`;
this.indicator.style.translate = `0 ${offset.top}px`;
break;
}
}
// This stores tabs and panels so we can refer to a cache instead of calling querySelectorAll() multiple times.
syncTabsAndPanels() {
this.tabs = this.getAllTabs({ includeDisabled: false });
this.panels = this.getAllPanels();
this.syncIndicator();
this.updateComplete.then(() => this.updateScrollControls());
}
updateScrollControls() {
if (this.noScrollControls) {
this.hasScrollControls = false;
} else {
this.hasScrollControls = ["top", "bottom"].includes(this.placement) && this.nav.scrollWidth > this.nav.clientWidth;
}
}
syncIndicator() {
const tab = this.getActiveTab();
if (tab) {
this.indicator.style.display = "block";
this.repositionIndicator();
} else {
this.indicator.style.display = "none";
}
}
/** Shows the specified tab panel. */
show(panel) {
const tab = this.tabs.find((el) => el.panel === panel);
if (tab) {
this.setActiveTab(tab, { scrollBehavior: "smooth" });
}
}
render() {
const isRtl = this.localize.dir() === "rtl";
return x`
<div
part="base"
class=${e({
"tab-group": true,
"tab-group--top": this.placement === "top",
"tab-group--bottom": this.placement === "bottom",
"tab-group--start": this.placement === "start",
"tab-group--end": this.placement === "end",
"tab-group--rtl": this.localize.dir() === "rtl",
"tab-group--has-scroll-controls": this.hasScrollControls
})}
@click=${this.handleClick}
@keydown=${this.handleKeyDown}
>
<div class="tab-group__nav-container" part="nav">
${this.hasScrollControls ? x`
<sl-icon-button
part="scroll-button scroll-button--start"
exportparts="base:scroll-button__base"
class="tab-group__scroll-button tab-group__scroll-button--start"
name=${isRtl ? "chevron-right" : "chevron-left"}
library="system"
label=${this.localize.term("scrollToStart")}
@click=${this.handleScrollToStart}
></sl-icon-button>
` : ""}
<div class="tab-group__nav">
<div part="tabs" class="tab-group__tabs" role="tablist">
<div part="active-tab-indicator" class="tab-group__indicator"></div>
<slot name="nav" @slotchange=${this.syncTabsAndPanels}></slot>
</div>
</div>
${this.hasScrollControls ? x`
<sl-icon-button
part="scroll-button scroll-button--end"
exportparts="base:scroll-button__base"
class="tab-group__scroll-button tab-group__scroll-button--end"
name=${isRtl ? "chevron-left" : "chevron-right"}
library="system"
label=${this.localize.term("scrollToEnd")}
@click=${this.handleScrollToEnd}
></sl-icon-button>
` : ""}
</div>
<slot part="body" class="tab-group__body" @slotchange=${this.syncTabsAndPanels}></slot>
</div>
`;
}
};
SlTabGroup.styles = tab_group_styles_default;
SlTabGroup.dependencies = { "sl-icon-button": SlIconButton };
__decorateClass([
e2(".tab-group")
], SlTabGroup.prototype, "tabGroup", 2);
__decorateClass([
e2(".tab-group__body")
], SlTabGroup.prototype, "body", 2);
__decorateClass([
e2(".tab-group__nav")
], SlTabGroup.prototype, "nav", 2);
__decorateClass([
e2(".tab-group__indicator")
], SlTabGroup.prototype, "indicator", 2);
__decorateClass([
r()
], SlTabGroup.prototype, "hasScrollControls", 2);
__decorateClass([
n()
], SlTabGroup.prototype, "placement", 2);
__decorateClass([
n()
], SlTabGroup.prototype, "activation", 2);
__decorateClass([
n({ attribute: "no-scroll-controls", type: Boolean })
], SlTabGroup.prototype, "noScrollControls", 2);
__decorateClass([
watch("noScrollControls", { waitUntilFirstUpdate: true })
], SlTabGroup.prototype, "updateScrollControls", 1);
__decorateClass([
watch("placement", { waitUntilFirstUpdate: true })
], SlTabGroup.prototype, "syncIndicator", 1);
export {
SlTabGroup
};