@@ -18,12 +18,17 @@ import {ColumnResize} from './column-resize';
18
18
* The details of how resizing works for tables for flex mat-tables are quite different.
19
19
*/
20
20
@Injectable ( )
21
- export abstract class ResizeStrategy {
21
+ export abstract class ResizeStrategy implements OnDestroy {
22
22
protected abstract readonly columnResize : ColumnResize ;
23
23
protected abstract readonly styleScheduler : _CoalescedStyleScheduler ;
24
24
protected abstract readonly table : CdkTable < unknown > ;
25
25
26
26
private _pendingResizeDelta : number | null = null ;
27
+ private _tableObserved = false ;
28
+ private _elemSizeCache = new WeakMap < HTMLElement , { width : number ; height : number } > ( ) ;
29
+ private _resizeObserver = globalThis ?. ResizeObserver
30
+ ? new globalThis . ResizeObserver ( entries => this . _updateCachedSizes ( entries ) )
31
+ : null ;
27
32
28
33
/** Updates the width of the specified column. */
29
34
abstract applyColumnSize (
@@ -51,7 +56,7 @@ export abstract class ResizeStrategy {
51
56
protected updateTableWidthAndStickyColumns ( delta : number ) : void {
52
57
if ( this . _pendingResizeDelta === null ) {
53
58
const tableElement = this . columnResize . elementRef . nativeElement ;
54
- const tableWidth = getElementWidth ( tableElement ) ;
59
+ const tableWidth = this . getElementWidth ( tableElement ) ;
55
60
56
61
this . styleScheduler . schedule ( ( ) => {
57
62
tableElement . style . width = coerceCssPixelValue ( tableWidth + this . _pendingResizeDelta ! ) ;
@@ -66,6 +71,48 @@ export abstract class ResizeStrategy {
66
71
67
72
this . _pendingResizeDelta = ( this . _pendingResizeDelta ?? 0 ) + delta ;
68
73
}
74
+
75
+ /** Gets the style.width pixels on the specified element if present, otherwise its offsetWidth. */
76
+ protected getElementWidth ( element : HTMLElement ) {
77
+ // Optimization: Check style.width first as we probably set it already before reading
78
+ // offsetWidth which triggers layout.
79
+ return (
80
+ coercePixelsFromCssValue ( element . style . width ) ||
81
+ this . _elemSizeCache . get ( element ) ?. width ||
82
+ element . offsetWidth
83
+ ) ;
84
+ }
85
+
86
+ /** Informs the ResizeStrategy instance of a column that may be resized in the future. */
87
+ registerColumn ( column : HTMLElement ) {
88
+ if ( ! this . _tableObserved ) {
89
+ this . _tableObserved = true ;
90
+ this . _resizeObserver ?. observe ( this . columnResize . elementRef . nativeElement , {
91
+ box : 'border-box' ,
92
+ } ) ;
93
+ }
94
+ this . _resizeObserver ?. observe ( column , { box : 'border-box' } ) ;
95
+ }
96
+
97
+ ngOnDestroy ( ) : void {
98
+ this . _resizeObserver ?. disconnect ( ) ;
99
+ }
100
+
101
+ private _updateCachedSizes ( entries : ResizeObserverEntry [ ] ) {
102
+ for ( const entry of entries ) {
103
+ const newEntry = entry . borderBoxSize ?. length
104
+ ? {
105
+ width : entry . borderBoxSize [ 0 ] . inlineSize ,
106
+ height : entry . borderBoxSize [ 0 ] . blockSize ,
107
+ }
108
+ : {
109
+ width : entry . contentRect . width ,
110
+ height : entry . contentRect . height ,
111
+ } ;
112
+
113
+ this . _elemSizeCache . set ( entry . target as HTMLElement , newEntry ) ;
114
+ }
115
+ }
69
116
}
70
117
71
118
/**
@@ -87,7 +134,7 @@ export class TableLayoutFixedResizeStrategy extends ResizeStrategy {
87
134
sizeInPx : number ,
88
135
previousSizeInPx ?: number ,
89
136
) : void {
90
- const delta = sizeInPx - ( previousSizeInPx ?? getElementWidth ( columnHeader ) ) ;
137
+ const delta = sizeInPx - ( previousSizeInPx ?? this . getElementWidth ( columnHeader ) ) ;
91
138
92
139
if ( delta === 0 ) {
93
140
return ;
@@ -101,14 +148,14 @@ export class TableLayoutFixedResizeStrategy extends ResizeStrategy {
101
148
}
102
149
103
150
applyMinColumnSize ( _ : string , columnHeader : HTMLElement , sizeInPx : number ) : void {
104
- const currentWidth = getElementWidth ( columnHeader ) ;
151
+ const currentWidth = this . getElementWidth ( columnHeader ) ;
105
152
const newWidth = Math . max ( currentWidth , sizeInPx ) ;
106
153
107
154
this . applyColumnSize ( _ , columnHeader , newWidth , currentWidth ) ;
108
155
}
109
156
110
157
applyMaxColumnSize ( _ : string , columnHeader : HTMLElement , sizeInPx : number ) : void {
111
- const currentWidth = getElementWidth ( columnHeader ) ;
158
+ const currentWidth = this . getElementWidth ( columnHeader ) ;
112
159
const newWidth = Math . min ( currentWidth , sizeInPx ) ;
113
160
114
161
this . applyColumnSize ( _ , columnHeader , newWidth , currentWidth ) ;
@@ -189,7 +236,8 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest
189
236
return `cdk-column-${ cssFriendlyColumnName } ` ;
190
237
}
191
238
192
- ngOnDestroy ( ) : void {
239
+ override ngOnDestroy ( ) : void {
240
+ super . ngOnDestroy ( ) ;
193
241
this . _styleElement ?. remove ( ) ;
194
242
this . _styleElement = undefined ;
195
243
}
@@ -277,13 +325,6 @@ function coercePixelsFromCssValue(cssValue: string): number {
277
325
return Number ( cssValue . match ( / ( \d + ) p x / ) ?. [ 1 ] ) ;
278
326
}
279
327
280
- /** Gets the style.width pixels on the specified element if present, otherwise its offsetWidth. */
281
- function getElementWidth ( element : HTMLElement ) {
282
- // Optimization: Check style.width first as we probably set it already before reading
283
- // offsetWidth which triggers layout.
284
- return coercePixelsFromCssValue ( element . style . width ) || element . offsetWidth ;
285
- }
286
-
287
328
/**
288
329
* Converts CSS flex values as set in CdkFlexTableResizeStrategy to numbers,
289
330
* eg "0 0.01 123px" to 123.
0 commit comments