Skip to content

Commit db7f00f

Browse files
crisbetojelbourn
authored andcommitted
fix(ripple): ripples not being cleared if touch sequence is canceled (#12936)
If the browser's touch sequence gets canceled by something, the `touchend` event won't fire which means that the ripples won't be cleared from the ripple container. These changes add an extra handler to make sure that they are.
1 parent 85aa144 commit db7f00f

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

src/lib/core/ripple/ripple-renderer.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,14 @@ export class RippleRenderer {
110110
this._containerElement = elementRef.nativeElement;
111111

112112
// Specify events which need to be registered on the trigger.
113-
this._triggerEvents.set('mousedown', this.onMousedown);
114-
this._triggerEvents.set('mouseup', this.onPointerUp);
115-
this._triggerEvents.set('mouseleave', this.onPointerUp);
116-
117-
this._triggerEvents.set('touchstart', this.onTouchStart);
118-
this._triggerEvents.set('touchend', this.onPointerUp);
113+
this._triggerEvents
114+
.set('mousedown', this.onMousedown)
115+
.set('mouseup', this.onPointerUp)
116+
.set('mouseleave', this.onPointerUp)
117+
118+
.set('touchstart', this.onTouchStart)
119+
.set('touchend', this.onPointerUp)
120+
.set('touchcancel', this.onPointerUp);
119121
}
120122
}
121123

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Platform} from '@angular/cdk/platform';
22
import {
3+
createTouchEvent,
34
createMouseEvent,
45
dispatchEvent,
56
dispatchMouseEvent,
@@ -130,6 +131,43 @@ describe('MatRipple', () => {
130131
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
131132
}));
132133

134+
it('should clear ripples if the touch sequence is cancelled', fakeAsync(() => {
135+
dispatchTouchEvent(rippleTarget, 'touchstart');
136+
tick(enterDuration);
137+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(1);
138+
139+
dispatchTouchEvent(rippleTarget, 'touchcancel');
140+
tick(exitDuration);
141+
142+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
143+
}));
144+
145+
it('should launch multiple ripples for multi-touch', fakeAsync(() => {
146+
const touchEvent = createTouchEvent('touchstart');
147+
148+
Object.defineProperties(touchEvent, {
149+
changedTouches: {
150+
value: [
151+
{pageX: 0, pageY: 0},
152+
{pageX: 10, pageY: 10},
153+
{pageX: 20, pageY: 20}
154+
]
155+
}
156+
});
157+
158+
dispatchEvent(rippleTarget, touchEvent);
159+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(3);
160+
161+
tick(enterDuration);
162+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(3);
163+
164+
dispatchTouchEvent(rippleTarget, 'touchend');
165+
166+
tick(exitDuration);
167+
168+
expect(rippleTarget.querySelectorAll('.mat-ripple-element').length).toBe(0);
169+
}));
170+
133171
it('should ignore synthetic mouse events after touchstart', () => fakeAsync(() => {
134172
dispatchTouchEvent(rippleTarget, 'touchstart');
135173
dispatchTouchEvent(rippleTarget, 'mousedown');

0 commit comments

Comments
 (0)