@momo-kits/carousel 0.0.3-beta → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Carousel.js CHANGED
@@ -1 +1,1390 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _extends2=_interopRequireDefault(require("@babel/runtime/helpers/extends"));var _defineProperty2=_interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));var _toConsumableArray2=_interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));var _classCallCheck2=_interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));var _createClass2=_interopRequireDefault(require("@babel/runtime/helpers/createClass"));var _assertThisInitialized2=_interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));var _inherits2=_interopRequireDefault(require("@babel/runtime/helpers/inherits"));var _possibleConstructorReturn2=_interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));var _getPrototypeOf2=_interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));var _react=_interopRequireWildcard(require("react"));var _reactNative=require("react-native");var _propTypes=_interopRequireDefault(require("prop-types"));var _animation=require("./utils/animation");var _jsxFileName="/Users/trinh.ho2/momo-folk/kits/src/libs/carousel/dist/Carousel.js";function _getRequireWildcardCache(nodeInterop){if(typeof WeakMap!=="function")return null;var cacheBabelInterop=new WeakMap();var cacheNodeInterop=new WeakMap();return(_getRequireWildcardCache=function _getRequireWildcardCache(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop;})(nodeInterop);}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule){return obj;}if(obj===null||typeof obj!=="object"&&typeof obj!=="function"){return{default:obj};}var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj)){return cache.get(obj);}var newObj={};var hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj){if(key!=="default"&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;if(desc&&(desc.get||desc.set)){Object.defineProperty(newObj,key,desc);}else{newObj[key]=obj[key];}}}newObj.default=obj;if(cache){cache.set(obj,newObj);}return newObj;}function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly){symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable;});}keys.push.apply(keys,symbols);}return keys;}function _objectSpread(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};if(i%2){ownKeys(Object(source),true).forEach(function(key){(0,_defineProperty2.default)(target,key,source[key]);});}else if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source));}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key));});}}return target;}function _createSuper(Derived){var hasNativeReflectConstruct=_isNativeReflectConstruct();return function _createSuperInternal(){var Super=(0,_getPrototypeOf2.default)(Derived),result;if(hasNativeReflectConstruct){var NewTarget=(0,_getPrototypeOf2.default)(this).constructor;result=Reflect.construct(Super,arguments,NewTarget);}else{result=Super.apply(this,arguments);}return(0,_possibleConstructorReturn2.default)(this,result);};}function _isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}));return true;}catch(e){return false;}}var IS_IOS=_reactNative.Platform.OS==='ios';var AnimatedFlatList=_reactNative.FlatList?_reactNative.Animated.createAnimatedComponent(_reactNative.FlatList):null;var AnimatedScrollView=_reactNative.Animated.createAnimatedComponent(_reactNative.ScrollView);var IS_RTL=_reactNative.I18nManager.isRTL;var Carousel=function(_PureComponent){(0,_inherits2.default)(Carousel,_PureComponent);var _super=_createSuper(Carousel);function Carousel(props){var _this;(0,_classCallCheck2.default)(this,Carousel);_this=_super.call(this,props);_this.state={hideCarousel:true,interpolators:[]};var initialActiveItem=_this._getFirstItem(props.firstItem);_this._activeItem=initialActiveItem;_this._previousActiveItem=initialActiveItem;_this._previousFirstItem=initialActiveItem;_this._previousItemsLength=initialActiveItem;_this._mounted=false;_this._positions=[];_this._currentContentOffset=0;_this._canFireBeforeCallback=false;_this._canFireCallback=false;_this._scrollOffsetRef=null;_this._onScrollTriggered=true;_this._lastScrollDate=0;_this._scrollEnabled=props.scrollEnabled!==false;_this._initPositionsAndInterpolators=_this._initPositionsAndInterpolators.bind((0,_assertThisInitialized2.default)(_this));_this._renderItem=_this._renderItem.bind((0,_assertThisInitialized2.default)(_this));_this._onSnap=_this._onSnap.bind((0,_assertThisInitialized2.default)(_this));_this._onLayout=_this._onLayout.bind((0,_assertThisInitialized2.default)(_this));_this._onScroll=_this._onScroll.bind((0,_assertThisInitialized2.default)(_this));_this._onScrollBeginDrag=props.enableSnap?_this._onScrollBeginDrag.bind((0,_assertThisInitialized2.default)(_this)):undefined;_this._onScrollEnd=props.enableSnap||props.autoplay?_this._onScrollEnd.bind((0,_assertThisInitialized2.default)(_this)):undefined;_this._onScrollEndDrag=!props.enableMomentum?_this._onScrollEndDrag.bind((0,_assertThisInitialized2.default)(_this)):undefined;_this._onMomentumScrollEnd=props.enableMomentum?_this._onMomentumScrollEnd.bind((0,_assertThisInitialized2.default)(_this)):undefined;_this._onTouchStart=_this._onTouchStart.bind((0,_assertThisInitialized2.default)(_this));_this._onTouchEnd=_this._onTouchEnd.bind((0,_assertThisInitialized2.default)(_this));_this._onTouchRelease=_this._onTouchRelease.bind((0,_assertThisInitialized2.default)(_this));_this._getKeyExtractor=_this._getKeyExtractor.bind((0,_assertThisInitialized2.default)(_this));_this._setScrollHandler(props);_this._ignoreNextMomentum=false;if(!_reactNative.ViewPropTypes){console.warn("react-native-snap-carousel: \n It is recommended to use at least version 0.44 of React Native with the plugin");}if(!props.vertical&&(!props.sliderWidth||!props.itemWidth)){console.warn("react-native-snap-carousel: You need to specify both sliderWidth and itemWidth \n for horizontal carousels");}if(props.vertical&&(!props.sliderHeight||!props.itemHeight)){console.warn("react-native-snap-carousel: You need to specify both sliderHeight and itemHeight \n for vertical carousels");}if(props.apparitionDelay&&!IS_IOS&&!props.useScrollView){console.warn("react-native-snap-carousel: Using apparitionDelay on Android \n is not recommended since it can lead to rendering issues");}if(props.customAnimationType||props.customAnimationOptions){console.warn("react-native-snap-carousel: Props customAnimationType and \n customAnimationOptions have been renamed to activeAnimationType and activeAnimationOptions");}if(props.onScrollViewScroll){console.warn("react-native-snap-carousel: Prop onScrollViewScroll has been removed. \n Use onScroll instead");}return _this;}(0,_createClass2.default)(Carousel,[{key:"componentDidMount",value:function componentDidMount(){var _this2=this;var _this$props=this.props,apparitionDelay=_this$props.apparitionDelay,autoplay=_this$props.autoplay,firstItem=_this$props.firstItem;var _firstItem=this._getFirstItem(firstItem);var apparitionCallback=function apparitionCallback(){_this2.setState({hideCarousel:false});if(autoplay){_this2.startAutoplay();}};this._mounted=true;this._initPositionsAndInterpolators();requestAnimationFrame(function(){if(!_this2._mounted){return;}_this2._snapToItem(_firstItem,false,false,true,false);_this2._hackActiveSlideAnimation(_firstItem,'start',true);if(apparitionDelay){_this2._apparitionTimeout=setTimeout(function(){apparitionCallback();},apparitionDelay);}else{apparitionCallback();}});}},{key:"UNSAFE_componentWillReceiveProps",value:function UNSAFE_componentWillReceiveProps(nextProps){var interpolators=this.state.interpolators;var _this$props2=this.props,itemHeight=_this$props2.itemHeight,itemWidth=_this$props2.itemWidth,scrollEnabled=_this$props2.scrollEnabled,sliderHeight=_this$props2.sliderHeight,sliderWidth=_this$props2.sliderWidth,onScroll=_this$props2.onScroll;var itemsLength=this._getCustomDataLength(nextProps);if(!itemsLength){return;}var nextFirstItem=this._getFirstItem(nextProps.firstItem,nextProps);var nextActiveItem=this._activeItem||this._activeItem===0?this._activeItem:nextFirstItem;var hasNewSliderWidth=nextProps.sliderWidth&&nextProps.sliderWidth!==sliderWidth;var hasNewSliderHeight=nextProps.sliderHeight&&nextProps.sliderHeight!==sliderHeight;var hasNewItemWidth=nextProps.itemWidth&&nextProps.itemWidth!==itemWidth;var hasNewItemHeight=nextProps.itemHeight&&nextProps.itemHeight!==itemHeight;var hasNewScrollEnabled=nextProps.scrollEnabled!==scrollEnabled;if(nextActiveItem>itemsLength-1){nextActiveItem=itemsLength-1;}if(hasNewScrollEnabled){this._setScrollEnabled(nextProps.scrollEnabled);}if(interpolators.length!==itemsLength||hasNewSliderWidth||hasNewSliderHeight||hasNewItemWidth||hasNewItemHeight){this._activeItem=nextActiveItem;this._previousItemsLength=itemsLength;this._initPositionsAndInterpolators(nextProps);if(this._previousItemsLength>itemsLength){this._hackActiveSlideAnimation(nextActiveItem,null,true);}if(hasNewSliderWidth||hasNewSliderHeight||hasNewItemWidth||hasNewItemHeight){this._snapToItem(nextActiveItem,false,false,false,false);}}else if(nextFirstItem!==this._previousFirstItem&&nextFirstItem!==this._activeItem){this._activeItem=nextFirstItem;this._previousFirstItem=nextFirstItem;this._snapToItem(nextFirstItem,false,true,false,false);}if(nextProps.onScroll!==onScroll){this._setScrollHandler(nextProps);}}},{key:"componentWillUnmount",value:function componentWillUnmount(){this._mounted=false;this.stopAutoplay();clearTimeout(this._apparitionTimeout);clearTimeout(this._hackSlideAnimationTimeout);clearTimeout(this._enableAutoplayTimeout);clearTimeout(this._autoplayTimeout);clearTimeout(this._snapNoMomentumTimeout);clearTimeout(this._edgeItemTimeout);clearTimeout(this._lockScrollTimeout);}},{key:"realIndex",get:function get(){return this._activeItem;}},{key:"currentIndex",get:function get(){return this._getDataIndex(this._activeItem);}},{key:"currentScrollPosition",get:function get(){return this._currentContentOffset;}},{key:"_setScrollHandler",value:function _setScrollHandler(props){var scrollEventConfig={listener:this._onScroll,useNativeDriver:true};this._scrollPos=new _reactNative.Animated.Value(0);var argMapping=props.vertical?[{nativeEvent:{contentOffset:{y:this._scrollPos}}}]:[{nativeEvent:{contentOffset:{x:this._scrollPos}}}];if(props.onScroll&&Array.isArray(props.onScroll._argMapping)){argMapping.pop();var _props$onScroll$_argM=(0,_slicedToArray2.default)(props.onScroll._argMapping,1),argMap=_props$onScroll$_argM[0];if(argMap&&argMap.nativeEvent&&argMap.nativeEvent.contentOffset){this._scrollPos=argMap.nativeEvent.contentOffset.x||argMap.nativeEvent.contentOffset.y||this._scrollPos;}argMapping.push.apply(argMapping,(0,_toConsumableArray2.default)(props.onScroll._argMapping));}this._onScrollHandler=_reactNative.Animated.event(argMapping,scrollEventConfig);}},{key:"_needsScrollView",value:function _needsScrollView(){var useScrollView=this.props.useScrollView;return useScrollView||!AnimatedFlatList||this._shouldUseStackLayout()||this._shouldUseTinderLayout();}},{key:"_needsRTLAdaptations",value:function _needsRTLAdaptations(){var vertical=this.props.vertical;return IS_RTL&&!IS_IOS&&!vertical;}},{key:"_canLockScroll",value:function _canLockScroll(){var _this$props3=this.props,scrollEnabled=_this$props3.scrollEnabled,enableMomentum=_this$props3.enableMomentum,lockScrollWhileSnapping=_this$props3.lockScrollWhileSnapping;return scrollEnabled&&!enableMomentum&&lockScrollWhileSnapping;}},{key:"_enableLoop",value:function _enableLoop(){var _this$props4=this.props,data=_this$props4.data,enableSnap=_this$props4.enableSnap,loop=_this$props4.loop;return enableSnap&&loop&&data&&data.length&&data.length>1;}},{key:"_shouldAnimateSlides",value:function _shouldAnimateSlides(){var props=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.props;var inactiveSlideOpacity=props.inactiveSlideOpacity,inactiveSlideScale=props.inactiveSlideScale,scrollInterpolator=props.scrollInterpolator,slideInterpolatedStyle=props.slideInterpolatedStyle;return inactiveSlideOpacity<1||inactiveSlideScale<1||!!scrollInterpolator||!!slideInterpolatedStyle||this._shouldUseShiftLayout()||this._shouldUseStackLayout()||this._shouldUseTinderLayout();}},{key:"_shouldUseCustomAnimation",value:function _shouldUseCustomAnimation(){var activeAnimationOptions=this.props.activeAnimationOptions;return!!activeAnimationOptions&&!this._shouldUseStackLayout()&&!this._shouldUseTinderLayout();}},{key:"_shouldUseShiftLayout",value:function _shouldUseShiftLayout(){var _this$props5=this.props,inactiveSlideShift=_this$props5.inactiveSlideShift,layout=_this$props5.layout;return layout==='default'&&inactiveSlideShift!==0;}},{key:"_shouldUseStackLayout",value:function _shouldUseStackLayout(){var layout=this.props.layout;return layout==='stack';}},{key:"_shouldUseTinderLayout",value:function _shouldUseTinderLayout(){var layout=this.props.layout;return layout==='tinder';}},{key:"_getCustomData",value:function _getCustomData(){var props=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.props;var data=props.data,loopClonesPerSide=props.loopClonesPerSide;var dataLength=data&&data.length;if(!dataLength){return[];}if(!this._enableLoop()){return data;}var previousItems=[];var nextItems=[];if(loopClonesPerSide>dataLength){var _previousItems2,_nextItems2;var dataMultiplier=Math.floor(loopClonesPerSide/dataLength);var remainder=loopClonesPerSide%dataLength;for(var i=0;i<dataMultiplier;i+=1){var _previousItems,_nextItems;(_previousItems=previousItems).push.apply(_previousItems,(0,_toConsumableArray2.default)(data));(_nextItems=nextItems).push.apply(_nextItems,(0,_toConsumableArray2.default)(data));}(_previousItems2=previousItems).unshift.apply(_previousItems2,(0,_toConsumableArray2.default)(data.slice(-remainder)));(_nextItems2=nextItems).push.apply(_nextItems2,(0,_toConsumableArray2.default)(data.slice(0,remainder)));}else{previousItems=data.slice(-loopClonesPerSide);nextItems=data.slice(0,loopClonesPerSide);}return previousItems.concat(data,nextItems);}},{key:"_getCustomDataLength",value:function _getCustomDataLength(){var props=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.props;var data=props.data,loopClonesPerSide=props.loopClonesPerSide;var dataLength=data&&data.length;if(!dataLength){return 0;}return this._enableLoop()?dataLength+2*loopClonesPerSide:dataLength;}},{key:"_getCustomIndex",value:function _getCustomIndex(index){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:this.props;var itemsLength=this._getCustomDataLength(props);if(!itemsLength||!index&&index!==0){return 0;}return this._needsRTLAdaptations()?itemsLength-index-1:index;}},{key:"_getDataIndex",value:function _getDataIndex(index){var _this$props6=this.props,data=_this$props6.data,loopClonesPerSide=_this$props6.loopClonesPerSide;var dataLength=data&&data.length;if(!this._enableLoop()||!dataLength){return index;}if(index>=dataLength+loopClonesPerSide){return loopClonesPerSide>dataLength?(index-loopClonesPerSide)%dataLength:index-dataLength-loopClonesPerSide;}if(index<loopClonesPerSide){if(loopClonesPerSide>dataLength){var baseDataIndexes=[];var dataIndexes=[];var dataMultiplier=Math.floor(loopClonesPerSide/dataLength);var remainder=loopClonesPerSide%dataLength;for(var i=0;i<dataLength;i+=1){baseDataIndexes.push(i);}for(var j=0;j<dataMultiplier;j+=1){dataIndexes.push.apply(dataIndexes,baseDataIndexes);}dataIndexes.unshift.apply(dataIndexes,(0,_toConsumableArray2.default)(baseDataIndexes.slice(-remainder)));return dataIndexes[index];}return index+dataLength-loopClonesPerSide;}return index-loopClonesPerSide;}},{key:"_getPositionIndex",value:function _getPositionIndex(index){var _this$props7=this.props,loop=_this$props7.loop,loopClonesPerSide=_this$props7.loopClonesPerSide;return loop?index+loopClonesPerSide:index;}},{key:"_getFirstItem",value:function _getFirstItem(index){var props=arguments.length>1&&arguments[1]!==undefined?arguments[1]:this.props;var loopClonesPerSide=props.loopClonesPerSide;var itemsLength=this._getCustomDataLength(props);if(!itemsLength||index>itemsLength-1||index<0){return 0;}return this._enableLoop()?index+loopClonesPerSide:index;}},{key:"_getWrappedRef",value:function _getWrappedRef(){return this._carouselRef&&this._carouselRef.getNode&&this._carouselRef.getNode();}},{key:"_getScrollEnabled",value:function _getScrollEnabled(){return this._scrollEnabled;}},{key:"_setScrollEnabled",value:function _setScrollEnabled(){var scrollEnabled=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;var wrappedRef=this._getWrappedRef();if(!wrappedRef||!wrappedRef.setNativeProps){return;}wrappedRef.setNativeProps({scrollEnabled:scrollEnabled});this._scrollEnabled=scrollEnabled;}},{key:"_getKeyExtractor",value:function _getKeyExtractor(item,index){return this._needsScrollView()?"scrollview-item-"+index:"flatlist-item-"+index;}},{key:"_getScrollOffset",value:function _getScrollOffset(event){var vertical=this.props.vertical;return event&&event.nativeEvent&&event.nativeEvent.contentOffset&&event.nativeEvent.contentOffset[vertical?'y':'x']||0;}},{key:"_getContainerInnerMargin",value:function _getContainerInnerMargin(){var opposite=arguments.length>0&&arguments[0]!==undefined?arguments[0]:false;var _this$props8=this.props,sliderWidth=_this$props8.sliderWidth,sliderHeight=_this$props8.sliderHeight,itemWidth=_this$props8.itemWidth,itemHeight=_this$props8.itemHeight,vertical=_this$props8.vertical,activeSlideAlignment=_this$props8.activeSlideAlignment;if(activeSlideAlignment==='start'&&!opposite||activeSlideAlignment==='end'&&opposite){return 0;}if(activeSlideAlignment==='end'&&!opposite||activeSlideAlignment==='start'&&opposite){return vertical?sliderHeight-itemHeight:sliderWidth-itemWidth;}return vertical?(sliderHeight-itemHeight)/2:(sliderWidth-itemWidth)/2;}},{key:"_getViewportOffset",value:function _getViewportOffset(){var _this$props9=this.props,sliderWidth=_this$props9.sliderWidth,sliderHeight=_this$props9.sliderHeight,itemWidth=_this$props9.itemWidth,itemHeight=_this$props9.itemHeight,vertical=_this$props9.vertical,activeSlideAlignment=_this$props9.activeSlideAlignment;if(activeSlideAlignment==='start'){return vertical?itemHeight/2:itemWidth/2;}if(activeSlideAlignment==='end'){return vertical?sliderHeight-itemHeight/2:sliderWidth-itemWidth/2;}return vertical?sliderHeight/2:sliderWidth/2;}},{key:"_getCenter",value:function _getCenter(offset){return offset+this._getViewportOffset()-this._getContainerInnerMargin();}},{key:"_getActiveItem",value:function _getActiveItem(offset){var _this$props10=this.props,activeSlideOffset=_this$props10.activeSlideOffset,swipeThreshold=_this$props10.swipeThreshold;var center=this._getCenter(offset);var centerOffset=activeSlideOffset||swipeThreshold;for(var i=0;i<this._positions.length;i+=1){var _this$_positions$i=this._positions[i],start=_this$_positions$i.start,end=_this$_positions$i.end;if(center+centerOffset>=start&&center-centerOffset<=end){return i;}}var lastIndex=this._positions.length-1;if(this._positions[lastIndex]&&center-centerOffset>this._positions[lastIndex].end){return lastIndex;}return 0;}},{key:"_initPositionsAndInterpolators",value:function _initPositionsAndInterpolators(){var _this3=this;var props=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.props;var data=props.data,itemWidth=props.itemWidth,itemHeight=props.itemHeight,scrollInterpolator=props.scrollInterpolator,vertical=props.vertical;var sizeRef=vertical?itemHeight:itemWidth;if(!data||!data.length){return;}var interpolators=[];this._positions=[];this._getCustomData(props).forEach(function(itemData,index){var _index=_this3._getCustomIndex(index,props);var animatedValue;_this3._positions[index]={start:index*sizeRef,end:index*sizeRef+sizeRef};if(!_this3._shouldAnimateSlides(props)){animatedValue=new _reactNative.Animated.Value(1);}else if(_this3._shouldUseCustomAnimation()){animatedValue=new _reactNative.Animated.Value(_index===_this3._activeItem?1:0);}else{var interpolator;if(scrollInterpolator){interpolator=scrollInterpolator(_index,props);}else if(_this3._shouldUseStackLayout()){interpolator=(0,_animation.stackScrollInterpolator)(_index,props);}else if(_this3._shouldUseTinderLayout()){interpolator=(0,_animation.tinderScrollInterpolator)(_index,props);}if(!interpolator||!interpolator.inputRange||!interpolator.outputRange){interpolator=(0,_animation.defaultScrollInterpolator)(_index,props);}animatedValue=_this3._scrollPos.interpolate(_objectSpread(_objectSpread({},interpolator),{},{extrapolate:'clamp'}));}interpolators.push(animatedValue);});this.setState({interpolators:interpolators});}},{key:"_getSlideAnimation",value:function _getSlideAnimation(index,toValue){var interpolators=this.state.interpolators;var _this$props11=this.props,activeAnimationType=_this$props11.activeAnimationType,activeAnimationOptions=_this$props11.activeAnimationOptions;var animatedValue=interpolators&&interpolators[index];if(!animatedValue&&animatedValue!==0){return null;}var animationCommonOptions=_objectSpread(_objectSpread({isInteraction:false,useNativeDriver:true},activeAnimationOptions),{},{toValue:toValue});return _reactNative.Animated.parallel([_reactNative.Animated.timing(animatedValue,_objectSpread(_objectSpread({},animationCommonOptions),{},{easing:_reactNative.Easing.linear})),_reactNative.Animated[activeAnimationType](animatedValue,_objectSpread({},animationCommonOptions))]);}},{key:"_playCustomSlideAnimation",value:function _playCustomSlideAnimation(current,next){var interpolators=this.state.interpolators;var itemsLength=this._getCustomDataLength();var _currentIndex=this._getCustomIndex(current);var _currentDataIndex=this._getDataIndex(_currentIndex);var _nextIndex=this._getCustomIndex(next);var _nextDataIndex=this._getDataIndex(_nextIndex);var animations=[];if(this._enableLoop()){for(var i=0;i<itemsLength;i+=1){if(this._getDataIndex(i)===_currentDataIndex&&interpolators[i]){animations.push(this._getSlideAnimation(i,0));}else if(this._getDataIndex(i)===_nextDataIndex&&interpolators[i]){animations.push(this._getSlideAnimation(i,1));}}}else{if(interpolators[current]){animations.push(this._getSlideAnimation(current,0));}if(interpolators[next]){animations.push(this._getSlideAnimation(next,1));}}_reactNative.Animated.parallel(animations,{stopTogether:false}).start();}},{key:"_hackActiveSlideAnimation",value:function _hackActiveSlideAnimation(index,goTo){var _this4=this;var force=arguments.length>2&&arguments[2]!==undefined?arguments[2]:false;var data=this.props.data;if(!this._mounted||!this._carouselRef||!this._positions[index]||!force&&this._enableLoop()){return;}var offset=this._positions[index]&&this._positions[index].start;if(!offset&&offset!==0){return;}var itemsLength=data&&data.length;var direction=goTo||itemsLength===1?'start':'end';this._scrollTo(offset+(direction==='start'?-1:1),false);clearTimeout(this._hackSlideAnimationTimeout);this._hackSlideAnimationTimeout=setTimeout(function(){_this4._scrollTo(offset,false);},50);}},{key:"_lockScroll",value:function _lockScroll(){var _this5=this;var lockScrollTimeoutDuration=this.props.lockScrollTimeoutDuration;clearTimeout(this._lockScrollTimeout);this._lockScrollTimeout=setTimeout(function(){_this5._releaseScroll();},lockScrollTimeoutDuration);this._setScrollEnabled(false);}},{key:"_releaseScroll",value:function _releaseScroll(){clearTimeout(this._lockScrollTimeout);this._setScrollEnabled(true);}},{key:"_repositionScroll",value:function _repositionScroll(index){var _this$props12=this.props,data=_this$props12.data,loopClonesPerSide=_this$props12.loopClonesPerSide;var dataLength=data&&data.length;if(!this._enableLoop()||!dataLength||index>=loopClonesPerSide&&index<dataLength+loopClonesPerSide){return;}var repositionTo=index;if(index>=dataLength+loopClonesPerSide){repositionTo=index-dataLength;}else if(index<loopClonesPerSide){repositionTo=index+dataLength;}this._snapToItem(repositionTo,false,false,false,false);}},{key:"_scrollTo",value:function _scrollTo(offset){var animated=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;var vertical=this.props.vertical;var wrappedRef=this._getWrappedRef();if(!this._mounted||!wrappedRef){return;}var specificOptions=this._needsScrollView()?{x:vertical?0:offset,y:vertical?offset:0}:{offset:offset};var options=_objectSpread(_objectSpread({},specificOptions),{},{animated:animated});if(this._needsScrollView()){wrappedRef.scrollTo(options);}else{wrappedRef.scrollToOffset(options);}}},{key:"_onScroll",value:function _onScroll(event){var _this$props13=this.props,callbackOffsetMargin=_this$props13.callbackOffsetMargin,enableMomentum=_this$props13.enableMomentum,onScroll=_this$props13.onScroll;var scrollOffset=event?this._getScrollOffset(event):this._currentContentOffset;var nextActiveItem=this._getActiveItem(scrollOffset);var itemReached=nextActiveItem===this._itemToSnapTo;var scrollConditions=scrollOffset>=this._scrollOffsetRef-callbackOffsetMargin&&scrollOffset<=this._scrollOffsetRef+callbackOffsetMargin;this._currentContentOffset=scrollOffset;this._onScrollTriggered=true;this._lastScrollDate=Date.now();if(this._activeItem!==nextActiveItem&&this._shouldUseCustomAnimation()){this._playCustomSlideAnimation(this._activeItem,nextActiveItem);}if(enableMomentum){clearTimeout(this._snapNoMomentumTimeout);if(this._activeItem!==nextActiveItem){this._activeItem=nextActiveItem;}if(itemReached){if(this._canFireBeforeCallback){this._onBeforeSnap(this._getDataIndex(nextActiveItem));}if(scrollConditions&&this._canFireCallback){this._onSnap(this._getDataIndex(nextActiveItem));}}}else if(this._activeItem!==nextActiveItem&&itemReached){if(this._canFireBeforeCallback){this._onBeforeSnap(this._getDataIndex(nextActiveItem));}if(scrollConditions){this._activeItem=nextActiveItem;if(this._canLockScroll()){this._releaseScroll();}if(this._canFireCallback){this._onSnap(this._getDataIndex(nextActiveItem));}}}if(nextActiveItem===this._itemToSnapTo&&scrollOffset===this._scrollOffsetRef){this._repositionScroll(nextActiveItem);}if(typeof onScroll==='function'&&event){onScroll(event);}}},{key:"_onStartShouldSetResponderCapture",value:function _onStartShouldSetResponderCapture(event){var onStartShouldSetResponderCapture=this.props.onStartShouldSetResponderCapture;if(onStartShouldSetResponderCapture){onStartShouldSetResponderCapture(event);}return this._getScrollEnabled();}},{key:"_onTouchStart",value:function _onTouchStart(){var onTouchStart=this.props.onTouchStart;if(this._getScrollEnabled()!==false&&this._autoplaying){this.stopAutoplay();}if(onTouchStart){onTouchStart();}}},{key:"_onTouchEnd",value:function _onTouchEnd(){var _this$props14=this.props,onTouchEnd=_this$props14.onTouchEnd,autoplay=_this$props14.autoplay;if(this._getScrollEnabled()!==false&&autoplay&&!this._autoplaying){this.startAutoplay();}if(onTouchEnd){onTouchEnd();}}},{key:"_onScrollBeginDrag",value:function _onScrollBeginDrag(event){var onScrollBeginDrag=this.props.onScrollBeginDrag;if(!this._getScrollEnabled()){return;}this._scrollStartOffset=this._getScrollOffset(event);this._scrollStartActive=this._getActiveItem(this._scrollStartOffset);this._ignoreNextMomentum=false;if(onScrollBeginDrag){onScrollBeginDrag(event);}}},{key:"_onScrollEndDrag",value:function _onScrollEndDrag(event){var onScrollEndDrag=this.props.onScrollEndDrag;if(this._carouselRef){if(this._onScrollEnd)this._onScrollEnd();}if(onScrollEndDrag){onScrollEndDrag(event);}}},{key:"_onMomentumScrollEnd",value:function _onMomentumScrollEnd(event){var onMomentumScrollEnd=this.props.onMomentumScrollEnd;if(this._carouselRef){if(this._onScrollEnd)this._onScrollEnd();}if(onMomentumScrollEnd){onMomentumScrollEnd(event);}}},{key:"_onScrollEnd",value:function _onScrollEnd(){var _this6=this;var _this$props15=this.props,autoplay=_this$props15.autoplay,autoplayDelay=_this$props15.autoplayDelay,enableSnap=_this$props15.enableSnap;if(this._ignoreNextMomentum){this._ignoreNextMomentum=false;return;}this._scrollEndOffset=this._currentContentOffset;this._scrollEndActive=this._getActiveItem(this._scrollEndOffset);if(enableSnap){this._snapScroll(this._scrollEndOffset-this._scrollStartOffset);}if(autoplay&&!this._autoplaying){clearTimeout(this._enableAutoplayTimeout);this._enableAutoplayTimeout=setTimeout(function(){_this6.startAutoplay();},autoplayDelay+50);}}},{key:"_onTouchRelease",value:function _onTouchRelease(){var _this7=this;var enableMomentum=this.props.enableMomentum;if(enableMomentum&&IS_IOS){clearTimeout(this._snapNoMomentumTimeout);this._snapNoMomentumTimeout=setTimeout(function(){_this7._snapToItem(_this7._activeItem);},100);}}},{key:"_onLayout",value:function _onLayout(event){var onLayout=this.props.onLayout;if(this._onLayoutInitDone){this._initPositionsAndInterpolators();this._snapToItem(this._activeItem,false,false,false,false);}else{this._onLayoutInitDone=true;}if(onLayout){onLayout(event);}}},{key:"_snapScroll",value:function _snapScroll(delta){var swipeThreshold=this.props.swipeThreshold;if(!this._scrollEndActive&&this._scrollEndActive!==0&&IS_IOS){this._scrollEndActive=this._scrollStartActive;}if(this._scrollStartActive!==this._scrollEndActive){this._snapToItem(this._scrollEndActive);}else{if(delta>0){if(delta>swipeThreshold){this._snapToItem(this._scrollStartActive+1);}else{this._snapToItem(this._scrollEndActive);}}else if(delta<0){if(delta<-swipeThreshold){this._snapToItem(this._scrollStartActive-1);}else{this._snapToItem(this._scrollEndActive);}}else{this._snapToItem(this._scrollEndActive);}}}},{key:"_snapToItem",value:function _snapToItem(index){var _this8=this;var animated=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;var fireCallback=arguments.length>2&&arguments[2]!==undefined?arguments[2]:true;var initial=arguments.length>3&&arguments[3]!==undefined?arguments[3]:false;var lockScroll=arguments.length>4&&arguments[4]!==undefined?arguments[4]:true;var _this$props16=this.props,enableMomentum=_this$props16.enableMomentum,onSnapToItem=_this$props16.onSnapToItem,onBeforeSnapToItem=_this$props16.onBeforeSnapToItem;var itemsLength=this._getCustomDataLength();var wrappedRef=this._getWrappedRef();if(!itemsLength||!wrappedRef){return;}if(!index||index<0){index=0;}else if(itemsLength>0&&index>=itemsLength){index=itemsLength-1;}if(index!==this._previousActiveItem){this._previousActiveItem=index;if(lockScroll&&this._canLockScroll()){this._lockScroll();}if(fireCallback){if(onBeforeSnapToItem){this._canFireBeforeCallback=true;}if(onSnapToItem){this._canFireCallback=true;}}}this._itemToSnapTo=index;this._scrollOffsetRef=this._positions[index]&&this._positions[index].start;this._onScrollTriggered=false;if(!this._scrollOffsetRef&&this._scrollOffsetRef!==0){return;}this._scrollTo(this._scrollOffsetRef,animated);if(enableMomentum){if(IS_IOS&&!initial){this._ignoreNextMomentum=true;}if(index===0||index===itemsLength-1){clearTimeout(this._edgeItemTimeout);this._edgeItemTimeout=setTimeout(function(){if(!initial&&index===_this8._activeItem&&!_this8._onScrollTriggered){_this8._onScroll();}},250);}}}},{key:"_onBeforeSnap",value:function _onBeforeSnap(index){var onBeforeSnapToItem=this.props.onBeforeSnapToItem;if(!this._carouselRef){return;}this._canFireBeforeCallback=false;if(onBeforeSnapToItem)onBeforeSnapToItem(index);}},{key:"_onSnap",value:function _onSnap(index){var onSnapToItem=this.props.onSnapToItem;if(!this._carouselRef){return;}this._canFireCallback=false;if(onSnapToItem)onSnapToItem(index);}},{key:"startAutoplay",value:function startAutoplay(){var _this9=this;var _this$props17=this.props,autoplayInterval=_this$props17.autoplayInterval,autoplayDelay=_this$props17.autoplayDelay;if(this._autoplaying){return;}clearTimeout(this._autoplayTimeout);this._autoplayTimeout=setTimeout(function(){_this9._autoplaying=true;_this9._autoplayInterval=setInterval(function(){if(_this9._autoplaying){_this9.snapToNext();}},autoplayInterval);},autoplayDelay);}},{key:"stopAutoplay",value:function stopAutoplay(){this._autoplaying=false;clearInterval(this._autoplayInterval);}},{key:"snapToItem",value:function snapToItem(index){var animated=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;var fireCallback=arguments.length>2&&arguments[2]!==undefined?arguments[2]:true;if(!index||index<0){index=0;}var positionIndex=this._getPositionIndex(index);if(positionIndex===this._activeItem){return;}this._snapToItem(positionIndex,animated,fireCallback);}},{key:"snapToNext",value:function snapToNext(){var animated=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;var fireCallback=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;var itemsLength=this._getCustomDataLength();var newIndex=this._activeItem+1;if(newIndex>itemsLength-1){if(!this._enableLoop()){return;}newIndex=0;}this._snapToItem(newIndex,animated,fireCallback);}},{key:"snapToPrev",value:function snapToPrev(){var animated=arguments.length>0&&arguments[0]!==undefined?arguments[0]:true;var fireCallback=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;var itemsLength=this._getCustomDataLength();var newIndex=this._activeItem-1;if(newIndex<0){if(!this._enableLoop()){return;}newIndex=itemsLength-1;}this._snapToItem(newIndex,animated,fireCallback);}},{key:"triggerRenderingHack",value:function triggerRenderingHack(offset){if(Date.now()-this._lastScrollDate<500){return;}var scrollPosition=this._currentContentOffset;if(!scrollPosition&&scrollPosition!==0){return;}var scrollOffset=offset||(scrollPosition===0?1:-1);this._scrollTo(scrollPosition+scrollOffset,false);}},{key:"_getSlideInterpolatedStyle",value:function _getSlideInterpolatedStyle(index,animatedValue){var _this$props18=this.props,layoutCardOffset=_this$props18.layoutCardOffset,slideInterpolatedStyle=_this$props18.slideInterpolatedStyle;if(slideInterpolatedStyle){return slideInterpolatedStyle(index,animatedValue,this.props);}if(this._shouldUseTinderLayout()){return(0,_animation.tinderAnimatedStyles)(index,animatedValue,this.props,layoutCardOffset);}if(this._shouldUseStackLayout()){return(0,_animation.stackAnimatedStyles)(index,animatedValue,this.props,layoutCardOffset);}if(this._shouldUseShiftLayout()){return(0,_animation.shiftAnimatedStyles)(index,animatedValue,this.props);}return(0,_animation.defaultAnimatedStyles)(index,animatedValue,this.props);}},{key:"_renderItem",value:function _renderItem(_ref){var item=_ref.item,index=_ref.index;var interpolators=this.state.interpolators;var _this$props19=this.props,hasParallaxImages=_this$props19.hasParallaxImages,itemWidth=_this$props19.itemWidth,itemHeight=_this$props19.itemHeight,keyExtractor=_this$props19.keyExtractor,renderItem=_this$props19.renderItem,sliderHeight=_this$props19.sliderHeight,sliderWidth=_this$props19.sliderWidth,slideStyle=_this$props19.slideStyle,vertical=_this$props19.vertical,isCustomScrollWidth=_this$props19.isCustomScrollWidth;var animatedValue=interpolators&&interpolators[index];if(!animatedValue&&animatedValue!==0){return null;}var animate=this._shouldAnimateSlides();var ComponentView=animate?_reactNative.Animated.View:_reactNative.View;var animatedStyle=animate?this._getSlideInterpolatedStyle(index,animatedValue):{};var parallaxProps=hasParallaxImages?{scrollPosition:this._scrollPos,carouselRef:this._carouselRef,vertical:vertical,sliderWidth:sliderWidth,sliderHeight:sliderHeight,itemWidth:itemWidth,itemHeight:itemHeight}:undefined;var specificProps=this._needsScrollView()?{key:keyExtractor?keyExtractor(item,index):this._getKeyExtractor(item,index)}:{};var mainDimension=isCustomScrollWidth?{}:{width:itemWidth};return _react.default.createElement(ComponentView,(0,_extends2.default)({style:[mainDimension,slideStyle,animatedStyle],pointerEvents:"box-none"},specificProps,{__source:{fileName:_jsxFileName,lineNumber:1159,columnNumber:13}}),renderItem({item:item,index:index,realIndex:this._getDataIndex(index),activeIndex:this._getDataIndex(this._activeItem)},parallaxProps));}},{key:"_getComponentOverridableProps",value:function _getComponentOverridableProps(){var _this$props20=this.props,enableMomentum=_this$props20.enableMomentum,itemWidth=_this$props20.itemWidth,itemHeight=_this$props20.itemHeight,loopClonesPerSide=_this$props20.loopClonesPerSide,sliderWidth=_this$props20.sliderWidth,sliderHeight=_this$props20.sliderHeight,vertical=_this$props20.vertical;var visibleItems=Math.ceil(vertical?sliderHeight/itemHeight:sliderWidth/itemWidth)+1;var initialNumPerSide=this._enableLoop()?loopClonesPerSide:2;var initialNumToRender=visibleItems+initialNumPerSide*2;var maxToRenderPerBatch=1+initialNumToRender*2;var windowSize=maxToRenderPerBatch;var specificProps=!this._needsScrollView()?{initialNumToRender:initialNumToRender,maxToRenderPerBatch:maxToRenderPerBatch,windowSize:windowSize}:{};return _objectSpread({decelerationRate:enableMomentum?0.9:'fast',showsHorizontalScrollIndicator:false,showsVerticalScrollIndicator:false,overScrollMode:'never',automaticallyAdjustContentInsets:false,directionalLockEnabled:true,pinchGestureEnabled:false,scrollsToTop:false,removeClippedSubviews:!this._needsScrollView(),inverted:this._needsRTLAdaptations()},specificProps);}},{key:"_getComponentStaticProps",value:function _getComponentStaticProps(){var _this10=this;var hideCarousel=this.state.hideCarousel;var _this$props21=this.props,containerCustomStyle=_this$props21.containerCustomStyle,contentContainerCustomStyle=_this$props21.contentContainerCustomStyle,keyExtractor=_this$props21.keyExtractor,sliderWidth=_this$props21.sliderWidth,sliderHeight=_this$props21.sliderHeight,style=_this$props21.style,vertical=_this$props21.vertical;var containerStyle=[containerCustomStyle||style||{},hideCarousel?{opacity:0}:{},vertical?{height:sliderHeight,flexDirection:'column'}:{width:sliderWidth,flexDirection:this._needsRTLAdaptations()?'row-reverse':'row'}];var contentContainerStyle=[vertical?{paddingTop:this._getContainerInnerMargin(),paddingBottom:this._getContainerInnerMargin(true)}:{paddingLeft:this._getContainerInnerMargin(),paddingRight:this._getContainerInnerMargin(true)},contentContainerCustomStyle||{}];var specificProps=!this._needsScrollView()?{renderItem:this._renderItem,numColumns:1,getItemLayout:undefined,initialScrollIndex:undefined,keyExtractor:keyExtractor||this._getKeyExtractor}:{};return _objectSpread({ref:function ref(c){return _this10._carouselRef=c;},data:this._getCustomData(),style:containerStyle,contentContainerStyle:contentContainerStyle,horizontal:!vertical,scrollEventThrottle:1,onScroll:this._onScrollHandler,onScrollBeginDrag:this._onScrollBeginDrag,onScrollEndDrag:this._onScrollEndDrag,onMomentumScrollEnd:this._onMomentumScrollEnd,onResponderRelease:this._onTouchRelease,onStartShouldSetResponderCapture:this._onStartShouldSetResponderCapture,onTouchStart:this._onTouchStart,onTouchEnd:this._onScrollEnd,onLayout:this._onLayout},specificProps);}},{key:"render",value:function render(){var _this11=this;var _this$props22=this.props,data=_this$props22.data,renderItem=_this$props22.renderItem,useScrollView=_this$props22.useScrollView;if(!data||!renderItem){return null;}var props=_objectSpread(_objectSpread(_objectSpread({},this._getComponentOverridableProps()),this.props),this._getComponentStaticProps());var ScrollViewComponent=typeof useScrollView==='function'?useScrollView:AnimatedScrollView;return this._needsScrollView()?_react.default.createElement(ScrollViewComponent,(0,_extends2.default)({},props,{__source:{fileName:_jsxFileName,lineNumber:1289,columnNumber:13}}),this._getCustomData().map(function(item,index){return _this11._renderItem({item:item,index:index,realIndex:_this11._getDataIndex(index),activeIndex:_this11._getDataIndex(_this11._activeItem)});})):_react.default.createElement(AnimatedFlatList,(0,_extends2.default)({},props,{__source:{fileName:_jsxFileName,lineNumber:1297,columnNumber:13}}));}}]);return Carousel;}(_react.PureComponent);exports.default=Carousel;Carousel.propTypes={data:_propTypes.default.array.isRequired,renderItem:_propTypes.default.func.isRequired,itemWidth:_propTypes.default.number,itemHeight:_propTypes.default.number,sliderWidth:_propTypes.default.number,sliderHeight:_propTypes.default.number,activeAnimationType:_propTypes.default.string,activeAnimationOptions:_propTypes.default.object,activeSlideAlignment:_propTypes.default.oneOf(['center','end','start']),activeSlideOffset:_propTypes.default.number,apparitionDelay:_propTypes.default.number,autoplay:_propTypes.default.bool,autoplayDelay:_propTypes.default.number,autoplayInterval:_propTypes.default.number,callbackOffsetMargin:_propTypes.default.number,containerCustomStyle:_propTypes.default.oneOfType([_propTypes.default.object,_propTypes.default.array]),contentContainerCustomStyle:_propTypes.default.oneOfType([_propTypes.default.object,_propTypes.default.array]),enableMomentum:_propTypes.default.bool,enableSnap:_propTypes.default.bool,firstItem:_propTypes.default.number,hasParallaxImages:_propTypes.default.bool,inactiveSlideOpacity:_propTypes.default.number,inactiveSlideScale:_propTypes.default.number,inactiveSlideShift:_propTypes.default.number,layout:_propTypes.default.oneOf(['default','stack','tinder']),layoutCardOffset:_propTypes.default.number,lockScrollTimeoutDuration:_propTypes.default.number,lockScrollWhileSnapping:_propTypes.default.bool,loop:_propTypes.default.bool,loopClonesPerSide:_propTypes.default.number,scrollEnabled:_propTypes.default.bool,scrollInterpolator:_propTypes.default.func,slideInterpolatedStyle:_propTypes.default.func,slideStyle:_propTypes.default.object,shouldOptimizeUpdates:_propTypes.default.bool,swipeThreshold:_propTypes.default.number,useScrollView:_propTypes.default.oneOfType([_propTypes.default.bool,_propTypes.default.func]),vertical:_propTypes.default.bool,showsPagination:_propTypes.default.bool,isCustomScrollWidth:_propTypes.default.bool,onBeforeSnapToItem:_propTypes.default.func,onSnapToItem:_propTypes.default.func};Carousel.defaultProps={activeAnimationType:'timing',activeAnimationOptions:null,activeSlideAlignment:'center',activeSlideOffset:20,apparitionDelay:0,autoplay:false,autoplayDelay:1000,autoplayInterval:3000,callbackOffsetMargin:5,containerCustomStyle:{},contentContainerCustomStyle:{},enableMomentum:false,enableSnap:true,firstItem:0,hasParallaxImages:false,inactiveSlideOpacity:0.7,inactiveSlideScale:0.9,inactiveSlideShift:0,layout:'default',lockScrollTimeoutDuration:1000,lockScrollWhileSnapping:false,loop:false,loopClonesPerSide:3,scrollEnabled:true,slideStyle:{},shouldOptimizeUpdates:true,swipeThreshold:20,useScrollView:!AnimatedFlatList,vertical:false,showsPagination:true,isCustomScrollWidth:false};
1
+ /* eslint-disable no-undef */
2
+ /* eslint-disable no-lonely-if */
3
+ /* eslint-disable no-param-reassign */
4
+ /* eslint-disable react/jsx-props-no-spreading */
5
+ import React, { PureComponent } from 'react';
6
+ import {
7
+ Animated, Easing, FlatList, I18nManager, Platform, ScrollView, View, ViewPropTypes
8
+ } from 'react-native';
9
+ import PropTypes from 'prop-types';
10
+ import {
11
+ defaultScrollInterpolator,
12
+ stackScrollInterpolator,
13
+ tinderScrollInterpolator,
14
+ defaultAnimatedStyles,
15
+ shiftAnimatedStyles,
16
+ stackAnimatedStyles,
17
+ tinderAnimatedStyles
18
+ } from './utils/animation';
19
+
20
+ const IS_IOS = Platform.OS === 'ios';
21
+
22
+ // Native driver for scroll events
23
+ // See: https://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html
24
+ const AnimatedFlatList = FlatList ? Animated.createAnimatedComponent(FlatList) : null;
25
+ const AnimatedScrollView = Animated.createAnimatedComponent(ScrollView);
26
+
27
+ // React Native automatically handles RTL layouts; unfortunately, it's buggy with horizontal ScrollView
28
+ // See https://github.com/facebook/react-native/issues/11960
29
+ // NOTE: the following variable is not declared in the constructor
30
+ // otherwise it is undefined at init, which messes with custom indexes
31
+ const IS_RTL = I18nManager.isRTL;
32
+
33
+ export default class Carousel extends PureComponent {
34
+ constructor(props) {
35
+ super(props);
36
+
37
+ this.state = {
38
+ hideCarousel: true,
39
+ interpolators: []
40
+ };
41
+
42
+ // The following values are not stored in the state because 'setState()' is asynchronous
43
+ // and this results in an absolutely crappy behavior on Android while swiping (see #156)
44
+ const initialActiveItem = this._getFirstItem(props.firstItem);
45
+ this._activeItem = initialActiveItem;
46
+ this._previousActiveItem = initialActiveItem;
47
+ this._previousFirstItem = initialActiveItem;
48
+ this._previousItemsLength = initialActiveItem;
49
+
50
+ this._mounted = false;
51
+ this._positions = [];
52
+ this._currentContentOffset = 0; // store ScrollView's scroll position
53
+ this._canFireBeforeCallback = false;
54
+ this._canFireCallback = false;
55
+ this._scrollOffsetRef = null;
56
+ this._onScrollTriggered = true; // used when momentum is enabled to prevent an issue with edges items
57
+ this._lastScrollDate = 0; // used to work around a FlatList bug
58
+ this._scrollEnabled = props.scrollEnabled !== false;
59
+
60
+ this._initPositionsAndInterpolators = this._initPositionsAndInterpolators.bind(this);
61
+ this._renderItem = this._renderItem.bind(this);
62
+ this._onSnap = this._onSnap.bind(this);
63
+
64
+ this._onLayout = this._onLayout.bind(this);
65
+ this._onScroll = this._onScroll.bind(this);
66
+ this._onScrollBeginDrag = props.enableSnap ? this._onScrollBeginDrag.bind(this) : undefined;
67
+ this._onScrollEnd = props.enableSnap || props.autoplay ? this._onScrollEnd.bind(this) : undefined;
68
+ this._onScrollEndDrag = !props.enableMomentum ? this._onScrollEndDrag.bind(this) : undefined;
69
+ this._onMomentumScrollEnd = props.enableMomentum ? this._onMomentumScrollEnd.bind(this) : undefined;
70
+ this._onTouchStart = this._onTouchStart.bind(this);
71
+ this._onTouchEnd = this._onTouchEnd.bind(this);
72
+ this._onTouchRelease = this._onTouchRelease.bind(this);
73
+
74
+ this._getKeyExtractor = this._getKeyExtractor.bind(this);
75
+
76
+ this._setScrollHandler(props);
77
+
78
+ // This bool aims at fixing an iOS bug due to scrollTo that triggers onMomentumScrollEnd.
79
+ // onMomentumScrollEnd fires this._snapScroll, thus creating an infinite loop.
80
+ this._ignoreNextMomentum = false;
81
+ this._animated = false;
82
+
83
+ // Warnings
84
+ if (!ViewPropTypes) {
85
+ console.warn(`react-native-snap-carousel:
86
+ It is recommended to use at least version 0.44 of React Native with the plugin`);
87
+ }
88
+ if (!props.vertical && (!props.sliderWidth || !props.itemWidth)) {
89
+ console.warn(`react-native-snap-carousel: You need to specify both sliderWidth and itemWidth
90
+ for horizontal carousels`);
91
+ }
92
+ if (props.vertical && (!props.sliderHeight || !props.itemHeight)) {
93
+ console.warn(`react-native-snap-carousel: You need to specify both sliderHeight and itemHeight
94
+ for vertical carousels`);
95
+ }
96
+ if (props.apparitionDelay && !IS_IOS && !props.useScrollView) {
97
+ console.warn(`react-native-snap-carousel: Using apparitionDelay on Android
98
+ is not recommended since it can lead to rendering issues`);
99
+ }
100
+ if (props.customAnimationType || props.customAnimationOptions) {
101
+ console.warn(`react-native-snap-carousel: Props customAnimationType and
102
+ customAnimationOptions have been renamed to activeAnimationType and activeAnimationOptions`);
103
+ }
104
+ if (props.onScrollViewScroll) {
105
+ console.warn(`react-native-snap-carousel: Prop onScrollViewScroll has been removed.
106
+ Use onScroll instead`);
107
+ }
108
+ }
109
+
110
+ componentDidMount() {
111
+ const { apparitionDelay, autoplay, firstItem } = this.props;
112
+ const _firstItem = this._getFirstItem(firstItem);
113
+ const apparitionCallback = () => {
114
+ this.setState({ hideCarousel: false });
115
+ if (autoplay) {
116
+ this.startAutoplay();
117
+ }
118
+ };
119
+
120
+ this._mounted = true;
121
+ this._initPositionsAndInterpolators();
122
+
123
+ // Without 'requestAnimationFrame' or a `0` timeout, images will randomly not be rendered on Android...
124
+ requestAnimationFrame(() => {
125
+ if (!this._mounted) {
126
+ return;
127
+ }
128
+
129
+ this._snapToItem(_firstItem, false, false, true, false);
130
+ this._hackActiveSlideAnimation(_firstItem, 'start', true);
131
+
132
+ if (apparitionDelay) {
133
+ this._apparitionTimeout = setTimeout(() => {
134
+ apparitionCallback();
135
+ }, apparitionDelay);
136
+ } else {
137
+ apparitionCallback();
138
+ }
139
+ });
140
+ }
141
+
142
+ // shouldComponentUpdate(nextProps, nextState) {
143
+ // const { shouldOptimizeUpdates } = this.props;
144
+ // if (shouldOptimizeUpdates === false) {
145
+ // return true;
146
+ // }
147
+ // if (shallowCompare(this.props, nextProps)) {
148
+ // return true;
149
+ // }
150
+ // if (shallowCompare(this.state, nextState)) {
151
+ // return true;
152
+ // }
153
+ // return false;
154
+ // }
155
+
156
+ UNSAFE_componentWillReceiveProps(nextProps) {
157
+ const { interpolators } = this.state;
158
+ const {
159
+ itemHeight, itemWidth, scrollEnabled, sliderHeight, sliderWidth, onScroll
160
+ } = this.props;
161
+ const itemsLength = this._getCustomDataLength(nextProps);
162
+
163
+ if (!itemsLength) {
164
+ return;
165
+ }
166
+
167
+ const nextFirstItem = this._getFirstItem(nextProps.firstItem, nextProps);
168
+ let nextActiveItem = this._activeItem || this._activeItem === 0 ? this._activeItem : nextFirstItem;
169
+
170
+ const hasNewSliderWidth = nextProps.sliderWidth && nextProps.sliderWidth !== sliderWidth;
171
+ const hasNewSliderHeight = nextProps.sliderHeight && nextProps.sliderHeight !== sliderHeight;
172
+ const hasNewItemWidth = nextProps.itemWidth && nextProps.itemWidth !== itemWidth;
173
+ const hasNewItemHeight = nextProps.itemHeight && nextProps.itemHeight !== itemHeight;
174
+ const hasNewScrollEnabled = nextProps.scrollEnabled !== scrollEnabled;
175
+
176
+ // Prevent issues with dynamically removed items
177
+ if (nextActiveItem > itemsLength - 1) {
178
+ nextActiveItem = itemsLength - 1;
179
+ }
180
+
181
+ // Handle changing scrollEnabled independent of user -> carousel interaction
182
+ if (hasNewScrollEnabled) {
183
+ this._setScrollEnabled(nextProps.scrollEnabled);
184
+ }
185
+
186
+ if (interpolators.length !== itemsLength || hasNewSliderWidth
187
+ || hasNewSliderHeight || hasNewItemWidth || hasNewItemHeight) {
188
+ this._activeItem = nextActiveItem;
189
+ this._previousItemsLength = itemsLength;
190
+
191
+ this._initPositionsAndInterpolators(nextProps);
192
+
193
+ // Handle scroll issue when dynamically removing items (see #133)
194
+ // This also fixes first item's active state on Android
195
+ // Because 'initialScrollIndex' apparently doesn't trigger scroll
196
+ if (this._previousItemsLength > itemsLength) {
197
+ this._hackActiveSlideAnimation(nextActiveItem, null, true);
198
+ }
199
+
200
+ if (hasNewSliderWidth || hasNewSliderHeight || hasNewItemWidth || hasNewItemHeight) {
201
+ this._snapToItem(nextActiveItem, false, false, false, false);
202
+ }
203
+ } else if (nextFirstItem !== this._previousFirstItem && nextFirstItem !== this._activeItem) {
204
+ this._activeItem = nextFirstItem;
205
+ this._previousFirstItem = nextFirstItem;
206
+ this._snapToItem(nextFirstItem, false, true, false, false);
207
+ }
208
+
209
+ if (nextProps.onScroll !== onScroll) {
210
+ this._setScrollHandler(nextProps);
211
+ }
212
+ }
213
+
214
+ componentWillUnmount() {
215
+ this._mounted = false;
216
+ this.stopAutoplay();
217
+ clearTimeout(this._apparitionTimeout);
218
+ clearTimeout(this._hackSlideAnimationTimeout);
219
+ clearTimeout(this._enableAutoplayTimeout);
220
+ clearTimeout(this._autoplayTimeout);
221
+ clearTimeout(this._snapNoMomentumTimeout);
222
+ clearTimeout(this._edgeItemTimeout);
223
+ clearTimeout(this._lockScrollTimeout);
224
+ }
225
+
226
+ get realIndex() {
227
+ return this._activeItem;
228
+ }
229
+
230
+ get currentIndex() {
231
+ return this._getDataIndex(this._activeItem);
232
+ }
233
+
234
+ get currentScrollPosition() {
235
+ return this._currentContentOffset;
236
+ }
237
+
238
+ _setScrollHandler(props) {
239
+ // Native driver for scroll events
240
+ const scrollEventConfig = {
241
+ listener: this._onScroll,
242
+ useNativeDriver: true,
243
+ };
244
+ this._scrollPos = new Animated.Value(0);
245
+ const argMapping = props.vertical
246
+ ? [{ nativeEvent: { contentOffset: { y: this._scrollPos } } }]
247
+ : [{ nativeEvent: { contentOffset: { x: this._scrollPos } } }];
248
+
249
+ if (props.onScroll && Array.isArray(props.onScroll._argMapping)) {
250
+ // Because of a react-native issue https://github.com/facebook/react-native/issues/13294
251
+ argMapping.pop();
252
+ const [argMap] = props.onScroll._argMapping;
253
+ if (argMap && argMap.nativeEvent && argMap.nativeEvent.contentOffset) {
254
+ // Shares the same animated value passed in props
255
+ this._scrollPos = argMap.nativeEvent.contentOffset.x
256
+ || argMap.nativeEvent.contentOffset.y
257
+ || this._scrollPos;
258
+ }
259
+ argMapping.push(...props.onScroll._argMapping);
260
+ }
261
+ this._onScrollHandler = Animated.event(
262
+ argMapping,
263
+ scrollEventConfig
264
+ );
265
+ }
266
+
267
+ _needsScrollView() {
268
+ const { useScrollView } = this.props;
269
+ return useScrollView || !AnimatedFlatList || this._shouldUseStackLayout() || this._shouldUseTinderLayout();
270
+ }
271
+
272
+ _needsRTLAdaptations() {
273
+ const { vertical } = this.props;
274
+ return IS_RTL && !IS_IOS && !vertical;
275
+ }
276
+
277
+ _canLockScroll() {
278
+ const { scrollEnabled, enableMomentum, lockScrollWhileSnapping } = this.props;
279
+ return scrollEnabled && !enableMomentum && lockScrollWhileSnapping;
280
+ }
281
+
282
+ _enableLoop() {
283
+ const { data, enableSnap, loop } = this.props;
284
+ return enableSnap && loop && data && data.length && data.length > 1;
285
+ }
286
+
287
+ _shouldAnimateSlides(props = this.props) {
288
+ const {
289
+ inactiveSlideOpacity, inactiveSlideScale, scrollInterpolator, slideInterpolatedStyle
290
+ } = props;
291
+ return inactiveSlideOpacity < 1
292
+ || inactiveSlideScale < 1
293
+ || !!scrollInterpolator
294
+ || !!slideInterpolatedStyle
295
+ || this._shouldUseShiftLayout()
296
+ || this._shouldUseStackLayout()
297
+ || this._shouldUseTinderLayout();
298
+ }
299
+
300
+ _shouldUseCustomAnimation() {
301
+ const { activeAnimationOptions } = this.props;
302
+ return !!activeAnimationOptions && !this._shouldUseStackLayout() && !this._shouldUseTinderLayout();
303
+ }
304
+
305
+ _shouldUseShiftLayout() {
306
+ const { inactiveSlideShift, layout } = this.props;
307
+ return layout === 'default' && inactiveSlideShift !== 0;
308
+ }
309
+
310
+ _shouldUseStackLayout() {
311
+ const { layout } = this.props;
312
+ return layout === 'stack';
313
+ }
314
+
315
+ _shouldUseTinderLayout() {
316
+ const { layout } = this.props;
317
+ return layout === 'tinder';
318
+ }
319
+
320
+ _getCustomData(props = this.props) {
321
+ const { data, loopClonesPerSide } = props;
322
+ const dataLength = data && data.length;
323
+
324
+ if (!dataLength) {
325
+ return [];
326
+ }
327
+
328
+ if (!this._enableLoop()) {
329
+ return data;
330
+ }
331
+
332
+ let previousItems = [];
333
+ let nextItems = [];
334
+
335
+ if (loopClonesPerSide > dataLength) {
336
+ const dataMultiplier = Math.floor(loopClonesPerSide / dataLength);
337
+ const remainder = loopClonesPerSide % dataLength;
338
+
339
+ for (let i = 0; i < dataMultiplier; i += 1) {
340
+ previousItems.push(...data);
341
+ nextItems.push(...data);
342
+ }
343
+
344
+ previousItems.unshift(...data.slice(-remainder));
345
+ nextItems.push(...data.slice(0, remainder));
346
+ } else {
347
+ previousItems = data.slice(-loopClonesPerSide);
348
+ nextItems = data.slice(0, loopClonesPerSide);
349
+ }
350
+ return previousItems.concat(data, nextItems);
351
+ }
352
+
353
+ _getCustomDataLength(props = this.props) {
354
+ const { data, loopClonesPerSide } = props;
355
+ const dataLength = data && data.length;
356
+
357
+ if (!dataLength) {
358
+ return 0;
359
+ }
360
+
361
+ return this._enableLoop() ? dataLength + (2 * loopClonesPerSide) : dataLength;
362
+ }
363
+
364
+ _getCustomIndex(index, props = this.props) {
365
+ const itemsLength = this._getCustomDataLength(props);
366
+
367
+ if (!itemsLength || (!index && index !== 0)) {
368
+ return 0;
369
+ }
370
+
371
+ return this._needsRTLAdaptations() ? itemsLength - index - 1 : index;
372
+ }
373
+
374
+ _getDataIndex(index) {
375
+ const { data, loopClonesPerSide } = this.props;
376
+ const dataLength = data && data.length;
377
+
378
+ if (!this._enableLoop() || !dataLength) {
379
+ return index;
380
+ }
381
+
382
+ if (index >= dataLength + loopClonesPerSide) {
383
+ return loopClonesPerSide > dataLength
384
+ ? (index - loopClonesPerSide) % dataLength
385
+ : index - dataLength - loopClonesPerSide;
386
+ } if (index < loopClonesPerSide) {
387
+ // TODO: is there a simpler way of determining the interpolated index?
388
+ if (loopClonesPerSide > dataLength) {
389
+ const baseDataIndexes = [];
390
+ const dataIndexes = [];
391
+ const dataMultiplier = Math.floor(loopClonesPerSide / dataLength);
392
+ const remainder = loopClonesPerSide % dataLength;
393
+
394
+ for (let i = 0; i < dataLength; i += 1) {
395
+ baseDataIndexes.push(i);
396
+ }
397
+
398
+ for (let j = 0; j < dataMultiplier; j += 1) {
399
+ dataIndexes.push(...baseDataIndexes);
400
+ }
401
+
402
+ dataIndexes.unshift(...baseDataIndexes.slice(-remainder));
403
+ return dataIndexes[index];
404
+ }
405
+ return index + dataLength - loopClonesPerSide;
406
+ }
407
+ return index - loopClonesPerSide;
408
+ }
409
+
410
+ // Used with `snapToItem()` and 'PaginationDot'
411
+ _getPositionIndex(index) {
412
+ const { loop, loopClonesPerSide } = this.props;
413
+ return loop ? index + loopClonesPerSide : index;
414
+ }
415
+
416
+ _getFirstItem(index, props = this.props) {
417
+ const { loopClonesPerSide } = props;
418
+ const itemsLength = this._getCustomDataLength(props);
419
+
420
+ if (!itemsLength || index > itemsLength - 1 || index < 0) {
421
+ return 0;
422
+ }
423
+
424
+ return this._enableLoop() ? index + loopClonesPerSide : index;
425
+ }
426
+
427
+ _getWrappedRef() {
428
+ if (this._carouselRef && (
429
+ (this._needsScrollView() && this._carouselRef.scrollTo)
430
+ || (!this._needsScrollView() && this._carouselRef.scrollToOffset)
431
+ )) {
432
+ return this._carouselRef;
433
+ }
434
+ // https://github.com/facebook/react-native/issues/10635
435
+ // https://stackoverflow.com/a/48786374/8412141
436
+ return this._carouselRef && this._carouselRef.getNode && this._carouselRef.getNode();
437
+ }
438
+
439
+ _getScrollEnabled() {
440
+ return this._scrollEnabled;
441
+ }
442
+
443
+ _setScrollEnabled(scrollEnabled = true) {
444
+ const wrappedRef = this._getWrappedRef();
445
+
446
+ if (!wrappedRef || !wrappedRef.setNativeProps) {
447
+ return;
448
+ }
449
+
450
+ // 'setNativeProps()' is used instead of 'setState()' because the latter
451
+ // really takes a toll on Android behavior when momentum is disabled
452
+ wrappedRef.setNativeProps({ scrollEnabled });
453
+ this._scrollEnabled = scrollEnabled;
454
+ }
455
+
456
+ _getKeyExtractor(item, index) {
457
+ return this._needsScrollView() ? `scrollview-item-${index}` : `flatlist-item-${index}`;
458
+ }
459
+
460
+ _getScrollOffset(event) {
461
+ const { vertical } = this.props;
462
+ return (event && event.nativeEvent && event.nativeEvent.contentOffset
463
+ && event.nativeEvent.contentOffset[vertical ? 'y' : 'x']) || 0;
464
+ }
465
+
466
+ _getContainerInnerMargin(opposite = false) {
467
+ const {
468
+ sliderWidth, sliderHeight, itemWidth, itemHeight, vertical, activeSlideAlignment
469
+ } = this.props;
470
+
471
+ if ((activeSlideAlignment === 'start' && !opposite)
472
+ || (activeSlideAlignment === 'end' && opposite)) {
473
+ return 0;
474
+ } if ((activeSlideAlignment === 'end' && !opposite)
475
+ || (activeSlideAlignment === 'start' && opposite)) {
476
+ return vertical ? sliderHeight - itemHeight : sliderWidth - itemWidth;
477
+ }
478
+ return vertical ? (sliderHeight - itemHeight) / 2 : (sliderWidth - itemWidth) / 2;
479
+ }
480
+
481
+ _getViewportOffset() {
482
+ const {
483
+ sliderWidth, sliderHeight, itemWidth, itemHeight, vertical, activeSlideAlignment
484
+ } = this.props;
485
+
486
+ if (activeSlideAlignment === 'start') {
487
+ return vertical ? itemHeight / 2 : itemWidth / 2;
488
+ } if (activeSlideAlignment === 'end') {
489
+ return vertical
490
+ ? sliderHeight - (itemHeight / 2)
491
+ : sliderWidth - (itemWidth / 2);
492
+ }
493
+ return vertical ? sliderHeight / 2 : sliderWidth / 2;
494
+ }
495
+
496
+ _getCenter(offset) {
497
+ return offset + this._getViewportOffset() - this._getContainerInnerMargin();
498
+ }
499
+
500
+ _getActiveItem(offset) {
501
+ const { activeSlideOffset, swipeThreshold } = this.props;
502
+ const center = this._getCenter(offset);
503
+ const centerOffset = activeSlideOffset || swipeThreshold;
504
+
505
+ for (let i = 0; i < this._positions.length; i += 1) {
506
+ const { start, end } = this._positions[i];
507
+ if (center + centerOffset >= start && center - centerOffset <= end) {
508
+ return i;
509
+ }
510
+ }
511
+
512
+ const lastIndex = this._positions.length - 1;
513
+ if (this._positions[lastIndex] && center - centerOffset > this._positions[lastIndex].end) {
514
+ return lastIndex;
515
+ }
516
+
517
+ return 0;
518
+ }
519
+
520
+ _initPositionsAndInterpolators(props = this.props) {
521
+ const {
522
+ data, itemWidth, itemHeight, scrollInterpolator, vertical
523
+ } = props;
524
+ const sizeRef = vertical ? itemHeight : itemWidth;
525
+
526
+ if (!data || !data.length) {
527
+ return;
528
+ }
529
+
530
+ const interpolators = [];
531
+ this._positions = [];
532
+
533
+ this._getCustomData(props).forEach((itemData, index) => {
534
+ const _index = this._getCustomIndex(index, props);
535
+ let animatedValue;
536
+
537
+ this._positions[index] = {
538
+ start: index * sizeRef,
539
+ end: index * sizeRef + sizeRef
540
+ };
541
+
542
+ if (!this._shouldAnimateSlides(props)) {
543
+ animatedValue = new Animated.Value(1);
544
+ } else if (this._shouldUseCustomAnimation()) {
545
+ animatedValue = new Animated.Value(_index === this._activeItem ? 1 : 0);
546
+ } else {
547
+ let interpolator;
548
+
549
+ if (scrollInterpolator) {
550
+ interpolator = scrollInterpolator(_index, props);
551
+ } else if (this._shouldUseStackLayout()) {
552
+ interpolator = stackScrollInterpolator(_index, props);
553
+ } else if (this._shouldUseTinderLayout()) {
554
+ interpolator = tinderScrollInterpolator(_index, props);
555
+ }
556
+
557
+ if (!interpolator || !interpolator?.inputRange || !interpolator?.outputRange) {
558
+ interpolator = defaultScrollInterpolator(_index, props);
559
+ }
560
+
561
+ animatedValue = this._scrollPos.interpolate({
562
+ ...interpolator,
563
+ extrapolate: 'clamp'
564
+ });
565
+ }
566
+
567
+ interpolators.push(animatedValue);
568
+ });
569
+ this.setState({ interpolators });
570
+ }
571
+
572
+ _getSlideAnimation(index, toValue) {
573
+ const { interpolators } = this.state;
574
+ const { activeAnimationType, activeAnimationOptions } = this.props;
575
+
576
+ const animatedValue = interpolators && interpolators[index];
577
+
578
+ if (!animatedValue && animatedValue !== 0) {
579
+ return null;
580
+ }
581
+
582
+ const animationCommonOptions = {
583
+ isInteraction: false,
584
+ useNativeDriver: true,
585
+ ...activeAnimationOptions,
586
+ toValue
587
+ };
588
+
589
+ return Animated.parallel([
590
+ Animated.timing(
591
+ animatedValue,
592
+ { ...animationCommonOptions, easing: Easing.linear }
593
+ ),
594
+ Animated[activeAnimationType](
595
+ animatedValue,
596
+ { ...animationCommonOptions }
597
+ )
598
+ ]);
599
+ }
600
+
601
+ _playCustomSlideAnimation(current, next) {
602
+ const { interpolators } = this.state;
603
+ const itemsLength = this._getCustomDataLength();
604
+ const _currentIndex = this._getCustomIndex(current);
605
+ const _currentDataIndex = this._getDataIndex(_currentIndex);
606
+ const _nextIndex = this._getCustomIndex(next);
607
+ const _nextDataIndex = this._getDataIndex(_nextIndex);
608
+ const animations = [];
609
+
610
+ // Keep animations in sync when looping
611
+ if (this._enableLoop()) {
612
+ for (let i = 0; i < itemsLength; i += 1) {
613
+ if (this._getDataIndex(i) === _currentDataIndex && interpolators[i]) {
614
+ animations.push(this._getSlideAnimation(i, 0));
615
+ } else if (this._getDataIndex(i) === _nextDataIndex && interpolators[i]) {
616
+ animations.push(this._getSlideAnimation(i, 1));
617
+ }
618
+ }
619
+ } else {
620
+ if (interpolators[current]) {
621
+ animations.push(this._getSlideAnimation(current, 0));
622
+ }
623
+ if (interpolators[next]) {
624
+ animations.push(this._getSlideAnimation(next, 1));
625
+ }
626
+ }
627
+
628
+ Animated.parallel(animations, { stopTogether: false }).start();
629
+ }
630
+
631
+ _hackActiveSlideAnimation(index, goTo, force = false) {
632
+ const { data } = this.props;
633
+
634
+ if (!this._mounted || !this._carouselRef || !this._positions[index] || (!force && this._enableLoop())) {
635
+ return;
636
+ }
637
+
638
+ const offset = this._positions[index] && this._positions[index].start;
639
+
640
+ if (!offset && offset !== 0) {
641
+ return;
642
+ }
643
+
644
+ const itemsLength = data && data.length;
645
+ const direction = goTo || itemsLength === 1 ? 'start' : 'end';
646
+
647
+ this._scrollTo(offset + (direction === 'start' ? -1 : 1), false);
648
+
649
+ clearTimeout(this._hackSlideAnimationTimeout);
650
+ this._hackSlideAnimationTimeout = setTimeout(() => {
651
+ this._scrollTo(offset, false);
652
+ }, 50); // works randomly when set to '0'
653
+ }
654
+
655
+ _lockScroll() {
656
+ const { lockScrollTimeoutDuration } = this.props;
657
+ clearTimeout(this._lockScrollTimeout);
658
+ this._lockScrollTimeout = setTimeout(() => {
659
+ this._releaseScroll();
660
+ }, lockScrollTimeoutDuration);
661
+ this._setScrollEnabled(false);
662
+ }
663
+
664
+ _releaseScroll() {
665
+ clearTimeout(this._lockScrollTimeout);
666
+ this._setScrollEnabled(true);
667
+ }
668
+
669
+ _repositionScroll(index) {
670
+ const { data, loopClonesPerSide } = this.props;
671
+ const dataLength = data && data.length;
672
+
673
+ if (!this._enableLoop() || !dataLength
674
+ || (index >= loopClonesPerSide && index < dataLength + loopClonesPerSide)) {
675
+ return;
676
+ }
677
+
678
+ let repositionTo = index;
679
+
680
+ if (index >= dataLength + loopClonesPerSide) {
681
+ repositionTo = index - dataLength;
682
+ } else if (index < loopClonesPerSide) {
683
+ repositionTo = index + dataLength;
684
+ }
685
+ this._snapToItem(repositionTo, false, false, false, false);
686
+ }
687
+
688
+ _scrollTo(offset, animated = true) {
689
+ const { vertical } = this.props;
690
+ const wrappedRef = this._getWrappedRef();
691
+
692
+ if (!this._mounted || !wrappedRef) {
693
+ return;
694
+ }
695
+
696
+ const specificOptions = this._needsScrollView() ? {
697
+ x: vertical ? 0 : offset,
698
+ y: vertical ? offset : 0
699
+ } : {
700
+ offset
701
+ };
702
+ const options = {
703
+ ...specificOptions,
704
+ animated
705
+ };
706
+
707
+ setTimeout(() => {
708
+ if (this._needsScrollView()) {
709
+ wrappedRef.scrollTo(options);
710
+ } else {
711
+ wrappedRef.scrollToOffset(options);
712
+ }
713
+ }, (!animated && this._animated) ? 200 : 0);
714
+
715
+ this._animated = animated;
716
+ }
717
+
718
+ _onScroll(event) {
719
+ const { callbackOffsetMargin, enableMomentum, onScroll } = this.props;
720
+
721
+ const scrollOffset = event ? this._getScrollOffset(event) : this._currentContentOffset;
722
+ const nextActiveItem = this._getActiveItem(scrollOffset);
723
+ const itemReached = nextActiveItem === this._itemToSnapTo;
724
+ const scrollConditions = scrollOffset >= this._scrollOffsetRef - callbackOffsetMargin
725
+ && scrollOffset <= this._scrollOffsetRef + callbackOffsetMargin;
726
+
727
+ this._currentContentOffset = scrollOffset;
728
+ this._onScrollTriggered = true;
729
+ this._lastScrollDate = Date.now();
730
+
731
+ if (this._activeItem !== nextActiveItem && this._shouldUseCustomAnimation()) {
732
+ this._playCustomSlideAnimation(this._activeItem, nextActiveItem);
733
+ }
734
+
735
+ if (enableMomentum) {
736
+ clearTimeout(this._snapNoMomentumTimeout);
737
+
738
+ if (this._activeItem !== nextActiveItem) {
739
+ this._activeItem = nextActiveItem;
740
+ }
741
+
742
+ if (itemReached) {
743
+ if (this._canFireBeforeCallback) {
744
+ this._onBeforeSnap(this._getDataIndex(nextActiveItem));
745
+ }
746
+
747
+ if (scrollConditions && this._canFireCallback) {
748
+ this._onSnap(this._getDataIndex(nextActiveItem));
749
+ }
750
+ }
751
+ } else if (this._activeItem !== nextActiveItem && itemReached) {
752
+ if (this._canFireBeforeCallback) {
753
+ this._onBeforeSnap(this._getDataIndex(nextActiveItem));
754
+ }
755
+
756
+ if (scrollConditions) {
757
+ this._activeItem = nextActiveItem;
758
+
759
+ if (this._canLockScroll()) {
760
+ this._releaseScroll();
761
+ }
762
+
763
+ if (this._canFireCallback) {
764
+ this._onSnap(this._getDataIndex(nextActiveItem));
765
+ }
766
+ }
767
+ }
768
+ if (nextActiveItem === this._itemToSnapTo
769
+ && scrollOffset === this._scrollOffsetRef) {
770
+ this._repositionScroll(nextActiveItem);
771
+ }
772
+
773
+ if (typeof onScroll === 'function' && event) {
774
+ onScroll(event);
775
+ }
776
+ }
777
+
778
+ _onStartShouldSetResponderCapture(event) {
779
+ const { onStartShouldSetResponderCapture } = this.props;
780
+
781
+ if (onStartShouldSetResponderCapture) {
782
+ onStartShouldSetResponderCapture(event);
783
+ }
784
+
785
+ return this._getScrollEnabled();
786
+ }
787
+
788
+ _onTouchStart() {
789
+ const { onTouchStart } = this.props;
790
+
791
+ // `onTouchStart` is fired even when `scrollEnabled` is set to `false`
792
+ if (this._getScrollEnabled() !== false && this._autoplaying) {
793
+ this.stopAutoplay();
794
+ }
795
+
796
+ if (onTouchStart) {
797
+ onTouchStart();
798
+ }
799
+ }
800
+
801
+ _onTouchEnd() {
802
+ const { onTouchEnd, autoplay } = this.props;
803
+
804
+ if (this._getScrollEnabled() !== false && autoplay && !this._autoplaying) {
805
+ // This event is buggy on Android, so a fallback is provided in _onScrollEnd()
806
+ this.startAutoplay();
807
+ }
808
+
809
+ if (onTouchEnd) {
810
+ onTouchEnd();
811
+ }
812
+ }
813
+
814
+ // Used when `enableSnap` is ENABLED
815
+ _onScrollBeginDrag(event) {
816
+ const { onScrollBeginDrag } = this.props;
817
+
818
+ if (!this._getScrollEnabled()) {
819
+ return;
820
+ }
821
+
822
+ this._scrollStartOffset = this._getScrollOffset(event);
823
+ this._scrollStartActive = this._getActiveItem(this._scrollStartOffset);
824
+ this._ignoreNextMomentum = false;
825
+ // this._canFireCallback = false;
826
+
827
+ if (onScrollBeginDrag) {
828
+ onScrollBeginDrag(event);
829
+ }
830
+ }
831
+
832
+ // Used when `enableMomentum` is DISABLED
833
+ _onScrollEndDrag(event) {
834
+ const { onScrollEndDrag } = this.props;
835
+
836
+ if (this._carouselRef) {
837
+ if (this._onScrollEnd) this._onScrollEnd();
838
+ }
839
+
840
+ if (onScrollEndDrag) {
841
+ onScrollEndDrag(event);
842
+ }
843
+ }
844
+
845
+ // Used when `enableMomentum` is ENABLED
846
+ _onMomentumScrollEnd(event) {
847
+ const { onMomentumScrollEnd } = this.props;
848
+
849
+ if (this._carouselRef) {
850
+ if (this._onScrollEnd) this._onScrollEnd();
851
+ }
852
+
853
+ if (onMomentumScrollEnd) {
854
+ onMomentumScrollEnd(event);
855
+ }
856
+ }
857
+
858
+ _onScrollEnd() {
859
+ const { autoplay, autoplayDelay, enableSnap } = this.props;
860
+
861
+ if (this._ignoreNextMomentum) {
862
+ // iOS fix
863
+ this._ignoreNextMomentum = false;
864
+ return;
865
+ }
866
+
867
+ this._scrollEndOffset = this._currentContentOffset;
868
+ this._scrollEndActive = this._getActiveItem(this._scrollEndOffset);
869
+
870
+ if (enableSnap) {
871
+ this._snapScroll(this._scrollEndOffset - this._scrollStartOffset);
872
+ }
873
+
874
+ // The touchEnd event is buggy on Android, so this will serve as a fallback whenever needed
875
+ // https://github.com/facebook/react-native/issues/9439
876
+ if (autoplay && !this._autoplaying) {
877
+ clearTimeout(this._enableAutoplayTimeout);
878
+ this._enableAutoplayTimeout = setTimeout(() => {
879
+ this.startAutoplay();
880
+ }, autoplayDelay + 50);
881
+ }
882
+ }
883
+
884
+ // Due to a bug, this event is only fired on iOS
885
+ // https://github.com/facebook/react-native/issues/6791
886
+ // it's fine since we're only fixing an iOS bug in it, so ...
887
+ _onTouchRelease() {
888
+ const { enableMomentum } = this.props;
889
+
890
+ if (enableMomentum && IS_IOS) {
891
+ clearTimeout(this._snapNoMomentumTimeout);
892
+ this._snapNoMomentumTimeout = setTimeout(() => {
893
+ this._snapToItem(this._activeItem);
894
+ }, 100);
895
+ }
896
+ }
897
+
898
+ _onLayout(event) {
899
+ const { onLayout } = this.props;
900
+
901
+ // Prevent unneeded actions during the first 'onLayout' (triggered on init)
902
+ if (this._onLayoutInitDone) {
903
+ this._initPositionsAndInterpolators();
904
+ this._snapToItem(this._activeItem, false, false, false, false);
905
+ } else {
906
+ this._onLayoutInitDone = true;
907
+ }
908
+
909
+ if (onLayout) {
910
+ onLayout(event);
911
+ }
912
+ }
913
+
914
+ _snapScroll(delta) {
915
+ const { swipeThreshold } = this.props;
916
+
917
+ // When using momentum and releasing the touch with
918
+ // no velocity, scrollEndActive will be undefined (iOS)
919
+ if (!this._scrollEndActive && this._scrollEndActive !== 0 && IS_IOS) {
920
+ this._scrollEndActive = this._scrollStartActive;
921
+ }
922
+
923
+ if (this._scrollStartActive !== this._scrollEndActive) {
924
+ // Snap to the new active item
925
+ this._snapToItem(this._scrollEndActive);
926
+ } else {
927
+ // Snap depending on delta
928
+ if (delta > 0) {
929
+ if (delta > swipeThreshold) {
930
+ this._snapToItem(this._scrollStartActive + 1);
931
+ } else {
932
+ this._snapToItem(this._scrollEndActive);
933
+ }
934
+ } else if (delta < 0) {
935
+ if (delta < -swipeThreshold) {
936
+ this._snapToItem(this._scrollStartActive - 1);
937
+ } else {
938
+ this._snapToItem(this._scrollEndActive);
939
+ }
940
+ } else {
941
+ // Snap to current
942
+ this._snapToItem(this._scrollEndActive);
943
+ }
944
+ }
945
+ }
946
+
947
+ _snapToItem(index, animated = true, fireCallback = true, initial = false, lockScroll = true) {
948
+ const { enableMomentum, onSnapToItem, onBeforeSnapToItem } = this.props;
949
+ const itemsLength = this._getCustomDataLength();
950
+ const wrappedRef = this._getWrappedRef();
951
+
952
+ if (!itemsLength || !wrappedRef) {
953
+ return;
954
+ }
955
+
956
+ if (!index || index < 0) {
957
+ index = 0;
958
+ } else if (itemsLength > 0 && index >= itemsLength) {
959
+ index = itemsLength - 1;
960
+ }
961
+
962
+ if (index !== this._previousActiveItem) {
963
+ this._previousActiveItem = index;
964
+
965
+ // Placed here to allow overscrolling for edges items
966
+ if (lockScroll && this._canLockScroll()) {
967
+ this._lockScroll();
968
+ }
969
+
970
+ if (fireCallback) {
971
+ if (onBeforeSnapToItem) {
972
+ this._canFireBeforeCallback = true;
973
+ }
974
+
975
+ if (onSnapToItem) {
976
+ this._canFireCallback = true;
977
+ }
978
+ }
979
+ }
980
+
981
+ this._itemToSnapTo = index;
982
+ this._scrollOffsetRef = this._positions[index] && this._positions[index].start;
983
+ this._onScrollTriggered = false;
984
+
985
+ if (!this._scrollOffsetRef && this._scrollOffsetRef !== 0) {
986
+ return;
987
+ }
988
+
989
+ this._scrollTo(this._scrollOffsetRef, animated);
990
+
991
+ if (enableMomentum) {
992
+ // iOS fix, check the note in the constructor
993
+ if (IS_IOS && !initial) {
994
+ this._ignoreNextMomentum = true;
995
+ }
996
+
997
+ // When momentum is enabled and the user is overscrolling or swiping very quickly,
998
+ // 'onScroll' is not going to be triggered for edge items. Then callback won't be
999
+ // fired and loop won't work since the scrollview is not going to be repositioned.
1000
+ // As a workaround, '_onScroll()' will be called manually for these items if a given
1001
+ // condition hasn't been met after a small delay.
1002
+ // WARNING: this is ok only when relying on 'momentumScrollEnd', not with 'scrollEndDrag'
1003
+ if (index === 0 || index === itemsLength - 1) {
1004
+ clearTimeout(this._edgeItemTimeout);
1005
+ this._edgeItemTimeout = setTimeout(() => {
1006
+ if (!initial && index === this._activeItem && !this._onScrollTriggered) {
1007
+ this._onScroll();
1008
+ }
1009
+ }, 250);
1010
+ }
1011
+ }
1012
+ }
1013
+
1014
+ _onBeforeSnap(index) {
1015
+ const { onBeforeSnapToItem } = this.props;
1016
+
1017
+ if (!this._carouselRef) {
1018
+ return;
1019
+ }
1020
+
1021
+ this._canFireBeforeCallback = false;
1022
+ if (onBeforeSnapToItem) onBeforeSnapToItem(index);
1023
+ }
1024
+
1025
+ _onSnap(index) {
1026
+ const { onSnapToItem } = this.props;
1027
+
1028
+ if (!this._carouselRef) {
1029
+ return;
1030
+ }
1031
+
1032
+ this._canFireCallback = false;
1033
+ if (onSnapToItem) onSnapToItem(index);
1034
+ }
1035
+
1036
+ startAutoplay() {
1037
+ const { autoplayInterval, autoplayDelay } = this.props;
1038
+
1039
+ if (this._autoplaying) {
1040
+ return;
1041
+ }
1042
+
1043
+ clearTimeout(this._autoplayTimeout);
1044
+ this._autoplayTimeout = setTimeout(() => {
1045
+ this._autoplaying = true;
1046
+ this._autoplayInterval = setInterval(() => {
1047
+ if (this._autoplaying) {
1048
+ this.snapToNext();
1049
+ }
1050
+ }, autoplayInterval);
1051
+ }, autoplayDelay);
1052
+ }
1053
+
1054
+ stopAutoplay() {
1055
+ this._autoplaying = false;
1056
+ clearInterval(this._autoplayInterval);
1057
+ }
1058
+
1059
+ snapToItem(index, animated = true, fireCallback = true) {
1060
+ if (!index || index < 0) {
1061
+ index = 0;
1062
+ }
1063
+
1064
+ const positionIndex = this._getPositionIndex(index);
1065
+
1066
+ if (positionIndex === this._activeItem) {
1067
+ return;
1068
+ }
1069
+
1070
+ this._snapToItem(positionIndex, animated, fireCallback);
1071
+ }
1072
+
1073
+ snapToNext(animated = true, fireCallback = true) {
1074
+ const itemsLength = this._getCustomDataLength();
1075
+
1076
+ let newIndex = this._activeItem + 1;
1077
+ if (newIndex > itemsLength - 1) {
1078
+ if (!this._enableLoop()) {
1079
+ return;
1080
+ }
1081
+ newIndex = 0;
1082
+ }
1083
+ this._snapToItem(newIndex, animated, fireCallback);
1084
+ }
1085
+
1086
+ snapToPrev(animated = true, fireCallback = true) {
1087
+ const itemsLength = this._getCustomDataLength();
1088
+
1089
+ let newIndex = this._activeItem - 1;
1090
+ if (newIndex < 0) {
1091
+ if (!this._enableLoop()) {
1092
+ return;
1093
+ }
1094
+ newIndex = itemsLength - 1;
1095
+ }
1096
+ this._snapToItem(newIndex, animated, fireCallback);
1097
+ }
1098
+
1099
+ // https://github.com/facebook/react-native/issues/1831#issuecomment-231069668
1100
+ triggerRenderingHack(offset) {
1101
+ // Avoid messing with user scroll
1102
+ if (Date.now() - this._lastScrollDate < 500) {
1103
+ return;
1104
+ }
1105
+
1106
+ const scrollPosition = this._currentContentOffset;
1107
+ if (!scrollPosition && scrollPosition !== 0) {
1108
+ return;
1109
+ }
1110
+
1111
+ const scrollOffset = offset || (scrollPosition === 0 ? 1 : -1);
1112
+ this._scrollTo(scrollPosition + scrollOffset, false);
1113
+ }
1114
+
1115
+ _getSlideInterpolatedStyle(index, animatedValue) {
1116
+ const { layoutCardOffset, slideInterpolatedStyle } = this.props;
1117
+
1118
+ if (slideInterpolatedStyle) {
1119
+ return slideInterpolatedStyle(index, animatedValue, this.props);
1120
+ } if (this._shouldUseTinderLayout()) {
1121
+ return tinderAnimatedStyles(index, animatedValue, this.props, layoutCardOffset);
1122
+ } if (this._shouldUseStackLayout()) {
1123
+ return stackAnimatedStyles(index, animatedValue, this.props, layoutCardOffset);
1124
+ } if (this._shouldUseShiftLayout()) {
1125
+ return shiftAnimatedStyles(index, animatedValue, this.props);
1126
+ }
1127
+ return defaultAnimatedStyles(index, animatedValue, this.props);
1128
+ }
1129
+
1130
+ _renderItem({ item, index }) {
1131
+ const { interpolators } = this.state;
1132
+ const {
1133
+ hasParallaxImages,
1134
+ itemWidth,
1135
+ itemHeight,
1136
+ keyExtractor,
1137
+ renderItem,
1138
+ sliderHeight,
1139
+ sliderWidth,
1140
+ slideStyle,
1141
+ vertical,
1142
+ isCustomScrollWidth
1143
+ } = this.props;
1144
+
1145
+ const animatedValue = interpolators && interpolators[index];
1146
+
1147
+ if (!animatedValue && animatedValue !== 0) {
1148
+ return null;
1149
+ }
1150
+
1151
+ const animate = this._shouldAnimateSlides();
1152
+ const ComponentView = animate ? Animated.View : View;
1153
+ const animatedStyle = animate ? this._getSlideInterpolatedStyle(index, animatedValue) : {};
1154
+
1155
+ const parallaxProps = hasParallaxImages ? {
1156
+ scrollPosition: this._scrollPos,
1157
+ carouselRef: this._carouselRef,
1158
+ vertical,
1159
+ sliderWidth,
1160
+ sliderHeight,
1161
+ itemWidth,
1162
+ itemHeight
1163
+ } : undefined;
1164
+
1165
+ const specificProps = this._needsScrollView() ? {
1166
+ key: keyExtractor ? keyExtractor(item, index) : this._getKeyExtractor(item, index)
1167
+ } : {};
1168
+ const mainDimension = isCustomScrollWidth ? {} : { width: itemWidth };
1169
+ return (
1170
+ <ComponentView
1171
+ style={[mainDimension, slideStyle, animatedStyle]}
1172
+ pointerEvents="box-none"
1173
+ {...specificProps}
1174
+ >
1175
+ {renderItem({
1176
+ item, index, realIndex: this._getDataIndex(index), activeIndex: this._getDataIndex(this._activeItem)
1177
+ }, parallaxProps)}
1178
+ </ComponentView>
1179
+ );
1180
+ }
1181
+
1182
+ _getComponentOverridableProps() {
1183
+ const {
1184
+ enableMomentum,
1185
+ itemWidth,
1186
+ itemHeight,
1187
+ loopClonesPerSide,
1188
+ sliderWidth,
1189
+ sliderHeight,
1190
+ vertical
1191
+ } = this.props;
1192
+
1193
+ const visibleItems = Math.ceil(vertical
1194
+ ? sliderHeight / itemHeight
1195
+ : sliderWidth / itemWidth) + 1;
1196
+ const initialNumPerSide = this._enableLoop() ? loopClonesPerSide : 2;
1197
+ const initialNumToRender = visibleItems + (initialNumPerSide * 2);
1198
+ const maxToRenderPerBatch = 1 + (initialNumToRender * 2);
1199
+ const windowSize = maxToRenderPerBatch;
1200
+
1201
+ const specificProps = !this._needsScrollView() ? {
1202
+ initialNumToRender,
1203
+ maxToRenderPerBatch,
1204
+ windowSize
1205
+ // updateCellsBatchingPeriod
1206
+ } : {};
1207
+
1208
+ return {
1209
+ decelerationRate: enableMomentum ? 0.9 : 'fast',
1210
+ showsHorizontalScrollIndicator: false,
1211
+ showsVerticalScrollIndicator: false,
1212
+ overScrollMode: 'never',
1213
+ automaticallyAdjustContentInsets: false,
1214
+ directionalLockEnabled: true,
1215
+ pinchGestureEnabled: false,
1216
+ scrollsToTop: false,
1217
+ removeClippedSubviews: !this._needsScrollView(),
1218
+ inverted: this._needsRTLAdaptations(),
1219
+ // renderToHardwareTextureAndroid: true,
1220
+ ...specificProps
1221
+ };
1222
+ }
1223
+
1224
+ _getComponentStaticProps() {
1225
+ const { hideCarousel } = this.state;
1226
+ const {
1227
+ containerCustomStyle,
1228
+ contentContainerCustomStyle,
1229
+ keyExtractor,
1230
+ sliderWidth,
1231
+ sliderHeight,
1232
+ style,
1233
+ vertical
1234
+ } = this.props;
1235
+
1236
+ const containerStyle = [
1237
+ containerCustomStyle || style || {},
1238
+ hideCarousel ? { opacity: 0 } : {},
1239
+ vertical
1240
+ ? { height: sliderHeight, flexDirection: 'column' }
1241
+ // LTR hack; see https://github.com/facebook/react-native/issues/11960
1242
+ // and https://github.com/facebook/react-native/issues/13100#issuecomment-328986423
1243
+ : { width: sliderWidth, flexDirection: this._needsRTLAdaptations() ? 'row-reverse' : 'row' }
1244
+ ];
1245
+ const contentContainerStyle = [
1246
+ vertical ? {
1247
+ paddingTop: this._getContainerInnerMargin(),
1248
+ paddingBottom: this._getContainerInnerMargin(true)
1249
+ } : {
1250
+ paddingLeft: this._getContainerInnerMargin(),
1251
+ paddingRight: this._getContainerInnerMargin(true)
1252
+ },
1253
+ contentContainerCustomStyle || {}
1254
+ ];
1255
+
1256
+ const specificProps = !this._needsScrollView() ? {
1257
+ // extraData: this.state,
1258
+ renderItem: this._renderItem,
1259
+ numColumns: 1,
1260
+ getItemLayout: undefined, // see #193
1261
+ initialScrollIndex: undefined, // see #193
1262
+ keyExtractor: keyExtractor || this._getKeyExtractor
1263
+ } : {};
1264
+ return {
1265
+ ref: (c) => this._carouselRef = c,
1266
+ data: this._getCustomData(),
1267
+ style: containerStyle,
1268
+ contentContainerStyle,
1269
+ horizontal: !vertical,
1270
+ scrollEventThrottle: 1,
1271
+ onScroll: this._onScrollHandler,
1272
+ onScrollBeginDrag: this._onScrollBeginDrag,
1273
+ onScrollEndDrag: this._onScrollEndDrag,
1274
+ onMomentumScrollEnd: this._onMomentumScrollEnd,
1275
+ onResponderRelease: this._onTouchRelease,
1276
+ onStartShouldSetResponderCapture: this._onStartShouldSetResponderCapture,
1277
+ onTouchStart: this._onTouchStart,
1278
+ onTouchEnd: this._onScrollEnd,
1279
+ onLayout: this._onLayout,
1280
+ ...specificProps
1281
+ };
1282
+ }
1283
+
1284
+ render() {
1285
+ const { data, renderItem, useScrollView } = this.props;
1286
+
1287
+ if (!data || !renderItem) {
1288
+ return null;
1289
+ }
1290
+
1291
+ const props = {
1292
+ ...this._getComponentOverridableProps(),
1293
+ ...this.props,
1294
+ ...this._getComponentStaticProps()
1295
+ };
1296
+
1297
+ const ScrollViewComponent = typeof useScrollView === 'function' ? useScrollView : AnimatedScrollView;
1298
+
1299
+ return this._needsScrollView() ? (
1300
+ <ScrollViewComponent {...props}>
1301
+ {
1302
+ this._getCustomData().map((item, index) => this._renderItem({
1303
+ item, index, realIndex: this._getDataIndex(index), activeIndex: this._getDataIndex(this._activeItem)
1304
+ }))
1305
+ }
1306
+ </ScrollViewComponent>
1307
+ ) : (
1308
+ <AnimatedFlatList {...props} />
1309
+ );
1310
+ }
1311
+ }
1312
+
1313
+ Carousel.propTypes = {
1314
+ data: PropTypes.array.isRequired,
1315
+ renderItem: PropTypes.func.isRequired,
1316
+ itemWidth: PropTypes.number, // required for horizontal carousel
1317
+ itemHeight: PropTypes.number, // required for vertical carousel
1318
+ sliderWidth: PropTypes.number, // required for horizontal carousel
1319
+ sliderHeight: PropTypes.number, // required for vertical carousel
1320
+ activeAnimationType: PropTypes.string,
1321
+ activeAnimationOptions: PropTypes.object,
1322
+ activeSlideAlignment: PropTypes.oneOf(['center', 'end', 'start']),
1323
+ activeSlideOffset: PropTypes.number,
1324
+ apparitionDelay: PropTypes.number,
1325
+ autoplay: PropTypes.bool,
1326
+ autoplayDelay: PropTypes.number,
1327
+ autoplayInterval: PropTypes.number,
1328
+ callbackOffsetMargin: PropTypes.number,
1329
+ containerCustomStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
1330
+ contentContainerCustomStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
1331
+ enableMomentum: PropTypes.bool,
1332
+ enableSnap: PropTypes.bool,
1333
+ firstItem: PropTypes.number,
1334
+ hasParallaxImages: PropTypes.bool,
1335
+ inactiveSlideOpacity: PropTypes.number,
1336
+ inactiveSlideScale: PropTypes.number,
1337
+ inactiveSlideShift: PropTypes.number,
1338
+ layout: PropTypes.oneOf(['default', 'stack', 'tinder']),
1339
+ layoutCardOffset: PropTypes.number,
1340
+ lockScrollTimeoutDuration: PropTypes.number,
1341
+ lockScrollWhileSnapping: PropTypes.bool,
1342
+ loop: PropTypes.bool,
1343
+ loopClonesPerSide: PropTypes.number,
1344
+ scrollEnabled: PropTypes.bool,
1345
+ scrollInterpolator: PropTypes.func,
1346
+ slideInterpolatedStyle: PropTypes.func,
1347
+ slideStyle: PropTypes.object,
1348
+ shouldOptimizeUpdates: PropTypes.bool,
1349
+ swipeThreshold: PropTypes.number,
1350
+ useScrollView: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
1351
+ vertical: PropTypes.bool,
1352
+ showsPagination: PropTypes.bool,
1353
+ isCustomScrollWidth: PropTypes.bool,
1354
+ onBeforeSnapToItem: PropTypes.func,
1355
+ onSnapToItem: PropTypes.func,
1356
+ };
1357
+
1358
+ Carousel.defaultProps = {
1359
+ activeAnimationType: 'timing',
1360
+ activeAnimationOptions: null,
1361
+ activeSlideAlignment: 'center',
1362
+ activeSlideOffset: 20,
1363
+ apparitionDelay: 0,
1364
+ autoplay: false,
1365
+ autoplayDelay: 1000,
1366
+ autoplayInterval: 3000,
1367
+ callbackOffsetMargin: 5,
1368
+ containerCustomStyle: {},
1369
+ contentContainerCustomStyle: {},
1370
+ enableMomentum: false,
1371
+ enableSnap: true,
1372
+ firstItem: 0,
1373
+ hasParallaxImages: false,
1374
+ inactiveSlideOpacity: 0.7,
1375
+ inactiveSlideScale: 0.9,
1376
+ inactiveSlideShift: 0,
1377
+ layout: 'default',
1378
+ lockScrollTimeoutDuration: 1000,
1379
+ lockScrollWhileSnapping: false,
1380
+ loop: false,
1381
+ loopClonesPerSide: 3,
1382
+ scrollEnabled: true,
1383
+ slideStyle: {},
1384
+ shouldOptimizeUpdates: true,
1385
+ swipeThreshold: 20,
1386
+ useScrollView: !AnimatedFlatList,
1387
+ vertical: false,
1388
+ showsPagination: true,
1389
+ isCustomScrollWidth: false,
1390
+ };