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

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 (101) hide show
  1. package/build/commonjs/Carousel/Carousel.js +24 -29
  2. package/build/commonjs/Carousel/Carousel.js.map +1 -1
  3. package/build/commonjs/Carousel/CarouselProps.js.map +1 -1
  4. package/build/commonjs/Carousel/animation/createDefaultScrollAnimation.js +2 -2
  5. package/build/commonjs/Carousel/animation/createDefaultScrollAnimation.js.map +1 -1
  6. package/build/commonjs/Carousel/animation/parallaxItemStyleFactory.js +2 -2
  7. package/build/commonjs/Carousel/animation/parallaxItemStyleFactory.js.map +1 -1
  8. package/build/commonjs/Carousel/components/ItemView.js +4 -4
  9. package/build/commonjs/Carousel/components/ItemView.js.map +1 -1
  10. package/build/commonjs/Carousel/components/ScrollViewGesture.js +6 -6
  11. package/build/commonjs/Carousel/components/ScrollViewGesture.js.map +1 -1
  12. package/build/commonjs/Carousel/{hooks → components}/useItemInterpolation.js +6 -4
  13. package/build/commonjs/Carousel/components/useItemInterpolation.js.map +1 -0
  14. package/build/commonjs/Carousel/hooks/index.js +0 -16
  15. package/build/commonjs/Carousel/hooks/index.js.map +1 -1
  16. package/build/commonjs/Carousel/hooks/useIndexController.js +28 -44
  17. package/build/commonjs/Carousel/hooks/useIndexController.js.map +1 -1
  18. package/build/commonjs/Carousel/hooks/useItemVisibilityStore.js +12 -12
  19. package/build/commonjs/Carousel/hooks/useItemVisibilityStore.js.map +1 -1
  20. package/build/commonjs/Carousel/hooks/usePagingAnimation.js +72 -56
  21. package/build/commonjs/Carousel/hooks/usePagingAnimation.js.map +1 -1
  22. package/build/commonjs/Carousel/tick.js +16 -0
  23. package/build/commonjs/Carousel/tick.js.map +1 -0
  24. package/build/commonjs/Carousel/types.js +1 -0
  25. package/build/commonjs/Carousel/types.js.map +1 -1
  26. package/build/commonjs/ViewPager/ChildrenMemoizedPage.js +44 -35
  27. package/build/commonjs/ViewPager/ChildrenMemoizedPage.js.map +1 -1
  28. package/build/commonjs/ViewPager/ViewPagerNative.js +2 -3
  29. package/build/commonjs/ViewPager/ViewPagerNative.js.map +1 -1
  30. package/build/commonjs/ViewPager/usePageStore.js +5 -0
  31. package/build/commonjs/ViewPager/usePageStore.js.map +1 -1
  32. package/build/commonjs/ViewabilityTrackerView/measureViewability.js +6 -6
  33. package/build/commonjs/ViewabilityTrackerView/measureViewability.js.map +1 -1
  34. package/build/module/Carousel/Carousel.js +23 -30
  35. package/build/module/Carousel/Carousel.js.map +1 -1
  36. package/build/module/Carousel/CarouselProps.js.map +1 -1
  37. package/build/module/Carousel/animation/createDefaultScrollAnimation.js +2 -2
  38. package/build/module/Carousel/animation/createDefaultScrollAnimation.js.map +1 -1
  39. package/build/module/Carousel/animation/parallaxItemStyleFactory.js +2 -2
  40. package/build/module/Carousel/animation/parallaxItemStyleFactory.js.map +1 -1
  41. package/build/module/Carousel/components/ItemView.js +3 -3
  42. package/build/module/Carousel/components/ItemView.js.map +1 -1
  43. package/build/module/Carousel/components/ScrollViewGesture.js +6 -6
  44. package/build/module/Carousel/components/ScrollViewGesture.js.map +1 -1
  45. package/build/module/Carousel/{hooks → components}/useItemInterpolation.js +3 -3
  46. package/build/module/Carousel/components/useItemInterpolation.js.map +1 -0
  47. package/build/module/Carousel/hooks/index.js +0 -2
  48. package/build/module/Carousel/hooks/index.js.map +1 -1
  49. package/build/module/Carousel/hooks/useIndexController.js +29 -40
  50. package/build/module/Carousel/hooks/useIndexController.js.map +1 -1
  51. package/build/module/Carousel/hooks/useItemVisibilityStore.js +10 -11
  52. package/build/module/Carousel/hooks/useItemVisibilityStore.js.map +1 -1
  53. package/build/module/Carousel/hooks/usePagingAnimation.js +73 -56
  54. package/build/module/Carousel/hooks/usePagingAnimation.js.map +1 -1
  55. package/build/module/Carousel/tick.js +6 -0
  56. package/build/module/Carousel/tick.js.map +1 -0
  57. package/build/module/Carousel/types.js +1 -0
  58. package/build/module/Carousel/types.js.map +1 -1
  59. package/build/module/ViewPager/ChildrenMemoizedPage.js +44 -35
  60. package/build/module/ViewPager/ChildrenMemoizedPage.js.map +1 -1
  61. package/build/module/ViewPager/ViewPagerNative.js +2 -3
  62. package/build/module/ViewPager/ViewPagerNative.js.map +1 -1
  63. package/build/module/ViewPager/usePageStore.js +5 -0
  64. package/build/module/ViewPager/usePageStore.js.map +1 -1
  65. package/build/module/ViewabilityTrackerView/measureViewability.js +2 -2
  66. package/build/module/ViewabilityTrackerView/measureViewability.js.map +1 -1
  67. package/build/typescript/Carousel/CarouselProps.d.ts +2 -2
  68. package/build/typescript/Carousel/components/ScrollViewGesture.d.ts +2 -2
  69. package/build/typescript/Carousel/{hooks → components}/useItemInterpolation.d.ts +0 -0
  70. package/build/typescript/Carousel/hooks/index.d.ts +0 -2
  71. package/build/typescript/Carousel/hooks/useIndexController.d.ts +3 -3
  72. package/build/typescript/Carousel/hooks/useItemVisibilityStore.d.ts +3 -3
  73. package/build/typescript/Carousel/hooks/usePagingAnimation.d.ts +5 -7
  74. package/build/typescript/Carousel/tick.d.ts +2 -0
  75. package/build/typescript/Carousel/types.d.ts +10 -2
  76. package/package.json +3 -3
  77. package/src/Carousel/Carousel.tsx +19 -31
  78. package/src/Carousel/CarouselProps.ts +9 -2
  79. package/src/Carousel/animation/createDefaultScrollAnimation.ts +2 -2
  80. package/src/Carousel/animation/parallaxItemStyleFactory.ts +1 -1
  81. package/src/Carousel/components/ItemView.tsx +3 -3
  82. package/src/Carousel/components/ScrollViewGesture.tsx +8 -7
  83. package/src/Carousel/{hooks → components}/useItemInterpolation.ts +3 -3
  84. package/src/Carousel/hooks/index.ts +0 -2
  85. package/src/Carousel/hooks/useIndexController.tsx +36 -47
  86. package/src/Carousel/hooks/useItemVisibilityStore.ts +14 -14
  87. package/src/Carousel/hooks/usePagingAnimation.ts +104 -64
  88. package/src/Carousel/tick.ts +6 -0
  89. package/src/Carousel/types.ts +14 -2
  90. package/src/ViewPager/ChildrenMemoizedPage.tsx +46 -39
  91. package/src/ViewPager/ViewPagerNative.tsx +3 -3
  92. package/src/ViewPager/usePageStore.ts +6 -0
  93. package/src/ViewabilityTrackerView/measureViewability.ts +1 -3
  94. package/build/commonjs/Carousel/hooks/useDimensionChangeReaction.js +0 -23
  95. package/build/commonjs/Carousel/hooks/useDimensionChangeReaction.js.map +0 -1
  96. package/build/commonjs/Carousel/hooks/useItemInterpolation.js.map +0 -1
  97. package/build/module/Carousel/hooks/useDimensionChangeReaction.js +0 -14
  98. package/build/module/Carousel/hooks/useDimensionChangeReaction.js.map +0 -1
  99. package/build/module/Carousel/hooks/useItemInterpolation.js.map +0 -1
  100. package/build/typescript/Carousel/hooks/useDimensionChangeReaction.d.ts +0 -7
  101. package/src/Carousel/hooks/useDimensionChangeReaction.ts +0 -25
