Skip to content

Commit

Permalink
feat(material/tabs): ink bar animation synchronize
Browse files Browse the repository at this point in the history
The animation of the ink bar of the mat tab group and the mat tab nav bar is now synchronized with the animationDuration of the tab body.
When the animation duration of the tab body was set to e.g. 0ms the ink bar still had an animation of 500ms. The following feat extends the animationDuration property to not only affect the tab body but also the ink bar of the tab group and the tab nav bar.

Fixes angular#25068
  • Loading branch information
markusingvarsson committed May 7, 2023
1 parent 44b57a5 commit 62d4853
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ <h3>No animation</h3>
<h3>Very slow animation</h3>
<!-- #docregion slow-animation-duration -->
<mat-tab-group animationDuration="2000ms">
<!-- #enddocregion slow-animation-duration -->
<!-- #enddocregion slow-animation-duration -->
<mat-tab label="First">Content 1</mat-tab>
<mat-tab label="Second">Content 2</mat-tab>
<mat-tab label="Third">Content 3</mat-tab>
Expand Down
20 changes: 14 additions & 6 deletions src/material/tabs/_tabs-common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
@use '../core/tokens/token-utils';
@use 'sass:map';


$mat-tab-animation-duration: 500ms !default;

// Combines the various structural styles we need for the tab group and tab nav bar.
Expand Down Expand Up @@ -214,7 +213,13 @@ $mat-tab-animation-duration: 500ms !default;
@include mdc-tab-indicator-theme.theme(tokens-mdc-tab-indicator.get-unthemable-tokens());
@include mdc-tab-theme.secondary-navigation-tab-theme(tokens-mdc-tab.get-unthemable-tokens());
@include token-utils.create-token-values(
tokens-mat-tab-header.$prefix, tokens-mat-tab-header.get-unthemable-tokens());
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 {
Expand Down Expand Up @@ -309,7 +314,7 @@ $mat-tab-animation-duration: 500ms !default;
// The `span` is in the selector in order to increase the specificity, ensuring
// that it's always higher than the selector that declares the transition.
._mat-animation-noopable {
span.mdc-tab-indicator__content,
--mat-tab-animation-duration: 0;
span.mdc-tab__text-label {
transition: none;
}
Expand Down Expand Up @@ -354,7 +359,8 @@ $mat-tab-animation-duration: 500ms !default;
) {
// Note that these selectors target direct descendants so
// that the styles don't apply to any nested tab groups.
> #{$header-selector}, > .mat-mdc-tab-header-pagination {
> #{$header-selector},
> .mat-mdc-tab-header-pagination {
// Set background color for the tab group
@include token-utils.create-token-slot(background-color, background-color);
}
Expand Down Expand Up @@ -386,13 +392,15 @@ $mat-tab-animation-duration: 500ms !default;
}
}

> #{$header-selector}, > .mat-mdc-tab-header-pagination {
> #{$header-selector},
> .mat-mdc-tab-header-pagination {
.mat-mdc-tab-header-pagination-chevron,
.mat-mdc-focus-indicator::before {
@include token-utils.create-token-slot(border-color, foreground-color);
}

.mat-ripple-element, .mdc-tab__ripple::before {
.mat-ripple-element,
.mdc-tab__ripple::before {
@include token-utils.create-token-slot(background-color, foreground-color);
}

Expand Down
9 changes: 9 additions & 0 deletions src/material/tabs/tab-group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
27 changes: 14 additions & 13 deletions src/material/tabs/tab-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/

import {FocusOrigin} from '@angular/cdk/a11y';
import {
BooleanInput,
NumberInput,
coerceBooleanProperty,
coerceNumberProperty,
} from '@angular/cdk/coercion';
import {
AfterContentChecked,
AfterContentInit,
Expand All @@ -25,26 +32,19 @@ import {
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
import {MAT_TAB_GROUP, MatTab} from './tab';
import {MatTabHeader} from './tab-header';
import {
BooleanInput,
coerceBooleanProperty,
coerceNumberProperty,
NumberInput,
} from '@angular/cdk/coercion';
import {
CanColor,
CanDisableRipple,
ThemePalette,
mixinColor,
mixinDisableRipple,
ThemePalette,
} from '@angular/material/core';
import {merge, Subscription} from 'rxjs';
import {MAT_TABS_CONFIG, MatTabsConfig} from './tab-config';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
import {Subscription, merge} from 'rxjs';
import {startWith} from 'rxjs/operators';
import {FocusOrigin} from '@angular/cdk/a11y';
import {MAT_TAB_GROUP, MatTab} from './tab';
import {MAT_TABS_CONFIG, MatTabsConfig} from './tab-config';
import {MatTabHeader} from './tab-header';

/** Used to generate unique ID's for each tab component */
let nextId = 0;
Expand Down Expand Up @@ -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 {
Expand Down
40 changes: 40 additions & 0 deletions src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: `
Expand Down Expand Up @@ -545,3 +573,15 @@ class TabLinkWithNgIf {
class TabBarWithInactiveTabsOnInit {
tabs = [0, 1, 2];
}

@Component({
template: `
<nav [animationDuration]="500" mat-tab-nav-bar [tabPanel]="tabPanel">
<a mat-tab-link *ngFor="let link of links">{{link}}</a>
</nav>
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>,
`,
})
class TabsWithCustomAnimationDuration {
links = ['First', 'Second', 'Third'];
}
14 changes: 13 additions & 1 deletion src/material/tabs/tab-nav-bar/tab-nav-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<MatTabLink>;
@ViewChild('tabListContainer', {static: true}) _tabListContainer: ElementRef;
@ViewChild('tabList', {static: true}) _tabList: ElementRef;
Expand Down
5 changes: 4 additions & 1 deletion tools/public_api_guard/material/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -514,7 +517,7 @@ export class MatTabNav extends _MatTabNavBase implements AfterContentInit, After
// (undocumented)
_tabListInner: ElementRef;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<MatTabNav, "[mat-tab-nav-bar]", ["matTabNavBar", "matTabNav"], { "color": { "alias": "color"; "required": false; }; "fitInkBarToContent": { "alias": "fitInkBarToContent"; "required": false; }; "stretchTabs": { "alias": "mat-stretch-tabs"; "required": false; }; }, {}, ["_items"], ["*"], false, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<MatTabNav, "[mat-tab-nav-bar]", ["matTabNavBar", "matTabNav"], { "color": { "alias": "color"; "required": false; }; "fitInkBarToContent": { "alias": "fitInkBarToContent"; "required": false; }; "stretchTabs": { "alias": "mat-stretch-tabs"; "required": false; }; "animationDuration": { "alias": "animationDuration"; "required": false; }; }, {}, ["_items"], ["*"], false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<MatTabNav, [null, { optional: true; }, null, null, null, null, { optional: true; }, { optional: true; }]>;
}
Expand Down

0 comments on commit 62d4853

Please sign in to comment.