Skip to content

Commit d2d80ba

Browse files
committed
feat(ripple): add option to change global speedFactor
* Refactors the `MD_DISABLE_RIPPLES` token to a configuration object, that can also include options like a global `baseSpeedFactor`.
1 parent d78a370 commit d2d80ba

File tree

3 files changed

+65
-18
lines changed

3 files changed

+65
-18
lines changed

src/lib/core/ripple/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {CompatibilityModule} from '../compatibility/compatibility';
44
import {VIEWPORT_RULER_PROVIDER} from '../overlay/position/viewport-ruler';
55
import {SCROLL_DISPATCHER_PROVIDER} from '../overlay/scroll/scroll-dispatcher';
66

7-
export {MdRipple, MD_DISABLE_RIPPLES} from './ripple';
7+
export {MdRipple, RippleGlobalOptions, MD_RIPPLE_GLOBAL_OPTIONS} from './ripple';
88
export {RippleRef, RippleState} from './ripple-ref';
99
export {RippleConfig} from './ripple-renderer';
1010

src/lib/core/ripple/ripple.spec.ts

+49-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {TestBed, ComponentFixture, fakeAsync, tick, inject} from '@angular/core/testing';
22
import {Component, ViewChild} from '@angular/core';
3-
import {MdRipple, MdRippleModule, MD_DISABLE_RIPPLES, RippleState} from './index';
43
import {ViewportRuler} from '../overlay/position/viewport-ruler';
54
import {RIPPLE_FADE_OUT_DURATION, RIPPLE_FADE_IN_DURATION} from './ripple-renderer';
65
import {dispatchMouseEvent} from '../testing/dispatch-events';
6+
import {
7+
MdRipple, MdRippleModule, MD_RIPPLE_GLOBAL_OPTIONS, RippleState, RippleGlobalOptions
8+
} from './index';
79

