├── .gitignore
├── .npmignore
├── README.md
├── Swiper.js
├── package.json
└── src
└── Swiper.jsx
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .module-cache/
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .module-cache/
2 | src/
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | react-swiper
2 | ================
3 |
4 | > Detects and triggers touch events for swiping such as onSwipeLeft, onSwipeDown, etc. with ReactJS
5 |
6 | ## Installation
7 |
8 | ```bash
9 | npm install --save react react-swiper
10 | ```
11 |
12 | ## Usage
13 |
14 | ### Example with defaults
15 |
16 | Creating an example component:
17 |
18 | ```javascript
19 | var React = require('react');
20 | var Swiper = require('react-swiper');
21 |
22 | React.initializeTouchEvents(true);
23 |
24 | var Example = React.createClass({
25 |
26 | render: function() {
27 | return (
28 |
29 | Hello world!
30 |
31 | );
32 | },
33 |
34 | handleLeftSwipe: function (e) {
35 | console.log(e);
36 | }
37 |
38 | });
39 |
40 | module.exports = Example;
41 | ```
42 |
43 | The `Swiper` component will render a `
` element by default, this can be changed either by providing the `tagName` property or the `component` property.
44 |
45 | ### Example with custom element
46 |
47 | Creating a Swiper link (i.e. a swipeable `` element):
48 |
49 | ```javascript
50 | var React = require('react');
51 | var Swiper = require('react-swiper');
52 |
53 | React.initializeTouchEvents(true);
54 |
55 | var Example = React.createClass({
56 |
57 | render: function() {
58 | return (
59 |
60 | Swipe or click me...
61 |
62 | );
63 | },
64 |
65 | handleSwipe: function (e) {
66 | console.log(e);
67 | }
68 |
69 | });
70 |
71 | module.exports = Example;
72 | ```
73 |
74 | ### Example with custom component
75 |
76 | Creating a Swiper from another component:
77 |
78 | ```javascript
79 | var React = require('react');
80 | var Swiper = require('react-swiper');
81 | var MyComponent = require('./my-component');
82 |
83 | React.initializeTouchEvents(true);
84 |
85 | var Example = React.createClass({
86 |
87 | render: function() {
88 | return (
89 |
90 | );
91 | },
92 |
93 | handleSwipe: function (e) {
94 | console.log(e);
95 | }
96 |
97 | });
98 |
99 | module.exports = Example;
100 | ```
101 |
102 | ## Properties
103 |
104 | ### `tagName`
105 |
106 | **Type** `String`
107 |
108 | **Default** `"div"`
109 |
110 |
111 | Specifies what type of element the `Swiper` component should be rendered as. See `component` below as well.
112 |
113 | ### `component`
114 |
115 | **Type** `ReactComponent`
116 |
117 | **Default** `undefined`
118 |
119 |
120 | Specifies what component `Swiper` should be rendered as. See `tagName` above as well. If both `tagName` and `component` are specified the later takes precedence.
121 |
122 | ### `onSwipe`
123 |
124 | **Type** `Function(event)`
125 |
126 | **Default** `undefined`
127 |
128 |
129 | If provided it's called on all swipes.
130 |
131 | Example `event`:
132 |
133 | ```javascript
134 | {
135 | type: String, // The type of swipe, e.g. "swipeLeft", "swipeUp" or "swipeDownRight"
136 | timeStampStart: Date, // Timestamp for when the swipe was initiated
137 | timeStampEnd: Date, // Timestamp for when the swipe was finished,
138 | initialTouch: Touch, // A Touch object for the initial touch position - https://developer.mozilla.org/en-US/docs/Web/API/Touch
139 | finalTouch: Touch, // A Touch object for the final touch position
140 | }
141 | ```
142 |
143 | ### `onSwipe`
144 |
145 | **Direction** `Up`, `UpRight`, `Right`, `DownRight`, `Down`, `DownLeft`, `Left` and `UpLeft`
146 |
147 | **Type** `Function(event)`
148 |
149 | **Default** `undefined`
150 |
151 |
152 | If provided it's called with a swipe event (see example in `onSwipe` above) for a swipe in the wanted direction.
153 | E.g. `onSwipeUp` is called for swipes in the up direction.
154 |
155 | ## `minSwipeLength`
156 |
157 | **Type** `Number`
158 |
159 | **Default** `75`
160 |
161 |
162 | The minimum swipe length that's required for a swipe event to be triggered.
163 |
164 | ## `moveThreshold`
165 |
166 | **Type** `Number`
167 |
168 | **Default** `10`
169 |
170 |
171 | The minimum move length in one direction to be considered as the swipe direction, this also affects the required velocity in which the swipe must occur.
172 |
173 |
174 | ## License
175 |
176 | MIT
177 |
--------------------------------------------------------------------------------
/Swiper.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jsx React.DOM
3 | */
4 |
5 | var React = require('react'),
6 | objectAssign = require('object-assign');
7 |
8 | var Swiper = React.createClass({displayName: 'Swiper',
9 | propTypes: {
10 | tagName: React.PropTypes.string,
11 | component: React.PropTypes.element,
12 | minSwipeLength: React.PropTypes.number,
13 | moveThreshold: React.PropTypes.number,
14 | onSwipe: React.PropTypes.func,
15 | onSwipeLeft: React.PropTypes.func,
16 | onSwipeUpLeft: React.PropTypes.func,
17 | onSwipeUp: React.PropTypes.func,
18 | onSwipeUpRight: React.PropTypes.func,
19 | onSwipeRight: React.PropTypes.func,
20 | onSwipeDownRight: React.PropTypes.func,
21 | onSwipeDown: React.PropTypes.func,
22 | onSwipeDownLeft: React.PropTypes.func
23 | },
24 |
25 | getDefaultProps: function() {
26 | return {
27 | tagName: 'div',
28 | minSwipeLength: 75,
29 | moveThreshold: 10
30 | };
31 | },
32 |
33 | getInitialState: function () {
34 | return {
35 | direction: null,
36 | initialTouch: null,
37 | touch: null,
38 | swipeStart: null
39 | };
40 | },
41 |
42 | render: function() {
43 | var Component = this.props.component || this.props.tagName;
44 | return (
45 | Component(Object.assign({}, this.props, {onTouchStart: this.handleTouchStart,
46 | onTouchEnd: this.handleTouchEnd,
47 | onTouchCancel: this.handleTouchEnd,
48 | onTouchMove: this.handleTouchMove}),
49 | this.props.children
50 | )
51 | );
52 | },
53 |
54 | handleTouchStart: function (e) {
55 | if (e.touches.length !== 1) {
56 | return;
57 | }
58 | this._initiateSwipe(e.touches[0]);
59 | },
60 |
61 | handleTouchEnd: function (e) {
62 | if (!this.state.direction) {
63 | return;
64 | }
65 | if (this._getSwipeLength(this.state.initialTouch) > this.props.minSwipeLength) {
66 | var method = this._getEventMethodName();
67 | var evt = {
68 | type: this._getEventTypeName(),
69 | timeStampStart: this.state.swipeStart,
70 | timeStampEnd: new Date(),
71 | initialTouch: this.state.initialTouch,
72 | finalTouch: this.state.touch
73 | };
74 | this.props.onSwipe && this.props.onSwipe(evt);
75 | this.props[method] && this.props[method](evt);
76 | e.preventDefault();
77 | }
78 | this._resetSwipe();
79 | },
80 |
81 | handleTouchMove: function (e) {
82 | if (e.touches.length !== 1 || !this.state.direction) {
83 | return;
84 | }
85 | var touch = e.touches[0];
86 | var direction = this._getSwipeDirection(touch);
87 | if (this._isSwipeDirectionUnchanged(direction)) {
88 | this._updateSwipe(direction, touch);
89 | e.preventDefault();
90 | return;
91 | }
92 | this._resetSwipe();
93 | },
94 |
95 | _initiateSwipe: function (touch) {
96 | this.setState({direction: {x: null, y: null}, initialTouch: touch, touch: touch, swipeStart: new Date()});
97 | },
98 |
99 | _resetSwipe: function () {
100 | this.setState(this.getInitialState());
101 | },
102 |
103 | _updateSwipe: function (direction, touch) {
104 | this.setState({direction:direction, touch:touch});
105 | },
106 |
107 | _getSwipeLength: function (touch) {
108 | return this._getSwipeLengthX(touch) + this._getSwipeLengthY(touch);
109 | },
110 |
111 | _getSwipeLengthX: function (touch) {
112 | return Math.abs(touch.pageX - this.state.touch.pageX);
113 | },
114 |
115 | _getSwipeLengthY: function (touch) {
116 | return Math.abs(touch.pageY - this.state.touch.pageY);
117 | },
118 |
119 | _getSwipeDirection: function (touch) {
120 | var dir = objectAssign({x: null, y: null}, this.state.direction);
121 | if (this._getSwipeLengthY(touch) > this.props.moveThreshold) {
122 | dir.y = this._getSwipeDirectionY(touch);
123 | }
124 | if (this._getSwipeLengthX(touch) > this.props.moveThreshold) {
125 | dir.x = this._getSwipeDirectionX(touch);
126 | }
127 | return dir;
128 | },
129 |
130 | _getSwipeDirectionX: function (touch) {
131 | return touch.pageX < this.state.touch.pageX ? 'Left' : 'Right';
132 | },
133 |
134 | _getSwipeDirectionY: function (touch) {
135 | return touch.pageY < this.state.touch.pageY ? 'Up' : 'Down';
136 | },
137 |
138 | _getSwipeDirectionName: function () {
139 | return (this.state.direction.y || '') + (this.state.direction.x || '');
140 | },
141 |
142 | _isSwipeDirectionUnchanged: function (direction) {
143 | return (!this.state.direction.x || this.state.direction.x === direction.x) &&
144 | (!this.state.direction.y || this.state.direction.y === direction.y);
145 | },
146 |
147 | _getEventMethodName: function () {
148 | return 'onSwipe' + this._getSwipeDirectionName();
149 | },
150 |
151 | _getEventTypeName: function () {
152 | return 'swipe' + this._getSwipeDirectionName();
153 | }
154 | });
155 |
156 | module.exports = Swiper;
157 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swiper",
3 | "version": "0.1.5",
4 | "description": "Detects and triggers touch events for swiping such as onSwipeLeft, onSwipeDown, etc. with ReactJS",
5 | "main": "Swiper.js",
6 | "scripts": {
7 | "build": "jsx --harmony -x jsx src/ ./"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/joakimbeng/react-swiper"
12 | },
13 | "keywords": [
14 | "react",
15 | "swipe",
16 | "touch",
17 | "event"
18 | ],
19 | "author": "Joakim Carlstein ",
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/joakimbeng/react-swiper/issues"
23 | },
24 | "homepage": "https://github.com/joakimbeng/react-swiper",
25 | "devDependencies": {
26 | "react-tools": "~0.11.2"
27 | },
28 | "dependencies": {
29 | "object-assign": "^2.0.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Swiper.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @jsx React.DOM
3 | */
4 |
5 | var React = require('react'),
6 | objectAssign = require('object-assign');
7 |
8 | var Swiper = React.createClass({
9 | propTypes: {
10 | tagName: React.PropTypes.string,
11 | component: React.PropTypes.element,
12 | minSwipeLength: React.PropTypes.number,
13 | moveThreshold: React.PropTypes.number,
14 | onSwipe: React.PropTypes.func,
15 | onSwipeLeft: React.PropTypes.func,
16 | onSwipeUpLeft: React.PropTypes.func,
17 | onSwipeUp: React.PropTypes.func,
18 | onSwipeUpRight: React.PropTypes.func,
19 | onSwipeRight: React.PropTypes.func,
20 | onSwipeDownRight: React.PropTypes.func,
21 | onSwipeDown: React.PropTypes.func,
22 | onSwipeDownLeft: React.PropTypes.func
23 | },
24 |
25 | getDefaultProps: function() {
26 | return {
27 | tagName: 'div',
28 | minSwipeLength: 75,
29 | moveThreshold: 10
30 | };
31 | },
32 |
33 | getInitialState: function () {
34 | return {
35 | direction: null,
36 | initialTouch: null,
37 | touch: null,
38 | swipeStart: null
39 | };
40 | },
41 |
42 | render: function() {
43 | var Component = this.props.component || this.props.tagName;
44 | return (
45 |
49 | {this.props.children}
50 |
51 | );
52 | },
53 |
54 | handleTouchStart: function (e) {
55 | if (e.touches.length !== 1) {
56 | return;
57 | }
58 | this._initiateSwipe(e.touches[0]);
59 | },
60 |
61 | handleTouchEnd: function (e) {
62 | if (!this.state.direction) {
63 | return;
64 | }
65 | if (this._getSwipeLength(this.state.initialTouch) > this.props.minSwipeLength) {
66 | var method = this._getEventMethodName();
67 | var evt = {
68 | type: this._getEventTypeName(),
69 | timeStampStart: this.state.swipeStart,
70 | timeStampEnd: new Date(),
71 | initialTouch: this.state.initialTouch,
72 | finalTouch: this.state.touch
73 | };
74 | this.props.onSwipe && this.props.onSwipe(evt);
75 | this.props[method] && this.props[method](evt);
76 | e.preventDefault();
77 | }
78 | this._resetSwipe();
79 | },
80 |
81 | handleTouchMove: function (e) {
82 | if (e.touches.length !== 1 || !this.state.direction) {
83 | return;
84 | }
85 | var touch = e.touches[0];
86 | var direction = this._getSwipeDirection(touch);
87 | if (this._isSwipeDirectionUnchanged(direction)) {
88 | this._updateSwipe(direction, touch);
89 | e.preventDefault();
90 | return;
91 | }
92 | this._resetSwipe();
93 | },
94 |
95 | _initiateSwipe: function (touch) {
96 | this.setState({direction: {x: null, y: null}, initialTouch: touch, touch: touch, swipeStart: new Date()});
97 | },
98 |
99 | _resetSwipe: function () {
100 | this.setState(this.getInitialState());
101 | },
102 |
103 | _updateSwipe: function (direction, touch) {
104 | this.setState({direction, touch});
105 | },
106 |
107 | _getSwipeLength: function (touch) {
108 | return this._getSwipeLengthX(touch) + this._getSwipeLengthY(touch);
109 | },
110 |
111 | _getSwipeLengthX: function (touch) {
112 | return Math.abs(touch.pageX - this.state.touch.pageX);
113 | },
114 |
115 | _getSwipeLengthY: function (touch) {
116 | return Math.abs(touch.pageY - this.state.touch.pageY);
117 | },
118 |
119 | _getSwipeDirection: function (touch) {
120 | var dir = objectAssign({x: null, y: null}, this.state.direction);
121 | if (this._getSwipeLengthY(touch) > this.props.moveThreshold) {
122 | dir.y = this._getSwipeDirectionY(touch);
123 | }
124 | if (this._getSwipeLengthX(touch) > this.props.moveThreshold) {
125 | dir.x = this._getSwipeDirectionX(touch);
126 | }
127 | return dir;
128 | },
129 |
130 | _getSwipeDirectionX: function (touch) {
131 | return touch.pageX < this.state.touch.pageX ? 'Left' : 'Right';
132 | },
133 |
134 | _getSwipeDirectionY: function (touch) {
135 | return touch.pageY < this.state.touch.pageY ? 'Up' : 'Down';
136 | },
137 |
138 | _getSwipeDirectionName: function () {
139 | return (this.state.direction.y || '') + (this.state.direction.x || '');
140 | },
141 |
142 | _isSwipeDirectionUnchanged: function (direction) {
143 | return (!this.state.direction.x || this.state.direction.x === direction.x) &&
144 | (!this.state.direction.y || this.state.direction.y === direction.y);
145 | },
146 |
147 | _getEventMethodName: function () {
148 | return 'onSwipe' + this._getSwipeDirectionName();
149 | },
150 |
151 | _getEventTypeName: function () {
152 | return 'swipe' + this._getSwipeDirectionName();
153 | }
154 | });
155 |
156 | module.exports = Swiper;
157 |
--------------------------------------------------------------------------------