@fountain-ui/lab 2.0.0-beta.11 → 2.0.0-beta.14

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 (289) hide show
  1. package/build/commonjs/Carousel/Carousel.js +142 -0
  2. package/build/commonjs/Carousel/Carousel.js.map +1 -0
  3. package/build/commonjs/Carousel/CarouselProps.js.map +1 -1
  4. package/build/commonjs/Carousel/animation/animationUtils.js +9 -0
  5. package/build/commonjs/Carousel/animation/animationUtils.js.map +1 -0
  6. package/build/commonjs/Carousel/animation/createDefaultItemStyle.js +15 -0
  7. package/build/commonjs/Carousel/animation/createDefaultItemStyle.js.map +1 -0
  8. package/build/commonjs/Carousel/animation/createDefaultScrollAnimation.js +20 -0
  9. package/build/commonjs/Carousel/animation/createDefaultScrollAnimation.js.map +1 -0
  10. package/build/commonjs/Carousel/animation/index.js +40 -0
  11. package/build/commonjs/Carousel/animation/index.js.map +1 -0
  12. package/build/commonjs/Carousel/animation/normalItemStyleFactory.js +27 -0
  13. package/build/commonjs/Carousel/animation/normalItemStyleFactory.js.map +1 -0
  14. package/build/commonjs/Carousel/animation/parallaxItemStyleFactory.js +65 -0
  15. package/build/commonjs/Carousel/animation/parallaxItemStyleFactory.js.map +1 -0
  16. package/build/commonjs/Carousel/components/InternalContext.js +29 -0
  17. package/build/commonjs/Carousel/components/InternalContext.js.map +1 -0
  18. package/build/commonjs/Carousel/components/ItemView.js +66 -0
  19. package/build/commonjs/Carousel/components/ItemView.js.map +1 -0
  20. package/build/commonjs/Carousel/components/RootView.js +86 -0
  21. package/build/commonjs/Carousel/components/RootView.js.map +1 -0
  22. package/build/commonjs/Carousel/components/ScrollViewGesture.js +81 -0
  23. package/build/commonjs/Carousel/components/ScrollViewGesture.js.map +1 -0
  24. package/build/commonjs/Carousel/components/index.js +40 -0
  25. package/build/commonjs/Carousel/components/index.js.map +1 -0
  26. package/build/commonjs/Carousel/hooks/index.js +64 -0
  27. package/build/commonjs/Carousel/hooks/index.js.map +1 -0
  28. package/build/commonjs/Carousel/hooks/useAutoplayController.js +58 -0
  29. package/build/commonjs/Carousel/hooks/useAutoplayController.js.map +1 -0
  30. package/build/commonjs/Carousel/hooks/useDimensionChangeReaction.js +23 -0
  31. package/build/commonjs/Carousel/hooks/useDimensionChangeReaction.js.map +1 -0
  32. package/build/commonjs/Carousel/hooks/useIndexController.js +70 -0
  33. package/build/commonjs/Carousel/hooks/useIndexController.js.map +1 -0
  34. package/build/commonjs/Carousel/hooks/useItemInterpolation.js +63 -0
  35. package/build/commonjs/Carousel/hooks/useItemInterpolation.js.map +1 -0
  36. package/build/commonjs/Carousel/hooks/useItemVisibilityStore.js +95 -0
  37. package/build/commonjs/Carousel/hooks/useItemVisibilityStore.js.map +1 -0
  38. package/build/commonjs/Carousel/hooks/useLoopedData.js +33 -0
  39. package/build/commonjs/Carousel/hooks/useLoopedData.js.map +1 -0
  40. package/build/commonjs/Carousel/hooks/usePagingAnimation.js +162 -0
  41. package/build/commonjs/Carousel/hooks/usePagingAnimation.js.map +1 -0
  42. package/build/commonjs/Carousel/index.js +16 -2
  43. package/build/commonjs/Carousel/index.js.map +1 -1
  44. package/build/commonjs/Carousel/types.js +7 -0
  45. package/build/commonjs/Carousel/types.js.map +1 -0
  46. package/build/commonjs/ViewPager/ChildrenMemoizedPage.js +53 -59
  47. package/build/commonjs/ViewPager/ChildrenMemoizedPage.js.map +1 -1
  48. package/build/commonjs/ViewPager/InternalContext.js +17 -0
  49. package/build/commonjs/ViewPager/InternalContext.js.map +1 -0
  50. package/build/commonjs/ViewPager/PageStateContext.js +22 -0
  51. package/build/commonjs/ViewPager/PageStateContext.js.map +1 -0
  52. package/build/commonjs/ViewPager/ViewPagerNative.js +90 -25
  53. package/build/commonjs/ViewPager/ViewPagerNative.js.map +1 -1
  54. package/build/commonjs/ViewPager/ViewPagerProps.js.map +1 -1
  55. package/build/commonjs/ViewPager/ViewPagerWeb.js +27 -14
  56. package/build/commonjs/ViewPager/ViewPagerWeb.js.map +1 -1
  57. package/build/commonjs/ViewPager/index.js +8 -0
  58. package/build/commonjs/ViewPager/index.js.map +1 -1
  59. package/build/commonjs/ViewPager/index.native.js +8 -0
  60. package/build/commonjs/ViewPager/index.native.js.map +1 -1
  61. package/build/commonjs/ViewPager/types.js +6 -0
  62. package/build/commonjs/ViewPager/types.js.map +1 -0
  63. package/build/commonjs/ViewPager/usePageStore.js +30 -0
  64. package/build/commonjs/ViewPager/usePageStore.js.map +1 -0
  65. package/build/commonjs/ViewPager/utils.js +3 -1
  66. package/build/commonjs/ViewPager/utils.js.map +1 -1
  67. package/build/commonjs/ViewabilityTrackerView/Viewability.js +2 -0
  68. package/build/commonjs/ViewabilityTrackerView/Viewability.js.map +1 -0
  69. package/build/commonjs/ViewabilityTrackerView/ViewabilityTrackerView.js +45 -0
  70. package/build/commonjs/ViewabilityTrackerView/ViewabilityTrackerView.js.map +1 -0
  71. package/build/commonjs/ViewabilityTrackerView/ViewabilityTrackerViewProps.js +2 -0
  72. package/build/commonjs/ViewabilityTrackerView/ViewabilityTrackerViewProps.js.map +1 -0
  73. package/build/commonjs/{Carousel/index.native.js → ViewabilityTrackerView/index.js} +3 -3
  74. package/build/commonjs/ViewabilityTrackerView/index.js.map +1 -0
  75. package/build/commonjs/ViewabilityTrackerView/measureViewability.js +42 -0
  76. package/build/commonjs/ViewabilityTrackerView/measureViewability.js.map +1 -0
  77. package/build/commonjs/ViewabilityTrackerView/useViewabilityTracker.js +88 -0
  78. package/build/commonjs/ViewabilityTrackerView/useViewabilityTracker.js.map +1 -0
  79. package/build/commonjs/hooks/index.js +16 -0
  80. package/build/commonjs/hooks/index.js.map +1 -1
  81. package/build/commonjs/hooks/useDeferredExecutor.js +45 -0
  82. package/build/commonjs/hooks/useDeferredExecutor.js.map +1 -0
  83. package/build/commonjs/hooks/useIsMounted.js +22 -0
  84. package/build/commonjs/hooks/useIsMounted.js.map +1 -0
  85. package/build/commonjs/hooks/useUnstableCollapsibleAppBar.js +1 -1
  86. package/build/commonjs/hooks/useUnstableCollapsibleAppBar.js.map +1 -1
  87. package/build/commonjs/index.js +22 -1
  88. package/build/commonjs/index.js.map +1 -1
  89. package/build/module/Carousel/Carousel.js +120 -0
  90. package/build/module/Carousel/Carousel.js.map +1 -0
  91. package/build/module/Carousel/CarouselProps.js.map +1 -1
  92. package/build/module/Carousel/animation/animationUtils.js +2 -0
  93. package/build/module/Carousel/animation/animationUtils.js.map +1 -0
  94. package/build/module/Carousel/animation/createDefaultItemStyle.js +3 -0
  95. package/build/module/Carousel/animation/createDefaultItemStyle.js.map +1 -0
  96. package/build/module/Carousel/animation/createDefaultScrollAnimation.js +11 -0
  97. package/build/module/Carousel/animation/createDefaultScrollAnimation.js.map +1 -0
  98. package/build/module/Carousel/animation/index.js +5 -0
  99. package/build/module/Carousel/animation/index.js.map +1 -0
  100. package/build/module/Carousel/animation/normalItemStyleFactory.js +18 -0
  101. package/build/module/Carousel/animation/normalItemStyleFactory.js.map +1 -0
  102. package/build/module/Carousel/animation/parallaxItemStyleFactory.js +55 -0
  103. package/build/module/Carousel/animation/parallaxItemStyleFactory.js.map +1 -0
  104. package/build/module/Carousel/components/InternalContext.js +19 -0
  105. package/build/module/Carousel/components/InternalContext.js.map +1 -0
  106. package/build/module/Carousel/components/ItemView.js +46 -0
  107. package/build/module/Carousel/components/ItemView.js.map +1 -0
  108. package/build/module/Carousel/components/RootView.js +65 -0
  109. package/build/module/Carousel/components/RootView.js.map +1 -0
  110. package/build/module/Carousel/components/ScrollViewGesture.js +67 -0
  111. package/build/module/Carousel/components/ScrollViewGesture.js.map +1 -0
  112. package/build/module/Carousel/components/index.js +5 -0
  113. package/build/module/Carousel/components/index.js.map +1 -0
  114. package/build/module/Carousel/hooks/index.js +8 -0
  115. package/build/module/Carousel/hooks/index.js.map +1 -0
  116. package/build/module/Carousel/hooks/useAutoplayController.js +48 -0
  117. package/build/module/Carousel/hooks/useAutoplayController.js.map +1 -0
  118. package/build/module/Carousel/hooks/useDimensionChangeReaction.js +14 -0
  119. package/build/module/Carousel/hooks/useDimensionChangeReaction.js.map +1 -0
  120. package/build/module/Carousel/hooks/useIndexController.js +54 -0
  121. package/build/module/Carousel/hooks/useIndexController.js.map +1 -0
  122. package/build/module/Carousel/hooks/useItemInterpolation.js +51 -0
  123. package/build/module/Carousel/hooks/useItemInterpolation.js.map +1 -0
  124. package/build/module/Carousel/hooks/useItemVisibilityStore.js +87 -0
  125. package/build/module/Carousel/hooks/useItemVisibilityStore.js.map +1 -0
  126. package/build/module/Carousel/hooks/useLoopedData.js +24 -0
  127. package/build/module/Carousel/hooks/useLoopedData.js.map +1 -0
  128. package/build/module/Carousel/hooks/usePagingAnimation.js +153 -0
  129. package/build/module/Carousel/hooks/usePagingAnimation.js.map +1 -0
  130. package/build/module/Carousel/index.js +2 -1
  131. package/build/module/Carousel/index.js.map +1 -1
  132. package/build/module/Carousel/types.js +3 -0
  133. package/build/module/Carousel/types.js.map +1 -0
  134. package/build/module/ViewPager/ChildrenMemoizedPage.js +48 -56
  135. package/build/module/ViewPager/ChildrenMemoizedPage.js.map +1 -1
  136. package/build/module/ViewPager/InternalContext.js +7 -0
  137. package/build/module/ViewPager/InternalContext.js.map +1 -0
  138. package/build/module/ViewPager/PageStateContext.js +10 -0
  139. package/build/module/ViewPager/PageStateContext.js.map +1 -0
  140. package/build/module/ViewPager/ViewPagerNative.js +90 -27
  141. package/build/module/ViewPager/ViewPagerNative.js.map +1 -1
  142. package/build/module/ViewPager/ViewPagerProps.js.map +1 -1
  143. package/build/module/ViewPager/ViewPagerWeb.js +25 -15
  144. package/build/module/ViewPager/ViewPagerWeb.js.map +1 -1
  145. package/build/module/ViewPager/index.js +1 -0
  146. package/build/module/ViewPager/index.js.map +1 -1
  147. package/build/module/ViewPager/index.native.js +1 -0
  148. package/build/module/ViewPager/index.native.js.map +1 -1
  149. package/build/module/ViewPager/types.js +2 -0
  150. package/build/module/ViewPager/types.js.map +1 -0
  151. package/build/module/ViewPager/usePageStore.js +20 -0
  152. package/build/module/ViewPager/usePageStore.js.map +1 -0
  153. package/build/module/ViewPager/utils.js +1 -0
  154. package/build/module/ViewPager/utils.js.map +1 -1
  155. package/build/module/ViewabilityTrackerView/Viewability.js +2 -0
  156. package/build/module/ViewabilityTrackerView/Viewability.js.map +1 -0
  157. package/build/module/ViewabilityTrackerView/ViewabilityTrackerView.js +28 -0
  158. package/build/module/ViewabilityTrackerView/ViewabilityTrackerView.js.map +1 -0
  159. package/build/module/ViewabilityTrackerView/ViewabilityTrackerViewProps.js +2 -0
  160. package/build/module/ViewabilityTrackerView/ViewabilityTrackerViewProps.js.map +1 -0
  161. package/build/module/ViewabilityTrackerView/index.js +2 -0
  162. package/build/module/ViewabilityTrackerView/index.js.map +1 -0
  163. package/build/module/ViewabilityTrackerView/measureViewability.js +34 -0
  164. package/build/module/ViewabilityTrackerView/measureViewability.js.map +1 -0
  165. package/build/module/ViewabilityTrackerView/useViewabilityTracker.js +73 -0
  166. package/build/module/ViewabilityTrackerView/useViewabilityTracker.js.map +1 -0
  167. package/build/module/hooks/index.js +2 -0
  168. package/build/module/hooks/index.js.map +1 -1
  169. package/build/module/hooks/useDeferredExecutor.js +33 -0
  170. package/build/module/hooks/useDeferredExecutor.js.map +1 -0
  171. package/build/module/hooks/useIsMounted.js +13 -0
  172. package/build/module/hooks/useIsMounted.js.map +1 -0
  173. package/build/module/hooks/useUnstableCollapsibleAppBar.js +1 -1
  174. package/build/module/hooks/useUnstableCollapsibleAppBar.js.map +1 -1
  175. package/build/module/index.js +2 -0
  176. package/build/module/index.js.map +1 -1
  177. package/build/typescript/Carousel/Carousel.d.ts +5 -0
  178. package/build/typescript/Carousel/CarouselProps.d.ts +33 -48
  179. package/build/typescript/Carousel/animation/animationUtils.d.ts +1 -0
  180. package/build/typescript/Carousel/animation/createDefaultItemStyle.d.ts +2 -0
  181. package/build/typescript/Carousel/animation/createDefaultScrollAnimation.d.ts +2 -0
  182. package/build/typescript/Carousel/animation/index.d.ts +4 -0
  183. package/build/typescript/Carousel/animation/normalItemStyleFactory.d.ts +2 -0
  184. package/build/typescript/Carousel/animation/parallaxItemStyleFactory.d.ts +9 -0
  185. package/build/typescript/Carousel/components/InternalContext.d.ts +14 -0
  186. package/build/typescript/Carousel/components/ItemView.d.ts +9 -0
  187. package/build/typescript/Carousel/components/RootView.d.ts +16 -0
  188. package/build/typescript/Carousel/components/ScrollViewGesture.d.ts +12 -0
  189. package/build/typescript/Carousel/components/index.d.ts +4 -0
  190. package/build/typescript/Carousel/hooks/index.d.ts +7 -0
  191. package/build/typescript/Carousel/hooks/useAutoplayController.d.ts +7 -0
  192. package/build/typescript/Carousel/hooks/useDimensionChangeReaction.d.ts +7 -0
  193. package/build/typescript/Carousel/hooks/useIndexController.d.ts +10 -0
  194. package/build/typescript/Carousel/hooks/useItemInterpolation.d.ts +2 -0
  195. package/build/typescript/Carousel/hooks/useItemVisibilityStore.d.ts +7 -0
  196. package/build/typescript/Carousel/hooks/useLoopedData.d.ts +1 -0
  197. package/build/typescript/Carousel/hooks/usePagingAnimation.d.ts +18 -0
  198. package/build/typescript/Carousel/index.d.ts +3 -1
  199. package/build/typescript/Carousel/types.d.ts +79 -0
  200. package/build/typescript/ViewPager/ChildrenMemoizedPage.d.ts +1 -1
  201. package/build/typescript/ViewPager/InternalContext.d.ts +7 -0
  202. package/build/typescript/ViewPager/PageStateContext.d.ts +7 -0
  203. package/build/typescript/ViewPager/ViewPagerNative.d.ts +2 -2
  204. package/build/typescript/ViewPager/ViewPagerProps.d.ts +13 -20
  205. package/build/typescript/ViewPager/ViewPagerWeb.d.ts +2 -2
  206. package/build/typescript/ViewPager/index.d.ts +3 -1
  207. package/build/typescript/ViewPager/index.native.d.ts +1 -0
  208. package/build/typescript/ViewPager/types.d.ts +19 -0
  209. package/build/typescript/ViewPager/usePageStore.d.ts +2 -0
  210. package/build/typescript/ViewPager/utils.d.ts +2 -1
  211. package/build/typescript/ViewabilityTrackerView/Viewability.d.ts +3 -0
  212. package/build/typescript/ViewabilityTrackerView/ViewabilityTrackerView.d.ts +2 -0
  213. package/build/typescript/ViewabilityTrackerView/ViewabilityTrackerViewProps.d.ts +22 -0
  214. package/build/typescript/ViewabilityTrackerView/index.d.ts +2 -0
  215. package/build/typescript/ViewabilityTrackerView/measureViewability.d.ts +11 -0
  216. package/build/typescript/ViewabilityTrackerView/useViewabilityTracker.d.ts +11 -0
  217. package/build/typescript/hooks/index.d.ts +2 -0
  218. package/build/typescript/hooks/useDeferredExecutor.d.ts +11 -0
  219. package/build/typescript/hooks/useIsMounted.d.ts +4 -0
  220. package/build/typescript/index.d.ts +2 -0
  221. package/package.json +4 -19
  222. package/src/Carousel/Carousel.tsx +152 -0
  223. package/src/Carousel/CarouselProps.ts +35 -53
  224. package/src/Carousel/animation/animationUtils.ts +1 -0
  225. package/src/Carousel/animation/createDefaultItemStyle.ts +3 -0
  226. package/src/Carousel/animation/createDefaultScrollAnimation.ts +13 -0
  227. package/src/Carousel/animation/index.ts +4 -0
  228. package/src/Carousel/animation/normalItemStyleFactory.ts +19 -0
  229. package/src/Carousel/animation/parallaxItemStyleFactory.ts +79 -0
  230. package/src/Carousel/components/InternalContext.ts +33 -0
  231. package/src/Carousel/components/ItemView.tsx +66 -0
  232. package/src/Carousel/components/RootView.tsx +79 -0
  233. package/src/Carousel/components/ScrollViewGesture.tsx +87 -0
  234. package/src/Carousel/components/index.ts +4 -0
  235. package/src/Carousel/hooks/index.ts +7 -0
  236. package/src/Carousel/hooks/useAutoplayController.ts +57 -0
  237. package/src/Carousel/hooks/useDimensionChangeReaction.ts +25 -0
  238. package/src/Carousel/hooks/useIndexController.tsx +76 -0
  239. package/src/Carousel/hooks/useItemInterpolation.ts +107 -0
  240. package/src/Carousel/hooks/useItemVisibilityStore.ts +107 -0
  241. package/src/Carousel/hooks/useLoopedData.ts +26 -0
  242. package/src/Carousel/hooks/usePagingAnimation.ts +195 -0
  243. package/src/Carousel/index.ts +4 -2
  244. package/src/Carousel/types.ts +97 -0
  245. package/src/ViewPager/ChildrenMemoizedPage.tsx +55 -54
  246. package/src/ViewPager/InternalContext.ts +13 -0
  247. package/src/ViewPager/PageStateContext.ts +15 -0
  248. package/src/ViewPager/ViewPagerNative.tsx +114 -43
  249. package/src/ViewPager/ViewPagerProps.ts +15 -25
  250. package/src/ViewPager/ViewPagerWeb.tsx +30 -21
  251. package/src/ViewPager/index.native.ts +1 -0
  252. package/src/ViewPager/index.ts +3 -1
  253. package/src/ViewPager/types.ts +24 -0
  254. package/src/ViewPager/usePageStore.ts +24 -0
  255. package/src/ViewPager/utils.tsx +3 -2
  256. package/src/ViewabilityTrackerView/Viewability.ts +3 -0
  257. package/src/ViewabilityTrackerView/ViewabilityTrackerView.tsx +33 -0
  258. package/src/ViewabilityTrackerView/ViewabilityTrackerViewProps.ts +25 -0
  259. package/src/ViewabilityTrackerView/index.ts +2 -0
  260. package/src/ViewabilityTrackerView/measureViewability.ts +56 -0
  261. package/src/ViewabilityTrackerView/useViewabilityTracker.ts +85 -0
  262. package/src/hooks/index.ts +2 -0
  263. package/src/hooks/useDeferredExecutor.ts +46 -0
  264. package/src/hooks/useIsMounted.ts +19 -0
  265. package/src/hooks/useUnstableCollapsibleAppBar.ts +1 -1
  266. package/src/index.ts +3 -0
  267. package/build/commonjs/Carousel/CarouselNative.js +0 -72
  268. package/build/commonjs/Carousel/CarouselNative.js.map +0 -1
  269. package/build/commonjs/Carousel/CarouselWeb.js +0 -237
  270. package/build/commonjs/Carousel/CarouselWeb.js.map +0 -1
  271. package/build/commonjs/Carousel/index.native.js.map +0 -1
  272. package/build/commonjs/Carousel/utils.js +0 -19
  273. package/build/commonjs/Carousel/utils.js.map +0 -1
  274. package/build/module/Carousel/CarouselNative.js +0 -54
  275. package/build/module/Carousel/CarouselNative.js.map +0 -1
  276. package/build/module/Carousel/CarouselWeb.js +0 -215
  277. package/build/module/Carousel/CarouselWeb.js.map +0 -1
  278. package/build/module/Carousel/index.native.js +0 -2
  279. package/build/module/Carousel/index.native.js.map +0 -1
  280. package/build/module/Carousel/utils.js +0 -7
  281. package/build/module/Carousel/utils.js.map +0 -1
  282. package/build/typescript/Carousel/CarouselNative.d.ts +0 -2
  283. package/build/typescript/Carousel/CarouselWeb.d.ts +0 -4
  284. package/build/typescript/Carousel/index.native.d.ts +0 -1
  285. package/build/typescript/Carousel/utils.d.ts +0 -6
  286. package/src/Carousel/CarouselNative.tsx +0 -67
  287. package/src/Carousel/CarouselWeb.tsx +0 -222
  288. package/src/Carousel/index.native.ts +0 -1
  289. package/src/Carousel/utils.ts +0 -11
