@leonsilicon/react-native-reanimated-carousel 0.0.0
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.
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/lib/commonjs/components/Carousel.js +2 -0
- package/lib/commonjs/components/Carousel.js.map +1 -0
- package/lib/commonjs/components/CarouselLayout.js +2 -0
- package/lib/commonjs/components/CarouselLayout.js.map +1 -0
- package/lib/commonjs/components/ItemLayout.js +2 -0
- package/lib/commonjs/components/ItemLayout.js.map +1 -0
- package/lib/commonjs/components/ItemRenderer.js +2 -0
- package/lib/commonjs/components/ItemRenderer.js.map +1 -0
- package/lib/commonjs/components/LazyView.js +2 -0
- package/lib/commonjs/components/LazyView.js.map +1 -0
- package/lib/commonjs/components/Pagination/Basic/PaginationItem.js +2 -0
- package/lib/commonjs/components/Pagination/Basic/PaginationItem.js.map +1 -0
- package/lib/commonjs/components/Pagination/Basic/index.js +2 -0
- package/lib/commonjs/components/Pagination/Basic/index.js.map +1 -0
- package/lib/commonjs/components/Pagination/Custom/PaginationItem.js +2 -0
- package/lib/commonjs/components/Pagination/Custom/PaginationItem.js.map +1 -0
- package/lib/commonjs/components/Pagination/Custom/index.js +2 -0
- package/lib/commonjs/components/Pagination/Custom/index.js.map +1 -0
- package/lib/commonjs/components/Pagination/index.js +2 -0
- package/lib/commonjs/components/Pagination/index.js.map +1 -0
- package/lib/commonjs/components/ScrollViewGesture.js +2 -0
- package/lib/commonjs/components/ScrollViewGesture.js.map +1 -0
- package/lib/commonjs/constants/index.js +2 -0
- package/lib/commonjs/constants/index.js.map +1 -0
- package/lib/commonjs/hooks/useAutoPlay.js +2 -0
- package/lib/commonjs/hooks/useAutoPlay.js.map +1 -0
- package/lib/commonjs/hooks/useCarouselController.js +2 -0
- package/lib/commonjs/hooks/useCarouselController.js.map +1 -0
- package/lib/commonjs/hooks/useCheckMounted.js +2 -0
- package/lib/commonjs/hooks/useCheckMounted.js.map +1 -0
- package/lib/commonjs/hooks/useCommonVariables.js +2 -0
- package/lib/commonjs/hooks/useCommonVariables.js.map +1 -0
- package/lib/commonjs/hooks/useInitProps.js +2 -0
- package/lib/commonjs/hooks/useInitProps.js.map +1 -0
- package/lib/commonjs/hooks/useLayoutConfig.js +2 -0
- package/lib/commonjs/hooks/useLayoutConfig.js.map +1 -0
- package/lib/commonjs/hooks/useOffsetX.js +2 -0
- package/lib/commonjs/hooks/useOffsetX.js.map +1 -0
- package/lib/commonjs/hooks/useOnProgressChange.js +2 -0
- package/lib/commonjs/hooks/useOnProgressChange.js.map +1 -0
- package/lib/commonjs/hooks/usePanGestureProxy.js +2 -0
- package/lib/commonjs/hooks/usePanGestureProxy.js.map +1 -0
- package/lib/commonjs/hooks/usePropsErrorBoundary.js +2 -0
- package/lib/commonjs/hooks/usePropsErrorBoundary.js.map +1 -0
- package/lib/commonjs/hooks/useSizeResolver.js +2 -0
- package/lib/commonjs/hooks/useSizeResolver.js.map +1 -0
- package/lib/commonjs/hooks/useUpdateGestureConfig.js +2 -0
- package/lib/commonjs/hooks/useUpdateGestureConfig.js.map +1 -0
- package/lib/commonjs/hooks/useVisibleRanges.js +2 -0
- package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -0
- package/lib/commonjs/index.js +2 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/layouts/index.js +2 -0
- package/lib/commonjs/layouts/index.js.map +1 -0
- package/lib/commonjs/layouts/normal.js +2 -0
- package/lib/commonjs/layouts/normal.js.map +1 -0
- package/lib/commonjs/layouts/parallax.js +2 -0
- package/lib/commonjs/layouts/parallax.js.map +1 -0
- package/lib/commonjs/layouts/stack.js +2 -0
- package/lib/commonjs/layouts/stack.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/store/index.js +2 -0
- package/lib/commonjs/store/index.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/utils/compute-gesture-translation.js +2 -0
- package/lib/commonjs/utils/compute-gesture-translation.js.map +1 -0
- package/lib/commonjs/utils/compute-offset-if-data-changed.js +2 -0
- package/lib/commonjs/utils/compute-offset-if-data-changed.js.map +1 -0
- package/lib/commonjs/utils/compute-offset-if-size-changed.js +2 -0
- package/lib/commonjs/utils/compute-offset-if-size-changed.js.map +1 -0
- package/lib/commonjs/utils/compute-offset-if-sizes-changed.js +2 -0
- package/lib/commonjs/utils/compute-offset-if-sizes-changed.js.map +1 -0
- package/lib/commonjs/utils/computed-with-auto-fill-data.js +2 -0
- package/lib/commonjs/utils/computed-with-auto-fill-data.js.map +1 -0
- package/lib/commonjs/utils/deal-with-animation.js +2 -0
- package/lib/commonjs/utils/deal-with-animation.js.map +1 -0
- package/lib/commonjs/utils/handleroffset-direction.js +2 -0
- package/lib/commonjs/utils/handleroffset-direction.js.map +1 -0
- package/lib/commonjs/utils/log.js +2 -0
- package/lib/commonjs/utils/log.js.map +1 -0
- package/lib/commonjs/utils/sanitize-animation-style.js +2 -0
- package/lib/commonjs/utils/sanitize-animation-style.js.map +1 -0
- package/lib/commonjs/utils/size-resolver.js +2 -0
- package/lib/commonjs/utils/size-resolver.js.map +1 -0
- package/lib/module/components/Carousel.js +2 -0
- package/lib/module/components/Carousel.js.map +1 -0
- package/lib/module/components/CarouselLayout.js +2 -0
- package/lib/module/components/CarouselLayout.js.map +1 -0
- package/lib/module/components/ItemLayout.js +2 -0
- package/lib/module/components/ItemLayout.js.map +1 -0
- package/lib/module/components/ItemRenderer.js +2 -0
- package/lib/module/components/ItemRenderer.js.map +1 -0
- package/lib/module/components/LazyView.js +2 -0
- package/lib/module/components/LazyView.js.map +1 -0
- package/lib/module/components/Pagination/Basic/PaginationItem.js +2 -0
- package/lib/module/components/Pagination/Basic/PaginationItem.js.map +1 -0
- package/lib/module/components/Pagination/Basic/index.js +2 -0
- package/lib/module/components/Pagination/Basic/index.js.map +1 -0
- package/lib/module/components/Pagination/Custom/PaginationItem.js +2 -0
- package/lib/module/components/Pagination/Custom/PaginationItem.js.map +1 -0
- package/lib/module/components/Pagination/Custom/index.js +2 -0
- package/lib/module/components/Pagination/Custom/index.js.map +1 -0
- package/lib/module/components/Pagination/index.js +2 -0
- package/lib/module/components/Pagination/index.js.map +1 -0
- package/lib/module/components/ScrollViewGesture.js +2 -0
- package/lib/module/components/ScrollViewGesture.js.map +1 -0
- package/lib/module/constants/index.js +2 -0
- package/lib/module/constants/index.js.map +1 -0
- package/lib/module/hooks/useAutoPlay.js +2 -0
- package/lib/module/hooks/useAutoPlay.js.map +1 -0
- package/lib/module/hooks/useCarouselController.js +2 -0
- package/lib/module/hooks/useCarouselController.js.map +1 -0
- package/lib/module/hooks/useCheckMounted.js +2 -0
- package/lib/module/hooks/useCheckMounted.js.map +1 -0
- package/lib/module/hooks/useCommonVariables.js +2 -0
- package/lib/module/hooks/useCommonVariables.js.map +1 -0
- package/lib/module/hooks/useInitProps.js +2 -0
- package/lib/module/hooks/useInitProps.js.map +1 -0
- package/lib/module/hooks/useLayoutConfig.js +2 -0
- package/lib/module/hooks/useLayoutConfig.js.map +1 -0
- package/lib/module/hooks/useOffsetX.js +2 -0
- package/lib/module/hooks/useOffsetX.js.map +1 -0
- package/lib/module/hooks/useOnProgressChange.js +2 -0
- package/lib/module/hooks/useOnProgressChange.js.map +1 -0
- package/lib/module/hooks/usePanGestureProxy.js +2 -0
- package/lib/module/hooks/usePanGestureProxy.js.map +1 -0
- package/lib/module/hooks/usePropsErrorBoundary.js +2 -0
- package/lib/module/hooks/usePropsErrorBoundary.js.map +1 -0
- package/lib/module/hooks/useSizeResolver.js +2 -0
- package/lib/module/hooks/useSizeResolver.js.map +1 -0
- package/lib/module/hooks/useUpdateGestureConfig.js +2 -0
- package/lib/module/hooks/useUpdateGestureConfig.js.map +1 -0
- package/lib/module/hooks/useVisibleRanges.js +2 -0
- package/lib/module/hooks/useVisibleRanges.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/layouts/index.js +2 -0
- package/lib/module/layouts/index.js.map +1 -0
- package/lib/module/layouts/normal.js +2 -0
- package/lib/module/layouts/normal.js.map +1 -0
- package/lib/module/layouts/parallax.js +2 -0
- package/lib/module/layouts/parallax.js.map +1 -0
- package/lib/module/layouts/stack.js +2 -0
- package/lib/module/layouts/stack.js.map +1 -0
- package/lib/module/store/index.js +2 -0
- package/lib/module/store/index.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils/compute-gesture-translation.js +2 -0
- package/lib/module/utils/compute-gesture-translation.js.map +1 -0
- package/lib/module/utils/compute-offset-if-data-changed.js +2 -0
- package/lib/module/utils/compute-offset-if-data-changed.js.map +1 -0
- package/lib/module/utils/compute-offset-if-size-changed.js +2 -0
- package/lib/module/utils/compute-offset-if-size-changed.js.map +1 -0
- package/lib/module/utils/compute-offset-if-sizes-changed.js +2 -0
- package/lib/module/utils/compute-offset-if-sizes-changed.js.map +1 -0
- package/lib/module/utils/computed-with-auto-fill-data.js +2 -0
- package/lib/module/utils/computed-with-auto-fill-data.js.map +1 -0
- package/lib/module/utils/deal-with-animation.js +2 -0
- package/lib/module/utils/deal-with-animation.js.map +1 -0
- package/lib/module/utils/handleroffset-direction.js +2 -0
- package/lib/module/utils/handleroffset-direction.js.map +1 -0
- package/lib/module/utils/log.js +2 -0
- package/lib/module/utils/log.js.map +1 -0
- package/lib/module/utils/sanitize-animation-style.js +2 -0
- package/lib/module/utils/sanitize-animation-style.js.map +1 -0
- package/lib/module/utils/size-resolver.js +2 -0
- package/lib/module/utils/size-resolver.js.map +1 -0
- package/lib/typescript/components/Carousel.d.ts +8 -0
- package/lib/typescript/components/Carousel.d.ts.map +1 -0
- package/lib/typescript/components/CarouselLayout.d.ts +6 -0
- package/lib/typescript/components/CarouselLayout.d.ts.map +1 -0
- package/lib/typescript/components/ItemLayout.d.ts +15 -0
- package/lib/typescript/components/ItemLayout.d.ts.map +1 -0
- package/lib/typescript/components/ItemRenderer.d.ts +24 -0
- package/lib/typescript/components/ItemRenderer.d.ts.map +1 -0
- package/lib/typescript/components/LazyView.d.ts +8 -0
- package/lib/typescript/components/LazyView.d.ts.map +1 -0
- package/lib/typescript/components/Pagination/Basic/PaginationItem.d.ts +29 -0
- package/lib/typescript/components/Pagination/Basic/PaginationItem.d.ts.map +1 -0
- package/lib/typescript/components/Pagination/Basic/index.d.ts +23 -0
- package/lib/typescript/components/Pagination/Basic/index.d.ts.map +1 -0
- package/lib/typescript/components/Pagination/Custom/PaginationItem.d.ts +35 -0
- package/lib/typescript/components/Pagination/Custom/PaginationItem.d.ts.map +1 -0
- package/lib/typescript/components/Pagination/Custom/index.d.ts +26 -0
- package/lib/typescript/components/Pagination/Custom/index.d.ts.map +1 -0
- package/lib/typescript/components/Pagination/index.d.ts +5 -0
- package/lib/typescript/components/Pagination/index.d.ts.map +1 -0
- package/lib/typescript/components/ScrollViewGesture.d.ts +19 -0
- package/lib/typescript/components/ScrollViewGesture.d.ts.map +1 -0
- package/lib/typescript/constants/index.d.ts +9 -0
- package/lib/typescript/constants/index.d.ts.map +1 -0
- package/lib/typescript/hooks/useAutoPlay.d.ts +12 -0
- package/lib/typescript/hooks/useAutoPlay.d.ts.map +1 -0
- package/lib/typescript/hooks/useCarouselController.d.ts +28 -0
- package/lib/typescript/hooks/useCarouselController.d.ts.map +1 -0
- package/lib/typescript/hooks/useCheckMounted.d.ts +3 -0
- package/lib/typescript/hooks/useCheckMounted.d.ts.map +1 -0
- package/lib/typescript/hooks/useCommonVariables.d.ts +13 -0
- package/lib/typescript/hooks/useCommonVariables.d.ts.map +1 -0
- package/lib/typescript/hooks/useInitProps.d.ts +17 -0
- package/lib/typescript/hooks/useInitProps.d.ts.map +1 -0
- package/lib/typescript/hooks/useLayoutConfig.d.ts +10 -0
- package/lib/typescript/hooks/useLayoutConfig.d.ts.map +1 -0
- package/lib/typescript/hooks/useOffsetX.d.ts +24 -0
- package/lib/typescript/hooks/useOffsetX.d.ts.map +1 -0
- package/lib/typescript/hooks/useOnProgressChange.d.ts +14 -0
- package/lib/typescript/hooks/useOnProgressChange.d.ts.map +1 -0
- package/lib/typescript/hooks/usePanGestureProxy.d.ts +10 -0
- package/lib/typescript/hooks/usePanGestureProxy.d.ts.map +1 -0
- package/lib/typescript/hooks/usePropsErrorBoundary.d.ts +5 -0
- package/lib/typescript/hooks/usePropsErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/hooks/useSizeResolver.d.ts +27 -0
- package/lib/typescript/hooks/useSizeResolver.d.ts.map +1 -0
- package/lib/typescript/hooks/useUpdateGestureConfig.d.ts +6 -0
- package/lib/typescript/hooks/useUpdateGestureConfig.d.ts.map +1 -0
- package/lib/typescript/hooks/useVisibleRanges.d.ts +23 -0
- package/lib/typescript/hooks/useVisibleRanges.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +7 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/layouts/index.d.ts +11 -0
- package/lib/typescript/layouts/index.d.ts.map +1 -0
- package/lib/typescript/layouts/normal.d.ts +16 -0
- package/lib/typescript/layouts/normal.d.ts.map +1 -0
- package/lib/typescript/layouts/parallax.d.ts +50 -0
- package/lib/typescript/layouts/parallax.d.ts.map +1 -0
- package/lib/typescript/layouts/stack.d.ts +38 -0
- package/lib/typescript/layouts/stack.d.ts.map +1 -0
- package/lib/typescript/store/index.d.ts +38 -0
- package/lib/typescript/store/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +326 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/lib/typescript/utils/compute-gesture-translation.d.ts +9 -0
- package/lib/typescript/utils/compute-gesture-translation.d.ts.map +1 -0
- package/lib/typescript/utils/compute-offset-if-data-changed.d.ts +9 -0
- package/lib/typescript/utils/compute-offset-if-data-changed.d.ts.map +1 -0
- package/lib/typescript/utils/compute-offset-if-size-changed.d.ts +6 -0
- package/lib/typescript/utils/compute-offset-if-size-changed.d.ts.map +1 -0
- package/lib/typescript/utils/compute-offset-if-sizes-changed.d.ts +14 -0
- package/lib/typescript/utils/compute-offset-if-sizes-changed.d.ts.map +1 -0
- package/lib/typescript/utils/computed-with-auto-fill-data.d.ts +23 -0
- package/lib/typescript/utils/computed-with-auto-fill-data.d.ts.map +1 -0
- package/lib/typescript/utils/deal-with-animation.d.ts +3 -0
- package/lib/typescript/utils/deal-with-animation.d.ts.map +1 -0
- package/lib/typescript/utils/handleroffset-direction.d.ts +4 -0
- package/lib/typescript/utils/handleroffset-direction.d.ts.map +1 -0
- package/lib/typescript/utils/log.d.ts +7 -0
- package/lib/typescript/utils/log.d.ts.map +1 -0
- package/lib/typescript/utils/sanitize-animation-style.d.ts +3 -0
- package/lib/typescript/utils/sanitize-animation-style.d.ts.map +1 -0
- package/lib/typescript/utils/size-resolver.d.ts +87 -0
- package/lib/typescript/utils/size-resolver.d.ts.map +1 -0
- package/package.json +151 -0
- package/src/components/Carousel.test.tsx +1153 -0
- package/src/components/Carousel.tsx +35 -0
- package/src/components/CarouselLayout.tsx +231 -0
- package/src/components/ItemLayout.tsx +217 -0
- package/src/components/ItemRenderer.tsx +114 -0
- package/src/components/LazyView.test.tsx +61 -0
- package/src/components/LazyView.tsx +14 -0
- package/src/components/Pagination/Basic/PaginationItem.tsx +149 -0
- package/src/components/Pagination/Basic/index.tsx +98 -0
- package/src/components/Pagination/Custom/PaginationItem.tsx +166 -0
- package/src/components/Pagination/Custom/index.tsx +111 -0
- package/src/components/Pagination/Pagination.test.tsx +178 -0
- package/src/components/Pagination/index.tsx +7 -0
- package/src/components/ScrollViewGesture.tsx +577 -0
- package/src/components/rnr-demo.test.tsx +53 -0
- package/src/constants/index.ts +11 -0
- package/src/hooks/useAutoPlay.test.ts +194 -0
- package/src/hooks/useAutoPlay.ts +58 -0
- package/src/hooks/useCarouselController.test.tsx +1158 -0
- package/src/hooks/useCarouselController.tsx +525 -0
- package/src/hooks/useCheckMounted.test.ts +47 -0
- package/src/hooks/useCheckMounted.ts +14 -0
- package/src/hooks/useCommonVariables.test.tsx +384 -0
- package/src/hooks/useCommonVariables.ts +202 -0
- package/src/hooks/useInitProps.test.tsx +134 -0
- package/src/hooks/useInitProps.ts +111 -0
- package/src/hooks/useLayoutConfig.test.tsx +247 -0
- package/src/hooks/useLayoutConfig.ts +30 -0
- package/src/hooks/useOffsetX.test.ts +110 -0
- package/src/hooks/useOffsetX.ts +109 -0
- package/src/hooks/useOnProgressChange.test.tsx +207 -0
- package/src/hooks/useOnProgressChange.ts +105 -0
- package/src/hooks/usePanGestureProxy.test.tsx +368 -0
- package/src/hooks/usePanGestureProxy.ts +144 -0
- package/src/hooks/usePropsErrorBoundary.ts +138 -0
- package/src/hooks/useSizeResolver.test.tsx +112 -0
- package/src/hooks/useSizeResolver.ts +106 -0
- package/src/hooks/useUpdateGestureConfig.test.ts +89 -0
- package/src/hooks/useUpdateGestureConfig.ts +14 -0
- package/src/hooks/useVisibleRanges.test.tsx +366 -0
- package/src/hooks/useVisibleRanges.tsx +123 -0
- package/src/index.tsx +13 -0
- package/src/layouts/index.tsx +12 -0
- package/src/layouts/normal.ts +32 -0
- package/src/layouts/parallax.test.ts +239 -0
- package/src/layouts/parallax.ts +83 -0
- package/src/layouts/stack.test.ts +252 -0
- package/src/layouts/stack.ts +306 -0
- package/src/store/index.test.tsx +314 -0
- package/src/store/index.tsx +66 -0
- package/src/types.ts +348 -0
- package/src/utils/compute-gesture-translation.test.ts +70 -0
- package/src/utils/compute-gesture-translation.ts +29 -0
- package/src/utils/compute-offset-if-data-changed.test.ts +133 -0
- package/src/utils/compute-offset-if-data-changed.ts +44 -0
- package/src/utils/compute-offset-if-size-changed.test.ts +78 -0
- package/src/utils/compute-offset-if-size-changed.ts +14 -0
- package/src/utils/compute-offset-if-sizes-changed.test.ts +74 -0
- package/src/utils/compute-offset-if-sizes-changed.ts +44 -0
- package/src/utils/computed-with-auto-fill-data.test.ts +298 -0
- package/src/utils/computed-with-auto-fill-data.ts +92 -0
- package/src/utils/deal-with-animation.test.ts +181 -0
- package/src/utils/deal-with-animation.ts +17 -0
- package/src/utils/handleroffset-direction.test.ts +124 -0
- package/src/utils/handleroffset-direction.ts +18 -0
- package/src/utils/index.test.ts +90 -0
- package/src/utils/log.test.ts +134 -0
- package/src/utils/log.ts +12 -0
- package/src/utils/sanitize-animation-style.test.ts +40 -0
- package/src/utils/sanitize-animation-style.ts +20 -0
- package/src/utils/size-resolver.test.ts +193 -0
- package/src/utils/size-resolver.ts +216 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react-hooks";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { useSharedValue } from "react-native-reanimated";
|
|
4
|
+
|
|
5
|
+
import { useSizeResolver } from "./useSizeResolver";
|
|
6
|
+
|
|
7
|
+
describe("useSizeResolver", () => {
|
|
8
|
+
it("returns a uniform resolver when getItemSize is undefined", () => {
|
|
9
|
+
const { result } = renderHook(() => {
|
|
10
|
+
const size = useSharedValue(120);
|
|
11
|
+
return useSizeResolver({
|
|
12
|
+
dataLength: 5,
|
|
13
|
+
getItemSize: undefined,
|
|
14
|
+
uniformSize: size,
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(result.current.variable).toBe(false);
|
|
19
|
+
expect(result.current.itemSize(0)).toBe(120);
|
|
20
|
+
expect(result.current.offsetAt(3)).toBe(360);
|
|
21
|
+
expect(result.current.indexAt(120)).toBe(1);
|
|
22
|
+
expect(result.current.total.value).toBe(600);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns a variable resolver when getItemSize is provided", () => {
|
|
26
|
+
const widths = [80, 150, 220, 100, 300];
|
|
27
|
+
const { result } = renderHook(() => {
|
|
28
|
+
const size = useSharedValue(0);
|
|
29
|
+
return useSizeResolver({
|
|
30
|
+
dataLength: widths.length,
|
|
31
|
+
getItemSize: (i: number) => widths[i],
|
|
32
|
+
uniformSize: size,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(result.current.variable).toBe(true);
|
|
37
|
+
expect(result.current.itemSize(2)).toBe(220);
|
|
38
|
+
expect(result.current.offsetAt(3)).toBe(450);
|
|
39
|
+
expect(result.current.indexAt(700)).toBe(4);
|
|
40
|
+
expect(result.current.total.value).toBe(850);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("rebuilds the prefix table when getItemSize identity changes", () => {
|
|
44
|
+
let widths = [100, 100, 100];
|
|
45
|
+
const { result, rerender } = renderHook(
|
|
46
|
+
({ getter }: { getter: (i: number) => number }) => {
|
|
47
|
+
const size = useSharedValue(0);
|
|
48
|
+
return useSizeResolver({
|
|
49
|
+
dataLength: widths.length,
|
|
50
|
+
getItemSize: getter,
|
|
51
|
+
uniformSize: size,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
{ initialProps: { getter: (i: number) => widths[i] } }
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(result.current.total.value).toBe(300);
|
|
58
|
+
|
|
59
|
+
widths = [200, 200, 200];
|
|
60
|
+
rerender({ getter: (i: number) => widths[i] });
|
|
61
|
+
|
|
62
|
+
expect(result.current.total.value).toBe(600);
|
|
63
|
+
expect(result.current.offsetAt(2)).toBe(400);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("rebuilds when dataLength changes", () => {
|
|
67
|
+
const widths = [100, 100, 100, 100, 100];
|
|
68
|
+
const getItemSize = (i: number) => widths[i];
|
|
69
|
+
const { result, rerender } = renderHook(
|
|
70
|
+
({ length }: { length: number }) => {
|
|
71
|
+
const size = useSharedValue(0);
|
|
72
|
+
return useSizeResolver({
|
|
73
|
+
dataLength: length,
|
|
74
|
+
getItemSize,
|
|
75
|
+
uniformSize: size,
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
{ initialProps: { length: 3 } }
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(result.current.total.value).toBe(300);
|
|
82
|
+
|
|
83
|
+
rerender({ length: 5 });
|
|
84
|
+
|
|
85
|
+
expect(result.current.total.value).toBe(500);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("reflects uniform-size changes in offsetAt immediately", () => {
|
|
89
|
+
const { result } = renderHook(() => {
|
|
90
|
+
const size = useSharedValue(100);
|
|
91
|
+
const resolver = useSizeResolver({
|
|
92
|
+
dataLength: 4,
|
|
93
|
+
getItemSize: undefined,
|
|
94
|
+
uniformSize: size,
|
|
95
|
+
});
|
|
96
|
+
return { size, resolver };
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(result.current.resolver.total.value).toBe(400);
|
|
100
|
+
expect(result.current.resolver.offsetAt(2)).toBe(200);
|
|
101
|
+
|
|
102
|
+
act(() => {
|
|
103
|
+
result.current.size.value = 200;
|
|
104
|
+
});
|
|
105
|
+
// The uniform resolver reads `size.value` on every call, so `offsetAt`
|
|
106
|
+
// reflects the change immediately (no rerender needed). The mirrored
|
|
107
|
+
// `total` is updated by the animated reaction, which doesn't fire
|
|
108
|
+
// synchronously in jest — but that's fine; consumers should rely on
|
|
109
|
+
// `offsetAt`/`total` from worklets where the reaction runs eagerly.
|
|
110
|
+
expect(result.current.resolver.offsetAt(2)).toBe(400);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useAnimatedReaction, useSharedValue } from "react-native-reanimated";
|
|
3
|
+
import type { SharedValue } from "react-native-reanimated";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
buildPrefixSum,
|
|
7
|
+
createUniformSizeResolver,
|
|
8
|
+
createVariableSizeResolver,
|
|
9
|
+
} from "../utils/size-resolver";
|
|
10
|
+
import type { SizeResolver } from "../utils/size-resolver";
|
|
11
|
+
|
|
12
|
+
interface Opts {
|
|
13
|
+
/** Number of items the resolver should cover. */
|
|
14
|
+
dataLength: number;
|
|
15
|
+
/** Active-axis per-item size getter, or `undefined` in uniform mode. */
|
|
16
|
+
getItemSize: ((index: number) => number) | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Uniform-mode scalar size (page width/height). Read on every worklet tick.
|
|
19
|
+
* `null` is treated as 0 — this lets us accept `common.resolvedSize` (which
|
|
20
|
+
* is `SharedValue<number | null>`) directly without a cast.
|
|
21
|
+
*/
|
|
22
|
+
uniformSize: SharedValue<number | null>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Builds a `SizeResolver` from props. In variable-size mode, computes the
|
|
27
|
+
* prefix-sum array on the JS thread and ferries it into SharedValues so the
|
|
28
|
+
* UI thread can look up offsets without a thread-hop. In uniform-size mode,
|
|
29
|
+
* returns a resolver that reads the existing scalar `size` SharedValue.
|
|
30
|
+
*
|
|
31
|
+
* The variable-mode resolver re-runs `getItemSize(i)` for every index whenever
|
|
32
|
+
* either `dataLength` or the getter identity changes. Memoize the getter to
|
|
33
|
+
* avoid spurious rebuilds — same convention as React deps.
|
|
34
|
+
*/
|
|
35
|
+
export function useSizeResolver(opts: Opts): SizeResolver {
|
|
36
|
+
const { dataLength, getItemSize, uniformSize } = opts;
|
|
37
|
+
const variable = typeof getItemSize === "function";
|
|
38
|
+
|
|
39
|
+
const dataLengthSv = useSharedValue(dataLength);
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
dataLengthSv.value = dataLength;
|
|
42
|
+
}, [dataLength, dataLengthSv]);
|
|
43
|
+
|
|
44
|
+
// Variable-mode shared state. We create the SharedValues unconditionally so
|
|
45
|
+
// hook order stays stable across uniform/variable toggles.
|
|
46
|
+
const sizesSv = useSharedValue<number[]>([]);
|
|
47
|
+
const prefixSv = useSharedValue<number[]>([0]);
|
|
48
|
+
const totalSv = useSharedValue<number>(0);
|
|
49
|
+
const hintSv = useSharedValue<number>(0);
|
|
50
|
+
// Uniform-mode mirror of `uniformSize * dataLength` so consumers always read
|
|
51
|
+
// `total` consistently regardless of mode. We initialise to 0 (filled by the
|
|
52
|
+
// sync effect below) to avoid reading SharedValues during render.
|
|
53
|
+
const uniformTotalSv = useSharedValue<number>(0);
|
|
54
|
+
|
|
55
|
+
// Rebuild the prefix-sum table whenever inputs change.
|
|
56
|
+
const built = React.useMemo(() => {
|
|
57
|
+
if (!variable || !getItemSize || dataLength <= 0) return null;
|
|
58
|
+
return buildPrefixSum(dataLength, getItemSize);
|
|
59
|
+
}, [variable, getItemSize, dataLength]);
|
|
60
|
+
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
if (!built) return;
|
|
63
|
+
sizesSv.value = built.sizes;
|
|
64
|
+
prefixSv.value = built.prefix;
|
|
65
|
+
totalSv.value = built.total;
|
|
66
|
+
// Reset the index-cache hint when the table changes — old indices may not
|
|
67
|
+
// map to the new prefix layout.
|
|
68
|
+
hintSv.value = 0;
|
|
69
|
+
}, [built, sizesSv, prefixSv, totalSv, hintSv]);
|
|
70
|
+
|
|
71
|
+
// Keep the uniform-mode `total` mirror in sync with the scalar size and
|
|
72
|
+
// dataLength. The animated reaction handles live updates from the UI thread
|
|
73
|
+
// (e.g. when onLayout writes a new size); the layout effect seeds the
|
|
74
|
+
// initial value synchronously so the first render sees a correct total.
|
|
75
|
+
useAnimatedReaction(
|
|
76
|
+
() => ({ size: uniformSize.value ?? 0, length: dataLengthSv.value }),
|
|
77
|
+
({ size, length }) => {
|
|
78
|
+
if (variable) return;
|
|
79
|
+
uniformTotalSv.value = size * length;
|
|
80
|
+
},
|
|
81
|
+
[variable]
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
React.useLayoutEffect(() => {
|
|
85
|
+
if (variable) return;
|
|
86
|
+
const v = uniformSize.value ?? 0;
|
|
87
|
+
uniformTotalSv.value = v * dataLength;
|
|
88
|
+
}, [variable, uniformSize, dataLength, uniformTotalSv]);
|
|
89
|
+
|
|
90
|
+
return React.useMemo<SizeResolver>(() => {
|
|
91
|
+
if (variable) {
|
|
92
|
+
return createVariableSizeResolver({
|
|
93
|
+
sizes: sizesSv,
|
|
94
|
+
prefix: prefixSv,
|
|
95
|
+
total: totalSv,
|
|
96
|
+
count: dataLengthSv,
|
|
97
|
+
hint: hintSv,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return createUniformSizeResolver({
|
|
101
|
+
size: uniformSize,
|
|
102
|
+
count: dataLengthSv,
|
|
103
|
+
total: uniformTotalSv,
|
|
104
|
+
});
|
|
105
|
+
}, [variable, sizesSv, prefixSv, totalSv, hintSv, uniformSize, dataLengthSv, uniformTotalSv]);
|
|
106
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
2
|
+
|
|
3
|
+
import { useUpdateGestureConfig } from "./useUpdateGestureConfig";
|
|
4
|
+
|
|
5
|
+
describe("useUpdateGestureConfig", () => {
|
|
6
|
+
const mockGesture = {
|
|
7
|
+
enabled: jest.fn().mockReturnThis(),
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
jest.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should update gesture enabled state", () => {
|
|
15
|
+
renderHook(() =>
|
|
16
|
+
useUpdateGestureConfig(mockGesture as any, {
|
|
17
|
+
enabled: true,
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
expect(mockGesture.enabled).toHaveBeenCalledWith(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should handle undefined enabled state", () => {
|
|
25
|
+
renderHook(() => useUpdateGestureConfig(mockGesture as any, {}));
|
|
26
|
+
|
|
27
|
+
expect(mockGesture.enabled).not.toHaveBeenCalled();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should update when enabled state changes", () => {
|
|
31
|
+
const { rerender } = renderHook((props) => useUpdateGestureConfig(mockGesture as any, props), {
|
|
32
|
+
initialProps: { enabled: true },
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
expect(mockGesture.enabled).toHaveBeenCalledWith(true);
|
|
36
|
+
|
|
37
|
+
rerender({ enabled: false });
|
|
38
|
+
expect(mockGesture.enabled).toHaveBeenCalledWith(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should not update when enabled state remains the same", () => {
|
|
42
|
+
const { rerender } = renderHook((props) => useUpdateGestureConfig(mockGesture as any, props), {
|
|
43
|
+
initialProps: { enabled: true },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
mockGesture.enabled.mockClear();
|
|
47
|
+
|
|
48
|
+
rerender({ enabled: true });
|
|
49
|
+
expect(mockGesture.enabled).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should handle gesture object changes", () => {
|
|
53
|
+
const newMockGesture = {
|
|
54
|
+
enabled: jest.fn().mockReturnThis(),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const { rerender } = renderHook(
|
|
58
|
+
({ gesture, config }) => useUpdateGestureConfig(gesture as any, config),
|
|
59
|
+
{
|
|
60
|
+
initialProps: {
|
|
61
|
+
gesture: mockGesture,
|
|
62
|
+
config: { enabled: true },
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(mockGesture.enabled).toHaveBeenCalledWith(true);
|
|
68
|
+
|
|
69
|
+
rerender({
|
|
70
|
+
gesture: newMockGesture,
|
|
71
|
+
config: { enabled: true },
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(newMockGesture.enabled).toHaveBeenCalledWith(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should cleanup properly on unmount", () => {
|
|
78
|
+
const { unmount } = renderHook(() =>
|
|
79
|
+
useUpdateGestureConfig(mockGesture as any, {
|
|
80
|
+
enabled: true,
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
mockGesture.enabled.mockClear();
|
|
85
|
+
unmount();
|
|
86
|
+
|
|
87
|
+
expect(mockGesture.enabled).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import type { PanGesture } from "react-native-gesture-handler";
|
|
3
|
+
|
|
4
|
+
export interface GestureConfig {
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const useUpdateGestureConfig = (gesture: PanGesture, config: GestureConfig) => {
|
|
9
|
+
const { enabled } = config;
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (typeof enabled !== "undefined") gesture.enabled(enabled);
|
|
13
|
+
}, [enabled, gesture]);
|
|
14
|
+
};
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { useSharedValue } from "react-native-reanimated";
|
|
2
|
+
|
|
3
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
4
|
+
|
|
5
|
+
import { buildPrefixSum, createVariableSizeResolver } from "../utils/size-resolver";
|
|
6
|
+
import { useVisibleRanges } from "./useVisibleRanges";
|
|
7
|
+
|
|
8
|
+
const viewSize = 393;
|
|
9
|
+
|
|
10
|
+
describe("useVisibleRanges", () => {
|
|
11
|
+
it("should only display the front of the list when loop is false", async () => {
|
|
12
|
+
const hook = renderHook(() => {
|
|
13
|
+
const translation = useSharedValue(-0);
|
|
14
|
+
const range = useVisibleRanges({
|
|
15
|
+
total: 10,
|
|
16
|
+
translation,
|
|
17
|
+
viewSize,
|
|
18
|
+
windowSize: 4,
|
|
19
|
+
loop: false,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return range;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const expected = hook.result.current.value;
|
|
26
|
+
|
|
27
|
+
expect(expected).toMatchInlineSnapshot(`
|
|
28
|
+
{
|
|
29
|
+
"negativeRange": [
|
|
30
|
+
0,
|
|
31
|
+
0,
|
|
32
|
+
],
|
|
33
|
+
"positiveRange": [
|
|
34
|
+
0,
|
|
35
|
+
3,
|
|
36
|
+
],
|
|
37
|
+
}
|
|
38
|
+
`);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should display the rear of the list and the front of the list when loop is true", async () => {
|
|
42
|
+
const hook = renderHook(() => {
|
|
43
|
+
const translation = useSharedValue(-0);
|
|
44
|
+
const range = useVisibleRanges({
|
|
45
|
+
total: 10,
|
|
46
|
+
translation,
|
|
47
|
+
viewSize,
|
|
48
|
+
windowSize: 4,
|
|
49
|
+
loop: true,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return range;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const expected = hook.result.current.value;
|
|
56
|
+
|
|
57
|
+
expect(expected).toMatchInlineSnapshot(`
|
|
58
|
+
{
|
|
59
|
+
"negativeRange": [
|
|
60
|
+
8,
|
|
61
|
+
9,
|
|
62
|
+
],
|
|
63
|
+
"positiveRange": [
|
|
64
|
+
0,
|
|
65
|
+
2,
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
`);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should shows the increased range of the list when the loop is false and swiped the carousel.", async () => {
|
|
72
|
+
const slide0hook = renderHook(() => {
|
|
73
|
+
const translation = useSharedValue(-0 * viewSize);
|
|
74
|
+
const range = useVisibleRanges({
|
|
75
|
+
total: 10,
|
|
76
|
+
translation,
|
|
77
|
+
viewSize,
|
|
78
|
+
windowSize: 4,
|
|
79
|
+
loop: false,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return range;
|
|
83
|
+
}).result.current.value;
|
|
84
|
+
|
|
85
|
+
const slide1hook = renderHook(() => {
|
|
86
|
+
const translation = useSharedValue(-1 * viewSize);
|
|
87
|
+
const range = useVisibleRanges({
|
|
88
|
+
total: 10,
|
|
89
|
+
translation,
|
|
90
|
+
viewSize,
|
|
91
|
+
windowSize: 4,
|
|
92
|
+
loop: false,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return range;
|
|
96
|
+
}).result.current.value;
|
|
97
|
+
|
|
98
|
+
const slide2hook = renderHook(() => {
|
|
99
|
+
const translation = useSharedValue(-2 * viewSize);
|
|
100
|
+
const range = useVisibleRanges({
|
|
101
|
+
total: 10,
|
|
102
|
+
translation,
|
|
103
|
+
viewSize,
|
|
104
|
+
windowSize: 4,
|
|
105
|
+
loop: false,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return range;
|
|
109
|
+
}).result.current.value;
|
|
110
|
+
|
|
111
|
+
const slide3hook = renderHook(() => {
|
|
112
|
+
const translation = useSharedValue(-3 * viewSize);
|
|
113
|
+
const range = useVisibleRanges({
|
|
114
|
+
total: 10,
|
|
115
|
+
translation,
|
|
116
|
+
viewSize,
|
|
117
|
+
windowSize: 4,
|
|
118
|
+
loop: false,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return range;
|
|
122
|
+
}).result.current.value;
|
|
123
|
+
|
|
124
|
+
// [0,3] Display the 0,1,2,3 items.
|
|
125
|
+
expect(slide0hook).toMatchInlineSnapshot(`
|
|
126
|
+
{
|
|
127
|
+
"negativeRange": [
|
|
128
|
+
0,
|
|
129
|
+
0,
|
|
130
|
+
],
|
|
131
|
+
"positiveRange": [
|
|
132
|
+
0,
|
|
133
|
+
3,
|
|
134
|
+
],
|
|
135
|
+
}
|
|
136
|
+
`);
|
|
137
|
+
|
|
138
|
+
// [1,4] Display the 1,2,3,4 items.
|
|
139
|
+
expect(slide1hook).toMatchInlineSnapshot(`
|
|
140
|
+
{
|
|
141
|
+
"negativeRange": [
|
|
142
|
+
0,
|
|
143
|
+
1,
|
|
144
|
+
],
|
|
145
|
+
"positiveRange": [
|
|
146
|
+
1,
|
|
147
|
+
4,
|
|
148
|
+
],
|
|
149
|
+
}
|
|
150
|
+
`);
|
|
151
|
+
|
|
152
|
+
// [2,5] Display the 2,3,4,5 items.
|
|
153
|
+
expect(slide2hook).toMatchInlineSnapshot(`
|
|
154
|
+
{
|
|
155
|
+
"negativeRange": [
|
|
156
|
+
0,
|
|
157
|
+
2,
|
|
158
|
+
],
|
|
159
|
+
"positiveRange": [
|
|
160
|
+
2,
|
|
161
|
+
5,
|
|
162
|
+
],
|
|
163
|
+
}
|
|
164
|
+
`);
|
|
165
|
+
|
|
166
|
+
// [3.6] Display the 3,4,5,6 items.
|
|
167
|
+
expect(slide3hook).toMatchInlineSnapshot(`
|
|
168
|
+
{
|
|
169
|
+
"negativeRange": [
|
|
170
|
+
0,
|
|
171
|
+
3,
|
|
172
|
+
],
|
|
173
|
+
"positiveRange": [
|
|
174
|
+
3,
|
|
175
|
+
6,
|
|
176
|
+
],
|
|
177
|
+
}
|
|
178
|
+
`);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should clamp ranges on right overdrag in non-loop mode", () => {
|
|
182
|
+
const hook = renderHook(() => {
|
|
183
|
+
// Simulate overdrag to the right at the first page (positive translation)
|
|
184
|
+
const translation = useSharedValue(viewSize * 0.25);
|
|
185
|
+
const range = useVisibleRanges({
|
|
186
|
+
total: 5,
|
|
187
|
+
translation,
|
|
188
|
+
viewSize,
|
|
189
|
+
windowSize: 3,
|
|
190
|
+
loop: false,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return range;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(hook.result.current.value).toEqual({
|
|
197
|
+
negativeRange: [0, 0],
|
|
198
|
+
positiveRange: [0, 2],
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should return empty positive range when total is 0", () => {
|
|
203
|
+
const hook = renderHook(() => {
|
|
204
|
+
const translation = useSharedValue(0);
|
|
205
|
+
const range = useVisibleRanges({
|
|
206
|
+
total: 0,
|
|
207
|
+
translation,
|
|
208
|
+
viewSize,
|
|
209
|
+
windowSize: 4,
|
|
210
|
+
loop: false,
|
|
211
|
+
});
|
|
212
|
+
return range;
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(hook.result.current.value).toEqual({
|
|
216
|
+
negativeRange: [0, 0],
|
|
217
|
+
positiveRange: [0, -1],
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe("viewSize boundary conditions", () => {
|
|
222
|
+
it("should return safe defaults when viewSize is NaN", () => {
|
|
223
|
+
const hook = renderHook(() => {
|
|
224
|
+
const translation = useSharedValue(0);
|
|
225
|
+
const range = useVisibleRanges({
|
|
226
|
+
total: 6,
|
|
227
|
+
translation,
|
|
228
|
+
// Invalid runtime value should not break range calculation
|
|
229
|
+
viewSize: Number.NaN,
|
|
230
|
+
windowSize: 4,
|
|
231
|
+
loop: false,
|
|
232
|
+
});
|
|
233
|
+
return range;
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(hook.result.current.value).toEqual({
|
|
237
|
+
negativeRange: [0, 0],
|
|
238
|
+
positiveRange: [0, 3],
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should return safe defaults when viewSize is 0", () => {
|
|
243
|
+
const hook = renderHook(() => {
|
|
244
|
+
const translation = useSharedValue(0);
|
|
245
|
+
const range = useVisibleRanges({
|
|
246
|
+
total: 10,
|
|
247
|
+
translation,
|
|
248
|
+
viewSize: 0,
|
|
249
|
+
windowSize: 4,
|
|
250
|
+
loop: false,
|
|
251
|
+
});
|
|
252
|
+
return range;
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Should not crash and return sensible defaults
|
|
256
|
+
expect(hook.result.current.value).toEqual({
|
|
257
|
+
negativeRange: [0, 0],
|
|
258
|
+
positiveRange: [0, 3], // Math.min(10-1, 4-1) = 3
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it("should return safe defaults when viewSize is negative", () => {
|
|
263
|
+
const hook = renderHook(() => {
|
|
264
|
+
const translation = useSharedValue(0);
|
|
265
|
+
const range = useVisibleRanges({
|
|
266
|
+
total: 5,
|
|
267
|
+
translation,
|
|
268
|
+
viewSize: -100,
|
|
269
|
+
windowSize: 3,
|
|
270
|
+
loop: true,
|
|
271
|
+
});
|
|
272
|
+
return range;
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(hook.result.current.value).toEqual({
|
|
276
|
+
negativeRange: [0, 0],
|
|
277
|
+
positiveRange: [0, 2], // Math.min(5-1, 3-1) = 2
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should handle small total with viewSize 0", () => {
|
|
282
|
+
const hook = renderHook(() => {
|
|
283
|
+
const translation = useSharedValue(0);
|
|
284
|
+
const range = useVisibleRanges({
|
|
285
|
+
total: 2,
|
|
286
|
+
translation,
|
|
287
|
+
viewSize: 0,
|
|
288
|
+
windowSize: 5,
|
|
289
|
+
loop: false,
|
|
290
|
+
});
|
|
291
|
+
return range;
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
expect(hook.result.current.value).toEqual({
|
|
295
|
+
negativeRange: [0, 0],
|
|
296
|
+
positiveRange: [0, 1], // Math.min(2-1, 5-1) = 1
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("should handle loop mode with viewSize 0", () => {
|
|
301
|
+
const hook = renderHook(() => {
|
|
302
|
+
const translation = useSharedValue(0);
|
|
303
|
+
const range = useVisibleRanges({
|
|
304
|
+
total: 6,
|
|
305
|
+
translation,
|
|
306
|
+
viewSize: 0,
|
|
307
|
+
windowSize: 4,
|
|
308
|
+
loop: true,
|
|
309
|
+
});
|
|
310
|
+
return range;
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
expect(hook.result.current.value).toEqual({
|
|
314
|
+
negativeRange: [0, 0],
|
|
315
|
+
positiveRange: [0, 3], // Math.min(6-1, 4-1) = 3
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
describe("variable-size resolver", () => {
|
|
321
|
+
const widths = [80, 150, 220, 100, 300, 100, 120, 200, 90, 180];
|
|
322
|
+
const built = buildPrefixSum(widths.length, (i) => widths[i]);
|
|
323
|
+
|
|
324
|
+
const makeRange = (translationValue: number) =>
|
|
325
|
+
renderHook(() => {
|
|
326
|
+
const translation = useSharedValue(translationValue);
|
|
327
|
+
const sizes = useSharedValue(built.sizes);
|
|
328
|
+
const prefix = useSharedValue(built.prefix);
|
|
329
|
+
const total = useSharedValue(built.total);
|
|
330
|
+
const count = useSharedValue(widths.length);
|
|
331
|
+
const resolver = createVariableSizeResolver({ sizes, prefix, total, count });
|
|
332
|
+
return useVisibleRanges({
|
|
333
|
+
total: widths.length,
|
|
334
|
+
translation,
|
|
335
|
+
viewSize: 0,
|
|
336
|
+
windowSize: 4,
|
|
337
|
+
loop: false,
|
|
338
|
+
resolver,
|
|
339
|
+
});
|
|
340
|
+
}).result.current.value;
|
|
341
|
+
|
|
342
|
+
it("locates currentIndex via resolver.indexAt at the start", () => {
|
|
343
|
+
// translation = 0 → current item is index 0
|
|
344
|
+
expect(makeRange(0)).toEqual({
|
|
345
|
+
negativeRange: [0, 0],
|
|
346
|
+
positiveRange: [0, 3],
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("locates currentIndex when scrolled into item 2", () => {
|
|
351
|
+
// prefix[2] = 230. Scrolling -250 lands inside item 2.
|
|
352
|
+
expect(makeRange(-250)).toEqual({
|
|
353
|
+
negativeRange: [0, 2],
|
|
354
|
+
positiveRange: [2, 5],
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it("locates currentIndex when scrolled past item 4", () => {
|
|
359
|
+
// prefix[5] = 850. Scrolling -870 lands inside item 5.
|
|
360
|
+
expect(makeRange(-870)).toEqual({
|
|
361
|
+
negativeRange: [2, 5],
|
|
362
|
+
positiveRange: [5, 8],
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
});
|