@@ -59,7 +59,9 @@ const getScrollIndicatorDimensions = (
59
59
scrollWrapper : HTMLDivElement ,
60
60
theadElement : HTMLDivElement ,
61
61
hasStickyHeader : boolean ,
62
- hasStickyFirstColumn : boolean
62
+ hasStickyFirstColumn : boolean ,
63
+ hasFirstColumnPxWidth : boolean ,
64
+ isStickyColumnPinned : boolean
63
65
) => {
64
66
const horizontalScrollBarHeight =
65
67
scrollWrapper . offsetHeight - scrollWrapper . clientHeight ;
@@ -80,8 +82,13 @@ const getScrollIndicatorDimensions = (
80
82
leftOffset += elAsHTMLElement . offsetWidth ;
81
83
} ) ;
82
84
83
- // offsets the left: -1px position if there are multiple sticky columns
84
- if ( stickyColumnHeaders . length > 1 ) {
85
+ // offsets the left: -1px position if there are multiple sticky columns or the first column has a fixed pixel width
86
+ if ( stickyColumnHeaders . length > 1 || hasFirstColumnPxWidth ) {
87
+ leftOffset -= 1 ;
88
+ }
89
+
90
+ // offsets the left: -1px position if the sticky column is already pinned when the scroll indicator is calculated
91
+ if ( isStickyColumnPinned ) {
85
92
leftOffset -= 1 ;
86
93
}
87
94
}
@@ -98,7 +105,8 @@ const getScrollIndicatorDimensions = (
98
105
99
106
const getStickyColumnLeftOffset = (
100
107
theadElement : HTMLDivElement ,
101
- hasRowSelection : boolean
108
+ hasRowSelection : boolean ,
109
+ isStickyColumnPinned : boolean
102
110
) => {
103
111
// if there is no select checkbox column, the sticky column is all the way to the left
104
112
if ( ! hasRowSelection ) return '0px' ;
@@ -107,7 +115,14 @@ const getStickyColumnLeftOffset = (
107
115
'.hds-advanced-table__th--is-selectable'
108
116
) as HTMLElement ;
109
117
110
- return `${ selectableCell ?. offsetWidth } px` ;
118
+ let leftOffset = selectableCell ?. offsetWidth ?? 0 ;
119
+
120
+ // if the sticky column is pinned when the offset is calculated, we need to account for the increased width of the border
121
+ if ( isStickyColumnPinned && leftOffset > 0 ) {
122
+ leftOffset -= 2 ;
123
+ }
124
+
125
+ return `${ leftOffset } px` ;
111
126
} ;
112
127
113
128
export interface HdsAdvancedTableSignature {
@@ -189,10 +204,12 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
189
204
private _scrollHandler ! : ( event : Event ) => void ;
190
205
private _resizeObserver ! : ResizeObserver ;
191
206
private _theadElement ! : HTMLDivElement ;
207
+ private _scrollWrapperElement ! : HTMLDivElement ;
192
208
193
209
@tracked scrollIndicatorDimensions = DEFAULT_SCROLL_DIMENSIONS ;
194
210
@tracked isStickyColumnPinned = false ;
195
211
@tracked isStickyHeaderPinned = false ;
212
+ @tracked hasPinnedFirstColumn : boolean | undefined = undefined ;
196
213
@tracked showScrollIndicatorLeft = false ;
197
214
@tracked showScrollIndicatorRight = false ;
198
215
@tracked showScrollIndicatorTop = false ;
@@ -244,6 +261,10 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
244
261
! hasResizableColumns
245
262
) ;
246
263
}
264
+
265
+ if ( hasStickyFirstColumn ) {
266
+ this . hasPinnedFirstColumn = true ;
267
+ }
247
268
}
248
269
249
270
get identityKey ( ) : string | undefined {
@@ -261,8 +282,19 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
261
282
return childrenKey ;
262
283
}
263
284
285
+ get hasStickyFirstColumn ( ) : boolean | undefined {
286
+ // The user-controlled `hasPinnedFirstColumn` variable takes precedence over the model's `hasStickyFirstColumn` property.
287
+ if ( this . hasPinnedFirstColumn !== undefined ) {
288
+ return this . hasPinnedFirstColumn ;
289
+ } else if ( this . args . hasStickyFirstColumn === false ) {
290
+ return this . args . hasStickyFirstColumn ;
291
+ }
292
+
293
+ return undefined ;
294
+ }
295
+
264
296
get hasScrollIndicator ( ) : boolean {
265
- if ( this . args . hasStickyFirstColumn ) {
297
+ if ( this . hasStickyFirstColumn ) {
266
298
return true ;
267
299
}
268
300
@@ -429,78 +461,39 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
429
461
) ;
430
462
431
463
private _setUpScrollWrapper = modifier ( ( element : HTMLDivElement ) => {
432
- this . _scrollHandler = ( ) => {
433
- // 6px as a buffer so the shadow doesn't appear over the border radius on the edge of the table
434
- const SCROLL_BUFFER = 6 ;
435
-
436
- // left scroll indicator and sticky column styles
437
- if ( element . scrollLeft > SCROLL_BUFFER && ! this . showScrollIndicatorLeft ) {
438
- if ( this . args . hasStickyFirstColumn ) {
439
- this . isStickyColumnPinned = true ;
440
- }
441
- this . showScrollIndicatorLeft = true ;
442
- } else if ( element . scrollLeft === 0 && this . showScrollIndicatorLeft ) {
443
- this . isStickyColumnPinned = false ;
444
- this . showScrollIndicatorLeft = false ;
445
- }
446
-
447
- // the right edge is how far the user can scroll, which is the full width of the table - the visible section of the table (also subtract the buffer)
448
- const rightEdge =
449
- element . scrollWidth - element . clientWidth - SCROLL_BUFFER ;
450
-
451
- // right scroll indicator
452
- if ( element . scrollLeft < rightEdge ) {
453
- this . showScrollIndicatorRight = true ;
454
- } else {
455
- this . showScrollIndicatorRight = false ;
456
- }
457
-
458
- // sticky header
459
- if ( element . scrollTop > 0 ) {
460
- if ( this . hasStickyHeader ) {
461
- this . isStickyHeaderPinned = true ;
462
- }
463
- this . showScrollIndicatorTop = true ;
464
- } else {
465
- if ( this . hasStickyHeader ) {
466
- this . isStickyHeaderPinned = false ;
467
- }
468
- this . showScrollIndicatorTop = false ;
469
- }
470
-
471
- // the bottom edge is how far the user can scroll, which is the full height of the table - the visible section of the table (also subtract the buffer)
472
- const bottomEdge =
473
- element . scrollHeight - element . clientHeight - SCROLL_BUFFER ;
464
+ this . _scrollWrapperElement = element ;
474
465
475
- // bottom scroll indicator
476
- if ( element . scrollTop < bottomEdge ) {
477
- this . showScrollIndicatorBottom = true ;
478
- } else {
479
- this . showScrollIndicatorBottom = false ;
480
- }
466
+ this . _scrollHandler = ( ) => {
467
+ this . _updateScrollIndicators ( element ) ;
481
468
} ;
482
469
483
470
element . addEventListener ( 'scroll' , this . _scrollHandler ) ;
484
471
485
472
const updateMeasurements = ( ) => {
486
473
this . _tableHeight = element . clientHeight ;
487
474
475
+ const hasFirstColumnPxWidth =
476
+ this . _tableModel . columns [ 0 ] ?. pxWidth !== undefined ;
477
+
488
478
this . scrollIndicatorDimensions = getScrollIndicatorDimensions (
489
479
element ,
490
480
this . _theadElement ,
491
481
this . hasStickyHeader ,
492
- hasStickyFirstColumn
482
+ this . hasStickyFirstColumn ? true : false ,
483
+ hasFirstColumnPxWidth ,
484
+ this . isStickyColumnPinned
493
485
) ;
494
486
495
- if ( hasStickyFirstColumn ) {
487
+ if ( this . hasStickyFirstColumn ) {
496
488
this . stickyColumnOffset = getStickyColumnLeftOffset (
497
489
this . _theadElement ,
498
- isSelectable
490
+ isSelectable ,
491
+ this . isStickyColumnPinned
499
492
) ;
500
493
}
501
494
} ;
502
495
503
- const { hasStickyFirstColumn = false , isSelectable = false } = this . args ;
496
+ const { isSelectable = false } = this . args ;
504
497
505
498
this . _resizeObserver = new ResizeObserver ( ( entries ) => {
506
499
entries . forEach ( ( ) => {
@@ -637,4 +630,71 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
637
630
this . _isSelectAllCheckboxSelected = this . _selectAllCheckbox . checked ;
638
631
}
639
632
}
633
+
634
+ private _updateScrollIndicators ( element : HTMLElement ) : void {
635
+ // 6px as a buffer so the shadow doesn't appear over the border radius on the edge of the table
636
+ const SCROLL_BUFFER = 6 ;
637
+
638
+ // left scroll indicator and sticky column styles
639
+ if ( element . scrollLeft > SCROLL_BUFFER ) {
640
+ if ( this . hasStickyFirstColumn ) {
641
+ this . isStickyColumnPinned = true ;
642
+ }
643
+ if ( ! this . showScrollIndicatorLeft ) {
644
+ this . showScrollIndicatorLeft = true ;
645
+ }
646
+ } else if ( element . scrollLeft === 0 && this . showScrollIndicatorLeft ) {
647
+ this . isStickyColumnPinned = false ;
648
+ this . showScrollIndicatorLeft = false ;
649
+ }
650
+
651
+ // the right edge is how far the user can scroll, which is the full width of the table - the visible section of the table (also subtract the buffer)
652
+ const rightEdge = element . scrollWidth - element . clientWidth - SCROLL_BUFFER ;
653
+
654
+ // right scroll indicator
655
+ if ( element . scrollLeft < rightEdge ) {
656
+ this . showScrollIndicatorRight = true ;
657
+ } else {
658
+ this . showScrollIndicatorRight = false ;
659
+ }
660
+
661
+ // sticky header
662
+ if ( element . scrollTop > 0 ) {
663
+ if ( this . hasStickyHeader ) {
664
+ this . isStickyHeaderPinned = true ;
665
+ }
666
+ this . showScrollIndicatorTop = true ;
667
+ } else {
668
+ if ( this . hasStickyHeader ) {
669
+ this . isStickyHeaderPinned = false ;
670
+ }
671
+ this . showScrollIndicatorTop = false ;
672
+ }
673
+
674
+ // the bottom edge is how far the user can scroll, which is the full height of the table - the visible section of the table (also subtract the buffer)
675
+ const bottomEdge =
676
+ element . scrollHeight - element . clientHeight - SCROLL_BUFFER ;
677
+
678
+ // bottom scroll indicator
679
+ if ( element . scrollTop < bottomEdge ) {
680
+ this . showScrollIndicatorBottom = true ;
681
+ } else {
682
+ this . showScrollIndicatorBottom = false ;
683
+ }
684
+ }
685
+
686
+ private _onPinFirstColumn = ( ) : void => {
687
+ this . hasPinnedFirstColumn = this . hasPinnedFirstColumn ? false : true ;
688
+ // we need to retrigger the scroll indicator updates if the pinned state is changed when the table is already scrolled
689
+ this . _updateScrollIndicators ( this . _scrollWrapperElement ) ;
690
+ } ;
691
+
692
+ private _isStickyColumn = (
693
+ column : HdsAdvancedTableColumnType
694
+ ) : boolean | undefined => {
695
+ if ( column . isFirst && this . hasStickyFirstColumn !== undefined ) {
696
+ return this . hasStickyFirstColumn ;
697
+ }
698
+ return undefined ;
699
+ } ;
640
700
}
0 commit comments