@@ -10,163 +10,169 @@ const approximateHeaderPxFromCharLength = (charLength) =>
1010 charLength < 15 ? Math . sqrt ( charLength * 1500 ) : 8 * charLength ;
1111const approximateContentPxFromCharLength = ( charLength ) => 8 * charLength ;
1212
13- export const useDynamicColumnWidths = ( hooks ) => {
14- hooks . columns . push ( ( columns , { instance } ) => {
15- if ( ! instance . state || ! instance . rows ) {
16- return columns ;
17- }
18-
19- const { rows, state } = instance ;
20-
21- const { hiddenColumns, tableClientWidth : totalWidth } = state ;
22- const { scaleWidthMode, loading } = instance . webComponentsReactProperties ;
13+ const columnsDeps = ( deps , { instance : { state, webComponentsReactProperties } } ) => [
14+ ...deps ,
15+ state . tableClientWidth ,
16+ webComponentsReactProperties . scaleWidthMode ,
17+ webComponentsReactProperties . loading
18+ ] ;
2319
24- const visibleColumns = columns . filter ( Boolean ) . filter ( ( item ) => {
25- return ( item . isVisible ?? true ) && ! hiddenColumns . includes ( item . accessor ) ;
26- } ) ;
20+ const columns = ( columns , { instance } ) => {
21+ if ( ! instance . state || ! instance . rows ) {
22+ return columns ;
23+ }
2724
28- const calculateDefaultTableWidth = ( ) => {
29- const columnsWithFixedWidth = visibleColumns . filter ( ( { width } ) => width ?? false ) . map ( ( { width } ) => width ) ;
30- const fixedWidth = columnsWithFixedWidth . reduce ( ( acc , val ) => acc + val , 0 ) ;
25+ const { rows, state } = instance ;
3126
32- const defaultColumnsCount = visibleColumns . length - columnsWithFixedWidth . length ;
27+ const { hiddenColumns, tableClientWidth : totalWidth } = state ;
28+ const { scaleWidthMode, loading } = instance . webComponentsReactProperties ;
3329
34- // check if columns are visible and table has width
35- if ( visibleColumns . length > 0 && totalWidth > 0 ) {
36- // set fixedWidth as defaultWidth if visible columns have fixed value
37- if ( visibleColumns . length === columnsWithFixedWidth . length ) {
38- return fixedWidth / visibleColumns . length ;
39- }
40- // spread default columns
41- if ( totalWidth >= fixedWidth + defaultColumnsCount * DEFAULT_COLUMN_WIDTH ) {
42- return ( totalWidth - fixedWidth ) / defaultColumnsCount ;
43- } else {
44- // set defaultWidth for default columns if table is overflowing
45- return DEFAULT_COLUMN_WIDTH ;
46- }
47- } else {
48- return DEFAULT_COLUMN_WIDTH ;
49- }
50- } ;
30+ const visibleColumns = columns . filter ( Boolean ) . filter ( ( item ) => {
31+ return ( item . isVisible ?? true ) && ! hiddenColumns . includes ( item . accessor ) ;
32+ } ) ;
5133
52- if ( columns . length === 0 || ! totalWidth ) return columns ;
34+ const calculateDefaultTableWidth = ( ) => {
35+ const columnsWithFixedWidth = visibleColumns . filter ( ( { width } ) => width ?? false ) . map ( ( { width } ) => width ) ;
36+ const fixedWidth = columnsWithFixedWidth . reduce ( ( acc , val ) => acc + val , 0 ) ;
5337
54- const hasData = rows . some ( ( row ) => ! row . original ?. emptyRow ) ;
38+ const defaultColumnsCount = visibleColumns . length - columnsWithFixedWidth . length ;
5539
56- if ( scaleWidthMode === TableScaleWidthMode . Default || ( ! hasData && loading ) ) {
57- const defaultWidth = calculateDefaultTableWidth ( ) ;
58- return columns . map ( ( column ) => ( { ...column , width : column . width ?? defaultWidth } ) ) ;
40+ // check if columns are visible and table has width
41+ if ( visibleColumns . length > 0 && totalWidth > 0 ) {
42+ // set fixedWidth as defaultWidth if visible columns have fixed value
43+ if ( visibleColumns . length === columnsWithFixedWidth . length ) {
44+ return fixedWidth / visibleColumns . length ;
45+ }
46+ // spread default columns
47+ if ( totalWidth >= fixedWidth + defaultColumnsCount * DEFAULT_COLUMN_WIDTH ) {
48+ return ( totalWidth - fixedWidth ) / defaultColumnsCount ;
49+ }
5950 }
51+ return DEFAULT_COLUMN_WIDTH ;
52+ } ;
6053
61- const rowSample = rows . slice ( 0 , ROW_SAMPLE_SIZE ) ;
54+ if ( columns . length === 0 || ! totalWidth ) return columns ;
6255
63- const columnMeta = visibleColumns . reduce ( ( acc , column ) => {
64- if ( column . id === '__ui5wcr__internal_selection_column' || column . id === '__ui5wcr__internal_highlight_column' ) {
65- acc [ column . accessor ] = {
66- minHeaderWidth : column . width ,
67- fullWidth : column . width ,
68- contentCharAvg : 0
69- } ;
70- return acc ;
71- }
56+ const hasData = rows . some ( ( row ) => ! row . original ?. emptyRow ) ;
57+
58+ if ( scaleWidthMode === TableScaleWidthMode . Default || ( ! hasData && loading ) ) {
59+ const defaultWidth = calculateDefaultTableWidth ( ) ;
60+ return columns . map ( ( column ) => ( { ...column , width : column . width ?? defaultWidth } ) ) ;
61+ }
7262
73- const headerLength = typeof column . Header === 'string' ? column . Header . length : DEFAULT_HEADER_NUM_CHAR ;
74-
75- // max character length
76- const contentMaxCharLength = Math . max (
77- headerLength ,
78- ...rowSample . map ( ( row ) => {
79- const dataPoint = row . values ?. [ column . accessor ] ;
80- if ( dataPoint ) {
81- if ( typeof dataPoint === 'string' ) return dataPoint . length ;
82- if ( typeof dataPoint === 'number' ) return ( dataPoint + '' ) . length ;
83- }
84- return 0 ;
85- } )
86- ) ;
87-
88- // avg character length
89- const contentCharAvg =
90- rowSample . reduce ( ( acc , item ) => {
91- const dataPoint = item . values ?. [ column . accessor ] ;
92- let val = 0 ;
93- if ( dataPoint ) {
94- if ( typeof dataPoint === 'string' ) val = dataPoint . length ;
95- if ( typeof dataPoint === 'number' ) val = ( dataPoint + '' ) . length ;
96- }
97- return acc + val ;
98- } , 0 ) / rowSample . length ;
99-
100- const minHeaderWidth = approximateHeaderPxFromCharLength ( headerLength ) ;
63+ const rowSample = rows . slice ( 0 , ROW_SAMPLE_SIZE ) ;
10164
65+ const columnMeta = visibleColumns . reduce ( ( acc , column ) => {
66+ if ( column . id === '__ui5wcr__internal_selection_column' || column . id === '__ui5wcr__internal_highlight_column' ) {
10267 acc [ column . accessor ] = {
103- minHeaderWidth,
104- fullWidth : Math . max ( minHeaderWidth , approximateContentPxFromCharLength ( contentMaxCharLength ) ) ,
105- contentCharAvg
68+ minHeaderWidth : column . width ,
69+ fullWidth : column . width ,
70+ contentCharAvg : 0
10671 } ;
10772 return acc ;
108- } , { } ) ;
109-
110- const totalCharNum = Object . values ( columnMeta ) . reduce (
111- ( acc : number , item : any ) => acc + item . contentCharAvg ,
112- 0
113- ) as number ;
114-
115- let reservedWidth = visibleColumns . reduce ( ( acc , column ) => {
116- const { minHeaderWidth, fullWidth } = columnMeta [ column . accessor ] ;
117- return (
118- acc +
119- Math . max (
120- column . minWidth || 0 ,
121- column . width || 0 ,
122- minHeaderWidth || 0 ,
123- scaleWidthMode === TableScaleWidthMode . Grow ? fullWidth : 0
124- ) || 0
125- ) ;
126- } , 0 ) ;
127-
128- let availableWidth = totalWidth - reservedWidth ;
129-
130- if ( scaleWidthMode === TableScaleWidthMode . Smart || availableWidth > 0 ) {
131- if ( scaleWidthMode === TableScaleWidthMode . Grow ) {
132- reservedWidth = visibleColumns . reduce ( ( acc , column ) => {
133- const { minHeaderWidth } = columnMeta [ column . accessor ] ;
134- return acc + Math . max ( column . minWidth || 0 , column . width || 0 , minHeaderWidth || 0 ) || 0 ;
135- } , 0 ) ;
136- availableWidth = totalWidth - reservedWidth ;
137- }
138-
139- return columns . map ( ( column ) => {
140- const isColumnVisible = ( column . isVisible ?? true ) && ! hiddenColumns . includes ( column . accessor ) ;
141- if ( isColumnVisible ) {
142- const { minHeaderWidth, contentCharAvg } = columnMeta [ column . accessor ] ;
143- const additionalSpaceFactor = totalCharNum > 0 ? contentCharAvg / totalCharNum : 1 / visibleColumns . length ;
73+ }
14474
145- const targetWidth = additionalSpaceFactor * availableWidth + minHeaderWidth ;
75+ const headerLength = typeof column . Header === 'string' ? column . Header . length : DEFAULT_HEADER_NUM_CHAR ;
14676
147- return {
148- ...column ,
149- width : column . width ?? targetWidth ,
150- minWidth : column . minWidth ?? minHeaderWidth
151- } ;
77+ // max character length
78+ const contentMaxCharLength = Math . max (
79+ headerLength ,
80+ ...rowSample . map ( ( row ) => {
81+ const dataPoint = row . values ?. [ column . accessor ] ;
82+ if ( dataPoint ) {
83+ if ( typeof dataPoint === 'string' ) return dataPoint . length ;
84+ if ( typeof dataPoint === 'number' ) return ( dataPoint + '' ) . length ;
85+ }
86+ return 0 ;
87+ } )
88+ ) ;
89+
90+ // avg character length
91+ const contentCharAvg =
92+ rowSample . reduce ( ( acc , item ) => {
93+ const dataPoint = item . values ?. [ column . accessor ] ;
94+ let val = 0 ;
95+ if ( dataPoint ) {
96+ if ( typeof dataPoint === 'string' ) val = dataPoint . length ;
97+ if ( typeof dataPoint === 'number' ) val = ( dataPoint + '' ) . length ;
15298 }
99+ return acc + val ;
100+ } , 0 ) / rowSample . length ;
153101
154- return column ;
155- } ) ;
102+ const minHeaderWidth = approximateHeaderPxFromCharLength ( headerLength ) ;
103+
104+ acc [ column . accessor ] = {
105+ minHeaderWidth,
106+ fullWidth : Math . max ( minHeaderWidth , approximateContentPxFromCharLength ( contentMaxCharLength ) ) ,
107+ contentCharAvg
108+ } ;
109+ return acc ;
110+ } , { } ) ;
111+
112+ const totalCharNum = Object . values ( columnMeta ) . reduce (
113+ ( acc : number , item : any ) => acc + item . contentCharAvg ,
114+ 0
115+ ) as number ;
116+
117+ let reservedWidth = visibleColumns . reduce ( ( acc , column ) => {
118+ const { minHeaderWidth, fullWidth } = columnMeta [ column . accessor ] ;
119+ return (
120+ acc +
121+ Math . max (
122+ column . minWidth || 0 ,
123+ column . width || 0 ,
124+ minHeaderWidth || 0 ,
125+ scaleWidthMode === TableScaleWidthMode . Grow ? fullWidth : 0
126+ ) || 0
127+ ) ;
128+ } , 0 ) ;
129+
130+ let availableWidth = totalWidth - reservedWidth ;
131+
132+ if ( scaleWidthMode === TableScaleWidthMode . Smart || availableWidth > 0 ) {
133+ if ( scaleWidthMode === TableScaleWidthMode . Grow ) {
134+ reservedWidth = visibleColumns . reduce ( ( acc , column ) => {
135+ const { minHeaderWidth } = columnMeta [ column . accessor ] ;
136+ return acc + Math . max ( column . minWidth || 0 , column . width || 0 , minHeaderWidth || 0 ) || 0 ;
137+ } , 0 ) ;
138+ availableWidth = totalWidth - reservedWidth ;
156139 }
157140
158- // TableScaleWidthMode Grow
159141 return columns . map ( ( column ) => {
160142 const isColumnVisible = ( column . isVisible ?? true ) && ! hiddenColumns . includes ( column . accessor ) ;
161143 if ( isColumnVisible ) {
162- const { fullWidth } = columnMeta [ column . accessor ] ;
144+ const { minHeaderWidth, contentCharAvg } = columnMeta [ column . accessor ] ;
145+ const additionalSpaceFactor = totalCharNum > 0 ? contentCharAvg / totalCharNum : 1 / visibleColumns . length ;
146+
147+ const targetWidth = additionalSpaceFactor * availableWidth + minHeaderWidth ;
148+
163149 return {
164150 ...column ,
165- width : column . width ?? fullWidth ,
166- maxWidth : MAX_WIDTH
151+ width : column . width ?? targetWidth ,
152+ minWidth : column . minWidth ?? minHeaderWidth
167153 } ;
168154 }
155+
169156 return column ;
170157 } ) ;
158+ }
159+
160+ // TableScaleWidthMode Grow
161+ return columns . map ( ( column ) => {
162+ const isColumnVisible = ( column . isVisible ?? true ) && ! hiddenColumns . includes ( column . accessor ) ;
163+ if ( isColumnVisible ) {
164+ const { fullWidth } = columnMeta [ column . accessor ] ;
165+ return {
166+ ...column ,
167+ width : column . width ?? fullWidth ,
168+ maxWidth : MAX_WIDTH
169+ } ;
170+ }
171+ return column ;
171172 } ) ;
172173} ;
174+
175+ export const useDynamicColumnWidths = ( hooks ) => {
176+ hooks . columns . push ( columns ) ;
177+ hooks . columnsDeps . push ( columnsDeps ) ;
178+ } ;
0 commit comments