Skip to content

Commit d72c1bc

Browse files
authored
Fix focus logic and CSS changes (#6507)
1 parent 90babef commit d72c1bc

File tree

6 files changed

+91
-42
lines changed

6 files changed

+91
-42
lines changed

src/cdk/stepper/stepper.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,12 @@ export class CdkStepper {
109109
@Input()
110110
get selectedIndex() { return this._selectedIndex; }
111111
set selectedIndex(index: number) {
112-
if (this._selectedIndex != index && !this._anyControlsInvalid(index)) {
112+
if (this._anyControlsInvalid(index)) {
113+
// remove focus from clicked step header if the step is not able to be selected
114+
this._stepHeader.toArray()[index].nativeElement.blur();
115+
} else if (this._selectedIndex != index) {
113116
this._emitStepperSelectionEvent(index);
114-
this._focusStep(this._selectedIndex);
117+
this._focusIndex = this._selectedIndex;
115118
}
116119
}
117120
private _selectedIndex: number = 0;

src/lib/stepper/_stepper-theme.scss

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99

1010
.mat-horizontal-stepper-header, .mat-vertical-stepper-header {
1111

12+
&:focus,
13+
&:hover {
14+
background-color: mat-color($background, hover);
15+
}
16+
1217
.mat-stepper-label {
1318
color: mat-color($foreground, text);
1419
}
@@ -33,11 +38,11 @@
3338
background-color: mat-color($background, card);
3439
}
3540

36-
.mat-vertical-content-container {
41+
.mat-stepper-vertical-line::before {
3742
border-left-color: mat-color($foreground, divider);
3843
}
3944

40-
.mat-connector-line {
45+
.mat-stepper-horizontal-line {
4146
border-top-color: mat-color($foreground, divider);
4247
}
4348
}

src/lib/stepper/stepper-horizontal.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
</div>
2222
</div>
2323

24-
<div *ngIf="!isLast" class="mat-connector-line"></div>
24+
<div *ngIf="!isLast" class="mat-stepper-horizontal-line"></div>
2525
</ng-container>
2626
</div>
2727
<div class="mat-horizontal-content-container">

src/lib/stepper/stepper-vertical.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
</div>
2020

2121
</div>
22-
<div class="mat-vertical-content-container">
22+
<div class="mat-vertical-content-container" [class.mat-stepper-vertical-line]="!isLast">
2323
<div class="mat-vertical-stepper-content" role="tabpanel"
2424
[@stepTransition]="_getAnimationDirection(i)"
2525
[id]="_getStepContentId(i)"

src/lib/stepper/stepper.scss

+32-36
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
11
@import '../core/style/variables';
22

33
$mat-horizontal-stepper-header-height: 72px !default;
4-
$mat-label-header-height: 24px !default;
4+
$mat-stepper-label-header-height: 24px !default;
55
$mat-stepper-label-min-width: 50px !default;
66
$mat-stepper-side-gap: 24px !default;
7-
$mat-vertical-stepper-content-margin: 12px !default;
8-
$mat-vertical-content-padding-bottom: 32px !default;
9-
$mat-vertical-content-container-padding: 8px !default;
10-
$mat-connector-line-width: 1px !default;
11-
$mat-connector-line-gap: 8px !default;
12-
$mat-horizontal-connector-line-size: 5% !default;
13-
$mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-gap !default;
7+
$mat-vertical-stepper-content-margin: 36px !default;
8+
$mat-stepper-line-width: 1px !default;
9+
$mat-stepper-line-gap: 8px !default;
1410

1511
:host {
1612
display: block;
17-
padding: 0 $mat-stepper-side-gap $mat-stepper-side-gap $mat-stepper-side-gap;
1813
}
1914

2015
.mat-stepper-label {
@@ -28,10 +23,10 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga
2823

2924
.mat-stepper-index {
3025
border-radius: 50%;
31-
height: $mat-label-header-height;
32-
width: $mat-label-header-height;
26+
height: $mat-stepper-label-header-height;
27+
width: $mat-stepper-label-header-height;
3328
text-align: center;
34-
line-height: $mat-label-header-height;
29+
line-height: $mat-stepper-label-header-height;
3530
}
3631

3732
.mat-horizontal-stepper-header-container {
@@ -46,9 +41,10 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga
4641
overflow: hidden;
4742
align-items: center;
4843
outline: none;
44+
padding: 0 $mat-stepper-side-gap;
4945

5046
.mat-stepper-index {
51-
margin-right: $mat-connector-line-gap;
47+
margin-right: $mat-stepper-line-gap;
5248
display: inline-block;
5349
flex: none;
5450
}
@@ -57,21 +53,21 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga
5753
.mat-vertical-stepper-header {
5854
display: flex;
5955
align-items: center;
60-
margin: $mat-connector-line-gap 0;
56+
padding: $mat-stepper-side-gap;
6157
outline: none;
6258

6359
.mat-stepper-index {
64-
margin-right: $mat-vertical-stepper-content-margin;
60+
margin-right: $mat-vertical-stepper-content-margin - $mat-stepper-side-gap;
6561
}
6662
}
6763

68-
.mat-connector-line {
69-
border-top-width: $mat-connector-line-width;
64+
.mat-stepper-horizontal-line {
65+
border-top-width: $mat-stepper-line-width;
7066
border-top-style: solid;
71-
width: $mat-horizontal-connector-line-size;
7267
flex: auto;
73-
margin: 0 $mat-connector-line-gap;
7468
height: 0;
69+
margin: 0 $mat-stepper-line-gap - $mat-stepper-side-gap;
70+
min-width: $mat-stepper-line-gap + $mat-stepper-side-gap;
7571
}
7672

7773
.mat-horizontal-stepper-content {
@@ -84,35 +80,35 @@ $mat-vertical-stepper-margin-top: $mat-stepper-side-gap - $mat-connector-line-ga
8480

8581
.mat-horizontal-content-container {
8682
overflow: hidden;
83+
padding: 0 $mat-stepper-side-gap $mat-stepper-side-gap $mat-stepper-side-gap;
8784
}
8885

8986
.mat-vertical-content-container {
90-
border-left-width: $mat-connector-line-width;
91-
border-left-style: solid;
9287
margin-left: $mat-vertical-stepper-content-margin;
93-
padding: $mat-vertical-content-container-padding 0;
88+
border: 0;
89+
position: relative;
90+
}
91+
92+
.mat-stepper-vertical-line::before {
93+
content: '';
94+
position: absolute;
95+
top: $mat-stepper-line-gap - $mat-stepper-side-gap;
96+
bottom: $mat-stepper-line-gap - $mat-stepper-side-gap;
97+
left: 0;
98+
border-left-width: $mat-stepper-line-width;
99+
border-left-style: solid;
94100
}
95101

96102
.mat-vertical-stepper-content {
97-
padding-left: $mat-stepper-side-gap;
98103
overflow: hidden;
99104
}
100105

101106
.mat-vertical-content {
102-
padding-bottom: $mat-vertical-content-padding-bottom;
107+
padding: 0 $mat-stepper-side-gap $mat-stepper-side-gap $mat-stepper-side-gap;
103108
}
104109

105-
.mat-step {
106-
margin-top: $mat-connector-line-gap;
107-
108-
&:last-child {
109-
.mat-vertical-content-container {
110-
border: none;
111-
}
112-
}
113-
114-
&:first-child {
115-
margin-top: 0;
116-
padding-top: $mat-vertical-stepper-margin-top;
110+
.mat-step:last-child {
111+
.mat-vertical-content-container {
112+
border: none;
117113
}
118114
}

src/lib/stepper/stepper.spec.ts

+45
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ describe('MdHorizontalStepper', () => {
7575
let stepHeaders = fixture.debugElement.queryAll(By.css('.mat-horizontal-stepper-header'));
7676
checkKeyboardEvent(stepperComponent, fixture, stepHeaders);
7777
});
78+
79+
it('should not set focus on header of selected step if header is not clicked', () => {
80+
let stepHeaderEl = fixture.debugElement
81+
.queryAll(By.css('.mat-horizontal-stepper-header'))[1].nativeElement;
82+
checkStepHeaderFocusNotCalled(stepHeaderEl, stepperComponent, fixture);
83+
});
7884
});
7985

8086
describe('linear horizontal stepper', () => {
@@ -105,6 +111,12 @@ describe('MdHorizontalStepper', () => {
105111
.queryAll(By.css('.mat-horizontal-stepper-header'))[1].nativeElement;
106112
checkLinearStepperValidity(stepHeaderEl, stepperComponent, testComponent, fixture);
107113
});
114+
115+
it('should not focus step header upon click if it is not able to be selected', () => {
116+
let stepHeaderEl = fixture.debugElement
117+
.queryAll(By.css('.mat-horizontal-stepper-header'))[1].nativeElement;
118+
checkStepHeaderBlur(stepHeaderEl, fixture);
119+
});
108120
});
109121
});
110122

@@ -173,6 +185,12 @@ describe('MdVerticalStepper', () => {
173185
let stepHeaders = fixture.debugElement.queryAll(By.css('.mat-vertical-stepper-header'));
174186
checkKeyboardEvent(stepperComponent, fixture, stepHeaders);
175187
});
188+
189+
it('should not set focus on header of selected step if header is not clicked', () => {
190+
let stepHeaderEl = fixture.debugElement
191+
.queryAll(By.css('.mat-vertical-stepper-header'))[1].nativeElement;
192+
checkStepHeaderFocusNotCalled(stepHeaderEl, stepperComponent, fixture);
193+
});
176194
});
177195

178196
describe('linear vertical stepper', () => {
@@ -204,6 +222,12 @@ describe('MdVerticalStepper', () => {
204222

205223
checkLinearStepperValidity(stepHeaderEl, stepperComponent, testComponent, fixture);
206224
});
225+
226+
it('should not focus step header upon click if it is not able to be selected', () => {
227+
let stepHeaderEl = fixture.debugElement
228+
.queryAll(By.css('.mat-vertical-stepper-header'))[1].nativeElement;
229+
checkStepHeaderBlur(stepHeaderEl, fixture);
230+
});
207231
});
208232
});
209233

@@ -387,6 +411,19 @@ function checkKeyboardEvent(stepperComponent: MdStepper,
387411
'Expected index of selected step to change to index of focused step after SPACE event.');
388412
}
389413

414+
function checkStepHeaderFocusNotCalled(stepHeaderEl: HTMLElement,
415+
stepperComponent: MdStepper,
416+
fixture: ComponentFixture<any>) {
417+
let nextButtonNativeEl = fixture.debugElement
418+
.queryAll(By.directive(MdStepperNext))[0].nativeElement;
419+
spyOn(stepHeaderEl, 'focus');
420+
nextButtonNativeEl.click();
421+
fixture.detectChanges();
422+
423+
expect(stepperComponent.selectedIndex).toBe(1);
424+
expect(stepHeaderEl.focus).not.toHaveBeenCalled();
425+
}
426+
390427
function checkLinearStepperValidity(stepHeaderEl: HTMLElement,
391428
stepperComponent: MdStepper,
392429
testComponent:
@@ -412,6 +449,14 @@ function checkLinearStepperValidity(stepHeaderEl: HTMLElement,
412449
expect(stepperComponent.selectedIndex).toBe(1);
413450
}
414451

452+
function checkStepHeaderBlur(stepHeaderEl: HTMLElement, fixture: ComponentFixture<any>) {
453+
spyOn(stepHeaderEl, 'blur');
454+
stepHeaderEl.click();
455+
fixture.detectChanges();
456+
457+
expect(stepHeaderEl.blur).toHaveBeenCalled();
458+
}
459+
415460
@Component({
416461
template: `
417462
<md-horizontal-stepper>

0 commit comments

Comments
 (0)