@@ -1,9 +1,9 @@
1
- import { useCallback, useEffect, useMemo, useRef } from 'react';
2
- import { Animated, Platform } from 'react-native';
1
+ import { useCallback, useRef } from 'react';
2
+ import { Animated } from 'react-native';
3
3
  import type {
4
4
  CreateScrollAnimation,
5
5
  DirectionalPagingAnimationConfig,
6
- GetCurrentIndex,
6
+ IndexController,
7
7
  IndexPagingAnimationConfig,
8
8
  PagingAnimationConfig,
9
9
  PagingAnimationType,
@@ -12,19 +12,17 @@ import type {
12
12
  } from '../types';
13
13
 
14
14
  export interface PagingAnimationParameters {
15
- controlledTx: Animated.Value;
16
15
  createScrollAnimation: CreateScrollAnimation;
17
- getCurrentIndex: GetCurrentIndex;
18
16
  itemWidth: number;
19
- lastIndex: number;
17
+ indexController: IndexController;
20
18
  loop: boolean;
21
19
  numberOfData: number;
22
- offsetTx: Animated.Value;
20
+ offsetX: Animated.Value;
21
+ translateX: Animated.Value;
23
22
  }
24
23
 
25
24
  export interface UsePagingAnimation {
26
- finalizeAnimation: () => void;
27
- globalInterpolation: Animated.AnimatedInterpolation;
25
+ interruptAnimation: () => void;
28
26
  startPagingAnimation: StartPagingAnimation;
29
27
  }
30
28
 
@@ -41,77 +39,110 @@ function directionToValue(itemWidth: number) {
41
39
  };
42
40
  }
