react-native-reorderable-list 0.13.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/NestedReorderableList.js +2 -0
- package/lib/commonjs/components/NestedReorderableList.js.map +1 -1
- package/lib/commonjs/components/ReorderableList.js +4 -3
- package/lib/commonjs/components/ReorderableList.js.map +1 -1
- package/lib/commonjs/components/ReorderableListCore/ReorderableListCore.js +3 -1
- package/lib/commonjs/components/ReorderableListCore/ReorderableListCore.js.map +1 -1
- package/lib/commonjs/components/ReorderableListCore/useReorderableListCore.js +76 -40
- package/lib/commonjs/components/ReorderableListCore/useReorderableListCore.js.map +1 -1
- package/lib/commonjs/components/ScrollViewContainer.js +14 -3
- package/lib/commonjs/components/ScrollViewContainer.js.map +1 -1
- package/lib/commonjs/contexts/ScrollViewContainerContext.js.map +1 -1
- package/lib/module/components/NestedReorderableList.js +2 -0
- package/lib/module/components/NestedReorderableList.js.map +1 -1
- package/lib/module/components/ReorderableList.js +4 -3
- package/lib/module/components/ReorderableList.js.map +1 -1
- package/lib/module/components/ReorderableListCore/ReorderableListCore.js +3 -1
- package/lib/module/components/ReorderableListCore/ReorderableListCore.js.map +1 -1
- package/lib/module/components/ReorderableListCore/useReorderableListCore.js +77 -41
- package/lib/module/components/ReorderableListCore/useReorderableListCore.js.map +1 -1
- package/lib/module/components/ScrollViewContainer.js +16 -5
- package/lib/module/components/ScrollViewContainer.js.map +1 -1
- package/lib/module/contexts/ScrollViewContainerContext.js.map +1 -1
- package/lib/typescript/components/NestedReorderableList.d.ts.map +1 -1
- package/lib/typescript/components/ReorderableList.d.ts.map +1 -1
- package/lib/typescript/components/ReorderableListCore/ReorderableListCore.d.ts +1 -0
- package/lib/typescript/components/ReorderableListCore/ReorderableListCore.d.ts.map +1 -1
- package/lib/typescript/components/ReorderableListCore/useReorderableListCore.d.ts +4 -4
- package/lib/typescript/components/ReorderableListCore/useReorderableListCore.d.ts.map +1 -1
- package/lib/typescript/components/ScrollViewContainer.d.ts.map +1 -1
- package/lib/typescript/contexts/ScrollViewContainerContext.d.ts +1 -0
- package/lib/typescript/contexts/ScrollViewContainerContext.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/NestedReorderableList.tsx +2 -0
- package/src/components/ReorderableList.tsx +3 -2
- package/src/components/ReorderableListCore/ReorderableListCore.tsx +4 -1
- package/src/components/ReorderableListCore/useReorderableListCore.ts +141 -89
- package/src/components/ScrollViewContainer.tsx +23 -5
- package/src/contexts/ScrollViewContainerContext.ts +1 -0
|
@@ -32,6 +32,7 @@ const AnimatedFlatList = Animated.createAnimatedComponent(
|
|
|
32
32
|
interface ReorderableListCoreProps<T> extends ReorderableListProps<T> {
|
|
33
33
|
// not optional but undefined to avoid forgetting to pass a prop
|
|
34
34
|
scrollViewContainerRef: React.RefObject<ScrollView> | undefined;
|
|
35
|
+
scrollViewPageY: SharedValue<number> | undefined;
|
|
35
36
|
scrollViewHeightY: SharedValue<number> | undefined;
|
|
36
37
|
scrollViewScrollOffsetY: SharedValue<number> | undefined;
|
|
37
38
|
scrollViewScrollEnabled: SharedValue<boolean> | undefined;
|
|
@@ -56,6 +57,7 @@ const ReorderableListCore = <T,>(
|
|
|
56
57
|
onDragEnd,
|
|
57
58
|
onIndexChange,
|
|
58
59
|
scrollViewContainerRef,
|
|
60
|
+
scrollViewPageY,
|
|
59
61
|
scrollViewHeightY,
|
|
60
62
|
scrollViewScrollOffsetY,
|
|
61
63
|
scrollViewScrollEnabled,
|
|
@@ -96,9 +98,11 @@ const ReorderableListCore = <T,>(
|
|
|
96
98
|
onDragEnd,
|
|
97
99
|
onIndexChange,
|
|
98
100
|
scrollViewContainerRef,
|
|
101
|
+
scrollViewPageY,
|
|
99
102
|
scrollViewHeightY,
|
|
100
103
|
scrollViewScrollOffsetY,
|
|
101
104
|
scrollViewScrollEnabled,
|
|
105
|
+
scrollable,
|
|
102
106
|
// flatlist will default to true if we pass explicitly undefined,
|
|
103
107
|
// but internally we would treat it as false, so we force true
|
|
104
108
|
initialScrollEnabled:
|
|
@@ -107,7 +111,6 @@ const ReorderableListCore = <T,>(
|
|
|
107
111
|
typeof initialScrollViewScrollEnabled === 'undefined'
|
|
108
112
|
? true
|
|
109
113
|
: initialScrollViewScrollEnabled,
|
|
110
|
-
nestedScrollable: scrollable,
|
|
111
114
|
cellAnimations,
|
|
112
115
|
shouldUpdateActiveItem,
|
|
113
116
|
panEnabled,
|
|
@@ -16,12 +16,14 @@ import Animated, {
|
|
|
16
16
|
AnimatedRef,
|
|
17
17
|
Easing,
|
|
18
18
|
SharedValue,
|
|
19
|
+
measure,
|
|
19
20
|
runOnJS,
|
|
20
21
|
runOnUI,
|
|
21
22
|
scrollTo,
|
|
22
23
|
useAnimatedReaction,
|
|
23
24
|
useAnimatedRef,
|
|
24
25
|
useAnimatedScrollHandler,
|
|
26
|
+
useDerivedValue,
|
|
25
27
|
useSharedValue,
|
|
26
28
|
withDelay,
|
|
27
29
|
withTiming,
|
|
@@ -37,9 +39,9 @@ import {
|
|
|
37
39
|
ReorderableListDragEndEvent,
|
|
38
40
|
ReorderableListDragStartEvent,
|
|
39
41
|
ReorderableListIndexChangeEvent,
|
|
42
|
+
ReorderableListReorderEvent,
|
|
40
43
|
ReorderableListState,
|
|
41
44
|
} from '../../types';
|
|
42
|
-
import type {ReorderableListReorderEvent} from '../../types';
|
|
43
45
|
|
|
44
46
|
const version = React.version.split('.');
|
|
45
47
|
const hasAutomaticBatching = version.length
|
|
@@ -60,12 +62,13 @@ interface UseReorderableListCoreArgs<T> {
|
|
|
60
62
|
onIndexChange?: (event: ReorderableListIndexChangeEvent) => void;
|
|
61
63
|
onLayout?: (event: LayoutChangeEvent) => void;
|
|
62
64
|
scrollViewContainerRef: React.RefObject<ScrollView> | undefined;
|
|
65
|
+
scrollViewPageY: SharedValue<number> | undefined;
|
|
63
66
|
scrollViewHeightY: SharedValue<number> | undefined;
|
|
64
67
|
scrollViewScrollOffsetY: SharedValue<number> | undefined;
|
|
65
68
|
scrollViewScrollEnabled: SharedValue<boolean> | undefined;
|
|
69
|
+
scrollable: boolean | undefined;
|
|
66
70
|
initialScrollEnabled: boolean | undefined;
|
|
67
71
|
initialScrollViewScrollEnabled: boolean | undefined;
|
|
68
|
-
nestedScrollable: boolean | undefined;
|
|
69
72
|
cellAnimations: ReorderableListCellAnimations | undefined;
|
|
70
73
|
shouldUpdateActiveItem: boolean | undefined;
|
|
71
74
|
panEnabled: boolean;
|
|
@@ -86,12 +89,13 @@ export const useReorderableListCore = <T>({
|
|
|
86
89
|
onLayout,
|
|
87
90
|
onIndexChange,
|
|
88
91
|
scrollViewContainerRef,
|
|
92
|
+
scrollViewPageY,
|
|
89
93
|
scrollViewHeightY,
|
|
90
94
|
scrollViewScrollOffsetY,
|
|
91
95
|
scrollViewScrollEnabled,
|
|
96
|
+
scrollable,
|
|
92
97
|
initialScrollEnabled,
|
|
93
98
|
initialScrollViewScrollEnabled,
|
|
94
|
-
nestedScrollable,
|
|
95
99
|
cellAnimations,
|
|
96
100
|
shouldUpdateActiveItem,
|
|
97
101
|
panActivateAfterLongPress,
|
|
@@ -107,7 +111,7 @@ export const useReorderableListCore = <T>({
|
|
|
107
111
|
const startItemDragCenterY = useSharedValue<number>(0);
|
|
108
112
|
const flatListScrollOffsetY = useSharedValue(0);
|
|
109
113
|
const flatListHeightY = useSharedValue(0);
|
|
110
|
-
const
|
|
114
|
+
const flatListPageY = useSharedValue(0);
|
|
111
115
|
// The scroll y translation of the list since drag start
|
|
112
116
|
const dragScrollTranslationY = useSharedValue(0);
|
|
113
117
|
// The initial scroll offset y of the list on drag start
|
|
@@ -136,6 +140,11 @@ export const useReorderableListCore = <T>({
|
|
|
136
140
|
const lastDragDirectionPivot = useSharedValue<number | null>(null);
|
|
137
141
|
const autoscrollDelta = useSharedValue(autoscrollActivationDelta);
|
|
138
142
|
|
|
143
|
+
// Position of the list relative to the scroll container
|
|
144
|
+
const nestedFlatListPositionY = useDerivedValue(
|
|
145
|
+
() => flatListPageY.value - (scrollViewPageY?.value || 0),
|
|
146
|
+
);
|
|
147
|
+
|
|
139
148
|
useEffect(() => {
|
|
140
149
|
duration.value = animationDuration;
|
|
141
150
|
autoscrollDelta.value = autoscrollActivationDelta;
|
|
@@ -543,7 +552,7 @@ export const useReorderableListCore = <T>({
|
|
|
543
552
|
},
|
|
544
553
|
);
|
|
545
554
|
|
|
546
|
-
const
|
|
555
|
+
const computeHiddenArea = useCallback(() => {
|
|
547
556
|
'worklet';
|
|
548
557
|
if (!scrollViewScrollOffsetY || !scrollViewHeightY) {
|
|
549
558
|
return {top: 0, bottom: 0};
|
|
@@ -569,103 +578,121 @@ export const useReorderableListCore = <T>({
|
|
|
569
578
|
flatListHeightY,
|
|
570
579
|
]);
|
|
571
580
|
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
'worklet';
|
|
575
|
-
const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
|
|
576
|
-
const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
|
|
577
|
-
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
578
|
-
const visibleHeight =
|
|
579
|
-
flatListHeightY.value -
|
|
580
|
-
(hiddenArea.top + hiddenArea.bottom) -
|
|
581
|
-
(offsetTop + offsetBottom);
|
|
581
|
+
const computeThresholdArea = useCallback(() => {
|
|
582
|
+
'worklet';
|
|
582
583
|
|
|
583
|
-
|
|
584
|
-
const top = area + offsetTop;
|
|
585
|
-
const bottom = flatListHeightY.value - area - offsetBottom;
|
|
584
|
+
const hiddenArea = computeHiddenArea();
|
|
586
585
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
586
|
+
const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
|
|
587
|
+
const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
|
|
588
|
+
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
589
|
+
const visibleHeight =
|
|
590
|
+
flatListHeightY.value -
|
|
591
|
+
(hiddenArea.top + hiddenArea.bottom) -
|
|
592
|
+
(offsetTop + offsetBottom);
|
|
591
593
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
|
|
596
|
-
const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
|
|
597
|
-
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
598
|
-
|
|
599
|
-
const area = flatListHeightY.value * threshold;
|
|
600
|
-
const top = area + offsetTop;
|
|
601
|
-
const bottom = flatListHeightY.value - area - offsetBottom;
|
|
602
|
-
|
|
603
|
-
// if the hidden area is 0 then we don't have a threshold area
|
|
604
|
-
// we might have floating errors like 0.0001 which we should ignore
|
|
605
|
-
return {
|
|
606
|
-
top: hiddenArea.top > 0.1 ? top + hiddenArea.top : 0,
|
|
607
|
-
bottom: hiddenArea.bottom > 0.1 ? bottom - hiddenArea.bottom : 0,
|
|
608
|
-
};
|
|
609
|
-
},
|
|
610
|
-
[autoscrollThreshold, autoscrollThresholdOffset, flatListHeightY],
|
|
611
|
-
);
|
|
594
|
+
const area = visibleHeight * threshold;
|
|
595
|
+
const top = area + offsetTop;
|
|
596
|
+
const bottom = flatListHeightY.value - area - offsetBottom;
|
|
612
597
|
|
|
613
|
-
|
|
598
|
+
return {top, bottom};
|
|
599
|
+
}, [
|
|
600
|
+
computeHiddenArea,
|
|
601
|
+
autoscrollThreshold,
|
|
602
|
+
autoscrollThresholdOffset,
|
|
603
|
+
flatListHeightY,
|
|
604
|
+
]);
|
|
605
|
+
|
|
606
|
+
const computeContainerThresholdArea = useCallback(() => {
|
|
607
|
+
'worklet';
|
|
608
|
+
if (!scrollViewHeightY) {
|
|
609
|
+
return {top: -Infinity, bottom: Infinity};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
|
|
613
|
+
const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
|
|
614
|
+
const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
|
|
615
|
+
const visibleHeight = scrollViewHeightY.value - (offsetTop + offsetBottom);
|
|
616
|
+
|
|
617
|
+
const area = visibleHeight * threshold;
|
|
618
|
+
const top = area + offsetTop;
|
|
619
|
+
const bottom = visibleHeight - area - offsetBottom;
|
|
620
|
+
|
|
621
|
+
return {top, bottom};
|
|
622
|
+
}, [autoscrollThreshold, autoscrollThresholdOffset, scrollViewHeightY]);
|
|
623
|
+
|
|
624
|
+
const shouldScrollContainer = useCallback(
|
|
614
625
|
(y: number) => {
|
|
615
626
|
'worklet';
|
|
616
|
-
const
|
|
617
|
-
const
|
|
627
|
+
const containerThresholdArea = computeContainerThresholdArea();
|
|
628
|
+
const nestedListHiddenArea = computeHiddenArea();
|
|
618
629
|
|
|
619
|
-
//
|
|
630
|
+
// We should scroll the container if there's a hidden part of the nested list.
|
|
631
|
+
// We might have floating errors like 0.0001 which we should ignore.
|
|
620
632
|
return (
|
|
621
|
-
(
|
|
622
|
-
(
|
|
633
|
+
(nestedListHiddenArea.top > 0.01 && y <= containerThresholdArea.top) ||
|
|
634
|
+
(nestedListHiddenArea.bottom > 0.01 &&
|
|
635
|
+
y >= containerThresholdArea.bottom)
|
|
623
636
|
);
|
|
624
637
|
},
|
|
625
|
-
[
|
|
638
|
+
[computeHiddenArea, computeContainerThresholdArea],
|
|
626
639
|
);
|
|
627
640
|
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
'worklet';
|
|
631
|
-
const hiddenArea = calculateHiddenArea();
|
|
641
|
+
const getRelativeContainerY = useCallback(() => {
|
|
642
|
+
'worklet';
|
|
632
643
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
644
|
+
return (
|
|
645
|
+
currentY.value +
|
|
646
|
+
nestedFlatListPositionY.value -
|
|
647
|
+
scrollViewDragInitialScrollOffsetY.value
|
|
648
|
+
);
|
|
649
|
+
}, [currentY, nestedFlatListPositionY, scrollViewDragInitialScrollOffsetY]);
|
|
638
650
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}
|
|
651
|
+
const getRelativeListY = useCallback(() => {
|
|
652
|
+
'worklet';
|
|
642
653
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
const thresholdArea = calculateThresholdArea(hiddenArea);
|
|
646
|
-
if (y <= thresholdArea.top) {
|
|
647
|
-
return -1;
|
|
648
|
-
}
|
|
654
|
+
return currentY.value + scrollViewDragScrollTranslationY.value;
|
|
655
|
+
}, [currentY, scrollViewDragScrollTranslationY]);
|
|
649
656
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
657
|
+
const scrollDirection = useCallback(() => {
|
|
658
|
+
'worklet';
|
|
659
|
+
|
|
660
|
+
const relativeContainerY = getRelativeContainerY();
|
|
661
|
+
if (shouldScrollContainer(relativeContainerY)) {
|
|
662
|
+
const containerThresholdArea = computeContainerThresholdArea();
|
|
663
|
+
if (relativeContainerY <= containerThresholdArea.top) {
|
|
664
|
+
return -1;
|
|
653
665
|
}
|
|
654
666
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
667
|
+
if (relativeContainerY >= containerThresholdArea.bottom) {
|
|
668
|
+
return 1;
|
|
669
|
+
}
|
|
670
|
+
} else if (scrollable) {
|
|
671
|
+
const relativeListY = getRelativeListY();
|
|
672
|
+
const thresholdArea = computeThresholdArea();
|
|
673
|
+
|
|
674
|
+
if (relativeListY <= thresholdArea.top) {
|
|
675
|
+
return -1;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (relativeListY >= thresholdArea.bottom) {
|
|
679
|
+
return 1;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return 0;
|
|
684
|
+
}, [
|
|
685
|
+
shouldScrollContainer,
|
|
686
|
+
computeThresholdArea,
|
|
687
|
+
computeContainerThresholdArea,
|
|
688
|
+
getRelativeContainerY,
|
|
689
|
+
getRelativeListY,
|
|
690
|
+
scrollable,
|
|
691
|
+
]);
|
|
665
692
|
|
|
666
693
|
useAnimatedReaction(
|
|
667
|
-
() => currentY.value
|
|
668
|
-
|
|
694
|
+
() => currentY.value,
|
|
695
|
+
() => {
|
|
669
696
|
if (
|
|
670
697
|
state.value === ReorderableListState.DRAGGED ||
|
|
671
698
|
state.value === ReorderableListState.AUTOSCROLL
|
|
@@ -676,7 +703,7 @@ export const useReorderableListCore = <T>({
|
|
|
676
703
|
// 1. Within the threshold area (top or bottom of list)
|
|
677
704
|
// 2. Have dragged in the same direction as the scroll
|
|
678
705
|
// 3. Not already in autoscroll mode
|
|
679
|
-
if (dragDirection.value === scrollDirection(
|
|
706
|
+
if (dragDirection.value === scrollDirection()) {
|
|
680
707
|
// When the first two conditions are met and it's already in autoscroll mode, we let it continue (no-op)
|
|
681
708
|
if (state.value !== ReorderableListState.AUTOSCROLL) {
|
|
682
709
|
state.value = ReorderableListState.AUTOSCROLL;
|
|
@@ -697,9 +724,8 @@ export const useReorderableListCore = <T>({
|
|
|
697
724
|
autoscrollTrigger.value !== lastAutoscrollTrigger.value &&
|
|
698
725
|
state.value === ReorderableListState.AUTOSCROLL
|
|
699
726
|
) {
|
|
700
|
-
let y = currentY.value + scrollViewDragScrollTranslationY.value;
|
|
701
727
|
const autoscrollIncrement =
|
|
702
|
-
|
|
728
|
+
dragDirection.value *
|
|
703
729
|
AUTOSCROLL_CONFIG.increment *
|
|
704
730
|
autoscrollSpeedScale;
|
|
705
731
|
|
|
@@ -708,7 +734,13 @@ export const useReorderableListCore = <T>({
|
|
|
708
734
|
let listRef =
|
|
709
735
|
flatListRef as unknown as AnimatedRef<Animated.ScrollView>;
|
|
710
736
|
|
|
711
|
-
|
|
737
|
+
// Checking on every autoscroll whether to scroll the container,
|
|
738
|
+
// this allows to smoothly pass the scroll from the container to the nested list
|
|
739
|
+
// without any gesture input.
|
|
740
|
+
if (
|
|
741
|
+
scrollViewScrollOffsetY &&
|
|
742
|
+
shouldScrollContainer(getRelativeContainerY())
|
|
743
|
+
) {
|
|
712
744
|
scrollOffset = scrollViewScrollOffsetY.value;
|
|
713
745
|
listRef =
|
|
714
746
|
scrollViewContainerRef as unknown as AnimatedRef<Animated.ScrollView>;
|
|
@@ -750,7 +782,7 @@ export const useReorderableListCore = <T>({
|
|
|
750
782
|
}
|
|
751
783
|
});
|
|
752
784
|
|
|
753
|
-
//
|
|
785
|
+
// container scroll handler
|
|
754
786
|
useAnimatedReaction(
|
|
755
787
|
() => scrollViewScrollOffsetY?.value,
|
|
756
788
|
value => {
|
|
@@ -826,12 +858,32 @@ export const useReorderableListCore = <T>({
|
|
|
826
858
|
|
|
827
859
|
const handleFlatListLayout = useCallback(
|
|
828
860
|
(e: LayoutChangeEvent) => {
|
|
829
|
-
nestedFlatListPositionY.value = e.nativeEvent.layout.y;
|
|
830
861
|
flatListHeightY.value = e.nativeEvent.layout.height;
|
|
831
862
|
|
|
863
|
+
// If nested in a scroll container.
|
|
864
|
+
if (scrollViewScrollOffsetY) {
|
|
865
|
+
// Timeout fixes a bug where measure returns height 0.
|
|
866
|
+
setTimeout(() => {
|
|
867
|
+
runOnUI(() => {
|
|
868
|
+
const measurement = measure(flatListRef);
|
|
869
|
+
if (!measurement) {
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
flatListPageY.value = measurement.pageY;
|
|
874
|
+
})();
|
|
875
|
+
}, 100);
|
|
876
|
+
}
|
|
877
|
+
|
|
832
878
|
onLayout?.(e);
|
|
833
879
|
},
|
|
834
|
-
[
|
|
880
|
+
[
|
|
881
|
+
flatListRef,
|
|
882
|
+
flatListPageY,
|
|
883
|
+
flatListHeightY,
|
|
884
|
+
scrollViewScrollOffsetY,
|
|
885
|
+
onLayout,
|
|
886
|
+
],
|
|
835
887
|
);
|
|
836
888
|
|
|
837
889
|
const handleRef = (value: FlatList<T>) => {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import React, {useMemo} from 'react';
|
|
1
|
+
import React, {useCallback, useMemo} from 'react';
|
|
2
2
|
import {LayoutChangeEvent} from 'react-native';
|
|
3
3
|
|
|
4
4
|
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
|
|
5
5
|
import Animated, {
|
|
6
|
+
measure,
|
|
7
|
+
runOnUI,
|
|
6
8
|
useAnimatedRef,
|
|
7
9
|
useAnimatedScrollHandler,
|
|
8
10
|
useComposedEventHandler,
|
|
@@ -21,6 +23,7 @@ export const ScrollViewContainer: React.FC<ScrollViewContainerProps> = ({
|
|
|
21
23
|
const scrollViewScrollEnabled = useSharedValue(scrollEnabled);
|
|
22
24
|
const scrollViewContainerRef = useAnimatedRef<Animated.ScrollView>();
|
|
23
25
|
const scrollViewScrollOffsetY = useSharedValue(0);
|
|
26
|
+
const scrollViewPageY = useSharedValue(0);
|
|
24
27
|
const scrollViewHeightY = useSharedValue(0);
|
|
25
28
|
|
|
26
29
|
const outerScrollGesture = useMemo(() => Gesture.Native(), []);
|
|
@@ -40,6 +43,7 @@ export const ScrollViewContainer: React.FC<ScrollViewContainerProps> = ({
|
|
|
40
43
|
const contextValue = useMemo(
|
|
41
44
|
() => ({
|
|
42
45
|
scrollViewContainerRef,
|
|
46
|
+
scrollViewPageY,
|
|
43
47
|
scrollViewHeightY,
|
|
44
48
|
scrollViewScrollOffsetY,
|
|
45
49
|
scrollViewScrollEnabled,
|
|
@@ -48,6 +52,7 @@ export const ScrollViewContainer: React.FC<ScrollViewContainerProps> = ({
|
|
|
48
52
|
}),
|
|
49
53
|
[
|
|
50
54
|
scrollViewContainerRef,
|
|
55
|
+
scrollViewPageY,
|
|
51
56
|
scrollViewHeightY,
|
|
52
57
|
scrollViewScrollOffsetY,
|
|
53
58
|
scrollViewScrollEnabled,
|
|
@@ -56,11 +61,24 @@ export const ScrollViewContainer: React.FC<ScrollViewContainerProps> = ({
|
|
|
56
61
|
],
|
|
57
62
|
);
|
|
58
63
|
|
|
59
|
-
const handleLayout = (
|
|
60
|
-
|
|
64
|
+
const handleLayout = useCallback(
|
|
65
|
+
(e: LayoutChangeEvent) => {
|
|
66
|
+
scrollViewHeightY.value = e.nativeEvent.layout.height;
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
// measuring pageY allows wrapping nested lists in other views
|
|
69
|
+
runOnUI(() => {
|
|
70
|
+
const measurement = measure(scrollViewContainerRef);
|
|
71
|
+
if (!measurement) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
scrollViewPageY.value = measurement.pageY;
|
|
76
|
+
})();
|
|
77
|
+
|
|
78
|
+
onLayout?.(e);
|
|
79
|
+
},
|
|
80
|
+
[onLayout, scrollViewContainerRef, scrollViewHeightY, scrollViewPageY],
|
|
81
|
+
);
|
|
64
82
|
|
|
65
83
|
return (
|
|
66
84
|
<ScrollViewContainerContext.Provider value={contextValue}>
|
|
@@ -6,6 +6,7 @@ import {SharedValue} from 'react-native-reanimated';
|
|
|
6
6
|
|
|
7
7
|
interface ScrollViewContainerContextData {
|
|
8
8
|
scrollViewContainerRef: React.RefObject<ScrollView>;
|
|
9
|
+
scrollViewPageY: SharedValue<number>;
|
|
9
10
|
scrollViewHeightY: SharedValue<number>;
|
|
10
11
|
scrollViewScrollOffsetY: SharedValue<number>;
|
|
11
12
|
scrollViewScrollEnabled: SharedValue<boolean>;
|