Skip to content

Commit 3edf105

Browse files
devversionmmalerba
authored andcommitted
fix(checkbox): create ripple on label mousedown (#3206)
* Now triggers the ripple on label mousedown (similar as to slide-toggle and radio) * Only sets cursor for underlying `label` element (similar as for native checkbox inputs) * Adds a test that confirms that ripples work for checkbox Fixes #3030
1 parent bbda25f commit 3edf105

File tree

4 files changed

+54
-33
lines changed

4 files changed

+54
-33
lines changed

src/lib/checkbox/checkbox.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<label class="mat-checkbox-layout">
1+
<label class="mat-checkbox-layout" #label>
22
<div class="mat-checkbox-inner-container">
33
<input #input
44
class="mat-checkbox-input cdk-visually-hidden" type="checkbox"
@@ -16,7 +16,7 @@
1616
(change)="_onInteractionEvent($event)"
1717
(click)="_onInputClick($event)">
1818
<div md-ripple *ngIf="!_isRippleDisabled()" class="mat-checkbox-ripple"
19-
[mdRippleTrigger]="_getHostElement()"
19+
[mdRippleTrigger]="label"
2020
[mdRippleCentered]="true"></div>
2121
<div class="mat-checkbox-frame"></div>
2222
<div class="mat-checkbox-background">

src/lib/checkbox/checkbox.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,17 @@ $_mat-checkbox-mark-stroke-size: 2 / 15 * $mat-checkbox-size !default;
187187
}
188188

189189
.mat-checkbox {
190-
cursor: pointer;
191190
font-family: $mat-font-family;
192191

193192
// Animation
194193
transition: background $swift-ease-out-duration $swift-ease-out-timing-function,
195194
mat-elevation-transition-property-value();
196195
}
197196

