From 66ee1cf9063db433504e542f70fc01ec301ef2c3 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 18 Dec 2017 19:40:50 +0100 Subject: [PATCH] refactor: export component animations for reuse Exports all of the component animations so they can be reused by consumers. Fixes #8904. --- src/lib/dialog/dialog-animations.ts | 32 +++++++ src/lib/dialog/dialog-container.ts | 16 +--- src/lib/dialog/public-api.ts | 2 +- src/lib/expansion/expansion-animations.ts | 54 ++++++++++++ src/lib/expansion/expansion-panel-header.ts | 28 ++---- src/lib/expansion/expansion-panel.ts | 13 +-- src/lib/expansion/public-api.ts | 1 + src/lib/form-field/form-field-animations.ts | 30 +++++++ src/lib/form-field/form-field.ts | 13 +-- src/lib/form-field/public-api.ts | 1 + src/lib/menu/menu-animations.ts | 88 ++++++++++--------- src/lib/menu/menu-directive.ts | 6 +- src/lib/menu/public-api.ts | 3 +- src/lib/select/select-animations.ts | 97 ++++++++++++--------- src/lib/select/select.ts | 6 +- src/lib/sidenav/drawer-animations.ts | 34 ++++++++ src/lib/sidenav/drawer.ts | 18 +--- src/lib/sidenav/public-api.ts | 2 +- src/lib/sidenav/sidenav.ts | 17 +--- src/lib/snack-bar/public-api.ts | 2 +- src/lib/snack-bar/simple-snack-bar.ts | 12 +-- src/lib/snack-bar/snack-bar-animations.ts | 46 ++++++++++ src/lib/snack-bar/snack-bar-container.ts | 26 +----- src/lib/sort/public-api.ts | 2 +- src/lib/sort/sort-animations.ts | 70 +++++++++++++++ src/lib/sort/sort-header.ts | 52 ++--------- src/lib/stepper/public-api.ts | 1 + src/lib/stepper/stepper-animations.ts | 37 ++++++++ src/lib/stepper/stepper.ts | 20 +---- src/lib/tabs/public-api.ts | 1 + src/lib/tabs/tab-body.ts | 29 +----- src/lib/tabs/tabs-animations.ts | 38 ++++++++ src/lib/tooltip/public-api.ts | 2 +- src/lib/tooltip/tooltip-animations.ts | 28 ++++++ src/lib/tooltip/tooltip.ts | 12 +-- 35 files changed, 524 insertions(+), 315 deletions(-) create mode 100644 src/lib/dialog/dialog-animations.ts create mode 100644 src/lib/expansion/expansion-animations.ts create mode 100644 src/lib/form-field/form-field-animations.ts create mode 100644 src/lib/sidenav/drawer-animations.ts create mode 100644 src/lib/snack-bar/snack-bar-animations.ts create mode 100644 src/lib/sort/sort-animations.ts create mode 100644 src/lib/stepper/stepper-animations.ts create mode 100644 src/lib/tabs/tabs-animations.ts create mode 100644 src/lib/tooltip/tooltip-animations.ts diff --git a/src/lib/dialog/dialog-animations.ts b/src/lib/dialog/dialog-animations.ts new file mode 100644 index 000000000000..989d85662a33 --- /dev/null +++ b/src/lib/dialog/dialog-animations.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Animations used by MatDialog. */ +export const matDialogAnimations: { + readonly slideDialog: AnimationTriggerMetadata; +} = { + /** Animation that slides the dialog in and out of view and fades the opacity. */ + slideDialog: trigger('slideDialog', [ + // Note: The `enter` animation doesn't transition to something like `translate3d(0, 0, 0) + // scale(1)`, because for some reason specifying the transform explicitly, causes IE both + // to blur the dialog content and decimate the animation performance. Leaving it as `none` + // solves both issues. + state('enter', style({ transform: 'none', opacity: 1 })), + state('void', style({ transform: 'translate3d(0, 25%, 0) scale(0.9)', opacity: 0 })), + state('exit', style({ transform: 'translate3d(0, 25%, 0)', opacity: 0 })), + transition('* => *', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')), + ]) +}; diff --git a/src/lib/dialog/dialog-container.ts b/src/lib/dialog/dialog-container.ts index afc437a9e9ad..ee34a1eed0ce 100644 --- a/src/lib/dialog/dialog-container.ts +++ b/src/lib/dialog/dialog-container.ts @@ -19,8 +19,9 @@ import { ViewEncapsulation, ChangeDetectionStrategy, } from '@angular/core'; -import {animate, AnimationEvent, state, style, transition, trigger} from '@angular/animations'; import {DOCUMENT} from '@angular/common'; +import {AnimationEvent} from '@angular/animations'; +import {matDialogAnimations} from './dialog-animations'; import { BasePortalOutlet, ComponentPortal, @@ -55,18 +56,7 @@ export function throwMatDialogContentAlreadyAttachedError() { // Using OnPush for dialogs caused some G3 sync issues. Disabled until we can track them down. // tslint:disable-next-line:validate-decorators changeDetection: ChangeDetectionStrategy.Default, - animations: [ - trigger('slideDialog', [ - // Note: The `enter` animation doesn't transition to something like `translate3d(0, 0, 0) - // scale(1)`, because for some reason specifying the transform explicitly, causes IE both - // to blur the dialog content and decimate the animation performance. Leaving it as `none` - // solves both issues. - state('enter', style({ transform: 'none', opacity: 1 })), - state('void', style({ transform: 'translate3d(0, 25%, 0) scale(0.9)', opacity: 0 })), - state('exit', style({ transform: 'translate3d(0, 25%, 0)', opacity: 0 })), - transition('* => *', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')), - ]) - ], + animations: [matDialogAnimations.slideDialog], host: { 'class': 'mat-dialog-container', 'tabindex': '-1', diff --git a/src/lib/dialog/public-api.ts b/src/lib/dialog/public-api.ts index 7df9a5f3b1dd..f3e8ddbeff26 100644 --- a/src/lib/dialog/public-api.ts +++ b/src/lib/dialog/public-api.ts @@ -12,4 +12,4 @@ export * from './dialog-container'; export * from './dialog-content-directives'; export * from './dialog-config'; export * from './dialog-ref'; - +export * from './dialog-animations'; diff --git a/src/lib/expansion/expansion-animations.ts b/src/lib/expansion/expansion-animations.ts new file mode 100644 index 000000000000..e638ec247cb9 --- /dev/null +++ b/src/lib/expansion/expansion-animations.ts @@ -0,0 +1,54 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Time and timing curve for expansion panel animations. */ +export const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,1)'; + +/** Animations used by the Material expansion panel. */ +export const matExpansionAnimations: { + readonly indicatorRotate: AnimationTriggerMetadata; + readonly expansionHeaderHeight: AnimationTriggerMetadata; + readonly bodyExpansion: AnimationTriggerMetadata; +} = { + /** Animation that rotates the indicator arrow. */ + indicatorRotate: trigger('indicatorRotate', [ + state('collapsed', style({transform: 'rotate(0deg)'})), + state('expanded', style({transform: 'rotate(180deg)'})), + transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)), + ]), + + /** Animation that expands and collapses the panel header height. */ + expansionHeaderHeight: trigger('expansionHeight', [ + state('collapsed', style({ + height: '{{collapsedHeight}}', + }), { + params: {collapsedHeight: '48px'}, + }), + state('expanded', style({ + height: '{{expandedHeight}}' + }), { + params: {expandedHeight: '64px'} + }), + transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)), + ]), + + /** Animation that expands and collapses the panel content. */ + bodyExpansion: trigger('bodyExpansion', [ + state('collapsed', style({height: '0px', visibility: 'hidden'})), + state('expanded', style({height: '*', visibility: 'visible'})), + transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)), + ]) +}; diff --git a/src/lib/expansion/expansion-panel-header.ts b/src/lib/expansion/expansion-panel-header.ts index 5cbc7d07b5df..b68cf5348839 100644 --- a/src/lib/expansion/expansion-panel-header.ts +++ b/src/lib/expansion/expansion-panel-header.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {animate, state, style, transition, trigger} from '@angular/animations'; import {FocusMonitor} from '@angular/cdk/a11y'; import {ENTER, SPACE} from '@angular/cdk/keycodes'; import {filter} from 'rxjs/operators/filter'; @@ -23,7 +22,8 @@ import { } from '@angular/core'; import {merge} from 'rxjs/observable/merge'; import {Subscription} from 'rxjs/Subscription'; -import {EXPANSION_PANEL_ANIMATION_TIMING, MatExpansionPanel} from './expansion-panel'; +import {MatExpansionPanel} from './expansion-panel'; +import {matExpansionAnimations} from './expansion-animations'; /** @@ -41,6 +41,10 @@ import {EXPANSION_PANEL_ANIMATION_TIMING, MatExpansionPanel} from './expansion-p encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, + animations: [ + matExpansionAnimations.indicatorRotate, + matExpansionAnimations.expansionHeaderHeight + ], host: { 'class': 'mat-expansion-panel-header', 'role': 'button', @@ -59,26 +63,6 @@ import {EXPANSION_PANEL_ANIMATION_TIMING, MatExpansionPanel} from './expansion-p } }`, }, - animations: [ - trigger('indicatorRotate', [ - state('collapsed', style({transform: 'rotate(0deg)'})), - state('expanded', style({transform: 'rotate(180deg)'})), - transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)), - ]), - trigger('expansionHeight', [ - state('collapsed', style({ - height: '{{collapsedHeight}}', - }), { - params: {collapsedHeight: '48px'}, - }), - state('expanded', style({ - height: '{{expandedHeight}}' - }), { - params: {expandedHeight: '64px'} - }), - transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)), - ]), - ], }) export class MatExpansionPanelHeader implements OnDestroy { private _parentChangeSubscription = Subscription.EMPTY; diff --git a/src/lib/expansion/expansion-panel.ts b/src/lib/expansion/expansion-panel.ts index 68a51394c906..f6e251318296 100644 --- a/src/lib/expansion/expansion-panel.ts +++ b/src/lib/expansion/expansion-panel.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {animate, state, style, transition, trigger} from '@angular/animations'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -35,9 +34,7 @@ import {startWith} from 'rxjs/operators/startWith'; import {MatAccordion} from './accordion'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {MatExpansionPanelContent} from './expansion-panel-content'; - -/** Time and timing curve for expansion panel animations. */ -export const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,1)'; +import {matExpansionAnimations} from './expansion-animations'; // Boilerplate for applying mixins to MatExpansionPanel. /** @docs-private */ @@ -79,6 +76,7 @@ export type MatExpansionPanelState = 'expanded' | 'collapsed'; changeDetection: ChangeDetectionStrategy.OnPush, inputs: ['disabled', 'expanded'], outputs: ['opened', 'closed'], + animations: [matExpansionAnimations.bodyExpansion], host: { 'class': 'mat-expansion-panel', '[class.mat-expanded]': 'expanded', @@ -87,13 +85,6 @@ export type MatExpansionPanelState = 'expanded' | 'collapsed'; providers: [ {provide: _MatExpansionPanelMixinBase, useExisting: forwardRef(() => MatExpansionPanel)} ], - animations: [ - trigger('bodyExpansion', [ - state('collapsed', style({height: '0px', visibility: 'hidden'})), - state('expanded', style({height: '*', visibility: 'visible'})), - transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)), - ]), - ], }) export class MatExpansionPanel extends _MatExpansionPanelMixinBase implements CanDisable, AfterContentInit, OnChanges, OnDestroy { diff --git a/src/lib/expansion/public-api.ts b/src/lib/expansion/public-api.ts index b5baa2372a6b..7f4e568aa9bd 100644 --- a/src/lib/expansion/public-api.ts +++ b/src/lib/expansion/public-api.ts @@ -11,3 +11,4 @@ export * from './accordion'; export * from './expansion-panel'; export * from './expansion-panel-header'; export * from './expansion-panel-content'; +export * from './expansion-animations'; diff --git a/src/lib/form-field/form-field-animations.ts b/src/lib/form-field/form-field-animations.ts new file mode 100644 index 000000000000..8b4683b11a49 --- /dev/null +++ b/src/lib/form-field/form-field-animations.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Animations used by the MatFormField. */ +export const matFormFieldAnimations: { + readonly transitionMessages: AnimationTriggerMetadata +} = { + /** Animation that transitions the form field's error and hint messages. */ + transitionMessages: trigger('transitionMessages', [ + // TODO(mmalerba): Use angular animations for label animation as well. + state('enter', style({ opacity: 1, transform: 'translateY(0%)' })), + transition('void => enter', [ + style({ opacity: 0, transform: 'translateY(-100%)' }), + animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)'), + ]), + ]) +}; diff --git a/src/lib/form-field/form-field.ts b/src/lib/form-field/form-field.ts index 5e75603f39ff..30b968d93ed1 100644 --- a/src/lib/form-field/form-field.ts +++ b/src/lib/form-field/form-field.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {animate, state, style, transition, trigger} from '@angular/animations'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {take} from 'rxjs/operators/take'; import {startWith} from 'rxjs/operators/startWith'; @@ -41,6 +40,7 @@ import {MatPlaceholder} from './placeholder'; import {MatLabel} from './label'; import {MatPrefix} from './prefix'; import {MatSuffix} from './suffix'; +import {matFormFieldAnimations} from './form-field-animations'; let nextUniqueId = 0; @@ -57,16 +57,7 @@ let nextUniqueId = 0; // The MatInput styles are fairly minimal so it shouldn't be a big deal for people who // aren't using MatInput. styleUrls: ['form-field.css', '../input/input.css'], - animations: [ - // TODO(mmalerba): Use angular animations for label animation as well. - trigger('transitionMessages', [ - state('enter', style({ opacity: 1, transform: 'translateY(0%)' })), - transition('void => enter', [ - style({ opacity: 0, transform: 'translateY(-100%)' }), - animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)'), - ]), - ]), - ], + animations: [matFormFieldAnimations.transitionMessages], host: { 'class': 'mat-input-container mat-form-field', '[class.mat-input-invalid]': '_control.errorState', diff --git a/src/lib/form-field/public-api.ts b/src/lib/form-field/public-api.ts index 318a140850e1..ebe915de484c 100644 --- a/src/lib/form-field/public-api.ts +++ b/src/lib/form-field/public-api.ts @@ -16,3 +16,4 @@ export * from './placeholder'; export * from './prefix'; export * from './suffix'; export * from './label'; +export * from './form-field-animations'; diff --git a/src/lib/menu/menu-animations.ts b/src/lib/menu/menu-animations.ts index c0190a4f4e99..6440cc1aceed 100644 --- a/src/lib/menu/menu-animations.ts +++ b/src/lib/menu/menu-animations.ts @@ -16,50 +16,58 @@ import{ } from '@angular/animations'; /** - * Below are all the animations for the mat-menu component. + * Animations used by the mat-menu component. * Animation duration and timing values are based on: * https://material.io/guidelines/components/menus.html#menus-usage */ +export const matMenuAnimations: { + readonly transformMenu: AnimationTriggerMetadata; + readonly fadeInItems: AnimationTriggerMetadata; +} = { + /** + * This animation controls the menu panel's entry and exit from the page. + * + * When the menu panel is added to the DOM, it scales in and fades in its border. + * + * When the menu panel is removed from the DOM, it simply fades out after a brief + * delay to display the ripple. + */ + transformMenu: trigger('transformMenu', [ + // TODO(kara): switch to :enter and :leave once Mobile Safari is sorted out. + state('void', style({ + opacity: 0, + // This starts off from 0.01, instead of 0, because there's an issue in the Angular animations + // as of 4.2, which causes the animation to be skipped if it starts from 0. + transform: 'scale(0.01, 0.01)' + })), + state('enter-start', style({ + opacity: 1, + transform: 'scale(1, 0.5)' + })), + state('enter', style({ + transform: 'scale(1, 1)' + })), + transition('void => enter-start', animate('100ms linear')), + transition('enter-start => enter', animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)')), + transition('* => void', animate('150ms 50ms linear', style({opacity: 0}))) + ]), -/** - * This animation controls the menu panel's entry and exit from the page. - * - * When the menu panel is added to the DOM, it scales in and fades in its border. - * - * When the menu panel is removed from the DOM, it simply fades out after a brief - * delay to display the ripple. - */ - -// TODO(kara): switch to :enter and :leave once Mobile Safari is sorted out. -export const transformMenu: AnimationTriggerMetadata = trigger('transformMenu', [ - state('void', style({ - opacity: 0, - // This starts off from 0.01, instead of 0, because there's an issue in the Angular animations - // as of 4.2, which causes the animation to be skipped if it starts from 0. - transform: 'scale(0.01, 0.01)' - })), - state('enter-start', style({ - opacity: 1, - transform: 'scale(1, 0.5)' - })), - state('enter', style({ - transform: 'scale(1, 1)' - })), - transition('void => enter-start', animate('100ms linear')), - transition('enter-start => enter', animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)')), - transition('* => void', animate('150ms 50ms linear', style({opacity: 0}))) -]); + /** + * This animation fades in the background color and content of the menu panel + * after its containing element is scaled in. + */ + fadeInItems: trigger('fadeInItems', [ + state('showing', style({opacity: 1})), + transition('void => *', [ + style({opacity: 0}), + animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)') + ]) + ]) +}; +/** @deprecated */ +export const fadeInItems = matMenuAnimations.fadeInItems; -/** - * This animation fades in the background color and content of the menu panel - * after its containing element is scaled in. - */ -export const fadeInItems: AnimationTriggerMetadata = trigger('fadeInItems', [ - state('showing', style({opacity: 1})), - transition('void => *', [ - style({opacity: 0}), - animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)') - ]) -]); +/** @deprecated */ +export const transformMenu = matMenuAnimations.transformMenu; diff --git a/src/lib/menu/menu-directive.ts b/src/lib/menu/menu-directive.ts index 977a34707a31..8452087298e7 100644 --- a/src/lib/menu/menu-directive.ts +++ b/src/lib/menu/menu-directive.ts @@ -34,7 +34,7 @@ import { import {Observable} from 'rxjs/Observable'; import {merge} from 'rxjs/observable/merge'; import {Subscription} from 'rxjs/Subscription'; -import {fadeInItems, transformMenu} from './menu-animations'; +import {matMenuAnimations} from './menu-animations'; import {throwMatMenuInvalidPositionX, throwMatMenuInvalidPositionY} from './menu-errors'; import {MatMenuItem} from './menu-item'; import {MatMenuPanel} from './menu-panel'; @@ -74,8 +74,8 @@ const MAT_MENU_BASE_ELEVATION = 2; encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, animations: [ - transformMenu, - fadeInItems + matMenuAnimations.transformMenu, + matMenuAnimations.fadeInItems ], exportAs: 'matMenu' }) diff --git a/src/lib/menu/public-api.ts b/src/lib/menu/public-api.ts index 71b517e58184..45c297145213 100644 --- a/src/lib/menu/public-api.ts +++ b/src/lib/menu/public-api.ts @@ -8,6 +8,5 @@ export * from './menu-module'; export * from './menu'; +export * from './menu-animations'; export {MAT_MENU_SCROLL_STRATEGY} from './menu-trigger'; -export {fadeInItems, transformMenu} from './menu-animations'; - diff --git a/src/lib/select/select-animations.ts b/src/lib/select/select-animations.ts index 434be7c71681..0b95a1fac173 100644 --- a/src/lib/select/select-animations.ts +++ b/src/lib/select/select-animations.ts @@ -21,49 +21,60 @@ import { * * The values below match the implementation of the AngularJS Material mat-select animation. */ - -/** - * This animation transforms the select's overlay panel on and off the page. - * - * When the panel is attached to the DOM, it expands its width by the amount of padding, scales it - * up to 100% on the Y axis, fades in its border, and translates slightly up and to the - * side to ensure the option text correctly overlaps the trigger text. - * - * When the panel is removed from the DOM, it simply fades out linearly. - */ -export const transformPanel: AnimationTriggerMetadata = trigger('transformPanel', [ - state('showing', style({ - opacity: 1, - minWidth: 'calc(100% + 32px)', // 32px = 2 * 16px padding - transform: 'scaleY(1)' - })), - state('showing-multiple', style({ - opacity: 1, - minWidth: 'calc(100% + 64px)', // 64px = 48px padding on the left + 16px padding on the right - transform: 'scaleY(1)' - })), - transition('void => *', [ - style({ - opacity: 0, - minWidth: '100%', - transform: 'scaleY(0)' - }), - animate('150ms cubic-bezier(0.25, 0.8, 0.25, 1)') +export const matSelectAnimations: { + readonly transformPanel: AnimationTriggerMetadata; + readonly fadeInContent: AnimationTriggerMetadata; +} = { + /** + * This animation transforms the select's overlay panel on and off the page. + * + * When the panel is attached to the DOM, it expands its width by the amount of padding, scales it + * up to 100% on the Y axis, fades in its border, and translates slightly up and to the + * side to ensure the option text correctly overlaps the trigger text. + * + * When the panel is removed from the DOM, it simply fades out linearly. + */ + transformPanel: trigger('transformPanel', [ + state('showing', style({ + opacity: 1, + minWidth: 'calc(100% + 32px)', // 32px = 2 * 16px padding + transform: 'scaleY(1)' + })), + state('showing-multiple', style({ + opacity: 1, + minWidth: 'calc(100% + 64px)', // 64px = 48px padding on the left + 16px padding on the right + transform: 'scaleY(1)' + })), + transition('void => *', [ + style({ + opacity: 0, + minWidth: '100%', + transform: 'scaleY(0)' + }), + animate('150ms cubic-bezier(0.25, 0.8, 0.25, 1)') + ]), + transition('* => void', [ + animate('250ms 100ms linear', style({opacity: 0})) + ]) ]), - transition('* => void', [ - animate('250ms 100ms linear', style({opacity: 0})) - ]) -]); -/** - * This animation fades in the background color and text content of the - * select's options. It is time delayed to occur 100ms after the overlay - * panel has transformed in. - */ -export const fadeInContent: AnimationTriggerMetadata = trigger('fadeInContent', [ - state('showing', style({opacity: 1})), - transition('void => showing', [ - style({opacity: 0}), - animate('150ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)') + /** + * This animation fades in the background color and text content of the + * select's options. It is time delayed to occur 100ms after the overlay + * panel has transformed in. + */ + fadeInContent: trigger('fadeInContent', [ + state('showing', style({opacity: 1})), + transition('void => showing', [ + style({opacity: 0}), + animate('150ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)') + ]) ]) -]); +}; + + +/** @deprecated */ +export const transformPanel = matSelectAnimations.transformPanel; + +/** @deprecated */ +export const fadeInContent = matSelectAnimations.fadeInContent; diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index 778f16bc8764..f7ef6f0bce5a 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -77,7 +77,7 @@ import {Observable} from 'rxjs/Observable'; import {merge} from 'rxjs/observable/merge'; import {Subject} from 'rxjs/Subject'; import {defer} from 'rxjs/observable/defer'; -import {fadeInContent, transformPanel} from './select-animations'; +import {matSelectAnimations} from './select-animations'; import { getMatSelectDynamicMultipleError, getMatSelectNonArrayValueError, @@ -201,8 +201,8 @@ export class MatSelectTrigger {} '(blur)': '_onBlur()', }, animations: [ - transformPanel, - fadeInContent + matSelectAnimations.transformPanel, + matSelectAnimations.fadeInContent ], providers: [ {provide: MatFormFieldControl, useExisting: MatSelect}, diff --git a/src/lib/sidenav/drawer-animations.ts b/src/lib/sidenav/drawer-animations.ts new file mode 100644 index 000000000000..6a5a671e9ccc --- /dev/null +++ b/src/lib/sidenav/drawer-animations.ts @@ -0,0 +1,34 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Animations used by the Material drawers. */ +export const matDrawerAnimations: { + readonly transformDrawer: AnimationTriggerMetadata; +} = { + /** Animation that slides a drawer in and out. */ + transformDrawer: trigger('transform', [ + state('open, open-instant', style({ + transform: 'translate3d(0, 0, 0)', + visibility: 'visible', + })), + state('void', style({ + visibility: 'hidden', + })), + transition('void => open-instant', animate('0ms')), + transition('void <=> open, open-instant => void', + animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) + ]) +}; diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index 750456315103..0742055522f1 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {animate, AnimationEvent, state, style, transition, trigger} from '@angular/animations'; +import {AnimationEvent} from '@angular/animations'; import {FocusTrap, FocusTrapFactory, FocusMonitor, FocusOrigin} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; @@ -42,6 +42,7 @@ import {debounceTime} from 'rxjs/operators/debounceTime'; import {map} from 'rxjs/operators/map'; import {Subject} from 'rxjs/Subject'; import {Observable} from 'rxjs/Observable'; +import {matDrawerAnimations} from './drawer-animations'; /** Throws an exception when two MatDrawer are matching the same position. */ @@ -109,20 +110,7 @@ export class MatDrawerContent implements AfterContentInit { selector: 'mat-drawer', exportAs: 'matDrawer', template: '', - animations: [ - trigger('transform', [ - state('open, open-instant', style({ - transform: 'translate3d(0, 0, 0)', - visibility: 'visible', - })), - state('void', style({ - visibility: 'hidden', - })), - transition('void => open-instant', animate('0ms')), - transition('void <=> open, open-instant => void', - animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) - ]) - ], + animations: [matDrawerAnimations.transformDrawer], host: { 'class': 'mat-drawer', '[@transform]': '_animationState', diff --git a/src/lib/sidenav/public-api.ts b/src/lib/sidenav/public-api.ts index 32be34343165..5276be4aa808 100644 --- a/src/lib/sidenav/public-api.ts +++ b/src/lib/sidenav/public-api.ts @@ -9,4 +9,4 @@ export * from './sidenav-module'; export * from './drawer'; export * from './sidenav'; - +export * from './drawer-animations'; diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 24b88086db4e..1fb22d0e7121 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -13,7 +13,7 @@ import { ViewEncapsulation } from '@angular/core'; import {MatDrawer, MatDrawerContainer, MatDrawerContent} from './drawer'; -import {animate, state, style, transition, trigger} from '@angular/animations'; +import {matDrawerAnimations} from './drawer-animations'; import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion'; @@ -44,20 +44,7 @@ export class MatSidenavContent extends MatDrawerContent { selector: 'mat-sidenav', exportAs: 'matSidenav', template: '', - animations: [ - trigger('transform', [ - state('open, open-instant', style({ - transform: 'translate3d(0, 0, 0)', - visibility: 'visible', - })), - state('void', style({ - visibility: 'hidden', - })), - transition('void => open-instant', animate('0ms')), - transition('void <=> open, open-instant => void', - animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) - ]) - ], + animations: [matDrawerAnimations.transformDrawer], host: { 'class': 'mat-drawer mat-sidenav', 'tabIndex': '-1', diff --git a/src/lib/snack-bar/public-api.ts b/src/lib/snack-bar/public-api.ts index 7bf602760cfd..0fe123dcdcf3 100644 --- a/src/lib/snack-bar/public-api.ts +++ b/src/lib/snack-bar/public-api.ts @@ -12,4 +12,4 @@ export * from './snack-bar-container'; export * from './snack-bar-config'; export * from './snack-bar-ref'; export * from './simple-snack-bar'; - +export * from './snack-bar-animations'; diff --git a/src/lib/snack-bar/simple-snack-bar.ts b/src/lib/snack-bar/simple-snack-bar.ts index 1433adbc3717..09b7e20be2e9 100644 --- a/src/lib/snack-bar/simple-snack-bar.ts +++ b/src/lib/snack-bar/simple-snack-bar.ts @@ -7,10 +7,9 @@ */ import {Component, ViewEncapsulation, Inject, ChangeDetectionStrategy} from '@angular/core'; -import {trigger, style, transition, animate} from '@angular/animations'; -import {AnimationCurves, AnimationDurations} from '@angular/material/core'; import {MatSnackBarRef} from './snack-bar-ref'; import {MAT_SNACK_BAR_DATA} from './snack-bar-config'; +import {matSnackBarAnimations} from './snack-bar-animations'; /** @@ -25,14 +24,7 @@ import {MAT_SNACK_BAR_DATA} from './snack-bar-config'; encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, - animations: [ - trigger('contentFade', [ - transition(':enter', [ - style({opacity: '0'}), - animate(`${AnimationDurations.COMPLEX} ${AnimationCurves.STANDARD_CURVE}`) - ]) - ]) - ], + animations: [matSnackBarAnimations.contentFade], host: { '[@contentFade]': '', 'class': 'mat-simple-snackbar', diff --git a/src/lib/snack-bar/snack-bar-animations.ts b/src/lib/snack-bar/snack-bar-animations.ts new file mode 100644 index 000000000000..d3c5681c38c4 --- /dev/null +++ b/src/lib/snack-bar/snack-bar-animations.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; +import {AnimationCurves, AnimationDurations} from '@angular/material/core'; + +/** @docs-private */ +export const SHOW_ANIMATION = + `${AnimationDurations.ENTERING} ${AnimationCurves.DECELERATION_CURVE}`; + +/** @docs-private */ +export const HIDE_ANIMATION = + `${AnimationDurations.EXITING} ${AnimationCurves.ACCELERATION_CURVE}`; + +/** Animations used by the Material snack bar. */ +export const matSnackBarAnimations: { + readonly contentFade: AnimationTriggerMetadata; + readonly snackBarState: AnimationTriggerMetadata; +} = { + /** Animation that slides the dialog in and out of view and fades the opacity. */ + contentFade: trigger('contentFade', [ + transition(':enter', [ + style({opacity: '0'}), + animate(`${AnimationDurations.COMPLEX} ${AnimationCurves.STANDARD_CURVE}`) + ]) + ]), + + /** Animation that shows and hides a snack bar. */ + snackBarState: trigger('state', [ + state('visible-top, visible-bottom', style({transform: 'translateY(0%)'})), + transition('visible-top => hidden-top, visible-bottom => hidden-bottom', + animate(HIDE_ANIMATION)), + transition('void => visible-top, void => visible-bottom', animate(SHOW_ANIMATION)), + ]) +}; diff --git a/src/lib/snack-bar/snack-bar-container.ts b/src/lib/snack-bar/snack-bar-container.ts index 28dc26cced8d..c20d24e98270 100644 --- a/src/lib/snack-bar/snack-bar-container.ts +++ b/src/lib/snack-bar/snack-bar-container.ts @@ -18,30 +18,17 @@ import { ViewEncapsulation, ChangeDetectorRef, } from '@angular/core'; -import { - trigger, - state, - style, - transition, - animate, - AnimationEvent, -} from '@angular/animations'; +import {AnimationEvent} from '@angular/animations'; import { BasePortalOutlet, ComponentPortal, CdkPortalOutlet, } from '@angular/cdk/portal'; import {take} from 'rxjs/operators/take'; -import {AnimationCurves, AnimationDurations} from '@angular/material/core'; import {Observable} from 'rxjs/Observable'; import {Subject} from 'rxjs/Subject'; import {MatSnackBarConfig} from './snack-bar-config'; - - -export const SHOW_ANIMATION = - `${AnimationDurations.ENTERING} ${AnimationCurves.DECELERATION_CURVE}`; -export const HIDE_ANIMATION = - `${AnimationDurations.EXITING} ${AnimationCurves.ACCELERATION_CURVE}`; +import {matSnackBarAnimations} from './snack-bar-animations'; /** * Internal component that wraps user-provided snack bar content. @@ -55,20 +42,13 @@ export const HIDE_ANIMATION = changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, + animations: [matSnackBarAnimations.snackBarState], host: { 'role': 'alert', 'class': 'mat-snack-bar-container', '[@state]': '_animationState', '(@state.done)': 'onAnimationEnd($event)' }, - animations: [ - trigger('state', [ - state('visible-top, visible-bottom', style({transform: 'translateY(0%)'})), - transition('visible-top => hidden-top, visible-bottom => hidden-bottom', - animate(HIDE_ANIMATION)), - transition('void => visible-top, void => visible-bottom', animate(SHOW_ANIMATION)), - ]) - ], }) export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy { /** Whether the component has been destroyed. */ diff --git a/src/lib/sort/public-api.ts b/src/lib/sort/public-api.ts index 651365193d3c..a62a44f74bd3 100644 --- a/src/lib/sort/public-api.ts +++ b/src/lib/sort/public-api.ts @@ -11,4 +11,4 @@ export * from './sort-direction'; export * from './sort-header'; export * from './sort-header-intl'; export * from './sort'; - +export * from './sort-animations'; diff --git a/src/lib/sort/sort-animations.ts b/src/lib/sort/sort-animations.ts new file mode 100644 index 000000000000..c5cf2264daf2 --- /dev/null +++ b/src/lib/sort/sort-animations.ts @@ -0,0 +1,70 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + keyframes, + AnimationTriggerMetadata, +} from '@angular/animations'; +import {AnimationCurves, AnimationDurations} from '@angular/material/core'; + +const SORT_ANIMATION_TRANSITION = AnimationDurations.ENTERING + ' ' + + AnimationCurves.STANDARD_CURVE; + +/** Animations used by MatSort. */ +export const matSortAnimations: { + readonly indicator: AnimationTriggerMetadata; + readonly leftPointer: AnimationTriggerMetadata; + readonly rightPointer: AnimationTriggerMetadata; + readonly indicatorToggle: AnimationTriggerMetadata; +} = { + /** Animation that moves the sort indicator. */ + indicator: trigger('indicator', [ + state('asc', style({transform: 'translateY(0px)'})), + // 10px is the height of the sort indicator, minus the width of the pointers + state('desc', style({transform: 'translateY(10px)'})), + transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION)) + ]), + + /** Animation that rotates the left pointer of the indicator based on the sorting direction. */ + leftPointer: trigger('leftPointer', [ + state('asc', style({transform: 'rotate(-45deg)'})), + state('desc', style({transform: 'rotate(45deg)'})), + transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION)) + ]), + + /** Animation that rotates the right pointer of the indicator based on the sorting direction. */ + rightPointer: trigger('rightPointer', [ + state('asc', style({transform: 'rotate(45deg)'})), + state('desc', style({transform: 'rotate(-45deg)'})), + transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION)) + ]), + + /** Animation that moves the indicator in and out of view when sorting is enabled/disabled. */ + indicatorToggle: trigger('indicatorToggle', [ + transition('void => asc', animate(SORT_ANIMATION_TRANSITION, keyframes([ + style({transform: 'translateY(25%)', opacity: 0}), + style({transform: 'none', opacity: 1}) + ]))), + transition('asc => void', animate(SORT_ANIMATION_TRANSITION, keyframes([ + style({transform: 'none', opacity: 1}), + style({transform: 'translateY(-25%)', opacity: 0}) + ]))), + transition('void => desc', animate(SORT_ANIMATION_TRANSITION, keyframes([ + style({transform: 'translateY(-25%)', opacity: 0}), + style({transform: 'none', opacity: 1}) + ]))), + transition('desc => void', animate(SORT_ANIMATION_TRANSITION, keyframes([ + style({transform: 'none', opacity: 1}), + style({transform: 'translateY(25%)', opacity: 0}) + ]))), + ]) +}; diff --git a/src/lib/sort/sort-header.ts b/src/lib/sort/sort-header.ts index 62a7babbdce6..342342988ced 100644 --- a/src/lib/sort/sort-header.ts +++ b/src/lib/sort/sort-header.ts @@ -15,26 +15,14 @@ import { ViewEncapsulation } from '@angular/core'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; -import { - trigger, - state, - style, - animate, - transition, - keyframes, -} from '@angular/animations'; import {CdkColumnDef} from '@angular/cdk/table'; import {Subscription} from 'rxjs/Subscription'; import {merge} from 'rxjs/observable/merge'; import {MatSort, MatSortable} from './sort'; import {MatSortHeaderIntl} from './sort-header-intl'; import {getSortHeaderNotContainedWithinSortError} from './sort-errors'; -import {AnimationCurves, AnimationDurations} from '@angular/material/core'; import {CanDisable, mixinDisabled} from '@angular/material/core'; - - -const SORT_ANIMATION_TRANSITION = - AnimationDurations.ENTERING + ' ' + AnimationCurves.STANDARD_CURVE; +import {matSortAnimations} from './sort-animations'; // Boilerplate for applying mixins to the sort header. /** @docs-private */ @@ -67,40 +55,10 @@ export const _MatSortHeaderMixinBase = mixinDisabled(MatSortHeaderBase); changeDetection: ChangeDetectionStrategy.OnPush, inputs: ['disabled'], animations: [ - trigger('indicator', [ - state('asc', style({transform: 'translateY(0px)'})), - // 10px is the height of the sort indicator, minus the width of the pointers - state('desc', style({transform: 'translateY(10px)'})), - transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION)) - ]), - trigger('leftPointer', [ - state('asc', style({transform: 'rotate(-45deg)'})), - state('desc', style({transform: 'rotate(45deg)'})), - transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION)) - ]), - trigger('rightPointer', [ - state('asc', style({transform: 'rotate(45deg)'})), - state('desc', style({transform: 'rotate(-45deg)'})), - transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION)) - ]), - trigger('indicatorToggle', [ - transition('void => asc', animate(SORT_ANIMATION_TRANSITION, keyframes([ - style({transform: 'translateY(25%)', opacity: 0}), - style({transform: 'none', opacity: 1}) - ]))), - transition('asc => void', animate(SORT_ANIMATION_TRANSITION, keyframes([ - style({transform: 'none', opacity: 1}), - style({transform: 'translateY(-25%)', opacity: 0}) - ]))), - transition('void => desc', animate(SORT_ANIMATION_TRANSITION, keyframes([ - style({transform: 'translateY(-25%)', opacity: 0}), - style({transform: 'none', opacity: 1}) - ]))), - transition('desc => void', animate(SORT_ANIMATION_TRANSITION, keyframes([ - style({transform: 'none', opacity: 1}), - style({transform: 'translateY(25%)', opacity: 0}) - ]))), - ]) + matSortAnimations.indicator, + matSortAnimations.leftPointer, + matSortAnimations.rightPointer, + matSortAnimations.indicatorToggle ] }) export class MatSortHeader extends _MatSortHeaderMixinBase implements MatSortable, CanDisable { diff --git a/src/lib/stepper/public-api.ts b/src/lib/stepper/public-api.ts index 40d5d6395e10..edae51641041 100644 --- a/src/lib/stepper/public-api.ts +++ b/src/lib/stepper/public-api.ts @@ -12,3 +12,4 @@ export * from './stepper'; export * from './stepper-button'; export * from './step-header'; export * from './stepper-intl'; +export * from './stepper-animations'; diff --git a/src/lib/stepper/stepper-animations.ts b/src/lib/stepper/stepper-animations.ts new file mode 100644 index 000000000000..cd109b25f213 --- /dev/null +++ b/src/lib/stepper/stepper-animations.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Animations used by the Material steppers. */ +export const matStepperAnimations: { + readonly horizontalStepTransition: AnimationTriggerMetadata; + readonly verticalStepTransition: AnimationTriggerMetadata; +} = { + /** Animation that transitions the step along the X axis in a horizontal stepper. */ + horizontalStepTransition: trigger('stepTransition', [ + state('previous', style({transform: 'translate3d(-100%, 0, 0)', visibility: 'hidden'})), + state('current', style({transform: 'none', visibility: 'visible'})), + state('next', style({transform: 'translate3d(100%, 0, 0)', visibility: 'hidden'})), + transition('* => *', animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')) + ]), + + /** Animation that transitions the step along the Y axis in a vertical stepper. */ + verticalStepTransition: trigger('stepTransition', [ + state('previous', style({height: '0px', visibility: 'hidden'})), + state('next', style({height: '0px', visibility: 'hidden'})), + state('current', style({height: '*', visibility: 'visible'})), + transition('* <=> current', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')) + ]) +}; diff --git a/src/lib/stepper/stepper.ts b/src/lib/stepper/stepper.ts index a5c795bc2cfa..86ddf1c15ab7 100644 --- a/src/lib/stepper/stepper.ts +++ b/src/lib/stepper/stepper.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {animate, state, style, transition, trigger} from '@angular/animations'; import {CdkStep, CdkStepper} from '@angular/cdk/stepper'; import { AfterContentInit, @@ -28,6 +27,7 @@ import {ErrorStateMatcher} from '@angular/material/core'; import {MatStepHeader} from './step-header'; import {MatStepLabel} from './step-label'; import {takeUntil} from 'rxjs/operators/takeUntil'; +import {matStepperAnimations} from './stepper-animations'; @Component({ moduleId: module.id, @@ -89,14 +89,7 @@ export class MatStepper extends CdkStepper implements AfterContentInit { 'aria-orientation': 'horizontal', 'role': 'tablist', }, - animations: [ - trigger('stepTransition', [ - state('previous', style({transform: 'translate3d(-100%, 0, 0)', visibility: 'hidden'})), - state('current', style({transform: 'none', visibility: 'visible'})), - state('next', style({transform: 'translate3d(100%, 0, 0)', visibility: 'hidden'})), - transition('* => *', animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')) - ]) - ], + animations: [matStepperAnimations.horizontalStepTransition], providers: [{provide: MatStepper, useExisting: MatHorizontalStepper}], encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, @@ -116,14 +109,7 @@ export class MatHorizontalStepper extends MatStepper { } 'aria-orientation': 'vertical', 'role': 'tablist', }, - animations: [ - trigger('stepTransition', [ - state('previous', style({height: '0px', visibility: 'hidden'})), - state('next', style({height: '0px', visibility: 'hidden'})), - state('current', style({height: '*', visibility: 'visible'})), - transition('* <=> current', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')) - ]) - ], + animations: [matStepperAnimations.verticalStepTransition], providers: [{provide: MatStepper, useExisting: MatVerticalStepper}], encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, diff --git a/src/lib/tabs/public-api.ts b/src/lib/tabs/public-api.ts index 5bdae5816899..e02e25709874 100644 --- a/src/lib/tabs/public-api.ts +++ b/src/lib/tabs/public-api.ts @@ -20,3 +20,4 @@ export {MatTabLabelWrapper} from './tab-label-wrapper'; export {MatTab} from './tab'; export {MatTabLabel} from './tab-label'; export {MatTabNav, MatTabLink} from './tab-nav-bar/index'; +export * from './tabs-animations'; diff --git a/src/lib/tabs/tab-body.ts b/src/lib/tabs/tab-body.ts index 17afd2c39c43..65698fca5038 100644 --- a/src/lib/tabs/tab-body.ts +++ b/src/lib/tabs/tab-body.ts @@ -23,17 +23,11 @@ import { ViewContainerRef, forwardRef, } from '@angular/core'; -import { - trigger, - state, - style, - animate, - transition, - AnimationEvent, -} from '@angular/animations'; +import {AnimationEvent} from '@angular/animations'; import {TemplatePortal, CdkPortalOutlet} from '@angular/cdk/portal'; import {Directionality, Direction} from '@angular/cdk/bidi'; import {Subscription} from 'rxjs/Subscription'; +import {matTabsAnimations} from './tabs-animations'; /** * These position states are used internally as animation states for the tab body. Setting the @@ -118,27 +112,10 @@ export class MatTabBodyPortal extends CdkPortalOutlet implements OnInit, OnDestr encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, + animations: [matTabsAnimations.translateTab], host: { 'class': 'mat-tab-body', }, - animations: [ - trigger('translateTab', [ - // Note: transitions to `none` instead of 0, because some browsers might blur the content. - state('center, void, left-origin-center, right-origin-center', style({transform: 'none'})), - state('left', style({transform: 'translate3d(-100%, 0, 0)'})), - state('right', style({transform: 'translate3d(100%, 0, 0)'})), - transition('* => left, * => right, left => center, right => center', - animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')), - transition('void => left-origin-center', [ - style({transform: 'translate3d(-100%, 0, 0)'}), - animate('500ms cubic-bezier(0.35, 0, 0.25, 1)') - ]), - transition('void => right-origin-center', [ - style({transform: 'translate3d(100%, 0, 0)'}), - animate('500ms cubic-bezier(0.35, 0, 0.25, 1)') - ]) - ]) - ] }) export class MatTabBody implements OnInit { /** Event emitted when the tab begins to animate towards the center as the active tab. */ diff --git a/src/lib/tabs/tabs-animations.ts b/src/lib/tabs/tabs-animations.ts new file mode 100644 index 000000000000..6a608373b460 --- /dev/null +++ b/src/lib/tabs/tabs-animations.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Animations used by the Material tabs. */ +export const matTabsAnimations: { + readonly translateTab: AnimationTriggerMetadata; +} = { + /** Animation translates a tab along the X axis. */ + translateTab: trigger('translateTab', [ + // Note: transitions to `none` instead of 0, because some browsers might blur the content. + state('center, void, left-origin-center, right-origin-center', style({transform: 'none'})), + state('left', style({transform: 'translate3d(-100%, 0, 0)'})), + state('right', style({transform: 'translate3d(100%, 0, 0)'})), + transition('* => left, * => right, left => center, right => center', + animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')), + transition('void => left-origin-center', [ + style({transform: 'translate3d(-100%, 0, 0)'}), + animate('500ms cubic-bezier(0.35, 0, 0.25, 1)') + ]), + transition('void => right-origin-center', [ + style({transform: 'translate3d(100%, 0, 0)'}), + animate('500ms cubic-bezier(0.35, 0, 0.25, 1)') + ]) + ]) +}; diff --git a/src/lib/tooltip/public-api.ts b/src/lib/tooltip/public-api.ts index 6d24abe03a81..4181ad895781 100644 --- a/src/lib/tooltip/public-api.ts +++ b/src/lib/tooltip/public-api.ts @@ -8,4 +8,4 @@ export * from './tooltip-module'; export * from './tooltip'; - +export * from './tooltip-animations'; diff --git a/src/lib/tooltip/tooltip-animations.ts b/src/lib/tooltip/tooltip-animations.ts new file mode 100644 index 000000000000..e4422456bf24 --- /dev/null +++ b/src/lib/tooltip/tooltip-animations.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + animate, + state, + style, + transition, + trigger, + AnimationTriggerMetadata, +} from '@angular/animations'; + +/** Animations used by MatTooltip. */ +export const matTooltipAnimations: { + readonly tooltipState: AnimationTriggerMetadata; +} = { + /** Animation that transitions a tooltip in and out. */ + tooltipState: trigger('state', [ + state('initial, void, hidden', style({transform: 'scale(0)'})), + state('visible', style({transform: 'scale(1)'})), + transition('* => visible', animate('150ms cubic-bezier(0.0, 0.0, 0.2, 1)')), + transition('* => hidden', animate('150ms cubic-bezier(0.4, 0.0, 1, 1)')), + ]) +}; diff --git a/src/lib/tooltip/tooltip.ts b/src/lib/tooltip/tooltip.ts index 8fa538c13bd6..e56bf8263f91 100644 --- a/src/lib/tooltip/tooltip.ts +++ b/src/lib/tooltip/tooltip.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {animate, AnimationEvent, state, style, transition, trigger} from '@angular/animations'; +import {AnimationEvent} from '@angular/animations'; import {AriaDescriber, FocusMonitor} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; @@ -44,6 +44,7 @@ import { } from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {Subject} from 'rxjs/Subject'; +import {matTooltipAnimations} from './tooltip-animations'; export type TooltipPosition = 'left' | 'right' | 'above' | 'below' | 'before' | 'after'; @@ -474,14 +475,7 @@ export type TooltipVisibility = 'initial' | 'visible' | 'hidden'; encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, - animations: [ - trigger('state', [ - state('initial, void, hidden', style({transform: 'scale(0)'})), - state('visible', style({transform: 'scale(1)'})), - transition('* => visible', animate('150ms cubic-bezier(0.0, 0.0, 0.2, 1)')), - transition('* => hidden', animate('150ms cubic-bezier(0.4, 0.0, 1, 1)')), - ]) - ], + animations: [matTooltipAnimations.tooltipState], host: { // Forces the element to have a layout in IE and Edge. This fixes issues where the element // won't be rendered if the animations are disabled or there is no web animations polyfill.