Skip to content

Commit b214f70

Browse files
committed
Refactor code for shared functionality between vertical and horizontal stepper
1 parent edd0a03 commit b214f70

15 files changed

+232
-87
lines changed

src/cdk/stepper/public_api.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,20 @@ import {CdkStepper, CdkStep} from './stepper';
1111
import {CommonModule} from '@angular/common';
1212
import {CdkStepLabel} from './step-label';
1313
import {CdkStepperNext, CdkStepperPrevious} from './stepper-button';
14+
import {CdkStepIcon} from './step-icon';
15+
import {CdkStepLabelContainer} from './step-label-container';
1416

1517
@NgModule({
1618
imports: [CommonModule],
17-
exports: [CdkStep, CdkStepper, CdkStepLabel, CdkStepperNext, CdkStepperPrevious],
18-
declarations: [CdkStep, CdkStepper, CdkStepLabel, CdkStepperNext, CdkStepperPrevious]
19+
exports: [CdkStep, CdkStepper, CdkStepLabel, CdkStepperNext, CdkStepperPrevious, CdkStepIcon,
20+
CdkStepLabelContainer],
21+
declarations: [CdkStep, CdkStepper, CdkStepLabel, CdkStepperNext, CdkStepperPrevious, CdkStepIcon,
22+
CdkStepLabelContainer]
1923
})
2024
export class CdkStepperModule {}
2125

2226
export * from './stepper';
2327
export * from './step-label';
2428
export * from './stepper-button';
29+
export * from './step-icon';
30+
export * from './step-label-container';

src/cdk/stepper/step-icon.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive, Input} from '@angular/core';
10+
import {CdkStep} from './stepper';
11+
12+
@Directive({
13+
selector: 'cdkStepIcon'
14+
})
15+
export class CdkStepIcon {
16+
/** Step of the icon to be displayed. */
17+
@Input()
18+
step: CdkStep;
19+
20+
/** Whether the step of the icon to be displayed is active. */
21+
@Input()
22+
selected: boolean;
23+
24+
/** Index of the step. */
25+
@Input()
26+
index: number;
27+
28+
/** Whether the user has touched the step that is not selected. */
29+
get notTouched() {
30+
return this._getIndicatorType() == 'number' && !this.selected;
31+
}
32+
33+
/** Returns the type of icon to be displayed. */
34+
_getIndicatorType(): 'number' | 'edit' | 'done' {
35+
if (!this.step.completed || this.selected) {
36+
return 'number';
37+
} else {
38+
return this.step.editable ? 'edit' : 'done';
39+
}
40+
}
41+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive, Input} from '@angular/core';
10+
import {CdkStep} from './stepper';
11+
12+
@Directive({
13+
selector: 'cdkStepLabelContainer'
14+
})
15+
export class CdkStepLabelContainer {
16+
/** Step of the label to be displayed. */
17+
@Input()
18+
step: CdkStep;
19+
20+
/** Whether the step of label to be displayed is selected. */
21+
@Input()
22+
selected: boolean;
23+
24+
/** Whether the label to be displayed is active. */
25+
get active() {
26+
return this.step.completed || this.selected;
27+
}
28+
}

src/cdk/stepper/stepper.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,6 @@ export class CdkStepper {
202202
}
203203
}
204204

205-
_getIndicatorType(index: number): 'number' | 'edit' | 'done' {
206-
const step = this._steps.toArray()[index];
207-
if (!step.completed || this._selectedIndex == index) {
208-
return 'number';
209-
} else {
210-
return step.editable ? 'edit' : 'done';
211-
}
212-
}
213-
214205
private _emitStepperSelectionEvent(newIndex: number): void {
215206
const stepsArray = this._steps.toArray();
216207
this.selectionChange.emit({

src/lib/stepper/_stepper-theme.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
color: mat-color($foreground, disabled-text);
2424
}
2525

26-
.mat-step-indicator {
26+
.mat-step-icon {
2727
background-color: mat-color($primary);
2828
color: mat-color($primary, default-contrast);
2929
}
@@ -33,7 +33,7 @@
3333
color: mat-color($foreground, disabled-text);
3434
}
3535

36-
.mat-step-indicator-not-touched {
36+
.mat-step-icon-not-touched {
3737
background-color: mat-color($foreground, disabled-text);
3838
}
3939
}

src/lib/stepper/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {MdCommonModule} from '../core';
1818
import {MdStepLabel} from './step-label';
1919
import {MdStepperNext, MdStepperPrevious} from './stepper-button';
2020
import {MdIconModule} from '../icon/index';
21+
import {MdStepIcon} from './step-icon';
22+
import {MdStepLabelContainer} from './step-label-container';
2123

2224
@NgModule({
2325
imports: [
@@ -29,9 +31,9 @@ import {MdIconModule} from '../icon/index';
2931
MdIconModule
3032
],
3133
exports: [MdCommonModule, MdHorizontalStepper, MdVerticalStepper, MdStep, MdStepLabel, MdStepper,
32-
MdStepperNext, MdStepperPrevious],
34+
MdStepperNext, MdStepperPrevious, MdStepIcon, MdStepLabelContainer],
3335
declarations: [MdHorizontalStepper, MdVerticalStepper, MdStep, MdStepLabel, MdStepper,
34-
MdStepperNext, MdStepperPrevious],
36+
MdStepperNext, MdStepperPrevious, MdStepIcon, MdStepLabelContainer],
3537
})
3638
export class MdStepperModule {}
3739

