// ============================================================================ // Stylescape | Aside Handler // ============================================================================ // Manages sidebar/aside menu visibility with localStorage persistence. // Supports data-ss-aside attributes for declarative configuration. // ============================================================================ import { StateManager } from "../state/StateManager.js"; import { LocalStorageManager } from "../storage/LocalStorageManager.js"; /** * Configuration options for AsideHandler */ export interface AsideHandlerOptions { /** CSS class for visible state */ visibleClass?: string; /** Initial visibility state */ initialState?: "show" | "hide"; /** Enable localStorage persistence */ persist?: boolean; /** Callback when menu opens */ onOpen?: (menu: HTMLElement) => void; /** Callback when menu closes */ onClose?: (menu: HTMLElement) => void; } /** * Aside/sidebar menu handler with persistence support. * Manages the toggle state of sidebar menus with localStorage. * * @example JavaScript * ```typescript * const aside = new AsideHandler("sideMenu", "menuToggle") * * // Programmatic control * aside.showMenu() * aside.hideMenu() * aside.toggleMenu() * ``` * * @example HTML with data-ss * ```html * * * ``` */ export class AsideHandler { /** CSS class applied when menu is visible */ private static readonly VISIBLE_CLASS = "active"; /** LocalStorage key suffix for visibility state */ private static readonly VISIBLE_SUFFIX = "_visibility"; /** State value for visible menu */ private static readonly VISIBLE_STATE = "show"; /** State value for hidden menu */ private static readonly HIDDEN_STATE = "hide"; /** LocalStorage manager instance */ localStorageManager: LocalStorageManager; /** State manager instance */ stateManager: StateManager; /** ID of the aside menu element */ menuId: string; /** ID of the toggle switch element */ switchId: string; /** Reference to the aside menu element */ asideMenu: HTMLElement | null = null; /** Reference to the toggle switch element */ asideSwitch: HTMLElement | null = null; /** Current visibility state */ asideMenuActive: string = AsideHandler.HIDDEN_STATE; /** * Creates a new AsideHandler instance. * * @param menuId - ID of the aside menu element * @param switchId - ID of the toggle button element */ constructor(menuId: string, switchId: string) { this.localStorageManager = LocalStorageManager.getInstance(); this.stateManager = new StateManager(); this.menuId = menuId; this.switchId = switchId; this.assertMenu(); this.setupToggleListener(); this.updateStateMenu(); } /** * Queries and caches DOM references for menu and switch elements. */ private assertMenu(): void { this.asideMenu = document.getElementById(this.menuId); this.asideSwitch = document.getElementById(this.switchId); } /** * Sets up click event listener on the toggle switch. */ private setupToggleListener(): void { if (this.asideSwitch) { this.asideSwitch.addEventListener("click", () => this.toggleMenu(), ); } } /** * Toggles the menu between visible and hidden states. */ public toggleMenu(): void { this.assertMenu(); if (this.asideMenu?.classList.contains(AsideHandler.VISIBLE_CLASS)) { this.hideMenu(); } else { this.showMenu(); } } /** * Shows the menu and persists the state to localStorage. */ public showMenu(): void { this.assertMenu(); this.localStorageManager.setValue( this.menuId + AsideHandler.VISIBLE_SUFFIX, AsideHandler.VISIBLE_STATE, ); this.updateStateMenu(); } /** * Hides the menu and persists the state to localStorage. */ public hideMenu(): void { this.assertMenu(); this.localStorageManager.setValue( this.menuId + AsideHandler.VISIBLE_SUFFIX, AsideHandler.HIDDEN_STATE, ); this.updateStateMenu(); } /** * Updates the visual state of the menu based on stored preference. * Applies or removes the visible class on both menu and switch. */ public updateStateMenu(): void { this.assertMenu(); if (!this.asideMenu) return; this.asideMenuActive = this.localStorageManager.getValue( this.menuId + AsideHandler.VISIBLE_SUFFIX, ) || this.asideMenuActive; const isVisible = this.asideMenuActive === AsideHandler.VISIBLE_STATE; this.asideMenu.classList.toggle(AsideHandler.VISIBLE_CLASS, isVisible); this.asideSwitch?.classList.toggle( AsideHandler.VISIBLE_CLASS, isVisible, ); } }