├── .eslintrc ├── .flowconfig ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── example ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .watchmanconfig ├── App.js ├── app.json ├── assets │ ├── icon.png │ ├── spb.jpg │ └── splash.png ├── babel.config.js ├── metro.config.js └── package.json ├── package-lock.json ├── package.json ├── src ├── ImageView.js ├── controls │ ├── Close.js │ ├── Next.js │ ├── Prev.js │ └── index.js ├── styles.js ├── types.js └── utils.js ├── static ├── demo.gif ├── demoV2.gif ├── demo_android.gif └── demo_ios.gif └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "airbnb", 5 | "plugin:flowtype/recommended", 6 | "plugin:jest/recommended", 7 | "prettier", 8 | "prettier/react" 9 | ], 10 | "plugins": [ 11 | "flowtype", 12 | "jest", 13 | "prettier" 14 | ], 15 | "rules": { 16 | "prettier/prettier": "error", 17 | "react/jsx-filename-extension": [ 18 | 1, 19 | { 20 | "extensions": [ 21 | ".js", 22 | ".jsx" 23 | ] 24 | } 25 | ], 26 | "import/extensions": "off", 27 | "import/no-unresolved": "off", 28 | "react/require-default-props": "off", 29 | "react/destructuring-assignment": "off", 30 | "global-require": "off", 31 | "no-restricted-properties": "off", 32 | "no-unused-vars": "error", 33 | "import/no-extraneous-dependencies": "error", 34 | "flowtype/no-weak-types": [ 35 | 1, 36 | { 37 | "any": true, 38 | "Function": true, 39 | "Object": false 40 | } 41 | ] 42 | }, 43 | "env": { 44 | "es6": true 45 | } 46 | } -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | ; Ignore metro 20 | .*/node_modules/metro/.* 21 | 22 | [include] 23 | 24 | [libs] 25 | node_modules/react-native/Libraries/react-native/react-native-interface.js 26 | node_modules/react-native/flow/ 27 | node_modules/react-native/flow-github/ 28 | 29 | [options] 30 | emoji=true 31 | 32 | module.system=haste 33 | 34 | munge_underscores=true 35 | 36 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 37 | 38 | module.file_ext=.js 39 | module.file_ext=.jsx 40 | module.file_ext=.json 41 | module.file_ext=.native.js 42 | 43 | suppress_type=$FlowIssue 44 | suppress_type=$FlowFixMe 45 | suppress_type=$FlowFixMeProps 46 | suppress_type=$FlowFixMeState 47 | 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 51 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 52 | 53 | [version] 54 | ^0.71.0 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea 3 | .expo -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "parser": "flow", 4 | "printWidth": 80, 5 | "singleQuote": true, 6 | "tabWidth": 4, 7 | "trailingComma": "es5" 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Anton Kalinin 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 | ## If you are using React Native >= 0.59.0 it's recommended to use similar package https://github.com/jobtoday/react-native-image-viewing as improved and better supported version! 2 | 3 | [![npm version](https://badge.fury.io/js/react-native-image-view.svg)](https://badge.fury.io/js/react-native-image-view) 4 | 5 | React Native modal image view with pinch zoom and carousel. 6 | 7 | Try with expo: https://expo.io/@antonkalinin/react-native-image-view 8 | 9 | #### Warning: Breaking changes since v2.0.0: 10 | 11 | - instead of prop `source` => `images` 12 | - no title prop for footer, please use `renderFooter` instead 13 | 14 | ## Installation 15 | 16 | ```bash 17 | yarn add react-native-image-view 18 | ``` 19 | 20 | or 21 | 22 | ```bash 23 | npm install --save react-native-image-view 24 | ``` 25 | 26 | ## Demo 27 | 28 |

29 | 30 |

