├── .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 | [![npm version](https://img.shields.io/npm/v/react-swipeable-views.svg)](https://www.npmjs.com/package/react-swipeable-views) | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views.svg)](https://www.npmjs.com/package/react-swipeable-views) | 5.08 | 8 | | react-swipeable-views-utils | [![npm version](https://img.shields.io/npm/v/react-swipeable-views-utils.svg)](https://www.npmjs.com/package/react-swipeable-views-utils) | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views-utils.svg)](https://www.npmjs.com/package/react-swipeable-views-utils) | 3.52 | 9 | | react-swipeable-views-native | [![npm version](https://img.shields.io/npm/v/react-swipeable-views-native.svg)](https://www.npmjs.com/package/react-swipeable-views-native) | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views-native.svg)](https://www.npmjs.com/package/react-swipeable-views-native) | ? | 10 | 11 | [![Build Status](https://travis-ci.org/oliviertassinari/react-swipeable-views.svg?branch=master)](https://travis-ci.org/oliviertassinari/react-swipeable-views) 12 | [![Dependencies](https://img.shields.io/david/oliviertassinari/react-swipeable-views.svg)](https://david-dm.org/oliviertassinari/react-swipeable-views) 13 | [![DevDependencies](https://img.shields.io/david/dev/oliviertassinari/react-swipeable-views.svg)](https://david-dm.org/oliviertassinari/react-swipeable-views#info=devDependencies&view=list) 14 | [![Donate](https://img.shields.io/badge/$-support-green.svg)](https://www.paypal.me/oliviertassinari/10) 15 | [![TypeScript definitions on DefinitelyTyped](https://img.shields.io/badge/style-.d.ts-green.svg?style=flat&label=DefinitelyTyped)](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-swipeable-views) 16 | [![Coverage Status](https://img.shields.io/codecov/c/github/oliviertassinari/react-swipeable-views/master.svg)](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 | ![usage](/static/usage.gif) 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 | 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 | 93 | 94 | ); 95 | } 96 | 97 | return ( 98 | 99 | 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 | 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 | 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 | 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 | 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 |
35 |
slide n°3
36 |
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 | cover 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 | 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 | 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 | [![npm version](https://img.shields.io/npm/v/react-swipeable-views.svg)](https://www.npmjs.com/package/react-swipeable-views) | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views.svg)](https://www.npmjs.com/package/react-swipeable-views) | 5.08 | 10 | | react-swipeable-views-utils | [![npm version](https://img.shields.io/npm/v/react-swipeable-views-utils.svg)](https://www.npmjs.com/package/react-swipeable-views-utils) | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views-utils.svg)](https://www.npmjs.com/package/react-swipeable-views-utils) | 3.52 | 11 | | react-swipeable-views-native | [![npm version](https://img.shields.io/npm/v/react-swipeable-views-native.svg)](https://www.npmjs.com/package/react-swipeable-views-native) | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views-native.svg)](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 | ![browser](/static/platformBrowser.gif) 19 | 20 | ### iOS 21 | 22 | ![ios](/static/platformIOS.gif) 23 | 24 | ### Android 25 | 26 | ![android](/static/platformAndroid.gif) 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 | ![usage](/static/usage.gif) 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 | 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 | [![npm version](https://img.shields.io/npm/v/react-swipeable-views-native.svg)](https://www.npmjs.com/package/react-swipeable-views-native) 4 | [![npm downloads](https://img.shields.io/npm/dm/react-swipeable-views-native.svg)](https://www.npmjs.com/package/react-swipeable-views-native) 5 | [![Demo](https://img.shields.io/badge/demo-expo-blue.svg)](https://expo.io/@yacut/react-swipeable-views-native) 6 | [![Donate](https://img.shields.io/badge/$-support-green.svg)](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 |