Skip to content

Commit bda6e47

Browse files
committed
feat(stepper): create stepper global options and update logic in _getIndicatorType
1 parent 5f0deba commit bda6e47

File tree

2 files changed

+70
-29
lines changed

2 files changed

+70
-29
lines changed

src/cdk/stepper/stepper.ts

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
TemplateRef,
3232
ViewChild,
3333
ViewEncapsulation,
34+
InjectionToken,
3435
} from '@angular/core';
3536
import {DOCUMENT} from '@angular/common';
3637
import {AbstractControl} from '@angular/forms';
@@ -66,7 +67,7 @@ export class StepperSelectionEvent {
6667
}
6768

6869
/** The state of each step. */
69-
export type StepState = 'number' | 'edit' | 'done' | 'error';
70+
export type StepState = 'number' | 'edit' | 'done' | 'error' | string;
7071

7172
/** Enum to represent the different states of the steps. */
7273
export const STEP_STATE = {
@@ -76,6 +77,26 @@ export const STEP_STATE = {
7677
ERROR: 'error'
7778
};
7879

80+
/** InjectionToken that can be used to specify the global stepper options. */
81+
export const MAT_STEPPER_GLOBAL_OPTIONS =
82+
new InjectionToken<StepperOptions>('mat-stepper-global-options');
83+
84+
/** Configurable options for floating labels. */
85+
export interface StepperOptions {
86+
/**
87+
* Whether the stepper should display an error state or not.
88+
* Default behavior is assumed to be false.
89+
*/
90+
showError?: boolean;
91+
92+
/**
93+
* Whether the stepper should use the Material UI guidelines when
94+
* displaying the icons or not.
95+
* Default behavior is assumed to be false.
96+
*/
97+
useGuidelines?: boolean;
98+
}
99+
79100
@Component({
80101
moduleId: module.id,
81102
selector: 'cdk-step',
@@ -85,6 +106,10 @@ export const STEP_STATE = {
85106
changeDetection: ChangeDetectionStrategy.OnPush,
86107
})
87108
export class CdkStep implements OnChanges {
109+
private _stepperOptions: StepperOptions;
110+
_showError: boolean;
111+
_useGuidelines: boolean;
112+
88113
/** Template for step label if it exists. */
89114
@ContentChild(CdkStepLabel) stepLabel: CdkStepLabel;
90115

@@ -112,6 +137,9 @@ export class CdkStep implements OnChanges {
112137
*/
113138
@Input('aria-labelledby') ariaLabelledby: string;
114139

140+
/** State of the step. */
141+
@Input() state: StepState;
142+
115143
/** Whether the user can return to this step once it has been marked as complted. */
116144
@Input()
117145
get editable(): boolean { return this._editable; }
@@ -128,51 +156,42 @@ export class CdkStep implements OnChanges {
128156
}
129157
private _optional = false;
130158

131-
/** State of the step. */
132-
@Input()
133-
get state(): StepState | string | null { return this._state; }
134-
set state(value: StepState | string | null) {
135-
this._state = value;
136-
}
137-
private _state: StepState | string | null = null;
138-
139-
/** Whether to show the step is in an error state. */
140-
@Input()
141-
get showError(): boolean { return this._showError; }
142-
set showError(value: boolean) {
143-
this._showError = value;
144-
}
145-
private _showError: boolean = false;
146-
147159
/** Whether step is marked as completed. */
148160
@Input()
149161
get completed(): boolean {
150-
return this._customCompleted == null ? this._defaultCompleted() : this._customCompleted;
162+
return this._customCompleted == null ? this._getDefaultCompleted() : this._customCompleted;
151163
}
152164
set completed(value: boolean) {
153165
this._customCompleted = coerceBooleanProperty(value);
154166
}
155167
private _customCompleted: boolean | null = null;
156168

157-
private _defaultCompleted() {
169+
private _getDefaultCompleted() {
158170
return this.stepControl ? this.stepControl.valid && this.interacted : this.interacted;
159171
}
160172

161173
/** Whether step has error. */
162174
@Input()
163175
get hasError(): boolean {
164-
return this._customError == null ? this._getDefaultError : this._customError;
176+
return this._customError || this._getDefaultError();
165177
}
166178
set hasError(value: boolean) {
167179
this._customError = coerceBooleanProperty(value);
168180
}
169181
private _customError: boolean | null = null;
170182

171-
private get _getDefaultError() {
183+
private _getDefaultError() {
172184
return this.stepControl && this.stepControl.invalid;
173185
}
174186

175-
constructor(@Inject(forwardRef(() => CdkStepper)) private _stepper: CdkStepper) { }
187+
constructor(
188+
@Inject(forwardRef(() => CdkStepper)) private _stepper: CdkStepper,
189+
@Optional() @Inject(MAT_STEPPER_GLOBAL_OPTIONS) stepperOptions: StepperOptions
190+
) {
191+
this._stepperOptions = stepperOptions ? stepperOptions : {};
192+
this._showError = !!this._stepperOptions.showError;
193+
this._useGuidelines = !!this._stepperOptions.useGuidelines;
194+
}
176195

177196
/** Selects this step component. */
178197
select(): void {
@@ -343,20 +362,41 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
343362
}
344363

345364
/** Returns the type of icon to be displayed. */
346-
_getIndicatorType(index: number, state: StepState | string | null = null): StepState | string {
365+
_getIndicatorType(index: number, state: StepState = STEP_STATE.NUMBER): StepState {
347366
const step = this._steps.toArray()[index];
348367
const isCurrentStep = this._isCurrentStep(index);
349368

350-
if (step.showError && step.hasError && !isCurrentStep) {
369+
if (step._useGuidelines) {
370+
return this._getGuidelineLogic(step, isCurrentStep, state);
371+
} else {
372+
return this._getDefaultIndicatorLogic(step, isCurrentStep);
373+
}
374+
}
375+
376+
private _getDefaultIndicatorLogic(step: CdkStep, isCurrentStep: boolean): StepState {
377+
if (step._showError && step.hasError && !isCurrentStep) {
378+
return STEP_STATE.ERROR;
379+
} else if (!step.completed || isCurrentStep) {
380+
return STEP_STATE.NUMBER;
381+
} else {
382+
return step.editable ? STEP_STATE.EDIT : STEP_STATE.DONE;
383+
}
384+
}
385+
386+
private _getGuidelineLogic(
387+
step: CdkStep,
388+
isCurrentStep: boolean,
389+
state: StepState = STEP_STATE.NUMBER): StepState {
390+
if (step._showError && step.hasError && !isCurrentStep) {
351391
return STEP_STATE.ERROR;
352392
} else if (step.completed && !isCurrentStep) {
353393
return STEP_STATE.DONE;
354394
} else if (step.completed && isCurrentStep) {
355-
return state || STEP_STATE.NUMBER;
395+
return state;
356396
} else if (step.editable && isCurrentStep) {
357397
return STEP_STATE.EDIT;
358398
} else {
359-
return state || STEP_STATE.NUMBER;
399+
return state;
360400
}
361401
}
362402

src/lib/stepper/stepper.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {Directionality} from '@angular/cdk/bidi';
10-
import {CdkStep, CdkStepper, StepContentPositionState} from '@angular/cdk/stepper';
10+
import {CdkStep, CdkStepper, StepContentPositionState, MAT_STEPPER_GLOBAL_OPTIONS, StepperOptions} from '@angular/cdk/stepper';
1111
import {AnimationEvent} from '@angular/animations';
1212
import {
1313
AfterContentInit,
@@ -55,8 +55,9 @@ export class MatStep extends CdkStep implements ErrorStateMatcher {
5555
@ContentChild(MatStepLabel) stepLabel: MatStepLabel;
5656

5757
constructor(@Inject(forwardRef(() => MatStepper)) stepper: MatStepper,
58-
@SkipSelf() private _errorStateMatcher: ErrorStateMatcher) {
59-
super(stepper);
58+
@SkipSelf() private _errorStateMatcher: ErrorStateMatcher,
59+
@Optional() @Inject(MAT_STEPPER_GLOBAL_OPTIONS) stepperOptions: StepperOptions) {
60+
super(stepper, stepperOptions);
6061
}
6162

6263
/** Custom error state matcher that additionally checks for validity of interacted form. */

0 commit comments

Comments
 (0)