Skip to content

Stepper alternative label #12674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/lib/stepper/stepper.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ For more complex labels, add a template with the `matStepLabel` directive inside
</mat-vertical-stepper>
```

#### Label position
For `mat-horizontal-stepper` it's possible to define the position of the label. `end` is the default value, while `bottom` will place it under the step icon instead of at its side.
This behaviour is controlled by `labelPosition` property.

<!-- example(stepper-label-position-bottom) -->

### Stepper buttons
There are two button directives to support navigation between different steps:
`matStepperPrevious` and `matStepperNext`.
Expand Down
58 changes: 58 additions & 0 deletions src/lib/stepper/stepper.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

$mat-horizontal-stepper-header-height: 72px !default;
$mat-stepper-label-header-height: 24px !default;
$mat-stepper-label-position-bottom-top-gap: 16px !default;
$mat-stepper-side-gap: 24px !default;
$mat-vertical-stepper-content-margin: 36px !default;
$mat-stepper-line-width: 1px !default;
Expand All @@ -16,6 +17,10 @@ $mat-stepper-line-gap: 8px !default;
white-space: nowrap;
display: flex;
align-items: center;

.mat-stepper-label-position-bottom & {
align-items: flex-start;
}
}

.mat-stepper-horizontal-line {
Expand All @@ -25,6 +30,25 @@ $mat-stepper-line-gap: 8px !default;
height: 0;
margin: 0 $mat-stepper-line-gap - $mat-stepper-side-gap;
min-width: $mat-stepper-line-gap + $mat-stepper-side-gap;

.mat-stepper-label-position-bottom & {
margin: 0;
min-width: 0;
position: relative;
top: $mat-stepper-side-gap + $mat-stepper-label-header-height / 2;
}
}

%mat-header-horizontal-line-label-position-bottom {
border-top-color: rgba(0, 0, 0, 0.12);
border-top-width: $mat-stepper-line-width;
border-top-style: solid;
content: '';
display: inline-block;
height: 0;
position: absolute;
top: $mat-stepper-side-gap + $mat-stepper-label-header-height / 2;
width: calc(50% - #{$mat-stepper-label-header-height / 2 + $mat-stepper-line-gap});
}

.mat-horizontal-stepper-header {
Expand All @@ -43,6 +67,40 @@ $mat-stepper-line-gap: 8px !default;
margin-left: $mat-stepper-line-gap;
}
}

.mat-stepper-label-position-bottom & {
box-sizing: border-box;
flex-direction: column;
// We use auto instead of fixed 104px (by spec) because when there is an optional step
// the height is greater than that
height: auto;
padding: $mat-stepper-side-gap;

[dir='ltr'] &:not(:last-child)::after,
[dir='rtl'] &:not(:first-child)::after {
@extend %mat-header-horizontal-line-label-position-bottom;
right: 0;
}

[dir='ltr'] &:not(:first-child)::before,
[dir='rtl'] &:not(:last-child)::before {
@extend %mat-header-horizontal-line-label-position-bottom;
left: 0;
}

& .mat-step-icon,
& .mat-step-icon-not-touched {
// Cleans margin both for ltr and rtl direction
margin-right: 0;
margin-left: 0;
}

& .mat-step-label {
padding: $mat-stepper-label-position-bottom-top-gap 0 0 0;
text-align: center;
width: 100%;
}
}
}

.mat-vertical-stepper-header {
Expand Down
12 changes: 10 additions & 2 deletions src/lib/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
EventEmitter,
forwardRef,
Inject,
Input,
Optional,
Output,
QueryList,
Expand All @@ -38,9 +39,10 @@ import {
import {FormControl, FormGroupDirective, NgForm} from '@angular/forms';
import {DOCUMENT} from '@angular/common';
import {ErrorStateMatcher} from '@angular/material/core';
import {takeUntil} from 'rxjs/operators';

import {MatStepHeader} from './step-header';
import {MatStepLabel} from './step-label';
import {takeUntil} from 'rxjs/operators';
import {matStepperAnimations} from './stepper-animations';
import {MatStepperIcon, MatStepperIconContext} from './stepper-icon';

Expand Down Expand Up @@ -124,6 +126,8 @@ export class MatStepper extends _CdkStepper implements AfterContentInit {
inputs: ['selectedIndex'],
host: {
'class': 'mat-stepper-horizontal',
'[class.mat-stepper-label-position-end]': 'labelPosition == "end"',
'[class.mat-stepper-label-position-bottom]': 'labelPosition == "bottom"',
'aria-orientation': 'horizontal',
'role': 'tablist',
},
Expand All @@ -132,7 +136,11 @@ export class MatStepper extends _CdkStepper implements AfterContentInit {
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatHorizontalStepper extends MatStepper { }
export class MatHorizontalStepper extends MatStepper {
/** Whether the label should display in bottom or end position. */
@Input()
labelPosition: 'bottom' | 'end' = 'end';
}

@Component({
moduleId: module.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** No CSS for this example */
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<mat-horizontal-stepper labelPosition="bottom" #stepper>
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Fill out your name</ng-template>
<mat-form-field>
<input matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="secondFormGroup" optional>
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>Fill out your address</ng-template>
<mat-form-field>
<input matInput placeholder="Address" formControlName="secondCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step>
<ng-template matStepLabel>Done</ng-template>
You are now done.
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button (click)="stepper.reset()">Reset</button>
</div>
</mat-step>
</mat-horizontal-stepper>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';

/**
* @title Stepper label bottom position
*/
@Component({
selector: 'stepper-label-position-bottom-example',
templateUrl: 'stepper-label-position-bottom-example.html',
styleUrls: ['stepper-label-position-bottom-example.css'],
})
export class StepperLabelPositionBottomExample implements OnInit {
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;

constructor(private _formBuilder: FormBuilder) {}

ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required]
});
}
}