197+
.mat-checkbox-label {
198+
cursor: pointer;
199+
}
200+
198201
.mat-checkbox-layout {
199202
// `cursor: inherit` ensures that the wrapper element gets the same cursor as the mat-checkbox
200203
// (e.g. pointer by default, regular when disabled), instead of the browser default.

src/lib/checkbox/checkbox.spec.ts

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -190,17 +190,6 @@ describe('MdCheckbox', () => {
190190
expect(inputElement.disabled).toBe(false);
191191
});
192192

193-
it('should not have a ripple when disabled', () => {
194-
let rippleElement = checkboxNativeElement.querySelector('[md-ripple]');
195-
expect(rippleElement).toBeTruthy('Expected an enabled checkbox to have a ripple');
196-
197-
testComponent.isDisabled = true;
198-
fixture.detectChanges();
199-
200-
rippleElement = checkboxNativeElement.querySelector('[md-ripple]');
201-
expect(rippleElement).toBeFalsy('Expected a disabled checkbox not to have a ripple');
202-
});
203-
204193
it('should not toggle `checked` state upon interation while disabled', () => {
205194
testComponent.isDisabled = true;
206195
fixture.detectChanges();
@@ -324,6 +313,44 @@ describe('MdCheckbox', () => {
324313
expect(document.activeElement).toBe(inputElement);
325314
});
326315

316+
describe('ripple elements', () => {
317+
318+
it('should show ripples on label mousedown', () => {
319+
expect(checkboxNativeElement.querySelector('.mat-ripple-element')).toBeFalsy();
320+
321+
dispatchFakeEvent(labelElement, 'mousedown');
322+
dispatchFakeEvent(labelElement, 'mouseup');
323+
324+
expect(checkboxNativeElement.querySelectorAll('.mat-ripple-element').length).toBe(1);
325+
});
326+
327+
it('should not have a ripple when disabled', () => {
328+
let rippleElement = checkboxNativeElement.querySelector('[md-ripple]');
329+
expect(rippleElement).toBeTruthy('Expected an enabled checkbox to have a ripple');
330+
331+
testComponent.isDisabled = true;
332+
fixture.detectChanges();
333+
334+
rippleElement = checkboxNativeElement.querySelector('[md-ripple]');
335+
expect(rippleElement).toBeFalsy('Expected a disabled checkbox not to have a ripple');
336+
});
337+
338+
it('should remove ripple if mdRippleDisabled input is set', async(() => {
339+
testComponent.disableRipple = true;
340+
fixture.detectChanges();
341+
342+
expect(checkboxNativeElement.querySelectorAll('[md-ripple]').length)
343+
.toBe(0, 'Expect no [md-ripple] in checkbox');
344+
345+
testComponent.disableRipple = false;
346+
fixture.detectChanges();
347+
348+
expect(checkboxNativeElement.querySelectorAll('[md-ripple]').length)
349+
.toBe(1, 'Expect [md-ripple] in checkbox');
350+
}));
351+
352+
});
353+
327354
describe('color behaviour', () => {
328355
it('should apply class based on color attribute', () => {
329356
testComponent.checkboxColor = 'primary';
@@ -544,19 +571,6 @@ describe('MdCheckbox', () => {
544571
expect(inputElement.tabIndex).toBe(13);
545572
});
546573

547-
it('should remove ripple if mdRippleDisabled input is set', async(() => {
548-
testComponent.disableRipple = true;
549-
fixture.detectChanges();
550-
551-
expect(checkboxNativeElement.querySelectorAll('[md-ripple]').length)
552-
.toBe(0, 'Expect no [md-ripple] in checkbox');
553-
554-
testComponent.disableRipple = false;
555-
fixture.detectChanges();
556-
557-
expect(checkboxNativeElement.querySelectorAll('[md-ripple]').length)
558-
.toBe(1, 'Expect [md-ripple] in checkbox');
559-
}));
560574
});
561575

562576
describe('with multiple checkboxes', () => {
@@ -678,6 +692,7 @@ describe('MdCheckbox', () => {
678692
[(indeterminate)]="isIndeterminate"
679693
[disabled]="isDisabled"
680694
[color]="checkboxColor"
695+
[disableRipple]="disableRipple"
681696
(change)="changeCount = changeCount + 1"
682697
(click)="onCheckboxClick($event)"
683698
(change)="onCheckboxChange($event)">
@@ -691,6 +706,7 @@ class SingleCheckbox {
691706
isRequired: boolean = false;
692707
isIndeterminate: boolean = false;
693708
isDisabled: boolean = false;
709+
disableRipple: boolean = false;
694710
parentElementClicked: boolean = false;
695711
parentElementKeyedUp: boolean = false;
696712
lastKeydownEvent: Event = null;
@@ -728,14 +744,12 @@ class MultipleCheckboxes { }
728744
template: `
729745
<md-checkbox
730746
[tabIndex]="customTabIndex"
731-
[disabled]="isDisabled"
732-
[disableRipple]="disableRipple">
747+
[disabled]="isDisabled">
733748
</md-checkbox>`,
734749
})
735750
class CheckboxWithTabIndex {
736751
customTabIndex: number = 7;
737752
isDisabled: boolean = false;
738-
disableRipple: boolean = false;
739753
}
740754

741755
/** Simple test component with an aria-label set. */
@@ -771,3 +785,10 @@ class CheckboxWithChangeEvent {
771785
class CheckboxWithFormControl {
772786
formControl = new FormControl();
773787
}
788+
789+
// TODO(devversion): replace with global utility once pull request #2943 is merged.
790+
function dispatchFakeEvent(element: HTMLElement, eventName: string): void {
791+
let event = document.createEvent('Event');
792+
event.initEvent(eventName, true, true);
793+
element.dispatchEvent(event);
794+
}

src/lib/checkbox/checkbox.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,9 +397,6 @@ export class MdCheckbox implements ControlValueAccessor {
397397
return `mat-checkbox-anim-${animSuffix}`;
398398
}
399399

400-
_getHostElement() {
401-
return this._elementRef.nativeElement;
402-
}
403400
}
404401

405402

0 commit comments

Comments
 (0)