diff --git a/src/shared/lib/helpers/createVirtualizer/createVirtualizer.svelte.ts b/src/shared/lib/helpers/createVirtualizer/createVirtualizer.svelte.ts index aeb67a7..4b92eb3 100644 --- a/src/shared/lib/helpers/createVirtualizer/createVirtualizer.svelte.ts +++ b/src/shared/lib/helpers/createVirtualizer/createVirtualizer.svelte.ts @@ -202,6 +202,16 @@ export function createVirtualizer( }); } + // console.log('🎯 Virtual Items Calculation:', { + // scrollOffset, + // containerHeight, + // viewportEnd, + // startIdx, + // endIdx, + // withOverscan: { start, end }, + // itemCount: end - start, + // }); + return result; }); // Svelte Actions (The DOM Interface) @@ -225,32 +235,48 @@ export function createVirtualizer( return rect.top + window.scrollY; }; - let cachedOffsetTop = getElementOffset(); + let cachedOffsetTop = 0; + let rafId: number | null = null; containerHeight = window.innerHeight; const handleScroll = () => { - // Use cached offset for scroll calculations - scrollOffset = Math.max(0, window.scrollY - cachedOffsetTop); + if (rafId !== null) return; + + rafId = requestAnimationFrame(() => { + // Get current position of element relative to viewport + const rect = node.getBoundingClientRect(); + // Calculate how much of the element has scrolled past the top of viewport + // When element.top is 0, element is at top of viewport + // When element.top is -100, element has scrolled up 100px past viewport top + const scrolledPastTop = Math.max(0, -rect.top); + scrollOffset = scrolledPastTop; + rafId = null; + }); + + // 🔍 DIAGNOSTIC + // console.log('📜 Scroll Event:', { + // windowScrollY: window.scrollY, + // elementRectTop: rect.top, + // scrolledPastTop, + // containerHeight + // }); }; const handleResize = () => { - const oldHeight = containerHeight; containerHeight = window.innerHeight; - - // Recalculate offset on resize (layout may have shifted) - const newOffsetTop = getElementOffset(); - if (Math.abs(newOffsetTop - cachedOffsetTop) > 0.5) { - cachedOffsetTop = newOffsetTop; - handleScroll(); // Recalculate scroll position - } + cachedOffsetTop = getElementOffset(); + handleScroll(); }; + // Initial setup + requestAnimationFrame(() => { + cachedOffsetTop = getElementOffset(); + handleScroll(); + }); + window.addEventListener('scroll', handleScroll, { passive: true }); window.addEventListener('resize', handleResize); - // Initial calculation - handleScroll(); - return { destroy() { window.removeEventListener('scroll', handleScroll); @@ -259,6 +285,10 @@ export function createVirtualizer( cancelAnimationFrame(frameId); frameId = null; } + if (rafId !== null) { + cancelAnimationFrame(rafId); + rafId = null; + } elementRef = null; }, }; @@ -366,6 +396,12 @@ export function createVirtualizer( } return { + get scrollOffset() { + return scrollOffset; + }, + get containerHeight() { + return containerHeight; + }, /** Computed array of visible items to render (reactive) */ get items() { return items;