Skip to content

Commit c473a3c

Browse files
committed
fix(material/tabs): update MatTab _scrollToLabel function to always display a label from its start (#26736)
1 parent 5ea4ca5 commit c473a3c

File tree

3 files changed

+37
-22
lines changed

3 files changed

+37
-22
lines changed

src/material/legacy-tabs/tab-header.spec.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,10 @@ describe('MatTabHeader', () => {
272272
// Focus on the last tab, expect this to be the maximum scroll distance.
273273
appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1;
274274
fixture.detectChanges();
275-
expect(appComponent.tabHeader.scrollDistance).toBe(
276-
appComponent.tabHeader._getMaxScrollDistance(),
275+
const {offsetLeft, offsetWidth} = appComponent.getSelectedLabel(
276+
appComponent.tabHeader.focusIndex,
277277
);
278+
expect(appComponent.getLengthOfTabList()).toBe(offsetLeft + offsetWidth);
278279

279280
// Focus on the first tab, expect this to be the maximum scroll distance.
280281
appComponent.tabHeader.focusIndex = 0;
@@ -331,9 +332,10 @@ describe('MatTabHeader', () => {
331332
// Focus the last tab so the header scrolls to the end.
332333
appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1;
333334
fixture.detectChanges();
334-
expect(appComponent.tabHeader.scrollDistance).toBe(
335-
appComponent.tabHeader._getMaxScrollDistance(),
335+
const {offsetLeft, offsetWidth} = appComponent.getSelectedLabel(
336+
appComponent.tabHeader.focusIndex,
336337
);
338+
expect(appComponent.getLengthOfTabList()).toBe(offsetLeft + offsetWidth);
337339

338340
// Remove the first two tabs which includes the selected tab.
339341
appComponent.tabs = appComponent.tabs.slice(2);
@@ -362,9 +364,8 @@ describe('MatTabHeader', () => {
362364
// Focus on the last tab, expect this to be the maximum scroll distance.
363365
appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1;
364366
fixture.detectChanges();
365-
expect(appComponent.tabHeader.scrollDistance).toBe(
366-
appComponent.tabHeader._getMaxScrollDistance(),
367-
);
367+
const {offsetLeft} = appComponent.getSelectedLabel(appComponent.tabHeader.focusIndex);
368+
expect(offsetLeft).toBe(0);
368369

369370
// Focus on the first tab, expect this to be the maximum scroll distance.
370371
appComponent.tabHeader.focusIndex = 0;
@@ -757,4 +758,12 @@ class SimpleTabHeaderApp {
757758
this.tabs.push({label: 'new'});
758759
}
759760
}
761+
762+
getLengthOfTabList() {
763+
return this.tabHeader._tabListInner.nativeElement.scrollWidth;
764+
}
765+
766+
getSelectedLabel(index: number) {
767+
return this.tabHeader._items.toArray()[this.tabHeader.focusIndex].elementRef.nativeElement;
768+
}
760769
}

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ const passiveEventListenerOptions = normalizePassiveListenerOptions({
5757
*/
5858
export type ScrollDirection = 'after' | 'before';
5959

60-
/**
61-
* The distance in pixels that will be overshot when scrolling a tab label into view. This helps
62-
* provide a small affordance to the label next to it.
63-
*/
64-
const EXAGGERATED_OVERSCROLL = 60;
65-
6660
/**
6761
* Amount of milliseconds to wait before starting to scroll the header automatically.
6862
* Set a little conservatively in order to handle fake events dispatched on touch devices.
@@ -524,10 +518,13 @@ export abstract class MatPaginatedTabHeader
524518

525519
if (labelBeforePos < beforeVisiblePos) {
526520
// Scroll header to move label to the before direction
527-
this.scrollDistance -= beforeVisiblePos - labelBeforePos + EXAGGERATED_OVERSCROLL;
521+
this.scrollDistance -= beforeVisiblePos - labelBeforePos;
528522
} else if (labelAfterPos > afterVisiblePos) {
529523
// Scroll header to move label to the after direction
530-
this.scrollDistance += labelAfterPos - afterVisiblePos + EXAGGERATED_OVERSCROLL;
524+
this.scrollDistance += Math.min(
525+
labelAfterPos - afterVisiblePos,
526+
labelBeforePos - beforeVisiblePos,
527+
);
531528
}
532529
}
533530

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,10 @@ describe('MDC-based MatTabHeader', () => {
266266
// Focus on the last tab, expect this to be the maximum scroll distance.
267267
appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1;
268268
fixture.detectChanges();
269-
expect(appComponent.tabHeader.scrollDistance).toBe(
270-
appComponent.tabHeader._getMaxScrollDistance(),
269+
const {offsetLeft, offsetWidth} = appComponent.getSelectedLabel(
270+
appComponent.tabHeader.focusIndex,
271271
);
272+
expect(appComponent.getLengthOfTabList()).toBe(offsetLeft + offsetWidth);
272273

273274
// Focus on the first tab, expect this to be the maximum scroll distance.
274275
appComponent.tabHeader.focusIndex = 0;
@@ -329,9 +330,10 @@ describe('MDC-based MatTabHeader', () => {
329330
// Focus the last tab so the header scrolls to the end.
330331
appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1;
331332
fixture.detectChanges();
332-
expect(appComponent.tabHeader.scrollDistance).toBe(
333-
appComponent.tabHeader._getMaxScrollDistance(),
333+
const {offsetLeft, offsetWidth} = appComponent.getSelectedLabel(
334+
appComponent.tabHeader.focusIndex,
334335
);
336+
expect(appComponent.getLengthOfTabList()).toBe(offsetLeft + offsetWidth);
335337

336338
// Remove the first two tabs which includes the selected tab.
337339
appComponent.tabs = appComponent.tabs.slice(2);
@@ -360,9 +362,8 @@ describe('MDC-based MatTabHeader', () => {
360362
// Focus on the last tab, expect this to be the maximum scroll distance.
361363
appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1;
362364
fixture.detectChanges();
363-
expect(appComponent.tabHeader.scrollDistance).toBe(
364-
appComponent.tabHeader._getMaxScrollDistance(),
365-
);
365+
const {offsetLeft} = appComponent.getSelectedLabel(appComponent.tabHeader.focusIndex);
366+
expect(offsetLeft).toBe(0);
366367

367368
// Focus on the first tab, expect this to be the maximum scroll distance.
368369
appComponent.tabHeader.focusIndex = 0;
@@ -757,4 +758,12 @@ class SimpleTabHeaderApp {
757758
this.tabs.push({label: 'new'});
758759
}
759760
}
761+
762+
getLengthOfTabList() {
763+
return this.tabHeader._tabListInner.nativeElement.scrollWidth;
764+
}
765+
766+
getSelectedLabel(index: number) {
767+
return this.tabHeader._items.toArray()[this.tabHeader.focusIndex].elementRef.nativeElement;
768+
}
760769
}

0 commit comments

Comments
 (0)