Skip to content

Commit

Permalink
[added] getPointerEventStreamsFromElement(element)
Browse files Browse the repository at this point in the history
Summary:
This is pretty cool, because it lets us support Chrome and Safari; touch and mouse; with a single stream of events and no reliance on polyfills!

Closes #212

Reviewers: O2 Material Motion, O3 Material JavaScript platform reviewers, #material_motion, featherless

Reviewed By: O2 Material Motion, #material_motion, featherless

Subscribers: featherless

Tags: #material_motion

Differential Revision: http://codereview.cc/D3122
  • Loading branch information
appsforartists committed Apr 27, 2017
1 parent 8d9a3d3 commit 8ed8ac5
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/core/src/interactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
* under the License.
*/

export * from './Draggable';
export { default as Draggable } from './Draggable';

export * from './Spring';
export { default as Spring } from './Spring';

Expand Down
1 change: 1 addition & 0 deletions packages/demos-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"material-motion-experimental-addons": "0.0.0",
"material-motion-springs-rebound": "0.0.0",
"material-motion": "0.0.0",
"material-motion-views-dom": "0.0.0",
"material-motion-views-react": "0.0.0",
"react": "15.4.1",
"react-dom": "15.4.1",
Expand Down
1 change: 0 additions & 1 deletion packages/demos-react/site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
<script>
[
[Object.entries, 'https://unpkg.com/babel-polyfill@6.16.0/dist/polyfill.min.js'],
[window.PointerEvent, 'https://unpkg.com/pepjs@0.4.2/dist/pep.min.js'],
].forEach(
function ([test, polyfill]) {
if (!test) {
Expand Down
135 changes: 135 additions & 0 deletions packages/demos-react/src/QuickiePointerEventTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/** @license
* Copyright 2016 - present The Material Motion Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

import * as React from 'react';

import {
Draggable,
GestureRecognitionState,
MotionObservable,
Subscription,
dragSystem,
} from 'material-motion';

import {
getPointerEventStreamsFromElement,
} from 'material-motion-views-dom';

export class QuickiePointerEventTest extends React.Component {
state = {
x: 0,
y: 0,
state: GestureRecognitionState.POSSIBLE,
velocity: {
x: 0,
y: 0,
},
};

testEvents = (element: Element) => {
let subscriptions: Array<Subscription> = [];

if (element) {
const draggable = new Draggable(
getPointerEventStreamsFromElement(element)
);

const drag$ = dragSystem(draggable);
const velocity$ = drag$.velocity(
MotionObservable.from(draggable.state)._filter(
state => state === GestureRecognitionState.RECOGNIZED
)
);

subscriptions = [
drag$.subscribe(this.setState.bind(this)),
velocity$.subscribe(
(velocity: { x: number, y: number }) => this.setState({ velocity })
),
draggable.state.subscribe(
(state: GestureRecognitionState) => {
this.setState({ state });

if (state === GestureRecognitionState.RECOGNIZED) {
this.setState({
x: 0,
y: 0,
});
}
}
),
];

} else {
subscriptions.forEach(subscription => subscription.unsubscribe());
}
}

render = () => {
const {
x,
y,
velocity,
state,
} = this.state;

return (
<div>
<div
style = {
{
position: 'fixed',
top: 150,
left: 50,
borderRadius: 28,
width: 56,
height: 56,
backgroundColor: 'blue',
transform: `translate(${ x }px, ${ y }px)`,
touchAction: 'none',
}
}
ref = { this.testEvents }
/>
<table
style = {
{
padding: 16,
}
}
>
<tr>
<td>
State
</td>
<td>
{ GestureRecognitionState[state] }
</td>
</tr>
<tr>
<td>
Last recorded velocity
</td>
<td>
{ velocity.x }, { velocity.y }
</td>
</tr>
</table>
</div>
);
}
}
export default QuickiePointerEventTest;
6 changes: 6 additions & 0 deletions packages/demos-react/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Miss from 'react-router/Miss';
import Router from 'react-router/BrowserRouter';

// import ExampleMain from './example/components/ExampleMain';
import QuickiePointerEventTest from './QuickiePointerEventTest';

// To add a new demo, import the correct component above and add it to the links
// list below. Everything else is automatic.
Expand All @@ -31,6 +32,11 @@ const links = [
// name: 'ExampleMain',
// component: ExampleMain,
// },
{
href: '/pointer-events/',
name: 'QuickiePointerEventTest',
component: QuickiePointerEventTest,
},
];

function Links() {
Expand Down
49 changes: 49 additions & 0 deletions packages/views-dom/src/getEventStreamFromElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/** @license
* Copyright 2016 - present The Material Motion Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

import {
MotionObservable,
Observer,
} from 'material-motion';

// Passive event feature detection from
// https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
let supportsPassiveListeners = false;
try {
const eventOptions: any = Object.defineProperty({}, 'passive', {
get() {
supportsPassiveListeners = true;
}
});
window.addEventListener("test", () => {}, eventOptions);
} catch (e) {}

const eventListenerOptions = supportsPassiveListeners
? { passive: true }
: false;

export function getEventStreamFromElement(type: string, element: Element): MotionObservable<Event> {
return new MotionObservable(
(observer: Observer<Event>) => {
element.addEventListener(type, observer.next, eventListenerOptions);

return () => {
element.removeEventListener(type, observer.next, eventListenerOptions);
}
}
);
}
export default getEventStreamFromElement;
63 changes: 63 additions & 0 deletions packages/views-dom/src/getPointerEventStreamsFromElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/** @license
* Copyright 2016 - present The Material Motion Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

import {
MotionObservable,
PartialPointerEvent,
} from 'material-motion';

import {
convertTouchEventsToPointerEvents,
} from './convertTouchEventsToPointerEvents';

import {
getEventStreamFromElement,
} from './getEventStreamFromElement';

export type PointerEventStreams = {
down$: MotionObservable<PartialPointerEvent>,
move$: MotionObservable<PartialPointerEvent>,
up$: MotionObservable<PartialPointerEvent>,
};

export function getPointerEventStreamsFromElement(element: Element): PointerEventStreams {
if (window.PointerEvent) {
return {
down$: getEventStreamFromElement('pointerdown', element),
move$: getEventStreamFromElement('pointermove', element),
up$: getEventStreamFromElement('pointerup', element),
};
} else {
return {
down$: getEventStreamFromElement('mousedown', element).merge(
convertTouchEventsToPointerEvents(
getEventStreamFromElement('touchstart', element)
)
),
move$: getEventStreamFromElement('mousemove', element).merge(
convertTouchEventsToPointerEvents(
getEventStreamFromElement('touchmove', element)
)
),
up$: getEventStreamFromElement('mouseup', element).merge(
convertTouchEventsToPointerEvents(
getEventStreamFromElement('touchend', element)
)
),
};
}
}
export default getPointerEventStreamsFromElement;
9 changes: 9 additions & 0 deletions packages/views-dom/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
* under the License.
*/

export * from './convertTouchEventsToPointerEvents';
export { default as convertTouchEventsToPointerEvents } from './convertTouchEventsToPointerEvents';

export * from './createMotionElementFromDOMNode';
export { default as createMotionElementFromDOMNode } from './createMotionElementFromDOMNode';

export * from './getEventStreamFromElement';
export { default as getEventStreamFromElement } from './getEventStreamFromElement';

export * from './getPointerEventStreamsFromElement';
export { default as getPointerEventStreamsFromElement } from './getPointerEventStreamsFromElement';

0 comments on commit 8ed8ac5

Please sign in to comment.