UNPKG

@stimulus-library/controllers

Version:

A library of useful controllers for Stimulus

78 lines (77 loc) 2.84 kB
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"];