@@ -15,6 +15,7 @@ import type {
1515 RenderErrorMessage ,
1616} from './types' ;
1717import { useScrollBasedChunks } from './useScrollBasedChunks' ;
18+ import { calculateElementOffsetTop } from './utils' ;
1819
1920import './PaginatedTable.scss' ;
2021
@@ -62,13 +63,15 @@ export const PaginatedTable = <T, F>({
6263 const { sortParams, foundEntities} = tableState ;
6364
6465 const tableRef = React . useRef < HTMLDivElement > ( null ) ;
66+ const [ tableOffset , setTableOffset ] = React . useState ( 0 ) ;
6567
66- const activeChunks = useScrollBasedChunks ( {
68+ const chunkStates = useScrollBasedChunks ( {
6769 scrollContainerRef,
6870 tableRef,
6971 totalItems : foundEntities ,
7072 rowHeight,
7173 chunkSize,
74+ tableOffset,
7275 } ) ;
7376
7477 // this prevent situation when filters are new, but active chunks is not yet recalculated (it will be done to the next rendrer, so we bring filters change on the next render too)
@@ -99,6 +102,25 @@ export const PaginatedTable = <T, F>({
99102 [ onDataFetched , setFoundEntities , setIsInitialLoad , setTotalEntities ] ,
100103 ) ;
101104
105+ React . useLayoutEffect ( ( ) => {
106+ const scrollContainer = scrollContainerRef . current ;
107+ const table = tableRef . current ;
108+ if ( table && scrollContainer ) {
109+ setTableOffset ( calculateElementOffsetTop ( table , scrollContainer ) ) ;
110+ }
111+ } , [ scrollContainerRef . current , tableRef . current , foundEntities ] ) ;
112+
113+ // Set will-change: transform on scroll container if not already set
114+ React . useLayoutEffect ( ( ) => {
115+ const scrollContainer = scrollContainerRef . current ;
116+ if ( scrollContainer ) {
117+ const computedStyle = window . getComputedStyle ( scrollContainer ) ;
118+ if ( computedStyle . willChange !== 'transform' ) {
119+ scrollContainer . style . willChange = 'transform' ;
120+ }
121+ }
122+ } , [ scrollContainerRef . current ] ) ;
123+
102124 // Reset table on initialization and filters change
103125 React . useLayoutEffect ( ( ) => {
104126 const defaultTotal = initialEntitiesCount || 0 ;
@@ -110,32 +132,71 @@ export const PaginatedTable = <T, F>({
110132 } , [ initialEntitiesCount , setTotalEntities , setFoundEntities , setIsInitialLoad ] ) ;
111133
112134 const renderChunks = ( ) => {
113- return activeChunks . map ( ( isActive , index ) => (
114- < TableChunk < T , F >
115- key = { index }
116- id = { index }
117- calculatedCount = { index === activeChunks . length - 1 ? lastChunkSize : chunkSize }
118- chunkSize = { chunkSize }
119- rowHeight = { rowHeight }
120- columns = { columns }
121- fetchData = { fetchData }
122- filters = { filters }
123- tableName = { tableName }
124- sortParams = { sortParams }
125- getRowClassName = { getRowClassName }
126- renderErrorMessage = { renderErrorMessage }
127- renderEmptyDataMessage = { renderEmptyDataMessage }
128- onDataFetched = { handleDataFetched }
129- isActive = { isActive }
130- keepCache = { keepCache }
131- />
132- ) ) ;
135+ const chunks : React . ReactElement [ ] = [ ] ;
136+ let i = 0 ;
137+
138+ while ( i < chunkStates . length ) {
139+ const chunkState = chunkStates [ i ] ;
140+ const shouldRender = chunkState . shouldRender ;
141+ const shouldFetch = chunkState . shouldFetch ;
142+ const isActive = shouldRender || shouldFetch ;
143+
144+ if ( isActive ) {
145+ // Render active chunk normally
146+ chunks . push (
147+ < TableChunk < T , F >
148+ key = { i }
149+ id = { i }
150+ calculatedCount = { i === chunkStates . length - 1 ? lastChunkSize : chunkSize }
151+ chunkSize = { chunkSize }
152+ rowHeight = { rowHeight }
153+ columns = { columns }
154+ fetchData = { fetchData }
155+ filters = { filters }
156+ tableName = { tableName }
157+ sortParams = { sortParams }
158+ getRowClassName = { getRowClassName }
159+ renderErrorMessage = { renderErrorMessage }
160+ renderEmptyDataMessage = { renderEmptyDataMessage }
161+ onDataFetched = { handleDataFetched }
162+ shouldFetch = { chunkState . shouldFetch }
163+ shouldRender = { chunkState . shouldRender }
164+ keepCache = { keepCache }
165+ /> ,
166+ ) ;
167+ i ++ ;
168+ } else {
169+ // Find consecutive inactive chunks and merge them
170+ const startIndex = i ;
171+ let totalHeight = 0 ;
172+
173+ while (
174+ i < chunkStates . length &&
175+ ! chunkStates [ i ] . shouldRender &&
176+ ! chunkStates [ i ] . shouldFetch
177+ ) {
178+ const currentChunkSize =
179+ i === chunkStates . length - 1 ? lastChunkSize : chunkSize ;
180+ totalHeight += currentChunkSize * rowHeight ;
181+ i ++ ;
182+ }
183+
184+ // Render merged empty tbody for consecutive inactive chunks
185+ chunks . push (
186+ < tr style = { { height : `${ totalHeight } px` } } key = { `merged-${ startIndex } -${ i - 1 } ` } >
187+ < td colSpan = { columns . length } style = { { padding : 0 , border : 'none' } } />
188+ </ tr > ,
189+ ) ;
190+ }
191+ }
192+
193+ return chunks ;
133194 } ;
134195
135196 const renderTable = ( ) => (
136197 < table className = { b ( 'table' ) } >
137198 < TableHead columns = { columns } onSort = { setSortParams } onColumnsResize = { onColumnsResize } />
138- { renderChunks ( ) }
199+ < tbody > { renderChunks ( ) } </ tbody >
139200 </ table >
140201 ) ;
141202
0 commit comments