react-native-reanimated-carousel 1.0.7 → 1.0.11

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 (79) hide show
  1. package/README.md +40 -51
  2. package/README.zh-CN.md +41 -52
  3. package/lib/commonjs/Carousel.js +96 -120
  4. package/lib/commonjs/Carousel.js.map +1 -1
  5. package/lib/commonjs/CarouselItem.js +35 -14
  6. package/lib/commonjs/CarouselItem.js.map +1 -1
  7. package/lib/commonjs/LazyView.js +26 -0
  8. package/lib/commonjs/LazyView.js.map +1 -0
  9. package/lib/commonjs/ScrollViewGesture.js +196 -0
  10. package/lib/commonjs/ScrollViewGesture.js.map +1 -0
  11. package/lib/commonjs/hooks/useCarouselController.js +9 -9
  12. package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
  13. package/lib/commonjs/hooks/useIndexController.js +3 -3
  14. package/lib/commonjs/hooks/useIndexController.js.map +1 -1
  15. package/lib/commonjs/hooks/useOffsetX.js +20 -33
  16. package/lib/commonjs/hooks/useOffsetX.js.map +1 -1
  17. package/lib/commonjs/hooks/usePropsErrorBoundary.js +11 -2
  18. package/lib/commonjs/hooks/usePropsErrorBoundary.js.map +1 -1
  19. package/lib/commonjs/hooks/useVisibleRanges.js +42 -0
  20. package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -0
  21. package/lib/commonjs/index.js.map +1 -1
  22. package/lib/commonjs/layouts/ParallaxLayout.js +55 -19
  23. package/lib/commonjs/layouts/ParallaxLayout.js.map +1 -1
  24. package/lib/commonjs/types.js +6 -0
  25. package/lib/commonjs/types.js.map +1 -0
  26. package/lib/commonjs/utils/log.js +2 -2
  27. package/lib/commonjs/utils/log.js.map +1 -1
  28. package/lib/module/Carousel.js +92 -117
  29. package/lib/module/Carousel.js.map +1 -1
  30. package/lib/module/CarouselItem.js +31 -14
  31. package/lib/module/CarouselItem.js.map +1 -1
  32. package/lib/module/LazyView.js +14 -0
  33. package/lib/module/LazyView.js.map +1 -0
  34. package/lib/module/ScrollViewGesture.js +172 -0
  35. package/lib/module/ScrollViewGesture.js.map +1 -0
  36. package/lib/module/hooks/useCarouselController.js +9 -9
  37. package/lib/module/hooks/useCarouselController.js.map +1 -1
  38. package/lib/module/hooks/useIndexController.js +3 -3
  39. package/lib/module/hooks/useIndexController.js.map +1 -1
  40. package/lib/module/hooks/useOffsetX.js +20 -33
  41. package/lib/module/hooks/useOffsetX.js.map +1 -1
  42. package/lib/module/hooks/usePropsErrorBoundary.js +11 -2
  43. package/lib/module/hooks/usePropsErrorBoundary.js.map +1 -1
  44. package/lib/module/hooks/useVisibleRanges.js +34 -0
  45. package/lib/module/hooks/useVisibleRanges.js.map +1 -0
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/layouts/ParallaxLayout.js +49 -21
  48. package/lib/module/layouts/ParallaxLayout.js.map +1 -1
  49. package/lib/module/types.js +2 -0
  50. package/lib/module/types.js.map +1 -0
  51. package/lib/module/utils/log.js +2 -2
  52. package/lib/module/utils/log.js.map +1 -1
  53. package/lib/typescript/Carousel.d.ts +3 -113
  54. package/lib/typescript/CarouselItem.d.ts +5 -3
  55. package/lib/typescript/LazyView.d.ts +6 -0
  56. package/lib/typescript/ScrollViewGesture.d.ts +18 -0
  57. package/lib/typescript/hooks/useCarouselController.d.ts +1 -1
  58. package/lib/typescript/hooks/useIndexController.d.ts +1 -1
  59. package/lib/typescript/hooks/useOffsetX.d.ts +3 -2
  60. package/lib/typescript/hooks/usePropsErrorBoundary.d.ts +2 -2
  61. package/lib/typescript/hooks/useVisibleRanges.d.ts +11 -0
  62. package/lib/typescript/index.d.ts +1 -1
  63. package/lib/typescript/layouts/ParallaxLayout.d.ts +4 -0
  64. package/lib/typescript/types.d.ts +129 -0
  65. package/lib/typescript/utils/log.d.ts +1 -1
  66. package/package.json +1 -1
  67. package/src/Carousel.tsx +104 -269
  68. package/src/CarouselItem.tsx +62 -16
  69. package/src/LazyView.tsx +15 -0
  70. package/src/ScrollViewGesture.tsx +249 -0
  71. package/src/hooks/useCarouselController.tsx +10 -10
  72. package/src/hooks/useIndexController.ts +4 -4
  73. package/src/hooks/useOffsetX.ts +22 -38
  74. package/src/hooks/usePropsErrorBoundary.ts +12 -4
  75. package/src/hooks/useVisibleRanges.tsx +42 -0
  76. package/src/index.tsx +1 -1
  77. package/src/layouts/ParallaxLayout.tsx +89 -27
  78. package/src/types.ts +137 -0
  79. package/src/utils/log.ts +2 -2