@@ -40,3 +42,5 @@ export * from './stepper-vertical';
4042
export * from './step-label';
4143
export * from './stepper';
4244
export * from './stepper-button';
45+
export * from './step-icon';
46+
export * from './step-label-container';

src/lib/stepper/step-icon.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div [ngSwitch]="_getIndicatorType()">
2+
<span *ngSwitchCase="'number'">{{index + 1}}</span>
3+
<md-icon *ngSwitchCase="'edit'">create</md-icon>
4+
<md-icon *ngSwitchCase="'done'">done</md-icon>
5+
</div>

src/lib/stepper/step-icon.spec.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import {MdStepperModule} from './index';
2+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
3+
import {Component, ViewChild} from '@angular/core';
4+
import {MdStep, MdStepper} from './stepper';
5+
import {MdStepIcon} from './step-icon';
6+
import {By} from '@angular/platform-browser';
7+
8+
describe('MdStepIcon', () => {
9+
10+
beforeEach(async(() => {
11+
TestBed.configureTestingModule({
12+
imports: [MdStepperModule],
13+
declarations: [SimpleStepIconApp],
14+
providers: [
15+
{provide: MdStepper, useClass: MdStepper}
16+
]
17+
});
18+
TestBed.compileComponents();
19+
}));
20+
21+
describe('setting icon', () => {
22+
let stepIconComponent: MdStepIcon;
23+
let fixture: ComponentFixture<SimpleStepIconApp>;
24+
let testComponent: SimpleStepIconApp;
25+
26+
beforeEach(() => {
27+
fixture = TestBed.createComponent(SimpleStepIconApp);
28+
fixture.detectChanges();
29+
30+
stepIconComponent = fixture.debugElement.query(By.css('md-step-icon')).componentInstance;
31+
testComponent = fixture.componentInstance;
32+
});
33+
34+
it('should set done icon if step is non-editable and completed', () => {
35+
stepIconComponent.selected = true;
36+
fixture.detectChanges();
37+
38+
expect(stepIconComponent._getIndicatorType()).toBe('number');
39+
40+
testComponent.mdStep.completed = true;
41+
testComponent.mdStep.editable = false;
42+
stepIconComponent.selected = false;
43+
fixture.detectChanges();
44+
45+
expect(stepIconComponent._getIndicatorType()).toBe('done');
46+
});
47+
48+
it('should set create icon if step is editable and completed', () => {
49+
stepIconComponent.selected = true;
50+
fixture.detectChanges();
51+
52+
expect(stepIconComponent._getIndicatorType()).toBe('number');
53+
54+
testComponent.mdStep.completed = true;
55+
testComponent.mdStep.editable = true;
56+
stepIconComponent.selected = false;
57+
fixture.detectChanges();
58+
59+
expect(stepIconComponent._getIndicatorType()).toBe('edit');
60+
});
61+
62+
it('should set "mat-step-icon-not-touched" class if the step ', () => {
63+
let stepIconEl = fixture.debugElement.query(By.css('md-step-icon')).nativeElement;
64+
65+
testComponent.mdStep.completed = false;
66+
stepIconComponent.selected = false;
67+
fixture.detectChanges();
68+
69+
expect(stepIconComponent._getIndicatorType()).toBe('number');
70+
expect(stepIconEl.classList).toContain('mat-step-icon-not-touched');
71+
});
72+
});
73+
});
74+
75+
@Component({
76+
template: `
77+
<md-step>step</md-step>
78+
<md-step-icon [step]="mdStep"></md-step-icon>
79+
`
80+
})
81+
class SimpleStepIconApp {
82+
@ViewChild(MdStep) mdStep: MdStep;
83+
}

src/lib/stepper/step-icon.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Component} from '@angular/core';
10+
import {CdkStepIcon} from '@angular/cdk/stepper';
11+
12+
@Component({
13+
selector: 'md-step-icon, mat-step-icon',
14+
templateUrl: 'step-icon.html',
15+
host: {
16+
'class': 'mat-step-icon',
17+
'[class.mat-step-icon-not-touched]': 'notTouched'
18+
}
19+
})
20+
export class MdStepIcon extends CdkStepIcon { }
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- If there is a label template, use it. -->
2+
<ng-container class="label" *ngIf="step.stepLabel" [ngTemplateOutlet]="step.stepLabel.template">
3+
</ng-container>
4+
<!-- It there is no label template, fall back to the text label. -->
5+
<div class="label" *ngIf="!step.stepLabel">{{step.label}}</div>
6+
7+
<div class="mat-step-optional" *ngIf="step.optional">Optional</div>

0 commit comments

Comments
 (0)