Skip to content

Commit 3dfef13

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

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

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

Lines changed: 31 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,35 @@ 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 itemContainerItemChanged = new Subject<void>();
254+
255+
// Check to see if ResizeObserver is supported and if not, stub the function
256+
// out so that it does nothing if not supported
257+
const observer =
258+
typeof ResizeObserver === 'function'
259+
? new ResizeObserver(() => {
260+
itemContainerItemChanged.next();
261+
})
262+
: {
263+
observe: () => {},
264+
};
265+
266+
return merge(this._items.changes, itemContainerItemChanged).pipe(
267+
startWith(this._items),
268+
map(() => {
269+
for (const item of this._items.toArray()) {
270+
this._ngZone.runOutsideAngular(() => {
271+
observer.observe(item.elementRef.nativeElement);
272+
});
273+
}
274+
}),
275+
);
276+
}
277+
249278
ngAfterContentChecked(): void {
250279
// If the number of tab labels have changed, check if scrolling should be enabled
251280
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)