@@ -1,98 +1,99 @@
1
- import React, { memo, useState } from 'react';
1
+ import React, { memo, useContext, useEffect, useMemo, useState } from 'react';
2
2
  import { Platform, View } from 'react-native';
3
- import { runOnJS, useAnimatedReaction } from 'react-native-reanimated';
4
3
  import { StyleSheet } from '@fountain-ui/core';
5
- import type { PageProps } from './ViewPagerProps';
6
-
7
- const OFFSCREEN_RERENDER_LIMIT = 1;
4
+ import type { PageProps } from './types';
5
+ import PageStateContext from './PageStateContext';
6
+ import InternalContext from './InternalContext';
8
7
 
9
8
  const styles = StyleSheet.create({
9
+ fill: { width: '100%', height: '100%' },
10
10
  none: { display: 'none' },
11
11
  });
12
12
 
13
- interface PageState {
14
- active: boolean;
15
- visited: boolean;
13
+ interface InternalPageState {
14
+ isActive: boolean;
15
+ isLoaded: boolean;
16
16
  }
17
17
 
18
18
  function Page(props: PageProps) {
19
19
  const {
20
20
  index,
21
+ initialPage,
21
22
  children,
22
23
  loading,
23
- sharedIndex,
24
+ offscreenPageRerenderLimit,
24
25
  } = props;
25
26
 
26
- const assumeInitialPageState = (): PageState => {
27
- const activeIndex = sharedIndex.value;
27
+ const { pageStore } = useContext(InternalContext);
28
28
 
29
- const active = index === activeIndex;
29
+ const assumeInitialPageState = (): InternalPageState => {
30
+ const activeIndex = initialPage;
30
31
 
31
- if (Platform.OS === 'web') {
32
- return { active, visited: active };
33
- }
32
+ const isActive = index === activeIndex;
34
33
 
35
34
  if (loading === 'eager') {
36
- return { active, visited: true };
35
+ return { isActive, isLoaded: true };
37
36
  }
38
37
 
39
- const visited = index >= activeIndex - OFFSCREEN_RERENDER_LIMIT
40
- && index <= activeIndex + OFFSCREEN_RERENDER_LIMIT;
38
+ const isLoaded = index >= activeIndex - offscreenPageRerenderLimit
39
+ && index <= activeIndex + offscreenPageRerenderLimit;
41
40
 
42
- return { active, visited };
41
+ return { isActive, isLoaded };
43
42
  };
44
43
 
45
- const [pageState, setPageState] = useState<PageState>(assumeInitialPageState);
44
+ const [pageState, setPageState] = useState<InternalPageState>(assumeInitialPageState);
46
45
 
47
- const content = pageState.visited ? children : null;
46
+ const content = pageState.isLoaded ? children : null;
48
47
 
49
- const updatePageState = (active: boolean, neighbor: boolean) => {
50
- setPageState(prevState => {
51
- if (prevState.active !== active) {
52
- return { active, visited: active || prevState.visited };
53
- }
48
+ useEffect(() => {
49
+ return pageStore.subscribe(newPage => {
50
+ const activeIndex = newPage;
54
51
 
55
- if (neighbor && !prevState.visited) {
56
- return { ...prevState, visited: true };
57
- }
52
+ const isActive = index === activeIndex;
58
53
 
59
- return prevState;
60
- });
61
- };
54
+ const shouldRerender = index >= activeIndex - offscreenPageRerenderLimit
55
+ && index <= activeIndex + offscreenPageRerenderLimit;
62
56
 
63
- useAnimatedReaction(
64
- () => {
65
- const activeIndex = sharedIndex.value;
57
+ const becomeNeighbor = shouldRerender && !isActive;
66
58
 
67
- const willVisible = index >= activeIndex - OFFSCREEN_RERENDER_LIMIT
68
- && index <= activeIndex + OFFSCREEN_RERENDER_LIMIT;
59
+ setPageState(prevState => {
60
+ if (prevState.isActive !== isActive) {
61
+ return {
62
+ ...prevState,
63
+ isActive,
64
+ isLoaded: isActive || prevState.isLoaded,
65
+ };
66
+ }
69
67
 
70
- const willActive = index === activeIndex;
71
- const willNeighbor = Platform.OS === 'web' ? false : (willVisible && !willActive);
68
+ if (becomeNeighbor && !prevState.isLoaded) {
69
+ return {
70
+ ...prevState,
71
+ isLoaded: true,
72
+ };
73
+ }
72
74
 
73
- return { willActive, willNeighbor };
74
- },
75
- (nextState, prevState) => {
76
- const activeStateChanged = nextState.willActive !== prevState?.willActive;
77
- const willNewNeighbor = nextState.willNeighbor && !prevState?.willNeighbor;
75
+ return prevState;
76
+ });
77
+ });
78
+ }, [pageStore, index]);
78
79
 
79
- if (activeStateChanged || willNewNeighbor) {
80
- runOnJS(updatePageState)(nextState.willActive, nextState.willNeighbor);
81
- }
82
- },
83
- [index],
84
- );
80
+ const contextValue = useMemo(() => ({
81
+ isActive: pageState.isActive,
82
+ }), [pageState.isActive]);
85
83
 
86
84
  const style = Platform.OS === 'web'
87
- ? (pageState.active ? StyleSheet.absoluteFill : styles.none)
88
- : undefined;
85
+ ? (pageState.isActive ? StyleSheet.absoluteFill : styles.none)
86
+ : styles.fill;
89
87
 
90
88
  return (
91
89
  <View
92
- children={content}
93
90
  collapsable={false}
94
91
  style={style}
95
- />
92
+ >
93
+ <PageStateContext.Provider value={contextValue}>
94
+ {content}
95
+ </PageStateContext.Provider>
96
+ </View>
96
97
  );
97
98
  }
98
99
 
@@ -0,0 +1,13 @@
1
+ import { createContext } from 'react';
2
+ import type { MonoStore } from '@fountain-ui/core';
3
+ import { MockStore } from '@fountain-ui/core';
4
+
5
+ export interface InternalContextValue {
6
+ pageStore: MonoStore<number>;
7
+ }
8
+
9
+ const InternalContext = createContext<InternalContextValue>({
10
+ pageStore: new MockStore(),
11
+ });
12
+
13
+ export default InternalContext;
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ interface PageState {
4
+ isActive: boolean;
5
+ }
6
+
7
+ const initialPageState: Readonly<PageState> = { isActive: false };
8
+
9
+ const PageStateContext = createContext<PageState>(initialPageState);
10
+
11
+ export const useViewPagerPageState = () => {
12
+ return useContext(PageStateContext);
13
+ };
14
+
15
+ export default PageStateContext;
@@ -1,10 +1,12 @@
1
- import React, { Children, forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
1
+ import React, { Children, forwardRef, useCallback, useEffect, useImperativeHandle, useRef } from 'react';
2
2
  import type { ViewPagerOnPageSelectedEvent } from 'react-native-pager-view';
3
3
  import RNViewPager from 'react-native-pager-view';
4
- import { useSharedValue } from 'react-native-reanimated';
4
+ import { useSyncAnimatedValue } from '@fountain-ui/core';
5
5
  import type ViewPagerProps from './ViewPagerProps';
6
- import type { ViewPagerInstance } from './ViewPagerProps';
7
- import { defaultInitialPage, defaultLoading, defaultPageComponent } from './utils';
6
+ import type { ViewPagerInstance } from './types';
7
+ import { defaultInitialPage, defaultLoading, defaultOffscreenPageRerenderLimit, defaultPageComponent } from './utils';
8
+ import usePageStore from './usePageStore';
9
+ import InternalContext from './InternalContext';
8
10
 
9
11
  const ViewPager = forwardRef<ViewPagerInstance, ViewPagerProps>(function ViewPager(props, ref) {
10
12
  const {
@@ -12,66 +14,135 @@ const ViewPager = forwardRef<ViewPagerInstance, ViewPagerProps>(function ViewPag
12
14
  initialPage = defaultInitialPage,
13
15
  keyboardDismissMode = 'on-drag',
14
16
  loading = defaultLoading,
17
+ offscreenPageRerenderLimit = defaultOffscreenPageRerenderLimit,
15
18
  onChange,
16
19
  pageComponent = defaultPageComponent,
17
20
  pageForceRerenderKey,
18
21
  scrollEnabled = true,
19
22
  style,
23
+ UNSTABLE_sharedPage,
20
24
  } = props;
21
25
 
22
- const sharedIndex = useSharedValue<number>(initialPage);
26
+ const fallbackSharedPage = useSyncAnimatedValue({ initialValue: initialPage });
27
+
28
+ const sharedPage = UNSTABLE_sharedPage ?? fallbackSharedPage;
29
+
30
+ const pageRef = useRef<number>(sharedPage.initialValue);
31
+
32
+ const desiredPageRef = useRef<number>(NaN);
33
+
23
34
  const pagerRef = useRef<RNViewPager | null>(null);
24
35
 
25
- const setPage = (newIndex: number) => {
26
- requestAnimationFrame(() => {
27
- pagerRef.current?.setPage(newIndex);
36
+ const animationFrameRef = useRef<number>(NaN);
37
+
38
+ const setPage = useCallback((newPage: number) => {
39
+ if (!Number.isInteger(newPage)) {
40
+ return;
41
+ }
42
+
43
+ animationFrameRef.current = requestAnimationFrame(() => {
44
+ if (Number.isFinite(desiredPageRef.current)) {
45
+ if (pageRef.current === desiredPageRef.current) {
46
+ // end of state machine. clear desired page.
47
+ desiredPageRef.current = NaN;
48
+ return;
49
+ }
50
+
51
+ if (newPage === desiredPageRef.current) {
52
+ return;
53
+ }
54
+ }
55
+
56
+ desiredPageRef.current = newPage;
57
+ pagerRef.current?.setPage(newPage);
28
58
  });
29
- };
59
+ }, []);
30
60
 
31
- useImperativeHandle(
32
- ref,
33
- () => ({ setPage }),
34
- [],
35
- );
61
+ useEffect(() => {
62
+ return () => {
63
+ if (animationFrameRef.current) {
64
+ cancelAnimationFrame(animationFrameRef.current);
65
+ }
66
+ };
67
+ }, []);
68
+
69
+ useEffect(() => {
70
+ const animatedValue = sharedPage.animatedValue;
71
+ const id = animatedValue.addListener(newValue => {
72
+ const newPage = newValue.value;
73
+ pageRef.current = newPage;
74
+ setPage(newPage);
75
+ });
76
+
77
+ return () => {
78
+ animatedValue.removeListener(id);
79
+ };
80
+ }, [sharedPage]);
36
81
 
37
82
  const handlePageSelected = useCallback((e: ViewPagerOnPageSelectedEvent) => {
38
- const currentIndex = sharedIndex.value;
39
- const nextIndex = e.nativeEvent.position;
83
+ if (Number.isFinite(desiredPageRef.current)) {
84
+ // onPageSelected is called from outer controlling mechanism
85
+ // e.g. sharedPage.value is changed, setPage() is called
86
+ // Due to the onPageSelected bug,
87
+ // we don't trust the value from event, (e.nativeEvent.position)
88
+ // other than that trust the value from desiredPageRef.
40
89
 
41
- if (currentIndex === nextIndex) {
42
- return;
43
- }
90
+ const desiredPage = desiredPageRef.current;
91
+
92
+ if (pageRef.current === desiredPage) {
93
+ // end of state machine. clear desired page.
94
+ desiredPageRef.current = NaN;
95
+ } else {
96
+ sharedPage.animatedValue.setValue(desiredPage);
97
+ }
98
+
99
+ onChange?.(desiredPage);
100
+ } else {
101
+ const trustfulNextPage = e.nativeEvent.position;
44
102
 
45
- sharedIndex.value = nextIndex;
103
+ if (trustfulNextPage !== pageRef.current) {
104
+ desiredPageRef.current = trustfulNextPage;
105
+ sharedPage.animatedValue.setValue(trustfulNextPage);
106
+ }
46
107
 
47
- if (onChange) {
48
- onChange(nextIndex);
108
+ onChange?.(trustfulNextPage);
49
109
  }
50
- }, [onChange]);
110
+ }, [onChange, sharedPage]);
111
+
112
+ useImperativeHandle(
113
+ ref,
114
+ () => ({ setPage }),
115
+ [setPage],
116
+ );
117
+
118
+ const pageStore = usePageStore(sharedPage);
51
119
 
52
120
  const PageComponent = pageComponent;
53
121
 
54
122
  return (
55
- <RNViewPager
56
- ref={pagerRef}
57
- initialPage={initialPage}
58
- keyboardDismissMode={keyboardDismissMode}
59
- onPageSelected={handlePageSelected}
60
- pageMargin={8}
61
- scrollEnabled={scrollEnabled}
62
- style={style}
63
- >
64
- {Children.map(children, (child, index) => (
65
- <PageComponent
66
- key={index}
67
- children={child}
68
- index={index}
69
- loading={loading}
70
- rerenderKey={pageForceRerenderKey}
71
- sharedIndex={sharedIndex}
72
- />
73
- ))}
74
- </RNViewPager>
123
+ <InternalContext.Provider value={{ pageStore }}>
124
+ <RNViewPager
125
+ ref={pagerRef}
126
+ initialPage={sharedPage.initialValue}
127
+ keyboardDismissMode={keyboardDismissMode}
128
+ onPageSelected={handlePageSelected}
129
+ pageMargin={8}
130
+ scrollEnabled={scrollEnabled}
131
+ style={style}
132
+ >
133
+ {Children.map(children, (child, index) => (
134
+ <PageComponent
135
+ key={index}
136
+ children={child}
137
+ index={index}
138
+ initialPage={sharedPage.initialValue}
139
+ loading={loading}
140
+ offscreenPageRerenderLimit={offscreenPageRerenderLimit}
141
+ rerenderKey={pageForceRerenderKey}
142
+ />
143
+ ))}
144
+ </RNViewPager>
145
+ </InternalContext.Provider>
75
146
  );
76
147
  });
77
148
 
@@ -1,28 +1,6 @@
1
- import type { ComponentType, PropsWithChildren, ReactNode, Ref } from 'react';
2
- import type { ViewProps } from 'react-native';
3
- import type { SharedValue } from 'react-native-reanimated';
4
- import type { ComponentProps } from '@fountain-ui/core';
5
-
6
- export type KeyboardDismissMode = 'none' | 'on-drag';
7
-
8
- export type PageProps = PropsWithChildren<ViewProps> & {
9
- index: number;
10
- loading: ViewPagerProps['loading'];
11
- sharedIndex: SharedValue<number>;
12
- rerenderKey?: ViewPagerProps['pageForceRerenderKey'];
13
- };
14
-
15
- export type PageComponent = ComponentType<PageProps>;
16
-
17
- export type Loading = 'lazy' | 'eager';
18
-
19
- export interface ViewPagerInstance {
20
- /**
21
- * Function to scroll to a specific page in the ViewPager. Invalid index is ignored.
22
- * @param index
23
- */
24
- setPage: (index: number) => void;
25
- }
1
+ import type { ReactNode, Ref } from 'react';
2
+ import type { ComponentProps, SyncAnimatedValue } from '@fountain-ui/core';
3
+ import type { KeyboardDismissMode, Loading, PageComponent, ViewPagerInstance } from './types';
26
4
 
27
5
  export default interface ViewPagerProps extends ComponentProps<{
28
6
  ref?: Ref<ViewPagerInstance>;
@@ -44,6 +22,13 @@ export default interface ViewPagerProps extends ComponentProps<{
44
22
  */
45
23
  loading?: Loading;
46
24
 
25
+ /**
26
+ * Mobile only. The number of pages that should be re-rendered to either side of the current page.
27
+ * Changing this value after the component mount has no effect.
28
+ * @default 0
29
+ */
30
+ offscreenPageRerenderLimit?: number;
31
+
47
32
  /**
48
33
  * Callback fired when an index is changed.
49
34
  */
@@ -71,4 +56,9 @@ export default interface ViewPagerProps extends ComponentProps<{
71
56
  * @default 'on-drag'
72
57
  */
73
58
  keyboardDismissMode?: KeyboardDismissMode;
59
+
60
+ /**
61
+ * Unstable API.
62
+ */
63
+ UNSTABLE_sharedPage?: SyncAnimatedValue;
74
64
  }> {}
@@ -1,10 +1,11 @@
1
- import React, { Children, forwardRef, useImperativeHandle } from 'react';
1
+ import React, { Children, forwardRef, useCallback, useImperativeHandle } from 'react';
2
2
  import { View } from 'react-native';
3
- import { useSharedValue } from 'react-native-reanimated';
4
- import { StyleSheet } from '@fountain-ui/core';
3
+ import { StyleSheet, useSyncAnimatedValue } from '@fountain-ui/core';
5
4
  import type ViewPagerProps from './ViewPagerProps';
6
- import type { ViewPagerInstance } from './ViewPagerProps';
5
+ import type { ViewPagerInstance } from './types';
7
6
  import { defaultInitialPage, defaultLoading, defaultPageComponent } from './utils';
7
+ import usePageStore from './usePageStore';
8
+ import InternalContext from './InternalContext';
8
9
 
9
10
  const styles = StyleSheet.create({
10
11
  root: {
@@ -22,35 +23,43 @@ const ViewPager = forwardRef<ViewPagerInstance, ViewPagerProps>(function ViewPag
22
23
  pageComponent = defaultPageComponent,
23
24
  pageForceRerenderKey,
24
25
  style,
26
+ UNSTABLE_sharedPage,
25
27
  } = props;
26
28
 
27
- const sharedIndex = useSharedValue<number>(initialPage);
29
+ const fallbackSharedPage = useSyncAnimatedValue({ initialValue: initialPage });
28
30
 
29
- const setPage = (newIndex: number) => {
30
- sharedIndex.value = newIndex;
31
- };
31
+ const sharedPage = UNSTABLE_sharedPage ?? fallbackSharedPage;
32
+
33
+ const setPage = useCallback((newPage: number) => {
34
+ sharedPage.animatedValue.setValue(newPage);
35
+ }, [sharedPage]);
32
36
 
33
37
  useImperativeHandle(
34
38
  ref,
35
39
  () => ({ setPage }),
36
- [],
40
+ [setPage],
37
41
  );
38
42
 
43
+ const pageStore = usePageStore(sharedPage);
44
+
39
45
  const PageComponent = pageComponent;
40
46
 
41
47
  return (
42
- <View style={[styles.root, style]}>
43
- {Children.map(children, (child, index) => (
44
- <PageComponent
45
- key={index}
46
- children={child}
47
- index={index}
48
- loading={loading}
49
- rerenderKey={pageForceRerenderKey}
50
- sharedIndex={sharedIndex}
51
- />
52
- ))}
53
- </View>
48
+ <InternalContext.Provider value={{ pageStore }}>
49
+ <View style={[styles.root, style]}>
50
+ {Children.map(children, (child, index) => (
51
+ <PageComponent
52
+ key={index}
53
+ children={child}
54
+ index={index}
55
+ initialPage={sharedPage.initialValue}
56
+ loading={loading}
57
+ offscreenPageRerenderLimit={0} // All offscreen pages will not be re-rendered
58
+ rerenderKey={pageForceRerenderKey}
59
+ />
60
+ ))}
61
+ </View>
62
+ </InternalContext.Provider>
54
63
  );
55
64
  });
56
65
 
@@ -1 +1,2 @@
1
1
  export { default } from './ViewPagerNative';
2
+ export { useViewPagerPageState } from './PageStateContext';
@@ -1,2 +1,4 @@
1
1
  export { default } from './ViewPagerWeb';
2
- export type { default as ViewPagerProps, ViewPagerInstance } from './ViewPagerProps';
2
+ export type { default as ViewPagerProps } from './ViewPagerProps';
3
+ export type { ViewPagerInstance } from './types';
4
+ export { useViewPagerPageState } from './PageStateContext';
@@ -0,0 +1,24 @@
1
+ import type { ComponentType, PropsWithChildren } from 'react';
2
+ import type { ViewProps } from 'react-native';
3
+
4
+ export type PageProps = PropsWithChildren<ViewProps> & {
5
+ index: number;
6
+ initialPage: number;
7
+ loading: Loading;
8
+ offscreenPageRerenderLimit: number;
9
+ rerenderKey?: any;
10
+ };
11
+
12
+ export type KeyboardDismissMode = 'none' | 'on-drag';
13
+
14
+ export type PageComponent = ComponentType<PageProps>;
15
+
16
+ export type Loading = 'lazy' | 'eager';
17
+
18
+ export interface ViewPagerInstance {
19
+ /**
20
+ * Function to scroll to a specific page in the ViewPager. Invalid index is ignored.
21
+ * @param index
22
+ */
23
+ setPage: (index: number) => void;
24
+ }
@@ -0,0 +1,24 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import type { MonoStore, SyncAnimatedValue } from '@fountain-ui/core';
3
+ import { SimpleStore } from '@fountain-ui/core';
4
+
5
+ export default function usePageStore(value: SyncAnimatedValue): MonoStore<number> {
6
+ const {
7
+ animatedValue,
8
+ initialValue,
9
+ } = value;
10
+
11
+ const store = useRef(new SimpleStore(initialValue)).current;
12
+
13
+ useEffect(() => {
14
+ const id = animatedValue.addListener((newPage) => {
15
+ store.dispatch(newPage.value);
16
+ });
17
+
18
+ return () => {
19
+ animatedValue.removeListener(id);
20
+ };
21
+ }, [animatedValue]);
22
+
23
+ return store;
24
+ };
@@ -1,9 +1,10 @@
1
- import React from 'react';
2
- import { Loading, PageComponent } from './ViewPagerProps';
3
1
  import ChildrenMemoizedPage from './ChildrenMemoizedPage';
2
+ import type { Loading, PageComponent } from './types';
4
3
 
5
4
  export const defaultInitialPage: number = 0;
6
5
 
7
6
  export const defaultLoading: Loading = 'lazy';
8
7
 
8
+ export const defaultOffscreenPageRerenderLimit: number = 0;
9
+
9
10
  export const defaultPageComponent: PageComponent = ChildrenMemoizedPage;
@@ -0,0 +1,3 @@
1
+ export default interface Viewability {
2
+ visible: boolean;
3
+ }
@@ -0,0 +1,33 @@
1
+ import React, { useRef } from 'react';
2
+ import { View } from 'react-native';
3
+ import useViewabilityTracker from './useViewabilityTracker';
4
+ import type ViewabilityTrackerViewProps from './ViewabilityTrackerViewProps';
5
+
6
+
7
+ export default function ViewabilityTrackerView(props: ViewabilityTrackerViewProps) {
8
+ const {
9
+ enabled = true,
10
+ measurementIntervalMillis = 1000,
11
+ onViewabilityChange,
12
+ visiblePercentThreshold = 50,
13
+ ...otherProps
14
+ } = props;
15
+
16
+ const viewRef = useRef<View>(null);
17
+
18
+ useViewabilityTracker({
19
+ enabled,
20
+ measurementIntervalMillis,
21
+ onViewabilityChange,
22
+ viewRef,
23
+ visiblePercentThreshold,
24
+ });
25
+
26
+ return (
27
+ <View
28
+ {...otherProps}
29
+ ref={viewRef}
30
+ collapsable={false}
31
+ />
32
+ );
33
+ };
@@ -0,0 +1,25 @@
1
+ import type { ViewProps } from 'react-native';
2
+ import type { OverridableComponentProps } from '@fountain-ui/core';
3
+ import type Viewability from './Viewability';
4
+
5
+ export default interface ViewabilityTrackerViewProps extends OverridableComponentProps<ViewProps, {
6
+ /**
7
+ * @default true
8
+ */
9
+ enabled?: boolean;
10
+
11
+ /**
12
+ * @default 1000
13
+ */
14
+ measurementIntervalMillis?: number;
15
+
16
+ /**
17
+ *
18
+ */
19
+ onViewabilityChange?: (viewability: Viewability) => void;
20
+
21
+ /**
22
+ * @default 50
23
+ */
24
+ visiblePercentThreshold?: number;
25
+ }> {}
@@ -0,0 +1,2 @@
1
+ export { default } from './ViewabilityTrackerView';
2
+ export type { default as ViewabilityTrackerViewProps } from './ViewabilityTrackerViewProps';