Skip to content

Commit 63fd77d

Browse files
committed
feat(stepper): create stepper global options and update logic in _getIndicatorType
1 parent dd56ac7 commit 63fd77d

File tree

2 files changed

+67
-29
lines changed

2 files changed

+67
-29
lines changed

src/cdk/stepper/stepper.ts

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
TemplateRef,
3131
ViewChild,
3232
ViewEncapsulation,
33+
InjectionToken,
3334
} from '@angular/core';
3435
import {AbstractControl} from '@angular/forms';
3536
import {CdkStepLabel} from './step-label';
@@ -64,7 +65,7 @@ export class StepperSelectionEvent {
6465
}
6566

6667
/** The state of each step. */
67-
export type StepState = 'number' | 'edit' | 'done' | 'error';
68+
export type StepState = 'number' | 'edit' | 'done' | 'error' | string;
6869

6970
/** Enum to represent the different states of the steps. */
7071
export const STEP_STATE = {
@@ -74,6 +75,26 @@ export const STEP_STATE = {
7475
ERROR: 'error'
7576
};
7677

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

@@ -110,6 +135,9 @@ export class CdkStep implements OnChanges {
110135
*/
111136
@Input('aria-labelledby') ariaLabelledby: string;
112137

138+
/** State of the step. */
139+
@Input() state: StepState;
140+
113141
/** Whether the user can return to this step once it has been marked as complted. */
114142
@Input()
115143
get editable(): boolean { return this._editable; }
@@ -126,51 +154,42 @@ export class CdkStep implements OnChanges {
126154
}
127155
private _optional = false;
128156

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

155-
private get _defaultCompleted() {
167+
private _getDefaultCompleted() {
156168
return this.stepControl ? this.stepControl.valid && this.interacted : this.interacted;
157169
}
158170

159171
/** Whether step has error. */
160172
@Input()
161173
get hasError(): boolean {
162-
return this._customError == null ? this._getDefaultError : this._customError;
174+
return this._customError || this._getDefaultError();
163175
}
164176
set hasError(value: boolean) {
165177
this._customError = coerceBooleanProperty(value);
166178
}
167179
private _customError: boolean | null = null;
168180

169-
private get _getDefaultError() {
181+
private _getDefaultError() {
170182
return this.stepControl && this.stepControl.invalid;
171183
}
172184

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

175194
/** Selects this step component. */
176195
select(): void {
@@ -331,20 +350,38 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
331350
}
332351

333352
/** Returns the type of icon to be displayed. */
334-
_getIndicatorType(index: number, state: StepState | string | null = null): StepState | string {
353+
_getIndicatorType(index: number, state: StepState = STEP_STATE.NUMBER): StepState {
335354
const step = this._steps.toArray()[index];
336355
const isCurrentStep = this._isCurrentStep(index);
337356

338-
if (step.showError && step.hasError && !isCurrentStep) {
357+
if (step._useGuidelines) {
358+
return this._getGuidelineLogic(step, isCurrentStep, state);
359+
} else {
360+
return this._getDefaultIndicatorLogic(step, isCurrentStep);
361+
}
362+
}
363+
364+
private _getDefaultIndicatorLogic(step: CdkStep, isCurrentStep: boolean): StepState {
365+
if (step._showError && step.hasError && !isCurrentStep) {
366+
return STEP_STATE.ERROR;
367+
} else if(!step.completed || isCurrentStep) {
368+
return STEP_STATE.NUMBER;
369+
} else {
370+
return step.editable ? STEP_STATE.EDIT : STEP_STATE.DONE;
371+
}
372+
}
373+
374+
private _getGuidelineLogic(step: CdkStep, isCurrentStep: boolean, state: StepState = STEP_STATE.NUMBER): StepState {
375+
if (step._showError && step.hasError && !isCurrentStep) {
339376
return STEP_STATE.ERROR;
340377
} else if (step.completed && !isCurrentStep) {
341378
return STEP_STATE.DONE;
342379
} else if (step.completed && isCurrentStep) {
343-
return state || STEP_STATE.NUMBER;
380+
return state;
344381
} else if (step.editable && isCurrentStep) {
345382
return STEP_STATE.EDIT;
346383
} else {
347-
return state || STEP_STATE.NUMBER;
384+
return state;
348385
}
349386
}
350387

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,
@@ -51,8 +51,9 @@ export class MatStep extends CdkStep implements ErrorStateMatcher {
5151
@ContentChild(MatStepLabel) stepLabel: MatStepLabel;
5252

5353
constructor(@Inject(forwardRef(() => MatStepper)) stepper: MatStepper,
54-
@SkipSelf() private _errorStateMatcher: ErrorStateMatcher) {
55-
super(stepper);
54+
@SkipSelf() private _errorStateMatcher: ErrorStateMatcher,
55+
@Optional() @Inject(MAT_STEPPER_GLOBAL_OPTIONS) stepperOptions: StepperOptions) {
56+
super(stepper, stepperOptions);
5657
}
5758

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

0 commit comments

Comments
 (0)