/**
* **YaiTabs 1.0 - Advanced Tab Component System**
*
* **Key Features:**
* - **Performance**: Single event listener per container, scales infinitely
* - **Infinite Nesting**: Tested to 55+ levels without performance degradation
* - **Auto-Disambiguation**: Intelligent ID conflict resolution for nested components
* - **WCAG 2.1 AA Compliance**: Full accessibility with dynamic ARIA management
* - **Dynamic Content Loading**: Fetch-based content with comprehensive delay controls
* - **Hash Routing**: URL-based navigation with browser history integration
* - **Animation System**: 9 smooth CSS-based transition behaviors
* - **Remote Control**: Content buttons can control parent tab navigation
* - **Framework Agnostic**: Works with React, Vue, Angular, or Vanilla JS
*
* **Performance Metrics:**
* - Initialization: < 100ms for complex nested structures
* - Interaction Response: < 16ms (60fps guaranteed)
* - Memory Footprint: ~460 LOC, minimal runtime overhead
*
* @author YaiJS Team - Advanced component architecture
* @license MIT
* @see https://github.com/yaijs/yai/tree/main/tabs
*/
import { HookContext, LifecycleCallbacks, YaiCore, YaiCoreConfig } from '../yai-core.js';
/**
* **Animation Behaviors**
*
* Smooth CSS-based transitions optimized for performance and accessibility.
* All animations use transform + opacity for hardware acceleration.
*/
export type AnimationBehavior =
/** Smooth opacity transition (default) */
| 'fade'
/** Slide animation from bottom to top */
| 'slide-up'
/** Slide animation from top to bottom */
| 'slide-down'
/** Slide animation from right to left */
| 'slide-left'
/** Slide animation from left to right */
| 'slide-right'
/** Scale-based zoom transition */
| 'zoom'
/** 3D flip transition effect */
| 'flip'
/** Blur transition with opacity */
| 'blur'
/** No animation, instant switch */
| 'instant';
/**
* π§ **Navigation Positioning Options**
*
* Controls where the tab navigation appears relative to content.
* Automatically handles CSS flexbox layout and ARIA orientation.
*/
export type NavigationPosition =
/** Navigation at top (default, horizontal orientation) */
| 'top'
/** Navigation on left (vertical orientation) */
| 'left'
/** Navigation on right (vertical orientation) */
| 'right'
/** Navigation at bottom (horizontal orientation) */
| 'bottom';
/**
* π·οΈ **Tab Container HTML Attributes**
*
* Data attributes for the main tab container element.
*
* @example
* ```html
*
* ```
*/
export interface TabContainerAttributes {
/** Main identifier for tab components (required) */
'data-yai-tabs'?: string;
/** Animation behavior for tab transitions */
'data-behavior'?: AnimationBehavior;
/** Navigation positioning */
'data-nav'?: NavigationPosition;
/** Visual theme identifier */
'data-theme'?: string;
/** Browser history handling mode */
'data-history-mode'?: 'replace' | 'push';
/** URL hash parameter key for routing */
'data-ref-path'?: string;
}
/**
* ποΈ **Tab Button HTML Attributes**
*
* Data attributes for tab navigation buttons.
*
* @example
* ```html
*
* ```
*/
export interface TabButtonAttributes {
/** Button action type (required for buttons) */
'data-tab-action'?: 'open';
/** Target panel ID (matches data-tab value) */
'data-open'?: string;
/** Marks as default/initial active tab */
'data-default'?: boolean;
/** Dynamic content URL for fetch-based loading */
'data-url'?: string;
/** Append content instead of replacing (default: false) */
'data-append'?: string;
/** Pre-fetch delay in milliseconds */
'data-delay'?: string;
/** Post-fetch delay in milliseconds */
'data-post-delay'?: string;
/** Minimum loading time (prevents flicker) */
'data-min-loading'?: string;
/** Always reload content (bypass cache) */
'data-url-refresh'?: boolean;
/** Marker set after content is loaded (internal use) */
'data-url-loaded'?: boolean;
/** Text to restore after loading completes */
'data-restore-text'?: string;
}
/**
* π **Tab Content Panel HTML Attributes**
*
* Data attributes for tab content containers.
*
* @example
* ```html
*
* Tab content here...
*
* ```
*/
export interface TabContentAttributes {
/** Panel identifier (matches data-open value) */
'data-tab'?: string;
/** Remove default padding from content */
'data-spaceless'?: boolean;
}
/**
* βοΈ **YaiTabs Configuration Interface**
*
* Comprehensive configuration options extending YaiCore functionality
* with tab-specific features and intelligent defaults.
*/
export interface YaiTabsConfig extends YaiCoreConfig {
/** Default animation behavior when data-behavior is not specified */
behavior?: AnimationBehavior;
/** Default navigation position */
navigation?: NavigationPosition;
/** Default tab to open (by ID) */
defaultTab?: string;
/** Automatically focus first container's active tab on init */
autoFocus?: boolean;
/** Enable comprehensive ARIA accessibility setup */
autoAccessibility?: boolean;
/** Enable URL hash-based routing */
hashRouting?: boolean;
/** Enable remote control from content buttons */
remoteControl?: boolean;
/** Animation duration in milliseconds */
animationDuration?: number;
/** CSS class name for loading state */
loadingClass?: string;
/** CSS class name for active state */
activeClass?: string;
/** CSS class name for hidden state */
hiddenClass?: string;
/** Prefix for auto-generated disambiguation IDs */
disambiguationPrefix?: string;
/** Automatically resolve ID conflicts in nested components */
autoDisambiguate?: boolean;
/** Allow closing active tab by clicking it again */
closable?: boolean;
}
/**
* π£ **Tab-Specific Hook Context**
*
* Extended context object passed to tab lifecycle hooks with
* tab-specific metadata and references.
*/
export interface TabHookContext extends HookContext {
/** Current tab identifier */
tabId?: string;
/** Tab button element */
tabButton?: Element;
/** Tab content panel element */
tabContent?: Element;
/** Target container for the operation */
targetContainer?: Element;
/** Content URL being loaded */
url?: string;
/** Animation behavior being used */
animationBehavior?: AnimationBehavior;
}
/**
* π **Tab Lifecycle Callbacks**
*
* Tab-specific lifecycle hooks extending base functionality.
* Currently uses base callbacks - can be extended for tab-specific events.
*/
export interface TabLifecycleCallbacks extends LifecycleCallbacks {
// Base callbacks are sufficient for current implementation
// Future tab-specific callbacks can be added here:
// beforeTabChange?: (context: TabHookContext) => void | Promise
;
// afterTabChange?: (context: TabHookContext) => void | Promise;
}
/**
* ποΈ **YaiTabs Class - Advanced Tab Component**
*
* Advanced tab system built on YEH's architecture.
* Provides enterprise-grade functionality with infinite scalability.
*
* **π― Core Architecture:**
* - Single event listener per container using event delegation
* - Lazy component activation for optimal performance
* - Automatic ID disambiguation for conflict resolution
* - Hook-based extensibility for custom behavior
* - Dynamic content loading with comprehensive delay management
*
* **π Usage Examples:**
*
* @example
* **Basic Usage:**
* ```typescript
* // Initialize with default configuration
* const tabs = new YaiTabs();
*
* // Custom configuration
* const tabs = new YaiTabs({
* behavior: 'slide-up',
* autoFocus: true,
* autoDisambiguate: true
* });
* ```
*
* @example
* **Hook-Based Customization:**
* ```typescript
* const tabs = new YaiTabs()
* .hook('setLoading', ({ target, container }) => {
* target?.classList.add('loading');
* target?.setAttribute('aria-busy', 'true');
* })
* .hook('removeLoading', ({ target, container }) => {
* target?.classList.remove('loading');
* target?.setAttribute('aria-busy', 'false');
* })
* .hook('contentReady', ({ content, target }) => {
* content?.classList.add('fade-in');
* if (target?.dataset.restoreText) {
* target.textContent = target.dataset.restoreText;
* }
* });
* ```
*
* @example
* **HTML Structure:**
* ```html
*
*
*
*
*
*
*
*
*
*
Static content for tab 1
*
*
*
*
*
*
Static content for tab 3
*
*
*
*
*
*
Nested content 1
*
Nested content 2
*
*
*
*
*
* ```
*
* @example
* **Dynamic Content with Delays:**
* ```html
*
* ```
*
* @example
* **Hash Routing Setup:**
* ```html
*
*
*
*
*
*
Dashboard Content
*
Settings Content
*
*
*
* ```
*
* **π― Performance Features:**
* - **Lazy Component Activation**: Nested components activate only when needed
* - **DOM Caching**: Intelligent query caching reduces DOM traversal
* - **Event Delegation**: Single listener handles all tab interactions
* - **Memory Management**: Automatic cleanup prevents memory leaks
*
* **βΏ Accessibility Features:**
* - **WCAG 2.1 AA Compliant**: Full keyboard navigation and screen reader support
* - **Dynamic ARIA**: Automatic role, state, and property management
* - **Keyboard Navigation**: Arrow keys, Home/End, Enter/Space, Escape
* - **Focus Management**: Automatic focus restoration after dynamic content loading
* - **Unique IDs**: Container-scoped ID generation prevents conflicts
*/
export declare class YaiTabs extends YaiCore {
protected config: Required;
protected routeMap: Map;
/**
* ποΈ **Create YaiTabs Instance**
*
* Initialize a new tab component with optional configuration.
* Automatically sets up event delegation, lazy components, and accessibility.
*
* @param config - Optional configuration object
*/
constructor(config?: YaiTabsConfig);
/**
* π **Initialize Component System**
*
* Core initialization method that:
* - Discovers and processes all tab containers
* - Initializes default tabs and accessibility
* - Processes hash routing if enabled
*/
init(): void;
/**
* π **Initialize All Tab Containers**
*
* Discovers and initializes all tab containers in the specified root element.
* Handles both root-level and nested components with proper lazy activation.
*
* @param rootElement - Root element to search for tab containers (default: document)
*/
initializeAllContainers(rootElement?: Document): void;
/**
* π **Open Tab**
*
* Core method to open a tab with full animation and lifecycle support.
* Handles dynamic content loading, accessibility updates, and event broadcasting.
*
* @param target - Button element that triggered the action
* @param event - Original event object (null for programmatic calls)
* @param container - Tab container element
* @param isDefaultInitialization - Whether this is initial default tab opening
*
* @example
* ```typescript
* // Programmatic tab opening
* const button = document.querySelector('[data-open="tab2"]');
* const container = document.querySelector('[data-yai-tabs]');
* tabs.openTab(button, null, container);
* ```
*/
openTab(target: Element, event: Event | null, container: Element, isDefaultInitialization?: boolean): void;
/**
* π **Check if Closable**
*
* Determine if tabs in a container are closable by checking the data-closable attribute.
* Falls back to global config.closable if attribute is not set.
*
* @param container - Tab container element to check
* @returns True if tabs are closable, false otherwise
* @example
* ```typescript
* // Per-container override via data attribute
* ...
*
* // Check closability
* if (tabs.getIsClosable(container)) {
* // Show close buttons
* }
* ```
*/
getIsClosable(container: Element): boolean;
/**
* β **Close Tab**
*
* Close the currently active tab if closable option is enabled.
* Handles cleanup and state management for proper tab closure.
*
* @param target - Button element for the tab to close
* @param event - Original event object
* @param container - Tab container element
*/
closeTab(target: Element, event: Event | null, container: Element): void;
/**
* π **Toggle Loading State**
*
* Manage loading states for tab buttons and containers with visual feedback.
* Called automatically during content loading operations.
*
* @param container - Container element to update
* @param isLoading - Whether to show (true) or hide (false) loading state
* @param target - Button element that triggered loading
*/
toggleLoading(container: Element, isLoading?: boolean, target?: Element | null): void;
/**
* π±οΈ **Handle Click Events**
*
* Main click event handler using YEH's delegation system.
* Routes clicks to appropriate action handlers based on data attributes.
*
* @param event - Click event object
* @param target - Element that was clicked
* @param container - Container element for the interaction
*/
handleClick(event: Event, target: Element, container: Element): void;
/**
* β¨οΈ **Handle Keyboard Events**
*
* Comprehensive keyboard navigation handler supporting:
* - Arrow keys for tab navigation
* - Home/End for first/last tab
* - Enter/Space for activation
* - Escape for parent navigation
*
* @param event - Keyboard event object
* @param target - Element with focus
* @param container - Container element for navigation
*/
handleKeydown(event: KeyboardEvent, target: Element, container: Element): void;
/**
* π **Handle Hash Change Events**
*
* Process URL hash changes for browser-based navigation.
* Syncs tab state with URL parameters for bookmarkable tabs.
*/
handleHashchange(): void;
// === Internal Processing Methods ===
/**
* π·οΈ **Mark Root Containers**
*
* Mark root containers with data-root attribute and optionally apply lazy optimization.
* Always sets data-root on root containers, and conditionally makes nested components lazy
* based on config.lazyNestedComponents setting.
*/
protected _markRootContainers(): void;
/**
* β‘ **Activate Lazy Components**
*
* Restore data-yai-tabs attributes to lazy components after root registration.
* Enables proper component discovery while maintaining performance.
*/
protected _activateLazyComponents(): void;
/**
* π **Auto-Disambiguate IDs**
*
* Automatically resolve ID conflicts between nested components.
* Generates unique IDs while preserving original references for routing.
*
* @param scope - Document scope to process (default: document)
*/
protected _autoDisambiguateIds(scope?: Document): void;
/**
* π **Process Root Container**
*
* Full initialization for root-level containers including:
* - Event listener registration
* - Accessibility setup
* - Default tab activation
* - Nesting level calculation
*
* @param data - Container processing data object
*/
protected _processContainer(data: any): void;
/**
* πΏ **Process Nested Container**
*
* Lightweight initialization for nested containers that rely on
* parent event delegation for optimal performance.
*
* @param data - Container processing data object
*/
protected _processNestedContainer(data: any): void;
/**
* π§ **Update ARIA Orientation**
*
* Dynamically detect and set ARIA orientation based on actual CSS layout.
* Called during user interaction for guaranteed accuracy.
*
* @param container - Container to update orientation for
*/
protected _updateAriaOrientation(container: Element): void;
/**
* βΏ **Update ARIA States**
*
* Update ARIA attributes for all tab buttons and panels in a container.
* Maintains accessibility compliance during tab state changes.
*
* @param container - Container to update ARIA states for
*/
protected _updateAriaStates(container: Element): void;
/**
* π§Ή **Cleanup Stale Active States**
*
* Remove active states from elements that should no longer be active.
* Prevents state conflicts during rapid interactions.
*/
protected _cleanupStaleActiveStates(): void;
/**
* π **Cleanup Hidden Panels**
*
* Remove focusable elements from hidden tab panels to improve
* keyboard navigation and accessibility.
*/
protected _cleanupHiddenPanels(): void;
/**
* βΏ **Setup Complete Accessibility**
*
* Configure comprehensive ARIA attributes for WCAG 2.1 AA compliance.
* Sets up roles, states, properties, and keyboard navigation.
*
* @param data - Container data with accessibility metadata
*/
protected _setupCompleteAccessibility(data: any): void;
/**
* π« **Remove Active States**
*
* Remove active classes and ARIA states from specified elements.
* Supports custom selector arrays for flexible state management.
*
* @param target - Target element context
* @param container - Container to process
* @param selectors - CSS selectors for elements to deactivate
*/
protected _removeActive(target: Element, container: Element, selectors?: string[]): void;
/**
* π― **Initialize Nested Defaults**
*
* Discover and activate default tabs in newly loaded content.
* Handles nested component initialization after dynamic loading.
*
* @param content - Content container to process
*/
protected _initializeNestedDefaults(content: Element): void;
/**
* π **Post-Process Content**
*
* Final processing after content loading including:
* - Nested component discovery
* - Default tab activation
* - Event system integration
*
* @param container - Container that received new content
*/
protected _postProcessContent(container: Element): void;
/**
* π― **Activate Default Tabs**
*
* Find and activate default tabs in a container.
* Handles both data-default attributes and configuration-based defaults.
*
* @param container - Container to process for default tabs
*/
protected _activateDefaultTabs(container: Element): void;
/**
* πΎ **Preserve Navigation State**
*
* Store current navigation state for restoration after dynamic loading.
* Maintains user context during content updates.
*
* @param containerOrPanel - Container or panel to preserve state for
*/
protected _preserveNavigationState(containerOrPanel: Element): void;
/**
* β©οΈ **Restore Navigation State**
*
* Restore previously saved navigation state after content loading.
* Ensures user context is maintained across dynamic updates.
*
* @param content - Content that was dynamically loaded
*/
protected _restoreNavigationState(content: Element): void;
/**
* π§Ή **Cleanup Sibling Branch Parameters**
*
* Clean up hash routing parameters for sibling containers
* to prevent cross-contamination in complex nested structures.
*
* @param container - Container to clean up parameters for
*/
protected _cleanupSiblingBranchParameters(container: Element): void;
/**
* π **Cleanup Nested Hash Entries**
*
* Remove hash routing entries for nested components that are
* no longer active or relevant.
*
* @param parentContainer - Parent container to clean entries for
*/
protected _cleanupNestedHashEntries(parentContainer: Element): void;
/**
* π **Preserve Content Height**
*
* Maintain container height during transitions to prevent layout shift.
* Essential for smooth animations and user experience.
*
* @param container - Container to preserve height for
*/
protected _preserveContentHeight(container: Element): void;
/**
* π **Manage Focus for Hidden Elements**
*
* Remove tabindex from elements in hidden panels to improve
* keyboard navigation flow and accessibility.
*
* @param container - Container to manage focus for
*/
protected _manageFocusForHiddenElements(container: Element): void;
// === Utility Methods ===
/**
* ποΈ **Check Element Visibility**
*
* Determine if an element is visible in the current viewport.
* Used for optimization and accessibility decisions.
*
* @param element - Element to check visibility for
* @returns True if element is visible
*/
protected isElementVisible(element: Element): boolean;
/**
* π¦ **Check Container Visibility**
*
* Determine if a tab container is currently visible.
* Used for initialization and performance optimizations.
*
* @param container - Container to check visibility for
* @returns True if container is visible
*/
protected isContainerVisible(container: Element): boolean;
/**
* π·οΈ **Mark Root Container**
*
* Add or remove root container markers for component hierarchy tracking.
* Essential for proper event delegation and performance optimization.
*
* @param element - Element to mark/unmark
* @param add - Whether to add (true) or remove (false) marker
* @param marker - Custom marker attribute name
*/
protected _markRootContainer(element: Element, add?: boolean, marker?: string | null): void;
/**
* π£ **Hook Management (Extended)**
*
* Register lifecycle hooks with tab-specific context support.
* Extends base hook system with tab-aware functionality.
*
* @param hookName - Name of the lifecycle hook
* @param callback - Callback function to register
* @returns this for method chaining
*
* @example
* ```typescript
* tabs.hook('contentReady', ({ content, tabId, container }) => {
* console.log(`Tab ${tabId} content ready in container:`, container);
* content?.classList.add('loaded');
* });
* ```
*/
hook(hookName: keyof TabLifecycleCallbacks, callback: TabLifecycleCallbacks[keyof TabLifecycleCallbacks]): this;
// === Static Utility Methods ===
/**
* π **Reconstruct URL from Reference Path**
*
* Static utility to build URL hash from a target reference path.
* Reconstructs the complete navigation state including all parent levels.
*
* @param targetRef - Reference path of the target container (data-ref-path value)
* @param targetValue - Optional explicit value for the target level
* @param containerElement - Root element to search within (default: document)
* @returns Reconstructed hash URL string (e.g., "#main-tabs=2&nested-tabs=1")
*
* @example
* ```typescript
* // Reconstruct URL for a specific tab state
* const url = YaiTabs.reconstructUrlFromRef('nested-tabs', '3');
* // Returns: "#main-tabs=2&nested-tabs=3" (includes parent state)
*
* // Get current active state
* const currentUrl = YaiTabs.reconstructUrlFromRef('nested-tabs');
* // Returns URL reflecting currently active tabs
* ```
*/
static reconstructUrlFromRef(targetRef: string, targetValue?: string | Element, containerElement?: Element | Document): string;
/**
* πΊοΈ **Get Reference Path Data**
*
* Static utility to retrieve the full hierarchical path for a reference.
* Returns ancestor chain from root to target for proper URL reconstruction.
*
* @param targetRef - Reference path to look up
* @param scope - Root element to search within (default: document)
* @returns Object containing full path array and any errors
*
* @example
* ```typescript
* const pathData = YaiTabs.getRefPath('nested-tabs');
* // Returns: { fullPath: ['main-tabs', 'nested-tabs'], error: null }
*
* // Handle errors
* const result = YaiTabs.getRefPath('invalid-ref');
* if (result.error) {
* console.error('Reference not found:', result.error);
* }
* ```
*/
static getRefPath(targetRef: string, scope?: Element | Document): {
fullPath: string[];
error: string | null;
};
}
/**
* π€ **Module Exports**
*/
// Export main class as default
export default YaiTabs;
// Re-export base types for convenience
export { HookContext, LifecycleCallbacks, YaiCore, YaiCoreConfig } from './yai-core.js';
/**
* π― **Quick Start Guide**
*
* 1. **Basic Setup:**
* ```html
*
*
*
*
Content 1
*
Content 2
*
*
* ```
*
* 2. **JavaScript Initialization:**
* ```javascript
* import YaiTabs from './yai-tabs.js';
* const tabs = new YaiTabs();
* ```
*
* 3. **Custom Configuration:**
* ```javascript
* const tabs = new YaiTabs({
* behavior: 'slide-up',
* autoFocus: true,
* autoDisambiguate: true
* });
* ```
*
* **π§ Advanced Features:**
* - **Infinite Nesting**: Tab containers can be nested infinitely
* - **Dynamic Content**: Use data-url for fetch-based content loading
* - **Hash Routing**: Add data-ref-path for URL-based navigation
* - **Custom Hooks**: Use .hook() method for lifecycle customization
* - **Accessibility**: Full WCAG 2.1 AA compliance with keyboard navigation
*
* **β‘ Performance Tips:**
* - Use data-spaceless to remove default padding
* - Leverage data-delay and data-min-loading for smooth UX
* - Enable autoDisambiguate for conflict-free nested IDs
*/