@@ -17,6 +17,12 @@ export const RIPPLE_FADE_IN_DURATION = 450;
17
17
/** Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor. */
18
18
export const RIPPLE_FADE_OUT_DURATION = 400 ;
19
19
20
+ /**
21
+ * Timeout for ignoring mouse events. Mouse events will be temporary ignored after touch
22
+ * events to avoid synthetic mouse events.
23
+ */
24
+ const ignoreMouseEventsTimeout = 800 ;
25
+
20
26
export type RippleConfig = {
21
27
color ?: string ;
22
28
centered ?: boolean ;
@@ -40,15 +46,18 @@ export class RippleRenderer {
40
46
/** Element which triggers the ripple elements on mouse events. */
41
47
private _triggerElement : HTMLElement | null ;
42
48
43
- /** Whether the mouse is currently down or not. */
44
- private _isMousedown : boolean = false ;
49
+ /** Whether the pointer is currently down or not. */
50
+ private _isPointerDown : boolean = false ;
45
51
46
52
/** Events to be registered on the trigger element. */
47
53
private _triggerEvents = new Map < string , any > ( ) ;
48
54
49
55
/** Set of currently active ripple references. */
50
56
private _activeRipples = new Set < RippleRef > ( ) ;
51
57
58
+ /** Time in milliseconds when the last touchstart event happened. */
59
+ private _lastTouchStartEvent : number ;
60
+
52
61
/** Ripple config for all ripples created by events. */
53
62
rippleConfig : RippleConfig = { } ;
54
63
@@ -62,8 +71,11 @@ export class RippleRenderer {
62
71
63
72
// Specify events which need to be registered on the trigger.
64
73
this . _triggerEvents . set ( 'mousedown' , this . onMousedown . bind ( this ) ) ;
65
- this . _triggerEvents . set ( 'mouseup' , this . onMouseup . bind ( this ) ) ;
66
- this . _triggerEvents . set ( 'mouseleave' , this . onMouseup . bind ( this ) ) ;
74
+ this . _triggerEvents . set ( 'mouseup' , this . onPointerUp . bind ( this ) ) ;
75
+ this . _triggerEvents . set ( 'mouseleave' , this . onPointerUp . bind ( this ) ) ;
76
+
77
+ this . _triggerEvents . set ( 'touchstart' , this . onTouchStart . bind ( this ) ) ;
78
+ this . _triggerEvents . set ( 'touchend' , this . onPointerUp . bind ( this ) ) ;
67
79
68
80
// By default use the host element as trigger element.
69
81
this . setTriggerElement ( this . _containerElement ) ;
@@ -122,7 +134,7 @@ export class RippleRenderer {
122
134
this . runTimeoutOutsideZone ( ( ) => {
123
135
rippleRef . state = RippleState . VISIBLE ;
124
136
125
- if ( ! config . persistent && ! this . _isMousedown ) {
137
+ if ( ! config . persistent && ! this . _isPointerDown ) {
126
138
rippleRef . fadeOut ( ) ;
127
139
}
128
140
} , duration ) ;
@@ -175,21 +187,37 @@ export class RippleRenderer {
175
187
this . _triggerElement = element ;
176
188
}
177
189
178
- /** Function being called whenever the trigger is being pressed. */
190
+ /** Function being called whenever the trigger is being pressed using mouse . */
179
191
private onMousedown ( event : MouseEvent ) {
180
- if ( ! this . rippleDisabled ) {
181
- this . _isMousedown = true ;
192
+ const isSyntheticEvent = this . _lastTouchStartEvent &&
193
+ Date . now ( ) < this . _lastTouchStartEvent + ignoreMouseEventsTimeout ;
194
+
195
+ if ( ! this . rippleDisabled && ! isSyntheticEvent ) {
196
+ this . _isPointerDown = true ;
182
197
this . fadeInRipple ( event . clientX , event . clientY , this . rippleConfig ) ;
183
198
}
184
199
}
185
200
201
+ /** Function being called whenever the trigger is being pressed using touch. */
202
+ private onTouchStart ( event : TouchEvent ) {
203
+ if ( ! this . rippleDisabled ) {
204
+ // Some browsers fire mouse events after a `touchstart` event. Those synthetic mouse
205
+ // events will launch a second ripple if we don't ignore mouse events for a specific
206
+ // time after a touchstart event.
207
+ this . _lastTouchStartEvent = Date . now ( ) ;
208
+ this . _isPointerDown = true ;
209
+
210
+ this . fadeInRipple ( event . touches [ 0 ] . clientX , event . touches [ 0 ] . clientY , this . rippleConfig ) ;
211
+ }
212
+ }
213
+
186
214
/** Function being called whenever the trigger is being released. */
187
- private onMouseup ( ) {
188
- if ( ! this . _isMousedown ) {
215
+ private onPointerUp ( ) {
216
+ if ( ! this . _isPointerDown ) {
189
217
return ;
190
218
}
191
219
192
- this . _isMousedown = false ;
220
+ this . _isPointerDown = false ;
193
221
194
222
// Fade-out all ripples that are completely visible and not persistent.
195
223
this . _activeRipples . forEach ( ripple => {
0 commit comments