diff --git a/src/material/tabs/_tabs-common.scss b/src/material/tabs/_tabs-common.scss index f22b4580eca2..15c36eb4326e 100644 --- a/src/material/tabs/_tabs-common.scss +++ b/src/material/tabs/_tabs-common.scss @@ -217,6 +217,10 @@ $mat-tab-animation-duration: 500ms !default; tokens-mat-tab-header.$prefix, tokens-mat-tab-header.get-unthemable-tokens()); } + .mdc-tab-indicator .mdc-tab-indicator__content { + transition-duration: var(--mat-tab-animation-duration, 250ms); + } + .mat-mdc-tab-header-pagination { @include vendor-prefixes.user-select(none); position: relative; diff --git a/src/material/tabs/tab-group.spec.ts b/src/material/tabs/tab-group.spec.ts index 371232caf531..0b092d81f4b7 100644 --- a/src/material/tabs/tab-group.spec.ts +++ b/src/material/tabs/tab-group.spec.ts @@ -999,6 +999,15 @@ describe('nested MatTabGroup with enabled animations', () => { tick(); }).not.toThrow(); })); + + it('should set appropiate css variable given a specified animationDuration', fakeAsync(() => { + let fixture = TestBed.createComponent(TabsWithCustomAnimationDuration); + fixture.detectChanges(); + tick(); + + const tabGroup = fixture.nativeElement.querySelector('.mat-mdc-tab-group'); + expect(tabGroup.style.getPropertyValue('--mat-tab-animation-duration')).toBe('500ms'); + })); }); describe('MatTabGroup with ink bar fit to content', () => { diff --git a/src/material/tabs/tab-group.ts b/src/material/tabs/tab-group.ts index 4157bf08ab14..fc3e775910a1 100644 --- a/src/material/tabs/tab-group.ts +++ b/src/material/tabs/tab-group.ts @@ -528,6 +528,7 @@ export abstract class _MatTabGroupBase '[class.mat-mdc-tab-group-dynamic-height]': 'dynamicHeight', '[class.mat-mdc-tab-group-inverted-header]': 'headerPosition === "below"', '[class.mat-mdc-tab-group-stretch-tabs]': 'stretchTabs', + '[style.--mat-tab-animation-duration]': 'animationDuration', }, }) export class MatTabGroup extends _MatTabGroupBase { diff --git a/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts b/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts index 0dbc5dbb894c..d30951ef920f 100644 --- a/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts +++ b/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts @@ -489,6 +489,34 @@ describe('MatTabNavBar with a default config', () => { }); }); +describe('MatTabNavBar with enabled animations', () => { + beforeEach(fakeAsync(() => { + TestBed.configureTestingModule({ + imports: [MatTabsModule, BrowserAnimationsModule], + declarations: [TabsWithCustomAnimationDuration], + }); + + TestBed.compileComponents(); + })); + + it('should not throw when setting an animationDuration without units', fakeAsync(() => { + expect(() => { + let fixture = TestBed.createComponent(TabsWithCustomAnimationDuration); + fixture.detectChanges(); + tick(); + }).not.toThrow(); + })); + + it('should set appropiate css variable given a specified animationDuration', fakeAsync(() => { + let fixture = TestBed.createComponent(TabsWithCustomAnimationDuration); + fixture.detectChanges(); + tick(); + + const tabNavBar = fixture.nativeElement.querySelector('.mat-mdc-tab-nav-bar'); + expect(tabNavBar.style.getPropertyValue('--mat-tab-animation-duration')).toBe('500ms'); + })); +}); + @Component({ selector: 'test-app', template: ` @@ -545,3 +573,15 @@ class TabLinkWithNgIf { class TabBarWithInactiveTabsOnInit { tabs = [0, 1, 2]; } + +@Component({ + template: ` + + , + `, +}) +class TabsWithCustomAnimationDuration { + links = ['First', 'Second', 'Third']; +} diff --git a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts b/src/material/tabs/tab-nav-bar/tab-nav-bar.ts index f48df15ea368..6ec9ca681b1e 100644 --- a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/material/tabs/tab-nav-bar/tab-nav-bar.ts @@ -45,7 +45,7 @@ import {Directionality} from '@angular/cdk/bidi'; import {ViewportRuler} from '@angular/cdk/scrolling'; import {Platform} from '@angular/cdk/platform'; import {MatInkBar, MatInkBarItem, mixinInkBarItem} from '../ink-bar'; -import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; +import {BooleanInput, coerceBooleanProperty, NumberInput} from '@angular/cdk/coercion'; import {BehaviorSubject, Subject} from 'rxjs'; import {startWith, takeUntil} from 'rxjs/operators'; import {SPACE} from '@angular/cdk/keycodes'; @@ -319,6 +319,7 @@ const _MatTabLinkBaseWithInkBarItem = mixinInkBarItem(_MatTabLinkBase); '[class.mat-accent]': 'color === "accent"', '[class.mat-warn]': 'color === "warn"', '[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"', + '[style.--mat-tab-animation-duration]': 'animationDuration', }, encapsulation: ViewEncapsulation.None, // tslint:disable-next-line:validate-decorators @@ -346,6 +347,17 @@ export class MatTabNav extends _MatTabNavBase implements AfterContentInit, After } private _stretchTabs = true; + @Input() + get animationDuration(): string { + return this._animationDuration; + } + + set animationDuration(value: NumberInput) { + this._animationDuration = /^\d+$/.test(value + '') ? value + 'ms' : (value as string); + } + + private _animationDuration: string; + @ContentChildren(forwardRef(() => MatTabLink), {descendants: true}) _items: QueryList; @ViewChild('tabListContainer', {static: true}) _tabListContainer: ElementRef; @ViewChild('tabList', {static: true}) _tabList: ElementRef; diff --git a/tools/public_api_guard/material/tabs.md b/tools/public_api_guard/material/tabs.md index 527854e2cb43..f11a43b522c0 100644 --- a/tools/public_api_guard/material/tabs.md +++ b/tools/public_api_guard/material/tabs.md @@ -489,6 +489,9 @@ export class _MatTabLinkBase extends _MatTabLinkMixinBase implements AfterViewIn // @public export class MatTabNav extends _MatTabNavBase implements AfterContentInit, AfterViewInit { constructor(elementRef: ElementRef, dir: Directionality, ngZone: NgZone, changeDetectorRef: ChangeDetectorRef, viewportRuler: ViewportRuler, platform: Platform, animationMode?: string, defaultConfig?: MatTabsConfig); + // (undocumented) + get animationDuration(): string; + set animationDuration(value: NumberInput); get fitInkBarToContent(): boolean; set fitInkBarToContent(v: BooleanInput); // (undocumented) @@ -514,7 +517,7 @@ export class MatTabNav extends _MatTabNavBase implements AfterContentInit, After // (undocumented) _tabListInner: ElementRef; // (undocumented) - static ɵcmp: i0.ɵɵComponentDeclaration; + static ɵcmp: i0.ɵɵComponentDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; }