@@ -50,6 +50,7 @@ import {
5050 RowClassName ,
5151 CustomizeComponent ,
5252 ColumnType ,
53+ CustomizeScrollBody ,
5354} from './interface' ;
5455import TableContext from './context/TableContext' ;
5556import BodyContext from './context/BodyContext' ;
@@ -68,6 +69,9 @@ import { findAllChildrenKeys, renderExpandIcon } from './utils/expandUtil';
6869// Used for conditions cache
6970const EMPTY_DATA = [ ] ;
7071
72+ // Used for customize scroll
73+ const EMPTY_SCROLL_TARGET = { } ;
74+
7175export const INTERNAL_HOOKS = 'rc-table-internal-hook' ;
7276
7377export interface TableProps < RecordType extends DefaultRecordType >
@@ -98,7 +102,7 @@ export interface TableProps<RecordType extends DefaultRecordType>
98102 // Customize
99103 id ?: string ;
100104 showHeader ?: boolean ;
101- components ?: TableComponents ;
105+ components ?: TableComponents < RecordType > ;
102106 onRow ?: GetComponentProps < RecordType > ;
103107 onHeaderRow ?: GetComponentProps < ColumnType < RecordType > [ ] > ;
104108 emptyText ?: React . ReactNode | ( ( ) => React . ReactNode ) ;
@@ -188,13 +192,15 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
188192 }
189193
190194 // ==================== Customize =====================
191- const mergedComponents = React . useMemo ( ( ) => mergeObject < TableComponents > ( components , { } ) , [
192- components ,
193- ] ) ;
195+ const mergedComponents = React . useMemo (
196+ ( ) => mergeObject < TableComponents < RecordType > > ( components , { } ) ,
197+ [ components ] ,
198+ ) ;
194199
195200 const getComponent = React . useCallback < GetComponent > (
196201 ( path , defaultComponent ) =>
197- getPathValue < CustomizeComponent , TableComponents > ( mergedComponents , path ) || defaultComponent ,
202+ getPathValue < CustomizeComponent , TableComponents < RecordType >> ( mergedComponents , path ) ||
203+ defaultComponent ,
198204 [ mergedComponents ] ,
199205 ) ;
200206
@@ -354,18 +360,25 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
354360 /* eslint-enable */
355361 }
356362
357- const onScroll : React . UIEventHandler < HTMLDivElement > = ( { currentTarget } ) => {
358- const { scrollLeft, scrollWidth, clientWidth } = currentTarget ;
363+ const onScroll = ( {
364+ currentTarget,
365+ scrollLeft,
366+ } : React . UIEvent < HTMLDivElement > & { scrollLeft ?: number } ) => {
367+ const mergedScrollLeft = typeof scrollLeft === 'number' ? scrollLeft : currentTarget . scrollLeft ;
359368
360- if ( ! getScrollTarget ( ) || getScrollTarget ( ) === currentTarget ) {
361- setScrollTarget ( currentTarget ) ;
369+ const compareTarget = currentTarget || EMPTY_SCROLL_TARGET ;
370+ if ( ! getScrollTarget ( ) || getScrollTarget ( ) === compareTarget ) {
371+ setScrollTarget ( compareTarget ) ;
362372
363- forceScroll ( scrollLeft , scrollHeaderRef . current ) ;
364- forceScroll ( scrollLeft , scrollBodyRef . current ) ;
373+ forceScroll ( mergedScrollLeft , scrollHeaderRef . current ) ;
374+ forceScroll ( mergedScrollLeft , scrollBodyRef . current ) ;
365375 }
366376
367- setPingedLeft ( scrollLeft > 0 ) ;
368- setPingedRight ( scrollLeft < scrollWidth - clientWidth ) ;
377+ if ( currentTarget ) {
378+ const { scrollWidth, clientWidth } = currentTarget ;
379+ setPingedLeft ( mergedScrollLeft > 0 ) ;
380+ setPingedRight ( mergedScrollLeft < scrollWidth - clientWidth ) ;
381+ }
369382 } ;
370383
371384 const triggerOnScroll = ( ) => {
@@ -451,26 +464,40 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
451464 ) ;
452465
453466 const footerTable = summary && < Footer > { summary ( mergedData ) } </ Footer > ;
467+ const customizeScrollBody = getComponent ( [ 'body' ] ) as CustomizeScrollBody < RecordType > ;
468+
469+ if (
470+ process . env . NODE_ENV !== 'production' &&
471+ typeof customizeScrollBody === 'function' &&
472+ ! fixHeader
473+ ) {
474+ warning ( false , '`components.body` with render props is only work on `scroll.y`.' ) ;
475+ }
454476
455477 if ( fixHeader ) {
456- groupTableNode = (
457- < >
458- { /* Header Table */ }
459- { showHeader !== false && (
460- < div
461- style = { {
462- ...scrollXStyle ,
463- marginBottom : fixColumn ? - scrollbarSize : null ,
464- } }
465- onScroll = { onScroll }
466- ref = { scrollHeaderRef }
467- className = { classNames ( `${ prefixCls } -header` ) }
468- >
469- < FixedHeader { ...headerProps } { ...columnContext } />
470- </ div >
471- ) }
478+ let bodyContent : React . ReactNode ;
472479
473- { /* Body Table */ }
480+ if ( typeof customizeScrollBody === 'function' ) {
481+ bodyContent = customizeScrollBody ( mergedData , {
482+ scrollbarSize,
483+ ref : scrollBodyRef ,
484+ onScroll,
485+ } ) ;
486+ headerProps . colWidths = flattenColumns . map ( ( { width } , index ) => {
487+ const colWidth = index === columns . length - 1 ? ( width as number ) - scrollbarSize : width ;
488+
489+ if ( typeof colWidth === 'number' && ! Number . isNaN ( colWidth ) ) {
490+ return colWidth ;
491+ }
492+ warning (
493+ false ,
494+ 'When use `components.body` with render props. Each column should have a fixed value.' ,
495+ ) ;
496+
497+ return 0 ;
498+ } ) as number [ ] ;
499+ } else {
500+ bodyContent = (
474501 < div
475502 style = { {
476503 ...scrollXStyle ,
@@ -491,6 +518,28 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
491518 { footerTable }
492519 </ TableComponent >
493520 </ div >
521+ ) ;
522+ }
523+
524+ groupTableNode = (
525+ < >
526+ { /* Header Table */ }
527+ { showHeader !== false && (
528+ < div
529+ style = { {
530+ ...scrollXStyle ,
531+ marginBottom : fixColumn ? - scrollbarSize : null ,
532+ } }
533+ onScroll = { onScroll }
534+ ref = { scrollHeaderRef }
535+ className = { classNames ( `${ prefixCls } -header` ) }
536+ >
537+ < FixedHeader { ...headerProps } { ...columnContext } />
538+ </ div >
539+ ) }
540+
541+ { /* Body Table */ }
542+ { bodyContent }
494543 </ >
495544 ) ;
496545 } else {
0 commit comments