react-native-reanimated-carousel 2.0.0 → 2.2.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.
Files changed (68) hide show
  1. package/README.md +40 -10
  2. package/README.zh-CN.md +42 -9
  3. package/lib/commonjs/Carousel.js +20 -10
  4. package/lib/commonjs/Carousel.js.map +1 -1
  5. package/lib/commonjs/ScrollViewGesture.js +13 -5
  6. package/lib/commonjs/ScrollViewGesture.js.map +1 -1
  7. package/lib/commonjs/constants/index.js +9 -1
  8. package/lib/commonjs/constants/index.js.map +1 -1
  9. package/lib/commonjs/hooks/useAutoPlay.js +22 -16
  10. package/lib/commonjs/hooks/useAutoPlay.js.map +1 -1
  11. package/lib/commonjs/hooks/useCarouselController.js +94 -30
  12. package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
  13. package/lib/commonjs/hooks/useInitProps.js +4 -1
  14. package/lib/commonjs/hooks/useInitProps.js.map +1 -1
  15. package/lib/commonjs/layouts/BaseLayout.js +14 -8
  16. package/lib/commonjs/layouts/BaseLayout.js.map +1 -1
  17. package/lib/commonjs/layouts/normal.js +1 -1
  18. package/lib/commonjs/layouts/normal.js.map +1 -1
  19. package/lib/commonjs/layouts/parallax.js.map +1 -1
  20. package/lib/commonjs/layouts/stack.js +15 -0
  21. package/lib/commonjs/layouts/stack.js.map +1 -1
  22. package/lib/module/Carousel.js +20 -10
  23. package/lib/module/Carousel.js.map +1 -1
  24. package/lib/module/ScrollViewGesture.js +13 -6
  25. package/lib/module/ScrollViewGesture.js.map +1 -1
  26. package/lib/module/constants/index.js +5 -0
  27. package/lib/module/constants/index.js.map +1 -1
  28. package/lib/module/hooks/useAutoPlay.js +22 -16
  29. package/lib/module/hooks/useAutoPlay.js.map +1 -1
  30. package/lib/module/hooks/useCarouselController.js +91 -30
  31. package/lib/module/hooks/useCarouselController.js.map +1 -1
  32. package/lib/module/hooks/useInitProps.js +4 -1
  33. package/lib/module/hooks/useInitProps.js.map +1 -1
  34. package/lib/module/layouts/BaseLayout.js +14 -10
  35. package/lib/module/layouts/BaseLayout.js.map +1 -1
  36. package/lib/module/layouts/normal.js +2 -2
  37. package/lib/module/layouts/normal.js.map +1 -1
  38. package/lib/module/layouts/parallax.js.map +1 -1
  39. package/lib/module/layouts/stack.js +12 -0
  40. package/lib/module/layouts/stack.js.map +1 -1
  41. package/lib/typescript/constants/index.d.ts +3 -0
  42. package/lib/typescript/hooks/useAutoPlay.d.ts +1 -1
  43. package/lib/typescript/hooks/useCarouselController.d.ts +8 -5
  44. package/lib/typescript/hooks/useInitProps.d.ts +3 -6
  45. package/lib/typescript/layouts/BaseLayout.d.ts +3 -0
  46. package/lib/typescript/layouts/parallax.d.ts +9 -1
  47. package/lib/typescript/layouts/stack.d.ts +25 -0
  48. package/lib/typescript/types.d.ts +45 -32
  49. package/package.json +11 -4
  50. package/src/Carousel.tsx +27 -8
  51. package/src/ScrollViewGesture.tsx +12 -5
  52. package/src/constants/index.ts +6 -0
  53. package/src/hooks/useAutoPlay.ts +20 -23
  54. package/src/hooks/useCarouselController.tsx +112 -50
  55. package/src/hooks/useInitProps.ts +18 -8
  56. package/src/layouts/BaseLayout.tsx +26 -12
  57. package/src/layouts/normal.ts +2 -7
  58. package/src/layouts/parallax.ts +10 -1
  59. package/src/layouts/stack.ts +42 -0
  60. package/src/types.ts +50 -32
  61. package/CHANGELOG.md +0 -324
  62. package/lib/commonjs/hooks/useIndexController.js +0 -65
  63. package/lib/commonjs/hooks/useIndexController.js.map +0 -1
  64. package/lib/module/hooks/useIndexController.js +0 -52
  65. package/lib/module/hooks/useIndexController.js.map +0 -1
  66. package/lib/typescript/hooks/useIndexController.d.ts +0 -18
  67. package/src/.DS_Store +0 -0
  68. package/src/hooks/useIndexController.ts +0 -78