31 | 32 | ## Usage 33 | ```jsx 34 | import ImageView from 'react-native-image-view'; 35 | 36 | const images = [ 37 | { 38 | source: { 39 | uri: 'https://cdn.pixabay.com/photo/2017/08/17/10/47/paris-2650808_960_720.jpg', 40 | }, 41 | title: 'Paris', 42 | width: 806, 43 | height: 720, 44 | }, 45 | ]; 46 | 47 | (My footer)} 52 | /> 53 | ``` 54 | 55 | #### [See example for better understanding](https://github.com/antonKalinin/react-native-image-view/blob/master/example/App.js) 56 | 57 | ## Props 58 | 59 | Prop name | Description | Type | Default value | Platform | 60 | --------------------|---------------|-----------|---------------|----------| 61 | `animationType` | Type of animation modal presented with | "none", "fade", "slide" | "none" | 62 | `backgroundColor` | Background color of the modal in HEX (#0099CC) | string | null | 63 | `controls` | Config of available controls (see below) | Object | {close: true} | 64 | `glideAlways` | Emulates ScrollView glide animation if built-in was not triggered | boolean | false | Android 65 | `glideAlwaysDelay` | Defines delay in milliseconds for glideAlways | number | 75 | Android 66 | `images` | Array of images to display, see below image item description | array | [] | 67 | `imageIndex` | Current index of image to display | number | 0 | 68 | `isVisible` | Is modal shown or not | boolean | false | 69 | `isTapZoomEnabled` | Zoom image when double tapped | boolean | true | 70 | `isPinchZoomEnabled` | Zoom image with pinch gesture | boolean | true | 71 | `isSwipeCloseEnabled` | Close modal with swipe up or down | boolean | true | 72 | `onClose` | Function called on modal closed | function | none | 73 | `onImageChange` | Function called when image is changed | function | none | 74 | `renderFooter` | Function returns a footer element | function | none | 75 | 76 | #### Image item: 77 | 78 | ```js 79 | { 80 | source: any, // Image Component source object 81 | width: ?number, // Width of full screen image (optional but recommended) 82 | height: ?number, // Height of full screen image (optional but recommended) 83 | // any other props you need to render your footer 84 | } 85 | ``` 86 | 87 | It's recommended to specify width and height to speed up rendering, overwise component needs to fetch images sizes and cache them in images objects passed as props. 88 | 89 | #### controls prop: 90 | 91 | ```js 92 | type ControlType = React.Component<{onPress: () => void}> | null | boolean, 93 | 94 | { 95 | close: ControlType // Component for close button in up right corner, as onPress prop accepts function to close modal 96 | next: ControlType, // Component for next image button, as onPress prop accepts function to scroll to next image 97 | prev: ControlType, // Component for previous image button, as onPress prop accepts function to scroll to previous image 98 | } 99 | ``` 100 | 101 | To use default components just set `{next: true, prev: true}`, close is showing by default. To create custom controls check src/controls. 102 | 103 | ### License 104 | [MIT](LICENSE) 105 | -------------------------------------------------------------------------------- /example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb", 4 | "prettier", 5 | "prettier/flowtype", 6 | "prettier/react" 7 | ], 8 | "rules": { 9 | "indent": ["error", 4], 10 | "comma-dangle": ["error", { 11 | "arrays": "always-multiline", 12 | "objects": "always-multiline", 13 | "imports": "always-multiline", 14 | "exports": "always-multiline", 15 | "functions": "ignore" 16 | }], 17 | "no-console": 0, 18 | "no-restricted-properties": 0, 19 | "object-curly-spacing": ["error", "never"], 20 | "prettier/prettier": "error", 21 | "react/prop-types": ["error", {"customValidators": ["skipUndeclared"]}], 22 | "react/jsx-indent-props": ["error", 4], 23 | "react/jsx-indent": ["error", 4], 24 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }] 25 | }, 26 | "root": true, 27 | "plugins": [ 28 | "react", 29 | "flowtype", 30 | "prettier" 31 | ], 32 | "settings": { 33 | "flowtype": { 34 | "onlyFilesWithFlowAnnotation": true 35 | } 36 | }, 37 | "parser": "babel-eslint", 38 | "parserOptions": { 39 | "ecmaFeatures": { 40 | "experimentalObjectRestSpread": true 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | ; Ignore metro 20 | .*/node_modules/metro/.* 21 | 22 | [include] 23 | 24 | [libs] 25 | node_modules/react-native/Libraries/react-native/react-native-interface.js 26 | node_modules/react-native/flow/ 27 | node_modules/react-native/flow-github/ 28 | 29 | [options] 30 | emoji=true 31 | 32 | module.system=haste 33 | 34 | munge_underscores=true 35 | 36 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 37 | 38 | module.file_ext=.js 39 | module.file_ext=.jsx 40 | module.file_ext=.json 41 | module.file_ext=.native.js 42 | 43 | suppress_type=$FlowIssue 44 | suppress_type=$FlowFixMe 45 | suppress_type=$FlowFixMeProps 46 | suppress_type=$FlowFixMeState 47 | 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 51 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 52 | 53 | [version] 54 | ^0.71.0 -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | yarn.lock 5 | ImageView.js 6 | types.js 7 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /example/App.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { 3 | Text, 4 | View, 5 | Image, 6 | TouchableOpacity, 7 | StyleSheet, 8 | Dimensions, 9 | Platform, 10 | } from 'react-native'; 11 | 12 | // import ImageView from '../src/ImageView'; 13 | import ImageView from 'react-native-image-view'; 14 | 15 | const {width} = Dimensions.get('window'); 16 | 17 | const cities = [ 18 | { 19 | source: { 20 | uri: 21 | 'https://avatars.mds.yandex.net/get-pdb/49816/d9152cc6-bf48-4e44-b2d5-de73b2e94454/s800', 22 | }, 23 | title: 'London', 24 | }, 25 | { 26 | // eslint-disable-next-line 27 | source: require('./assets/spb.jpg'), 28 | title: 'St-Petersburg', 29 | width: 1200, 30 | height: 800, 31 | }, 32 | { 33 | source: { 34 | uri: 35 | 'https://cdn.pixabay.com/photo/2017/08/17/10/47/paris-2650808_960_720.jpg', 36 | }, 37 | title: 'Paris', 38 | width: 806, 39 | height: 720, 40 | }, 41 | ]; 42 | 43 | const nature = [ 44 | { 45 | source: { 46 | uri: 47 | 'https://images.fineartamerica.com/images/artworkimages/mediumlarge/1/1-forest-in-fog-russian-nature-forest-mist-dmitry-ilyshev.jpg', 48 | }, 49 | title: 'Switzerland', 50 | }, 51 | 52 | { 53 | source: { 54 | uri: 55 | 'https://i.pinimg.com/564x/a5/1b/63/a51b63c13c7c41fa333b302fc7938f06.jpg', 56 | }, 57 | title: 'USA', 58 | width: 400, 59 | height: 800, 60 | }, 61 | { 62 | source: { 63 | uri: 64 | 'https://guidetoiceland.imgix.net/4935/x/0/top-10-beautiful-waterfalls-of-iceland-8?auto=compress%2Cformat&ch=Width%2CDPR&dpr=1&ixlib=php-2.1.1&w=883&s=1fb8e5e1906e1d18fc6b08108a9dde8d', 65 | }, 66 | title: 'Iceland', 67 | width: 880, 68 | height: 590, 69 | }, 70 | ]; 71 | 72 | const tabs = [ 73 | {title: 'Cities', images: cities}, 74 | {title: 'Nature', images: nature}, 75 | ]; 76 | 77 | const styles = StyleSheet.create({ 78 | container: { 79 | flex: 1, 80 | flexDirection: 'column', 81 | alignItems: 'center', 82 | justifyContent: 'center', 83 | backgroundColor: '#000', 84 | paddingTop: Platform.select({ios: 0, android: 10}), 85 | }, 86 | tabs: { 87 | flexDirection: 'row', 88 | }, 89 | tab: { 90 | flex: 1, 91 | height: 30, 92 | alignItems: 'center', 93 | justifyContent: 'flex-end', 94 | }, 95 | tabTitle: { 96 | color: '#EEE', 97 | }, 98 | tabTitleActive: { 99 | fontWeight: '700', 100 | color: '#FFF', 101 | }, 102 | footer: { 103 | width, 104 | height: 50, 105 | flexDirection: 'row', 106 | alignItems: 'center', 107 | justifyContent: 'center', 108 | backgroundColor: 'rgba(0, 0, 0, 0.4)', 109 | paddingHorizontal: 10, 110 | paddingVertical: 5, 111 | }, 112 | footerButton: { 113 | flexDirection: 'row', 114 | marginLeft: 15, 115 | }, 116 | footerText: { 117 | fontSize: 16, 118 | color: '#FFF', 119 | textAlign: 'center', 120 | }, 121 | }); 122 | 123 | export default class App extends Component { 124 | constructor(props) { 125 | super(props); 126 | 127 | this.state = { 128 | activeTab: 0, 129 | imageIndex: 0, 130 | isImageViewVisible: false, 131 | likes: [...cities, ...nature].reduce((acc, image) => { 132 | acc[image.title] = 0; 133 | 134 | return acc; 135 | }, {}), 136 | }; 137 | 138 | this.renderFooter = this.renderFooter.bind(this); 139 | } 140 | 141 | renderFooter({title}) { 142 | const {likes} = this.state; 143 | 144 | return ( 145 | 146 | {title} 147 | { 150 | const imageLikes = likes[title] + 1; 151 | this.setState({likes: {...likes, [title]: imageLikes}}); 152 | }} 153 | > 154 | 155 | 156 | {likes[title]} 157 | 158 | 159 | 160 | ); 161 | } 162 | 163 | render() { 164 | const {isImageViewVisible, activeTab, imageIndex} = this.state; 165 | const images = tabs[activeTab].images || []; 166 | 167 | return ( 168 | 169 | 170 | {images.map((image, index) => ( 171 | { 174 | this.setState({ 175 | imageIndex: index, 176 | isImageViewVisible: true, 177 | }); 178 | }} 179 | > 180 | 185 | 186 | ))} 187 | 188 | 189 | {tabs.map(({title}, index) => ( 190 | { 194 | this.setState({ 195 | activeTab: index, 196 | }); 197 | }} 198 | > 199 | 206 | {title} 207 | 208 | 209 | ))} 210 | 211 | this.setState({isImageViewVisible: false})} 219 | onImageChange={index => { 220 | console.log(index); 221 | }} 222 | /> 223 | 224 | ); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "react-native-image-view", 4 | "description": "React Native modal image view with pinch zoom", 5 | "slug": "react-native-image-view", 6 | "privacy": "public", 7 | "sdkVersion": "35.0.0", 8 | "version": "1.0.0", 9 | "orientation": "portrait", 10 | "primaryColor": "#cccccc", 11 | "icon": "./assets/icon.png", 12 | "splash": { 13 | "image": "./assets/splash.png", 14 | "resizeMode": "contain", 15 | "backgroundColor": "#ffffff" 16 | }, 17 | "ios": { 18 | "supportsTablet": true 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/example/assets/icon.png -------------------------------------------------------------------------------- /example/assets/spb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/example/assets/spb.jpg -------------------------------------------------------------------------------- /example/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/example/assets/splash.png -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | resolver: { 5 | extraNodeModules: new Proxy( 6 | {}, 7 | { 8 | get: (target, name) => 9 | path.join(process.cwd(), `node_modules/${name}`), 10 | } 11 | ), 12 | }, 13 | projectRoot: [path.resolve(__dirname)], 14 | watchFolders: [path.resolve(__dirname, '../src')], 15 | }; 16 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "private": true, 4 | "dependencies": { 5 | "expo": "^35.0.0", 6 | "react": "16.8.6", 7 | "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz", 8 | "react-native-image-view": "^2.1.6" 9 | }, 10 | "devDependencies": { 11 | "babel-eslint": "10.0.1", 12 | "babel-preset-expo": "7.0.0", 13 | "eslint": "5.16.0", 14 | "eslint-config-airbnb": "17.1.0", 15 | "eslint-config-prettier": "4.3.0", 16 | "eslint-plugin-flowtype": "3.9.1", 17 | "eslint-plugin-import": "2.17.3", 18 | "eslint-plugin-jsx-a11y": "6.2.1", 19 | "eslint-plugin-prettier": "3.1.0", 20 | "eslint-plugin-react": "7.13.0", 21 | "flow-bin": "0.100.0", 22 | "prettier": "1.18.2" 23 | }, 24 | "scripts": { 25 | "eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-image-view", 3 | "version": "2.1.9", 4 | "description": "React Native modal image view with pinch zoom", 5 | "main": "src/ImageView", 6 | "scripts": { 7 | "flow": "flow", 8 | "eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check", 9 | "postversion": "git push origin master && git push --tags origin master" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/antonKalinin/react-native-image-view.git" 14 | }, 15 | "peerDependencies": { 16 | "react": ">=15.2.0", 17 | "react-native": ">=0.44.0" 18 | }, 19 | "devDependencies": { 20 | "babel-eslint": "10.0.1", 21 | "eslint": "5.16.0", 22 | "eslint-config-airbnb": "17.1.0", 23 | "eslint-config-prettier": "4.3.0", 24 | "eslint-plugin-flowtype": "3.9.1", 25 | "eslint-plugin-import": "2.17.3", 26 | "eslint-plugin-jest": "^21.17.0", 27 | "eslint-plugin-jsx-a11y": "6.2.1", 28 | "eslint-plugin-prettier": "3.1.0", 29 | "eslint-plugin-react": "7.13.0", 30 | "flow-bin": "0.100.0", 31 | "prettier": "1.18.2" 32 | }, 33 | "keywords": [ 34 | "react-native", 35 | "image", 36 | "zoom", 37 | "preview", 38 | "modal", 39 | "pinch", 40 | "component" 41 | ], 42 | "files": [ 43 | "package.json", 44 | "readme.md", 45 | "src" 46 | ], 47 | "author": "Anton Kalinin", 48 | "license": "MIT", 49 | "bugs": { 50 | "url": "https://github.com/antonKalinin/react-native-image-view/issues" 51 | }, 52 | "homepage": "https://github.com/antonKalinin/react-native-image-view#readme" 53 | } 54 | -------------------------------------------------------------------------------- /src/ImageView.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, {Component, type Node, type ComponentType} from 'react'; 4 | import { 5 | ActivityIndicator, 6 | Animated, 7 | Dimensions, 8 | FlatList, 9 | Modal, 10 | Platform, 11 | View, 12 | SafeAreaView, 13 | } from 'react-native'; 14 | 15 | import { 16 | type ControlType, 17 | type ControlsType, 18 | type DimensionsType, 19 | type EventType, 20 | type ImageType, 21 | type ImageSizeType, 22 | type GestureState, 23 | type NativeEventType, 24 | type TouchType, 25 | type TransitionType, 26 | type TranslateType, 27 | } from './types'; 28 | 29 | import { 30 | addIndexesToImages, 31 | calculateInitialTranslate, 32 | fetchImageSize, 33 | generatePanHandlers, 34 | getImagesWithoutSize, 35 | getScale, 36 | getDistance, 37 | getInitialParams, 38 | hexToRgb, 39 | isHex, 40 | scalesAreEqual, 41 | } from './utils'; 42 | 43 | import createStyles from './styles'; 44 | import {Close, Prev, Next} from './controls'; 45 | 46 | const IMAGE_SPEED_FOR_CLOSE = 1.1; 47 | const SCALE_MAXIMUM = 5; 48 | const HEADER_HEIGHT = 60; 49 | const SCALE_MAX_MULTIPLIER = 3; 50 | const FREEZE_SCROLL_DISTANCE = 15; 51 | const BACKGROUND_OPACITY_MULTIPLIER = 0.003; 52 | const defaultBackgroundColor = [0, 0, 0]; 53 | 54 | const getScreenDimensions = () => ({ 55 | screenWidth: Dimensions.get('window').width, 56 | screenHeight: Dimensions.get('window').height, 57 | }); 58 | 59 | let styles = createStyles(getScreenDimensions()); 60 | 61 | type PropsType = { 62 | animationType: 'none' | 'fade' | 'slide', 63 | backgroundColor?: string, 64 | glideAlways?: boolean, 65 | glideAlwaysDelay?: number, 66 | images: ImageType[], 67 | imageIndex: number, 68 | isVisible: boolean, 69 | isTapZoomEnabled: boolean, 70 | isPinchZoomEnabled: boolean, 71 | isSwipeCloseEnabled: boolean, 72 | onClose: () => {}, 73 | onImageChange: number => {}, 74 | renderFooter: ImageType => {}, 75 | controls: { 76 | close?: ComponentType | boolean, 77 | next?: ComponentType | boolean, 78 | prev?: ComponentType | boolean, 79 | }, 80 | }; 81 | 82 | export type StateType = { 83 | images: ImageType[], 84 | isVisible: boolean, 85 | imageIndex: number, 86 | imageScale: number, 87 | imageTranslate: {x: number, y: number}, 88 | scrollEnabled: boolean, 89 | panelsVisible: boolean, 90 | isFlatListRerendered: boolean, 91 | screenDimensions: {screenWidth: number, screenHeight: number}, 92 | }; 93 | 94 | export default class ImageView extends Component { 95 | static defaultProps = { 96 | backgroundColor: null, 97 | images: [], 98 | imageIndex: 0, 99 | isTapZoomEnabled: true, 100 | isPinchZoomEnabled: true, 101 | isSwipeCloseEnabled: true, 102 | glideAlways: false, 103 | glideAlwaysDelay: 75, 104 | controls: {prev: null, next: null}, 105 | }; 106 | 107 | constructor(props: PropsType) { 108 | super(props); 109 | 110 | // calculate initial scale and translate for images 111 | const initialScreenDimensions = getScreenDimensions(); 112 | this.imageInitialParams = props.images.map(image => 113 | getInitialParams(image, initialScreenDimensions) 114 | ); 115 | 116 | this.state = { 117 | images: props.images, 118 | isVisible: props.isVisible, 119 | imageIndex: props.imageIndex, 120 | imageScale: 1, 121 | imageTranslate: {x: 0, y: 0}, 122 | scrollEnabled: true, 123 | panelsVisible: true, 124 | isFlatListRerendered: false, 125 | screenDimensions: initialScreenDimensions, 126 | }; 127 | this.glideAlwaysTimer = null; 128 | this.listRef = null; 129 | this.isScrolling = false; 130 | this.footerHeight = 0; 131 | this.initialTouches = []; 132 | this.currentTouchesNum = 0; 133 | this.doubleTapTimer = null; 134 | this.modalAnimation = new Animated.Value(0); 135 | this.modalBackgroundOpacity = new Animated.Value(0); 136 | 137 | this.headerTranslateValue = new Animated.ValueXY(); 138 | this.footerTranslateValue = new Animated.ValueXY(); 139 | 140 | this.imageScaleValue = new Animated.Value(this.getInitialScale()); 141 | const {x, y} = this.getInitialTranslate(); 142 | this.imageTranslateValue = new Animated.ValueXY({x, y}); 143 | 144 | this.panResponder = generatePanHandlers( 145 | (event: EventType): void => this.onGestureStart(event.nativeEvent), 146 | (event: EventType, gestureState: GestureState): void => 147 | this.onGestureMove(event.nativeEvent, gestureState), 148 | (event: EventType, gestureState: GestureState): void => 149 | this.onGestureRelease(event.nativeEvent, gestureState) 150 | ); 151 | 152 | const imagesWithoutSize = getImagesWithoutSize( 153 | addIndexesToImages(props.images) 154 | ); 155 | 156 | if (imagesWithoutSize.length) { 157 | Promise.all(fetchImageSize(imagesWithoutSize)).then( 158 | this.setSizeForImages 159 | ); 160 | } 161 | } 162 | 163 | componentDidMount() { 164 | styles = createStyles(this.state.screenDimensions); 165 | Dimensions.addEventListener('change', this.onChangeDimension); 166 | } 167 | 168 | componentDidUpdate() { 169 | const {images, imageIndex, isVisible} = this.state; 170 | 171 | if ( 172 | typeof this.props.isVisible !== 'undefined' && 173 | this.props.isVisible !== isVisible 174 | ) { 175 | this.onNextImagesReceived(this.props.images, this.props.imageIndex); 176 | 177 | if ( 178 | images !== this.props.images || 179 | imageIndex !== this.props.imageIndex 180 | ) { 181 | const imagesWithoutSize = getImagesWithoutSize( 182 | addIndexesToImages(this.props.images) 183 | ); 184 | 185 | if (imagesWithoutSize.length) { 186 | Promise.all(fetchImageSize(imagesWithoutSize)).then( 187 | updatedImages => 188 | this.onNextImagesReceived( 189 | this.setSizeForImages(updatedImages), 190 | this.props.imageIndex 191 | ) 192 | ); 193 | } 194 | } 195 | 196 | this.setState({ 197 | isVisible: this.props.isVisible, 198 | isFlatListRerendered: false, 199 | }); 200 | 201 | this.modalBackgroundOpacity.setValue(0); 202 | 203 | if (this.props.isVisible) { 204 | Animated.timing(this.modalAnimation, { 205 | duration: 400, 206 | toValue: 1, 207 | }).start(); 208 | } 209 | } 210 | } 211 | 212 | componentWillUnmount() { 213 | Dimensions.removeEventListener('change', this.onChangeDimension); 214 | 215 | if (this.glideAlwaysTimer) { 216 | clearTimeout(this.glideAlwaysTimer); 217 | } 218 | } 219 | 220 | onChangeDimension = ({window}: {window: DimensionsType}) => { 221 | const screenDimensions = { 222 | screenWidth: window.width, 223 | screenHeight: window.height, 224 | }; 225 | 226 | this.setState({screenDimensions}); 227 | styles = createStyles(screenDimensions); 228 | 229 | this.onNextImagesReceived(this.props.images, this.state.imageIndex); 230 | }; 231 | 232 | onNextImagesReceived(images: Array, imageIndex: number = 0) { 233 | this.imageInitialParams = images.map(image => 234 | getInitialParams(image, this.state.screenDimensions) 235 | ); 236 | const {scale, translate} = this.imageInitialParams[imageIndex] || { 237 | scale: 1, 238 | translate: {}, 239 | }; 240 | 241 | this.setState({ 242 | images, 243 | imageIndex, 244 | imageScale: scale, 245 | imageTranslate: translate, 246 | isFlatListRerendered: false, 247 | }); 248 | 249 | this.imageScaleValue.setValue(scale); 250 | this.imageTranslateValue.setValue(translate); 251 | } 252 | 253 | // $FlowFixMe 254 | onFlatListRender = flatListRef => { 255 | const {images, imageIndex, isFlatListRerendered} = this.state; 256 | 257 | if (flatListRef && !isFlatListRerendered) { 258 | this.listRef = flatListRef; 259 | this.setState({ 260 | isFlatListRerendered: true, 261 | }); 262 | 263 | // Fix for android https://github.com/facebook/react-native/issues/13202 264 | if (images.length > 0) { 265 | const nextTick = new Promise(resolve => setTimeout(resolve, 0)); 266 | nextTick.then(() => { 267 | flatListRef.scrollToIndex({ 268 | index: imageIndex, 269 | animated: false, 270 | }); 271 | }); 272 | } 273 | } 274 | }; 275 | 276 | onNextImage = (event: EventType) => { 277 | const {imageIndex} = this.state; 278 | const {x} = event.nativeEvent.contentOffset || {x: 0}; 279 | 280 | const nextImageIndex = Math.round( 281 | x / this.state.screenDimensions.screenWidth 282 | ); 283 | 284 | this.isScrolling = 285 | Math.ceil(x) % this.state.screenDimensions.screenWidth > 10; 286 | 287 | if (imageIndex !== nextImageIndex && nextImageIndex >= 0) { 288 | const nextImageScale = this.getInitialScale(nextImageIndex); 289 | const nextImageTranslate = this.getInitialTranslate(nextImageIndex); 290 | 291 | this.setState({ 292 | imageIndex: nextImageIndex, 293 | imageScale: nextImageScale, 294 | imageTranslate: nextImageTranslate, 295 | }); 296 | 297 | this.imageScaleValue.setValue(nextImageScale); 298 | this.imageTranslateValue.setValue(nextImageTranslate); 299 | 300 | if (typeof this.props.onImageChange === 'function') { 301 | this.props.onImageChange(nextImageIndex); 302 | } 303 | } 304 | }; 305 | 306 | onGestureStart(event: NativeEventType) { 307 | this.initialTouches = event.touches; 308 | this.currentTouchesNum = event.touches.length; 309 | } 310 | 311 | /** 312 | * If image is moved from its original position 313 | * then disable scroll (for ScrollView) 314 | */ 315 | onGestureMove(event: NativeEventType, gestureState: GestureState) { 316 | if (this.isScrolling && this.state.scrollEnabled) { 317 | return; 318 | } 319 | 320 | if (this.currentTouchesNum === 1 && event.touches.length === 2) { 321 | this.initialTouches = event.touches; 322 | } 323 | 324 | const {isSwipeCloseEnabled, isPinchZoomEnabled} = this.props; 325 | 326 | const { 327 | images, 328 | imageIndex, 329 | imageScale, 330 | imageTranslate, 331 | screenDimensions, 332 | } = this.state; 333 | const {screenHeight} = screenDimensions; 334 | const {touches} = event; 335 | const {x, y} = imageTranslate; 336 | const {dx, dy} = gestureState; 337 | const imageInitialScale = this.getInitialScale(); 338 | const {height} = images[imageIndex]; 339 | 340 | if (imageScale !== imageInitialScale) { 341 | this.imageTranslateValue.x.setValue(x + dx); 342 | } 343 | 344 | // Do not allow to move image vertically until it fits to the screen 345 | if (imageScale * height > screenHeight) { 346 | this.imageTranslateValue.y.setValue(y + dy); 347 | } 348 | 349 | // if image not scaled and fits to the screen 350 | if ( 351 | isSwipeCloseEnabled && 352 | scalesAreEqual(imageScale, imageInitialScale) && 353 | height * imageInitialScale < screenHeight 354 | ) { 355 | const backgroundOpacity = Math.abs( 356 | dy * BACKGROUND_OPACITY_MULTIPLIER 357 | ); 358 | 359 | this.imageTranslateValue.y.setValue(y + dy); 360 | this.modalBackgroundOpacity.setValue( 361 | backgroundOpacity > 1 ? 1 : backgroundOpacity 362 | ); 363 | } 364 | 365 | const currentDistance = getDistance(touches); 366 | const initialDistance = getDistance(this.initialTouches); 367 | 368 | const scrollEnabled = Math.abs(dy) < FREEZE_SCROLL_DISTANCE; 369 | this.setState({scrollEnabled}); 370 | 371 | if (!initialDistance) { 372 | return; 373 | } 374 | 375 | if (!isPinchZoomEnabled || touches.length < 2) { 376 | return; 377 | } 378 | 379 | let nextScale = getScale(currentDistance, initialDistance) * imageScale; 380 | 381 | if (nextScale < imageInitialScale) { 382 | nextScale = imageInitialScale; 383 | } else if (nextScale > SCALE_MAXIMUM) { 384 | nextScale = SCALE_MAXIMUM; 385 | } 386 | 387 | this.imageScaleValue.setValue(nextScale); 388 | this.currentTouchesNum = event.touches.length; 389 | } 390 | 391 | onGestureRelease(event: NativeEventType, gestureState: GestureState) { 392 | if (this.glideAlwaysTimer) { 393 | clearTimeout(this.glideAlwaysTimer); 394 | } 395 | 396 | if (this.props.glideAlways && Platform.OS === 'android') { 397 | this.glideAlwaysTimer = setTimeout(() => { 398 | this.glideAlwaysTimer = null; 399 | // If standard glide is not triggered then emulate it 400 | // $FlowFixMe 401 | if (this.listRef && this.listRef.scrollToIndex) { 402 | this.listRef.scrollToIndex({ 403 | index: this.state.imageIndex, 404 | animated: true, 405 | }); 406 | } 407 | }, this.props.glideAlwaysDelay); 408 | } 409 | 410 | if (this.isScrolling) { 411 | return; 412 | } 413 | 414 | const {imageScale} = this.state; 415 | const {isSwipeCloseEnabled, isTapZoomEnabled} = this.props; 416 | 417 | let {_value: scale} = this.imageScaleValue; 418 | const {_value: modalBackgroundOpacity} = this.modalBackgroundOpacity; 419 | 420 | const {dx, dy, vy} = gestureState; 421 | const imageInitialScale = this.getInitialScale(); 422 | const imageInitialTranslate = this.getInitialTranslate(); 423 | 424 | // Position haven't changed, so it just tap 425 | if (event && !dx && !dy && scalesAreEqual(imageScale, scale)) { 426 | // Double tap timer is launched, its double tap 427 | 428 | if (isTapZoomEnabled && this.doubleTapTimer) { 429 | clearTimeout(this.doubleTapTimer); 430 | this.doubleTapTimer = null; 431 | 432 | scale = scalesAreEqual(imageInitialScale, scale) 433 | ? scale * SCALE_MAX_MULTIPLIER 434 | : imageInitialScale; 435 | 436 | Animated.timing(this.imageScaleValue, { 437 | toValue: scale, 438 | duration: 300, 439 | }).start(); 440 | 441 | this.togglePanels(scale === imageInitialScale); 442 | } else { 443 | this.doubleTapTimer = setTimeout(() => { 444 | this.togglePanels(); 445 | this.doubleTapTimer = null; 446 | }, 200); 447 | } 448 | } 449 | 450 | const {x, y} = this.calculateNextTranslate(dx, dy, scale); 451 | const scrollEnabled = 452 | scale === this.getInitialScale() && 453 | x === imageInitialTranslate.x && 454 | y === imageInitialTranslate.y; 455 | 456 | Animated.parallel( 457 | [ 458 | modalBackgroundOpacity > 0 459 | ? Animated.timing(this.modalBackgroundOpacity, { 460 | toValue: 0, 461 | duration: 100, 462 | }) 463 | : null, 464 | Animated.timing(this.imageTranslateValue.x, { 465 | toValue: x, 466 | duration: 100, 467 | }), 468 | Animated.timing(this.imageTranslateValue.y, { 469 | toValue: y, 470 | duration: 100, 471 | }), 472 | ].filter(Boolean) 473 | ).start(); 474 | 475 | // Close modal with animation if image not scaled and high vertical gesture speed 476 | if ( 477 | isSwipeCloseEnabled && 478 | scale === imageInitialScale && 479 | Math.abs(vy) >= IMAGE_SPEED_FOR_CLOSE 480 | ) { 481 | Animated.timing(this.imageTranslateValue.y, { 482 | toValue: y + 400 * vy, 483 | duration: 150, 484 | }).start(this.close); 485 | } 486 | 487 | this.setState({ 488 | imageScale: scale, 489 | imageTranslate: {x, y}, 490 | scrollEnabled, 491 | }); 492 | } 493 | 494 | onImageLoaded(index: number) { 495 | const {images} = this.state; 496 | 497 | images[index] = {...images[index], loaded: true}; 498 | 499 | this.setState({images}); 500 | } 501 | 502 | onMomentumScrollBegin = () => { 503 | this.isScrolling = true; 504 | if (this.glideAlwaysTimer) { 505 | // If FlatList started gliding then prevent glideAlways scrolling 506 | clearTimeout(this.glideAlwaysTimer); 507 | } 508 | }; 509 | 510 | onMomentumScrollEnd = () => { 511 | this.isScrolling = false; 512 | }; 513 | 514 | getItemLayout = (_: *, index: number): Object => { 515 | const {screenWidth} = this.state.screenDimensions; 516 | 517 | return {length: screenWidth, offset: screenWidth * index, index}; 518 | }; 519 | 520 | getInitialScale(index?: number): number { 521 | const imageIndex = index !== undefined ? index : this.state.imageIndex; 522 | const imageParams = this.imageInitialParams[imageIndex]; 523 | 524 | return imageParams ? imageParams.scale : 1; 525 | } 526 | 527 | getInitialTranslate(index?: number): TranslateType { 528 | const imageIndex = index !== undefined ? index : this.state.imageIndex; 529 | const imageParams = this.imageInitialParams[imageIndex]; 530 | 531 | return imageParams ? imageParams.translate : {x: 0, y: 0}; 532 | } 533 | 534 | getImageStyle( 535 | image: ImageType, 536 | index: number 537 | ): {width?: number, height?: number, transform?: any, opacity?: number} { 538 | const {imageIndex, screenDimensions} = this.state; 539 | const {width, height} = image; 540 | 541 | if (!width || !height) { 542 | return {opacity: 0}; 543 | } 544 | 545 | // very strange caching, fix it with changing size to 1 pixel 546 | const {x, y} = calculateInitialTranslate( 547 | width, 548 | height + 1, 549 | screenDimensions 550 | ); 551 | const translateValue = new Animated.ValueXY({x, y}); 552 | 553 | const transform = 554 | index === imageIndex 555 | ? this.imageTranslateValue.getTranslateTransform() 556 | : translateValue.getTranslateTransform(); 557 | 558 | const scale = 559 | index === imageIndex 560 | ? this.imageScaleValue 561 | : this.getInitialScale(index); 562 | // $FlowFixMe 563 | transform.push({scale}); 564 | 565 | return {width, height, transform}; 566 | } 567 | 568 | getControls = (): ControlsType => { 569 | const {close, prev, next} = this.props.controls; 570 | const controls = {close: Close, prev: undefined, next: undefined}; 571 | 572 | if (close === null) { 573 | controls.close = null; 574 | } 575 | 576 | if (close) { 577 | controls.close = close === true ? Close : close; 578 | } 579 | 580 | if (prev) { 581 | controls.prev = prev === true ? Prev : prev; 582 | } 583 | 584 | if (next) { 585 | controls.next = next === true ? Next : next; 586 | } 587 | 588 | return controls; 589 | }; 590 | 591 | setSizeForImages = (nextImages: Array): Array => { 592 | if (nextImages.length === 0) { 593 | return []; 594 | } 595 | 596 | const {images} = this.state; 597 | 598 | return images.map((image, index) => { 599 | const nextImageSize = nextImages.find( 600 | nextImage => nextImage.index === index 601 | ); 602 | 603 | /* eslint-disable */ 604 | if (nextImageSize) { 605 | image.width = nextImageSize.width; 606 | image.height = nextImageSize.height; 607 | } 608 | /* eslint-enable */ 609 | 610 | return image; 611 | }); 612 | }; 613 | 614 | scrollToNext = () => { 615 | if (this.listRef && typeof this.listRef.scrollToIndex === 'function') { 616 | this.listRef.scrollToIndex({ 617 | index: this.state.imageIndex + 1, 618 | animated: true, 619 | }); 620 | } 621 | }; 622 | 623 | scrollToPrev = () => { 624 | if (this.listRef && typeof this.listRef.scrollToIndex === 'function') { 625 | this.listRef.scrollToIndex({ 626 | index: this.state.imageIndex - 1, 627 | animated: true, 628 | }); 629 | } 630 | }; 631 | 632 | imageInitialParams: TransitionType[]; 633 | glideAlwaysTimer: ?TimeoutID; 634 | listRef: *; 635 | isScrolling: boolean; 636 | footerHeight: number; 637 | initialTouches: TouchType[]; 638 | currentTouchesNum: number; 639 | doubleTapTimer: ?TimeoutID; 640 | modalAnimation: *; 641 | modalBackgroundOpacity: *; 642 | headerTranslateValue: *; 643 | footerTranslateValue: *; 644 | imageScaleValue: *; 645 | imageTranslateValue: *; 646 | panResponder: *; 647 | 648 | calculateNextTranslate( 649 | dx: number, 650 | dy: number, 651 | scale: number 652 | ): {x: number, y: number} { 653 | const { 654 | images, 655 | imageIndex, 656 | imageTranslate, 657 | screenDimensions, 658 | } = this.state; 659 | const {x, y} = imageTranslate; 660 | const {screenWidth, screenHeight} = screenDimensions; 661 | const {width, height} = images[imageIndex]; 662 | const imageInitialScale = this.getInitialScale(); 663 | 664 | const getTranslate = (axis: string): number => { 665 | const imageSize = axis === 'x' ? width : height; 666 | const screenSize = axis === 'x' ? screenWidth : screenHeight; 667 | const leftLimit = (scale * imageSize - imageSize) / 2; 668 | const rightLimit = screenSize - imageSize - leftLimit; 669 | 670 | let nextTranslate = axis === 'x' ? x + dx : y + dy; 671 | 672 | // Less than the screen 673 | if (screenSize > scale * imageSize) { 674 | if (width >= height) { 675 | nextTranslate = (screenSize - imageSize) / 2; 676 | } else { 677 | nextTranslate = 678 | screenSize / 2 - 679 | (imageSize * (scale / imageInitialScale)) / 2; 680 | } 681 | 682 | return nextTranslate; 683 | } 684 | 685 | if (nextTranslate > leftLimit) { 686 | nextTranslate = leftLimit; 687 | } 688 | 689 | if (nextTranslate < rightLimit) { 690 | nextTranslate = rightLimit; 691 | } 692 | 693 | return nextTranslate; 694 | }; 695 | 696 | return {x: getTranslate('x'), y: getTranslate('y')}; 697 | } 698 | 699 | togglePanels(isVisible?: boolean) { 700 | const panelsVisible = 701 | typeof isVisible !== 'undefined' 702 | ? isVisible 703 | : !this.state.panelsVisible; 704 | // toggle footer and header 705 | this.setState({panelsVisible}); 706 | 707 | Animated.timing(this.headerTranslateValue.y, { 708 | toValue: !panelsVisible ? -(HEADER_HEIGHT + 44) : 0, 709 | duration: 200, 710 | useNativeDriver: true, 711 | }).start(); 712 | 713 | if (this.footerHeight > 0) { 714 | Animated.timing(this.footerTranslateValue.y, { 715 | toValue: !panelsVisible ? this.footerHeight : 0, 716 | duration: 200, 717 | useNativeDriver: true, 718 | }).start(); 719 | } 720 | } 721 | 722 | listKeyExtractor = (image: ImageType): string => 723 | this.state.images.indexOf(image).toString(); 724 | 725 | close = () => { 726 | this.setState({isVisible: false}); 727 | 728 | if (typeof this.props.onClose === 'function') { 729 | this.props.onClose(); 730 | } 731 | }; 732 | 733 | renderImage = ({item: image, index}: {item: *, index: number}): * => { 734 | const loaded = image.loaded && image.width && image.height; 735 | 736 | return ( 737 | true} 740 | > 741 | this.onImageLoaded(index)} 746 | {...this.panResponder.panHandlers} 747 | /> 748 | {!loaded && } 749 | 750 | ); 751 | }; 752 | 753 | render(): Node { 754 | const {animationType, renderFooter, backgroundColor} = this.props; 755 | const { 756 | images, 757 | imageIndex, 758 | imageScale, 759 | isVisible, 760 | scrollEnabled, 761 | } = this.state; 762 | 763 | const {close, prev, next} = this.getControls(); 764 | const imageInitialScale = this.getInitialScale(); 765 | const headerTranslate = this.headerTranslateValue.getTranslateTransform(); 766 | const footerTranslate = this.footerTranslateValue.getTranslateTransform(); 767 | const rgbBackgroundColor = 768 | backgroundColor && isHex(backgroundColor) 769 | ? hexToRgb(backgroundColor) 770 | : defaultBackgroundColor; 771 | const rgb = rgbBackgroundColor.join(','); 772 | const animatedBackgroundColor = this.modalBackgroundOpacity.interpolate( 773 | { 774 | inputRange: [0, 1], 775 | outputRange: [`rgba(${rgb}, 0.9)`, `rgba(${rgb}, 0.2)`], 776 | } 777 | ); 778 | 779 | const isPrevVisible = 780 | imageScale === imageInitialScale && imageIndex > 0; 781 | const isNextVisible = 782 | imageScale === imageInitialScale && imageIndex < images.length - 1; 783 | 784 | return ( 785 | 792 | 798 | 806 | 807 | {!!close && 808 | React.createElement(close, {onPress: this.close})} 809 | 810 | 811 | null} 820 | keyExtractor={this.listKeyExtractor} 821 | onScroll={this.onNextImage} 822 | renderItem={this.renderImage} 823 | getItemLayout={this.getItemLayout} 824 | onMomentumScrollBegin={this.onMomentumScrollBegin} 825 | onMomentumScrollEnd={this.onMomentumScrollEnd} 826 | /> 827 | {prev && 828 | isPrevVisible && 829 | React.createElement(prev, {onPress: this.scrollToPrev})} 830 | {next && 831 | isNextVisible && 832 | React.createElement(next, {onPress: this.scrollToNext})} 833 | {renderFooter && ( 834 | { 837 | this.footerHeight = event.nativeEvent.layout.height; 838 | }} 839 | > 840 | {typeof renderFooter === 'function' && 841 | images[imageIndex] && 842 | renderFooter(images[imageIndex])} 843 | 844 | )} 845 | 846 | ); 847 | } 848 | } 849 | -------------------------------------------------------------------------------- /src/controls/Close.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import {StyleSheet, Text, TouchableOpacity} from 'react-native'; 4 | 5 | const HIT_SLOP = {top: 15, left: 15, right: 15, bottom: 15}; 6 | 7 | const styles = StyleSheet.create({ 8 | closeButton: { 9 | alignSelf: 'flex-end', 10 | height: 24, 11 | width: 24, 12 | borderRadius: 12, 13 | backgroundColor: 'rgba(0,0,0,0.2)', 14 | alignItems: 'center', 15 | justifyContent: 'center', 16 | marginTop: 25, 17 | marginRight: 15, 18 | }, 19 | closeButton__text: { 20 | backgroundColor: 'transparent', 21 | fontSize: 25, 22 | lineHeight: 25, 23 | color: '#FFF', 24 | textAlign: 'center', 25 | }, 26 | }); 27 | 28 | export default ({onPress}: {onPress: () => *}) => ( 29 | 34 | × 35 | 36 | ); 37 | -------------------------------------------------------------------------------- /src/controls/Next.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import {StyleSheet, Text, TouchableOpacity} from 'react-native'; 4 | 5 | const HIT_SLOP = {top: 15, left: 15, right: 15, bottom: 15}; 6 | 7 | const styles = StyleSheet.create({ 8 | nextButton: { 9 | position: 'absolute', 10 | zIndex: 100, 11 | right: 10, 12 | top: '50%', 13 | height: 32, 14 | width: 32, 15 | borderRadius: 16, 16 | backgroundColor: 'rgba(0,0,0,0.3)', 17 | alignItems: 'center', 18 | justifyContent: 'center', 19 | }, 20 | nextButton__text: { 21 | backgroundColor: 'transparent', 22 | fontSize: 25, 23 | lineHeight: 25, 24 | color: '#FFF', 25 | textAlign: 'center', 26 | }, 27 | }); 28 | 29 | export default ({onPress}: {onPress: () => *}) => ( 30 | 35 | 36 | 37 | ); 38 | -------------------------------------------------------------------------------- /src/controls/Prev.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import {StyleSheet, Text, TouchableOpacity} from 'react-native'; 4 | 5 | const HIT_SLOP = {top: 15, left: 15, right: 15, bottom: 15}; 6 | 7 | const styles = StyleSheet.create({ 8 | prevButton: { 9 | position: 'absolute', 10 | zIndex: 100, 11 | left: 10, 12 | top: '50%', 13 | height: 32, 14 | width: 32, 15 | borderRadius: 16, 16 | backgroundColor: 'rgba(0,0,0,0.3)', 17 | alignItems: 'center', 18 | justifyContent: 'center', 19 | }, 20 | prevButton__text: { 21 | backgroundColor: 'transparent', 22 | fontSize: 25, 23 | lineHeight: 25, 24 | color: '#FFF', 25 | textAlign: 'center', 26 | }, 27 | }); 28 | 29 | export default ({onPress}: {onPress: () => *}) => ( 30 | 35 | 36 | 37 | ); 38 | -------------------------------------------------------------------------------- /src/controls/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export {default as Close} from './Close'; 3 | export {default as Prev} from './Prev'; 4 | export {default as Next} from './Next'; 5 | -------------------------------------------------------------------------------- /src/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | 3 | const HEADER_HEIGHT = 60; 4 | 5 | export default function createStyles({screenWidth, screenHeight}) { 6 | return StyleSheet.create({ 7 | underlay: { 8 | position: 'absolute', 9 | top: 0, 10 | left: 0, 11 | right: 0, 12 | bottom: 0, 13 | }, 14 | container: { 15 | width: screenWidth, 16 | height: screenHeight, 17 | }, 18 | header: { 19 | position: 'absolute', 20 | top: 0, 21 | left: 0, 22 | zIndex: 100, 23 | height: HEADER_HEIGHT, 24 | width: screenWidth, 25 | }, 26 | imageContainer: { 27 | width: screenWidth, 28 | height: screenHeight, 29 | overflow: 'hidden', 30 | }, 31 | loading: { 32 | position: 'absolute', 33 | top: screenHeight / 2 - 20, 34 | alignSelf: 'center', 35 | }, 36 | footer: { 37 | position: 'absolute', 38 | bottom: 0, 39 | left: 0, 40 | right: 0, 41 | zIndex: 100, 42 | }, 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {type ComponentType} from 'react'; 3 | 4 | export type ControlType = { 5 | onPress: () => void, 6 | }; 7 | 8 | export type ControlsType = { 9 | close?: ?ComponentType, 10 | next?: ComponentType, 11 | prev?: ComponentType, 12 | }; 13 | 14 | export type TouchType = { 15 | pageX: number, 16 | pageY: number, 17 | }; 18 | 19 | export type NativeEventType = { 20 | touches: Array, 21 | contentOffset: {x: number, y: number}, 22 | }; 23 | 24 | export type EventType = {nativeEvent: NativeEventType}; 25 | 26 | export type ImageType = { 27 | source: any, 28 | width: number, 29 | height: number, 30 | title: ?string, 31 | index: number, 32 | }; 33 | 34 | export type TranslateType = { 35 | x: number, 36 | y: number, 37 | }; 38 | 39 | export type GestureState = { 40 | dx: number, 41 | dy: number, 42 | vx: number, 43 | vy: number, 44 | }; 45 | 46 | export type DimensionsType = {width: number, height: number}; 47 | export type ScreenDimensionsType = {screenWidth: number, screenHeight: number}; 48 | 49 | export type ImageSizeType = DimensionsType & {index: number}; 50 | 51 | export type TransitionType = {scale: number, translate: TranslateType}; 52 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {Image, PanResponder} from 'react-native'; 3 | 4 | import { 5 | type EventType, 6 | type GestureState, 7 | type ImageType, 8 | type TouchType, 9 | type TranslateType, 10 | type TransitionType, 11 | type DimensionsType, 12 | type ScreenDimensionsType, 13 | } from './types'; 14 | 15 | const SCALE_EPSILON = 0.01; 16 | const SCALE_MULTIPLIER = 1.2; 17 | 18 | export const generatePanHandlers = ( 19 | onStart: (EventType, GestureState) => *, 20 | onMove: (EventType, GestureState) => *, 21 | onRelease: (EventType, GestureState) => * 22 | ): * => 23 | PanResponder.create({ 24 | onStartShouldSetPanResponder: (): boolean => true, 25 | onStartShouldSetPanResponderCapture: (): boolean => true, 26 | onMoveShouldSetPanResponder: (): boolean => true, 27 | onMoveShouldSetPanResponderCapture: (): boolean => true, 28 | onPanResponderGrant: onStart, 29 | onPanResponderMove: onMove, 30 | onPanResponderRelease: onRelease, 31 | onPanResponderTerminate: onRelease, 32 | onPanResponderTerminationRequest: (): void => {}, 33 | onShouldBlockNativeResponder: () => false, 34 | }); 35 | 36 | export const getScale = ( 37 | currentDistance: number, 38 | initialDistance: number 39 | ): number => (currentDistance / initialDistance) * SCALE_MULTIPLIER; 40 | 41 | export const getDistance = (touches: Array): number => { 42 | const [a, b] = touches; 43 | 44 | if (a == null || b == null) { 45 | return 0; 46 | } 47 | 48 | return Math.sqrt( 49 | Math.pow(a.pageX - b.pageX, 2) + Math.pow(a.pageY - b.pageY, 2) 50 | ); 51 | }; 52 | 53 | export const calculateInitialScale = ( 54 | imageWidth: number = 0, 55 | imageHeight: number = 0, 56 | {screenWidth, screenHeight}: ScreenDimensionsType 57 | ): number => { 58 | const screenRatio = screenHeight / screenWidth; 59 | const imageRatio = imageHeight / imageWidth; 60 | 61 | if (imageWidth > screenWidth || imageHeight > screenHeight) { 62 | if (screenRatio > imageRatio) { 63 | return screenWidth / imageWidth; 64 | } 65 | 66 | return screenHeight / imageHeight; 67 | } 68 | 69 | return 1; 70 | }; 71 | 72 | export const calculateInitialTranslate = ( 73 | imageWidth: number = 0, 74 | imageHeight: number = 0, 75 | {screenWidth, screenHeight}: ScreenDimensionsType 76 | ): TranslateType => { 77 | const getTranslate = (axis: string): number => { 78 | const imageSize = axis === 'x' ? imageWidth : imageHeight; 79 | const screenSize = axis === 'x' ? screenWidth : screenHeight; 80 | 81 | if (imageWidth >= imageHeight) { 82 | return (screenSize - imageSize) / 2; 83 | } 84 | 85 | return screenSize / 2 - imageSize / 2; 86 | }; 87 | 88 | return { 89 | x: getTranslate('x'), 90 | y: getTranslate('y'), 91 | }; 92 | }; 93 | 94 | export const getInitialParams = ( 95 | {width, height}: DimensionsType, 96 | screenDimensions: Object 97 | ): TransitionType => ({ 98 | scale: calculateInitialScale(width, height, screenDimensions), 99 | translate: calculateInitialTranslate(width, height, screenDimensions), 100 | }); 101 | 102 | export function fetchImageSize(images: Array = []) { 103 | return images.reduce((acc, image) => { 104 | if ( 105 | image.source && 106 | image.source.uri && 107 | (!image.width || !image.height) 108 | ) { 109 | const imageSize = new Promise((resolve, reject) => { 110 | Image.getSize( 111 | image.source.uri, 112 | (width, height) => 113 | resolve({ 114 | width, 115 | height, 116 | index: image.index, 117 | }), 118 | reject 119 | ); 120 | }); 121 | 122 | acc.push(imageSize); 123 | } 124 | 125 | return acc; 126 | }, []); 127 | } 128 | 129 | const shortHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; 130 | const fullHexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; 131 | 132 | export const isHex = (color: string): boolean => 133 | fullHexRegex.test(color) || shortHexRegex.test(color); 134 | 135 | export const hexToRgb = (hex: string): number[] => { 136 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") 137 | const input = hex.replace( 138 | shortHexRegex, 139 | (m, r, g, b) => `${r}${r}${g}${g}${b}${b}` 140 | ); 141 | 142 | const [match, r, g, b] = [].concat(fullHexRegex.exec(input)); 143 | 144 | if (!match) { 145 | return []; 146 | } 147 | 148 | return [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)]; 149 | }; 150 | 151 | export const addIndexesToImages = (images: ImageType[]): ImageType[] => 152 | images.map((image, index) => ({...image, index})); 153 | 154 | export const getImagesWithoutSize = (images: ImageType[]) => 155 | images.filter(({width, height}) => !width || !height); 156 | 157 | export const scalesAreEqual = (scaleA: number, scaleB: number): boolean => 158 | Math.abs(scaleA - scaleB) < SCALE_EPSILON; 159 | -------------------------------------------------------------------------------- /static/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/static/demo.gif -------------------------------------------------------------------------------- /static/demoV2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/static/demoV2.gif -------------------------------------------------------------------------------- /static/demo_android.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/static/demo_android.gif -------------------------------------------------------------------------------- /static/demo_ios.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antonKalinin/react-native-image-view/2450ec459839e036181dcd42d8e09725237a9694/static/demo_ios.gif -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.0.0" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" 8 | integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== 9 | dependencies: 10 | "@babel/highlight" "^7.0.0" 11 | 12 | "@babel/generator@^7.4.4": 13 | version "7.4.4" 14 | resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041" 15 | integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ== 16 | dependencies: 17 | "@babel/types" "^7.4.4" 18 | jsesc "^2.5.1" 19 | lodash "^4.17.11" 20 | source-map "^0.5.0" 21 | trim-right "^1.0.1" 22 | 23 | "@babel/helper-function-name@^7.1.0": 24 | version "7.1.0" 25 | resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" 26 | integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== 27 | dependencies: 28 | "@babel/helper-get-function-arity" "^7.0.0" 29 | "@babel/template" "^7.1.0" 30 | "@babel/types" "^7.0.0" 31 | 32 | "@babel/helper-get-function-arity@^7.0.0": 33 | version "7.0.0" 34 | resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" 35 | integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== 36 | dependencies: 37 | "@babel/types" "^7.0.0" 38 | 39 | "@babel/helper-split-export-declaration@^7.4.4": 40 | version "7.4.4" 41 | resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" 42 | integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== 43 | dependencies: 44 | "@babel/types" "^7.4.4" 45 | 46 | "@babel/highlight@^7.0.0": 47 | version "7.0.0" 48 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" 49 | integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== 50 | dependencies: 51 | chalk "^2.0.0" 52 | esutils "^2.0.2" 53 | js-tokens "^4.0.0" 54 | 55 | "@babel/parser@^7.0.0", "@babel/parser@^7.4.4", "@babel/parser@^7.4.5": 56 | version "7.4.5" 57 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872" 58 | integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew== 59 | 60 | "@babel/template@^7.1.0": 61 | version "7.4.4" 62 | resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" 63 | integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== 64 | dependencies: 65 | "@babel/code-frame" "^7.0.0" 66 | "@babel/parser" "^7.4.4" 67 | "@babel/types" "^7.4.4" 68 | 69 | "@babel/traverse@^7.0.0": 70 | version "7.4.5" 71 | resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.5.tgz#4e92d1728fd2f1897dafdd321efbff92156c3216" 72 | integrity sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A== 73 | dependencies: 74 | "@babel/code-frame" "^7.0.0" 75 | "@babel/generator" "^7.4.4" 76 | "@babel/helper-function-name" "^7.1.0" 77 | "@babel/helper-split-export-declaration" "^7.4.4" 78 | "@babel/parser" "^7.4.5" 79 | "@babel/types" "^7.4.4" 80 | debug "^4.1.0" 81 | globals "^11.1.0" 82 | lodash "^4.17.11" 83 | 84 | "@babel/types@^7.0.0", "@babel/types@^7.4.4": 85 | version "7.4.4" 86 | resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0" 87 | integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ== 88 | dependencies: 89 | esutils "^2.0.2" 90 | lodash "^4.17.11" 91 | to-fast-properties "^2.0.0" 92 | 93 | acorn-jsx@^5.0.0: 94 | version "5.0.1" 95 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" 96 | integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== 97 | 98 | acorn@^6.0.7: 99 | version "6.1.1" 100 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" 101 | integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== 102 | 103 | ajv@^6.9.1: 104 | version "6.10.0" 105 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" 106 | integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== 107 | dependencies: 108 | fast-deep-equal "^2.0.1" 109 | fast-json-stable-stringify "^2.0.0" 110 | json-schema-traverse "^0.4.1" 111 | uri-js "^4.2.2" 112 | 113 | ansi-escapes@^3.2.0: 114 | version "3.2.0" 115 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" 116 | integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== 117 | 118 | ansi-regex@^3.0.0: 119 | version "3.0.0" 120 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 121 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 122 | 123 | ansi-regex@^4.1.0: 124 | version "4.1.0" 125 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 126 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 127 | 128 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 129 | version "3.2.1" 130 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 131 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 132 | dependencies: 133 | color-convert "^1.9.0" 134 | 135 | argparse@^1.0.7: 136 | version "1.0.10" 137 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 138 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 139 | dependencies: 140 | sprintf-js "~1.0.2" 141 | 142 | aria-query@^3.0.0: 143 | version "3.0.0" 144 | resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" 145 | integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= 146 | dependencies: 147 | ast-types-flow "0.0.7" 148 | commander "^2.11.0" 149 | 150 | array-includes@^3.0.3: 151 | version "3.0.3" 152 | resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" 153 | integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= 154 | dependencies: 155 | define-properties "^1.1.2" 156 | es-abstract "^1.7.0" 157 | 158 | ast-types-flow@0.0.7, ast-types-flow@^0.0.7: 159 | version "0.0.7" 160 | resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" 161 | integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= 162 | 163 | astral-regex@^1.0.0: 164 | version "1.0.0" 165 | resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" 166 | integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== 167 | 168 | axobject-query@^2.0.2: 169 | version "2.0.2" 170 | resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" 171 | integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww== 172 | dependencies: 173 | ast-types-flow "0.0.7" 174 | 175 | babel-eslint@10.0.1: 176 | version "10.0.1" 177 | resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" 178 | integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ== 179 | dependencies: 180 | "@babel/code-frame" "^7.0.0" 181 | "@babel/parser" "^7.0.0" 182 | "@babel/traverse" "^7.0.0" 183 | "@babel/types" "^7.0.0" 184 | eslint-scope "3.7.1" 185 | eslint-visitor-keys "^1.0.0" 186 | 187 | balanced-match@^1.0.0: 188 | version "1.0.0" 189 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 190 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 191 | 192 | brace-expansion@^1.1.7: 193 | version "1.1.11" 194 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 195 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 196 | dependencies: 197 | balanced-match "^1.0.0" 198 | concat-map "0.0.1" 199 | 200 | callsites@^3.0.0: 201 | version "3.1.0" 202 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 203 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 204 | 205 | chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: 206 | version "2.4.2" 207 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 208 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 209 | dependencies: 210 | ansi-styles "^3.2.1" 211 | escape-string-regexp "^1.0.5" 212 | supports-color "^5.3.0" 213 | 214 | chardet@^0.7.0: 215 | version "0.7.0" 216 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" 217 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== 218 | 219 | cli-cursor@^2.1.0: 220 | version "2.1.0" 221 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" 222 | integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= 223 | dependencies: 224 | restore-cursor "^2.0.0" 225 | 226 | cli-width@^2.0.0: 227 | version "2.2.0" 228 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" 229 | integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= 230 | 231 | color-convert@^1.9.0: 232 | version "1.9.3" 233 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 234 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 235 | dependencies: 236 | color-name "1.1.3" 237 | 238 | color-name@1.1.3: 239 | version "1.1.3" 240 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 241 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 242 | 243 | commander@^2.11.0: 244 | version "2.20.0" 245 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" 246 | integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== 247 | 248 | concat-map@0.0.1: 249 | version "0.0.1" 250 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 251 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 252 | 253 | contains-path@^0.1.0: 254 | version "0.1.0" 255 | resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" 256 | integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= 257 | 258 | cross-spawn@^6.0.5: 259 | version "6.0.5" 260 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 261 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 262 | dependencies: 263 | nice-try "^1.0.4" 264 | path-key "^2.0.1" 265 | semver "^5.5.0" 266 | shebang-command "^1.2.0" 267 | which "^1.2.9" 268 | 269 | damerau-levenshtein@^1.0.4: 270 | version "1.0.5" 271 | resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz#780cf7144eb2e8dbd1c3bb83ae31100ccc31a414" 272 | integrity sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA== 273 | 274 | debug@^2.6.8, debug@^2.6.9: 275 | version "2.6.9" 276 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 277 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 278 | dependencies: 279 | ms "2.0.0" 280 | 281 | debug@^4.0.1, debug@^4.1.0: 282 | version "4.1.1" 283 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 284 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== 285 | dependencies: 286 | ms "^2.1.1" 287 | 288 | deep-is@~0.1.3: 289 | version "0.1.3" 290 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 291 | integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= 292 | 293 | define-properties@^1.1.2, define-properties@^1.1.3: 294 | version "1.1.3" 295 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 296 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 297 | dependencies: 298 | object-keys "^1.0.12" 299 | 300 | doctrine@1.5.0: 301 | version "1.5.0" 302 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" 303 | integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= 304 | dependencies: 305 | esutils "^2.0.2" 306 | isarray "^1.0.0" 307 | 308 | doctrine@^2.1.0: 309 | version "2.1.0" 310 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" 311 | integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== 312 | dependencies: 313 | esutils "^2.0.2" 314 | 315 | doctrine@^3.0.0: 316 | version "3.0.0" 317 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 318 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 319 | dependencies: 320 | esutils "^2.0.2" 321 | 322 | emoji-regex@^7.0.1, emoji-regex@^7.0.2: 323 | version "7.0.3" 324 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 325 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 326 | 327 | error-ex@^1.2.0: 328 | version "1.3.2" 329 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 330 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 331 | dependencies: 332 | is-arrayish "^0.2.1" 333 | 334 | es-abstract@^1.11.0, es-abstract@^1.12.0, es-abstract@^1.7.0: 335 | version "1.13.0" 336 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" 337 | integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== 338 | dependencies: 339 | es-to-primitive "^1.2.0" 340 | function-bind "^1.1.1" 341 | has "^1.0.3" 342 | is-callable "^1.1.4" 343 | is-regex "^1.0.4" 344 | object-keys "^1.0.12" 345 | 346 | es-to-primitive@^1.2.0: 347 | version "1.2.0" 348 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" 349 | integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== 350 | dependencies: 351 | is-callable "^1.1.4" 352 | is-date-object "^1.0.1" 353 | is-symbol "^1.0.2" 354 | 355 | escape-string-regexp@^1.0.5: 356 | version "1.0.5" 357 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 358 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 359 | 360 | eslint-config-airbnb-base@^13.1.0: 361 | version "13.1.0" 362 | resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" 363 | integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw== 364 | dependencies: 365 | eslint-restricted-globals "^0.1.1" 366 | object.assign "^4.1.0" 367 | object.entries "^1.0.4" 368 | 369 | eslint-config-airbnb@17.1.0: 370 | version "17.1.0" 371 | resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" 372 | integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw== 373 | dependencies: 374 | eslint-config-airbnb-base "^13.1.0" 375 | object.assign "^4.1.0" 376 | object.entries "^1.0.4" 377 | 378 | eslint-config-prettier@4.3.0: 379 | version "4.3.0" 380 | resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.3.0.tgz#c55c1fcac8ce4518aeb77906984e134d9eb5a4f0" 381 | integrity sha512-sZwhSTHVVz78+kYD3t5pCWSYEdVSBR0PXnwjDRsUs8ytIrK8PLXw+6FKp8r3Z7rx4ZszdetWlXYKOHoUrrwPlA== 382 | dependencies: 383 | get-stdin "^6.0.0" 384 | 385 | eslint-import-resolver-node@^0.3.2: 386 | version "0.3.2" 387 | resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" 388 | integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== 389 | dependencies: 390 | debug "^2.6.9" 391 | resolve "^1.5.0" 392 | 393 | eslint-module-utils@^2.4.0: 394 | version "2.4.0" 395 | resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" 396 | integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== 397 | dependencies: 398 | debug "^2.6.8" 399 | pkg-dir "^2.0.0" 400 | 401 | eslint-plugin-flowtype@3.9.1: 402 | version "3.9.1" 403 | resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-3.9.1.tgz#6491d930e1f96d53c510e0393e635fddd4a4cac5" 404 | integrity sha512-ZlV6SbIXqz2ysvG0F64ZH07dqzLrwMdM1s0UNfoxdXjr4kMKuPPoLViwK+gFC952QIf341AmP4BKtKOhcB96Ug== 405 | dependencies: 406 | lodash "^4.17.11" 407 | 408 | eslint-plugin-import@2.17.3: 409 | version "2.17.3" 410 | resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.3.tgz#00548b4434c18faebaba04b24ae6198f280de189" 411 | integrity sha512-qeVf/UwXFJbeyLbxuY8RgqDyEKCkqV7YC+E5S5uOjAp4tOc8zj01JP3ucoBM8JcEqd1qRasJSg6LLlisirfy0Q== 412 | dependencies: 413 | array-includes "^3.0.3" 414 | contains-path "^0.1.0" 415 | debug "^2.6.9" 416 | doctrine "1.5.0" 417 | eslint-import-resolver-node "^0.3.2" 418 | eslint-module-utils "^2.4.0" 419 | has "^1.0.3" 420 | lodash "^4.17.11" 421 | minimatch "^3.0.4" 422 | read-pkg-up "^2.0.0" 423 | resolve "^1.11.0" 424 | 425 | eslint-plugin-jest@^21.17.0: 426 | version "21.27.2" 427 | resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.27.2.tgz#2a795b7c3b5e707df48a953d651042bd01d7b0a8" 428 | integrity sha512-0E4OIgBJVlAmf1KfYFtZ3gYxgUzC5Eb3Jzmrc9ikI1OY+/cM8Kh72Ti7KfpeHNeD3HJNf9SmEfmvQLIz44Hrhw== 429 | 430 | eslint-plugin-jsx-a11y@6.2.1: 431 | version "6.2.1" 432 | resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c" 433 | integrity sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w== 434 | dependencies: 435 | aria-query "^3.0.0" 436 | array-includes "^3.0.3" 437 | ast-types-flow "^0.0.7" 438 | axobject-query "^2.0.2" 439 | damerau-levenshtein "^1.0.4" 440 | emoji-regex "^7.0.2" 441 | has "^1.0.3" 442 | jsx-ast-utils "^2.0.1" 443 | 444 | eslint-plugin-prettier@3.1.0: 445 | version "3.1.0" 446 | resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d" 447 | integrity sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA== 448 | dependencies: 449 | prettier-linter-helpers "^1.0.0" 450 | 451 | eslint-plugin-react@7.13.0: 452 | version "7.13.0" 453 | resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.13.0.tgz#bc13fd7101de67996ea51b33873cd9dc2b7e5758" 454 | integrity sha512-uA5LrHylu8lW/eAH3bEQe9YdzpPaFd9yAJTwTi/i/BKTD7j6aQMKVAdGM/ML72zD6womuSK7EiGtMKuK06lWjQ== 455 | dependencies: 456 | array-includes "^3.0.3" 457 | doctrine "^2.1.0" 458 | has "^1.0.3" 459 | jsx-ast-utils "^2.1.0" 460 | object.fromentries "^2.0.0" 461 | prop-types "^15.7.2" 462 | resolve "^1.10.1" 463 | 464 | eslint-restricted-globals@^0.1.1: 465 | version "0.1.1" 466 | resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" 467 | integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc= 468 | 469 | eslint-scope@3.7.1: 470 | version "3.7.1" 471 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" 472 | integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= 473 | dependencies: 474 | esrecurse "^4.1.0" 475 | estraverse "^4.1.1" 476 | 477 | eslint-scope@^4.0.3: 478 | version "4.0.3" 479 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" 480 | integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== 481 | dependencies: 482 | esrecurse "^4.1.0" 483 | estraverse "^4.1.1" 484 | 485 | eslint-utils@^1.3.1: 486 | version "1.3.1" 487 | resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" 488 | integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== 489 | 490 | eslint-visitor-keys@^1.0.0: 491 | version "1.0.0" 492 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" 493 | integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== 494 | 495 | eslint@5.16.0: 496 | version "5.16.0" 497 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" 498 | integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== 499 | dependencies: 500 | "@babel/code-frame" "^7.0.0" 501 | ajv "^6.9.1" 502 | chalk "^2.1.0" 503 | cross-spawn "^6.0.5" 504 | debug "^4.0.1" 505 | doctrine "^3.0.0" 506 | eslint-scope "^4.0.3" 507 | eslint-utils "^1.3.1" 508 | eslint-visitor-keys "^1.0.0" 509 | espree "^5.0.1" 510 | esquery "^1.0.1" 511 | esutils "^2.0.2" 512 | file-entry-cache "^5.0.1" 513 | functional-red-black-tree "^1.0.1" 514 | glob "^7.1.2" 515 | globals "^11.7.0" 516 | ignore "^4.0.6" 517 | import-fresh "^3.0.0" 518 | imurmurhash "^0.1.4" 519 | inquirer "^6.2.2" 520 | js-yaml "^3.13.0" 521 | json-stable-stringify-without-jsonify "^1.0.1" 522 | levn "^0.3.0" 523 | lodash "^4.17.11" 524 | minimatch "^3.0.4" 525 | mkdirp "^0.5.1" 526 | natural-compare "^1.4.0" 527 | optionator "^0.8.2" 528 | path-is-inside "^1.0.2" 529 | progress "^2.0.0" 530 | regexpp "^2.0.1" 531 | semver "^5.5.1" 532 | strip-ansi "^4.0.0" 533 | strip-json-comments "^2.0.1" 534 | table "^5.2.3" 535 | text-table "^0.2.0" 536 | 537 | espree@^5.0.1: 538 | version "5.0.1" 539 | resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" 540 | integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== 541 | dependencies: 542 | acorn "^6.0.7" 543 | acorn-jsx "^5.0.0" 544 | eslint-visitor-keys "^1.0.0" 545 | 546 | esprima@^4.0.0: 547 | version "4.0.1" 548 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 549 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 550 | 551 | esquery@^1.0.1: 552 | version "1.0.1" 553 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" 554 | integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== 555 | dependencies: 556 | estraverse "^4.0.0" 557 | 558 | esrecurse@^4.1.0: 559 | version "4.2.1" 560 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" 561 | integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== 562 | dependencies: 563 | estraverse "^4.1.0" 564 | 565 | estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: 566 | version "4.2.0" 567 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 568 | integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= 569 | 570 | esutils@^2.0.2: 571 | version "2.0.2" 572 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 573 | integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= 574 | 575 | external-editor@^3.0.3: 576 | version "3.0.3" 577 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" 578 | integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== 579 | dependencies: 580 | chardet "^0.7.0" 581 | iconv-lite "^0.4.24" 582 | tmp "^0.0.33" 583 | 584 | fast-deep-equal@^2.0.1: 585 | version "2.0.1" 586 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 587 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= 588 | 589 | fast-diff@^1.1.2: 590 | version "1.2.0" 591 | resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" 592 | integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== 593 | 594 | fast-json-stable-stringify@^2.0.0: 595 | version "2.0.0" 596 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 597 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 598 | 599 | fast-levenshtein@~2.0.4: 600 | version "2.0.6" 601 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 602 | integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= 603 | 604 | figures@^2.0.0: 605 | version "2.0.0" 606 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" 607 | integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= 608 | dependencies: 609 | escape-string-regexp "^1.0.5" 610 | 611 | file-entry-cache@^5.0.1: 612 | version "5.0.1" 613 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" 614 | integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== 615 | dependencies: 616 | flat-cache "^2.0.1" 617 | 618 | find-up@^2.0.0, find-up@^2.1.0: 619 | version "2.1.0" 620 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" 621 | integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= 622 | dependencies: 623 | locate-path "^2.0.0" 624 | 625 | flat-cache@^2.0.1: 626 | version "2.0.1" 627 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" 628 | integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== 629 | dependencies: 630 | flatted "^2.0.0" 631 | rimraf "2.6.3" 632 | write "1.0.3" 633 | 634 | flatted@^2.0.0: 635 | version "2.0.0" 636 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" 637 | integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== 638 | 639 | flow-bin@0.100.0: 640 | version "0.100.0" 641 | resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.100.0.tgz#729902726658cfa0a81425d6401f9625cf9f5534" 642 | integrity sha512-jcethhgrslBJukH7Z7883ohFFpzLrdsOEwHxvn5NwuTWbNaE71GAl55/PEBRJwYpDvYkRlqgcNkANTv0x5XjqA== 643 | 644 | fs.realpath@^1.0.0: 645 | version "1.0.0" 646 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 647 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 648 | 649 | function-bind@^1.1.1: 650 | version "1.1.1" 651 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 652 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 653 | 654 | functional-red-black-tree@^1.0.1: 655 | version "1.0.1" 656 | resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" 657 | integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= 658 | 659 | get-stdin@^6.0.0: 660 | version "6.0.0" 661 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" 662 | integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== 663 | 664 | glob@^7.1.2, glob@^7.1.3: 665 | version "7.1.4" 666 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" 667 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== 668 | dependencies: 669 | fs.realpath "^1.0.0" 670 | inflight "^1.0.4" 671 | inherits "2" 672 | minimatch "^3.0.4" 673 | once "^1.3.0" 674 | path-is-absolute "^1.0.0" 675 | 676 | globals@^11.1.0, globals@^11.7.0: 677 | version "11.12.0" 678 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 679 | integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== 680 | 681 | graceful-fs@^4.1.2: 682 | version "4.1.15" 683 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" 684 | integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== 685 | 686 | has-flag@^3.0.0: 687 | version "3.0.0" 688 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 689 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 690 | 691 | has-symbols@^1.0.0: 692 | version "1.0.0" 693 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" 694 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= 695 | 696 | has@^1.0.1, has@^1.0.3: 697 | version "1.0.3" 698 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 699 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 700 | dependencies: 701 | function-bind "^1.1.1" 702 | 703 | hosted-git-info@^2.1.4: 704 | version "2.7.1" 705 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" 706 | integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== 707 | 708 | iconv-lite@^0.4.24: 709 | version "0.4.24" 710 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 711 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 712 | dependencies: 713 | safer-buffer ">= 2.1.2 < 3" 714 | 715 | ignore@^4.0.6: 716 | version "4.0.6" 717 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" 718 | integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== 719 | 720 | import-fresh@^3.0.0: 721 | version "3.0.0" 722 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" 723 | integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ== 724 | dependencies: 725 | parent-module "^1.0.0" 726 | resolve-from "^4.0.0" 727 | 728 | imurmurhash@^0.1.4: 729 | version "0.1.4" 730 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 731 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 732 | 733 | inflight@^1.0.4: 734 | version "1.0.6" 735 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 736 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 737 | dependencies: 738 | once "^1.3.0" 739 | wrappy "1" 740 | 741 | inherits@2: 742 | version "2.0.3" 743 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 744 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 745 | 746 | inquirer@^6.2.2: 747 | version "6.3.1" 748 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7" 749 | integrity sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA== 750 | dependencies: 751 | ansi-escapes "^3.2.0" 752 | chalk "^2.4.2" 753 | cli-cursor "^2.1.0" 754 | cli-width "^2.0.0" 755 | external-editor "^3.0.3" 756 | figures "^2.0.0" 757 | lodash "^4.17.11" 758 | mute-stream "0.0.7" 759 | run-async "^2.2.0" 760 | rxjs "^6.4.0" 761 | string-width "^2.1.0" 762 | strip-ansi "^5.1.0" 763 | through "^2.3.6" 764 | 765 | is-arrayish@^0.2.1: 766 | version "0.2.1" 767 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 768 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= 769 | 770 | is-callable@^1.1.4: 771 | version "1.1.4" 772 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" 773 | integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== 774 | 775 | is-date-object@^1.0.1: 776 | version "1.0.1" 777 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 778 | integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= 779 | 780 | is-fullwidth-code-point@^2.0.0: 781 | version "2.0.0" 782 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 783 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 784 | 785 | is-promise@^2.1.0: 786 | version "2.1.0" 787 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" 788 | integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= 789 | 790 | is-regex@^1.0.4: 791 | version "1.0.4" 792 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 793 | integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= 794 | dependencies: 795 | has "^1.0.1" 796 | 797 | is-symbol@^1.0.2: 798 | version "1.0.2" 799 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" 800 | integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== 801 | dependencies: 802 | has-symbols "^1.0.0" 803 | 804 | isarray@^1.0.0: 805 | version "1.0.0" 806 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 807 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 808 | 809 | isexe@^2.0.0: 810 | version "2.0.0" 811 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 812 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 813 | 814 | "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: 815 | version "4.0.0" 816 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 817 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 818 | 819 | js-yaml@^3.13.0: 820 | version "3.13.1" 821 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 822 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 823 | dependencies: 824 | argparse "^1.0.7" 825 | esprima "^4.0.0" 826 | 827 | jsesc@^2.5.1: 828 | version "2.5.2" 829 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" 830 | integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== 831 | 832 | json-schema-traverse@^0.4.1: 833 | version "0.4.1" 834 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 835 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 836 | 837 | json-stable-stringify-without-jsonify@^1.0.1: 838 | version "1.0.1" 839 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 840 | integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= 841 | 842 | jsx-ast-utils@^2.0.1, jsx-ast-utils@^2.1.0: 843 | version "2.1.0" 844 | resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz#0ee4e2c971fb9601c67b5641b71be80faecf0b36" 845 | integrity sha512-yDGDG2DS4JcqhA6blsuYbtsT09xL8AoLuUR2Gb5exrw7UEM19sBcOTq+YBBhrNbl0PUC4R4LnFu+dHg2HKeVvA== 846 | dependencies: 847 | array-includes "^3.0.3" 848 | 849 | levn@^0.3.0, levn@~0.3.0: 850 | version "0.3.0" 851 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 852 | integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= 853 | dependencies: 854 | prelude-ls "~1.1.2" 855 | type-check "~0.3.2" 856 | 857 | load-json-file@^2.0.0: 858 | version "2.0.0" 859 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" 860 | integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= 861 | dependencies: 862 | graceful-fs "^4.1.2" 863 | parse-json "^2.2.0" 864 | pify "^2.0.0" 865 | strip-bom "^3.0.0" 866 | 867 | locate-path@^2.0.0: 868 | version "2.0.0" 869 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" 870 | integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= 871 | dependencies: 872 | p-locate "^2.0.0" 873 | path-exists "^3.0.0" 874 | 875 | lodash@^4.17.11: 876 | version "4.17.11" 877 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" 878 | integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== 879 | 880 | loose-envify@^1.4.0: 881 | version "1.4.0" 882 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 883 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 884 | dependencies: 885 | js-tokens "^3.0.0 || ^4.0.0" 886 | 887 | mimic-fn@^1.0.0: 888 | version "1.2.0" 889 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" 890 | integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== 891 | 892 | minimatch@^3.0.4: 893 | version "3.0.4" 894 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 895 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 896 | dependencies: 897 | brace-expansion "^1.1.7" 898 | 899 | minimist@0.0.8: 900 | version "0.0.8" 901 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 902 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 903 | 904 | mkdirp@^0.5.1: 905 | version "0.5.1" 906 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 907 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 908 | dependencies: 909 | minimist "0.0.8" 910 | 911 | ms@2.0.0: 912 | version "2.0.0" 913 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 914 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 915 | 916 | ms@^2.1.1: 917 | version "2.1.2" 918 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 919 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 920 | 921 | mute-stream@0.0.7: 922 | version "0.0.7" 923 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" 924 | integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= 925 | 926 | natural-compare@^1.4.0: 927 | version "1.4.0" 928 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 929 | integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= 930 | 931 | nice-try@^1.0.4: 932 | version "1.0.5" 933 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 934 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 935 | 936 | normalize-package-data@^2.3.2: 937 | version "2.5.0" 938 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" 939 | integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== 940 | dependencies: 941 | hosted-git-info "^2.1.4" 942 | resolve "^1.10.0" 943 | semver "2 || 3 || 4 || 5" 944 | validate-npm-package-license "^3.0.1" 945 | 946 | object-assign@^4.1.1: 947 | version "4.1.1" 948 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 949 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 950 | 951 | object-keys@^1.0.11, object-keys@^1.0.12: 952 | version "1.1.1" 953 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 954 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 955 | 956 | object.assign@^4.1.0: 957 | version "4.1.0" 958 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 959 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 960 | dependencies: 961 | define-properties "^1.1.2" 962 | function-bind "^1.1.1" 963 | has-symbols "^1.0.0" 964 | object-keys "^1.0.11" 965 | 966 | object.entries@^1.0.4: 967 | version "1.1.0" 968 | resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" 969 | integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== 970 | dependencies: 971 | define-properties "^1.1.3" 972 | es-abstract "^1.12.0" 973 | function-bind "^1.1.1" 974 | has "^1.0.3" 975 | 976 | object.fromentries@^2.0.0: 977 | version "2.0.0" 978 | resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab" 979 | integrity sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA== 980 | dependencies: 981 | define-properties "^1.1.2" 982 | es-abstract "^1.11.0" 983 | function-bind "^1.1.1" 984 | has "^1.0.1" 985 | 986 | once@^1.3.0: 987 | version "1.4.0" 988 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 989 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 990 | dependencies: 991 | wrappy "1" 992 | 993 | onetime@^2.0.0: 994 | version "2.0.1" 995 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" 996 | integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= 997 | dependencies: 998 | mimic-fn "^1.0.0" 999 | 1000 | optionator@^0.8.2: 1001 | version "0.8.2" 1002 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 1003 | integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= 1004 | dependencies: 1005 | deep-is "~0.1.3" 1006 | fast-levenshtein "~2.0.4" 1007 | levn "~0.3.0" 1008 | prelude-ls "~1.1.2" 1009 | type-check "~0.3.2" 1010 | wordwrap "~1.0.0" 1011 | 1012 | os-tmpdir@~1.0.2: 1013 | version "1.0.2" 1014 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1015 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 1016 | 1017 | p-limit@^1.1.0: 1018 | version "1.3.0" 1019 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" 1020 | integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== 1021 | dependencies: 1022 | p-try "^1.0.0" 1023 | 1024 | p-locate@^2.0.0: 1025 | version "2.0.0" 1026 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" 1027 | integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= 1028 | dependencies: 1029 | p-limit "^1.1.0" 1030 | 1031 | p-try@^1.0.0: 1032 | version "1.0.0" 1033 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" 1034 | integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= 1035 | 1036 | parent-module@^1.0.0: 1037 | version "1.0.1" 1038 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 1039 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1040 | dependencies: 1041 | callsites "^3.0.0" 1042 | 1043 | parse-json@^2.2.0: 1044 | version "2.2.0" 1045 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 1046 | integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= 1047 | dependencies: 1048 | error-ex "^1.2.0" 1049 | 1050 | path-exists@^3.0.0: 1051 | version "3.0.0" 1052 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 1053 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 1054 | 1055 | path-is-absolute@^1.0.0: 1056 | version "1.0.1" 1057 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1058 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1059 | 1060 | path-is-inside@^1.0.2: 1061 | version "1.0.2" 1062 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 1063 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= 1064 | 1065 | path-key@^2.0.1: 1066 | version "2.0.1" 1067 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 1068 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 1069 | 1070 | path-parse@^1.0.6: 1071 | version "1.0.6" 1072 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 1073 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 1074 | 1075 | path-type@^2.0.0: 1076 | version "2.0.0" 1077 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" 1078 | integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= 1079 | dependencies: 1080 | pify "^2.0.0" 1081 | 1082 | pify@^2.0.0: 1083 | version "2.3.0" 1084 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 1085 | integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= 1086 | 1087 | pkg-dir@^2.0.0: 1088 | version "2.0.0" 1089 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" 1090 | integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= 1091 | dependencies: 1092 | find-up "^2.1.0" 1093 | 1094 | prelude-ls@~1.1.2: 1095 | version "1.1.2" 1096 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 1097 | integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= 1098 | 1099 | prettier-linter-helpers@^1.0.0: 1100 | version "1.0.0" 1101 | resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" 1102 | integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== 1103 | dependencies: 1104 | fast-diff "^1.1.2" 1105 | 1106 | prettier@1.18.2: 1107 | version "1.18.2" 1108 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" 1109 | integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== 1110 | 1111 | progress@^2.0.0: 1112 | version "2.0.3" 1113 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" 1114 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== 1115 | 1116 | prop-types@^15.7.2: 1117 | version "15.7.2" 1118 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" 1119 | integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== 1120 | dependencies: 1121 | loose-envify "^1.4.0" 1122 | object-assign "^4.1.1" 1123 | react-is "^16.8.1" 1124 | 1125 | punycode@^2.1.0: 1126 | version "2.1.1" 1127 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1128 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 1129 | 1130 | react-is@^16.8.1: 1131 | version "16.8.6" 1132 | resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" 1133 | integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== 1134 | 1135 | read-pkg-up@^2.0.0: 1136 | version "2.0.0" 1137 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" 1138 | integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= 1139 | dependencies: 1140 | find-up "^2.0.0" 1141 | read-pkg "^2.0.0" 1142 | 1143 | read-pkg@^2.0.0: 1144 | version "2.0.0" 1145 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" 1146 | integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= 1147 | dependencies: 1148 | load-json-file "^2.0.0" 1149 | normalize-package-data "^2.3.2" 1150 | path-type "^2.0.0" 1151 | 1152 | regexpp@^2.0.1: 1153 | version "2.0.1" 1154 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" 1155 | integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== 1156 | 1157 | resolve-from@^4.0.0: 1158 | version "4.0.0" 1159 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 1160 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1161 | 1162 | resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.5.0: 1163 | version "1.11.1" 1164 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" 1165 | integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== 1166 | dependencies: 1167 | path-parse "^1.0.6" 1168 | 1169 | restore-cursor@^2.0.0: 1170 | version "2.0.0" 1171 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" 1172 | integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= 1173 | dependencies: 1174 | onetime "^2.0.0" 1175 | signal-exit "^3.0.2" 1176 | 1177 | rimraf@2.6.3: 1178 | version "2.6.3" 1179 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" 1180 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== 1181 | dependencies: 1182 | glob "^7.1.3" 1183 | 1184 | run-async@^2.2.0: 1185 | version "2.3.0" 1186 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" 1187 | integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= 1188 | dependencies: 1189 | is-promise "^2.1.0" 1190 | 1191 | rxjs@^6.4.0: 1192 | version "6.5.2" 1193 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" 1194 | integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== 1195 | dependencies: 1196 | tslib "^1.9.0" 1197 | 1198 | "safer-buffer@>= 2.1.2 < 3": 1199 | version "2.1.2" 1200 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1201 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1202 | 1203 | "semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.5.1: 1204 | version "5.7.0" 1205 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" 1206 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== 1207 | 1208 | shebang-command@^1.2.0: 1209 | version "1.2.0" 1210 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1211 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 1212 | dependencies: 1213 | shebang-regex "^1.0.0" 1214 | 1215 | shebang-regex@^1.0.0: 1216 | version "1.0.0" 1217 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1218 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 1219 | 1220 | signal-exit@^3.0.2: 1221 | version "3.0.2" 1222 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1223 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 1224 | 1225 | slice-ansi@^2.1.0: 1226 | version "2.1.0" 1227 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" 1228 | integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== 1229 | dependencies: 1230 | ansi-styles "^3.2.0" 1231 | astral-regex "^1.0.0" 1232 | is-fullwidth-code-point "^2.0.0" 1233 | 1234 | source-map@^0.5.0: 1235 | version "0.5.7" 1236 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 1237 | integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= 1238 | 1239 | spdx-correct@^3.0.0: 1240 | version "3.1.0" 1241 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" 1242 | integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== 1243 | dependencies: 1244 | spdx-expression-parse "^3.0.0" 1245 | spdx-license-ids "^3.0.0" 1246 | 1247 | spdx-exceptions@^2.1.0: 1248 | version "2.2.0" 1249 | resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" 1250 | integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== 1251 | 1252 | spdx-expression-parse@^3.0.0: 1253 | version "3.0.0" 1254 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" 1255 | integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== 1256 | dependencies: 1257 | spdx-exceptions "^2.1.0" 1258 | spdx-license-ids "^3.0.0" 1259 | 1260 | spdx-license-ids@^3.0.0: 1261 | version "3.0.4" 1262 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" 1263 | integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== 1264 | 1265 | sprintf-js@~1.0.2: 1266 | version "1.0.3" 1267 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1268 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 1269 | 1270 | string-width@^2.1.0: 1271 | version "2.1.1" 1272 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1273 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 1274 | dependencies: 1275 | is-fullwidth-code-point "^2.0.0" 1276 | strip-ansi "^4.0.0" 1277 | 1278 | string-width@^3.0.0: 1279 | version "3.1.0" 1280 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 1281 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 1282 | dependencies: 1283 | emoji-regex "^7.0.1" 1284 | is-fullwidth-code-point "^2.0.0" 1285 | strip-ansi "^5.1.0" 1286 | 1287 | strip-ansi@^4.0.0: 1288 | version "4.0.0" 1289 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1290 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1291 | dependencies: 1292 | ansi-regex "^3.0.0" 1293 | 1294 | strip-ansi@^5.1.0: 1295 | version "5.2.0" 1296 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 1297 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 1298 | dependencies: 1299 | ansi-regex "^4.1.0" 1300 | 1301 | strip-bom@^3.0.0: 1302 | version "3.0.0" 1303 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1304 | integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= 1305 | 1306 | strip-json-comments@^2.0.1: 1307 | version "2.0.1" 1308 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1309 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1310 | 1311 | supports-color@^5.3.0: 1312 | version "5.5.0" 1313 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1314 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1315 | dependencies: 1316 | has-flag "^3.0.0" 1317 | 1318 | table@^5.2.3: 1319 | version "5.4.0" 1320 | resolved "https://registry.yarnpkg.com/table/-/table-5.4.0.tgz#d772a3216e68829920a41a32c18eda286c95d780" 1321 | integrity sha512-nHFDrxmbrkU7JAFKqKbDJXfzrX2UBsWmrieXFTGxiI5e4ncg3VqsZeI4EzNmX0ncp4XNGVeoxIWJXfCIXwrsvw== 1322 | dependencies: 1323 | ajv "^6.9.1" 1324 | lodash "^4.17.11" 1325 | slice-ansi "^2.1.0" 1326 | string-width "^3.0.0" 1327 | 1328 | text-table@^0.2.0: 1329 | version "0.2.0" 1330 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1331 | integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= 1332 | 1333 | through@^2.3.6: 1334 | version "2.3.8" 1335 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1336 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 1337 | 1338 | tmp@^0.0.33: 1339 | version "0.0.33" 1340 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 1341 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 1342 | dependencies: 1343 | os-tmpdir "~1.0.2" 1344 | 1345 | to-fast-properties@^2.0.0: 1346 | version "2.0.0" 1347 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 1348 | integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= 1349 | 1350 | trim-right@^1.0.1: 1351 | version "1.0.1" 1352 | resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" 1353 | integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= 1354 | 1355 | tslib@^1.9.0: 1356 | version "1.9.3" 1357 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" 1358 | integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== 1359 | 1360 | type-check@~0.3.2: 1361 | version "0.3.2" 1362 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1363 | integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= 1364 | dependencies: 1365 | prelude-ls "~1.1.2" 1366 | 1367 | uri-js@^4.2.2: 1368 | version "4.2.2" 1369 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 1370 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== 1371 | dependencies: 1372 | punycode "^2.1.0" 1373 | 1374 | validate-npm-package-license@^3.0.1: 1375 | version "3.0.4" 1376 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" 1377 | integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== 1378 | dependencies: 1379 | spdx-correct "^3.0.0" 1380 | spdx-expression-parse "^3.0.0" 1381 | 1382 | which@^1.2.9: 1383 | version "1.3.1" 1384 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1385 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1386 | dependencies: 1387 | isexe "^2.0.0" 1388 | 1389 | wordwrap@~1.0.0: 1390 | version "1.0.0" 1391 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1392 | integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= 1393 | 1394 | wrappy@1: 1395 | version "1.0.2" 1396 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1397 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1398 | 1399 | write@1.0.3: 1400 | version "1.0.3" 1401 | resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" 1402 | integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== 1403 | dependencies: 1404 | mkdirp "^0.5.1" 1405 | --------------------------------------------------------------------------------