Skip to content

Commit 50785b3

Browse files
committed
feat(ripples): support updating global ripple options at runtime
* Allows updating any global ripple option at runtime. This makes it possible for developers to disable ripples at runtime. Closes angular#9729
1 parent d22f48c commit 50785b3

File tree

11 files changed

+302
-202
lines changed

11 files changed

+302
-202
lines changed

src/dev-app/dev-app-module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {CommonModule} from '@angular/common';
1212
import {HttpClientModule} from '@angular/common/http';
1313
import {NgModule} from '@angular/core';
1414
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
15+
import {MAT_RIPPLE_GLOBAL_OPTIONS} from '@angular/material';
1516
import {ExampleModule} from '@angular/material-examples';
1617
import {BrowserModule} from '@angular/platform-browser';
1718
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@@ -50,6 +51,7 @@ import {ProgressBarDemo} from './progress-bar/progress-bar-demo';
5051
import {ProgressSpinnerDemo} from './progress-spinner/progress-spinner-demo';
5152
import {RadioDemo} from './radio/radio-demo';
5253
import {RippleDemo} from './ripple/ripple-demo';
54+
import {DevAppRippleOptions} from './ripple/ripple-options';
5355
import {DEV_APP_ROUTES} from './routes';
5456
import {ScreenTypeDemo} from './screen-type/screen-type-demo';
5557
import {SelectDemo} from './select/select-demo';
@@ -140,6 +142,7 @@ import {VirtualScrollDemo} from './virtual-scroll/virtual-scroll-demo';
140142
],
141143
providers: [
142144
{provide: OverlayContainer, useClass: FullscreenOverlayContainer},
145+
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useExisting: DevAppRippleOptions},
143146
],
144147
entryComponents: [
145148
ContentElementDialog,

src/dev-app/dev-app.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ <h1>Angular Material Demos</h1>
3434
<mat-icon>fullscreen</mat-icon>
3535
</button>
3636
<button mat-button (click)="toggleTheme()">{{dark ? 'Light' : 'Dark'}} theme</button>
37+
<button mat-button (click)="rippleOptions.disabled = !rippleOptions.disabled">
38+
{{rippleOptions.disabled ? 'Enable' : 'Disable'}} ripples
39+
</button>
3740
<button mat-button (click)="root.dir = (root.dir === 'rtl' ? 'ltr' : 'rtl')"
3841
title="Toggle between RTL and LTR">
3942
{{root.dir.toUpperCase()}}

src/dev-app/dev-app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import {OverlayContainer} from '@angular/cdk/overlay';
1010
import {Component, ElementRef, ViewEncapsulation} from '@angular/core';
11+
import {DevAppRippleOptions} from './ripple/ripple-options';
1112

1213
/** Root component for the dev-app demos. */
1314
@Component({
@@ -69,7 +70,8 @@ export class DevAppComponent {
6970

7071
constructor(
7172
private _element: ElementRef<HTMLElement>,
72-
private _overlayContainer: OverlayContainer) {}
73+
private _overlayContainer: OverlayContainer,
74+
public rippleOptions: DevAppRippleOptions) {}
7375

7476
toggleFullscreen() {
7577
// Cast to `any`, because the typings don't include the browser-prefixed methods.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Injectable} from '@angular/core';
10+
import {RippleGlobalOptions} from '@angular/material';
11+
12+
/**
13+
* Global ripple options for the dev-app. The ripple options are used as a class
14+
* so that the global options can be changed at runtime.
15+
*/
16+
@Injectable({providedIn: 'root'})
17+
export class DevAppRippleOptions implements RippleGlobalOptions {
18+
19+
/** Whether ripples should be disabled */
20+
disabled: boolean = false;
21+
}

src/lib/chips/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ng_test_library(
5151
"@angular//packages/platform-browser/animations",
5252
"//src/cdk/a11y",
5353
"//src/cdk/bidi",
54+
"//src/lib/core",
5455
"//src/cdk/keycodes",
5556
"//src/cdk/platform",
5657
"//src/cdk/testing",

src/lib/chips/chip.spec.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {BACKSPACE, DELETE, SPACE} from '@angular/cdk/keycodes';
33
import {createKeyboardEvent, dispatchFakeEvent} from '@angular/cdk/testing';
44
import {Component, DebugElement} from '@angular/core';
55
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
6+
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
67
import {By} from '@angular/platform-browser';
78
import {Subject} from 'rxjs';
89
import {MatChip, MatChipEvent, MatChipSelectionChange, MatChipsModule} from './index';
@@ -13,19 +14,22 @@ describe('Chips', () => {
1314
let chipDebugElement: DebugElement;
1415
let chipNativeElement: HTMLElement;
1516
let chipInstance: MatChip;
17+
let globalRippleOptions: RippleGlobalOptions;
1618

1719
let dir = 'ltr';
1820

1921
beforeEach(async(() => {
22+
globalRippleOptions = {};
2023
TestBed.configureTestingModule({
2124
imports: [MatChipsModule],
2225
declarations: [BasicChip, SingleChip],
23-
providers: [{
24-
provide: Directionality, useFactory: () => ({
26+
providers: [
27+
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
28+
{provide: Directionality, useFactory: () => ({
2529
value: dir,
2630
change: new Subject()
27-
})
28-
}]
31+
})},
32+
]
2933
});
3034

3135
TestBed.compileComponents();
@@ -203,6 +207,13 @@ describe('Chips', () => {
203207
subscription.unsubscribe();
204208
});
205209

210+
it('should be able to disable ripples through ripple global options at runtime', () => {
211+
expect(chipInstance.rippleDisabled).toBe(false, 'Expected chip ripples to be enabled.');
212+
213+
globalRippleOptions.disabled = true;
214+
215+
expect(chipInstance.rippleDisabled).toBe(true, 'Expected chip ripples to be disabled.');
216+
});
206217
});
207218

208219
describe('keyboard behavior', () => {

src/lib/chips/chip.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -123,21 +123,20 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes
123123
/** Reference to the RippleRenderer for the chip. */
124124
private _chipRipple: RippleRenderer;
125125

126-
/** Whether the ripples are globally disabled through the RippleGlobalOptions */
127-
private _ripplesGloballyDisabled = false;
128-
129126
/**
130-
* Ripple configuration for ripples that are launched on pointer down.
127+
* Ripple configuration for ripples that are launched on pointer down. The ripple config
128+
* is set to the global ripple options since we don't have any configurable options for
129+
* the chip ripples.
131130
* @docs-private
132131
*/
133-
rippleConfig: RippleConfig = {};
132+
rippleConfig: RippleConfig & RippleGlobalOptions;
134133

135134
/**
136135
* Whether ripples are disabled on interaction
137136
* @docs-private
138137
*/
139138
get rippleDisabled(): boolean {
140-
return this.disabled || this.disableRipple || this._ripplesGloballyDisabled;
139+
return this.disabled || this.disableRipple || !!this.rippleConfig.disabled;
141140
}
142141

143142
/** Whether the chip has focus. */
@@ -225,22 +224,15 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes
225224
constructor(public _elementRef: ElementRef,
226225
private _ngZone: NgZone,
227226
platform: Platform,
228-
@Optional() @Inject(MAT_RIPPLE_GLOBAL_OPTIONS) globalOptions: RippleGlobalOptions) {
227+
@Optional() @Inject(MAT_RIPPLE_GLOBAL_OPTIONS)
228+
globalRippleOptions: RippleGlobalOptions | null) {
229229
super(_elementRef);
230230

231231
this._addHostClassName();
232232

233233
this._chipRipple = new RippleRenderer(this, _ngZone, _elementRef, platform);
234234
this._chipRipple.setupTriggerEvents(_elementRef.nativeElement);
235-
236-
if (globalOptions) {
237-
// TODO(paul): Do not copy each option manually. Allow dynamic global option changes: #9729
238-
this._ripplesGloballyDisabled = !!globalOptions.disabled;
239-
this.rippleConfig = {
240-
animation: globalOptions.animation,
241-
terminateOnPointerUp: globalOptions.terminateOnPointerUp,
242-
};
243-
}
235+
this.rippleConfig = globalRippleOptions || {};
244236
}
245237

246238
_addHostClassName() {

0 commit comments

Comments
 (0)