@hortonstudio/main 1.9.22 → 1.9.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -64
- package/dist/assets/hs-animations-BDMqlbof.js +3 -0
- package/dist/assets/hs-animations-BDMqlbof.js. +3 -0
- package/dist/assets/hs-animations-BDMqlbof.js.gz +0 -0
- package/dist/assets/hs-animations-BDMqlbof.js.map +1 -0
- package/dist/assets/hs-attributeSelector-6pGcDBo-.js +2 -0
- package/dist/assets/hs-attributeSelector-6pGcDBo-.js.map +1 -0
- package/dist/assets/hs-comparison-Ja8EiSGD.js +2 -0
- package/dist/assets/hs-comparison-Ja8EiSGD.js. +2 -0
- package/dist/assets/hs-comparison-Ja8EiSGD.js.gz +0 -0
- package/dist/assets/hs-comparison-Ja8EiSGD.js.map +1 -0
- package/dist/assets/hs-counter-Bfh7_P60.js +2 -0
- package/dist/assets/hs-counter-Bfh7_P60.js. +2 -0
- package/dist/assets/hs-counter-Bfh7_P60.js.gz +0 -0
- package/dist/assets/hs-counter-Bfh7_P60.js.map +1 -0
- package/dist/assets/hs-cssVariables-BjuwJfDJ.js +2 -0
- package/dist/assets/hs-cssVariables-BjuwJfDJ.js.map +1 -0
- package/dist/assets/hs-default-CLmDRb9d.js +2 -0
- package/dist/assets/hs-default-CLmDRb9d.js. +2 -0
- package/dist/assets/hs-default-CLmDRb9d.js.gz +0 -0
- package/dist/assets/hs-default-CLmDRb9d.js.map +1 -0
- package/dist/assets/hs-form-COFGgawz.js +2 -0
- package/dist/assets/hs-form-COFGgawz.js. +2 -0
- package/dist/assets/hs-form-COFGgawz.js.gz +0 -0
- package/dist/assets/hs-form-COFGgawz.js.map +1 -0
- package/dist/assets/hs-marquee-CZ9pmCbT.js +2 -0
- package/dist/assets/hs-marquee-CZ9pmCbT.js. +2 -0
- package/dist/assets/hs-marquee-CZ9pmCbT.js.gz +0 -0
- package/dist/assets/hs-marquee-CZ9pmCbT.js.map +1 -0
- package/dist/assets/hs-modalManager-H_YegPAO.js +2 -0
- package/dist/assets/hs-modalManager-H_YegPAO.js. +2 -0
- package/dist/assets/hs-modalManager-H_YegPAO.js.gz +0 -0
- package/dist/assets/hs-modalManager-H_YegPAO.js.map +1 -0
- package/dist/assets/hs-normalize-CTwtG5-a.js +2 -0
- package/dist/assets/hs-normalize-CTwtG5-a.js. +2 -0
- package/dist/assets/hs-normalize-CTwtG5-a.js.gz +0 -0
- package/dist/assets/hs-normalize-CTwtG5-a.js.map +1 -0
- package/dist/assets/hs-orchestrator-J8b7XRk1.js +2 -0
- package/dist/assets/hs-orchestrator-J8b7XRk1.js. +2 -0
- package/dist/assets/hs-orchestrator-J8b7XRk1.js.gz +0 -0
- package/dist/assets/hs-orchestrator-J8b7XRk1.js.map +1 -0
- package/dist/assets/hs-pagination-DcOxmDPJ.js +2 -0
- package/dist/assets/hs-pagination-DcOxmDPJ.js. +2 -0
- package/dist/assets/hs-pagination-DcOxmDPJ.js.gz +0 -0
- package/dist/assets/hs-pagination-DcOxmDPJ.js.map +1 -0
- package/dist/assets/hs-structure-DhNix64P.js +3 -0
- package/dist/assets/hs-structure-DhNix64P.js. +3 -0
- package/dist/assets/hs-structure-DhNix64P.js.gz +0 -0
- package/dist/assets/hs-structure-DhNix64P.js.map +1 -0
- package/dist/assets/hs-tabs-CaxqHoGW.js +2 -0
- package/dist/assets/hs-tabs-CaxqHoGW.js. +2 -0
- package/dist/assets/hs-tabs-CaxqHoGW.js.gz +0 -0
- package/dist/assets/hs-tabs-CaxqHoGW.js.map +1 -0
- package/dist/assets/hs-toc-fxIQS7tz.js +2 -0
- package/dist/assets/hs-toc-fxIQS7tz.js. +2 -0
- package/dist/assets/hs-toc-fxIQS7tz.js.gz +0 -0
- package/dist/assets/hs-toc-fxIQS7tz.js.map +1 -0
- package/dist/assets/hs-transition-CDNuGJNq.js +2 -0
- package/dist/assets/hs-transition-CDNuGJNq.js. +2 -0
- package/dist/assets/hs-transition-CDNuGJNq.js.gz +0 -0
- package/dist/assets/hs-transition-CDNuGJNq.js.map +1 -0
- package/dist/assets/hs-utils-CKm6QhLw.js +2 -0
- package/dist/assets/hs-utils-CKm6QhLw.js.map +1 -0
- package/dist/main.js +2 -2
- package/dist/main.js. +2 -2
- package/dist/main.js.gz +0 -0
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
- package/dist/assets/animations-igIF6V0K.js +0 -3
- package/dist/assets/animations-igIF6V0K.js. +0 -3
- package/dist/assets/animations-igIF6V0K.js.gz +0 -0
- package/dist/assets/animations-igIF6V0K.js.map +0 -1
- package/dist/assets/counter-B9xmgh8V.js +0 -2
- package/dist/assets/counter-B9xmgh8V.js. +0 -2
- package/dist/assets/counter-B9xmgh8V.js.gz +0 -0
- package/dist/assets/counter-B9xmgh8V.js.map +0 -1
- package/dist/assets/cssVariables-n9wQSSYb.js +0 -2
- package/dist/assets/cssVariables-n9wQSSYb.js.map +0 -1
- package/dist/assets/default-CZ6vle49.js +0 -2
- package/dist/assets/default-CZ6vle49.js. +0 -2
- package/dist/assets/default-CZ6vle49.js.gz +0 -0
- package/dist/assets/default-CZ6vle49.js.map +0 -1
- package/dist/assets/modalManager-LtDi9OJz.js +0 -2
- package/dist/assets/modalManager-LtDi9OJz.js. +0 -2
- package/dist/assets/modalManager-LtDi9OJz.js.gz +0 -0
- package/dist/assets/modalManager-LtDi9OJz.js.map +0 -1
- package/dist/assets/normalize-DWI4olFS.js +0 -2
- package/dist/assets/normalize-DWI4olFS.js. +0 -2
- package/dist/assets/normalize-DWI4olFS.js.gz +0 -0
- package/dist/assets/normalize-DWI4olFS.js.map +0 -1
- package/dist/assets/structure--7b3v7AH.js +0 -2
- package/dist/assets/structure--7b3v7AH.js. +0 -2
- package/dist/assets/structure--7b3v7AH.js.gz +0 -0
- package/dist/assets/structure--7b3v7AH.js.map +0 -1
- package/dist/assets/utils-DA-PANmk.js +0 -2
- package/dist/assets/utils-DA-PANmk.js.map +0 -1
- package/dist/bootstrap.js +0 -2
- package/dist/bootstrap.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hs-modalManager-H_YegPAO.js","sources":["../../src/utils/gsap.ts","../../src/utils/heightAnimator.ts","../../src/utils/modalManager.ts"],"sourcesContent":["/**\n * GSAP Handler\n *\n * Centralized GSAP detection, error handling, and utilities.\n * Provides type-safe access to GSAP, ScrollTrigger, and Draggable.\n *\n * Features:\n * - Global scroll velocity tracking\n * - ScrollTrigger refresh on image load\n * - Prefers-reduced-motion detection\n */\n\n// Type definitions for externally loaded GSAP\nexport interface GsapTween {\n kill: () => void;\n then: () => Promise<void>;\n}\n\nexport interface GsapTimeline {\n to: (target: unknown, vars: Record<string, unknown>, position?: number | string) => GsapTimeline;\n from: (\n target: unknown,\n vars: Record<string, unknown>,\n position?: number | string\n ) => GsapTimeline;\n set: (target: unknown, vars: Record<string, unknown>, position?: number | string) => GsapTimeline;\n call: (callback: () => void, params?: unknown[], position?: number | string) => GsapTimeline;\n play: () => GsapTimeline;\n pause: () => GsapTimeline;\n kill: () => void;\n timeScale: (value: number) => GsapTimeline;\n}\n\ninterface GsapPlugin {\n create: (config: unknown) => void;\n getAll: () => unknown[];\n refresh: () => void;\n}\n\ninterface GsapDraggable {\n create: (target: unknown, vars?: Record<string, unknown>) => unknown[];\n}\n\ninterface GsapInstance {\n to: (target: unknown, vars: Record<string, unknown>) => GsapTween;\n from: (target: unknown, vars: Record<string, unknown>) => GsapTween;\n set: (target: unknown, vars: Record<string, unknown>) => void;\n timeline: (vars?: Record<string, unknown>) => GsapTimeline;\n registerPlugin: (...plugins: unknown[]) => void;\n ticker: {\n add: (callback: () => void) => void;\n remove: (callback: () => void) => void;\n };\n}\n\n// Declare global types for GSAP (loaded externally)\ndeclare global {\n interface Window {\n gsap?: GsapInstance;\n ScrollTrigger?: GsapPlugin;\n Draggable?: GsapDraggable;\n }\n}\n\nlet hasWarned = false;\nlet globalScrollVelocity = 0;\nlet globalScrollDirection = 0; // 1 = down, -1 = up, 0 = not scrolling\nlet scrollVelocityInitialized = false;\nlet scrollTriggerRefreshInitialized = false;\n\n/**\n * Initialize global scroll velocity tracking\n */\nexport function initScrollVelocityTracking(): void {\n if (scrollVelocityInitialized || !hasScrollTrigger()) {\n return;\n }\n\n const gsap = window.gsap!;\n\n // Track scroll position and smooth velocity\n let lastScrollY = window.scrollY;\n let lastTime = performance.now();\n let targetVelocity = 0;\n let currentVelocity = 0;\n\n // Update target velocity and direction on scroll\n window.ScrollTrigger!.create({\n onUpdate: () => {\n const currentScrollY = window.scrollY;\n const currentTime = performance.now();\n const deltaY = currentScrollY - lastScrollY;\n const deltaTime = currentTime - lastTime;\n\n // Update scroll direction\n if (deltaY > 0) {\n globalScrollDirection = 1; // Scrolling down\n } else if (deltaY < 0) {\n globalScrollDirection = -1; // Scrolling up\n }\n\n // Calculate velocity in pixels per second (framerate-independent)\n // Avoid division by zero\n if (deltaTime > 0) {\n targetVelocity = (Math.abs(deltaY) / deltaTime) * 1000; // Convert to pixels/second\n }\n\n lastScrollY = currentScrollY;\n lastTime = currentTime;\n },\n });\n\n // Smoothly lerp current velocity to target velocity every frame\n gsap.ticker.add(() => {\n // Lerp factor: lower = smoother (0.08 for buttery smooth)\n const lerpFactor = 0.08;\n\n // Interpolate current velocity towards target\n currentVelocity += (targetVelocity - currentVelocity) * lerpFactor;\n\n // Decay target velocity (simulates friction) - slower decay for smoothness\n targetVelocity *= 0.95;\n\n // Snap to zero when very small\n if (Math.abs(currentVelocity) < 0.1) {\n currentVelocity = 0;\n }\n if (Math.abs(targetVelocity) < 0.1) {\n targetVelocity = 0;\n }\n\n // Update global velocity\n globalScrollVelocity = currentVelocity;\n });\n\n scrollVelocityInitialized = true;\n}\n\n/**\n * Get current scroll velocity\n * @returns Current scroll velocity (pixels per second)\n */\nexport function getScrollVelocity(): number {\n return globalScrollVelocity;\n}\n\n/**\n * Get current scroll direction\n * @returns 1 for down, -1 for up, 0 for not scrolling\n */\nexport function getScrollDirection(): number {\n return globalScrollDirection;\n}\n\n/**\n * Check if GSAP is available\n */\nexport function hasGsap(): boolean {\n return typeof window.gsap !== 'undefined';\n}\n\n/**\n * Check if ScrollTrigger is available\n */\nexport function hasScrollTrigger(): boolean {\n return typeof window.ScrollTrigger !== 'undefined';\n}\n\n/**\n * Check if Draggable is available\n */\nexport function hasDraggable(): boolean {\n return typeof window.Draggable !== 'undefined';\n}\n\n/**\n * Get GSAP instance with type safety\n */\nexport function getGsap(\n moduleName?: string,\n required: boolean = true\n): { gsap: GsapInstance; ScrollTrigger?: GsapPlugin; Draggable?: GsapDraggable } | null {\n if (!hasGsap()) {\n if (required && !hasWarned) {\n console.warn(\n '[gsap] GSAP library not detected. Some animations will be skipped. ' +\n 'Add GSAP to your project: https://greensock.com/docs/v3/Installation'\n );\n hasWarned = true;\n } else if (moduleName && !hasWarned) {\n console.warn(`[${moduleName}] GSAP not available, module will use fallback behavior`);\n hasWarned = true;\n }\n return null;\n }\n\n return {\n gsap: window.gsap!,\n ScrollTrigger: window.ScrollTrigger,\n Draggable: window.Draggable,\n };\n}\n\n/**\n * Warn about missing GSAP dependencies\n * Call this from modules to alert developers about missing plugins\n *\n * @param moduleName - Name of the module requiring the dependency\n * @param dependencies - Array of dependency names (e.g., ['ScrollTrigger', 'Draggable'])\n * @param severity - 'error' for required dependencies, 'warn' for optional\n *\n * @example\n * // Required dependency (module won't work without it)\n * warnMissingDependencies('marquee', ['ScrollTrigger'], 'error');\n *\n * @example\n * // Optional dependency (module has fallback)\n * warnMissingDependencies('counter', ['ScrollTrigger'], 'warn');\n */\nexport function warnMissingDependencies(\n moduleName: string,\n dependencies: Array<'ScrollTrigger' | 'Draggable'>,\n severity: 'error' | 'warn' = 'warn'\n): void {\n const missing: string[] = [];\n\n dependencies.forEach((dep) => {\n if (dep === 'ScrollTrigger' && !hasScrollTrigger()) {\n missing.push('ScrollTrigger');\n } else if (dep === 'Draggable' && !hasDraggable()) {\n missing.push('Draggable');\n }\n });\n\n if (missing.length === 0) return;\n\n const pluginList = missing.join(', ');\n const message =\n severity === 'error'\n ? `[${moduleName}] Missing required GSAP plugin(s): ${pluginList}. Module will not work correctly. Add to your project: https://greensock.com/docs/v3/Installation`\n : `[${moduleName}] Missing optional GSAP plugin(s): ${pluginList}. Some features will be disabled. Add for full functionality: https://greensock.com/docs/v3/Installation`;\n\n if (severity === 'error') {\n console.error(message);\n } else {\n console.warn(message);\n }\n}\n\n/**\n * Reset warning state (useful for testing)\n */\nexport function resetGsapWarning(): void {\n hasWarned = false;\n}\n\n/**\n * Initialize ScrollTrigger refresh on image load\n */\nexport function initScrollTriggerRefresh(): void {\n if (scrollTriggerRefreshInitialized || !hasScrollTrigger()) {\n return;\n }\n\n let refreshTimeout: ReturnType<typeof setTimeout> | null = null;\n const refreshDelay = 50; // Debounce delay in ms\n\n // Debounced refresh function\n const debouncedRefresh = () => {\n if (refreshTimeout !== null) {\n clearTimeout(refreshTimeout);\n }\n refreshTimeout = setTimeout(() => {\n window.ScrollTrigger!.refresh();\n refreshTimeout = null;\n }, refreshDelay);\n };\n\n // Listen for all image load events using event delegation\n document.addEventListener(\n 'load',\n (e) => {\n if (e.target instanceof HTMLImageElement) {\n debouncedRefresh();\n }\n },\n true\n ); // Use capture phase to catch all image loads\n\n scrollTriggerRefreshInitialized = true;\n}\n\n/**\n * Check if user prefers reduced motion\n * @returns true if user prefers reduced motion\n */\nexport function prefersReducedMotion(): boolean {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n","/**\n * Height Animator\n *\n * GSAP-based height animations with singleton pattern.\n * Supports customizable duration, easing, and respects prefers-reduced-motion.\n */\nimport config from '@config';\nimport { getGsap, prefersReducedMotion, type GsapTween } from './gsap.ts';\n\ninterface AnimateOptions {\n duration?: number;\n ease?: string;\n}\n\nclass HeightAnimator {\n #activeAnimations = new Map<HTMLElement, GsapTween>();\n\n /**\n * Animate element height to open or closed state\n */\n async animate(\n element: HTMLElement,\n isOpen: boolean,\n options: AnimateOptions = {}\n ): Promise<void> {\n const gsapLib = getGsap('heightAnimator');\n if (!gsapLib) return;\n\n const { gsap } = gsapLib;\n\n const heightAttr = config._global.attributes.height;\n const heightValue = config._global.attributes.heightValue;\n const durationAttr = config._global.attributes.heightDuration;\n const easeAttr = config._global.attributes.heightEase;\n\n // Check for custom height target element\n const heightTarget =\n element.hasAttribute?.(heightAttr) && element.getAttribute(heightAttr) === heightValue\n ? element\n : (element.querySelector?.(`[${heightAttr}=\"${heightValue}\"]`) as HTMLElement) || element;\n\n // Cancel existing animation on this element\n const existingAnim = this.#activeAnimations.get(heightTarget);\n if (existingAnim) {\n existingAnim.kill();\n this.#activeAnimations.delete(heightTarget);\n }\n\n // Get attributes - check both the target AND its parent wrapper\n let durationValue = heightTarget.getAttribute(durationAttr);\n let easeValue = heightTarget.getAttribute(easeAttr);\n\n // If not found on target, check parent wrapper\n if (!durationValue && heightTarget.parentElement) {\n durationValue = heightTarget.parentElement.getAttribute(durationAttr);\n }\n if (!easeValue && heightTarget.parentElement) {\n easeValue = heightTarget.parentElement.getAttribute(easeAttr);\n }\n\n // Fallback chain: attribute > options > default\n let duration = durationValue\n ? parseInt(durationValue, 10) / 1000\n : (options.duration || 300) / 1000;\n\n // Force instant updates if user prefers reduced motion\n if (prefersReducedMotion()) {\n duration = 0;\n }\n\n const ease = easeValue || options.ease || 'power2.inOut';\n\n // Create animation\n const animation = gsap.to(heightTarget, {\n height: isOpen ? 'auto' : 0,\n duration: duration,\n ease: ease,\n });\n\n // Track active animation\n this.#activeAnimations.set(heightTarget, animation);\n\n // Wait for animation to complete\n try {\n await animation.then();\n } finally {\n this.#activeAnimations.delete(heightTarget);\n }\n }\n\n /**\n * Set element height immediately without animation (for initial state)\n */\n setHeight(element: HTMLElement, isOpen: boolean): void {\n const gsapLib = getGsap('heightAnimator');\n if (!gsapLib) return;\n\n const { gsap } = gsapLib;\n\n const heightAttr = config._global.attributes.height;\n const heightValue = config._global.attributes.heightValue;\n\n // Check for custom height target element\n const heightTarget =\n element.hasAttribute?.(heightAttr) && element.getAttribute(heightAttr) === heightValue\n ? element\n : (element.querySelector?.(`[${heightAttr}=\"${heightValue}\"]`) as HTMLElement) || element;\n\n // Set immediately without animation\n gsap.set(heightTarget, {\n height: isOpen ? 'auto' : 0,\n });\n }\n\n /**\n * Cancel all active animations (for cleanup)\n */\n cancelAll(): void {\n this.#activeAnimations.forEach((anim) => anim.kill());\n this.#activeAnimations.clear();\n }\n}\n\n// Export singleton instance\nexport const heightAnimator = new HeightAnimator();\n\n// Export bound methods for convenience\nexport const animateHeight = heightAnimator.animate.bind(heightAnimator);\nexport const setHeight = heightAnimator.setHeight.bind(heightAnimator);\n","/**\n * Modal Manager\n *\n * Reference-counted modal state management with body class handling.\n * Automatically detects and handles Lenis smooth scroll (stop on open, start on close).\n * Supports extensible hooks for custom callbacks.\n *\n * Usage:\n * import { openModal, closeModal } from '@utils/modalManager';\n * openModal(); // Register modal as open, auto-stops Lenis if detected\n * closeModal(); // Register modal as closed, auto-starts Lenis if detected\n *\n * Lenis Integration:\n * - Auto-detects window.lenis and stops/starts automatically\n * - Works whether Lenis loads before or after this module\n * - Disable auto-handling: window.HS.modal.setLenisEnabled(false);\n * - Manual control still available: window.HS.modal.onOpen(() => customLogic());\n *\n * External API:\n * window.HS.modal.open();\n * window.HS.modal.close();\n * window.HS.modal.setLenisEnabled(false); // Disable auto Lenis handling\n * window.HS.modal.onOpen(() => customCallback()); // Additional callbacks\n */\nimport config from '@config';\n\ntype ModalCallback = () => void;\n\nlet activeModalCount = 0;\nconst openCallbacks: ModalCallback[] = [];\nconst closeCallbacks: ModalCallback[] = [];\n\n// Lenis integration settings\nlet lenisEnabled = true; // Auto-detect and handle Lenis by default\nlet lenisInstance: unknown = null; // Cache Lenis instance\n\n/**\n * Detect and get Lenis instance from window\n */\nfunction getLenis(): { stop: () => void; start: () => void } | null {\n if (!lenisEnabled) return null;\n\n // Check cached instance first\n if (lenisInstance) return lenisInstance as { stop: () => void; start: () => void };\n\n // Try to find Lenis on window\n const win = window as Window & { lenis?: { stop: () => void; start: () => void } };\n if (win.lenis && typeof win.lenis.stop === 'function' && typeof win.lenis.start === 'function') {\n lenisInstance = win.lenis;\n return win.lenis;\n }\n\n return null;\n}\n\n/**\n * Enable or disable automatic Lenis integration\n */\nexport function setLenisEnabled(enabled: boolean): void {\n lenisEnabled = enabled;\n if (!enabled) {\n lenisInstance = null; // Clear cache when disabled\n }\n}\n\n/**\n * Register a callback to run when first modal opens\n */\nexport function onModalOpen(callback: ModalCallback): () => void {\n if (typeof callback !== 'function') {\n console.warn('[modalManager] onModalOpen requires a function');\n return () => {};\n }\n\n openCallbacks.push(callback);\n\n // Return unregister function\n return () => {\n const index = openCallbacks.indexOf(callback);\n if (index > -1) openCallbacks.splice(index, 1);\n };\n}\n\n/**\n * Register a callback to run when last modal closes\n */\nexport function onModalClose(callback: ModalCallback): () => void {\n if (typeof callback !== 'function') {\n console.warn('[modalManager] onModalClose requires a function');\n return () => {};\n }\n\n closeCallbacks.push(callback);\n\n // Return unregister function\n return () => {\n const index = closeCallbacks.indexOf(callback);\n if (index > -1) closeCallbacks.splice(index, 1);\n };\n}\n\n/**\n * Register a modal as open\n */\nexport function openModal(): void {\n activeModalCount++;\n\n // Only apply effects when first modal opens\n if (activeModalCount === 1) {\n const modalOpenClass = config._global.classes.modalOpen;\n const overflowHiddenClass = config._global.classes.overflowHidden;\n\n document.body.classList.add(overflowHiddenClass, modalOpenClass);\n\n // Auto-stop Lenis if detected\n const lenis = getLenis();\n if (lenis) {\n try {\n lenis.stop();\n } catch (error) {\n console.error('[modalManager] Error stopping Lenis:', error);\n }\n }\n\n // Run all registered open callbacks\n openCallbacks.forEach((callback) => {\n try {\n callback();\n } catch (error) {\n console.error('[modalManager] Error in open callback:', error);\n }\n });\n }\n}\n\n/**\n * Register a modal as closed\n */\nexport function closeModal(): void {\n activeModalCount--;\n\n // Only remove effects when last modal closes\n if (activeModalCount === 0) {\n const modalOpenClass = config._global.classes.modalOpen;\n const overflowHiddenClass = config._global.classes.overflowHidden;\n\n document.body.classList.remove(overflowHiddenClass, modalOpenClass);\n\n // Auto-start Lenis if detected\n const lenis = getLenis();\n if (lenis) {\n try {\n lenis.start();\n } catch (error) {\n console.error('[modalManager] Error starting Lenis:', error);\n }\n }\n\n // Run all registered close callbacks\n closeCallbacks.forEach((callback) => {\n try {\n callback();\n } catch (error) {\n console.error('[modalManager] Error in close callback:', error);\n }\n });\n }\n\n // Safety: prevent negative count\n if (activeModalCount < 0) {\n console.warn('[modalManager] Modal count went negative, resetting to 0');\n activeModalCount = 0;\n }\n}\n\n/**\n * Get current modal count (for debugging)\n */\nexport function getActiveModalCount(): number {\n return activeModalCount;\n}\n\n/**\n * Check if any modals are currently open\n */\nexport function isModalOpen(): boolean {\n return activeModalCount > 0;\n}\n\n// Expose globally for external scripts\ninterface WindowWithHS extends Window {\n HS?: {\n modal?: {\n open: () => void;\n close: () => void;\n getCount: () => number;\n isOpen: () => boolean;\n onOpen: (callback: ModalCallback) => () => void;\n onClose: (callback: ModalCallback) => () => void;\n setLenisEnabled: (enabled: boolean) => void;\n };\n };\n}\n\nif (typeof window !== 'undefined') {\n const win = window as WindowWithHS;\n win.HS = win.HS || {};\n win.HS.modal = {\n open: openModal,\n close: closeModal,\n getCount: getActiveModalCount,\n isOpen: isModalOpen,\n onOpen: onModalOpen,\n onClose: onModalClose,\n setLenisEnabled: setLenisEnabled,\n };\n}\n"],"names":["hasWarned","globalScrollVelocity","globalScrollDirection","scrollVelocityInitialized","scrollTriggerRefreshInitialized","initScrollVelocityTracking","hasScrollTrigger","gsap","window","lastScrollY","scrollY","lastTime","performance","now","targetVelocity","currentVelocity","ScrollTrigger","create","onUpdate","currentScrollY","currentTime","deltaY","deltaTime","Math","abs","ticker","add","getScrollVelocity","getScrollDirection","getGsap","moduleName","required","console","warn","Draggable","warnMissingDependencies","dependencies","severity","missing","forEach","dep","push","length","pluginList","join","message","error","initScrollTriggerRefresh","refreshTimeout","document","addEventListener","e","target","HTMLImageElement","clearTimeout","setTimeout","refresh","prefersReducedMotion","matchMedia","matches","heightAnimator","activeAnimations","Map","animate","element","isOpen","options","gsapLib","heightAttr","config","_global","attributes","height","heightValue","durationAttr","heightDuration","easeAttr","heightEase","heightTarget","hasAttribute","getAttribute","querySelector","existingAnim","this","get","kill","delete","durationValue","easeValue","parentElement","duration","parseInt","ease","animation","to","set","then","setHeight","cancelAll","anim","clear","animateHeight","bind","activeModalCount","openCallbacks","closeCallbacks","lenisEnabled","lenisInstance","getLenis","win","lenis","stop","start","openModal","modalOpenClass","classes","modalOpen","overflowHiddenClass","overflowHidden","body","classList","callback","closeModal","remove","HS","modal","open","close","getCount","onOpen","index","indexOf","splice","onClose","setLenisEnabled","enabled"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{c as e}from"../main.js";import{q as t,a as r,g as n}from"./hs-attributeSelector-6pGcDBo-.js";import"./hs-modalManager-H_YegPAO.js";import{g as o}from"./hs-utils-CKm6QhLw.js";function s(e){const t=[],r=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null);let n;for(;n=r.nextNode();)n.nodeValue?.trim()&&t.push(n);return t}function i(e){const t=[];return e.hasAttribute("href")&&t.push(e),t.push(...Array.from(e.querySelectorAll("[href]"))),t}function c(e){if(e.hasAttribute("src")){if(e.getAttribute("src"))return e}const t=e.querySelector("[src]");if(t){if(t.getAttribute("src"))return t}return null}function a(e,t,r){if(function(e,t){const r=t.attributes.properties.syncField;return null!==e.querySelector(`[${r}]`)}(t,r))return void function(e,t,r){const n=r.attributes.properties.syncField;e.querySelectorAll(`[${n}]`).forEach(e=>{const r=e.getAttribute(n),o=t.querySelector(`[${n}="${r}"]`);if(!o)return;const i=c(e),a=c(o);if(i&&a){const e=i.getAttribute("src");e&&a.setAttribute("src",e)}else if(e.hasAttribute("href")&&o.hasAttribute("href")){const t=e.getAttribute("href");t&&o.setAttribute("href",t)}else{const t=s(e),r=t.length>0?t[0].nodeValue:e.textContent.trim();if(r){const e=s(o);e.length>0?e[0].nodeValue=r:o.textContent=r}}})}(e,t,r);const n=s(e),o=n.length>0?n[0].nodeValue:"",a=i(e),l=a.length>0?a[0].getAttribute("href"):"";if(o){s(t).forEach(e=>{e.nodeValue=o})}if(l){i(t).forEach(e=>{e.setAttribute("href",l)})}}const l="hs-dupe-no-transition";let u=!1;async function d(e){!function(){if(u)return;const e=document.createElement("style");e.textContent=`\n .${l},\n .${l} * {\n transition: none !important;\n animation: none !important;\n }\n `,document.head.appendChild(e),u=!0}();const r={processedElements:[]};return t(e,"wrapper").forEach(e=>{const t=e.getAttribute("data-hs-dupe");if(!t||"child"!==t&&"self"!==t)return void console.warn('[dupe] Invalid mode. Use "child" or "self":',e);const n=e.getAttribute("data-hs-dupe-count");let o=n?parseInt(n,10):1;(isNaN(o)||o<1)&&(console.warn("[dupe] Invalid count, using default of 1:",e),o=1),o>20&&(console.warn(`[dupe] Count of ${o} exceeds maximum of 20. Capping at 20.`),o=20);const s={hidden:e.hasAttribute("data-hs-dupe-hidden"),noSelect:e.hasAttribute("data-hs-dupe-no-select")};"child"===t?function(e,t,r,n){const o=e.children[0];if(!o)return;const s=[];for(let i=0;i<t;i++){const t=o.cloneNode(!0);t.classList.add(l),p(t,r),e.appendChild(t),s.push(t),t.offsetHeight,requestAnimationFrame(()=>{t.classList.remove(l)})}n.processedElements.push({element:e,mode:"child",clones:s})}(e,o,s,r):"self"===t&&function(e,t,r,n){const o=e.parentNode;if(!o)return void console.warn("[dupe] Element has no parent, cannot duplicate self:",e);const s=[];let i=e;for(let c=0;c<t;c++){const t=e.cloneNode(!0);t.classList.add(l),t.removeAttribute("data-hs-dupe"),t.removeAttribute("data-hs-dupe-count"),t.removeAttribute("data-hs-dupe-hidden"),t.removeAttribute("data-hs-dupe-no-select"),p(t,r),i.nextSibling?o.insertBefore(t,i.nextSibling):o.appendChild(t),s.push(t),i=t,t.offsetHeight,requestAnimationFrame(()=>{t.classList.remove(l)})}n.processedElements.push({element:e,mode:"self",clones:s})}(e,o,s,r)}),{result:`dupe processed ${r.processedElements.length} elements`,destroy:()=>{r.processedElements.forEach(({clones:e})=>{e.forEach(e=>{e.parentNode&&e.parentNode.removeChild(e)})}),r.processedElements.length=0}}}function p(e,t){if(t.hidden&&e.setAttribute("aria-hidden","true"),t.noSelect){const t=e;t.style.userSelect="none",t.style.webkitUserSelect="none",t.style.msUserSelect="none"}}async function h(){const s={destroyFunctions:[]},i=e.normalize;try{const l=await async function(e){const n=t(e,"source"),o=new Map;n.forEach(t=>{const r=t.getAttribute(e.attributes.properties.syncId);r&&o.set(r,t)});const s=t(e,"target");let i=0,c=0;return s.forEach(n=>{const s=n.getAttribute(e.attributes.properties.syncId);if(!s||!o.has(s))return void c++;const l=o.get(s),u=r(e,"item",n);if(!u)return void console.warn(`[sync] Target list "${s}" missing item template`);const d="child"===u.getAttribute(e.attributes.properties.syncMode),p=r(e,"ignore",n),h=t(e,"item",l);if(0===h.length)return void console.warn(`[sync] Source list "${s}" has no items`);let f;if(d){const e=u.firstElementChild;if(!e)return void console.warn(`[sync] Target list "${s}" has sync-mode="child" but item wrapper has no children`);f=e.cloneNode(!0)}else f=u.cloneNode(!0),f.removeAttribute(e.attributes.elements.item.primary.split("=")[0]);let m=!1;if(p){let e=p.nextElementSibling;for(;e;){if(e===u){m=!0;break}e=e.nextElementSibling}}if(d){for(;u.firstChild;)u.removeChild(u.firstChild);h.forEach(t=>{const r=f.cloneNode(!0);a(t,r,e),u.appendChild(r)}),u.removeAttribute(e.attributes.elements.item.primary.split("=")[0])}else{Array.from(n.children).forEach(e=>{e!==p&&e.remove()});const t=Array.from(h).map(t=>{const r=f.cloneNode(!0);return a(t,r,e),r});p?m?t.forEach(e=>{n.appendChild(e)}):t.forEach(e=>{n.insertBefore(e,p)}):t.forEach(e=>{n.appendChild(e)})}i++}),{result:`sync initialized (${i} synced, ${c} skipped)`}}(i.sync);l&&"destroy"in l&&"function"==typeof l.destroy&&s.destroyFunctions.push(l.destroy);const u=await async function(){const e={processedWrappers:[]};return t(o.clickable,"wrapper").forEach(t=>{const r=t.querySelector(":scope > button"),n=t.querySelector(":scope > a");if(!r||!n)return;const o=n.getAttribute("href");let s,i;o&&""!==o&&"#"!==o?(s=n,i=r):(s=r,i=n);const c="button"===s.getAttribute("data-hs-clickable");c||s.setAttribute("data-hs-clickable","button"),i.remove(),e.processedWrappers.push({wrapper:t,keptElement:s,wasLink:s===n,addedAttribute:!c})}),{result:`clickable processed ${e.processedWrappers.length} wrappers`,destroy:()=>{e.processedWrappers.forEach(({keptElement:e,addedAttribute:t})=>{t&&e.removeAttribute("data-hs-clickable")}),e.processedWrappers.length=0}}}();u&&"destroy"in u&&"function"==typeof u.destroy&&s.destroyFunctions.push(u.destroy);const p=await d(i.dupe);p&&"destroy"in p&&"function"==typeof p.destroy&&s.destroyFunctions.push(p.destroy);const h=(c=e.structure?.["site-settings"],function(){const e=r(c,"wrapper");if(!e)return;const o=t(c,"list",e);if(0===o.length)return;const s={};if(o.forEach(e=>{const t=n(c,"setting");e.querySelectorAll(t).forEach(e=>{const t=e.cloneNode(!0),r=n(c,"hide");t.querySelectorAll(r).forEach(e=>{const t=c.attributes.elements.hide.primary.match(/data-site-settings-hide/)[0],r=e.getAttribute(t);r&&r.split(" ").filter(e=>e.trim()).some(t=>e.classList.contains(t))&&e.remove()});const o=c.attributes.elements.setting.primary.match(/data-site-settings/)[0],i=e.getAttribute(o),a=t.textContent.trim(),l=e.getAttribute("href");i&&(a||l)&&(s[i]={text:a||null,href:l||null})})}),0===Object.keys(s).length)return;const i=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{acceptNode:e=>{const t=e.textContent;for(const r in s)if(t.includes(`{{${r}}}`))return NodeFilter.FILTER_ACCEPT;return NodeFilter.FILTER_SKIP}}),a=[];let l;for(;l=i.nextNode();)a.push(l);a.forEach(e=>{let t=e.textContent,r=!1;for(const n in s){const e=`{{${n}}}`;if(t.includes(e)){const o=s[n],i=o.text||o.href;i&&(t=t.replace(new RegExp(e,"g"),i),r=!0)}}r&&(e.textContent=t)}),document.querySelectorAll("a[href]").forEach(e=>{let t=e.getAttribute("href"),r=!1;for(const n in s){const e=`{{${n}}}`;if(t.includes(e)){const o=s[n];o.href?(t=o.href,r=!0):o.text&&(t=t.replace(new RegExp(e,"g"),o.text),r=!0)}}r&&e.setAttribute("href",t)})}(),{result:"site-settings initialized",destroy:()=>{}});h&&"destroy"in h&&"function"==typeof h.destroy&&s.destroyFunctions.push(h.destroy);const f=function(e){return function(){const t=(new Date).getFullYear().toString(),r=["January","February","March","April","May","June","July","August","September","October","November","December"][(new Date).getMonth()],n=e.attributes.placeholders.year,o=e.attributes.placeholders.month,s=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{acceptNode:e=>e.textContent.includes(n)||e.textContent.includes(o)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}),i=[];let c;for(;c=s.nextNode();)i.push(c);const a=new RegExp(n.replace(/[{}]/g,"\\$&"),"gi"),l=new RegExp(o.replace(/[{}]/g,"\\$&"),"gi");i.forEach(e=>{let n=e.textContent.replace(a,t);n=n.replace(l,r),n!==e.textContent&&(e.textContent=n)})}(),{result:"year-replacement initialized",destroy:()=>{}}}(e.structure?.["year-replacement"]);return f&&"destroy"in f&&"function"==typeof f.destroy&&s.destroyFunctions.push(f.destroy),{result:"normalize initialized",destroy:()=>{s.destroyFunctions.reverse().forEach(e=>{try{e()}catch(t){console.error("[normalize] Error during cleanup:",t)}}),s.destroyFunctions.length=0}}}catch(l){throw console.error("[normalize] Initialization failed:",l),s.destroyFunctions.reverse().forEach(e=>{try{e()}catch(t){console.error("[normalize] Error during error cleanup:",t)}}),l}var c}export{h as init};
|
|
2
|
+
//# sourceMappingURL=hs-normalize-CTwtG5-a.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{c as e}from"../main.js";import{q as t,a as r,g as n}from"./hs-attributeSelector-6pGcDBo-.js";import"./hs-modalManager-H_YegPAO.js";import{g as o}from"./hs-utils-CKm6QhLw.js";function s(e){const t=[],r=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null);let n;for(;n=r.nextNode();)n.nodeValue?.trim()&&t.push(n);return t}function i(e){const t=[];return e.hasAttribute("href")&&t.push(e),t.push(...Array.from(e.querySelectorAll("[href]"))),t}function c(e){if(e.hasAttribute("src")){if(e.getAttribute("src"))return e}const t=e.querySelector("[src]");if(t){if(t.getAttribute("src"))return t}return null}function a(e,t,r){if(function(e,t){const r=t.attributes.properties.syncField;return null!==e.querySelector(`[${r}]`)}(t,r))return void function(e,t,r){const n=r.attributes.properties.syncField;e.querySelectorAll(`[${n}]`).forEach(e=>{const r=e.getAttribute(n),o=t.querySelector(`[${n}="${r}"]`);if(!o)return;const i=c(e),a=c(o);if(i&&a){const e=i.getAttribute("src");e&&a.setAttribute("src",e)}else if(e.hasAttribute("href")&&o.hasAttribute("href")){const t=e.getAttribute("href");t&&o.setAttribute("href",t)}else{const t=s(e),r=t.length>0?t[0].nodeValue:e.textContent.trim();if(r){const e=s(o);e.length>0?e[0].nodeValue=r:o.textContent=r}}})}(e,t,r);const n=s(e),o=n.length>0?n[0].nodeValue:"",a=i(e),l=a.length>0?a[0].getAttribute("href"):"";if(o){s(t).forEach(e=>{e.nodeValue=o})}if(l){i(t).forEach(e=>{e.setAttribute("href",l)})}}const l="hs-dupe-no-transition";let u=!1;async function d(e){!function(){if(u)return;const e=document.createElement("style");e.textContent=`\n .${l},\n .${l} * {\n transition: none !important;\n animation: none !important;\n }\n `,document.head.appendChild(e),u=!0}();const r={processedElements:[]};return t(e,"wrapper").forEach(e=>{const t=e.getAttribute("data-hs-dupe");if(!t||"child"!==t&&"self"!==t)return void console.warn('[dupe] Invalid mode. Use "child" or "self":',e);const n=e.getAttribute("data-hs-dupe-count");let o=n?parseInt(n,10):1;(isNaN(o)||o<1)&&(console.warn("[dupe] Invalid count, using default of 1:",e),o=1),o>20&&(console.warn(`[dupe] Count of ${o} exceeds maximum of 20. Capping at 20.`),o=20);const s={hidden:e.hasAttribute("data-hs-dupe-hidden"),noSelect:e.hasAttribute("data-hs-dupe-no-select")};"child"===t?function(e,t,r,n){const o=e.children[0];if(!o)return;const s=[];for(let i=0;i<t;i++){const t=o.cloneNode(!0);t.classList.add(l),p(t,r),e.appendChild(t),s.push(t),t.offsetHeight,requestAnimationFrame(()=>{t.classList.remove(l)})}n.processedElements.push({element:e,mode:"child",clones:s})}(e,o,s,r):"self"===t&&function(e,t,r,n){const o=e.parentNode;if(!o)return void console.warn("[dupe] Element has no parent, cannot duplicate self:",e);const s=[];let i=e;for(let c=0;c<t;c++){const t=e.cloneNode(!0);t.classList.add(l),t.removeAttribute("data-hs-dupe"),t.removeAttribute("data-hs-dupe-count"),t.removeAttribute("data-hs-dupe-hidden"),t.removeAttribute("data-hs-dupe-no-select"),p(t,r),i.nextSibling?o.insertBefore(t,i.nextSibling):o.appendChild(t),s.push(t),i=t,t.offsetHeight,requestAnimationFrame(()=>{t.classList.remove(l)})}n.processedElements.push({element:e,mode:"self",clones:s})}(e,o,s,r)}),{result:`dupe processed ${r.processedElements.length} elements`,destroy:()=>{r.processedElements.forEach(({clones:e})=>{e.forEach(e=>{e.parentNode&&e.parentNode.removeChild(e)})}),r.processedElements.length=0}}}function p(e,t){if(t.hidden&&e.setAttribute("aria-hidden","true"),t.noSelect){const t=e;t.style.userSelect="none",t.style.webkitUserSelect="none",t.style.msUserSelect="none"}}async function h(){const s={destroyFunctions:[]},i=e.normalize;try{const l=await async function(e){const n=t(e,"source"),o=new Map;n.forEach(t=>{const r=t.getAttribute(e.attributes.properties.syncId);r&&o.set(r,t)});const s=t(e,"target");let i=0,c=0;return s.forEach(n=>{const s=n.getAttribute(e.attributes.properties.syncId);if(!s||!o.has(s))return void c++;const l=o.get(s),u=r(e,"item",n);if(!u)return void console.warn(`[sync] Target list "${s}" missing item template`);const d="child"===u.getAttribute(e.attributes.properties.syncMode),p=r(e,"ignore",n),h=t(e,"item",l);if(0===h.length)return void console.warn(`[sync] Source list "${s}" has no items`);let f;if(d){const e=u.firstElementChild;if(!e)return void console.warn(`[sync] Target list "${s}" has sync-mode="child" but item wrapper has no children`);f=e.cloneNode(!0)}else f=u.cloneNode(!0),f.removeAttribute(e.attributes.elements.item.primary.split("=")[0]);let m=!1;if(p){let e=p.nextElementSibling;for(;e;){if(e===u){m=!0;break}e=e.nextElementSibling}}if(d){for(;u.firstChild;)u.removeChild(u.firstChild);h.forEach(t=>{const r=f.cloneNode(!0);a(t,r,e),u.appendChild(r)}),u.removeAttribute(e.attributes.elements.item.primary.split("=")[0])}else{Array.from(n.children).forEach(e=>{e!==p&&e.remove()});const t=Array.from(h).map(t=>{const r=f.cloneNode(!0);return a(t,r,e),r});p?m?t.forEach(e=>{n.appendChild(e)}):t.forEach(e=>{n.insertBefore(e,p)}):t.forEach(e=>{n.appendChild(e)})}i++}),{result:`sync initialized (${i} synced, ${c} skipped)`}}(i.sync);l&&"destroy"in l&&"function"==typeof l.destroy&&s.destroyFunctions.push(l.destroy);const u=await async function(){const e={processedWrappers:[]};return t(o.clickable,"wrapper").forEach(t=>{const r=t.querySelector(":scope > button"),n=t.querySelector(":scope > a");if(!r||!n)return;const o=n.getAttribute("href");let s,i;o&&""!==o&&"#"!==o?(s=n,i=r):(s=r,i=n);const c="button"===s.getAttribute("data-hs-clickable");c||s.setAttribute("data-hs-clickable","button"),i.remove(),e.processedWrappers.push({wrapper:t,keptElement:s,wasLink:s===n,addedAttribute:!c})}),{result:`clickable processed ${e.processedWrappers.length} wrappers`,destroy:()=>{e.processedWrappers.forEach(({keptElement:e,addedAttribute:t})=>{t&&e.removeAttribute("data-hs-clickable")}),e.processedWrappers.length=0}}}();u&&"destroy"in u&&"function"==typeof u.destroy&&s.destroyFunctions.push(u.destroy);const p=await d(i.dupe);p&&"destroy"in p&&"function"==typeof p.destroy&&s.destroyFunctions.push(p.destroy);const h=(c=e.structure?.["site-settings"],function(){const e=r(c,"wrapper");if(!e)return;const o=t(c,"list",e);if(0===o.length)return;const s={};if(o.forEach(e=>{const t=n(c,"setting");e.querySelectorAll(t).forEach(e=>{const t=e.cloneNode(!0),r=n(c,"hide");t.querySelectorAll(r).forEach(e=>{const t=c.attributes.elements.hide.primary.match(/data-site-settings-hide/)[0],r=e.getAttribute(t);r&&r.split(" ").filter(e=>e.trim()).some(t=>e.classList.contains(t))&&e.remove()});const o=c.attributes.elements.setting.primary.match(/data-site-settings/)[0],i=e.getAttribute(o),a=t.textContent.trim(),l=e.getAttribute("href");i&&(a||l)&&(s[i]={text:a||null,href:l||null})})}),0===Object.keys(s).length)return;const i=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{acceptNode:e=>{const t=e.textContent;for(const r in s)if(t.includes(`{{${r}}}`))return NodeFilter.FILTER_ACCEPT;return NodeFilter.FILTER_SKIP}}),a=[];let l;for(;l=i.nextNode();)a.push(l);a.forEach(e=>{let t=e.textContent,r=!1;for(const n in s){const e=`{{${n}}}`;if(t.includes(e)){const o=s[n],i=o.text||o.href;i&&(t=t.replace(new RegExp(e,"g"),i),r=!0)}}r&&(e.textContent=t)}),document.querySelectorAll("a[href]").forEach(e=>{let t=e.getAttribute("href"),r=!1;for(const n in s){const e=`{{${n}}}`;if(t.includes(e)){const o=s[n];o.href?(t=o.href,r=!0):o.text&&(t=t.replace(new RegExp(e,"g"),o.text),r=!0)}}r&&e.setAttribute("href",t)})}(),{result:"site-settings initialized",destroy:()=>{}});h&&"destroy"in h&&"function"==typeof h.destroy&&s.destroyFunctions.push(h.destroy);const f=function(e){return function(){const t=(new Date).getFullYear().toString(),r=["January","February","March","April","May","June","July","August","September","October","November","December"][(new Date).getMonth()],n=e.attributes.placeholders.year,o=e.attributes.placeholders.month,s=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{acceptNode:e=>e.textContent.includes(n)||e.textContent.includes(o)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}),i=[];let c;for(;c=s.nextNode();)i.push(c);const a=new RegExp(n.replace(/[{}]/g,"\\$&"),"gi"),l=new RegExp(o.replace(/[{}]/g,"\\$&"),"gi");i.forEach(e=>{let n=e.textContent.replace(a,t);n=n.replace(l,r),n!==e.textContent&&(e.textContent=n)})}(),{result:"year-replacement initialized",destroy:()=>{}}}(e.structure?.["year-replacement"]);return f&&"destroy"in f&&"function"==typeof f.destroy&&s.destroyFunctions.push(f.destroy),{result:"normalize initialized",destroy:()=>{s.destroyFunctions.reverse().forEach(e=>{try{e()}catch(t){console.error("[normalize] Error during cleanup:",t)}}),s.destroyFunctions.length=0}}}catch(l){throw console.error("[normalize] Initialization failed:",l),s.destroyFunctions.reverse().forEach(e=>{try{e()}catch(t){console.error("[normalize] Error during error cleanup:",t)}}),l}var c}export{h as init};
|
|
2
|
+
//# sourceMappingURL=hs-normalize-CTwtG5-a.js.map
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hs-normalize-CTwtG5-a.js","sources":["../../src/modules/normalize/functions/sync.ts","../../src/modules/normalize/functions/dupe.ts","../../src/modules/normalize/normalize.ts","../../src/modules/normalize/functions/clickable.ts","../../src/modules/normalize/functions/site-settings.ts","../../src/modules/normalize/functions/year-replacement.ts"],"sourcesContent":["/**\n * List Sync\n *\n * Syncs collection list data to static lists by sync-id.\n *\n * Simple mode (text/href):\n * <div data-hs-sync=\"source\" data-hs-sync-id=\"services\">\n * <a data-hs-sync=\"item\" href=\"/service-1\">Service 1</a>\n * </div>\n * <div data-hs-sync=\"target\" data-hs-sync-id=\"services\">\n * <a data-hs-sync=\"item\" href=\"#\">Placeholder</a>\n * </div>\n *\n * Field-based mode (named fields):\n * <div data-hs-sync=\"source\" data-hs-sync-id=\"projects\">\n * <div data-hs-sync=\"item\">\n * <img data-hs-sync-field=\"before\" src=\"/before.jpg\">\n * <img data-hs-sync-field=\"after\" src=\"/after.jpg\">\n * </div>\n * </div>\n * <div data-hs-sync=\"target\" data-hs-sync-id=\"projects\">\n * <div data-hs-sync=\"item\">\n * <img data-hs-sync-field=\"before\" src=\"/placeholder.jpg\">\n * <img data-hs-sync-field=\"after\" src=\"/placeholder.jpg\">\n * </div>\n * </div>\n *\n * Child mode (wrapper templates):\n * <div data-hs-sync=\"target\" data-hs-sync-id=\"marquee\">\n * <div data-hs-sync=\"item\" data-hs-sync-mode=\"child\">\n * <div class=\"marquee_list\">\n * <img data-hs-sync-field=\"image\" src=\"/placeholder.jpg\">\n * </div>\n * </div>\n * </div>\n *\n * Supports data-hs-sync=\"ignore\" to preserve elements during sync.\n */\n\nimport { querySelectorAll, querySelector } from '@utils';\n\n/**\n * Get all text nodes within an element\n */\nfunction getTextNodes(element: Element): Text[] {\n const textNodes: Text[] = [];\n const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null);\n\n let node: Node | null;\n while ((node = walker.nextNode())) {\n // Skip empty/whitespace-only nodes\n if (node.nodeValue?.trim()) {\n textNodes.push(node as Text);\n }\n }\n\n return textNodes;\n}\n\n/**\n * Get all elements with href attribute (including the element itself)\n */\nfunction getHrefElements(element: Element): Element[] {\n const hrefs: Element[] = [];\n\n // Check if element itself has href\n if (element.hasAttribute('href')) {\n hrefs.push(element);\n }\n\n // Check descendants\n hrefs.push(...Array.from(element.querySelectorAll('[href]')));\n\n return hrefs;\n}\n\n/**\n * Check if item uses field-based syncing\n */\nfunction usesFieldBasedSync(\n item: Element,\n config: { attributes: { properties: { syncField: string } } }\n): boolean {\n const fieldAttr = config.attributes.properties.syncField;\n return item.querySelector(`[${fieldAttr}]`) !== null;\n}\n\n/**\n * Find element with src attribute (check element itself, then descendants)\n */\nfunction findElementWithSrc(element: Element): Element | null {\n // Check element itself\n if (element.hasAttribute('src')) {\n const src = element.getAttribute('src');\n if (src) return element;\n }\n\n // Check descendants\n const descendant = element.querySelector('[src]');\n if (descendant) {\n const src = descendant.getAttribute('src');\n if (src) return descendant;\n }\n\n return null;\n}\n\n/**\n * Sync data using field-based mapping\n * Maps fields by name between source and target\n */\nfunction syncFieldBasedData(\n sourceItem: Element,\n targetClone: Element,\n config: { attributes: { properties: { syncField: string } } }\n): void {\n const fieldAttr = config.attributes.properties.syncField;\n\n // Get all fields in source\n const sourceFields = sourceItem.querySelectorAll(`[${fieldAttr}]`);\n\n sourceFields.forEach((sourceField: Element) => {\n const fieldName = sourceField.getAttribute(fieldAttr);\n\n // Find matching field in target\n const targetField = targetClone.querySelector(`[${fieldAttr}=\"${fieldName}\"]`);\n if (!targetField) return;\n\n // Try to find elements with src (for images)\n const sourceImgElement = findElementWithSrc(sourceField);\n const targetImgElement = findElementWithSrc(targetField);\n\n if (sourceImgElement && targetImgElement) {\n // Sync src attribute\n const src = sourceImgElement.getAttribute('src');\n if (src) {\n targetImgElement.setAttribute('src', src);\n }\n }\n // Link elements: sync href\n else if (sourceField.hasAttribute('href') && targetField.hasAttribute('href')) {\n const href = sourceField.getAttribute('href');\n if (href) {\n targetField.setAttribute('href', href);\n }\n }\n // Text elements: sync text content\n else {\n const sourceTextNodes = getTextNodes(sourceField);\n const sourceText =\n sourceTextNodes.length > 0 ? sourceTextNodes[0].nodeValue : sourceField.textContent.trim();\n\n if (sourceText) {\n const targetTextNodes = getTextNodes(targetField);\n if (targetTextNodes.length > 0) {\n targetTextNodes[0].nodeValue = sourceText;\n } else {\n targetField.textContent = sourceText;\n }\n }\n }\n });\n}\n\n/**\n * Sync data from source item to target clone\n * Extracts text and href from source, applies to ALL matching elements in target\n */\nfunction syncItemData(\n sourceItem: Element,\n targetClone: Element,\n config: { attributes: { properties: { syncField: string } } }\n): void {\n // Check if using field-based syncing\n if (usesFieldBasedSync(targetClone, config)) {\n syncFieldBasedData(sourceItem, targetClone, config);\n return;\n }\n\n // Fallback to simple syncing (existing behavior)\n // Get text content from source (first non-empty text node)\n const sourceTextNodes = getTextNodes(sourceItem);\n const sourceText = sourceTextNodes.length > 0 ? sourceTextNodes[0].nodeValue : '';\n\n // Get href from source (first href element)\n const sourceHrefs = getHrefElements(sourceItem);\n const sourceHref = sourceHrefs.length > 0 ? sourceHrefs[0].getAttribute('href') : '';\n\n // Apply source text to ALL text nodes in target\n if (sourceText) {\n const targetTextNodes = getTextNodes(targetClone);\n targetTextNodes.forEach((node) => {\n node.nodeValue = sourceText;\n });\n }\n\n // Apply source href to ALL href elements in target\n if (sourceHref) {\n const targetHrefs = getHrefElements(targetClone);\n targetHrefs.forEach((el) => {\n el.setAttribute('href', sourceHref);\n });\n }\n}\n\ninterface SyncConfig {\n attributes: {\n elements: {\n item: { primary: string };\n };\n properties: {\n syncId: string;\n syncField: string;\n syncMode: string;\n };\n };\n}\n\nexport async function init(config: SyncConfig): Promise<{ result: string }> {\n // Find all source lists and build map by sync-id\n const sourceLists = querySelectorAll(config, 'source');\n const sourceMap = new Map<string, Element>();\n\n sourceLists.forEach((source) => {\n const syncId = source.getAttribute(config.attributes.properties.syncId);\n if (syncId) {\n sourceMap.set(syncId, source);\n }\n });\n\n // Find all target lists\n const targetLists = querySelectorAll(config, 'target');\n let syncedCount = 0;\n let skippedCount = 0;\n\n targetLists.forEach((target) => {\n const syncId = target.getAttribute(config.attributes.properties.syncId);\n\n // Skip if no sync-id or no matching source\n if (!syncId || !sourceMap.has(syncId)) {\n skippedCount++;\n return;\n }\n\n const source = sourceMap.get(syncId);\n\n // Find item template in target (element to clone)\n const targetTemplateWrapper = querySelector(config, 'item', target);\n if (!targetTemplateWrapper) {\n console.warn(`[sync] Target list \"${syncId}\" missing item template`);\n return;\n }\n\n // Check sync mode - determines which element to use as template\n const syncMode = targetTemplateWrapper.getAttribute(config.attributes.properties.syncMode);\n const isChildMode = syncMode === 'child';\n\n // Find ignore element in target (if exists)\n const ignoreElement = querySelector(config, 'ignore', target);\n\n // Find all source items\n const sourceItems = querySelectorAll(config, 'item', source);\n if (sourceItems.length === 0) {\n console.warn(`[sync] Source list \"${syncId}\" has no items`);\n return;\n }\n\n // Determine template based on mode\n let template: Element;\n if (isChildMode) {\n // Child mode: clone the wrapper, we'll replace its child content\n const firstChild = targetTemplateWrapper.firstElementChild;\n if (!firstChild) {\n console.warn(\n `[sync] Target list \"${syncId}\" has sync-mode=\"child\" but item wrapper has no children`\n );\n return;\n }\n // Clone the child element to use for syncing data\n template = firstChild.cloneNode(true) as Element;\n } else {\n // Default mode: clone the item element itself\n template = targetTemplateWrapper.cloneNode(true) as Element;\n template.removeAttribute(config.attributes.elements.item.primary.split('=')[0]);\n }\n\n // Determine insertion strategy if ignore exists\n let insertAfterIgnore = false;\n if (ignoreElement) {\n // Check if template wrapper comes after ignore element\n let currentElement = ignoreElement.nextElementSibling;\n while (currentElement) {\n if (currentElement === targetTemplateWrapper) {\n insertAfterIgnore = true;\n break;\n }\n currentElement = currentElement.nextElementSibling;\n }\n }\n\n if (isChildMode) {\n // CHILD MODE: Keep wrapper as single element, duplicate children inside it\n // Clear the wrapper's children\n while (targetTemplateWrapper.firstChild) {\n targetTemplateWrapper.removeChild(targetTemplateWrapper.firstChild);\n }\n\n // Create synced children and append to the wrapper\n sourceItems.forEach((sourceItem) => {\n const childClone = template.cloneNode(true) as Element;\n syncItemData(sourceItem, childClone, config);\n targetTemplateWrapper.appendChild(childClone);\n });\n\n // Remove data-hs-sync=\"item\" attribute from wrapper\n targetTemplateWrapper.removeAttribute(config.attributes.elements.item.primary.split('=')[0]);\n } else {\n // DEFAULT MODE: Duplicate the item element itself\n // Clear target list, but preserve ignore element\n const children = Array.from(target.children);\n children.forEach((child) => {\n if (child !== ignoreElement) {\n child.remove();\n }\n });\n\n // Create synced items\n const syncedItems = Array.from(sourceItems).map((sourceItem) => {\n const clone = template.cloneNode(true) as Element;\n syncItemData(sourceItem, clone, config);\n return clone;\n });\n\n // Insert synced items based on strategy\n if (ignoreElement) {\n if (insertAfterIgnore) {\n // Insert all items after ignore\n syncedItems.forEach((item) => {\n target.appendChild(item);\n });\n } else {\n // Insert all items before ignore\n syncedItems.forEach((item) => {\n target.insertBefore(item, ignoreElement);\n });\n }\n } else {\n // No ignore element, just append all\n syncedItems.forEach((item) => {\n target.appendChild(item);\n });\n }\n }\n\n syncedCount++;\n });\n\n return {\n result: `sync initialized (${syncedCount} synced, ${skippedCount} skipped)`,\n };\n}\n","/**\n * Element Duplication\n *\n * Duplicates elements for marquee effects and visual consistency.\n *\n * Child mode (duplicate children):\n * <div data-hs-dupe=\"child\" data-hs-dupe-count=\"2\">\n * <div class=\"marquee_item\">Content</div>\n * </div>\n *\n * Self mode (duplicate wrapper):\n * <div data-hs-dupe=\"self\" data-hs-dupe-count=\"3\">Content</div>\n *\n * Modifiers: data-hs-dupe-hidden (aria-hidden), data-hs-dupe-no-select (disable selection).\n */\nimport { querySelectorAll } from '@utils';\n\nconst MAX_DUPE_COUNT = 20;\nconst TRANSITION_CLASS = 'hs-dupe-no-transition';\n\n// Inject CSS once\nlet cssInjected = false;\nfunction injectCSS(): void {\n if (cssInjected) return;\n\n const style = document.createElement('style');\n style.textContent = `\n .${TRANSITION_CLASS},\n .${TRANSITION_CLASS} * {\n transition: none !important;\n animation: none !important;\n }\n `;\n document.head.appendChild(style);\n cssInjected = true;\n}\n\ninterface DupeConfig {\n attributes: {\n elements: {\n [key: string]: {\n primary: string;\n aliases?: string[];\n };\n };\n };\n}\n\ninterface CleanupRecord {\n element: Element;\n mode: string;\n clones: Element[];\n}\n\ninterface DupeOptions {\n hidden: boolean;\n noSelect: boolean;\n}\n\nexport async function init(config: DupeConfig): Promise<{ result: string; destroy: () => void }> {\n // Inject CSS on first init\n injectCSS();\n\n const cleanup: { processedElements: CleanupRecord[] } = {\n processedElements: [],\n };\n\n // Find all elements with dupe attribute\n const dupeElements = querySelectorAll(config, 'wrapper');\n\n dupeElements.forEach((element) => {\n // Get dupe mode (child or self)\n const mode = element.getAttribute('data-hs-dupe');\n if (!mode || (mode !== 'child' && mode !== 'self')) {\n console.warn('[dupe] Invalid mode. Use \"child\" or \"self\":', element);\n return;\n }\n\n // Get dupe count (default: 1)\n const countAttr = element.getAttribute('data-hs-dupe-count');\n let count = countAttr ? parseInt(countAttr, 10) : 1;\n\n // Validate and cap count\n if (isNaN(count) || count < 1) {\n console.warn('[dupe] Invalid count, using default of 1:', element);\n count = 1;\n }\n\n if (count > MAX_DUPE_COUNT) {\n console.warn(\n `[dupe] Count of ${count} exceeds maximum of ${MAX_DUPE_COUNT}. Capping at ${MAX_DUPE_COUNT}.`\n );\n count = MAX_DUPE_COUNT;\n }\n\n // Get modifier options\n const options = {\n hidden: element.hasAttribute('data-hs-dupe-hidden'),\n noSelect: element.hasAttribute('data-hs-dupe-no-select'),\n };\n\n // Execute duplication based on mode\n if (mode === 'child') {\n dupeChild(element, count, options, cleanup);\n } else if (mode === 'self') {\n dupeSelf(element, count, options, cleanup);\n }\n });\n\n return {\n result: `dupe processed ${cleanup.processedElements.length} elements`,\n destroy: () => {\n // Remove all cloned elements\n cleanup.processedElements.forEach(({ clones }) => {\n clones.forEach((clone) => {\n if (clone.parentNode) {\n clone.parentNode.removeChild(clone);\n }\n });\n });\n cleanup.processedElements.length = 0;\n },\n };\n}\n\nfunction dupeChild(\n element: Element,\n count: number,\n options: DupeOptions,\n cleanup: { processedElements: CleanupRecord[] }\n): void {\n // Get first direct child\n const firstChild = element.children[0];\n\n // Silently skip if no child exists (e.g., empty slot waiting for CMS content)\n if (!firstChild) {\n return;\n }\n\n const clones: Element[] = [];\n\n // Create clones and append as siblings\n for (let i = 0; i < count; i++) {\n const clone = firstChild.cloneNode(true) as Element;\n\n // Disable transitions during insertion\n clone.classList.add(TRANSITION_CLASS);\n\n // Apply modifiers to clone\n applyModifiers(clone, options);\n\n // Append to DOM\n element.appendChild(clone);\n clones.push(clone);\n\n // Force reflow\n (clone as HTMLElement).offsetHeight;\n\n // Re-enable transitions on next frame\n requestAnimationFrame(() => {\n clone.classList.remove(TRANSITION_CLASS);\n });\n }\n\n // Track for cleanup\n cleanup.processedElements.push({\n element,\n mode: 'child',\n clones,\n });\n}\n\nfunction dupeSelf(\n element: Element,\n count: number,\n options: DupeOptions,\n cleanup: { processedElements: CleanupRecord[] }\n): void {\n const parent = element.parentNode;\n\n if (!parent) {\n console.warn('[dupe] Element has no parent, cannot duplicate self:', element);\n return;\n }\n\n const clones: Element[] = [];\n\n // Create clones and insert as next siblings\n let referenceNode: Element | Node = element;\n for (let i = 0; i < count; i++) {\n const clone = element.cloneNode(true) as Element;\n\n // Disable transitions during insertion\n clone.classList.add(TRANSITION_CLASS);\n\n // Remove dupe attributes from clone\n clone.removeAttribute('data-hs-dupe');\n clone.removeAttribute('data-hs-dupe-count');\n clone.removeAttribute('data-hs-dupe-hidden');\n clone.removeAttribute('data-hs-dupe-no-select');\n\n // Apply modifiers to clone\n applyModifiers(clone, options);\n\n // Insert after reference node\n if (referenceNode.nextSibling) {\n parent.insertBefore(clone, referenceNode.nextSibling);\n } else {\n parent.appendChild(clone);\n }\n\n clones.push(clone);\n referenceNode = clone; // Next clone goes after this one\n\n // Force reflow\n (clone as HTMLElement).offsetHeight;\n\n // Re-enable transitions on next frame\n requestAnimationFrame(() => {\n clone.classList.remove(TRANSITION_CLASS);\n });\n }\n\n // Track for cleanup\n cleanup.processedElements.push({\n element,\n mode: 'self',\n clones,\n });\n}\n\nfunction applyModifiers(clone: Element, options: DupeOptions): void {\n // Add aria-hidden if requested\n if (options.hidden) {\n clone.setAttribute('aria-hidden', 'true');\n }\n\n // Add user-select: none if requested\n if (options.noSelect) {\n const htmlClone = clone as HTMLElement;\n htmlClone.style.userSelect = 'none';\n (htmlClone.style as unknown as { webkitUserSelect: string }).webkitUserSelect = 'none';\n (htmlClone.style as unknown as { msUserSelect: string }).msUserSelect = 'none';\n }\n}\n","/**\n * Normalize Orchestrator\n *\n * Sequential DOM normalization: Sync → Clickable → Dupe → Site Settings → Year Replacement.\n * Critical first phase that prepares DOM structure for all other modules.\n */\nimport config from '@config';\nimport { init as syncInit } from './functions/sync.ts';\nimport { init as clickableInit } from './functions/clickable.ts';\nimport { init as dupeInit } from './functions/dupe.ts';\nimport { init as siteSettingsInit } from './functions/site-settings.ts';\nimport { init as yearReplacementInit } from './functions/year-replacement.ts';\n\nconst CONFIG_ROOT = 'normalize';\n\nexport async function init(): Promise<{ result: string; destroy: () => void }> {\n const cleanup: { destroyFunctions: (() => void)[] } = { destroyFunctions: [] };\n const moduleConfig = config[CONFIG_ROOT];\n\n try {\n // Phase 1a: Sync (populates lists with collection data) - must complete first\n const syncResult = await syncInit(\n moduleConfig.sync as unknown as {\n attributes: {\n elements: { item: { primary: string } };\n properties: { syncId: string; syncField: string; syncMode: string };\n };\n }\n );\n if (syncResult && 'destroy' in syncResult && typeof syncResult.destroy === 'function') {\n cleanup.destroyFunctions.push(syncResult.destroy as () => void);\n }\n\n // Phase 1b: Clickable (normalizes button/link structure) - runs after sync creates content\n const clickableResult = await clickableInit();\n if (\n clickableResult &&\n 'destroy' in clickableResult &&\n typeof clickableResult.destroy === 'function'\n ) {\n cleanup.destroyFunctions.push(clickableResult.destroy as () => void);\n }\n\n // Phase 1c: Dupe (duplicates normalized elements)\n const dupeResult = await dupeInit(\n moduleConfig.dupe as unknown as {\n attributes: { elements: { [key: string]: { primary: string; aliases?: string[] } } };\n }\n );\n if (dupeResult && 'destroy' in dupeResult && typeof dupeResult.destroy === 'function') {\n cleanup.destroyFunctions.push(dupeResult.destroy as () => void);\n }\n\n // Phase 1d: Site Settings (applies global site configuration)\n const siteSettingsResult = siteSettingsInit(config.structure?.['site-settings']);\n if (\n siteSettingsResult &&\n 'destroy' in siteSettingsResult &&\n typeof siteSettingsResult.destroy === 'function'\n ) {\n cleanup.destroyFunctions.push(siteSettingsResult.destroy as () => void);\n }\n\n // Phase 1e: Year Replacement (replaces year tokens)\n const yearReplacementResult = yearReplacementInit(config.structure?.['year-replacement']);\n if (\n yearReplacementResult &&\n 'destroy' in yearReplacementResult &&\n typeof yearReplacementResult.destroy === 'function'\n ) {\n cleanup.destroyFunctions.push(yearReplacementResult.destroy as () => void);\n }\n\n return {\n result: 'normalize initialized',\n destroy: () => {\n // Call all destroy functions in reverse order\n cleanup.destroyFunctions.reverse().forEach((destroyFn) => {\n try {\n destroyFn();\n } catch (error) {\n console.error('[normalize] Error during cleanup:', error);\n }\n });\n cleanup.destroyFunctions.length = 0;\n },\n };\n } catch (error) {\n console.error('[normalize] Initialization failed:', error);\n // Cleanup any partial initialization\n cleanup.destroyFunctions.reverse().forEach((fn) => {\n try {\n fn();\n } catch (cleanupError) {\n console.error('[normalize] Error during error cleanup:', cleanupError);\n }\n });\n throw error;\n }\n}\n","/**\n * Clickable Normalization\n *\n * Normalizes clickable wrappers by keeping either button or link based on href validity.\n * Removes the unused element and ensures the kept element has data-hs-clickable=\"button\".\n *\n * Structure:\n * <div data-hs-clickable=\"wrapper\">\n * <button data-hs-clickable=\"button\">Click</button>\n * <a data-hs-clickable=\"button\" href=\"/page\">Click</a>\n * </div>\n *\n * Logic: Keep link if href is valid, otherwise keep button.\n */\nimport { globalConfig, querySelectorAll } from '@utils';\n\ninterface ProcessedWrapper {\n wrapper: Element;\n keptElement: Element;\n wasLink: boolean;\n addedAttribute: boolean;\n}\n\nexport async function init(): Promise<{ result: string; destroy: () => void }> {\n const cleanup: { processedWrappers: ProcessedWrapper[] } = {\n processedWrappers: [],\n };\n\n // Find all clickable wrappers using global clickable config\n const wrappers = querySelectorAll(\n globalConfig.clickable as {\n attributes: { elements: { [key: string]: { primary: string; aliases?: string[] } } };\n },\n 'wrapper'\n );\n\n wrappers.forEach((wrapper) => {\n // Find direct button and link children\n const button = wrapper.querySelector(':scope > button');\n const link = wrapper.querySelector(':scope > a');\n\n // Only process if both exist\n if (!button || !link) return;\n\n // Check if link has valid href\n const href = link.getAttribute('href');\n const hasValidHref = href && href !== '' && href !== '#';\n\n let keptElement: Element;\n let removedElement: Element;\n\n if (hasValidHref) {\n // Keep link, remove button\n keptElement = link;\n removedElement = button;\n } else {\n // Keep button, remove link\n keptElement = button;\n removedElement = link;\n }\n\n // Check if kept element already has data-hs-clickable=\"button\"\n const hadAttribute = keptElement.getAttribute('data-hs-clickable') === 'button';\n\n // Ensure kept element has data-hs-clickable=\"button\"\n if (!hadAttribute) {\n keptElement.setAttribute('data-hs-clickable', 'button');\n }\n\n // Remove the other element\n removedElement.remove();\n\n // Track for cleanup\n cleanup.processedWrappers.push({\n wrapper,\n keptElement,\n wasLink: keptElement === link,\n addedAttribute: !hadAttribute,\n });\n });\n\n return {\n result: `clickable processed ${cleanup.processedWrappers.length} wrappers`,\n destroy: () => {\n // On destroy, we can't restore deleted elements\n // Only remove the attribute if we added it\n cleanup.processedWrappers.forEach(({ keptElement, addedAttribute }) => {\n if (addedAttribute) {\n keptElement.removeAttribute('data-hs-clickable');\n }\n });\n cleanup.processedWrappers.length = 0;\n },\n };\n}\n","/**\n * Site Settings\n *\n * Collects dynamic values from designated elements and replaces {{placeholder}} text throughout the page.\n * Supports both text content and href attributes for proper link handling.\n *\n * Features:\n * - Collects settings from wrapper/list structure with text and href values\n * - Replaces {{name}} placeholders in text content and link hrefs\n * - Complete href replacement for links (prevents Webflow \"https://\" prefix issues)\n * - Conditional hide feature to exclude elements based on class names\n * - One-time replacement on page load (no ongoing observers)\n *\n * Structure:\n * <div data-site-settings-element=\"wrapper\">\n * <div data-site-settings-element=\"list\">\n * <a data-site-settings=\"email\" href=\"mailto:info@example.com\">info@example.com</a>\n * <a data-site-settings=\"phone\" href=\"tel:+15551234567\">(555) 123-4567</a>\n * </div>\n * </div>\n *\n * Usage:\n * Text: \"Contact us at {{email}}\" → \"Contact us at info@example.com\"\n * Link: <a href=\"{{email}}\">Email</a> → <a href=\"mailto:info@example.com\">Email</a>\n */\n\nimport { querySelector, querySelectorAll, getSelector } from '@utils';\n\nexport function init(config) {\n function setupSiteSettings() {\n const wrapper = querySelector(config, 'wrapper');\n\n if (!wrapper) {\n return;\n }\n\n // Find all lists inside the wrapper\n const lists = querySelectorAll(config, 'list', wrapper);\n\n if (lists.length === 0) {\n return;\n }\n\n // Collect all site settings data\n const siteSettings = {};\n\n lists.forEach((list) => {\n // Find all descendants with data-site-settings attribute\n const settingSelector = getSelector(config, 'setting');\n const settingElements = list.querySelectorAll(settingSelector);\n\n settingElements.forEach((element) => {\n // Clone the element to avoid modifying the original DOM\n const clonedElement = element.cloneNode(true) as Element;\n\n // Find and remove elements with data-site-settings-hide that match their classes\n const hideSelector = getSelector(config, 'hide');\n const hideElements = clonedElement.querySelectorAll(hideSelector);\n\n hideElements.forEach((hideElement) => {\n const hideAttr =\n config.attributes.elements.hide.primary.match(/data-site-settings-hide/)[0];\n const hideValue = hideElement.getAttribute(hideAttr);\n\n if (hideValue) {\n // Split by spaces to get all class names to check\n const classesToHide = hideValue.split(' ').filter((c) => c.trim());\n\n // Check if element has any of the classes\n const hasMatchingClass = classesToHide.some((className) =>\n hideElement.classList.contains(className)\n );\n\n // Remove element if it has a matching class\n if (hasMatchingClass) {\n hideElement.remove();\n }\n }\n });\n\n const settingAttr =\n config.attributes.elements.setting.primary.match(/data-site-settings/)[0];\n const settingName = element.getAttribute(settingAttr);\n const settingText = clonedElement.textContent.trim();\n const settingHref = element.getAttribute('href');\n\n // Store if name exists and either text or href exists\n if (settingName && (settingText || settingHref)) {\n siteSettings[settingName] = {\n text: settingText || null,\n href: settingHref || null,\n };\n }\n });\n });\n\n // If no site settings found, exit early\n if (Object.keys(siteSettings).length === 0) {\n return;\n }\n\n // Replace text content efficiently using TreeWalker\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {\n acceptNode: (node) => {\n // Check if any site setting names exist in the text content\n const text = node.textContent;\n for (const name in siteSettings) {\n if (text.includes(`{{${name}}}`)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n }\n return NodeFilter.FILTER_SKIP;\n },\n });\n\n const textNodes = [];\n let node;\n while ((node = walker.nextNode())) {\n textNodes.push(node);\n }\n\n // Replace text in collected nodes\n textNodes.forEach((textNode) => {\n let newText = textNode.textContent;\n let hasChanges = false;\n\n for (const name in siteSettings) {\n const placeholder = `{{${name}}}`;\n if (newText.includes(placeholder)) {\n const setting = siteSettings[name];\n // Use text value if available, otherwise use href value, otherwise skip\n const replacementValue = setting.text || setting.href;\n if (replacementValue) {\n newText = newText.replace(new RegExp(placeholder, 'g'), replacementValue);\n hasChanges = true;\n }\n }\n }\n\n if (hasChanges) {\n textNode.textContent = newText;\n }\n });\n\n // Replace link hrefs\n const links = document.querySelectorAll('a[href]');\n links.forEach((link) => {\n let href = link.getAttribute('href');\n let hasChanges = false;\n\n for (const name in siteSettings) {\n const placeholder = `{{${name}}}`;\n if (href.includes(placeholder)) {\n const setting = siteSettings[name];\n\n // If setting has a dedicated href, completely replace the entire href\n // (prevents Webflow's default \"https://\" from breaking tel:, mailto:, etc.)\n if (setting.href) {\n href = setting.href;\n hasChanges = true;\n }\n // Otherwise, do normal placeholder replacement with text value\n else if (setting.text) {\n href = href.replace(new RegExp(placeholder, 'g'), setting.text);\n hasChanges = true;\n }\n }\n }\n\n if (hasChanges) {\n link.setAttribute('href', href);\n }\n });\n }\n\n setupSiteSettings();\n\n return {\n result: 'site-settings initialized',\n destroy: () => {\n // No cleanup needed - this module only modifies DOM during init\n },\n };\n}\n","/**\n * Year Replacement\n *\n * Automatically replaces {{year}} and {{month}} placeholders with current values.\n * Scans all text nodes on page load and performs one-time replacement.\n *\n * Features:\n * - Case-insensitive placeholder matching\n * - Uses TreeWalker for efficient text node scanning\n * - No ongoing observers (one-time replacement)\n * - Configurable placeholders via config.json\n *\n * Example:\n * \"Copyright {{year}}\" → \"Copyright 2024\"\n * \"{{month}} Newsletter\" → \"January Newsletter\"\n */\n\nexport function init(config) {\n function setupYearReplacement() {\n const currentYear = new Date().getFullYear().toString();\n const monthNames = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ];\n const currentMonth = monthNames[new Date().getMonth()];\n\n const yearPlaceholder = config.attributes.placeholders.year;\n const monthPlaceholder = config.attributes.placeholders.month;\n\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {\n acceptNode: (node) => {\n return node.textContent.includes(yearPlaceholder) ||\n node.textContent.includes(monthPlaceholder)\n ? NodeFilter.FILTER_ACCEPT\n : NodeFilter.FILTER_SKIP;\n },\n });\n\n const textNodes = [];\n let node;\n while ((node = walker.nextNode())) {\n textNodes.push(node);\n }\n\n // Create regex patterns from config placeholders\n const yearRegex = new RegExp(yearPlaceholder.replace(/[{}]/g, '\\\\$&'), 'gi');\n const monthRegex = new RegExp(monthPlaceholder.replace(/[{}]/g, '\\\\$&'), 'gi');\n\n textNodes.forEach((textNode) => {\n let newText = textNode.textContent.replace(yearRegex, currentYear);\n newText = newText.replace(monthRegex, currentMonth);\n if (newText !== textNode.textContent) {\n textNode.textContent = newText;\n }\n });\n }\n\n setupYearReplacement();\n\n return {\n result: 'year-replacement initialized',\n destroy: () => {\n // No cleanup needed - this is a one-time text replacement\n },\n };\n}\n"],"names":["getTextNodes","element","textNodes","walker","document","createTreeWalker","NodeFilter","SHOW_TEXT","node","nextNode","nodeValue","trim","push","getHrefElements","hrefs","hasAttribute","Array","from","querySelectorAll","findElementWithSrc","getAttribute","descendant","querySelector","syncItemData","sourceItem","targetClone","config","item","fieldAttr","attributes","properties","syncField","usesFieldBasedSync","forEach","sourceField","fieldName","targetField","sourceImgElement","targetImgElement","src","setAttribute","href","sourceTextNodes","sourceText","length","textContent","targetTextNodes","syncFieldBasedData","sourceHrefs","sourceHref","el","TRANSITION_CLASS","cssInjected","async","init","style","createElement","head","appendChild","injectCSS","cleanup","processedElements","mode","console","warn","countAttr","count","parseInt","isNaN","options","hidden","noSelect","firstChild","children","clones","i","clone","cloneNode","classList","add","applyModifiers","offsetHeight","requestAnimationFrame","remove","dupeChild","parent","parentNode","referenceNode","removeAttribute","nextSibling","insertBefore","dupeSelf","result","destroy","removeChild","htmlClone","userSelect","webkitUserSelect","msUserSelect","destroyFunctions","moduleConfig","syncResult","sourceLists","sourceMap","Map","source","syncId","set","targetLists","syncedCount","skippedCount","target","has","get","targetTemplateWrapper","isChildMode","syncMode","ignoreElement","sourceItems","template","firstElementChild","elements","primary","split","insertAfterIgnore","currentElement","nextElementSibling","childClone","child","syncedItems","map","syncInit","sync","clickableResult","processedWrappers","globalConfig","clickable","wrapper","button","link","keptElement","removedElement","hadAttribute","wasLink","addedAttribute","clickableInit","dupeResult","dupeInit","dupe","siteSettingsResult","structure","lists","siteSettings","list","settingSelector","getSelector","clonedElement","hideSelector","hideElement","hideAttr","hide","match","hideValue","filter","c","some","className","contains","settingAttr","setting","settingName","settingText","settingHref","text","Object","keys","body","acceptNode","name","includes","FILTER_ACCEPT","FILTER_SKIP","textNode","newText","hasChanges","placeholder","replacementValue","replace","RegExp","setupSiteSettings","yearReplacementResult","currentYear","Date","getFullYear","toString","currentMonth","getMonth","yearPlaceholder","placeholders","year","monthPlaceholder","month","yearRegex","monthRegex","setupYearReplacement","yearReplacementInit","reverse","destroyFn","error","fn","cleanupError"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){const r=new Map;return{scan:async function(){const t=[],s=e.filter(e=>{const s=document.querySelector(e.selector);return s&&r.has(e.name)?(t.push({name:e.name,status:"already-loaded"}),!1):s}).map(e=>e.import().then(r=>({module:e,moduleExports:r,success:!0})).catch(r=>({module:e,error:r,success:!1}))),o=await Promise.allSettled(s);for(const e of o)if("fulfilled"===e.status&&e.value.success){const{module:s,moduleExports:o}=e.value;try{const{init:e}=o,a=void 0!==s.config?await e(s.config):await e();r.set(s.name,a),t.push({name:s.name,status:"loaded"})}catch(c){const e=c instanceof Error?c.message:String(c);console.error(`[orchestrator] Failed to initialize ${s.name}:`,c),t.push({name:s.name,status:"failed",error:e})}}else if("fulfilled"!==e.status||e.value.success)"rejected"===e.status&&console.error("[orchestrator] Unexpected error:",e.reason);else{const r=e.value,{module:s,error:o}=r,a=o instanceof Error?o.message:String(o);console.error(`[orchestrator] Failed to load ${s.name}:`,o),t.push({name:s.name,status:"failed",error:a})}const a=t.filter(e=>"loaded"===e.status),n=t.filter(e=>"failed"===e.status);return{results:t,loaded:a,failed:n}},destroy:function(){r.forEach((e,r)=>{try{e?.destroy&&e.destroy()}catch(t){console.error(`[orchestrator] Error destroying ${r}:`,t)}}),r.clear()}}}export{e as c};
|
|
2
|
+
//# sourceMappingURL=hs-orchestrator-J8b7XRk1.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){const r=new Map;return{scan:async function(){const t=[],s=e.filter(e=>{const s=document.querySelector(e.selector);return s&&r.has(e.name)?(t.push({name:e.name,status:"already-loaded"}),!1):s}).map(e=>e.import().then(r=>({module:e,moduleExports:r,success:!0})).catch(r=>({module:e,error:r,success:!1}))),o=await Promise.allSettled(s);for(const e of o)if("fulfilled"===e.status&&e.value.success){const{module:s,moduleExports:o}=e.value;try{const{init:e}=o,a=void 0!==s.config?await e(s.config):await e();r.set(s.name,a),t.push({name:s.name,status:"loaded"})}catch(c){const e=c instanceof Error?c.message:String(c);console.error(`[orchestrator] Failed to initialize ${s.name}:`,c),t.push({name:s.name,status:"failed",error:e})}}else if("fulfilled"!==e.status||e.value.success)"rejected"===e.status&&console.error("[orchestrator] Unexpected error:",e.reason);else{const r=e.value,{module:s,error:o}=r,a=o instanceof Error?o.message:String(o);console.error(`[orchestrator] Failed to load ${s.name}:`,o),t.push({name:s.name,status:"failed",error:a})}const a=t.filter(e=>"loaded"===e.status),n=t.filter(e=>"failed"===e.status);return{results:t,loaded:a,failed:n}},destroy:function(){r.forEach((e,r)=>{try{e?.destroy&&e.destroy()}catch(t){console.error(`[orchestrator] Error destroying ${r}:`,t)}}),r.clear()}}}export{e as c};
|
|
2
|
+
//# sourceMappingURL=hs-orchestrator-J8b7XRk1.js.map
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hs-orchestrator-J8b7XRk1.js","sources":["../../src/utils/orchestrator.ts"],"sourcesContent":["/**\n * Orchestrator Utility\n *\n * Generic orchestrator factory for registry-based module loading.\n * Provides consistent scanning, initialization, and cleanup across all orchestrators.\n *\n * Features:\n * - Registry-based module discovery\n * - Prevents duplicate initialization\n * - SPA-friendly rescan support\n * - Automatic cleanup on destroy\n * - Error handling per module\n *\n * Usage:\n * const REGISTRY = [\n * { name: 'counter', selector: '[data-hs-anim=\"counter\"]', import: () => import('./counter.ts') },\n * ];\n *\n * export async function init() {\n * const orchestrator = createOrchestrator(REGISTRY);\n * const results = await orchestrator.scan();\n *\n * return {\n * result: `initialized (${results.loaded.length} active)`,\n * rescan: orchestrator.scan,\n * destroy: orchestrator.destroy,\n * };\n * }\n */\n\nexport interface ModuleRegistryEntry<TConfig = unknown> {\n name: string;\n selector: string;\n import: () => Promise<{ init: (config?: TConfig) => Promise<ModuleInstance> | ModuleInstance }>;\n config?: TConfig;\n}\n\nexport interface ModuleInstance {\n result?: string;\n destroy?: () => void;\n rescan?: () => Promise<unknown>;\n}\n\nexport interface ScanResult {\n name: string;\n status: 'loaded' | 'failed' | 'already-loaded';\n error?: string;\n}\n\nexport interface OrchestratorReturn {\n scan: () => Promise<{ results: ScanResult[]; loaded: ScanResult[]; failed: ScanResult[] }>;\n destroy: () => void;\n}\n\n/**\n * Create an orchestrator for a module registry\n * @param registry - Array of module definitions with selectors and imports\n */\nexport function createOrchestrator(registry: ModuleRegistryEntry[]): OrchestratorReturn {\n const activeModules = new Map<string, ModuleInstance>();\n\n /**\n * Scan DOM and initialize modules that exist on the page\n */\n async function scan() {\n const results: ScanResult[] = [];\n\n // Step 1: Find which modules are on the page\n const modulesToLoad = registry.filter((module) => {\n const exists = document.querySelector(module.selector);\n if (exists && activeModules.has(module.name)) {\n results.push({ name: module.name, status: 'already-loaded' });\n return false; // Already loaded, skip\n }\n return exists;\n });\n\n // Step 2: Download all needed modules in parallel\n const importPromises = modulesToLoad.map((module) =>\n module\n .import()\n .then(\n (moduleExports) =>\n ({ module, moduleExports, success: true }) as {\n module: ModuleRegistryEntry;\n moduleExports: {\n init: (config?: unknown) => Promise<ModuleInstance> | ModuleInstance;\n };\n success: true;\n }\n )\n .catch(\n (error) =>\n ({ module, error, success: false }) as {\n module: ModuleRegistryEntry;\n error: unknown;\n success: false;\n }\n )\n );\n\n const importResults = await Promise.allSettled(importPromises);\n\n // Step 3: Initialize each successfully downloaded module\n for (const result of importResults) {\n if (result.status === 'fulfilled' && result.value.success) {\n // Success case: module downloaded successfully\n const { module, moduleExports } = result.value;\n try {\n const { init } = moduleExports;\n // Call init with config if provided, otherwise call with no args\n const instance = module.config !== undefined ? await init(module.config) : await init();\n activeModules.set(module.name, instance);\n results.push({ name: module.name, status: 'loaded' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(`[orchestrator] Failed to initialize ${module.name}:`, error);\n results.push({ name: module.name, status: 'failed', error: errorMessage });\n }\n } else if (result.status === 'fulfilled' && !result.value.success) {\n // Download failed (caught by import's .catch())\n const value = result.value as {\n module: ModuleRegistryEntry;\n error: unknown;\n success: false;\n };\n const { module, error } = value;\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(`[orchestrator] Failed to load ${module.name}:`, error);\n results.push({ name: module.name, status: 'failed', error: errorMessage });\n } else if (result.status === 'rejected') {\n // Promise itself rejected (shouldn't happen with our catch handler)\n console.error(`[orchestrator] Unexpected error:`, result.reason);\n }\n }\n\n const loaded = results.filter((r) => r.status === 'loaded');\n const failed = results.filter((r) => r.status === 'failed');\n\n return { results, loaded, failed };\n }\n\n /**\n * Destroy all active modules and clear registry\n */\n function destroy() {\n activeModules.forEach((instance, name) => {\n try {\n if (instance?.destroy) {\n instance.destroy();\n }\n } catch (error) {\n console.error(`[orchestrator] Error destroying ${name}:`, error);\n }\n });\n activeModules.clear();\n }\n\n return {\n scan,\n destroy,\n };\n}\n"],"names":["createOrchestrator","registry","activeModules","Map","scan","async","results","importPromises","filter","module","exists","document","querySelector","selector","has","name","push","status","map","import","then","moduleExports","success","catch","error","importResults","Promise","allSettled","result","value","init","instance","config","set","errorMessage","Error","message","String","console","reason","loaded","r","failed","destroy","forEach","clear"],"mappings":"AA0DO,SAASA,EAAmBC,GACjC,MAAMC,MAAoBC,IAmG1B,MAAO,CACLC,KA/FFC,iBACE,MAAMC,EAAwB,GAaxBC,EAVgBN,EAASO,OAAQC,IACrC,MAAMC,EAASC,SAASC,cAAcH,EAAOI,UAC7C,OAAIH,GAAUR,EAAcY,IAAIL,EAAOM,OACrCT,EAAQU,KAAK,CAAED,KAAMN,EAAOM,KAAME,OAAQ,oBACnC,GAEFP,IAI4BQ,IAAKT,GACxCA,EACGU,SACAC,KACEC,IAAA,CACIZ,SAAQY,gBAAeC,SAAS,KAQtCC,MACEC,IAAA,CACIf,SAAQe,QAAOF,SAAS,MAQ7BG,QAAsBC,QAAQC,WAAWpB,GAG/C,IAAA,MAAWqB,KAAUH,EACnB,GAAsB,cAAlBG,EAAOX,QAA0BW,EAAOC,MAAMP,QAAS,CAEzD,MAAMb,OAAEA,EAAAY,cAAQA,GAAkBO,EAAOC,MACzC,IACE,MAAMC,KAAEA,GAAST,EAEXU,OAA6B,IAAlBtB,EAAOuB,aAA6BF,EAAKrB,EAAOuB,cAAgBF,IACjF5B,EAAc+B,IAAIxB,EAAOM,KAAMgB,GAC/BzB,EAAQU,KAAK,CAAED,KAAMN,EAAOM,KAAME,OAAQ,UAC5C,OAASO,GACP,MAAMU,EAAeV,aAAiBW,MAAQX,EAAMY,QAAUC,OAAOb,GACrEc,QAAQd,MAAM,uCAAuCf,EAAOM,QAASS,GACrElB,EAAQU,KAAK,CAAED,KAAMN,EAAOM,KAAME,OAAQ,SAAUO,MAAOU,GAC7D,CACF,SAA6B,cAAlBN,EAAOX,QAA2BW,EAAOC,MAAMP,QAW7B,aAAlBM,EAAOX,QAEhBqB,QAAQd,MAAM,mCAAoCI,EAAOW,YAbQ,CAEjE,MAAMV,EAAQD,EAAOC,OAKfpB,OAAEA,EAAAe,MAAQA,GAAUK,EACpBK,EAAeV,aAAiBW,MAAQX,EAAMY,QAAUC,OAAOb,GACrEc,QAAQd,MAAM,iCAAiCf,EAAOM,QAASS,GAC/DlB,EAAQU,KAAK,CAAED,KAAMN,EAAOM,KAAME,OAAQ,SAAUO,MAAOU,GAC7D,CAMF,MAAMM,EAASlC,EAAQE,OAAQiC,GAAmB,WAAbA,EAAExB,QACjCyB,EAASpC,EAAQE,OAAQiC,GAAmB,WAAbA,EAAExB,QAEvC,MAAO,CAAEX,UAASkC,SAAQE,SAC5B,EAoBEC,QAfF,WACEzC,EAAc0C,QAAQ,CAACb,EAAUhB,KAC/B,IACMgB,GAAUY,SACZZ,EAASY,SAEb,OAASnB,GACPc,QAAQd,MAAM,mCAAmCT,KAASS,EAC5D,IAEFtB,EAAc2C,OAChB,EAMF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{g as e}from"./hs-utils-CKm6QhLw.js";import{q as t,a as n,g as r}from"./hs-attributeSelector-6pGcDBo-.js";import{c as o}from"./hs-cssVariables-BjuwJfDJ.js";import"./hs-modalManager-H_YegPAO.js";import"../main.js";function i(i){const a={observers:[],handlers:[],liveRegions:[]};try{t(i,"wrapper").forEach(t=>{try{const s=function(t,i,a){const s=n(a,"list",t);if(!s)return console.warn("[pagination] Missing required element: list"),null;const l=s.parentElement;if(!l)return null;const c={controls:n(a,"controls",t),counter:n(a,"counter",t),dotsWrap:n(a,"dots",t),nextButton:null,prevButton:null};if(!c.controls)return{initialized:!1};const d=n(a,"next",t),u=n(a,"previous",t),g=r(e.clickable,"button"),p=d?.querySelector(g)||d,h=u?.querySelector(g)||u;if(!p||!h)return console.warn("[pagination] Missing required navigation buttons"),null;c.nextButton=p,c.prevButton=h,c.nextButton.setAttribute("aria-label","Go to next page"),c.prevButton.setAttribute("aria-label","Go to previous page"),c.counter&&(c.counter.setAttribute("aria-live","polite"),c.counter.setAttribute("aria-label","Current page"));const m=parseInt(c.controls?.getAttribute(a.attributes.properties.show)||"6")||6,v=parseInt(c.controls?.getAttribute(a.attributes.properties.showMobile)||String(m))||m,f=()=>getComputedStyle(s).getPropertyValue(o.state).trim()===e.cssVars.state.values.active,b=Array.from(s.children),y=b.length;if(!y)return null;const P={totalPages:1,currentIndex:1,currentPage:1,isAnimating:!1,itemsPerPage:m,dotTemplates:{active:null,inactive:null}};let A=[];const x=document.createElement("div");x.className="sr-only",x.setAttribute("aria-live","assertive"),x.setAttribute("aria-atomic","true"),x.style.cssText="position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden;",t.appendChild(x),i.liveRegions.push(x);const E=()=>{c.counter&&(c.counter.textContent=`${P.currentPage} / ${P.totalPages}`)},w=()=>{x.textContent=`Page ${P.currentPage} of ${P.totalPages}`,setTimeout(()=>x.textContent="",1e3)},T=()=>{A.forEach((e,t)=>{const n=e;t===P.currentIndex?n.removeAttribute("inert"):n.setAttribute("inert","")})},C=()=>{const e=A[P.currentIndex];e&&void 0!==e.offsetHeight&&(l.style.height=e.offsetHeight+"px")},I=()=>{if(!c.dotsWrap)return;const e=Array.from(c.dotsWrap.children);if(!e.length)return;const t=e.find(e=>e.classList.contains("is-active")),n=e.find(e=>!e.classList.contains("is-active"));P.dotTemplates.active=t?t.cloneNode(!0):e[0].cloneNode(!0),P.dotTemplates.inactive=n?n.cloneNode(!0):e[0].cloneNode(!0),c.dotsWrap.innerHTML="",c.dotsWrap.setAttribute("role","group"),c.dotsWrap.setAttribute("aria-label","Page navigation");for(let r=1;r<=P.totalPages;r++){const e=(1===r?P.dotTemplates.active:P.dotTemplates.inactive).cloneNode(!0);e.setAttribute("role","button"),e.setAttribute("tabindex","0"),e.setAttribute("aria-label",`Go to page ${r}`),e.setAttribute("aria-current",1===r?"page":"false"),e.setAttribute("data-page",String(r)),1===r?e.classList.add("is-active"):e.classList.remove("is-active");const t=()=>k(r);e.addEventListener("click",t),i.handlers.push({element:e,event:"click",handler:t});const n=e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),k(r))};e.addEventListener("keydown",n),i.handlers.push({element:e,event:"keydown",handler:n}),c.dotsWrap.appendChild(e)}},L=()=>{if(!c.dotsWrap)return;Array.from(c.dotsWrap.children).forEach((e,t)=>{t+1===P.currentPage?(e.classList.add("is-active"),e.setAttribute("aria-current","page")):(e.classList.remove("is-active"),e.setAttribute("aria-current","false"))})},W=(e=null)=>{const t=f();if(P.itemsPerPage=e||(t?v:m),P.totalPages=Math.ceil(y/P.itemsPerPage),c.dotsWrap&&(i.handlers=i.handlers.filter(({element:e})=>!c.dotsWrap.contains(e))),Array.from(l.children).forEach(e=>{e!==s&&l.removeChild(e)}),s.innerHTML="",b.forEach(e=>s.appendChild(e)),P.totalPages<=1)return c.controls&&(c.controls.contains(document.activeElement)&&document.activeElement&&document.activeElement.blur(),c.controls.style.display="none",c.controls.setAttribute("aria-hidden","true")),c.dotsWrap&&(c.dotsWrap.style.display="none",c.dotsWrap.setAttribute("aria-hidden","true")),Object.assign(P,{totalPages:1,currentIndex:1,currentPage:1,isAnimating:!1}),l.style.cssText=`transform: translateX(0%); height: ${s.offsetHeight}px;`,A=[s],1;c.controls&&(c.controls.style.display="",c.controls.removeAttribute("aria-hidden")),c.dotsWrap&&(c.dotsWrap.style.display="",c.dotsWrap.removeAttribute("aria-hidden"));const n=Array.from({length:P.totalPages},(e,t)=>{const n=s.cloneNode(!1),r=t*P.itemsPerPage,o=Math.min(r+P.itemsPerPage,y);return b.slice(r,o).forEach(e=>n.appendChild(e.cloneNode(!0))),n});return l.insertBefore(n[n.length-1].cloneNode(!0),s),n.slice(1).forEach(e=>l.appendChild(e)),l.appendChild(n[0].cloneNode(!0)),s.innerHTML="",Array.from(n[0].children).forEach(e=>s.appendChild(e)),Object.assign(P,{currentIndex:1,currentPage:1,isAnimating:!1}),A=Array.from(l.children),l.style.transform="translateX(-100%)",E(),C(),T(),I(),P.totalPages};let B=f();const N=new ResizeObserver(()=>{if(P.isAnimating)return;const e=f();e!==B?(B=e,W()):C()});N.observe(l),i.observers.push(N),W();const k=e=>{if(P.isAnimating||P.totalPages<=1||e===P.currentPage)return;P.isAnimating=!0,P.currentIndex=e,P.currentPage=e,E(),w(),C(),L(),f()&&c.controls&&setTimeout(()=>{const e=80,t=c.controls.getBoundingClientRect().bottom+window.pageYOffset-window.innerHeight+e;window.scrollTo({top:t,behavior:"smooth"})},50),l.style.transform=`translateX(${100*-P.currentIndex}%)`;let t=null;const n=()=>{clearTimeout(t),l.removeEventListener("transitionend",n),E(),w(),C(),T(),L(),P.isAnimating=!1};t=setTimeout(n,1e3),l.addEventListener("transitionend",n)},H=e=>{if(P.isAnimating||P.totalPages<=1)return;P.isAnimating=!0,P.currentIndex+=e,P.currentPage=P.currentIndex>P.totalPages?1:P.currentIndex<1?P.totalPages:P.currentIndex,E(),w(),C(),L(),f()&&c.controls&&setTimeout(()=>{const e=80,t=c.controls.getBoundingClientRect().bottom+window.pageYOffset-window.innerHeight+e;window.scrollTo({top:t,behavior:"smooth"})},50),l.style.transform=`translateX(${100*-P.currentIndex}%)`;let t=null;const n=()=>{clearTimeout(t),l.removeEventListener("transitionend",n),P.currentIndex>P.totalPages?(P.currentIndex=1,P.currentPage=1,l.style.transition="none",l.style.transform="translateX(-100%)",l.offsetHeight,l.style.transition=""):P.currentIndex<1&&(P.currentIndex=P.totalPages,P.currentPage=P.totalPages,l.style.transition="none",l.style.transform=`translateX(${100*-P.totalPages}%)`,l.offsetHeight,l.style.transition=""),E(),w(),C(),T(),L(),P.isAnimating=!1};t=setTimeout(n,1e3),l.addEventListener("transitionend",n)},M=()=>H(1),$=()=>H(-1);return c.nextButton.addEventListener("click",M),c.prevButton.addEventListener("click",$),i.handlers.push({element:c.nextButton,event:"click",handler:M},{element:c.prevButton,event:"click",handler:$}),{initialized:!0}}(t,a,i);s||console.warn("[pagination] Failed to initialize container",t)}catch(s){console.error("[pagination] Error initializing container:",s,t)}})}catch(s){console.error("[pagination] Critical error during initialization:",s)}return{result:"pagination initialized",destroy:()=>{try{a.liveRegions.forEach(e=>{try{e.parentNode&&e.parentNode.removeChild(e)}catch(s){console.error("[pagination] Error removing live region:",s)}}),a.liveRegions.length=0,a.observers.forEach(e=>{try{e.disconnect()}catch(s){console.error("[pagination] Error disconnecting observer:",s)}}),a.observers.length=0,a.handlers.forEach(({element:e,event:t,handler:n})=>{try{e.removeEventListener(t,n)}catch(s){console.error("[pagination] Error removing event listener:",s)}}),a.handlers.length=0}catch(s){console.error("[pagination] Critical error during cleanup:",s)}}}}export{i as init};
|
|
2
|
+
//# sourceMappingURL=hs-pagination-DcOxmDPJ.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{g as e}from"./hs-utils-CKm6QhLw.js";import{q as t,a as n,g as r}from"./hs-attributeSelector-6pGcDBo-.js";import{c as o}from"./hs-cssVariables-BjuwJfDJ.js";import"./hs-modalManager-H_YegPAO.js";import"../main.js";function i(i){const a={observers:[],handlers:[],liveRegions:[]};try{t(i,"wrapper").forEach(t=>{try{const s=function(t,i,a){const s=n(a,"list",t);if(!s)return console.warn("[pagination] Missing required element: list"),null;const l=s.parentElement;if(!l)return null;const c={controls:n(a,"controls",t),counter:n(a,"counter",t),dotsWrap:n(a,"dots",t),nextButton:null,prevButton:null};if(!c.controls)return{initialized:!1};const d=n(a,"next",t),u=n(a,"previous",t),g=r(e.clickable,"button"),p=d?.querySelector(g)||d,h=u?.querySelector(g)||u;if(!p||!h)return console.warn("[pagination] Missing required navigation buttons"),null;c.nextButton=p,c.prevButton=h,c.nextButton.setAttribute("aria-label","Go to next page"),c.prevButton.setAttribute("aria-label","Go to previous page"),c.counter&&(c.counter.setAttribute("aria-live","polite"),c.counter.setAttribute("aria-label","Current page"));const m=parseInt(c.controls?.getAttribute(a.attributes.properties.show)||"6")||6,v=parseInt(c.controls?.getAttribute(a.attributes.properties.showMobile)||String(m))||m,f=()=>getComputedStyle(s).getPropertyValue(o.state).trim()===e.cssVars.state.values.active,b=Array.from(s.children),y=b.length;if(!y)return null;const P={totalPages:1,currentIndex:1,currentPage:1,isAnimating:!1,itemsPerPage:m,dotTemplates:{active:null,inactive:null}};let A=[];const x=document.createElement("div");x.className="sr-only",x.setAttribute("aria-live","assertive"),x.setAttribute("aria-atomic","true"),x.style.cssText="position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden;",t.appendChild(x),i.liveRegions.push(x);const E=()=>{c.counter&&(c.counter.textContent=`${P.currentPage} / ${P.totalPages}`)},w=()=>{x.textContent=`Page ${P.currentPage} of ${P.totalPages}`,setTimeout(()=>x.textContent="",1e3)},T=()=>{A.forEach((e,t)=>{const n=e;t===P.currentIndex?n.removeAttribute("inert"):n.setAttribute("inert","")})},C=()=>{const e=A[P.currentIndex];e&&void 0!==e.offsetHeight&&(l.style.height=e.offsetHeight+"px")},I=()=>{if(!c.dotsWrap)return;const e=Array.from(c.dotsWrap.children);if(!e.length)return;const t=e.find(e=>e.classList.contains("is-active")),n=e.find(e=>!e.classList.contains("is-active"));P.dotTemplates.active=t?t.cloneNode(!0):e[0].cloneNode(!0),P.dotTemplates.inactive=n?n.cloneNode(!0):e[0].cloneNode(!0),c.dotsWrap.innerHTML="",c.dotsWrap.setAttribute("role","group"),c.dotsWrap.setAttribute("aria-label","Page navigation");for(let r=1;r<=P.totalPages;r++){const e=(1===r?P.dotTemplates.active:P.dotTemplates.inactive).cloneNode(!0);e.setAttribute("role","button"),e.setAttribute("tabindex","0"),e.setAttribute("aria-label",`Go to page ${r}`),e.setAttribute("aria-current",1===r?"page":"false"),e.setAttribute("data-page",String(r)),1===r?e.classList.add("is-active"):e.classList.remove("is-active");const t=()=>k(r);e.addEventListener("click",t),i.handlers.push({element:e,event:"click",handler:t});const n=e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),k(r))};e.addEventListener("keydown",n),i.handlers.push({element:e,event:"keydown",handler:n}),c.dotsWrap.appendChild(e)}},L=()=>{if(!c.dotsWrap)return;Array.from(c.dotsWrap.children).forEach((e,t)=>{t+1===P.currentPage?(e.classList.add("is-active"),e.setAttribute("aria-current","page")):(e.classList.remove("is-active"),e.setAttribute("aria-current","false"))})},W=(e=null)=>{const t=f();if(P.itemsPerPage=e||(t?v:m),P.totalPages=Math.ceil(y/P.itemsPerPage),c.dotsWrap&&(i.handlers=i.handlers.filter(({element:e})=>!c.dotsWrap.contains(e))),Array.from(l.children).forEach(e=>{e!==s&&l.removeChild(e)}),s.innerHTML="",b.forEach(e=>s.appendChild(e)),P.totalPages<=1)return c.controls&&(c.controls.contains(document.activeElement)&&document.activeElement&&document.activeElement.blur(),c.controls.style.display="none",c.controls.setAttribute("aria-hidden","true")),c.dotsWrap&&(c.dotsWrap.style.display="none",c.dotsWrap.setAttribute("aria-hidden","true")),Object.assign(P,{totalPages:1,currentIndex:1,currentPage:1,isAnimating:!1}),l.style.cssText=`transform: translateX(0%); height: ${s.offsetHeight}px;`,A=[s],1;c.controls&&(c.controls.style.display="",c.controls.removeAttribute("aria-hidden")),c.dotsWrap&&(c.dotsWrap.style.display="",c.dotsWrap.removeAttribute("aria-hidden"));const n=Array.from({length:P.totalPages},(e,t)=>{const n=s.cloneNode(!1),r=t*P.itemsPerPage,o=Math.min(r+P.itemsPerPage,y);return b.slice(r,o).forEach(e=>n.appendChild(e.cloneNode(!0))),n});return l.insertBefore(n[n.length-1].cloneNode(!0),s),n.slice(1).forEach(e=>l.appendChild(e)),l.appendChild(n[0].cloneNode(!0)),s.innerHTML="",Array.from(n[0].children).forEach(e=>s.appendChild(e)),Object.assign(P,{currentIndex:1,currentPage:1,isAnimating:!1}),A=Array.from(l.children),l.style.transform="translateX(-100%)",E(),C(),T(),I(),P.totalPages};let B=f();const N=new ResizeObserver(()=>{if(P.isAnimating)return;const e=f();e!==B?(B=e,W()):C()});N.observe(l),i.observers.push(N),W();const k=e=>{if(P.isAnimating||P.totalPages<=1||e===P.currentPage)return;P.isAnimating=!0,P.currentIndex=e,P.currentPage=e,E(),w(),C(),L(),f()&&c.controls&&setTimeout(()=>{const e=80,t=c.controls.getBoundingClientRect().bottom+window.pageYOffset-window.innerHeight+e;window.scrollTo({top:t,behavior:"smooth"})},50),l.style.transform=`translateX(${100*-P.currentIndex}%)`;let t=null;const n=()=>{clearTimeout(t),l.removeEventListener("transitionend",n),E(),w(),C(),T(),L(),P.isAnimating=!1};t=setTimeout(n,1e3),l.addEventListener("transitionend",n)},H=e=>{if(P.isAnimating||P.totalPages<=1)return;P.isAnimating=!0,P.currentIndex+=e,P.currentPage=P.currentIndex>P.totalPages?1:P.currentIndex<1?P.totalPages:P.currentIndex,E(),w(),C(),L(),f()&&c.controls&&setTimeout(()=>{const e=80,t=c.controls.getBoundingClientRect().bottom+window.pageYOffset-window.innerHeight+e;window.scrollTo({top:t,behavior:"smooth"})},50),l.style.transform=`translateX(${100*-P.currentIndex}%)`;let t=null;const n=()=>{clearTimeout(t),l.removeEventListener("transitionend",n),P.currentIndex>P.totalPages?(P.currentIndex=1,P.currentPage=1,l.style.transition="none",l.style.transform="translateX(-100%)",l.offsetHeight,l.style.transition=""):P.currentIndex<1&&(P.currentIndex=P.totalPages,P.currentPage=P.totalPages,l.style.transition="none",l.style.transform=`translateX(${100*-P.totalPages}%)`,l.offsetHeight,l.style.transition=""),E(),w(),C(),T(),L(),P.isAnimating=!1};t=setTimeout(n,1e3),l.addEventListener("transitionend",n)},M=()=>H(1),$=()=>H(-1);return c.nextButton.addEventListener("click",M),c.prevButton.addEventListener("click",$),i.handlers.push({element:c.nextButton,event:"click",handler:M},{element:c.prevButton,event:"click",handler:$}),{initialized:!0}}(t,a,i);s||console.warn("[pagination] Failed to initialize container",t)}catch(s){console.error("[pagination] Error initializing container:",s,t)}})}catch(s){console.error("[pagination] Critical error during initialization:",s)}return{result:"pagination initialized",destroy:()=>{try{a.liveRegions.forEach(e=>{try{e.parentNode&&e.parentNode.removeChild(e)}catch(s){console.error("[pagination] Error removing live region:",s)}}),a.liveRegions.length=0,a.observers.forEach(e=>{try{e.disconnect()}catch(s){console.error("[pagination] Error disconnecting observer:",s)}}),a.observers.length=0,a.handlers.forEach(({element:e,event:t,handler:n})=>{try{e.removeEventListener(t,n)}catch(s){console.error("[pagination] Error removing event listener:",s)}}),a.handlers.length=0}catch(s){console.error("[pagination] Critical error during cleanup:",s)}}}}export{i as init};
|
|
2
|
+
//# sourceMappingURL=hs-pagination-DcOxmDPJ.js.map
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hs-pagination-DcOxmDPJ.js","sources":["../../src/modules/structure/functions/pagination.ts"],"sourcesContent":["/**\n * Pagination\n *\n * Paginated lists with controls, counters, and dot navigation.\n * Supports infinite looping, mobile/desktop layouts, and full accessibility.\n *\n * Features:\n * - Infinite loop navigation with cloned pages\n * - Responsive items-per-page (desktop/mobile breakpoints)\n * - Dot navigation with keyboard support\n * - Live region announcements for screen readers\n * - Auto-hide controls for single page\n * - Dynamic height adjustment\n * - Focus management with inert attribute\n *\n * HTML Structure:\n * <div data-hs-pagination=\"wrapper\">\n * <div data-hs-pagination=\"list\">\n * <!-- Items here -->\n * </div>\n * <div data-hs-pagination=\"controls\" data-hs-pagination-show=\"6\" data-hs-pagination-show-mobile=\"3\">\n * <div data-hs-pagination=\"previous\"><button>Prev</button></div>\n * <div data-hs-pagination=\"counter\"></div>\n * <div data-hs-pagination=\"next\"><button>Next</button></div>\n * </div>\n * <div data-hs-pagination=\"dots\">\n * <div class=\"is-active\">•</div>\n * <div>•</div>\n * </div>\n * </div>\n */\n\nimport { querySelectorAll, querySelector, getSelector, globalConfig, cssVariables } from '@utils';\n\nexport function init(config) {\n const cleanup = {\n observers: [] as ResizeObserver[],\n handlers: [] as Array<{ element: Element; event: string; handler: EventListener }>,\n liveRegions: [] as HTMLElement[],\n };\n\n // Initialize all pagination containers\n try {\n querySelectorAll(config, 'wrapper').forEach((container) => {\n try {\n const instance = initPaginationInstance(container, cleanup, config);\n if (!instance) {\n console.warn('[pagination] Failed to initialize container', container);\n }\n } catch (error) {\n console.error('[pagination] Error initializing container:', error, container);\n }\n });\n } catch (error) {\n console.error('[pagination] Critical error during initialization:', error);\n }\n\n return {\n result: 'pagination initialized',\n destroy: () => {\n try {\n // Remove all live regions\n cleanup.liveRegions.forEach((liveRegion) => {\n try {\n if (liveRegion.parentNode) {\n liveRegion.parentNode.removeChild(liveRegion);\n }\n } catch (error) {\n console.error('[pagination] Error removing live region:', error);\n }\n });\n cleanup.liveRegions.length = 0;\n\n // Disconnect all observers\n cleanup.observers.forEach((obs) => {\n try {\n obs.disconnect();\n } catch (error) {\n console.error('[pagination] Error disconnecting observer:', error);\n }\n });\n cleanup.observers.length = 0;\n\n // Remove all event listeners\n cleanup.handlers.forEach(({ element, event, handler }) => {\n try {\n element.removeEventListener(event, handler);\n } catch (error) {\n console.error('[pagination] Error removing event listener:', error);\n }\n });\n cleanup.handlers.length = 0;\n } catch (error) {\n console.error('[pagination] Critical error during cleanup:', error);\n }\n },\n };\n}\n\nfunction initPaginationInstance(\n container: Element,\n cleanup: {\n observers: ResizeObserver[];\n handlers: Array<{ element: Element; event: string; handler: EventListener }>;\n liveRegions: HTMLElement[];\n },\n config: any\n) {\n const list = querySelector(config, 'list', container) as HTMLElement;\n if (!list) {\n console.warn('[pagination] Missing required element: list');\n return null;\n }\n\n const wrapper = list.parentElement as HTMLElement;\n if (!wrapper) return null;\n\n const elements = {\n controls: querySelector(config, 'controls', container) as HTMLElement | null,\n counter: querySelector(config, 'counter', container) as HTMLElement | null,\n dotsWrap: querySelector(config, 'dots', container) as HTMLElement | null,\n nextButton: null as HTMLElement | null,\n prevButton: null as HTMLElement | null,\n };\n\n // Early exit for infinite mode - no controls means no pagination\n if (!elements.controls) {\n return { initialized: false };\n }\n\n // Find next/previous buttons using clickable pattern\n const nextClickable = querySelector(config, 'next', container);\n const prevClickable = querySelector(config, 'previous', container);\n\n const clickableSelector = getSelector(\n globalConfig.clickable as {\n attributes: { elements: { [key: string]: { primary: string; aliases?: string[] } } };\n },\n 'button'\n );\n const nextButton = (nextClickable?.querySelector(clickableSelector) ||\n nextClickable) as HTMLElement | null;\n const prevButton = (prevClickable?.querySelector(clickableSelector) ||\n prevClickable) as HTMLElement | null;\n\n if (!nextButton || !prevButton) {\n console.warn('[pagination] Missing required navigation buttons');\n return null;\n }\n\n elements.nextButton = nextButton;\n elements.prevButton = prevButton;\n\n // Add ARIA attributes to buttons\n elements.nextButton.setAttribute('aria-label', 'Go to next page');\n elements.prevButton.setAttribute('aria-label', 'Go to previous page');\n if (elements.counter) {\n elements.counter.setAttribute('aria-live', 'polite');\n elements.counter.setAttribute('aria-label', 'Current page');\n }\n\n // Parse configuration from attributes\n const desktopItems =\n parseInt(elements.controls?.getAttribute(config.attributes.properties.show) || '6') || 6;\n const mobileItems =\n parseInt(\n elements.controls?.getAttribute(config.attributes.properties.showMobile) ||\n String(desktopItems)\n ) || desktopItems;\n\n const isMobileLayout = () => {\n const stateValue = getComputedStyle(list).getPropertyValue(cssVariables.state).trim();\n return stateValue === globalConfig.cssVars.state.values.active;\n };\n\n const allItems = Array.from(list.children) as HTMLElement[];\n const totalItems = allItems.length;\n if (!totalItems) return null;\n\n const state = {\n totalPages: 1,\n currentIndex: 1,\n currentPage: 1,\n isAnimating: false,\n itemsPerPage: desktopItems,\n dotTemplates: { active: null as Element | null, inactive: null as Element | null },\n };\n let wrapperChildren: Element[] = [];\n\n // Create live region for announcements\n const liveRegion = document.createElement('div');\n liveRegion.className = 'sr-only';\n liveRegion.setAttribute('aria-live', 'assertive');\n liveRegion.setAttribute('aria-atomic', 'true');\n liveRegion.style.cssText =\n 'position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden;';\n container.appendChild(liveRegion);\n cleanup.liveRegions.push(liveRegion);\n\n const updateCounter = () => {\n if (elements.counter) {\n elements.counter.textContent = `${state.currentPage} / ${state.totalPages}`;\n }\n };\n\n const announcePageChange = () => {\n liveRegion.textContent = `Page ${state.currentPage} of ${state.totalPages}`;\n setTimeout(() => (liveRegion.textContent = ''), 1000);\n };\n\n const manageFocus = () => {\n wrapperChildren.forEach((page, index) => {\n const htmlPage = page as HTMLElement;\n if (index === state.currentIndex) {\n htmlPage.removeAttribute('inert');\n } else {\n htmlPage.setAttribute('inert', '');\n }\n });\n };\n\n const updateHeight = () => {\n const targetPage = wrapperChildren[state.currentIndex] as HTMLElement;\n if (targetPage && targetPage.offsetHeight !== undefined) {\n wrapper.style.height = targetPage.offsetHeight + 'px';\n }\n };\n\n const initializeDots = () => {\n if (!elements.dotsWrap) return;\n\n // Find existing dots as templates\n const existingDots = Array.from(elements.dotsWrap.children);\n if (!existingDots.length) return;\n\n // Identify active and inactive templates\n const activeDot = existingDots.find((dot) => dot.classList.contains('is-active'));\n const inactiveDot = existingDots.find((dot) => !dot.classList.contains('is-active'));\n\n // Store templates (use same template for both if only one exists)\n state.dotTemplates.active = activeDot\n ? (activeDot.cloneNode(true) as Element)\n : (existingDots[0].cloneNode(true) as Element);\n state.dotTemplates.inactive = inactiveDot\n ? (inactiveDot.cloneNode(true) as Element)\n : (existingDots[0].cloneNode(true) as Element);\n\n // Clear existing dots\n elements.dotsWrap.innerHTML = '';\n\n // Add pagination accessibility attributes\n elements.dotsWrap.setAttribute('role', 'group');\n elements.dotsWrap.setAttribute('aria-label', 'Page navigation');\n\n // Create dots for each page\n for (let i = 1; i <= state.totalPages; i++) {\n const dot = (i === 1 ? state.dotTemplates.active : state.dotTemplates.inactive)!.cloneNode(\n true\n ) as HTMLElement;\n\n // Add accessibility attributes\n dot.setAttribute('role', 'button');\n dot.setAttribute('tabindex', '0');\n dot.setAttribute('aria-label', `Go to page ${i}`);\n dot.setAttribute('aria-current', i === 1 ? 'page' : 'false');\n dot.setAttribute('data-page', String(i));\n\n // Set initial active state\n if (i === 1) {\n dot.classList.add('is-active');\n } else {\n dot.classList.remove('is-active');\n }\n\n // Click handler\n const clickHandler = () => navigateToPage(i);\n dot.addEventListener('click', clickHandler);\n cleanup.handlers.push({ element: dot, event: 'click', handler: clickHandler });\n\n // Keyboard handler\n const keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateToPage(i);\n }\n };\n dot.addEventListener('keydown', keyHandler as EventListener);\n cleanup.handlers.push({\n element: dot,\n event: 'keydown',\n handler: keyHandler as EventListener,\n });\n\n elements.dotsWrap.appendChild(dot);\n }\n };\n\n const updateActiveDot = () => {\n if (!elements.dotsWrap) return;\n\n const dots = Array.from(elements.dotsWrap.children);\n dots.forEach((dot, index) => {\n const dotPage = index + 1;\n if (dotPage === state.currentPage) {\n dot.classList.add('is-active');\n dot.setAttribute('aria-current', 'page');\n } else {\n dot.classList.remove('is-active');\n dot.setAttribute('aria-current', 'false');\n }\n });\n };\n\n const initializePagination = (forceItemsPerPage: number | null = null) => {\n const currentIsMobile = isMobileLayout();\n state.itemsPerPage = forceItemsPerPage || (currentIsMobile ? mobileItems : desktopItems);\n state.totalPages = Math.ceil(totalItems / state.itemsPerPage);\n\n // Remove old dot event handlers to prevent memory leaks\n if (elements.dotsWrap) {\n cleanup.handlers = cleanup.handlers.filter(({ element }) => {\n return !elements.dotsWrap!.contains(element);\n });\n }\n\n // Clean up previous page lists\n Array.from(wrapper.children).forEach((child) => {\n if (child !== list) wrapper.removeChild(child);\n });\n list.innerHTML = '';\n allItems.forEach((item) => list.appendChild(item));\n\n // Single page case\n if (state.totalPages <= 1) {\n if (elements.controls) {\n if (elements.controls.contains(document.activeElement) && document.activeElement) {\n (document.activeElement as HTMLElement).blur();\n }\n elements.controls.style.display = 'none';\n elements.controls.setAttribute('aria-hidden', 'true');\n }\n if (elements.dotsWrap) {\n elements.dotsWrap.style.display = 'none';\n elements.dotsWrap.setAttribute('aria-hidden', 'true');\n }\n Object.assign(state, { totalPages: 1, currentIndex: 1, currentPage: 1, isAnimating: false });\n wrapper.style.cssText = `transform: translateX(0%); height: ${list.offsetHeight}px;`;\n wrapperChildren = [list];\n return 1;\n }\n\n // Show controls and dots\n if (elements.controls) {\n elements.controls.style.display = '';\n elements.controls.removeAttribute('aria-hidden');\n }\n if (elements.dotsWrap) {\n elements.dotsWrap.style.display = '';\n elements.dotsWrap.removeAttribute('aria-hidden');\n }\n\n // Create page lists\n const pageLists = Array.from({ length: state.totalPages }, (_, page) => {\n const pageList = list.cloneNode(false) as HTMLElement;\n const startIndex = page * state.itemsPerPage;\n const endIndex = Math.min(startIndex + state.itemsPerPage, totalItems);\n allItems\n .slice(startIndex, endIndex)\n .forEach((item) => pageList.appendChild(item.cloneNode(true)));\n return pageList;\n });\n\n // Insert cloned pages for infinite loop\n wrapper.insertBefore(pageLists[pageLists.length - 1].cloneNode(true), list);\n pageLists.slice(1).forEach((page) => wrapper.appendChild(page));\n wrapper.appendChild(pageLists[0].cloneNode(true));\n\n // Populate original list with first page\n list.innerHTML = '';\n Array.from(pageLists[0].children).forEach((item) => list.appendChild(item as Node));\n\n Object.assign(state, { currentIndex: 1, currentPage: 1, isAnimating: false });\n wrapperChildren = Array.from(wrapper.children);\n wrapper.style.transform = 'translateX(-100%)';\n\n updateCounter();\n updateHeight();\n manageFocus();\n initializeDots();\n return state.totalPages;\n };\n\n let currentLayoutIsMobile = isMobileLayout();\n\n const checkLayoutChange = () => {\n // Prevent resize during animation\n if (state.isAnimating) return;\n\n const newIsMobile = isMobileLayout();\n if (newIsMobile !== currentLayoutIsMobile) {\n currentLayoutIsMobile = newIsMobile;\n initializePagination();\n } else {\n updateHeight();\n }\n };\n\n const resizeObserver = new ResizeObserver(checkLayoutChange);\n resizeObserver.observe(wrapper);\n cleanup.observers.push(resizeObserver);\n\n initializePagination();\n\n const navigateToPage = (targetPage: number) => {\n if (state.isAnimating || state.totalPages <= 1 || targetPage === state.currentPage) return;\n state.isAnimating = true;\n\n state.currentIndex = targetPage;\n state.currentPage = targetPage;\n\n updateCounter();\n announcePageChange();\n updateHeight();\n updateActiveDot();\n\n if (isMobileLayout() && elements.controls) {\n setTimeout(() => {\n const controlsBottom =\n elements.controls.getBoundingClientRect().bottom + window.pageYOffset;\n const clearance = 5 * 16; // 5rem in pixels\n const targetScrollPosition = controlsBottom - window.innerHeight + clearance;\n window.scrollTo({ top: targetScrollPosition, behavior: 'smooth' });\n }, 50);\n }\n\n wrapper.style.transform = `translateX(${-state.currentIndex * 100}%)`;\n\n let transitionTimeout = null;\n\n const handleTransitionEnd = () => {\n clearTimeout(transitionTimeout);\n wrapper.removeEventListener('transitionend', handleTransitionEnd);\n\n updateCounter();\n announcePageChange();\n updateHeight();\n manageFocus();\n updateActiveDot();\n state.isAnimating = false;\n };\n\n // Safety timeout in case transitionend never fires\n transitionTimeout = setTimeout(handleTransitionEnd, 1000);\n\n wrapper.addEventListener('transitionend', handleTransitionEnd);\n };\n\n const navigate = (direction: number) => {\n if (state.isAnimating || state.totalPages <= 1) return;\n state.isAnimating = true;\n state.currentIndex += direction;\n\n state.currentPage =\n state.currentIndex > state.totalPages\n ? 1\n : state.currentIndex < 1\n ? state.totalPages\n : state.currentIndex;\n\n updateCounter();\n announcePageChange();\n updateHeight();\n updateActiveDot();\n\n if (isMobileLayout() && elements.controls) {\n setTimeout(() => {\n const controlsBottom =\n elements.controls.getBoundingClientRect().bottom + window.pageYOffset;\n const clearance = 5 * 16; // 5rem in pixels\n const targetScrollPosition = controlsBottom - window.innerHeight + clearance;\n window.scrollTo({ top: targetScrollPosition, behavior: 'smooth' });\n }, 50);\n }\n\n wrapper.style.transform = `translateX(${-state.currentIndex * 100}%)`;\n\n let transitionTimeout = null;\n\n const handleTransitionEnd = () => {\n clearTimeout(transitionTimeout);\n wrapper.removeEventListener('transitionend', handleTransitionEnd);\n\n if (state.currentIndex > state.totalPages) {\n state.currentIndex = 1;\n state.currentPage = 1;\n // Disable transition for instant jump\n wrapper.style.transition = 'none';\n wrapper.style.transform = 'translateX(-100%)';\n // Force reflow to apply the instant jump\n wrapper.offsetHeight;\n // Re-enable CSS transition\n wrapper.style.transition = '';\n } else if (state.currentIndex < 1) {\n state.currentIndex = state.totalPages;\n state.currentPage = state.totalPages;\n // Disable transition for instant jump\n wrapper.style.transition = 'none';\n wrapper.style.transform = `translateX(${-state.totalPages * 100}%)`;\n // Force reflow to apply the instant jump\n wrapper.offsetHeight;\n // Re-enable CSS transition\n wrapper.style.transition = '';\n }\n\n updateCounter();\n announcePageChange();\n updateHeight();\n manageFocus();\n updateActiveDot();\n state.isAnimating = false;\n };\n\n // Safety timeout in case transitionend never fires\n transitionTimeout = setTimeout(handleTransitionEnd, 1000);\n\n wrapper.addEventListener('transitionend', handleTransitionEnd);\n };\n\n const nextHandler = () => navigate(1);\n const prevHandler = () => navigate(-1);\n\n elements.nextButton.addEventListener('click', nextHandler);\n elements.prevButton.addEventListener('click', prevHandler);\n\n cleanup.handlers.push(\n { element: elements.nextButton, event: 'click', handler: nextHandler },\n { element: elements.prevButton, event: 'click', handler: prevHandler }\n );\n\n return { initialized: true };\n}\n"],"names":["init","config","cleanup","observers","handlers","liveRegions","querySelectorAll","forEach","container","instance","list","querySelector","console","warn","wrapper","parentElement","elements","controls","counter","dotsWrap","nextButton","prevButton","initialized","nextClickable","prevClickable","clickableSelector","getSelector","globalConfig","clickable","setAttribute","desktopItems","parseInt","getAttribute","attributes","properties","show","mobileItems","showMobile","String","isMobileLayout","getComputedStyle","getPropertyValue","cssVariables","state","trim","cssVars","values","active","allItems","Array","from","children","totalItems","length","totalPages","currentIndex","currentPage","isAnimating","itemsPerPage","dotTemplates","inactive","wrapperChildren","liveRegion","document","createElement","className","style","cssText","appendChild","push","updateCounter","textContent","announcePageChange","setTimeout","manageFocus","page","index","htmlPage","removeAttribute","updateHeight","targetPage","offsetHeight","height","initializeDots","existingDots","activeDot","find","dot","classList","contains","inactiveDot","cloneNode","innerHTML","i","add","remove","clickHandler","navigateToPage","addEventListener","element","event","handler","keyHandler","e","key","preventDefault","updateActiveDot","initializePagination","forceItemsPerPage","currentIsMobile","Math","ceil","filter","child","removeChild","item","activeElement","blur","display","Object","assign","pageLists","_","pageList","startIndex","endIndex","min","slice","insertBefore","transform","currentLayoutIsMobile","resizeObserver","ResizeObserver","newIsMobile","observe","clearance","targetScrollPosition","getBoundingClientRect","bottom","window","pageYOffset","innerHeight","scrollTo","top","behavior","transitionTimeout","handleTransitionEnd","clearTimeout","removeEventListener","navigate","direction","transition","nextHandler","prevHandler","initPaginationInstance","error","result","destroy","parentNode","obs","disconnect"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/hs-toc-fxIQS7tz.js","main.js","assets/hs-attributeSelector-6pGcDBo-.js","assets/hs-modalManager-H_YegPAO.js","assets/hs-pagination-DcOxmDPJ.js","assets/hs-utils-CKm6QhLw.js","assets/hs-cssVariables-BjuwJfDJ.js","assets/hs-comparison-Ja8EiSGD.js","assets/hs-tabs-CaxqHoGW.js","assets/hs-form-COFGgawz.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as t,c as r}from"../main.js";import{g as o}from"./hs-attributeSelector-6pGcDBo-.js";import"./hs-modalManager-H_YegPAO.js";import{c as a}from"./hs-orchestrator-J8b7XRk1.js";const e=r.structure,s=[{name:"toc",selector:o(e.toc,"list"),import:()=>t(()=>import("./hs-toc-fxIQS7tz.js"),__vite__mapDeps([0,1,2,3]))},{name:"pagination",selector:o(e.pagination,"wrapper"),import:()=>t(()=>import("./hs-pagination-DcOxmDPJ.js"),__vite__mapDeps([4,5,3,1,2,6])),config:e.pagination},{name:"comparison",selector:o(e.comparison,"wrapper"),import:()=>t(()=>import("./hs-comparison-Ja8EiSGD.js"),__vite__mapDeps([7,5,3,1,2,6])),config:e.comparison},{name:"tabs",selector:o(e.tabs,"wrapper"),import:()=>t(()=>import("./hs-tabs-CaxqHoGW.js"),__vite__mapDeps([8,1,5,3,2]))},{name:"form",selector:"[data-hs-form]",import:()=>t(()=>import("./hs-form-COFGgawz.js"),__vite__mapDeps([9,1,2,3]))}],i=(()=>{const t=s.filter(t=>document.querySelector(t.selector)).map(t=>t.import().catch(r=>(console.error(`[structure] Failed to preload ${t.name}:`,r),null)));return Promise.allSettled(t)})();async function n(){await i;const t=a(s),{loaded:r}=await t.scan();return{result:`structure initialized (${r.length} active)`,rescan:t.scan,destroy:t.destroy}}export{n as init};
|
|
3
|
+
//# sourceMappingURL=hs-structure-DhNix64P.js.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/hs-toc-fxIQS7tz.js","main.js","assets/hs-attributeSelector-6pGcDBo-.js","assets/hs-modalManager-H_YegPAO.js","assets/hs-pagination-DcOxmDPJ.js","assets/hs-utils-CKm6QhLw.js","assets/hs-cssVariables-BjuwJfDJ.js","assets/hs-comparison-Ja8EiSGD.js","assets/hs-tabs-CaxqHoGW.js","assets/hs-form-COFGgawz.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as t,c as r}from"../main.js";import{g as o}from"./hs-attributeSelector-6pGcDBo-.js";import"./hs-modalManager-H_YegPAO.js";import{c as a}from"./hs-orchestrator-J8b7XRk1.js";const e=r.structure,s=[{name:"toc",selector:o(e.toc,"list"),import:()=>t(()=>import("./hs-toc-fxIQS7tz.js"),__vite__mapDeps([0,1,2,3]))},{name:"pagination",selector:o(e.pagination,"wrapper"),import:()=>t(()=>import("./hs-pagination-DcOxmDPJ.js"),__vite__mapDeps([4,5,3,1,2,6])),config:e.pagination},{name:"comparison",selector:o(e.comparison,"wrapper"),import:()=>t(()=>import("./hs-comparison-Ja8EiSGD.js"),__vite__mapDeps([7,5,3,1,2,6])),config:e.comparison},{name:"tabs",selector:o(e.tabs,"wrapper"),import:()=>t(()=>import("./hs-tabs-CaxqHoGW.js"),__vite__mapDeps([8,1,5,3,2]))},{name:"form",selector:"[data-hs-form]",import:()=>t(()=>import("./hs-form-COFGgawz.js"),__vite__mapDeps([9,1,2,3]))}],i=(()=>{const t=s.filter(t=>document.querySelector(t.selector)).map(t=>t.import().catch(r=>(console.error(`[structure] Failed to preload ${t.name}:`,r),null)));return Promise.allSettled(t)})();async function n(){await i;const t=a(s),{loaded:r}=await t.scan();return{result:`structure initialized (${r.length} active)`,rescan:t.scan,destroy:t.destroy}}export{n as init};
|
|
3
|
+
//# sourceMappingURL=hs-structure-DhNix64P.js.map
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":";qLA+BA,MAAMA,EAAeC,EAAOC,UAOtBC,EAA4C,CAChD,CACEC,KAAM,MACNC,SAAUC,EAAYN,EAAaO,IAAqB,QACxDC,OAAQ,IAAAC,EAAA,IAAMD,OAAO,wBAAwBE,6BAE/C,CACEN,KAAM,aACNC,SAAUC,EAAYN,EAAaW,WAA4B,WAC/DH,OAAQ,UAAMA,OAAO,+BAA2BE,gCAChDT,OAAQD,EAAaW,YAEvB,CACEP,KAAM,aACNC,SAAUC,EAAYN,EAAaY,WAA4B,WAC/DJ,OAAQ,UAAMA,OAAO,+BAA2BE,gCAChDT,OAAQD,EAAaY,YAEvB,CACER,KAAM,OACNC,SAAUC,EAAYN,EAAaa,KAAsB,WACzDL,OAAQ,UAAMA,OAAO,yBAAqBE,+BAE5C,CACEN,KAAM,OACNC,SAAU,iBACVG,OAAQ,IAAAC,EAAA,IAAMD,OAAO,yBAA0BE,8BAM7CI,QACJ,MAKMC,EALmBZ,EAAmBa,OAAQC,GAClDC,SAASC,cAAcF,EAAOZ,WAISe,IAAKH,GAC5CA,EAAOT,SAASa,MAAOC,IACrBC,QAAQD,MAAM,iCAAiCL,EAAOb,QAASkB,GACxD,QAIX,OAAOE,QAAQC,WAAWV,EAC5B,KAEAW,eAAsBC,UAEdb,EAEN,MAAMc,EAAeC,EAAmB1B,IAClC2B,OAAEA,SAAiBF,EAAaG,OAEtC,MAAO,CACLC,OAAQ,0BAA0BF,EAAOG,iBACzCC,OAAQN,EAAaG,KACrBI,QAASP,EAAaO,QAE1B","names":["moduleConfig","config","structure","STRUCTURE_REGISTRY","name","selector","getSelector","toc","import","__vitePreload","__VITE_PRELOAD__","pagination","comparison","tabs","preloadStructure","preloadPromises","filter","module","document","querySelector","map","catch","error","console","Promise","allSettled","async","init","orchestrator","createOrchestrator","loaded","scan","result","length","rescan","destroy"],"ignoreList":[],"sources":["../../src/modules/structure/structure.ts"],"sourcesContent":["/**\n * Structure Orchestrator\n *\n * Conditionally loads structural DOM modification modules based on element presence.\n * Uses registry pattern for scalable module management.\n *\n * Features:\n * - Registry-based conditional loading\n * - Dynamic imports for code-splitting\n * - Prevents duplicate initialization\n * - SPA-friendly rescan() method\n * - Only loads modules when needed on page\n *\n * Architecture:\n * - Runs after normalize, before default\n * - Modifies DOM structure (IDs, pagination, comparisons)\n * - Other modules may depend on these structural changes\n *\n * Adding new modules:\n * 1. Add entry to STRUCTURE_REGISTRY below\n * 2. That's it - orchestrator handles the rest\n */\n\nimport config from '@config';\nimport {\n createOrchestrator,\n type ModuleRegistryEntry,\n getSelector,\n type ModuleConfig,\n} from '@utils';\n\nconst moduleConfig = config.structure;\n\n/**\n * Structure Registry\n * Add new structural modules here - one line per module\n * Selectors pulled directly from config for consistency\n */\nconst STRUCTURE_REGISTRY: ModuleRegistryEntry[] = [\n {\n name: 'toc',\n selector: getSelector(moduleConfig.toc as ModuleConfig, 'list'),\n import: () => import('./functions/toc/toc.ts'),\n },\n {\n name: 'pagination',\n selector: getSelector(moduleConfig.pagination as ModuleConfig, 'wrapper'),\n import: () => import('./functions/pagination.ts'),\n config: moduleConfig.pagination,\n },\n {\n name: 'comparison',\n selector: getSelector(moduleConfig.comparison as ModuleConfig, 'wrapper'),\n import: () => import('./functions/comparison.ts'),\n config: moduleConfig.comparison,\n },\n {\n name: 'tabs',\n selector: getSelector(moduleConfig.tabs as ModuleConfig, 'wrapper'),\n import: () => import('./functions/tabs.ts'),\n },\n {\n name: 'form',\n selector: '[data-hs-form]',\n import: () => import('./functions/form/form.ts'),\n },\n];\n\n// Pre-download structure modules as soon as this file loads (before init is called)\n// This allows parallel downloads during the normalize phase\nconst preloadStructure = (() => {\n const modulesToPreload = STRUCTURE_REGISTRY.filter((module) =>\n document.querySelector(module.selector)\n );\n\n // Download all found modules in parallel\n const preloadPromises = modulesToPreload.map((module) =>\n module.import().catch((error) => {\n console.error(`[structure] Failed to preload ${module.name}:`, error);\n return null;\n })\n );\n\n return Promise.allSettled(preloadPromises);\n})();\n\nexport async function init() {\n // Wait for preloading to complete (modules are already downloaded)\n await preloadStructure;\n\n const orchestrator = createOrchestrator(STRUCTURE_REGISTRY);\n const { loaded } = await orchestrator.scan();\n\n return {\n result: `structure initialized (${loaded.length} active)`,\n rescan: orchestrator.scan,\n destroy: orchestrator.destroy,\n };\n}\n"],"file":"hs-structure-DhNix64P.js"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{c as t}from"../main.js";import{g as e}from"./hs-utils-CKm6QhLw.js";import{q as s,a as n,g as a}from"./hs-attributeSelector-6pGcDBo-.js";import{p as i,g as r}from"./hs-modalManager-H_YegPAO.js";const o=t.structure.tabs;function l(){const l={handlers:[],timers:[],animationFrames:[],observers:[]},c=(t,e,s,n)=>{t.addEventListener(e,s,n),l.handlers.push({element:t,event:e,handler:s,options:n})},p=t=>l.animationFrames.push(t),u=()=>`${t._global.cssVars.prefix}${o.cssVars?.progress||"progress"}`,y=(t,e)=>t.style.setProperty(u(),String(e));function f(t){const s=n(o,"links",t),f=n(o,"list",t);if(!s||!f)return;const h=Array.from(s.children),d=Array.from(f.children),m=a(e.clickable,"button"),b=h.map(t=>t.querySelector(m)).filter(t=>null!==t);if(0===b.length)return;const g=t.getAttribute(o.attributes.properties?.autoplay||"data-hs-tab-autoplay"),v=t.getAttribute(o.attributes.properties?.duration||"data-hs-tab-duration"),E=t.getAttribute(o.attributes.properties?.hover||"data-hs-tab-hover"),A=t.getAttribute(o.attributes.properties?.animation||"data-hs-tab-animation"),w=t.getAttribute(o.attributes.properties?.animationDuration||"data-hs-tab-animation-duration"),P="true"===g,k=v?parseFloat(v):6,F="pause"===E,D=A,$=w?parseFloat(w):.3,L=`${"hs-tab"}-${Math.random().toString(36).substring(2,9)}`;d.forEach((t,e)=>{const s=t.id||`${L}-panel-${e}`,n=`${L}-tab-${e}`;t.id=s,b[e]&&(b[e].id=n,b[e].setAttribute("aria-controls",s))});let S=0,q=null,x=null,M=null,j=!1,C=!1,V=!1;async function I(t,s=!1){if(C)return;if(t<0||t>=d.length)return;if(t===S&&!s)return;C=!0;const n=S;if(S=t,b.forEach((e,s)=>{e.setAttribute("aria-selected",s===t?"true":"false"),e.setAttribute("tabindex",s===t?"0":"-1")}),h.forEach((s,n)=>{s.classList.toggle(e.classes.active,n===t)}),P)if(j){const e=h[n]?parseFloat(getComputedStyle(h[n]).getPropertyValue(u())||"0"):0;h.forEach((s,n)=>y(s,n===t?e:0))}else T();const a=d[n],o=d[t];"fade"!==D||s?"clip"!==D||s?d.forEach((s,n)=>{n===t?("fade"===D||"clip"===D?(s.style.position="",s.style.display="block","fade"===D?s.style.opacity="1":s.style.clipPath=""):s.style.display="block",s.inert=!1,s.style.pointerEvents="",s.classList.add(e.classes.active)):("fade"===D||"clip"===D?(s.style.display="none","fade"===D?s.style.opacity="0":s.style.clipPath=""):s.style.display="none",s.inert=!0,s.style.pointerEvents="none",s.classList.remove(e.classes.active))}):await async function(t,e,s){i()&&(s=0);const n=r("tabs",!1);if(!n)return t.style.display="none",t.style.position="",t.style.clipPath="",t.inert=!0,t.style.pointerEvents="none",e.style.display="block",e.style.position="",e.style.clipPath="",e.inert=!1,void(e.style.pointerEvents="");const{gsap:a}=n;return new Promise(n=>{const i=a.timeline({onComplete:()=>{t.style.display="none",t.style.position="",t.style.clipPath="",t.inert=!0,t.style.pointerEvents="none",e.style.position="",e.style.clipPath="",e.inert=!1,e.style.pointerEvents="",n()},defaults:{duration:s,ease:"power1.inOut"}});i.set(t,{position:"absolute",top:0,left:0,width:"100%",clipPath:"inset(0% 0% 0% 0%)"}),i.set(e,{display:"block",position:"relative",clipPath:"inset(0% 0% 100% 0%)"}),i.to(t,{clipPath:"inset(100% 0% 0% 0%)"}),i.to(e,{clipPath:"inset(0% 0% 0% 0%)"},"<40%")})}(a,o,$):await async function(t,e,s){i()&&(s=0);const n=r("tabs",!1);if(!n)return t.style.display="none",t.style.position="",t.inert=!0,t.style.pointerEvents="none",e.style.display="block",e.style.position="",e.inert=!1,void(e.style.pointerEvents="");const{gsap:a}=n;return new Promise(n=>{const i=a.timeline({onComplete:()=>{t.style.display="none",t.style.position="",t.style.opacity="",t.inert=!0,t.style.pointerEvents="none",e.style.position="",e.style.opacity="",e.inert=!1,e.style.pointerEvents="",n()},defaults:{duration:s,ease:"power1.out"}});i.set(t,{position:"absolute",top:0,left:0,width:"100%"}),i.set(e,{display:"block",position:"relative",opacity:0}),i.to(t,{opacity:0}),i.to(e,{opacity:1},"<50%")})}(a,o,$),C=!1}function O(t){if(P){M||(M=t);const e=Math.min((t-M)/(1e3*k),1);h.forEach((t,s)=>y(t,s===S?e:0)),e<1&&!j&&(x=requestAnimationFrame(O),x&&p(x))}else h.forEach((t,e)=>y(t,e===S?1:0))}function T(){if(z(),!P)return O(0);if(j||!V)return;const t=h[S]?parseFloat(getComputedStyle(h[S]).getPropertyValue(u())||"0"):0,e=t*k*1e3,s=Math.max(0,1e3*k-e);M=null;const n=t,a=performance.now(),i=t=>{const e=Math.min(n+(t-a)/(1e3*k),1);h.forEach((t,s)=>y(t,s===S?e:0)),e<1&&!j&&(x=requestAnimationFrame(i),x&&p(x))};var r;x=requestAnimationFrame(i),x&&p(x),q=window.setTimeout(()=>I((S+1)%d.length),s),r=q,l.timers.push(r)}function z(){null!==q&&(clearTimeout(q),q=null),null!==x&&(cancelAnimationFrame(x),x=null),M=null}const H=()=>{j=!0,z()},N=()=>{j=!1,T()};b.forEach((t,e)=>{c(t,"click",t=>{t.preventDefault(),I(e)})});const R=t=>{const e=b.indexOf(t.target);if(-1===e)return;let s=e;switch(t.key){case"ArrowLeft":case"ArrowUp":t.preventDefault(),s=0===e?b.length-1:e-1;break;case"ArrowRight":case"ArrowDown":t.preventDefault(),s=e===b.length-1?0:e+1;break;case"Home":t.preventDefault(),s=0;break;case"End":t.preventDefault(),s=b.length-1;break;default:return}C||(I(s),b[s].focus())};b.forEach(t=>c(t,"keydown",R)),F&&P&&(c(t,"mouseenter",H),c(t,"mouseleave",N));let U=!1;c(document,"keydown",()=>U=!0),c(document,"mousedown",()=>U=!1),P&&(c(t,"focusin",()=>{U&&(H(),K())}),c(t,"focusout",()=>{U&&j&&(N(),K())}));const _=`[${o.attributes.properties?.controls||"data-hs-tab-controls"}]`,B=t.querySelectorAll(_);let G=null,J=null;B.forEach(t=>{const s=t.getAttribute(o.attributes.properties?.controls||"data-hs-tab-controls"),n=t.querySelector(m);if(n)if("previous"===s)n.setAttribute("aria-label","Previous tab"),c(n,"click",t=>{t.preventDefault(),I(0===S?d.length-1:S-1)});else if("next"===s)n.setAttribute("aria-label","Next tab"),c(n,"click",t=>{t.preventDefault(),I((S+1)%d.length)});else if("toggle"===s){if(!P)return void(t.style.display="none");G=t,J=n,J.setAttribute("aria-label",j?"Play":"Pause"),G.classList.toggle(e.classes.active,!j),c(n,"click",t=>{t.preventDefault(),j?N():H(),K()})}});const K=()=>{G&&J&&(G.classList.toggle(e.classes.active,!j),J.setAttribute("aria-label",j?"Play":"Pause"))};if(I(0,!0),P){const e=new IntersectionObserver(t=>{t.forEach(t=>{V=t.isIntersecting,t.isIntersecting&&!j?T():z()})},{threshold:.1});e.observe(t),Q=e,l.observers.push(Q)}var Q}const h=s(o,"wrapper");return h.forEach(t=>{f(t)}),{result:`tabs initialized (${h.length} systems)`,destroy:()=>{l.timers.forEach(t=>clearTimeout(t)),l.timers.length=0,l.animationFrames.forEach(t=>cancelAnimationFrame(t)),l.animationFrames.length=0,l.observers.forEach(t=>t.disconnect()),l.observers.length=0,l.handlers.forEach(({element:t,event:e,handler:s,options:n})=>{t.removeEventListener(e,s,n)}),l.handlers.length=0}}}export{l as init};
|
|
2
|
+
//# sourceMappingURL=hs-tabs-CaxqHoGW.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{c as t}from"../main.js";import{g as e}from"./hs-utils-CKm6QhLw.js";import{q as s,a as n,g as a}from"./hs-attributeSelector-6pGcDBo-.js";import{p as i,g as r}from"./hs-modalManager-H_YegPAO.js";const o=t.structure.tabs;function l(){const l={handlers:[],timers:[],animationFrames:[],observers:[]},c=(t,e,s,n)=>{t.addEventListener(e,s,n),l.handlers.push({element:t,event:e,handler:s,options:n})},p=t=>l.animationFrames.push(t),u=()=>`${t._global.cssVars.prefix}${o.cssVars?.progress||"progress"}`,y=(t,e)=>t.style.setProperty(u(),String(e));function f(t){const s=n(o,"links",t),f=n(o,"list",t);if(!s||!f)return;const h=Array.from(s.children),d=Array.from(f.children),m=a(e.clickable,"button"),b=h.map(t=>t.querySelector(m)).filter(t=>null!==t);if(0===b.length)return;const g=t.getAttribute(o.attributes.properties?.autoplay||"data-hs-tab-autoplay"),v=t.getAttribute(o.attributes.properties?.duration||"data-hs-tab-duration"),E=t.getAttribute(o.attributes.properties?.hover||"data-hs-tab-hover"),A=t.getAttribute(o.attributes.properties?.animation||"data-hs-tab-animation"),w=t.getAttribute(o.attributes.properties?.animationDuration||"data-hs-tab-animation-duration"),P="true"===g,k=v?parseFloat(v):6,F="pause"===E,D=A,$=w?parseFloat(w):.3,L=`${"hs-tab"}-${Math.random().toString(36).substring(2,9)}`;d.forEach((t,e)=>{const s=t.id||`${L}-panel-${e}`,n=`${L}-tab-${e}`;t.id=s,b[e]&&(b[e].id=n,b[e].setAttribute("aria-controls",s))});let S=0,q=null,x=null,M=null,j=!1,C=!1,V=!1;async function I(t,s=!1){if(C)return;if(t<0||t>=d.length)return;if(t===S&&!s)return;C=!0;const n=S;if(S=t,b.forEach((e,s)=>{e.setAttribute("aria-selected",s===t?"true":"false"),e.setAttribute("tabindex",s===t?"0":"-1")}),h.forEach((s,n)=>{s.classList.toggle(e.classes.active,n===t)}),P)if(j){const e=h[n]?parseFloat(getComputedStyle(h[n]).getPropertyValue(u())||"0"):0;h.forEach((s,n)=>y(s,n===t?e:0))}else T();const a=d[n],o=d[t];"fade"!==D||s?"clip"!==D||s?d.forEach((s,n)=>{n===t?("fade"===D||"clip"===D?(s.style.position="",s.style.display="block","fade"===D?s.style.opacity="1":s.style.clipPath=""):s.style.display="block",s.inert=!1,s.style.pointerEvents="",s.classList.add(e.classes.active)):("fade"===D||"clip"===D?(s.style.display="none","fade"===D?s.style.opacity="0":s.style.clipPath=""):s.style.display="none",s.inert=!0,s.style.pointerEvents="none",s.classList.remove(e.classes.active))}):await async function(t,e,s){i()&&(s=0);const n=r("tabs",!1);if(!n)return t.style.display="none",t.style.position="",t.style.clipPath="",t.inert=!0,t.style.pointerEvents="none",e.style.display="block",e.style.position="",e.style.clipPath="",e.inert=!1,void(e.style.pointerEvents="");const{gsap:a}=n;return new Promise(n=>{const i=a.timeline({onComplete:()=>{t.style.display="none",t.style.position="",t.style.clipPath="",t.inert=!0,t.style.pointerEvents="none",e.style.position="",e.style.clipPath="",e.inert=!1,e.style.pointerEvents="",n()},defaults:{duration:s,ease:"power1.inOut"}});i.set(t,{position:"absolute",top:0,left:0,width:"100%",clipPath:"inset(0% 0% 0% 0%)"}),i.set(e,{display:"block",position:"relative",clipPath:"inset(0% 0% 100% 0%)"}),i.to(t,{clipPath:"inset(100% 0% 0% 0%)"}),i.to(e,{clipPath:"inset(0% 0% 0% 0%)"},"<40%")})}(a,o,$):await async function(t,e,s){i()&&(s=0);const n=r("tabs",!1);if(!n)return t.style.display="none",t.style.position="",t.inert=!0,t.style.pointerEvents="none",e.style.display="block",e.style.position="",e.inert=!1,void(e.style.pointerEvents="");const{gsap:a}=n;return new Promise(n=>{const i=a.timeline({onComplete:()=>{t.style.display="none",t.style.position="",t.style.opacity="",t.inert=!0,t.style.pointerEvents="none",e.style.position="",e.style.opacity="",e.inert=!1,e.style.pointerEvents="",n()},defaults:{duration:s,ease:"power1.out"}});i.set(t,{position:"absolute",top:0,left:0,width:"100%"}),i.set(e,{display:"block",position:"relative",opacity:0}),i.to(t,{opacity:0}),i.to(e,{opacity:1},"<50%")})}(a,o,$),C=!1}function O(t){if(P){M||(M=t);const e=Math.min((t-M)/(1e3*k),1);h.forEach((t,s)=>y(t,s===S?e:0)),e<1&&!j&&(x=requestAnimationFrame(O),x&&p(x))}else h.forEach((t,e)=>y(t,e===S?1:0))}function T(){if(z(),!P)return O(0);if(j||!V)return;const t=h[S]?parseFloat(getComputedStyle(h[S]).getPropertyValue(u())||"0"):0,e=t*k*1e3,s=Math.max(0,1e3*k-e);M=null;const n=t,a=performance.now(),i=t=>{const e=Math.min(n+(t-a)/(1e3*k),1);h.forEach((t,s)=>y(t,s===S?e:0)),e<1&&!j&&(x=requestAnimationFrame(i),x&&p(x))};var r;x=requestAnimationFrame(i),x&&p(x),q=window.setTimeout(()=>I((S+1)%d.length),s),r=q,l.timers.push(r)}function z(){null!==q&&(clearTimeout(q),q=null),null!==x&&(cancelAnimationFrame(x),x=null),M=null}const H=()=>{j=!0,z()},N=()=>{j=!1,T()};b.forEach((t,e)=>{c(t,"click",t=>{t.preventDefault(),I(e)})});const R=t=>{const e=b.indexOf(t.target);if(-1===e)return;let s=e;switch(t.key){case"ArrowLeft":case"ArrowUp":t.preventDefault(),s=0===e?b.length-1:e-1;break;case"ArrowRight":case"ArrowDown":t.preventDefault(),s=e===b.length-1?0:e+1;break;case"Home":t.preventDefault(),s=0;break;case"End":t.preventDefault(),s=b.length-1;break;default:return}C||(I(s),b[s].focus())};b.forEach(t=>c(t,"keydown",R)),F&&P&&(c(t,"mouseenter",H),c(t,"mouseleave",N));let U=!1;c(document,"keydown",()=>U=!0),c(document,"mousedown",()=>U=!1),P&&(c(t,"focusin",()=>{U&&(H(),K())}),c(t,"focusout",()=>{U&&j&&(N(),K())}));const _=`[${o.attributes.properties?.controls||"data-hs-tab-controls"}]`,B=t.querySelectorAll(_);let G=null,J=null;B.forEach(t=>{const s=t.getAttribute(o.attributes.properties?.controls||"data-hs-tab-controls"),n=t.querySelector(m);if(n)if("previous"===s)n.setAttribute("aria-label","Previous tab"),c(n,"click",t=>{t.preventDefault(),I(0===S?d.length-1:S-1)});else if("next"===s)n.setAttribute("aria-label","Next tab"),c(n,"click",t=>{t.preventDefault(),I((S+1)%d.length)});else if("toggle"===s){if(!P)return void(t.style.display="none");G=t,J=n,J.setAttribute("aria-label",j?"Play":"Pause"),G.classList.toggle(e.classes.active,!j),c(n,"click",t=>{t.preventDefault(),j?N():H(),K()})}});const K=()=>{G&&J&&(G.classList.toggle(e.classes.active,!j),J.setAttribute("aria-label",j?"Play":"Pause"))};if(I(0,!0),P){const e=new IntersectionObserver(t=>{t.forEach(t=>{V=t.isIntersecting,t.isIntersecting&&!j?T():z()})},{threshold:.1});e.observe(t),Q=e,l.observers.push(Q)}var Q}const h=s(o,"wrapper");return h.forEach(t=>{f(t)}),{result:`tabs initialized (${h.length} systems)`,destroy:()=>{l.timers.forEach(t=>clearTimeout(t)),l.timers.length=0,l.animationFrames.forEach(t=>cancelAnimationFrame(t)),l.animationFrames.length=0,l.observers.forEach(t=>t.disconnect()),l.observers.length=0,l.handlers.forEach(({element:t,event:e,handler:s,options:n})=>{t.removeEventListener(e,s,n)}),l.handlers.length=0}}}export{l as init};
|
|
2
|
+
//# sourceMappingURL=hs-tabs-CaxqHoGW.js.map
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hs-tabs-CaxqHoGW.js","sources":["../../src/modules/structure/functions/tabs.ts"],"sourcesContent":["/**\n * Tabs\n *\n * Accessible tab system with autoplay, keyboard navigation, and optional animations.\n * Index-based matching: first button controls first panel, second controls second, etc.\n *\n * Features:\n * - Index-based tab/panel matching (no manual ID configuration needed)\n * - Optional autoplay with configurable duration\n * - CSS progress variable for visual countdown (--_hs---progress)\n * - Pause on hover and focus (accessibility)\n * - Previous/next/toggle controls\n * - Keyboard navigation (Arrow keys, Home, End)\n * - Optional fade or height animations\n * - Respects prefers-reduced-motion\n * - Full ARIA support (auto-generated IDs, aria-controls, aria-selected)\n *\n * Structure:\n * <div data-hs-tab=\"wrapper\" data-hs-tab-autoplay=\"true\" data-hs-tab-duration=\"6\">\n * <div data-hs-tab=\"links\" role=\"tablist\">\n * <div class=\"tab-link\">\n * <button role=\"tab\" data-hs-clickable=\"button\">Tab 1</button>\n * </div>\n * </div>\n * <div data-hs-tab=\"list\">\n * <div role=\"tabpanel\">Panel 1 content</div>\n * <div role=\"tabpanel\">Panel 2 content</div>\n * </div>\n * </div>\n */\n\nimport config from '@config';\nimport {\n querySelectorAll,\n querySelector,\n getSelector,\n globalConfig,\n prefersReducedMotion,\n getGsap,\n hasGsap,\n} from '@utils';\n\ninterface EventHandler {\n element: Element | Document;\n event: string;\n handler: EventListener;\n options?: AddEventListenerOptions;\n}\n\ninterface ModuleConfig {\n attributes: {\n elements: Record<string, { primary: string; aliases?: string[] }>;\n properties?: Record<string, string>;\n };\n cssVars?: {\n progress?: string;\n };\n}\n\nconst moduleConfig = config.structure.tabs as ModuleConfig;\n\nexport function init() {\n const cleanup = {\n handlers: [] as EventHandler[],\n timers: [] as number[],\n animationFrames: [] as number[],\n observers: [] as IntersectionObserver[],\n };\n\n const addHandler = (\n element: Element | Document,\n event: string,\n handler: EventListener,\n options?: AddEventListenerOptions\n ): void => {\n element.addEventListener(event, handler, options);\n cleanup.handlers.push({ element, event, handler, options });\n };\n\n const addTimer = (id: number) => cleanup.timers.push(id);\n const addAnimationFrame = (id: number) => cleanup.animationFrames.push(id);\n const addObserver = (obs: IntersectionObserver) => cleanup.observers.push(obs);\n\n // Helper: Generate unique IDs for ARIA\n const generateId = (prefix: string) => `${prefix}-${Math.random().toString(36).substring(2, 9)}`;\n\n // Helper: Get CSS var name with prefix\n const getProgressVarName = () =>\n `${config._global.cssVars.prefix}${moduleConfig.cssVars?.progress || 'progress'}`;\n\n // Helper: Set progress CSS variable on element\n const setProgress = (element: HTMLElement, progress: number) =>\n element.style.setProperty(getProgressVarName(), String(progress));\n\n // Helper: Fade animation using GSAP\n async function animateFade(\n outPanel: HTMLElement,\n inPanel: HTMLElement,\n duration: number\n ): Promise<void> {\n // Handle reduced motion by setting duration to 0\n if (prefersReducedMotion()) duration = 0;\n\n const gsapInstance = getGsap('tabs', false);\n\n // Fallback to instant switch if GSAP not available\n if (!gsapInstance) {\n outPanel.style.display = 'none';\n outPanel.style.position = '';\n (outPanel as HTMLElement).inert = true;\n outPanel.style.pointerEvents = 'none';\n\n inPanel.style.display = 'block';\n inPanel.style.position = '';\n (inPanel as HTMLElement).inert = false;\n inPanel.style.pointerEvents = '';\n return;\n }\n\n const { gsap } = gsapInstance;\n\n return new Promise<void>((resolve) => {\n const tl = gsap.timeline({\n onComplete: () => {\n // Final cleanup after animation\n outPanel.style.display = 'none';\n outPanel.style.position = '';\n outPanel.style.opacity = '';\n (outPanel as HTMLElement).inert = true;\n outPanel.style.pointerEvents = 'none';\n\n inPanel.style.position = '';\n inPanel.style.opacity = '';\n (inPanel as HTMLElement).inert = false;\n inPanel.style.pointerEvents = '';\n\n resolve();\n },\n defaults: { duration: duration, ease: 'power1.out' },\n });\n\n // Set old panel to absolute position\n tl.set(outPanel, { position: 'absolute', top: 0, left: 0, width: '100%' });\n\n // Set new panel to visible and relative\n tl.set(inPanel, { display: 'block', position: 'relative', opacity: 0 });\n\n // Fade out old panel\n tl.to(outPanel, { opacity: 0 });\n\n // Fade in new panel (starts at 50% of fade out)\n tl.to(inPanel, { opacity: 1 }, '<50%');\n });\n }\n\n // Helper: Clip-path animation using GSAP\n async function animateClip(\n outPanel: HTMLElement,\n inPanel: HTMLElement,\n duration: number\n ): Promise<void> {\n // Handle reduced motion by setting duration to 0\n if (prefersReducedMotion()) duration = 0;\n\n const gsapInstance = getGsap('tabs', false);\n\n // Fallback to instant switch if GSAP not available\n if (!gsapInstance) {\n outPanel.style.display = 'none';\n outPanel.style.position = '';\n outPanel.style.clipPath = '';\n (outPanel as HTMLElement).inert = true;\n outPanel.style.pointerEvents = 'none';\n\n inPanel.style.display = 'block';\n inPanel.style.position = '';\n inPanel.style.clipPath = '';\n (inPanel as HTMLElement).inert = false;\n inPanel.style.pointerEvents = '';\n return;\n }\n\n const { gsap } = gsapInstance;\n\n return new Promise<void>((resolve) => {\n const tl = gsap.timeline({\n onComplete: () => {\n // Final cleanup after animation\n outPanel.style.display = 'none';\n outPanel.style.position = '';\n outPanel.style.clipPath = '';\n (outPanel as HTMLElement).inert = true;\n outPanel.style.pointerEvents = 'none';\n\n inPanel.style.position = '';\n inPanel.style.clipPath = '';\n (inPanel as HTMLElement).inert = false;\n inPanel.style.pointerEvents = '';\n\n resolve();\n },\n defaults: { duration: duration, ease: 'power1.inOut' },\n });\n\n // Set old panel to absolute position with full clip\n tl.set(outPanel, {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n clipPath: 'inset(0% 0% 0% 0%)',\n });\n\n // Set new panel to visible with bottom clipped\n tl.set(inPanel, { display: 'block', position: 'relative', clipPath: 'inset(0% 0% 100% 0%)' });\n\n // Clip out old panel (top to bottom)\n tl.to(outPanel, { clipPath: 'inset(100% 0% 0% 0%)' });\n\n // Clip in new panel (bottom to top, starts at 40% through clip out)\n tl.to(inPanel, { clipPath: 'inset(0% 0% 0% 0%)' }, '<40%');\n });\n }\n\n // Setup individual tab system\n function setupTabSystem(wrapper: Element): void {\n const linksWrapper = querySelector(moduleConfig as any, 'links', wrapper);\n const listWrapper = querySelector(moduleConfig as any, 'list', wrapper);\n\n if (!linksWrapper || !listWrapper) {\n return;\n }\n\n // Get tab links (direct children of links wrapper)\n const tabLinkElements = Array.from(linksWrapper.children);\n\n // Get tab panels (direct children of list wrapper)\n const tabPanels = Array.from(listWrapper.children) as HTMLElement[];\n\n // Find clickable buttons within each tab link element\n const clickableSelector = getSelector(globalConfig.clickable as any, 'button');\n const tabButtons = tabLinkElements\n .map((linkEl) => linkEl.querySelector(clickableSelector))\n .filter((btn) => btn !== null) as HTMLElement[];\n\n if (tabButtons.length === 0) {\n return;\n }\n\n // Get options from attributes\n const autoplayAttr = (wrapper as HTMLElement).getAttribute(\n moduleConfig.attributes.properties?.autoplay || 'data-hs-tab-autoplay'\n );\n const durationAttr = (wrapper as HTMLElement).getAttribute(\n moduleConfig.attributes.properties?.duration || 'data-hs-tab-duration'\n );\n const hoverAttr = (wrapper as HTMLElement).getAttribute(\n moduleConfig.attributes.properties?.hover || 'data-hs-tab-hover'\n );\n const animationAttr = (wrapper as HTMLElement).getAttribute(\n moduleConfig.attributes.properties?.animation || 'data-hs-tab-animation'\n );\n const animDurationAttr = (wrapper as HTMLElement).getAttribute(\n moduleConfig.attributes.properties?.animationDuration || 'data-hs-tab-animation-duration'\n );\n\n const autoplayEnabled = autoplayAttr === 'true';\n const duration = durationAttr ? parseFloat(durationAttr) : 6;\n const pauseOnHover = hoverAttr === 'pause';\n const animationType = animationAttr as 'fade' | 'clip' | null;\n const animationDuration = animDurationAttr ? parseFloat(animDurationAttr) : 0.3;\n\n // Generate unique ID for this tab system\n const tabSystemId = generateId('hs-tab');\n\n // Setup ARIA and IDs\n tabPanels.forEach((panel, index) => {\n const panelId = panel.id || `${tabSystemId}-panel-${index}`;\n const tabId = `${tabSystemId}-tab-${index}`;\n\n panel.id = panelId;\n if (tabButtons[index]) {\n tabButtons[index].id = tabId;\n tabButtons[index].setAttribute('aria-controls', panelId);\n }\n });\n\n // State\n let currentIndex = 0;\n let autoplayTimer: number | null = null;\n let progressAnimationFrame: number | null = null;\n let progressStartTime: number | null = null;\n let isPaused = false;\n let isTransitioning = false;\n let isInView = false;\n\n // Activate tab\n async function activateTab(index: number, skipAnimation = false): Promise<void> {\n // Block if transition in progress\n if (isTransitioning) return;\n\n // Validate index\n if (index < 0 || index >= tabPanels.length) return;\n if (index === currentIndex && !skipAnimation) return;\n\n // Lock IMMEDIATELY to block any further calls\n isTransitioning = true;\n\n const previousIndex = currentIndex;\n currentIndex = index;\n\n // Update button ARIA and active classes\n tabButtons.forEach((btn, i) => {\n btn.setAttribute('aria-selected', i === index ? 'true' : 'false');\n btn.setAttribute('tabindex', i === index ? '0' : '-1');\n });\n\n tabLinkElements.forEach((linkEl, i) => {\n linkEl.classList.toggle(globalConfig.classes.active, i === index);\n });\n\n // Handle progress transfer\n if (autoplayEnabled) {\n if (!isPaused) {\n startAutoplay();\n } else {\n const currentProgress = tabLinkElements[previousIndex]\n ? parseFloat(\n getComputedStyle(tabLinkElements[previousIndex] as HTMLElement).getPropertyValue(\n getProgressVarName()\n ) || '0'\n )\n : 0;\n\n tabLinkElements.forEach((linkEl, i) =>\n setProgress(linkEl as HTMLElement, i === index ? currentProgress : 0)\n );\n }\n }\n\n // Update panel visibility with animation\n const previousPanel = tabPanels[previousIndex];\n const currentPanel = tabPanels[index];\n\n if (animationType === 'fade' && !skipAnimation) {\n await animateFade(previousPanel, currentPanel, animationDuration);\n } else if (animationType === 'clip' && !skipAnimation) {\n await animateClip(previousPanel, currentPanel, animationDuration);\n } else {\n // Instant switch (no animation or skip)\n tabPanels.forEach((panel, i) => {\n if (i === index) {\n if (animationType === 'fade' || animationType === 'clip') {\n (panel as HTMLElement).style.position = '';\n (panel as HTMLElement).style.display = 'block';\n if (animationType === 'fade') {\n (panel as HTMLElement).style.opacity = '1';\n } else {\n (panel as HTMLElement).style.clipPath = '';\n }\n } else {\n (panel as HTMLElement).style.display = 'block';\n }\n (panel as HTMLElement).inert = false;\n (panel as HTMLElement).style.pointerEvents = '';\n panel.classList.add(globalConfig.classes.active);\n } else {\n if (animationType === 'fade' || animationType === 'clip') {\n (panel as HTMLElement).style.display = 'none';\n if (animationType === 'fade') {\n (panel as HTMLElement).style.opacity = '0';\n } else {\n (panel as HTMLElement).style.clipPath = '';\n }\n } else {\n (panel as HTMLElement).style.display = 'none';\n }\n (panel as HTMLElement).inert = true;\n (panel as HTMLElement).style.pointerEvents = 'none';\n panel.classList.remove(globalConfig.classes.active);\n }\n });\n }\n\n // Release lock\n isTransitioning = false;\n }\n\n // Progress animation\n function updateProgress(timestamp: number): void {\n if (autoplayEnabled) {\n if (!progressStartTime) progressStartTime = timestamp;\n const progress = Math.min((timestamp - progressStartTime) / (duration * 1000), 1);\n\n tabLinkElements.forEach((linkEl, i) =>\n setProgress(linkEl as HTMLElement, i === currentIndex ? progress : 0)\n );\n\n if (progress < 1 && !isPaused) {\n progressAnimationFrame = requestAnimationFrame(updateProgress);\n if (progressAnimationFrame) addAnimationFrame(progressAnimationFrame);\n }\n } else {\n tabLinkElements.forEach((linkEl, i) =>\n setProgress(linkEl as HTMLElement, i === currentIndex ? 1 : 0)\n );\n }\n }\n\n // Start autoplay\n function startAutoplay(): void {\n stopAutoplay();\n if (!autoplayEnabled) return updateProgress(0);\n if (isPaused || !isInView) return;\n\n // Get current progress to resume from (if any)\n const currentProgress = tabLinkElements[currentIndex]\n ? parseFloat(\n getComputedStyle(tabLinkElements[currentIndex] as HTMLElement).getPropertyValue(\n getProgressVarName()\n ) || '0'\n )\n : 0;\n\n // Calculate remaining time based on current progress\n const elapsedTime = currentProgress * duration * 1000; // Convert progress to milliseconds\n const remainingTime = Math.max(0, duration * 1000 - elapsedTime);\n\n // Start progress animation from current progress\n progressStartTime = null;\n const startProgress = currentProgress;\n const resumeStartTime = performance.now();\n\n const resumeUpdate = (timestamp: number): void => {\n const totalProgress = Math.min(\n startProgress + (timestamp - resumeStartTime) / (duration * 1000),\n 1\n );\n\n tabLinkElements.forEach((linkEl, i) =>\n setProgress(linkEl as HTMLElement, i === currentIndex ? totalProgress : 0)\n );\n\n if (totalProgress < 1 && !isPaused) {\n progressAnimationFrame = requestAnimationFrame(resumeUpdate);\n if (progressAnimationFrame) addAnimationFrame(progressAnimationFrame);\n }\n };\n\n progressAnimationFrame = requestAnimationFrame(resumeUpdate);\n if (progressAnimationFrame) addAnimationFrame(progressAnimationFrame);\n\n autoplayTimer = window.setTimeout(\n () => activateTab((currentIndex + 1) % tabPanels.length),\n remainingTime\n );\n addTimer(autoplayTimer);\n }\n\n // Stop autoplay\n function stopAutoplay(): void {\n if (autoplayTimer !== null) {\n clearTimeout(autoplayTimer);\n autoplayTimer = null;\n }\n if (progressAnimationFrame !== null) {\n cancelAnimationFrame(progressAnimationFrame);\n progressAnimationFrame = null;\n }\n progressStartTime = null;\n }\n\n // Pause/Resume autoplay\n const pauseAutoplay = () => {\n isPaused = true;\n stopAutoplay();\n };\n const resumeAutoplay = () => {\n isPaused = false;\n startAutoplay();\n };\n\n // Tab click handler\n tabButtons.forEach((button, index) => {\n addHandler(button, 'click', (e: Event) => {\n e.preventDefault();\n activateTab(index);\n });\n });\n\n // Keyboard navigation\n const keydownHandler = (e: KeyboardEvent): void => {\n const index = tabButtons.indexOf(e.target as HTMLElement);\n if (index === -1) return;\n\n let newIndex = index;\n switch (e.key) {\n case 'ArrowLeft':\n case 'ArrowUp':\n e.preventDefault();\n newIndex = index === 0 ? tabButtons.length - 1 : index - 1;\n break;\n case 'ArrowRight':\n case 'ArrowDown':\n e.preventDefault();\n newIndex = index === tabButtons.length - 1 ? 0 : index + 1;\n break;\n case 'Home':\n e.preventDefault();\n newIndex = 0;\n break;\n case 'End':\n e.preventDefault();\n newIndex = tabButtons.length - 1;\n break;\n default:\n return;\n }\n\n if (isTransitioning) return;\n activateTab(newIndex);\n tabButtons[newIndex].focus();\n };\n\n tabButtons.forEach((button) => addHandler(button, 'keydown', keydownHandler));\n\n // Pause on hover\n if (pauseOnHover && autoplayEnabled) {\n addHandler(wrapper, 'mouseenter', pauseAutoplay);\n addHandler(wrapper, 'mouseleave', resumeAutoplay);\n }\n\n // Pause on focus (keyboard only)\n let isUsingKeyboard = false;\n addHandler(document, 'keydown', () => (isUsingKeyboard = true));\n addHandler(document, 'mousedown', () => (isUsingKeyboard = false));\n\n if (autoplayEnabled) {\n addHandler(wrapper, 'focusin', () => {\n if (isUsingKeyboard) {\n pauseAutoplay();\n updateToggleState();\n }\n });\n addHandler(wrapper, 'focusout', () => {\n if (isUsingKeyboard && isPaused) {\n resumeAutoplay();\n updateToggleState();\n }\n });\n }\n\n // Previous/Next/Toggle controls\n const controlsSelector = `[${\n moduleConfig.attributes.properties?.controls || 'data-hs-tab-controls'\n }]`;\n const controls = wrapper.querySelectorAll(controlsSelector);\n\n // Find toggle button for state updates (may be null if no toggle or autoplay disabled)\n let toggleControl: Element | null = null;\n let toggleButton: HTMLElement | null = null;\n\n controls.forEach((control) => {\n const controlType = control.getAttribute(\n moduleConfig.attributes.properties?.controls || 'data-hs-tab-controls'\n );\n const controlButton = control.querySelector(clickableSelector);\n\n if (!controlButton) return;\n\n if (controlType === 'previous') {\n (controlButton as HTMLElement).setAttribute('aria-label', 'Previous tab');\n addHandler(controlButton, 'click', (e: Event) => {\n e.preventDefault();\n activateTab(currentIndex === 0 ? tabPanels.length - 1 : currentIndex - 1);\n });\n } else if (controlType === 'next') {\n (controlButton as HTMLElement).setAttribute('aria-label', 'Next tab');\n addHandler(controlButton, 'click', (e: Event) => {\n e.preventDefault();\n activateTab((currentIndex + 1) % tabPanels.length);\n });\n } else if (controlType === 'toggle') {\n // Hide toggle button if autoplay is disabled\n if (!autoplayEnabled) {\n (control as HTMLElement).style.display = 'none';\n return;\n }\n\n // Store references for updateToggleState function\n toggleControl = control;\n toggleButton = controlButton as HTMLElement;\n\n toggleButton.setAttribute('aria-label', isPaused ? 'Play' : 'Pause');\n toggleControl.classList.toggle(globalConfig.classes.active, !isPaused);\n\n addHandler(controlButton, 'click', (e: Event) => {\n e.preventDefault();\n isPaused ? resumeAutoplay() : pauseAutoplay();\n updateToggleState();\n });\n }\n });\n\n // Helper: Update toggle button state\n const updateToggleState = () => {\n if (!toggleControl || !toggleButton) return;\n toggleControl.classList.toggle(globalConfig.classes.active, !isPaused);\n toggleButton.setAttribute('aria-label', isPaused ? 'Play' : 'Pause');\n };\n\n // Initialize first tab as active\n activateTab(0, true);\n\n // IntersectionObserver for autoplay visibility control\n if (autoplayEnabled) {\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n isInView = entry.isIntersecting;\n entry.isIntersecting && !isPaused ? startAutoplay() : stopAutoplay();\n });\n },\n { threshold: 0.1 }\n );\n observer.observe(wrapper);\n addObserver(observer);\n }\n }\n\n // Find all tab wrappers and initialize\n const tabWrappers = querySelectorAll(moduleConfig as any, 'wrapper');\n\n tabWrappers.forEach((wrapper) => {\n setupTabSystem(wrapper);\n });\n\n return {\n result: `tabs initialized (${tabWrappers.length} systems)`,\n destroy: () => {\n // Clear all timers\n cleanup.timers.forEach((timerId) => clearTimeout(timerId));\n cleanup.timers.length = 0;\n\n // Clear all animation frames\n cleanup.animationFrames.forEach((frameId) => cancelAnimationFrame(frameId));\n cleanup.animationFrames.length = 0;\n\n // Disconnect all observers\n cleanup.observers.forEach((observer) => observer.disconnect());\n cleanup.observers.length = 0;\n\n // Remove all event listeners\n cleanup.handlers.forEach(({ element, event, handler, options }) => {\n element.removeEventListener(event, handler, options);\n });\n cleanup.handlers.length = 0;\n },\n };\n}\n"],"names":["moduleConfig","config","structure","tabs","init","cleanup","handlers","timers","animationFrames","observers","addHandler","element","event","handler","options","addEventListener","push","addAnimationFrame","id","getProgressVarName","_global","cssVars","prefix","progress","setProgress","style","setProperty","String","setupTabSystem","wrapper","linksWrapper","querySelector","listWrapper","tabLinkElements","Array","from","children","tabPanels","clickableSelector","getSelector","globalConfig","clickable","tabButtons","map","linkEl","filter","btn","length","autoplayAttr","getAttribute","attributes","properties","autoplay","durationAttr","duration","hoverAttr","hover","animationAttr","animation","animDurationAttr","animationDuration","autoplayEnabled","parseFloat","pauseOnHover","animationType","tabSystemId","Math","random","toString","substring","forEach","panel","index","panelId","tabId","setAttribute","currentIndex","autoplayTimer","progressAnimationFrame","progressStartTime","isPaused","isTransitioning","isInView","async","activateTab","skipAnimation","previousIndex","i","classList","toggle","classes","active","currentProgress","getComputedStyle","getPropertyValue","startAutoplay","previousPanel","currentPanel","position","display","opacity","clipPath","inert","pointerEvents","add","remove","outPanel","inPanel","prefersReducedMotion","gsapInstance","getGsap","gsap","Promise","resolve","tl","timeline","onComplete","defaults","ease","set","top","left","width","to","animateClip","animateFade","updateProgress","timestamp","min","requestAnimationFrame","stopAutoplay","elapsedTime","remainingTime","max","startProgress","resumeStartTime","performance","now","resumeUpdate","totalProgress","window","setTimeout","clearTimeout","cancelAnimationFrame","pauseAutoplay","resumeAutoplay","button","e","preventDefault","keydownHandler","indexOf","target","newIndex","key","focus","isUsingKeyboard","document","updateToggleState","controlsSelector","controls","querySelectorAll","toggleControl","toggleButton","control","controlType","controlButton","observer","IntersectionObserver","entries","entry","isIntersecting","threshold","observe","obs","tabWrappers","result","destroy","timerId","frameId","disconnect","removeEventListener"],"mappings":"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"}
|