@swmansion/react-native-bottom-sheet 0.5.1 → 0.6.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/lib/module/BottomSheetBase.js +10 -13
- package/lib/module/BottomSheetBase.js.map +1 -1
- package/lib/module/BottomSheetContext.js.map +1 -1
- package/lib/module/BottomSheetFlatList.js +3 -42
- package/lib/module/BottomSheetFlatList.js.map +1 -1
- package/lib/module/BottomSheetScrollView.js +3 -43
- package/lib/module/BottomSheetScrollView.js.map +1 -1
- package/lib/module/bottomSheetScrollable.js +35 -0
- package/lib/module/bottomSheetScrollable.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/useBottomSheetPanGesture.js +50 -30
- package/lib/module/useBottomSheetPanGesture.js.map +1 -1
- package/lib/module/useBottomSheetScrollable.js +14 -17
- package/lib/module/useBottomSheetScrollable.js.map +1 -1
- package/lib/typescript/src/BottomSheetBase.d.ts.map +1 -1
- package/lib/typescript/src/BottomSheetContext.d.ts +6 -4
- package/lib/typescript/src/BottomSheetContext.d.ts.map +1 -1
- package/lib/typescript/src/BottomSheetFlatList.d.ts +7 -12
- package/lib/typescript/src/BottomSheetFlatList.d.ts.map +1 -1
- package/lib/typescript/src/BottomSheetScrollView.d.ts +7 -14
- package/lib/typescript/src/BottomSheetScrollView.d.ts.map +1 -1
- package/lib/typescript/src/bottomSheetScrollable.d.ts +9 -0
- package/lib/typescript/src/bottomSheetScrollable.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/useBottomSheetPanGesture.d.ts +4 -6
- package/lib/typescript/src/useBottomSheetPanGesture.d.ts.map +1 -1
- package/lib/typescript/src/useBottomSheetScrollable.d.ts +1 -1
- package/lib/typescript/src/useBottomSheetScrollable.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/BottomSheetBase.tsx +16 -14
- package/src/BottomSheetContext.tsx +7 -4
- package/src/BottomSheetFlatList.tsx +16 -58
- package/src/BottomSheetScrollView.tsx +17 -61
- package/src/bottomSheetScrollable.tsx +42 -0
- package/src/index.tsx +3 -9
- package/src/useBottomSheetPanGesture.ts +61 -52
- package/src/useBottomSheetScrollable.ts +16 -23
|
@@ -4,11 +4,11 @@ import { scheduleOnRN } from 'react-native-worklets';
|
|
|
4
4
|
import {
|
|
5
5
|
measure,
|
|
6
6
|
scrollTo,
|
|
7
|
-
type AnimatedRef,
|
|
8
7
|
type SharedValue,
|
|
9
8
|
useSharedValue,
|
|
10
9
|
} from 'react-native-reanimated';
|
|
11
10
|
|
|
11
|
+
import type { ScrollableEntry } from './BottomSheetContext';
|
|
12
12
|
import { findSnapTarget } from './bottomSheetUtils';
|
|
13
13
|
|
|
14
14
|
interface BottomSheetPanGestureParams {
|
|
@@ -18,11 +18,8 @@ interface BottomSheetPanGestureParams {
|
|
|
18
18
|
detentsValue: SharedValue<number[]>;
|
|
19
19
|
isDraggableValue: SharedValue<boolean[]>;
|
|
20
20
|
currentIndex: SharedValue<number>;
|
|
21
|
-
|
|
22
|
-
hasScrollable: SharedValue<boolean>;
|
|
23
|
-
isScrollableGestureActive: SharedValue<boolean>;
|
|
21
|
+
scrollableEntries: ScrollableEntry[];
|
|
24
22
|
isScrollableLocked: SharedValue<boolean>;
|
|
25
|
-
scrollableRef: AnimatedRef<any>;
|
|
26
23
|
handleIndexChange: (nextIndex: number) => void;
|
|
27
24
|
animateToIndex: (targetIndex: number, velocity?: number) => void;
|
|
28
25
|
}
|
|
@@ -34,11 +31,8 @@ export const useBottomSheetPanGesture = ({
|
|
|
34
31
|
detentsValue,
|
|
35
32
|
isDraggableValue,
|
|
36
33
|
currentIndex,
|
|
37
|
-
|
|
38
|
-
hasScrollable,
|
|
39
|
-
isScrollableGestureActive,
|
|
34
|
+
scrollableEntries,
|
|
40
35
|
isScrollableLocked,
|
|
41
|
-
scrollableRef,
|
|
42
36
|
handleIndexChange,
|
|
43
37
|
animateToIndex,
|
|
44
38
|
}: BottomSheetPanGestureParams): PanGesture => {
|
|
@@ -48,7 +42,7 @@ export const useBottomSheetPanGesture = ({
|
|
|
48
42
|
const panStartY = useSharedValue(0);
|
|
49
43
|
const panActivated = useSharedValue(false);
|
|
50
44
|
const dragStartTranslateY = useSharedValue(0);
|
|
51
|
-
const
|
|
45
|
+
const activeScrollableIndex = useSharedValue(-1);
|
|
52
46
|
|
|
53
47
|
return Gesture.Pan()
|
|
54
48
|
.manualActivation(true)
|
|
@@ -58,21 +52,26 @@ export const useBottomSheetPanGesture = ({
|
|
|
58
52
|
isDraggingSheet.set(false);
|
|
59
53
|
isDraggingFromScrollable.set(false);
|
|
60
54
|
isScrollableLocked.set(false);
|
|
61
|
-
|
|
55
|
+
activeScrollableIndex.set(-1);
|
|
62
56
|
const touch = event.changedTouches[0] ?? event.allTouches[0];
|
|
63
57
|
if (touch !== undefined) {
|
|
64
58
|
panStartX.set(touch.absoluteX);
|
|
65
59
|
panStartY.set(touch.absoluteY);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
const entries = scrollableEntries;
|
|
61
|
+
for (let i = 0; i < entries.length; i++) {
|
|
62
|
+
const entry = entries[i];
|
|
63
|
+
if (entry === undefined) continue;
|
|
64
|
+
const layout = measure(entry.ref);
|
|
65
|
+
if (layout === null) continue;
|
|
66
|
+
const withinX =
|
|
67
|
+
touch.absoluteX >= layout.pageX &&
|
|
68
|
+
touch.absoluteX <= layout.pageX + layout.width;
|
|
69
|
+
const withinY =
|
|
70
|
+
touch.absoluteY >= layout.pageY &&
|
|
71
|
+
touch.absoluteY <= layout.pageY + layout.height;
|
|
72
|
+
if (withinX && withinY) {
|
|
73
|
+
activeScrollableIndex.set(i);
|
|
74
|
+
break;
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
}
|
|
@@ -84,12 +83,16 @@ export const useBottomSheetPanGesture = ({
|
|
|
84
83
|
if (!touch) return;
|
|
85
84
|
const deltaX = touch.absoluteX - panStartX.value;
|
|
86
85
|
const deltaY = touch.absoluteY - panStartY.value;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
const activeIdx = activeScrollableIndex.value;
|
|
87
|
+
if (activeIdx !== -1) {
|
|
88
|
+
const active = scrollableEntries[activeIdx];
|
|
89
|
+
if (
|
|
90
|
+
active !== undefined &&
|
|
91
|
+
active.scrollOffset.value > 0 &&
|
|
92
|
+
translateY.value <= 0
|
|
93
|
+
) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
93
96
|
}
|
|
94
97
|
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
95
98
|
stateManager.fail();
|
|
@@ -112,51 +115,57 @@ export const useBottomSheetPanGesture = ({
|
|
|
112
115
|
})
|
|
113
116
|
.onUpdate((event) => {
|
|
114
117
|
'worklet';
|
|
118
|
+
const activeIdx = activeScrollableIndex.value;
|
|
119
|
+
const hasActive = activeIdx !== -1;
|
|
120
|
+
const active = hasActive ? scrollableEntries[activeIdx] : undefined;
|
|
121
|
+
const activeOffset = active !== undefined ? active.scrollOffset.value : 0;
|
|
122
|
+
|
|
115
123
|
if (isDraggingSheet.value) {
|
|
116
|
-
if (isDraggingFromScrollable.value) {
|
|
117
|
-
scrollTo(
|
|
124
|
+
if (isDraggingFromScrollable.value && active !== undefined) {
|
|
125
|
+
scrollTo(active.ref, 0, 0, false);
|
|
118
126
|
}
|
|
119
127
|
} else {
|
|
120
128
|
const isDraggingDown = event.translationY > 0;
|
|
121
129
|
const canStartDrag =
|
|
122
|
-
!
|
|
123
|
-
scrollOffset.value <= 0 ||
|
|
124
|
-
!isTouchWithinScrollable.value;
|
|
130
|
+
!hasActive || activeOffset <= 0 || translateY.value > 0;
|
|
125
131
|
if (!canStartDrag || (!isDraggingDown && translateY.value <= 0)) {
|
|
126
132
|
return;
|
|
127
133
|
}
|
|
128
134
|
const isScrollableActive =
|
|
129
|
-
|
|
135
|
+
hasActive && active !== undefined && active.isGestureActive.value;
|
|
130
136
|
isDraggingSheet.set(true);
|
|
131
|
-
isDraggingFromScrollable.set(
|
|
132
|
-
isScrollableActive && isTouchWithinScrollable.value
|
|
133
|
-
);
|
|
137
|
+
isDraggingFromScrollable.set(isScrollableActive && activeOffset <= 0);
|
|
134
138
|
dragStartTranslateY.set(translateY.value - event.translationY);
|
|
135
|
-
isScrollableLocked.set(
|
|
136
|
-
if (
|
|
137
|
-
scrollTo(
|
|
139
|
+
isScrollableLocked.set(hasActive);
|
|
140
|
+
if (hasActive && active !== undefined && activeOffset <= 0) {
|
|
141
|
+
scrollTo(active.ref, 0, 0, false);
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
144
|
const rawTranslate = dragStartTranslateY.value + event.translationY;
|
|
145
|
+
const resolvedDetents = detentsValue.value;
|
|
146
|
+
const draggable = isDraggableValue.value;
|
|
147
|
+
let maxDraggableTranslateY = sheetHeight.value;
|
|
148
|
+
let foundDraggable = false;
|
|
149
|
+
for (let i = 0; i < resolvedDetents.length; i++) {
|
|
150
|
+
if (!(draggable[i] ?? true)) continue;
|
|
151
|
+
const t = sheetHeight.value - (resolvedDetents[i] ?? 0);
|
|
152
|
+
if (!foundDraggable || t > maxDraggableTranslateY) {
|
|
153
|
+
maxDraggableTranslateY = t;
|
|
154
|
+
foundDraggable = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
141
157
|
const nextTranslate = Math.min(
|
|
142
158
|
Math.max(rawTranslate, 0),
|
|
143
|
-
|
|
159
|
+
maxDraggableTranslateY
|
|
144
160
|
);
|
|
145
161
|
translateY.set(nextTranslate);
|
|
146
|
-
if (
|
|
147
|
-
isDraggingSheet.value &&
|
|
148
|
-
rawTranslate < 0 &&
|
|
149
|
-
isTouchWithinScrollable.value &&
|
|
150
|
-
hasScrollable.value
|
|
151
|
-
) {
|
|
162
|
+
if (isDraggingSheet.value && rawTranslate < 0 && hasActive) {
|
|
152
163
|
isDraggingSheet.set(false);
|
|
153
164
|
isScrollableLocked.set(false);
|
|
154
|
-
const resolvedDetentValues = detentsValue.value;
|
|
155
|
-
const draggable = isDraggableValue.value;
|
|
156
165
|
let targetSnapIndex = -1;
|
|
157
166
|
let targetSnapValue = -1;
|
|
158
|
-
for (let i =
|
|
159
|
-
const detentValue =
|
|
167
|
+
for (let i = resolvedDetents.length - 1; i >= 0; i--) {
|
|
168
|
+
const detentValue = resolvedDetents[i];
|
|
160
169
|
if (
|
|
161
170
|
detentValue !== undefined &&
|
|
162
171
|
(draggable[i] ?? true) &&
|
|
@@ -168,8 +177,8 @@ export const useBottomSheetPanGesture = ({
|
|
|
168
177
|
}
|
|
169
178
|
if (targetSnapIndex === -1) {
|
|
170
179
|
const maxSnap = sheetHeight.value;
|
|
171
|
-
for (let i =
|
|
172
|
-
if (
|
|
180
|
+
for (let i = resolvedDetents.length - 1; i >= 0; i--) {
|
|
181
|
+
if (resolvedDetents[i] === maxSnap) {
|
|
173
182
|
targetSnapIndex = i;
|
|
174
183
|
break;
|
|
175
184
|
}
|
|
@@ -5,7 +5,9 @@ import { isWorkletFunction, scheduleOnRN } from 'react-native-worklets';
|
|
|
5
5
|
import {
|
|
6
6
|
type SharedValue,
|
|
7
7
|
useAnimatedProps,
|
|
8
|
+
useAnimatedRef,
|
|
8
9
|
useAnimatedScrollHandler,
|
|
10
|
+
useSharedValue,
|
|
9
11
|
} from 'react-native-reanimated';
|
|
10
12
|
|
|
11
13
|
import { useBottomSheetContext } from './BottomSheetContext';
|
|
@@ -16,14 +18,11 @@ export const useBottomSheetScrollable = (
|
|
|
16
18
|
baseScrollEnabled: boolean | SharedValue<boolean | undefined> = true,
|
|
17
19
|
onScroll?: ScrollHandler
|
|
18
20
|
) => {
|
|
19
|
-
const {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
isScrollableLocked,
|
|
25
|
-
panGesture,
|
|
26
|
-
} = useBottomSheetContext();
|
|
21
|
+
const { isScrollableLocked, registerScrollable, panGesture } =
|
|
22
|
+
useBottomSheetContext();
|
|
23
|
+
const scrollableRef = useAnimatedRef();
|
|
24
|
+
const scrollOffset = useSharedValue(0);
|
|
25
|
+
const isGestureActive = useSharedValue(false);
|
|
27
26
|
const isWorkletScrollHandler =
|
|
28
27
|
onScroll !== undefined ? isWorkletFunction(onScroll) : false;
|
|
29
28
|
const scrollHandler = useAnimatedScrollHandler({
|
|
@@ -42,11 +41,11 @@ export const useBottomSheetScrollable = (
|
|
|
42
41
|
.simultaneousWithExternalGesture(panGesture)
|
|
43
42
|
.onStart(() => {
|
|
44
43
|
'worklet';
|
|
45
|
-
|
|
44
|
+
isGestureActive.set(true);
|
|
46
45
|
})
|
|
47
46
|
.onFinalize(() => {
|
|
48
47
|
'worklet';
|
|
49
|
-
|
|
48
|
+
isGestureActive.set(false);
|
|
50
49
|
});
|
|
51
50
|
const animatedProps = useAnimatedProps(() => {
|
|
52
51
|
const resolvedScrollEnabled =
|
|
@@ -58,18 +57,12 @@ export const useBottomSheetScrollable = (
|
|
|
58
57
|
};
|
|
59
58
|
});
|
|
60
59
|
useEffect(() => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return () => {
|
|
69
|
-
hasScrollable.set(false);
|
|
70
|
-
isScrollableGestureActive.set(false);
|
|
71
|
-
isScrollableLocked.set(false);
|
|
72
|
-
};
|
|
73
|
-
}, [hasScrollable, isScrollableGestureActive, isScrollableLocked]);
|
|
60
|
+
const unregister = registerScrollable({
|
|
61
|
+
ref: scrollableRef,
|
|
62
|
+
scrollOffset,
|
|
63
|
+
isGestureActive,
|
|
64
|
+
});
|
|
65
|
+
return unregister;
|
|
66
|
+
}, [registerScrollable, scrollableRef, scrollOffset, isGestureActive]);
|
|
74
67
|
return { scrollHandler, scrollableRef, nativeGesture, animatedProps };
|
|
75
68
|
};
|