@@ -16,14 +16,17 @@ limitations under the License.
1616*/
1717// Make TypeScript not remove the import.
1818import '@material/mwc-tab-indicator' ;
19+ import '@material/mwc-ripple' ;
20+
1921
2022import { addHasRemoveClass , BaseElement } from '@material/mwc-base/base-element' ;
2123import { observer } from '@material/mwc-base/observer' ;
22- import { ripple } from '@material/mwc-ripple/ripple-directive' ;
24+ import { Ripple } from '@material/mwc-ripple/mwc-ripple' ;
25+ import { RippleHandlers } from '@material/mwc-ripple/ripple-handlers' ;
2326import { TabIndicator } from '@material/mwc-tab-indicator' ;
2427import { MDCTabAdapter } from '@material/tab/adapter' ;
2528import MDCTabFoundation from '@material/tab/foundation' ;
26- import { html , property , query } from 'lit-element' ;
29+ import { eventOptions , html , internalProperty , property , query , queryAsync } from 'lit-element' ;
2730import { classMap } from 'lit-html/directives/class-map' ;
2831
2932export interface TabInteractionEventDetail {
@@ -83,9 +86,11 @@ export class TabBase extends BaseElement {
8386
8487 @query ( '.mdc-tab__content' ) private _contentElement ! : HTMLElement ;
8588
86- private _handleClick ( ) {
87- this . mdcFoundation . handleClick ( ) ;
88- }
89+ @internalProperty ( ) protected shouldRenderRipple = false ;
90+
91+ @queryAsync ( 'mwc-ripple' ) ripple ! : Promise < Ripple | null > ;
92+
93+ private rippleElement : Ripple | null = null ;
8994
9095 protected createRenderRoot ( ) {
9196 return this . attachShadow ( { mode : 'open' , delegatesFocus : true } ) ;
@@ -123,25 +128,28 @@ export class TabBase extends BaseElement {
123128 < span class ="mdc-tab__text-label "> ${ this . label } </ span > ` ;
124129 }
125130
126- const rippleDirective = ripple ( {
127- interactionNode : this ,
128- unbounded : false ,
129- } ) ;
130-
131131 return html `
132132 < button
133- @click ="${ this . _handleClick } "
133+ @click ="${ this . handleClick } "
134134 class ="mdc-tab ${ classMap ( classes ) } "
135135 role ="tab "
136136 aria-selected ="false "
137- tabindex ="-1 ">
137+ tabindex ="-1 "
138+ @focus ="${ this . focus } "
139+ @blur ="${ this . handleBlur } "
140+ @mousedown ="${ this . handleRippleMouseDown } "
141+ @mouseenter ="${ this . handleRippleMouseEnter } "
142+ @mouseleave ="${ this . handleRippleMouseLeave } "
143+ @touchstart ="${ this . handleRippleTouchStart } "
144+ @touchend ="${ this . handleRippleDeactivate } "
145+ @touchcancel ="${ this . handleRippleDeactivate } ">
138146 < span class ="mdc-tab__content ">
139147 ${ iconTemplate }
140148 ${ labelTemplate }
141149 ${ this . isMinWidthIndicator ? this . renderIndicator ( ) : '' }
142150 </ span >
143151 ${ this . isMinWidthIndicator ? '' : this . renderIndicator ( ) }
144- < span class =" mdc-tab__ripple " .ripple =" ${ rippleDirective } " > </ span >
152+ ${ this . renderRipple ( ) }
145153 </ button > ` ;
146154 }
147155
@@ -151,6 +159,14 @@ export class TabBase extends BaseElement {
151159 .fade ="${ this . isFadingIndicator } "> </ mwc-tab-indicator > ` ;
152160 }
153161
162+ // TODO(dfreedm): Make this use selected as a param after Polymer/internal#739
163+ /** @soyCompatible */
164+ protected renderRipple ( ) {
165+ return this . shouldRenderRipple ? html `
166+ < mwc-ripple primary > </ mwc-ripple >
167+ ` :
168+ '' ;
169+ }
154170
155171 protected createAdapter ( ) : MDCTabAdapter {
156172 return {
@@ -221,5 +237,65 @@ export class TabBase extends BaseElement {
221237 // NOTE: needed only for ShadyDOM where delegatesFocus is not implemented
222238 focus ( ) {
223239 this . mdcRoot . focus ( ) ;
240+ this . handleFocus ( ) ;
241+ }
242+
243+ protected rippleHandlers : RippleHandlers = new RippleHandlers ( ( ) => {
244+ this . shouldRenderRipple = true ;
245+ this . ripple . then ( ( v ) => this . rippleElement = v ) ;
246+ return this . ripple ;
247+ } ) ;
248+
249+ private handleClick ( ) {
250+ this . handleFocus ( ) ;
251+ this . mdcFoundation . handleClick ( ) ;
252+ }
253+
254+ private handleFocus ( ) {
255+ this . handleRippleFocus ( ) ;
256+ }
257+
258+ private handleBlur ( ) {
259+ this . handleRippleBlur ( ) ;
260+ }
261+
262+ protected handleRippleMouseDown ( event : Event ) {
263+ const onUp = ( ) => {
264+ window . removeEventListener ( 'mouseup' , onUp ) ;
265+
266+ this . handleRippleDeactivate ( ) ;
267+ } ;
268+
269+ window . addEventListener ( 'mouseup' , onUp ) ;
270+ this . rippleHandlers . startPress ( event ) ;
271+ }
272+
273+ @eventOptions ( { passive : true } )
274+ protected handleRippleTouchStart ( event : Event ) {
275+ this . rippleHandlers . startPress ( event ) ;
276+ }
277+
278+ protected handleRippleDeactivate ( ) {
279+ this . rippleHandlers . endPress ( ) ;
280+ }
281+
282+ protected handleRippleMouseEnter ( ) {
283+ this . rippleHandlers . startHover ( ) ;
284+ }
285+
286+ protected handleRippleMouseLeave ( ) {
287+ this . rippleHandlers . endHover ( ) ;
288+ }
289+
290+ protected handleRippleFocus ( ) {
291+ this . rippleHandlers . startFocus ( ) ;
292+ }
293+
294+ protected handleRippleBlur ( ) {
295+ this . rippleHandlers . endFocus ( ) ;
296+ }
297+
298+ get isRippleActive ( ) {
299+ return this . rippleElement ?. isActive || false ;
224300 }
225301}
0 commit comments