Skip to content

Commit 51cfade

Browse files
committed
feat(slide-toggle): align with 2018 material design spec
Aligns the slide toggle component with the latest Material design spec. The component was mostly on spec already, but these changes adjust the size of the ripple and add the new behavior/opacity when hovering and on focus.
1 parent e462f3d commit 51cfade

File tree

5 files changed

+48
-61
lines changed

5 files changed

+48
-61
lines changed

src/lib/slide-toggle/_slide-toggle-theme.scss

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,10 @@
4545

4646
// Ripple colors are based on the current palette and the state of the slide-toggle.
4747
// See https://material.google.com/components/selection-controls.html#selection-controls-switch
48-
$ripple-checked-opacity: 0.12;
49-
$ripple-unchecked-color: mat-color($foreground, base, if($is-dark, 0.12, 0.06));
50-
$ripple-primary-color: mat-color($primary, $thumb-checked-hue, $ripple-checked-opacity);
51-
$ripple-accent-color: mat-color($accent, $thumb-checked-hue, $ripple-checked-opacity);
52-
$ripple-warn-color: mat-color($warn, $thumb-checked-hue, $ripple-checked-opacity);
48+
$ripple-unchecked-color: mat-color($foreground, base);
49+
$ripple-primary-color: mat-color($primary, $thumb-checked-hue);
50+
$ripple-accent-color: mat-color($accent, $thumb-checked-hue);
51+
$ripple-warn-color: mat-color($warn, $thumb-checked-hue);
5352

5453
.mat-slide-toggle {
5554
@include _mat-slide-toggle-checked($accent, $thumb-checked-hue);

src/lib/slide-toggle/slide-toggle.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
[matRippleTrigger]="label"
2828
[matRippleDisabled]="disableRipple || disabled"
2929
[matRippleCentered]="true"
30-
[matRippleRadius]="23"
30+
[matRippleRadius]="20"
3131
[matRippleAnimation]="{enterDuration: 150}">
32+
33+
<div class="mat-ripple-element mat-slide-toggle-persistent-ripple"></div>
3234
</div>
3335

3436
</div>

src/lib/slide-toggle/slide-toggle.scss

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ $mat-slide-toggle-thumb-size: 20px !default;
99
$mat-slide-toggle-bar-border-radius: 8px !default;
1010
$mat-slide-toggle-height: 24px !default;
1111
$mat-slide-toggle-spacing: 8px !default;
12-
$mat-slide-toggle-ripple-radius: 23px !default;
12+
$mat-slide-toggle-ripple-radius: 20px !default;
1313
$mat-slide-toggle-bar-width: 36px !default;
1414
$mat-slide-toggle-bar-height: 14px !default;
1515
$mat-slide-toggle-bar-track-width: $mat-slide-toggle-bar-width - $mat-slide-toggle-thumb-size;
@@ -189,6 +189,31 @@ $mat-slide-toggle-bar-track-width: $mat-slide-toggle-bar-width - $mat-slide-togg
189189
width: $mat-slide-toggle-ripple-radius * 2;
190190
z-index: 1;
191191
pointer-events: none;
192+
193+
.mat-ripple-element:not(.mat-slide-toggle-persistent-ripple) {
194+
opacity: 0.16;
195+
}
196+
}
197+
198+
.mat-slide-toggle-persistent-ripple {
199+
width: 100%;
200+
height: 100%;
201+
transform: none;
202+
203+
.mat-slide-toggle-bar:hover & {
204+
opacity: 0.04;
205+
}
206+
207+
.mat-slide-toggle.cdk-focused & {
208+
opacity: 0.12;
209+
}
210+
211+
// We do this here, rather than having a `:not(.mat-slide-toggle-disabled)`
212+
// above in the `:hover`, because the `:not` will bump the specificity
213+
// a lot and will cause it to overide the focus styles.
214+
&, .mat-slide-toggle.mat-disabled .mat-slide-toggle-bar:hover & {
215+
opacity: 0;
216+
}
192217
}
193218

194219
/** Custom styling to make the slide-toggle usable in high contrast mode. */

src/lib/slide-toggle/slide-toggle.spec.ts

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {dispatchFakeEvent} from '@angular/cdk/testing';
33
import {Component} from '@angular/core';
44
import {ComponentFixture, fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing';
55
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
6-
import {defaultRippleAnimationConfig} from '@angular/material/core';
76
import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
87
import {BidiModule, Direction} from '@angular/cdk/bidi';
98
import {TestGestureConfig} from '../slider/test-gesture-config';
@@ -264,26 +263,6 @@ describe('MatSlideToggle without forms', () => {
264263
subscription.unsubscribe();
265264
}));
266265

