feat(scroller): Enhance Scroller class with callback execution and adaptive scroll listener
This commit is contained in:
		| @@ -1,5 +1,12 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 2025-01-31 - 2.3.0 - feat(scroller) | ||||
| Enhance Scroller class with callback execution and adaptive scroll listener | ||||
|  | ||||
| - Added support for executing scroll callbacks in the Scroller class. | ||||
| - Integrated adaptive scrolling mechanism using Lenis, with native smooth scrolling detection. | ||||
| - Ensured seamless switching between native scroll listener and Lenis scroll listener. | ||||
|  | ||||
| ## 2025-01-31 - 2.2.0 - feat(core) | ||||
| Enhance scrolling capabilities by integrating Scroller class and adding lenis support | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@design.estate/dees-domtools', | ||||
|   version: '2.2.0', | ||||
|   version: '2.3.0', | ||||
|   description: 'A package providing tools to simplify complex CSS structures and web development tasks, featuring TypeScript support and integration with various web technologies.' | ||||
| } | ||||
|   | ||||
| @@ -4,16 +4,32 @@ import * as plugins from './domtools.plugins.js'; | ||||
| export class Scroller { | ||||
|   public domtoolsInstance: DomTools; | ||||
|  | ||||
|   constructor( | ||||
|     domtoolsInstanceArg: DomTools, | ||||
|   ) { | ||||
|   // Array to store scroll callback functions. | ||||
|   private scrollCallbacks: Array<() => void> = []; | ||||
|  | ||||
|   // Lenis instance (if activated) or null. | ||||
|   private lenisInstance: plugins.Lenis | null = null; | ||||
|  | ||||
|   // Bound handlers to allow removal from event listeners. | ||||
|   private handleNativeScroll = (event: Event): void => { | ||||
|     this.executeScrollCallbacks(); | ||||
|   }; | ||||
|  | ||||
|   private handleLenisScroll = (info: any): void => { | ||||
|     this.executeScrollCallbacks(); | ||||
|   }; | ||||
|  | ||||
|   constructor(domtoolsInstanceArg: DomTools) { | ||||
|     this.domtoolsInstance = domtoolsInstanceArg; | ||||
|     // Attach the native scroll listener by default. | ||||
|     this.attachNativeScrollListener(); | ||||
|   } | ||||
|  | ||||
|   private sweetScroller = new plugins.SweetScroll({ | ||||
|     /* some options */ | ||||
|   }); // TODO: switch to scroller class | ||||
|   private sweetScroller = new plugins.SweetScroll({}); | ||||
|  | ||||
|   /** | ||||
|    * Scrolls to a given element with options. | ||||
|    */ | ||||
|   public async scrollToElement( | ||||
|     elementArg: HTMLElement, | ||||
|     optionsArg: Parameters<typeof this.sweetScroller.toElement>[1] | ||||
| @@ -22,6 +38,9 @@ export class Scroller { | ||||
|     await plugins.smartdelay.delayFor(optionsArg.duration); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Detects whether native smooth scrolling is enabled. | ||||
|    */ | ||||
|   public async detectNativeSmoothScroll() { | ||||
|     const done = plugins.smartpromise.defer<boolean>(); | ||||
|     const sampleSize = 100; | ||||
| @@ -64,14 +83,93 @@ export class Scroller { | ||||
|     return done.promise; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Enables Lenis scrolling. | ||||
|    * If optionsArg.disableOnNativeSmoothScroll is true and native smooth scrolling is detected, | ||||
|    * Lenis will be destroyed immediately. | ||||
|    */ | ||||
|   public async enableLenisScroll(optionsArg?: { disableOnNativeSmoothScroll?: boolean }) { | ||||
|     const lenis = new plugins.Lenis({ | ||||
|       autoRaf: true, | ||||
|     }); | ||||
|  | ||||
|     if (optionsArg?.disableOnNativeSmoothScroll) { | ||||
|       if (await this.detectNativeSmoothScroll()) { | ||||
|         lenis.destroy(); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Activate Lenis scrolling. | ||||
|     this.lenisInstance = lenis; | ||||
|     // Switch from native scroll listener to Lenis scroll listener. | ||||
|     this.detachNativeScrollListener(); | ||||
|     this.attachLenisScrollListener(); | ||||
|  | ||||
|     // Monkey-patch the destroy method so that when Lenis is destroyed, | ||||
|     // the native scroll listener is reattached. | ||||
|     const originalDestroy = lenis.destroy.bind(lenis); | ||||
|     lenis.destroy = () => { | ||||
|       originalDestroy(); | ||||
|       this.detachLenisScrollListener(); | ||||
|       this.attachNativeScrollListener(); | ||||
|       this.lenisInstance = null; | ||||
|     }; | ||||
|   } | ||||
| } | ||||
|  | ||||
|   /** | ||||
|    * Registers a callback to be executed on scroll. | ||||
|    * @param callback A function to execute on each scroll event. | ||||
|    */ | ||||
|   public onScroll(callback: () => void): void { | ||||
|     this.scrollCallbacks.push(callback); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Executes all registered scroll callbacks concurrently. | ||||
|    */ | ||||
|   private executeScrollCallbacks(): void { | ||||
|     // Execute all callbacks in parallel. | ||||
|     this.scrollCallbacks.forEach((callback) => { | ||||
|       try { | ||||
|         callback(); | ||||
|       } catch (error) { | ||||
|         console.error('Error in scroll callback:', error); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Attaches the native scroll event listener. | ||||
|    */ | ||||
|   private attachNativeScrollListener(): void { | ||||
|     window.addEventListener('scroll', this.handleNativeScroll, { passive: true }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Detaches the native scroll event listener. | ||||
|    */ | ||||
|   private detachNativeScrollListener(): void { | ||||
|     window.removeEventListener('scroll', this.handleNativeScroll); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Attaches the Lenis scroll event listener. | ||||
|    */ | ||||
|   private attachLenisScrollListener(): void { | ||||
|     if (this.lenisInstance) { | ||||
|       // Assuming that Lenis exposes an `on` method to listen to scroll events. | ||||
|       this.lenisInstance.on('scroll', this.handleLenisScroll); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Detaches the Lenis scroll event listener. | ||||
|    */ | ||||
|   private detachLenisScrollListener(): void { | ||||
|     if (this.lenisInstance) { | ||||
|       // Assuming that Lenis exposes an `off` method to remove scroll event listeners. | ||||
|       this.lenisInstance.off('scroll', this.handleLenisScroll); | ||||
|     } | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user