diff --git a/.gitignore b/.gitignore
index efb74d4..6f801c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ npm-debug.log
.Trashes
ehthumbs.db
Thumbs.db
+.idea/
diff --git a/README.md b/README.md
index b98097f..d56f6bc 100644
--- a/README.md
+++ b/README.md
@@ -41,10 +41,11 @@ All pointer events are supported:
`onPointerMove`, `onPointerDown`, `onPointerUp`, `onPointerOver`, `onPointerOut`, `onPointerEnter`, `onPointerLeave`, `onPointerCancel`
## Additional Props
-`` accepts two special non-pointer event props:
+`` accepts special non-pointer event props:
- `tagName [string = 'div']` - If you don't want a `
` to be rendered, you can pass any valid element type and it will be rendered instead.
- `touchAction [string = 'auto']` - When used with PEP in a browser that doesn't support pointer events, chances are the CSS property `touch-action` also isn't supported. PEP therefore supports a `touch-action` _attribute_, and this prop allows setting that in a fully declarative manner. You can read more about the PEP attribute [on its repo](https://github.com/jquery/PEP#polyfill-limitations).
+- `elementRef [function]` - Provides the generated element to a parent component. (optional)
## Example
[Here's a CodePen using Pointable](http://codepen.io/MillerTime/pen/QKaLky/) that allows toggling between pointer and mouse events, using the same components.
diff --git a/package.json b/package.json
index d56b725..58659cc 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"scripts": {
"build": "babel src -d lib",
"test": "jest",
+ "test:watch": "jest --watch",
"prepublish": "npm test && npm run build",
"release": "np"
},
@@ -57,7 +58,8 @@
"jest": "^20.0.1",
"np": "^2.14.1",
"prop-types": "^15.5.10",
- "react": "^15.5.4"
+ "react": "^15.5.4",
+ "react-test-renderer": "^15.5.4"
},
"peerDependencies": {
"react": "^15.5.0",
diff --git a/src/index.jsx b/src/index.jsx
index af90b4a..ef6b2e5 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -25,6 +25,11 @@ const pointerEventProps = Object.keys(pointerEventMap);
// Component with pointer events enabled (specially made for Pointer Events Polyfill)
class Pointable extends React.Component {
+ constructor() {
+ super();
+ this.setRef = this.setRef.bind(this);
+ }
+
// When component mounts, check for pointer event listeners in props and register them manually.
componentDidMount() {
initNodeWithPE(this.pointableNode, this.props);
@@ -35,6 +40,13 @@ class Pointable extends React.Component {
updateNodeWithPE(this.pointableNode, prevProps, this.props);
}
+ setRef(node) {
+ this.pointableNode = node;
+ if(this.props.elementRef) {
+ this.props.elementRef(node);
+ }
+ };
+
render() {
// Collect unused props to pass along to rendered node.
// This could be done simply with lodash, but avoiding the extra dependency here isn't difficult.
@@ -47,11 +59,12 @@ class Pointable extends React.Component {
delete otherProps.children;
delete otherProps.tagName;
delete otherProps.touchAction;
+ delete otherProps.elementRef;
const El = this.props.tagName;
return (
- this.pointableNode = node} {...otherProps}>
+
{this.props.children}
);
@@ -62,6 +75,7 @@ class Pointable extends React.Component {
Pointable.propTypes = {
tagName: PropTypes.string.isRequired,
touchAction: PropTypes.oneOf(['auto', 'none', 'pan-x', 'pan-y', 'manipulation']).isRequired,
+ elementRef: PropTypes.func,
onPointerMove: PropTypes.func,
onPointerDown: PropTypes.func,
onPointerUp: PropTypes.func,
diff --git a/test/component.test.js b/test/component.test.js
new file mode 100644
index 0000000..71aae82
--- /dev/null
+++ b/test/component.test.js
@@ -0,0 +1,110 @@
+import React from 'react';
+import renderer from 'react-test-renderer';
+import Pointable from "../src";
+
+let addEventListener;
+let setAttribute;
+
+function createNodeMock(element) {
+ if (element.type === 'div') {
+ return {
+ addEventListener,
+ setAttribute
+ };
+ }
+ return null;
+}
+
+const rendererOptions = {createNodeMock};
+
+describe("component", () => {
+
+ beforeEach(() => {
+ addEventListener = jest.fn();
+ setAttribute = jest.fn();
+ });
+
+ it("renders", () => {
+ const component = renderer.create(
+ ,
+ rendererOptions
+ );
+ const tree = component.toJSON();
+ expect(tree).toEqual({
+ "type": "div",
+ "props": {},
+ "children": null
+ });
+ expect(addEventListener).not.toHaveBeenCalled();
+ expect(setAttribute).not.toHaveBeenCalled();
+ });
+
+ it("renders with element type", () => {
+ const component = renderer.create(
+ ,
+ rendererOptions
+ );
+ const tree = component.toJSON();
+ expect(tree).toEqual({
+ "type": "section",
+ "props": {},
+ "children": null
+ });
+ expect(addEventListener).not.toHaveBeenCalled();
+ expect(setAttribute).not.toHaveBeenCalled();
+ });
+
+ it("renders with touch action", () => {
+ const onPointerMove = () => {};
+ const component = renderer.create(
+ ,
+ rendererOptions
+ );
+ const tree = component.toJSON();
+ expect(tree).toEqual({
+ "type": "div",
+ "props": {},
+ "children": null
+ });
+ expect(addEventListener).toHaveBeenCalledWith("pointermove", onPointerMove);
+ expect(setAttribute).toHaveBeenCalledWith('touch-action', 'auto');
+ });
+
+ it("passes ref to parent", () => {
+ const elementRef = jest.fn();
+ const ParentComponent = (props) => (
+
+ );
+ const component = renderer.create(
+ ,
+ rendererOptions
+ );
+ expect(elementRef).toHaveBeenCalled();
+ expect(addEventListener).not.toHaveBeenCalled();
+ expect(setAttribute).not.toHaveBeenCalled();
+ });
+
+ [
+ 'onPointerMove',
+ 'onPointerDown',
+ 'onPointerUp',
+ 'onPointerOver',
+ 'onPointerOut',
+ 'onPointerEnter',
+ 'onPointerLeave',
+ 'onPointerCancel'
+ ].forEach((evtName) => {
+ it(`adds event listener for ${evtName}`, () => {
+ const domEventName = evtName.substr(2).toLowerCase();
+ const handler = () => {};
+ const pointableProps = {
+ [evtName]: handler
+ };
+ const component = renderer.create(
+ ,
+ rendererOptions
+ );
+ expect(addEventListener).toHaveBeenCalledWith(domEventName, handler);
+ });
+ });
+});