@@ -52,6 +52,7 @@ import {
5252 CustomizeComponent ,
5353 ColumnType ,
5454 CustomizeScrollBody ,
55+ TableSticky ,
5556} from './interface' ;
5657import TableContext from './context/TableContext' ;
5758import BodyContext from './context/BodyContext' ;
@@ -67,6 +68,8 @@ import Panel from './Panel';
6768import Footer , { FooterComponents } from './Footer' ;
6869import { findAllChildrenKeys , renderExpandIcon } from './utils/expandUtil' ;
6970import { getCellFixedInfo } from './utils/fixUtil' ;
71+ import StickyScrollBar from './stickyScrollBar' ;
72+ import useSticky from './hooks/useSticky' ;
7073
7174// Used for conditions cache
7275const EMPTY_DATA = [ ] ;
@@ -155,6 +158,8 @@ export interface TableProps<RecordType = unknown> extends LegacyExpandableProps<
155158 internalRefs ?: {
156159 body : React . MutableRefObject < HTMLDivElement > ;
157160 } ;
161+
162+ sticky ?: boolean | TableSticky ;
158163}
159164
160165function Table < RecordType extends DefaultRecordType > ( props : TableProps < RecordType > ) {
@@ -186,6 +191,8 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
186191 internalHooks,
187192 transformColumns,
188193 internalRefs,
194+
195+ sticky,
189196 } = props ;
190197
191198 const mergedData = data || EMPTY_DATA ;
@@ -377,6 +384,10 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
377384 const horizonScroll = scroll && validateValue ( scroll . x ) ;
378385 const fixColumn = horizonScroll && flattenColumns . some ( ( { fixed } ) => fixed ) ;
379386
387+ // Sticky
388+ const stickyRef = React . useRef < { setScrollLeft : ( left : number ) => void } > ( ) ;
389+ const { isSticky, offsetHeader, offsetScroll, stickyClassName } = useSticky ( sticky , prefixCls ) ;
390+
380391 let scrollXStyle : React . CSSProperties ;
381392 let scrollYStyle : React . CSSProperties ;
382393 let scrollTableStyle : React . CSSProperties ;
@@ -412,11 +423,16 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
412423
413424 const [ setScrollTarget , getScrollTarget ] = useTimeoutLock ( null ) ;
414425
415- function forceScroll ( scrollLeft : number , target : HTMLDivElement ) {
426+ function forceScroll ( scrollLeft : number , target : HTMLDivElement | ( ( left : number ) => void ) ) {
416427 /* eslint-disable no-param-reassign */
417- if ( target && target . scrollLeft !== scrollLeft ) {
418- target . scrollLeft = scrollLeft ;
428+ if ( target ) {
429+ if ( typeof target === 'function' ) {
430+ target ( scrollLeft ) ;
431+ } else if ( target . scrollLeft !== scrollLeft ) {
432+ target . scrollLeft = scrollLeft ;
433+ }
419434 }
435+
420436 /* eslint-enable */
421437 }
422438
@@ -432,6 +448,7 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
432448
433449 forceScroll ( mergedScrollLeft , scrollHeaderRef . current ) ;
434450 forceScroll ( mergedScrollLeft , scrollBodyRef . current ) ;
451+ forceScroll ( mergedScrollLeft , stickyRef . current ?. setScrollLeft ) ;
435452 }
436453
437454 if ( currentTarget ) {
@@ -495,6 +512,7 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
495512 columCount : flattenColumns . length ,
496513 stickyOffsets,
497514 onHeaderRow,
515+ fixHeader,
498516 } ;
499517
500518 // Empty
@@ -513,7 +531,7 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
513531 const bodyTable = (
514532 < Body
515533 data = { mergedData }
516- measureColumnWidth = { fixHeader || horizonScroll }
534+ measureColumnWidth = { fixHeader || horizonScroll || isSticky }
517535 expandedKeys = { mergedExpandedKeys }
518536 rowExpandable = { rowExpandable }
519537 getRowKey = { getRowKey }
@@ -539,7 +557,7 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
539557 warning ( false , '`components.body` with render props is only work on `scroll.y`.' ) ;
540558 }
541559
542- if ( fixHeader ) {
560+ if ( fixHeader || isSticky ) {
543561 let bodyContent : React . ReactNode ;
544562
545563 if ( typeof customizeScrollBody === 'function' ) {
@@ -581,6 +599,15 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
581599 { bodyTable }
582600 { footerTable }
583601 </ TableComponent >
602+
603+ { isSticky && (
604+ < StickyScrollBar
605+ ref = { stickyRef }
606+ offsetScroll = { offsetScroll }
607+ scrollBodyRef = { scrollBodyRef }
608+ onScroll = { onScroll }
609+ />
610+ ) }
584611 </ div >
585612 ) ;
586613 }
@@ -592,10 +619,13 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
592619 < div
593620 style = { {
594621 overflow : 'hidden' ,
622+ ...( isSticky ? { top : offsetHeader } : { } ) ,
595623 } }
596624 onScroll = { onScroll }
597625 ref = { scrollHeaderRef }
598- className = { classNames ( `${ prefixCls } -header` ) }
626+ className = { classNames ( `${ prefixCls } -header` , {
627+ [ stickyClassName ] : ! ! stickyClassName ,
628+ } ) }
599629 >
600630 < FixedHeader { ...headerProps } { ...columnContext } direction = { direction } />
601631 </ div >
0 commit comments