267-
it('should show a ripple when focused by a keyboard action', fakeAsync(() => {
268-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length)
269-
.toBe(0, 'Expected no ripples to be present.');
270-
271-
dispatchFakeEvent(inputElement, 'keydown');
272-
dispatchFakeEvent(inputElement, 'focus');
273-
274-
tick(defaultRippleAnimationConfig.enterDuration);
275-
276-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length)
277-
.toBe(1, 'Expected the focus ripple to be showing up.');
278-
279-
dispatchFakeEvent(inputElement, 'blur');
280-
281-
tick(defaultRippleAnimationConfig.exitDuration);
282-
283-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length)
284-
.toBe(0, 'Expected focus ripple to be removed.');
285-
}));
286-
287266
it('should forward the required attribute', () => {
288267
testComponent.isRequired = true;
289268
fixture.detectChanges();
@@ -315,24 +294,27 @@ describe('MatSlideToggle without forms', () => {
315294
});
316295

317296
it('should show ripples on label mousedown', () => {
318-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length).toBe(0);
297+
const rippleSelector = '.mat-ripple-element:not(.mat-slide-toggle-persistent-ripple)';
298+
299+
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(0);
319300

320301
dispatchFakeEvent(labelElement, 'mousedown');
321302
dispatchFakeEvent(labelElement, 'mouseup');
322303

323-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length).toBe(1);
304+
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(1);
324305
});
325306

326307
it('should not show ripples when disableRipple is set', () => {
308+
const rippleSelector = '.mat-ripple-element:not(.mat-slide-toggle-persistent-ripple)';
327309
testComponent.disableRipple = true;
328310
fixture.detectChanges();
329311

330-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length).toBe(0);
312+
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(0);
331313

332314
dispatchFakeEvent(labelElement, 'mousedown');
333315
dispatchFakeEvent(labelElement, 'mouseup');
334316

335-
expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length).toBe(0);
317+
expect(slideToggleElement.querySelectorAll(rippleSelector).length).toBe(0);
336318
});
337319
});
338320

src/lib/slide-toggle/slide-toggle.ts

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {FocusMonitor, FocusOrigin} from '@angular/cdk/a11y';
9+
import {FocusMonitor} from '@angular/cdk/a11y';
1010
import {Directionality} from '@angular/cdk/bidi';
1111
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1212
import {Platform} from '@angular/cdk/platform';
@@ -35,12 +35,10 @@ import {
3535
CanDisableRipple,
3636
HammerInput,
3737
HasTabIndex,
38-
MatRipple,
3938
mixinColor,
4039
mixinDisabled,
4140
mixinDisableRipple,
4241
mixinTabIndex,
43-
RippleRef,
4442
} from '@angular/material/core';
4543
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
4644
import {
@@ -104,9 +102,6 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
104102
private _required: boolean = false;
105103
private _checked: boolean = false;
106104

107-
/** Reference to the focus state ripple. */
108-
private _focusRipple: RippleRef | null;
109-
110105
/** Whether the thumb is currently being dragged. */
111106
private _dragging = false;
112107

@@ -179,9 +174,6 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
179174
/** Reference to the underlying input element. */
180175
@ViewChild('input') _inputElement: ElementRef;
181176

182-
/** Reference to the ripple directive on the thumb container. */
183-
@ViewChild(MatRipple) _ripple: MatRipple;
184-
185177
constructor(elementRef: ElementRef,
186178
/**
187179
* @deprecated The `_platform` parameter to be removed.
@@ -202,12 +194,16 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
202194

203195
ngAfterContentInit() {
204196
this._focusMonitor
205-
.monitor(this._inputElement.nativeElement)
206-
.subscribe(focusOrigin => this._onInputFocusChange(focusOrigin));
197+
.monitor(this._elementRef.nativeElement, true)
198+
.subscribe(focusOrigin => {
199+
if (!focusOrigin) {
200+
this.onTouched();
201+
}
202+
});
207203
}
208204

209205
ngOnDestroy() {
210-
this._focusMonitor.stopMonitoring(this._inputElement.nativeElement);
206+
this._focusMonitor.stopMonitoring(this._elementRef.nativeElement);
211207
}
212208

213209
/** Method being called whenever the underlying input emits a change event. */
@@ -282,23 +278,6 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
282278
this.onChange(this.checked);
283279
}
284280

285-
/** Function is called whenever the focus changes for the input element. */
286-
private _onInputFocusChange(focusOrigin: FocusOrigin) {
287-
// TODO(paul): support `program`. See https://github.com/angular/material2/issues/9889
288-
if (!this._focusRipple && focusOrigin === 'keyboard') {
289-
// For keyboard focus show a persistent ripple as focus indicator.
290-
this._focusRipple = this._ripple.launch(0, 0, {persistent: true});
291-
} else if (!focusOrigin) {
292-
this.onTouched();
293-
294-
// Fade out and clear the focus ripple if one is currently present.
295-
if (this._focusRipple) {
296-
this._focusRipple.fadeOut();
297-
this._focusRipple = null;
298-
}
299-
}
300-
}
301-
302281
/**
303282
* Emits a change event on the `change` output. Also notifies the FormControl about the change.
304283
*/

0 commit comments

Comments
 (0)