├── .babelrc
├── .editorconfig
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .npmignore
├── .prettierignore
├── .travis.yml
├── LICENSE
├── README.md
├── demo
├── bundle.js
├── index.css
├── index.html
└── index.js
├── package-lock.json
├── package.json
├── src
└── index.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-react"
5 | ],
6 | "plugins": [
7 | "add-module-exports",
8 | "@babel/plugin-syntax-dynamic-import",
9 | "@babel/plugin-syntax-import-meta",
10 | "@babel/plugin-proposal-class-properties",
11 | "@babel/plugin-proposal-json-strings",
12 | [
13 | "@babel/plugin-proposal-decorators",
14 | {
15 | "legacy": true
16 | }
17 | ],
18 | "@babel/plugin-proposal-function-sent",
19 | "@babel/plugin-proposal-export-namespace-from",
20 | "@babel/plugin-proposal-numeric-separator",
21 | "@babel/plugin-proposal-throw-expressions",
22 | "@babel/plugin-proposal-export-default-from",
23 | "@babel/plugin-proposal-logical-assignment-operators",
24 | "@babel/plugin-proposal-optional-chaining",
25 | [
26 | "@babel/plugin-proposal-pipeline-operator",
27 | {
28 | "proposal": "minimal"
29 | }
30 | ],
31 | "@babel/plugin-proposal-nullish-coalescing-operator",
32 | "@babel/plugin-proposal-do-expressions",
33 | "@babel/plugin-proposal-function-bind"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | ## Demo link
4 |
5 | * you can use this link as a boilerplate -
6 | http://esnextb.in/?gist=8d9bf6bf17a4a3f779485e4baa6c3f26
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | *.log
4 |
5 | dist
6 | lib
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .github
2 | src
3 | demo
4 | test
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | demo/bundle.js
2 | demo/bundle.min.js
3 | dist
4 | lib
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 10
4 | - 8
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Dmitri Voronianski
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-swipe
2 |
3 | [](https://travis-ci.org/voronianski/react-swipe)
4 | [](http://badge.fury.io/js/react-swipe)
5 | [](http://www.npmjs.com/package/react-swipe)
6 |
7 |
8 | > [Brad Birdsall](https://github.com/thebird)'s [Swipe.js](https://github.com/voronianski/swipe-js-iso) as a [React](http://facebook.github.io/react) component.
9 |
10 | ## Demo
11 |
12 | Check out the [demo](http://voronianski.github.io/react-swipe/demo/) from a mobile device (real or emulated).
13 |
14 |
15 |
16 | ## Install
17 |
18 | ```bash
19 | npm install react swipe-js-iso react-swipe --save
20 | ```
21 |
22 | ## Usage
23 |
24 | ### Examples
25 |
26 | ```javascript
27 | import React from 'react';
28 | import ReactDOM from 'react-dom';
29 | import ReactSwipe from 'react-swipe';
30 |
31 | const Carousel = () => {
32 | let reactSwipeEl;
33 |
34 | return (
35 |
36 |
(reactSwipeEl = el)}
40 | >
41 | PANE 1
42 | PANE 2
43 | PANE 3
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
51 | ReactDOM.render(, document.getElementById('app'));
52 | ```
53 |
54 | ### Props
55 |
56 | - `swipeOptions: ?Object` - supports all original options from [Swipe.js config](https://github.com/voronianski/swipe-js-iso#config-options). If passed object differs from the previous one `react-swipe` will re-initiate underlying Swipe.js instance with fresh options
57 |
58 | - `style: ?Object` - object with 3 keys (see [defaults](https://github.com/voronianski/react-swipe/blob/gh-pages/src/index.js#L28)):
59 |
60 | - `container: ?Object`
61 | - `wrapper: ?Object`
62 | - `child: ?Object`
63 |
64 | - regular props as `className`, `id` for root component are also supported
65 |
66 | - `childCount: ?Number` - use it to explicitely tell `react-swipe` that it needs to re-initiate underlying Swipe.js instance. For example, by setting the `childCount` prop to the `length` of the images array that you pass into `react-swipe`, re-rendering will take place when the `images.length` differs from the previous `render` pass:
67 |
68 | ```js
69 | {images}
70 | ```
71 |
72 | ## Methods
73 |
74 | Component proxies all [Swipe.js instance methods](https://github.com/voronianski/swipe-js-iso/#swipe-api).
75 |
76 | ### Playground
77 |
78 | Configure the ReactSwipe component in a sandbox environment at [CodeSandbox](https://codesandbox.io/s/q86m8n9qnj).
79 |
80 | ---
81 |
82 | **MIT Licensed**
83 |
--------------------------------------------------------------------------------
/demo/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | div,
4 | span,
5 | object,
6 | iframe,
7 | h1,
8 | h2,
9 | h3,
10 | h4,
11 | h5,
12 | h6,
13 | p,
14 | del,
15 | dfn,
16 | em,
17 | img,
18 | ins,
19 | kbd,
20 | q,
21 | samp,
22 | small,
23 | strong,
24 | b,
25 | i,
26 | dl,
27 | dt,
28 | dd,
29 | ol,
30 | ul,
31 | li,
32 | fieldset,
33 | form,
34 | label,
35 | table,
36 | tbody,
37 | tfoot,
38 | thead,
39 | tr,
40 | th,
41 | td,
42 | article,
43 | aside,
44 | footer,
45 | header,
46 | nav,
47 | section {
48 | margin: 0;
49 | padding: 0;
50 | border: 0;
51 | outline: 0;
52 | font-size: 100%;
53 | vertical-align: baseline;
54 | background: transparent;
55 | }
56 |
57 | body {
58 | background: #f3f3f3;
59 | font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
60 | -webkit-text-size-adjust: none;
61 | }
62 |
63 | a {
64 | color: #14ade5;
65 | }
66 | a:hover {
67 | text-decoration: none;
68 | }
69 |
70 | .center {
71 | text-align: center;
72 | }
73 |
74 | h1 {
75 | font-size: 34px;
76 | margin: 50px auto 20px;
77 | color: #212121;
78 | }
79 |
80 | h2 {
81 | font-size: 14px;
82 | color: #3c3c3c;
83 | margin: 10px;
84 | }
85 |
86 | .mySwipe {
87 | margin: 0 auto;
88 | }
89 | .mySwipe .item {
90 | font-weight: bold;
91 | color: #14ade5;
92 | font-size: 20px;
93 | text-align: center;
94 | margin: 10px;
95 | padding: 100px 10px;
96 | box-shadow: 0 1px #ebebeb;
97 | background: #fff;
98 | border-radius: 5px;
99 | border: 1px solid;
100 | border-color: #e5e5e5 #d3d3d3 #b9c1c6;
101 | }
102 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ReactSwipe
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
23 |
29 |
30 |
31 |
32 |
33 | Fork me on GitHub
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/demo/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ReactDOM from 'react-dom';
3 | import querystring from 'querystring';
4 | import ReactSwipe from '../src';
5 |
6 | const query = querystring.parse(window.location.search.slice(1));
7 |
8 | // generate slide panes
9 | const numberOfSlides = parseInt(query.slidesNum, 10) || 20;
10 | const paneNodes = Array.apply(null, Array(numberOfSlides)).map((_, i) => {
11 | return (
12 |
15 | );
16 | });
17 |
18 | // change Swipe.js options by query params
19 | const startSlide = parseInt(query.startSlide, 10) || 0;
20 | const swipeOptions = {
21 | startSlide: startSlide < paneNodes.length && startSlide >= 0 ? startSlide : 0,
22 | auto: parseInt(query.auto, 10) || 0,
23 | speed: parseInt(query.speed, 10) || 300,
24 | disableScroll: query.disableScroll === 'true',
25 | continuous: query.continuous === 'true',
26 | widthOfSiblingSlidePreview:
27 | parseInt(query.widthOfSiblingSlidePreview, 10) || 0,
28 | callback() {
29 | console.log('slide changed');
30 | },
31 | transitionEnd() {
32 | console.log('ended transition');
33 | }
34 | };
35 |
36 | const Page = () => {
37 | let reactSwipeEl;
38 |
39 | return (
40 |
41 |
ReactSwipe.js
42 |
Open this page from a mobile device (real or emulated).
43 |
44 | You can pass{' '}
45 |
46 | Swipe.js options
47 | {' '}
48 | as query params.
49 |
50 |
51 |
(reactSwipeEl = el)}
55 | >
56 | {paneNodes}
57 |
58 |
59 |
60 |
61 | );
62 | };
63 |
64 | ReactDOM.render(, document.getElementById('app'));
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipe",
3 | "version": "6.0.4",
4 | "description": "Brad Birdsall's Swipe.js as a React component",
5 | "homepage": "https://github.com/voronianski/react-swipe",
6 | "keywords": [
7 | "react",
8 | "component",
9 | "carousel",
10 | "swipe",
11 | "react-component"
12 | ],
13 | "author": "Dmitri Voronianski ",
14 | "contributors": [
15 | "Jed Schmidt "
16 | ],
17 | "repository": {
18 | "type": "git",
19 | "url": "git://github.com/voronianski/react-swipe.git"
20 | },
21 | "main": "./lib/index.js",
22 | "license": "MIT",
23 | "engines": {
24 | "node": ">=8.0.0",
25 | "npm": ">=5.5.1"
26 | },
27 | "prettier": {
28 | "singleQuote": true
29 | },
30 | "husky": {
31 | "hooks": {
32 | "pre-commit": "pretty-quick --staged --ignore-path ./public"
33 | }
34 | },
35 | "browserslist": [
36 | "> 0.2%",
37 | "last 2 versions",
38 | "not ie <= 8",
39 | "not op_mini all"
40 | ],
41 | "dependencies": {
42 | "lodash.isequal": "^4.5.0",
43 | "prop-types": "^15.6.0",
44 | "swipe-js-iso": "^2.1.5"
45 | },
46 | "devDependencies": {
47 | "@babel/cli": "^7.0.0",
48 | "@babel/core": "^7.0.0",
49 | "@babel/plugin-proposal-class-properties": "^7.0.0",
50 | "@babel/plugin-proposal-decorators": "^7.0.0",
51 | "@babel/plugin-proposal-do-expressions": "^7.0.0",
52 | "@babel/plugin-proposal-export-default-from": "^7.0.0",
53 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
54 | "@babel/plugin-proposal-function-bind": "^7.0.0",
55 | "@babel/plugin-proposal-function-sent": "^7.0.0",
56 | "@babel/plugin-proposal-json-strings": "^7.0.0",
57 | "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
58 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",
59 | "@babel/plugin-proposal-numeric-separator": "^7.0.0",
60 | "@babel/plugin-proposal-optional-chaining": "^7.0.0",
61 | "@babel/plugin-proposal-pipeline-operator": "^7.0.0",
62 | "@babel/plugin-proposal-throw-expressions": "^7.0.0",
63 | "@babel/plugin-syntax-dynamic-import": "^7.0.0",
64 | "@babel/plugin-syntax-import-meta": "^7.0.0",
65 | "@babel/plugin-transform-object-assign": "^7.0.0",
66 | "@babel/preset-env": "^7.0.0",
67 | "@babel/preset-react": "^7.0.0",
68 | "@babel/register": "^7.0.0",
69 | "babel-loader": "^8.0.0",
70 | "babel-plugin-add-module-exports": "^0.2.1",
71 | "babelify": "^10.0.0",
72 | "browserify": "^16.2.3",
73 | "husky": "^1.2.0",
74 | "prettier": "^1.15.2",
75 | "pretty-quick": "^1.8.0",
76 | "react": "^16.6.3",
77 | "react-dom": "^16.6.3",
78 | "uglifyjs-webpack-plugin": "^2.0.1",
79 | "webpack": "^4.26.0",
80 | "webpack-cli": "^3.1.2",
81 | "webpack-umd-external": "^1.0.2"
82 | },
83 | "scripts": {
84 | "build": "npm run build-babel && npm run build-dist-dev && npm run build-dist-prod && npm run build-demo",
85 | "build-babel": "babel ./src/index.js --out-file ./lib/index.js",
86 | "build-dist-dev": "NODE_ENV=development webpack --config webpack.config --colors",
87 | "build-dist-prod": "NODE_ENV=production webpack --config webpack.config --progress --colors -p",
88 | "build-demo": "browserify ./demo/index.js -t [ babelify --presets [ @babel/preset-env @babel/preset-react ] ] -o ./demo/bundle.js",
89 | "test": "echo \"Comming soon ;)\" && exit 0",
90 | "prepublishOnly": "npm run build"
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React, { Component } from 'react';
3 | import Swipe from 'swipe-js-iso';
4 | import isEqual from 'lodash.isequal';
5 |
6 | class ReactSwipe extends Component {
7 | static propTypes = {
8 | swipeOptions: PropTypes.shape({
9 | startSlide: PropTypes.number,
10 | speed: PropTypes.number,
11 | auto: PropTypes.number,
12 | continuous: PropTypes.bool,
13 | disableScroll: PropTypes.bool,
14 | stopPropagation: PropTypes.bool,
15 | swiping: PropTypes.func,
16 | callback: PropTypes.func,
17 | transitionEnd: PropTypes.func
18 | }),
19 | style: PropTypes.shape({
20 | container: PropTypes.object,
21 | wrapper: PropTypes.object,
22 | child: PropTypes.object
23 | }),
24 | id: PropTypes.string,
25 | className: PropTypes.string,
26 | childCount: PropTypes.number
27 | };
28 |
29 | static defaultProps = {
30 | swipeOptions: {},
31 | style: {
32 | container: {
33 | overflow: 'hidden',
34 | visibility: 'hidden',
35 | position: 'relative'
36 | },
37 | wrapper: {
38 | overflow: 'hidden',
39 | position: 'relative'
40 | },
41 | child: {
42 | float: 'left',
43 | width: '100%',
44 | position: 'relative',
45 | transitionProperty: 'transform'
46 | }
47 | },
48 | className: '',
49 | childCount: 0
50 | };
51 |
52 | componentDidMount() {
53 | this.swipe = Swipe(this.containerEl, this.props.swipeOptions);
54 | }
55 |
56 | componentDidUpdate(prevProps) {
57 | const { childCount, swipeOptions } = this.props;
58 | const shouldUpdateSwipeInstance =
59 | prevProps.childCount !== childCount ||
60 | !isEqual(prevProps.swipeOptions, swipeOptions);
61 |
62 | if (shouldUpdateSwipeInstance) {
63 | this.swipe.kill();
64 | this.swipe = Swipe(this.containerEl, this.props.swipeOptions);
65 | }
66 | }
67 |
68 | componentWillUnmount() {
69 | this.swipe.kill();
70 | this.swipe = void 0;
71 | }
72 |
73 | next() {
74 | this.swipe.next();
75 | }
76 |
77 | prev() {
78 | this.swipe.prev();
79 | }
80 |
81 | slide(...args) {
82 | this.swipe.slide(...args);
83 | }
84 |
85 | getPos() {
86 | return this.swipe.getPos();
87 | }
88 |
89 | getNumSlides() {
90 | return this.swipe.getNumSlides();
91 | }
92 |
93 | render() {
94 | const { id, className, style, children } = this.props;
95 |
96 | return (
97 | (this.containerEl = el)}
100 | className={`react-swipe-container ${className}`}
101 | style={style.container}
102 | >
103 |
104 | {React.Children.map(children, child => {
105 | if (!child) {
106 | return null;
107 | }
108 |
109 | const childStyle = child.props.style
110 | ? { ...style.child, ...child.props.style }
111 | : style.child;
112 |
113 | return React.cloneElement(child, { style: childStyle });
114 | })}
115 |
116 |
117 | );
118 | }
119 | }
120 |
121 | export default ReactSwipe;
122 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
4 | const webpackUMDExternal = require('webpack-umd-external');
5 |
6 | const env = process.env.NODE_ENV || 'development';
7 | const isProduction = env === 'production';
8 | const outputFileName = isProduction ? 'react-swipe.min.js' : 'react-swipe.js';
9 |
10 | const config = {
11 | mode: isProduction ? 'production' : 'development',
12 |
13 | devtool: false,
14 |
15 | target: 'web',
16 |
17 | entry: './src/index.js',
18 |
19 | output: {
20 | path: path.join(__dirname, './dist'),
21 | filename: outputFileName,
22 | library: 'ReactSwipe',
23 | libraryTarget: 'umd',
24 | umdNamedDefine: true
25 | },
26 |
27 | optimization: {
28 | minimizer: [
29 | new UglifyJsPlugin({
30 | parallel: true,
31 | uglifyOptions: {
32 | compress: { warnings: false },
33 | output: { comments: false }
34 | }
35 | })
36 | ]
37 | },
38 |
39 | externals: webpackUMDExternal({
40 | react: 'React',
41 | 'swipe-js-iso': 'Swipe'
42 | }),
43 |
44 | resolve: {
45 | extensions: ['.js', '.jsx']
46 | },
47 |
48 | plugins: [
49 | new webpack.DefinePlugin({
50 | 'process.env': {
51 | NODE_ENV: JSON.stringify(env)
52 | }
53 | })
54 | ],
55 |
56 | module: {
57 | rules: [
58 | {
59 | test: /\.jsx?$/,
60 | exclude: /node_modules/,
61 | loader: 'babel-loader'
62 | }
63 | ]
64 | }
65 | };
66 |
67 | module.exports = config;
68 |
--------------------------------------------------------------------------------