Skip to content

Commit ce23395

Browse files
devversionjelbourn
authored andcommitted
feat(menu): allow disabling ripples on items (#8388)
Closes #8261
1 parent 131272a commit ce23395

File tree

4 files changed

+42
-15
lines changed

4 files changed

+42
-15
lines changed

src/lib/menu/menu-item.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
<ng-content></ng-content>
2-
<div class="mat-menu-ripple" *ngIf="!disabled" mat-ripple [matRippleTrigger]="_getHostElement()">
2+
<div class="mat-menu-ripple" matRipple
3+
[matRippleDisabled]="disableRipple || disabled"
4+
[matRippleTrigger]="_getHostElement()">
35
</div>

src/lib/menu/menu-item.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ import {
1414
OnDestroy,
1515
ViewEncapsulation,
1616
} from '@angular/core';
17-
import {CanDisable, mixinDisabled} from '@angular/material/core';
17+
import {
18+
CanDisable,
19+
CanDisableRipple,
20+
mixinDisabled,
21+
mixinDisableRipple
22+
} from '@angular/material/core';
1823
import {Subject} from 'rxjs/Subject';
1924

2025
// Boilerplate for applying mixins to MatMenuItem.
2126
/** @docs-private */
2227
export class MatMenuItemBase {}
23-
export const _MatMenuItemMixinBase = mixinDisabled(MatMenuItemBase);
28+
export const _MatMenuItemMixinBase = mixinDisableRipple(mixinDisabled(MatMenuItemBase));
2429

2530
/**
2631
* This directive is intended to be used inside an mat-menu tag.
@@ -30,7 +35,7 @@ export const _MatMenuItemMixinBase = mixinDisabled(MatMenuItemBase);
3035
moduleId: module.id,
3136
selector: '[mat-menu-item]',
3237
exportAs: 'matMenuItem',
33-
inputs: ['disabled'],
38+
inputs: ['disabled', 'disableRipple'],
3439
host: {
3540
'role': 'menuitem',
3641
'class': 'mat-menu-item',
@@ -47,8 +52,8 @@ export const _MatMenuItemMixinBase = mixinDisabled(MatMenuItemBase);
4752
preserveWhitespaces: false,
4853
templateUrl: 'menu-item.html',
4954
})
50-
export class MatMenuItem extends _MatMenuItemMixinBase implements FocusableOption, CanDisable,
51-
OnDestroy {
55+
export class MatMenuItem extends _MatMenuItemMixinBase
56+
implements FocusableOption, CanDisable, CanDisableRipple, OnDestroy {
5257

5358
/** Stream that emits when the menu item is hovered. */
5459
_hovered: Subject<MatMenuItem> = new Subject();

src/lib/menu/menu.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,10 @@ button.mat-menu-item {
8282

8383
.mat-menu-ripple {
8484
@include mat-fill;
85+
86+
// Prevent any pointer events on the ripple container for a menu item. The ripple container is
87+
// not the trigger element for the ripples and can be therefore disabled like that. Disabling
88+
// the pointer events ensures that there is no `click` event that can bubble up and cause
89+
// the menu panel to close.
90+
pointer-events: none;
8591
}

src/lib/menu/menu.spec.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
MatMenuItem,
2727
} from './index';
2828
import {MENU_PANEL_TOP_PADDING} from './menu-trigger';
29-
import {extendObject} from '@angular/material/core';
29+
import {extendObject, MatRipple} from '@angular/material/core';
3030
import {
3131
dispatchKeyboardEvent,
3232
dispatchMouseEvent,
@@ -490,29 +490,43 @@ describe('MatMenu', () => {
490490
});
491491

492492
describe('animations', () => {
493-
it('should include the ripple on items by default', () => {
493+
it('should enable ripples on items by default', () => {
494494
const fixture = TestBed.createComponent(SimpleMenu);
495495
fixture.detectChanges();
496496

497497
fixture.componentInstance.trigger.openMenu();
498+
498499
const item = fixture.debugElement.query(By.css('.mat-menu-item'));
499-
const ripple = item.query(By.css('.mat-ripple'));
500+
const ripple = item.query(By.css('.mat-ripple')).injector.get<MatRipple>(MatRipple);
500501

501-
expect(ripple).not.toBeNull();
502+
expect(ripple.disabled).toBe(false);
502503
});
503504

504-
it('should remove the ripple on disabled items', () => {
505+
it('should disable ripples on disabled items', () => {
505506
const fixture = TestBed.createComponent(SimpleMenu);
506507
fixture.detectChanges();
507508

508509
fixture.componentInstance.trigger.openMenu();
510+
511+
// The second menu item in the `SimpleMenu` component is disabled.
509512
const items = fixture.debugElement.queryAll(By.css('.mat-menu-item'));
513+
const ripple = items[1].query(By.css('.mat-ripple')).injector.get<MatRipple>(MatRipple);
510514

511-
// items[1] is disabled, so the ripple should not be present
512-
const ripple = items[1].query(By.css('.mat-ripple'));
513-
expect(ripple).toBeNull();
515+
expect(ripple.disabled).toBe(true);
514516
});
515517

518+
it('should disable ripples if disableRipple is set', () => {
519+
const fixture = TestBed.createComponent(SimpleMenu);
520+
fixture.detectChanges();
521+
522+
fixture.componentInstance.trigger.openMenu();
523+
524+
// The third menu item in the `SimpleMenu` component has ripples disabled.
525+
const items = fixture.debugElement.queryAll(By.css('.mat-menu-item'));
526+
const ripple = items[2].query(By.css('.mat-ripple')).injector.get<MatRipple>(MatRipple);
527+
528+
expect(ripple.disabled).toBe(true);
529+
});
516530
});
517531

518532
describe('close event', () => {
@@ -1115,7 +1129,7 @@ describe('MatMenu default overrides', () => {
11151129
<mat-menu class="custom-one custom-two" #menu="matMenu" (closed)="closeCallback($event)">
11161130
<button mat-menu-item> Item </button>
11171131
<button mat-menu-item disabled> Disabled </button>
1118-
<button mat-menu-item>
1132+
<button mat-menu-item disableRipple>
11191133
<fake-icon>unicorn</fake-icon>
11201134
Item with an icon
11211135
</button>

0 commit comments

Comments
 (0)