Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Pointer Events #12507

Merged
merged 2 commits into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions fixtures/dom/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class Header extends React.Component {
<option value="/event-pooling">Event Pooling</option>
<option value="/custom-elements">Custom Elements</option>
<option value="/media-events">Media Events</option>
<option value="/pointer-events">Pointer Events</option>
</select>
</label>
<label htmlFor="react_version">
Expand Down
3 changes: 3 additions & 0 deletions fixtures/dom/src/components/fixtures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ErrorHandling from './error-handling';
import EventPooling from './event-pooling';
import CustomElementFixtures from './custom-elements';
import MediaEventsFixtures from './media-events';
import PointerEventsFixtures from './pointer-events';

const React = window.React;

Expand Down Expand Up @@ -46,6 +47,8 @@ function FixturesPage() {
return <CustomElementFixtures />;
case '/media-events':
return <MediaEventsFixtures />;
case '/pointer-events':
return <PointerEventsFixtures />;
default:
return <p>Please select a test fixture.</p>;
}
Expand Down
90 changes: 90 additions & 0 deletions fixtures/dom/src/components/fixtures/pointer-events/drag-box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const React = window.React;

const CIRCLE_SIZE = 80;

class DragBox extends React.Component {
state = {
hasCapture: false,
circleLeft: 80,
circleTop: 80,
};
isDragging = false;
previousLeft = 0;
previousTop = 0;

onDown = event => {
this.isDragging = true;
event.target.setPointerCapture(event.pointerId);

// We store the initial coordinates to be able to calculate the changes
// later on.
this.extractPositionDelta(event);
};

onMove = event => {
if (!this.isDragging) {
return;
}
const {left, top} = this.extractPositionDelta(event);

this.setState(({circleLeft, circleTop}) => ({
circleLeft: circleLeft + left,
circleTop: circleTop + top,
}));
};

onUp = event => (this.isDragging = false);
onGotCapture = event => this.setState({hasCapture: true});
onLostCapture = event => this.setState({hasCapture: false});

extractPositionDelta = event => {
const left = event.pageX;
const top = event.pageY;
const delta = {
left: left - this.previousLeft,
top: top - this.previousTop,
};
this.previousLeft = left;
this.previousTop = top;
return delta;
};

render() {
const {hasCapture, circleLeft, circleTop} = this.state;

const boxStyle = {
border: '1px solid #d9d9d9',
margin: '10px 0 20px',
minHeight: 400,
width: '100%',
position: 'relative',
};

const circleStyle = {
width: CIRCLE_SIZE,
height: CIRCLE_SIZE,
borderRadius: CIRCLE_SIZE / 2,
position: 'absolute',
left: circleLeft,
top: circleTop,
backgroundColor: hasCapture ? 'blue' : 'green',
touchAction: 'none',
};

return (
<div style={boxStyle}>
<div
style={circleStyle}
onPointerDown={this.onDown}
onPointerMove={this.onMove}
onPointerUp={this.onUp}
onPointerCancel={this.onUp}
onGotPointerCapture={this.onGotCapture}
onLostPointerCapture={this.onLostCapture}
/>
</div>
);
}
}

export default DragBox;
25 changes: 25 additions & 0 deletions fixtures/dom/src/components/fixtures/pointer-events/drag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import TestCase from '../../TestCase';
import DragBox from './drag-box';

const React = window.React;

class Drag extends React.Component {
render() {
return (
<TestCase title="Drag" description="">
<TestCase.Steps>
<li>Drag the circle below with any pointer tool</li>
</TestCase.Steps>

<TestCase.ExpectedResult>
While dragging, the circle must have turn blue to indicate that a
pointer capture was received.
</TestCase.ExpectedResult>

<DragBox />
</TestCase>
);
}
}

export default Drag;
34 changes: 34 additions & 0 deletions fixtures/dom/src/components/fixtures/pointer-events/hover-box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const React = window.React;

class DrawBox extends React.Component {
render() {
const boxStyle = {
border: '1px solid #d9d9d9',
margin: '10px 0 20px',
padding: '20px 20px',
touchAction: 'none',
};

const obstacleStyle = {
border: '1px solid #d9d9d9',
width: '25%',
height: '200px',
margin: '12.5%',
display: 'inline-block',
};

return (
<div
style={boxStyle}
onPointerOver={this.props.onOver}
onPointerOut={this.props.onOut}
onPointerEnter={this.props.onEnter}
onPointerLeave={this.props.onLeave}>
<div style={obstacleStyle} />
<div style={obstacleStyle} />
</div>
);
}
}

export default DrawBox;
51 changes: 51 additions & 0 deletions fixtures/dom/src/components/fixtures/pointer-events/hover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import TestCase from '../../TestCase';
import HoverBox from './hover-box';

const React = window.React;

class Hover extends React.Component {
state = {
overs: 0,
outs: 0,
enters: 0,
leaves: 0,
};

onOver = () => this.setState({overs: this.state.overs + 1});
onOut = () => this.setState({outs: this.state.outs + 1});
onEnter = () => this.setState({enters: this.state.enters + 1});
onLeave = () => this.setState({leaves: this.state.leaves + 1});

render() {
const {overs, outs, enters, leaves} = this.state;

return (
<TestCase title="Hover" description="">
<TestCase.Steps>
<li>Hover over the above box and the obstacles</li>
</TestCase.Steps>

<TestCase.ExpectedResult>
Overs and outs should increase when moving over the obstacles but
enters and leaves should not.
</TestCase.ExpectedResult>

<HoverBox
onOver={this.onOver}
onOut={this.onOut}
onEnter={this.onEnter}
onLeave={this.onLeave}
/>

<p>
Pointer Overs: <b>{overs}</b> <br />
Pointer Outs: <b>{outs}</b> <br />
Pointer Enters: <b>{enters}</b> <br />
Pointer Leaves: <b>{leaves}</b> <br />
</p>
</TestCase>
);
}
}

export default Hover;
20 changes: 20 additions & 0 deletions fixtures/dom/src/components/fixtures/pointer-events/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import FixtureSet from '../../FixtureSet';
import Drag from './drag';
import Hover from './hover';

const React = window.React;

class PointerEvents extends React.Component {
render() {
return (
<FixtureSet
title="Pointer Events"
description="Pointer Events are not supported in every browser. The examples below might not work in every browser. To test pointer events, make sure to use Google Chrome, Firefox, Internet Explorer, or Edge.">
<Drag />
<Hover />
</FixtureSet>
);
}
}

export default PointerEvents;
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Array [
"ended",
"error",
"focus",
"gotPointerCapture",
"input",
"invalid",
"keyDown",
Expand All @@ -44,6 +45,7 @@ Array [
"loadStart",
"loadedData",
"loadedMetadata",
"lostPointerCapture",
"mouseDown",
"mouseEnter",
"mouseLeave",
Expand All @@ -55,6 +57,14 @@ Array [
"pause",
"play",
"playing",
"pointerCancel",
"pointerDown",
"pointerEnter",
"pointerLeave",
"pointerMove",
"pointerOut",
"pointerOver",
"pointerUp",
"progress",
"rateChange",
"reset",
Expand Down
26 changes: 26 additions & 0 deletions packages/react-dom/src/events/DOMTopLevelEventTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ export const TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted');
export const TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended');
export const TOP_ERROR = unsafeCastStringToDOMTopLevelType('error');
export const TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus');
export const TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType(
'gotpointercapture',
);
export const TOP_INPUT = unsafeCastStringToDOMTopLevelType('input');
export const TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid');
export const TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown');
Expand All @@ -83,6 +86,9 @@ export const TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata');
export const TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType(
'loadedmetadata',
);
export const TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType(
'lostpointercapture',
);
export const TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown');
export const TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove');
export const TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout');
Expand All @@ -92,6 +98,26 @@ export const TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste');
export const TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause');
export const TOP_PLAY = unsafeCastStringToDOMTopLevelType('play');
export const TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing');
export const TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType(
'pointercancel',
);
export const TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType(
'pointerdown',
);
export const TOP_POINTER_ENTER = unsafeCastStringToDOMTopLevelType(
'pointerenter',
);
export const TOP_POINTER_LEAVE = unsafeCastStringToDOMTopLevelType(
'pointerleave',
);
export const TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType(
'pointermove',
);
export const TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout');
export const TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType(
'pointerover',
);
export const TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup');
export const TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress');
export const TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange');
export const TOP_RESET = unsafeCastStringToDOMTopLevelType('reset');
Expand Down