43
41
 
42
+ function toValueCompensator(itemWidth: number) {
43
+ return function (toValue: number, currentOffset: number): number {
44
+ const remainder = Math.abs(currentOffset % itemWidth);
45
+
46
+ const halfOfItemWidth = Math.abs(itemWidth / 2);
47
+ const compensateVector = remainder > halfOfItemWidth
48
+ ? remainder - itemWidth
49
+ : remainder;
50
+
51
+ const direction = currentOffset > 0 ? -1 : 1;
52
+
53
+ return toValue + (direction * compensateVector);
54
+ };
55
+ }
56
+
44
57
  export default function usePagingAnimation(params: PagingAnimationParameters): UsePagingAnimation {
45
58
  const {
46
- controlledTx,
47
59
  createScrollAnimation,
48
- getCurrentIndex,
49
60
  itemWidth,
50
- lastIndex,
61
+ indexController,
51
62
  loop,
52
63
  numberOfData,
53
- offsetTx,
64
+ offsetX,
65
+ translateX,
54
66
  } = params;
55
67
 
56
- const animationRef = useRef<Animated.CompositeAnimation | null>(null);
57
- const toValueRef = useRef<number>(0);
68
+ const {
69
+ getCurrentIndex,
70
+ lastIndex,
71
+ notifyAnimationState,
72
+ notifyOffsetHasChanged,
73
+ } = indexController;
58
74
 
59
- const globalInterpolation = useMemo(
60
- () => Animated.add(controlledTx, offsetTx),
61
- [controlledTx, offsetTx],
62
- );
75
+ const toValueRef = useRef<number>(0);
76
+ const currentOffsetRef = useRef<number>(0);
63
77
 
64
- useEffect(() => {
65
- const subscriptionId = controlledTx.addListener((value) => {
66
- const currentTx = value.value;
78
+ const isAnimatingRef = useRef<boolean>(false);
67
79
 
68
- // Prevent infinite loop
69
- if (currentTx !== 0) {
70
- const maxWidth = numberOfData * itemWidth;
80
+ const maxWidth = Math.abs(numberOfData * itemWidth);
71
81
 
72
- if (Math.abs(Math.round(currentTx)) === Math.round(maxWidth)) {
73
- // reset position
74
- controlledTx.setValue(0);
75
- }
82
+ const ensureOffsetBoundary: (offset: number) => number = useCallback((offset: number) => {
83
+ if (loop) {
84
+ const isCloseToEnd = Math.abs(offset) >= (maxWidth - itemWidth);
85
+ if (isCloseToEnd) {
86
+ const signOfOffset = offset > 0 ? 1 : -1;
87
+ return offset + (-signOfOffset * maxWidth);
76
88
  }
77
- });
89
+ }
78
90
 
79
- return () => {
80
- controlledTx.removeListener(subscriptionId);
81
- };
82
- }, [numberOfData, itemWidth]);
91
+ return offset % maxWidth;
92
+ }, [itemWidth, loop, maxWidth]);
83
93
 
84
- const finalizeAnimation = useCallback(() => {
85
- const stopUnfinishedSnapAnimation = () => {
86
- if (animationRef.current) {
87
- animationRef.current?.stop();
88
- animationRef.current = null;
89
- }
90
- };
94
+ const requireNewOffset = useCallback((newOffset: number) => {
95
+ const nextOffset = ensureOffsetBoundary(newOffset);
91
96
 
92
- const resetBoundary = () => {
93
- controlledTx.setOffset(toValueRef.current);
94
- controlledTx.flattenOffset();
95
-
96
- // FIXME: react-native-web bug maybe?
97
- // `AnimatedValue.flattenOffset()` does not trigger any event listener.
98
- // Accessing value directly via `_value` is dangerous but working on web (`useNativeDriver` always false).
99
- // So setting same value with `value.setValue(value._value)` will trigger event listener.
100
- if (Platform.OS === 'web') {
101
- // @ts-ignore
102
- controlledTx.setValue(controlledTx._value);
103
- }
97
+ currentOffsetRef.current = nextOffset;
98
+ offsetX.setValue(nextOffset);
104
99
 
105
- offsetTx.setValue(0);
106
- toValueRef.current = 0;
107
- };
100
+ toValueRef.current = 0;
101
+ translateX.setValue(0);
102
+ }, [
103
+ ensureOffsetBoundary,
104
+ offsetX,
105
+ translateX,
106
+ ]);
107
+
108
+ const interruptAnimation = useCallback(() => {
109
+ if (!isAnimatingRef.current) {
110
+ return;
111
+ }
112
+
113
+ translateX.stopAnimation(lastValue => {
114
+ isAnimatingRef.current = false;
115
+
116
+ const prevOffset = currentOffsetRef.current;
117
+ const totalOffset = prevOffset + lastValue;
118
+
119
+ notifyOffsetHasChanged(totalOffset);
120
+ notifyAnimationState('interrupted');
121
+
122
+ requireNewOffset(totalOffset);
123
+ });
124
+ }, [requireNewOffset, translateX]);
125
+
126
+ const finalizeAnimation = useCallback(() => {
127
+ notifyAnimationState('finished');
108
128
 
109
- stopUnfinishedSnapAnimation();
129
+ isAnimatingRef.current = false;
110
130
 
111
- resetBoundary();
112
- }, [controlledTx]);
131
+ const prevOffset = currentOffsetRef.current;
132
+ const toValue = toValueRef.current;
133
+ const totalOffset = prevOffset + toValue;
134
+
135
+ requireNewOffset(totalOffset);
136
+ }, [
137
+ notifyAnimationState,
138
+ requireNewOffset,
139
+ ]);
113
140
 
114
141
  const startPagingAnimation = useCallback((type: PagingAnimationType, config: PagingAnimationConfig) => {
142
+ if (isAnimatingRef.current) {
143
+ return;
144
+ }
145
+
115
146
  const configWithDefaults: PagingAnimationConfig = {
116
147
  animated: true,
117
148
  ...config,
@@ -120,6 +151,7 @@ export default function usePagingAnimation(params: PagingAnimationParameters): U
120
151
  const currentIndex = getCurrentIndex();
121
152
 
122
153
  const getValueByDirectionOnAllAdjacentItemsVisible = directionToValue(itemWidth);
154
+ const compensateToValue = toValueCompensator(itemWidth);
123
155
 
124
156
  const getValueByDirectionalPagingOnLoopDisabled = (_config: DirectionalPagingAnimationConfig): number => {
125
157
  const { direction, isOriginatedFromGesture } = _config;
@@ -159,22 +191,29 @@ export default function usePagingAnimation(params: PagingAnimationParameters): U
159
191
  return distance * direction;
160
192
  };
161
193
 
162
- const toValue = type === 'directional'
194
+ const wantedToValue = type === 'directional'
163
195
  // @ts-ignore
164
196
  ? getValueByDirectionalPaging(configWithDefaults)
165
197
  // @ts-ignore
166
198
  : getValueByIndexPaging(configWithDefaults);
167
199
 
200
+ const toValue = compensateToValue(wantedToValue, currentOffsetRef.current);
201
+
168
202
  toValueRef.current = toValue;
203
+ isAnimatingRef.current = true;
204
+
205
+ notifyOffsetHasChanged(currentOffsetRef.current + toValue);
169
206
 
170
207
  if (configWithDefaults.animated) {
171
- const animation = createScrollAnimation(offsetTx, toValue);
172
- animationRef.current = animation;
208
+ const animation = createScrollAnimation(translateX, toValue);
209
+
173
210
  animation.start(({ finished }) => {
174
211
  if (finished) {
175
212
  finalizeAnimation();
176
213
  }
177
214
  });
215
+
216
+ notifyAnimationState('started');
178
217
  } else {
179
218
  finalizeAnimation();
180
219
  }
@@ -185,11 +224,12 @@ export default function usePagingAnimation(params: PagingAnimationParameters): U
185
224
  itemWidth,
186
225
  lastIndex,
187
226
  loop,
227
+ notifyAnimationState,
228
+ notifyOffsetHasChanged,
188
229
  ]);
189
230
 
190
231
  return {
191
- globalInterpolation,
192
- finalizeAnimation,
232
+ interruptAnimation,
193
233
  startPagingAnimation,
194
234
  };
195
235
  };
@@ -0,0 +1,6 @@
1
+ import { logger } from '@fountain-ui/utils';
2
+
3
+ export default logger('Carousel', {
4
+ enabled: __DEV__,
5
+ format: 'diff',
6
+ });
@@ -5,6 +5,10 @@ const directions = ['next', 'prev', 'stay'] as const;
5
5
 
6
6
  export type PagingDirection = (typeof directions)[number];
7
7
 
8
+ const animationStates = ['started', 'finished', 'interrupted'] as const;
9
+
10
+ export type AnimationState = (typeof animationStates)[number];
11
+
8
12
  export type ItemHeight = number | 'auto';
9
13
 
10
14
  export interface RenderItem<T> {
@@ -23,11 +27,19 @@ export interface GetCurrentIndex {
23
27
  (): number;
24
28
  }
25
29
 
30
+ export interface OnIndexChange {
31
+ (itemIndex: number): void;
32
+ }
33
+
34
+ export interface OnPositionChange {
35
+ (position: number): void;
36
+ }
37
+
26
38
  export interface IndexController {
27
- currentIndex: number;
28
39
  getCurrentIndex: GetCurrentIndex;
29
40
  lastIndex: number;
30
- monitorElement: ReactElement;
41
+ notifyAnimationState: (state: AnimationState) => void;
42
+ notifyOffsetHasChanged: (offset: number) => void;
31
43
  }
32
44
 
33
45
  export type PagingAnimationType = 'directional' | 'index';
@@ -1,4 +1,4 @@
1
- import React, { memo, useContext, useEffect, useMemo, useState } from 'react';
1
+ import React, { memo, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react';
2
2
  import { Platform, View } from 'react-native';
3
3
  import { StyleSheet } from '@fountain-ui/core';
4
4
  import type { PageProps } from './types';
@@ -10,9 +10,14 @@ const styles = StyleSheet.create({
10
10
  none: { display: 'none' },
11
11
  });
12
12
 
13
- interface InternalPageState {
13
+ interface InternalPageDescription {
14
14
  isActive: boolean;
15
- isLoaded: boolean;
15
+ becomeNeighbor: boolean;
16
+ }
17
+
18
+ interface InternalPageState {
19
+ active: boolean;
20
+ loaded: boolean;
16
21
  }
17
22
 
18
23
  function Page(props: PageProps) {
@@ -26,63 +31,65 @@ function Page(props: PageProps) {
26
31
 
27
32
  const { pageStore } = useContext(InternalContext);
28
33
 
29
- const assumeInitialPageState = (): InternalPageState => {
30
- const activeIndex = initialPage;
34
+ const computePageDescription: (page: number) => InternalPageDescription = useCallback((page: number) => {
35
+ const activeIndex = page;
31
36
 
32
37
  const isActive = index === activeIndex;
33
38
 
39
+ const shouldRerender = index >= activeIndex - offscreenPageRerenderLimit
40
+ && index <= activeIndex + offscreenPageRerenderLimit;
41
+
42
+ const becomeNeighbor = shouldRerender && !isActive;
43
+
44
+ return { isActive, becomeNeighbor };
45
+ }, [index]);
46
+
47
+ const [initialState] = useState<InternalPageState>(() => {
48
+ const { isActive, becomeNeighbor } = computePageDescription(initialPage);
49
+
34
50
  if (loading === 'eager') {
35
- return { isActive, isLoaded: true };
51
+ return { active: isActive, loaded: true };
36
52
  }
37
53
 
38
- const isLoaded = index >= activeIndex - offscreenPageRerenderLimit
39
- && index <= activeIndex + offscreenPageRerenderLimit;
54
+ return { active: isActive, loaded: isActive || becomeNeighbor };
55
+ });
40
56
 
41
- return { isActive, isLoaded };
42
- };
57
+ // `Bailing out of a state update` is not working as expected.
58
+ const pageStateRef = useRef<InternalPageState>(initialState);
59
+ const [, forceRender] = useReducer((s) => s + 1, 0);
43
60
 
44
- const [pageState, setPageState] = useState<InternalPageState>(assumeInitialPageState);
61
+ const { active, loaded } = pageStateRef.current;
45
62
 
46
- const content = pageState.isLoaded ? children : null;
63
+ const content = loaded ? children : null;
47
64
 
48
65
  useEffect(() => {
49
66
  return pageStore.subscribe(newPage => {
50
- const activeIndex = newPage;
51
-
52
- const isActive = index === activeIndex;
53
-
54
- const shouldRerender = index >= activeIndex - offscreenPageRerenderLimit
55
- && index <= activeIndex + offscreenPageRerenderLimit;
67
+ const { isActive, becomeNeighbor } = computePageDescription(newPage);
56
68
 
57
- const becomeNeighbor = shouldRerender && !isActive;
69
+ const currentState = pageStateRef.current;
58
70
 
59
- setPageState(prevState => {
60
- if (prevState.isActive !== isActive) {
61
- return {
62
- ...prevState,
63
- isActive,
64
- isLoaded: isActive || prevState.isLoaded,
65
- };
66
- }
71
+ const newState: InternalPageState = {
72
+ active: isActive,
73
+ loaded: isActive || becomeNeighbor ? true : currentState.loaded,
74
+ };
67
75
 
68
- if (becomeNeighbor && !prevState.isLoaded) {
69
- return {
70
- ...prevState,
71
- isLoaded: true,
72
- };
73
- }
76
+ if (
77
+ currentState.active !== newState.active
78
+ || currentState.loaded !== newState.loaded
79
+ ) {
80
+ pageStateRef.current = newState;
74
81
 
75
- return prevState;
76
- });
82
+ forceRender();
83
+ }
77
84
  });
78
- }, [pageStore, index]);
85
+ }, [pageStore, computePageDescription]);
79
86
 
80
87
  const contextValue = useMemo(() => ({
81
- isActive: pageState.isActive,
82
- }), [pageState.isActive]);
88
+ isActive: active,
89
+ }), [active]);
83
90
 
84
91
  const style = Platform.OS === 'web'
85
- ? (pageState.isActive ? StyleSheet.absoluteFill : styles.none)
92
+ ? (active ? StyleSheet.absoluteFill : styles.none)
86
93
  : styles.fill;
87
94
 
88
95
  return (
@@ -77,7 +77,7 @@ const ViewPager = forwardRef<ViewPagerInstance, ViewPagerProps>(function ViewPag
77
77
  return () => {
78
78
  animatedValue.removeListener(id);
79
79
  };
80
- }, [sharedPage]);
80
+ }, [sharedPage, setPage]);
81
81
 
