From 2f972c6db23b38546f0d9a8ca7c80ca019d33465 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Sat, 9 Dec 2017 13:13:31 +0100 Subject: [PATCH] Use ripple renderer without MatRipple --- src/lib/core/ripple/index.ts | 6 +-- src/lib/core/ripple/ripple-renderer.ts | 28 ++++++++++---- src/lib/core/ripple/ripple.ts | 13 +++++-- src/lib/tabs/tab-nav-bar/tab-nav-bar.ts | 51 ++++++++++++++----------- 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/lib/core/ripple/index.ts b/src/lib/core/ripple/index.ts index 94da47051775..d76f94314e58 100644 --- a/src/lib/core/ripple/index.ts +++ b/src/lib/core/ripple/index.ts @@ -11,9 +11,9 @@ import {PlatformModule} from '@angular/cdk/platform'; import {MatCommonModule} from '../common-behaviors/common-module'; import {MatRipple} from './ripple'; -export {MatRipple, RippleGlobalOptions, MAT_RIPPLE_GLOBAL_OPTIONS} from './ripple'; -export {RippleRef, RippleState} from './ripple-ref'; -export {RippleConfig, RIPPLE_FADE_IN_DURATION, RIPPLE_FADE_OUT_DURATION} from './ripple-renderer'; +export * from './ripple'; +export * from './ripple-ref'; +export * from './ripple-renderer'; @NgModule({ imports: [MatCommonModule, PlatformModule], diff --git a/src/lib/core/ripple/ripple-renderer.ts b/src/lib/core/ripple/ripple-renderer.ts index 2a3fc057b032..cf66bf122f37 100644 --- a/src/lib/core/ripple/ripple-renderer.ts +++ b/src/lib/core/ripple/ripple-renderer.ts @@ -8,7 +8,6 @@ import {ElementRef, NgZone} from '@angular/core'; import {Platform} from '@angular/cdk/platform'; -import {MatRipple} from './ripple'; import {RippleRef, RippleState} from './ripple-ref'; /** Fade-in duration for the ripples. Can be modified with the speedFactor option. */ @@ -31,6 +30,19 @@ export type RippleConfig = { persistent?: boolean; }; +/** + * Interface that describes the target for launching ripples. + * It defines the ripple configuration and disabled state for interaction ripples. + * @docs-private + */ +export interface RippleTarget { + /** Configuration for ripples that are launched on pointer down. */ + rippleConfig: RippleConfig; + + /** Whether ripples on pointer down should be disabled. */ + rippleDisabled: boolean; +} + /** * Helper service that performs DOM manipulations. Not intended to be used outside this module. * The constructor takes a reference to the ripple directive's host element and a map of DOM @@ -58,7 +70,7 @@ export class RippleRenderer { /** Time in milliseconds when the last touchstart event happened. */ private _lastTouchStartEvent: number; - constructor(private _ripple: MatRipple, + constructor(private _target: RippleTarget, private _ngZone: NgZone, elementRef: ElementRef, platform: Platform) { @@ -170,7 +182,7 @@ export class RippleRenderer { } // Remove all previously registered event listeners from the trigger element. - this._removeTriggerListeners(); + this._removeTriggerEvents(); this._ngZone.runOutsideAngular(() => { this._triggerEvents.forEach((fn, type) => element.addEventListener(type, fn)); @@ -184,15 +196,15 @@ export class RippleRenderer { const isSyntheticEvent = this._lastTouchStartEvent && Date.now() < this._lastTouchStartEvent + IGNORE_MOUSE_EVENTS_TIMEOUT; - if (!this._ripple.disabled && !isSyntheticEvent) { + if (!this._target.rippleDisabled && !isSyntheticEvent) { this._isPointerDown = true; - this.fadeInRipple(event.clientX, event.clientY, this._ripple.rippleConfig); + this.fadeInRipple(event.clientX, event.clientY, this._target.rippleConfig); } } /** Function being called whenever the trigger is being pressed using touch. */ private onTouchStart(event: TouchEvent) { - if (!this._ripple.disabled) { + if (!this._target.rippleDisabled) { // Some browsers fire mouse events after a `touchstart` event. Those synthetic mouse // events will launch a second ripple if we don't ignore mouse events for a specific // time after a touchstart event. @@ -200,7 +212,7 @@ export class RippleRenderer { this._isPointerDown = true; this.fadeInRipple( - event.touches[0].clientX, event.touches[0].clientY, this._ripple.rippleConfig); + event.touches[0].clientX, event.touches[0].clientY, this._target.rippleConfig); } } @@ -226,7 +238,7 @@ export class RippleRenderer { } /** Removes previously registered event listeners from the trigger element. */ - _removeTriggerListeners() { + _removeTriggerEvents() { if (this._triggerElement) { this._triggerEvents.forEach((fn, type) => { this._triggerElement!.removeEventListener(type, fn); diff --git a/src/lib/core/ripple/ripple.ts b/src/lib/core/ripple/ripple.ts index c4e8e5c70000..5a26091d10b7 100644 --- a/src/lib/core/ripple/ripple.ts +++ b/src/lib/core/ripple/ripple.ts @@ -19,7 +19,7 @@ import { Optional, } from '@angular/core'; import {RippleRef} from './ripple-ref'; -import {RippleConfig, RippleRenderer} from './ripple-renderer'; +import {RippleConfig, RippleRenderer, RippleTarget} from './ripple-renderer'; /** Configurable options for `matRipple`. */ export interface RippleGlobalOptions { @@ -49,7 +49,7 @@ export const MAT_RIPPLE_GLOBAL_OPTIONS = '[class.mat-ripple-unbounded]': 'unbounded' } }) -export class MatRipple implements OnInit, OnDestroy { +export class MatRipple implements OnInit, OnDestroy, RippleTarget { /** Custom color for all ripples. */ @Input('matRippleColor') color: string; @@ -82,7 +82,7 @@ export class MatRipple implements OnInit, OnDestroy { * by using the `launch()` method. */ @Input('matRippleDisabled') - get disabled() { return this._disabled || !!this._globalOptions.disabled; } + get disabled() { return this._disabled; } set disabled(value: boolean) { this._disabled = value; this._setupTriggerEventsIfEnabled(); @@ -125,7 +125,7 @@ export class MatRipple implements OnInit, OnDestroy { } ngOnDestroy() { - this._rippleRenderer._removeTriggerListeners(); + this._rippleRenderer._removeTriggerEvents(); } /** Launches a manual ripple at the specified position. */ @@ -148,6 +148,11 @@ export class MatRipple implements OnInit, OnDestroy { }; } + /** Whether ripples on pointer-down are disabled or not. */ + get rippleDisabled(): boolean { + return this.disabled || !!this._globalOptions.disabled; + } + /** Sets up the the trigger event listeners if ripples are enabled. */ private _setupTriggerEventsIfEnabled() { if (!this.disabled && this._isInitialized) { diff --git a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts index 175b942cd3f2..f45438e3ec69 100644 --- a/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts +++ b/src/lib/tabs/tab-nav-bar/tab-nav-bar.ts @@ -8,7 +8,6 @@ import {Directionality} from '@angular/cdk/bidi'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {Platform} from '@angular/cdk/platform'; -import {takeUntil} from 'rxjs/operators/takeUntil'; import {ViewportRuler} from '@angular/cdk/scrolling'; import { AfterContentInit, @@ -39,12 +38,15 @@ import { mixinColor, mixinDisabled, mixinDisableRipple, - mixinTabIndex, + mixinTabIndex, RippleConfig, RippleGlobalOptions, + RippleRenderer, + RippleTarget, ThemePalette, } from '@angular/material/core'; import {merge} from 'rxjs/observable/merge'; import {of as observableOf} from 'rxjs/observable/of'; +import {takeUntil} from 'rxjs/operators/takeUntil'; import {Subject} from 'rxjs/Subject'; import {MatInkBar} from '../ink-bar'; @@ -171,7 +173,8 @@ export class MatTabNav extends _MatTabNavMixinBase implements AfterContentInit, // Boilerplate for applying mixins to MatTabLink. export class MatTabLinkBase {} -export const _MatTabLinkMixinBase = mixinTabIndex(mixinDisabled(MatTabLinkBase)); +export const _MatTabLinkMixinBase = + mixinTabIndex(mixinDisableRipple(mixinDisabled(MatTabLinkBase))); /** * Link inside of a `mat-tab-nav-bar`. @@ -179,7 +182,7 @@ export const _MatTabLinkMixinBase = mixinTabIndex(mixinDisabled(MatTabLinkBase)) @Directive({ selector: '[mat-tab-link], [matTabLink]', exportAs: 'matTabLink', - inputs: ['disabled', 'tabIndex'], + inputs: ['disabled', 'disableRipple', 'tabIndex'], host: { 'class': 'mat-tab-link', '[attr.aria-disabled]': 'disabled.toString()', @@ -189,16 +192,13 @@ export const _MatTabLinkMixinBase = mixinTabIndex(mixinDisabled(MatTabLinkBase)) } }) export class MatTabLink extends _MatTabLinkMixinBase - implements OnDestroy, CanDisable, HasTabIndex { + implements OnDestroy, CanDisable, CanDisableRipple, HasTabIndex, RippleTarget { /** Whether the tab link is active or not. */ private _isActive: boolean = false; - /** Whether the ripples for this tab should be disabled or not. */ - private _disableRipple: boolean = false; - - /** Reference to the instance of the ripple for the tab link. */ - private _tabLinkRipple: MatRipple; + /** Reference to the RippleRenderer for the tab-link. */ + private _tabLinkRipple: RippleRenderer; /** Whether the link is active. */ @Input() @@ -210,11 +210,18 @@ export class MatTabLink extends _MatTabLinkMixinBase } } - /** Whether ripples should be disabled or not. */ - get disableRipple(): boolean { return this.disabled || this._disableRipple; } - set disableRipple(value: boolean) { - this._disableRipple = value; - this._tabLinkRipple.disabled = this.disableRipple; + /** + * Ripple configuration for ripples that are launched on pointer down. + * @docs-private + */ + rippleConfig: RippleConfig = {}; + + /** + * Whether ripples are disabled on interaction + * @docs-private + */ + get rippleDisabled(): boolean { + return this.disabled || this.disableRipple; } constructor(private _tabNavBar: MatTabNav, @@ -225,17 +232,17 @@ export class MatTabLink extends _MatTabLinkMixinBase @Attribute('tabindex') tabIndex: string) { super(); - // Manually create a ripple instance that uses the tab link element as trigger element. - // Notice that the lifecycle hooks for the ripple config won't be called anymore. - this._tabLinkRipple = new MatRipple(_elementRef, ngZone, platform, globalOptions); - this._tabLinkRipple.ngOnInit(); + this._tabLinkRipple = new RippleRenderer(this, ngZone, _elementRef, platform); + this._tabLinkRipple.setupTriggerEvents(_elementRef.nativeElement); this.tabIndex = parseInt(tabIndex) || 0; + + if (globalOptions) { + this.rippleConfig = {speedFactor: globalOptions.baseSpeedFactor}; + } } ngOnDestroy() { - // Manually call the ngOnDestroy lifecycle hook of the ripple instance because it won't be - // called automatically since its instance is not created by Angular. - this._tabLinkRipple.ngOnDestroy(); + this._tabLinkRipple._removeTriggerEvents(); } }