forked from angular/components
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstepper.ts
156 lines (136 loc) · 5.15 KB
/
stepper.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* @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 {Directionality} from '@angular/cdk/bidi';
import {CdkStep, CdkStepper, StepContentPositionState} from '@angular/cdk/stepper';
import {AnimationEvent} from '@angular/animations';
import {
AfterContentInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
ContentChildren,
Directive,
EventEmitter,
forwardRef,
Inject,
Optional,
Output,
QueryList,
SkipSelf,
TemplateRef,
ViewChildren,
ViewEncapsulation,
} from '@angular/core';
import {FormControl, FormGroupDirective, NgForm} from '@angular/forms';
import {ErrorStateMatcher} from '@angular/material/core';
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';
// TODO(devversion): workaround for https://github.com/angular/material2/issues/12760
export const _CdkStepper = CdkStepper;
@Component({
moduleId: module.id,
selector: 'mat-step',
templateUrl: 'step.html',
providers: [{provide: ErrorStateMatcher, useExisting: MatStep}],
encapsulation: ViewEncapsulation.None,
exportAs: 'matStep',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatStep extends CdkStep implements ErrorStateMatcher {
/** Content for step label given by `<ng-template matStepLabel>`. */
@ContentChild(MatStepLabel) stepLabel: MatStepLabel;
constructor(@Inject(forwardRef(() => MatStepper)) stepper: MatStepper,
@SkipSelf() private _errorStateMatcher: ErrorStateMatcher) {
super(stepper);
}
/** Custom error state matcher that additionally checks for validity of interacted form. */
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const originalErrorState = this._errorStateMatcher.isErrorState(control, form);
// Custom error state checks for the validity of form that is not submitted or touched
// since user can trigger a form change by calling for another step without directly
// interacting with the current form.
const customErrorState = !!(control && control.invalid && this.interacted);
return originalErrorState || customErrorState;
}
}
@Directive({
selector: '[matStepper]'
})
export class MatStepper extends _CdkStepper implements AfterContentInit {
/** The list of step headers of the steps in the stepper. */
@ViewChildren(MatStepHeader) _stepHeader: QueryList<MatStepHeader>;
/** Steps that the stepper holds. */
@ContentChildren(MatStep) _steps: QueryList<MatStep>;
/** Custom icon overrides passed in by the consumer. */
@ContentChildren(MatStepperIcon) _icons: QueryList<MatStepperIcon>;
/** Event emitted when the current step is done transitioning in. */
@Output() readonly animationDone: EventEmitter<void> = new EventEmitter<void>();
/** Consumer-specified template-refs to be used to override the header icons. */
_iconOverrides: {[key: string]: TemplateRef<MatStepperIconContext>} = {};
ngAfterContentInit() {
const icons = this._icons.toArray();
['edit', 'done', 'number'].forEach(name => {
const override = icons.find(icon => icon.name === name);
if (override) {
this._iconOverrides[name] = override.templateRef;
}
});
// Mark the component for change detection whenever the content children query changes
this._steps.changes.pipe(takeUntil(this._destroyed)).subscribe(() => this._stateChanged());
}
_animationDone(event: AnimationEvent) {
if ((event.toState as StepContentPositionState) === 'current') {
this.animationDone.emit();
}
}
}
@Component({
moduleId: module.id,
selector: 'mat-horizontal-stepper',
exportAs: 'matHorizontalStepper',
templateUrl: 'stepper-horizontal.html',
styleUrls: ['stepper.css'],
inputs: ['selectedIndex'],
host: {
'class': 'mat-stepper-horizontal',
'aria-orientation': 'horizontal',
'role': 'tablist',
},
animations: [matStepperAnimations.horizontalStepTransition],
providers: [{provide: MatStepper, useExisting: MatHorizontalStepper}],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatHorizontalStepper extends MatStepper { }
@Component({
moduleId: module.id,
selector: 'mat-vertical-stepper',
exportAs: 'matVerticalStepper',
templateUrl: 'stepper-vertical.html',
styleUrls: ['stepper.css'],
inputs: ['selectedIndex'],
host: {
'class': 'mat-stepper-vertical',
'aria-orientation': 'vertical',
'role': 'tablist',
},
animations: [matStepperAnimations.verticalStepTransition],
providers: [{provide: MatStepper, useExisting: MatVerticalStepper}],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatVerticalStepper extends MatStepper {
constructor(@Optional() dir: Directionality, changeDetectorRef: ChangeDetectorRef) {
super(dir, changeDetectorRef);
this._orientation = 'vertical';
}
}