@swmansion/react-native-bottom-sheet 0.5.5 → 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 +33 -23
- 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 +44 -53
- package/src/useBottomSheetScrollable.ts +16 -23
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
animated?: boolean;
|
|
7
|
-
};
|
|
8
|
-
export interface BottomSheetScrollViewProps extends Omit<ScrollViewProps, 'onScroll' | 'ref'> {
|
|
1
|
+
import type { Ref, ReactElement } from 'react';
|
|
2
|
+
import { ScrollView, type NativeScrollEvent, type ScrollViewProps } from 'react-native';
|
|
3
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
4
|
+
export type BottomSheetScrollViewProps = Omit<ScrollViewProps, 'onScroll' | 'scrollEnabled' | 'ref'> & {
|
|
5
|
+
scrollEnabled?: boolean | SharedValue<boolean | undefined>;
|
|
9
6
|
onScroll?: (event: NativeScrollEvent) => void;
|
|
10
|
-
ref?: Ref<
|
|
11
|
-
}
|
|
12
|
-
export declare const BottomSheetScrollView: ({ scrollEnabled, onScroll, ref, ...rest }: BottomSheetScrollViewProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
-
export type BottomSheetScrollViewMethods = {
|
|
14
|
-
scrollTo: (options: ScrollToOptions) => void;
|
|
7
|
+
ref?: Ref<ScrollView>;
|
|
15
8
|
};
|
|
16
|
-
export
|
|
9
|
+
export declare const BottomSheetScrollView: (props: BottomSheetScrollViewProps) => ReactElement;
|
|
17
10
|
//# sourceMappingURL=BottomSheetScrollView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheetScrollView.d.ts","sourceRoot":"","sources":["../../../src/BottomSheetScrollView.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"BottomSheetScrollView.d.ts","sourceRoot":"","sources":["../../../src/BottomSheetScrollView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAI3D,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC3C,eAAe,EACf,UAAU,GAAG,eAAe,GAAG,KAAK,CACrC,GAAG;IACF,aAAa,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC3D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,GAAG,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAwC,CACxE,KAAK,EAAE,0BAA0B,KAC9B,YAAY,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ComponentType, type Ref } from 'react';
|
|
2
|
+
import type { NativeScrollEvent } from 'react-native';
|
|
3
|
+
import { type SharedValue } from 'react-native-reanimated';
|
|
4
|
+
export declare function bottomSheetScrollable<P extends Record<string, any>, R = unknown>(ScrollableComponent: ComponentType<P>): ({ scrollEnabled, onScroll, ref, ...rest }: Omit<P, "onScroll" | "scrollEnabled" | "ref"> & {
|
|
5
|
+
scrollEnabled?: boolean | SharedValue<boolean | undefined>;
|
|
6
|
+
onScroll?: (event: NativeScrollEvent) => void;
|
|
7
|
+
ref?: Ref<R>;
|
|
8
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=bottomSheetScrollable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bottomSheetScrollable.d.ts","sourceRoot":"","sources":["../../../src/bottomSheetScrollable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,GAAG,EAAuB,MAAM,OAAO,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIrE,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7B,CAAC,GAAG,OAAO,EACX,mBAAmB,EAAE,aAAa,CAAC,CAAC,CAAC,IAI7B,2CAKL,IAAI,CAAC,CAAC,EAAE,UAAU,GAAG,eAAe,GAAG,KAAK,CAAC,GAAG;IACjD,aAAa,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC3D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;CACd,6CAkBF"}
|
|
@@ -4,10 +4,10 @@ export { ModalBottomSheet } from './ModalBottomSheet';
|
|
|
4
4
|
export type { ModalBottomSheetProps } from './ModalBottomSheet';
|
|
5
5
|
export { BottomSheetProvider } from './BottomSheetProvider';
|
|
6
6
|
export { BottomSheetFlatList } from './BottomSheetFlatList';
|
|
7
|
-
export type {
|
|
7
|
+
export type { BottomSheetFlatListProps } from './BottomSheetFlatList';
|
|
8
8
|
export { BottomSheetScrollView } from './BottomSheetScrollView';
|
|
9
|
-
export type {
|
|
9
|
+
export type { BottomSheetScrollViewProps } from './BottomSheetScrollView';
|
|
10
10
|
export type { Detent, DetentValue } from './BottomSheetBase';
|
|
11
11
|
export { programmatic } from './BottomSheetBase';
|
|
12
|
-
export {
|
|
12
|
+
export { bottomSheetScrollable } from './bottomSheetScrollable';
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PanGesture } from 'react-native-gesture-handler';
|
|
2
|
-
import { type
|
|
2
|
+
import { type SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import type { ScrollableEntry } from './BottomSheetContext';
|
|
3
4
|
interface BottomSheetPanGestureParams {
|
|
4
5
|
animationTarget: SharedValue<number>;
|
|
5
6
|
translateY: SharedValue<number>;
|
|
@@ -7,14 +8,11 @@ interface BottomSheetPanGestureParams {
|
|
|
7
8
|
detentsValue: SharedValue<number[]>;
|
|
8
9
|
isDraggableValue: SharedValue<boolean[]>;
|
|
9
10
|
currentIndex: SharedValue<number>;
|
|
10
|
-
|
|
11
|
-
hasScrollable: SharedValue<boolean>;
|
|
12
|
-
isScrollableGestureActive: SharedValue<boolean>;
|
|
11
|
+
scrollableEntries: ScrollableEntry[];
|
|
13
12
|
isScrollableLocked: SharedValue<boolean>;
|
|
14
|
-
scrollableRef: AnimatedRef<any>;
|
|
15
13
|
handleIndexChange: (nextIndex: number) => void;
|
|
16
14
|
animateToIndex: (targetIndex: number, velocity?: number) => void;
|
|
17
15
|
}
|
|
18
|
-
export declare const useBottomSheetPanGesture: ({ animationTarget, translateY, sheetHeight, detentsValue, isDraggableValue, currentIndex,
|
|
16
|
+
export declare const useBottomSheetPanGesture: ({ animationTarget, translateY, sheetHeight, detentsValue, isDraggableValue, currentIndex, scrollableEntries, isScrollableLocked, handleIndexChange, animateToIndex, }: BottomSheetPanGestureParams) => PanGesture;
|
|
19
17
|
export {};
|
|
20
18
|
//# sourceMappingURL=useBottomSheetPanGesture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBottomSheetPanGesture.d.ts","sourceRoot":"","sources":["../../../src/useBottomSheetPanGesture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAG/D,OAAO,EAGL,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"useBottomSheetPanGesture.d.ts","sourceRoot":"","sources":["../../../src/useBottomSheetPanGesture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAG/D,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,UAAU,2BAA2B;IACnC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,gBAAgB,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IACzC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,kBAAkB,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACzC,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE;AAED,eAAO,MAAM,wBAAwB,GAAI,uKAWtC,2BAA2B,KAAG,UA6LhC,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { type SharedValue } from 'react-native-reanimated';
|
|
|
3
3
|
type ScrollHandler = (event: NativeScrollEvent) => void;
|
|
4
4
|
export declare const useBottomSheetScrollable: (baseScrollEnabled?: boolean | SharedValue<boolean | undefined>, onScroll?: ScrollHandler) => {
|
|
5
5
|
scrollHandler: import("react-native-reanimated").ScrollHandlerProcessed<Record<string, unknown>>;
|
|
6
|
-
scrollableRef: import("react-native-reanimated").AnimatedRef<any
|
|
6
|
+
scrollableRef: import("react-native-reanimated").AnimatedRef<import("react").Component<{}, {}, any>>;
|
|
7
7
|
nativeGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/nativeGesture").NativeGesture;
|
|
8
8
|
animatedProps: Partial<{
|
|
9
9
|
scrollEnabled: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBottomSheetScrollable.d.ts","sourceRoot":"","sources":["../../../src/useBottomSheetScrollable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EACL,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"useBottomSheetScrollable.d.ts","sourceRoot":"","sources":["../../../src/useBottomSheetScrollable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EACL,KAAK,WAAW,EAKjB,MAAM,yBAAyB,CAAC;AAIjC,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAExD,eAAO,MAAM,wBAAwB,GACnC,oBAAmB,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,SAAS,CAAQ,EACpE,WAAW,aAAa;;;;;;;CAiDzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swmansion/react-native-bottom-sheet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Provides bottom-sheet components for React Native.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"@react-native/babel-preset": "0.83.0",
|
|
64
64
|
"@react-native/eslint-config": "0.83.0",
|
|
65
65
|
"@types/react": "19.2.14",
|
|
66
|
+
"babel-plugin-react-compiler": "1.0.0",
|
|
66
67
|
"del-cli": "6.0.0",
|
|
67
68
|
"eslint": "9.39.2",
|
|
68
69
|
"eslint-config-prettier": "10.1.8",
|
package/src/BottomSheetBase.tsx
CHANGED
|
@@ -4,7 +4,6 @@ import type { LayoutChangeEvent } from 'react-native';
|
|
|
4
4
|
import { Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
|
|
5
5
|
import type { SharedValue, WithSpringConfig } from 'react-native-reanimated';
|
|
6
6
|
import Animated, {
|
|
7
|
-
useAnimatedRef,
|
|
8
7
|
useAnimatedReaction,
|
|
9
8
|
useAnimatedStyle,
|
|
10
9
|
useDerivedValue,
|
|
@@ -15,7 +14,10 @@ import { scheduleOnUI } from 'react-native-worklets';
|
|
|
15
14
|
import { GestureDetector } from 'react-native-gesture-handler';
|
|
16
15
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
17
16
|
import { Portal } from './BottomSheetProvider';
|
|
18
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
BottomSheetContextProvider,
|
|
19
|
+
type ScrollableEntry,
|
|
20
|
+
} from './BottomSheetContext';
|
|
19
21
|
import {
|
|
20
22
|
clampIndex,
|
|
21
23
|
isDetentProgrammatic,
|
|
@@ -97,11 +99,17 @@ export const BottomSheetBase = ({
|
|
|
97
99
|
const translateY = useSharedValue(initialMaxSnap);
|
|
98
100
|
const animationTarget = useSharedValue(NaN);
|
|
99
101
|
const sheetHeight = useSharedValue(initialMaxSnap);
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
const [scrollableEntries, setScrollableEntries] = useState<ScrollableEntry[]>(
|
|
103
|
+
[]
|
|
104
|
+
);
|
|
103
105
|
const isScrollableLocked = useSharedValue(false);
|
|
104
|
-
|
|
106
|
+
|
|
107
|
+
const registerScrollable = useCallback((entry: ScrollableEntry) => {
|
|
108
|
+
setScrollableEntries((prev) => [...prev, entry]);
|
|
109
|
+
return () => {
|
|
110
|
+
setScrollableEntries((prev) => prev.filter((e) => e !== entry));
|
|
111
|
+
};
|
|
112
|
+
}, []);
|
|
105
113
|
|
|
106
114
|
const detentsValue = useSharedValue(normalizedDetents);
|
|
107
115
|
const isDraggableValue = useSharedValue(isDraggable);
|
|
@@ -185,11 +193,8 @@ export const BottomSheetBase = ({
|
|
|
185
193
|
detentsValue,
|
|
186
194
|
isDraggableValue,
|
|
187
195
|
currentIndex,
|
|
188
|
-
|
|
189
|
-
hasScrollable,
|
|
190
|
-
isScrollableGestureActive,
|
|
196
|
+
scrollableEntries,
|
|
191
197
|
isScrollableLocked,
|
|
192
|
-
scrollableRef,
|
|
193
198
|
handleIndexChange,
|
|
194
199
|
animateToIndex,
|
|
195
200
|
});
|
|
@@ -225,11 +230,8 @@ export const BottomSheetBase = ({
|
|
|
225
230
|
position: internalPosition,
|
|
226
231
|
index: currentIndex,
|
|
227
232
|
sheetHeight,
|
|
228
|
-
scrollOffset,
|
|
229
|
-
scrollableRef,
|
|
230
|
-
hasScrollable,
|
|
231
|
-
isScrollableGestureActive,
|
|
232
233
|
isScrollableLocked,
|
|
234
|
+
registerScrollable,
|
|
233
235
|
panGesture,
|
|
234
236
|
}}
|
|
235
237
|
>
|
|
@@ -2,16 +2,19 @@ import { createContext, useContext } from 'react';
|
|
|
2
2
|
import type { PanGesture } from 'react-native-gesture-handler';
|
|
3
3
|
import type { AnimatedRef, SharedValue } from 'react-native-reanimated';
|
|
4
4
|
|
|
5
|
+
export interface ScrollableEntry {
|
|
6
|
+
ref: AnimatedRef<any>;
|
|
7
|
+
scrollOffset: SharedValue<number>;
|
|
8
|
+
isGestureActive: SharedValue<boolean>;
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
export interface BottomSheetContextType {
|
|
6
12
|
translateY: SharedValue<number>;
|
|
7
13
|
position: SharedValue<number>;
|
|
8
14
|
index: SharedValue<number>;
|
|
9
15
|
sheetHeight: SharedValue<number>;
|
|
10
|
-
scrollOffset: SharedValue<number>;
|
|
11
|
-
scrollableRef: AnimatedRef<any>;
|
|
12
|
-
hasScrollable: SharedValue<boolean>;
|
|
13
|
-
isScrollableGestureActive: SharedValue<boolean>;
|
|
14
16
|
isScrollableLocked: SharedValue<boolean>;
|
|
17
|
+
registerScrollable: (entry: ScrollableEntry) => () => void;
|
|
15
18
|
panGesture: PanGesture;
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -1,63 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
1
|
+
import { FlatList, type NativeScrollEvent } from 'react-native';
|
|
2
|
+
import type {
|
|
3
|
+
FlatListPropsWithLayout,
|
|
4
|
+
SharedValue,
|
|
5
|
+
} from 'react-native-reanimated';
|
|
6
|
+
import type { Ref, ReactElement } from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { bottomSheetScrollable } from './bottomSheetScrollable';
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
10
|
+
export type BottomSheetFlatListProps<T> = Omit<
|
|
11
|
+
FlatListPropsWithLayout<T>,
|
|
12
|
+
'onScroll' | 'scrollEnabled' | 'ref'
|
|
13
|
+
> & {
|
|
14
|
+
scrollEnabled?: boolean | SharedValue<boolean | undefined>;
|
|
12
15
|
onScroll?: (event: NativeScrollEvent) => void;
|
|
13
|
-
ref?: Ref<
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const BottomSheetFlatList = <T,>({
|
|
17
|
-
scrollEnabled,
|
|
18
|
-
onScroll,
|
|
19
|
-
ref,
|
|
20
|
-
...rest
|
|
21
|
-
}: BottomSheetFlatListProps<T>) => {
|
|
22
|
-
const { scrollHandler, scrollableRef, nativeGesture, animatedProps } =
|
|
23
|
-
useBottomSheetScrollable(scrollEnabled, onScroll);
|
|
24
|
-
|
|
25
|
-
useImperativeHandle(
|
|
26
|
-
ref,
|
|
27
|
-
() => ({
|
|
28
|
-
scrollToOffset: ({ offset, animated }) => {
|
|
29
|
-
const resolvedAnimated = animated ?? true;
|
|
30
|
-
scheduleOnUI(
|
|
31
|
-
(
|
|
32
|
-
animatedRef: Parameters<typeof scrollTo>[0],
|
|
33
|
-
y: number,
|
|
34
|
-
shouldAnimate: boolean
|
|
35
|
-
) => {
|
|
36
|
-
'worklet';
|
|
37
|
-
scrollTo(animatedRef, 0, y, shouldAnimate);
|
|
38
|
-
},
|
|
39
|
-
scrollableRef,
|
|
40
|
-
offset,
|
|
41
|
-
resolvedAnimated
|
|
42
|
-
);
|
|
43
|
-
},
|
|
44
|
-
}),
|
|
45
|
-
[scrollableRef]
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<GestureDetector gesture={nativeGesture}>
|
|
50
|
-
<Animated.FlatList
|
|
51
|
-
{...rest}
|
|
52
|
-
animatedProps={animatedProps}
|
|
53
|
-
ref={scrollableRef}
|
|
54
|
-
onScroll={scrollHandler}
|
|
55
|
-
scrollEventThrottle={16}
|
|
56
|
-
/>
|
|
57
|
-
</GestureDetector>
|
|
58
|
-
);
|
|
16
|
+
ref?: Ref<FlatList<T>>;
|
|
59
17
|
};
|
|
60
18
|
|
|
61
|
-
export
|
|
62
|
-
|
|
63
|
-
|
|
19
|
+
export const BottomSheetFlatList = bottomSheetScrollable(FlatList) as <T>(
|
|
20
|
+
props: BottomSheetFlatListProps<T>
|
|
21
|
+
) => ReactElement;
|
|
@@ -1,66 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { Ref, ReactElement } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ScrollView,
|
|
4
|
+
type NativeScrollEvent,
|
|
5
|
+
type ScrollViewProps,
|
|
6
|
+
} from 'react-native';
|
|
7
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
6
8
|
|
|
7
|
-
import {
|
|
9
|
+
import { bottomSheetScrollable } from './bottomSheetScrollable';
|
|
8
10
|
|
|
9
|
-
type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
export type BottomSheetScrollViewProps = Omit<
|
|
12
|
+
ScrollViewProps,
|
|
13
|
+
'onScroll' | 'scrollEnabled' | 'ref'
|
|
14
|
+
> & {
|
|
15
|
+
scrollEnabled?: boolean | SharedValue<boolean | undefined>;
|
|
13
16
|
onScroll?: (event: NativeScrollEvent) => void;
|
|
14
|
-
ref?: Ref<
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const BottomSheetScrollView = ({
|
|
18
|
-
scrollEnabled,
|
|
19
|
-
onScroll,
|
|
20
|
-
ref,
|
|
21
|
-
...rest
|
|
22
|
-
}: BottomSheetScrollViewProps) => {
|
|
23
|
-
const { scrollHandler, scrollableRef, nativeGesture, animatedProps } =
|
|
24
|
-
useBottomSheetScrollable(scrollEnabled, onScroll);
|
|
25
|
-
|
|
26
|
-
useImperativeHandle(
|
|
27
|
-
ref,
|
|
28
|
-
() => ({
|
|
29
|
-
scrollTo: ({ x = 0, y = 0, animated }) => {
|
|
30
|
-
const resolvedAnimated = animated ?? true;
|
|
31
|
-
scheduleOnUI(
|
|
32
|
-
(
|
|
33
|
-
animatedRef: Parameters<typeof scrollTo>[0],
|
|
34
|
-
xValue: number,
|
|
35
|
-
yValue: number,
|
|
36
|
-
shouldAnimate: boolean
|
|
37
|
-
) => {
|
|
38
|
-
'worklet';
|
|
39
|
-
scrollTo(animatedRef, xValue, yValue, shouldAnimate);
|
|
40
|
-
},
|
|
41
|
-
scrollableRef,
|
|
42
|
-
x,
|
|
43
|
-
y,
|
|
44
|
-
resolvedAnimated
|
|
45
|
-
);
|
|
46
|
-
},
|
|
47
|
-
}),
|
|
48
|
-
[scrollableRef]
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<GestureDetector gesture={nativeGesture}>
|
|
53
|
-
<Animated.ScrollView
|
|
54
|
-
{...rest}
|
|
55
|
-
animatedProps={animatedProps}
|
|
56
|
-
ref={scrollableRef}
|
|
57
|
-
onScroll={scrollHandler}
|
|
58
|
-
scrollEventThrottle={16}
|
|
59
|
-
/>
|
|
60
|
-
</GestureDetector>
|
|
61
|
-
);
|
|
17
|
+
ref?: Ref<ScrollView>;
|
|
62
18
|
};
|
|
63
19
|
|
|
64
|
-
export
|
|
65
|
-
|
|
66
|
-
|
|
20
|
+
export const BottomSheetScrollView = bottomSheetScrollable(ScrollView) as (
|
|
21
|
+
props: BottomSheetScrollViewProps
|
|
22
|
+
) => ReactElement;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ComponentType, type Ref, useImperativeHandle } from 'react';
|
|
2
|
+
import type { NativeScrollEvent } from 'react-native';
|
|
3
|
+
import { GestureDetector } from 'react-native-gesture-handler';
|
|
4
|
+
import Animated, { type SharedValue } from 'react-native-reanimated';
|
|
5
|
+
|
|
6
|
+
import { useBottomSheetScrollable } from './useBottomSheetScrollable';
|
|
7
|
+
|
|
8
|
+
export function bottomSheetScrollable<
|
|
9
|
+
P extends Record<string, any>,
|
|
10
|
+
R = unknown
|
|
11
|
+
>(ScrollableComponent: ComponentType<P>) {
|
|
12
|
+
const AnimatedComponent =
|
|
13
|
+
Animated.createAnimatedComponent(ScrollableComponent);
|
|
14
|
+
|
|
15
|
+
return ({
|
|
16
|
+
scrollEnabled,
|
|
17
|
+
onScroll,
|
|
18
|
+
ref,
|
|
19
|
+
...rest
|
|
20
|
+
}: Omit<P, 'onScroll' | 'scrollEnabled' | 'ref'> & {
|
|
21
|
+
scrollEnabled?: boolean | SharedValue<boolean | undefined>;
|
|
22
|
+
onScroll?: (event: NativeScrollEvent) => void;
|
|
23
|
+
ref?: Ref<R>;
|
|
24
|
+
}) => {
|
|
25
|
+
const { scrollHandler, scrollableRef, nativeGesture, animatedProps } =
|
|
26
|
+
useBottomSheetScrollable(scrollEnabled, onScroll);
|
|
27
|
+
|
|
28
|
+
useImperativeHandle(ref, () => scrollableRef.current as R, [scrollableRef]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<GestureDetector gesture={nativeGesture}>
|
|
32
|
+
<AnimatedComponent
|
|
33
|
+
{...(rest as any)}
|
|
34
|
+
animatedProps={animatedProps}
|
|
35
|
+
ref={scrollableRef}
|
|
36
|
+
onScroll={scrollHandler}
|
|
37
|
+
scrollEventThrottle={16}
|
|
38
|
+
/>
|
|
39
|
+
</GestureDetector>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -4,15 +4,9 @@ export { ModalBottomSheet } from './ModalBottomSheet';
|
|
|
4
4
|
export type { ModalBottomSheetProps } from './ModalBottomSheet';
|
|
5
5
|
export { BottomSheetProvider } from './BottomSheetProvider';
|
|
6
6
|
export { BottomSheetFlatList } from './BottomSheetFlatList';
|
|
7
|
-
export type {
|
|
8
|
-
BottomSheetFlatListMethods,
|
|
9
|
-
BottomSheetFlatListProps,
|
|
10
|
-
} from './BottomSheetFlatList';
|
|
7
|
+
export type { BottomSheetFlatListProps } from './BottomSheetFlatList';
|
|
11
8
|
export { BottomSheetScrollView } from './BottomSheetScrollView';
|
|
12
|
-
export type {
|
|
13
|
-
BottomSheetScrollViewMethods,
|
|
14
|
-
BottomSheetScrollViewProps,
|
|
15
|
-
} from './BottomSheetScrollView';
|
|
9
|
+
export type { BottomSheetScrollViewProps } from './BottomSheetScrollView';
|
|
16
10
|
export type { Detent, DetentValue } from './BottomSheetBase';
|
|
17
11
|
export { programmatic } from './BottomSheetBase';
|
|
18
|
-
export {
|
|
12
|
+
export { bottomSheetScrollable } from './bottomSheetScrollable';
|
|
@@ -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,13 +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
|
-
|
|
93
|
-
|
|
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
|
+
}
|
|
94
96
|
}
|
|
95
97
|
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
96
98
|
stateManager.fail();
|
|
@@ -113,36 +115,30 @@ export const useBottomSheetPanGesture = ({
|
|
|
113
115
|
})
|
|
114
116
|
.onUpdate((event) => {
|
|
115
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
|
+
|
|
116
123
|
if (isDraggingSheet.value) {
|
|
117
|
-
if (isDraggingFromScrollable.value) {
|
|
118
|
-
scrollTo(
|
|
124
|
+
if (isDraggingFromScrollable.value && active !== undefined) {
|
|
125
|
+
scrollTo(active.ref, 0, 0, false);
|
|
119
126
|
}
|
|
120
127
|
} else {
|
|
121
128
|
const isDraggingDown = event.translationY > 0;
|
|
122
129
|
const canStartDrag =
|
|
123
|
-
!
|
|
124
|
-
scrollOffset.value <= 0 ||
|
|
125
|
-
translateY.value > 0 ||
|
|
126
|
-
!isTouchWithinScrollable.value;
|
|
130
|
+
!hasActive || activeOffset <= 0 || translateY.value > 0;
|
|
127
131
|
if (!canStartDrag || (!isDraggingDown && translateY.value <= 0)) {
|
|
128
132
|
return;
|
|
129
133
|
}
|
|
130
134
|
const isScrollableActive =
|
|
131
|
-
|
|
135
|
+
hasActive && active !== undefined && active.isGestureActive.value;
|
|
132
136
|
isDraggingSheet.set(true);
|
|
133
|
-
isDraggingFromScrollable.set(
|
|
134
|
-
isScrollableActive &&
|
|
135
|
-
isTouchWithinScrollable.value &&
|
|
136
|
-
scrollOffset.value <= 0
|
|
137
|
-
);
|
|
137
|
+
isDraggingFromScrollable.set(isScrollableActive && activeOffset <= 0);
|
|
138
138
|
dragStartTranslateY.set(translateY.value - event.translationY);
|
|
139
|
-
isScrollableLocked.set(
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
hasScrollable.value &&
|
|
143
|
-
scrollOffset.value <= 0
|
|
144
|
-
) {
|
|
145
|
-
scrollTo(scrollableRef, 0, 0, false);
|
|
139
|
+
isScrollableLocked.set(hasActive);
|
|
140
|
+
if (hasActive && active !== undefined && activeOffset <= 0) {
|
|
141
|
+
scrollTo(active.ref, 0, 0, false);
|
|
146
142
|
}
|
|
147
143
|
}
|
|
148
144
|
const rawTranslate = dragStartTranslateY.value + event.translationY;
|
|
@@ -163,12 +159,7 @@ export const useBottomSheetPanGesture = ({
|
|
|
163
159
|
maxDraggableTranslateY
|
|
164
160
|
);
|
|
165
161
|
translateY.set(nextTranslate);
|
|
166
|
-
if (
|
|
167
|
-
isDraggingSheet.value &&
|
|
168
|
-
rawTranslate < 0 &&
|
|
169
|
-
isTouchWithinScrollable.value &&
|
|
170
|
-
hasScrollable.value
|
|
171
|
-
) {
|
|
162
|
+
if (isDraggingSheet.value && rawTranslate < 0 && hasActive) {
|
|
172
163
|
isDraggingSheet.set(false);
|
|
173
164
|
isScrollableLocked.set(false);
|
|
174
165
|
let targetSnapIndex = -1;
|