From a9c8487d91fed36a0c0c412957ac636595f909ee Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Fri, 5 Jan 2018 19:36:54 +0100 Subject: [PATCH] feat(ripple): support animation duration overwrites * Adds a new option to the ripples that allows developers to have a better control of the animation (all ripples, or even individual ripples). * Deprecates the `matRippleSpeedFactor` in favor of the `matRippleAnimation` binding that accepts a `RippleAnimationConfig`. The configuration is more explicit, clean and not confusing as the `speedFactor`. * To provide a more user-friendly `launch()` method API, the passed ripple config will extend the default ripple config from the `MatRipple` instance (removes unnecessary bloat; requested in https://github.com/angular/material2/issues/4179#issuecomment-295889498) * Disables ripples for most of the demo buttons in the ripple demo (allows better debugging; when pressing the buttons) --- src/demo-app/ripple/ripple-demo.html | 7 +- src/demo-app/ripple/ripple-demo.ts | 14 +++- src/lib/checkbox/checkbox.html | 6 +- src/lib/checkbox/checkbox.spec.ts | 6 +- src/lib/checkbox/checkbox.ts | 5 +- src/lib/core/ripple/ripple-renderer.ts | 53 ++++++++++----- src/lib/core/ripple/ripple.md | 27 +++++++- src/lib/core/ripple/ripple.spec.ts | 81 ++++++++++++++++++----- src/lib/core/ripple/ripple.ts | 27 ++++++-- src/lib/radio/radio.html | 6 +- src/lib/radio/radio.spec.ts | 6 +- src/lib/radio/radio.ts | 5 +- src/lib/slide-toggle/slide-toggle.html | 6 +- src/lib/slide-toggle/slide-toggle.spec.ts | 6 +- src/lib/slide-toggle/slide-toggle.ts | 5 +- src/lib/tabs/tab-nav-bar/tab-nav-bar.ts | 5 +- 16 files changed, 184 insertions(+), 81 deletions(-) diff --git a/src/demo-app/ripple/ripple-demo.html b/src/demo-app/ripple/ripple-demo.html index 98feef4e9d23..fec5235a4f22 100644 --- a/src/demo-app/ripple/ripple-demo.html +++ b/src/demo-app/ripple/ripple-demo.html @@ -35,9 +35,10 @@
- - - + + + +
+ [matRippleRadius]="25" + [matRippleCentered]="true" + [matRippleAnimation]="{enterDuration: 300}">
diff --git a/src/lib/checkbox/checkbox.spec.ts b/src/lib/checkbox/checkbox.spec.ts index b03514d6b122..6ed191d067d3 100644 --- a/src/lib/checkbox/checkbox.spec.ts +++ b/src/lib/checkbox/checkbox.spec.ts @@ -11,7 +11,7 @@ import {Component, DebugElement} from '@angular/core'; import {By} from '@angular/platform-browser'; import {dispatchFakeEvent} from '@angular/cdk/testing'; import {MatCheckbox, MatCheckboxChange, MatCheckboxModule} from './index'; -import {RIPPLE_FADE_IN_DURATION, RIPPLE_FADE_OUT_DURATION} from '@angular/material/core'; +import {defaultRippleAnimationConfig} from '@angular/material/core'; import {MAT_CHECKBOX_CLICK_ACTION} from './checkbox-config'; @@ -395,13 +395,13 @@ describe('MatCheckbox', () => { dispatchFakeEvent(inputElement, 'keydown'); dispatchFakeEvent(inputElement, 'focus'); - tick(RIPPLE_FADE_IN_DURATION); + tick(defaultRippleAnimationConfig.enterDuration); expect(fixture.nativeElement.querySelectorAll('.mat-ripple-element').length) .toBe(1, 'Expected ripple after element is focused.'); dispatchFakeEvent(checkboxInstance._inputElement.nativeElement, 'blur'); - tick(RIPPLE_FADE_OUT_DURATION); + tick(defaultRippleAnimationConfig.exitDuration); expect(fixture.nativeElement.querySelectorAll('.mat-ripple-element').length) .toBe(0, 'Expected no ripple after element is blurred.'); diff --git a/src/lib/checkbox/checkbox.ts b/src/lib/checkbox/checkbox.ts index b439f4abc270..0eabc2d388be 100644 --- a/src/lib/checkbox/checkbox.ts +++ b/src/lib/checkbox/checkbox.ts @@ -181,9 +181,6 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc /** Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. */ @ViewChild(MatRipple) _ripple: MatRipple; - /** Ripple configuration for the mouse ripples and focus indicators. */ - _rippleConfig: RippleConfig = {centered: true, radius: 25, speedFactor: 1.5}; - /** * Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. * @docs-private @@ -346,7 +343,7 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements ControlValueAc /** Function is called whenever the focus changes for the input element. */ private _onInputFocusChange(focusOrigin: FocusOrigin) { if (!this._focusRipple && focusOrigin === 'keyboard') { - this._focusRipple = this._ripple.launch(0, 0, {persistent: true, ...this._rippleConfig}); + this._focusRipple = this._ripple.launch(0, 0, {persistent: true}); } else if (!focusOrigin) { this._removeFocusRipple(); this.onTouched(); diff --git a/src/lib/core/ripple/ripple-renderer.ts b/src/lib/core/ripple/ripple-renderer.ts index a01c808e754e..130968887c7b 100644 --- a/src/lib/core/ripple/ripple-renderer.ts +++ b/src/lib/core/ripple/ripple-renderer.ts @@ -9,26 +9,27 @@ import {ElementRef, NgZone} from '@angular/core'; import {Platform, supportsPassiveEventListeners} from '@angular/cdk/platform'; import {RippleRef, RippleState} from './ripple-ref'; -/** Fade-in duration for the ripples. Can be modified with the speedFactor option. */ -export const RIPPLE_FADE_IN_DURATION = 450; - -/** Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor. */ -export const RIPPLE_FADE_OUT_DURATION = 400; - -/** - * Timeout for ignoring mouse events. Mouse events will be temporary ignored after touch - * events to avoid synthetic mouse events. - */ -const IGNORE_MOUSE_EVENTS_TIMEOUT = 800; - export type RippleConfig = { color?: string; centered?: boolean; radius?: number; - speedFactor?: number; persistent?: boolean; + animation?: RippleAnimationConfig; + /** @deprecated Use the animation property instead. */ + speedFactor?: number; }; +/** + * Interface that describes the configuration for the animation of a ripple. + * There are two animation phases with different durations for the ripples. + */ +export interface RippleAnimationConfig { + /** Duration in milliseconds for the enter animation. */ + enterDuration: number; + /** Duration in milliseconds for the exit animation. */ + exitDuration: number; +} + /** * Interface that describes the target for launching ripples. * It defines the ripple configuration and disabled state for interaction ripples. @@ -37,11 +38,25 @@ export type RippleConfig = { export interface RippleTarget { /** Configuration for ripples that are launched on pointer down. */ rippleConfig: RippleConfig; - /** Whether ripples on pointer down should be disabled. */ rippleDisabled: boolean; } +/** + * Default ripple animation configuration for ripples without an explicit + * animation config specified. + */ +export const defaultRippleAnimationConfig: RippleAnimationConfig = { + enterDuration: 450, + exitDuration: 400 +}; + +/** + * Timeout for ignoring mouse events. Mouse events will be temporary ignored after touch + * events to avoid synthetic mouse events. + */ +const ignoreMouseEventsTimeout = 800; + /** * Helper service that performs DOM manipulations. Not intended to be used outside this module. * The constructor takes a reference to the ripple directive's host element and a map of DOM @@ -99,6 +114,7 @@ export class RippleRenderer { */ fadeInRipple(x: number, y: number, config: RippleConfig = {}): RippleRef { const containerRect = this._containerElement.getBoundingClientRect(); + const animationConfig = {...defaultRippleAnimationConfig, ...config.animation}; if (config.centered) { x = containerRect.left + containerRect.width / 2; @@ -106,9 +122,9 @@ export class RippleRenderer { } const radius = config.radius || distanceToFurthestCorner(x, y, containerRect); - const duration = RIPPLE_FADE_IN_DURATION / (config.speedFactor || 1); const offsetX = x - containerRect.left; const offsetY = y - containerRect.top; + const duration = animationConfig.enterDuration / (config.speedFactor || 1); const ripple = document.createElement('div'); ripple.classList.add('mat-ripple-element'); @@ -159,8 +175,9 @@ export class RippleRenderer { } const rippleEl = rippleRef.element; + const animationConfig = {...defaultRippleAnimationConfig, ...rippleRef.config.animation}; - rippleEl.style.transitionDuration = `${RIPPLE_FADE_OUT_DURATION}ms`; + rippleEl.style.transitionDuration = `${animationConfig.exitDuration}ms`; rippleEl.style.opacity = '0'; rippleRef.state = RippleState.FADING_OUT; @@ -169,7 +186,7 @@ export class RippleRenderer { this.runTimeoutOutsideZone(() => { rippleRef.state = RippleState.HIDDEN; rippleEl.parentNode!.removeChild(rippleEl); - }, RIPPLE_FADE_OUT_DURATION); + }, animationConfig.exitDuration); } /** Fades out all currently active ripples. */ @@ -197,7 +214,7 @@ export class RippleRenderer { /** Function being called whenever the trigger is being pressed using mouse. */ private onMousedown = (event: MouseEvent) => { const isSyntheticEvent = this._lastTouchStartEvent && - Date.now() < this._lastTouchStartEvent + IGNORE_MOUSE_EVENTS_TIMEOUT; + Date.now() < this._lastTouchStartEvent + ignoreMouseEventsTimeout; if (!this._target.rippleDisabled && !isSyntheticEvent) { this._isPointerDown = true; diff --git a/src/lib/core/ripple/ripple.md b/src/lib/core/ripple/ripple.md index c0aaf9850846..b0b708f6e0e3 100644 --- a/src/lib/core/ripple/ripple.md +++ b/src/lib/core/ripple/ripple.md @@ -75,8 +75,11 @@ Global ripple options can be specified by setting the `MAT_RIPPLE_GLOBAL_OPTIONS ```ts const globalRippleConfig: RippleGlobalOptions = { disabled: true, - baseSpeedFactor: 1.5 // Ripples will animate 50% faster than before. -} + animation: { + enterDuration: 300, + exitDuration: 0 + } +}; @NgModule({ providers: [ @@ -86,3 +89,23 @@ const globalRippleConfig: RippleGlobalOptions = { ``` All available global options can be seen in the `RippleGlobalOptions` interface. + +### Disabling animation + +The animation of ripples can be disabled by using the `animation` global option. If the +`enterDuration` and `exitDuration` is being set to `0`, ripples will just appear without any +animation. + +This is specifically useful in combination with the `disabled` global option, because globally +disabling ripples won't affect the focus indicator ripples. If someone still wants to disable +those ripples for performance reasons, the duration can be set to `0`, to remove the ripple feel. + +```ts +const globalRippleConfig: RippleGlobalOptions = { + disabled: true, + animation: { + enterDuration: 0, + exitDuration: 0 + } +}; +``` diff --git a/src/lib/core/ripple/ripple.spec.ts b/src/lib/core/ripple/ripple.spec.ts index 09517ba85ffb..fd9b49027eda 100644 --- a/src/lib/core/ripple/ripple.spec.ts +++ b/src/lib/core/ripple/ripple.spec.ts @@ -2,11 +2,13 @@ import {TestBed, ComponentFixture, fakeAsync, tick, inject} from '@angular/core/ import {Component, ViewChild} from '@angular/core'; import {Platform} from '@angular/cdk/platform'; import {dispatchMouseEvent, dispatchTouchEvent} from '@angular/cdk/testing'; -import {RIPPLE_FADE_OUT_DURATION, RIPPLE_FADE_IN_DURATION} from './ripple-renderer'; +import {defaultRippleAnimationConfig, RippleAnimationConfig} from './ripple-renderer'; import { MatRipple, MatRippleModule, MAT_RIPPLE_GLOBAL_OPTIONS, RippleState, RippleGlobalOptions } from './index'; +/** Shorthands for the enter and exit duration of ripples. */ +const {enterDuration, exitDuration} = defaultRippleAnimationConfig; describe('MatRipple', () => { let fixture: ComponentFixture; @@ -108,12 +110,12 @@ describe('MatRipple', () => { dispatchTouchEvent(rippleTarget, 'touchstart'); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); - tick(RIPPLE_FADE_IN_DURATION); + tick(enterDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); dispatchTouchEvent(rippleTarget, 'touchend'); - tick(RIPPLE_FADE_OUT_DURATION); + tick(exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); @@ -122,12 +124,12 @@ describe('MatRipple', () => { dispatchTouchEvent(rippleTarget, 'touchstart'); dispatchTouchEvent(rippleTarget, 'mousedown'); - tick(RIPPLE_FADE_IN_DURATION); + tick(enterDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); dispatchTouchEvent(rippleTarget, 'touchend'); - tick(RIPPLE_FADE_OUT_DURATION); + tick(exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); @@ -139,7 +141,7 @@ describe('MatRipple', () => { expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); // Calculates the duration for fading-in and fading-out the ripple. - tick(RIPPLE_FADE_IN_DURATION + RIPPLE_FADE_OUT_DURATION); + tick(enterDuration + exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); @@ -151,19 +153,19 @@ describe('MatRipple', () => { // Fakes the duration of fading-in and fading-out normal ripples. // The fade-out duration has been added to ensure that didn't start fading out. - tick(RIPPLE_FADE_IN_DURATION + RIPPLE_FADE_OUT_DURATION); + tick(enterDuration + exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); dispatchMouseEvent(rippleTarget, 'mouseup'); - tick(RIPPLE_FADE_OUT_DURATION); + tick(exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); it('should not hide ripples while animating.', fakeAsync(() => { // Calculates the duration for fading-in and fading-out the ripple. - let hideDuration = RIPPLE_FADE_IN_DURATION + RIPPLE_FADE_OUT_DURATION; + let hideDuration = enterDuration + exitDuration; dispatchMouseEvent(rippleTarget, 'mousedown'); dispatchMouseEvent(rippleTarget, 'mouseup'); @@ -323,13 +325,13 @@ describe('MatRipple', () => { // Calculates the duration for fading-in and fading-out the ripple. Also adds some // extra time to demonstrate that the ripples are persistent. - tick(RIPPLE_FADE_IN_DURATION + RIPPLE_FADE_OUT_DURATION + 5000); + tick(enterDuration + exitDuration + 5000); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); rippleRef.fadeOut(); - tick(RIPPLE_FADE_OUT_DURATION); + tick(exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); @@ -341,11 +343,11 @@ describe('MatRipple', () => { expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); - tick(RIPPLE_FADE_IN_DURATION / 2); + tick(enterDuration / 2); rippleDirective.fadeOutAll(); - tick(RIPPLE_FADE_OUT_DURATION); + tick(exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length) .toBe(0, 'Expected no ripples to be active after calling fadeOutAll.'); @@ -359,7 +361,7 @@ describe('MatRipple', () => { expect(rippleRef.state).toBe(RippleState.FADING_IN); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); - tick(RIPPLE_FADE_IN_DURATION); + tick(enterDuration); expect(rippleRef.state).toBe(RippleState.VISIBLE); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); @@ -369,12 +371,25 @@ describe('MatRipple', () => { expect(rippleRef.state).toBe(RippleState.FADING_OUT); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); - tick(RIPPLE_FADE_OUT_DURATION); + tick(exitDuration); expect(rippleRef.state).toBe(RippleState.HIDDEN); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); + it('should allow setting a specific animation config for a ripple', fakeAsync(() => { + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + + rippleDirective.launch(0, 0, { + animation: {enterDuration: 120, exitDuration: 0} + }); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); + + tick(120); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + })); }); describe('global ripple options', () => { @@ -449,7 +464,7 @@ describe('MatRipple', () => { let fadeInFactor = 1 / 0.5; // Calculates the duration for fading-in and fading-out the ripple. - tick(RIPPLE_FADE_IN_DURATION * fadeInFactor + RIPPLE_FADE_OUT_DURATION); + tick(enterDuration * fadeInFactor + exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); @@ -466,11 +481,25 @@ describe('MatRipple', () => { let fadeInFactor = 1 / (0.5 * 1.5); // Calculates the duration for fading-in and fading-out the ripple. - tick(RIPPLE_FADE_IN_DURATION * fadeInFactor + RIPPLE_FADE_OUT_DURATION); + tick(enterDuration * fadeInFactor + exitDuration); expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); })); + it('should support changing the animation duration', fakeAsync(() => { + createTestComponent({ + animation: {enterDuration: 100, exitDuration: 100} + }); + + rippleDirective.launch(0, 0); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); + + // Wait the 200ms of the enter duration and exit duration. + tick(100 + 100); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + })); }); describe('configuring behavior', () => { @@ -487,7 +516,7 @@ describe('MatRipple', () => { }); it('sets ripple color', () => { - let backgroundColor = 'rgba(12, 34, 56, 0.8)'; + const backgroundColor = 'rgba(12, 34, 56, 0.8)'; controller.color = backgroundColor; fixture.detectChanges(); @@ -583,6 +612,20 @@ describe('MatRipple', () => { expect(pxStringToFloat(ripple.style.width)).toBeCloseTo(2 * customRadius, 1); expect(pxStringToFloat(ripple.style.height)).toBeCloseTo(2 * customRadius, 1); }); + + it('should be able to specify animation config through binding', fakeAsync(() => { + controller.animationConfig = {enterDuration: 150, exitDuration: 150}; + fixture.detectChanges(); + + dispatchMouseEvent(rippleTarget, 'mousedown'); + dispatchMouseEvent(rippleTarget, 'mouseup'); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1); +9 + tick(150 + 150); + + expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0); + })); }); }); @@ -607,12 +650,14 @@ class BasicRippleContainer { [matRippleCentered]="centered" [matRippleRadius]="radius" [matRippleDisabled]="disabled" + [matRippleAnimation]="animationConfig" [matRippleColor]="color">
`, }) class RippleContainerWithInputBindings { + animationConfig: RippleAnimationConfig; trigger: HTMLElement; centered = false; disabled = false; diff --git a/src/lib/core/ripple/ripple.ts b/src/lib/core/ripple/ripple.ts index 5a26091d10b7..52c2d693f0fa 100644 --- a/src/lib/core/ripple/ripple.ts +++ b/src/lib/core/ripple/ripple.ts @@ -19,7 +19,7 @@ import { Optional, } from '@angular/core'; import {RippleRef} from './ripple-ref'; -import {RippleConfig, RippleRenderer, RippleTarget} from './ripple-renderer'; +import {RippleAnimationConfig, RippleConfig, RippleRenderer, RippleTarget} from './ripple-renderer'; /** Configurable options for `matRipple`. */ export interface RippleGlobalOptions { @@ -29,10 +29,17 @@ export interface RippleGlobalOptions { */ disabled?: boolean; + /** + * Configuration for the animation duration of the ripples. + * There are two phases with different durations for the ripples. + */ + animation?: RippleAnimationConfig; + /** * If set, the default duration of the fade-in animation is divided by this value. For example, * setting it to 0.5 will cause the ripple fade-in animation to take twice as long. * A changed speedFactor will not affect the fade-out duration of the ripples. + * @deprecated Use the `animation` global option instead. */ baseSpeedFactor?: number; } @@ -74,9 +81,16 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { * If set, the normal duration of ripple animations is divided by this value. For example, * setting it to 0.5 will cause the animations to take twice as long. * A changed speedFactor will not modify the fade-out duration of the ripples. + * @deprecated Use the [matRippleAnimation] binding instead. */ @Input('matRippleSpeedFactor') speedFactor: number = 1; + /** + * Configuration for the ripple animation. Allows modifying the enter and exit animation + * duration of the ripples. + */ + @Input('matRippleAnimation') animation: RippleAnimationConfig; + /** * Whether click events will not trigger the ripple. Ripples can be still launched manually * by using the `launch()` method. @@ -129,8 +143,8 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { } /** Launches a manual ripple at the specified position. */ - launch(x: number, y: number, config: RippleConfig = this): RippleRef { - return this._rippleRenderer.fadeInRipple(x, y, config); + launch(x: number, y: number, config?: RippleConfig): RippleRef { + return this._rippleRenderer.fadeInRipple(x, y, {...this.rippleConfig, ...config}); } /** Fades out all currently showing ripple elements. */ @@ -142,13 +156,14 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget { get rippleConfig(): RippleConfig { return { centered: this.centered, - speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor || 1), radius: this.radius, - color: this.color + color: this.color, + animation: {...this._globalOptions.animation, ...this.animation}, + speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor || 1), }; } - /** Whether ripples on pointer-down are disabled or not. */ + /** Whether ripples on pointer-down are disabled or not. */ get rippleDisabled(): boolean { return this.disabled || !!this._globalOptions.disabled; } diff --git a/src/lib/radio/radio.html b/src/lib/radio/radio.html index 4c77e164b2a2..1a6ee2606dc7 100644 --- a/src/lib/radio/radio.html +++ b/src/lib/radio/radio.html @@ -8,9 +8,9 @@
+ [matRippleCentered]="true" + [matRippleRadius]="23" + [matRippleAnimation]="{enterDuration: 300}">
diff --git a/src/lib/radio/radio.spec.ts b/src/lib/radio/radio.spec.ts index aa275181a417..102ee7843509 100644 --- a/src/lib/radio/radio.spec.ts +++ b/src/lib/radio/radio.spec.ts @@ -4,7 +4,7 @@ import {Component, DebugElement} from '@angular/core'; import {By} from '@angular/platform-browser'; import {ViewportRuler} from '@angular/cdk/scrolling'; import {dispatchFakeEvent, FakeViewportRuler} from '@angular/cdk/testing'; -import {RIPPLE_FADE_IN_DURATION, RIPPLE_FADE_OUT_DURATION} from '@angular/material/core'; +import {defaultRippleAnimationConfig} from '@angular/material/core'; import {MatRadioButton, MatRadioChange, MatRadioGroup, MatRadioModule} from './index'; describe('MatRadio', () => { @@ -209,13 +209,13 @@ describe('MatRadio', () => { dispatchFakeEvent(radioInputElements[0], 'keydown'); dispatchFakeEvent(radioInputElements[0], 'focus'); - tick(RIPPLE_FADE_IN_DURATION); + tick(defaultRippleAnimationConfig.enterDuration); expect(radioNativeElements[0].querySelectorAll('.mat-ripple-element').length) .toBe(1, 'Expected one ripple after keyboard focus.'); dispatchFakeEvent(radioInputElements[0], 'blur'); - tick(RIPPLE_FADE_OUT_DURATION); + tick(defaultRippleAnimationConfig.exitDuration); expect(radioNativeElements[0].querySelectorAll('.mat-ripple-element').length) .toBe(0, 'Expected no ripples on blur.'); diff --git a/src/lib/radio/radio.ts b/src/lib/radio/radio.ts index 8c3ff6cc629a..f81cff215a6c 100644 --- a/src/lib/radio/radio.ts +++ b/src/lib/radio/radio.ts @@ -482,9 +482,6 @@ export class MatRadioButton extends _MatRadioButtonMixinBase /** The child ripple instance. */ @ViewChild(MatRipple) _ripple: MatRipple; - /** Ripple configuration for the mouse ripples and focus indicators. */ - _rippleConfig: RippleConfig = {centered: true, radius: 23, speedFactor: 1.5}; - /** Reference to the current focus ripple. */ private _focusRipple: RippleRef | null; @@ -598,7 +595,7 @@ export class MatRadioButton extends _MatRadioButtonMixinBase /** Function is called whenever the focus changes for the input element. */ private _onInputFocusChange(focusOrigin: FocusOrigin) { if (!this._focusRipple && focusOrigin === 'keyboard') { - this._focusRipple = this._ripple.launch(0, 0, {persistent: true, ...this._rippleConfig}); + this._focusRipple = this._ripple.launch(0, 0, {persistent: true}); } else if (!focusOrigin) { if (this.radioGroup) { this.radioGroup._touch(); diff --git a/src/lib/slide-toggle/slide-toggle.html b/src/lib/slide-toggle/slide-toggle.html index e1c56ad44cde..cdd7b5902d28 100644 --- a/src/lib/slide-toggle/slide-toggle.html +++ b/src/lib/slide-toggle/slide-toggle.html @@ -25,9 +25,9 @@
+ [matRippleCentered]="true" + [matRippleRadius]="23" + [matRippleAnimation]="{enterDuration: 300}">
diff --git a/src/lib/slide-toggle/slide-toggle.spec.ts b/src/lib/slide-toggle/slide-toggle.spec.ts index b95bf06c96e3..306cdefda2e5 100644 --- a/src/lib/slide-toggle/slide-toggle.spec.ts +++ b/src/lib/slide-toggle/slide-toggle.spec.ts @@ -8,7 +8,7 @@ import {NgModel, FormsModule, ReactiveFormsModule, FormControl} from '@angular/f import {MatSlideToggle, MatSlideToggleChange, MatSlideToggleModule} from './index'; import {TestGestureConfig} from '../slider/test-gesture-config'; import {dispatchFakeEvent} from '@angular/cdk/testing'; -import {RIPPLE_FADE_IN_DURATION, RIPPLE_FADE_OUT_DURATION} from '@angular/material/core'; +import {defaultRippleAnimationConfig} from '@angular/material/core'; describe('MatSlideToggle without forms', () => { let gestureConfig: TestGestureConfig; @@ -263,14 +263,14 @@ describe('MatSlideToggle without forms', () => { dispatchFakeEvent(inputElement, 'keydown'); dispatchFakeEvent(inputElement, 'focus'); - tick(RIPPLE_FADE_IN_DURATION); + tick(defaultRippleAnimationConfig.enterDuration); expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length) .toBe(1, 'Expected the focus ripple to be showing up.'); dispatchFakeEvent(inputElement, 'blur'); - tick(RIPPLE_FADE_OUT_DURATION); + tick(defaultRippleAnimationConfig.exitDuration); expect(slideToggleElement.querySelectorAll('.mat-ripple-element').length) .toBe(0, 'Expected focus ripple to be removed.'); diff --git a/src/lib/slide-toggle/slide-toggle.ts b/src/lib/slide-toggle/slide-toggle.ts index a661df7177ad..f478b97b7f24 100644 --- a/src/lib/slide-toggle/slide-toggle.ts +++ b/src/lib/slide-toggle/slide-toggle.ts @@ -139,9 +139,6 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro /** Reference to the ripple directive on the thumb container. */ @ViewChild(MatRipple) _ripple: MatRipple; - /** Ripple configuration for the mouse ripples and focus indicators. */ - _rippleConfig: RippleConfig = {centered: true, radius: 23, speedFactor: 1.5}; - constructor(elementRef: ElementRef, private _platform: Platform, private _focusMonitor: FocusMonitor, @@ -234,7 +231,7 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro private _onInputFocusChange(focusOrigin: FocusOrigin) { if (!this._focusRipple && focusOrigin === 'keyboard') { // For keyboard focus show a persistent ripple as focus indicator. - this._focusRipple = this._ripple.launch(0, 0, {persistent: true, ...this._rippleConfig}); + this._focusRipple = this._ripple.launch(0, 0, {persistent: true}); } else if (!focusOrigin) { this.onTouched(); diff --git a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts index b4ea13503cd4..a0f3a5bfe028 100644 --- a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts @@ -237,7 +237,10 @@ export class MatTabLink extends _MatTabLinkMixinBase this.tabIndex = parseInt(tabIndex) || 0; if (globalOptions) { - this.rippleConfig = {speedFactor: globalOptions.baseSpeedFactor}; + this.rippleConfig = { + speedFactor: globalOptions.baseSpeedFactor, + animation: globalOptions.animation, + }; } }