package/README.md CHANGED
@@ -11,29 +11,22 @@ English | [简体中文](./README.zh-CN.md)
11
11
  [![github closed issues](https://img.shields.io/github/issues-closed/dohooo/react-native-reanimated-carousel.svg?style=flat-square&colorB=44cc11)](https://github.com/dohooo/react-native-reanimated-carousel/issues?q=is%3Aissue+is%3Aclosed)
12
12
 
13
13
  <p align="center">
14
- <img src="assets/normal.gif" width="300"/>
14
+ <img src="assets/normal-horizontal.gif" width="300"/>
15
+ <img src="assets/normal-vertical.gif" width="300"/>
16
+ <img src="assets/parallax-horizontal.gif" width="300"/>
17
+ <img src="assets/parallax-vertical.gif" width="300"/>
15
18
  </p>
16
19
 
17
20
  <br/>
18
21
 
19
- ## Here comes the official edition!
22
+ ## ReactNative community's best use of the carousel component! 🎉🎉🎉
20
23
 
21
- `v1` has been born, now the carousel will be more natural, and fixed various bugs in the 0.x version, this library will continue to maintain, rest assured to use! [come and experience](https://snack.expo.dev/@zhaodonghao586/simple-carousel) 🎉🎉🎉
22
-
23
- Updates:
24
-
25
- - Reconstructed some logic, sliding animation more smooth, natural
26
- - timingConfig -> springConfig (The configuration of the 'duration' property is no longer supported by this configuration)
27
- - [...](https://github.com/dohooo/react-native-reanimated-carousel/releases/tag/v1.0.0)
24
+ - It completely solves this [problem](https://github.com/meliorence/react-native-snap-carousel/issues/632) for `react-native-snap-carousel`! More styles and apis in development... [Try it](https://snack.expo.dev/@zhaodonghao586/simple-carousel)
25
+ - **Simple**、**Infinitely scrolling very smooth**、**Fully implemented using Reanimated 2!**
28
26
 
29
27
  ## Reason
30
-
31
- 🎉 **It completely solves [this problem](https://github.com/meliorence/react-native-snap-carousel/issues/632) for `react-native-snap-carousel`! Simple、Infinitely scrolling very smooth、Fully implemented using Reanimated 2!**
32
-
33
- > The common RN infinite scroll component. It's common to get stuck on a fast slide. Wait for the next element to appear. This component will not have similar problems. That's why this library was created.
34
-
35
- > At present, it only meets the needs of my work. Welcome to raise PR/ISSUES.[Try it with snack](https://snack.expo.dev/@zhaodonghao586/simple-carousel)
36
-
28
+ <details>
29
+ <summary>The common RN infinite scroll component. It get stuck on a fast slide. Wait for the next element to appear. This component will not have similar problems.Because using a completely different approach so the best performance is achieved.That's why this library was created.</summary>
37
30
  <p align="center">
38
31
  Use react-native-snap-carousel for quick swiping,you can see caton clearly when you reach the junction.(gif 4.6mb)
39
32
  </p>
@@ -42,11 +35,12 @@ Updates:
42
35
  </p>
43
36
 
44
37
  <p align="center">
45
- Compared with react-native-reanimated-carousel,The actual test was ten slides per second, but it didn't show up very well in gif.(gif 83mb)
38
+ Compared with react-native-reanimated-carousel,The actual test was ten slides per second, but it didn't show up very well in gif.
46
39
  </p>
47
40
  <p align="center">
48
- <img src="assets/fast.gif" width="50%"/>
41
+ <img src="assets/normal-fast.gif" width="50%"/>
49
42
  </p>
43
+ </details>
50
44
 
51
45
  ---
52
46
 
@@ -72,51 +66,46 @@ If use EXPO managed workflow please ensure that the version is greater than 41.B
72
66
 
73
67
  ## Usage
74
68
 
75
- ```typescript
69
+ ```tsx
76
70
  import Carousel from 'react-native-reanimated-carousel';
77
71
 
78
- // ...
79
-
80
72
  <Carousel<{ color: string }>
81
73
  width={width}
82
74
  data={[{ color: 'red' }, { color: 'purple' }, { color: 'yellow' }]}
83
75
  renderItem={({ color }) => {
84
- return (
85
- <View
86
- style={{
87
- backgroundColor: color,
88
- justifyContent: 'center',
89
- flex: 1,
90
- }}
91
- />
92
- );
76
+ return <View style={{ backgroundColor: color, flex: 1 }} />;
93
77
  }}
94
78
  />;
95
79
  ```
96
80
 
81
+ ## Optimizing
82
+
83
+ - When rendering a large number of elements, you can use the 'windowSize' property to control how many items of the current element are rendered. The default is full rendering. After testing without this property, frames will drop when rendering 200 empty views. After setting this property, rendering 1000 empty views is still smooth. (The specific number depends on the phone model tested)
84
+
97
85
  ## Props
98
86
 
99
- | name | required | default | types | description |
100
- | ----------------------- | -------- | -------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
101
- | data | ✅ | | T[] | Carousel items data set |
102
- | width | ✅ | | number | Specified carousel container width |
103
- | renderItem | ✅ | | (data: T, index: number) => React.ReactNode | Render carousel item |
104
- | defaultIndex | ❌ | 0 | number | Default index |
105
- | autoPlay | ❌ | false | boolean | Auto play |
106
- | autoPlayReverse | ❌ | false | boolean | Auto play reverse playback |
107
- | autoPlayInterval | ❌ | 1000 | autoPlayInterval | Auto play playback interval |
108
- | mode | ❌ | defalut | 'default'\|'parallax' | Carousel Animated transitions |
109
- | loop | ❌ | true | boolean | Carousel loop playback |
110
- | parallaxScrollingOffset | ❌ | 100 | number | When use 'parallax' Layout props,this prop can be control prev/next item offset |
111
- | parallaxScrollingScale | ❌ | 0.8 | number | When use 'parallax' Layout props,this prop can be control prev/next item scale |
112
- | style | ❌ | {} | ViewStyle | Carousel container style |
113
- | height | ❌ | '100%' | undefined \| string \| number | Specified carousel container height |
114
- | springConfig | ❌ | {damping: 100} | Animated.WithSpringConfig | Spring config of translation animated |
115
- | onSnapToItem | ❌ | | (index: number) => void | Callback fired when navigating to an item |
116
- | onScrollBegin | ❌ | | () => void | Callback fired when scroll begin |
117
- | onScrollEnd | ❌ | | (previous: number, current: number) => void | Callback fired when scroll end |
118
- | panGestureHandlerProps | ❌ | {} | Omit<Partial\<PanGestureHandlerProps\>,'onHandlerStateChange'> | PanGestureHandler props |
119
- | onProgressChange | ❌ | | onProgressChange?: (offsetProgress: number,absoluteProgress: number) => void | On progress change. `offsetProgress`:Total of offset distance (0 390 780 ...); `absoluteProgress`:Convert to index (0 1 2 ...) |
87
+ | name | required | default | types | description |
88
+ | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
89
+ | data | ✅ | | T[] | Carousel items data set |
90
+ | width | ✅ | | number | Specified carousel container width |
91
+ | renderItem | ✅ | | (data: T, index: number) => React.ReactNode | Render carousel item |
92
+ | defaultIndex | ❌ | 0 | number | Default index |
93
+ | autoPlay | ❌ | false | boolean | Auto play |
94
+ | autoPlayReverse | ❌ | false | boolean | Auto play reverse playback |
95
+ | autoPlayInterval | ❌ | 1000 | autoPlayInterval | Auto play playback interval |
96
+ | mode | ❌ | defalut | 'default'\|'parallax' | Carousel Animated transitions |
97
+ | loop | ❌ | true | boolean | Carousel loop playback |
98
+ | parallaxScrollingOffset | ❌ | 100 | number | When use 'parallax' Layout props,this prop can be control prev/next item offset |
99
+ | parallaxScrollingScale | ❌ | 0.8 | number | When use 'parallax' Layout props,this prop can be control prev/next item scale |
100
+ | style | ❌ | {} | ViewStyle | Carousel container style |
101
+ | height | ❌ | '100%' | undefined \| string \| number | Specified carousel container height |
102
+ | onSnapToItem | ❌ | | (index: number) => void | Callback fired when navigating to an item |
103
+ | onScrollBegin | ❌ | | () => void | Callback fired when scroll begin |
104
+ | onScrollEnd | ❌ | | (previous: number, current: number) => void | Callback fired when scroll end |
105
+ | panGestureHandlerProps | ❌ | {} | Omit<Partial\<PanGestureHandlerProps\>,'onHandlerStateChange'> | PanGestureHandler props |
106
+ | windowSize | ❌ | 0 | number | The maximum number of items that can respond to pan gesture events, `0` means all items will respond to pan gesture events |
107
+ | onProgressChange | ❌ | | onProgressChange?: (offsetProgress: number,absoluteProgress: number) => void | On progress change. `offsetProgress`:Total of offset distance (0 390 780 ...); `absoluteProgress`:Convert to index (0 1 2 ...) |
108
+ | vertical | ❌ | false | boolean | Layout items vertically instead of horizontally |
120
109
 
121
110
  ## Ref
122
111
 
package/README.zh-CN.md CHANGED
@@ -11,30 +11,23 @@
11
11
  [![github closed issues](https://img.shields.io/github/issues-closed/dohooo/react-native-reanimated-carousel.svg?style=flat-square&colorB=44cc11)](https://github.com/dohooo/react-native-reanimated-carousel/issues?q=is%3Aissue+is%3Aclosed)
12
12
 
13
13
  <p align="center">
14
- <img src="assets/normal.gif" width="300"/>
14
+ <img src="assets/normal-horizontal.gif" width="300"/>
15
+ <img src="assets/normal-vertical.gif" width="300"/>
16
+ <img src="assets/parallax-horizontal.gif" width="300"/>
17
+ <img src="assets/parallax-vertical.gif" width="300"/>
15
18
  </p>
16
19
 
17
20
  <br/>
18
21
 
19
- ## 正式版来了!
22
+ ## ReactNative 社区最好用的轮播图组件! 🎉🎉🎉
20
23
 
21
- `v1`已经诞生,现在轮播图的滚动将会更加自然,并且修复了 0.x 版本中出现的各种 bug,此库将会持续维护,放心使用! [快来体验](https://snack.expo.dev/@zhaodonghao586/simple-carousel) 🎉🎉🎉
22
-
23
- 更新:
24
-
25
- - 重构了部分逻辑,滑动动画更加流畅、自然
26
- - timingConfig -> springConfig (此配置不再支持对`duration`属性的配置)
27
- - [...](https://github.com/dohooo/react-native-reanimated-carousel/releases/tag/v1.0.0)
24
+ - 完全解决了`react-native-snap-carousel`的[问题](https://github.com/meliorence/react-native-snap-carousel/issues/632)! 更多样式与API正在开发中...[试一下](https://snack.expo.dev/@zhaodonghao586/simple-carousel)
25
+ - **易用**、**无限滚动**、**完全使用 Reanimated2 实现**
28
26
 
29
27
  ## 原因
30
-
31
- 🎉 **完全解决了`react-native-snap-carousel`的[这个问题](https://github.com/meliorence/react-native-snap-carousel/issues/632)! 易用、无限滚动、完全使用 Reanimated2 实现**
32
-
33
- > 常见的无限滚动轮播图,在快速滑动时会出现卡住的情况,这是因为实现方式而导致的问题。这个组件用了不同的方式来实现,解决了这个问题,这就是创建这个库的原因。
34
-
35
- > 目前他只满足了我工作上的需要,欢迎大家的 ISSUES/PR。[在 SNACK 上尝试](https://snack.expo.dev/@zhaodonghao586/simple-carousel)
36
-
37
- <p align="center">
28
+ <details>
29
+ <summary>常见的无限滚动轮播图,在快速滑动时会出现卡住的情况,这是因为实现方式而导致的问题。所以这个组件用了完全不同的方式来实现,并获得了最佳的性能也解决了这个问题,这就是创建这个库的原因。</summary>
30
+ <p align="center">
38
31
  使用react-native-snap-carousel快速滑动,当到连接处时可以看清楚的看到卡顿。(gif 4.6mb)
39
32
  </p>
40
33
  <p align="center">
@@ -42,11 +35,12 @@
42
35
  </p>
43
36
 
44
37
  <p align="center">
45
- 使用react-native-reanimated-carousel对比,每秒滚动十张依然顺畅链接,无限滚动。这里使用了gif无法很清晰的看出。(gif 83mb)
38
+ 使用react-native-reanimated-carousel对比,每秒滚动十张依然顺畅链接,无限滚动。这里使用了gif无法很清晰的看出。
46
39
  </p>
47
40
  <p align="center">
48
- <img src="assets/fast.gif" width="50%"/>
41
+ <img src="assets/normal-fast.gif" width="50%"/>
49
42
  </p>
43
+ </details>
50
44
 
51
45
  ---
52
46
 
@@ -72,51 +66,46 @@ npm install react-native-reanimated-carousel
72
66
 
73
67
  ## 使用
74
68
 
75
- ```typescript
69
+ ```tsx
76
70
  import Carousel from 'react-native-reanimated-carousel';
77
71
 
78
- // ...
79
-
80
72
  <Carousel<{ color: string }>
81
73
  width={width}
82
74
  data={[{ color: 'red' }, { color: 'purple' }, { color: 'yellow' }]}
83
75
  renderItem={({ color }) => {
84
- return (
85
- <View
86
- style={{
87
- backgroundColor: color,
88
- justifyContent: 'center',
89
- flex: 1,
90
- }}
91
- />
92
- );
76
+ return <View style={{ backgroundColor: color, flex: 1 }} />;
93
77
  }}
94
78
  />;
95
79
  ```
96
80
 
81
+ ## 优化
82
+
83
+ - 当渲染大量元素时,可使用`windowSize`属性,来控制当前元素的两侧渲染数量,默认为全量渲染。经测试不加此属性,渲染 200 个空 view 时会出现掉帧情况,设置此属性后渲染 1000 个空 view 依旧流畅。(具体数量与测试的手机型号相关)
84
+
97
85
  ## Props
98
86
 
99
- | name | required | default | types | description |
100
- | ----------------------- | -------- | -------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
101
- | data | ✅ | | T[] | 即将渲染的数据集合 |
102
- | width | ✅ | | number | 轮播图容器的宽度 |
103
- | renderItem | ✅ | | (data: T, index: number) => React.ReactNode | 渲染元素的方法 |
104
- | defaultIndex | ❌ | 0 | number | 默认 index |
105
- | autoPlay | ❌ | false | boolean | 是否自动播放 |
106
- | autoPlayReverse | ❌ | false | boolean | 是否倒序自动播放 |
107
- | autoPlayInterval | ❌ | 1000 | autoPlayInterval | 自动播放的间隔 |
108
- | mode | ❌ | defalut | 'default'\|'parallax' | 轮播图播放模式,`default`为默认无任何 UI 效果,演示图片使用的`parallax` |
109
- | loop | ❌ | true | boolean | 是否循环播放 |
110
- | parallaxScrollingOffset | ❌ | 100 | number | 当使用 mode=`parallax`,这个属性可以控制两侧图片离中间元素的距离 |
111
- | parallaxScrollingScale | ❌ | 0.8 | number | 当使用 mode=`parallax`,这个属性可以控制两侧图片的缩放比例 |
112
- | style | ❌ | {} | ViewStyle | 轮播图容器样式 |
113
- | height | ❌ | '100%' | undefined \| string \| number | 指定轮播图容器高度 |
114
- | springConfig | ❌ | {damping: 100} | Animated.WithSpringConfig | 配置动画效果 |
115
- | onSnapToItem | ❌ | | (index: number) => void | 切换至另一张轮播图时触发 |
116
- | onScrollBegin | ❌ | | () => void | 切换动画开始时触发 |
117
- | onScrollEnd | ❌ | | (previous: number, current: number) => void | 切换动画结束时触发 |
118
- | panGestureHandlerProps | ❌ | {} | Omit<Partial\<PanGestureHandlerProps\>,'onHandlerStateChange'> | PanGestureHandler props |
119
- | onProgressChange | ❌ | | onProgressChange?: (offsetProgress: number,absoluteProgress: number) => void | 当滚动进度发生变化时触发 `offsetProgress`:总的偏移值 (0 390 780 ...); `absoluteProgress`:转化为 index 的进度变化 (0 1 2 ...) |
87
+ | name | required | default | types | description |
88
+ | ----------------------- | -------- | ------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
89
+ | data | ✅ | | T[] | 即将渲染的数据集合 |
90
+ | width | ✅ | | number | 轮播图容器的宽度 |
91
+ | renderItem | ✅ | | (data: T, index: number) => React.ReactNode | 渲染元素的方法 |
92
+ | defaultIndex | ❌ | 0 | number | 默认 index |
93
+ | autoPlay | ❌ | false | boolean | 是否自动播放 |
94
+ | autoPlayReverse | ❌ | false | boolean | 是否倒序自动播放 |
95
+ | autoPlayInterval | ❌ | 1000 | autoPlayInterval | 自动播放的间隔 |
96
+ | mode | ❌ | defalut | 'default'\|'parallax' | 轮播图播放模式,`default`为默认无任何 UI 效果,演示图片使用的`parallax` |
97
+ | loop | ❌ | true | boolean | 是否循环播放 |
98
+ | parallaxScrollingOffset | ❌ | 100 | number | 当使用 mode=`parallax`,这个属性可以控制两侧图片离中间元素的距离 |
99
+ | parallaxScrollingScale | ❌ | 0.8 | number | 当使用 mode=`parallax`,这个属性可以控制两侧图片的缩放比例 |
100
+ | style | ❌ | {} | ViewStyle | 轮播图容器样式 |
101
+ | height | ❌ | '100%' | undefined \| string \| number | 指定轮播图容器高度 |
102
+ | onSnapToItem | ❌ | | (index: number) => void | 切换至另一张轮播图时触发 |
103
+ | onScrollBegin | ❌ | | () => void | 切换动画开始时触发 |
104
+ | onScrollEnd | ❌ | | (previous: number, current: number) => void | 切换动画结束时触发 |
105
+ | panGestureHandlerProps | ❌ | {} | Omit<Partial\<PanGestureHandlerProps\>,'onHandlerStateChange'> | PanGestureHandler props |
106
+ | windowSize | ❌ | 0 | number | 能响应平移手势事件的最大 item 数量,0 表示所有元素都会先响应 |
107
+ | onProgressChange | ❌ | | onProgressChange?: (offsetProgress: number,absoluteProgress: number) => void | 当滚动进度发生变化时触发 `offsetProgress`:总的偏移值 (0 390 780 ...); `absoluteProgress`:转化为 index 的进度变化 (0 1 2 ...) |
108
+ | vertical | ❌ | false | boolean | 将元素垂直布局而不是水平 |
120
109
 
121
110
  ## Ref
122
111
 
@@ -7,8 +7,6 @@ exports.default = void 0;
7
7
 
8
8
  var _react = _interopRequireDefault(require("react"));
9
9
 
10
- var _reactNativeGestureHandler = require("react-native-gesture-handler");
11
-
12
10
  var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
13
11
 
14
12
  var _CarouselItem = require("./CarouselItem");
@@ -23,22 +21,21 @@ var _useIndexController = require("./hooks/useIndexController");
23
21
 
24
22
  var _usePropsErrorBoundary = require("./hooks/usePropsErrorBoundary");
25
23
 
24
+ var _ScrollViewGesture = require("./ScrollViewGesture");
25
+
26
+ var _useVisibleRanges = require("./hooks/useVisibleRanges");
27
+
28
+ var _reactNative = require("react-native");
29
+
26
30
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
31
 
28
32
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
29
33
 
30
34
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31
35
 
32
- function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
33
-
34
- const defaultSpringConfig = {
35
- damping: 100
36
- };
37
-
38
36
  function Carousel(props, ref) {
39
37
  const {
40
38
  defaultIndex = 0,
41
- height = '100%',
42
39
  data: _data = [],
43
40
  loop = true,
44
41
  mode = 'default',
@@ -47,37 +44,39 @@ function Carousel(props, ref) {
47
44
  autoPlayInterval = 1000,
48
45
  parallaxScrollingOffset,
49
46
  parallaxScrollingScale,
50
- style,
47
+ style = {},
51
48
  panGestureHandlerProps = {},
52
49
  renderItem,
53
50
  onSnapToItem,
54
- onProgressChange
51
+ onProgressChange,
52
+ windowSize,
53
+ vertical,
54
+ onScrollBegin,
55
+ onScrollEnd
55
56
  } = props;
56
57
  (0, _usePropsErrorBoundary.usePropsErrorBoundary)({ ...props,
57
- defaultIndex,
58
- height,
59
58
  data: _data,
60
- loop,
61
59
  mode,
62
- autoPlay,
63
- autoPlayReverse,
64
- autoPlayInterval,
65
- parallaxScrollingOffset,
66
- parallaxScrollingScale,
60
+ loop,
67
61
  style,
68
- panGestureHandlerProps,
69
- // @ts-ignore
70
- renderItem,
71
- onSnapToItem,
72
- onProgressChange
62
+ defaultIndex,
63
+ autoPlayInterval,
64
+ panGestureHandlerProps
73
65
  });
74
- const timingConfig = { ...defaultSpringConfig,
75
- ...props.springConfig
66
+ const width = Math.round(props.width || 0);
67
+ const height = Math.round(props.height || 0);
68
+ const size = vertical ? height : width;
69
+ const layoutStyle = {
70
+ width: width || '100%',
71
+ height: height || '100%'
76
72
  };
77
- const width = Math.round(props.width);
78
- const defaultHandlerOffsetX = -Math.abs(defaultIndex * width);
73
+ const defaultHandlerOffsetX = -Math.abs(defaultIndex * size);
79
74
  const handlerOffsetX = (0, _reactNativeReanimated.useSharedValue)(defaultHandlerOffsetX);
80
75
 
76
+ _react.default.useEffect(() => {
77
+ handlerOffsetX.value = defaultHandlerOffsetX;
78
+ }, [vertical, handlerOffsetX, defaultHandlerOffsetX]);
79
+
81
80
  const data = _react.default.useMemo(() => {
82
81
  if (!loop) return _data;
83
82
 
@@ -93,21 +92,21 @@ function Carousel(props, ref) {
93
92
  }, [_data, loop]);
94
93
 
95
94
  const indexController = (0, _useIndexController.useIndexController)({
96
- originalLength: _data.length,
95
+ originalLength: data.length,
97
96
  length: data.length,
98
97
  handlerOffsetX,
99
- width,
98
+ size,
100
99
  loop,
101
100
  onChange: i => onSnapToItem && (0, _reactNativeReanimated.runOnJS)(onSnapToItem)(i)
102
101
  });
103
102
  const carouselController = (0, _useCarouselController.useCarouselController)({
104
103
  loop,
105
- width,
104
+ size,
106
105
  handlerOffsetX,
107
106
  indexController,
108
107
  disable: !data.length,
109
- onScrollBegin: () => (0, _reactNativeReanimated.runOnJS)(onScrollBegin)(),
110
- onScrollEnd: () => (0, _reactNativeReanimated.runOnJS)(onScrollEnd)()
108
+ onScrollBegin: () => (0, _reactNativeReanimated.runOnJS)(_onScrollBegin)(),
109
+ onScrollEnd: () => (0, _reactNativeReanimated.runOnJS)(_onScrollEnd)()
111
110
  });
112
111
  const {
113
112
  run,
@@ -125,40 +124,46 @@ function Carousel(props, ref) {
125
124
  computedIndex
126
125
  } = indexController;
127
126
 
128
- const onScrollBegin = _react.default.useCallback(() => {
129
- var _props$onScrollBegin;
127
+ const _onScrollBegin = _react.default.useCallback(() => {
128
+ onScrollBegin === null || onScrollBegin === void 0 ? void 0 : onScrollBegin();
129
+ }, [onScrollBegin]);
130
130
 
131
+ const scrollViewGestureOnScrollBegin = _react.default.useCallback(() => {
131
132
  pause();
132
- (_props$onScrollBegin = props.onScrollBegin) === null || _props$onScrollBegin === void 0 ? void 0 : _props$onScrollBegin.call(props);
133
- }, [pause, props]);
134
133
 
135
- const onScrollEnd = _react.default.useCallback(() => {
136
- var _props$onScrollEnd;
134
+ _onScrollBegin();
135
+ }, [_onScrollBegin, pause]);
137
136
 
138
- run();
137
+ const _onScrollEnd = _react.default.useCallback(() => {
139
138
  computedIndex();
140
- (_props$onScrollEnd = props.onScrollEnd) === null || _props$onScrollEnd === void 0 ? void 0 : _props$onScrollEnd.call(props, sharedPreIndex.current, sharedIndex.current);
141
- }, [sharedPreIndex, sharedIndex, computedIndex, props, run]);
139
+ onScrollEnd === null || onScrollEnd === void 0 ? void 0 : onScrollEnd(sharedPreIndex.current, sharedIndex.current);
140
+ }, [sharedPreIndex, sharedIndex, computedIndex, onScrollEnd]);
141
+
142
+ const scrollViewGestureOnScrollEnd = _react.default.useCallback(() => {
143
+ run();
144
+
145
+ _onScrollEnd();
146
+ }, [_onScrollEnd, run]);
142
147
 
143
148
  const offsetX = (0, _reactNativeReanimated.useDerivedValue)(() => {
144
- const totalWidth = width * data.length;
145
- const x = handlerOffsetX.value % totalWidth;
149
+ const totalSize = size * data.length;
150
+ const x = handlerOffsetX.value % totalSize;
146
151
 
147
152
  if (!loop) {
148
153
  return handlerOffsetX.value;
149
154
  }
150
155
 
151
156
  return isNaN(x) ? 0 : x;
152
- }, [loop, width, data]);
157
+ }, [loop, size, data]);
153
158
  (0, _reactNativeReanimated.useAnimatedReaction)(() => offsetX.value, value => {
154
- let absoluteProgress = Math.abs(value / width);
159
+ let absoluteProgress = Math.abs(value / size);
155
160
 
156
161
  if (value > 0) {
157
162
  absoluteProgress = data.length - absoluteProgress;
158
163
  }
159
164
 
160
165
  !!onProgressChange && (0, _reactNativeReanimated.runOnJS)(onProgressChange)(value, absoluteProgress);
161
- }, [onProgressChange, data]);
166
+ }, [onProgressChange, props.children]);
162
167
 
163
168
  const next = _react.default.useCallback(() => {
164
169
  return carouselController.next();
@@ -176,64 +181,6 @@ function Carousel(props, ref) {
176
181
  carouselController.to(i, animated);
177
182
  }, [carouselController]);
178
183
 
179
- const animatedListScrollHandler = (0, _reactNativeReanimated.useAnimatedGestureHandler)({
180
- onStart: (_, ctx) => {
181
- (0, _reactNativeReanimated.runOnJS)(pause)();
182
- (0, _reactNativeReanimated.runOnJS)(onScrollBegin)();
183
- (0, _reactNativeReanimated.cancelAnimation)(handlerOffsetX);
184
- ctx.currentContentOffsetX = handlerOffsetX.value;
185
- ctx.start = true;
186
- },
187
- onActive: (e, ctx) => {
188
- const {
189
- translationX
190
- } = e;
191
-
192
- if (!loop && (handlerOffsetX.value >= 0 || handlerOffsetX.value <= -(data.length - 1) * width)) {
193
- handlerOffsetX.value = ctx.currentContentOffsetX + translationX / 2;
194
- return;
195
- }
196
-
197
- handlerOffsetX.value = ctx.currentContentOffsetX + translationX;
198
- },
199
- onEnd: e => {
200
- function _withAnimationCallback(num) {
201
- return (0, _reactNativeReanimated.withSpring)(num, Object.assign({}, timingConfig, {
202
- velocity: e.velocityX
203
- }), isFinished => {
204
- if (isFinished) {
205
- (0, _reactNativeReanimated.runOnJS)(onScrollEnd)();
206
- }
207
- });
208
- }
209
-
210
- const page = Math.round(handlerOffsetX.value / width);
211
- const velocityPage = Math.round((handlerOffsetX.value + e.velocityX) / width);
212
- let pageWithVelocity = Math.min(page + 1, Math.max(page - 1, velocityPage));
213
-
214
- if (!loop) {
215
- pageWithVelocity = Math.max(-(data.length - 1), Math.min(0, pageWithVelocity));
216
- }
217
-
218
- if (loop) {
219
- handlerOffsetX.value = _withAnimationCallback(pageWithVelocity * width);
220
- return;
221
- }
222
-
223
- if (handlerOffsetX.value >= 0) {
224
- handlerOffsetX.value = _withAnimationCallback(0);
225
- return;
226
- }
227
-
228
- if (handlerOffsetX.value <= -(data.length - 1) * width) {
229
- handlerOffsetX.value = _withAnimationCallback(-(data.length - 1) * width);
230
- return;
231
- }
232
-
233
- handlerOffsetX.value = _withAnimationCallback(pageWithVelocity * width);
234
- }
235
- }, [loop, data, onScrollBegin, onScrollEnd]);
236
-
237
184
  _react.default.useImperativeHandle(ref, () => ({
238
185
  next,
239
186
  prev,
@@ -241,6 +188,13 @@ function Carousel(props, ref) {
241
188
  goToIndex
242
189
  }), [getCurrentIndex, goToIndex, next, prev]);
243
190
 
191
+ const visibleRanges = (0, _useVisibleRanges.useVisibleRanges)({
192
+ total: data.length,
193
+ viewSize: size,
194
+ translation: handlerOffsetX,
195
+ windowSize
196
+ });
197
+
244
198
  const renderLayout = _react.default.useCallback((item, i) => {
245
199
  switch (mode) {
246
200
  case 'parallax':
@@ -249,10 +203,13 @@ function Carousel(props, ref) {
249
203
  parallaxScrollingScale: parallaxScrollingScale,
250
204
  data: data,
251
205
  width: width,
206
+ height: height,
252
207
  handlerOffsetX: offsetX,
253
208
  index: i,
254
209
  key: i,
255
- loop: loop
210
+ loop: loop,
211
+ visibleRanges: visibleRanges,
212
+ vertical: vertical
256
213
  }, renderItem(item, i));
257
214
 
258
215
  default:
@@ -263,25 +220,44 @@ function Carousel(props, ref) {
263
220
  handlerOffsetX: offsetX,
264
221
  index: i,
265
222
  key: i,
266
- loop: loop
223
+ loop: loop,
224
+ visibleRanges: visibleRanges,
225
+ vertical: vertical
267
226
  }, renderItem(item, i));
268
227
  }
269
- }, [loop, mode, data, height, offsetX, parallaxScrollingOffset, parallaxScrollingScale, width, renderItem]);
270
-
271
- return /*#__PURE__*/_react.default.createElement(_reactNativeGestureHandler.PanGestureHandler, _extends({}, panGestureHandlerProps, {
272
- onGestureEvent: animatedListScrollHandler
273
- }), /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
274
- // eslint-disable-next-line react-native/no-inline-styles
275
- style: { ...style,
276
- width,
277
- height,
278
- flexDirection: 'row',
279
- position: 'relative'
280
- }
281
- }, data.map(renderLayout)));
228
+ }, [loop, mode, data, offsetX, parallaxScrollingOffset, parallaxScrollingScale, renderItem, visibleRanges, vertical, width, height]);
229
+
230
+ return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
231
+ style: [styles.container, layoutStyle, style]
232
+ }, /*#__PURE__*/_react.default.createElement(_ScrollViewGesture.ScrollViewGesture, {
233
+ pagingEnabled: true,
234
+ vertical: vertical,
235
+ infinite: loop,
236
+ translation: handlerOffsetX,
237
+ style: style,
238
+ max: data.length * size,
239
+ size: size,
240
+ panGestureHandlerProps: panGestureHandlerProps,
241
+ onScrollBegin: scrollViewGestureOnScrollBegin,
242
+ onScrollEnd: scrollViewGestureOnScrollEnd
243
+ }, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, {
244
+ style: [styles.container, layoutStyle, style, vertical ? styles.itemsVertical : styles.itemsHorizontal]
245
+ }, data.map(renderLayout))));
282
246
  }
283
247
 
284
248
  var _default = /*#__PURE__*/_react.default.forwardRef(Carousel);
285
249
 
286
250
  exports.default = _default;
251
+
252
+ const styles = _reactNative.StyleSheet.create({
253
+ container: {
254
+ overflow: 'hidden'
255
+ },
256
+ itemsHorizontal: {
257
+ flexDirection: 'row'
258
+ },
259
+ itemsVertical: {
260
+ flexDirection: 'column'
261
+ }
262
+ });
287
263
  //# sourceMappingURL=Carousel.js.map