Skip to content

Commit 5390d87

Browse files
committed
fix(material/tabs): ensure the ink bar realigns when the tab header items have changed in dimensions
1 parent a47869c commit 5390d87

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {ViewportRuler} from '@angular/cdk/scrolling';
3232
import {FocusKeyManager, FocusableOption} from '@angular/cdk/a11y';
3333
import {ENTER, SPACE, hasModifierKey} from '@angular/cdk/keycodes';
3434
import {merge, of as observableOf, Subject, timer, fromEvent} from 'rxjs';
35-
import {take, takeUntil} from 'rxjs/operators';
35+
import {take, map, startWith, takeUntil} from 'rxjs/operators';
3636
import {Platform, normalizePassiveListenerOptions} from '@angular/cdk/platform';
3737
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
3838

@@ -218,7 +218,7 @@ export abstract class MatPaginatedTabHeader
218218

219219
// On dir change or window resize, realign the ink bar and update the orientation of
220220
// the key manager if the direction has changed.
221-
merge(dirChange, resize, this._items.changes)
221+
merge(dirChange, resize, this._getItemChanges())
222222
.pipe(takeUntil(this._destroyed))
223223
.subscribe(() => {
224224
// We need to defer this to give the browser some time to recalculate
@@ -246,6 +246,30 @@ export abstract class MatPaginatedTabHeader
246246
});
247247
}
248248

249+
/** A method responsible for sending any change that could affect layout about
250+
* items to subscribers.
251+
*/
252+
_getItemChanges() {
253+
const itemsTracked = new Set<MatPaginatedTabHeaderItem>();
254+
const itemContainerItemChanged = new Subject<void>();
255+
256+
const observer = new ResizeObserver(() => {
257+
itemContainerItemChanged.next();
258+
});
259+
260+
return merge(this._items.changes, itemContainerItemChanged).pipe(
261+
startWith(this._items),
262+
map(() => {
263+
for (const item of this._items.toArray()) {
264+
if (!itemsTracked.has(item)) {
265+
observer.observe(item.elementRef.nativeElement);
266+
}
267+
}
268+
this._items.forEach(item => itemsTracked.add(item));
269+
}),
270+
);
271+
}
272+
249273
ngAfterContentChecked(): void {
250274
// If the number of tab labels have changed, check if scrolling should be enabled
251275
if (this._tabLabelCount != this._items.length) {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,23 @@ describe('MatTabHeader', () => {
636636
discardPeriodicTasks();
637637
}));
638638

639+
it('should re-align the ink bar when the size of a tab changes', fakeAsync(() => {
640+
fixture = TestBed.createComponent(SimpleTabHeaderApp);
641+
fixture.detectChanges();
642+
643+
const inkBar = fixture.componentInstance.tabHeader._inkBar;
644+
645+
spyOn(inkBar, 'alignToElement');
646+
647+
// Change font-size which would trigger a container width change
648+
(fixture.elementRef.nativeElement as HTMLElement).style.fontSize = '20px';
649+
tick(150);
650+
fixture.detectChanges();
651+
652+
expect(inkBar.alignToElement).toHaveBeenCalled();
653+
discardPeriodicTasks();
654+
}));
655+
639656
it('should update arrows when the window is resized', fakeAsync(() => {
640657
fixture = TestBed.createComponent(SimpleTabHeaderApp);
641658

0 commit comments

Comments
 (0)