Skip to content

Commit

Permalink
Use ripple renderer without MatRipple
Browse files Browse the repository at this point in the history
  • Loading branch information
devversion committed Dec 9, 2017
1 parent 3274e49 commit 2f972c6
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 37 deletions.
6 changes: 3 additions & 3 deletions src/lib/core/ripple/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
28 changes: 20 additions & 8 deletions src/lib/core/ripple/ripple-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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));
Expand All @@ -184,23 +196,23 @@ 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.
this._lastTouchStartEvent = Date.now();
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);
}
}

Expand All @@ -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);
Expand Down
13 changes: 9 additions & 4 deletions src/lib/core/ripple/ripple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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. */
Expand All @@ -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) {
Expand Down
51 changes: 29 additions & 22 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -171,15 +173,16 @@ 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`.
*/
@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()',
Expand All @@ -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()
Expand All @@ -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,
Expand All @@ -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();
}
}

0 comments on commit 2f972c6

Please sign in to comment.