Skip to content

Commit 564af51

Browse files
committed
fix(material/tabs): make MatTab _scrollheader function smarter to display content fully (#26737)
1 parent 5ea4ca5 commit 564af51

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

src/material/tabs/paginated-tab-header.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ export type ScrollDirection = 'after' | 'before';
6363
*/
6464
const EXAGGERATED_OVERSCROLL = 60;
6565

66+
/**
67+
* The distance in pixels added on top of the scroll amount when using paginations to scroll a
68+
* tab list. It is used to compensate for the padding on either side of a label.
69+
*/
70+
const REDEEMING_OVERSCROLL = 24;
71+
6672
/**
6773
* Amount of milliseconds to wait before starting to scroll the header automatically.
6874
* Set a little conservatively in order to handle fake events dispatched on touch devices.
@@ -468,18 +474,37 @@ export abstract class MatPaginatedTabHeader
468474

469475
/**
470476
* Moves the tab list in the 'before' or 'after' direction (towards the beginning of the list or
471-
* the end of the list, respectively). The distance to scroll is computed to be a third of the
472-
* length of the tab list view window.
477+
* the end of the list, respectively). The distance to scroll is computed to be the smaller value
478+
* between the remaining space to the (left/right) border and a third of the length of the tab
479+
* list view window.
473480
*
474481
* This is an expensive call that forces a layout reflow to compute box and scroll metrics and
475482
* should be called sparingly.
476483
*/
477484
_scrollHeader(direction: ScrollDirection) {
478485
const viewLength = this._tabListContainer.nativeElement.offsetWidth;
479486

480-
// Move the scroll distance one-third the length of the tab list's viewport.
481-
const scrollAmount = ((direction == 'before' ? -1 : 1) * viewLength) / 3;
487+
// minLeftSpace: the distance from the first fully rendered label to the left border of the viewport.
488+
// minRightSpace: the distance from the last fully rendered label to the right border of the viewport.
489+
let minLeftSpace = Number.MAX_SAFE_INTEGER;
490+
let minRightSpace = Number.MAX_SAFE_INTEGER;
491+
this._items.toArray().forEach(tab => {
492+
const {offsetLeft, offsetWidth} = tab.elementRef.nativeElement;
493+
const leftSpace = offsetLeft - this.scrollDistance + REDEEMING_OVERSCROLL;
494+
const rightSpace =
495+
viewLength - (offsetLeft + offsetWidth - this.scrollDistance) + REDEEMING_OVERSCROLL;
496+
if (leftSpace > 0) {
497+
minLeftSpace = Math.min(minLeftSpace, leftSpace);
498+
}
499+
if (rightSpace > 0) {
500+
minRightSpace = Math.min(minRightSpace, rightSpace);
501+
}
502+
});
482503

504+
const scrollAmount =
505+
direction == 'before'
506+
? -Math.min(minRightSpace, viewLength / 3)
507+
: Math.min(minLeftSpace, viewLength / 3);
483508
return this._scrollTo(this._scrollDistance + scrollAmount);
484509
}
485510

0 commit comments

Comments
 (0)