react-native-reanimated-carousel 3.3.0 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,362 +0,0 @@
1
- import { useMemo } from "react";
2
- import type { TransformsStyle, ViewStyle } from "react-native";
3
- import { Dimensions } from "react-native";
4
- import { Extrapolate, interpolate } from "react-native-reanimated";
5
-
6
- import type { IComputedDirectionTypes, CustomConfig } from "../types";
7
-
8
- const screen = Dimensions.get("window");
9
-
10
- export interface ILayoutConfig {
11
- showLength?: number
12
- moveSize?: number
13
- stackInterval?: number
14
- scaleInterval?: number
15
- opacityInterval?: number
16
- rotateZDeg?: number
17
- snapDirection?: "left" | "right"
18
- }
19
-
20
- export type TStackModeProps = IComputedDirectionTypes<{
21
- /**
22
- * Carousel Animated transitions.
23
- */
24
- mode?: "horizontal-stack" | "vertical-stack"
25
- /**
26
- * Stack animation style.
27
- * @default
28
- * mode: 'vertical',
29
- * snapDirection: 'right',
30
- * moveSize: window.width,
31
- * stackInterval: 30,
32
- * scaleInterval: 0.08,
33
- * rotateZDeg: 135,
34
- */
35
- modeConfig?: ILayoutConfig
36
- }>;
37
-
38
- export function horizontalStackLayout(modeConfig: ILayoutConfig = {}) {
39
- return (_value: number) => {
40
- "worklet";
41
-
42
- const {
43
- showLength,
44
- snapDirection = "left",
45
- moveSize = screen.width,
46
- stackInterval = 18,
47
- scaleInterval = 0.04,
48
- opacityInterval = 0.1,
49
- rotateZDeg = 30,
50
- } = modeConfig;
51
-
52
- const transform: TransformsStyle["transform"] = [];
53
- const { validLength, value, inputRange } = getCommonVariables({
54
- showLength: showLength!,
55
- value: _value,
56
- snapDirection,
57
- });
58
- const { zIndex, opacity } = getCommonStyles({
59
- validLength,
60
- value,
61
- opacityInterval,
62
- snapDirection,
63
- });
64
-
65
- const styles: ViewStyle = {
66
- transform,
67
- zIndex,
68
- opacity,
69
- };
70
-
71
- let translateX: number;
72
- let scale: number;
73
- let rotateZ: string;
74
-
75
- if (snapDirection === "left") {
76
- translateX = interpolate(
77
- value,
78
- inputRange,
79
- [-moveSize, 0, validLength * stackInterval],
80
- Extrapolate.CLAMP,
81
- );
82
- scale = interpolate(
83
- value,
84
- inputRange,
85
- [1, 1, 1 - validLength * scaleInterval],
86
- Extrapolate.CLAMP,
87
- );
88
- rotateZ = `${interpolate(
89
- value,
90
- inputRange,
91
- [-rotateZDeg, 0, 0],
92
- Extrapolate.CLAMP,
93
- )}deg`;
94
- }
95
- else if (snapDirection === "right") {
96
- translateX = interpolate(
97
- value,
98
- inputRange,
99
- [-validLength * stackInterval, 0, moveSize],
100
- Extrapolate.CLAMP,
101
- );
102
- scale = interpolate(
103
- value,
104
- inputRange,
105
- [1 - validLength * scaleInterval, 1, 1],
106
- Extrapolate.CLAMP,
107
- );
108
- rotateZ = `${interpolate(
109
- value,
110
- inputRange,
111
- [0, 0, rotateZDeg],
112
- Extrapolate.CLAMP,
113
- )}deg`;
114
- }
115
-
116
- transform.push(
117
- {
118
- translateX: translateX!,
119
- },
120
- {
121
- scale: scale!,
122
- },
123
- {
124
- rotateZ: rotateZ!,
125
- },
126
- );
127
-
128
- return styles;
129
- };
130
- }
131
-
132
- export function useHorizontalStackLayout(
133
- customAnimationConfig: ILayoutConfig = {},
134
- customConfig: CustomConfig = {},
135
- ) {
136
- const config = useMemo(
137
- () => ({
138
- type:
139
- customAnimationConfig.snapDirection === "right"
140
- ? "negative"
141
- : "positive",
142
- viewCount: customAnimationConfig.showLength,
143
- ...customConfig,
144
- }),
145
- [customAnimationConfig, customConfig],
146
- );
147
-
148
- return {
149
- layout: horizontalStackLayout(customAnimationConfig),
150
- config,
151
- };
152
- }
153
-
154
- export function verticalStackLayout(modeConfig: ILayoutConfig = {}) {
155
- return (_value: number) => {
156
- "worklet";
157
-
158
- const {
159
- showLength,
160
- snapDirection = "left",
161
- moveSize = screen.width,
162
- stackInterval = 18,
163
- scaleInterval = 0.04,
164
- opacityInterval = 0.1,
165
- rotateZDeg = 30,
166
- } = modeConfig;
167
- const transform: TransformsStyle["transform"] = [];
168
- const { validLength, value, inputRange } = getCommonVariables({
169
- showLength: showLength!,
170
- value: _value,
171
- snapDirection,
172
- });
173
- const { zIndex, opacity } = getCommonStyles({
174
- validLength,
175
- value,
176
- opacityInterval,
177
- snapDirection,
178
- });
179
-
180
- const styles: ViewStyle = {
181
- transform,
182
- zIndex,
183
- opacity,
184
- };
185
-
186
- let translateX: number;
187
- let scale: number;
188
- let rotateZ: string;
189
- let translateY: number;
190
-
191
- if (snapDirection === "left") {
192
- translateX = interpolate(
193
- value,
194
- inputRange,
195
- [-moveSize, 0, 0],
196
- Extrapolate.CLAMP,
197
- );
198
- scale = interpolate(
199
- value,
200
- inputRange,
201
- [1, 1, 1 - validLength * scaleInterval],
202
- Extrapolate.CLAMP,
203
- );
204
- rotateZ = `${interpolate(
205
- value,
206
- inputRange,
207
- [-rotateZDeg, 0, 0],
208
- Extrapolate.CLAMP,
209
- )}deg`;
210
- translateY = interpolate(
211
- value,
212
- inputRange,
213
- [0, 0, validLength * stackInterval],
214
- Extrapolate.CLAMP,
215
- );
216
- }
217
- else if (snapDirection === "right") {
218
- translateX = interpolate(
219
- value,
220
- inputRange,
221
- [0, 0, moveSize],
222
- Extrapolate.CLAMP,
223
- );
224
- scale = interpolate(
225
- value,
226
- inputRange,
227
- [1 - validLength * scaleInterval, 1, 1],
228
- Extrapolate.CLAMP,
229
- );
230
- rotateZ = `${interpolate(
231
- value,
232
- inputRange,
233
- [0, 0, rotateZDeg],
234
- Extrapolate.CLAMP,
235
- )}deg`;
236
- translateY = interpolate(
237
- value,
238
- inputRange,
239
- [validLength * stackInterval, 0, 0],
240
- Extrapolate.CLAMP,
241
- );
242
- }
243
-
244
- transform.push(
245
- {
246
- translateX: translateX!,
247
- },
248
- {
249
- scale: scale!,
250
- },
251
- {
252
- rotateZ: rotateZ!,
253
- },
254
- {
255
- translateY: translateY!,
256
- },
257
- );
258
-
259
- return styles;
260
- };
261
- }
262
-
263
- function getCommonVariables(opts: {
264
- value: number
265
- showLength: number
266
- snapDirection: "left" | "right"
267
- }) {
268
- "worklet";
269
-
270
- const { showLength, value: _value, snapDirection } = opts;
271
- function easeInOutCubic(v: number): number {
272
- return v < 0.5 ? 4 * v * v * v : 1 - (-2 * v + 2) ** 3 / 2;
273
- }
274
- const page = Math.floor(Math.abs(_value));
275
- const diff = Math.abs(_value) % 1;
276
- const value
277
- = _value < 0
278
- ? -(page + easeInOutCubic(diff))
279
- : page + easeInOutCubic(diff);
280
- const validLength = showLength! - 1;
281
-
282
- let inputRange: [number, number, number];
283
-
284
- if (snapDirection === "left")
285
- inputRange = [-1, 0, validLength];
286
- else if (snapDirection === "right")
287
- inputRange = [-validLength, 0, 1];
288
- else
289
- throw new Error("snapDirection must be set to either left or right");
290
-
291
- return {
292
- inputRange,
293
- validLength,
294
- value,
295
- };
296
- }
297
-
298
- function getCommonStyles(opts: {
299
- value: number
300
- validLength: number
301
- opacityInterval: number
302
- snapDirection: "left" | "right"
303
- }) {
304
- "worklet";
305
-
306
- const { snapDirection, validLength, value, opacityInterval } = opts;
307
-
308
- let zIndex: number;
309
- let opacity: number;
310
-
311
- if (snapDirection === "left") {
312
- zIndex
313
- = Math.floor(
314
- interpolate(
315
- value,
316
- [-1.5, -1, -1 + Number.MIN_VALUE, 0, validLength],
317
- [
318
- Number.MIN_VALUE,
319
- validLength,
320
- validLength,
321
- validLength - 1,
322
- -1,
323
- ],
324
- ) * 10000,
325
- ) / 100;
326
-
327
- opacity = interpolate(
328
- value,
329
- [-1, 0, validLength - 1, validLength],
330
- [0.25, 1, 1 - (validLength - 1) * opacityInterval, 0.25],
331
- );
332
- }
333
- else if (snapDirection === "right") {
334
- zIndex
335
- = Math.floor(
336
- interpolate(
337
- value,
338
- [-validLength, 0, 1 - Number.MIN_VALUE, 1, 1.5],
339
- [
340
- 1,
341
- validLength - 1,
342
- validLength,
343
- validLength,
344
- Number.MIN_VALUE,
345
- ],
346
- ) * 10000,
347
- ) / 100;
348
- opacity = interpolate(
349
- value,
350
- [-validLength, 1 - validLength, 0, 1],
351
- [0.25, 1 - (validLength - 1) * opacityInterval, 1, 0.25],
352
- );
353
- }
354
- else {
355
- throw new Error("snapDirection must be set to either left or right");
356
- }
357
-
358
- return {
359
- zIndex,
360
- opacity,
361
- };
362
- }
@@ -1,13 +0,0 @@
1
- import React from "react";
2
-
3
- import type { TInitializeCarouselProps } from "../hooks/useInitProps";
4
-
5
- export interface IContext {
6
- props: TInitializeCarouselProps<any>
7
- common: {
8
- size: number
9
- validLength: number
10
- }
11
- }
12
-
13
- export const CTX = React.createContext<IContext>({} as IContext);
package/src/types.ts DELETED
@@ -1,237 +0,0 @@
1
- import type { StyleProp, ViewStyle } from "react-native";
2
- import type { PanGestureHandlerProps } from "react-native-gesture-handler";
3
- import type {
4
- AnimatedStyleProp,
5
- SharedValue,
6
- WithSpringConfig,
7
- WithTimingConfig,
8
- } from "react-native-reanimated";
9
- import type Animated from "react-native-reanimated";
10
-
11
- import type { TParallaxModeProps } from "./layouts/parallax";
12
- import type { TStackModeProps } from "./layouts/stack";
13
-
14
- export type IComputedDirectionTypes<T, VP = {}, HP = {}> =
15
- | (T &
16
- VP & {
17
- /**
18
- * Layout items vertically instead of horizontally
19
- */
20
- vertical: true
21
- /**
22
- * Layout items vertically instead of horizontally
23
- */
24
- /**
25
- * Specified carousel container width.
26
- */
27
- width?: number
28
- height: number
29
- })
30
- | (T &
31
- HP & {
32
- /**
33
- * Layout items vertically instead of horizontally
34
- */
35
- vertical?: false
36
- /**
37
- * Layout items vertically instead of horizontally
38
- */
39
- /**
40
- * Specified carousel container width.
41
- */
42
- width: number
43
- height?: number
44
- });
45
-
46
- export interface CustomConfig {
47
- type?: "negative" | "positive"
48
- viewCount?: number
49
- }
50
-
51
- export interface WithSpringAnimation {
52
- type: "spring"
53
- config: WithSpringConfig
54
- }
55
-
56
- export interface WithTimingAnimation {
57
- type: "timing"
58
- config: WithTimingConfig
59
- }
60
-
61
- export type WithAnimation = WithSpringAnimation | WithTimingAnimation;
62
-
63
- export type TCarouselProps<T = any> = {
64
- ref?: React.Ref<ICarouselInstance>
65
- /**
66
- * The default animated value of the carousel.
67
- */
68
- defaultScrollOffsetValue?: SharedValue<number>
69
- /**
70
- * Carousel loop playback.
71
- * @default true
72
- */
73
- loop?: boolean
74
- /**
75
- * Carousel items data set.
76
- */
77
- data: T[]
78
- /**
79
- * Auto fill data array to allow loop playback when the loop props is true.
80
- * @default true
81
- * @example
82
- * [1] => [1, 1, 1]
83
- * [1, 2] => [1, 2, 1, 2]
84
- */
85
- autoFillData?: boolean
86
- /**
87
- * Default index
88
- * @default 0
89
- */
90
- defaultIndex?: number
91
- /**
92
- * Auto play
93
- */
94
- autoPlay?: boolean
95
- /**
96
- * Auto play
97
- * @description reverse playback
98
- */
99
- autoPlayReverse?: boolean
100
- /**
101
- * Auto play
102
- * @description playback interval
103
- */
104
- autoPlayInterval?: number
105
- /**
106
- * Time a scroll animation takes to finish
107
- * @default 500 (ms)
108
- */
109
- scrollAnimationDuration?: number
110
- /**
111
- * Carousel container style
112
- */
113
- style?: StyleProp<ViewStyle>
114
- /**
115
- * PanGestureHandler props
116
- */
117
- panGestureHandlerProps?: Partial<
118
- Omit<PanGestureHandlerProps, "onHandlerStateChange" | "enabled">
119
- >
120
- /**
121
- * Determines the maximum number of items will respond to pan gesture events,
122
- * windowSize={11} will active visible item plus up to 5 items above and 5 below the viewpor,
123
- * Reducing this number will reduce the calculation of the animation value and may improve performance.
124
- * @default 0 all items will respond to pan gesture events.
125
- */
126
- windowSize?: number
127
- /**
128
- * When true, the scroll view stops on multiples of the scroll view's size when scrolling.
129
- * @default true
130
- */
131
- pagingEnabled?: boolean
132
- /**
133
- * If enabled, releasing the touch will scroll to the nearest item.
134
- * valid when pagingEnabled=false
135
- * @default true
136
- */
137
- snapEnabled?: boolean
138
- /**
139
- * If enabled, items will scroll to the first placement when scrolling past the edge rather than closing to the last. (previous conditions: loop=false)
140
- * @default true
141
- */
142
- overscrollEnabled?: boolean
143
- /**
144
- * If false, Carousel will not respond to any gestures.
145
- * @default true
146
- */
147
- enabled?: boolean
148
- /**
149
- * Specifies the scrolling animation effect.
150
- */
151
- withAnimation?: WithAnimation
152
- /**
153
- * Used to locate this view in end-to-end tests.
154
- */
155
- testID?: string
156
- /**
157
- * Custom carousel config.
158
- */
159
- customConfig?: () => CustomConfig
160
- /**
161
- * Custom animations.
162
- * Must use `worklet`, Details: https://docs.swmansion.com/react-native-reanimated/docs/2.2.0/worklets/
163
- */
164
- customAnimation?: (value: number) => AnimatedStyleProp<ViewStyle>
165
- /**
166
- * Render carousel item.
167
- */
168
- renderItem: CarouselRenderItem<T>
169
- /**
170
- * Callback fired when navigating to an item.
171
- */
172
- onSnapToItem?: (index: number) => void
173
- /**
174
- * On scroll begin
175
- */
176
- onScrollBegin?: () => void
177
- /**
178
- * On scroll end
179
- */
180
- onScrollEnd?: (index: number) => void
181
- /**
182
- * On progress change
183
- * @param offsetProgress Total of offset distance (0 390 780 ...)
184
- * @param absoluteProgress Convert to index (0 1 2 ...)
185
- */
186
- onProgressChange?: (
187
- offsetProgress: number,
188
- absoluteProgress: number
189
- ) => void
190
-
191
- // ============================== deprecated props ==============================
192
- /**
193
- * If enabled, releasing the touch will scroll to the nearest item.
194
- * valid when pagingEnabled=false
195
- * @deprecated please use snapEnabled instead
196
- */
197
- enableSnap?: boolean
198
- } & (TParallaxModeProps | TStackModeProps);
199
-
200
- export interface ICarouselInstance {
201
- /**
202
- * Scroll to previous item, it takes one optional argument (count),
203
- * which allows you to specify how many items to cross
204
- */
205
- prev: (opts?: Omit<TCarouselActionOptions, "index">) => void
206
- /**
207
- * Scroll to next item, it takes one optional argument (count),
208
- * which allows you to specify how many items to cross
209
- */
210
- next: (opts?: Omit<TCarouselActionOptions, "index">) => void
211
- /**
212
- * Get current item index
213
- */
214
- getCurrentIndex: () => number
215
- /**
216
- * Use value to scroll to a position where relative to the current position,
217
- * scrollTo(-2) is equivalent to prev(2), scrollTo(2) is equivalent to next(2)
218
- */
219
- scrollTo: (opts?: TCarouselActionOptions) => void
220
- }
221
-
222
- export interface CarouselRenderItemInfo<ItemT> {
223
- item: ItemT
224
- index: number
225
- animationValue: Animated.SharedValue<number>
226
- }
227
-
228
- export type CarouselRenderItem<ItemT> = (
229
- info: CarouselRenderItemInfo<ItemT>
230
- ) => React.ReactElement;
231
-
232
- export interface TCarouselActionOptions {
233
- index?: number
234
- count?: number
235
- animated?: boolean
236
- onFinished?: () => void
237
- }
@@ -1,94 +0,0 @@
1
- import { DATA_LENGTH } from "../constants";
2
-
3
- const { SINGLE_ITEM, DOUBLE_ITEM } = DATA_LENGTH;
4
-
5
- function isAutoFillData(params: { autoFillData: boolean; loop: boolean }) {
6
- "worklet";
7
- return !!params.loop && !!params.autoFillData;
8
- }
9
-
10
- type BaseParams<T extends object = {}> = {
11
- autoFillData: boolean
12
- loop: boolean
13
- } & T;
14
-
15
- export function convertToSharedIndex(
16
- params: BaseParams<{ index: number; rawDataLength: number }>,
17
- ) {
18
- "worklet";
19
- const { loop, rawDataLength, index, autoFillData } = params;
20
-
21
- if (isAutoFillData({ loop, autoFillData })) {
22
- switch (rawDataLength) {
23
- case SINGLE_ITEM:
24
- return 0;
25
- case DOUBLE_ITEM:
26
- return index % 2;
27
- }
28
- }
29
-
30
- return index;
31
- }
32
-
33
- export function computedOffsetXValueWithAutoFillData(
34
- params: BaseParams<{
35
- rawDataLength: number
36
- value: number
37
- size: number
38
- }>,
39
- ) {
40
- "worklet";
41
-
42
- const { rawDataLength, value, size, loop, autoFillData } = params;
43
-
44
- if (isAutoFillData({ loop, autoFillData })) {
45
- switch (rawDataLength) {
46
- case SINGLE_ITEM:
47
- return value % size;
48
- case DOUBLE_ITEM:
49
- return value % (size * 2);
50
- }
51
- }
52
-
53
- return value;
54
- }
55
-
56
- export function computedRealIndexWithAutoFillData(
57
- params: BaseParams<{
58
- index: number
59
- dataLength: number
60
- }>,
61
- ) {
62
- const { index, dataLength, loop, autoFillData } = params;
63
-
64
- if (isAutoFillData({ loop, autoFillData })) {
65
- switch (dataLength) {
66
- case SINGLE_ITEM:
67
- return index % 1;
68
- case DOUBLE_ITEM:
69
- return index % 2;
70
- }
71
- }
72
-
73
- return index;
74
- }
75
-
76
- export function computedFillDataWithAutoFillData<T>(
77
- params: BaseParams<{
78
- data: T[]
79
- dataLength: number
80
- }>,
81
- ): T[] {
82
- const { data, loop, autoFillData, dataLength } = params;
83
-
84
- if (isAutoFillData({ loop, autoFillData })) {
85
- switch (dataLength) {
86
- case SINGLE_ITEM:
87
- return [data[0], data[0], data[0]];
88
- case DOUBLE_ITEM:
89
- return [data[0], data[1], data[0], data[1]];
90
- }
91
- }
92
-
93
- return data;
94
- }
@@ -1,19 +0,0 @@
1
- import { withSpring, withTiming } from "react-native-reanimated";
2
-
3
- import type { WithAnimation } from "../types";
4
-
5
- export function dealWithAnimation(
6
- withAnimation: WithAnimation,
7
- ): (value: number, cb: (isFinished: boolean) => void) => number {
8
- "worklet";
9
- switch (withAnimation.type) {
10
- case "spring":
11
- return (value, cb) => withSpring(value, withAnimation.config, isFinished =>
12
- cb(isFinished as boolean),
13
- );
14
- case "timing":
15
- return (value, cb) => withTiming(value, withAnimation.config, isFinished =>
16
- cb(isFinished as boolean),
17
- );
18
- }
19
- }