@momo-kits/carousel 0.73.3-beta.5 → 0.74.2-react-native.1

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