feat: make hammerjs optional (#2280)

* feat: make hammerjs optional

Makes HammerJS and logs a warning if it's missing, instead of crashing the app.

* Rename the MdHammerEvent interface.

* Replace the HammerJS annotations with stripped-down alternatives.

* Remove "hammerjs" from the "types" config.
This commit is contained in:
Kristiyan Kostadinov
2016-12-20 23:36:25 +02:00
committed by Jeremy Elbourn
parent d076bd319f
commit 28691ca780
10 changed files with 80 additions and 24 deletions
+3 -1
View File
@@ -32,11 +32,13 @@
"@angular/http": "^2.2.0",
"@angular/platform-browser": "^2.2.0",
"core-js": "^2.4.1",
"hammerjs": "^2.0.8",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.38",
"zone.js": "^0.6.23"
},
"optionalDependencies": {
"hammerjs": "^2.0.8"
},
"devDependencies": {
"@angular/compiler-cli": "^2.2.0",
"@angular/platform-browser-dynamic": "^2.2.0",
+1 -4
View File
@@ -21,10 +21,7 @@
"@angular/material": [
"../../dist/@angular/material"
]
},
"types": [
"hammerjs"
]
}
},
"angularCompilerOptions": {
"genDir": "../../dist",
+1 -4
View File
@@ -22,10 +22,7 @@
"@angular/material": [
"../../dist/@angular/material"
]
},
"types": [
"hammerjs"
]
}
},
"angularCompilerOptions": {
"genDir": "../../dist",
+1
View File
@@ -50,6 +50,7 @@ export * from './overlay/position/connected-position';
// Gestures
export {GestureConfig} from './gestures/gesture-config';
export * from './gestures/gesture-annotations';
// Ripple
export {MdRipple, MdRippleModule} from './ripple/ripple';
@@ -0,0 +1,48 @@
/**
* Stripped-down HammerJS annotations to be used within Material, which are necessary,
* because HammerJS is an optional dependency. For the full annotations see:
* https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/hammerjs
*/
/** @docs-private */
export interface HammerInput {
preventDefault: () => {};
deltaX: number;
deltaY: number;
center: { x: number; y: number; };
}
/** @docs-private */
export interface HammerStatic {
new(element: HTMLElement | SVGElement, options?: any): HammerManager;
Pan: Recognizer;
Swipe: Recognizer;
Press: Recognizer;
}
/** @docs-private */
export interface Recognizer {
new(options?: any): Recognizer;
recognizeWith(otherRecognizer: Recognizer | string): Recognizer;
}
/** @docs-private */
export interface RecognizerStatic {
new(options?: any): Recognizer;
}
/** @docs-private */
export interface HammerInstance {
on(eventName: string, callback: Function): void;
off(eventName: string, callback: Function): void;
}
/** @docs-private */
export interface HammerManager {
add(recogniser: Recognizer | Recognizer[]): Recognizer;
set(options: any): HammerManager;
emit(event: string, data: any): void;
off(events: string, handler?: Function): void;
on(events: string, handler: Function): void;
}
+22 -9
View File
@@ -1,19 +1,32 @@
import {Injectable} from '@angular/core';
import {Injectable, isDevMode} from '@angular/core';
import {HammerGestureConfig} from '@angular/platform-browser';
import {HammerStatic, HammerInstance, Recognizer, RecognizerStatic} from './gesture-annotations';
/* Adjusts configuration of our gesture library, Hammer. */
@Injectable()
export class GestureConfig extends HammerGestureConfig {
private _hammer: HammerStatic = typeof window !== 'undefined' ? (window as any).Hammer : null;
/* List of new event names to add to the gesture support list */
events: string[] = [
events: string[] = this._hammer ? [
'longpress',
'slide',
'slidestart',
'slideend',
'slideright',
'slideleft'
];
] : [];
constructor() {
super();
if (!this._hammer && isDevMode()) {
console.warn(
'Could not find HammerJS. Certain Angular Material ' +
'components may not work correctly.'
);
}
}
/*
* Builds Hammer instance manually to add custom recognizers that match the Material Design spec.
@@ -28,12 +41,12 @@ export class GestureConfig extends HammerGestureConfig {
* TODO: Confirm threshold numbers with Material Design UX Team
* */
buildHammer(element: HTMLElement) {
const mc = new Hammer(element);
const mc = new this._hammer(element);
// Default Hammer Recognizers.
let pan = new Hammer.Pan();
let swipe = new Hammer.Swipe();
let press = new Hammer.Press();
let pan = new this._hammer.Pan();
let swipe = new this._hammer.Swipe();
let press = new this._hammer.Press();
// Notice that a HammerJS recognizer can only depend on one other recognizer once.
// Otherwise the previous `recognizeWith` will be dropped.
@@ -46,12 +59,12 @@ export class GestureConfig extends HammerGestureConfig {
// Add customized gestures to Hammer manager
mc.add([swipe, press, pan, slide, longpress]);
return mc;
return mc as HammerInstance;
}
/** Creates a new recognizer, without affecting the default recognizers of HammerJS */
private _createRecognizer(base: Recognizer, options: any, ...inheritances: Recognizer[]) {
let recognizer = new (<RecognizerStatic> base.constructor)(options);
let recognizer = new (base.constructor as RecognizerStatic)(options);
inheritances.push(base);
inheritances.forEach(item => recognizer.recognizeWith(item));
+1
View File
@@ -19,6 +19,7 @@ import {
applyCssTransform,
coerceBooleanProperty,
GestureConfig,
HammerInput,
DefaultStyleCompatibilityModeModule,
} from '../core';
import {Observable} from 'rxjs/Observable';
+1 -2
View File
@@ -14,11 +14,11 @@ import {NG_VALUE_ACCESSOR, ControlValueAccessor, FormsModule} from '@angular/for
import {HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
import {
GestureConfig,
HammerInput,
coerceBooleanProperty,
coerceNumberProperty,
DefaultStyleCompatibilityModeModule,
} from '../core';
import {Input as HammerInput} from 'hammerjs';
import {Dir} from '../core/rtl/dir';
import {CommonModule} from '@angular/common';
import {
@@ -32,7 +32,6 @@ import {
DOWN_ARROW,
} from '../core/keyboard/keycodes';
/**
* Visually, a 30px separation between tick marks looks best. This is very subjective but it is
* the default separation we chose.
+2 -2
View File
@@ -1,5 +1,5 @@
import {Injectable} from '@angular/core';
import {GestureConfig} from '../core';
import {GestureConfig, HammerManager} from '../core';
/**
* An extension of GestureConfig that exposes the underlying HammerManager instances.
@@ -17,7 +17,7 @@ export class TestGestureConfig extends GestureConfig {
* Create a mapping of Hammer instances to element so that events can be emitted during testing.
*/
buildHammer(element: HTMLElement) {
let mc = super.buildHammer(element);
let mc = super.buildHammer(element) as HammerManager;
if (this.hammerInstances.get(element)) {
this.hammerInstances.get(element).push(mc);
-2
View File
@@ -17,8 +17,6 @@
"stripInternal": false,
"typeRoots": [
"../../node_modules/@types"
],
"types": [
]
},
"exclude": [