@momo-kits/carousel 0.150.3-beta.20 → 0.151.1-beta.2
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/animation.ts +17 -148
- package/index.tsx +700 -1330
- package/package.json +20 -20
- package/types.ts +18 -64
package/index.tsx
CHANGED
|
@@ -1,1470 +1,840 @@
|
|
|
1
|
-
import React
|
|
2
|
-
forwardRef,
|
|
3
|
-
useCallback,
|
|
4
|
-
useEffect,
|
|
5
|
-
useImperativeHandle,
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
} from 'react';
|
|
1
|
+
import React from 'react';
|
|
9
2
|
import {
|
|
10
3
|
Animated,
|
|
11
|
-
|
|
4
|
+
Dimensions,
|
|
5
|
+
GestureResponderEvent,
|
|
12
6
|
LayoutChangeEvent,
|
|
13
|
-
NativeSyntheticEvent,
|
|
14
7
|
NativeScrollEvent,
|
|
8
|
+
NativeSyntheticEvent,
|
|
15
9
|
Platform,
|
|
16
10
|
View,
|
|
11
|
+
ViewStyle,
|
|
17
12
|
} from 'react-native';
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
shiftAnimatedStyles,
|
|
22
|
-
stackAnimatedStyles,
|
|
23
|
-
stackScrollInterpolator,
|
|
24
|
-
tinderAnimatedStyles,
|
|
25
|
-
tinderScrollInterpolator,
|
|
26
|
-
} from './animation';
|
|
27
|
-
import { CarouselProps, CarouselRef, Position } from './types';
|
|
13
|
+
import { defaultAnimatedStyles, defaultScrollInterpolator } from './animation';
|
|
14
|
+
import { CarouselProps, CarouselRef, CarouselState, Position } from './types';
|
|
15
|
+
import { Spacing } from '@momo-kits/foundation';
|
|
28
16
|
|
|
29
17
|
const IS_ANDROID = Platform.OS === 'android';
|
|
30
18
|
const IS_IOS = Platform.OS === 'ios';
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
activeSlideAlignment
|
|
36
|
-
activeSlideOffset
|
|
37
|
-
apparitionDelay
|
|
38
|
-
autoplay
|
|
39
|
-
autoplayDelay
|
|
40
|
-
autoplayInterval
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
useExperimentalSnap
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
sliderWidth,
|
|
60
|
-
sliderHeight,
|
|
61
|
-
renderItem,
|
|
62
|
-
scrollInterpolator,
|
|
63
|
-
slideInterpolatedStyle,
|
|
64
|
-
slideStyle,
|
|
65
|
-
containerCustomStyle,
|
|
66
|
-
contentContainerCustomStyle,
|
|
67
|
-
style,
|
|
68
|
-
keyExtractor,
|
|
69
|
-
getItemLayout: getItemLayoutProp,
|
|
70
|
-
CellRendererComponent,
|
|
71
|
-
onScroll,
|
|
72
|
-
onScrollIndexChanged,
|
|
73
|
-
onSnapToItem,
|
|
74
|
-
onMomentumScrollEnd,
|
|
75
|
-
onLayout,
|
|
76
|
-
onTouchStart,
|
|
77
|
-
onTouchEnd,
|
|
78
|
-
} = props;
|
|
79
|
-
|
|
80
|
-
// State
|
|
81
|
-
const [hideCarousel, setHideCarousel] = useState(!!apparitionDelay);
|
|
82
|
-
const [interpolators, setInterpolators] = useState<
|
|
83
|
-
Animated.AnimatedInterpolation<number>[]
|
|
84
|
-
>([]);
|
|
85
|
-
|
|
86
|
-
// Refs for instance variables
|
|
87
|
-
const mountedRef = useRef(false);
|
|
88
|
-
const carouselRef = useRef<any>(null);
|
|
89
|
-
const scrollPosRef = useRef(new Animated.Value(0));
|
|
90
|
-
const onScrollHandlerRef = useRef<any>(null);
|
|
91
|
-
const positionsRef = useRef<Position[]>([]);
|
|
92
|
-
const currentScrollOffsetRef = useRef(0);
|
|
93
|
-
const scrollEnabledRef = useRef(scrollEnabledProp !== false);
|
|
94
|
-
const activeItemRef = useRef(0);
|
|
95
|
-
const onScrollActiveItemRef = useRef(0);
|
|
96
|
-
const previousFirstItemRef = useRef(0);
|
|
97
|
-
const previousItemsLengthRef = useRef(0);
|
|
98
|
-
const onLayoutInitDoneRef = useRef(false);
|
|
99
|
-
|
|
100
|
-
// Autoplay refs
|
|
101
|
-
const autoplayRef = useRef(false);
|
|
102
|
-
const autoplayingRef = useRef(false);
|
|
103
|
-
const autoplayTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
104
|
-
const autoplayIntervalRef = useRef<ReturnType<typeof setInterval> | null>(
|
|
105
|
-
null,
|
|
106
|
-
);
|
|
107
|
-
const enableAutoplayTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
|
|
108
|
-
null,
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Other timeouts
|
|
112
|
-
const initTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
113
|
-
const apparitionTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
|
|
114
|
-
null,
|
|
115
|
-
);
|
|
116
|
-
const hackSlideAnimationTimeoutRef = useRef<ReturnType<
|
|
117
|
-
typeof setTimeout
|
|
118
|
-
> | null>(null);
|
|
119
|
-
const snapNoMomentumTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
|
|
120
|
-
null,
|
|
121
|
-
);
|
|
122
|
-
const androidRepositioningTimeoutRef = useRef<ReturnType<
|
|
123
|
-
typeof setTimeout
|
|
124
|
-
> | null>(null);
|
|
125
|
-
|
|
126
|
-
// Helper functions
|
|
127
|
-
const needsScrollView = useCallback(() => {
|
|
128
|
-
return IS_ANDROID
|
|
129
|
-
? useScrollView ||
|
|
130
|
-
!Animated.FlatList ||
|
|
131
|
-
shouldUseStackLayout() ||
|
|
132
|
-
shouldUseTinderLayout()
|
|
133
|
-
: useScrollView || !Animated.FlatList;
|
|
134
|
-
}, [useScrollView, layout]);
|
|
135
|
-
|
|
136
|
-
const needsRTLAdaptations = useCallback(() => {
|
|
137
|
-
return IS_RTL && IS_ANDROID && !vertical;
|
|
138
|
-
}, [vertical]);
|
|
139
|
-
|
|
140
|
-
const enableLoop = useCallback(() => {
|
|
141
|
-
return enableSnap && loop && data && data.length && data.length > 1;
|
|
142
|
-
}, [enableSnap, loop, data]);
|
|
19
|
+
const screenWidth = Dimensions.get('window').width;
|
|
20
|
+
|
|
21
|
+
class Carousel extends React.PureComponent<CarouselProps, CarouselState> {
|
|
22
|
+
static defaultProps = {
|
|
23
|
+
activeSlideAlignment: 'start',
|
|
24
|
+
activeSlideOffset: 20,
|
|
25
|
+
apparitionDelay: 0,
|
|
26
|
+
autoplay: false,
|
|
27
|
+
autoplayDelay: 1000,
|
|
28
|
+
autoplayInterval: 3000,
|
|
29
|
+
callbackOffsetMargin: 5,
|
|
30
|
+
containerCustomStyle: {},
|
|
31
|
+
contentContainerCustomStyle: {},
|
|
32
|
+
enableSnap: true,
|
|
33
|
+
firstItem: 0,
|
|
34
|
+
hasParallaxImages: false,
|
|
35
|
+
loop: false,
|
|
36
|
+
loopClonesPerSide: 3,
|
|
37
|
+
scrollEnabled: true,
|
|
38
|
+
slideStyle: {},
|
|
39
|
+
shouldOptimizeUpdates: true,
|
|
40
|
+
vertical: false,
|
|
41
|
+
isCustomScrollWidth: false,
|
|
42
|
+
disableIntervalMomentum: IS_ANDROID,
|
|
43
|
+
useExperimentalSnap: IS_ANDROID,
|
|
44
|
+
visibleItem: 1,
|
|
45
|
+
full: false,
|
|
46
|
+
};
|
|
143
47
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const shouldRepositionScroll = useCallback(
|
|
176
|
-
(index: number) => {
|
|
177
|
-
const dataLength = data && data.length;
|
|
178
|
-
if (
|
|
179
|
-
!enableSnap ||
|
|
180
|
-
!dataLength ||
|
|
181
|
-
!enableLoop() ||
|
|
182
|
-
(index >= loopClonesPerSide && index < dataLength + loopClonesPerSide)
|
|
183
|
-
) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
return true;
|
|
187
|
-
},
|
|
188
|
-
[data, enableSnap, loopClonesPerSide, enableLoop],
|
|
189
|
-
);
|
|
48
|
+
_activeItem;
|
|
49
|
+
_onScrollActiveItem;
|
|
50
|
+
_previousFirstItem;
|
|
51
|
+
_previousItemsLength;
|
|
52
|
+
_mounted;
|
|
53
|
+
_positions: Position[];
|
|
54
|
+
_currentScrollOffset;
|
|
55
|
+
_scrollEnabled;
|
|
56
|
+
_initTimeout?: ReturnType<typeof setTimeout>;
|
|
57
|
+
_apparitionTimeout?: ReturnType<typeof setTimeout>;
|
|
58
|
+
_enableAutoplayTimeout?: ReturnType<typeof setTimeout>;
|
|
59
|
+
_autoplayTimeout?: ReturnType<typeof setTimeout>;
|
|
60
|
+
_snapNoMomentumTimeout?: ReturnType<typeof setTimeout>;
|
|
61
|
+
_androidRepositioningTimeout?: ReturnType<typeof setTimeout>;
|
|
62
|
+
_scrollPos?: Animated.Value;
|
|
63
|
+
_onScrollHandler?: (...args: any[]) => void;
|
|
64
|
+
_autoplay?: boolean;
|
|
65
|
+
_autoplaying?: boolean;
|
|
66
|
+
_autoplayInterval?: ReturnType<typeof setInterval>;
|
|
67
|
+
_carouselRef: any;
|
|
68
|
+
_onLayoutInitDone?: boolean;
|
|
69
|
+
|
|
70
|
+
constructor(props: CarouselProps) {
|
|
71
|
+
super(props);
|
|
72
|
+
|
|
73
|
+
this.state = {
|
|
74
|
+
hideCarousel: !!props.apparitionDelay,
|
|
75
|
+
interpolators: [],
|
|
76
|
+
containerWidth: screenWidth,
|
|
77
|
+
itemWidth: screenWidth - Spacing.L * 2,
|
|
78
|
+
};
|
|
190
79
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
80
|
+
const initialActiveItem = this._getFirstItem(props.firstItem || 0);
|
|
81
|
+
this._activeItem = initialActiveItem;
|
|
82
|
+
this._onScrollActiveItem = initialActiveItem;
|
|
83
|
+
this._previousFirstItem = initialActiveItem;
|
|
84
|
+
this._previousItemsLength = initialActiveItem;
|
|
85
|
+
|
|
86
|
+
this._mounted = false;
|
|
87
|
+
this._positions = [];
|
|
88
|
+
this._currentScrollOffset = 0;
|
|
89
|
+
this._scrollEnabled = props.scrollEnabled;
|
|
90
|
+
|
|
91
|
+
this._getItemLayout = this._getItemLayout.bind(this);
|
|
92
|
+
this._getKeyExtractor = this._getKeyExtractor.bind(this);
|
|
93
|
+
this._onLayout = this._onLayout.bind(this);
|
|
94
|
+
this._onScroll = this._onScroll.bind(this);
|
|
95
|
+
this._onMomentumScrollEnd = this._onMomentumScrollEnd.bind(this);
|
|
96
|
+
this._onTouchStart = this._onTouchStart.bind(this);
|
|
97
|
+
this._onTouchEnd = this._onTouchEnd.bind(this);
|
|
98
|
+
this._renderItem = this._renderItem.bind(this);
|
|
99
|
+
this._setScrollHandler(props);
|
|
100
|
+
}
|
|
206
101
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
102
|
+
componentDidMount() {
|
|
103
|
+
const { apparitionDelay, autoplay } = this.props;
|
|
210
104
|
|
|
211
|
-
|
|
212
|
-
|
|
105
|
+
this._mounted = true;
|
|
106
|
+
this._initPositionsAndInterpolators();
|
|
213
107
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
108
|
+
// Without 'requestAnimationFrame' or a `0` timeout, images will randomly not be rendered on Android...
|
|
109
|
+
this._initTimeout = setTimeout(() => {
|
|
110
|
+
if (!this._mounted) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
217
113
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
114
|
+
const apparitionCallback = () => {
|
|
115
|
+
if (apparitionDelay) {
|
|
116
|
+
this.setState({ hideCarousel: false });
|
|
117
|
+
}
|
|
118
|
+
if (autoplay) {
|
|
119
|
+
this.startAutoplay();
|
|
221
120
|
}
|
|
121
|
+
};
|
|
222
122
|
|
|
223
|
-
|
|
224
|
-
|
|
123
|
+
if (apparitionDelay) {
|
|
124
|
+
this._apparitionTimeout = setTimeout(() => {
|
|
125
|
+
apparitionCallback();
|
|
126
|
+
}, apparitionDelay);
|
|
225
127
|
} else {
|
|
226
|
-
|
|
227
|
-
nextItems = propsData.slice(0, loopClones);
|
|
128
|
+
apparitionCallback();
|
|
228
129
|
}
|
|
130
|
+
}, 1);
|
|
131
|
+
}
|
|
229
132
|
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const getCustomDataLength = useCallback(
|
|
236
|
-
(propsOverride = props) => {
|
|
237
|
-
const {
|
|
238
|
-
data: propsData = [],
|
|
239
|
-
loopClonesPerSide: loopClones = loopClonesPerSide,
|
|
240
|
-
} = propsOverride;
|
|
241
|
-
const dataLength = propsData && propsData.length;
|
|
242
|
-
|
|
243
|
-
if (!dataLength) {
|
|
244
|
-
return 0;
|
|
245
|
-
}
|
|
133
|
+
componentDidUpdate(prevProps: CarouselProps) {
|
|
134
|
+
const { interpolators } = this.state;
|
|
135
|
+
const { firstItem = 0, scrollEnabled } = this.props;
|
|
136
|
+
const itemsLength = this._getCustomDataLength(this.props);
|
|
246
137
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
);
|
|
138
|
+
if (!itemsLength) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
251
141
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
142
|
+
const nextFirstItem = this._getFirstItem(firstItem, this.props);
|
|
143
|
+
let nextActiveItem =
|
|
144
|
+
typeof this._activeItem !== 'undefined'
|
|
145
|
+
? this._activeItem
|
|
146
|
+
: nextFirstItem;
|
|
255
147
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
148
|
+
if (nextActiveItem > itemsLength - 1) {
|
|
149
|
+
nextActiveItem = itemsLength - 1;
|
|
150
|
+
}
|
|
259
151
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
);
|
|
152
|
+
if (scrollEnabled !== prevProps.scrollEnabled) {
|
|
153
|
+
this._setScrollEnabled(scrollEnabled);
|
|
154
|
+
}
|
|
264
155
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (!enableLoop() || !dataLength) {
|
|
269
|
-
return index;
|
|
270
|
-
}
|
|
156
|
+
if (interpolators.length !== itemsLength) {
|
|
157
|
+
this._activeItem = nextActiveItem;
|
|
158
|
+
this._previousItemsLength = itemsLength;
|
|
271
159
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const remainder = loopClonesPerSide % dataLength;
|
|
282
|
-
|
|
283
|
-
for (let i = 0; i < dataLength; i++) {
|
|
284
|
-
baseDataIndexes.push(i);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
for (let j = 0; j < dataMultiplier; j++) {
|
|
288
|
-
dataIndexes.push(...baseDataIndexes);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
dataIndexes.unshift(...baseDataIndexes.slice(-remainder));
|
|
292
|
-
return dataIndexes[index];
|
|
293
|
-
} else {
|
|
294
|
-
return index + dataLength - loopClonesPerSide;
|
|
295
|
-
}
|
|
296
|
-
} else {
|
|
297
|
-
return index - loopClonesPerSide;
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
[data, loopClonesPerSide, enableLoop],
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
const getPositionIndex = useCallback(
|
|
304
|
-
(index: number) => {
|
|
305
|
-
return loop ? index + loopClonesPerSide : index;
|
|
306
|
-
},
|
|
307
|
-
[loop, loopClonesPerSide],
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
const getSnapOffsets = useCallback(() => {
|
|
311
|
-
const offset = getItemMainDimension();
|
|
312
|
-
return [...Array(getCustomDataLength())].map((_, i) => {
|
|
313
|
-
return i * offset;
|
|
314
|
-
});
|
|
315
|
-
}, [getCustomDataLength, itemWidth, itemHeight, vertical]);
|
|
160
|
+
this._initPositionsAndInterpolators(this.props);
|
|
161
|
+
} else if (
|
|
162
|
+
nextFirstItem !== this._previousFirstItem &&
|
|
163
|
+
nextFirstItem !== this._activeItem
|
|
164
|
+
) {
|
|
165
|
+
this._activeItem = nextFirstItem;
|
|
166
|
+
this._previousFirstItem = nextFirstItem;
|
|
167
|
+
this._snapToItem(nextFirstItem, false, true, true);
|
|
168
|
+
}
|
|
316
169
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const itemsLength = getCustomDataLength(propsOverride);
|
|
170
|
+
if (this.props.onScroll !== prevProps.onScroll) {
|
|
171
|
+
this._setScrollHandler(this.props);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
322
174
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
175
|
+
componentWillUnmount() {
|
|
176
|
+
this._mounted = false;
|
|
177
|
+
this.stopAutoplay();
|
|
178
|
+
if (this._initTimeout != null) clearTimeout(this._initTimeout);
|
|
179
|
+
if (this._apparitionTimeout != null) clearTimeout(this._apparitionTimeout);
|
|
180
|
+
if (this._enableAutoplayTimeout != null)
|
|
181
|
+
clearTimeout(this._enableAutoplayTimeout);
|
|
182
|
+
if (this._autoplayTimeout != null) clearTimeout(this._autoplayTimeout);
|
|
183
|
+
if (this._snapNoMomentumTimeout != null)
|
|
184
|
+
clearTimeout(this._snapNoMomentumTimeout);
|
|
185
|
+
if (this._androidRepositioningTimeout != null)
|
|
186
|
+
clearTimeout(this._androidRepositioningTimeout);
|
|
187
|
+
}
|
|
326
188
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
189
|
+
_setScrollHandler(props: CarouselProps) {
|
|
190
|
+
const scrollEventConfig = {
|
|
191
|
+
listener: this._onScroll,
|
|
192
|
+
useNativeDriver: true,
|
|
193
|
+
};
|
|
194
|
+
this._scrollPos = new Animated.Value(0);
|
|
195
|
+
const argMapping = [
|
|
196
|
+
{ nativeEvent: { contentOffset: { x: this._scrollPos } } },
|
|
197
|
+
];
|
|
331
198
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
199
|
+
if (props.onScroll && Array.isArray(props.onScroll._argMapping)) {
|
|
200
|
+
argMapping.pop();
|
|
201
|
+
const [argMap] = props.onScroll._argMapping;
|
|
202
|
+
if (argMap && argMap.nativeEvent && argMap.nativeEvent.contentOffset) {
|
|
203
|
+
this._scrollPos =
|
|
204
|
+
argMap.nativeEvent.contentOffset.x ||
|
|
205
|
+
argMap.nativeEvent.contentOffset.y ||
|
|
206
|
+
this._scrollPos;
|
|
207
|
+
}
|
|
208
|
+
argMapping.push(...props.onScroll._argMapping);
|
|
339
209
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
210
|
+
this._onScrollHandler = Animated.event(argMapping, scrollEventConfig);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_enableLoop() {
|
|
214
|
+
const { data, enableSnap, loop } = this.props;
|
|
215
|
+
return enableSnap && loop && data && data.length && data.length > 1;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
_shouldAnimateSlides(props = this.props) {
|
|
219
|
+
const { inactiveSlideOpacity = 1, inactiveSlideScale = 1 } = props;
|
|
220
|
+
return inactiveSlideOpacity < 1 || inactiveSlideScale < 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
_shouldRepositionScroll(index: number) {
|
|
224
|
+
const { data, enableSnap, loopClonesPerSide = 3 } = this.props;
|
|
225
|
+
const dataLength = data && data.length;
|
|
226
|
+
return !(
|
|
227
|
+
!enableSnap ||
|
|
228
|
+
!dataLength ||
|
|
229
|
+
!this._enableLoop() ||
|
|
230
|
+
(index >= loopClonesPerSide && index < dataLength + loopClonesPerSide)
|
|
344
231
|
);
|
|
345
|
-
}
|
|
232
|
+
}
|
|
346
233
|
|
|
347
|
-
|
|
348
|
-
return
|
|
349
|
-
}
|
|
234
|
+
_isMultiple(x: number, y: number) {
|
|
235
|
+
return Math.round(Math.round(x / y) / (1 / y)) === Math.round(x);
|
|
236
|
+
}
|
|
350
237
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
238
|
+
_getCustomData(props = this.props) {
|
|
239
|
+
const { data, loopClonesPerSide = 3 } = props;
|
|
240
|
+
const dataLength = data && data.length;
|
|
354
241
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
242
|
+
if (!dataLength) {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
358
245
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
[getWrappedRef],
|
|
363
|
-
);
|
|
246
|
+
if (!this._enableLoop()) {
|
|
247
|
+
return data;
|
|
248
|
+
}
|
|
364
249
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}, [vertical, itemHeight, itemWidth]);
|
|
250
|
+
let previousItems = [];
|
|
251
|
+
let nextItems = [];
|
|
368
252
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
positionsRef.current[index] &&
|
|
373
|
-
positionsRef.current[index].start
|
|
374
|
-
);
|
|
375
|
-
}, []);
|
|
376
|
-
|
|
377
|
-
const getItemLayout = useCallback(
|
|
378
|
-
(_: any, index: number) => {
|
|
379
|
-
const itemMainDimension = getItemMainDimension();
|
|
380
|
-
return {
|
|
381
|
-
index,
|
|
382
|
-
length: itemMainDimension,
|
|
383
|
-
offset: itemMainDimension * index,
|
|
384
|
-
};
|
|
385
|
-
},
|
|
386
|
-
[getItemMainDimension],
|
|
387
|
-
);
|
|
388
|
-
|
|
389
|
-
const getCellRendererComponent = useCallback(
|
|
390
|
-
({ children, index, style: cellStyle, ...cellProps }: any) => {
|
|
391
|
-
const customStyle = [
|
|
392
|
-
cellStyle,
|
|
393
|
-
!IS_ANDROID ? { zIndex: getCustomDataLength() - index } : {},
|
|
394
|
-
];
|
|
395
|
-
|
|
396
|
-
return (
|
|
397
|
-
<View style={customStyle} key={index} {...cellProps}>
|
|
398
|
-
{children}
|
|
399
|
-
</View>
|
|
400
|
-
);
|
|
401
|
-
},
|
|
402
|
-
[getCustomDataLength],
|
|
403
|
-
);
|
|
404
|
-
|
|
405
|
-
const getKeyExtractor = useCallback(
|
|
406
|
-
(_: any, index: number) => {
|
|
407
|
-
return needsScrollView()
|
|
408
|
-
? `scrollview-item-${index}`
|
|
409
|
-
: `flatlist-item-${index}`;
|
|
410
|
-
},
|
|
411
|
-
[needsScrollView],
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
const getScrollOffset = useCallback(
|
|
415
|
-
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
416
|
-
return (
|
|
417
|
-
(event &&
|
|
418
|
-
event.nativeEvent &&
|
|
419
|
-
event.nativeEvent.contentOffset &&
|
|
420
|
-
event.nativeEvent.contentOffset[vertical ? 'y' : 'x']) ||
|
|
421
|
-
0
|
|
422
|
-
);
|
|
423
|
-
},
|
|
424
|
-
[vertical],
|
|
425
|
-
);
|
|
426
|
-
|
|
427
|
-
const getContainerInnerMargin = useCallback(
|
|
428
|
-
(opposite = false) => {
|
|
429
|
-
if (
|
|
430
|
-
(activeSlideAlignment === 'start' && !opposite) ||
|
|
431
|
-
(activeSlideAlignment === 'end' && opposite)
|
|
432
|
-
) {
|
|
433
|
-
return 0;
|
|
434
|
-
} else if (
|
|
435
|
-
(activeSlideAlignment === 'end' && !opposite) ||
|
|
436
|
-
(activeSlideAlignment === 'start' && opposite)
|
|
437
|
-
) {
|
|
438
|
-
return vertical ? sliderHeight - itemHeight : sliderWidth - itemWidth;
|
|
439
|
-
} else {
|
|
440
|
-
return vertical
|
|
441
|
-
? (sliderHeight - itemHeight) / 2
|
|
442
|
-
: (sliderWidth - itemWidth) / 2;
|
|
443
|
-
}
|
|
444
|
-
},
|
|
445
|
-
[
|
|
446
|
-
activeSlideAlignment,
|
|
447
|
-
vertical,
|
|
448
|
-
sliderHeight,
|
|
449
|
-
itemHeight,
|
|
450
|
-
sliderWidth,
|
|
451
|
-
itemWidth,
|
|
452
|
-
],
|
|
453
|
-
);
|
|
454
|
-
|
|
455
|
-
const getActiveSlideOffset = useCallback(() => {
|
|
456
|
-
const itemMainDimension = getItemMainDimension();
|
|
457
|
-
const minOffset = 10;
|
|
458
|
-
return itemMainDimension / 2 - activeSlideOffset >= minOffset
|
|
459
|
-
? activeSlideOffset
|
|
460
|
-
: minOffset;
|
|
461
|
-
}, [getItemMainDimension, activeSlideOffset]);
|
|
462
|
-
|
|
463
|
-
const getActiveItem = useCallback(
|
|
464
|
-
(offset: number) => {
|
|
465
|
-
const itemMainDimension = getItemMainDimension();
|
|
466
|
-
const center = offset + itemMainDimension / 2;
|
|
467
|
-
const activeOffset = getActiveSlideOffset();
|
|
468
|
-
const lastIndex = positionsRef.current.length - 1;
|
|
469
|
-
let itemIndex;
|
|
470
|
-
|
|
471
|
-
if (offset <= 0) {
|
|
472
|
-
return 0;
|
|
473
|
-
}
|
|
253
|
+
if (loopClonesPerSide > dataLength) {
|
|
254
|
+
const dataMultiplier = Math.floor(loopClonesPerSide / dataLength);
|
|
255
|
+
const remainder = loopClonesPerSide % dataLength;
|
|
474
256
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
) {
|
|
479
|
-
return lastIndex;
|
|
257
|
+
for (let i = 0; i < dataMultiplier; i++) {
|
|
258
|
+
previousItems.push(...data);
|
|
259
|
+
nextItems.push(...data);
|
|
480
260
|
}
|
|
481
261
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}
|
|
262
|
+
previousItems.unshift(...data.slice(-remainder));
|
|
263
|
+
nextItems.push(...data.slice(0, remainder));
|
|
264
|
+
} else {
|
|
265
|
+
previousItems = data.slice(-loopClonesPerSide);
|
|
266
|
+
nextItems = data.slice(0, loopClonesPerSide);
|
|
267
|
+
}
|
|
489
268
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
[getItemMainDimension, getActiveSlideOffset],
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
const getSlideInterpolatedStyle = useCallback(
|
|
496
|
-
(index: number, animatedValue: Animated.AnimatedInterpolation<number>) => {
|
|
497
|
-
if (slideInterpolatedStyle) {
|
|
498
|
-
return slideInterpolatedStyle(index, animatedValue, props);
|
|
499
|
-
} else if (shouldUseTinderLayout()) {
|
|
500
|
-
return tinderAnimatedStyles(
|
|
501
|
-
index,
|
|
502
|
-
animatedValue,
|
|
503
|
-
props,
|
|
504
|
-
layoutCardOffset,
|
|
505
|
-
);
|
|
506
|
-
} else if (shouldUseStackLayout()) {
|
|
507
|
-
return stackAnimatedStyles(
|
|
508
|
-
index,
|
|
509
|
-
animatedValue,
|
|
510
|
-
props,
|
|
511
|
-
layoutCardOffset,
|
|
512
|
-
);
|
|
513
|
-
} else if (shouldUseShiftLayout()) {
|
|
514
|
-
return shiftAnimatedStyles(index, animatedValue, props);
|
|
515
|
-
} else {
|
|
516
|
-
return defaultAnimatedStyles(index, animatedValue, props);
|
|
517
|
-
}
|
|
518
|
-
},
|
|
519
|
-
[
|
|
520
|
-
slideInterpolatedStyle,
|
|
521
|
-
shouldUseTinderLayout,
|
|
522
|
-
shouldUseStackLayout,
|
|
523
|
-
shouldUseShiftLayout,
|
|
524
|
-
layoutCardOffset,
|
|
525
|
-
props,
|
|
526
|
-
],
|
|
527
|
-
);
|
|
528
|
-
|
|
529
|
-
const initPositionsAndInterpolators = useCallback(
|
|
530
|
-
(propsOverride = props) => {
|
|
531
|
-
const { data: propsData = [], scrollInterpolator: scrollInterp } =
|
|
532
|
-
propsOverride;
|
|
533
|
-
const itemMainDimension = getItemMainDimension();
|
|
534
|
-
|
|
535
|
-
if (!propsData || !propsData.length) {
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
269
|
+
return previousItems.concat(data, nextItems);
|
|
270
|
+
}
|
|
538
271
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
itemMainDimension <= 0 ||
|
|
543
|
-
!isFinite(itemMainDimension)
|
|
544
|
-
) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
272
|
+
_getCustomDataLength(props = this.props) {
|
|
273
|
+
const { data, loopClonesPerSide = 3 } = props;
|
|
274
|
+
const dataLength = data && data.length;
|
|
547
275
|
|
|
548
|
-
|
|
549
|
-
|
|
276
|
+
if (!dataLength) {
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
550
279
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
let animatedValue: Animated.AnimatedInterpolation<number>;
|
|
280
|
+
return this._enableLoop() ? dataLength + 2 * loopClonesPerSide : dataLength;
|
|
281
|
+
}
|
|
554
282
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
end: index * itemMainDimension + itemMainDimension,
|
|
558
|
-
};
|
|
283
|
+
_getCustomIndex(index: number, props = this.props) {
|
|
284
|
+
const itemsLength = this._getCustomDataLength(props);
|
|
559
285
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if (!hasValidRange) {
|
|
589
|
-
animatedValue = new Animated.Value(1) as any;
|
|
590
|
-
} else {
|
|
591
|
-
animatedValue = scrollPosRef.current.interpolate({
|
|
592
|
-
...interpolator,
|
|
593
|
-
extrapolate: 'clamp',
|
|
594
|
-
});
|
|
595
|
-
}
|
|
286
|
+
if (!itemsLength || typeof index === 'undefined') {
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return index;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
_getDataIndex(index: number) {
|
|
294
|
+
const { data, loopClonesPerSide = 3 } = this.props;
|
|
295
|
+
const dataLength = data && data.length;
|
|
296
|
+
if (!this._enableLoop() || !dataLength) {
|
|
297
|
+
return index;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (index >= dataLength + loopClonesPerSide) {
|
|
301
|
+
return loopClonesPerSide > dataLength
|
|
302
|
+
? (index - loopClonesPerSide) % dataLength
|
|
303
|
+
: index - dataLength - loopClonesPerSide;
|
|
304
|
+
} else if (index < loopClonesPerSide) {
|
|
305
|
+
if (loopClonesPerSide > dataLength) {
|
|
306
|
+
const baseDataIndexes = [];
|
|
307
|
+
const dataIndexes = [];
|
|
308
|
+
const dataMultiplier = Math.floor(loopClonesPerSide / dataLength);
|
|
309
|
+
const remainder = loopClonesPerSide % dataLength;
|
|
310
|
+
|
|
311
|
+
for (let i = 0; i < dataLength; i++) {
|
|
312
|
+
baseDataIndexes.push(i);
|
|
596
313
|
}
|
|
597
314
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
setInterpolators(newInterpolators);
|
|
602
|
-
},
|
|
603
|
-
[
|
|
604
|
-
data,
|
|
605
|
-
getItemMainDimension,
|
|
606
|
-
getCustomData,
|
|
607
|
-
getCustomIndex,
|
|
608
|
-
shouldAnimateSlides,
|
|
609
|
-
shouldUseStackLayout,
|
|
610
|
-
shouldUseTinderLayout,
|
|
611
|
-
scrollInterpolator,
|
|
612
|
-
],
|
|
613
|
-
);
|
|
614
|
-
|
|
615
|
-
const hackActiveSlideAnimation = useCallback(
|
|
616
|
-
(index: number, scrollValue = 1) => {
|
|
617
|
-
const offset = getItemScrollOffset(index);
|
|
315
|
+
for (let j = 0; j < dataMultiplier; j++) {
|
|
316
|
+
dataIndexes.push(...baseDataIndexes);
|
|
317
|
+
}
|
|
618
318
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
) {
|
|
624
|
-
return;
|
|
319
|
+
dataIndexes.unshift(...baseDataIndexes.slice(-remainder));
|
|
320
|
+
return dataIndexes[index];
|
|
321
|
+
} else {
|
|
322
|
+
return index + dataLength - loopClonesPerSide;
|
|
625
323
|
}
|
|
324
|
+
} else {
|
|
325
|
+
return index - loopClonesPerSide;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
_getFirstItem(index: number, props = this.props) {
|
|
330
|
+
const { loopClonesPerSide = 3 } = props;
|
|
331
|
+
const itemsLength = this._getCustomDataLength(props);
|
|
626
332
|
|
|
627
|
-
|
|
628
|
-
|
|
333
|
+
if (!itemsLength || index > itemsLength - 1 || index < 0) {
|
|
334
|
+
return 0;
|
|
335
|
+
}
|
|
629
336
|
|
|
630
|
-
|
|
337
|
+
return this._enableLoop() ? index + loopClonesPerSide : index;
|
|
338
|
+
}
|
|
631
339
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
hackSlideAnimationTimeoutRef.current = setTimeout(() => {
|
|
636
|
-
scrollTo({ offset, animated: false });
|
|
637
|
-
}, 1);
|
|
638
|
-
},
|
|
639
|
-
[getItemScrollOffset],
|
|
640
|
-
);
|
|
641
|
-
|
|
642
|
-
const repositionScroll = useCallback(
|
|
643
|
-
(index: number, animated = false) => {
|
|
644
|
-
const dataLength = data && data.length;
|
|
645
|
-
|
|
646
|
-
if (typeof index === 'undefined' || !shouldRepositionScroll(index)) {
|
|
647
|
-
return;
|
|
648
|
-
}
|
|
340
|
+
_getWrappedRef() {
|
|
341
|
+
return this._carouselRef;
|
|
342
|
+
}
|
|
649
343
|
|
|
650
|
-
|
|
344
|
+
_getScrollEnabled() {
|
|
345
|
+
return this._scrollEnabled;
|
|
346
|
+
}
|
|
651
347
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
348
|
+
_setScrollEnabled(scrollEnabled = true) {
|
|
349
|
+
this._scrollEnabled = scrollEnabled;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
_getItemMainDimension() {
|
|
353
|
+
const { itemWidth } = this.state;
|
|
354
|
+
const { full } = this.props;
|
|
355
|
+
return full ? itemWidth : itemWidth + Spacing.S;
|
|
356
|
+
}
|
|
657
357
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
358
|
+
_getItemScrollOffset(index: number) {
|
|
359
|
+
return (
|
|
360
|
+
this._positions && this._positions[index] && this._positions[index].start
|
|
361
|
+
);
|
|
362
|
+
}
|
|
662
363
|
|
|
663
|
-
|
|
664
|
-
(
|
|
665
|
-
|
|
364
|
+
_getItemLayout(_: any, index: number) {
|
|
365
|
+
const itemMainDimension = this._getItemMainDimension();
|
|
366
|
+
return {
|
|
666
367
|
index,
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
animated?: boolean;
|
|
672
|
-
}) => {
|
|
673
|
-
const wrappedRef = getWrappedRef();
|
|
674
|
-
if (
|
|
675
|
-
!mountedRef.current ||
|
|
676
|
-
!wrappedRef ||
|
|
677
|
-
(typeof offset === 'undefined' && typeof index === 'undefined')
|
|
678
|
-
) {
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
368
|
+
length: itemMainDimension,
|
|
369
|
+
offset: itemMainDimension * index,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
681
372
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
} else {
|
|
686
|
-
scrollToOffset = offset;
|
|
687
|
-
}
|
|
373
|
+
_getKeyExtractor(_: any, index: any) {
|
|
374
|
+
return `flatlist-item-${index}`;
|
|
375
|
+
}
|
|
688
376
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
377
|
+
_getScrollOffset(event: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
378
|
+
return event.nativeEvent.contentOffset.x;
|
|
379
|
+
}
|
|
692
380
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
animated,
|
|
702
|
-
};
|
|
703
|
-
|
|
704
|
-
if (needsScrollView()) {
|
|
705
|
-
wrappedRef.scrollTo(options);
|
|
706
|
-
} else {
|
|
707
|
-
wrappedRef.scrollToOffset(options);
|
|
708
|
-
}
|
|
709
|
-
},
|
|
710
|
-
[getWrappedRef, getItemScrollOffset, needsScrollView, vertical],
|
|
711
|
-
);
|
|
712
|
-
|
|
713
|
-
const handleTouchStart = useCallback(
|
|
714
|
-
(event: any) => {
|
|
715
|
-
if (getScrollEnabled() !== false && autoplayingRef.current) {
|
|
716
|
-
pauseAutoPlay();
|
|
717
|
-
}
|
|
381
|
+
_getActiveSlideOffset() {
|
|
382
|
+
const { activeSlideOffset = 0 } = this.props;
|
|
383
|
+
const itemMainDimension = this._getItemMainDimension();
|
|
384
|
+
const minOffset = 10;
|
|
385
|
+
return itemMainDimension / 2 - activeSlideOffset >= minOffset
|
|
386
|
+
? activeSlideOffset
|
|
387
|
+
: minOffset;
|
|
388
|
+
}
|
|
718
389
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
390
|
+
_getActiveItem(offset: number) {
|
|
391
|
+
const itemMainDimension = this._getItemMainDimension();
|
|
392
|
+
const center = offset + itemMainDimension / 2;
|
|
393
|
+
const activeSlideOffset = this._getActiveSlideOffset();
|
|
394
|
+
const lastIndex = this._positions.length - 1;
|
|
395
|
+
let itemIndex;
|
|
723
396
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
getScrollEnabled() &&
|
|
728
|
-
autoplayRef.current &&
|
|
729
|
-
!autoplayingRef.current
|
|
730
|
-
) {
|
|
731
|
-
startAutoplay();
|
|
732
|
-
}
|
|
397
|
+
if (offset <= 0) {
|
|
398
|
+
return 0;
|
|
399
|
+
}
|
|
733
400
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
741
|
-
const scrollOffset = event
|
|
742
|
-
? getScrollOffset(event)
|
|
743
|
-
: currentScrollOffsetRef.current;
|
|
744
|
-
const nextActiveItem = getActiveItem(scrollOffset);
|
|
745
|
-
const dataLength = getCustomDataLength();
|
|
746
|
-
const lastItemScrollOffset = getItemScrollOffset(dataLength - 1);
|
|
747
|
-
|
|
748
|
-
currentScrollOffsetRef.current = scrollOffset;
|
|
749
|
-
|
|
750
|
-
if (nextActiveItem !== onScrollActiveItemRef.current) {
|
|
751
|
-
onScrollActiveItemRef.current = nextActiveItem;
|
|
752
|
-
onScrollIndexChanged &&
|
|
753
|
-
onScrollIndexChanged(getDataIndex(nextActiveItem));
|
|
754
|
-
}
|
|
401
|
+
if (
|
|
402
|
+
this._positions[lastIndex] &&
|
|
403
|
+
offset >= this._positions[lastIndex].start
|
|
404
|
+
) {
|
|
405
|
+
return lastIndex;
|
|
406
|
+
}
|
|
755
407
|
|
|
408
|
+
for (let i = 0; i < this._positions.length; i++) {
|
|
409
|
+
const { start, end } = this._positions[i];
|
|
756
410
|
if (
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
Math.floor(scrollOffset) >= Math.floor(lastItemScrollOffset))
|
|
411
|
+
center + activeSlideOffset >= start &&
|
|
412
|
+
center - activeSlideOffset <= end
|
|
760
413
|
) {
|
|
761
|
-
|
|
762
|
-
|
|
414
|
+
itemIndex = i;
|
|
415
|
+
break;
|
|
763
416
|
}
|
|
417
|
+
}
|
|
764
418
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
},
|
|
769
|
-
[
|
|
770
|
-
getScrollOffset,
|
|
771
|
-
getActiveItem,
|
|
772
|
-
getCustomDataLength,
|
|
773
|
-
getItemScrollOffset,
|
|
774
|
-
getDataIndex,
|
|
775
|
-
onScrollIndexChanged,
|
|
776
|
-
onScroll,
|
|
777
|
-
repositionScroll,
|
|
778
|
-
],
|
|
779
|
-
);
|
|
780
|
-
|
|
781
|
-
const handleMomentumScrollEnd = useCallback(
|
|
782
|
-
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
783
|
-
const scrollOffset = event
|
|
784
|
-
? getScrollOffset(event)
|
|
785
|
-
: currentScrollOffsetRef.current;
|
|
786
|
-
const nextActiveItem = getActiveItem(scrollOffset);
|
|
787
|
-
const hasSnapped = isMultiple(
|
|
788
|
-
scrollOffset,
|
|
789
|
-
vertical ? itemHeight : itemWidth,
|
|
790
|
-
);
|
|
791
|
-
|
|
792
|
-
if (nextActiveItem !== activeItemRef.current) {
|
|
793
|
-
activeItemRef.current = nextActiveItem;
|
|
794
|
-
onSnapToItem && onSnapToItem(getDataIndex(nextActiveItem));
|
|
795
|
-
|
|
796
|
-
if (hasSnapped && IS_ANDROID) {
|
|
797
|
-
repositionScroll(nextActiveItem);
|
|
798
|
-
} else if (IS_IOS) {
|
|
799
|
-
repositionScroll(nextActiveItem);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
419
|
+
return itemIndex || 0;
|
|
420
|
+
}
|
|
802
421
|
|
|
803
|
-
|
|
422
|
+
_initPositionsAndInterpolators(props = this.props) {
|
|
423
|
+
const { data } = props;
|
|
424
|
+
const itemMainDimension = this._getItemMainDimension();
|
|
804
425
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
enableAutoplayTimeoutRef.current = setTimeout(() => {
|
|
810
|
-
startAutoplay();
|
|
811
|
-
}, autoplayDelay);
|
|
812
|
-
}
|
|
813
|
-
},
|
|
814
|
-
[
|
|
815
|
-
getScrollOffset,
|
|
816
|
-
getActiveItem,
|
|
817
|
-
isMultiple,
|
|
818
|
-
vertical,
|
|
819
|
-
itemHeight,
|
|
820
|
-
itemWidth,
|
|
821
|
-
onSnapToItem,
|
|
822
|
-
getDataIndex,
|
|
823
|
-
repositionScroll,
|
|
824
|
-
onMomentumScrollEnd,
|
|
825
|
-
autoplayDelay,
|
|
826
|
-
],
|
|
827
|
-
);
|
|
828
|
-
|
|
829
|
-
const handleLayout = useCallback(
|
|
830
|
-
(event: LayoutChangeEvent) => {
|
|
831
|
-
if (onLayoutInitDoneRef.current) {
|
|
832
|
-
initPositionsAndInterpolators();
|
|
833
|
-
snapToItem(activeItemRef.current, false, false, true);
|
|
834
|
-
} else {
|
|
835
|
-
onLayoutInitDoneRef.current = true;
|
|
836
|
-
}
|
|
426
|
+
if (!data || !data.length) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
837
429
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
[initPositionsAndInterpolators, onLayout],
|
|
841
|
-
);
|
|
842
|
-
|
|
843
|
-
const snapToItem = useCallback(
|
|
844
|
-
(
|
|
845
|
-
index: number,
|
|
846
|
-
animated = true,
|
|
847
|
-
fireCallback = true,
|
|
848
|
-
forceScrollTo = false,
|
|
849
|
-
) => {
|
|
850
|
-
const itemsLength = getCustomDataLength();
|
|
851
|
-
const wrappedRef = getWrappedRef();
|
|
852
|
-
if (!itemsLength || !wrappedRef) {
|
|
853
|
-
return;
|
|
854
|
-
}
|
|
430
|
+
const interpolators: any[] = [];
|
|
431
|
+
this._positions = [];
|
|
855
432
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
index = itemsLength - 1;
|
|
860
|
-
}
|
|
433
|
+
this._getCustomData(props).forEach((_itemData, index) => {
|
|
434
|
+
const _index = this._getCustomIndex(index, props);
|
|
435
|
+
let animatedValue;
|
|
861
436
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
437
|
+
this._positions[index] = {
|
|
438
|
+
start: index * itemMainDimension,
|
|
439
|
+
end: index * itemMainDimension + itemMainDimension,
|
|
440
|
+
};
|
|
865
441
|
|
|
866
|
-
|
|
442
|
+
if (!this._shouldAnimateSlides(props) || !this._scrollPos) {
|
|
443
|
+
animatedValue = new Animated.Value(1);
|
|
444
|
+
} else {
|
|
445
|
+
let interpolator = defaultScrollInterpolator(
|
|
446
|
+
_index,
|
|
447
|
+
this.state.itemWidth,
|
|
448
|
+
);
|
|
867
449
|
|
|
868
|
-
|
|
869
|
-
|
|
450
|
+
animatedValue = this._scrollPos.interpolate({
|
|
451
|
+
...interpolator,
|
|
452
|
+
extrapolate: 'clamp',
|
|
453
|
+
});
|
|
870
454
|
}
|
|
871
455
|
|
|
872
|
-
|
|
456
|
+
interpolators.push(animatedValue);
|
|
457
|
+
});
|
|
873
458
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
activeItemRef.current = index;
|
|
459
|
+
this.setState({ interpolators });
|
|
460
|
+
}
|
|
877
461
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
462
|
+
_repositionScroll(index: number, animated = false) {
|
|
463
|
+
const { data, loopClonesPerSide = 3 } = this.props;
|
|
464
|
+
const dataLength = data && data.length;
|
|
881
465
|
|
|
882
|
-
|
|
883
|
-
if (animated) {
|
|
884
|
-
if (androidRepositioningTimeoutRef.current) {
|
|
885
|
-
clearTimeout(androidRepositioningTimeoutRef.current);
|
|
886
|
-
}
|
|
887
|
-
androidRepositioningTimeoutRef.current = setTimeout(() => {
|
|
888
|
-
repositionScroll(index, false);
|
|
889
|
-
}, 400);
|
|
890
|
-
} else {
|
|
891
|
-
repositionScroll(index);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
},
|
|
896
|
-
[
|
|
897
|
-
getCustomDataLength,
|
|
898
|
-
getWrappedRef,
|
|
899
|
-
getItemScrollOffset,
|
|
900
|
-
scrollTo,
|
|
901
|
-
onSnapToItem,
|
|
902
|
-
getDataIndex,
|
|
903
|
-
shouldRepositionScroll,
|
|
904
|
-
repositionScroll,
|
|
905
|
-
],
|
|
906
|
-
);
|
|
907
|
-
|
|
908
|
-
const startAutoplay = useCallback(() => {
|
|
909
|
-
autoplayRef.current = true;
|
|
910
|
-
|
|
911
|
-
if (autoplayingRef.current) {
|
|
466
|
+
if (typeof index === 'undefined' || !this._shouldRepositionScroll(index)) {
|
|
912
467
|
return;
|
|
913
468
|
}
|
|
914
469
|
|
|
915
|
-
|
|
916
|
-
clearTimeout(autoplayTimeoutRef.current);
|
|
917
|
-
}
|
|
918
|
-
autoplayTimeoutRef.current = setTimeout(() => {
|
|
919
|
-
autoplayingRef.current = true;
|
|
920
|
-
autoplayIntervalRef.current = setInterval(() => {
|
|
921
|
-
if (autoplayingRef.current) {
|
|
922
|
-
snapToNext();
|
|
923
|
-
}
|
|
924
|
-
}, autoplayInterval);
|
|
925
|
-
}, autoplayDelay);
|
|
926
|
-
}, [autoplayInterval, autoplayDelay]);
|
|
470
|
+
let repositionTo = index;
|
|
927
471
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
if (
|
|
931
|
-
|
|
932
|
-
}
|
|
933
|
-
if (enableAutoplayTimeoutRef.current) {
|
|
934
|
-
clearTimeout(enableAutoplayTimeoutRef.current);
|
|
472
|
+
if (index >= dataLength + loopClonesPerSide) {
|
|
473
|
+
repositionTo = index - dataLength;
|
|
474
|
+
} else if (index < loopClonesPerSide) {
|
|
475
|
+
repositionTo = index + dataLength;
|
|
935
476
|
}
|
|
936
|
-
|
|
937
|
-
|
|
477
|
+
|
|
478
|
+
this._snapToItem(repositionTo, animated, false);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
_onTouchStart(event: any) {
|
|
482
|
+
const { onTouchStart } = this.props;
|
|
483
|
+
|
|
484
|
+
if (this._getScrollEnabled() !== false && this._autoplaying) {
|
|
485
|
+
this.pauseAutoPlay();
|
|
938
486
|
}
|
|
939
|
-
}, []);
|
|
940
487
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
pauseAutoPlay();
|
|
944
|
-
}, [pauseAutoPlay]);
|
|
488
|
+
onTouchStart && onTouchStart(event);
|
|
489
|
+
}
|
|
945
490
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
if (!index || index < 0) {
|
|
949
|
-
index = 0;
|
|
950
|
-
}
|
|
491
|
+
_onTouchEnd(event: GestureResponderEvent) {
|
|
492
|
+
const { onTouchEnd } = this.props;
|
|
951
493
|
|
|
952
|
-
|
|
494
|
+
if (
|
|
495
|
+
this._getScrollEnabled() !== false &&
|
|
496
|
+
this._autoplay &&
|
|
497
|
+
!this._autoplaying
|
|
498
|
+
) {
|
|
499
|
+
this.startAutoplay();
|
|
500
|
+
}
|
|
953
501
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
502
|
+
onTouchEnd && onTouchEnd(event);
|
|
503
|
+
}
|
|
957
504
|
|
|
958
|
-
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
|
|
505
|
+
_onScroll(event: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
506
|
+
const { onScroll, onScrollIndexChanged, onSnapToItem } = this.props;
|
|
507
|
+
const scrollOffset = event
|
|
508
|
+
? this._getScrollOffset(event)
|
|
509
|
+
: this._currentScrollOffset;
|
|
510
|
+
const nextActiveItem = this._getActiveItem(scrollOffset);
|
|
511
|
+
const dataLength = this._getCustomDataLength();
|
|
512
|
+
const lastItemScrollOffset = this._getItemScrollOffset(dataLength - 1);
|
|
962
513
|
|
|
963
|
-
|
|
964
|
-
(animated = true, fireCallback = true) => {
|
|
965
|
-
const itemsLength = getCustomDataLength();
|
|
514
|
+
this._currentScrollOffset = scrollOffset;
|
|
966
515
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
[getCustomDataLength, snapToItem],
|
|
974
|
-
);
|
|
975
|
-
|
|
976
|
-
const snapToPrev = useCallback(
|
|
977
|
-
(animated = true, fireCallback = true) => {
|
|
978
|
-
const itemsLength = getCustomDataLength();
|
|
979
|
-
|
|
980
|
-
let newIndex = activeItemRef.current - 1;
|
|
981
|
-
if (newIndex < 0) {
|
|
982
|
-
newIndex = itemsLength - 1;
|
|
983
|
-
}
|
|
984
|
-
snapToItem(newIndex, animated, fireCallback);
|
|
985
|
-
},
|
|
986
|
-
[getCustomDataLength, snapToItem],
|
|
987
|
-
);
|
|
988
|
-
|
|
989
|
-
const triggerRenderingHack = useCallback(
|
|
990
|
-
(offset = 1) => {
|
|
991
|
-
hackActiveSlideAnimation(activeItemRef.current, offset);
|
|
992
|
-
},
|
|
993
|
-
[hackActiveSlideAnimation],
|
|
994
|
-
);
|
|
995
|
-
|
|
996
|
-
// Display warnings
|
|
997
|
-
const displayWarnings = useCallback(() => {
|
|
998
|
-
const pluginName = 'react-native-snap-carousel';
|
|
999
|
-
|
|
1000
|
-
if (!vertical && (!sliderWidth || !itemWidth)) {
|
|
1001
|
-
console.error(
|
|
1002
|
-
`${pluginName}: You need to specify both 'sliderWidth' and 'itemWidth' for horizontal carousels`,
|
|
1003
|
-
);
|
|
1004
|
-
}
|
|
1005
|
-
if (vertical && (!sliderHeight || !itemHeight)) {
|
|
1006
|
-
console.error(
|
|
1007
|
-
`${pluginName}: You need to specify both 'sliderHeight' and 'itemHeight' for vertical carousels`,
|
|
1008
|
-
);
|
|
516
|
+
if (nextActiveItem !== this._onScrollActiveItem) {
|
|
517
|
+
this._onScrollActiveItem = nextActiveItem;
|
|
518
|
+
onScrollIndexChanged &&
|
|
519
|
+
onScrollIndexChanged(this._getDataIndex(nextActiveItem));
|
|
520
|
+
|
|
521
|
+
onSnapToItem && onSnapToItem(this._getDataIndex(nextActiveItem));
|
|
1009
522
|
}
|
|
1010
|
-
}, [vertical, sliderWidth, itemWidth, sliderHeight, itemHeight]);
|
|
1011
523
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
? [{ nativeEvent: { contentOffset: { y: scrollPosRef.current } } }]
|
|
1021
|
-
: [{ nativeEvent: { contentOffset: { x: scrollPosRef.current } } }];
|
|
524
|
+
if (
|
|
525
|
+
(IS_IOS && scrollOffset > lastItemScrollOffset) ||
|
|
526
|
+
(IS_ANDROID &&
|
|
527
|
+
Math.floor(scrollOffset) > Math.floor(lastItemScrollOffset))
|
|
528
|
+
) {
|
|
529
|
+
this._activeItem = nextActiveItem;
|
|
530
|
+
this._repositionScroll(nextActiveItem);
|
|
531
|
+
}
|
|
1022
532
|
|
|
1023
|
-
if (onScroll
|
|
1024
|
-
|
|
1025
|
-
const [argMap] = (onScroll as any)._argMapping;
|
|
1026
|
-
if (argMap && argMap.nativeEvent && argMap.nativeEvent.contentOffset) {
|
|
1027
|
-
scrollPosRef.current =
|
|
1028
|
-
argMap.nativeEvent.contentOffset.x ||
|
|
1029
|
-
argMap.nativeEvent.contentOffset.y ||
|
|
1030
|
-
scrollPosRef.current;
|
|
1031
|
-
}
|
|
1032
|
-
argMapping.push(...(onScroll as any)._argMapping);
|
|
533
|
+
if (typeof onScroll === 'function' && event) {
|
|
534
|
+
onScroll(event);
|
|
1033
535
|
}
|
|
1034
|
-
|
|
1035
|
-
}, [handleScroll, vertical, onScroll]);
|
|
1036
|
-
|
|
1037
|
-
// Expose public methods via ref
|
|
1038
|
-
useImperativeHandle(
|
|
1039
|
-
ref,
|
|
1040
|
-
() => ({
|
|
1041
|
-
snapToItem: snapToItemPublic,
|
|
1042
|
-
snapToNext,
|
|
1043
|
-
snapToPrev,
|
|
1044
|
-
startAutoplay,
|
|
1045
|
-
pauseAutoPlay,
|
|
1046
|
-
stopAutoplay,
|
|
1047
|
-
triggerRenderingHack,
|
|
1048
|
-
get realIndex() {
|
|
1049
|
-
return activeItemRef.current;
|
|
1050
|
-
},
|
|
1051
|
-
get currentIndex() {
|
|
1052
|
-
return getDataIndex(activeItemRef.current);
|
|
1053
|
-
},
|
|
1054
|
-
get currentScrollPosition() {
|
|
1055
|
-
return currentScrollOffsetRef.current;
|
|
1056
|
-
},
|
|
1057
|
-
}),
|
|
1058
|
-
[
|
|
1059
|
-
snapToItemPublic,
|
|
1060
|
-
snapToNext,
|
|
1061
|
-
snapToPrev,
|
|
1062
|
-
startAutoplay,
|
|
1063
|
-
pauseAutoPlay,
|
|
1064
|
-
stopAutoplay,
|
|
1065
|
-
triggerRenderingHack,
|
|
1066
|
-
getDataIndex,
|
|
1067
|
-
],
|
|
1068
|
-
);
|
|
1069
|
-
|
|
1070
|
-
// componentDidMount
|
|
1071
|
-
useEffect(() => {
|
|
1072
|
-
mountedRef.current = true;
|
|
1073
|
-
initPositionsAndInterpolators();
|
|
1074
|
-
displayWarnings();
|
|
1075
|
-
setScrollHandler();
|
|
1076
|
-
|
|
1077
|
-
initTimeoutRef.current = setTimeout(() => {
|
|
1078
|
-
if (!mountedRef.current) {
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
536
|
+
}
|
|
1081
537
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
538
|
+
_onMomentumScrollEnd(event: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
539
|
+
const { autoplayDelay, onMomentumScrollEnd, onSnapToItem } = this.props;
|
|
540
|
+
const { itemWidth } = this.state;
|
|
541
|
+
const scrollOffset = event
|
|
542
|
+
? this._getScrollOffset(event)
|
|
543
|
+
: this._currentScrollOffset;
|
|
544
|
+
const nextActiveItem = this._getActiveItem(scrollOffset);
|
|
545
|
+
const hasSnapped = this._isMultiple(scrollOffset, itemWidth);
|
|
1090
546
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
}
|
|
547
|
+
if (nextActiveItem !== this._activeItem) {
|
|
548
|
+
this._activeItem = nextActiveItem;
|
|
549
|
+
onSnapToItem && onSnapToItem(this._getDataIndex(nextActiveItem));
|
|
1095
550
|
|
|
1096
|
-
if (
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
} else {
|
|
1101
|
-
apparitionCallback();
|
|
551
|
+
if (hasSnapped && IS_ANDROID) {
|
|
552
|
+
this._repositionScroll(nextActiveItem);
|
|
553
|
+
} else if (IS_IOS) {
|
|
554
|
+
this._repositionScroll(nextActiveItem);
|
|
1102
555
|
}
|
|
1103
|
-
}
|
|
556
|
+
}
|
|
1104
557
|
|
|
1105
|
-
|
|
1106
|
-
mountedRef.current = false;
|
|
1107
|
-
stopAutoplay();
|
|
1108
|
-
if (initTimeoutRef.current) clearTimeout(initTimeoutRef.current);
|
|
1109
|
-
if (apparitionTimeoutRef.current)
|
|
1110
|
-
clearTimeout(apparitionTimeoutRef.current);
|
|
1111
|
-
if (hackSlideAnimationTimeoutRef.current)
|
|
1112
|
-
clearTimeout(hackSlideAnimationTimeoutRef.current);
|
|
1113
|
-
if (enableAutoplayTimeoutRef.current)
|
|
1114
|
-
clearTimeout(enableAutoplayTimeoutRef.current);
|
|
1115
|
-
if (autoplayTimeoutRef.current) clearTimeout(autoplayTimeoutRef.current);
|
|
1116
|
-
if (snapNoMomentumTimeoutRef.current)
|
|
1117
|
-
clearTimeout(snapNoMomentumTimeoutRef.current);
|
|
1118
|
-
if (androidRepositioningTimeoutRef.current)
|
|
1119
|
-
clearTimeout(androidRepositioningTimeoutRef.current);
|
|
1120
|
-
};
|
|
1121
|
-
}, []);
|
|
558
|
+
onMomentumScrollEnd && onMomentumScrollEnd(event);
|
|
1122
559
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
560
|
+
if (IS_ANDROID && this._autoplay && !this._autoplaying) {
|
|
561
|
+
if (this._enableAutoplayTimeout != null)
|
|
562
|
+
clearTimeout(this._enableAutoplayTimeout);
|
|
563
|
+
this._enableAutoplayTimeout = setTimeout(() => {
|
|
564
|
+
this.startAutoplay();
|
|
565
|
+
}, autoplayDelay);
|
|
1127
566
|
}
|
|
1128
|
-
}
|
|
567
|
+
}
|
|
1129
568
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
const itemsLength = getCustomDataLength();
|
|
569
|
+
_onLayout(event: LayoutChangeEvent) {
|
|
570
|
+
const { onLayout, visibleItem = 1 } = this.props;
|
|
1133
571
|
|
|
1134
|
-
if (
|
|
1135
|
-
|
|
572
|
+
if (this._onLayoutInitDone) {
|
|
573
|
+
this._initPositionsAndInterpolators();
|
|
574
|
+
this._snapToItem(this._activeItem, false, false, true);
|
|
575
|
+
} else {
|
|
576
|
+
this._onLayoutInitDone = true;
|
|
577
|
+
}
|
|
578
|
+
const containerWidth = event.nativeEvent.layout.width;
|
|
579
|
+
let itemWidth =
|
|
580
|
+
this.props.visibleItem === 1
|
|
581
|
+
? screenWidth - Spacing.M * 2
|
|
582
|
+
: Math.ceil(
|
|
583
|
+
(containerWidth * 0.9 - visibleItem * Spacing.S) / visibleItem,
|
|
584
|
+
);
|
|
585
|
+
if (this.props.itemWidth) {
|
|
586
|
+
itemWidth = this.props.itemWidth;
|
|
587
|
+
}
|
|
588
|
+
if (this.props.full) {
|
|
589
|
+
itemWidth = containerWidth;
|
|
1136
590
|
}
|
|
1137
591
|
|
|
1138
|
-
|
|
1139
|
-
let nextActiveItem =
|
|
1140
|
-
typeof activeItemRef.current !== 'undefined'
|
|
1141
|
-
? activeItemRef.current
|
|
1142
|
-
: nextFirstItem;
|
|
592
|
+
this.setState({ containerWidth, itemWidth });
|
|
1143
593
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
(previousItemsLengthRef.current !== itemsLength ||
|
|
1147
|
-
previousItemsLengthRef.current === 0)) ||
|
|
1148
|
-
(!vertical &&
|
|
1149
|
-
(previousItemsLengthRef.current !== itemsLength ||
|
|
1150
|
-
previousItemsLengthRef.current === 0));
|
|
594
|
+
onLayout && onLayout(event);
|
|
595
|
+
}
|
|
1151
596
|
|
|
1152
|
-
|
|
1153
|
-
|
|
597
|
+
_getPositionIndex(index: number) {
|
|
598
|
+
const { loop, loopClonesPerSide = 3 } = this.props;
|
|
599
|
+
return loop ? index + loopClonesPerSide : index;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
_snapToItem(
|
|
603
|
+
index: number,
|
|
604
|
+
animated = true,
|
|
605
|
+
fireCallback = true,
|
|
606
|
+
forceScrollTo = false,
|
|
607
|
+
) {
|
|
608
|
+
const { onSnapToItem } = this.props;
|
|
609
|
+
const itemsLength = this._getCustomDataLength();
|
|
610
|
+
const wrappedRef = this._getWrappedRef();
|
|
611
|
+
if (!itemsLength || !wrappedRef) {
|
|
612
|
+
return;
|
|
1154
613
|
}
|
|
1155
614
|
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1158
|
-
|
|
615
|
+
if (!index || index < 0) {
|
|
616
|
+
index = 0;
|
|
617
|
+
} else if (itemsLength > 0 && index >= itemsLength) {
|
|
618
|
+
index = itemsLength - 1;
|
|
619
|
+
}
|
|
1159
620
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
621
|
+
if (index === this._activeItem && !forceScrollTo) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
this._carouselRef.scrollToIndex({
|
|
626
|
+
index,
|
|
627
|
+
animated: true,
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
const requiresManualTrigger = !animated || IS_ANDROID;
|
|
631
|
+
if (requiresManualTrigger) {
|
|
632
|
+
this._activeItem = index;
|
|
633
|
+
|
|
634
|
+
if (fireCallback) {
|
|
635
|
+
onSnapToItem && onSnapToItem(this._getDataIndex(index));
|
|
1163
636
|
}
|
|
1164
637
|
|
|
1165
|
-
if (
|
|
1166
|
-
|
|
638
|
+
if (IS_ANDROID && this._shouldRepositionScroll(index)) {
|
|
639
|
+
if (animated) {
|
|
640
|
+
this._androidRepositioningTimeout = setTimeout(() => {
|
|
641
|
+
this._repositionScroll(index, false);
|
|
642
|
+
}, 400);
|
|
643
|
+
} else {
|
|
644
|
+
this._repositionScroll(index);
|
|
645
|
+
}
|
|
1167
646
|
}
|
|
1168
|
-
} else if (
|
|
1169
|
-
nextFirstItem !== previousFirstItemRef.current &&
|
|
1170
|
-
nextFirstItem !== activeItemRef.current
|
|
1171
|
-
) {
|
|
1172
|
-
activeItemRef.current = nextFirstItem;
|
|
1173
|
-
previousFirstItemRef.current = nextFirstItem;
|
|
1174
|
-
snapToItem(nextFirstItem, false, true, true);
|
|
1175
647
|
}
|
|
1176
|
-
}
|
|
1177
|
-
data,
|
|
1178
|
-
firstItem,
|
|
1179
|
-
interpolators.length,
|
|
1180
|
-
vertical,
|
|
1181
|
-
itemWidth,
|
|
1182
|
-
itemHeight,
|
|
1183
|
-
sliderWidth,
|
|
1184
|
-
sliderHeight,
|
|
1185
|
-
]);
|
|
1186
|
-
|
|
1187
|
-
// componentDidUpdate - handle onScroll prop changes
|
|
1188
|
-
useEffect(() => {
|
|
1189
|
-
setScrollHandler();
|
|
1190
|
-
}, [onScroll]);
|
|
1191
|
-
|
|
1192
|
-
// Render item
|
|
1193
|
-
const renderItemComponent = useCallback(
|
|
1194
|
-
({ item, index }: { item: any; index: number }) => {
|
|
1195
|
-
const animatedValue = interpolators && interpolators[index];
|
|
1196
|
-
|
|
1197
|
-
if (typeof animatedValue === 'undefined') {
|
|
1198
|
-
return null;
|
|
1199
|
-
}
|
|
648
|
+
}
|
|
1200
649
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
const dataIndex = getDataIndex(index);
|
|
1207
|
-
|
|
1208
|
-
const mainDimension = vertical
|
|
1209
|
-
? { height: itemHeight }
|
|
1210
|
-
: { width: itemWidth };
|
|
1211
|
-
const specificProps = needsScrollView()
|
|
1212
|
-
? {
|
|
1213
|
-
key: keyExtractor
|
|
1214
|
-
? keyExtractor(item, index)
|
|
1215
|
-
: getKeyExtractor(item, index),
|
|
1216
|
-
}
|
|
1217
|
-
: {};
|
|
1218
|
-
|
|
1219
|
-
return (
|
|
1220
|
-
<Component
|
|
1221
|
-
style={[mainDimension, slideStyle, animatedStyle]}
|
|
1222
|
-
pointerEvents="box-none"
|
|
1223
|
-
{...specificProps}
|
|
1224
|
-
>
|
|
1225
|
-
{vertical
|
|
1226
|
-
? renderItem(
|
|
1227
|
-
{
|
|
1228
|
-
item,
|
|
1229
|
-
index,
|
|
1230
|
-
dataIndex,
|
|
1231
|
-
realIndex: getDataIndex(index),
|
|
1232
|
-
activeIndex: getDataIndex(activeItemRef.current),
|
|
1233
|
-
},
|
|
1234
|
-
{
|
|
1235
|
-
scrollPosition: scrollPosRef.current,
|
|
1236
|
-
carouselRef: carouselRef.current,
|
|
1237
|
-
vertical: vertical,
|
|
1238
|
-
sliderHeight: sliderHeight,
|
|
1239
|
-
itemHeight: itemHeight,
|
|
1240
|
-
},
|
|
1241
|
-
)
|
|
1242
|
-
: renderItem(
|
|
1243
|
-
{
|
|
1244
|
-
item,
|
|
1245
|
-
index,
|
|
1246
|
-
dataIndex,
|
|
1247
|
-
realIndex: getDataIndex(index),
|
|
1248
|
-
activeIndex: getDataIndex(activeItemRef.current),
|
|
1249
|
-
},
|
|
1250
|
-
{
|
|
1251
|
-
scrollPosition: scrollPosRef.current,
|
|
1252
|
-
carouselRef: carouselRef.current,
|
|
1253
|
-
vertical: false,
|
|
1254
|
-
sliderWidth: sliderWidth,
|
|
1255
|
-
itemWidth: itemWidth,
|
|
1256
|
-
},
|
|
1257
|
-
)}
|
|
1258
|
-
</Component>
|
|
1259
|
-
);
|
|
1260
|
-
},
|
|
1261
|
-
[
|
|
1262
|
-
interpolators,
|
|
1263
|
-
shouldAnimateSlides,
|
|
1264
|
-
getSlideInterpolatedStyle,
|
|
1265
|
-
getDataIndex,
|
|
1266
|
-
vertical,
|
|
1267
|
-
itemHeight,
|
|
1268
|
-
itemWidth,
|
|
1269
|
-
needsScrollView,
|
|
1270
|
-
keyExtractor,
|
|
1271
|
-
getKeyExtractor,
|
|
1272
|
-
slideStyle,
|
|
1273
|
-
renderItem,
|
|
1274
|
-
sliderHeight,
|
|
1275
|
-
sliderWidth,
|
|
1276
|
-
],
|
|
1277
|
-
);
|
|
1278
|
-
|
|
1279
|
-
// Get component props
|
|
1280
|
-
const getComponentOverridableProps = useCallback(() => {
|
|
1281
|
-
const visibleItems =
|
|
1282
|
-
Math.max(
|
|
1283
|
-
1,
|
|
1284
|
-
Math.ceil(
|
|
1285
|
-
vertical
|
|
1286
|
-
? (sliderHeight || 1) / (itemHeight || 1)
|
|
1287
|
-
: (sliderWidth || 1) / (itemWidth || 1),
|
|
1288
|
-
),
|
|
1289
|
-
) + 1;
|
|
1290
|
-
const initialNumPerSide = enableLoop() ? loopClonesPerSide : 2;
|
|
1291
|
-
const initialNumToRender = Math.max(
|
|
1292
|
-
1,
|
|
1293
|
-
visibleItems + initialNumPerSide * 2,
|
|
1294
|
-
);
|
|
1295
|
-
const maxToRenderPerBatch = Math.max(
|
|
1296
|
-
1,
|
|
1297
|
-
initialNumToRender + initialNumPerSide * 2,
|
|
1298
|
-
);
|
|
1299
|
-
const windowSize = Math.max(2, maxToRenderPerBatch);
|
|
650
|
+
_renderItem(info: { item: any; index: number }) {
|
|
651
|
+
const { item, index } = info;
|
|
652
|
+
const { interpolators, itemWidth } = this.state;
|
|
653
|
+
const { slideStyle, full } = this.props;
|
|
654
|
+
const animatedValue = interpolators && interpolators[index];
|
|
1300
655
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
maxToRenderPerBatch,
|
|
1305
|
-
windowSize,
|
|
1306
|
-
}
|
|
1307
|
-
: {};
|
|
656
|
+
if (typeof animatedValue === 'undefined') {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
1308
659
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
decelerationRate: 'fast' as const,
|
|
1313
|
-
directionalLockEnabled: true,
|
|
1314
|
-
disableScrollViewPanResponder: false,
|
|
1315
|
-
inverted: needsRTLAdaptations(),
|
|
1316
|
-
overScrollMode: 'never' as const,
|
|
1317
|
-
pinchGestureEnabled: false,
|
|
1318
|
-
pointerEvents: hideCarousel ? ('none' as const) : ('auto' as const),
|
|
1319
|
-
scrollsToTop: false,
|
|
1320
|
-
showsHorizontalScrollIndicator: false,
|
|
1321
|
-
showsVerticalScrollIndicator: false,
|
|
1322
|
-
};
|
|
1323
|
-
}, [
|
|
1324
|
-
vertical,
|
|
1325
|
-
sliderHeight,
|
|
1326
|
-
itemHeight,
|
|
1327
|
-
sliderWidth,
|
|
1328
|
-
itemWidth,
|
|
1329
|
-
enableLoop,
|
|
1330
|
-
loopClonesPerSide,
|
|
1331
|
-
needsScrollView,
|
|
1332
|
-
needsRTLAdaptations,
|
|
1333
|
-
hideCarousel,
|
|
1334
|
-
]);
|
|
1335
|
-
|
|
1336
|
-
const getComponentStaticProps = useCallback(() => {
|
|
1337
|
-
const containerStyle = [
|
|
1338
|
-
containerCustomStyle || style || {},
|
|
1339
|
-
hideCarousel ? { opacity: 0 } : {},
|
|
1340
|
-
vertical
|
|
1341
|
-
? { height: sliderHeight, flexDirection: 'column' as const }
|
|
1342
|
-
: {
|
|
1343
|
-
width: sliderWidth,
|
|
1344
|
-
flexDirection: needsRTLAdaptations()
|
|
1345
|
-
? ('row-reverse' as const)
|
|
1346
|
-
: ('row' as const),
|
|
1347
|
-
},
|
|
1348
|
-
];
|
|
660
|
+
const animate = this._shouldAnimateSlides();
|
|
661
|
+
const Component = animate ? Animated.View : View;
|
|
662
|
+
const mainDimension = { width: itemWidth };
|
|
1349
663
|
|
|
1350
|
-
|
|
1351
|
-
? {
|
|
1352
|
-
paddingTop: getContainerInnerMargin(),
|
|
1353
|
-
paddingBottom: getContainerInnerMargin(true),
|
|
1354
|
-
}
|
|
664
|
+
let spacingStyle: ViewStyle = this.props.loop
|
|
665
|
+
? { marginLeft: Spacing.S }
|
|
1355
666
|
: {
|
|
1356
|
-
|
|
1357
|
-
|
|
667
|
+
marginLeft: index === 0 ? Spacing.M : 0,
|
|
668
|
+
marginRight:
|
|
669
|
+
index === this._getCustomDataLength() - 1 ? Spacing.M : Spacing.S,
|
|
1358
670
|
};
|
|
1359
671
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
672
|
+
if (full) {
|
|
673
|
+
spacingStyle = {};
|
|
674
|
+
}
|
|
675
|
+
const animatedStyle = defaultAnimatedStyles(animatedValue, this.props);
|
|
676
|
+
return (
|
|
677
|
+
<Component
|
|
678
|
+
style={[
|
|
679
|
+
mainDimension,
|
|
680
|
+
animatedStyle,
|
|
681
|
+
{ overflow: 'hidden' },
|
|
682
|
+
spacingStyle,
|
|
683
|
+
slideStyle,
|
|
684
|
+
]}
|
|
685
|
+
pointerEvents="box-none"
|
|
686
|
+
>
|
|
687
|
+
{this.props.renderItem({
|
|
688
|
+
item,
|
|
689
|
+
index,
|
|
690
|
+
})}
|
|
691
|
+
</Component>
|
|
692
|
+
);
|
|
693
|
+
}
|
|
1364
694
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
snapToOffsets: getSnapOffsets(),
|
|
1373
|
-
};
|
|
695
|
+
startAutoplay() {
|
|
696
|
+
const { autoplayInterval, autoplayDelay } = this.props;
|
|
697
|
+
this._autoplay = true;
|
|
698
|
+
|
|
699
|
+
if (this._autoplaying) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
1374
702
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
keyExtractor: keyExtractor || getKeyExtractor,
|
|
1382
|
-
numColumns: 1,
|
|
1383
|
-
renderItem: renderItemComponent as any, // Type cast for compatibility
|
|
703
|
+
if (this._autoplayTimeout != null) clearTimeout(this._autoplayTimeout);
|
|
704
|
+
this._autoplayTimeout = setTimeout(() => {
|
|
705
|
+
this._autoplaying = true;
|
|
706
|
+
this._autoplayInterval = setInterval(() => {
|
|
707
|
+
if (this._autoplaying) {
|
|
708
|
+
this.snapToNext();
|
|
1384
709
|
}
|
|
1385
|
-
|
|
710
|
+
}, autoplayInterval);
|
|
711
|
+
}, autoplayDelay);
|
|
712
|
+
}
|
|
1386
713
|
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
horizontal: !vertical,
|
|
1394
|
-
scrollEventThrottle: 1,
|
|
1395
|
-
style: containerStyle,
|
|
1396
|
-
onLayout: handleLayout,
|
|
1397
|
-
onMomentumScrollEnd: handleMomentumScrollEnd,
|
|
1398
|
-
onScroll: onScrollHandlerRef.current,
|
|
1399
|
-
onTouchStart: handleTouchStart,
|
|
1400
|
-
onTouchEnd: handleTouchEnd,
|
|
1401
|
-
};
|
|
1402
|
-
}, [
|
|
1403
|
-
containerCustomStyle,
|
|
1404
|
-
style,
|
|
1405
|
-
hideCarousel,
|
|
1406
|
-
vertical,
|
|
1407
|
-
sliderHeight,
|
|
1408
|
-
sliderWidth,
|
|
1409
|
-
needsRTLAdaptations,
|
|
1410
|
-
getContainerInnerMargin,
|
|
1411
|
-
useExperimentalSnap,
|
|
1412
|
-
contentContainerCustomStyle,
|
|
1413
|
-
disableIntervalMomentum,
|
|
1414
|
-
activeSlideAlignment,
|
|
1415
|
-
getItemMainDimension,
|
|
1416
|
-
getSnapOffsets,
|
|
1417
|
-
needsScrollView,
|
|
1418
|
-
CellRendererComponent,
|
|
1419
|
-
getCellRendererComponent,
|
|
1420
|
-
getItemLayout,
|
|
1421
|
-
getFirstItem,
|
|
1422
|
-
firstItem,
|
|
1423
|
-
keyExtractor,
|
|
1424
|
-
getKeyExtractor,
|
|
1425
|
-
renderItemComponent,
|
|
1426
|
-
getCustomData,
|
|
1427
|
-
handleLayout,
|
|
1428
|
-
handleMomentumScrollEnd,
|
|
1429
|
-
handleTouchStart,
|
|
1430
|
-
handleTouchEnd,
|
|
1431
|
-
]);
|
|
1432
|
-
|
|
1433
|
-
// Render
|
|
1434
|
-
if (!data || !renderItem) {
|
|
1435
|
-
return null;
|
|
714
|
+
pauseAutoPlay() {
|
|
715
|
+
this._autoplaying = false;
|
|
716
|
+
if (this._autoplayTimeout != null) clearTimeout(this._autoplayTimeout);
|
|
717
|
+
if (this._enableAutoplayTimeout != null)
|
|
718
|
+
clearTimeout(this._enableAutoplayTimeout);
|
|
719
|
+
if (this._autoplayInterval != null) clearInterval(this._autoplayInterval);
|
|
1436
720
|
}
|
|
1437
721
|
|
|
1438
|
-
|
|
1439
|
-
|
|
722
|
+
stopAutoplay() {
|
|
723
|
+
this._autoplay = false;
|
|
724
|
+
this.pauseAutoPlay();
|
|
725
|
+
}
|
|
1440
726
|
|
|
1441
|
-
|
|
1442
|
-
|
|
727
|
+
snapToItem(index: number, animated = true, fireCallback = true) {
|
|
728
|
+
if (!index || index < 0) {
|
|
729
|
+
index = 0;
|
|
730
|
+
}
|
|
1443
731
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
732
|
+
const positionIndex = this._getPositionIndex(index);
|
|
733
|
+
|
|
734
|
+
if (positionIndex === this._activeItem) {
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
1449
737
|
|
|
1450
|
-
|
|
1451
|
-
|
|
738
|
+
this._snapToItem(positionIndex, animated, fireCallback);
|
|
739
|
+
}
|
|
1452
740
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
});
|
|
741
|
+
snapToNext(animated = true, fireCallback = true) {
|
|
742
|
+
const itemsLength = this._getCustomDataLength();
|
|
743
|
+
|
|
744
|
+
let newIndex = this._activeItem + 1;
|
|
745
|
+
if (newIndex > itemsLength - 1) {
|
|
746
|
+
newIndex = 0;
|
|
747
|
+
}
|
|
748
|
+
this._snapToItem(newIndex, animated, fireCallback);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
snapToPrev(animated = true, fireCallback = true) {
|
|
752
|
+
const itemsLength = this._getCustomDataLength();
|
|
1466
753
|
|
|
1467
|
-
|
|
754
|
+
let newIndex = this._activeItem - 1;
|
|
755
|
+
if (newIndex < 0) {
|
|
756
|
+
newIndex = itemsLength - 1;
|
|
757
|
+
}
|
|
758
|
+
this._snapToItem(newIndex, animated, fireCallback);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
render() {
|
|
762
|
+
const {
|
|
763
|
+
loopClonesPerSide = 3,
|
|
764
|
+
visibleItem = 1,
|
|
765
|
+
firstItem = 0,
|
|
766
|
+
getItemLayout,
|
|
767
|
+
keyExtractor,
|
|
768
|
+
style,
|
|
769
|
+
disableIntervalMomentum,
|
|
770
|
+
enableSnap,
|
|
771
|
+
contentContainerStyle,
|
|
772
|
+
} = this.props;
|
|
773
|
+
const { hideCarousel } = this.state;
|
|
774
|
+
|
|
775
|
+
const initialNumPerSide = this._enableLoop() ? loopClonesPerSide : 2;
|
|
776
|
+
const initialNumToRender =
|
|
777
|
+
visibleItem > 2
|
|
778
|
+
? visibleItem + initialNumPerSide * 2
|
|
779
|
+
: initialNumPerSide * 2;
|
|
780
|
+
const maxToRenderPerBatch = initialNumToRender;
|
|
781
|
+
const windowSize = maxToRenderPerBatch;
|
|
782
|
+
|
|
783
|
+
const snapToInterval = enableSnap
|
|
784
|
+
? this._getItemMainDimension()
|
|
785
|
+
: undefined;
|
|
786
|
+
|
|
787
|
+
const specificProps = {
|
|
788
|
+
getItemLayout: getItemLayout || this._getItemLayout,
|
|
789
|
+
initialScrollIndex: this._getFirstItem(firstItem),
|
|
790
|
+
keyExtractor: keyExtractor || this._getKeyExtractor,
|
|
791
|
+
renderItem: this._renderItem,
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
return (
|
|
795
|
+
<Animated.FlatList
|
|
796
|
+
{...this.props}
|
|
797
|
+
{...specificProps}
|
|
798
|
+
ref={c => {
|
|
799
|
+
this._carouselRef = c;
|
|
800
|
+
}}
|
|
801
|
+
overScrollMode={'never'}
|
|
802
|
+
snapToInterval={
|
|
803
|
+
this.props.snapToInterval ? this.props.snapToInterval : snapToInterval
|
|
804
|
+
}
|
|
805
|
+
disableIntervalMomentum={disableIntervalMomentum}
|
|
806
|
+
pointerEvents={hideCarousel ? 'none' : 'auto'}
|
|
807
|
+
decelerationRate={'fast'}
|
|
808
|
+
numColumns={1}
|
|
809
|
+
style={[
|
|
810
|
+
style,
|
|
811
|
+
{ width: '100%', flexDirection: 'row' },
|
|
812
|
+
hideCarousel ? { opacity: 0 } : {},
|
|
813
|
+
]}
|
|
814
|
+
automaticallyAdjustContentInsets={false}
|
|
815
|
+
directionalLockEnabled
|
|
816
|
+
contentContainerStyle={contentContainerStyle}
|
|
817
|
+
disableScrollViewPanResponder={false}
|
|
818
|
+
pinchGestureEnabled={false}
|
|
819
|
+
scrollsToTop={false}
|
|
820
|
+
showsHorizontalScrollIndicator={false}
|
|
821
|
+
showsVerticalScrollIndicator={false}
|
|
822
|
+
initialNumToRender={initialNumToRender}
|
|
823
|
+
maxToRenderPerBatch={maxToRenderPerBatch}
|
|
824
|
+
windowSize={windowSize}
|
|
825
|
+
pagingEnabled={enableSnap}
|
|
826
|
+
data={this._getCustomData()}
|
|
827
|
+
horizontal
|
|
828
|
+
scrollEventThrottle={1}
|
|
829
|
+
onLayout={this._onLayout}
|
|
830
|
+
onMomentumScrollEnd={this._onMomentumScrollEnd}
|
|
831
|
+
onScroll={this._onScrollHandler}
|
|
832
|
+
onTouchStart={this._onTouchStart}
|
|
833
|
+
onTouchEnd={this._onTouchEnd}
|
|
834
|
+
/>
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
1468
838
|
|
|
1469
839
|
export { Carousel };
|
|
1470
|
-
export type {
|
|
840
|
+
export type { CarouselProps, CarouselRef };
|