@stimulus-library/controllers
Version:
A library of useful controllers for Stimulus
78 lines (77 loc) • 2.84 kB
JavaScript
import { BaseController, clamp } from "@stimulus-library/utilities";
import { installClassMethods, useCollectionEventListener } from "@stimulus-library/mixins";
export class TabsController extends BaseController {
get defaultHideClasses() {
return ["hide"];
}
get defaultActiveClasses() {
return ["is-active"];
}
get _currentTab() {
return this.hasCurrentTabValue ? this.currentTabValue : 0;
}
get _equalize() {
return this.hasEqualizeValue ? this.equalizeValue : false;
}
connect() {
useCollectionEventListener(this, this.linkTargets, "click", this.switchTabs);
installClassMethods(this);
if (this._equalize) {
this._setMinHeight();
}
this.currentTabValue = this._currentTab;
}
switchTabs(event) {
event.preventDefault();
this.currentTabValue = this.linkTargets.indexOf(event.currentTarget);
}
currentTabValueChanged() {
let index = this._currentTab;
index = this._clampIndex(index);
requestAnimationFrame(() => this._selectTab(index));
}
_selectTab(index) {
index = this._clampIndex(index);
const links = this.linkTargets;
const panels = this.contentTargets;
const activePanel = panels[index];
const activeLink = links[index];
const otherPanels = [...panels.slice(0, index), ...panels.slice(index + 1)];
const otherLinks = [...links.slice(0, index), ...links.slice(index + 1)];
this.addActiveClasses(activeLink);
activeLink.setAttribute("aria-selected", "true");
this.addActiveClasses(activePanel);
this.removeHideClasses(activePanel);
otherLinks.forEach((link) => {
link.removeAttribute("aria-selected");
this.removeActiveClasses(link);
});
otherPanels.forEach((panel) => {
this.removeActiveClasses(panel);
this.addHideClasses(panel);
});
}
_clampIndex(index) {
return clamp(index, 0, this.contentTargets.length - 1);
}
_setMinHeight() {
let minHeight = 0;
this.contentTargets.forEach((content) => {
const hidden = content.hasAttribute("tab-hidden");
if (hidden) {
this.removeHideClasses(content);
}
const height = content.offsetHeight;
if (height > minHeight) {
minHeight = height;
}
if (hidden) {
this.addHideClasses(content);
}
});
this.contentTargets.forEach((content) => content.style.minHeight = minHeight + "px");
}
}
TabsController.values = { currentTab: Number, equalize: Boolean };
TabsController.targets = ["link", "content"];
TabsController.classes = ["active", "hide"];