From af3ab4c077bc4536952db0f22ac0f71b0a647275 Mon Sep 17 00:00:00 2001 From: Hamid Shoja Date: Wed, 6 Nov 2024 14:07:39 +0100 Subject: [PATCH 1/3] fix: add explicit debounce fallback --- packages/virtual-core/src/index.ts | 50 +++++++++++++++++------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/virtual-core/src/index.ts b/packages/virtual-core/src/index.ts index 2b3d4ff1..57b0adbe 100644 --- a/packages/virtual-core/src/index.ts +++ b/packages/virtual-core/src/index.ts @@ -133,6 +133,7 @@ const supportsScrollend = export const observeElementOffset = ( instance: Virtualizer, cb: (offset: number, isScrolling: boolean) => void, + debounceFallbackEnabled = false, ) => { const element = instance.scrollElement if (!element) { @@ -144,15 +145,16 @@ export const observeElementOffset = ( } let offset = 0 - const fallback = supportsScrollend - ? () => undefined - : debounce( - targetWindow, - () => { - cb(offset, false) - }, - instance.options.isScrollingResetDelay, - ) + const fallback = + !debounceFallbackEnabled && supportsScrollend + ? () => undefined + : debounce( + targetWindow, + () => { + cb(offset, false) + }, + instance.options.isScrollingResetDelay, + ) const createHandler = (isScrolling: boolean) => () => { const { horizontal, isRtl } = instance.options @@ -292,6 +294,7 @@ export interface VirtualizerOptions< observeElementOffset: ( instance: Virtualizer, cb: (offset: number, isScrolling: boolean) => void, + debounceFallbackEnabled?: boolean, ) => void | (() => void) // Optional @@ -334,6 +337,7 @@ export class Virtualizer< scrollElement: TScrollElement | null = null targetWindow: (Window & typeof globalThis) | null = null isScrolling = false + debounceFallbackEnabled = false private scrollToIndexTimeoutId: number | null = null measurementsCache: Array = [] private itemSizeCache = new Map() @@ -496,18 +500,22 @@ export class Virtualizer< ) this.unsubs.push( - this.options.observeElementOffset(this, (offset, isScrolling) => { - this.scrollAdjustments = 0 - this.scrollDirection = isScrolling - ? this.getScrollOffset() < offset - ? 'forward' - : 'backward' - : null - this.scrollOffset = offset - this.isScrolling = isScrolling - - this.maybeNotify() - }), + this.options.observeElementOffset( + this, + (offset, isScrolling) => { + this.scrollAdjustments = 0 + this.scrollDirection = isScrolling + ? this.getScrollOffset() < offset + ? 'forward' + : 'backward' + : null + this.scrollOffset = offset + this.isScrolling = isScrolling + + this.maybeNotify() + }, + this.debounceFallbackEnabled, + ), ) } } From a7effba1d0037d2eb64fdafd1f3fea573874da9b Mon Sep 17 00:00:00 2001 From: Hamid Shoja Date: Wed, 6 Nov 2024 16:29:44 +0100 Subject: [PATCH 2/3] review comments --- docs/api/virtualizer.md | 10 +++++++++ packages/virtual-core/src/index.ts | 36 +++++++++++++----------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/docs/api/virtualizer.md b/docs/api/virtualizer.md index ffa51478..6e23dc13 100644 --- a/docs/api/virtualizer.md +++ b/docs/api/virtualizer.md @@ -240,6 +240,16 @@ This option allows you to specify the duration to wait after the last scroll eve The implementation of this option is driven by the need for a reliable mechanism to handle scrolling behavior across different browsers. Until all browsers uniformly support the scrollEnd event. +### `useScrollendEvent` + +```tsx +useScrollendEvent: boolean +``` + +This option allows you to switch to use debounced fallback to reset the isScrolling instance property after `isScrollingResetDelay` milliseconds. The default value is `true`. + +The implementation of this option is driven by the need for a reliable mechanism to handle scrolling behavior across different browsers. Until all browsers uniformly support the scrollEnd event. + ### `isRtl` ```tsx diff --git a/packages/virtual-core/src/index.ts b/packages/virtual-core/src/index.ts index 57b0adbe..427b4356 100644 --- a/packages/virtual-core/src/index.ts +++ b/packages/virtual-core/src/index.ts @@ -133,7 +133,6 @@ const supportsScrollend = export const observeElementOffset = ( instance: Virtualizer, cb: (offset: number, isScrolling: boolean) => void, - debounceFallbackEnabled = false, ) => { const element = instance.scrollElement if (!element) { @@ -146,7 +145,7 @@ export const observeElementOffset = ( let offset = 0 const fallback = - !debounceFallbackEnabled && supportsScrollend + instance.options.useScrollendEvent && supportsScrollend ? () => undefined : debounce( targetWindow, @@ -294,9 +293,7 @@ export interface VirtualizerOptions< observeElementOffset: ( instance: Virtualizer, cb: (offset: number, isScrolling: boolean) => void, - debounceFallbackEnabled?: boolean, ) => void | (() => void) - // Optional debug?: boolean initialRect?: Rect @@ -324,6 +321,7 @@ export interface VirtualizerOptions< initialMeasurementsCache?: Array lanes?: number isScrollingResetDelay?: number + useScrollendEvent?: boolean enabled?: boolean isRtl?: boolean } @@ -337,7 +335,6 @@ export class Virtualizer< scrollElement: TScrollElement | null = null targetWindow: (Window & typeof globalThis) | null = null isScrolling = false - debounceFallbackEnabled = false private scrollToIndexTimeoutId: number | null = null measurementsCache: Array = [] private itemSizeCache = new Map() @@ -416,6 +413,7 @@ export class Virtualizer< isScrollingResetDelay: 150, enabled: true, isRtl: false, + useScrollendEvent: true, ...opts, } } @@ -500,22 +498,18 @@ export class Virtualizer< ) this.unsubs.push( - this.options.observeElementOffset( - this, - (offset, isScrolling) => { - this.scrollAdjustments = 0 - this.scrollDirection = isScrolling - ? this.getScrollOffset() < offset - ? 'forward' - : 'backward' - : null - this.scrollOffset = offset - this.isScrolling = isScrolling - - this.maybeNotify() - }, - this.debounceFallbackEnabled, - ), + this.options.observeElementOffset(this, (offset, isScrolling) => { + this.scrollAdjustments = 0 + this.scrollDirection = isScrolling + ? this.getScrollOffset() < offset + ? 'forward' + : 'backward' + : null + this.scrollOffset = offset + this.isScrolling = isScrolling + + this.maybeNotify() + }), ) } } From 85604b0ef6779d54b8c9d99be6b1f7d8c742a6d9 Mon Sep 17 00:00:00 2001 From: Hamid Shoja Date: Thu, 7 Nov 2024 11:19:05 +0100 Subject: [PATCH 3/3] add useScrollendEvent to observeWindowOffset --- packages/virtual-core/src/index.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/virtual-core/src/index.ts b/packages/virtual-core/src/index.ts index 427b4356..c66c8c92 100644 --- a/packages/virtual-core/src/index.ts +++ b/packages/virtual-core/src/index.ts @@ -130,9 +130,11 @@ export const observeWindowRect = ( const supportsScrollend = typeof window == 'undefined' ? true : 'onscrollend' in window +type ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void + export const observeElementOffset = ( instance: Virtualizer, - cb: (offset: number, isScrolling: boolean) => void, + cb: ObserveOffsetCallBack, ) => { const element = instance.scrollElement if (!element) { @@ -178,7 +180,7 @@ export const observeElementOffset = ( export const observeWindowOffset = ( instance: Virtualizer, - cb: (offset: number, isScrolling: boolean) => void, + cb: ObserveOffsetCallBack, ) => { const element = instance.scrollElement if (!element) { @@ -190,15 +192,16 @@ export const observeWindowOffset = ( } let offset = 0 - const fallback = supportsScrollend - ? () => undefined - : debounce( - targetWindow, - () => { - cb(offset, false) - }, - instance.options.isScrollingResetDelay, - ) + const fallback = + instance.options.useScrollendEvent && supportsScrollend + ? () => undefined + : debounce( + targetWindow, + () => { + cb(offset, false) + }, + instance.options.isScrollingResetDelay, + ) const createHandler = (isScrolling: boolean) => () => { offset = element[instance.options.horizontal ? 'scrollX' : 'scrollY'] @@ -292,7 +295,7 @@ export interface VirtualizerOptions< ) => void | (() => void) observeElementOffset: ( instance: Virtualizer, - cb: (offset: number, isScrolling: boolean) => void, + cb: ObserveOffsetCallBack, ) => void | (() => void) // Optional debug?: boolean