├── .DS_Store ├── CHANGELOG.md ├── README.md ├── example ├── .babelrc ├── .buckconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .watchmanconfig ├── __tests__ │ ├── index.android.js │ └── index.ios.js ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── keystores │ │ ├── BUCK │ │ └── debug.keystore.properties │ └── settings.gradle ├── app.json ├── index.android.js ├── index.ios.js ├── ios │ ├── example-tvOS │ │ └── Info.plist │ ├── example-tvOSTests │ │ └── Info.plist │ ├── example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── package-lock.json ├── package.json ├── src │ ├── components │ │ └── SliderEntry.js │ ├── index.js │ ├── static │ │ └── entries.js │ └── styles │ │ ├── SliderEntry.style.js │ │ └── index.style.js └── yarn.lock ├── package-lock.json ├── package.json ├── src ├── carousel │ └── Carousel.js ├── index.js ├── pagination │ ├── Pagination.js │ ├── Pagination.style.js │ ├── PaginationDot.js │ └── README.md └── parallaximage │ ├── ParallaxImage.js │ ├── ParallaxImage.style.js │ └── README.md └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/react-native-snap-carousel/8f65a9af47c7943d5319966f37458fef8f4e244e/.DS_Store -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v3.0.0 2 | ### Breaking changes 3 | * Plugin is now built on top of `FlatList`, which allows for huge performance optimizations. From now on, items must be rendered using props `data` and `renderItem`. 4 | ### General 5 | * Add `ParallaxImage` component (see the specific documentation [here](https://github.com/archriss/react-native-snap-carousel/blob/master/src/parallaximage/README.md)) 6 | * Add prop `activeSlideAlignment` 7 | * Fix issue with autoplay when setting `scrollEnabled` to `false` 8 | * Prevent going back to the first item when overscrolling the last one 9 | * Prevent callback from being called at the wrong time in some specific scenarios 10 | 11 | ## v2.4.0 12 | * Add `Pagination` component (see the specific documentation [here](https://github.com/archriss/react-native-snap-carousel/blob/master/src/pagination/README.md)) 13 | * Allow `firstItem` to be changed dynamically 14 | * Allow `0` value for `carouselHorizontalPadding` and `carouselVerticalPadding` (thanks [@bonbonez](https://github.com/bonbonez)) 15 | * Keep the easing of slide's opacity animation linear 16 | * Use native driver for slide's animation (can be overridden via `animationOptions`) 17 | 18 | ## v2.3.1 19 | * Fix issue when snap is disabled 20 | 21 | ## v2.3.0 22 | * Refactor callback handling to provide a more reliable solution when momentum is disabled 23 | * Fix issue with parallel animations (thanks [@jnbt](https://github.com/jnbt)) 24 | * Prevent calls to `undefined` interpolators when working with dynamic slides (thanks [@cskaynar](https://github.com/cskaynar)) 25 | * Improve vertical mode 26 | * Add prop `scrollEndDragDebounceValue` 27 | * Expose current scroll position with `this.currentScrollPosition` 28 | * Remove props `scrollEndDragThrottleValue` and `snapCallbackDebounceValue` (use `scrollEndDragDebounceValue` instead) 29 | 30 | ## v2.2.2 31 | * Fix issue that prevented inactive styles of first and last items to be applied when using `snapToPrev` and `snapToNext` methods 32 | 33 | ## v2.2.1 34 | * Do not mark `sliderWidth` and `sliderHeight` as required 35 | * Add warnings when properties specific to carousel's orientation haven't been set 36 | 37 | ## v2.2.0 38 | * Implement vertical mode (prop `vertical`) 39 | * Make sure that current active item is properly updated when snapping 40 | * Prevent issues when 'sliderWidth' is smaller than viewport's width 41 | * Recalculate card positions on layout to handle rotation (thanks [@andrewpope](https://github.com/andrewpope)); make sure to read [this note](https://github.com/archriss/react-native-snap-carousel#handling-device-rotation) 42 | * Refresh card positions if slider and/or item's dimensions are updated (thanks [@hoangnm](https://github.com/hoangnm)) 43 | * Add props `scrollEndDragThrottleValue` and `snapCallbackDebounceValue` 44 | * Expose `View`'s `onLayout` prop 45 | * Deprecate prop `onScrollViewScroll` 46 | 47 | ## v2.1.4 48 | * Add prop `onScrollViewScroll` 49 | 50 | ## v2.1.3 51 | * Default value for `showsHorizontalScrollIndicator` is now `false` 52 | * Expose `ScrollView`'s `onSscroll` prop (thanks [@radko93](https://github.com/radko93)) 53 | 54 | ## v2.1.2 55 | * Do not trigger `onSnapToItem` when snapping back to the same slide (thanks [@rgabs](https://github.com/rgabs)) 56 | * Add prop `carouselHorizontalPadding` to override container's inner padding (thanks [@skeie](https://github.com/skeie)) 57 | 58 | ## v2.1.1 59 | * Ensure compatibility with RN 0.43 (previous version of plugin's dependency `react-addons-shallow-compare` was breaking with React 16) 60 | * Fix issue with padding on iOS that could cause the carousel to snap back when its last item was clicked 61 | 62 | ## v2.1.0 63 | * Add RTL support 64 | * Keep current active item when adding slides dynamically 65 | * Prevent invalid `firstItem` number 66 | * Add prop `activeSlideOffset` 67 | 68 | ## v2.0.3 69 | 70 | * Prevent error when carousel has only one child (thanks [@kevinvandijk](https://github.com/kevinvandijk)) 71 | * Fix issue when appending dynamic slides (the first one was ignored) 72 | * Fix edge case that prevented the first slide from being focused when swiping back with momentum enabled 73 | * Bump example's RN version to 0.42.3 74 | 75 | ## v2.0.2 76 | 77 | * Make sure that scroll indicator is hidden by default 78 | 79 | ## v2.0.1 80 | 81 | * Fix un-handled exception with interpolators (thanks [@chitezh](https://github.com/chitezh)) 82 | 83 | ## v2.0.0 84 | 85 | * Items are now direct children of the `` component, which makes it easier to use (thanks [@Jonarod](https://github.com/Jonarod)) 86 | * Props `items` and `renderItem` have been removed 87 | 88 | ## v1.6.1 89 | 90 | * Due to some touch events being buggy, rework methods so the children will receive touch events on Android 91 | 92 | ## v1.6.0 93 | 94 | * Add prop `enableMomentum` 95 | * Fix an infinite-loop on iOS with momentum enabled 96 | * Fix the snapping effect when releasing touch without interia on iOS with momentum enabled 97 | * Fix autoplay on Android, it should start and stop properly and stop being triggered while swiping 98 | * Use `View.propTypes.style` instead of `PropTypes.number` in styles validation (thanks [@pesakitan22](https://github.com/pesakitan22)) 99 | 100 | ## v1.5.0 101 | 102 | * Items length can now be changed on-the-fly (thanks [@superical](https://github.com/superical)) 103 | * Now handling momentum (thanks [@FakeYou](https://github.com/FakeYou)) 104 | 105 | ## v1.4.0 106 | 107 | * Better update strategy with shallowCompare 108 | * Add `snapToNext()`, `snapToPrev()`, `currentIndex` methods and properties 109 | 110 | ## v1.3.1 111 | 112 | * Properly center on first item when mounting component on Android (potentially iOS too) 113 | 114 | ## v1.3.0 115 | 116 | * Pass the item data as the 2nd param of `onSnapToItem` callback 117 | 118 | ## v1.2.1 119 | 120 | * Fix reference call when the component has been unmounted 121 | 122 | ## v1.2.0 123 | 124 | * Add prop `onSnapToItem` 125 | 126 | ## v1.1.0 127 | 128 | * Center slides properly 129 | * Handle one slide only 130 | * Add props `inactiveSlideScale`, `inactiveSlideOpacity`, `containerCustomStyle` and `contentContainerCustomStyle` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-snap-carousel 2 | Swiper component for React Native featuring **previews**, **snapping effect**, **parallax images**, **performant handling of huge numbers of items**, and **RTL support**. Compatible with Android & iOS. 3 | 4 | ![platforms](https://img.shields.io/badge/platforms-Android%20%7C%20iOS-brightgreen.svg?style=flat-square) 5 | [![npm](https://img.shields.io/npm/v/react-native-snap-carousel.svg?style=flat-square)](https://www.npmjs.com/package/react-native-snap-carousel) 6 | [![github release](https://img.shields.io/github/release/archriss/react-native-snap-carousel.svg?style=flat-square)](https://github.com/archriss/react-native-snap-carousel/releases) 7 | [![github issues](https://img.shields.io/github/issues/archriss/react-native-snap-carousel.svg?style=flat-square)](https://github.com/archriss/react-native-snap-carousel/issues) 8 | [![github closed issues](https://img.shields.io/github/issues-closed/archriss/react-native-snap-carousel.svg?style=flat-square)](https://github.com/archriss/react-native-snap-carousel/issues?q=is%3Aissue+is%3Aclosed) 9 | 10 | ## Table of contents 11 | 12 | 1. [Showcase](#showcase) 13 | 1. [Usage](#usage) 14 | 1. [Migration from version 2.x](#migration-from-version-2x) 15 | 1. [Props](#props) 16 | 1. [Methods](#methods) 17 | 1. [Getters](#getters) 18 | 1. [Example](#example) 19 | 1. [`ParallaxImage` component](#parallaximage-component) 20 | 1. [`Pagination` component](#pagination-component) 21 | 1. [Tips and tricks](#tips-and-tricks) 22 | 1. [Known issues](#known-issues) 23 | 1. [TODO](#todo) 24 | 1. [Credits](#credits) 25 | 26 | ## Showcase 27 | 28 | ### Archriss' "Ville d'Aix-en-Provence" app 29 | 30 | **The React Native version of this app (6.0.0) is going to be available on [Android](https://play.google.com/store/apps/details?id=fr.archriss.aixmobile.app) and [iOS](https://itunes.apple.com/fr/app/ville-daix-en-provence/id494548366?mt=8) by mid-september** (the current one is Cordova-powered). It uses **version 3.0.0** of the plugin, with `FlatList`'s implementation and [parallax images](#parallaximage-component). 31 | 32 | ![react-native-snap-carousel archriss aix](http://i.imgur.com/vmMp520.gif) 33 | ![react-native-snap-carousel archriss aix](http://i.imgur.com/OdQUYHS.gif) 34 | 35 | ### Archriss' showcase app 36 | 37 | **You can try the app live on [Android](https://play.google.com/store/apps/details?id=fr.archriss.demo.app) and [iOS](https://itunes.apple.com/lu/app/archriss-presentation-mobile/id1180954376?mt=8).** It currently uses **version 1.4.0** of the plugin. Be aware that sliders' layouts will break on RTL devices since support was added in version 2.1.0 (see [#38](https://github.com/archriss/react-native-snap-carousel/issues/38)). 38 | 39 | ![react-native-snap-carousel](http://i.imgur.com/Fope3uj.gif) 40 | ![react-native-snap-carousel](http://i.imgur.com/WNOBYfl.gif) 41 | ![react-native-snap-carousel](http://i.imgur.com/sK5DKaG.gif) 42 | 43 | > Please note that **we do not plan on Open-Sourcing the code of our showcase app**. Still, we've put together [an example](#example) for you to play with, and you can find some insight about our map implementation [in this comment](https://github.com/archriss/react-native-snap-carousel/issues/11#issuecomment-265147385). 44 | > The folks at [codedaily.io](https://codedaily.io) have put together a great tutorial about implementing a similar feature. [Go check it out!](https://codedaily.io/tutorials/9/Build-a-Map-with-Custom-Animated-Markers-and-Region-Focus-when-Content-is-Scrolled-in-React-Native) 45 | 46 | ## Usage 47 | 48 | ``` 49 | $ npm install --save react-native-snap-carousel 50 | ``` 51 | 52 | ```javascript 53 | import Carousel from 'react-native-snap-carousel'; 54 | 55 | export class MyCarousel extends Component { 56 | 57 | _renderItem ({item, index}) { 58 | return ( 59 | 60 | { item.title } 61 | 62 | ); 63 | } 64 | 65 | render () { 66 | return ( 67 | { this._carousel = c; }} 69 | data={this.state.entries} 70 | renderItem={this._renderItem} 71 | sliderWidth={sliderWidth} 72 | itemWidth={itemWidth} 73 | /> 74 | ); 75 | } 76 | } 77 | ``` 78 | 79 | ## Migration from version 2.x 80 | 81 | Slides are no longer appended as direct children of the component. There are two new props that takes care of their rendering: `data` and `renderItem` (both are inherited from `FlatList`). 82 | 83 | If you were already looping throught an array of data to populate the carousel, the migration is pretty straightforward. Just pass your slides' data to the `data` prop, convert your slides' getter to a function and pass it to the `renderItem` prop: you're good to go! 84 | 85 | **From** 86 | ```javascript 87 | get slides () { 88 | return this.state.entries.map((entry, index) => { 89 | return ( 90 | 91 | { entry.title } 92 | 93 | ); 94 | }); 95 | } 96 | 97 | render () { 98 | return ( 99 | 103 | { this.slides } 104 | 105 | ); 106 | } 107 | ``` 108 | 109 | **To** 110 | ```javascript 111 | _renderItem ({item, index}) { 112 | return ( 113 | 114 | { item.title } 115 | 116 | ); 117 | } 118 | 119 | render () { 120 | return ( 121 | 127 | ); 128 | } 129 | ``` 130 | 131 | > Note that the `key` prop is no longer needed for carousel's items. If you want to provide a custom key, you should pass your own [`keyExtractor`](https://facebook.github.io/react-native/docs/flatlist.html#keyextractor) to the ``. 132 | 133 | If you were previously appending random types of children, you will need to rely on a specific bit of data to return the proper element from your `renderItem` function. 134 | 135 | **Example** 136 | ```javascript 137 | _renderItem ({item, index}) { 138 | if (item.type === 'text') { 139 | return ; 140 | } else if (item.type === 'image') { 141 | return ; 142 | } else { 143 | return ; 144 | } 145 | } 146 | ``` 147 | 148 | ## Props 149 | 150 | ### Required 151 | 152 | Prop | Description | Type | Default 153 | ------ | ------ | ------ | ------ 154 | **data** | Array of items to loop on | Array | **Required** 155 | **renderItem** | Takes an item from data and renders it into the list. The function receives one argument `{item, index}` (see [Usage](#usage)) and must return a React element. | Function | **Required** 156 | **itemWidth** | Width in pixels of carousel's items, **must be the same for all of them** | Number | **Required for __horizontal__ carousel** 157 | **sliderWidth** | Width in pixels of the carousel itself | Number | **Required for __horizontal__ carousel** 158 | **itemHeight** | Height in pixels of carousel's items, **must be the same for all of them** | Number | **Required for __vertical__ carousel** 159 | **sliderHeight** | Height in pixels of the carousel itself | Number | **Required for __vertical__ carousel** 160 | 161 | ### Behavior 162 | 163 | Prop | Description | Type | Default 164 | ------ | ------ | ------ | ------ 165 | activeSlideOffset | From slider's center, minimum slide distance to be scrolled before being set to active | Number | `25` 166 | apparitionDelay | `FlatList`'s init is a real mess, with lots of unneeded flickers and slides movement. This prop controls the delay during which the carousel will be hidden when mounted. | Number | `250` 167 | enableMomentum | See [momentum](#momentum) | Boolean | `false` 168 | enableSnap | If enabled, releasing the touch will scroll to the center of the nearest/active item | Boolean | `true` 169 | firstItem | Index of the first item to display | Number | `0` 170 | hasParallaxImages | Whether the carousel contains `` components or not. Required for specific data to be passed to children. | Boolean | `false` 171 | scrollEndDragDebounceValue | **When momentum is disabled**, this prop defines the timeframe during which multiple callback calls should be "grouped" into a single one. This debounce also helps smoothing the snap effect by providing a bit of inertia when touch is released. **Note that this will delay callback's execution.** | Number | `50` for iOS, `150` for Android 172 | shouldOptimizeUpdates | Whether to implement a `shouldComponentUpdate` strategy to minimize updates | Boolean | `true` 173 | snapOnAndroid | Snapping on android is sometimes choppy, especially when swiping quickly, so you can disable it | Boolean | `true` 174 | swipeEnabled | When disabled, the view cannot be scrolled via touch interaction. It takes advantage of `ScrollView`'s prop `scrollEnabled`, with just a tiny tweak regarding autoplay. | Boolean | `true` 175 | swipeThreshold | Delta x when swiping to trigger the snap | Number | `20` 176 | useNativeOnScroll | Move `onScroll` events to the native thread in order to prevent the tiny lag associated with RN's JS bridge. **Activate this if you have a `transform` and/or `opacity` animation that needs to follow carousel's scroll position closely**. More info in [this post](https://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html). Note that it will be activated if `hasParallaxImages` is set to `true` and/or if `scrollEventThrottle` is set to less than `16`. | Boolean | `false` 177 | vertical | Layout slides vertically instead of horizontally | Boolean | `false` 178 | 179 | ### Autoplay 180 | 181 | Prop | Description | Type | Default 182 | ------ | ------ | ------ | ------ 183 | autoplay | Trigger autoplay on mount. **Warning: this prop cannot be changed dynamically.** | Boolean | `false` 184 | autoplayDelay | Delay before enabling autoplay on startup & after releasing the touch | Number | `5000` 185 | autoplayInterval | Delay in ms until navigating to the next item | Number | `3000` 186 | 187 | ### Style and animation 188 | 189 | Prop | Description | Type | Default 190 | ------ | ------ | ------ | ------ 191 | activeSlideAlignment | Determine active slide's alignment relative to the carousel. Possible values are: `'start'`, `'center'` and `'end'`. | String | `'center'` 192 | animationFunc | Animated animation to use; you must provide the name of the method. Note that it will only be applied to the scale animation since opacity's animation type will always be set to `timing` (no one wants the opacity to 'bounce' around) | String | `timing` 193 | animationOptions | Animation options to be merged with the default ones. Can be used without `animationFunc`. Note that opacity's easing will be kept linear. | Object | `{ duration: 600, easing: Easing.elastic(1) }` 194 | containerCustomStyle | Optional styles for Scrollview's global wrapper | View Style Object | `{}` 195 | contentContainerCustomStyle | Optional styles for Scrollview's items container | View Style Object | `{}` 196 | inactiveSlideOpacity | Value of the opacity effect applied to inactive slides | Number | `1` 197 | inactiveSlideScale | Value of the 'scale' transform applied to inactive slides | Number | `0.9` 198 | slideStyle | Optional style for each item's container (the one whose scale and opacity are animated) | Animated View Style Object | {} 199 | 200 | ### Callbacks 201 | 202 | Prop | Description | Type | Default 203 | ------ | ------ | ------ | ------ 204 | onLayout(event) | Exposed `View` callback; invoked on mount and layout changes | Function | `undefined` 205 | onScroll(event) | Exposed `ScrollView` callback; fired while scrolling | Function | `undefined` 206 | onSnapToItem(slideIndex) | Callback fired when navigating to an item | Function | `undefined` 207 | 208 | ### Inherited props 209 | 210 | The component is built on top of the `FlatList` component, meaning it inherits from [`FlatList`](https://facebook.github.io/react-native/docs/flatlist.html), [`VirtualizedList`](https://facebook.github.io/react-native/docs/virtualizedlist.html), and [`ScrollView`](https://facebook.github.io/react-native/docs/scrollview.html). 211 | 212 | You can use almost all props from this three components, but some of them can't be overriden because it would mess with our implementation's logic. 213 | 214 | Here are a few useful props regarding carousel's **style and "feeling"**: `showsHorizontalScrollIndicator`, `scrollEnabled` (if you want to scroll only programmatically), `overScrollMode` (android), `bounces` (ios), `decelerationRate` (ios), `scrollEventThrottle` (ios). 215 | 216 | And here are some useful ones for **performance optimizations and rendering**: `initialNumToRender`, `maxToRenderPerBatch`, `windowSize`, `updateCellsBatchingPeriod`, `extraData`, `removeClippedSubviews` (the latter may have bugs, as stated in [RN's doc](https://facebook.github.io/react-native/docs/flatlist.html#removeclippedsubviews)). The first three are already implemented with default parameters, but you can override them if they don't suit your needs. 217 | 218 | ## Methods 219 | 220 | ### Reference to the component 221 | 222 | In order to use the following methods, you need to create a reference to the carousel's instance. There are two ways of doing it. 223 | 224 | #### ref as a callback attribute (**recommended**) 225 | ```javascript 226 | { this._carousel = c; }} 229 | /> 230 | 231 | // methods can then be called this way 232 | onPress={() => { this._carousel.snapToNext(); }} 233 | ``` 234 | 235 | #### ref as a string attribute ([legacy](http://stackoverflow.com/questions/37468913/why-ref-string-is-legacy)) 236 | ```javascript 237 | 241 | 242 | // methods can then be called this way 243 | onPress={() => { this.refs.carousel.snapToNext(); }} 244 | ``` 245 | 246 | ### Available methods 247 | 248 | Method | Description 249 | ------ | ------ 250 | `startAutoplay (instantly = false)` | Start the autoplay manually 251 | `stopAutoplay ()` | Stop the autoplay manually 252 | `snapToItem (index, animated = true)` | Snap to an item manually 253 | `snapToNext (animated = true)` | Snap to next item manually 254 | `snapToPrev (animated = true)` | Snap to previous item manually 255 | 256 | ## Getters 257 | 258 | > You need a reference to the carousel's instance (see [above](#reference-to-the-component) if needed). 259 | 260 | Property | Description 261 | ------ | ------ 262 | `currentIndex` | Current active item (`int`, starts at 0) 263 | `currentScrollPosition` | Underlying `ScrollView`'s current content offset (`int`, starts at `0` if `activeSlideAlignment` is set to `start`, negative value otherwise) 264 | 265 | ## Example 266 | You can find the following example in the [/example](https://github.com/archriss/react-native-snap-carousel/tree/master/example) folder. 267 | 268 | ![react-native-snap-carousel](http://i.imgur.com/m0297Ys.gif) 269 | 270 | ## `ParallaxImage` component 271 | 272 | Version `3.0.0` introduced a `` component, an image component aware of carousel's current scroll position and therefore able to display a nice parallax effect. 273 | 274 | ![react-native-snap-carousel parallax image](http://i.imgur.com/6iIb4SR.gif) 275 | 276 | You can find the documentation for this component [here](https://github.com/archriss/react-native-snap-carousel/blob/flatlist/src/parallaximage/README.md). 277 | 278 | ## `Pagination` component 279 | 280 | Starting with version `2.4.0`, a customizable `` component has been added. This is how it looks like with its default configuration: 281 | 282 | ![react-native-snap-carousel pagination](http://i.imgur.com/FLQcGGL.gif) 283 | 284 | You can find the documentation for this component [here](https://github.com/archriss/react-native-snap-carousel/blob/master/src/pagination/README.md). 285 | 286 | ## Tips and tricks 287 | 288 | ### Momentum 289 | 290 | Since version `1.5.0`, the snapping effect can be based on momentum (by setting `enableMomentum` to `true`) instead of when you're releasing your finger. It means that the component will wait until the `ScrollView` isn't moving anymore to snap. 291 | 292 | By default, the inertia isn't too high on Android. However, we had to tweak the default iOS value a bit to make sure the snapping isn't delayed for too long. You can adjust this value to your needs thanks to [this prop](https://facebook.github.io/react-native/docs/scrollview.html#decelerationrate). 293 | 294 | If momentum is disabled (default behavior), make sure to play with prop `scrollEndDragDebounceValue` since it can help achieving a better snap feeling. 295 | 296 | > **We recommend setting `enableMomentum` to `false` (default) and `decelerationRate` to `'fast'` when you are displaying only one main slide** (as in the showcase above), and to use `true` and `0.9` otherwise. 297 | 298 | ### Margin between slides 299 | If you need some **extra horizontal margin** between slides (besides the one resulting from the scale effect), you should add it as `paddingHorizontal` on slide's container. Make sure to take this into account when calculating item's width. 300 | 301 | ```javascript 302 | const horizontalMargin = 20; 303 | const slideWidth = 280; 304 | 305 | const sliderWidth = Dimensions.get('window').width; 306 | const itemWidth = slideWidth + horizontalMargin * 2; 307 | const itemHeight = 200; 308 | 309 | const styles = Stylesheet.create({ 310 | slide: { 311 | width: itemWidth, 312 | height: itemHeight 313 | // other styles for your item's container 314 | } 315 | }; 316 | ``` 317 | 318 | ### Handling device rotation 319 | 320 | Since version 2.2.0, slides will re-center properly if you update slider and/or items' dimensions when `onLayout` is fired. 321 | 322 | Here is an example of a working implementation (thanks [@andrewpope](https://github.com/archriss/react-native-snap-carousel/pull/76#issuecomment-306187425)): 323 | 324 | ``` 325 | constructor(props) { 326 | super(props); 327 | this.state = { 328 | viewport: { 329 | width: Dimensions.get('window').width, 330 | height: Dimensions.get('window').height 331 | } 332 | }; 333 | } 334 | 335 | render() { 336 | return ( 337 | { 339 | this.setState({ 340 | viewport: { 341 | width: Dimensions.get('window').width, 342 | height: Dimensions.get('window').height 343 | } 344 | }); 345 | }} 346 | > 347 | { this.carousel = c; } } 349 | sliderWidth={this.state.viewport.width} 350 | itemWidth={this.state.viewport.width} 351 | ... 352 | /> 353 | 354 | ); 355 | } 356 | ``` 357 | 358 | ### Fullscreen slides 359 | 360 | While the plugin hasn't been designed with this use case in mind, you can easily implement fullscreen slides. The following code should serve as a good starting point. 361 | 362 | ```javascript 363 | const { width: viewportWidth, height: viewportHeight } = Dimensions.get('window'); 364 | 365 | export class MyCarousel extends Component { 366 | 367 | _renderItem ({item, index}) { 368 | return ( 369 | // or { flex: 1 } for responsive height 370 | ); 371 | } 372 | 373 | render () { 374 | return ( 375 | 384 | ); 385 | } 386 | } 387 | ``` 388 | 389 | [This plugin](https://github.com/shichongrui/react-native-on-layout) can also prove useful. 390 | 391 | ### Android performances 392 | 393 | Make sure to test carousel's performances **without JS Dev Mode enabled**. 394 | 395 | It can take user experience from "crappy and sluggish" to "pretty good" - it's Android though, so nothing like "perfect" or "incredibly smooth"... 396 | 397 | 398 | ### Understanding styles 399 | 400 | Here is a screenshot that should help you understand how each of the above variables is used. 401 | 402 | ![react-native-snap-carousel info](http://i.imgur.com/PMi6aBd.jpg) 403 | 404 | ## Known issues 405 | 406 | ### FlatList and ScrollView's limitations 407 | 408 | Note that this plugin is built on top of React Native's `FlatList` which, in turn, is based on `ScrollView`. Unfortunately, its implementation shows flaws that affect the plugin, the main ones being the following: 409 | - there is no `scrollEnd` event 410 | - `scrollTo` method doesn't accept any callback 411 | - Android's `scrollTo` animation is quite brutal. 412 | 413 | On top of that, `FlatList` has its own set of bugs and buggy behaviors. 414 | 415 | We're trying to work around these issues, but the result is not always as smooth as we'd want it to be. Keep that in mind and go spam [React Native's Feature Request](https://react-native.canny.io/feature-requests) ;-) 416 | 417 | ### Unreliable callbacks 418 | 419 | When `enableMomentum` is disabled, providing a reliable callback is really tricky since no `scrollEnd` event has been exposed yet for the `ScrollView` component. We can only rely on the `scrollDragEnd` event, which comes with a huge bunch of issues. See [#34](https://github.com/archriss/react-native-snap-carousel/issues/34) for more information. 420 | 421 | Version 2.3.0 tackled these issues with a bunch of flags and hacks. But you could still be facing the following one: **when you build a debug version of your app without enabling JS remote debugging**, timers will desynchronize and callbacks will be a complete mess. Try to either enable remote debugging or build a production version of your app, and everything should get back to normal. 422 | 423 | ### Error with Jest 424 | 425 | You might encounter the following error when using the plugin in conjonction with Jest: `TypeError: Cannot read property 'style' of undefined at Object.`. 426 | 427 | As you can see [here](https://github.com/facebook/react-native/blob/master/jest/setup.js), this is because React Native mocks `ScrollView` for you when you write unit tests with Jest. 428 | 429 | The easiest workaround is to add `jest.unmock('ScrollView')` before importing the component in your test file (thanks [@hoangnm](https://github.com/hoangnm) for the tip!). 430 | 431 | ### React Native version 432 | 433 | **RN 0.44.x is the minimum version required to use the plugin.** 434 | 435 | Bear in mind that we follow RN evolutions closely, which means newer versions of the plugin might break when used in conjunction with a version of RN that is not the latest stable one. 436 | 437 | ### RTL support (experimental) 438 | 439 | Since version 2.1.0, the plugin is compatible with RTL layouts. Our implementation relies on miscellaneous hacks that work around a [React Native bug](https://github.com/facebook/react-native/issues/11960) with horizontal `ScrollView`. 440 | 441 | As such, this feature should be considered experimental since it might break with newer versions of React Native. 442 | 443 | ## TODO 444 | 445 | - [ ] Implement 'loop' mode 446 | - [ ] Handle changing major props on-the-fly 447 | - [ ] Handle autoplay properly when updating children's length 448 | - [x] Add parallax image component 449 | - [x] Base the plugin on `FlatList` instead of `ScrollView` 450 | - [x] Add alignment option 451 | - [x] Add pagination component 452 | - [x] Add vertical implementation 453 | - [x] Handle device orientation event (see [this note] (https://github.com/archriss/react-native-snap-carousel#handling-device-rotation)) 454 | - [x] Add RTL support 455 | - [x] Improve momemtum handling 456 | - [x] Improve snap on Android 457 | - [x] Handle passing 1 item only 458 | - [x] Fix centering 459 | 460 | ## Credits 461 | 462 | Written by [Maxime Bertonnier](https://fr.linkedin.com/in/maxime-bertonnier-744351aa) ([Exilz](https://github.com/Exilz)) and [Benoît Delmaire](https://fr.linkedin.com/in/benoitdelmaire) ([bd-arc](https://github.com/bd-arc)) at 463 | [Archriss](http://www.archriss.com/). 464 | -------------------------------------------------------------------------------- /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /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 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | munge_underscores=true 30 | 31 | 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' 32 | 33 | suppress_type=$FlowIssue 34 | suppress_type=$FlowFixMe 35 | suppress_type=$FixMe 36 | 37 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 38 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 41 | 42 | unsafe.enable_getters_and_setters=true 43 | 44 | [version] 45 | ^0.49.1 -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.android.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /example/__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.ios.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /example/android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.rndiffapp", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.rndiffapp", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 37 | * // for example: to disable dev mode in the staging build type (if configured) 38 | * devDisabledInStaging: true, 39 | * // The configuration property can be in the following formats 40 | * // 'devDisabledIn${productFlavor}${buildType}' 41 | * // 'devDisabledIn${buildType}' 42 | * 43 | * // the root of your project, i.e. where "package.json" lives 44 | * root: "../../", 45 | * 46 | * // where to put the JS bundle asset in debug mode 47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 48 | * 49 | * // where to put the JS bundle asset in release mode 50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 51 | * 52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 53 | * // require('./image.png')), in debug mode 54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 55 | * 56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 57 | * // require('./image.png')), in release mode 58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 59 | * 60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 64 | * // for example, you might want to remove it from here. 65 | * inputExcludes: ["android/**", "ios/**"], 66 | * 67 | * // override which node gets called and with what additional arguments 68 | * nodeExecutableAndArgs: ["node"], 69 | * 70 | * // supply additional arguments to the packager 71 | * extraPackagerArgs: [] 72 | * ] 73 | */ 74 | 75 | apply from: "../../node_modules/react-native/react.gradle" 76 | 77 | /** 78 | * Set this to true to create two separate APKs instead of one: 79 | * - An APK that only works on ARM devices 80 | * - An APK that only works on x86 devices 81 | * The advantage is the size of the APK is reduced by about 4MB. 82 | * Upload all the APKs to the Play Store and people will download 83 | * the correct one based on the CPU architecture of their device. 84 | */ 85 | def enableSeparateBuildPerCPUArchitecture = false 86 | 87 | /** 88 | * Run Proguard to shrink the Java bytecode in release builds. 89 | */ 90 | def enableProguardInReleaseBuilds = false 91 | 92 | android { 93 | compileSdkVersion 23 94 | buildToolsVersion "23.0.1" 95 | 96 | defaultConfig { 97 | applicationId "com.example" 98 | minSdkVersion 16 99 | targetSdkVersion 22 100 | versionCode 1 101 | versionName "1.0.0" 102 | ndk { 103 | abiFilters "armeabi-v7a", "x86" 104 | } 105 | } 106 | splits { 107 | abi { 108 | reset() 109 | enable enableSeparateBuildPerCPUArchitecture 110 | universalApk false // If true, also generate a universal APK 111 | include "armeabi-v7a", "x86" 112 | } 113 | } 114 | buildTypes { 115 | release { 116 | minifyEnabled enableProguardInReleaseBuilds 117 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 118 | } 119 | } 120 | // applicationVariants are e.g. debug, release 121 | applicationVariants.all { variant -> 122 | variant.outputs.each { output -> 123 | // For each separate APK per architecture, set a unique version code as described here: 124 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 125 | def versionCodes = ["armeabi-v7a":1, "x86":2] 126 | def abi = output.getFilter(OutputFile.ABI) 127 | if (abi != null) { // null for the universal-debug, universal-release variants 128 | output.versionCodeOverride = 129 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 130 | } 131 | } 132 | } 133 | } 134 | 135 | dependencies { 136 | compile project(':react-native-linear-gradient') 137 | compile fileTree(dir: "libs", include: ["*.jar"]) 138 | compile "com.android.support:appcompat-v7:23.0.1" 139 | compile "com.facebook.react:react-native:+" // From node_modules 140 | } 141 | 142 | // Run this once to be able to run the application with BUCK 143 | // puts all compile dependencies into folder libs for BUCK to use 144 | task copyDownloadableDepsToLibs(type: Copy) { 145 | from configurations.compile 146 | into 'libs' 147 | } -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "example"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.BV.LinearGradient.LinearGradientPackage; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | import com.facebook.soloader.SoLoader; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainApplication extends Application implements ReactApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 18 | @Override 19 | public boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | return Arrays.asList( 26 | new MainReactPackage(), 27 | new LinearGradientPackage() 28 | ); 29 | } 30 | }; 31 | 32 | @Override 33 | public ReactNativeHost getReactNativeHost() { 34 | return mReactNativeHost; 35 | } 36 | 37 | @Override 38 | public void onCreate() { 39 | super.onCreate(); 40 | SoLoader.init(this, /* native exopackage */ false); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/react-native-snap-carousel/8f65a9af47c7943d5319966f37458fef8f4e244e/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/react-native-snap-carousel/8f65a9af47c7943d5319966f37458fef8f4e244e/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/react-native-snap-carousel/8f65a9af47c7943d5319966f37458fef8f4e244e/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/react-native-snap-carousel/8f65a9af47c7943d5319966f37458fef8f4e244e/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | example 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevstar/react-native-snap-carousel/8f65a9af47c7943d5319966f37458fef8f4e244e/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /example/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) -------------------------------------------------------------------------------- /example/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'example' 2 | include ':react-native-linear-gradient' 3 | project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android') 4 | 5 | include ':app' 6 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "displayName": "example" 4 | } -------------------------------------------------------------------------------- /example/index.android.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import Root from './src/index'; 3 | 4 | AppRegistry.registerComponent('example', () => Root); 5 | -------------------------------------------------------------------------------- /example/index.ios.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import Root from './src/index'; 3 | 4 | AppRegistry.registerComponent('example', () => Root); 5 | -------------------------------------------------------------------------------- /example/ios/example-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/ios/example-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example/ios/example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"example" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /example/ios/example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /example/ios/example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | fr_FR 7 | CFBundleDisplayName 8 | example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0.0 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSExceptionDomains 30 | 31 | imgur.com 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | NSIncludesSubdomains 36 | 37 | 38 | localhost 39 | 40 | NSExceptionAllowsInsecureHTTPLoads 41 | 42 | 43 | 44 | 45 | NSLocationWhenInUseUsageDescription 46 | 47 | UILaunchStoryboardName 48 | LaunchScreen 49 | UIRequiredDeviceCapabilities 50 | 51 | armv7 52 | 53 | UIStatusBarStyle 54 | UIStatusBarStyleLightContent 55 | UISupportedInterfaceOrientations 56 | 57 | UIInterfaceOrientationPortrait 58 | 59 | UISupportedInterfaceOrientations~ipad 60 | 61 | UIInterfaceOrientationPortrait 62 | 63 | UIViewControllerBasedStatusBarAppearance 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /example/ios/example/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/ios/exampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/exampleTests/exampleTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface exampleTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation exampleTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "0.4.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "react": "16.0.0-alpha.12", 10 | "react-native": "~0.47.1", 11 | "react-native-linear-gradient": "^2.1.0", 12 | "react-native-snap-carousel": "file:../" 13 | }, 14 | "devDependencies": { 15 | "babel-preset-react-native": "1.9.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/src/components/SliderEntry.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { View, Text, Image, TouchableOpacity } from 'react-native'; 3 | import { ParallaxImage } from 'react-native-snap-carousel'; 4 | import styles from 'example/src/styles/SliderEntry.style'; 5 | 6 | export default class SliderEntry extends Component { 7 | 8 | static propTypes = { 9 | data: PropTypes.object.isRequired, 10 | even: PropTypes.bool, 11 | parallax: PropTypes.bool, 12 | parallaxProps: PropTypes.object 13 | }; 14 | 15 | get image () { 16 | const { data: { illustration }, parallax, parallaxProps, even } = this.props; 17 | 18 | return parallax ? ( 19 | 28 | ) : ( 29 | 33 | ); 34 | } 35 | 36 | render () { 37 | const { data: { title, subtitle }, even } = this.props; 38 | 39 | const uppercaseTitle = title ? ( 40 | 44 | { title.toUpperCase() } 45 | 46 | ) : false; 47 | 48 | return ( 49 | { alert(`You've clicked '${title}'`); }} 53 | > 54 | 55 | { this.image } 56 | 57 | 58 | 59 | { uppercaseTitle } 60 | 64 | { subtitle } 65 | 66 | 67 | 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, ScrollView, Text, StatusBar, Platform } from 'react-native'; 3 | import LinearGradient from 'react-native-linear-gradient'; 4 | import Carousel, { Pagination } from 'react-native-snap-carousel'; 5 | import { sliderWidth, itemWidth } from 'example/src/styles/SliderEntry.style'; 6 | import SliderEntry from 'example/src/components/SliderEntry'; 7 | import styles, { colors } from 'example/src/styles/index.style'; 8 | import { ENTRIES1, ENTRIES2 } from 'example/src/static/entries'; 9 | 10 | const SLIDER_1_FIRST_ITEM = 1; 11 | 12 | export default class example extends Component { 13 | 14 | constructor (props) { 15 | super(props); 16 | this.state = { 17 | slider1ActiveSlide: SLIDER_1_FIRST_ITEM 18 | }; 19 | } 20 | 21 | _renderItem ({item, index}) { 22 | return ( 23 | 27 | ); 28 | } 29 | 30 | _renderItemWithParallax ({item, index}, parallaxProps) { 31 | return ( 32 | 38 | ); 39 | } 40 | 41 | get example1 () { 42 | const { slider1ActiveSlide } = this.state; 43 | 44 | return ( 45 | 46 | Example 1 47 | No momentum | Parallax | Pagination | Scale | Opacity 48 | this.setState({ slider1ActiveSlide: index }) } 62 | /> 63 | 71 | 72 | ); 73 | } 74 | 75 | get example2 () { 76 | return ( 77 | 78 | Example 2 79 | Momentum | Left-aligned | Autoplay 80 | 96 | 97 | ); 98 | } 99 | 100 | get gradient () { 101 | return ( 102 | 108 | ); 109 | } 110 | 111 | render () { 112 | return ( 113 | 114 | 119 | { this.gradient } 120 | 127 | { this.example1 } 128 | { this.example2 } 129 | 130 | 131 | ); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /example/src/static/entries.js: -------------------------------------------------------------------------------- 1 | export const ENTRIES1 = [ 2 | { 3 | title: 'Beautiful and dramatic Antelope Canyon', 4 | subtitle: 'Lorem ipsum dolor sit amet et nuncat mergitur', 5 | illustration: 'http://i.imgur.com/UYiroysl.jpg' 6 | }, 7 | { 8 | title: 'Earlier this morning, NYC', 9 | subtitle: 'Lorem ipsum dolor sit amet', 10 | illustration: 'http://i.imgur.com/UPrs1EWl.jpg' 11 | }, 12 | { 13 | title: 'White Pocket Sunset', 14 | subtitle: 'Lorem ipsum dolor sit amet et nuncat ', 15 | illustration: 'http://i.imgur.com/MABUbpDl.jpg' 16 | }, 17 | { 18 | title: 'Acrocorinth, Greece', 19 | subtitle: 'Lorem ipsum dolor sit amet et nuncat mergitur', 20 | illustration: 'http://i.imgur.com/KZsmUi2l.jpg' 21 | }, 22 | { 23 | title: 'The lone tree, majestic landscape of New Zealand', 24 | subtitle: 'Lorem ipsum dolor sit amet', 25 | illustration: 'http://i.imgur.com/2nCt3Sbl.jpg' 26 | }, 27 | { 28 | title: 'Middle Earth, Germany', 29 | subtitle: 'Lorem ipsum dolor sit amet', 30 | illustration: 'http://i.imgur.com/lceHsT6l.jpg' 31 | } 32 | ]; 33 | 34 | export const ENTRIES2 = [ 35 | { 36 | title: 'Favourites landscapes', 37 | subtitle: 'Lorem ipsum dolor sit amet', 38 | illustration: 'http://i.imgur.com/SsJmZ9jl.jpg' 39 | }, 40 | { 41 | title: 'Favourites landscapes', 42 | subtitle: 'Lorem ipsum dolor sit amet et nuncat mergitur', 43 | illustration: 'http://i.imgur.com/5tj6S7Ol.jpg' 44 | }, 45 | { 46 | title: 'Favourites landscapes', 47 | subtitle: 'Lorem ipsum dolor sit amet et nuncat', 48 | illustration: 'http://i.imgur.com/pmSqIFZl.jpg' 49 | }, 50 | { 51 | title: 'Favourites landscapes', 52 | subtitle: 'Lorem ipsum dolor sit amet et nuncat mergitur', 53 | illustration: 'http://i.imgur.com/cA8zoGel.jpg' 54 | }, 55 | { 56 | title: 'Favourites landscapes', 57 | subtitle: 'Lorem ipsum dolor sit amet', 58 | illustration: 'http://i.imgur.com/pewusMzl.jpg' 59 | }, 60 | { 61 | title: 'Favourites landscapes', 62 | subtitle: 'Lorem ipsum dolor sit amet et nuncat', 63 | illustration: 'http://i.imgur.com/l49aYS3l.jpg' 64 | } 65 | ]; 66 | -------------------------------------------------------------------------------- /example/src/styles/SliderEntry.style.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet, Dimensions, Platform } from 'react-native'; 2 | import { colors } from 'example/src/styles/index.style'; 3 | 4 | const { width: viewportWidth, height: viewportHeight } = Dimensions.get('window'); 5 | 6 | function wp (percentage) { 7 | const value = (percentage * viewportWidth) / 100; 8 | return Math.round(value); 9 | } 10 | 11 | const slideHeight = viewportHeight * 0.4; 12 | const slideWidth = wp(75); 13 | const itemHorizontalMargin = wp(2); 14 | 15 | export const sliderWidth = viewportWidth; 16 | export const itemWidth = slideWidth + itemHorizontalMargin * 2; 17 | 18 | const entryBorderRadius = 8; 19 | 20 | export default StyleSheet.create({ 21 | slideInnerContainer: { 22 | width: itemWidth, 23 | height: slideHeight, 24 | paddingHorizontal: itemHorizontalMargin, 25 | paddingBottom: 18 // needed for shadow 26 | }, 27 | imageContainer: { 28 | flex: 1, 29 | backgroundColor: 'white', 30 | borderTopLeftRadius: entryBorderRadius, 31 | borderTopRightRadius: entryBorderRadius 32 | }, 33 | imageContainerEven: { 34 | backgroundColor: colors.black 35 | }, 36 | image: { 37 | ...StyleSheet.absoluteFillObject, 38 | resizeMode: 'cover', 39 | borderRadius: Platform.OS === 'ios' ? entryBorderRadius : 0, 40 | borderTopLeftRadius: entryBorderRadius, 41 | borderTopRightRadius: entryBorderRadius 42 | }, 43 | // image's border radius is buggy on ios; let's hack it! 44 | radiusMask: { 45 | position: 'absolute', 46 | bottom: 0, 47 | left: 0, 48 | right: 0, 49 | height: entryBorderRadius, 50 | backgroundColor: 'white' 51 | }, 52 | radiusMaskEven: { 53 | backgroundColor: colors.black 54 | }, 55 | textContainer: { 56 | justifyContent: 'center', 57 | paddingTop: 20 - entryBorderRadius, 58 | paddingBottom: 20, 59 | paddingHorizontal: 16, 60 | backgroundColor: 'white', 61 | borderBottomLeftRadius: entryBorderRadius, 62 | borderBottomRightRadius: entryBorderRadius 63 | }, 64 | textContainerEven: { 65 | backgroundColor: colors.black 66 | }, 67 | title: { 68 | color: colors.black, 69 | fontSize: 13, 70 | fontWeight: 'bold', 71 | letterSpacing: 0.5 72 | }, 73 | titleEven: { 74 | color: 'white' 75 | }, 76 | subtitle: { 77 | marginTop: 6, 78 | color: colors.gray, 79 | fontSize: 12, 80 | fontStyle: 'italic' 81 | }, 82 | subtitleEven: { 83 | color: 'rgba(255, 255, 255, 0.7)' 84 | } 85 | }); 86 | -------------------------------------------------------------------------------- /example/src/styles/index.style.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | export const colors = { 4 | black: '#1a1917', 5 | gray: '#888888', 6 | background1: '#B721FF', 7 | background2: '#21D4FD' 8 | }; 9 | 10 | export default StyleSheet.create({ 11 | container: { 12 | flex: 1, 13 | backgroundColor: colors.background1 14 | }, 15 | gradient: { 16 | ...StyleSheet.absoluteFillObject 17 | }, 18 | scrollview: { 19 | flex: 1, 20 | paddingTop: 50 21 | }, 22 | scrollviewContentContainer: { 23 | paddingBottom: 50 24 | }, 25 | exampleContainer: { 26 | marginBottom: 30 27 | }, 28 | title: { 29 | backgroundColor: 'transparent', 30 | color: 'rgba(255, 255, 255, 0.9)', 31 | fontSize: 20, 32 | fontWeight: 'bold', 33 | textAlign: 'center' 34 | }, 35 | subtitle: { 36 | marginTop: 5, 37 | backgroundColor: 'transparent', 38 | color: 'rgba(255, 255, 255, 0.75)', 39 | fontSize: 13, 40 | fontStyle: 'italic', 41 | textAlign: 'center' 42 | }, 43 | slider: { 44 | marginTop: 25 45 | }, 46 | sliderContentContainer: { 47 | }, 48 | paginationContainer: { 49 | paddingVertical: 8 50 | }, 51 | paginationDot: { 52 | width: 8, 53 | height: 8, 54 | borderRadius: 4, 55 | marginHorizontal: 8, 56 | backgroundColor: 'rgba(255, 255, 255, 0.92)' 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-snap-carousel", 3 | "version": "3.0.0", 4 | "description": "Swiper component for React Native with previews, snapping effect, parallax images, performant handling of huge numbers of items, and RTL support. Compatible with Android & iOS.", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "github.com/archriss/react-native-snap-carousel" 9 | }, 10 | "keywords": [ 11 | "react", 12 | "native", 13 | "carousel", 14 | "slider", 15 | "swiper", 16 | "flatlist", 17 | "scrollview", 18 | "parallax", 19 | "images", 20 | "infinite", 21 | "scroll", 22 | "scrolling", 23 | "items", 24 | "snap", 25 | "android", 26 | "ios", 27 | "snapping", 28 | "component", 29 | "rtl" 30 | ], 31 | "author": "Archriss (github.com/archriss)", 32 | "license": "ISC", 33 | "dependencies": { 34 | "lodash.debounce": "4.0.8", 35 | "prop-types": "^15.5.10", 36 | "react-addons-shallow-compare": "15.6.0" 37 | }, 38 | "peerDependencies": { 39 | "react": "*", 40 | "react-native": "*" 41 | }, 42 | "devDependencies": { 43 | "babel-eslint": "^7.2.3", 44 | "eslint": "^3.19.0", 45 | "eslint-config-standard": "^10.2.1", 46 | "eslint-config-standard-react": "^5.0.0", 47 | "eslint-plugin-import": "^2.3.0", 48 | "eslint-plugin-node": "^5.0.0", 49 | "eslint-plugin-promise": "^3.5.0", 50 | "eslint-plugin-react": "^7.0.1", 51 | "eslint-plugin-standard": "^3.0.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/carousel/Carousel.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, FlatList, Animated, Platform, Easing, I18nManager, ViewPropTypes } from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import shallowCompare from 'react-addons-shallow-compare'; 5 | import _debounce from 'lodash.debounce'; 6 | 7 | // Native driver for scroll events 8 | // See: https://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html 9 | const AnimatedFlatList = Animated.createAnimatedComponent(FlatList); 10 | 11 | // React Native automatically handles RTL layouts; unfortunately, it's buggy with horizontal ScrollView 12 | // See https://github.com/facebook/react-native/issues/11960 13 | // NOTE: the following variable is not declared in the constructor 14 | // otherwise it is undefined at init, which messes with custom indexes 15 | const IS_RTL = I18nManager.isRTL; 16 | 17 | export default class Carousel extends Component { 18 | 19 | static propTypes = { 20 | ...FlatList.propTypes, 21 | data: PropTypes.array.isRequired, 22 | renderItem: PropTypes.func.isRequired, 23 | itemWidth: PropTypes.number, // required for horizontal carousel 24 | itemHeight: PropTypes.number, // required for vertical carousel 25 | sliderWidth: PropTypes.number, // required for horizontal carousel 26 | sliderHeight: PropTypes.number, // required for vertical carousel 27 | activeSlideAlignment: PropTypes.oneOf(['center', 'end', 'start']), 28 | activeSlideOffset: PropTypes.number, 29 | animationFunc: PropTypes.string, 30 | animationOptions: PropTypes.object, 31 | apparitionDelay: PropTypes.number, 32 | autoplay: PropTypes.bool, 33 | autoplayDelay: PropTypes.number, 34 | autoplayInterval: PropTypes.number, 35 | containerCustomStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 36 | contentContainerCustomStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 37 | enableMomentum: PropTypes.bool, 38 | enableSnap: PropTypes.bool, 39 | firstItem: PropTypes.number, 40 | hasParallaxImages: PropTypes.bool, 41 | inactiveSlideOpacity: PropTypes.number, 42 | inactiveSlideScale: PropTypes.number, 43 | scrollEndDragDebounceValue: PropTypes.number, 44 | slideStyle: Animated.View.propTypes.style, 45 | shouldOptimizeUpdates: PropTypes.bool, 46 | snapOnAndroid: PropTypes.bool, 47 | swipeThreshold: PropTypes.number, 48 | useNativeOnScroll: PropTypes.bool, 49 | vertical: PropTypes.bool, 50 | onSnapToItem: PropTypes.func 51 | }; 52 | 53 | static defaultProps = { 54 | activeSlideAlignment: 'center', 55 | activeSlideOffset: 25, 56 | animationFunc: 'timing', 57 | animationOptions: { 58 | duration: 600, 59 | easing: Easing.elastic(1) 60 | }, 61 | apparitionDelay: 250, 62 | autoplay: false, 63 | autoplayDelay: 5000, 64 | autoplayInterval: 3000, 65 | containerCustomStyle: {}, 66 | contentContainerCustomStyle: {}, 67 | enableMomentum: false, 68 | enableSnap: true, 69 | firstItem: 0, 70 | hasParallaxImages: false, 71 | inactiveSlideOpacity: 0.7, 72 | inactiveSlideScale: 0.9, 73 | scrollEndDragDebounceValue: Platform.OS === 'ios' ? 50 : 150, 74 | slideStyle: {}, 75 | shouldOptimizeUpdates: true, 76 | snapOnAndroid: true, 77 | swipeThreshold: 20, 78 | useNativeOnScroll: false, 79 | vertical: false 80 | } 81 | 82 | constructor (props) { 83 | super(props); 84 | 85 | const initialActiveItem = this._getFirstItem(props.firstItem); 86 | this.state = { 87 | activeItem: initialActiveItem, 88 | previousActiveItem: initialActiveItem, // used only when `enableMomentum` is set to `true` 89 | previousFirstItem: initialActiveItem, 90 | hideCarousel: true, 91 | interpolators: [] 92 | }; 93 | 94 | this._positions = []; 95 | this._currentContentOffset = 0; // store ScrollView's scroll position 96 | this._hasFiredEdgeItemCallback = true; // deal with overscroll and callback 97 | this._canFireCallback = false; // used only when `enableMomentum` is set to `false` 98 | this._isShortSnapping = false; // used only when `enableMomentum` is set to `false` 99 | 100 | this._initInterpolators = this._initInterpolators.bind(this); 101 | this._getItemLayout = this._getItemLayout.bind(this); 102 | this._renderItem = this._renderItem.bind(this); 103 | this._onScroll = this._onScroll.bind(this); 104 | this._onScrollEnd = this._snapEnabled || props.autoplay ? this._onScrollEnd.bind(this) : undefined; 105 | this._onScrollBeginDrag = this._snapEnabled ? this._onScrollBeginDrag.bind(this) : undefined; 106 | this._onScrollEndDrag = !props.enableMomentum ? this._onScrollEndDrag.bind(this) : undefined; 107 | this._onMomentumScrollEnd = props.enableMomentum ? this._onMomentumScrollEnd.bind(this) : undefined; 108 | this._onTouchStart = this._onTouchStart.bind(this); 109 | this._onTouchRelease = this._onTouchRelease.bind(this); 110 | this._onLayout = this._onLayout.bind(this); 111 | this._onSnap = this._onSnap.bind(this); 112 | 113 | // Native driver for scroll events 114 | if (props.useNativeOnScroll || props.hasParallaxImages || props.scrollEventThrottle < 16) { 115 | const scrollEventConfig = { 116 | listener: this._onScroll, 117 | useNativeDriver: true 118 | }; 119 | this._scrollPos = new Animated.Value(0); 120 | this._onScrollHandler = props.vertical ? 121 | Animated.event( 122 | [{ nativeEvent: { contentOffset: { y: this._scrollPos } } }], 123 | scrollEventConfig 124 | ) : Animated.event( 125 | [{ nativeEvent: { contentOffset: { x: this._scrollPos } } }], 126 | scrollEventConfig 127 | ); 128 | } else { 129 | this._onScrollHandler = this._onScroll; 130 | } 131 | 132 | // Debounce `_onScrollEndDrag` execution 133 | // This aims at improving snap feeling and callback reliability 134 | this._onScrollEndDragDebounced = !props.scrollEndDragDebounceValue ? 135 | this._onScrollEndDragDebounced.bind(this) : 136 | _debounce( 137 | this._onScrollEndDragDebounced, 138 | props.scrollEndDragDebounceValue, 139 | { leading: false, trailing: true } 140 | ).bind(this); 141 | 142 | // This bool aims at fixing an iOS bug due to scrollTo that triggers onMomentumScrollEnd. 143 | // onMomentumScrollEnd fires this._snapScroll, thus creating an infinite loop. 144 | this._ignoreNextMomentum = false; 145 | 146 | // Warnings 147 | if (!ViewPropTypes) { 148 | console.warn('react-native-snap-carousel: It is recommended to use at least version 0.44 of React Native with the plugin'); 149 | } 150 | if (!props.vertical && (!props.sliderWidth || !props.itemWidth)) { 151 | console.warn('react-native-snap-carousel: You need to specify both `sliderWidth` and `itemWidth` for horizontal carousels'); 152 | } 153 | if (props.vertical && (!props.sliderHeight || !props.itemHeight)) { 154 | console.warn('react-native-snap-carousel: You need to specify both `sliderHeight` and `itemHeight` for vertical carousels'); 155 | } 156 | if (props.onScrollViewScroll) { 157 | console.warn('react-native-snap-carousel: Prop `onScrollViewScroll` has been removed. Use `onScroll` instead'); 158 | } 159 | } 160 | 161 | componentDidMount () { 162 | const { firstItem, autoplay, apparitionDelay } = this.props; 163 | const _firstItem = this._getFirstItem(firstItem); 164 | 165 | this._initInterpolators(this.props, true); 166 | 167 | setTimeout(() => { 168 | this.snapToItem(_firstItem, false, false, true); 169 | 170 | if (autoplay) { 171 | this.startAutoplay(); 172 | } 173 | }, 0); 174 | 175 | // hide FlatList's awful init 176 | setTimeout(() => { 177 | this.setState({ hideCarousel: false }); 178 | }, apparitionDelay); 179 | } 180 | 181 | shouldComponentUpdate (nextProps, nextState) { 182 | if (this.props.shouldOptimizeUpdates === false) { 183 | return true; 184 | } else { 185 | return shallowCompare(this, nextProps, nextState); 186 | } 187 | } 188 | 189 | componentWillReceiveProps (nextProps) { 190 | const { activeItem, interpolators, previousFirstItem } = this.state; 191 | const { data, firstItem, sliderWidth, sliderHeight, itemWidth, itemHeight } = nextProps; 192 | 193 | const itemsLength = data.length; 194 | const nextFirstItem = this._getFirstItem(firstItem, nextProps); 195 | const nextActiveItem = activeItem || activeItem === 0 ? activeItem : nextFirstItem; 196 | 197 | const hasNewSliderWidth = sliderWidth && sliderWidth !== this.props.sliderWidth; 198 | const hasNewSliderHeight = sliderHeight && sliderHeight !== this.props.sliderHeight; 199 | const hasNewItemWidth = itemWidth && itemWidth !== this.props.itemWidth; 200 | const hasNewItemHeight = itemHeight && itemHeight !== this.props.itemHeight; 201 | 202 | if ((itemsLength && interpolators.length !== itemsLength) || 203 | hasNewSliderWidth || hasNewSliderHeight || hasNewItemWidth || hasNewItemHeight) { 204 | this._positions = []; 205 | this._calcCardPositions(nextProps); 206 | this._initInterpolators(nextProps); 207 | 208 | this.setState({ activeItem: nextActiveItem }); 209 | 210 | if (hasNewSliderWidth || hasNewSliderHeight || hasNewItemWidth || hasNewItemHeight || 211 | (IS_RTL && !nextProps.vertical)) { 212 | this.snapToItem(nextActiveItem, false, false); 213 | } 214 | } else if (nextFirstItem !== previousFirstItem && nextFirstItem !== activeItem) { 215 | this.setState({ 216 | previousFirstItem: nextFirstItem, 217 | activeItem: nextFirstItem 218 | }); 219 | this.snapToItem(nextFirstItem); 220 | } 221 | } 222 | 223 | componentWillUnmount () { 224 | this.stopAutoplay(); 225 | clearTimeout(this._enableAutoplayTimeout); 226 | clearTimeout(this._autoplayTimeout); 227 | clearTimeout(this._snapNoMomentumTimeout); 228 | clearTimeout(this._scrollToTimeout); 229 | } 230 | 231 | get _snapEnabled () { 232 | const { enableSnap, snapOnAndroid } = this.props; 233 | return enableSnap && (Platform.OS === 'ios' || snapOnAndroid); 234 | } 235 | 236 | get currentIndex () { 237 | return this.state.activeItem; 238 | } 239 | 240 | get currentScrollPosition () { 241 | return this._currentContentOffset; 242 | } 243 | 244 | _getCustomIndex (index, props = this.props) { 245 | const itemsLength = props.data && props.data.length; 246 | 247 | if (!itemsLength || (!index && index !== 0)) { 248 | return 0; 249 | } 250 | 251 | return IS_RTL && !props.vertical ? 252 | itemsLength - index - 1 : 253 | index; 254 | } 255 | 256 | _getFirstItem (index, props = this.props) { 257 | const itemsLength = props.data && props.data.length; 258 | 259 | if (!itemsLength || index > itemsLength - 1 || index < 0) { 260 | return 0; 261 | } 262 | 263 | return index; 264 | } 265 | 266 | _calcCardPositions (props = this.props) { 267 | const { data, itemWidth, itemHeight, vertical } = props; 268 | const sizeRef = vertical ? itemHeight : itemWidth; 269 | 270 | data.forEach((itemData, index) => { 271 | const _index = this._getCustomIndex(index, props); 272 | this._positions[index] = { 273 | start: _index * sizeRef, 274 | end: _index * sizeRef + sizeRef 275 | }; 276 | }); 277 | } 278 | 279 | _initInterpolators (props = this.props, initial = false) { 280 | const { activeItem } = this.state; 281 | const { data, firstItem } = props; 282 | 283 | let interpolators = []; 284 | const focusedItem = !initial && (activeItem || activeItem === 0) ? 285 | activeItem : 286 | this._getFirstItem(firstItem, props); 287 | 288 | data.forEach((itemData, index) => { 289 | const value = index === focusedItem ? 1 : 0; 290 | interpolators.push({ 291 | opacity: new Animated.Value(value), 292 | scale: new Animated.Value(value) 293 | }); 294 | }); 295 | this.setState({ interpolators }); 296 | } 297 | 298 | _getScrollOffset (event) { 299 | const { vertical } = this.props; 300 | return (event && event.nativeEvent && event.nativeEvent.contentOffset && 301 | event.nativeEvent.contentOffset[vertical ? 'y' : 'x']) || 0; 302 | } 303 | 304 | _getActiveItem (offset) { 305 | const { activeSlideOffset } = this.props; 306 | const center = this._getCenter(offset); 307 | 308 | for (let i = 0; i < this._positions.length; i++) { 309 | const { start, end } = this._positions[i]; 310 | if (center + activeSlideOffset >= start && center - activeSlideOffset <= end) { 311 | return i; 312 | } 313 | } 314 | 315 | const lastIndex = this._positions.length - 1; 316 | if (this._positions[lastIndex] && center - activeSlideOffset > this._positions[lastIndex].end) { 317 | return lastIndex; 318 | } 319 | 320 | return 0; 321 | } 322 | 323 | _getContainerInnerMargin (opposite = false) { 324 | const { sliderWidth, sliderHeight, itemWidth, itemHeight, vertical, activeSlideAlignment } = this.props; 325 | 326 | if ((activeSlideAlignment === 'start' && !opposite) || 327 | (activeSlideAlignment === 'end' && opposite)) { 328 | return 0; 329 | } else if ((activeSlideAlignment === 'end' && !opposite) || 330 | (activeSlideAlignment === 'start' && opposite)) { 331 | return vertical ? sliderHeight - itemHeight : sliderWidth - itemWidth; 332 | } else { 333 | return vertical ? (sliderHeight - itemHeight) / 2 : (sliderWidth - itemWidth) / 2; 334 | } 335 | } 336 | 337 | _getCenter (offset) { 338 | const { sliderWidth, sliderHeight, itemWidth, itemHeight, vertical, activeSlideAlignment } = this.props; 339 | 340 | let viewportOffset; 341 | if (activeSlideAlignment === 'start') { 342 | viewportOffset = vertical ? itemHeight / 2 : itemWidth / 2; 343 | } else if (activeSlideAlignment === 'end') { 344 | viewportOffset = vertical ? 345 | sliderHeight - (itemHeight / 2) : 346 | sliderWidth - (itemWidth / 2); 347 | } else { 348 | viewportOffset = vertical ? sliderHeight / 2 : sliderWidth / 2; 349 | } 350 | 351 | return offset + viewportOffset - (this._getContainerInnerMargin() * (IS_RTL ? -1 : 1)); 352 | } 353 | 354 | _getKeyExtractor (item, index) { 355 | return `carousel-item-${index}`; 356 | } 357 | 358 | _getItemLayout (data, index) { 359 | const { itemWidth, itemHeight, vertical } = this.props; 360 | const itemSize = vertical ? itemHeight : itemWidth; 361 | 362 | return { 363 | length: itemSize, 364 | offset: itemSize * index, 365 | index 366 | }; 367 | } 368 | 369 | _getItemOffset (index) { 370 | // 'viewPosition' doesn't work for the first item 371 | // It is always aligned to the left 372 | // Unfortunately, 'viewOffset' doesn't work on Android ATM 373 | if ((!IS_RTL && index === 0) || 374 | (IS_RTL && index === this.props.data.length - 1)) { 375 | return this._getContainerInnerMargin(); 376 | } 377 | 378 | return 0; 379 | } 380 | 381 | _getSlideAnimation (index, toValue) { 382 | const { animationFunc, animationOptions } = this.props; 383 | const animationCommonOptions = { 384 | isInteraction: false, 385 | useNativeDriver: true, 386 | ...animationOptions, 387 | toValue: toValue 388 | }; 389 | 390 | return Animated.parallel([ 391 | Animated['timing']( 392 | this.state.interpolators[index].opacity, 393 | { ...animationCommonOptions, easing: Easing.linear } 394 | ), 395 | Animated[animationFunc]( 396 | this.state.interpolators[index].scale, 397 | { ...animationCommonOptions } 398 | ) 399 | ]); 400 | } 401 | 402 | _onScroll (event) { 403 | const { activeItem } = this.state; 404 | const { data, enableMomentum, onScroll } = this.props; 405 | 406 | const scrollOffset = this._getScrollOffset(event); 407 | const newActiveItem = this._getActiveItem(scrollOffset); 408 | const itemsLength = data.length; 409 | let animations = []; 410 | 411 | this._currentContentOffset = scrollOffset; 412 | 413 | if (enableMomentum) { 414 | clearTimeout(this._snapNoMomentumTimeout); 415 | } 416 | 417 | if (activeItem !== newActiveItem) { 418 | if (activeItem === 0 || activeItem === itemsLength - 1) { 419 | this._hasFiredEdgeItemCallback = false; 420 | } 421 | 422 | // WARNING: `setState()` is asynchronous 423 | this.setState({ activeItem: newActiveItem }, () => { 424 | // When "short snapping", we can rely on the "activeItem/newActiveItem" comparison 425 | if (!enableMomentum && this._canFireCallback && this._isShortSnapping) { 426 | this._isShortSnapping = false; 427 | this._onSnap(newActiveItem); 428 | } 429 | }); 430 | 431 | // With dynamically removed items, `activeItem` and 432 | // `newActiveItem`'s interpolators might be `undefined` 433 | if (this.state.interpolators[activeItem]) { 434 | animations.push(this._getSlideAnimation(activeItem, 0)); 435 | } 436 | if (this.state.interpolators[newActiveItem]) { 437 | animations.push(this._getSlideAnimation(newActiveItem, 1)); 438 | } 439 | Animated.parallel(animations, { stopTogether: false }).start(); 440 | } 441 | 442 | // When scrolling, we need to check that we are not "short snapping", 443 | // that the new slide is different from the very first one, 444 | // that we are scrolling to the relevant slide, 445 | // and that callback can be fired 446 | if (!enableMomentum && this._canFireCallback && !this._isShortSnapping && 447 | (this._scrollStartActive !== newActiveItem || !this._hasFiredEdgeItemCallback) && 448 | this._itemToSnapTo === newActiveItem) { 449 | this.setState({ activeItem: newActiveItem }, () => { 450 | this._onSnap(newActiveItem); 451 | }); 452 | } 453 | 454 | if (onScroll) { 455 | onScroll(event); 456 | } 457 | } 458 | 459 | _onTouchStart () { 460 | // `onTouchStart` is fired even when `scrollEnabled` is set to `false` 461 | if (this.props.scrollEnabled !== false && this._autoplaying) { 462 | this.stopAutoplay(); 463 | } 464 | } 465 | 466 | // Used when `enableSnap` is ENABLED 467 | _onScrollBeginDrag (event) { 468 | const { onScrollBeginDrag } = this.props; 469 | 470 | this._scrollStartOffset = this._getScrollOffset(event); 471 | this._scrollStartActive = this._getActiveItem(this._scrollStartOffset); 472 | this._ignoreNextMomentum = false; 473 | this._canFireCallback = false; 474 | 475 | if (onScrollBeginDrag) { 476 | onScrollBeginDrag(event); 477 | } 478 | } 479 | 480 | // Used when `enableMomentum` is DISABLED 481 | _onScrollEndDrag (event) { 482 | const { onScrollEndDrag } = this.props; 483 | 484 | // event.persist(); // See https://stackoverflow.com/a/24679479 485 | this._onScrollEndDragDebounced(); 486 | 487 | if (onScrollEndDrag) { 488 | onScrollEndDrag(event); 489 | } 490 | } 491 | 492 | _onScrollEndDragDebounced (event) { 493 | if (this._flatlist && this._onScrollEnd) { 494 | this._onScrollEnd(); 495 | } 496 | } 497 | 498 | // Used when `enableMomentum` is ENABLED 499 | _onMomentumScrollEnd (event) { 500 | const { onMomentumScrollEnd } = this.props; 501 | 502 | if (this._flatlist && this._onScrollEnd) { 503 | this._onScrollEnd(); 504 | } 505 | 506 | if (onMomentumScrollEnd) { 507 | onMomentumScrollEnd(event); 508 | } 509 | } 510 | 511 | _onScrollEnd (event) { 512 | const { autoplay } = this.props; 513 | 514 | if (this._ignoreNextMomentum) { 515 | // iOS fix 516 | this._ignoreNextMomentum = false; 517 | return; 518 | } 519 | 520 | this._scrollEndOffset = this._currentContentOffset; 521 | this._scrollEndActive = this._getActiveItem(this._scrollEndOffset); 522 | 523 | if (this._snapEnabled) { 524 | const delta = this._scrollEndOffset - this._scrollStartOffset; 525 | this._snapScroll(delta); 526 | } 527 | 528 | if (autoplay) { 529 | // Restart autoplay after a little while 530 | // This could be done when releasing touch 531 | // but the event is buggy on Android... 532 | // https://github.com/facebook/react-native/issues/9439 533 | clearTimeout(this._enableAutoplayTimeout); 534 | this._enableAutoplayTimeout = setTimeout(() => { 535 | this.startAutoplay(); 536 | }, 300); 537 | } 538 | } 539 | 540 | // Due to a bug, this event is only fired on iOS 541 | // https://github.com/facebook/react-native/issues/6791 542 | // it's fine since we're only fixing an iOS bug in it, so ... 543 | _onTouchRelease (event) { 544 | if (this.props.enableMomentum && Platform.OS === 'ios') { 545 | clearTimeout(this._snapNoMomentumTimeout); 546 | this._snapNoMomentumTimeout = setTimeout(() => { 547 | this.snapToItem(this.currentIndex); 548 | }, 100); 549 | } 550 | } 551 | 552 | _onLayout (event) { 553 | const { onLayout } = this.props; 554 | 555 | this._calcCardPositions(); 556 | this.snapToItem(this.currentIndex, false, false); 557 | 558 | if (onLayout) { 559 | onLayout(event); 560 | } 561 | } 562 | 563 | _snapScroll (delta) { 564 | const { swipeThreshold, vertical } = this.props; 565 | 566 | // When using momentum and releasing the touch with 567 | // no velocity, scrollEndActive will be undefined (iOS) 568 | if (!this._scrollEndActive && this._scrollEndActive !== 0 && Platform.OS === 'ios') { 569 | this._scrollEndActive = this._scrollStartActive; 570 | } 571 | 572 | if (this._scrollStartActive !== this._scrollEndActive) { 573 | // Flag necessary in order to fire the callback 574 | // at the right time in `_onScroll()` 575 | this._isShortSnapping = false; 576 | 577 | // Snap to the new active item 578 | this.snapToItem(this._scrollEndActive); 579 | } else { 580 | this._isShortSnapping = true; 581 | 582 | // Snap depending on delta 583 | if (delta > 0) { 584 | if (delta > swipeThreshold) { 585 | if (IS_RTL && !vertical) { 586 | this.snapToItem(this._scrollStartActive - 1); 587 | } else { 588 | this.snapToItem(this._scrollStartActive + 1); 589 | } 590 | } else { 591 | this.snapToItem(this._scrollEndActive); 592 | } 593 | } else if (delta < 0) { 594 | if (delta < -swipeThreshold) { 595 | if (IS_RTL && !vertical) { 596 | this.snapToItem(this._scrollStartActive + 1); 597 | } else { 598 | this.snapToItem(this._scrollStartActive - 1); 599 | } 600 | } else { 601 | this.snapToItem(this._scrollEndActive); 602 | } 603 | } else { 604 | // Snap to current 605 | this.snapToItem(this._scrollEndActive); 606 | } 607 | } 608 | } 609 | 610 | _onSnap (index) { 611 | const { data, enableMomentum, onSnapToItem } = this.props; 612 | const itemsLength = data.length; 613 | 614 | if (this._flatlist) { 615 | if (enableMomentum) { 616 | onSnapToItem && onSnapToItem(index); 617 | } else if (this._canFireCallback) { 618 | this._canFireCallback = false; 619 | 620 | if (index === 0 || index === itemsLength - 1) { 621 | this._hasFiredEdgeItemCallback = true; 622 | } 623 | 624 | onSnapToItem && onSnapToItem(index); 625 | } 626 | } 627 | } 628 | 629 | startAutoplay () { 630 | const { autoplayInterval, autoplayDelay } = this.props; 631 | 632 | if (this._autoplaying) { 633 | return; 634 | } 635 | 636 | clearTimeout(this._autoplayTimeout); 637 | this._autoplayTimeout = setTimeout(() => { 638 | this._autoplaying = true; 639 | this._autoplayInterval = setInterval(() => { 640 | if (this._autoplaying) { 641 | this.snapToNext(); 642 | } 643 | }, autoplayInterval); 644 | }, autoplayDelay); 645 | } 646 | 647 | stopAutoplay () { 648 | this._autoplaying = false; 649 | clearInterval(this._autoplayInterval); 650 | } 651 | 652 | snapToItem (index, animated = true, fireCallback = true, initial = false) { 653 | const { previousActiveItem } = this.state; 654 | const { data, enableMomentum, scrollEndDragDebounceValue } = this.props; 655 | const itemsLength = data.length; 656 | 657 | if (!itemsLength) { 658 | return; 659 | } 660 | 661 | if (!index) { 662 | index = 0; 663 | } 664 | 665 | if (itemsLength > 0 && index >= itemsLength) { 666 | index = itemsLength - 1; 667 | this._isShortSnapping = false; // prevent issue #105 668 | if (this._scrollStartActive === itemsLength - 1 && this._hasFiredEdgeItemCallback) { 669 | fireCallback = false; 670 | } 671 | } else if (index < 0) { 672 | index = 0; 673 | this._isShortSnapping = false; // prevent issue #105 674 | if (this._scrollStartActive === 0 && this._hasFiredEdgeItemCallback) { 675 | fireCallback = false; 676 | } 677 | } else if (enableMomentum && index === previousActiveItem) { 678 | fireCallback = false; 679 | } 680 | 681 | // Make sure the component hasn't been unmounted 682 | if (this._flatlist) { 683 | if (enableMomentum) { 684 | this.setState({ previousActiveItem: index }); 685 | // Callback can be fired here when relying on 'onMomentumScrollEnd' 686 | if (fireCallback) { 687 | this._onSnap(index); 688 | } 689 | } else { 690 | // `_onScrollEndDragDebounced()` might occur when "peaking" to another item 691 | // Therefore we need to make sure that callback is fired when scrolling 692 | // back to the right one 693 | this._itemToSnapTo = index; 694 | 695 | // Callback needs to be fired while scrolling when relying on 'onScrollEndDrag' 696 | // Thus we need a flag on top of the debounce function to call it only once 697 | this._canFireCallback = this.props.onSnapToItem && fireCallback; 698 | 699 | // If user has scrolled to an edge item before the end of `scrollEndDragDebounceValue` 700 | // `onScroll()` won't be triggered and callback is not going to be fired 701 | // So we check if scroll position has been updated after a small delay and, 702 | // if not, it's safe to assume that callback should be called 703 | const scrollPosition = this._currentContentOffset; 704 | clearTimeout(this._scrollToTimeout); 705 | this._scrollToTimeout = setTimeout(() => { 706 | if (scrollPosition === this._currentContentOffset && this._canFireCallback) { 707 | this._onSnap(index); 708 | } 709 | }, Math.max(500, scrollEndDragDebounceValue + 50)); 710 | } 711 | 712 | // Unfortunately, 'viewPosition' is quite buggy at the moment 713 | // Moreover, 'viewOffset' just doesn't work on Android 714 | // const viewOffset = this._getItemOffset(index); 715 | // let viewPosition = 0.5; 716 | // if (activeSlideAlignment === 'start') { 717 | // viewPosition = IS_RTL ? 1 : 0; 718 | // } else if (activeSlideAlignment === 'end') { 719 | // viewPosition = IS_RTL ? 0 : 1; 720 | // } 721 | 722 | this._flatlist.scrollToIndex({ 723 | index, 724 | viewPosition: 0, 725 | viewOffset: 0, 726 | animated 727 | }); 728 | 729 | // iOS fix, check the note in the constructor 730 | if (!initial && Platform.OS === 'ios') { 731 | this._ignoreNextMomentum = true; 732 | } 733 | } 734 | } 735 | 736 | snapToNext (animated = true) { 737 | const itemsLength = this.props.data.length; 738 | 739 | let newIndex = this.currentIndex + 1; 740 | if (newIndex > itemsLength - 1) { 741 | newIndex = 0; 742 | } 743 | this.snapToItem(newIndex, animated); 744 | } 745 | 746 | snapToPrev (animated = true) { 747 | const itemsLength = this.props.data.length; 748 | 749 | let newIndex = this.currentIndex - 1; 750 | if (newIndex < 0) { 751 | newIndex = itemsLength - 1; 752 | } 753 | this.snapToItem(newIndex, animated); 754 | } 755 | 756 | _renderItem ({ item, index }) { 757 | const { interpolators } = this.state; 758 | const { 759 | renderItem, 760 | sliderWidth, 761 | sliderHeight, 762 | itemWidth, 763 | itemHeight, 764 | slideStyle, 765 | inactiveSlideScale, 766 | inactiveSlideOpacity, 767 | vertical, 768 | hasParallaxImages 769 | } = this.props; 770 | 771 | const animatedValue = interpolators && interpolators[index]; 772 | 773 | if (!animatedValue || !animatedValue.opacity || !animatedValue.scale) { 774 | return false; 775 | } 776 | 777 | const animatedStyle = { 778 | opacity: animatedValue.opacity.interpolate({ 779 | inputRange: [0, 1], 780 | outputRange: [inactiveSlideOpacity, 1] 781 | }), 782 | transform: [{ 783 | scale: animatedValue.scale.interpolate({ 784 | inputRange: [0, 1], 785 | outputRange: [inactiveSlideScale, 1] 786 | }) 787 | }] 788 | }; 789 | 790 | const parallaxProps = hasParallaxImages ? { 791 | scrollPosition: this._scrollPos, 792 | carouselRef: this._flatlist, 793 | vertical, 794 | sliderWidth, 795 | sliderHeight, 796 | itemWidth, 797 | itemHeight 798 | } : undefined; 799 | 800 | return ( 801 | 802 | { renderItem({ item, index }, parallaxProps) } 803 | 804 | ); 805 | } 806 | 807 | render () { 808 | const { hideCarousel } = this.state; 809 | const { 810 | containerCustomStyle, 811 | contentContainerCustomStyle, 812 | data, 813 | enableMomentum, 814 | firstItem, 815 | hasParallaxImages, 816 | itemWidth, 817 | itemHeight, 818 | keyExtractor, 819 | renderItem, 820 | sliderWidth, 821 | sliderHeight, 822 | useNativeOnScroll, 823 | vertical 824 | } = this.props; 825 | 826 | if (!data || !renderItem) { 827 | return false; 828 | } 829 | 830 | const wrapList = useNativeOnScroll || hasParallaxImages; 831 | const Component = wrapList ? AnimatedFlatList : FlatList; 832 | 833 | const style = [ 834 | containerCustomStyle || {}, 835 | hideCarousel ? { opacity: 0 } : {}, 836 | vertical ? 837 | { height: sliderHeight, flexDirection: 'column' } : 838 | // LTR hack; see https://github.com/facebook/react-native/issues/11960 839 | { width: sliderWidth, flexDirection: IS_RTL ? 'row-reverse' : 'row' } 840 | ]; 841 | const contentContainerStyle = [ 842 | contentContainerCustomStyle || {}, 843 | vertical ? { 844 | paddingTop: this._getContainerInnerMargin(), 845 | paddingBottom: this._getContainerInnerMargin(true) 846 | } : { 847 | paddingLeft: this._getContainerInnerMargin(), 848 | paddingRight: this._getContainerInnerMargin(true) 849 | } 850 | ]; 851 | 852 | const visibleItems = Math.ceil(vertical ? 853 | sliderHeight / itemHeight : 854 | sliderWidth / itemWidth) + 1; 855 | 856 | return ( 857 | { if (c) { this._flatlist = wrapList ? c._component : c; } }} 870 | data={data} 871 | renderItem={this._renderItem} 872 | // extraData={this.state} 873 | getItemLayout={this._getItemLayout} 874 | keyExtractor={keyExtractor || this._getKeyExtractor} 875 | initialScrollIndex={firstItem || undefined} 876 | numColumns={1} 877 | style={style} 878 | contentContainerStyle={contentContainerStyle} 879 | horizontal={!vertical} 880 | onScroll={this._onScrollHandler} 881 | onScrollBeginDrag={this._onScrollBeginDrag} 882 | onScrollEndDrag={this._onScrollEndDrag} 883 | onMomentumScrollEnd={this._onMomentumScrollEnd} 884 | onResponderRelease={this._onTouchRelease} 885 | onTouchStart={this._onTouchStart} 886 | onLayout={this._onLayout} 887 | /> 888 | ); 889 | } 890 | } 891 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Carousel from './carousel/Carousel'; 2 | import Pagination from './pagination/Pagination'; 3 | import ParallaxImage from './parallaximage/ParallaxImage'; 4 | 5 | export { Carousel as default, Pagination, ParallaxImage }; 6 | -------------------------------------------------------------------------------- /src/pagination/Pagination.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, ViewPropTypes } from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import PaginationDot from './PaginationDot'; 5 | import styles from './Pagination.style'; 6 | 7 | export default class Pagination extends Component { 8 | 9 | static propTypes = { 10 | dotsLength: PropTypes.number.isRequired, 11 | activeDotIndex: PropTypes.number.isRequired, 12 | containerStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 13 | dotStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 14 | inactiveDotStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 15 | inactiveDotOpacity: PropTypes.number, 16 | inactiveDotScale: PropTypes.number 17 | }; 18 | 19 | get dots () { 20 | const { 21 | dotsLength, 22 | activeDotIndex, 23 | dotStyle, 24 | inactiveDotStyle, 25 | inactiveDotOpacity, 26 | inactiveDotScale 27 | } = this.props; 28 | 29 | let dots = []; 30 | 31 | for (let i = 0; i < dotsLength; i++) { 32 | dots.push( 33 | 41 | ); 42 | } 43 | 44 | return dots; 45 | } 46 | 47 | render () { 48 | const { dotsLength, containerStyle } = this.props; 49 | 50 | if (!dotsLength || dotsLength < 2) { 51 | return false; 52 | } 53 | 54 | return ( 55 | 59 | { this.dots } 60 | 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pagination/Pagination.style.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | const DEFAULT_DOT_SIZE = 7; 4 | const DEFAULT_DOT_COLOR = 'rgba(0, 0, 0, 0.75)'; 5 | 6 | export default StyleSheet.create({ 7 | sliderPagination: { 8 | flexDirection: 'row', 9 | alignItems: 'center', 10 | justifyContent: 'center', 11 | paddingHorizontal: 20, 12 | paddingVertical: 30 13 | }, 14 | sliderPaginationDot: { 15 | width: DEFAULT_DOT_SIZE, 16 | height: DEFAULT_DOT_SIZE, 17 | borderRadius: DEFAULT_DOT_SIZE / 2, 18 | marginHorizontal: 8, 19 | backgroundColor: DEFAULT_DOT_COLOR 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /src/pagination/PaginationDot.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, Animated, Easing, ViewPropTypes } from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import styles from './Pagination.style'; 5 | 6 | export default class PaginationDot extends Component { 7 | 8 | static propTypes = { 9 | active: PropTypes.bool, 10 | style: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 11 | inactiveStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 12 | inactiveOpacity: PropTypes.number, 13 | inactiveScale: PropTypes.number 14 | }; 15 | 16 | static defaultProps = { 17 | inactiveOpacity: 0.5, 18 | inactiveScale: 0.5 19 | } 20 | 21 | constructor (props) { 22 | super(props); 23 | this.state = { 24 | animOpacity: new Animated.Value(0), 25 | animTransform: new Animated.Value(0) 26 | }; 27 | } 28 | 29 | componentDidMount () { 30 | if (this.props.active) { 31 | this._animate(1); 32 | } 33 | } 34 | 35 | componentWillReceiveProps (nextProps) { 36 | if (nextProps.active !== this.props.active) { 37 | this._animate(nextProps.active ? 1 : 0); 38 | } 39 | } 40 | 41 | _animate (toValue = 0) { 42 | const { animOpacity, animTransform } = this.state; 43 | 44 | Animated.parallel([ 45 | Animated.timing(animOpacity, { 46 | toValue, 47 | duration: 250, 48 | easing: Easing.linear, 49 | isInteraction: false, 50 | useNativeDriver: true 51 | }), 52 | Animated.spring(animTransform, { 53 | toValue, 54 | friction: 4, 55 | tension: 50, 56 | isInteraction: false, 57 | useNativeDriver: true 58 | }) 59 | ]).start(); 60 | } 61 | 62 | render () { 63 | const { animOpacity, animTransform } = this.state; 64 | const { active, style, inactiveStyle, inactiveOpacity, inactiveScale } = this.props; 65 | 66 | const animatedStyle = { 67 | opacity: animOpacity.interpolate({ 68 | inputRange: [0, 1], 69 | outputRange: [inactiveOpacity, 1] 70 | }), 71 | transform: [{ 72 | scale: animTransform.interpolate({ 73 | inputRange: [0, 1], 74 | outputRange: [inactiveScale, 1] 75 | }) 76 | }] 77 | }; 78 | const dotStyle = [ 79 | styles.sliderPaginationDot, 80 | style || {}, 81 | (!active && inactiveStyle) || {}, 82 | animatedStyle 83 | ]; 84 | 85 | return ( 86 | 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/pagination/README.md: -------------------------------------------------------------------------------- 1 | # `` component 2 | 3 | Starting with version `2.4.0`, a customizable `` component has been added. This is how it looks like with its default configuration: 4 | 5 | ![react-native-snap-carousel pagination](http://i.imgur.com/FLQcGGL.gif) 6 | 7 | ## Props 8 | 9 | Prop | Description | Type | Default 10 | ------ | ------ | ------ | ------ 11 | dotsLength | Number of dots to display | Number | **Required** 12 | activeDotIndex | Currently focused dot | Number | **Required** 13 | containerStyle | Style for dots' container that will be merged with the default one | View Style Object | `{}` 14 | dotStyle | Dots' style that will be merged with the default one | View Style Object | `{}` 15 | inactiveDotStyle | Dots' style that will be applied to inactive elements | View Style Object | `{}` 16 | inactiveDotOpacity | Value of the opacity effect applied to inactive dots | Number | `0.5` 17 | inactiveDotScale | Value of the 'scale' transform applied to inactive dots | Number | `0.5` 18 | 19 | ## Usage 20 | 21 | Since `` is, purposely, a separated component, you need to connect it to your `` component manually. This is pretty straightforward, but here is an example to get you started. 22 | 23 | ```javascript 24 | import Carousel, { Pagination } from 'react-native-snap-carousel'; 25 | 26 | export default class MyCarousel extends Component { 27 | 28 | _renderItem ({item, index}) { 29 | return 30 | } 31 | 32 | get pagination () { 33 | const { entries, activeSlide } = this.state; 34 | return ( 35 | 52 | ); 53 | } 54 | 55 | render () { 56 | return ( 57 | 58 | this.setState({ activeSlide: index }) } 62 | /> 63 | { this.pagination } 64 | 65 | ); 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /src/parallaximage/ParallaxImage.js: -------------------------------------------------------------------------------- 1 | // Parallax effect inspired by https://github.com/oblador/react-native-parallax/ 2 | 3 | import React, { Component } from 'react'; 4 | import { View, ViewPropTypes, Image, Animated, Easing, ActivityIndicator, findNodeHandle } from 'react-native'; 5 | import PropTypes from 'prop-types'; 6 | import styles from './ParallaxImage.style'; 7 | 8 | export default class ParallaxImage extends Component { 9 | 10 | static propTypes = { 11 | ...Image.propTypes, 12 | carouselRef: PropTypes.object, // passed from 13 | itemHeight: PropTypes.number, // passed from 14 | itemWidth: PropTypes.number, // passed from 15 | scrollPosition: PropTypes.object, // passed from 16 | sliderHeight: PropTypes.number, // passed from 17 | sliderWidth: PropTypes.number, // passed from 18 | vertical: PropTypes.bool, // passed from 19 | containerStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style, 20 | dimensions: PropTypes.shape({ 21 | width: PropTypes.number, 22 | height: PropTypes.number 23 | }), 24 | fadeDuration: PropTypes.number, 25 | parallaxFactor: PropTypes.number, 26 | showSpinner: PropTypes.bool, 27 | spinnerColor: PropTypes.string 28 | }; 29 | 30 | static defaultProps = { 31 | containerStyle: {}, 32 | fadeDuration: 500, 33 | parallaxFactor: 0.3, 34 | showSpinner: true, 35 | spinnerColor: 'rgba(0, 0, 0, 0.4)' 36 | } 37 | 38 | constructor (props) { 39 | super(props); 40 | this.state = { 41 | offset: 0, 42 | width: 0, 43 | height: 0, 44 | status: 1, // 1 -> loading; 2 -> loaded // 3 -> transition finished; 4 -> error 45 | animOpacity: new Animated.Value(0) 46 | }; 47 | this._onLoad = this._onLoad.bind(this); 48 | this._onError = this._onError.bind(this); 49 | } 50 | 51 | setNativeProps (nativeProps) { 52 | this._container.setNativeProps(nativeProps); 53 | } 54 | 55 | componentDidMount () { 56 | this._mounted = true; 57 | 58 | setTimeout(() => { 59 | this._measureLayout(); 60 | }, 0); 61 | } 62 | 63 | componentWillUnmount () { 64 | this._mounted = false; 65 | } 66 | 67 | _measureLayout () { 68 | if (this._container) { 69 | const { 70 | dimensions, 71 | vertical, 72 | carouselRef, 73 | sliderWidth, 74 | sliderHeight, 75 | itemWidth, 76 | itemHeight 77 | } = this.props; 78 | 79 | if (carouselRef) { 80 | this._container.measureLayout( 81 | findNodeHandle(carouselRef), 82 | (x, y, width, height, pageX, pageY) => { 83 | const offset = vertical ? 84 | y - ((sliderHeight - itemHeight) / 2) : 85 | x - ((sliderWidth - itemWidth) / 2); 86 | 87 | this.setState({ 88 | offset: offset, 89 | width: dimensions && dimensions.width ? 90 | dimensions.width : 91 | Math.ceil(width), 92 | height: dimensions && dimensions.height ? 93 | dimensions.height : 94 | Math.ceil(height) 95 | }); 96 | } 97 | ); 98 | } 99 | } 100 | } 101 | 102 | _onLoad (event) { 103 | const { animOpacity } = this.state; 104 | const { fadeDuration, onLoad } = this.props; 105 | 106 | if (!this._mounted) { 107 | return; 108 | } 109 | 110 | this.setState({ status: 2 }); 111 | 112 | if (onLoad) { 113 | onLoad(event); 114 | } 115 | 116 | Animated.timing(animOpacity, { 117 | toValue: 1, 118 | duration: fadeDuration, 119 | easing: Easing.out(Easing.quad), 120 | isInteraction: false, 121 | useNativeDriver: true 122 | }).start(() => { 123 | this.setState({ status: 3 }); 124 | }); 125 | } 126 | 127 | // If arg is missing from method signature, it just won't be called 128 | _onError (event) { 129 | const { onError } = this.props; 130 | 131 | this.setState({ status: 4 }); 132 | 133 | if (onError) { 134 | onError(event); 135 | } 136 | } 137 | 138 | get image () { 139 | const { status, animOpacity, offset, width, height } = this.state; 140 | const { 141 | scrollPosition, 142 | dimensions, 143 | vertical, 144 | sliderWidth, 145 | sliderHeight, 146 | parallaxFactor, 147 | style, 148 | ...other 149 | } = this.props; 150 | 151 | const parallaxPadding = (vertical ? height : width) * parallaxFactor; 152 | const dynamicStyles = { 153 | width: vertical ? width : width + parallaxPadding * 2, 154 | height: vertical ? height + parallaxPadding * 2 : height, 155 | opacity: animOpacity, 156 | transform: scrollPosition ? [ 157 | { 158 | translateX: !vertical ? scrollPosition.interpolate({ 159 | inputRange: [offset - sliderWidth, offset + sliderWidth], 160 | outputRange: [-parallaxPadding, parallaxPadding], 161 | extrapolate: 'clamp' 162 | }) : 0 163 | }, 164 | { 165 | translateY: vertical ? scrollPosition.interpolate({ 166 | inputRange: [offset - sliderHeight, offset + sliderHeight], 167 | outputRange: [-parallaxPadding, parallaxPadding], 168 | extrapolate: 'clamp' 169 | }) : 0 170 | } 171 | ] : [] 172 | }; 173 | 174 | return ( 175 | 181 | ); 182 | } 183 | 184 | get spinner () { 185 | const { status } = this.state; 186 | const { showSpinner, spinnerColor } = this.props; 187 | 188 | return status === 1 && showSpinner ? ( 189 | 190 | 195 | 196 | ) : false; 197 | } 198 | 199 | render () { 200 | const { containerStyle } = this.props; 201 | 202 | return ( 203 | { this._container = c; }} 205 | pointerEvents={'none'} 206 | style={[containerStyle, styles.container]} 207 | onLayout={this._measureLayout} 208 | > 209 | { this.image } 210 | { this.spinner } 211 | 212 | ); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/parallaximage/ParallaxImage.style.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | container: { 5 | overflow: 'hidden', 6 | alignItems: 'center', 7 | justifyContent: 'center' 8 | }, 9 | image: { 10 | position: 'relative', 11 | resizeMode: 'cover', 12 | width: null, 13 | height: null 14 | }, 15 | loaderContainer: { 16 | ...StyleSheet.absoluteFillObject, 17 | alignItems: 'center', 18 | justifyContent: 'center' 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/parallaximage/README.md: -------------------------------------------------------------------------------- 1 | # `` component 2 | 3 | Version `3.0.0` introduced a `` component, an image component aware of carousel's current scroll position and therefore able to display a nice parallax effect. 4 | 5 | ![react-native-snap-carousel parallax image](http://i.imgur.com/6iIb4SR.gif) 6 | 7 | ## Props 8 | 9 | Prop | Description | Type | Default 10 | ------ | ------ | ------ | ------ 11 | containerStyle | Optional style for image's container | View Style Object | `{}` 12 | dimensions | Optional on-screen dimensions of the image, as measured with [native methods](https://facebook.github.io/react-native/docs/direct-manipulation.html#other-native-methods). This allows for a bit of optimization, but it's sometimes tricky to get these in responsive layouts. | `{ width: number, height: number }` | `undefined` 13 | fadeDuration | Duration of the fade-in effect when image is loaded | Number | `500` 14 | parallaxFactor | Speed of the parallax effect. Be aware that the bigger the value, the more image will appear "zoomed in". | Number | `0.3` 15 | showSpinner | Whether to display a spinner while image is loading or not | Boolean | `true` 16 | spinnerColor | Color of the spinner | String | 'rgba(0, 0, 0, 0.4)' 17 | 18 | All [`` props](https://facebook.github.io/react-native/docs/image.html#props) are also inherited, **particularly `source` which is required**. 19 | 20 | ## Usage 21 | 22 | The first thing you need to do is to **set `hasParallaxImages` to `true` on your ``**. This has two consequences: 23 | - migrating scroll events to the native driver for top-notch performances 24 | - your custom `renderItem` function now has access to a second argument that must be passed to the ``. 25 | 26 | Here is an example that shows how to connect images to your carousel (note the `parallaxProps` argument). 27 | 28 | ```javascript 29 | import Carousel, { ParallaxImage } from 'react-native-snap-carousel'; 30 | 31 | export default class MyCarousel extends Component { 32 | 33 | _renderItem ({item, index}, parallaxProps) { 34 | return ( 35 | 36 | 43 | 44 | { item.title } 45 | 46 | 47 | ); 48 | } 49 | 50 | render () { 51 | return ( 52 | 57 | ); 58 | } 59 | ``` 60 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | acorn-jsx@^3.0.0: 6 | version "3.0.1" 7 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" 8 | dependencies: 9 | acorn "^3.0.4" 10 | 11 | acorn@^3.0.4: 12 | version "3.3.0" 13 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" 14 | 15 | acorn@^5.0.1: 16 | version "5.0.3" 17 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" 18 | 19 | ajv-keywords@^1.0.0: 20 | version "1.1.1" 21 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.1.1.tgz#02550bc605a3e576041565628af972e06c549d50" 22 | 23 | ajv@^4.7.0: 24 | version "4.9.0" 25 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.9.0.tgz#5a358085747b134eb567d6d15e015f1d7802f45c" 26 | dependencies: 27 | co "^4.6.0" 28 | json-stable-stringify "^1.0.1" 29 | 30 | ansi-escapes@^1.1.0: 31 | version "1.4.0" 32 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" 33 | 34 | ansi-regex@^2.0.0: 35 | version "2.0.0" 36 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" 37 | 38 | ansi-styles@^2.2.1: 39 | version "2.2.1" 40 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 41 | 42 | argparse@^1.0.7: 43 | version "1.0.9" 44 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 45 | dependencies: 46 | sprintf-js "~1.0.2" 47 | 48 | array-union@^1.0.1: 49 | version "1.0.2" 50 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 51 | dependencies: 52 | array-uniq "^1.0.1" 53 | 54 | array-uniq@^1.0.1: 55 | version "1.0.3" 56 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 57 | 58 | arrify@^1.0.0: 59 | version "1.0.1" 60 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 61 | 62 | asap@~2.0.3: 63 | version "2.0.5" 64 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" 65 | 66 | babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: 67 | version "6.22.0" 68 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" 69 | dependencies: 70 | chalk "^1.1.0" 71 | esutils "^2.0.2" 72 | js-tokens "^3.0.0" 73 | 74 | babel-eslint@^7.2.3: 75 | version "7.2.3" 76 | resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" 77 | dependencies: 78 | babel-code-frame "^6.22.0" 79 | babel-traverse "^6.23.1" 80 | babel-types "^6.23.0" 81 | babylon "^6.17.0" 82 | 83 | babel-messages@^6.23.0: 84 | version "6.23.0" 85 | resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" 86 | dependencies: 87 | babel-runtime "^6.22.0" 88 | 89 | babel-runtime@^6.22.0: 90 | version "6.23.0" 91 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" 92 | dependencies: 93 | core-js "^2.4.0" 94 | regenerator-runtime "^0.10.0" 95 | 96 | babel-traverse@^6.23.1: 97 | version "6.24.1" 98 | resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" 99 | dependencies: 100 | babel-code-frame "^6.22.0" 101 | babel-messages "^6.23.0" 102 | babel-runtime "^6.22.0" 103 | babel-types "^6.24.1" 104 | babylon "^6.15.0" 105 | debug "^2.2.0" 106 | globals "^9.0.0" 107 | invariant "^2.2.0" 108 | lodash "^4.2.0" 109 | 110 | babel-types@^6.23.0, babel-types@^6.24.1: 111 | version "6.24.1" 112 | resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" 113 | dependencies: 114 | babel-runtime "^6.22.0" 115 | esutils "^2.0.2" 116 | lodash "^4.2.0" 117 | to-fast-properties "^1.0.1" 118 | 119 | babylon@^6.15.0, babylon@^6.17.0: 120 | version "6.17.2" 121 | resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.2.tgz#201d25ef5f892c41bae49488b08db0dd476e9f5c" 122 | 123 | balanced-match@^0.4.1: 124 | version "0.4.2" 125 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 126 | 127 | brace-expansion@^1.0.0: 128 | version "1.1.6" 129 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 130 | dependencies: 131 | balanced-match "^0.4.1" 132 | concat-map "0.0.1" 133 | 134 | brace-expansion@^1.1.7: 135 | version "1.1.7" 136 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" 137 | dependencies: 138 | balanced-match "^0.4.1" 139 | concat-map "0.0.1" 140 | 141 | builtin-modules@^1.0.0, builtin-modules@^1.1.1: 142 | version "1.1.1" 143 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 144 | 145 | caller-path@^0.1.0: 146 | version "0.1.0" 147 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" 148 | dependencies: 149 | callsites "^0.2.0" 150 | 151 | callsites@^0.2.0: 152 | version "0.2.0" 153 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" 154 | 155 | chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: 156 | version "1.1.3" 157 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 158 | dependencies: 159 | ansi-styles "^2.2.1" 160 | escape-string-regexp "^1.0.2" 161 | has-ansi "^2.0.0" 162 | strip-ansi "^3.0.0" 163 | supports-color "^2.0.0" 164 | 165 | circular-json@^0.3.0: 166 | version "0.3.1" 167 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" 168 | 169 | cli-cursor@^1.0.1: 170 | version "1.0.2" 171 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" 172 | dependencies: 173 | restore-cursor "^1.0.1" 174 | 175 | cli-width@^2.0.0: 176 | version "2.1.0" 177 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" 178 | 179 | co@^4.6.0: 180 | version "4.6.0" 181 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 182 | 183 | code-point-at@^1.0.0: 184 | version "1.1.0" 185 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 186 | 187 | concat-map@0.0.1: 188 | version "0.0.1" 189 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 190 | 191 | concat-stream@^1.5.2: 192 | version "1.6.0" 193 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" 194 | dependencies: 195 | inherits "^2.0.3" 196 | readable-stream "^2.2.2" 197 | typedarray "^0.0.6" 198 | 199 | contains-path@^0.1.0: 200 | version "0.1.0" 201 | resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" 202 | 203 | core-js@^1.0.0: 204 | version "1.2.7" 205 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" 206 | 207 | core-js@^2.4.0: 208 | version "2.4.1" 209 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" 210 | 211 | core-util-is@~1.0.0: 212 | version "1.0.2" 213 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 214 | 215 | d@^0.1.1, d@~0.1.1: 216 | version "0.1.1" 217 | resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" 218 | dependencies: 219 | es5-ext "~0.10.2" 220 | 221 | debug@2.2.0: 222 | version "2.2.0" 223 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 224 | dependencies: 225 | ms "0.7.1" 226 | 227 | debug@^2.1.1, debug@^2.2.0: 228 | version "2.3.3" 229 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" 230 | dependencies: 231 | ms "0.7.2" 232 | 233 | deep-is@~0.1.3: 234 | version "0.1.3" 235 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 236 | 237 | del@^2.0.2: 238 | version "2.2.2" 239 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" 240 | dependencies: 241 | globby "^5.0.0" 242 | is-path-cwd "^1.0.0" 243 | is-path-in-cwd "^1.0.0" 244 | object-assign "^4.0.1" 245 | pify "^2.0.0" 246 | pinkie-promise "^2.0.0" 247 | rimraf "^2.2.8" 248 | 249 | doctrine@1.5.0: 250 | version "1.5.0" 251 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" 252 | dependencies: 253 | esutils "^2.0.2" 254 | isarray "^1.0.0" 255 | 256 | doctrine@^2.0.0: 257 | version "2.0.0" 258 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" 259 | dependencies: 260 | esutils "^2.0.2" 261 | isarray "^1.0.0" 262 | 263 | encoding@^0.1.11: 264 | version "0.1.12" 265 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 266 | dependencies: 267 | iconv-lite "~0.4.13" 268 | 269 | error-ex@^1.2.0: 270 | version "1.3.1" 271 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" 272 | dependencies: 273 | is-arrayish "^0.2.1" 274 | 275 | es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: 276 | version "0.10.12" 277 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" 278 | dependencies: 279 | es6-iterator "2" 280 | es6-symbol "~3.1" 281 | 282 | es6-iterator@2: 283 | version "2.0.0" 284 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" 285 | dependencies: 286 | d "^0.1.1" 287 | es5-ext "^0.10.7" 288 | es6-symbol "3" 289 | 290 | es6-map@^0.1.3: 291 | version "0.1.4" 292 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" 293 | dependencies: 294 | d "~0.1.1" 295 | es5-ext "~0.10.11" 296 | es6-iterator "2" 297 | es6-set "~0.1.3" 298 | es6-symbol "~3.1.0" 299 | event-emitter "~0.3.4" 300 | 301 | es6-set@~0.1.3: 302 | version "0.1.4" 303 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" 304 | dependencies: 305 | d "~0.1.1" 306 | es5-ext "~0.10.11" 307 | es6-iterator "2" 308 | es6-symbol "3" 309 | event-emitter "~0.3.4" 310 | 311 | es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: 312 | version "3.1.0" 313 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" 314 | dependencies: 315 | d "~0.1.1" 316 | es5-ext "~0.10.11" 317 | 318 | es6-weak-map@^2.0.1: 319 | version "2.0.1" 320 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" 321 | dependencies: 322 | d "^0.1.1" 323 | es5-ext "^0.10.8" 324 | es6-iterator "2" 325 | es6-symbol "3" 326 | 327 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 328 | version "1.0.5" 329 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 330 | 331 | escope@^3.6.0: 332 | version "3.6.0" 333 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" 334 | dependencies: 335 | es6-map "^0.1.3" 336 | es6-weak-map "^2.0.1" 337 | esrecurse "^4.1.0" 338 | estraverse "^4.1.1" 339 | 340 | eslint-config-standard-jsx@^4.0.0: 341 | version "4.0.1" 342 | resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.1.tgz#cd4e463d0268e2d9e707f61f42f73f5b3333c642" 343 | 344 | eslint-config-standard-react@^5.0.0: 345 | version "5.0.0" 346 | resolved "https://registry.yarnpkg.com/eslint-config-standard-react/-/eslint-config-standard-react-5.0.0.tgz#64c7b8140172852be810a53d48ee87649ff178e3" 347 | dependencies: 348 | eslint-config-standard-jsx "^4.0.0" 349 | 350 | eslint-config-standard@^10.2.1: 351 | version "10.2.1" 352 | resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" 353 | 354 | eslint-import-resolver-node@^0.2.0: 355 | version "0.2.3" 356 | resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" 357 | dependencies: 358 | debug "^2.2.0" 359 | object-assign "^4.0.1" 360 | resolve "^1.1.6" 361 | 362 | eslint-module-utils@^2.0.0: 363 | version "2.0.0" 364 | resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.0.0.tgz#a6f8c21d901358759cdc35dbac1982ae1ee58bce" 365 | dependencies: 366 | debug "2.2.0" 367 | pkg-dir "^1.0.0" 368 | 369 | eslint-plugin-import@^2.3.0: 370 | version "2.3.0" 371 | resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.3.0.tgz#37c801e0ada0e296cbdf20c3f393acb5b52af36b" 372 | dependencies: 373 | builtin-modules "^1.1.1" 374 | contains-path "^0.1.0" 375 | debug "^2.2.0" 376 | doctrine "1.5.0" 377 | eslint-import-resolver-node "^0.2.0" 378 | eslint-module-utils "^2.0.0" 379 | has "^1.0.1" 380 | lodash.cond "^4.3.0" 381 | minimatch "^3.0.3" 382 | read-pkg-up "^2.0.0" 383 | 384 | eslint-plugin-node@^5.0.0: 385 | version "5.0.0" 386 | resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.0.0.tgz#948b1fb82e3f0a744e86fad19aa4f49537d246cc" 387 | dependencies: 388 | ignore "^3.3.3" 389 | minimatch "^3.0.4" 390 | resolve "^1.3.3" 391 | semver "5.3.0" 392 | 393 | eslint-plugin-promise@^3.5.0: 394 | version "3.5.0" 395 | resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" 396 | 397 | eslint-plugin-react@^7.0.1: 398 | version "7.0.1" 399 | resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.0.1.tgz#e78107e1e559c6e2b17786bb67c2e2a010ad0d2f" 400 | dependencies: 401 | doctrine "^2.0.0" 402 | has "^1.0.1" 403 | jsx-ast-utils "^1.3.4" 404 | 405 | eslint-plugin-standard@^3.0.1: 406 | version "3.0.1" 407 | resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" 408 | 409 | eslint@^3.19.0: 410 | version "3.19.0" 411 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" 412 | dependencies: 413 | babel-code-frame "^6.16.0" 414 | chalk "^1.1.3" 415 | concat-stream "^1.5.2" 416 | debug "^2.1.1" 417 | doctrine "^2.0.0" 418 | escope "^3.6.0" 419 | espree "^3.4.0" 420 | esquery "^1.0.0" 421 | estraverse "^4.2.0" 422 | esutils "^2.0.2" 423 | file-entry-cache "^2.0.0" 424 | glob "^7.0.3" 425 | globals "^9.14.0" 426 | ignore "^3.2.0" 427 | imurmurhash "^0.1.4" 428 | inquirer "^0.12.0" 429 | is-my-json-valid "^2.10.0" 430 | is-resolvable "^1.0.0" 431 | js-yaml "^3.5.1" 432 | json-stable-stringify "^1.0.0" 433 | levn "^0.3.0" 434 | lodash "^4.0.0" 435 | mkdirp "^0.5.0" 436 | natural-compare "^1.4.0" 437 | optionator "^0.8.2" 438 | path-is-inside "^1.0.1" 439 | pluralize "^1.2.1" 440 | progress "^1.1.8" 441 | require-uncached "^1.0.2" 442 | shelljs "^0.7.5" 443 | strip-bom "^3.0.0" 444 | strip-json-comments "~2.0.1" 445 | table "^3.7.8" 446 | text-table "~0.2.0" 447 | user-home "^2.0.0" 448 | 449 | espree@^3.4.0: 450 | version "3.4.3" 451 | resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" 452 | dependencies: 453 | acorn "^5.0.1" 454 | acorn-jsx "^3.0.0" 455 | 456 | esprima@^2.6.0: 457 | version "2.7.3" 458 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 459 | 460 | esquery@^1.0.0: 461 | version "1.0.0" 462 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" 463 | dependencies: 464 | estraverse "^4.0.0" 465 | 466 | esrecurse@^4.1.0: 467 | version "4.1.0" 468 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" 469 | dependencies: 470 | estraverse "~4.1.0" 471 | object-assign "^4.0.1" 472 | 473 | estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0: 474 | version "4.2.0" 475 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 476 | 477 | estraverse@~4.1.0: 478 | version "4.1.1" 479 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" 480 | 481 | esutils@^2.0.2: 482 | version "2.0.2" 483 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 484 | 485 | event-emitter@~0.3.4: 486 | version "0.3.4" 487 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" 488 | dependencies: 489 | d "~0.1.1" 490 | es5-ext "~0.10.7" 491 | 492 | exit-hook@^1.0.0: 493 | version "1.1.1" 494 | resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" 495 | 496 | fast-levenshtein@~2.0.4: 497 | version "2.0.5" 498 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" 499 | 500 | fbjs@^0.8.4: 501 | version "0.8.12" 502 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04" 503 | dependencies: 504 | core-js "^1.0.0" 505 | isomorphic-fetch "^2.1.1" 506 | loose-envify "^1.0.0" 507 | object-assign "^4.1.0" 508 | promise "^7.1.1" 509 | setimmediate "^1.0.5" 510 | ua-parser-js "^0.7.9" 511 | 512 | figures@^1.3.5: 513 | version "1.7.0" 514 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 515 | dependencies: 516 | escape-string-regexp "^1.0.5" 517 | object-assign "^4.1.0" 518 | 519 | file-entry-cache@^2.0.0: 520 | version "2.0.0" 521 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" 522 | dependencies: 523 | flat-cache "^1.2.1" 524 | object-assign "^4.0.1" 525 | 526 | find-up@^1.0.0: 527 | version "1.1.2" 528 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 529 | dependencies: 530 | path-exists "^2.0.0" 531 | pinkie-promise "^2.0.0" 532 | 533 | find-up@^2.0.0: 534 | version "2.1.0" 535 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" 536 | dependencies: 537 | locate-path "^2.0.0" 538 | 539 | flat-cache@^1.2.1: 540 | version "1.2.1" 541 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" 542 | dependencies: 543 | circular-json "^0.3.0" 544 | del "^2.0.2" 545 | graceful-fs "^4.1.2" 546 | write "^0.2.1" 547 | 548 | fs.realpath@^1.0.0: 549 | version "1.0.0" 550 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 551 | 552 | function-bind@^1.0.2: 553 | version "1.1.0" 554 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" 555 | 556 | generate-function@^2.0.0: 557 | version "2.0.0" 558 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" 559 | 560 | generate-object-property@^1.1.0: 561 | version "1.2.0" 562 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 563 | dependencies: 564 | is-property "^1.0.0" 565 | 566 | glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: 567 | version "7.1.1" 568 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 569 | dependencies: 570 | fs.realpath "^1.0.0" 571 | inflight "^1.0.4" 572 | inherits "2" 573 | minimatch "^3.0.2" 574 | once "^1.3.0" 575 | path-is-absolute "^1.0.0" 576 | 577 | globals@^9.0.0, globals@^9.14.0: 578 | version "9.14.0" 579 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" 580 | 581 | globby@^5.0.0: 582 | version "5.0.0" 583 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" 584 | dependencies: 585 | array-union "^1.0.1" 586 | arrify "^1.0.0" 587 | glob "^7.0.3" 588 | object-assign "^4.0.1" 589 | pify "^2.0.0" 590 | pinkie-promise "^2.0.0" 591 | 592 | graceful-fs@^4.1.2: 593 | version "4.1.11" 594 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 595 | 596 | has-ansi@^2.0.0: 597 | version "2.0.0" 598 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 599 | dependencies: 600 | ansi-regex "^2.0.0" 601 | 602 | has@^1.0.1: 603 | version "1.0.1" 604 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" 605 | dependencies: 606 | function-bind "^1.0.2" 607 | 608 | hosted-git-info@^2.1.4: 609 | version "2.4.2" 610 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" 611 | 612 | iconv-lite@~0.4.13: 613 | version "0.4.17" 614 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d" 615 | 616 | ignore@^3.2.0: 617 | version "3.2.0" 618 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" 619 | 620 | ignore@^3.3.3: 621 | version "3.3.3" 622 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" 623 | 624 | imurmurhash@^0.1.4: 625 | version "0.1.4" 626 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 627 | 628 | inflight@^1.0.4: 629 | version "1.0.6" 630 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 631 | dependencies: 632 | once "^1.3.0" 633 | wrappy "1" 634 | 635 | inherits@2, inherits@^2.0.3, inherits@~2.0.1: 636 | version "2.0.3" 637 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 638 | 639 | inquirer@^0.12.0: 640 | version "0.12.0" 641 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" 642 | dependencies: 643 | ansi-escapes "^1.1.0" 644 | ansi-regex "^2.0.0" 645 | chalk "^1.0.0" 646 | cli-cursor "^1.0.1" 647 | cli-width "^2.0.0" 648 | figures "^1.3.5" 649 | lodash "^4.3.0" 650 | readline2 "^1.0.1" 651 | run-async "^0.1.0" 652 | rx-lite "^3.1.2" 653 | string-width "^1.0.1" 654 | strip-ansi "^3.0.0" 655 | through "^2.3.6" 656 | 657 | interpret@^1.0.0: 658 | version "1.0.1" 659 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" 660 | 661 | invariant@^2.2.0: 662 | version "2.2.2" 663 | resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" 664 | dependencies: 665 | loose-envify "^1.0.0" 666 | 667 | is-arrayish@^0.2.1: 668 | version "0.2.1" 669 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 670 | 671 | is-builtin-module@^1.0.0: 672 | version "1.0.0" 673 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" 674 | dependencies: 675 | builtin-modules "^1.0.0" 676 | 677 | is-fullwidth-code-point@^1.0.0: 678 | version "1.0.0" 679 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 680 | dependencies: 681 | number-is-nan "^1.0.0" 682 | 683 | is-fullwidth-code-point@^2.0.0: 684 | version "2.0.0" 685 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 686 | 687 | is-my-json-valid@^2.10.0: 688 | version "2.15.0" 689 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" 690 | dependencies: 691 | generate-function "^2.0.0" 692 | generate-object-property "^1.1.0" 693 | jsonpointer "^4.0.0" 694 | xtend "^4.0.0" 695 | 696 | is-path-cwd@^1.0.0: 697 | version "1.0.0" 698 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 699 | 700 | is-path-in-cwd@^1.0.0: 701 | version "1.0.0" 702 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" 703 | dependencies: 704 | is-path-inside "^1.0.0" 705 | 706 | is-path-inside@^1.0.0: 707 | version "1.0.0" 708 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" 709 | dependencies: 710 | path-is-inside "^1.0.1" 711 | 712 | is-property@^1.0.0: 713 | version "1.0.2" 714 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 715 | 716 | is-resolvable@^1.0.0: 717 | version "1.0.0" 718 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" 719 | dependencies: 720 | tryit "^1.0.1" 721 | 722 | is-stream@^1.0.1: 723 | version "1.1.0" 724 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 725 | 726 | isarray@^1.0.0, isarray@~1.0.0: 727 | version "1.0.0" 728 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 729 | 730 | isomorphic-fetch@^2.1.1: 731 | version "2.2.1" 732 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" 733 | dependencies: 734 | node-fetch "^1.0.1" 735 | whatwg-fetch ">=0.10.0" 736 | 737 | js-tokens@^2.0.0: 738 | version "2.0.0" 739 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" 740 | 741 | js-tokens@^3.0.0: 742 | version "3.0.1" 743 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" 744 | 745 | js-yaml@^3.5.1: 746 | version "3.7.0" 747 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" 748 | dependencies: 749 | argparse "^1.0.7" 750 | esprima "^2.6.0" 751 | 752 | json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: 753 | version "1.0.1" 754 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 755 | dependencies: 756 | jsonify "~0.0.0" 757 | 758 | jsonify@~0.0.0: 759 | version "0.0.0" 760 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 761 | 762 | jsonpointer@^4.0.0: 763 | version "4.0.0" 764 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" 765 | 766 | jsx-ast-utils@^1.3.4: 767 | version "1.4.1" 768 | resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" 769 | 770 | levn@^0.3.0, levn@~0.3.0: 771 | version "0.3.0" 772 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 773 | dependencies: 774 | prelude-ls "~1.1.2" 775 | type-check "~0.3.2" 776 | 777 | load-json-file@^2.0.0: 778 | version "2.0.0" 779 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" 780 | dependencies: 781 | graceful-fs "^4.1.2" 782 | parse-json "^2.2.0" 783 | pify "^2.0.0" 784 | strip-bom "^3.0.0" 785 | 786 | locate-path@^2.0.0: 787 | version "2.0.0" 788 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" 789 | dependencies: 790 | p-locate "^2.0.0" 791 | path-exists "^3.0.0" 792 | 793 | lodash.cond@^4.3.0: 794 | version "4.5.2" 795 | resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" 796 | 797 | lodash.debounce@4.0.8: 798 | version "4.0.8" 799 | resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" 800 | 801 | lodash.throttle@4.1.1: 802 | version "4.1.1" 803 | resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" 804 | 805 | lodash@^4.0.0, lodash@^4.2.0, lodash@^4.3.0: 806 | version "4.17.2" 807 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" 808 | 809 | loose-envify@^1.0.0: 810 | version "1.3.0" 811 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" 812 | dependencies: 813 | js-tokens "^2.0.0" 814 | 815 | minimatch@^3.0.2, minimatch@^3.0.3: 816 | version "3.0.3" 817 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 818 | dependencies: 819 | brace-expansion "^1.0.0" 820 | 821 | minimatch@^3.0.4: 822 | version "3.0.4" 823 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 824 | dependencies: 825 | brace-expansion "^1.1.7" 826 | 827 | minimist@0.0.8: 828 | version "0.0.8" 829 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 830 | 831 | mkdirp@^0.5.0, mkdirp@^0.5.1: 832 | version "0.5.1" 833 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 834 | dependencies: 835 | minimist "0.0.8" 836 | 837 | ms@0.7.1: 838 | version "0.7.1" 839 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" 840 | 841 | ms@0.7.2: 842 | version "0.7.2" 843 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" 844 | 845 | mute-stream@0.0.5: 846 | version "0.0.5" 847 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" 848 | 849 | natural-compare@^1.4.0: 850 | version "1.4.0" 851 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 852 | 853 | node-fetch@^1.0.1: 854 | version "1.7.1" 855 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5" 856 | dependencies: 857 | encoding "^0.1.11" 858 | is-stream "^1.0.1" 859 | 860 | normalize-package-data@^2.3.2: 861 | version "2.3.8" 862 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" 863 | dependencies: 864 | hosted-git-info "^2.1.4" 865 | is-builtin-module "^1.0.0" 866 | semver "2 || 3 || 4 || 5" 867 | validate-npm-package-license "^3.0.1" 868 | 869 | number-is-nan@^1.0.0: 870 | version "1.0.1" 871 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 872 | 873 | object-assign@^4.0.1, object-assign@^4.1.0: 874 | version "4.1.0" 875 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" 876 | 877 | once@^1.3.0: 878 | version "1.4.0" 879 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 880 | dependencies: 881 | wrappy "1" 882 | 883 | onetime@^1.0.0: 884 | version "1.1.0" 885 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" 886 | 887 | optionator@^0.8.2: 888 | version "0.8.2" 889 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 890 | dependencies: 891 | deep-is "~0.1.3" 892 | fast-levenshtein "~2.0.4" 893 | levn "~0.3.0" 894 | prelude-ls "~1.1.2" 895 | type-check "~0.3.2" 896 | wordwrap "~1.0.0" 897 | 898 | os-homedir@^1.0.0: 899 | version "1.0.2" 900 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 901 | 902 | p-limit@^1.1.0: 903 | version "1.1.0" 904 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" 905 | 906 | p-locate@^2.0.0: 907 | version "2.0.0" 908 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" 909 | dependencies: 910 | p-limit "^1.1.0" 911 | 912 | parse-json@^2.2.0: 913 | version "2.2.0" 914 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 915 | dependencies: 916 | error-ex "^1.2.0" 917 | 918 | path-exists@^2.0.0: 919 | version "2.1.0" 920 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 921 | dependencies: 922 | pinkie-promise "^2.0.0" 923 | 924 | path-exists@^3.0.0: 925 | version "3.0.0" 926 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 927 | 928 | path-is-absolute@^1.0.0: 929 | version "1.0.1" 930 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 931 | 932 | path-is-inside@^1.0.1: 933 | version "1.0.2" 934 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 935 | 936 | path-parse@^1.0.5: 937 | version "1.0.5" 938 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 939 | 940 | path-type@^2.0.0: 941 | version "2.0.0" 942 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" 943 | dependencies: 944 | pify "^2.0.0" 945 | 946 | pify@^2.0.0: 947 | version "2.3.0" 948 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 949 | 950 | pinkie-promise@^2.0.0: 951 | version "2.0.1" 952 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 953 | dependencies: 954 | pinkie "^2.0.0" 955 | 956 | pinkie@^2.0.0: 957 | version "2.0.4" 958 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 959 | 960 | pkg-dir@^1.0.0: 961 | version "1.0.0" 962 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" 963 | dependencies: 964 | find-up "^1.0.0" 965 | 966 | pluralize@^1.2.1: 967 | version "1.2.1" 968 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" 969 | 970 | prelude-ls@~1.1.2: 971 | version "1.1.2" 972 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 973 | 974 | process-nextick-args@~1.0.6: 975 | version "1.0.7" 976 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 977 | 978 | progress@^1.1.8: 979 | version "1.1.8" 980 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" 981 | 982 | promise@^7.1.1: 983 | version "7.1.1" 984 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" 985 | dependencies: 986 | asap "~2.0.3" 987 | 988 | react-addons-shallow-compare@15.5.2: 989 | version "15.5.2" 990 | resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.5.2.tgz#7cb0ee7acc8d7c93fcc202df0bf47ba916a7bdad" 991 | dependencies: 992 | fbjs "^0.8.4" 993 | object-assign "^4.1.0" 994 | 995 | read-pkg-up@^2.0.0: 996 | version "2.0.0" 997 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" 998 | dependencies: 999 | find-up "^2.0.0" 1000 | read-pkg "^2.0.0" 1001 | 1002 | read-pkg@^2.0.0: 1003 | version "2.0.0" 1004 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" 1005 | dependencies: 1006 | load-json-file "^2.0.0" 1007 | normalize-package-data "^2.3.2" 1008 | path-type "^2.0.0" 1009 | 1010 | readable-stream@^2.2.2: 1011 | version "2.2.11" 1012 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72" 1013 | dependencies: 1014 | core-util-is "~1.0.0" 1015 | inherits "~2.0.1" 1016 | isarray "~1.0.0" 1017 | process-nextick-args "~1.0.6" 1018 | safe-buffer "~5.0.1" 1019 | string_decoder "~1.0.0" 1020 | util-deprecate "~1.0.1" 1021 | 1022 | readline2@^1.0.1: 1023 | version "1.0.1" 1024 | resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" 1025 | dependencies: 1026 | code-point-at "^1.0.0" 1027 | is-fullwidth-code-point "^1.0.0" 1028 | mute-stream "0.0.5" 1029 | 1030 | rechoir@^0.6.2: 1031 | version "0.6.2" 1032 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 1033 | dependencies: 1034 | resolve "^1.1.6" 1035 | 1036 | regenerator-runtime@^0.10.0: 1037 | version "0.10.5" 1038 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" 1039 | 1040 | require-uncached@^1.0.2: 1041 | version "1.0.3" 1042 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" 1043 | dependencies: 1044 | caller-path "^0.1.0" 1045 | resolve-from "^1.0.0" 1046 | 1047 | resolve-from@^1.0.0: 1048 | version "1.0.1" 1049 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" 1050 | 1051 | resolve@^1.1.6: 1052 | version "1.1.7" 1053 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 1054 | 1055 | resolve@^1.3.3: 1056 | version "1.3.3" 1057 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" 1058 | dependencies: 1059 | path-parse "^1.0.5" 1060 | 1061 | restore-cursor@^1.0.1: 1062 | version "1.0.1" 1063 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" 1064 | dependencies: 1065 | exit-hook "^1.0.0" 1066 | onetime "^1.0.0" 1067 | 1068 | rimraf@^2.2.8: 1069 | version "2.5.4" 1070 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" 1071 | dependencies: 1072 | glob "^7.0.5" 1073 | 1074 | run-async@^0.1.0: 1075 | version "0.1.0" 1076 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" 1077 | dependencies: 1078 | once "^1.3.0" 1079 | 1080 | rx-lite@^3.1.2: 1081 | version "3.1.2" 1082 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" 1083 | 1084 | safe-buffer@~5.0.1: 1085 | version "5.0.1" 1086 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" 1087 | 1088 | "semver@2 || 3 || 4 || 5", semver@5.3.0: 1089 | version "5.3.0" 1090 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 1091 | 1092 | setimmediate@^1.0.5: 1093 | version "1.0.5" 1094 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 1095 | 1096 | shelljs@^0.7.5: 1097 | version "0.7.5" 1098 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" 1099 | dependencies: 1100 | glob "^7.0.0" 1101 | interpret "^1.0.0" 1102 | rechoir "^0.6.2" 1103 | 1104 | slice-ansi@0.0.4: 1105 | version "0.0.4" 1106 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" 1107 | 1108 | spdx-correct@~1.0.0: 1109 | version "1.0.2" 1110 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" 1111 | dependencies: 1112 | spdx-license-ids "^1.0.2" 1113 | 1114 | spdx-expression-parse@~1.0.0: 1115 | version "1.0.4" 1116 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" 1117 | 1118 | spdx-license-ids@^1.0.2: 1119 | version "1.2.2" 1120 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" 1121 | 1122 | sprintf-js@~1.0.2: 1123 | version "1.0.3" 1124 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1125 | 1126 | string-width@^1.0.1: 1127 | version "1.0.2" 1128 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1129 | dependencies: 1130 | code-point-at "^1.0.0" 1131 | is-fullwidth-code-point "^1.0.0" 1132 | strip-ansi "^3.0.0" 1133 | 1134 | string-width@^2.0.0: 1135 | version "2.0.0" 1136 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" 1137 | dependencies: 1138 | is-fullwidth-code-point "^2.0.0" 1139 | strip-ansi "^3.0.0" 1140 | 1141 | string_decoder@~1.0.0: 1142 | version "1.0.2" 1143 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179" 1144 | dependencies: 1145 | safe-buffer "~5.0.1" 1146 | 1147 | strip-ansi@^3.0.0: 1148 | version "3.0.1" 1149 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1150 | dependencies: 1151 | ansi-regex "^2.0.0" 1152 | 1153 | strip-bom@^3.0.0: 1154 | version "3.0.0" 1155 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1156 | 1157 | strip-json-comments@~2.0.1: 1158 | version "2.0.1" 1159 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1160 | 1161 | supports-color@^2.0.0: 1162 | version "2.0.0" 1163 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1164 | 1165 | table@^3.7.8: 1166 | version "3.8.3" 1167 | resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" 1168 | dependencies: 1169 | ajv "^4.7.0" 1170 | ajv-keywords "^1.0.0" 1171 | chalk "^1.1.1" 1172 | lodash "^4.0.0" 1173 | slice-ansi "0.0.4" 1174 | string-width "^2.0.0" 1175 | 1176 | text-table@~0.2.0: 1177 | version "0.2.0" 1178 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1179 | 1180 | through@^2.3.6: 1181 | version "2.3.8" 1182 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1183 | 1184 | to-fast-properties@^1.0.1: 1185 | version "1.0.2" 1186 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" 1187 | 1188 | tryit@^1.0.1: 1189 | version "1.0.3" 1190 | resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" 1191 | 1192 | type-check@~0.3.2: 1193 | version "0.3.2" 1194 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1195 | dependencies: 1196 | prelude-ls "~1.1.2" 1197 | 1198 | typedarray@^0.0.6: 1199 | version "0.0.6" 1200 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1201 | 1202 | ua-parser-js@^0.7.9: 1203 | version "0.7.12" 1204 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" 1205 | 1206 | user-home@^2.0.0: 1207 | version "2.0.0" 1208 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" 1209 | dependencies: 1210 | os-homedir "^1.0.0" 1211 | 1212 | util-deprecate@~1.0.1: 1213 | version "1.0.2" 1214 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1215 | 1216 | validate-npm-package-license@^3.0.1: 1217 | version "3.0.1" 1218 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" 1219 | dependencies: 1220 | spdx-correct "~1.0.0" 1221 | spdx-expression-parse "~1.0.0" 1222 | 1223 | whatwg-fetch@>=0.10.0: 1224 | version "2.0.3" 1225 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" 1226 | 1227 | wordwrap@~1.0.0: 1228 | version "1.0.0" 1229 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1230 | 1231 | wrappy@1: 1232 | version "1.0.2" 1233 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1234 | 1235 | write@^0.2.1: 1236 | version "0.2.1" 1237 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" 1238 | dependencies: 1239 | mkdirp "^0.5.1" 1240 | 1241 | xtend@^4.0.0: 1242 | version "4.0.1" 1243 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 1244 | --------------------------------------------------------------------------------