@@ -13,6 +13,13 @@ interface UseScrollBasedChunksProps {
1313 overscanCount ?: number ;
1414}
1515
16+ export interface VisibleRange {
17+ startChunk : number ;
18+ endChunk : number ;
19+ startRow : number ;
20+ endRow : number ;
21+ }
22+
1623const DEFAULT_OVERSCAN_COUNT = 1 ;
1724const THROTTLE_DELAY = 100 ;
1825
@@ -23,7 +30,7 @@ export const useScrollBasedChunks = ({
2330 rowHeight,
2431 chunkSize,
2532 overscanCount = DEFAULT_OVERSCAN_COUNT ,
26- } : UseScrollBasedChunksProps ) : boolean [ ] => {
33+ } : UseScrollBasedChunksProps ) : [ boolean [ ] , VisibleRange ] => {
2734 const chunksCount = React . useMemo (
2835 ( ) => Math . ceil ( totalItems / chunkSize ) ,
2936 [ chunkSize , totalItems ] ,
@@ -34,6 +41,12 @@ export const useScrollBasedChunks = ({
3441 Math . min ( overscanCount , Math . max ( chunksCount - 1 , 0 ) ) ,
3542 ) ;
3643
44+ // Track exact visible rows (not just chunks)
45+ const [ startRow , setStartRow ] = React . useState ( 0 ) ;
46+ const [ endRow , setEndRow ] = React . useState (
47+ Math . min ( overscanCount * chunkSize , Math . max ( totalItems - 1 , 0 ) ) ,
48+ ) ;
49+
3750 const calculateVisibleRange = React . useCallback ( ( ) => {
3851 const container = parentRef ?. current ;
3952 const table = tableRef . current ;
@@ -46,20 +59,38 @@ export const useScrollBasedChunks = ({
4659 const visibleStart = Math . max ( containerScroll - tableOffset , 0 ) ;
4760 const visibleEnd = visibleStart + container . clientHeight ;
4861
49- const start = Math . max ( Math . floor ( visibleStart / rowHeight / chunkSize ) - overscanCount , 0 ) ;
50- const end = Math . min (
62+ // Calculate visible chunks (with overscan)
63+ const startChunk = Math . max (
64+ Math . floor ( visibleStart / rowHeight / chunkSize ) - overscanCount ,
65+ 0 ,
66+ ) ;
67+ const endChunk = Math . min (
5168 Math . floor ( visibleEnd / rowHeight / chunkSize ) + overscanCount ,
5269 Math . max ( chunksCount - 1 , 0 ) ,
5370 ) ;
5471
55- return { start, end} ;
72+ // Calculate visible rows (more precise)
73+ const startRowIndex = Math . max ( Math . floor ( visibleStart / rowHeight ) , 0 ) ;
74+ const endRowIndex = Math . min (
75+ Math . floor ( visibleEnd / rowHeight ) ,
76+ Math . max ( totalItems - 1 , 0 ) ,
77+ ) ;
78+
79+ return {
80+ start : startChunk ,
81+ end : endChunk ,
82+ startRow : startRowIndex ,
83+ endRow : endRowIndex ,
84+ } ;
5685 } , [ parentRef , tableRef , rowHeight , chunkSize , overscanCount , chunksCount ] ) ;
5786
5887 const handleScroll = React . useCallback ( ( ) => {
5988 const newRange = calculateVisibleRange ( ) ;
6089 if ( newRange ) {
6190 setStartChunk ( newRange . start ) ;
6291 setEndChunk ( newRange . end ) ;
92+ setStartRow ( newRange . startRow ) ;
93+ setEndRow ( newRange . endRow ) ;
6394 }
6495 } , [ calculateVisibleRange ] ) ;
6596
@@ -81,12 +112,24 @@ export const useScrollBasedChunks = ({
81112 } ;
82113 } , [ handleScroll , parentRef ] ) ;
83114
84- return React . useMemo ( ( ) => {
115+ // Create the visibility information
116+ const activeChunks = React . useMemo ( ( ) => {
85117 // boolean array that represents active chunks
86- const activeChunks = Array ( chunksCount ) . fill ( false ) ;
118+ const chunks = Array ( chunksCount ) . fill ( false ) ;
87119 for ( let i = startChunk ; i <= endChunk ; i ++ ) {
88- activeChunks [ i ] = true ;
120+ chunks [ i ] = true ;
89121 }
90- return activeChunks ;
122+ return chunks ;
91123 } , [ chunksCount , startChunk , endChunk ] ) ;
124+
125+ const visibleRange = React . useMemo ( ( ) => {
126+ return {
127+ startChunk,
128+ endChunk,
129+ startRow,
130+ endRow,
131+ } ;
132+ } , [ startChunk , endChunk , startRow , endRow ] ) ;
133+
134+ return [ activeChunks , visibleRange ] ;
92135} ;
0 commit comments