├── .buckconfig
├── .circleci
├── .firebaserc
└── config.yml
├── .codecov.yml
├── .eslintignore
├── .eslintrc.js
├── .firebaserc
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .size-limit
├── .watchmanconfig
├── CHANGELOG.md
├── LICENSE
├── README.md
├── app.json
├── babel.config.js
├── docs
├── src
│ ├── modules
│ │ ├── components
│ │ │ ├── AppContent.js
│ │ │ ├── AppDrawer.js
│ │ │ ├── AppDrawerNavItem.js
│ │ │ ├── AppFrame.js
│ │ │ ├── AppTableOfContents.js
│ │ │ ├── AppWrapper.js
│ │ │ ├── Demo.js
│ │ │ ├── Head.js
│ │ │ ├── Link.js
│ │ │ ├── MarkdownDocs.js
│ │ │ ├── MarkdownElement.js
│ │ │ ├── Pagination.js
│ │ │ ├── PaginationDot.js
│ │ │ ├── prism.js
│ │ │ └── withRoot.js
│ │ ├── styles
│ │ │ └── getPageContext.js
│ │ └── utils
│ │ │ ├── find.js
│ │ │ ├── helpers.js
│ │ │ └── parseMarkdown.js
│ └── pages
│ │ ├── api
│ │ └── api.md
│ │ ├── demos
│ │ ├── DemoAnimateHeight.js
│ │ ├── DemoAutoPlay.js
│ │ ├── DemoAxis.js
│ │ ├── DemoCircular.js
│ │ ├── DemoCoverflow.js
│ │ ├── DemoHocs.js
│ │ ├── DemoKeyboard.js
│ │ ├── DemoNested.js
│ │ ├── DemoResistance.js
│ │ ├── DemoRtl.js
│ │ ├── DemoScroll.js
│ │ ├── DemoSimple.js
│ │ ├── DemoTabs.js
│ │ ├── DemoVirtualize.js
│ │ ├── DemoWidth.js
│ │ └── demos.md
│ │ └── getting-started
│ │ ├── example-projects.md
│ │ ├── installation.md
│ │ ├── supported-platforms.md
│ │ └── usage.md
└── webpackBaseConfig.js
├── examples
├── .gitignore
└── create-react-app
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
│ └── src
│ ├── App.js
│ └── index.js
├── firebase.json
├── lerna.json
├── native
├── .buckconfig
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── App.js
├── app.json
├── assets
│ ├── fonts
│ │ └── SpaceMono-Regular.ttf
│ └── images
│ │ ├── icon.png
│ │ ├── robot-dev.png
│ │ ├── robot-prod.png
│ │ └── splash.png
├── index.js
├── jest.config.js
├── package.json
├── packages
│ └── react-swipeable-views-native
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src
│ │ ├── SwipeableViews.animated.tsx
│ │ ├── SwipeableViews.scroll.tsx
│ │ └── index.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.prod.json
│ │ ├── tslint.json
│ │ └── yarn.lock
├── src
│ ├── App.tsx
│ ├── Footer.tsx
│ ├── Home.tsx
│ ├── Main.tsx
│ ├── demo
│ │ ├── AutoPlay.test.tsx
│ │ ├── AutoPlay.tsx
│ │ ├── Hocs.test.tsx
│ │ ├── Hocs.tsx
│ │ ├── Resistance.test.tsx
│ │ ├── Resistance.tsx
│ │ ├── Scroll.test.tsx
│ │ ├── Scroll.tsx
│ │ ├── Simple.test.tsx
│ │ ├── Simple.tsx
│ │ ├── Tabs.test.tsx
│ │ ├── Tabs.tsx
│ │ ├── Virtualize.test.tsx
│ │ ├── Virtualize.tsx
│ │ └── __snapshots__
│ │ │ ├── AutoPlay.test.tsx.snap
│ │ │ ├── Hocs.test.tsx.snap
│ │ │ ├── Resistance.test.tsx.snap
│ │ │ ├── Scroll.test.tsx.snap
│ │ │ ├── Simple.test.tsx.snap
│ │ │ ├── Tabs.test.tsx.snap
│ │ │ └── Virtualize.test.tsx.snap
│ ├── pagination
│ │ ├── NavButtom.tsx
│ │ ├── Pagination.tsx
│ │ └── PaginationDot.tsx
│ └── styles.ts
├── tsconfig.json
├── tslint.json
└── yarn.lock
├── next.config.js
├── package.json
├── packages
├── react-swipeable-views-core
│ ├── .npmignore
│ ├── package.json
│ └── src
│ │ ├── checkIndexBounds.js
│ │ ├── checkIndexBounds.test.js
│ │ ├── computeIndex.js
│ │ ├── computeIndex.test.js
│ │ ├── constant.js
│ │ ├── getDisplaySameSlide.js
│ │ ├── getDisplaySameSlide.test.js
│ │ ├── index.js
│ │ ├── mod.js
│ │ └── mod.test.js
├── react-swipeable-views-utils
│ ├── .npmignore
│ ├── package.json
│ └── src
│ │ ├── autoPlay.js
│ │ ├── autoPlay.test.js
│ │ ├── bindKeyboard.js
│ │ ├── bindKeyboard.test.js
│ │ ├── index.js
│ │ ├── virtualize.js
│ │ └── virtualize.test.js
└── react-swipeable-views
│ ├── .npmignore
│ ├── dist
│ └── legacy-browser-support.css
│ ├── package.json
│ └── src
│ ├── SwipeableViews.js
│ ├── SwipeableViews.test.js
│ └── index.js
├── pages
├── .eslintrc.js
├── _document.js
├── api
│ └── api.js
├── demos
│ └── demos.js
├── getting-started
│ ├── example-projects.js
│ ├── installation.js
│ ├── supported-platforms.js
│ └── usage.js
└── index.js
├── prettier.config.js
├── scripts
├── babel-plugin-preval.js
└── get-replacement.js
├── static
├── album-art-1.jpg
├── album-art-2.jpg
├── album-art-3.jpg
├── album-art-4.jpg
├── album-art-5.jpg
├── album-art-6.jpg
├── album-art-7.jpg
├── album-art-8.jpg
├── manifest.json
├── platformAndroid.gif
├── platformBrowser.gif
├── platformIOS.gif
└── usage.gif
├── test
├── consoleError.js
├── dom.js
├── mocha.opts
└── setup.js
└── yarn.lock
/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/.circleci/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "material-ui": "react-swipeable-views-395e4"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | defaults: &defaults
2 | working_directory: /tmp/react-swipeable-views
3 | docker:
4 | - image: circleci/node:10
5 | restore_repo: &restore_repo
6 | # The cache logic of CircleCI has been disabled for Security reasons.
7 | # We can no longer use it.
8 | # restore_cache:
9 | # keys:
10 | # - v1-repo-{{ .Branch }}-{{ .Revision }}
11 | run:
12 | name: Install js dependencies
13 | command: yarn
14 | version: 2
15 | jobs:
16 | checkout:
17 | <<: *defaults
18 | steps:
19 | - checkout
20 | - *restore_repo
21 | - run:
22 | name: Check versions and env
23 | command: |
24 | yarn --version
25 | node --version
26 | docker --version
27 | docker-compose --version
28 | env
29 | yarn cache dir
30 | - restore_cache:
31 | key: v1-yarn-sha-{{ checksum "yarn.lock" }}
32 | - run:
33 | name: Install js dependencies
34 | command: yarn
35 | - run:
36 | name: Should not have any git not staged
37 | command: git diff --exit-code
38 | - save_cache:
39 | key: v1-yarn-sha-{{ checksum "yarn.lock" }}
40 | paths:
41 | - ~/.cache/yarn/v1
42 | - save_cache:
43 | key: v1-repo-{{ .Branch }}-{{ .Revision }}
44 | paths:
45 | - /tmp/react-swipeable-views
46 | test_unit:
47 | <<: *defaults
48 | steps:
49 | - checkout
50 | - *restore_repo
51 | - run:
52 | name: Lint
53 | command: yarn lint
54 | - run:
55 | name: Is the size acceptable?
56 | command: yarn build && yarn size
57 | - run:
58 | name: Tests fake browser
59 | command: yarn test:coverage
60 | - run:
61 | name: Check coverage generated
62 | command: |
63 | if ! [[ -s coverage/lcov.info ]]
64 | then
65 | exit 1
66 | fi
67 | - run:
68 | name: Coverage
69 | command: bash <(curl -s https://codecov.io/bash)
70 | workflows:
71 | version: 2
72 | pipeline:
73 | jobs:
74 | - checkout
75 | - test_unit:
76 | requires:
77 | - checkout
78 |
--------------------------------------------------------------------------------
/.codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: master
3 | comment: false
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | .git
2 | /.next
3 | /coverage
4 | /docs/export
5 | /docs/src/modules/utils/find.js
6 | /flow/interfaces
7 | /next.config.js
8 | lib/
9 | node_modules
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | // So parent files don't get applied
5 | root: true,
6 | globals: {
7 | preval: false,
8 | },
9 | env: {
10 | es6: true,
11 | browser: true,
12 | node: true,
13 | mocha: true,
14 | },
15 | extends: ['plugin:import/recommended', 'airbnb'],
16 | parser: 'babel-eslint',
17 | parserOptions: {
18 | ecmaVersion: 7,
19 | sourceType: 'module',
20 | },
21 | plugins: ['babel', 'import', 'jsx-a11y', 'mocha', 'prettier'],
22 | settings: {
23 | 'import/resolver': {
24 | webpack: {
25 | config: path.join(__dirname, './docs/webpackBaseConfig.js'),
26 | },
27 | },
28 | },
29 | rules: {
30 | 'linebreak-style': 'off', // Don't play nicely with Windows
31 | 'arrow-body-style': 'off', // Incompatible with prettier
32 | 'arrow-parens': 'off', // Incompatible with prettier
33 | 'object-curly-newline': 'off', // Incompatible with prettier
34 | 'function-paren-newline': 'off', // Incompatible with prettier
35 | indent: 'off', // Incompatible with prettier
36 | 'implicit-arrow-linebreak': 'off', // Incompatible with prettier
37 | 'space-before-function-paren': 'off', // Incompatible with prettier
38 | 'no-confusing-arrow': 'off', // Incompatible with prettier
39 | 'no-mixed-operators': 'off', // Incompatible with prettier
40 | 'consistent-this': ['error', 'self'],
41 | 'max-len': [
42 | 'error',
43 | 100,
44 | 2,
45 | {
46 | ignoreUrls: true,
47 | },
48 | ], // airbnb is allowing some edge cases
49 | 'no-console': 'error', // airbnb is using warn
50 | 'prefer-destructuring': 'off', // airbnb is using error. destructuring harm grep potential.
51 | 'no-alert': 'error', // airbnb is using warn
52 | 'no-param-reassign': 'off', // airbnb use error
53 | 'no-prototype-builtins': 'off', // airbnb use error
54 | 'operator-linebreak': 'off', // airbnb use error
55 |
56 | // It would be better to enable this rule, but it might slow us down.
57 | 'import/no-extraneous-dependencies': 'off',
58 | 'import/namespace': ['error', { allowComputed: true }],
59 | 'import/order': [
60 | 'error',
61 | {
62 | groups: [['index', 'sibling', 'parent', 'internal', 'external', 'builtin']],
63 | 'newlines-between': 'never',
64 | },
65 | ],
66 | 'import/no-unresolved': 'off', // To fix at some point
67 |
68 | 'react/jsx-indent': 'off', // Incompatible with prettier
69 | 'react/jsx-closing-bracket-location': 'off', // Incompatible with prettier
70 | 'react/jsx-wrap-multilines': 'off', // Incompatible with prettier
71 | 'react/jsx-indent-props': 'off', // Incompatible with prettier
72 | 'react/jsx-one-expression-per-line': 'off', // Incompatible with prettier
73 | 'react/jsx-handler-names': [
74 | 'error',
75 | {
76 | // airbnb is disabling this rule
77 | eventHandlerPrefix: 'handle',
78 | eventHandlerPropPrefix: 'on',
79 | },
80 | ],
81 | 'react/jsx-curly-brace-presence': 'off', // airbnb use error, it's buggy
82 | 'react/forbid-prop-types': 'off', // airbnb use error
83 | 'react/require-default-props': 'off', // airbnb use error, it's buggy
84 | 'react/destructuring-assignment': 'off', // airbnb use error
85 | 'react/jsx-filename-extension': ['error', { extensions: ['.js'] }], // airbnb is using .jsx
86 | 'react/no-danger': 'error', // airbnb is using warn
87 | 'react/no-direct-mutation-state': 'error', // airbnb is using off
88 | 'react/no-find-dom-node': 'off', // airbnb use error
89 | 'react/sort-prop-types': 'error', // airbnb use off
90 |
91 | 'mocha/handle-done-callback': 'error',
92 | 'mocha/no-exclusive-tests': 'error',
93 | 'mocha/no-global-tests': 'error',
94 | 'mocha/no-pending-tests': 'error',
95 | 'mocha/no-skipped-tests': 'error',
96 |
97 | 'jsx-a11y/label-has-associated-control': 'off',
98 | 'jsx-a11y/label-has-for': 'off',
99 | 'jsx-a11y/no-autofocus': 'off', // We are a library, people do what they want.
100 |
101 | 'prettier/prettier': ['error'],
102 | },
103 | };
104 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "material-ui": "react-swipeable-views-395e4"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | - [ ] I have searched the [issues](https://github.com/oliviertassinari/react-swipeable-views/issues) of this repository and believe that this is not a duplicate.
10 |
11 | ## Expected Behavior
12 |
16 |
17 | ## Current Behavior
18 |
22 |
23 | ## Steps to Reproduce (for bugs)
24 |
35 |
36 | 1.
37 | 2.
38 | 3.
39 | 4.
40 |
41 | ## Context
42 |
46 |
47 | ## Your Environment
48 |
49 |
50 | | Tech | Version |
51 | |------------------------|---------|
52 | | react-swipeable-views | |
53 | | React | |
54 | | platform | |
55 | | etc | |
56 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /.nyc_output
3 | /docs/export/
4 | /.next/
5 | lib/
6 | *.log
7 |
8 | .DS_Store
9 |
10 | node_modules/
11 | npm-debug.log
12 | yarn-error.log
13 | /.firebase
14 |
15 | .idea/
16 |
--------------------------------------------------------------------------------
/.size-limit:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | path: "packages/react-swipeable-views/lib/index.js",
4 | limit: "9 KB"
5 | },
6 | {
7 | path: "packages/react-swipeable-views-utils/lib/index.js",
8 | limit: "8 KB"
9 | },
10 | {
11 | path: "packages/react-swipeable-views-core/lib/index.js",
12 | limit: "4 KB"
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | All notable changes are described on the [Releases](https://github.com/oliviertassinari/react-swipeable-views/releases) page.
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2015 Olivier Tassinari
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-swipeable-views
2 |
3 | > A React component for swipeable views.
4 |
5 | | Package | Version | Download | Size (kB gzipped) |
6 | |---------|:--------|:---------|:------------------|
7 | | react-swipeable-views | [](https://www.npmjs.com/package/react-swipeable-views) | [](https://www.npmjs.com/package/react-swipeable-views) | 5.08 |
8 | | react-swipeable-views-utils | [](https://www.npmjs.com/package/react-swipeable-views-utils) | [](https://www.npmjs.com/package/react-swipeable-views-utils) | 3.52 |
9 | | react-swipeable-views-native | [](https://www.npmjs.com/package/react-swipeable-views-native) | [](https://www.npmjs.com/package/react-swipeable-views-native) | ? |
10 |
11 | [](https://travis-ci.org/oliviertassinari/react-swipeable-views)
12 | [](https://david-dm.org/oliviertassinari/react-swipeable-views)
13 | [](https://david-dm.org/oliviertassinari/react-swipeable-views#info=devDependencies&view=list)
14 | [](https://www.paypal.me/oliviertassinari/10)
15 | [](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-swipeable-views)
16 | [](https://codecov.io/gh/oliviertassinari/react-swipeable-views/branch/master)
17 |
18 | ## Documentation
19 | ### Get started
20 | - [Installation](https://react-swipeable-views.com/getting-started/installation/)
21 | - [Usage](https://react-swipeable-views.com/getting-started/usage/)
22 | - [Example projects](https://react-swipeable-views.com/getting-started/example-projects/)
23 | - [Supported projects](https://react-swipeable-views.com/getting-started/example-projects/)
24 | ### Component API
25 | - [Component API](https://react-swipeable-views.com/api/api/)
26 | ### More
27 | - [Supported projects](https://react-swipeable-views.com/getting-started/example-projects/)
28 | - [Demos](https://react-swipeable-views.com/demos/demos/)
29 |
30 | ## Installation
31 |
32 | ### Browser
33 |
34 | ```sh
35 | npm install --save react-swipeable-views
36 | ```
37 |
38 | ### Native (experimental)
39 |
40 | ```sh
41 | npm install --save react-swipeable-views-native
42 | ```
43 |
44 | ## The problem solved
45 |
46 | Check out the [demos](https://react-swipeable-views.com/demos/demos/) from a mobile device (real or emulated).
47 | It's tiny (<10 kB gzipped), it quickly renders the first slide, then lazy-loads the others.
48 |
49 | ## Simple example
50 |
51 | 
52 |
53 | ### Browser
54 |
55 | ```jsx
56 | import React from 'react';
57 | import SwipeableViews from 'react-swipeable-views';
58 |
59 | const styles = {
60 | slide: {
61 | padding: 15,
62 | minHeight: 100,
63 | color: '#fff',
64 | },
65 | slide1: {
66 | background: '#FEA900',
67 | },
68 | slide2: {
69 | background: '#B3DC4A',
70 | },
71 | slide3: {
72 | background: '#6AC0FF',
73 | },
74 | };
75 |
76 | const MyComponent = () => (
77 |
78 |
79 | slide n°1
80 |
81 |
82 | slide n°2
83 |
84 |
85 | slide n°3
86 |
87 |
88 | );
89 |
90 | export default MyComponent;
91 | ```
92 |
93 | ### Native (experimental)
94 |
95 | react-native support is experimental and I have no plan pushing it forward.
96 | I start to think that lower level abstraction to share the implementation between the platforms are more appropriate.
97 | We have two different implementations of the react-swipeable-views API.
98 |
99 | ```jsx
100 | import React from 'react';
101 | import {
102 | StyleSheet,
103 | Text,
104 | View,
105 | } from 'react-native';
106 |
107 | import SwipeableViews from 'react-swipeable-views-native';
108 | // There is another version using the scroll component instead of animated.
109 | // I'm unsure which one give the best UX. Please give us some feedback.
110 | // import SwipeableViews from 'react-swipeable-views-native/lib/SwipeableViews.scroll';
111 |
112 | const styles = StyleSheet.create({
113 | slideContainer: {
114 | height: 100,
115 | },
116 | slide: {
117 | padding: 15,
118 | height: 100,
119 | },
120 | slide1: {
121 | backgroundColor: '#FEA900',
122 | },
123 | slide2: {
124 | backgroundColor: '#B3DC4A',
125 | },
126 | slide3: {
127 | backgroundColor: '#6AC0FF',
128 | },
129 | text: {
130 | color: '#fff',
131 | fontSize: 16,
132 | },
133 | });
134 |
135 | const MyComponent = () => (
136 |
137 |
138 |
139 | slide n°1
140 |
141 |
142 |
143 |
144 | slide n°2
145 |
146 |
147 |
148 |
149 | slide n°3
150 |
151 |
152 |
153 | );
154 |
155 | export default MyComponent;
156 | ```
157 |
158 | ## Who's using react-swipeable-views?
159 |
160 | - [Doctolib](https://github.com/doctolib)
161 | - [mastodon](https://github.com/tootsuite/mastodon)
162 | - [Material-UI](https://github.com/mui-org/material-ui)
163 | - [Tinder](https://tinder.com)
164 | - [Uber](https://www.uber.com)
165 | - Are you using this library? Add your company or project.
166 |
167 | ## License
168 |
169 | This project is licensed under the terms of the
170 | [MIT license](https://github.com/oliviertassinari/react-swipeable-views/blob/master/LICENSE).
171 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SwipeableViewsDocs",
3 | "displayName": "SwipeableViewsDocs"
4 | }
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | let defaultPresets;
2 |
3 | // We release a ES version of Material-UI.
4 | // It's something that matches the latest official supported features of JavaScript.
5 | // Nothing more (stage-1, etc), nothing less (require, etc).
6 | if (process.env.BABEL_ENV === 'es') {
7 | defaultPresets = [];
8 | } else {
9 | defaultPresets = [
10 | [
11 | '@babel/preset-env',
12 | {
13 | targets: {
14 | ie: 10,
15 | edge: 14,
16 | firefox: 28,
17 | chrome: 29,
18 | safari: 9,
19 | node: '6.11',
20 | },
21 | modules: ['modules', 'production-umd'].includes(process.env.BABEL_ENV) ? false : 'commonjs',
22 | },
23 | ],
24 | ];
25 | }
26 |
27 | module.exports = {
28 | presets: defaultPresets.concat(['@babel/preset-react']),
29 | plugins: [
30 | ['@babel/plugin-proposal-class-properties', { loose: true }],
31 | [
32 | '@babel/plugin-proposal-object-rest-spread',
33 | {
34 | // Workaround for https://github.com/babel/babel/issues/8323
35 | loose: process.env.BABEL_ENV !== 'es',
36 | },
37 | ],
38 | '@babel/plugin-transform-object-assign',
39 | '@babel/plugin-transform-runtime',
40 | ],
41 | env: {
42 | coverage: {
43 | plugins: [
44 | 'babel-plugin-istanbul',
45 | [
46 | 'babel-plugin-module-resolver',
47 | {
48 | root: ['./'],
49 | alias: {
50 | pages: './pages',
51 | 'react-swipeable-views': './packages/react-swipeable-views/src',
52 | 'react-swipeable-views-utils': './packages/react-swipeable-views-utils/src',
53 | 'react-swipeable-views-core': './packages/react-swipeable-views-core/src',
54 | docs: './docs',
55 | },
56 | },
57 | ],
58 | ],
59 | },
60 | development: {},
61 | 'docs-development': {
62 | plugins: [
63 | 'babel-plugin-preval',
64 | [
65 | 'babel-plugin-module-resolver',
66 | {
67 | alias: {
68 | 'react-swipeable-views': './packages/react-swipeable-views/src',
69 | 'react-swipeable-views-core': './packages/react-swipeable-views-core/src',
70 | 'react-swipeable-views-utils': './packages/react-swipeable-views-utils/src',
71 | docs: './docs',
72 | pages: './pages',
73 | },
74 | },
75 | ],
76 | ],
77 | },
78 | 'docs-production': {
79 | plugins: [
80 | 'babel-plugin-preval',
81 | [
82 | 'babel-plugin-module-resolver',
83 | {
84 | alias: {
85 | 'react-swipeable-views': './packages/react-swipeable-views/src',
86 | 'react-swipeable-views-core': './packages/react-swipeable-views-core/src',
87 | 'react-swipeable-views-utils': './packages/react-swipeable-views-utils/src',
88 | docs: './docs',
89 | pages: './pages',
90 | },
91 | },
92 | ],
93 | 'transform-react-constant-elements',
94 | 'transform-dev-warning',
95 | ['react-remove-properties', { properties: ['data-mui-test'] }],
96 | ['transform-react-remove-prop-types', { mode: 'remove' }],
97 | ],
98 | },
99 | es: {
100 | plugins: [
101 | 'transform-react-constant-elements',
102 | 'transform-dev-warning',
103 | ['react-remove-properties', { properties: ['data-mui-test'] }],
104 | [
105 | 'transform-react-remove-prop-types',
106 | {
107 | mode: 'wrap',
108 | },
109 | ],
110 | ],
111 | // It's most likely a babel bug.
112 | // We are using this ignore option in the CLI command but that has no effect.
113 | ignore: ['**/*.test.js'],
114 | },
115 | production: {
116 | plugins: [
117 | 'transform-react-constant-elements',
118 | 'transform-dev-warning',
119 | ['react-remove-properties', { properties: ['data-mui-test'] }],
120 | [
121 | 'transform-react-remove-prop-types',
122 | {
123 | mode: 'wrap',
124 | },
125 | ],
126 | ],
127 | // It's most likely a babel bug.
128 | // We are using this ignore option in the CLI command but that has no effect.
129 | ignore: ['**/*.test.js'],
130 | },
131 | 'production-umd': {
132 | plugins: [
133 | 'transform-react-constant-elements',
134 | 'transform-dev-warning',
135 | ['react-remove-properties', { properties: ['data-mui-test'] }],
136 | [
137 | 'transform-react-remove-prop-types',
138 | {
139 | mode: 'wrap',
140 | },
141 | ],
142 | ],
143 | },
144 | test: {
145 | sourceMaps: 'both',
146 | plugins: [
147 | [
148 | 'babel-plugin-module-resolver',
149 | {
150 | root: ['./'],
151 | alias: {
152 | 'react-swipeable-views': './packages/react-swipeable-views/src',
153 | 'react-swipeable-views-core': './packages/react-swipeable-views-core/src',
154 | 'react-swipeable-views-utils': './packages/react-swipeable-views-utils/src',
155 | docs: './docs',
156 | pages: './pages',
157 | },
158 | },
159 | ],
160 | ],
161 | },
162 | },
163 | };
164 |
--------------------------------------------------------------------------------
/docs/src/modules/components/AppContent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classNames from 'classnames';
4 | import { withStyles } from '@material-ui/core/styles';
5 |
6 | const styles = theme => ({
7 | root: {
8 | paddingTop: 80,
9 | flex: '1 1 100%',
10 | maxWidth: '100%',
11 | margin: '0 auto',
12 | paddingLeft: theme.spacing.unit * 2,
13 | paddingRight: theme.spacing.unit * 2,
14 | [theme.breakpoints.up('sm')]: {
15 | paddingLeft: theme.spacing.unit * 4,
16 | paddingRight: theme.spacing.unit * 4,
17 | maxWidth: 'calc(100% - 162px)',
18 | },
19 | [theme.breakpoints.up('lg')]: {
20 | paddingLeft: theme.spacing.unit * 5,
21 | paddingRight: theme.spacing.unit * 9,
22 | maxWidth: 'calc(100% - 240px - 162px)',
23 | },
24 | },
25 | });
26 |
27 | function AppContent(props) {
28 | const { className, classes, children } = props;
29 |
30 | return {children} ;
31 | }
32 |
33 | AppContent.propTypes = {
34 | children: PropTypes.node.isRequired,
35 | classes: PropTypes.object.isRequired,
36 | className: PropTypes.string,
37 | };
38 |
39 | export default withStyles(styles)(AppContent);
40 |
--------------------------------------------------------------------------------
/docs/src/modules/components/AppDrawer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import PropTypes from 'prop-types';
4 | import { withStyles } from '@material-ui/core/styles';
5 | import List from '@material-ui/core/List';
6 | import Drawer from '@material-ui/core/Drawer';
7 | import SwipeableDrawer from '@material-ui/core/SwipeableDrawer';
8 | import Typography from '@material-ui/core/Typography';
9 | import Divider from '@material-ui/core/Divider';
10 | import Hidden from '@material-ui/core/Hidden';
11 | import AppDrawerNavItem from 'docs/src/modules/components/AppDrawerNavItem';
12 | import Link from 'docs/src/modules/components/Link';
13 | import { pageToTitle } from 'docs/src/modules/utils/helpers';
14 |
15 | const styles = theme => ({
16 | paper: {
17 | width: 240,
18 | backgroundColor: theme.palette.background.paper,
19 | },
20 | title: {
21 | color: theme.palette.text.secondary,
22 | marginBottom: theme.spacing.unit / 2,
23 | '&:hover': {
24 | color: theme.palette.primary.main,
25 | },
26 | },
27 | // https://github.com/philipwalton/flexbugs#3-min-height-on-a-flex-container-wont-apply-to-its-flex-items
28 | toolbarIe11: {
29 | display: 'flex',
30 | },
31 | toolbar: {
32 | ...theme.mixins.toolbar,
33 | paddingLeft: theme.spacing.unit * 3,
34 | display: 'flex',
35 | flexGrow: 1,
36 | flexDirection: 'column',
37 | alignItems: 'flex-start',
38 | justifyContent: 'center',
39 | },
40 | anchor: {
41 | color: theme.palette.text.secondary,
42 | },
43 | });
44 |
45 | // eslint-disable-next-line react/prop-types
46 | function renderNavItems({ pages, ...params }) {
47 | return (
48 |
49 | {pages.reduce(
50 | // eslint-disable-next-line no-use-before-define
51 | (items, page) => reduceChildRoutes({ items, page, ...params }),
52 | [],
53 | )}
54 |
55 | );
56 | }
57 |
58 | function reduceChildRoutes({ props, activePage, items, page, depth }) {
59 | if (page.displayNav === false) {
60 | return items;
61 | }
62 |
63 | if (page.children && page.children.length > 1) {
64 | const title = pageToTitle(page);
65 | const openImmediately = activePage.pathname.indexOf(`${page.pathname}/`) === 0;
66 |
67 | items.push(
68 |
69 | {renderNavItems({ props, pages: page.children, activePage, depth: depth + 1 })}
70 | ,
71 | );
72 | } else {
73 | const title = pageToTitle(page);
74 | page = page.children && page.children.length === 1 ? page.children[0] : page;
75 |
76 | items.push(
77 | ,
84 | );
85 | }
86 |
87 | return items;
88 | }
89 |
90 | // iOS is hosted on high-end devices. We can enable the backdrop transition without
91 | // dropping frames. The performance will be good enough.
92 | // So:
93 | const iOS = process.browser && /iPad|iPhone|iPod/.test(navigator.userAgent);
94 |
95 | function AppDrawer(props, context) {
96 | const { classes, className, disablePermanent, mobileOpen, onClose, onOpen } = props;
97 |
98 | const drawer = (
99 |
100 |
101 |
102 |
103 |
104 | react-swipeable-views
105 |
106 |
107 | {process.env.LIB_VERSION ? (
108 |
109 | {`v${process.env.LIB_VERSION}`}
110 |
111 | ) : null}
112 |
113 |
114 |
115 | {renderNavItems({ props, pages: context.pages, activePage: context.activePage, depth: 0 })}
116 |
117 | );
118 |
119 | return (
120 |
121 |
122 |
135 | {drawer}
136 |
137 |
138 | {disablePermanent ? null : (
139 |
140 |
147 | {drawer}
148 |
149 |
150 | )}
151 |
152 | );
153 | }
154 |
155 | AppDrawer.propTypes = {
156 | classes: PropTypes.object.isRequired,
157 | className: PropTypes.string,
158 | disablePermanent: PropTypes.bool.isRequired,
159 | mobileOpen: PropTypes.bool.isRequired,
160 | onClose: PropTypes.func.isRequired,
161 | onOpen: PropTypes.func.isRequired,
162 | };
163 |
164 | AppDrawer.contextTypes = {
165 | activePage: PropTypes.object.isRequired,
166 | pages: PropTypes.array.isRequired,
167 | };
168 |
169 | export default withStyles(styles)(AppDrawer);
170 |
--------------------------------------------------------------------------------
/docs/src/modules/components/AppDrawerNavItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classNames from 'classnames';
4 | import { withStyles } from '@material-ui/core/styles';
5 | import ListItem from '@material-ui/core/ListItem';
6 | import Button from '@material-ui/core/Button';
7 | import Collapse from '@material-ui/core/Collapse';
8 | import Link from 'docs/src/modules/components/Link';
9 |
10 | const styles = theme => ({
11 | item: {
12 | display: 'block',
13 | paddingTop: 0,
14 | paddingBottom: 0,
15 | },
16 | itemLeaf: {
17 | display: 'flex',
18 | paddingTop: 0,
19 | paddingBottom: 0,
20 | },
21 | button: {
22 | justifyContent: 'flex-start',
23 | textTransform: 'none',
24 | width: '100%',
25 | },
26 | buttonLeaf: {
27 | justifyContent: 'flex-start',
28 | textTransform: 'none',
29 | width: '100%',
30 | fontWeight: theme.typography.fontWeightRegular,
31 | '&.depth-0': {
32 | fontWeight: theme.typography.fontWeightMedium,
33 | },
34 | },
35 | active: {
36 | color: theme.palette.primary.main,
37 | fontWeight: theme.typography.fontWeightMedium,
38 | },
39 | });
40 |
41 | class AppDrawerNavItem extends React.Component {
42 | state = {
43 | open: this.props.openImmediately,
44 | };
45 |
46 | componentDidMount() {
47 | // So we only run this logic once.
48 | if (!this.props.openImmediately) {
49 | return;
50 | }
51 |
52 | // Center the selected item in the list container.
53 | const activeElement = document.querySelector(`.${this.props.classes.active}`);
54 | if (activeElement && activeElement.scrollIntoView) {
55 | activeElement.scrollIntoView({});
56 | }
57 | }
58 |
59 | handleClick = () => {
60 | this.setState(state => ({ open: !state.open }));
61 | };
62 |
63 | render() {
64 | const {
65 | children,
66 | classes,
67 | depth,
68 | href,
69 | onClick,
70 | openImmediately,
71 | title,
72 | ...other
73 | } = this.props;
74 |
75 | const style = {
76 | paddingLeft: 8 * (3 + 2 * depth),
77 | };
78 |
79 | if (href) {
80 | return (
81 |
82 | (
84 |
85 | )}
86 | className={classNames(classes.buttonLeaf, `depth-${depth}`)}
87 | disableRipple
88 | onClick={onClick}
89 | style={style}
90 | >
91 | {title}
92 |
93 |
94 | );
95 | }
96 |
97 | return (
98 |
99 |
107 | {title}
108 |
109 |
110 | {children}
111 |
112 |
113 | );
114 | }
115 | }
116 |
117 | AppDrawerNavItem.propTypes = {
118 | children: PropTypes.node,
119 | classes: PropTypes.object.isRequired,
120 | depth: PropTypes.number.isRequired,
121 | href: PropTypes.string,
122 | onClick: PropTypes.func,
123 | openImmediately: PropTypes.bool,
124 | title: PropTypes.string.isRequired,
125 | };
126 |
127 | AppDrawerNavItem.defaultProps = {
128 | openImmediately: false,
129 | };
130 |
131 | export default withStyles(styles)(AppDrawerNavItem);
132 |
--------------------------------------------------------------------------------
/docs/src/modules/components/AppFrame.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import NProgress from 'nprogress';
4 | import Router from 'next/router';
5 | import { withStyles } from '@material-ui/core/styles';
6 | import Typography from '@material-ui/core/Typography';
7 | import AppBar from '@material-ui/core/AppBar';
8 | import Toolbar from '@material-ui/core/Toolbar';
9 | import IconButton from '@material-ui/core/IconButton';
10 | import Tooltip from '@material-ui/core/Tooltip';
11 | import CssBaseline from '@material-ui/core/CssBaseline';
12 | import MenuIcon from '@material-ui/icons/Menu';
13 | import NProgressBar from '@material-ui/docs/NProgressBar';
14 | import GithubIcon from '@material-ui/docs/svgIcons/GitHub';
15 | import AppDrawer from 'docs/src/modules/components/AppDrawer';
16 | import { pageToTitle } from 'docs/src/modules/utils/helpers';
17 |
18 | Router.onRouteChangeStart = () => {
19 | NProgress.start();
20 | };
21 |
22 | Router.onRouteChangeComplete = () => {
23 | NProgress.done();
24 | };
25 |
26 | Router.onRouteChangeError = () => {
27 | NProgress.done();
28 | };
29 |
30 | const styles = theme => ({
31 | root: {
32 | display: 'flex',
33 | },
34 | grow: {
35 | flex: '1 1 auto',
36 | },
37 | title: {
38 | marginLeft: 24,
39 | flex: '0 1 auto',
40 | },
41 | appBar: {
42 | transition: theme.transitions.create('width'),
43 | '@media print': {
44 | position: 'absolute',
45 | },
46 | },
47 | appBarHome: {
48 | boxShadow: 'none',
49 | },
50 | appBarShift: {
51 | [theme.breakpoints.up('lg')]: {
52 | width: 'calc(100% - 240px)',
53 | },
54 | },
55 | drawer: {
56 | [theme.breakpoints.up('lg')]: {
57 | width: 240,
58 | },
59 | },
60 | navIconHide: {
61 | [theme.breakpoints.up('lg')]: {
62 | display: 'none',
63 | },
64 | },
65 | });
66 |
67 | class AppFrame extends React.Component {
68 | state = {
69 | mobileOpen: false,
70 | };
71 |
72 | handleDrawerOpen = () => {
73 | this.setState({ mobileOpen: true });
74 | };
75 |
76 | handleDrawerClose = () => {
77 | this.setState({ mobileOpen: false });
78 | };
79 |
80 | render() {
81 | const { children, classes } = this.props;
82 |
83 | if (!this.context.activePage) {
84 | throw new Error('Missing activePage.');
85 | }
86 |
87 | const title =
88 | this.context.activePage.title !== false ? pageToTitle(this.context.activePage) : null;
89 |
90 | let disablePermanent = false;
91 | let navIconClassName = '';
92 | let appBarClassName = classes.appBar;
93 |
94 | if (title === null) {
95 | // home route, don't shift app bar or dock drawer
96 | disablePermanent = true;
97 | appBarClassName += ` ${classes.appBarHome}`;
98 | } else {
99 | navIconClassName = classes.navIconHide;
100 | appBarClassName += ` ${classes.appBarShift}`;
101 | }
102 |
103 | return (
104 |
105 |
106 |
107 |
108 |
109 |
115 |
116 |
117 | {title !== null && (
118 |
119 | {title}
120 |
121 | )}
122 |
123 |
124 |
130 |
131 |
132 |
133 |
134 |
135 |
142 | {children}
143 |
144 | );
145 | }
146 | }
147 |
148 | AppFrame.propTypes = {
149 | children: PropTypes.node.isRequired,
150 | classes: PropTypes.object.isRequired,
151 | };
152 |
153 | AppFrame.contextTypes = {
154 | activePage: PropTypes.shape({
155 | pathname: PropTypes.string.isRequired,
156 | }).isRequired,
157 | };
158 |
159 | export default withStyles(styles)(AppFrame);
160 |
--------------------------------------------------------------------------------
/docs/src/modules/components/AppTableOfContents.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/no-danger */
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import Link from 'docs/src/modules/components/Link';
6 | import marked from 'marked';
7 | import throttle from 'lodash/throttle';
8 | import EventListener from 'react-event-listener';
9 | import { withStyles } from '@material-ui/core/styles';
10 | import Typography from '@material-ui/core/Typography';
11 | import { textToHash } from 'docs/src/modules/components/MarkdownElement';
12 |
13 | const renderer = new marked.Renderer();
14 |
15 | let itemsServer = null;
16 | renderer.heading = (text, level) => {
17 | if (level === 1 || level > 3) {
18 | return;
19 | }
20 |
21 | if (level === 2) {
22 | itemsServer.push({
23 | text,
24 | level,
25 | hash: textToHash(text),
26 | children: [],
27 | });
28 | }
29 |
30 | if (level === 3) {
31 | itemsServer[itemsServer.length - 1].children.push({
32 | text,
33 | level,
34 | hash: textToHash(text),
35 | });
36 | }
37 | };
38 |
39 | const styles = theme => ({
40 | root: {
41 | top: 70,
42 | width: 162,
43 | flexShrink: 0,
44 | order: 2,
45 | position: 'sticky',
46 | wordBreak: 'break-word',
47 | height: 'calc(100vh - 70px)',
48 | overflowY: 'auto',
49 | padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 2}px ${theme.spacing.unit *
50 | 2}px 0`,
51 | display: 'none',
52 | [theme.breakpoints.up('sm')]: {
53 | display: 'block',
54 | },
55 | },
56 | contents: {
57 | marginTop: theme.spacing.unit * 2,
58 | },
59 | ul: {
60 | padding: 0,
61 | margin: 0,
62 | listStyleType: 'none',
63 | },
64 | item: {
65 | fontSize: 13,
66 | padding: `${theme.spacing.unit / 2}px 0`,
67 | },
68 | });
69 |
70 | class AppTableOfContents extends React.Component {
71 | handleScroll = throttle(() => {
72 | this.findActiveIndex();
73 | }, 166); // Corresponds to 10 frames at 60 Hz.
74 |
75 | constructor(props) {
76 | super(props);
77 | itemsServer = [];
78 | marked(props.contents.join(''), {
79 | renderer,
80 | });
81 | }
82 |
83 | state = {
84 | active: null,
85 | };
86 |
87 | componentDidMount() {
88 | this.itemsClient = [];
89 |
90 | itemsServer.forEach(item2 => {
91 | this.itemsClient.push({
92 | ...item2,
93 | node: document.getElementById(item2.hash),
94 | });
95 |
96 | if (item2.children.length > 0) {
97 | item2.children.forEach(item3 => {
98 | this.itemsClient.push({
99 | ...item3,
100 | node: document.getElementById(item3.hash),
101 | });
102 | });
103 | }
104 | });
105 |
106 | this.findActiveIndex();
107 | }
108 |
109 | componentWillUnmount() {
110 | this.handleScroll.cancel();
111 | }
112 |
113 | findActiveIndex = () => {
114 | let active;
115 |
116 | for (let i = 0; i < this.itemsClient.length; i += 1) {
117 | const item = this.itemsClient[i];
118 | if (
119 | document.documentElement.scrollTop < item.node.offsetTop + 100 ||
120 | i === this.itemsClient.length - 1
121 | ) {
122 | active = item;
123 | break;
124 | }
125 | }
126 |
127 | if (active && this.state.active !== active.hash) {
128 | this.setState({
129 | active: active.hash,
130 | });
131 | }
132 | };
133 |
134 | render() {
135 | const { classes } = this.props;
136 | const { active } = this.state;
137 |
138 | return (
139 |
140 | {itemsServer.length > 0 ? (
141 |
142 |
143 | Contents
144 |
145 |
146 |
147 | {itemsServer.map(item2 => (
148 |
149 | (
153 |
154 | )}
155 | >
156 |
157 |
158 | {item2.children.length > 0 ? (
159 |
160 | {item2.children.map(item3 => (
161 |
162 | (
169 |
170 | )}
171 | >
172 |
173 |
174 |
175 | ))}
176 |
177 | ) : null}
178 |
179 | ))}
180 |
181 |
182 | ) : null}
183 |
184 | );
185 | }
186 | }
187 |
188 | AppTableOfContents.propTypes = {
189 | classes: PropTypes.object.isRequired,
190 | contents: PropTypes.array.isRequired,
191 | };
192 |
193 | export default withStyles(styles)(AppTableOfContents);
194 |
--------------------------------------------------------------------------------
/docs/src/modules/components/AppWrapper.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-underscore-dangle */
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import { MuiThemeProvider } from '@material-ui/core/styles';
6 | import JssProvider from 'react-jss/lib/JssProvider';
7 | import { lightTheme, setPrismTheme } from 'docs/src/modules/components/prism';
8 | import getPageContext from 'docs/src/modules/styles/getPageContext';
9 |
10 | // Inject the insertion-point-jss after docssearch
11 | if (process.browser && !global.__INSERTION_POINT__) {
12 | global.__INSERTION_POINT__ = true;
13 | const styleNode = document.createComment('insertion-point-jss');
14 | const docsearchStylesSheet = document.querySelector('#insertion-point-jss');
15 |
16 | if (document.head && docsearchStylesSheet) {
17 | document.head.insertBefore(styleNode, docsearchStylesSheet.nextSibling);
18 | }
19 | }
20 |
21 | class AppWrapper extends React.Component {
22 | state = {};
23 |
24 | componentDidMount() {
25 | // Remove the server-side injected CSS.
26 | const jssStyles = document.querySelector('#jss-server-side');
27 | if (jssStyles && jssStyles.parentNode) {
28 | jssStyles.parentNode.removeChild(jssStyles);
29 | }
30 |
31 | setPrismTheme(lightTheme);
32 | }
33 |
34 | static getDerivedStateFromProps(nextProps, prevState) {
35 | if (typeof prevState.pageContext === 'undefined') {
36 | return {
37 | pageContext: nextProps.pageContext || getPageContext(),
38 | };
39 | }
40 |
41 | return null;
42 | }
43 |
44 | render() {
45 | const { children } = this.props;
46 | const { pageContext } = this.state;
47 |
48 | return (
49 |
54 |
55 | {children}
56 |
57 |
58 | );
59 | }
60 | }
61 |
62 | AppWrapper.propTypes = {
63 | children: PropTypes.node.isRequired,
64 | // eslint-disable-next-line react/no-unused-prop-types
65 | pageContext: PropTypes.object,
66 | };
67 |
68 | export default AppWrapper;
69 |
--------------------------------------------------------------------------------
/docs/src/modules/components/Head.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NextHead from 'next/head';
3 | import PropTypes from 'prop-types';
4 |
5 | function Head(props) {
6 | const { title, description } = props;
7 |
8 | return (
9 |
10 | {title}
11 |
12 | {/* Twitter */}
13 |
14 |
15 |
16 |
17 |
21 | {/* Facebook */}
22 |
23 |
24 |
25 |
29 |
30 |
31 | );
32 | }
33 |
34 | Head.propTypes = {
35 | description: PropTypes.string,
36 | title: PropTypes.string,
37 | };
38 |
39 | Head.defaultProps = {
40 | description: 'A React component for swipeable views.',
41 | title: 'react-swipeable-views',
42 | };
43 |
44 | export default Head;
45 |
--------------------------------------------------------------------------------
/docs/src/modules/components/Link.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classNames from 'classnames';
4 | import compose from 'recompose/compose';
5 | import { withRouter } from 'next/router';
6 | import NextLink from 'next/link';
7 | import { withStyles } from '@material-ui/core/styles';
8 |
9 | const styles = theme => ({
10 | root: {
11 | textDecoration: 'none',
12 | '&:hover': {
13 | textDecoration: 'underline',
14 | },
15 | },
16 | default: {
17 | color: 'inherit',
18 | },
19 | primary: {
20 | color: theme.palette.primary.main,
21 | },
22 | secondary: {
23 | color: theme.palette.secondary.main,
24 | },
25 | button: {
26 | '&:hover': {
27 | textDecoration: 'inherit',
28 | },
29 | },
30 | });
31 |
32 | class OnClick extends React.Component {
33 | handleClick = event => {
34 | if (this.props.onClick) {
35 | this.props.onClick(event);
36 | }
37 |
38 | if (this.props.onCustomClick) {
39 | this.props.onCustomClick(event);
40 | }
41 | };
42 |
43 | render() {
44 | const { component: ComponentProp, onCustomClick, ...props } = this.props;
45 | return ;
46 | }
47 | }
48 |
49 | OnClick.propTypes = {
50 | component: PropTypes.string.isRequired,
51 | onClick: PropTypes.func,
52 | onCustomClick: PropTypes.func,
53 | };
54 |
55 | function Link(props) {
56 | const {
57 | activeClassName,
58 | children: childrenProp,
59 | classes,
60 | className: classNameProp,
61 | component: ComponentProp,
62 | href,
63 | onClick,
64 | prefetch,
65 | router,
66 | variant,
67 | ...other
68 | } = props;
69 |
70 | let ComponentRoot;
71 | const className = classNames(classes.root, classes[variant], classNameProp);
72 | let RootProps;
73 | let children = childrenProp;
74 |
75 | if (ComponentProp) {
76 | ComponentRoot = ComponentProp;
77 | RootProps = {
78 | ...other,
79 | className,
80 | };
81 | } else if (href) {
82 | ComponentRoot = NextLink;
83 | RootProps = {
84 | href,
85 | prefetch,
86 | passHref: true,
87 | };
88 | children = (
89 |
97 | {children}
98 |
99 | );
100 | } else {
101 | ComponentRoot = 'a';
102 | RootProps = {
103 | ...other,
104 | className,
105 | };
106 | }
107 |
108 | return {children} ;
109 | }
110 |
111 | Link.defaultProps = {
112 | variant: 'default',
113 | activeClassName: 'active',
114 | };
115 |
116 | Link.propTypes = {
117 | activeClassName: PropTypes.string,
118 | children: PropTypes.node.isRequired,
119 | classes: PropTypes.object.isRequired,
120 | className: PropTypes.string,
121 | component: PropTypes.any,
122 | href: PropTypes.string,
123 | onClick: PropTypes.func,
124 | prefetch: PropTypes.bool,
125 | router: PropTypes.shape({
126 | pathname: PropTypes.string.isRequired,
127 | }).isRequired,
128 | variant: PropTypes.oneOf(['default', 'primary', 'secondary', 'button']),
129 | };
130 |
131 | export default compose(
132 | withRouter,
133 | withStyles(styles),
134 | )(Link);
135 |
--------------------------------------------------------------------------------
/docs/src/modules/components/MarkdownDocs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import kebabCase from 'lodash/kebabCase';
4 | import warning from 'warning';
5 | import { withStyles } from '@material-ui/core/styles';
6 | import Button from '@material-ui/core/Button';
7 | import MarkdownElement from 'docs/src/modules/components/MarkdownElement';
8 | import Head from 'docs/src/modules/components/Head';
9 | import AppContent from 'docs/src/modules/components/AppContent';
10 | import Demo from 'docs/src/modules/components/Demo';
11 | import AppFrame from 'docs/src/modules/components/AppFrame';
12 | import AppTableOfContents from 'docs/src/modules/components/AppTableOfContents';
13 | import {
14 | getHeaders,
15 | getContents,
16 | getTitle,
17 | getDescription,
18 | } from 'docs/src/modules/utils/parseMarkdown';
19 |
20 | const styles = theme => ({
21 | root: {
22 | marginBottom: 100,
23 | },
24 | header: {
25 | display: 'flex',
26 | flexDirection: 'column',
27 | alignItems: 'flex-end',
28 | },
29 | markdownElement: {
30 | marginTop: theme.spacing.unit * 2,
31 | marginBottom: theme.spacing.unit * 2,
32 | padding: `0 ${theme.spacing.unit}px`,
33 | },
34 | });
35 |
36 | const demoRegexp = /^"demo": "(.*)"/;
37 | const SOURCE_CODE_ROOT_URL =
38 | 'https://github.com/oliviertassinari/react-swipeable-views/tree/master';
39 |
40 | function MarkdownDocs(props, context) {
41 | const { classes, demos, disableAd, markdown, markdownLocation: markdownLocationProp } = props;
42 | const contents = getContents(markdown);
43 | const headers = getHeaders(markdown);
44 |
45 | let markdownLocation = markdownLocationProp || context.activePage.pathname;
46 |
47 | if (!markdownLocationProp) {
48 | const token = markdownLocation.split('/');
49 | token.push(token[token.length - 1]);
50 | markdownLocation = token.join('/');
51 |
52 | if (headers.filename) {
53 | markdownLocation = headers.filename;
54 | } else {
55 | markdownLocation = `/docs/src/pages${markdownLocation}.md`;
56 | }
57 | }
58 |
59 | if (headers.components.length > 0) {
60 | const section = markdownLocation.split('/')[4];
61 | contents.push(`
62 | ## API
63 |
64 | ${headers.components
65 | .map(
66 | component =>
67 | `- [<${component} />](${section === 'lab' ? '/lab/api' : '/api'}/${kebabCase(
68 | component,
69 | )})`,
70 | )
71 | .join('\n')}
72 | `);
73 | }
74 |
75 | return (
76 |
77 |
81 |
82 |
83 |
84 |
85 | {'Edit this page'}
86 |
87 |
88 | {contents.map((content, index) => {
89 | const match = content.match(demoRegexp);
90 |
91 | if (match && demos) {
92 | const demoOptions = JSON.parse(`{${content}}`);
93 |
94 | const name = demoOptions.demo;
95 | warning(demos && demos[name], `Missing demo: ${name}.`);
96 | return (
97 |
105 | );
106 | }
107 |
108 | return (
109 |
110 | );
111 | })}
112 |
113 |
114 | );
115 | }
116 |
117 | MarkdownDocs.propTypes = {
118 | classes: PropTypes.object.isRequired,
119 | demos: PropTypes.object,
120 | disableAd: PropTypes.bool,
121 | markdown: PropTypes.string.isRequired,
122 | // You can define the direction location of the markdown file.
123 | // Otherwise, we try to determine it with an heuristic.
124 | markdownLocation: PropTypes.string,
125 | };
126 |
127 | MarkdownDocs.defaultProps = {
128 | disableAd: false,
129 | };
130 |
131 | MarkdownDocs.contextTypes = {
132 | activePage: PropTypes.shape({
133 | pathname: PropTypes.string.isRequired,
134 | }).isRequired,
135 | };
136 |
137 | export default withStyles(styles)(MarkdownDocs);
138 |
--------------------------------------------------------------------------------
/docs/src/modules/components/Pagination.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import PaginationDot from './PaginationDot';
4 |
5 | const styles = {
6 | root: {
7 | position: 'absolute',
8 | bottom: 8,
9 | right: 8,
10 | display: 'flex',
11 | flexDirection: 'row',
12 | },
13 | };
14 |
15 | class Pagination extends React.Component {
16 | handleClick = (event, index) => {
17 | this.props.onChangeIndex(index);
18 | };
19 |
20 | render() {
21 | const { index, dots } = this.props;
22 |
23 | const children = [];
24 |
25 | for (let i = 0; i < dots; i += 1) {
26 | children.push(
27 | ,
28 | );
29 | }
30 |
31 | return {children}
;
32 | }
33 | }
34 |
35 | Pagination.propTypes = {
36 | dots: PropTypes.number.isRequired,
37 | index: PropTypes.number.isRequired,
38 | onChangeIndex: PropTypes.func.isRequired,
39 | };
40 |
41 | export default Pagination;
42 |
--------------------------------------------------------------------------------
/docs/src/modules/components/PaginationDot.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const styles = {
5 | root: {
6 | height: 18,
7 | width: 18,
8 | cursor: 'pointer',
9 | border: 0,
10 | background: 'none',
11 | padding: 0,
12 | },
13 | dot: {
14 | backgroundColor: '#e4e6e7',
15 | height: 12,
16 | width: 12,
17 | borderRadius: 6,
18 | margin: 3,
19 | },
20 | active: {
21 | backgroundColor: '#319fd6',
22 | },
23 | };
24 |
25 | class PaginationDot extends React.Component {
26 | handleClick = event => {
27 | this.props.onClick(event, this.props.index);
28 | };
29 |
30 | render() {
31 | const { active } = this.props;
32 |
33 | let styleDot;
34 |
35 | if (active) {
36 | styleDot = Object.assign({}, styles.dot, styles.active);
37 | } else {
38 | styleDot = styles.dot;
39 | }
40 |
41 | return (
42 |
43 |
44 |
45 | );
46 | }
47 | }
48 |
49 | PaginationDot.propTypes = {
50 | active: PropTypes.bool.isRequired,
51 | index: PropTypes.number.isRequired,
52 | onClick: PropTypes.func.isRequired,
53 | };
54 |
55 | export default PaginationDot;
56 |
--------------------------------------------------------------------------------
/docs/src/modules/components/prism.js:
--------------------------------------------------------------------------------
1 | import prism from 'prismjs';
2 | import 'prismjs/components/prism-css';
3 | import 'prismjs/components/prism-diff';
4 | import 'prismjs/components/prism-javascript';
5 | import 'prismjs/components/prism-jsx';
6 | import 'prismjs/components/prism-markup';
7 | import 'prismjs/components/prism-typescript';
8 | import lightTheme from 'prismjs/themes/prism.css';
9 | import darkTheme from 'prismjs/themes/prism-okaidia.css';
10 |
11 | export { lightTheme, darkTheme };
12 |
13 | let styleNode;
14 |
15 | if (process.browser) {
16 | styleNode = document.createElement('style');
17 | styleNode.setAttribute('data-prism', 'true');
18 | if (document.head) {
19 | document.head.appendChild(styleNode);
20 | }
21 | }
22 |
23 | export function setPrismTheme(theme) {
24 | styleNode.textContent = theme;
25 | }
26 |
27 | export default prism;
28 |
--------------------------------------------------------------------------------
/docs/src/modules/components/withRoot.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import find from 'lodash/find';
4 | import { withRouter } from 'next/router';
5 | import AppWrapper from 'docs/src/modules/components/AppWrapper';
6 |
7 | const pages = [
8 | {
9 | pathname: '/getting-started',
10 | children: [
11 | {
12 | pathname: '/getting-started/installation',
13 | },
14 | {
15 | pathname: '/getting-started/usage',
16 | },
17 | {
18 | pathname: '/getting-started/example-projects',
19 | },
20 | {
21 | pathname: '/getting-started/supported-platforms',
22 | },
23 | ],
24 | },
25 | {
26 | pathname: '/demos',
27 | title: 'Component Demos',
28 | children: [
29 | {
30 | pathname: '/demos/demos',
31 | },
32 | ],
33 | },
34 | {
35 | pathname: '/api',
36 | title: 'Component API',
37 | children: [
38 | {
39 | pathname: '/api/api',
40 | },
41 | ],
42 | },
43 | {
44 | pathname: '/',
45 | displayNav: false,
46 | title: false,
47 | },
48 | ];
49 |
50 | function findActivePage(currentPages, router) {
51 | const activePage = find(currentPages, page => {
52 | if (page.children) {
53 | return router.pathname.indexOf(`${page.pathname}/`) === 0;
54 | }
55 |
56 | // Should be an exact match if no children
57 | return router.pathname === page.pathname;
58 | });
59 |
60 | if (!activePage) {
61 | return null;
62 | }
63 |
64 | // We need to drill down
65 | if (activePage.pathname !== router.pathname) {
66 | return findActivePage(activePage.children, router);
67 | }
68 |
69 | return activePage;
70 | }
71 |
72 | function withRoot(Component) {
73 | class WithRoot extends React.Component {
74 | getChildContext() {
75 | const { router } = this.props;
76 |
77 | let pathname = router.pathname;
78 | if (pathname !== '/') {
79 | // The leading / is only added to support static hosting (resolve /index.html).
80 | // We remove it to normalize the pathname.
81 | pathname = pathname.replace(/\/$/, '');
82 | }
83 |
84 | return {
85 | pages,
86 | activePage: findActivePage(pages, { ...router, pathname }),
87 | };
88 | }
89 |
90 | render() {
91 | const { pageContext, ...other } = this.props;
92 | return (
93 |
94 |
95 |
96 |
97 |
98 | );
99 | }
100 | }
101 |
102 | WithRoot.propTypes = {
103 | pageContext: PropTypes.object,
104 | router: PropTypes.object.isRequired,
105 | };
106 |
107 | WithRoot.childContextTypes = {
108 | pages: PropTypes.array,
109 | activePage: PropTypes.object,
110 | };
111 |
112 | return withRouter(WithRoot);
113 | }
114 |
115 | export default withRoot;
116 |
--------------------------------------------------------------------------------
/docs/src/modules/styles/getPageContext.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-underscore-dangle */
2 |
3 | import { create, SheetsRegistry } from 'jss';
4 | import preset from 'jss-preset-default';
5 | import { createMuiTheme } from '@material-ui/core/styles';
6 | import amber from '@material-ui/core/colors/amber';
7 | import pink from '@material-ui/core/colors/pink';
8 | import createGenerateClassName from '@material-ui/core/styles/createGenerateClassName';
9 |
10 | function getTheme(theme) {
11 | return createMuiTheme({
12 | direction: theme.direction,
13 | palette: {
14 | primary: amber,
15 | secondary: pink,
16 | type: theme.paletteType,
17 | },
18 | nprogress: {
19 | color: amber[500],
20 | },
21 | });
22 | }
23 |
24 | const theme = getTheme({
25 | direction: 'ltr',
26 | paletteType: 'light',
27 | });
28 |
29 | // Configure JSS
30 | const jss = create(preset());
31 | jss.options.createGenerateClassName = createGenerateClassName;
32 | jss.options.insertionPoint = 'insertion-point-jss';
33 |
34 | function createContext() {
35 | return {
36 | jss,
37 | theme,
38 | // This is needed in order to deduplicate the injection of CSS in the page.
39 | sheetsManager: new Map(),
40 | // This is needed in order to inject the critical CSS.
41 | sheetsRegistry: new SheetsRegistry(),
42 | generateClassName: jss.options.createGenerateClassName(),
43 | };
44 | }
45 |
46 | export default function getPageContext() {
47 | // Make sure to create a new store for every server-side request so that data
48 | // isn't shared between connections (which would be bad)
49 | if (!process.browser) {
50 | return createContext();
51 | }
52 |
53 | // Reuse context on the client-side
54 | if (!global.__INIT_MATERIAL_UI__) {
55 | global.__INIT_MATERIAL_UI__ = createContext();
56 | }
57 |
58 | return global.__INIT_MATERIAL_UI__;
59 | }
60 |
--------------------------------------------------------------------------------
/docs/src/modules/utils/find.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const markdownRegex = /\.md$/;
5 |
6 | // Returns the markdowns of the documentation in a flat array.
7 | function findPagesMarkdown(
8 | directory = path.resolve(__dirname, '../../../src/pages'),
9 | pagesMarkdown = []
10 | ) {
11 | const items = fs.readdirSync(directory);
12 |
13 | items.forEach(item => {
14 | const itemPath = path.resolve(directory, item);
15 |
16 | if (fs.statSync(itemPath).isDirectory()) {
17 | findPagesMarkdown(itemPath, pagesMarkdown);
18 | return;
19 | }
20 |
21 | if (!markdownRegex.test(item)) {
22 | return;
23 | }
24 | let pathname = itemPath
25 | .replace(new RegExp(`\\${path.sep}`, 'g'), '/')
26 | .replace(/^.*\/pages/, '')
27 | .replace('.md', '');
28 |
29 | if (pathname.indexOf('/demos') === 0) {
30 | pathname = pathname
31 | .split('/')
32 | .slice(0, 3)
33 | .join('/');
34 | }
35 |
36 | pagesMarkdown.push({
37 | // Relative location in the path (URL) system.
38 | pathname,
39 | // Relative location in the file system.
40 | filename: itemPath,
41 | });
42 | });
43 |
44 | return pagesMarkdown;
45 | }
46 |
47 | const componentRegex = /^([A-Z][a-z]+)+\.js/;
48 |
49 | // Returns the component source in a flat array.
50 | function findComponents(directory = path.resolve(__dirname, '../../../../src'), components = []) {
51 | const items = fs.readdirSync(directory);
52 |
53 | items.forEach(item => {
54 | const itemPath = path.resolve(directory, item);
55 |
56 | if (fs.statSync(itemPath).isDirectory()) {
57 | findComponents(itemPath, components);
58 | return;
59 | }
60 |
61 | if (!componentRegex.test(item)) {
62 | return;
63 | }
64 |
65 | components.push({
66 | filename: itemPath,
67 | });
68 | });
69 |
70 | return components;
71 | }
72 |
73 | const jsRegex = /\.js$/;
74 | const blackList = ['/.eslintrc', '/_document'];
75 |
76 | // Returns the next.js pages available in a nested format.
77 | function findPages(
78 | options = {},
79 | directory = path.resolve(__dirname, '../../../../pages'),
80 | pages = []
81 | ) {
82 | fs.readdirSync(directory).forEach(item => {
83 | const itemPath = path.resolve(directory, item);
84 | const pathname = itemPath
85 | .replace(new RegExp(`\\${path.sep}`, 'g'), '/')
86 | .replace(/^.*\/pages/, '')
87 | .replace('.js', '')
88 | .replace(/^\/index$/, '/') // Replace `index` by `/`.
89 | .replace(/\/index$/, '');
90 |
91 | if (options.front && pathname.indexOf('/demos') === -1 && pathname.indexOf('/api') === -1) {
92 | return;
93 | }
94 |
95 | if (fs.statSync(itemPath).isDirectory()) {
96 | const children = [];
97 | pages.push({
98 | pathname,
99 | children,
100 | });
101 | findPages(options, itemPath, children);
102 | return;
103 | }
104 |
105 | if (!jsRegex.test(item) || blackList.includes(pathname)) {
106 | return;
107 | }
108 |
109 | pages.push({
110 | pathname,
111 | });
112 | });
113 |
114 | return pages;
115 | }
116 |
117 | module.exports = {
118 | findPages,
119 | findPagesMarkdown,
120 | findComponents,
121 | };
122 |
--------------------------------------------------------------------------------
/docs/src/modules/utils/helpers.js:
--------------------------------------------------------------------------------
1 | import warning from 'warning';
2 | import upperFirst from 'lodash/upperFirst';
3 | import camelCase from 'lodash/camelCase';
4 |
5 | export function titleize(string) {
6 | warning(
7 | typeof string === 'string' && string.length > 0,
8 | 'titleize(string) expects a non empty string argument.',
9 | );
10 |
11 | return string
12 | .split('-')
13 | .map(word => word.charAt(0).toUpperCase() + word.slice(1))
14 | .join(' ');
15 | }
16 |
17 | export function pageToTitle(page) {
18 | if (page.title) {
19 | return page.title;
20 | }
21 |
22 | const name = page.pathname.replace(/.*\//, '');
23 |
24 | if (page.pathname.indexOf('/api/') !== -1) {
25 | return upperFirst(camelCase(name));
26 | }
27 |
28 | return titleize(name);
29 | }
30 |
31 | export function getDependencies(raw) {
32 | const deps = {
33 | 'react-dom': 'latest',
34 | react: 'latest',
35 | };
36 | const re = /^import\s.*\sfrom\s+'([^']+)'/gm;
37 | let m;
38 | // eslint-disable-next-line no-cond-assign
39 | while ((m = re.exec(raw))) {
40 | // handle scope names
41 | const name = m[1].charAt(0) === '@' ? m[1].split('/', 2).join('/') : m[1].split('/', 1)[0];
42 | deps[name] = deps[name] || 'latest';
43 | }
44 | return deps;
45 | }
46 |
--------------------------------------------------------------------------------
/docs/src/modules/utils/parseMarkdown.js:
--------------------------------------------------------------------------------
1 | const headerRegExp = /---[\r\n]([\s\S]*)[\r\n]---/;
2 | const titleRegExp = /# (.*)[\r\n]/;
3 | const descriptionRegExp = /(.*)<\/p>[\r\n]/;
4 | const headerKeyValueRegExp = /(.*): (.*)/g;
5 | const emptyRegExp = /^\s*$/;
6 |
7 | export function getHeaders(markdown) {
8 | let header = markdown.match(headerRegExp);
9 |
10 | if (!header) {
11 | return {
12 | components: [],
13 | };
14 | }
15 |
16 | header = header[1];
17 |
18 | let regexMatchs;
19 | const headers = {};
20 |
21 | // eslint-disable-next-line no-cond-assign
22 | while ((regexMatchs = headerKeyValueRegExp.exec(header)) !== null) {
23 | headers[regexMatchs[1]] = regexMatchs[2];
24 | }
25 |
26 | if (headers.components) {
27 | headers.components = headers.components.split(', ').sort();
28 | } else {
29 | headers.components = [];
30 | }
31 |
32 | return headers;
33 | }
34 |
35 | export function getContents(markdown) {
36 | return markdown
37 | .replace(headerRegExp, '') // Remove header information
38 | .split(/^{{|}}$/gm) // Split markdown into an array, separating demos
39 | .filter(content => !emptyRegExp.test(content)); // Remove empty lines
40 | }
41 |
42 | export function getTitle(markdown) {
43 | const matches = markdown.match(titleRegExp);
44 |
45 | if (!matches || !matches[1]) {
46 | throw new Error('Missing title in the page');
47 | }
48 |
49 | return matches[1];
50 | }
51 |
52 | export function getDescription(markdown) {
53 | const matches = markdown.match(descriptionRegExp);
54 |
55 | if (!matches || !matches[1]) {
56 | throw new Error('Missing description in the page');
57 | }
58 |
59 | return matches[1];
60 | }
61 |
--------------------------------------------------------------------------------
/docs/src/pages/api/api.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 |
The API documentation.
4 |
5 | ## `SwipeableViews`
6 |
7 | | Name | Type | Default | Platform | Description |
8 | |:-----|:-----|:--------|:---------|:------------|
9 | | action | function(hooks) | | browser | This is callback property. It's called by the component on mount. This is useful when you want to trigger an action programmatically. It currently only supports updateHeight() action. |
10 | | animateHeight | bool | `false` | browser | If `true`, the height of the container will be animated to match the current slide height. Animating another style property has a negative impact regarding performance. |
11 | | animateTransitions | bool | `true` | all | If `false`, changes to the index prop will not cause an animated transition. |
12 | | axis | enum [`'x'`, `'x-reverse'`, `'y'`, `'y-reverse'`] | `'x'` | browser | The axis on which the slides will slide. |
13 | | children | node | | all | Use this property to provide your slides. |
14 | | containerStyle | object | `{}` | all | This is the inlined style that will be applied to each slide container. |
15 | | disabled | bool | `false` | all | If `true`, it will disable touch events. This is useful when you want to prohibit the user from changing slides. |
16 | | disableLazyLoading | bool | false | browser | This is the config used to disable lazy loading, if `true` it will render all the views in first rendering. |
17 | | enableMouseEvents | bool | `false` | browser | If `true`, it will enable mouse events. This will allow the user to perform the relevant swipe actions with a mouse. |
18 | | hysteresis | float | `0.6` | all | Configure hysteresis between slides. This value determines how far should user swipe to switch slide. |
19 | | ignoreNativeScroll | bool | false | browser | If `true`, it will ignore native scroll container. It can be used to filter out false positive that blocks the swipe. |
20 | | index | integer | `0` | all | This is the index of the slide to show. This is useful when you want to change the default slide shown. Or when you have tabs linked to each slide. |
21 | | onChangeIndex | function(index, indexLatest, meta) | | all | This is callback prop. It's call by the component when the shown slide change after a swipe made by the user. This is useful when you have tabs linked to each slide. |
22 | | onSwitching | function(index, type) | | all | This is callback prop. It's called by the component when the slide switching. This is useful when you want to implement something corresponding to the current slide position. |
23 | | onTransitionEnd | function | | all | The callback that fires when the animation comes to a rest. This is useful to defer CPU intensive task. |
24 | | resistance | bool | `false` | all | If true, it will add bounds effect on the edges. |
25 | | style | object | `{}` | all | This is the inlined style that will be applied on the root component. |
26 | | slideClassName | string || browser | This is the className that will be applied on the slide component. |
27 | | slideStyle | object | `{}` | all | This is the inlined style that will be applied on the slide component. |
28 | | springConfig | object | `{duration: '0.3s', easeFunction: '...', delay: '0s'}` | browser | This is the config used to create CSS transitions. This is useful to change the dynamic of the transition. |
29 | | springConfig | object | `{tension: 300, friction: 30}` | native.animated | This is the config given to Animated for the `spring`. This is useful to change the dynamic of the transition. |
30 | | threshold | integer | `5` | all | This is the threshold used for detecting a quick swipe. If the computed speed is above this value, the index change. |
31 |
32 | Any other properties like `className` will be applied to the root component.
33 |
34 | ## `virtualize`
35 |
36 | This HOC extends the properties of `SwipeableViews` and adds the following ones:
37 |
38 | | Name | Type | Default | Platform | Description |
39 | |:-----|:-----|:--------|:---------|:------------|
40 | | overscanSlideAfter | integer | `2` | all | Number of slide to render after the visible slide. |
41 | | overscanSlideBefore | integer | `3` | all | Number of slide to render before the visible slide. Separate from `overscanSlideAfter` as it's more difficult to keep the window up to date.|
42 | | slideCount | integer | | all | When set, it's adding a limit to the number of slide: [0, slideCount]. |
43 | | slideRenderer | func | | all | Responsible for rendering a slide given an index. ({ index: integer }): node |
44 |
45 | ## `autoPlay`
46 |
47 | This HOC extends the properties of `SwipeableViews` and adds the following ones:
48 |
49 | | Name | Type | Default | Platform | Description |
50 | |:-----|:-----|:--------|:---------|:------------|
51 | | autoplay | bool | `true` | all | If `false`, the auto play behavior is disabled. |
52 | | direction | enum: 'incremental' 'decremental' | `'incremental'` | all | This is the auto play direction. |
53 | | interval | integer | `3000` | all | Delay between auto play transitions (in ms). |
54 |
55 | ## `bindKeyboard`
56 |
57 | This HOC exposes the same properties as `SwipeableViews`.
58 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoAnimateHeight.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import SwipeableViews, { SwipeableViewsContext } from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slide: {
6 | padding: 15,
7 | minHeight: 100,
8 | color: '#fff',
9 | WebkitOverflowScrolling: 'touch', // iOS momentum scrolling
10 | },
11 | slide1: {
12 | backgroundColor: '#FEA900',
13 | },
14 | slide2: {
15 | maxHeight: 150,
16 | overflowY: 'auto',
17 | backgroundColor: '#B3DC4A',
18 | },
19 | slide3: {
20 | backgroundColor: '#6AC0FF',
21 | },
22 | slide4: {
23 | backgroundColor: '#FEA900',
24 | },
25 | button: {
26 | marginTop: 14,
27 | },
28 | };
29 |
30 | const list = [];
31 |
32 | for (let i = 0; i < 30; i += 1) {
33 | list.push({`item n°${i + 1}`}
);
34 | }
35 |
36 | class Slide4 extends PureComponent {
37 | static contextType = SwipeableViewsContext;
38 |
39 | state = {
40 | large: false,
41 | };
42 |
43 | componentDidUpdate() {
44 | const { slideUpdateHeight } = this.context;
45 | slideUpdateHeight();
46 | }
47 |
48 | handleClick = () => {
49 | this.setState(state => ({
50 | large: !state.large,
51 | }));
52 | };
53 |
54 | render() {
55 | return (
56 |
57 |
58 | {value => {
59 | this.context = value;
60 | return null;
61 | }}
62 |
63 | {list.slice(0, this.state.large ? 8 : 3)}
64 |
65 | {this.state.large ? 'Collaspe' : 'Expand'}
66 |
67 |
68 | );
69 | }
70 | }
71 |
72 | function DemoAnimateHeight() {
73 | return (
74 |
75 | {list.slice(0, 10)}
76 |
77 | {'This slide has a max-height limit:'}
78 |
79 |
80 | {list.slice(0, 7)}
81 |
82 | {list.slice(0, 7)}
83 |
84 |
85 | );
86 | }
87 |
88 | export default DemoAnimateHeight;
89 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoAutoPlay.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 | import { autoPlay } from 'react-swipeable-views-utils';
4 | import Pagination from 'docs/src/modules/components/Pagination';
5 |
6 | const AutoPlaySwipeableViews = autoPlay(SwipeableViews);
7 |
8 | const styles = {
9 | root: {
10 | position: 'relative',
11 | },
12 | slide: {
13 | padding: 15,
14 | minHeight: 100,
15 | color: '#fff',
16 | },
17 | slide1: {
18 | backgroundColor: '#FEA900',
19 | },
20 | slide2: {
21 | backgroundColor: '#B3DC4A',
22 | },
23 | slide3: {
24 | backgroundColor: '#6AC0FF',
25 | },
26 | };
27 |
28 | class DemoAutoPlay extends React.Component {
29 | state = {
30 | index: 0,
31 | };
32 |
33 | handleChangeIndex = index => {
34 | this.setState({
35 | index,
36 | });
37 | };
38 |
39 | render() {
40 | const { index } = this.state;
41 |
42 | return (
43 |
44 |
49 | slide n°1
50 | slide n°2
51 | slide n°3
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 |
59 | export default DemoAutoPlay;
60 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoAxis.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slideContainer: {
6 | height: 100,
7 | },
8 | slide: {
9 | padding: 15,
10 | minHeight: 100,
11 | color: '#fff',
12 | },
13 | slide1: {
14 | backgroundColor: '#FEA900',
15 | },
16 | slide2: {
17 | backgroundColor: '#B3DC4A',
18 | },
19 | scroll: {
20 | height: 100,
21 | overflow: 'scroll',
22 | },
23 | slide3: {
24 | height: 200,
25 | backgroundColor: '#6AC0FF',
26 | },
27 | };
28 |
29 | function DemoAxis() {
30 | return (
31 |
32 | slide n°1
33 | slide n°2
34 |
37 |
38 | );
39 | }
40 |
41 | export default DemoAxis;
42 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoCircular.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 | import { virtualize } from 'react-swipeable-views-utils';
4 | import { mod } from 'react-swipeable-views-core';
5 |
6 | const VirtualizeSwipeableViews = virtualize(SwipeableViews);
7 |
8 | const styles = {
9 | slide: {
10 | padding: 15,
11 | minHeight: 100,
12 | color: '#fff',
13 | },
14 | slide1: {
15 | backgroundColor: '#FEA900',
16 | },
17 | slide2: {
18 | backgroundColor: '#B3DC4A',
19 | },
20 | slide3: {
21 | backgroundColor: '#6AC0FF',
22 | },
23 | };
24 |
25 | function slideRenderer(params) {
26 | const { index, key } = params;
27 |
28 | switch (mod(index, 3)) {
29 | case 0:
30 | return (
31 |
32 | slide n°1
33 |
34 | );
35 |
36 | case 1:
37 | return (
38 |
39 | slide n°2
40 |
41 | );
42 |
43 | case 2:
44 | return (
45 |
46 | slide n°3
47 |
48 | );
49 |
50 | default:
51 | return null;
52 | }
53 | }
54 |
55 | function DemoSimple() {
56 | return ;
57 | }
58 |
59 | export default DemoSimple;
60 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoCoverflow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 | import Animated from 'animated/lib/targets/react-dom';
4 |
5 | const styles = {
6 | root: {
7 | background: '#000',
8 | padding: '0 50px',
9 | },
10 | slide: {
11 | padding: '24px 16px',
12 | color: '#fff',
13 | alignItems: 'center',
14 | justifyContent: 'center',
15 | flexDirection: 'column',
16 | display: 'flex',
17 | },
18 | img: {
19 | width: 180,
20 | height: 180,
21 | display: 'block',
22 | marginBottom: 16,
23 | },
24 | };
25 |
26 | const albums = [
27 | {
28 | name: 'Abbey Road',
29 | src: '/static/album-art-1.jpg',
30 | },
31 | {
32 | name: 'Bat Out of Hell',
33 | src: '/static/album-art-2.jpg',
34 | },
35 | {
36 | name: 'Homogenic',
37 | src: '/static/album-art-3.jpg',
38 | },
39 | {
40 | name: 'Number of the Beast',
41 | src: '/static/album-art-4.jpg',
42 | },
43 | {
44 | name: "It's Blitz",
45 | src: '/static/album-art-5.jpg',
46 | },
47 | {
48 | name: 'The Man-Machine',
49 | src: '/static/album-art-6.jpg',
50 | },
51 | {
52 | name: 'The Score',
53 | src: '/static/album-art-7.jpg',
54 | },
55 | {
56 | name: 'Lost Horizons',
57 | src: '/static/album-art-8.jpg',
58 | },
59 | ];
60 |
61 | class DemoCoverflow extends React.Component {
62 | state = {
63 | index: 0,
64 | position: new Animated.Value(0),
65 | };
66 |
67 | handleChangeIndex = index => {
68 | this.setState({ index });
69 | };
70 |
71 | handleSwitch = (index, type) => {
72 | if (type === 'end') {
73 | Animated.spring(this.state.position, { toValue: index }).start();
74 | return;
75 | }
76 | this.state.position.setValue(index);
77 | };
78 |
79 | render() {
80 | const { index, position } = this.state;
81 |
82 | return (
83 |
90 | {albums.map((album, currentIndex) => {
91 | const inputRange = albums.map((_, i) => i);
92 | const scale = position.interpolate({
93 | inputRange,
94 | outputRange: inputRange.map(i => {
95 | return currentIndex === i ? 1 : 0.7;
96 | }),
97 | });
98 | const opacity = position.interpolate({
99 | inputRange,
100 | outputRange: inputRange.map(i => {
101 | return currentIndex === i ? 1 : 0.3;
102 | }),
103 | });
104 | const translateX = position.interpolate({
105 | inputRange,
106 | outputRange: inputRange.map(i => {
107 | return (100 / 2) * (i - currentIndex);
108 | }),
109 | });
110 |
111 | return (
112 |
122 |
123 | {album.name}
124 |
125 | );
126 | })}
127 |
128 | );
129 | }
130 | }
131 |
132 | export default DemoCoverflow;
133 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoHocs.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/no-multi-comp */
2 |
3 | import React from 'react';
4 | import SwipeableViews from 'react-swipeable-views';
5 | import { autoPlay, virtualize, bindKeyboard } from 'react-swipeable-views-utils';
6 | import { mod } from 'react-swipeable-views-core';
7 |
8 | const EnhancedSwipeableViews = bindKeyboard(autoPlay(virtualize(SwipeableViews)));
9 |
10 | const styles = {
11 | slide: {
12 | padding: 15,
13 | minHeight: 100,
14 | color: '#fff',
15 | },
16 | slide1: {
17 | backgroundColor: '#FEA900',
18 | },
19 | slide2: {
20 | backgroundColor: '#B3DC4A',
21 | },
22 | slide3: {
23 | backgroundColor: '#6AC0FF',
24 | },
25 | };
26 |
27 | function slideRenderer(params) {
28 | const { index, key } = params;
29 | let style;
30 |
31 | switch (mod(index, 3)) {
32 | case 0:
33 | style = styles.slide1;
34 | break;
35 |
36 | case 1:
37 | style = styles.slide2;
38 | break;
39 |
40 | case 2:
41 | style = styles.slide3;
42 | break;
43 |
44 | default:
45 | break;
46 | }
47 |
48 | return (
49 |
50 | {`slide n°${index + 1}`}
51 |
52 | );
53 | }
54 |
55 | function DemoHocs() {
56 | return ;
57 | }
58 |
59 | export default DemoHocs;
60 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoKeyboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 | import { bindKeyboard } from 'react-swipeable-views-utils';
4 |
5 | const BindKeyboardSwipeableViews = bindKeyboard(SwipeableViews);
6 |
7 | const styles = {
8 | slide: {
9 | padding: 15,
10 | minHeight: 100,
11 | color: '#fff',
12 | },
13 | slide1: {
14 | backgroundColor: '#FEA900',
15 | },
16 | slide2: {
17 | backgroundColor: '#B3DC4A',
18 | },
19 | slide3: {
20 | backgroundColor: '#6AC0FF',
21 | },
22 | };
23 |
24 | function DemoKeyboard() {
25 | return (
26 |
27 | slide n°1
28 | slide n°2
29 | slide n°3
30 |
31 | );
32 | }
33 |
34 | export default DemoKeyboard;
35 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoNested.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slide: {
6 | padding: 15,
7 | minHeight: 100,
8 | color: '#fff',
9 | },
10 | slideContainerY: {
11 | height: 100,
12 | },
13 | slide1: {
14 | backgroundColor: '#FEA900',
15 | },
16 | slide2: {
17 | backgroundColor: '#B3DC4A',
18 | },
19 | slide3: {
20 | backgroundColor: '#6AC0FF',
21 | },
22 | divider: {
23 | height: 50,
24 | },
25 | };
26 |
27 | function DemoNested() {
28 | return (
29 |
30 |
31 |
32 |
33 | This is component is very large so we can test how a native scroll container is handled.
34 |
35 |
36 | slide n°1
37 |
38 |
39 | nested slide n°1.1
40 | nested slide n°1.2
41 |
42 |
43 |
44 |
45 |
46 | This is component is very large so we can test how a native scroll container is handled.
47 |
48 |
49 | slide n°2
50 |
51 |
52 | nested slide n°2.1
53 | nested slide n°2.2
54 |
55 |
56 |
57 | slide n°3
58 |
59 |
60 | nested slide n°3.1
61 | nested slide n°3.2
62 |
63 |
64 |
65 | );
66 | }
67 |
68 | export default DemoNested;
69 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoResistance.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slide: {
6 | padding: 15,
7 | minHeight: 100,
8 | color: '#fff',
9 | },
10 | slide1: {
11 | backgroundColor: '#FEA900',
12 | },
13 | slide2: {
14 | backgroundColor: '#B3DC4A',
15 | },
16 | slide3: {
17 | backgroundColor: '#6AC0FF',
18 | },
19 | };
20 |
21 | function DemoResistance() {
22 | return (
23 |
24 | slide n°1
25 | slide n°2
26 | slide n°3
27 |
28 | );
29 | }
30 |
31 | export default DemoResistance;
32 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoRtl.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | root: {
6 | // Simulates a global right-to-left direction.
7 | direction: 'rtl',
8 | },
9 | slide: {
10 | direction: 'rtl',
11 | padding: 15,
12 | minHeight: 100,
13 | color: '#fff',
14 | },
15 | slide1: {
16 | backgroundColor: '#FEA900',
17 | },
18 | slide2: {
19 | backgroundColor: '#B3DC4A',
20 | },
21 | slide3: {
22 | backgroundColor: '#6AC0FF',
23 | },
24 | };
25 |
26 | function DemoRtl() {
27 | return (
28 |
29 |
30 | slide n°1
31 | slide n°2
32 | slide n°3
33 |
34 |
35 | );
36 | }
37 |
38 | export default DemoRtl;
39 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoScroll.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slideContainer: {
6 | height: 100,
7 | WebkitOverflowScrolling: 'touch', // iOS momentum scrolling
8 | },
9 | slide: {
10 | padding: 15,
11 | minHeight: 100,
12 | color: '#fff',
13 | },
14 | slide1: {
15 | backgroundColor: '#FEA900',
16 | },
17 | slide2: {
18 | backgroundColor: '#B3DC4A',
19 | },
20 | slide3: {
21 | backgroundColor: '#6AC0FF',
22 | },
23 | };
24 |
25 | const list = [];
26 |
27 | for (let i = 0; i < 30; i += 1) {
28 | list.push({`item n°${i + 1}`}
);
29 | }
30 |
31 | function DemoScroll() {
32 | return (
33 |
34 | {list}
35 | slide n°2
36 | slide n°3
37 |
38 | );
39 | }
40 |
41 | export default DemoScroll;
42 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoSimple.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slide: {
6 | padding: 15,
7 | minHeight: 100,
8 | color: '#fff',
9 | },
10 | slide1: {
11 | backgroundColor: '#FEA900',
12 | },
13 | slide2: {
14 | backgroundColor: '#B3DC4A',
15 | },
16 | slide3: {
17 | backgroundColor: '#6AC0FF',
18 | },
19 | };
20 |
21 | function DemoSimple() {
22 | return (
23 |
24 | slide n°1
25 | slide n°2
26 | slide n°3
27 |
28 | );
29 | }
30 |
31 | export default DemoSimple;
32 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoTabs.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tabs from '@material-ui/core/Tabs';
3 | import Tab from '@material-ui/core/Tab';
4 | import MenuItem from '@material-ui/core/MenuItem';
5 | import Select from '@material-ui/core/Select';
6 | import SwipeableViews from 'react-swipeable-views';
7 |
8 | const styles = {
9 | tabs: {
10 | background: '#fff',
11 | },
12 | slide: {
13 | padding: 15,
14 | minHeight: 100,
15 | color: '#fff',
16 | },
17 | slide1: {
18 | backgroundColor: '#FEA900',
19 | },
20 | slide2: {
21 | backgroundColor: '#B3DC4A',
22 | },
23 | slide3: {
24 | backgroundColor: '#6AC0FF',
25 | },
26 | };
27 |
28 | class DemoTabs extends React.Component {
29 | state = {
30 | index: 0,
31 | };
32 |
33 | handleChange = (event, value) => {
34 | this.setState({
35 | index: value,
36 | });
37 | };
38 |
39 | handleChangeIndex = index => {
40 | this.setState({
41 | index,
42 | });
43 | };
44 |
45 | render() {
46 | const { index } = this.state;
47 |
48 | return (
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | slide n°1
57 |
58 | slide n°2
59 |
60 |
61 | None
62 |
63 | Ten
64 |
65 |
66 | slide n°3
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 | export default DemoTabs;
74 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoVirtualize.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/no-multi-comp */
2 |
3 | import React from 'react';
4 | import Button from '@material-ui/core/Button';
5 | import SwipeableViews from 'react-swipeable-views';
6 | import { virtualize, bindKeyboard } from 'react-swipeable-views-utils';
7 | import { mod } from 'react-swipeable-views-core';
8 |
9 | const VirtualizeSwipeableViews = bindKeyboard(virtualize(SwipeableViews));
10 |
11 | const styles = {
12 | slide: {
13 | padding: 15,
14 | minHeight: 100,
15 | color: '#fff',
16 | },
17 | slide1: {
18 | backgroundColor: '#FEA900',
19 | },
20 | slide2: {
21 | backgroundColor: '#B3DC4A',
22 | },
23 | slide3: {
24 | backgroundColor: '#6AC0FF',
25 | },
26 | };
27 |
28 | function slideRenderer(params) {
29 | const { index, key } = params;
30 | let style;
31 |
32 | switch (mod(index, 3)) {
33 | case 0:
34 | style = styles.slide1;
35 | break;
36 |
37 | case 1:
38 | style = styles.slide2;
39 | break;
40 |
41 | case 2:
42 | style = styles.slide3;
43 | break;
44 |
45 | default:
46 | break;
47 | }
48 |
49 | return (
50 |
51 | {`slide n°${index + 1}`}
52 |
53 | );
54 | }
55 |
56 | class DemoVirtualize extends React.Component {
57 | state = {
58 | index: 0,
59 | };
60 |
61 | handleChangeIndex = index => {
62 | this.setState({
63 | index,
64 | });
65 | };
66 |
67 | handleClick = () => {
68 | this.setState({
69 | index: 49,
70 | });
71 | };
72 |
73 | render() {
74 | return (
75 |
76 |
82 |
83 | {'go to slide n°50'}
84 |
85 | );
86 | }
87 | }
88 |
89 | export default DemoVirtualize;
90 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/DemoWidth.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | root: {
6 | padding: '0 30px',
7 | },
8 | slideContainer: {
9 | padding: '0 10px',
10 | },
11 | slide: {
12 | padding: 15,
13 | minHeight: 100,
14 | color: '#fff',
15 | },
16 | slide1: {
17 | backgroundColor: '#FEA900',
18 | },
19 | slide2: {
20 | backgroundColor: '#B3DC4A',
21 | },
22 | slide3: {
23 | backgroundColor: '#6AC0FF',
24 | },
25 | };
26 |
27 | function DemoWidth() {
28 | return (
29 |
30 | slide n°1
31 | slide n°2
32 | slide n°3
33 |
34 | );
35 | }
36 |
37 | export default DemoWidth;
38 |
--------------------------------------------------------------------------------
/docs/src/pages/demos/demos.md:
--------------------------------------------------------------------------------
1 | # Demos
2 |
3 | Demonstrate some use cases we are supporting.
4 |
5 | Note that on desktop, you might have to add the `enableMouseEvents` prop, in order for the demos to work properly.
6 |
7 | ## Simple
8 |
9 | A Simple case.
10 |
11 | {{"demo": "pages/demos/DemoSimple.js"}}
12 |
13 | ## Tabs
14 |
15 | With a header.
16 |
17 | {{"demo": "pages/demos/DemoTabs.js"}}
18 |
19 | ## Scroll
20 |
21 | Set a constant height and let the swipe and scroll behavior work in harmony.
22 |
23 | {{"demo": "pages/demos/DemoScroll.js"}}
24 |
25 | ## Animate height
26 |
27 | The container responds dynamically to its children.
28 |
29 | {{"demo": "pages/demos/DemoAnimateHeight.js"}}
30 |
31 | ## Resistance
32 |
33 | With a resistance bounds effet on the edges.
34 |
35 | {{"demo": "pages/demos/DemoResistance.js"}}
36 |
37 | ## Nested
38 |
39 | With nested swipeable-view component.
40 |
41 | {{"demo": "pages/demos/DemoNested.js"}}
42 |
43 | ## Auto play
44 |
45 | With the auto play HOC.
46 |
47 | {{"demo": "pages/demos/DemoAutoPlay.js"}}
48 |
49 | ## Virtualize
50 |
51 | With the virtualize HOC.
52 |
53 | {{"demo": "pages/demos/DemoVirtualize.js"}}
54 |
55 | ## Axis
56 |
57 | Swipe up and down.
58 |
59 | {{"demo": "pages/demos/DemoAxis.js"}}
60 |
61 | ## Keyboard
62 |
63 | With a keyboard binding.
64 |
65 | {{"demo": "pages/demos/DemoKeyboard.js"}}
66 |
67 | ## Hocs
68 |
69 | With all the HOCs.
70 |
71 | {{"demo": "pages/demos/DemoHocs.js"}}
72 |
73 | ## Custom width
74 |
75 | Custom width of slides.
76 |
77 | {{"demo": "pages/demos/DemoWidth.js"}}
78 |
79 | ## Rtl
80 |
81 | Right-to-left direction
82 |
83 | {{"demo": "pages/demos/DemoRtl.js"}}
84 |
85 | ## Circular
86 |
87 | The 3 slides are repeated indefinitely.
88 |
89 | {{"demo": "pages/demos/DemoCircular.js"}}
90 |
91 | ## Coverflow
92 |
93 | Custom display with a coverflow effect.
94 |
95 | {{"demo": "pages/demos/DemoCoverflow.js"}}
96 |
--------------------------------------------------------------------------------
/docs/src/pages/getting-started/example-projects.md:
--------------------------------------------------------------------------------
1 | # Example Projects
2 |
3 | Are you looking for an example project to get started?
4 |
5 | We host some example projects which you can find in the [GitHub repository](https://github.com/oliviertassinari/react-swipeable-views) under the [`/examples`](https://github.com/oliviertassinari/react-swipeable-views/tree/master/examples) folder:
6 | - [Create React App](https://github.com/oliviertassinari/react-swipeable-views/tree/master/examples/create-react-app)
7 |
--------------------------------------------------------------------------------
/docs/src/pages/getting-started/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | Install react-swipeable-views.
4 |
5 | react-swipeable-views is available as a npm packages.
6 |
7 | | Package | Version | Download | Size (kB gzipped) |
8 | |---------|:--------|:---------|:------------------|
9 | | react-swipeable-views | [](https://www.npmjs.com/package/react-swipeable-views) | [](https://www.npmjs.com/package/react-swipeable-views) | 5.08 |
10 | | react-swipeable-views-utils | [](https://www.npmjs.com/package/react-swipeable-views-utils) | [](https://www.npmjs.com/package/react-swipeable-views-utils) | 3.52 |
11 | | react-swipeable-views-native | [](https://www.npmjs.com/package/react-swipeable-views-native) | [](https://www.npmjs.com/package/react-swipeable-views-native) | ? |
12 |
13 | ## npm
14 |
15 | ```sh
16 | npm install --save react-swipeable-views
17 | ```
18 |
19 | ## Packages stucture
20 |
21 | The project is split into multiple packages.
22 | This is really useful for code sharing and isolation.
23 | We are using [Lerna](https://github.com/lerna/lerna) to do so.
24 | The project has the following packages:
25 | - `react-swipeable-views-core`: core modules shared between the different packages.
26 | - [react-swipeable-views](https://www.npmjs.com/package/react-swipeable-views): browser implementation of the ` ` component.
27 | - [react-swipeable-views-native](https://www.npmjs.com/package/react-swipeable-views-native): native implementation**s** of the ` ` component.
28 | - [react-swipeable-views-utils](https://www.npmjs.com/package/react-swipeable-views-utils): Higher order Components providing additional functionalities like `virtualize()`.
29 |
--------------------------------------------------------------------------------
/docs/src/pages/getting-started/supported-platforms.md:
--------------------------------------------------------------------------------
1 | ## Supported platforms
2 |
3 | Learn about the platforms, from modern to old, that are supported by react-swipeable-views.
4 |
5 | The API is as consistent as possible between the three platforms so
6 | the same component can be used independently on where it's running.
7 |
8 | ### Browser
9 |
10 | | IE | Edge | Windows Phone | Firefox | Chrome | Safari |
11 | |:------|:-----|:--------------|:--------|:-------|:-------|
12 | | >= 10 | ✓ | x | >= 28 | >= 29 | >= 8 |
13 |
14 | #### Legacy browser support
15 |
16 | react-swipeable-views supports modern browsers out-of-the-box, but requires additional CSS to support legacy browsers. To support IE 10 and older versions of Mobile Safari, include `react-swipeable-views/dist/legacy-browser-support.css`.
17 |
18 | 
19 |
20 | ### iOS
21 |
22 | 
23 |
24 | ### Android
25 |
26 | 
27 |
--------------------------------------------------------------------------------
/docs/src/pages/getting-started/usage.md:
--------------------------------------------------------------------------------
1 | # Usage
2 |
3 | Get started with react-swipeable-views in no time.
4 |
5 | ## Simple example
6 |
7 | 
8 |
9 | ### Browser
10 |
11 | ```jsx
12 | import React from 'react';
13 | import SwipeableViews from 'react-swipeable-views';
14 |
15 | const styles = {
16 | slide: {
17 | padding: 15,
18 | minHeight: 100,
19 | color: '#fff',
20 | },
21 | slide1: {
22 | background: '#FEA900',
23 | },
24 | slide2: {
25 | background: '#B3DC4A',
26 | },
27 | slide3: {
28 | background: '#6AC0FF',
29 | },
30 | };
31 |
32 | const MyComponent = () => (
33 |
34 |
35 | slide n°1
36 |
37 |
38 | slide n°2
39 |
40 |
41 | slide n°3
42 |
43 |
44 | );
45 |
46 | export default MyComponent;
47 | ```
48 |
49 | ### Native (experimental)
50 |
51 | react-native support is experimental and I have no plan pushing it forward.
52 | I start to think that lower level abstraction to share the implementation between the platforms are more appropriate.
53 | We have two different implementations of the react-swipeable-views API.
54 |
55 | ```jsx
56 | import React from 'react';
57 | import {
58 | StyleSheet,
59 | Text,
60 | View,
61 | } from 'react-native';
62 |
63 | import SwipeableViews from 'react-swipeable-views-native';
64 | // There is another version using the scroll component instead of animated.
65 | // I'm unsure which one give the best UX. Please give us some feedback.
66 | // import SwipeableViews from 'react-swipeable-views-native/lib/SwipeableViews.scroll';
67 |
68 | const styles = StyleSheet.create({
69 | slideContainer: {
70 | height: 100,
71 | },
72 | slide: {
73 | padding: 15,
74 | height: 100,
75 | },
76 | slide1: {
77 | backgroundColor: '#FEA900',
78 | },
79 | slide2: {
80 | backgroundColor: '#B3DC4A',
81 | },
82 | slide3: {
83 | backgroundColor: '#6AC0FF',
84 | },
85 | text: {
86 | color: '#fff',
87 | fontSize: 16,
88 | },
89 | });
90 |
91 | const MyComponent = () => (
92 |
93 |
94 |
95 | slide n°1
96 |
97 |
98 |
99 |
100 | slide n°2
101 |
102 |
103 |
104 |
105 | slide n°3
106 |
107 |
108 |
109 | );
110 |
111 | export default MyComponent;
112 | ```
113 |
114 |
115 | ## Example with `virtualize`
116 |
117 | The infinite feature is provided thanks to a *higher order component*.
118 | It's working independently of the targeted platform.
119 | You can have a look at *Demo 8* to see it in action.
120 | It's highly inspired by [react-virtualized](https://github.com/bvaughn/react-virtualized).
121 | Let's see an example with the browser:
122 |
123 | ```jsx
124 | import React from 'react';
125 | import SwipeableViews from 'react-swipeable-views';
126 | import { virtualize } from 'react-swipeable-views-utils';
127 |
128 | const VirtualizeSwipeableViews = virtualize(SwipeableViews);
129 |
130 | const slideRenderer = ({key, index}) => (
131 |
132 | {`slide n°${index + 1}`}
133 |
134 | );
135 |
136 | const MyComponent = () => (
137 |
138 | );
139 |
140 | export default MyComponent;
141 | ```
142 |
143 | ## Example with `autoPlay`
144 |
145 | The auto play feature is provided thanks to a *higher order component*.
146 | It's working independently of the targeted platform.
147 | You can have a look at *Demo 7* to see it in action.
148 | Let's see an example with the browser:
149 |
150 | ```jsx
151 | import React from 'react';
152 | import SwipeableViews from 'react-swipeable-views';
153 | import { autoPlay } from 'react-swipeable-views-utils';
154 |
155 | const AutoPlaySwipeableViews = autoPlay(SwipeableViews);
156 |
157 | const MyComponent = () => (
158 |
159 | slide n°1
160 | slide n°2
161 | slide n°3
162 |
163 | );
164 |
165 | export default MyComponent;
166 | ```
167 |
168 | ## Example with `bindKeyboard`
169 |
170 | The keyboard navigation feature is provided thanks to a *higher order component*.
171 | You can have a look at *Demo 9* to see it in action.
172 | Let's see an example with the browser:
173 |
174 | ```jsx
175 | import React from 'react';
176 | import SwipeableViews from 'react-swipeable-views';
177 | import { bindKeyboard } from 'react-swipeable-views-utils';
178 |
179 | const BindKeyboardSwipeableViews = bindKeyboard(SwipeableViews);
180 |
181 | const MyComponent = () => (
182 |
183 | slide n°1
184 | slide n°2
185 | slide n°3
186 |
187 | );
188 |
189 | export default MyComponent;
190 | ```
191 |
192 | ## API
193 |
194 | You can find the [API documentation section online](/api/api/).
195 |
196 | ## Composition of HOCs
197 |
198 | The composition order of the HOCs matters.
199 | The `virtualize` HOC needs to be the first one called.
200 | For instance:
201 | ```js
202 | // creates a function that invokes the given functions from right to left.
203 | import flowRight from 'lodash/flowRight';
204 |
205 | const EnhancedSwipeableViews = flowRight(
206 | bindKeyboard,
207 | autoPlay,
208 | virtualized,
209 | )(SwipeableViews);
210 | ```
211 |
212 | ## Performance on browser
213 |
214 | Having 60 FPS is critical for this type of component.
215 | We are rendering the slides at each request animation frame.
216 | That has one specific implication for package users.
217 | You need to add a **pure logic** in the *slides* components if your render method is expensive.
218 |
219 | The performance is not as good as they could be if we were using a data binding to update the styles.
220 | However, the implementation is simpler.
221 |
--------------------------------------------------------------------------------
/docs/webpackBaseConfig.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // This module isn't used to build the documentation. We use Next.js for that.
4 | // This module is used by the visual regression tests to run the demos.
5 | module.exports = {
6 | context: path.resolve(__dirname),
7 | resolve: {
8 | modules: [path.join(__dirname, '../'), 'node_modules'],
9 | alias: {
10 | 'react-swipeable-views': path.resolve(__dirname, '../packages/react-swipeable-views/src'),
11 | 'react-swipeable-views-core': path.resolve(
12 | __dirname,
13 | '../packages/react-swipeable-views-core/src',
14 | ),
15 | 'react-swipeable-views-utils': path.resolve(
16 | __dirname,
17 | '../packages/react-swipeable-views-utils/src',
18 | ),
19 | docs: __dirname,
20 | },
21 | },
22 | output: {
23 | path: path.join(__dirname, 'build'),
24 | filename: 'bundle.js',
25 | publicPath: '/build/',
26 | },
27 | module: {
28 | rules: [
29 | {
30 | test: /\.js$/,
31 | exclude: /node_modules/,
32 | loader: 'babel-loader',
33 | query: {
34 | cacheDirectory: true,
35 | },
36 | },
37 | ],
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | **/yarn.lock
2 |
--------------------------------------------------------------------------------
/examples/create-react-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/examples/create-react-app/README.md:
--------------------------------------------------------------------------------
1 | # Create React App example
2 |
3 | ## How to use
4 |
5 | Download the example [or clone the repo](https://github.com/oliviertassinari/react-swipeable-views):
6 |
7 | ```bash
8 | curl https://codeload.github.com/oliviertassinari/react-swipeable-views/tar.gz/v1-beta | tar -xz --strip=2 react-swipeable-views-master/examples/create-react-app
9 | cd create-react-app
10 | ```
11 |
12 | Install it and run:
13 |
14 | ```bash
15 | npm install
16 | npm run start
17 | ```
18 |
19 | ## The idea behind the example
20 |
21 | [Create React App](https://github.com/facebookincubator/create-react-app) with no build configuration.
22 |
--------------------------------------------------------------------------------
/examples/create-react-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-react-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "latest",
7 | "react-dom": "latest",
8 | "react-scripts": "latest",
9 | "react-swipeable-views": "latest"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test --env=jsdom",
15 | "eject": "react-scripts eject"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/create-react-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/examples/create-react-app/public/favicon.ico
--------------------------------------------------------------------------------
/examples/create-react-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 | You need to enable JavaScript to run this app.
27 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/examples/create-react-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/examples/create-react-app/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SwipeableViews from 'react-swipeable-views';
3 |
4 | const styles = {
5 | slide: {
6 | padding: 15,
7 | minHeight: 100,
8 | color: '#fff',
9 | },
10 | slide1: {
11 | backgroundColor: '#FEA900',
12 | },
13 | slide2: {
14 | backgroundColor: '#B3DC4A',
15 | },
16 | slide3: {
17 | backgroundColor: '#6AC0FF',
18 | },
19 | };
20 |
21 | function App() {
22 | return (
23 |
24 | slide n°1
25 | slide n°2
26 | slide n°3
27 |
28 | );
29 | }
30 |
31 | export default App;
32 |
--------------------------------------------------------------------------------
/examples/create-react-app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render( , document.querySelector('#root'));
6 |
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "docs/export",
4 | "headers": [
5 | {
6 | "source": "**",
7 | "headers": [
8 | {
9 | "key": "Cache-Control",
10 | "value": "no-cache"
11 | }
12 | ]
13 | },
14 | {
15 | "source": "**/*.js",
16 | "headers": [
17 | {
18 | "key": "Cache-Control",
19 | "value": "public, max-age=31536000"
20 | }
21 | ]
22 | },
23 | {
24 | "source" : "**/*.@(jpg|jpeg|gif|png|svg)",
25 | "headers": [
26 | {
27 | "key": "Cache-Control",
28 | "value": "public, max-age=7200"
29 | }
30 | ]
31 | }
32 | ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.0.0",
3 | "npmClient": "yarn",
4 | "version": "0.14.0",
5 | "packages": [
6 | "packages/*"
7 | ],
8 | "useWorkspaces": true
9 | }
10 |
--------------------------------------------------------------------------------
/native/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/native/.editorconfig:
--------------------------------------------------------------------------------
1 | # 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 |
11 |
--------------------------------------------------------------------------------
/native/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/native/.gitignore:
--------------------------------------------------------------------------------
1 | lib/
2 | *.log
3 | .expo
4 | .jest
5 |
6 | # OSX
7 | #
8 | .DS_Store
9 |
10 | # Xcode
11 | #
12 | build/
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata
22 | *.xccheckout
23 | *.moved-aside
24 | DerivedData
25 | *.hmap
26 | *.ipa
27 | *.xcuserstate
28 | project.xcworkspace
29 |
30 | # Android/IntelliJ
31 | #
32 | build/
33 | .idea
34 | .gradle
35 | local.properties
36 | *.iml
37 |
38 | # node.js
39 | #
40 | node_modules/
41 | npm-debug.log
42 | yarn-error.log
43 |
44 | # BUCK
45 | buck-out/
46 | \.buckd/
47 | *.keystore
48 |
49 | # fastlane
50 | #
51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
52 | # screenshots whenever they are needed.
53 | # For more information about the recommended setup visit:
54 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
55 |
56 | fastlane/report.xml
57 | fastlane/Preview.html
58 | fastlane/screenshots
59 |
--------------------------------------------------------------------------------
/native/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/native/App.js:
--------------------------------------------------------------------------------
1 | // app entry
2 | import { App } from './src/App';
3 |
4 | export default App;
5 |
--------------------------------------------------------------------------------
/native/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SwipeableViewsDocs",
3 | "displayName": "SwipeableViewsDocs",
4 | "expo": {
5 | "name": "react-swipeable-views-native",
6 | "description": "Demo project for react-swipeable-views-native component",
7 | "slug": "react-swipeable-views-native",
8 | "privacy": "public",
9 | "sdkVersion": "31.0.0",
10 | "platforms": [
11 | "ios",
12 | "android"
13 | ],
14 | "version": "1.0.0",
15 | "orientation": "portrait",
16 | "icon": "./assets/images/icon.png",
17 | "splash": {
18 | "image": "./assets/images/splash.png",
19 | "resizeMode": "contain",
20 | "backgroundColor": "#ffffff"
21 | },
22 | "updates": {
23 | "fallbackToCacheTimeout": 0
24 | },
25 | "assetBundlePatterns": [
26 | "**/*"
27 | ],
28 | "ios": {
29 | "supportsTablet": true
30 | },
31 | "githubUrl": "https://github.com/oliviertassinari/react-swipeable-views/tree/master/native/packages/react-swipeable-views-native"
32 | }
33 | }
--------------------------------------------------------------------------------
/native/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/native/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/native/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/native/assets/images/icon.png
--------------------------------------------------------------------------------
/native/assets/images/robot-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/native/assets/images/robot-dev.png
--------------------------------------------------------------------------------
/native/assets/images/robot-prod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/native/assets/images/robot-prod.png
--------------------------------------------------------------------------------
/native/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/native/assets/images/splash.png
--------------------------------------------------------------------------------
/native/index.js:
--------------------------------------------------------------------------------
1 | // app entry
2 | import app from './docs/src/App';
3 |
4 | app.start();
5 |
--------------------------------------------------------------------------------
/native/jest.config.js:
--------------------------------------------------------------------------------
1 | const { defaults: tsjPreset } = require('ts-jest/presets');
2 |
3 | module.exports = {
4 | ...tsjPreset,
5 | preset: 'react-native',
6 | transform: {
7 | ...tsjPreset.transform,
8 | '\\.js$': '/node_modules/react-native/jest/preprocessor.js',
9 | },
10 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
11 | // This is the only part which you can keep
12 | // from the above linked tutorial"s config:
13 | cacheDirectory: '.jest/cache',
14 | };
15 |
--------------------------------------------------------------------------------
/native/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SwipeableViewsDocs",
3 | "private": true,
4 | "scripts": {
5 | "start": "expo start",
6 | "android": "expo start --android",
7 | "ios": "expo start --ios",
8 | "eject": "expo eject",
9 | "test": "node ./node_modules/jest/bin/jest.js --watchAll"
10 | },
11 | "author": "Olivier Tassinari (https://github.com/oliviertassinari)",
12 | "maintainers": [
13 | "Olivier Tassinari (https://github.com/oliviertassinari)",
14 | "Roman Rogozhnikov (https://github.com/yacut)"
15 | ],
16 | "license": "MIT",
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/oliviertassinari/react-swipeable-views.git"
20 | },
21 | "main": "node_modules/expo/AppEntry.js",
22 | "dependencies": {
23 | "expo": "^31.0.2",
24 | "react": "16.5.0",
25 | "react-native": "https://github.com/expo/react-native/archive/sdk-31.0.0.tar.gz",
26 | "react-native-paper": "2.2.1",
27 | "react-navigation": "^2.18.2",
28 | "react-swipeable-views-core": "^0.13.0",
29 | "react-swipeable-views-utils": "^0.13.0"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.0.0-0",
33 | "@types/jest": "^23.3.9",
34 | "@types/node": "10.12.2",
35 | "@types/react": "^16.4.18",
36 | "@types/react-native": "^0.57.7",
37 | "@types/react-navigation": "^2.13.0",
38 | "@types/react-test-renderer": "^16.0.3",
39 | "babel-preset-expo": "^5.0.0",
40 | "jest-expo": "^31.0.0",
41 | "ts-jest": "^23.10.4",
42 | "typescript": "^3.1.6"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/.npmignore:
--------------------------------------------------------------------------------
1 | /*
2 | !/lib/*
3 | !/README.md
4 | !/CHANGELOG.md
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 0.13.0
2 |
3 | - upgrade React Native to 0.57
4 | - upgrade other dependencies
5 | - move to typescript
6 |
7 | ### 0.13.2
8 |
9 | - remove `warning` dependency
10 | - add snapshot tests
11 | - move example project to expo
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/README.md:
--------------------------------------------------------------------------------
1 | # react-swipeable-views-native
2 |
3 | [](https://www.npmjs.com/package/react-swipeable-views-native)
4 | [](https://www.npmjs.com/package/react-swipeable-views-native)
5 | [](https://expo.io/@yacut/react-swipeable-views-native)
6 | [](https://paypal.me/yacut)
7 |
8 | > A React Native component for swipeable views.
9 |
10 | ## Installation
11 |
12 | ```sh
13 | npm install --save react-swipeable-views-native
14 | # or
15 | yarn add react-swipeable-views-native
16 | ```
17 |
18 | ## Usage
19 |
20 | ```jsx
21 | import React from 'react';
22 | import {
23 | StyleSheet,
24 | Text,
25 | View,
26 | } from 'react-native';
27 |
28 | import SwipeableViews from 'react-swipeable-views-native';
29 | // There is another version using the scroll component instead of animated.
30 | // I'm unsure which one give the best UX. Please give us some feedback.
31 | // import SwipeableViews from 'react-swipeable-views-native/lib/SwipeableViews.scroll';
32 |
33 | const styles = StyleSheet.create({
34 | slideContainer: {
35 | height: 100,
36 | },
37 | slide: {
38 | padding: 15,
39 | height: 100,
40 | },
41 | slide1: {
42 | backgroundColor: '#FEA900',
43 | },
44 | slide2: {
45 | backgroundColor: '#B3DC4A',
46 | },
47 | slide3: {
48 | backgroundColor: '#6AC0FF',
49 | },
50 | text: {
51 | color: '#fff',
52 | fontSize: 16,
53 | },
54 | });
55 |
56 | const MyComponent = () => (
57 |
58 |
59 |
60 | slide n°1
61 |
62 |
63 |
64 |
65 | slide n°2
66 |
67 |
68 |
69 |
70 | slide n°3
71 |
72 |
73 |
74 | );
75 |
76 | export default MyComponent;
77 | ```
78 |
79 | ## License
80 |
81 | This project is licensed under the terms of the
82 | [MIT license](https://github.com/oliviertassinari/react-swipeable-views/blob/master/LICENSE).
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipeable-views-native",
3 | "version": "0.13.2",
4 | "description": "A React component for swipeable views",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "build": "NODE_ENV=production yarn clean && yarn tsc",
8 | "clean": "rimraf lib",
9 | "lint": "tslint -p tsconfig.json -c tslint.json",
10 | "prepublish": "yarn build && pkgfiles",
11 | "tsc": "tsc"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/oliviertassinari/react-swipeable-views.git"
16 | },
17 | "keywords": [
18 | "react-native",
19 | "react",
20 | "component",
21 | "swipe",
22 | "swipeable"
23 | ],
24 | "author": "Olivier Tassinari (https://github.com/oliviertassinari)",
25 | "maintainers": [
26 | "Olivier Tassinari (https://github.com/oliviertassinari)",
27 | "Roman Rogozhnikov (https://github.com/yacut)"
28 | ],
29 | "bugs": {
30 | "url": "https://github.com/oliviertassinari/react-swipeable-views/issues"
31 | },
32 | "dependencies": {
33 | "react-swipeable-views-core": "^0.13.0"
34 | },
35 | "peerDependencies": {
36 | "react": "^16.5",
37 | "react-native": ">= 0.57.0"
38 | },
39 | "devDependencies": {
40 | "@types/node": "10.12.2",
41 | "@types/react": "^16.4.18",
42 | "@types/react-native": "^0.57.7",
43 | "pkgfiles": "^2.3.2",
44 | "rimraf": "^2.6.2",
45 | "typescript": "3.1.6"
46 | },
47 | "license": "MIT"
48 | }
49 |
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/src/index.ts:
--------------------------------------------------------------------------------
1 | import SwipeableViews from './SwipeableViews.animated';
2 |
3 | export default SwipeableViews;
4 |
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "baseUrl": "./src",
5 | "declaration": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "jsx": "react",
9 | "lib": ["esnext", "dom"],
10 | "module": "commonjs",
11 | "moduleResolution": "node",
12 | "noImplicitAny": false,
13 | "noUnusedLocals": true,
14 | "outDir": "./lib",
15 | "removeComments": true,
16 | "skipLibCheck": true,
17 | "sourceMap": true,
18 | "strict": true,
19 | "target": "es5"
20 | },
21 | "exclude": [
22 | "node_modules",
23 | "lib"
24 | ]
25 | }
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/tsconfig.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json"
3 | }
--------------------------------------------------------------------------------
/native/packages/react-swipeable-views-native/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended",
5 | "tslint-react"
6 | ],
7 | "jsRules": {},
8 | "rules": {
9 | "object-literal-sort-keys": false
10 | },
11 | "rulesDirectory": []
12 | }
--------------------------------------------------------------------------------
/native/src/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { AppRegistry, StatusBar } from 'react-native';
3 | import Main from './Main';
4 | import { Provider as PaperProvider } from 'react-native-paper';
5 |
6 | export class App extends React.Component {
7 | componentDidMount() {
8 | StatusBar.setBarStyle('light-content');
9 | }
10 |
11 | render () {
12 | return (
13 |
14 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export default {
21 | start() {
22 | AppRegistry.registerComponent('SwipeableViewsDocs', () => App);
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/native/src/Footer.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Appbar } from 'react-native-paper';
3 | import { styles } from './styles';
4 |
5 | interface Props {
6 | maintainerName: string;
7 | repositoryName: string;
8 | maintainerUrl: string;
9 | repositoryUrl: string;
10 | version: string;
11 | }
12 |
13 | class Footer extends React.Component {
14 | render() {
15 | const { maintainerName, repositoryName, version } = this.props;
16 |
17 | return (
18 |
19 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default Footer;
29 |
--------------------------------------------------------------------------------
/native/src/Home.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { FlatList, View } from 'react-native';
3 | import { List, Divider, withTheme } from 'react-native-paper';
4 | import DemoSimple from './demo/Simple';
5 | import DemoTabs from './demo/Tabs';
6 | import DemoScroll from './demo/Scroll';
7 | import DemoResistance from './demo/Resistance';
8 | import DemoAutoPlay from './demo/AutoPlay';
9 | import DemoVirtualize from './demo/Virtualize';
10 | import DemoHocs from './demo/Hocs';
11 | import { Theme } from 'react-native-paper';
12 | import Footer from './Footer';
13 | import styles from './styles';
14 |
15 | const pkgInfo = require("../packages/react-swipeable-views-native/package.json");
16 |
17 | interface Props {
18 | theme: Theme;
19 | navigation: any;
20 | };
21 |
22 | export const demos = {
23 | simple: DemoSimple,
24 | tabs: DemoTabs,
25 | scroll: DemoScroll,
26 | resistance: DemoResistance,
27 | autoplay: DemoAutoPlay,
28 | virtualize: DemoVirtualize,
29 | hocs: DemoHocs,
30 | };
31 |
32 | const data = Object.keys(demos).map(id => ({ id, data: demos[id] }));
33 |
34 | class Home extends React.Component {
35 | _renderItem = ({ item }) => (
36 | this.props.navigation.navigate(item.id)}
40 | />
41 | );
42 |
43 | _keyExtractor = item => item.id;
44 |
45 | render() {
46 | const {
47 | theme: {
48 | colors: { background },
49 | },
50 | } = this.props;
51 |
52 | return (
53 |
54 |
61 |
68 |
69 | );
70 | }
71 | }
72 |
73 | export default withTheme(Home);
--------------------------------------------------------------------------------
/native/src/Main.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import Home, { demos } from './Home';
3 | import { createStackNavigator } from 'react-navigation';
4 | import { Appbar } from 'react-native-paper';
5 |
6 | const routes = Object.keys(demos)
7 | .map(id => ({ id, item: demos[id] }))
8 | .reduce((acc, { id, item }) => {
9 | const Comp = item;
10 | const Screen = props => ;
11 |
12 | Screen.navigationOptions = props => ({
13 | header: (
14 |
15 | props.navigation.goBack()} />
16 |
17 |
18 | ),
19 | ...(typeof Comp.navigationOptions === 'function'
20 | ? Comp.navigationOptions(props)
21 | : Comp.navigationOptions),
22 | });
23 |
24 | return {
25 | ...acc,
26 | [id]: { screen: Screen },
27 | };
28 | }, {});
29 |
30 | export default createStackNavigator(
31 | {
32 | home: { screen: Home },
33 | ...routes,
34 | },
35 | {
36 | headerMode: "screen",
37 | navigationOptions: () => ({
38 | header: (
39 |
40 |
41 |
42 | ),
43 | }),
44 | }
45 | );
46 |
--------------------------------------------------------------------------------
/native/src/demo/AutoPlay.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import AutoPlay from './AutoPlay';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('AutoPlay snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/AutoPlay.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View } from 'react-native';
3 | import SwipeableViews from '../../packages/react-swipeable-views-native/src';
4 | import { autoPlay } from 'react-swipeable-views-utils';
5 | import Pagination from '../pagination/Pagination';
6 | import { Title } from 'react-native-paper';
7 | import styles from '../styles';
8 |
9 | const AutoPlaySwipeableViews = autoPlay(SwipeableViews);
10 |
11 | class DemoAutoPlay extends React.Component<{}, {index: number}> {
12 | static title = "Auto play";
13 | static description = "With the auto play HOC";
14 |
15 | state = {
16 | index: 0,
17 | };
18 |
19 | handleChangeIndex = index => {
20 | this.setState({
21 | index,
22 | });
23 | };
24 |
25 | render() {
26 | const { index } = this.state;
27 |
28 | return (
29 |
30 |
31 |
32 | slide n°1
33 |
34 |
35 | slide n°2
36 |
37 |
38 | slide n°3
39 |
40 |
41 |
42 |
43 | );
44 | }
45 | }
46 |
47 | export default DemoAutoPlay;
48 |
--------------------------------------------------------------------------------
/native/src/demo/Hocs.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import Hocs from './Hocs';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('Hocs snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/Hocs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View } from 'react-native';
3 | import SwipeableViews from '../../packages/react-swipeable-views-native/src';
4 | import { virtualize, autoPlay } from 'react-swipeable-views-utils';
5 | import { mod } from 'react-swipeable-views-core';
6 | import { Title } from 'react-native-paper';
7 | import styles from '../styles';
8 |
9 | const EnhancedSwipeableViews = autoPlay(virtualize(SwipeableViews));
10 |
11 | function slideRenderer(params) {
12 | const { index, key } = params;
13 | let style;
14 |
15 | switch (mod(index, 3)) {
16 | case 0:
17 | style = styles.slide1;
18 | break;
19 |
20 | case 1:
21 | style = styles.slide2;
22 | break;
23 |
24 | case 2:
25 | style = styles.slide3;
26 | break;
27 |
28 | default:
29 | break;
30 | }
31 |
32 | return (
33 |
34 | {`slide n°${index + 1}`}
35 |
36 | );
37 | }
38 |
39 | class DemoHocs extends React.Component<{}> {
40 | static title = "Hocs";
41 | static description = "With all the HOCs";
42 |
43 | render() {
44 | return ;
45 | }
46 | }
47 |
48 | export default DemoHocs;
49 |
--------------------------------------------------------------------------------
/native/src/demo/Resistance.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import Resistance from './Resistance';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('Resistance snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/Resistance.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View } from 'react-native';
3 | import SwipeableViews from '../../packages/react-swipeable-views-native/src';
4 | import { Headline } from 'react-native-paper';
5 | import styles from '../styles';
6 |
7 | class DemoResistance extends React.Component<{}> {
8 | static title = "Resistance";
9 | static description = "With a resistance bounds effet on the edges";
10 |
11 | render() {
12 | return (
13 |
14 |
15 | slide n°1
16 |
17 |
18 | slide n°2
19 |
20 |
21 | slide n°3
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default DemoResistance;
29 |
--------------------------------------------------------------------------------
/native/src/demo/Scroll.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import Scroll from './Scroll';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('Scroll snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/Scroll.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View, ScrollView } from 'react-native';
3 | import SwipeableViews from '../../packages/react-swipeable-views-native/src/SwipeableViews.scroll';
4 | import { Headline } from 'react-native-paper';
5 | import styles from '../styles';
6 |
7 | const list: any = [];
8 |
9 | for (let i = 0; i < 30; i += 1) {
10 | list.push(
11 |
12 | {`item n°${i + 1}`}
13 | ,
14 | );
15 | }
16 |
17 | class DemoScroll extends React.Component<{}> {
18 | static title = "Scroll";
19 | static description = "Set a constant height and let the swipe and scroll behavior work in harmony";
20 |
21 | render() {
22 | return (
23 |
24 |
30 | {list}
31 |
32 |
33 | slide n°2
34 |
35 |
36 | slide n°3
37 |
38 |
39 | );
40 | }
41 | }
42 |
43 | export default DemoScroll;
44 |
--------------------------------------------------------------------------------
/native/src/demo/Simple.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import Simple from './Simple';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('Simple snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/Simple.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View } from 'react-native';
3 | import SwipeableViews from '../../packages/react-swipeable-views-native/src';
4 | import { Headline } from 'react-native-paper';
5 | import styles from '../styles';
6 |
7 | class DemoSimple extends React.Component<{}> {
8 | static title = "Simple";
9 | static description = "A simple case"
10 |
11 | render() {
12 | return (
13 |
14 |
15 | slide n°1
16 |
17 |
18 | slide n°2
19 |
20 |
21 | slide n°3
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default DemoSimple;
29 |
--------------------------------------------------------------------------------
/native/src/demo/Tabs.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import Tabs from './Tabs';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('Tabs snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/Tabs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View } from 'react-native';
3 | import { Headline, Appbar } from 'react-native-paper';
4 | import SwipeableViews from '../../packages/react-swipeable-views-native/src';
5 | import styles from '../styles';
6 | import NavButtom from '../pagination/NavButtom';
7 |
8 | class DemoTabs extends React.Component {
9 | static title = "Tabs";
10 | static description = "With a header";
11 |
12 | state = {
13 | index: 0,
14 | };
15 |
16 | handleChangeIndex = index => {
17 | this.setState({
18 | index,
19 | });
20 | };
21 |
22 | handleSwitching = (index, type) => {
23 | if (type === "end" && index !== this.state.index) {
24 | this.setState({
25 | index,
26 | });
27 | }
28 | }
29 |
30 | render() {
31 | const { index } = this.state;
32 |
33 | return (
34 |
35 |
36 |
37 | slide n°1
38 |
39 |
40 | slide n°2
41 |
42 |
43 | slide n°3
44 |
45 |
46 |
47 | this.handleChangeIndex(0)}
50 | selected={index === 0}
51 | />
52 | this.handleChangeIndex(1)}
55 | selected={index === 1}
56 | />
57 | this.handleChangeIndex(2)}
60 | selected={index === 2}
61 | />
62 |
63 |
64 | );
65 | }
66 | }
67 |
68 | export default DemoTabs;
69 |
--------------------------------------------------------------------------------
/native/src/demo/Virtualize.test.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import * as React from 'react';
3 | import Virtualize from './Virtualize';
4 | import * as renderer from 'react-test-renderer';
5 |
6 | describe('Virtualize snapshot', () => {
7 | jest.useFakeTimers();
8 |
9 | it('renders the root', async () => {
10 | const tree = renderer.create( ).toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/native/src/demo/Virtualize.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View } from 'react-native';
3 | import SwipeableViews from '../../packages/react-swipeable-views-native/src';
4 | import { virtualize } from 'react-swipeable-views-utils';
5 | import { mod } from 'react-swipeable-views-core';
6 | import { Headline } from 'react-native-paper';
7 | import styles from '../styles';
8 |
9 | const VirtualizeSwipeableViews = virtualize(SwipeableViews);
10 |
11 | function slideRenderer(params) {
12 | const { index, key } = params;
13 | let style;
14 |
15 | switch (mod(index, 3)) {
16 | case 0:
17 | style = styles.slide1;
18 | break;
19 |
20 | case 1:
21 | style = styles.slide2;
22 | break;
23 |
24 | case 2:
25 | style = styles.slide3;
26 | break;
27 |
28 | default:
29 | break;
30 | }
31 |
32 | return (
33 |
34 | {`slide n°${index + 1}`}
35 |
36 | );
37 | }
38 |
39 | class DemoVirtualize extends React.Component<{}> {
40 | static title = "Virtualize";
41 | static description = "With the virtualize HOC";
42 |
43 | state = {
44 | index: 0,
45 | };
46 |
47 | handleChangeIndex = index => {
48 | this.setState({
49 | index,
50 | });
51 | };
52 |
53 | render() {
54 | return (
55 |
60 | );
61 | }
62 | }
63 |
64 | export default DemoVirtualize;
65 |
--------------------------------------------------------------------------------
/native/src/demo/__snapshots__/Scroll.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Scroll snapshot renders the root 1`] = `
4 |
18 | `;
19 |
--------------------------------------------------------------------------------
/native/src/pagination/NavButtom.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Button, withTheme, Theme } from 'react-native-paper';
3 |
4 | interface Props {
5 | title: string;
6 | selected: boolean;
7 | onPress: () => void;
8 | theme: Theme;
9 | }
10 |
11 | class NavButtom extends React.Component {
12 | render() {
13 | const { selected, title, onPress } = this.props;
14 | const { colors } = this.props.theme;
15 |
16 | return (
17 |
23 | {title}
24 |
25 | );
26 | }
27 | }
28 |
29 | export default withTheme(NavButtom);
30 |
--------------------------------------------------------------------------------
/native/src/pagination/Pagination.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet, View } from 'react-native';
3 | import PaginationDot from './PaginationDot';
4 |
5 | const styles = StyleSheet.create({
6 | root: {
7 | position: 'absolute',
8 | bottom: 8,
9 | right: 8,
10 | flexDirection: 'row',
11 | },
12 | });
13 |
14 | interface Props {
15 | dots: number;
16 | index: number;
17 | onChangeIndex: (index: number) => void;
18 | }
19 |
20 | class Pagination extends React.Component {
21 | handleClick = (event, index) => {
22 | this.props.onChangeIndex(index);
23 | };
24 |
25 | render() {
26 | const { index, dots } = this.props;
27 |
28 | const children: any = [];
29 |
30 | for (let i = 0; i < dots; i += 1) {
31 | children.push(
32 | ,
33 | );
34 | }
35 |
36 | return {children} ;
37 | }
38 | }
39 |
40 | export default Pagination;
41 |
--------------------------------------------------------------------------------
/native/src/pagination/PaginationDot.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { StyleSheet, View } from 'react-native';
3 | import { TouchableRipple } from 'react-native-paper';
4 |
5 | const styles = StyleSheet.create({
6 | root: {
7 | height: 18,
8 | width: 18,
9 | borderRadius: 6,
10 | },
11 | dot: {
12 | backgroundColor: '#e4e6e7',
13 | height: 12,
14 | width: 12,
15 | borderRadius: 6,
16 | margin: 3,
17 | },
18 | active: {
19 | backgroundColor: '#319fd6',
20 | },
21 | });
22 |
23 | interface Props {
24 | active: boolean;
25 | index: number;
26 | onClick: (event: any, index: number) => void;
27 | }
28 |
29 | class PaginationDot extends React.Component {
30 | handleClick = event => {
31 | this.props.onClick(event, this.props.index);
32 | };
33 |
34 | render() {
35 | const { active } = this.props;
36 |
37 | let styleDot;
38 |
39 | if (active) {
40 | styleDot = [styles.dot, styles.active];
41 | } else {
42 | styleDot = styles.dot;
43 | }
44 |
45 | return (
46 |
47 |
48 |
49 | );
50 | }
51 | }
52 |
53 | export default PaginationDot;
54 |
--------------------------------------------------------------------------------
/native/src/styles.ts:
--------------------------------------------------------------------------------
1 | import { Colors } from "react-native-paper";
2 | import { StyleSheet } from 'react-native';
3 |
4 | export const styles = {
5 | screen: {
6 | flex: 1,
7 | },
8 | container: {
9 | flex: 1,
10 | },
11 | scroll: {
12 | flex: 1,
13 | },
14 | slideContainer: {
15 | flexGrow: 1,
16 | justifyContent: 'space-between',
17 | } as any,
18 | slide: {
19 | padding: 15,
20 | flex: 1,
21 | justifyContent: "center",
22 | } as any,
23 | slide1: {
24 | backgroundColor: Colors.yellow700,
25 | },
26 | slide2: {
27 | backgroundColor: Colors.green700,
28 | },
29 | slide3: {
30 | backgroundColor: Colors.blue700,
31 | },
32 | text: {
33 | color: Colors.white,
34 | textAlign: "center",
35 | } as any,
36 | toolbar: {
37 | position: 'absolute',
38 | left: 0,
39 | right: 0,
40 | bottom: 0,
41 | } as any,
42 | nav: {
43 | justifyContent: "space-between"
44 | } as any,
45 | };
46 |
47 | export default StyleSheet.create(styles);
--------------------------------------------------------------------------------
/native/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "baseUrl": "./src",
5 | "declaration": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "jsx": "react",
9 | "lib": ["esnext", "dom"],
10 | "module": "commonjs",
11 | "moduleResolution": "node",
12 | "noImplicitAny": false,
13 | "noUnusedLocals": true,
14 | "outDir": "./lib",
15 | "removeComments": true,
16 | "skipLibCheck": true,
17 | "sourceMap": true,
18 | "strict": true,
19 | "target": "es5"
20 | },
21 | "exclude": [
22 | "node_modules",
23 | "lib"
24 | ]
25 | }
--------------------------------------------------------------------------------
/native/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended",
5 | "tslint-react"
6 | ],
7 | "jsRules": {},
8 | "rules": {
9 | "object-literal-sort-keys": false
10 | },
11 | "rulesDirectory": []
12 | }
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const pkg = require('./packages/react-swipeable-views/package.json');
3 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
4 | const { findPages } = require('./docs/src/modules/utils/find');
5 |
6 | process.env.LIB_VERSION = pkg.version;
7 |
8 | module.exports = {
9 | webpack: config => {
10 | const plugins = config.plugins.concat([
11 | new webpack.DefinePlugin({
12 | 'process.env': {
13 | LIB_VERSION: JSON.stringify(process.env.LIB_VERSION),
14 | },
15 | }),
16 | ]);
17 |
18 | if (process.env.DOCS_STATS_ENABLED) {
19 | plugins.push(
20 | // For all options see https://github.com/th0r/webpack-bundle-analyzer#as-plugin
21 | new BundleAnalyzerPlugin({
22 | analyzerMode: 'server',
23 | generateStatsFile: true,
24 | // Will be available at `.next/stats.json`
25 | statsFilename: 'stats.json',
26 | }),
27 | );
28 | }
29 |
30 | return Object.assign({}, config, {
31 | plugins,
32 | node: {
33 | fs: 'empty',
34 | },
35 | module: Object.assign({}, config.module, {
36 | rules: config.module.rules.concat([
37 | {
38 | test: /\.(css|md)$/,
39 | loader: 'emit-file-loader',
40 | options: {
41 | name: 'dist/[path][name].[ext]',
42 | },
43 | },
44 | {
45 | test: /\.(css|md)$/,
46 | loader: 'raw-loader',
47 | },
48 | ]),
49 | }),
50 | });
51 | },
52 | webpackDevMiddleware: config => config,
53 | // next.js also provide a `defaultPathMap` so we could simplify the logic.
54 | // However, we keep it in order to prevent any future regression on the `findPages()` side.
55 | exportPathMap: () => {
56 | const map = {};
57 |
58 | function generateMap(pages) {
59 | pages.forEach(page => {
60 | if (!page.children) {
61 | map[page.pathname] = {
62 | page: page.pathname,
63 | };
64 | return;
65 | }
66 |
67 | generateMap(page.children);
68 | });
69 | }
70 |
71 | generateMap(findPages());
72 |
73 | return map;
74 | },
75 | onDemandEntries: {
76 | // Period (in ms) where the server will keep pages in the buffer
77 | maxInactiveAge: 120 * 1e3, // default 25s
78 | // Number of pages that should be kept simultaneously without being disposed
79 | pagesBufferLength: 3, // default 2
80 | },
81 | };
82 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipeable-views-workspace",
3 | "version": "0.14.0",
4 | "private": true,
5 | "scripts": {
6 | "lint": "eslint . && echo \"eslint: no lint errors\"",
7 | "test": "echo \"ok\"",
8 | "test:unit": "cross-env NODE_ENV=test mocha",
9 | "test:watch": "yarn test:unit -w",
10 | "test:coverage": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha && nyc report -r lcovonly",
11 | "test:coverage:html": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha && nyc report --reporter=html",
12 | "docs:dev": "rimraf node_modules/.cache/babel-loader && cross-env BABEL_ENV=docs-development next dev -p=8001",
13 | "docs:build": "cross-env BABEL_ENV=docs-production next build",
14 | "docs:export": "cross-env NODE_ENV=production BABEL_ENV=docs-production next export -o docs/export",
15 | "docs:deploy": "yarn docs:build && yarn docs:export",
16 | "prettier": "find . -name \"*.js\" | grep -v -f .eslintignore | xargs prettier --write --single-quote --trailing-comma all --print-width 100",
17 | "size": "size-limit",
18 | "size:why": "size-limit --why packages/react-swipeable-views/lib/index.js",
19 | "watch": "lerna exec --concurrency 99 -- babel src --out-dir lib --watch",
20 | "build": "rm -rf packages/*/lib && cross-env NODE_ENV=production lerna exec -- babel --config-file ../../babel.config.js src --out-dir lib --ignore test.js",
21 | "release": "yarn build && yarn lerna exec yarn prepublish && lerna publish",
22 | "postrelease": "yarn docs:deploy"
23 | },
24 | "author": "Olivier Tassinari (https://github.com/oliviertassinari)",
25 | "license": "MIT",
26 | "repository": {
27 | "type": "git",
28 | "url": "https://github.com/oliviertassinari/react-swipeable-views.git"
29 | },
30 | "devDependencies": {
31 | "@babel/cli": "7.0.0",
32 | "@babel/core": "7.0.0",
33 | "@babel/plugin-transform-object-assign": "7.0.0",
34 | "@babel/plugin-transform-runtime": "7.0.0",
35 | "@babel/preset-react": "7.0.0",
36 | "@babel/preset-stage-1": "7.0.0",
37 | "@babel/register": "7.0.0",
38 | "@babel/runtime": "7.0.0",
39 | "@material-ui/core": "^3.0.0",
40 | "@material-ui/docs": "^1.0.0-alpha.3",
41 | "@material-ui/icons": "^3.0.0",
42 | "animated": "^0.2.1",
43 | "autoprefixer": "^9.1.3",
44 | "babel-eslint": "^9.0.0",
45 | "babel-loader": "^8.0.0",
46 | "babel-plugin-istanbul": "^5.0.1",
47 | "babel-plugin-module-resolver": "^3.0.0",
48 | "babel-plugin-preval": "^2.0.0",
49 | "babel-plugin-react-remove-properties": "^0.2.5",
50 | "babel-plugin-transform-dev-warning": "^0.1.0",
51 | "babel-plugin-transform-react-constant-elements": "^6.23.0",
52 | "babel-plugin-transform-react-remove-prop-types": "^0.4.10",
53 | "chai": "^4.1.2",
54 | "chai-shallow-deep-equal": "^1.4.6",
55 | "clean-css": "^4.1.9",
56 | "clipboard-copy": "^2.0.0",
57 | "cross-env": "^5.1.1",
58 | "enzyme": "^3.2.0",
59 | "enzyme-adapter-react-16": "^1.1.0",
60 | "eslint": "^5.4.0",
61 | "eslint-config-airbnb": "^17.0.0",
62 | "eslint-plugin-babel": "^5.0.0",
63 | "eslint-plugin-import": "^2.8.0",
64 | "eslint-plugin-jsx-a11y": "^6.0.2",
65 | "eslint-plugin-mocha": "^5.0.0",
66 | "eslint-plugin-prettier": "^2.3.1",
67 | "eslint-plugin-react": "^7.5.1",
68 | "glob": "^7.1.2",
69 | "jsdom": "^12.0.0",
70 | "lerna": "^3.20.2",
71 | "lz-string": "^1.4.4",
72 | "mocha": "^5.0.0",
73 | "next": "^7.0.0-canary.5",
74 | "nyc": "^13.0.0",
75 | "postcss": "^7.0.2",
76 | "prettier": "^1.8.2",
77 | "prop-types": "^15.6.0",
78 | "raw-loader": "^0.5.1",
79 | "react": "^16.3.0",
80 | "react-dom": "^16.3.0",
81 | "recompose": "^0.29.0",
82 | "sinon": "^6.0.0",
83 | "size-limit": "^0.19.0",
84 | "webpack": "4.16.3",
85 | "webpack-bundle-analyzer": "^2.9.1"
86 | },
87 | "engines": {
88 | "node": ">=10.0.0"
89 | },
90 | "workspaces": [
91 | "packages/*"
92 | ]
93 | }
94 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/.npmignore:
--------------------------------------------------------------------------------
1 | /*
2 | !/src/*.js
3 | !/lib/*.js
4 | *.test.js
5 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipeable-views-core",
3 | "version": "0.14.0",
4 | "description": "react-swipeable-views core modules",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "prepublish": "pkgfiles"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/oliviertassinari/react-swipeable-views.git"
12 | },
13 | "author": "Olivier Tassinari (https://github.com/oliviertassinari)",
14 | "bugs": {
15 | "url": "https://github.com/oliviertassinari/react-swipeable-views/issues"
16 | },
17 | "dependencies": {
18 | "@babel/runtime": "7.0.0",
19 | "warning": "^4.0.1"
20 | },
21 | "devDependencies": {
22 | "pkgfiles": "^2.3.2"
23 | },
24 | "peerDependencies": {
25 | "react": "^15.3.0 || ^16.0.0 || ^17.0.0"
26 | },
27 | "license": "MIT",
28 | "engines": {
29 | "node": ">=6.0.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/checkIndexBounds.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import warning from 'warning';
3 |
4 | const checkIndexBounds = props => {
5 | const { index, children } = props;
6 |
7 | const childrenCount = React.Children.count(children);
8 |
9 | warning(
10 | index >= 0 && index <= childrenCount,
11 | `react-swipeable-view: the new index: ${index} is out of bounds: [0-${childrenCount}].`,
12 | );
13 | };
14 |
15 | export default checkIndexBounds;
16 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/checkIndexBounds.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import React from 'react';
4 | import { stub } from 'sinon';
5 | import { assert } from 'chai';
6 | import checkIndexBounds from './checkIndexBounds';
7 |
8 | describe('checkIndexBounds', () => {
9 | let children;
10 | let consoleStub;
11 |
12 | beforeEach(() => {
13 | children = [
,
];
14 | consoleStub = stub(console, 'error');
15 | });
16 |
17 | afterEach(() => {
18 | console.error.restore();
19 | });
20 |
21 | it('should not warn when the index is in the bounds', () => {
22 | checkIndexBounds({
23 | index: 0,
24 | children,
25 | });
26 | assert.strictEqual(consoleStub.callCount, 0);
27 | });
28 |
29 | it('should warn when the index is out of bounds', () => {
30 | checkIndexBounds({
31 | index: 3,
32 | children,
33 | });
34 | assert.strictEqual(consoleStub.callCount, 1);
35 | assert.strictEqual(
36 | consoleStub.args[0][0],
37 | 'Warning: react-swipeable-view: the new index: 3 is out of bounds: [0-2].',
38 | );
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/computeIndex.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import constant from './constant';
3 |
4 | export default function computeIndex(params) {
5 | const { children, startIndex, startX, pageX, viewLength, resistance } = params;
6 |
7 | const indexMax = React.Children.count(children) - 1;
8 | let index = startIndex + (startX - pageX) / viewLength;
9 | let newStartX;
10 |
11 | if (!resistance) {
12 | // Reset the starting point
13 | if (index < 0) {
14 | index = 0;
15 | newStartX = (index - startIndex) * viewLength + pageX;
16 | } else if (index > indexMax) {
17 | index = indexMax;
18 | newStartX = (index - startIndex) * viewLength + pageX;
19 | }
20 | } else if (index < 0) {
21 | index = Math.exp(index * constant.RESISTANCE_COEF) - 1;
22 | } else if (index > indexMax) {
23 | index = indexMax + 1 - Math.exp((indexMax - index) * constant.RESISTANCE_COEF);
24 | }
25 |
26 | return {
27 | index,
28 | startX: newStartX,
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/computeIndex.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { assert } from 'chai';
3 | import computeIndex from './computeIndex';
4 |
5 | describe('computeIndex', () => {
6 | let children;
7 |
8 | beforeEach(() => {
9 | children = [
,
,
];
10 | });
11 |
12 | it('should compute the next index correctly', () => {
13 | const actual = computeIndex({
14 | children,
15 | startIndex: 0,
16 | startX: 50,
17 | pageX: 10,
18 | viewLength: 100,
19 | resistance: false,
20 | }).index;
21 |
22 | assert.strictEqual(actual, 0.4);
23 | });
24 |
25 | describe('resistance', () => {
26 | it('should not allow to go beyound the bounds when false', () => {
27 | const actual = computeIndex({
28 | children,
29 | startIndex: 0,
30 | startX: 10,
31 | pageX: 50,
32 | viewLength: 100,
33 | resistance: false,
34 | }).index;
35 |
36 | assert.strictEqual(actual, 0);
37 | });
38 |
39 | it('should allow to go beyound the bounds when true', () => {
40 | const actual = computeIndex({
41 | children,
42 | startIndex: 0,
43 | startX: 10,
44 | pageX: 50,
45 | viewLength: 100,
46 | resistance: true,
47 | }).index;
48 |
49 | assert.closeTo(actual, -0.21, 0.05);
50 | });
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/constant.js:
--------------------------------------------------------------------------------
1 | export default {
2 | RESISTANCE_COEF: 0.6,
3 |
4 | // This value is closed to what browsers are using internally to
5 | // trigger a native scroll.
6 | UNCERTAINTY_THRESHOLD: 3, // px
7 | };
8 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/getDisplaySameSlide.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const getDisplaySameSlide = (props, nextProps) => {
4 | let displaySameSlide = false;
5 | const getChildrenKey = child => (child ? child.key : 'empty');
6 |
7 | if (props.children.length && nextProps.children.length) {
8 | const oldKeys = React.Children.map(props.children, getChildrenKey);
9 | const oldKey = oldKeys[props.index];
10 |
11 | if (oldKey !== null && oldKey !== undefined) {
12 | const newKeys = React.Children.map(nextProps.children, getChildrenKey);
13 | const newKey = newKeys[nextProps.index];
14 |
15 | if (oldKey === newKey) {
16 | displaySameSlide = true;
17 | }
18 | }
19 | }
20 |
21 | return displaySameSlide;
22 | };
23 |
24 | export default getDisplaySameSlide;
25 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/getDisplaySameSlide.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { assert } from 'chai';
3 | import { mount } from 'enzyme';
4 | import getDisplaySameSlide from './getDisplaySameSlide';
5 |
6 | const SwipeableViews = ({
7 | index, // eslint-disable-line react/prop-types
8 | ...props
9 | }) =>
;
10 |
11 | describe('getDisplaySameSlide', () => {
12 | it('should return false if there is no key', () => {
13 | const oldState = mount(
14 |
15 | {'slide n°1'}
16 | {'slide n°2'}
17 | {'slide n°3'}
18 | ,
19 | );
20 |
21 | const newState = mount(
22 |
23 | {'slide n°2'}
24 | {'slide n°3'}
25 | ,
26 | );
27 |
28 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), false);
29 | });
30 |
31 | it('should return true if we display the same slide', () => {
32 | const oldState = mount(
33 |
34 |
35 |
36 |
37 | ,
38 | );
39 |
40 | const newState = mount(
41 |
42 |
43 |
44 | ,
45 | );
46 |
47 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), true);
48 | });
49 |
50 | it('should return false if we do not display the same slide', () => {
51 | const oldState = mount(
52 |
53 |
54 |
55 |
56 | ,
57 | );
58 |
59 | const newState = mount(
60 |
61 |
62 |
63 |
64 | ,
65 | );
66 |
67 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), false);
68 | });
69 |
70 | it('should work with null old children', () => {
71 | const oldState = mount(
72 |
73 |
74 |
75 | {null}
76 | ,
77 | );
78 |
79 | const newState = mount(
80 |
81 |
82 |
83 |
84 | ,
85 | );
86 |
87 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), false);
88 | });
89 |
90 | it('should work with null new children', () => {
91 | const oldState = mount(
92 |
93 |
94 |
95 |
96 | ,
97 | );
98 |
99 | const newState = mount(
100 |
101 |
102 | {null}
103 |
104 | ,
105 | );
106 |
107 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), false);
108 | });
109 |
110 | it('should work with both null children', () => {
111 | const oldState = mount(
112 |
113 |
114 |
115 | {null}
116 | ,
117 | );
118 |
119 | const newState = mount(
120 |
121 |
122 | {null}
123 |
124 | ,
125 | );
126 |
127 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), true);
128 | });
129 |
130 | it('should work with dynamic children in arrays', () => {
131 | const oldState = mount(
132 |
133 |
134 | {['2', '3', '4'].map(k => (
135 |
136 | ))}
137 | ,
138 | );
139 |
140 | const newState = mount(
141 |
142 |
143 | {['2', '3', '4'].map(k => (
144 |
145 | ))}
146 | ,
147 | );
148 |
149 | assert.strictEqual(getDisplaySameSlide(oldState.props(), newState.props()), false);
150 | });
151 | });
152 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as checkIndexBounds } from './checkIndexBounds';
2 | export { default as computeIndex } from './computeIndex';
3 | export { default as constant } from './constant';
4 | export { default as getDisplaySameSlide } from './getDisplaySameSlide';
5 | export { default as mod } from './mod';
6 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/mod.js:
--------------------------------------------------------------------------------
1 | // Extended version of % with negative integer support.
2 | function mod(n, m) {
3 | const q = n % m;
4 | return q < 0 ? q + m : q;
5 | }
6 |
7 | export default mod;
8 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-core/src/mod.test.js:
--------------------------------------------------------------------------------
1 | import { assert } from 'chai';
2 | import mod from './mod';
3 |
4 | describe('mod', () => {
5 | it('should work when the integer is zero', () => {
6 | assert.strictEqual(mod(0, 4), 0);
7 | });
8 |
9 | it('should work when the integer is withing the bounds', () => {
10 | assert.strictEqual(mod(1, 4), 1);
11 | });
12 |
13 | it('should work when the integer is above the bounds', () => {
14 | assert.strictEqual(mod(-1, 4), 3);
15 | });
16 |
17 | it('should work when the integer is under the bounds', () => {
18 | assert.strictEqual(mod(6, 4), 2);
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-utils/.npmignore:
--------------------------------------------------------------------------------
1 | /*
2 | !/src/*.js
3 | !/lib/*.js
4 | *.test.js
5 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipeable-views-utils",
3 | "version": "0.14.0",
4 | "description": "react-swipeable-views utility modules",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "prepublish": "pkgfiles"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/oliviertassinari/react-swipeable-views.git"
12 | },
13 | "author": "Olivier Tassinari (https://github.com/oliviertassinari)",
14 | "bugs": {
15 | "url": "https://github.com/oliviertassinari/react-swipeable-views/issues"
16 | },
17 | "dependencies": {
18 | "@babel/runtime": "7.0.0",
19 | "keycode": "^2.1.7",
20 | "prop-types": "^15.6.0",
21 | "react-event-listener": "^0.6.0",
22 | "react-swipeable-views-core": "^0.14.0",
23 | "shallow-equal": "^1.2.1"
24 | },
25 | "devDependencies": {
26 | "pkgfiles": "^2.3.2"
27 | },
28 | "peerDependencies": {
29 | "react": "^15.3.0 || ^16.0.0 || ^17.0.0"
30 | },
31 | "license": "MIT",
32 | "engines": {
33 | "node": ">=6.0.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-utils/src/autoPlay.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { shallowEqualObjects } from 'shallow-equal';
4 | import EventListener from 'react-event-listener';
5 | import { mod } from 'react-swipeable-views-core';
6 |
7 | export default function autoPlay(MyComponent) {
8 | class AutoPlay extends React.Component {
9 | timer = null;
10 |
11 | constructor(props) {
12 | super(props);
13 |
14 | this.state.index = props.index || 0;
15 | }
16 |
17 | state = {};
18 |
19 | componentDidMount() {
20 | this.startInterval();
21 | }
22 |
23 | // eslint-disable-next-line camelcase,react/sort-comp
24 | UNSAFE_componentWillReceiveProps(nextProps) {
25 | const { index } = nextProps;
26 |
27 | if (typeof index === 'number' && index !== this.props.index) {
28 | this.setState({
29 | index,
30 | });
31 | }
32 | }
33 |
34 | componentDidUpdate(prevProps) {
35 | const shouldResetInterval = !shallowEqualObjects(
36 | {
37 | index: prevProps.index,
38 | interval: prevProps.interval,
39 | autoplay: prevProps.autoplay,
40 | },
41 | {
42 | index: this.props.index,
43 | interval: this.props.interval,
44 | autoplay: this.props.autoplay,
45 | },
46 | );
47 |
48 | if (shouldResetInterval) {
49 | this.startInterval();
50 | }
51 | }
52 |
53 | componentWillUnmount() {
54 | clearInterval(this.timer);
55 | }
56 |
57 | handleInterval = () => {
58 | const { children, direction, onChangeIndex, slideCount } = this.props;
59 |
60 | const indexLatest = this.state.index;
61 | let indexNew = indexLatest;
62 |
63 | if (direction === 'incremental') {
64 | indexNew += 1;
65 | } else {
66 | indexNew -= 1;
67 | }
68 |
69 | if (slideCount || children) {
70 | indexNew = mod(indexNew, slideCount || React.Children.count(children));
71 | }
72 |
73 | // Is uncontrolled
74 | if (this.props.index === undefined) {
75 | this.setState({
76 | index: indexNew,
77 | });
78 | }
79 |
80 | if (onChangeIndex) {
81 | onChangeIndex(indexNew, indexLatest);
82 | }
83 | };
84 |
85 | handleChangeIndex = (index, indexLatest, meta) => {
86 | // Is uncontrolled
87 | if (this.props.index === undefined) {
88 | this.setState({
89 | index,
90 | });
91 | }
92 |
93 | if (this.props.onChangeIndex) {
94 | this.props.onChangeIndex(index, indexLatest, meta);
95 | }
96 | };
97 |
98 | handleSwitching = (index, type) => {
99 | if (this.timer) {
100 | clearInterval(this.timer);
101 | this.timer = null;
102 | } else if (type === 'end') {
103 | this.startInterval();
104 | }
105 |
106 | if (this.props.onSwitching) {
107 | this.props.onSwitching(index, type);
108 | }
109 | };
110 |
111 | handleVisibilityChange = e => {
112 | if (e.target.hidden) {
113 | clearInterval(this.timer);
114 | } else {
115 | this.startInterval();
116 | }
117 | };
118 |
119 | startInterval() {
120 | const { autoplay, interval } = this.props;
121 |
122 | clearInterval(this.timer);
123 |
124 | if (autoplay) {
125 | this.timer = setInterval(this.handleInterval, interval);
126 | }
127 | }
128 |
129 | render() {
130 | const {
131 | autoplay,
132 | direction,
133 | index: indexProp,
134 | interval,
135 | onChangeIndex,
136 | ...other
137 | } = this.props;
138 |
139 | const { index } = this.state;
140 |
141 | if (!autoplay) {
142 | return ;
143 | }
144 |
145 | return (
146 |
147 |
153 |
154 | );
155 | }
156 | }
157 |
158 | AutoPlay.propTypes = {
159 | /**
160 | * If `false`, the auto play behavior is disabled.
161 | */
162 | autoplay: PropTypes.bool,
163 | /**
164 | * @ignore
165 | */
166 | children: PropTypes.node,
167 | /**
168 | * This is the auto play direction.
169 | */
170 | direction: PropTypes.oneOf(['incremental', 'decremental']),
171 | /**
172 | * @ignore
173 | */
174 | index: PropTypes.number,
175 | /**
176 | * Delay between auto play transitions (in ms).
177 | */
178 | interval: PropTypes.number,
179 | /**
180 | * @ignore
181 | */
182 | onChangeIndex: PropTypes.func,
183 | /**
184 | * @ignore
185 | */
186 | onSwitching: PropTypes.func,
187 | /**
188 | * @ignore
189 | */
190 | slideCount: PropTypes.number,
191 | };
192 |
193 | AutoPlay.defaultProps = {
194 | autoplay: true,
195 | direction: 'incremental',
196 | interval: 3000,
197 | };
198 |
199 | return AutoPlay;
200 | }
201 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-utils/src/bindKeyboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import keycode from 'keycode';
4 | import EventListener from 'react-event-listener';
5 | import { mod } from 'react-swipeable-views-core';
6 |
7 | export default function bindKeyboard(MyComponent) {
8 | class BindKeyboard extends React.Component {
9 | static propTypes = {
10 | /**
11 | * @ignore
12 | */
13 | axis: PropTypes.oneOf(['x', 'x-reverse', 'y', 'y-reverse']),
14 | /**
15 | * @ignore
16 | */
17 | children: PropTypes.node,
18 | /**
19 | * @ignore
20 | */
21 | index: PropTypes.number,
22 | /**
23 | * @ignore
24 | */
25 | onChangeIndex: PropTypes.func,
26 | /**
27 | * @ignore
28 | */
29 | slideCount: PropTypes.number,
30 | };
31 |
32 | state = {};
33 |
34 | // eslint-disable-next-line camelcase,react/sort-comp
35 | UNSAFE_componentWillMount() {
36 | this.setState({
37 | index: this.props.index || 0,
38 | });
39 | }
40 |
41 | // eslint-disable-next-line camelcase,react/sort-comp
42 | UNSAFE_componentWillReceiveProps(nextProps) {
43 | const { index } = nextProps;
44 |
45 | if (typeof index === 'number' && index !== this.props.index) {
46 | this.setState({
47 | index,
48 | });
49 | }
50 | }
51 |
52 | handleKeyDown = event => {
53 | let action;
54 | const { axis = 'x', children, onChangeIndex, slideCount } = this.props;
55 |
56 | switch (keycode(event)) {
57 | case 'page down':
58 | case 'down':
59 | if (axis === 'y') {
60 | action = 'decrease';
61 | } else if (axis === 'y-reverse') {
62 | action = 'increase';
63 | }
64 | break;
65 |
66 | case 'left':
67 | if (axis === 'x') {
68 | action = 'decrease';
69 | } else if (axis === 'x-reverse') {
70 | action = 'increase';
71 | }
72 | break;
73 |
74 | case 'page up':
75 | case 'up':
76 | if (axis === 'y') {
77 | action = 'increase';
78 | } else if (axis === 'y-reverse') {
79 | action = 'decrease';
80 | }
81 | break;
82 |
83 | case 'right':
84 | if (axis === 'x') {
85 | action = 'increase';
86 | } else if (axis === 'x-reverse') {
87 | action = 'decrease';
88 | }
89 | break;
90 |
91 | default:
92 | break;
93 | }
94 |
95 | if (action) {
96 | const indexLatest = this.state.index;
97 | let indexNew = indexLatest;
98 |
99 | if (action === 'increase') {
100 | indexNew += 1;
101 | } else {
102 | indexNew -= 1;
103 | }
104 |
105 | if (slideCount || children) {
106 | indexNew = mod(indexNew, slideCount || React.Children.count(children));
107 | }
108 |
109 | // Is uncontrolled
110 | if (this.props.index === undefined) {
111 | this.setState({
112 | index: indexNew,
113 | });
114 | }
115 |
116 | if (onChangeIndex) {
117 | onChangeIndex(indexNew, indexLatest);
118 | }
119 | }
120 | };
121 |
122 | handleChangeIndex = (index, indexLatest, meta) => {
123 | // Is uncontrolled
124 | if (this.props.index === undefined) {
125 | this.setState({
126 | index,
127 | });
128 | }
129 |
130 | if (this.props.onChangeIndex) {
131 | this.props.onChangeIndex(index, indexLatest, meta);
132 | }
133 | };
134 |
135 | render() {
136 | const { index: indexProp, onChangeIndex, ...other } = this.props;
137 |
138 | const { index } = this.state;
139 |
140 | return (
141 |
142 |
143 |
144 | );
145 | }
146 | }
147 |
148 | return BindKeyboard;
149 | }
150 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-utils/src/bindKeyboard.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import { assert } from 'chai';
4 | import { spy } from 'sinon';
5 | import keycode from 'keycode';
6 | import bindKeyboard from './bindKeyboard';
7 |
8 | const Empty = () =>
;
9 | const BindKeyboardSwipeableViews = bindKeyboard(Empty);
10 |
11 | describe('bindKeyboard', () => {
12 | let wrapper;
13 |
14 | beforeEach(() => {
15 | wrapper = shallow(
16 |
17 | {'slide n°1'}
18 | {'slide n°2'}
19 | {'slide n°3'}
20 | ,
21 | );
22 | });
23 |
24 | describe('prop: children', () => {
25 | it('should start at the beginning', () => {
26 | assert.strictEqual(wrapper.state().index, 0, 'Should start at the beginning.');
27 | });
28 | });
29 |
30 | describe('prop: slideCount', () => {
31 | it('should use the slideCount to compute the index limit', () => {
32 | wrapper.setProps({
33 | slideCount: 2,
34 | });
35 | wrapper.simulate('keydown', {
36 | keyCode: keycode('right'),
37 | });
38 | assert.strictEqual(wrapper.state().index, 1, 'Should increment the index.');
39 | wrapper.simulate('keydown', {
40 | keyCode: keycode('right'),
41 | });
42 | assert.strictEqual(wrapper.state().index, 0, 'Should go back to the beginning.');
43 | });
44 | });
45 |
46 | describe('keyboard strokes', () => {
47 | it('should increment the index', () => {
48 | wrapper.simulate('keydown', {
49 | keyCode: keycode('right'),
50 | });
51 |
52 | assert.strictEqual(wrapper.state().index, 1, 'Should have the right index.');
53 | });
54 |
55 | it('should decrement the index using a modulo', () => {
56 | wrapper.simulate('keydown', {
57 | keyCode: keycode('left'),
58 | });
59 |
60 | assert.strictEqual(wrapper.state().index, 2, 'Should have the right index.');
61 | });
62 | });
63 |
64 | describe('prop: onChangeIndex', () => {
65 | it('should be called and with the right arguments when using the keyboard', () => {
66 | const handleChangeIndex = spy();
67 |
68 | wrapper.setProps({
69 | onChangeIndex: handleChangeIndex,
70 | });
71 | wrapper.simulate('keydown', {
72 | keyCode: keycode('right'),
73 | });
74 |
75 | assert.strictEqual(
76 | handleChangeIndex.callCount,
77 | 1,
78 | 'Should be called the right number of time.',
79 | );
80 | assert.deepEqual(handleChangeIndex.args, [[1, 0]]);
81 | });
82 |
83 | it('should be called with the right value when swiping', () => {
84 | const handleChangeIndex = spy();
85 |
86 | wrapper.setProps({
87 | index: 0,
88 | onChangeIndex: handleChangeIndex,
89 | });
90 | wrapper.find(Empty).simulate('changeIndex', 1, 0);
91 | assert.deepEqual(handleChangeIndex.args, [[1, 0, undefined]]);
92 | assert.strictEqual(wrapper.state().index, 0, 'should no update the state index');
93 | });
94 | });
95 |
96 | describe('uncontrolled', () => {
97 | it('should update the state index when swiping', () => {
98 | wrapper.setProps({});
99 | wrapper.find(Empty).simulate('changeIndex', 1, 0);
100 | assert.strictEqual(wrapper.state().index, 1, 'should update the state index');
101 | });
102 | });
103 | });
104 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views-utils/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as autoPlay } from './autoPlay';
2 | export { default as bindKeyboard } from './bindKeyboard';
3 | export { default as virtualize } from './virtualize';
4 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views/.npmignore:
--------------------------------------------------------------------------------
1 | /*
2 | !/src/*.js
3 | !/lib/*.js
4 | !/dist/*
5 | *.test.js
6 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views/dist/legacy-browser-support.css:
--------------------------------------------------------------------------------
1 | .react-swipeable-view-container {
2 | display: -webkit-box;
3 | display: -ms-flexbox;
4 | }
5 |
6 | .react-swipeable-view-container > div {
7 | -ms-flex-negative: 0;
8 | }
9 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipeable-views",
3 | "version": "0.14.0",
4 | "description": "A React component for swipeable views",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "prepublish": "pkgfiles"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/oliviertassinari/react-swipeable-views.git"
12 | },
13 | "keywords": [
14 | "react",
15 | "component",
16 | "swipe",
17 | "swipeable"
18 | ],
19 | "author": "Olivier Tassinari (https://github.com/oliviertassinari)",
20 | "bugs": {
21 | "url": "https://github.com/oliviertassinari/react-swipeable-views/issues"
22 | },
23 | "dependencies": {
24 | "@babel/runtime": "7.0.0",
25 | "prop-types": "^15.5.4",
26 | "react-swipeable-views-core": "^0.14.0",
27 | "react-swipeable-views-utils": "^0.14.0",
28 | "warning": "^4.0.1"
29 | },
30 | "peerDependencies": {
31 | "react": "^15.3.0 || ^16.0.0 || ^17.0.0"
32 | },
33 | "devDependencies": {
34 | "pkgfiles": "^2.3.2"
35 | },
36 | "license": "MIT",
37 | "engines": {
38 | "node": ">=6.0.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/react-swipeable-views/src/index.js:
--------------------------------------------------------------------------------
1 | export { default, SwipeableViewsContext } from './SwipeableViews';
2 |
--------------------------------------------------------------------------------
/pages/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | rules: {
3 | 'global-require': 'off',
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/pages/_document.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Document, { Head, Main, NextScript } from 'next/document';
3 | import getPageContext from 'docs/src/modules/styles/getPageContext';
4 |
5 | // You can find a benchmark of the available CSS minifiers under
6 | // https://github.com/GoalSmashers/css-minification-benchmark
7 | // We have found that clean-css is faster than cssnano but the output is larger.
8 | // Waiting for https://github.com/cssinjs/jss/issues/279
9 | // 4% slower but 12% smaller output than doing it in a single step.
10 | //
11 | // It's using .browserslistrc
12 | let prefixer;
13 | let cleanCSS;
14 | if (process.env.NODE_ENV === 'production') {
15 | const postcss = require('postcss');
16 | const autoprefixer = require('autoprefixer');
17 | const CleanCSS = require('clean-css');
18 |
19 | prefixer = postcss([autoprefixer]);
20 | cleanCSS = new CleanCSS();
21 | }
22 |
23 | class MyDocument extends Document {
24 | render() {
25 | const { pageContext } = this.props;
26 |
27 | return (
28 |
29 |
30 | {/* Use minimum-scale=1 to enable GPU rasterization */}
31 |
35 | {/*
36 | manifest.json provides metadata used when your web app is added to the
37 | homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
38 | */}
39 |
40 | {/* PWA primary color */}
41 |
42 |
43 |
47 | {/*
48 | Preconnect allows the browser to setup early connections before an HTTP request
49 | is actually sent to the server.
50 | This includes DNS lookups, TLS negotiations, TCP handshakes.
51 | */}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | }
64 |
65 | MyDocument.getInitialProps = async ctx => {
66 | // Resolution order
67 | //
68 | // On the server:
69 | // 1. page.getInitialProps
70 | // 2. document.getInitialProps
71 | // 3. page.render
72 | // 4. document.render
73 | //
74 | // On the server with error:
75 | // 2. document.getInitialProps
76 | // 3. page.render
77 | // 4. document.render
78 | //
79 | // On the client
80 | // 1. page.getInitialProps
81 | // 3. page.render
82 |
83 | // Get the context of the page to collected side effects.
84 | const pageContext = getPageContext();
85 | const page = ctx.renderPage(Component => props => (
86 |
87 | ));
88 |
89 | let css = pageContext.sheetsRegistry.toString();
90 | if (process.env.NODE_ENV === 'production') {
91 | const result1 = await prefixer.process(css, { from: undefined });
92 | css = result1.css;
93 | css = cleanCSS.minify(css).styles;
94 | }
95 |
96 | return {
97 | ...page,
98 | pageContext,
99 | styles: (
100 |
105 | ),
106 | };
107 | };
108 |
109 | export default MyDocument;
110 |
--------------------------------------------------------------------------------
/pages/api/api.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import withRoot from 'docs/src/modules/components/withRoot';
3 | import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
4 | import markdown from 'docs/src/pages/api/api.md';
5 |
6 | function Page() {
7 | return ;
8 | }
9 |
10 | export default withRoot(Page);
11 |
--------------------------------------------------------------------------------
/pages/demos/demos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import withRoot from 'docs/src/modules/components/withRoot';
3 | import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
4 | import markdown from 'docs/src/pages/demos/demos.md';
5 |
6 | function Page() {
7 | return (
8 |
118 | );
119 | }
120 |
121 | export default withRoot(Page);
122 |
--------------------------------------------------------------------------------
/pages/getting-started/example-projects.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import withRoot from 'docs/src/modules/components/withRoot';
3 | import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
4 | import markdown from 'docs/src/pages/getting-started/example-projects.md';
5 |
6 | function Page() {
7 | return ;
8 | }
9 |
10 | export default withRoot(Page);
11 |
--------------------------------------------------------------------------------
/pages/getting-started/installation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import withRoot from 'docs/src/modules/components/withRoot';
3 | import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
4 | import markdown from 'docs/src/pages/getting-started/installation.md';
5 |
6 | function Page() {
7 | return ;
8 | }
9 |
10 | export default withRoot(Page);
11 |
--------------------------------------------------------------------------------
/pages/getting-started/supported-platforms.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import withRoot from 'docs/src/modules/components/withRoot';
3 | import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
4 | import markdown from 'docs/src/pages/getting-started/supported-platforms.md';
5 |
6 | function Page() {
7 | return ;
8 | }
9 |
10 | export default withRoot(Page);
11 |
--------------------------------------------------------------------------------
/pages/getting-started/usage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import withRoot from 'docs/src/modules/components/withRoot';
3 | import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
4 | import markdown from 'docs/src/pages/getting-started/usage.md';
5 |
6 | function Page() {
7 | return ;
8 | }
9 |
10 | export default withRoot(Page);
11 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import compose from 'recompose/compose';
6 | import Head from 'docs/src/modules/components/Head';
7 | import { withStyles } from '@material-ui/core/styles';
8 | import Typography from '@material-ui/core/Typography';
9 | import Button from '@material-ui/core/Button';
10 | import withRoot from 'docs/src/modules/components/withRoot';
11 | import AppFrame from 'docs/src/modules/components/AppFrame';
12 | import Link from 'docs/src/modules/components/Link';
13 |
14 | const styles = theme => ({
15 | root: {
16 | flex: '1 0 100%',
17 | },
18 | hero: {
19 | minHeight: '100vh', // Makes the hero full height until we get some more content.
20 | flex: '0 0 auto',
21 | display: 'flex',
22 | justifyContent: 'center',
23 | alignItems: 'center',
24 | backgroundColor: theme.palette.primary[500],
25 | color: theme.palette.getContrastText(theme.palette.primary[500]),
26 | },
27 | content: {
28 | paddingTop: theme.spacing.unit * 8,
29 | paddingBottom: theme.spacing.unit * 8,
30 | [theme.breakpoints.up('sm')]: {
31 | paddingTop: theme.spacing.unit * 16,
32 | paddingBottom: theme.spacing.unit * 16,
33 | },
34 | },
35 | text: {
36 | paddingLeft: theme.spacing.unit * 4,
37 | paddingRight: theme.spacing.unit * 4,
38 | display: 'flex',
39 | flexDirection: 'column',
40 | alignItems: 'center',
41 | justifyContent: 'center',
42 | },
43 | headline: {
44 | maxWidth: 500,
45 | textAlign: 'center',
46 | },
47 | button: {
48 | marginTop: theme.spacing.unit * 3,
49 | },
50 | });
51 |
52 | function PageHome(props) {
53 | const classes = props.classes;
54 |
55 | return (
56 |
57 |
58 |
59 |
60 |
61 |
62 |
69 | {'react-swipeable-views'}
70 |
71 |
77 | {'A React component for swipeable views.'}
78 |
79 | (
81 |
87 | )}
88 | className={classes.button}
89 | variant="raised"
90 | >
91 | {'Get Started'}
92 |
93 |
94 |
95 |
96 |
97 |
98 | );
99 | }
100 |
101 | PageHome.propTypes = {
102 | classes: PropTypes.object.isRequired,
103 | };
104 |
105 | export default compose(
106 | withRoot,
107 | withStyles(styles),
108 | )(PageHome);
109 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 100,
3 | singleQuote: true,
4 | trailingComma: 'all',
5 | bracketSpacing: true,
6 | jsxBracketSameLine: false,
7 | parser: 'babylon',
8 | semi: true,
9 | };
10 |
--------------------------------------------------------------------------------
/scripts/get-replacement.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // Waiting for https://github.com/kentcdodds/babel-plugin-preval/issues/52
3 |
4 | 'use strict';
5 |
6 | var requireFromString = require('require-from-string');
7 | var objectToAST = require('babel-plugin-preval/dist/object-to-ast');
8 |
9 | module.exports = getReplacement;
10 |
11 | function getReplacement(_ref) {
12 | var stringToPreval = _ref.string,
13 | filename = _ref.filename,
14 | babel = _ref.babel;
15 |
16 | var _babel$transform = babel.transform(stringToPreval, {
17 | filename,
18 | }),
19 | code = _babel$transform.code;
20 |
21 | var transpiled = `require('@babel/register');\n${code}`;
22 | var val = requireFromString(transpiled, filename);
23 | return objectToAST(val);
24 | }
25 |
--------------------------------------------------------------------------------
/static/album-art-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-1.jpg
--------------------------------------------------------------------------------
/static/album-art-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-2.jpg
--------------------------------------------------------------------------------
/static/album-art-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-3.jpg
--------------------------------------------------------------------------------
/static/album-art-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-4.jpg
--------------------------------------------------------------------------------
/static/album-art-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-5.jpg
--------------------------------------------------------------------------------
/static/album-art-6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-6.jpg
--------------------------------------------------------------------------------
/static/album-art-7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-7.jpg
--------------------------------------------------------------------------------
/static/album-art-8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/album-art-8.jpg
--------------------------------------------------------------------------------
/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-swipeable-views",
3 | "short_name": "RS-views",
4 | "display": "standalone",
5 | "start_url": "/",
6 | "theme_color": "#2196f3",
7 | "background_color": "#2196f3"
8 | }
9 |
--------------------------------------------------------------------------------
/static/platformAndroid.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/platformAndroid.gif
--------------------------------------------------------------------------------
/static/platformBrowser.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/platformBrowser.gif
--------------------------------------------------------------------------------
/static/platformIOS.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/platformIOS.gif
--------------------------------------------------------------------------------
/static/usage.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oliviertassinari/react-swipeable-views/be57b7d9ba34c349a725b5ce9c0b265e0a9a9c18/static/usage.gif
--------------------------------------------------------------------------------
/test/consoleError.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation, no-console */
2 |
3 | /**
4 | * Makes sure the tests fails when a PropType validation fails.
5 | */
6 | function consoleError() {
7 | console.error = (...args) => {
8 | console.log(...args);
9 | throw new Error(...args);
10 | };
11 | }
12 |
13 | module.exports = consoleError;
14 |
--------------------------------------------------------------------------------
/test/dom.js:
--------------------------------------------------------------------------------
1 | const { JSDOM } = require('jsdom');
2 | const Node = require('jsdom/lib/jsdom/living/node-document-position');
3 |
4 | // We can use jsdom-global at some point if maintaining these lists is a burden.
5 | const whitelist = ['HTMLElement', 'Performance'];
6 | const blacklist = ['sessionStorage', 'localStorage'];
7 |
8 | function createDOM() {
9 | const dom = new JSDOM('', { pretendToBeVisual: true });
10 | global.window = dom.window;
11 | global.Node = Node;
12 | global.document = dom.window.document;
13 | global.navigator = {
14 | userAgent: 'node.js',
15 | };
16 |
17 | Object.keys(dom.window)
18 | .filter(key => !blacklist.includes(key))
19 | .concat(whitelist)
20 | .forEach(key => {
21 | if (typeof global[key] === 'undefined') {
22 | global[key] = dom.window[key];
23 | }
24 | });
25 | }
26 |
27 | module.exports = createDOM;
28 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --require @babel/register
2 | --reporter dot
3 | --recursive
4 | test/setup.js
5 | packages/{,**/}*.test.js
6 |
--------------------------------------------------------------------------------
/test/setup.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | const enzyme = require('enzyme');
4 | const Adapter = require('enzyme-adapter-react-16');
5 | const chai = require('chai');
6 |
7 | require('./dom')();
8 | require('./consoleError')();
9 | chai.use(require('chai-shallow-deep-equal'));
10 |
11 | enzyme.configure({ adapter: new Adapter() });
12 |
--------------------------------------------------------------------------------