1- import { useState } from 'react' ;
1+ import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
2+
3+ import type {
4+ HandleTableColumnsResize ,
5+ TableColumnsWidthSetup ,
6+ } from '../../utils/hooks/useTableResize' ;
27
38import type { Column , OnSort , SortOrderType , SortParams } from './types' ;
49import { ASCENDING , DEFAULT_SORT_ORDER , DEFAULT_TABLE_ROW_HEIGHT , DESCENDING } from './constants' ;
510import { b } from './shared' ;
611
12+ const COLUMN_NAME_HTML_ATTRIBUTE = 'data-columnname' ;
13+
714// Icon similar to original DataTable icons to keep the same tables across diferent pages and tabs
815const SortIcon = ( { order} : { order ?: SortOrderType } ) => {
916 return (
1017 < svg
11- className = { b ( 'icon' , { desc : order === DESCENDING } ) }
18+ className = { b ( 'sort- icon' , { desc : order === DESCENDING } ) }
1219 viewBox = "0 0 10 6"
1320 width = "10"
1421 height = "6"
@@ -27,7 +34,7 @@ interface ColumnSortIconProps {
2734const ColumnSortIcon = ( { sortOrder, sortable, defaultSortOrder} : ColumnSortIconProps ) => {
2835 if ( sortable ) {
2936 return (
30- < span className = { b ( 'sort-icon' , { shadow : ! sortOrder } ) } >
37+ < span className = { b ( 'sort-icon-container ' , { shadow : ! sortOrder } ) } >
3138 < SortIcon order = { sortOrder || defaultSortOrder } />
3239 </ span >
3340 ) ;
@@ -36,21 +43,129 @@ const ColumnSortIcon = ({sortOrder, sortable, defaultSortOrder}: ColumnSortIconP
3643 }
3744} ;
3845
46+ interface TableHeadCellProps < T > {
47+ column : Column < T > ;
48+ sortOrder ?: SortOrderType ;
49+ defaultSortOrder : SortOrderType ;
50+ onSort ?: ( columnName : string ) => void ;
51+ rowHeight : number ;
52+ onCellMount ?: ( element : Element ) => void ;
53+ onCellUnMount ?: ( element : Element ) => void ;
54+ }
55+
56+ export const TableHeadCell = < T , > ( {
57+ column,
58+ sortOrder,
59+ defaultSortOrder,
60+ onSort,
61+ rowHeight,
62+ onCellMount,
63+ onCellUnMount,
64+ } : TableHeadCellProps < T > ) => {
65+ const cellWrapperRef = useRef < HTMLDivElement > ( null ) ;
66+
67+ useEffect ( ( ) => {
68+ const cellWrapper = cellWrapperRef . current ;
69+ if ( cellWrapper ) {
70+ onCellMount ?.( cellWrapper ) ;
71+ }
72+ return ( ) => {
73+ if ( cellWrapper ) {
74+ onCellUnMount ?.( cellWrapper ) ;
75+ }
76+ } ;
77+ } , [ onCellMount , onCellUnMount ] ) ;
78+
79+ const content = column . header ?? column . name ;
80+
81+ return (
82+ < th >
83+ < div
84+ ref = { cellWrapperRef }
85+ className = { b ( 'head-cell-wrapper' , {
86+ resizeable : column . resizeable ,
87+ } ) }
88+ style = { {
89+ height : `${ rowHeight } px` ,
90+ width : `${ column . width } px` ,
91+ } }
92+ { ...{
93+ [ COLUMN_NAME_HTML_ATTRIBUTE ] : column . name ,
94+ } }
95+ >
96+ < div
97+ className = { b (
98+ 'head-cell' ,
99+ { align : column . align , sortable : column . sortable } ,
100+ column . className ,
101+ ) }
102+ onClick = { ( ) => {
103+ if ( column . sortable ) {
104+ onSort ?.( column . name ) ;
105+ }
106+ } }
107+ >
108+ < div className = { b ( 'head-cell-content' ) } > { content } </ div >
109+ < ColumnSortIcon
110+ sortOrder = { sortOrder }
111+ sortable = { column . sortable }
112+ defaultSortOrder = { defaultSortOrder }
113+ />
114+ </ div >
115+ </ div >
116+ </ th >
117+ ) ;
118+ } ;
119+
39120interface TableHeadProps < T > {
40121 columns : Column < T > [ ] ;
41122 onSort ?: OnSort ;
123+ onColumnsResize ?: HandleTableColumnsResize ;
42124 defaultSortOrder ?: SortOrderType ;
43125 rowHeight ?: number ;
44126}
45127
46128export const TableHead = < T , > ( {
47129 columns,
48130 onSort,
131+ onColumnsResize,
49132 defaultSortOrder = DEFAULT_SORT_ORDER ,
50133 rowHeight = DEFAULT_TABLE_ROW_HEIGHT ,
51134} : TableHeadProps < T > ) => {
52135 const [ sortParams , setSortParams ] = useState < SortParams > ( { } ) ;
53136
137+ const isTableResizeable = Boolean ( onColumnsResize ) ;
138+
139+ const resizeObserver : ResizeObserver | undefined = useMemo ( ( ) => {
140+ if ( ! isTableResizeable ) {
141+ return undefined ;
142+ }
143+
144+ return new ResizeObserver ( ( entries ) => {
145+ const columnsWidth : TableColumnsWidthSetup = { } ;
146+ entries . forEach ( ( entry ) => {
147+ // @ts -ignore ignore custrom property usage
148+ const id = entry . target . attributes [ COLUMN_NAME_HTML_ATTRIBUTE ] ?. value ;
149+ columnsWidth [ id ] = entry . contentRect . width ;
150+ } ) ;
151+
152+ onColumnsResize ?.( columnsWidth ) ;
153+ } ) ;
154+ } , [ onColumnsResize , isTableResizeable ] ) ;
155+
156+ const handleCellMount = useCallback (
157+ ( element : Element ) => {
158+ resizeObserver ?. observe ( element ) ;
159+ } ,
160+ [ resizeObserver ] ,
161+ ) ;
162+ const handleCellUnMount = useCallback (
163+ ( element : Element ) => {
164+ resizeObserver ?. unobserve ( element ) ;
165+ } ,
166+ [ resizeObserver ] ,
167+ ) ;
168+
54169 const handleSort = ( columnId : string ) => {
55170 let newSortParams : SortParams = { } ;
56171
@@ -95,34 +210,20 @@ export const TableHead = <T,>({
95210 < thead className = { b ( 'head' ) } >
96211 < tr >
97212 { columns . map ( ( column ) => {
98- const content = column . header ?? column . name ;
99213 const sortOrder =
100214 sortParams . columnId === column . name ? sortParams . sortOrder : undefined ;
101215
102216 return (
103- < th
217+ < TableHeadCell
104218 key = { column . name }
105- className = { b (
106- 'th' ,
107- { align : column . align , sortable : column . sortable } ,
108- column . className ,
109- ) }
110- style = { {
111- height : `${ rowHeight } px` ,
112- } }
113- onClick = { ( ) => {
114- handleSort ( column . name ) ;
115- } }
116- >
117- < div className = { b ( 'head-cell' ) } >
118- { content }
119- < ColumnSortIcon
120- sortOrder = { sortOrder }
121- sortable = { column . sortable }
122- defaultSortOrder = { defaultSortOrder }
123- />
124- </ div >
125- </ th >
219+ column = { column }
220+ sortOrder = { sortOrder }
221+ defaultSortOrder = { defaultSortOrder }
222+ onSort = { handleSort }
223+ rowHeight = { rowHeight }
224+ onCellMount = { handleCellMount }
225+ onCellUnMount = { handleCellUnMount }
226+ />
126227 ) ;
127228 } ) }
128229 </ tr >
0 commit comments