810
/** Extracts the numeric value of a pixel size string like '123px'. */
911
const pxStringToFloat = (s: string) => {
@@ -346,29 +348,29 @@ describe('MdRipple', () => {
346348

347349
});
348350

349-
describe('with ripples disabled', () => {
351+
describe('global ripple options', () => {
350352
let rippleDirective: MdRipple;
351353

352-
beforeEach(() => {
353-
// Reset the previously configured testing module to be able to disable ripples globally.
354+
function createTestComponent(rippleConfig: RippleGlobalOptions) {
355+
// Reset the previously configured testing module to be able set new providers.
354356
// The testing module has been initialized in the root describe group for the ripples.
355357
TestBed.resetTestingModule();
356358
TestBed.configureTestingModule({
357359
imports: [MdRippleModule],
358360
declarations: [BasicRippleContainer],
359-
providers: [{ provide: MD_DISABLE_RIPPLES, useValue: true }]
361+
providers: [{ provide: MD_RIPPLE_GLOBAL_OPTIONS, useValue: rippleConfig }]
360362
});
361-
});
362363

363-
beforeEach(() => {
364364
fixture = TestBed.createComponent(BasicRippleContainer);
365365
fixture.detectChanges();
366366

367367
rippleTarget = fixture.nativeElement.querySelector('[mat-ripple]');
368368
rippleDirective = fixture.componentInstance.ripple;
369-
});
369+
}
370+
371+
it('when disabled should not show any ripples on mousedown', () => {
372+
createTestComponent({ disabled: true });
370373

371-
it('should not show any ripples on mousedown', () => {
372374
dispatchMouseEvent(rippleTarget, 'mousedown');
373375
dispatchMouseEvent(rippleTarget, 'mouseup');
374376

@@ -380,14 +382,51 @@ describe('MdRipple', () => {
380382
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
381383
});
382384

383-
it('should still allow manual ripples', () => {
385+
it('when disabled should still allow manual ripples', () => {
386+
createTestComponent({ disabled: true });
387+
384388
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
385389

386390
rippleDirective.launch(0, 0);
387391

388392
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);
389393
});
390394

395+
it('should support changing the baseSpeedFactor', fakeAsync(() => {
396+
createTestComponent({ baseSpeedFactor: 0.5 });
397+
398+
dispatchMouseEvent(rippleTarget, 'mousedown');
399+
dispatchMouseEvent(rippleTarget, 'mouseup');
400+
401+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);
402+
403+
// Calculates the speedFactor for the duration. Those factors needs to be inverted, because
404+
// a lower speed factor, will make the duration longer. For example: 0.5 => 2x duration.
405+
let fadeInFactor = 1 / 0.5;
406+
407+
// Calculates the duration for fading-in and fading-out the ripple.
408+
tick(RIPPLE_FADE_IN_DURATION * fadeInFactor + RIPPLE_FADE_OUT_DURATION);
409+
410+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
411+
}));
412+
413+
it('should combine individual speed factor with baseSpeedFactor', fakeAsync(() => {
414+
createTestComponent({ baseSpeedFactor: 0.5 });
415+
416+
rippleDirective.launch(0, 0, { speedFactor: 1.5 });
417+
418+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);
419+
420+
// Calculates the speedFactor for the duration. Those factors needs to be inverted, because
421+
// a lower speed factor, will make the duration longer. For example: 0.5 => 2x duration.
422+
let fadeInFactor = 1 / (0.5 * 1.5);
423+
424+
// Calculates the duration for fading-in and fading-out the ripple.
425+
tick(RIPPLE_FADE_IN_DURATION * fadeInFactor + RIPPLE_FADE_OUT_DURATION);
426+
427+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
428+
}));
429+
391430
});
392431

393432
describe('configuring behavior', () => {

src/lib/core/ripple/ripple.ts

+15-7
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ import {RippleConfig, RippleRenderer} from './ripple-renderer';
1414
import {ViewportRuler} from '../overlay/position/viewport-ruler';
1515
import {RippleRef} from './ripple-ref';
1616

17-
/** OpaqueToken that can be used to globally disable all ripples. Except programmatic ones. */
18-
export const MD_DISABLE_RIPPLES = new OpaqueToken('md-disable-ripples');
17+
/** OpqaueToken that can be used to specify the global ripple options. */
18+
export const MD_RIPPLE_GLOBAL_OPTIONS = new OpaqueToken('md-ripple-global-options');
19+
20+
export type RippleGlobalOptions = {
21+
disabled?: boolean;
22+
baseSpeedFactor?: number;
23+
};
1924

2025
@Directive({
2126
selector: '[md-ripple], [mat-ripple]',
@@ -70,9 +75,12 @@ export class MdRipple implements OnChanges, OnDestroy {
7075
/** Renderer for the ripple DOM manipulations. */
7176
private _rippleRenderer: RippleRenderer;
7277

73-
constructor(elementRef: ElementRef, ngZone: NgZone, ruler: ViewportRuler,
74-
@Optional() @Inject(MD_DISABLE_RIPPLES) private _forceDisableRipples: boolean) {
75-
78+
constructor(
79+
elementRef: ElementRef,
80+
ngZone: NgZone,
81+
ruler: ViewportRuler,
82+
@Optional() @Inject(MD_RIPPLE_GLOBAL_OPTIONS) private _globalOptions: RippleGlobalOptions
83+
) {
7684
this._rippleRenderer = new RippleRenderer(elementRef, ngZone, ruler);
7785
}
7886

@@ -81,7 +89,7 @@ export class MdRipple implements OnChanges, OnDestroy {
8189
this._rippleRenderer.setTriggerElement(this.trigger);
8290
}
8391

84-
this._rippleRenderer.rippleDisabled = this._forceDisableRipples || this.disabled;
92+
this._rippleRenderer.rippleDisabled = this._globalOptions.disabled || this.disabled;
8593
this._rippleRenderer.rippleConfig = this.rippleConfig;
8694
}
8795

@@ -104,7 +112,7 @@ export class MdRipple implements OnChanges, OnDestroy {
104112
get rippleConfig(): RippleConfig {
105113
return {
106114
centered: this.centered,
107-
speedFactor: this.speedFactor,
115+
speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor || 1),
108116
radius: this.radius,
109117
color: this.color
110118
};

0 commit comments

Comments
 (0)