diff --git a/src/cdk/stepper/stepper.ts b/src/cdk/stepper/stepper.ts index e80ff26fbf81..654e1c1c7c86 100644 --- a/src/cdk/stepper/stepper.ts +++ b/src/cdk/stepper/stepper.ts @@ -30,8 +30,14 @@ import {AbstractControl} from '@angular/forms'; /** Used to generate unique ID for each stepper component. */ let nextId = 0; +/** + * Position state of the content of each step in stepper that is used for transitioning + * the content into correct position upon step selection change. + */ +export type StepContentPositionState = 'previous' | 'current' | 'next'; + /** Change event emitted on selection changes. */ -export class CdkStepperSelectionEvent { +export class StepperSelectionEvent { /** Index of the step now selected. */ selectedIndex: number; @@ -119,7 +125,7 @@ export class CdkStepper { } /** Event emitted when the selected step has changed. */ - @Output() selectionChange = new EventEmitter(); + @Output() selectionChange = new EventEmitter(); /** The index of the step that the focus can be set. */ _focusIndex: number = 0; @@ -146,11 +152,23 @@ export class CdkStepper { return `mat-step-label-${this._groupId}-${i}`; } - /** Returns nique id for each step content element. */ + /** Returns unique id for each step content element. */ _getStepContentId(i: number): string { return `mat-step-content-${this._groupId}-${i}`; } + /** Returns position state of the step with the given index. */ + _getAnimationDirection(index: number): StepContentPositionState { + const position = index - this._selectedIndex; + if (position < 0) { + return 'previous'; + } else if (position > 0) { + return 'next'; + } else { + return 'current'; + } + } + private _emitStepperSelectionEvent(newIndex: number): void { const stepsArray = this._steps.toArray(); this.selectionChange.emit({ diff --git a/src/lib/stepper/_stepper-theme.scss b/src/lib/stepper/_stepper-theme.scss index a55c82c7abbf..4f72d6ab0f48 100644 --- a/src/lib/stepper/_stepper-theme.scss +++ b/src/lib/stepper/_stepper-theme.scss @@ -33,11 +33,11 @@ background-color: mat-color($background, card); } - .vertical-content-container { + .mat-vertical-content-container { border-left-color: mat-color($foreground, divider); } - .connector-line { + .mat-connector-line { border-top-color: mat-color($foreground, divider); } } diff --git a/src/lib/stepper/stepper-horizontal.html b/src/lib/stepper/stepper-horizontal.html index 5937fd04551b..0eade60c9f35 100644 --- a/src/lib/stepper/stepper-horizontal.html +++ b/src/lib/stepper/stepper-horizontal.html @@ -21,14 +21,16 @@ -
+
- -
- +
+
+ +
diff --git a/src/lib/stepper/stepper-horizontal.ts b/src/lib/stepper/stepper-horizontal.ts index 1609d6a9c7df..dbccf06a60c8 100644 --- a/src/lib/stepper/stepper-horizontal.ts +++ b/src/lib/stepper/stepper-horizontal.ts @@ -8,6 +8,7 @@ import {Component} from '@angular/core'; import {MdStepper} from './stepper'; +import {animate, state, style, transition, trigger} from '@angular/animations'; @Component({ moduleId: module.id, @@ -19,6 +20,15 @@ import {MdStepper} from './stepper'; 'class': 'mat-stepper-horizontal', 'role': 'tablist', }, + animations: [ + trigger('stepTransition', [ + state('previous', style({transform: 'translate3d(-100%, 0, 0)', visibility: 'hidden'})), + state('current', style({transform: 'translate3d(0%, 0, 0)', visibility: 'visible'})), + state('next', style({transform: 'translate3d(100%, 0, 0)', visibility: 'hidden'})), + transition('* => *', + animate('500ms cubic-bezier(0.35, 0, 0.25, 1)')) + ]) + ], providers: [{provide: MdStepper, useExisting: MdHorizontalStepper}] }) export class MdHorizontalStepper extends MdStepper { } diff --git a/src/lib/stepper/stepper-vertical.html b/src/lib/stepper/stepper-vertical.html index dfc87e4a4eb4..8efe7a283932 100644 --- a/src/lib/stepper/stepper-vertical.html +++ b/src/lib/stepper/stepper-vertical.html @@ -19,12 +19,15 @@
-
+
- +
+ +
diff --git a/src/lib/stepper/stepper-vertical.ts b/src/lib/stepper/stepper-vertical.ts index 52fc6038a44b..b72349db888c 100644 --- a/src/lib/stepper/stepper-vertical.ts +++ b/src/lib/stepper/stepper-vertical.ts @@ -8,6 +8,7 @@ import {Component} from '@angular/core'; import {MdStepper} from './stepper'; +import {animate, state, style, transition, trigger} from '@angular/animations'; @Component({ moduleId: module.id, @@ -19,6 +20,14 @@ import {MdStepper} from './stepper'; 'class': 'mat-stepper-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)')) + ]) + ], providers: [{provide: MdStepper, useExisting: MdVerticalStepper}] }) export class MdVerticalStepper extends MdStepper { } diff --git a/src/lib/stepper/stepper.scss b/src/lib/stepper/stepper.scss index 7e2cd497af27..25a58bcd490d 100644 --- a/src/lib/stepper/stepper.scss +++ b/src/lib/stepper/stepper.scss @@ -1,9 +1,11 @@ +@import '../core/style/variables'; + $mat-horizontal-stepper-header-height: 72px !default; $mat-label-header-height: 24px !default; $mat-stepper-label-min-width: 50px !default; $mat-stepper-side-gap: 24px !default; $mat-vertical-stepper-content-margin: 12px !default; -$mat-vertical-stepper-content-padding: 16px 0 32px $mat-stepper-side-gap !default; +$mat-vertical-content-padding-bottom: 32px !default; $mat-vertical-content-container-padding: 8px !default; $mat-connector-line-width: 1px !default; $mat-connector-line-gap: 8px !default; @@ -43,6 +45,7 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga line-height: $mat-horizontal-stepper-header-height; overflow: hidden; align-items: center; + outline: none; .mat-stepper-index { margin-right: $mat-connector-line-gap; @@ -55,13 +58,14 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga display: flex; align-items: center; margin: $mat-connector-line-gap 0; + outline: none; .mat-stepper-index { margin-right: $mat-vertical-stepper-content-margin; } } -.connector-line { +.mat-connector-line { border-top-width: $mat-connector-line-width; border-top-style: solid; width: $mat-horizontal-connector-line-size; @@ -70,11 +74,19 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga height: 0; } -.mat-horizontal-stepper-content[aria-expanded='false'] { - display: none; +.mat-horizontal-stepper-content { + overflow: hidden; + + &[aria-expanded='false'] { + height: 0; + } +} + +.mat-horizontal-content-container { + overflow: hidden; } -.vertical-content-container { +.mat-vertical-content-container { border-left-width: $mat-connector-line-width; border-left-style: solid; margin-left: $mat-vertical-stepper-content-margin; @@ -83,21 +95,18 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga .mat-vertical-stepper-content { padding-left: $mat-stepper-side-gap; + overflow: hidden; +} - &[aria-expanded='false'] { - display: none; - } - - &[aria-expanded='true'] { - padding: $mat-vertical-stepper-content-padding; - } +.mat-vertical-content { + padding-bottom: $mat-vertical-content-padding-bottom; } .mat-step { margin-top: $mat-connector-line-gap; &:last-child { - .vertical-content-container { + .mat-vertical-content-container { border: none; } }