82
82
  const handlePageSelected = useCallback((e: ViewPagerOnPageSelectedEvent) => {
83
83
  if (Number.isFinite(desiredPageRef.current)) {
@@ -103,9 +103,9 @@ const ViewPager = forwardRef<ViewPagerInstance, ViewPagerProps>(function ViewPag
103
103
  if (trustfulNextPage !== pageRef.current) {
104
104
  desiredPageRef.current = trustfulNextPage;
105
105
  sharedPage.animatedValue.setValue(trustfulNextPage);
106
- }
107
106
 
108
- onChange?.(trustfulNextPage);
107
+ onChange?.(trustfulNextPage);
108
+ }
109
109
  }
110
110
  }, [onChange, sharedPage]);
111
111
 
@@ -20,5 +20,11 @@ export default function usePageStore(value: SyncAnimatedValue): MonoStore<number
20
20
  };
21
21
  }, [animatedValue]);
22
22
 
23
+ useEffect(() => {
24
+ return () => {
25
+ store.removeAllListeners();
26
+ };
27
+ }, [store]);
28
+
23
29
  return store;
24
30
  };
@@ -1,4 +1,5 @@
1
1
  import type { View } from 'react-native';
2
+ import { clamp } from '@fountain-ui/utils';
2
3
 
3
4
  interface Rect {
4
5
  top: number,
@@ -27,9 +28,6 @@ const normalizePagePosition = (value?: number): number =>
27
28
  const normalizeViewSize = (size: number): number =>
28
29
  Number.isFinite(size) && size > 0 ? size : Number.MAX_SAFE_INTEGER;
29
30
 
30
- const clamp = (value: number, min: number, max: number): number =>
31
- Math.min(Math.max(value, min), max);
32
-
33
31
  export default function measureViewability({
34
32
  view,
35
33
  windowWidth,
@@ -1,23 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = useDimensionChangeReaction;
7
-
8
- var _react = require("react");
9
-
10
- function useDimensionChangeReaction(params) {
11
- const {
12
- controlledTx,
13
- currentIndex,
14
- itemWidth
15
- } = params;
16
- (0, _react.useEffect)(() => {
17
- const newTx = -currentIndex * itemWidth;
18
- controlledTx.setValue(newTx);
19
- }, [controlledTx, currentIndex, itemWidth]);
20
- }
21
-
22
- ;
23
- //# sourceMappingURL=useDimensionChangeReaction.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["useDimensionChangeReaction","params","controlledTx","currentIndex","itemWidth","useEffect","newTx","setValue"],"sources":["useDimensionChangeReaction.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { Animated } from 'react-native';\n\nexport interface Parameters {\n controlledTx: Animated.AnimatedValue;\n currentIndex: number;\n itemWidth: number;\n}\n\nexport default function useDimensionChangeReaction(params: Parameters) {\n const {\n controlledTx,\n currentIndex,\n itemWidth,\n } = params;\n\n useEffect(() => {\n const newTx = -currentIndex * itemWidth;\n controlledTx.setValue(newTx);\n }, [\n controlledTx,\n currentIndex,\n itemWidth,\n ]);\n};\n"],"mappings":";;;;;;;AAAA;;AASe,SAASA,0BAAT,CAAoCC,MAApC,EAAwD;EACnE,MAAM;IACFC,YADE;IAEFC,YAFE;IAGFC;EAHE,IAIFH,MAJJ;EAMA,IAAAI,gBAAA,EAAU,MAAM;IACZ,MAAMC,KAAK,GAAG,CAACH,YAAD,GAAgBC,SAA9B;IACAF,YAAY,CAACK,QAAb,CAAsBD,KAAtB;EACH,CAHD,EAGG,CACCJ,YADD,EAECC,YAFD,EAGCC,SAHD,CAHH;AAQH;;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"names":["OVERSCROLL_FRICTION_FACTOR","useItemInterpolation","index","itemWidth","data","globalInterpolation","loop","useContext","InternalContext","numberOfData","length","interpolationConfigOnLoop","useMemo","lastIndex","maxWidth","Math","abs","halfOfItemWidth","positiveCount","round","startPosition","max","min","inputRange","Number","MIN_VALUE","outputRange","extrapolate","interpolationConfigOnNoLoop","friction","interpolationConfig","offsetX","interpolate","Animated","divide"],"sources":["useItemInterpolation.ts"],"sourcesContent":["import { useContext, useMemo } from 'react';\nimport { Animated } from 'react-native';\nimport { InternalContext } from '../components';\n\nconst OVERSCROLL_FRICTION_FACTOR = 4;\n\nexport default function useItemInterpolation(index: number): Animated.AnimatedInterpolation {\n const {\n itemWidth,\n data,\n globalInterpolation,\n loop,\n } = useContext(InternalContext);\n\n const numberOfData = data.length;\n\n const interpolationConfigOnLoop = useMemo<Animated.InterpolationConfigType>(() => {\n const lastIndex = numberOfData - 1;\n const maxWidth = Math.abs(itemWidth * numberOfData);\n const halfOfItemWidth = 0.5 * itemWidth;\n\n const positiveCount = Math.round(lastIndex / 2);\n const startPosition = index > positiveCount\n ? (index - numberOfData) * itemWidth\n : itemWidth * index;\n\n const max = positiveCount * itemWidth;\n const min = -((lastIndex - positiveCount) * itemWidth);\n\n const inputRange = [\n -maxWidth,\n min - halfOfItemWidth - startPosition - Number.MIN_VALUE,\n min - halfOfItemWidth - startPosition,\n 0,\n max + halfOfItemWidth - startPosition,\n max + halfOfItemWidth - startPosition + Number.MIN_VALUE,\n maxWidth,\n ];\n\n const outputRange = [\n startPosition,\n max + halfOfItemWidth - Number.MIN_VALUE,\n min - halfOfItemWidth,\n startPosition,\n max + halfOfItemWidth,\n min - halfOfItemWidth + Number.MIN_VALUE,\n startPosition,\n ];\n\n return {\n inputRange,\n outputRange,\n extrapolate: 'clamp',\n };\n }, [\n index,\n itemWidth,\n numberOfData,\n ]);\n\n const interpolationConfigOnNoLoop = useMemo<Animated.InterpolationConfigType>(() => {\n const lastIndex = numberOfData - 1;\n const maxWidth = itemWidth * lastIndex;\n const startPosition = itemWidth * index;\n const friction = itemWidth / OVERSCROLL_FRICTION_FACTOR;\n\n const inputRange = [\n -(maxWidth + itemWidth), // overscroll\n -maxWidth,\n 0,\n itemWidth, // overscroll\n ];\n\n const outputRange = [\n -maxWidth + startPosition - friction,\n -maxWidth + startPosition,\n startPosition,\n startPosition + friction,\n ];\n\n return {\n inputRange,\n outputRange,\n extrapolate: 'clamp',\n };\n }, [\n index,\n itemWidth,\n numberOfData,\n ]);\n\n return useMemo(() => {\n const interpolationConfig = loop\n ? interpolationConfigOnLoop\n : interpolationConfigOnNoLoop;\n\n const offsetX = globalInterpolation.interpolate(interpolationConfig);\n\n return Animated.divide(offsetX, itemWidth);\n }, [\n globalInterpolation,\n interpolationConfigOnLoop,\n interpolationConfigOnNoLoop,\n itemWidth,\n loop,\n ]);\n};\n"],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- import { useEffect } from 'react';
2
- export default function useDimensionChangeReaction(params) {
3
- const {
4
- controlledTx,
5
- currentIndex,
6
- itemWidth
7
- } = params;
8
- useEffect(() => {
9
- const newTx = -currentIndex * itemWidth;
10
- controlledTx.setValue(newTx);
11
- }, [controlledTx, currentIndex, itemWidth]);
12
- }
13
- ;
14
- //# sourceMappingURL=useDimensionChangeReaction.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["useEffect","useDimensionChangeReaction","params","controlledTx","currentIndex","itemWidth","newTx","setValue"],"sources":["useDimensionChangeReaction.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { Animated } from 'react-native';\n\nexport interface Parameters {\n controlledTx: Animated.AnimatedValue;\n currentIndex: number;\n itemWidth: number;\n}\n\nexport default function useDimensionChangeReaction(params: Parameters) {\n const {\n controlledTx,\n currentIndex,\n itemWidth,\n } = params;\n\n useEffect(() => {\n const newTx = -currentIndex * itemWidth;\n controlledTx.setValue(newTx);\n }, [\n controlledTx,\n currentIndex,\n itemWidth,\n ]);\n};\n"],"mappings":"AAAA,SAASA,SAAT,QAA0B,OAA1B;AASA,eAAe,SAASC,0BAAT,CAAoCC,MAApC,EAAwD;EACnE,MAAM;IACFC,YADE;IAEFC,YAFE;IAGFC;EAHE,IAIFH,MAJJ;EAMAF,SAAS,CAAC,MAAM;IACZ,MAAMM,KAAK,GAAG,CAACF,YAAD,GAAgBC,SAA9B;IACAF,YAAY,CAACI,QAAb,CAAsBD,KAAtB;EACH,CAHQ,EAGN,CACCH,YADD,EAECC,YAFD,EAGCC,SAHD,CAHM,CAAT;AAQH;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"names":["useContext","useMemo","Animated","InternalContext","OVERSCROLL_FRICTION_FACTOR","useItemInterpolation","index","itemWidth","data","globalInterpolation","loop","numberOfData","length","interpolationConfigOnLoop","lastIndex","maxWidth","Math","abs","halfOfItemWidth","positiveCount","round","startPosition","max","min","inputRange","Number","MIN_VALUE","outputRange","extrapolate","interpolationConfigOnNoLoop","friction","interpolationConfig","offsetX","interpolate","divide"],"sources":["useItemInterpolation.ts"],"sourcesContent":["import { useContext, useMemo } from 'react';\nimport { Animated } from 'react-native';\nimport { InternalContext } from '../components';\n\nconst OVERSCROLL_FRICTION_FACTOR = 4;\n\nexport default function useItemInterpolation(index: number): Animated.AnimatedInterpolation {\n const {\n itemWidth,\n data,\n globalInterpolation,\n loop,\n } = useContext(InternalContext);\n\n const numberOfData = data.length;\n\n const interpolationConfigOnLoop = useMemo<Animated.InterpolationConfigType>(() => {\n const lastIndex = numberOfData - 1;\n const maxWidth = Math.abs(itemWidth * numberOfData);\n const halfOfItemWidth = 0.5 * itemWidth;\n\n const positiveCount = Math.round(lastIndex / 2);\n const startPosition = index > positiveCount\n ? (index - numberOfData) * itemWidth\n : itemWidth * index;\n\n const max = positiveCount * itemWidth;\n const min = -((lastIndex - positiveCount) * itemWidth);\n\n const inputRange = [\n -maxWidth,\n min - halfOfItemWidth - startPosition - Number.MIN_VALUE,\n min - halfOfItemWidth - startPosition,\n 0,\n max + halfOfItemWidth - startPosition,\n max + halfOfItemWidth - startPosition + Number.MIN_VALUE,\n maxWidth,\n ];\n\n const outputRange = [\n startPosition,\n max + halfOfItemWidth - Number.MIN_VALUE,\n min - halfOfItemWidth,\n startPosition,\n max + halfOfItemWidth,\n min - halfOfItemWidth + Number.MIN_VALUE,\n startPosition,\n ];\n\n return {\n inputRange,\n outputRange,\n extrapolate: 'clamp',\n };\n }, [\n index,\n itemWidth,\n numberOfData,\n ]);\n\n const interpolationConfigOnNoLoop = useMemo<Animated.InterpolationConfigType>(() => {\n const lastIndex = numberOfData - 1;\n const maxWidth = itemWidth * lastIndex;\n const startPosition = itemWidth * index;\n const friction = itemWidth / OVERSCROLL_FRICTION_FACTOR;\n\n const inputRange = [\n -(maxWidth + itemWidth), // overscroll\n -maxWidth,\n 0,\n itemWidth, // overscroll\n ];\n\n const outputRange = [\n -maxWidth + startPosition - friction,\n -maxWidth + startPosition,\n startPosition,\n startPosition + friction,\n ];\n\n return {\n inputRange,\n outputRange,\n extrapolate: 'clamp',\n };\n }, [\n index,\n itemWidth,\n numberOfData,\n ]);\n\n return useMemo(() => {\n const interpolationConfig = loop\n ? interpolationConfigOnLoop\n : interpolationConfigOnNoLoop;\n\n const offsetX = globalInterpolation.interpolate(interpolationConfig);\n\n return Animated.divide(offsetX, itemWidth);\n }, [\n globalInterpolation,\n interpolationConfigOnLoop,\n interpolationConfigOnNoLoop,\n itemWidth,\n loop,\n ]);\n};\n"],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import { Animated } from 'react-native';
2
- export interface Parameters {
3
- controlledTx: Animated.AnimatedValue;
4
- currentIndex: number;
5
- itemWidth: number;
6
- }
7
- export default function useDimensionChangeReaction(params: Parameters): void;
@@ -1,25 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { Animated } from 'react-native';
3
-
4
- export interface Parameters {
5
- controlledTx: Animated.AnimatedValue;
6
- currentIndex: number;
7
- itemWidth: number;
8
- }
9
-
10
- export default function useDimensionChangeReaction(params: Parameters) {
11
- const {
12
- controlledTx,
13
- currentIndex,
14
- itemWidth,
15
- } = params;
16
-
17
- useEffect(() => {
18
- const newTx = -currentIndex * itemWidth;
19
- controlledTx.setValue(newTx);
20
- }, [
21
- controlledTx,
22
- currentIndex,
23
- itemWidth,
24
- ]);
25
- };