@@ -12,8 +12,9 @@ import Animated, {
12
12
  useDerivedValue,
13
13
  useSharedValue,
14
14
  withDecay,
15
- withSpring,
15
+ withTiming,
16
16
  } from 'react-native-reanimated';
17
+ import { Easing } from './constants';
17
18
  import { CTX } from './store';
18
19
 
19
20
  type GestureContext = {
@@ -40,6 +41,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
40
41
  enableSnap,
41
42
  panGestureHandlerProps,
42
43
  loop: infinite,
44
+ scrollAnimationDuration,
43
45
  },
44
46
  } = React.useContext(CTX);
45
47
 
@@ -54,10 +56,11 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
54
56
  const _withSpring = React.useCallback(
55
57
  (toValue: number, onFinished?: () => void) => {
56
58
  'worklet';
57
- return withSpring(
59
+ return withTiming(
58
60
  toValue,
59
61
  {
60
- damping: 100,
62
+ duration: scrollAnimationDuration,
63
+ easing: Easing.easeOutQuart,
61
64
  },
62
65
  (isFinished) => {
63
66
  if (isFinished) {
@@ -66,7 +69,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
66
69
  }
67
70
  );
68
71
  },
69
- []
72
+ [scrollAnimationDuration]
70
73
  );
71
74
 
72
75
  const endWithSpring = React.useCallback(
@@ -199,7 +202,11 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
199
202
  !infinite &&
200
203
  (translation.value > 0 || translation.value < -ctx.max)
201
204
  ) {
202
- panTranslation = panTranslation * 0.5;
205
+ const boundary = translation.value > 0 ? 0 : -ctx.max;
206
+ const fixed = boundary - ctx.panOffset;
207
+ const dynamic = panTranslation - fixed;
208
+ translation.value = boundary + dynamic * 0.5;
209
+ return;
203
210
  }
204
211
 
205
212
  translation.value = ctx.panOffset + panTranslation;
@@ -1,4 +1,10 @@
1
+ import { Easing as _Easing } from 'react-native-reanimated';
2
+
1
3
  export enum DATA_LENGTH {
2
4
  SINGLE_ITEM = 1,
3
5
  DOUBLE_ITEM = 2,
4
6
  }
7
+
8
+ export const Easing = {
9
+ easeOutQuart: _Easing.bezier(0.25, 1, 0.5, 1),
10
+ };
@@ -15,44 +15,41 @@ export function useAutoPlay(opts: {
15
15
  } = opts;
16
16
 
17
17
  const timer = React.useRef<NodeJS.Timer>();
18
+ const stopped = React.useRef<boolean>(!autoPlay);
18
19
 
19
- const pause = React.useCallback(() => {
20
- timer.current && clearInterval(timer.current);
21
- }, []);
22
-
23
- const run = React.useCallback(() => {
24
- if (timer.current) {
25
- pause();
26
- }
27
-
28
- if (!autoPlay) {
20
+ const play = React.useCallback(() => {
21
+ if (stopped.current) {
29
22
  return;
30
23
  }
31
24
 
32
- timer.current = setInterval(() => {
25
+ timer.current = setTimeout(() => {
33
26
  autoPlayReverse
34
- ? carouselController.prev()
35
- : carouselController.next();
27
+ ? carouselController.prev({ onFinished: play })
28
+ : carouselController.next({ onFinished: play });
36
29
  }, autoPlayInterval);
37
- }, [
38
- pause,
39
- autoPlay,
40
- autoPlayReverse,
41
- autoPlayInterval,
42
- carouselController,
43
- ]);
30
+ }, [autoPlayReverse, autoPlayInterval, carouselController]);
31
+
32
+ const pause = React.useCallback(() => {
33
+ timer.current && clearInterval(timer.current);
34
+ stopped.current = true;
35
+ }, []);
36
+
37
+ const start = React.useCallback(() => {
38
+ stopped.current = false;
39
+ play();
40
+ }, [play]);
44
41
 
45
42
  React.useEffect(() => {
46
43
  if (autoPlay) {
47
- run();
44
+ start();
48
45
  } else {
49
46
  pause();
50
47
  }
51
48
  return pause;
52
- }, [run, pause, autoPlay]);
49
+ }, [pause, start, autoPlay]);
53
50
 
54
51
  return {
55
- run,
56
52
  pause,
53
+ start,
57
54
  };
58
55
  }
@@ -1,17 +1,20 @@
1
1
  import React from 'react';
2
2
  import type Animated from 'react-native-reanimated';
3
- import { runOnJS, useSharedValue, withSpring } from 'react-native-reanimated';
3
+ import { Easing } from '../constants';
4
+ import { runOnJS, useSharedValue, withTiming } from 'react-native-reanimated';
5
+ import type { TCarouselActionOptions } from '../types';
4
6
 
5
7
  interface IOpts {
6
8
  loop: boolean;
7
9
  size: number;
8
10
  handlerOffsetX: Animated.SharedValue<number>;
9
11
  disable?: boolean;
12
+ duration?: number;
13
+ originalLength: number;
14
+ length: number;
10
15
  onScrollBegin?: () => void;
11
16
  onScrollEnd?: () => void;
12
17
  // the length before fill data
13
- originalLength: number;
14
- length: number;
15
18
  onChange: (index: number) => void;
16
19
  }
17
20
 
@@ -20,14 +23,15 @@ export interface ICarouselController {
20
23
  index: Animated.SharedValue<number>;
21
24
  sharedIndex: React.MutableRefObject<number>;
22
25
  sharedPreIndex: React.MutableRefObject<number>;
23
- prev: () => void;
24
- next: () => void;
26
+ prev: (opts?: TCarouselActionOptions) => void;
27
+ next: (opts?: TCarouselActionOptions) => void;
25
28
  computedIndex: () => void;
26
29
  getCurrentIndex: () => number;
27
30
  to: (index: number, animated?: boolean) => void;
31
+ scrollTo: (opts?: TCarouselActionOptions) => void;
28
32
  }
29
33
 
30
- export function useCarouselController(opts: IOpts): ICarouselController {
34
+ export function useCarouselController(options: IOpts): ICarouselController {
31
35
  const {
32
36
  size,
33
37
  loop,
@@ -36,13 +40,27 @@ export function useCarouselController(opts: IOpts): ICarouselController {
36
40
  originalLength,
37
41
  length,
38
42
  onChange,
39
- } = opts;
43
+ duration,
44
+ } = options;
40
45
 
41
46
  const index = useSharedValue<number>(0);
42
47
  // The Index displayed to the user
43
48
  const sharedIndex = React.useRef<number>(0);
44
49
  const sharedPreIndex = React.useRef<number>(0);
45
50
 
51
+ const currentFixedPage = React.useCallback(() => {
52
+ if (loop) {
53
+ return -Math.round(handlerOffsetX.value / size);
54
+ }
55
+
56
+ const fixed = (handlerOffsetX.value / size) % length;
57
+ return Math.round(
58
+ handlerOffsetX.value <= 0
59
+ ? Math.abs(fixed)
60
+ : Math.abs(fixed > 0 ? length - fixed : 0)
61
+ );
62
+ }, [handlerOffsetX, length, size, loop]);
63
+
46
64
  const convertToSharedIndex = React.useCallback(
47
65
  (i: number) => {
48
66
  if (loop) {
@@ -89,65 +107,93 @@ export function useCarouselController(opts: IOpts): ICarouselController {
89
107
  }, [disable]);
90
108
 
91
109
  const onScrollEnd = React.useCallback(() => {
92
- opts.onScrollEnd?.();
93
- }, [opts]);
110
+ options.onScrollEnd?.();
111
+ }, [options]);
94
112
 
95
113
  const onScrollBegin = React.useCallback(() => {
96
- opts.onScrollBegin?.();
97
- }, [opts]);
114
+ options.onScrollBegin?.();
115
+ }, [options]);
98
116
 
99
- const scrollWithSpring = React.useCallback(
100
- (toValue: number, callback?: () => void) => {
101
- return withSpring(
117
+ const scrollWithTiming = React.useCallback(
118
+ (toValue: number, onFinished?: () => void) => {
119
+ return withTiming(
102
120
  toValue,
103
- { damping: 100 },
121
+ { duration, easing: Easing.easeOutQuart },
104
122
  (isFinished: boolean) => {
105
- callback?.();
106
123
  if (isFinished) {
107
124
  runOnJS(onScrollEnd)();
125
+ onFinished && runOnJS(onFinished)();
108
126
  }
109
127
  }
110
128
  );
111
129
  },
112
- [onScrollEnd]
130
+ [onScrollEnd, duration]
113
131
  );
114
132
 
115
- const next = React.useCallback(() => {
116
- if (!canSliding() || (!loop && index.value === length - 1)) return;
133
+ const next = React.useCallback(
134
+ (opts: TCarouselActionOptions = {}) => {
135
+ const { count = 1, animated = true, onFinished } = opts;
136
+ if (!canSliding() || (!loop && index.value >= length - 1)) return;
117
137
 
118
- onScrollBegin?.();
138
+ onScrollBegin?.();
119
139
 
120
- const currentPage = Math.round(handlerOffsetX.value / size);
140
+ const nextPage = currentFixedPage() + count;
141
+ index.value = nextPage;
121
142
 
122
- handlerOffsetX.value = scrollWithSpring((currentPage - 1) * size);
123
- }, [
124
- canSliding,
125
- loop,
126
- index.value,
127
- length,
128
- onScrollBegin,
129
- handlerOffsetX,
130
- size,
131
- scrollWithSpring,
132
- ]);
143
+ if (animated) {
144
+ handlerOffsetX.value = scrollWithTiming(
145
+ -nextPage * size,
146
+ onFinished
147
+ );
148
+ } else {
149
+ handlerOffsetX.value = -nextPage * size;
150
+ onFinished?.();
151
+ }
152
+ },
153
+ [
154
+ canSliding,
155
+ loop,
156
+ index,
157
+ length,
158
+ onScrollBegin,
159
+ handlerOffsetX,
160
+ size,
161
+ scrollWithTiming,
162
+ currentFixedPage,
163
+ ]
164
+ );
133
165
 
134
- const prev = React.useCallback(() => {
135
- if (!canSliding() || (!loop && index.value === 0)) return;
166
+ const prev = React.useCallback(
167
+ (opts: TCarouselActionOptions = {}) => {
168
+ const { count = 1, animated = true, onFinished } = opts;
169
+ if (!canSliding() || (!loop && index.value <= 0)) return;
136
170
 
137
- onScrollBegin?.();
171
+ onScrollBegin?.();
138
172
 
139
- const currentPage = Math.round(handlerOffsetX.value / size);
173
+ const prevPage = currentFixedPage() - count;
174
+ index.value = prevPage;
140
175
 
141
- handlerOffsetX.value = scrollWithSpring((currentPage + 1) * size);
142
- }, [
143
- canSliding,
144
- loop,
145
- index.value,
146
- onScrollBegin,
147
- handlerOffsetX,
148
- size,
149
- scrollWithSpring,
150
- ]);
176
+ if (animated) {
177
+ handlerOffsetX.value = scrollWithTiming(
178
+ -prevPage * size,
179
+ onFinished
180
+ );
181
+ } else {
182
+ handlerOffsetX.value = -prevPage * size;
183
+ onFinished?.();
184
+ }
185
+ },
186
+ [
187
+ canSliding,
188
+ loop,
189
+ index,
190
+ onScrollBegin,
191
+ handlerOffsetX,
192
+ size,
193
+ scrollWithTiming,
194
+ currentFixedPage,
195
+ ]
196
+ );
151
197
 
152
198
  const to = React.useCallback(
153
199
  (idx: number, animated: boolean = false) => {
@@ -159,9 +205,8 @@ export function useCarouselController(opts: IOpts): ICarouselController {
159
205
  const offset = handlerOffsetX.value + (index.value - idx) * size;
160
206
 
161
207
  if (animated) {
162
- handlerOffsetX.value = scrollWithSpring(offset, () => {
163
- index.value = idx;
164
- });
208
+ index.value = idx;
209
+ handlerOffsetX.value = scrollWithTiming(offset);
165
210
  } else {
166
211
  handlerOffsetX.value = offset;
167
212
  index.value = idx;
@@ -174,15 +219,32 @@ export function useCarouselController(opts: IOpts): ICarouselController {
174
219
  onScrollBegin,
175
220
  handlerOffsetX,
176
221
  size,
177
- scrollWithSpring,
222
+ scrollWithTiming,
178
223
  onScrollEnd,
179
224
  ]
180
225
  );
181
226
 
227
+ const scrollTo = React.useCallback(
228
+ (opts: TCarouselActionOptions = {}) => {
229
+ const { count, animated = false, onFinished } = opts;
230
+ if (!count) {
231
+ return;
232
+ }
233
+ const n = Math.round(count);
234
+ if (n < 0) {
235
+ prev({ count: Math.abs(n), animated, onFinished });
236
+ } else {
237
+ next({ count: n, animated, onFinished });
238
+ }
239
+ },
240
+ [prev, next]
241
+ );
242
+
182
243
  return {
183
244
  next,
184
245
  prev,
185
246
  to,
247
+ scrollTo,
186
248
  index,
187
249
  length,
188
250
  sharedIndex,
@@ -2,12 +2,20 @@ import React from 'react';
2
2
  import { DATA_LENGTH } from '../constants';
3
3
  import type { TCarouselProps } from '../types';
4
4
 
5
- export type TInitializeCarouselProps<T> = TCarouselProps<T> & {
6
- defaultIndex: Required<TCarouselProps>['defaultIndex'];
7
- loop: Required<TCarouselProps>['loop'];
8
- width: Required<TCarouselProps>['width'];
9
- height: Required<TCarouselProps>['height'];
10
- };
5
+ type TGetRequiredProps<P extends keyof TCarouselProps> = Record<
6
+ P,
7
+ Required<TCarouselProps>[P]
8
+ >;
9
+
10
+ export type TInitializeCarouselProps<T> = TCarouselProps<T> &
11
+ TGetRequiredProps<
12
+ | 'defaultIndex'
13
+ | 'loop'
14
+ | 'width'
15
+ | 'height'
16
+ | 'scrollAnimationDuration'
17
+ | 'autoPlayInterval'
18
+ >;
11
19
 
12
20
  export function useInitProps<T>(
13
21
  props: TCarouselProps<T>
@@ -16,7 +24,8 @@ export function useInitProps<T>(
16
24
  defaultIndex = 0,
17
25
  data: _data = [],
18
26
  loop = true,
19
- autoPlayInterval = 1000,
27
+ autoPlayInterval: _autoPlayInterval = 1000,
28
+ scrollAnimationDuration = 500,
20
29
  style = {},
21
30
  panGestureHandlerProps = {},
22
31
  pagingEnabled = true,
@@ -27,6 +36,7 @@ export function useInitProps<T>(
27
36
 
28
37
  const width = Math.round(_width || 0);
29
38
  const height = Math.round(_height || 0);
39
+ const autoPlayInterval = Math.max(_autoPlayInterval, 0);
30
40
 
31
41
  const data = React.useMemo<T[]>(() => {
32
42
  if (!loop) return _data;
@@ -49,13 +59,13 @@ export function useInitProps<T>(
49
59
  props.modeConfig.showLength =
50
60
  props.modeConfig?.showLength ?? data.length - 1;
51
61
  }
52
-
53
62
  return {
54
63
  ...props,
55
64
  defaultIndex,
56
65
  data,
57
66
  loop,
58
67
  autoPlayInterval,
68
+ scrollAnimationDuration,
59
69
  style,
60
70
  panGestureHandlerProps,
61
71
  pagingEnabled,
@@ -4,12 +4,13 @@ import Animated, {
4
4
  runOnJS,
5
5
  useAnimatedReaction,
6
6
  useAnimatedStyle,
7
+ useDerivedValue,
7
8
  } from 'react-native-reanimated';
8
9
  import { IOpts, useOffsetX } from '../hooks/useOffsetX';
9
10
  import type { IVisibleRanges } from '../hooks/useVisibleRanges';
10
11
  import { LazyView } from '../LazyView';
11
- import type { ILayoutConfig as IStackLayoutConfig } from './stack';
12
12
  import { CTX } from '../store';
13
+ import type { ILayoutConfig } from './stack';
13
14
 
14
15
  export type TAnimationStyle = (
15
16
  value: number
@@ -20,28 +21,39 @@ export const BaseLayout: React.FC<{
20
21
  handlerOffsetX: Animated.SharedValue<number>;
21
22
  visibleRanges: IVisibleRanges;
22
23
  animationStyle: TAnimationStyle;
24
+ children: (ctx: {
25
+ animationValue: Animated.SharedValue<number>;
26
+ }) => React.ReactElement;
23
27
  }> = (props) => {
24
28
  const { handlerOffsetX, index, children, visibleRanges, animationStyle } =
25
29
  props;
26
30
 
31
+ const context = React.useContext(CTX);
27
32
  const {
28
- props: { mode, loop, data, width, height, vertical, modeConfig },
29
- } = React.useContext(CTX);
30
-
31
- const [shouldUpdate, setShouldUpdate] = React.useState(false);
32
-
33
+ props: {
34
+ loop,
35
+ data,
36
+ width,
37
+ height,
38
+ vertical,
39
+ customConfig,
40
+ mode,
41
+ modeConfig,
42
+ },
43
+ } = context;
33
44
  const size = vertical ? height : width;
34
-
45
+ const [shouldUpdate, setShouldUpdate] = React.useState(false);
35
46
  let offsetXConfig: IOpts = {
36
47
  handlerOffsetX,
37
48
  index,
38
49
  size,
39
50
  data,
40
51
  loop,
52
+ ...(typeof customConfig === 'function' ? customConfig() : {}),
41
53
  };
42
54
 
43
55
  if (mode === 'horizontal-stack') {
44
- const { snapDirection, showLength } = modeConfig as IStackLayoutConfig;
56
+ const { snapDirection, showLength } = modeConfig as ILayoutConfig;
45
57
 
46
58
  offsetXConfig = {
47
59
  handlerOffsetX,
@@ -55,8 +67,8 @@ export const BaseLayout: React.FC<{
55
67
  }
56
68
 
57
69
  const x = useOffsetX(offsetXConfig, visibleRanges);
58
-
59
- const _animatedStyle = useAnimatedStyle(
70
+ const animationValue = useDerivedValue(() => x.value / size, [x, size]);
71
+ const animatedStyle = useAnimatedStyle(
60
72
  () => animationStyle(x.value / size),
61
73
  [animationStyle]
62
74
  );
@@ -90,10 +102,12 @@ export const BaseLayout: React.FC<{
90
102
  height: height || '100%',
91
103
  position: 'absolute',
92
104
  },
93
- _animatedStyle,
105
+ animatedStyle,
94
106
  ]}
95
107
  >
96
- <LazyView shouldUpdate={shouldUpdate}>{children}</LazyView>
108
+ <LazyView shouldUpdate={shouldUpdate}>
109
+ {children({ animationValue })}
110
+ </LazyView>
97
111
  </Animated.View>
98
112
  );
99
113
  };
@@ -1,16 +1,11 @@
1
- import { Extrapolate, interpolate } from 'react-native-reanimated';
1
+ import { interpolate } from 'react-native-reanimated';
2
2
 
3
3
  export function normalLayout(opts: { size: number; vertical: boolean }) {
4
4
  const { size, vertical } = opts;
5
5
 
6
6
  return (value: number) => {
7
7
  'worklet';
8
- const translate = interpolate(
9
- value,
10
- [-1, 0, 1],
11
- [-size, 0, size],
12
- Extrapolate.CLAMP
13
- );
8
+ const translate = interpolate(value, [-1, 0, 1], [-size, 0, size]);
14
9
 
15
10
  return {
16
11
  transform: [
@@ -1,11 +1,12 @@
1
1
  import { Extrapolate, interpolate } from 'react-native-reanimated';
2
+ import type { ComputedDirectionTypes } from '../types';
2
3
 
3
4
  type TBaseConfig = {
4
5
  size: number;
5
6
  vertical: boolean;
6
7
  };
7
8
 
8
- export interface ILayoutConfig {
9
+ interface ILayoutConfig {
9
10
  /**
10
11
  * When use default Layout props,this prop can be control prev/next item offset.
11
12
  * @default 100
@@ -18,6 +19,14 @@ export interface ILayoutConfig {
18
19
  parallaxScrollingScale?: number;
19
20
  }
20
21
 
22
+ export type TParallaxModeProps = ComputedDirectionTypes<{
23
+ /**
24
+ * Carousel Animated transitions.
25
+ */
26
+ mode?: 'parallax';
27
+ modeConfig?: ILayoutConfig;
28
+ }>;
29
+
21
30
  export function parallaxLayout(
22
31
  baseConfig: TBaseConfig,
23
32
  modeConfig: ILayoutConfig = {}
@@ -1,5 +1,7 @@
1
+ import { useMemo } from 'react';
1
2
  import { Dimensions, TransformsStyle, ViewStyle } from 'react-native';
2
3
  import { Extrapolate, interpolate } from 'react-native-reanimated';
4
+ import type { ComputedDirectionTypes, CustomConfig } from 'src/types';
3
5
 
4
6
  const screen = Dimensions.get('window');
5
7
 
@@ -13,6 +15,24 @@ export interface ILayoutConfig {
13
15
  snapDirection?: 'left' | 'right';
14
16
  }
15
17
 
18
+ export type TStackModeProps = ComputedDirectionTypes<{
19
+ /**
20
+ * Carousel Animated transitions.
21
+ */
22
+ mode?: 'horizontal-stack' | 'vertical-stack';
23
+ /**
24
+ * Stack animation style.
25
+ * @default
26
+ * mode: 'vertical',
27
+ * snapDirection: 'right',
28
+ * moveSize: window.width,
29
+ * stackInterval: 30,
30
+ * scaleInterval: 0.08,
31
+ * rotateZDeg: 135,
32
+ */
33
+ modeConfig?: ILayoutConfig;
34
+ }>;
35
+
16
36
  export function horizontalStackLayout(modeConfig: ILayoutConfig = {}) {
17
37
  return (_value: number) => {
18
38
  'worklet';
@@ -106,6 +126,28 @@ export function horizontalStackLayout(modeConfig: ILayoutConfig = {}) {
106
126
  };
107
127
  }
108
128
 
129
+ export function useHorizontalStackLayout(
130
+ customAnimationConfig: ILayoutConfig = {},
131
+ customConfig: CustomConfig = {}
132
+ ) {
133
+ const config = useMemo(
134
+ () => ({
135
+ type:
136
+ customAnimationConfig.snapDirection === 'right'
137
+ ? 'negative'
138
+ : 'positive',
139
+ viewCount: customAnimationConfig.showLength,
140
+ ...customConfig,
141
+ }),
142
+ [customAnimationConfig, customConfig]
143
+ );
144
+
145
+ return {
146
+ layout: horizontalStackLayout(customAnimationConfig),
147
+ config,
148
+ };
149
+ }
150
+
109
151
  export function verticalStackLayout(modeConfig: ILayoutConfig = {}) {
110
152
  return (_value: number) => {
111
153
  'worklet';