@momo-kits/carousel 0.0.65-alpha.14 → 0.0.65-alpha.16

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