Skip to content

Commit dd93237

Browse files
committed
Differentiate sliders focused via keyboard vs other means
1 parent 8b2ae0d commit dd93237

File tree

6 files changed

+110
-96
lines changed

6 files changed

+110
-96
lines changed

src/lib/slider/_slider-theme.scss

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
$mat-slider-disabled-color: rgba(black, 0.26);
1111
$mat-slider-labeled-min-value-thumb-color: black;
1212
$mat-slider-labeled-min-value-thumb-label-color: rgba(black, 0.26);
13+
$mat-slider-focus-ring-color: rgba(mat-color($accent), 0.2);
14+
$mat-slider-focus-ring-min-value-color: rgba(black, 0.12);
1315

1416
.mat-slider-track-background {
1517
background-color: $mat-slider-off-color;
@@ -19,6 +21,10 @@
1921
background-color: mat-color($accent);
2022
}
2123

24+
.mat-slider-focus-ring {
25+
background-color: $mat-slider-focus-ring-color;
26+
}
27+
2228
.mat-slider-thumb {
2329
background-color: mat-color($accent);
2430
}
@@ -32,7 +38,7 @@
3238
}
3339

3440
.mat-slider:hover,
35-
.mat-slider-active {
41+
.cdk-focused {
3642
.mat-slider-track-background {
3743
background-color: $mat-slider-off-focused-color;
3844
}
@@ -53,13 +59,17 @@
5359
}
5460

5561
.mat-slider-min-value {
62+
.mat-slider-focus-ring {
63+
background-color: $mat-slider-focus-ring-min-value-color;
64+
}
65+
5666
&.mat-slider-thumb-label-showing {
5767
.mat-slider-thumb,
5868
.mat-slider-thumb-label {
5969
background-color: $mat-slider-labeled-min-value-thumb-color;
6070
}
6171

62-
&.mat-slider-active {
72+
&.cdk-focused {
6373
.mat-slider-thumb,
6474
.mat-slider-thumb-label {
6575
background-color: $mat-slider-labeled-min-value-thumb-label-color;
@@ -74,7 +84,7 @@
7484
}
7585

7686
&:hover,
77-
&.mat-slider-active {
87+
&.cdk-focused {
7888
.mat-slider-thumb {
7989
border-color: $mat-slider-off-focused-color;
8090
}

src/lib/slider/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import {NgModule, ModuleWithProviders} from '@angular/core';
1+
import {ModuleWithProviders, NgModule} from '@angular/core';
22
import {HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
33
import {CommonModule} from '@angular/common';
44
import {FormsModule} from '@angular/forms';
5-
import {GestureConfig, CompatibilityModule} from '../core';
5+
import {CompatibilityModule, GestureConfig, StyleModule} from '../core';
66
import {MdSlider} from './slider';
7+
import {RtlModule} from '../core/rtl/dir';
78

89

910
@NgModule({
10-
imports: [CommonModule, FormsModule, CompatibilityModule],
11+
imports: [CommonModule, FormsModule, CompatibilityModule, StyleModule, RtlModule],
1112
exports: [MdSlider, CompatibilityModule],
1213
declarations: [MdSlider],
1314
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}]

src/lib/slider/slider.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<div class="mat-slider-ticks" [ngStyle]="ticksStyles"></div>
88
</div>
99
<div class="mat-slider-thumb-container" [ngStyle]="thumbContainerStyles">
10+
<div class="mat-slider-focus-ring"></div>
1011
<div class="mat-slider-thumb"></div>
1112
<div class="mat-slider-thumb-label">
1213
<span class="mat-slider-thumb-label-text">{{displayValue}}</span>

src/lib/slider/slider.scss

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ $mat-slider-thumb-label-size: 28px !default;
2424
$mat-slider-tick-color: rgba(0, 0, 0, 0.6) !default;
2525
$mat-slider-tick-size: 2px !default;
2626

27+
$mat-slider-focus-ring-size: 30px !default;
28+
2729

2830
.mat-slider {
2931
display: inline-block;
@@ -72,17 +74,29 @@ $mat-slider-tick-size: 2px !default;
7274
transition: opacity $swift-ease-out-duration $swift-ease-out-timing-function;
7375
}
7476

75-
// TODO(mmalerba): Simplify css to avoid unnecessary selectors.
76-
.mat-slider-disabled .mat-slider-ticks {
77-
opacity: 0;
78-
}
79-
8077
.mat-slider-thumb-container {
8178
position: absolute;
8279
z-index: 1;
8380
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function;
8481
}
8582

83+
.mat-slider-focus-ring {
84+
position: absolute;
85+
width: $mat-slider-focus-ring-size;
86+
height: $mat-slider-focus-ring-size;
87+
border-radius: 50%;
88+
transform: scale(0);
89+
opacity: 0;
90+
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function,
91+
background-color $swift-ease-out-duration $swift-ease-out-timing-function,
92+
opacity $swift-ease-out-duration $swift-ease-out-timing-function;
93+
94+
.cdk-keyboard-focused & {
95+
transform: scale(1);
96+
opacity: 1;
97+
}
98+
}
99+
86100
.mat-slider-thumb {
87101
position: absolute;
88102
right: -$mat-slider-thumb-size / 2;
@@ -143,15 +157,15 @@ $mat-slider-tick-size: 2px !default;
143157
transition: opacity $swift-ease-out-duration $swift-ease-out-timing-function;
144158
}
145159

146-
&.mat-slider-active,
160+
&.cdk-focused,
147161
&:hover {
148162
&:not(.mat-slider-hide-last-tick) {
149163
.mat-slider-wrapper::after {
150164
opacity: 1;
151165
}
152166
}
153167

154-
.mat-slider-ticks {
168+
&:not(.mat-slider-disabled) .mat-slider-ticks {
155169
opacity: 1;
156170
}
157171
}
@@ -160,6 +174,11 @@ $mat-slider-tick-size: 2px !default;
160174

161175
// Slider with thumb label.
162176
.mat-slider-thumb-label-showing {
177+
.mat-slider-focus-ring {
178+
transform: scale(0);
179+
opacity: 0;
180+
}
181+
163182
.mat-slider-thumb-label {
164183
display: flex;
165184
}
@@ -179,12 +198,7 @@ $mat-slider-tick-size: 2px !default;
179198

180199

181200
// Active slider.
182-
.mat-slider-active {
183-
.mat-slider-thumb {
184-
border-width: $mat-slider-thumb-border-width-active;
185-
transform: scale($mat-slider-thumb-focus-scale);
186-
}
187-
201+
.cdk-focused {
188202
&.mat-slider-thumb-label-showing .mat-slider-thumb {
189203
transform: scale(0);
190204
}
@@ -198,9 +212,23 @@ $mat-slider-tick-size: 2px !default;
198212
}
199213
}
200214

215+
.cdk-mouse-focused,
216+
.cdk-touch-focused,
217+
.cdk-program-focused {
218+
.mat-slider-thumb {
219+
border-width: $mat-slider-thumb-border-width-active;
220+
transform: scale($mat-slider-thumb-focus-scale);
221+
}
222+
}
223+
201224

202225
// Disabled slider.
203226
.mat-slider-disabled {
227+
.mat-slider-focus-ring {
228+
transform: scale(0);
229+
opacity: 0;
230+
}
231+
204232
.mat-slider-thumb {
205233
border-width: $mat-slider-thumb-border-width-disabled;
206234
transform: scale($mat-slider-thumb-disabled-scale);
@@ -271,6 +299,11 @@ $mat-slider-tick-size: 2px !default;
271299
top: 50%;
272300
}
273301

302+
.mat-slider-focus-ring {
303+
top: -$mat-slider-focus-ring-size / 2;
304+
right: -$mat-slider-focus-ring-size / 2;
305+
}
306+
274307
.mat-slider-thumb-label {
275308
right: -$mat-slider-thumb-label-size / 2;
276309
top: -($mat-slider-thumb-label-size + $mat-slider-thumb-arrow-gap);
@@ -282,7 +315,7 @@ $mat-slider-tick-size: 2px !default;
282315
transform: rotate(-45deg);
283316
}
284317

285-
&.mat-slider-active {
318+
&.cdk-focused {
286319
.mat-slider-thumb-label {
287320
transform: rotate(45deg);
288321
}
@@ -331,6 +364,11 @@ $mat-slider-tick-size: 2px !default;
331364
height: 100%;
332365
}
333366

367+
.mat-slider-focus-ring {
368+
bottom: -$mat-slider-focus-ring-size / 2;
369+
left: -$mat-slider-focus-ring-size / 2;
370+
}
371+
334372
.mat-slider-ticks {
335373
background: repeating-linear-gradient(to bottom, $mat-slider-tick-color,
336374
$mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent) repeat;
@@ -356,7 +394,7 @@ $mat-slider-tick-size: 2px !default;
356394
transform: rotate(45deg);
357395
}
358396

359-
&.mat-slider-active {
397+
&.cdk-focused {
360398
.mat-slider-thumb-label {
361399
transform: rotate(-45deg);
362400
}

src/lib/slider/slider.spec.ts

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2-
import {ReactiveFormsModule, FormControl, FormsModule} from '@angular/forms';
2+
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
33
import {Component, DebugElement} from '@angular/core';
44
import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
55
import {MdSlider, MdSliderModule} from './index';
66
import {TestGestureConfig} from './test-gesture-config';
77
import {RtlModule} from '../core/rtl/dir';
88
import {
9-
UP_ARROW,
10-
RIGHT_ARROW,
119
DOWN_ARROW,
12-
PAGE_DOWN,
13-
PAGE_UP,
1410
END,
1511
HOME,
16-
LEFT_ARROW
12+
LEFT_ARROW,
13+
PAGE_DOWN,
14+
PAGE_UP,
15+
RIGHT_ARROW,
16+
UP_ARROW
1717
} from '../core/keyboard/keycodes';
1818
import {dispatchKeyboardEvent, dispatchMouseEvent} from '../core/testing/dispatch-events';
1919

@@ -23,7 +23,7 @@ describe('MdSlider', () => {
2323

2424
beforeEach(async(() => {
2525
TestBed.configureTestingModule({
26-
imports: [MdSliderModule.forRoot(), RtlModule.forRoot(), ReactiveFormsModule, FormsModule],
26+
imports: [MdSliderModule, ReactiveFormsModule, FormsModule, RtlModule],
2727
declarations: [
2828
StandardSlider,
2929
DisabledSlider,
@@ -129,28 +129,6 @@ describe('MdSlider', () => {
129129
expect(trackFillElement.style.transform).toContain('scaleX(0.86)');
130130
});
131131

132-
it('should add the mat-slider-active class on click', () => {
133-
expect(sliderNativeElement.classList).not.toContain('mat-slider-active');
134-
135-
dispatchClickEventSequence(sliderNativeElement, 0.23);
136-
fixture.detectChanges();
137-
138-
expect(sliderNativeElement.classList).toContain('mat-slider-active');
139-
});
140-
141-
it('should remove the mat-slider-active class on blur', () => {
142-
dispatchClickEventSequence(sliderNativeElement, 0.95);
143-
fixture.detectChanges();
144-
145-
expect(sliderNativeElement.classList).toContain('mat-slider-active');
146-
147-
// Call the `onBlur` handler directly because we cannot simulate a focus event in unit tests.
148-
sliderInstance._onBlur();
149-
fixture.detectChanges();
150-
151-
expect(sliderNativeElement.classList).not.toContain('mat-slider-active');
152-
});
153-
154132
it('should add and remove the mat-slider-sliding class when sliding', () => {
155133
expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding');
156134

@@ -167,11 +145,6 @@ describe('MdSlider', () => {
167145

168146
it('should have thumb gap when at min value', () => {
169147
expect(trackFillElement.style.transform).toContain('translateX(-7px)');
170-
171-
dispatchClickEventSequence(sliderNativeElement, 0);
172-
fixture.detectChanges();
173-
174-
expect(trackFillElement.style.transform).toContain('translateX(-10px)');
175148
});
176149

177150
it('should not have thumb gap when not at min value', () => {
@@ -561,29 +534,6 @@ describe('MdSlider', () => {
561534
// The thumb label text is set to the slider's value. These should always be the same.
562535
expect(thumbLabelTextElement.textContent).toBe(`${sliderInstance.value}`);
563536
});
564-
565-
it('should show the thumb label on click', () => {
566-
expect(sliderNativeElement.classList).not.toContain('mat-slider-active');
567-
expect(sliderNativeElement.classList).toContain('mat-slider-thumb-label-showing');
568-
569-
dispatchClickEventSequence(sliderNativeElement, 0.49);
570-
fixture.detectChanges();
571-
572-
// The thumb label appears when the slider is active and the 'mat-slider-thumb-label-showing'
573-
// class is applied.
574-
expect(sliderNativeElement.classList).toContain('mat-slider-thumb-label-showing');
575-
expect(sliderNativeElement.classList).toContain('mat-slider-active');
576-
});
577-
578-
it('should show the thumb label on slide', () => {
579-
expect(sliderNativeElement.classList).not.toContain('mat-slider-active');
580-
581-
dispatchSlideEventSequence(sliderNativeElement, 0, 0.91, gestureConfig);
582-
fixture.detectChanges();
583-
584-
expect(sliderNativeElement.classList).toContain('mat-slider-thumb-label-showing');
585-
expect(sliderNativeElement.classList).toContain('mat-slider-active');
586-
});
587537
});
588538

589539
describe('slider as a custom form control', () => {

0 commit comments

Comments
 (0)