├── .babelrc ├── index.js ├── example.gif ├── demo.html ├── .gitignore ├── src ├── arrow.jsx ├── touch-handler.js ├── pagination.jsx └── react-shift.jsx ├── .npmignore ├── dist ├── touch-handler.js ├── arrow.js ├── react-shift.js.map └── react-shift.js ├── .eslintrc ├── karma.conf.js ├── LICENSE ├── demo ├── demo.css └── demo.jsx ├── test └── react-shift.js ├── gulpfile.js ├── package.json └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/react-shift'); 2 | -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sowiecki/react-shift/HEAD/example.gif -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # demo 2 | demo/demo.js 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # node-waf configuration 17 | .lock-wscript 18 | 19 | # Dependency directory 20 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 21 | node_modules 22 | 23 | .DS_Store 24 | .fuse_hidden* 25 | -------------------------------------------------------------------------------- /src/arrow.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const Arrow = ({ fakeLink, onClick, label, className, style }) => ( 5 | 10 | {label} 11 | 12 | ); 13 | 14 | Arrow.propTypes = { 15 | fakeLink: PropTypes.bool, 16 | onClick: PropTypes.func, 17 | label: PropTypes.string, 18 | className: PropTypes.string, 19 | style: PropTypes.object 20 | }; 21 | 22 | export default Arrow; 23 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /src/touch-handler.js: -------------------------------------------------------------------------------- 1 | const position = { 2 | right: 0, 3 | left: 0, 4 | direction: null, 5 | clear() { 6 | this.right = 0; 7 | this.left = 0; 8 | } 9 | }; 10 | 11 | export default (e, left, right) => { 12 | e = Math.round(e); 13 | 14 | position.direction = null; 15 | 16 | if (e < 450) { 17 | position.left += 1; 18 | position.right = 0; 19 | } else if (e > 550) { 20 | position.right += 1; 21 | position.left = 0; 22 | } 23 | 24 | if (position.left > 4) { 25 | position.clear(); 26 | left(); 27 | return; 28 | } 29 | 30 | if (position.right > 4) { 31 | position.clear(); 32 | right(); 33 | return; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /dist/touch-handler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var position = { 7 | right: 0, 8 | left: 0, 9 | direction: null, 10 | clear: function clear() { 11 | this.right = 0; 12 | this.left = 0; 13 | } 14 | }; 15 | 16 | exports.default = function (e, left, right) { 17 | e = Math.round(e); 18 | 19 | position.direction = null; 20 | 21 | if (e < 450) { 22 | position.left += 1; 23 | position.right = 0; 24 | } else if (e > 550) { 25 | position.right += 1; 26 | position.left = 0; 27 | } 28 | 29 | if (position.left > 4) { 30 | position.clear(); 31 | left(); 32 | return; 33 | } 34 | 35 | if (position.right > 4) { 36 | position.clear(); 37 | right(); 38 | return; 39 | } 40 | }; -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "filenames", 4 | "react" 5 | ], 6 | "extends": [ 7 | "airbnb" 8 | ], 9 | "parser": "babel-eslint", 10 | "ecmaFeatures": { 11 | "jsx": true, 12 | "modules": true 13 | }, 14 | "env": { 15 | "es6": true 16 | }, 17 | "rules": { 18 | "strict": 0, 19 | "quotes": [1, "single"], 20 | "jsx-quotes": 0, 21 | "indent": [2, 2, {"SwitchCase": 1}], 22 | "no-invalid-this": 0, 23 | "react/jsx-closing-bracket-location": [2, "after-props"], 24 | "react/jsx-boolean-value": 0, 25 | "react/jsx-space-before-closing": 0, 26 | "react/jsx-no-bind": 0, 27 | "react/sort-comp": 0, 28 | "valid-jsdoc": 0, 29 | "prefer-spread": 0, 30 | "comma-dangle": 0, 31 | "arrow-body-style": 0, 32 | "no-param-reassign": 0 33 | }, 34 | "globals": { 35 | "require": true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dist/arrow.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var Arrow = function Arrow(_ref) { 14 | var fakeLink = _ref.fakeLink; 15 | var onClick = _ref.onClick; 16 | var label = _ref.label; 17 | var className = _ref.className; 18 | var style = _ref.style; 19 | return _react2.default.createElement( 20 | 'a', 21 | { 22 | className: className, 23 | style: style, 24 | href: fakeLink ? '#' : null, 25 | onClick: onClick }, 26 | label 27 | ); 28 | }; 29 | 30 | Arrow.propTypes = { 31 | onClick: _react.PropTypes.func, 32 | label: _react.PropTypes.string, 33 | className: _react.PropTypes.string, 34 | style: _react.PropTypes.object 35 | }; 36 | 37 | exports.default = Arrow; -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | frameworks: ['browserify', 'mocha','chai', 'phantomjs-shim'], 4 | 'plugins': [ 5 | 'karma-browserify', 6 | 'karma-mocha', 7 | 'karma-chai', 8 | 'karma-phantomjs-launcher', 9 | 'karma-babel-preprocessor', 10 | 'karma-phantomjs-shim', 11 | 'karma-spec-reporter' 12 | ], 13 | reporters: ['spec'], 14 | singleRun: true, 15 | files: [ 16 | 'src/**/*', 17 | 'test/*.js' 18 | ], 19 | preprocessors: { 20 | 'src/**/*': ['browserify'], 21 | 'test/**/*': ['browserify'] 22 | }, 23 | babelPreprocessor: { 24 | options: { 25 | presets: ['es2015', 'react'], 26 | sourceMap: 'inline' 27 | } 28 | }, 29 | browserify: { 30 | debug: true, 31 | transform: ['babelify'] 32 | }, 33 | browsers: ['PhantomJS'], 34 | phantomjsLauncher: { 35 | exitOnResourceError: true 36 | } 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Sean 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/pagination.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const Pagination = (props) => { 5 | const { classes, styles, fakeLinks, page, pageCount, onClick } = props; 6 | 7 | const paginationArray = Array 8 | .apply(null, { length: pageCount + 1 }) 9 | .map(Number.call, Number); 10 | 11 | const renderPage = (n) => { 12 | return n === page ? ( 13 | 19 | {n + 1} 20 | 21 | ) : ( 22 | 28 | {n + 1} 29 | 30 | ); 31 | }; 32 | 33 | return ( 34 | 38 | {paginationArray.map(renderPage)} 39 | 40 | ); 41 | }; 42 | 43 | export default Pagination; 44 | 45 | Pagination.propTypes = { 46 | classes: PropTypes.object, 47 | styles: PropTypes.object, 48 | fakeLinks: PropTypes.bool, 49 | page: PropTypes.number, 50 | pageCount: PropTypes.number, 51 | onClick: PropTypes.func 52 | }; 53 | -------------------------------------------------------------------------------- /demo/demo.css: -------------------------------------------------------------------------------- 1 | html { 2 | width: 100%; 3 | } 4 | 5 | .react-shift-page-enter { 6 | position: absolute; 7 | right: 0; left: 0; 8 | opacity: 0.01; 9 | transition: opacity .25s ease-in; 10 | } 11 | .react-shift-page-enter .react-shift-page-enter-active { 12 | opacity: 1; 13 | } 14 | .react-shift-page-leave { 15 | position: absolute; 16 | right: 0; left: 0; 17 | opacity: 1; 18 | transition: opacity .25s ease-in; 19 | } 20 | .react-shift-page-leave .react-shift-page-leave-active { 21 | position: absolute; 22 | opacity: 0.01; 23 | transition: opacity .25s ease-in; 24 | } 25 | 26 | .react-shift-wrapper { 27 | height: 100%; 28 | width: 100%; 29 | font-family: Helvetica; 30 | } 31 | 32 | .react-shift-page { 33 | box-sizing: border-box; 34 | position: absolute; 35 | margin: 0 auto auto; 36 | padding: 10px; 37 | left: 0; right: 0; 38 | width: 100%; 39 | /*border: 2px solid #3f3f3f;*/ 40 | border-radius: 10px; 41 | } 42 | 43 | .react-shift-navigation { 44 | box-sizing: border-box; 45 | position: fixed; 46 | bottom: 100px; left: 0; right: 0; 47 | margin: 10px auto auto; 48 | padding: 2px; 49 | width: 600px; 50 | height: 60px; 51 | text-align: center; 52 | /*border: 2px solid #3f3f3f;*/ 53 | border-radius: 10px; 54 | } 55 | 56 | 57 | .react-shift-nav-arrow { 58 | display: inline-block; 59 | width: 60px; 60 | } 61 | 62 | a { 63 | font-size: 12px; 64 | transition: all .25s; 65 | 66 | } 67 | a.react-shift-current-page { 68 | font-size: 26px; 69 | 70 | } 71 | 72 | a.react-shift-fast-link { 73 | margin: 0 4px 0 4px; 74 | } 75 | -------------------------------------------------------------------------------- /test/react-shift.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import shallowRender from 'react-shallow-render'; 4 | import { findClass, findType } from 'react-shallow-renderer-helpers'; 5 | 6 | import Shift from '../src/react-shift.jsx'; 7 | import Arrow from '../src/arrow.jsx'; 8 | 9 | const shallowRenderer = TestUtils.createRenderer(); 10 | 11 | describe('Shift', () => { 12 | let component, children; 13 | 14 | const props = { 15 | classes: { 16 | page: 'test-page', 17 | navigation: 'test-navigation', 18 | navArrow: 'test-nav-arrow', 19 | nextPage: 'test-next-page', 20 | previousPage: 'test-previous-page' 21 | } 22 | }; 23 | 24 | beforeEach(() => { 25 | children = [ 26 |