@@ -87,39 +87,45 @@ export function setupRipple(
8787 }
8888
8989 let minimumPressTimeoutId : number | undefined ;
90+ const activateRipple = ( ) => {
91+ // If the ripple is already active, restart the current press animation.
92+ if ( ripple . classList . contains ( RIPPLE_CLASSES . active ) ) {
93+ const pressAnimation = ripple
94+ . getAnimations ( )
95+ . find (
96+ ( animation ) =>
97+ ( animation as Partial < CSSAnimation > ) . animationName ===
98+ 'ripple-press' ,
99+ ) ;
100+ pressAnimation ?. cancel ( ) ;
101+ pressAnimation ?. play ( ) ;
102+ }
103+
104+ // Emulate the `:active` class for a minimum press duration to show the
105+ // ripple effect on short clicks.
106+ ripple . classList . add ( RIPPLE_CLASSES . active ) ;
107+ clearTimeout ( minimumPressTimeoutId ) ;
108+ minimumPressTimeoutId = setTimeout ( ( ) => {
109+ ripple . classList . remove ( RIPPLE_CLASSES . active ) ;
110+ } , MINIMUM_PRESS_MS ) ;
111+ } ;
112+
113+ // Return true if the ripple is disabled, or if the ripple class has been
114+ // removed. This allows components to disable and re-enable ripple behavior.
115+ const isRippleDisabled = ( ) =>
116+ isDisabled ( ripple ) || ! ripple . matches ( `.${ RIPPLE_CLASSES . ripple } ` ) ;
117+
90118 ripple . addEventListener (
91119 'pointerdown' ,
92120 ( event : PointerEvent ) : void => {
93- if ( isDisabled ( ripple ) ) return ;
94-
121+ if ( isRippleDisabled ( ) ) return ;
95122 // Set ripple position to the pointer position.
96123 const rect = ripple . getBoundingClientRect ( ) ;
97124 const x = ( event . clientX - rect . x ) / rect . width ;
98125 const y = ( event . clientY - rect . y ) / rect . height ;
99126 ripple . style . setProperty ( '--ripple-x' , `${ x * 100 } %` ) ;
100127 ripple . style . setProperty ( '--ripple-y' , `${ y * 100 } %` ) ;
101-
102- // If another pointerdown is received while the ripple is active, restart
103- // the active press animation.
104- if ( ripple . classList . contains ( RIPPLE_CLASSES . active ) ) {
105- const pressAnimation = ripple
106- . getAnimations ( )
107- . find (
108- ( animation ) =>
109- ( animation as Partial < CSSAnimation > ) . animationName ===
110- 'ripple-press' ,
111- ) ;
112- pressAnimation ?. cancel ( ) ;
113- pressAnimation ?. play ( ) ;
114- }
115-
116- // Emulate the `:active` class for a minimum press duration to show the
117- // ripple effect on short clicks.
118- ripple . classList . add ( RIPPLE_CLASSES . active ) ;
119- clearTimeout ( minimumPressTimeoutId ) ;
120- minimumPressTimeoutId = setTimeout ( ( ) => {
121- ripple . classList . remove ( RIPPLE_CLASSES . active ) ;
122- } , MINIMUM_PRESS_MS ) ;
128+ activateRipple ( ) ;
123129 } ,
124130 opts ,
125131 ) ;
@@ -133,6 +139,18 @@ export function setupRipple(
133139 } ,
134140 opts ,
135141 ) ;
142+
143+ ripple . addEventListener (
144+ 'click' ,
145+ ( event ) => {
146+ // A UIEvent.detail click count of 0 indicates the click was not triggered
147+ // by a pointer. Show the ripple press effect for these clicks as well.
148+ if ( event . detail === 0 && ! isRippleDisabled ( ) ) {
149+ activateRipple ( ) ;
150+ }
151+ } ,
152+ opts ,
153+ ) ;
136154}
137155
138156/**
0 commit comments