Skip to content

feat(ripple): support ripple fade-out on pointer up #9694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/lib/core/ripple/ripple-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type RippleConfig = {
radius?: number;
persistent?: boolean;
animation?: RippleAnimationConfig;
terminateOnPointerUp?: boolean;
/** @deprecated Use the animation property instead. */
speedFactor?: number;
};
Expand Down Expand Up @@ -244,9 +245,14 @@ export class RippleRenderer {

this._isPointerDown = false;

// Fade-out all ripples that are completely visible and not persistent.
// Fade-out all ripples that are visible and not persistent.
this._activeRipples.forEach(ripple => {
if (!ripple.config.persistent && ripple.state === RippleState.VISIBLE) {
// By default, only ripples that are completely visible will fade out on pointer release.
// If the `terminateOnPointerUp` option is set, ripples that still fade in will also fade out.
const isVisible = ripple.state === RippleState.VISIBLE ||
ripple.config.terminateOnPointerUp && ripple.state === RippleState.FADING_IN;

if (!ripple.config.persistent && isVisible) {
ripple.fadeOut();
}
});
Expand Down
21 changes: 21 additions & 0 deletions src/lib/core/ripple/ripple.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,27 @@ describe('MatRipple', () => {

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
}));

it('should allow ripples to fade out immediately on pointer up', fakeAsync(() => {
createTestComponent({
terminateOnPointerUp: true
});

dispatchMouseEvent(rippleTarget, 'mousedown');
dispatchMouseEvent(rippleTarget, 'mouseup');

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);

// Ignore the enter duration, because we immediately fired the mouseup after the mousedown.
// This means that the ripple should just fade out, and there shouldn't be an enter animation.
tick(exitDuration);

expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);

// Since the enter duration is bigger than the exit duration, the enter duration timer
// will still exist. To properly finish all timers, we just wait the remaining time.
tick(enterDuration - exitDuration);
}));
});

describe('configuring behavior', () => {
Expand Down
7 changes: 7 additions & 0 deletions src/lib/core/ripple/ripple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export interface RippleGlobalOptions {
* @deprecated Use the `animation` global option instead.
*/
baseSpeedFactor?: number;

/**
* Whether ripples should start fading out immediately after the mouse our touch is released. By
* default, ripples will wait for the enter animation to complete and for mouse or touch release.
*/
terminateOnPointerUp?: boolean;
}

/** Injection token that can be used to specify the global ripple options. */
Expand Down Expand Up @@ -159,6 +165,7 @@ export class MatRipple implements OnInit, OnDestroy, RippleTarget {
radius: this.radius,
color: this.color,
animation: {...this._globalOptions.animation, ...this.animation},
terminateOnPointerUp: this._globalOptions.terminateOnPointerUp,
speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor || 1),
};
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ export class MatTabLink extends _MatTabLinkMixinBase

if (globalOptions) {
this.rippleConfig = {
terminateOnPointerUp: globalOptions.terminateOnPointerUp,
speedFactor: globalOptions.baseSpeedFactor,
animation: globalOptions.animation,
};
Expand Down