react-native-bottom-sheet-modal-lite 1.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/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/lib/module/BottomSheetModal.js +197 -0
- package/lib/module/BottomSheetModal.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/BottomSheetModal.d.ts +59 -0
- package/lib/typescript/BottomSheetModal.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/package.json +83 -0
- package/src/BottomSheetModal.tsx +369 -0
- package/src/index.ts +3 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
- Initial public release.
|
|
6
|
+
- Spring animations powered by React Native Reanimated.
|
|
7
|
+
- Pan gesture powered by React Native Gesture Handler.
|
|
8
|
+
- Backdrop press and pan-down dismissal.
|
|
9
|
+
- Keyboard avoidance props for replacing project-specific keyboard hooks.
|
|
10
|
+
- TypeScript declarations included.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nattawat Virunsuntornkul
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# react-native-bottom-sheet-modal-lite
|
|
2
|
+
|
|
3
|
+
A spring-animated bottom sheet modal for React Native, powered by `react-native-reanimated` and `react-native-gesture-handler`.
|
|
4
|
+
|
|
5
|
+
The default layout matches the original component:
|
|
6
|
+
|
|
7
|
+
- 300px visible height
|
|
8
|
+
- 30px draggable top area
|
|
9
|
+
- 30px top corner radius
|
|
10
|
+
- Transparent sheet background
|
|
11
|
+
- Dark 50% backdrop
|
|
12
|
+
- 200px hidden section below the screen
|
|
13
|
+
- Spring open, close, and snap-back animation
|
|
14
|
+
- Tap backdrop or drag down to dismiss
|
|
15
|
+
- Keyboard avoidance support
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install react-native-bottom-sheet-modal-lite react-native-reanimated react-native-gesture-handler
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For iOS, install CocoaPods after adding native dependencies:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
cd ios && pod install && cd ..
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Follow the Reanimated installation instructions for the version used by your app. Reanimated 4 also requires a compatible `react-native-worklets` version.
|
|
30
|
+
|
|
31
|
+
Wrap the app root with `GestureHandlerRootView`:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
35
|
+
|
|
36
|
+
export default function App() {
|
|
37
|
+
return (
|
|
38
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
39
|
+
<RootNavigator />
|
|
40
|
+
</GestureHandlerRootView>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The component also places a `GestureHandlerRootView` inside the native modal so gestures continue to work in modal content.
|
|
46
|
+
|
|
47
|
+
## Basic usage
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import React, { useState } from 'react';
|
|
51
|
+
import { Button, Text, View } from 'react-native';
|
|
52
|
+
import { BottomSheetModal } from 'react-native-bottom-sheet-modal-lite';
|
|
53
|
+
|
|
54
|
+
export default function ExampleScreen() {
|
|
55
|
+
const [visible, setVisible] = useState(false);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View style={{ flex: 1, justifyContent: 'center' }}>
|
|
59
|
+
<Button title="Open" onPress={() => setVisible(true)} />
|
|
60
|
+
|
|
61
|
+
<BottomSheetModal
|
|
62
|
+
visible={visible}
|
|
63
|
+
height={300}
|
|
64
|
+
backgroundColor="transparent"
|
|
65
|
+
onDismiss={() => setVisible(false)}
|
|
66
|
+
>
|
|
67
|
+
<View
|
|
68
|
+
style={{
|
|
69
|
+
flex: 1,
|
|
70
|
+
padding: 20,
|
|
71
|
+
backgroundColor: '#FFFFFF',
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
<Text>Bottom sheet content</Text>
|
|
75
|
+
</View>
|
|
76
|
+
</BottomSheetModal>
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
A default export is also available:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import BottomSheetModal from 'react-native-bottom-sheet-modal-lite';
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Replacing a project-specific keyboard hook
|
|
89
|
+
|
|
90
|
+
The original component used a local hook such as:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
const { behavior, offset } = useKeyboardAvoidConfig({ hasHeader: true });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
An npm package cannot import a hook from the consumer's project. Pass its values through props instead:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
const { behavior, offset } = useKeyboardAvoidConfig({ hasHeader: true });
|
|
100
|
+
|
|
101
|
+
<BottomSheetModal
|
|
102
|
+
visible={visible}
|
|
103
|
+
onDismiss={() => setVisible(false)}
|
|
104
|
+
keyboardBehavior={behavior}
|
|
105
|
+
keyboardVerticalOffset={offset}
|
|
106
|
+
>
|
|
107
|
+
{children}
|
|
108
|
+
</BottomSheetModal>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Without these props, the package defaults to `padding` on iOS, `height` on Android, and an offset of `0`.
|
|
112
|
+
|
|
113
|
+
## Props
|
|
114
|
+
|
|
115
|
+
| Prop | Type | Default | Description |
|
|
116
|
+
| --- | --- | --- | --- |
|
|
117
|
+
| `visible` | `boolean` | required | Controls modal visibility. |
|
|
118
|
+
| `onDismiss` | `() => void` | required | Called after a user dismisses the sheet. |
|
|
119
|
+
| `children` | `ReactNode` | required | Sheet content. |
|
|
120
|
+
| `height` | `number` | `300` | Visible sheet height. |
|
|
121
|
+
| `backgroundColor` | `string` | `transparent` | Sheet background color. |
|
|
122
|
+
| `backdropColor` | `string` | `rgba(0, 0, 0, 0.5)` | Backdrop color. |
|
|
123
|
+
| `closeOnBackdropPress` | `boolean` | `true` | Allows backdrop press to dismiss. |
|
|
124
|
+
| `enablePanDownToClose` | `boolean` | `true` | Allows dragging the handle down to dismiss. |
|
|
125
|
+
| `dragHandleHeight` | `number` | `30` | Height of the draggable top area. |
|
|
126
|
+
| `extraHeight` | `number` | `200` | Hidden height rendered below the screen. |
|
|
127
|
+
| `borderRadius` | `number` | `30` | Top corner radius. |
|
|
128
|
+
| `dismissThreshold` | `number` | `0.5` | Drag-distance ratio required to dismiss. |
|
|
129
|
+
| `dismissVelocity` | `number` | `900` | Downward velocity required to dismiss. |
|
|
130
|
+
| `keyboardBehavior` | `height \| position \| padding` | platform default | `KeyboardAvoidingView` behavior. |
|
|
131
|
+
| `keyboardVerticalOffset` | `number` | `0` | Keyboard offset. |
|
|
132
|
+
| `keyboardAvoidingEnabled` | `boolean` | `true` | Enables keyboard avoidance. |
|
|
133
|
+
| `containerStyle` | `StyleProp<ViewStyle>` | — | Sheet container style. |
|
|
134
|
+
| `backdropStyle` | `StyleProp<ViewStyle>` | — | Backdrop style. |
|
|
135
|
+
| `dragHandleStyle` | `StyleProp<ViewStyle>` | — | Draggable area style. |
|
|
136
|
+
| `contentContainerStyle` | `StyleProp<ViewStyle>` | — | Children wrapper style. |
|
|
137
|
+
|
|
138
|
+
## Local verification
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
npm install
|
|
142
|
+
npm run typecheck
|
|
143
|
+
npm run build
|
|
144
|
+
npm run pack:check
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Create a tarball:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
npm pack
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Install it in a React Native app:
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
npm install /absolute/path/react-native-bottom-sheet-modal-lite-1.0.0.tgz
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Publishing
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
npm login
|
|
163
|
+
npm publish
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { KeyboardAvoidingView, Modal, Platform, Pressable, StyleSheet, useWindowDimensions, View } from 'react-native';
|
|
5
|
+
import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
|
6
|
+
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
7
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
+
const DEFAULT_HEIGHT = 300;
|
|
9
|
+
const DEFAULT_DRAG_HANDLE_HEIGHT = 30;
|
|
10
|
+
const DEFAULT_EXTRA_HEIGHT = 200;
|
|
11
|
+
const DEFAULT_BORDER_RADIUS = 30;
|
|
12
|
+
const DEFAULT_DISMISS_VELOCITY = 900;
|
|
13
|
+
const SPRING_CONFIG = {
|
|
14
|
+
damping: 28,
|
|
15
|
+
stiffness: 300,
|
|
16
|
+
mass: 0.4,
|
|
17
|
+
overshootClamping: true
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A spring-animated React Native bottom sheet modal powered by Reanimated and
|
|
21
|
+
* React Native Gesture Handler.
|
|
22
|
+
*
|
|
23
|
+
* The default layout intentionally matches the original component: a 30px
|
|
24
|
+
* draggable top area, 30px top radius, transparent sheet background, and an
|
|
25
|
+
* extra 200px section rendered below the screen.
|
|
26
|
+
*/
|
|
27
|
+
export function BottomSheetModal({
|
|
28
|
+
visible,
|
|
29
|
+
onDismiss,
|
|
30
|
+
children,
|
|
31
|
+
backgroundColor = 'transparent',
|
|
32
|
+
height = DEFAULT_HEIGHT,
|
|
33
|
+
backdropColor = 'rgba(0, 0, 0, 0.5)',
|
|
34
|
+
closeOnBackdropPress = true,
|
|
35
|
+
enablePanDownToClose = true,
|
|
36
|
+
dragHandleHeight = DEFAULT_DRAG_HANDLE_HEIGHT,
|
|
37
|
+
extraHeight = DEFAULT_EXTRA_HEIGHT,
|
|
38
|
+
borderRadius = DEFAULT_BORDER_RADIUS,
|
|
39
|
+
dismissThreshold = 0.5,
|
|
40
|
+
dismissVelocity = DEFAULT_DISMISS_VELOCITY,
|
|
41
|
+
keyboardBehavior = Platform.OS === 'ios' ? 'padding' : 'height',
|
|
42
|
+
keyboardVerticalOffset = 0,
|
|
43
|
+
keyboardAvoidingEnabled = true,
|
|
44
|
+
containerStyle,
|
|
45
|
+
backdropStyle,
|
|
46
|
+
dragHandleStyle,
|
|
47
|
+
contentContainerStyle,
|
|
48
|
+
testID,
|
|
49
|
+
backdropAccessibilityLabel = 'Close bottom sheet'
|
|
50
|
+
}) {
|
|
51
|
+
const {
|
|
52
|
+
height: screenHeight
|
|
53
|
+
} = useWindowDimensions();
|
|
54
|
+
const translateY = useSharedValue(screenHeight);
|
|
55
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
56
|
+
const isClosingRef = useRef(false);
|
|
57
|
+
const resolvedHeight = useMemo(() => Math.max(Number.isFinite(height) ? height : DEFAULT_HEIGHT, 0), [height]);
|
|
58
|
+
const resolvedHandleHeight = useMemo(() => Math.max(Number.isFinite(dragHandleHeight) ? dragHandleHeight : 0, 0), [dragHandleHeight]);
|
|
59
|
+
const resolvedExtraHeight = useMemo(() => Math.max(Number.isFinite(extraHeight) ? extraHeight : 0, 0), [extraHeight]);
|
|
60
|
+
const resolvedThreshold = useMemo(() => Math.min(Math.max(dismissThreshold, 0), 1), [dismissThreshold]);
|
|
61
|
+
const finishDismiss = useCallback(() => {
|
|
62
|
+
isClosingRef.current = false;
|
|
63
|
+
setIsDragging(false);
|
|
64
|
+
onDismiss();
|
|
65
|
+
}, [onDismiss]);
|
|
66
|
+
const restoreOpenPosition = useCallback(() => {
|
|
67
|
+
translateY.value = withSpring(0, SPRING_CONFIG);
|
|
68
|
+
setIsDragging(false);
|
|
69
|
+
}, [translateY]);
|
|
70
|
+
const animateDismiss = useCallback(() => {
|
|
71
|
+
if (isClosingRef.current) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
isClosingRef.current = true;
|
|
75
|
+
translateY.value = withSpring(screenHeight, SPRING_CONFIG, finished => {
|
|
76
|
+
if (finished) {
|
|
77
|
+
runOnJS(finishDismiss)();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}, [finishDismiss, screenHeight, translateY]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (visible) {
|
|
83
|
+
isClosingRef.current = false;
|
|
84
|
+
translateY.value = withSpring(0, SPRING_CONFIG);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
translateY.value = withSpring(screenHeight, SPRING_CONFIG);
|
|
88
|
+
setIsDragging(false);
|
|
89
|
+
}, [screenHeight, translateY, visible]);
|
|
90
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
91
|
+
height: resolvedHeight + resolvedExtraHeight,
|
|
92
|
+
transform: [{
|
|
93
|
+
translateY: translateY.value + resolvedExtraHeight
|
|
94
|
+
}]
|
|
95
|
+
}));
|
|
96
|
+
const panGesture = useMemo(() => Gesture.Pan().enabled(enablePanDownToClose).onBegin(() => {
|
|
97
|
+
runOnJS(setIsDragging)(true);
|
|
98
|
+
}).onUpdate(event => {
|
|
99
|
+
translateY.value = Math.max(0, Math.min(resolvedHeight, event.translationY));
|
|
100
|
+
}).onEnd(event => {
|
|
101
|
+
const shouldDismiss = event.translationY > resolvedHeight * resolvedThreshold || event.velocityY > dismissVelocity;
|
|
102
|
+
if (shouldDismiss) {
|
|
103
|
+
translateY.value = withSpring(screenHeight, SPRING_CONFIG, finished => {
|
|
104
|
+
if (finished) {
|
|
105
|
+
runOnJS(finishDismiss)();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
} else {
|
|
109
|
+
translateY.value = withSpring(0, SPRING_CONFIG);
|
|
110
|
+
runOnJS(setIsDragging)(false);
|
|
111
|
+
}
|
|
112
|
+
}).onFinalize((_event, success) => {
|
|
113
|
+
if (!success) {
|
|
114
|
+
runOnJS(restoreOpenPosition)();
|
|
115
|
+
}
|
|
116
|
+
}), [dismissVelocity, enablePanDownToClose, finishDismiss, resolvedHeight, resolvedThreshold, restoreOpenPosition, screenHeight, translateY]);
|
|
117
|
+
const handleBackdropPress = useCallback(() => {
|
|
118
|
+
if (!closeOnBackdropPress || isDragging) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
animateDismiss();
|
|
122
|
+
}, [animateDismiss, closeOnBackdropPress, isDragging]);
|
|
123
|
+
return /*#__PURE__*/_jsx(Modal, {
|
|
124
|
+
visible: visible,
|
|
125
|
+
transparent: true,
|
|
126
|
+
animationType: "fade",
|
|
127
|
+
statusBarTranslucent: true,
|
|
128
|
+
onRequestClose: animateDismiss,
|
|
129
|
+
children: /*#__PURE__*/_jsx(KeyboardAvoidingView, {
|
|
130
|
+
style: styles.flex,
|
|
131
|
+
enabled: keyboardAvoidingEnabled,
|
|
132
|
+
behavior: keyboardBehavior,
|
|
133
|
+
keyboardVerticalOffset: keyboardVerticalOffset,
|
|
134
|
+
children: /*#__PURE__*/_jsxs(GestureHandlerRootView, {
|
|
135
|
+
style: styles.modalBackdrop,
|
|
136
|
+
children: [/*#__PURE__*/_jsx(Pressable, {
|
|
137
|
+
accessibilityRole: "button",
|
|
138
|
+
accessibilityLabel: backdropAccessibilityLabel,
|
|
139
|
+
style: [styles.backdrop, {
|
|
140
|
+
backgroundColor: backdropColor
|
|
141
|
+
}, backdropStyle],
|
|
142
|
+
onPress: handleBackdropPress,
|
|
143
|
+
pointerEvents: isDragging ? 'none' : 'auto'
|
|
144
|
+
}), /*#__PURE__*/_jsxs(Animated.View, {
|
|
145
|
+
testID: testID,
|
|
146
|
+
style: [styles.content, {
|
|
147
|
+
backgroundColor,
|
|
148
|
+
borderTopLeftRadius: borderRadius,
|
|
149
|
+
borderTopRightRadius: borderRadius
|
|
150
|
+
}, animatedStyle, containerStyle],
|
|
151
|
+
children: [/*#__PURE__*/_jsx(GestureDetector, {
|
|
152
|
+
gesture: panGesture,
|
|
153
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
154
|
+
style: [styles.dragHandle, {
|
|
155
|
+
height: resolvedHandleHeight,
|
|
156
|
+
borderTopLeftRadius: borderRadius,
|
|
157
|
+
borderTopRightRadius: borderRadius
|
|
158
|
+
}, dragHandleStyle]
|
|
159
|
+
})
|
|
160
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
161
|
+
style: [styles.childrenContainer, {
|
|
162
|
+
height: Math.max(resolvedHeight - resolvedHandleHeight, 0),
|
|
163
|
+
transform: [{
|
|
164
|
+
translateY: -resolvedHandleHeight
|
|
165
|
+
}]
|
|
166
|
+
}, contentContainerStyle],
|
|
167
|
+
children: children
|
|
168
|
+
})]
|
|
169
|
+
})]
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const styles = StyleSheet.create({
|
|
175
|
+
flex: {
|
|
176
|
+
flex: 1
|
|
177
|
+
},
|
|
178
|
+
modalBackdrop: {
|
|
179
|
+
flex: 1,
|
|
180
|
+
justifyContent: 'flex-end'
|
|
181
|
+
},
|
|
182
|
+
backdrop: {
|
|
183
|
+
...StyleSheet.absoluteFill
|
|
184
|
+
},
|
|
185
|
+
content: {
|
|
186
|
+
elevation: 5,
|
|
187
|
+
overflow: 'hidden'
|
|
188
|
+
},
|
|
189
|
+
dragHandle: {
|
|
190
|
+
zIndex: 100
|
|
191
|
+
},
|
|
192
|
+
childrenContainer: {
|
|
193
|
+
width: '100%'
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
export default BottomSheetModal;
|
|
197
|
+
//# sourceMappingURL=BottomSheetModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","KeyboardAvoidingView","Modal","Platform","Pressable","StyleSheet","useWindowDimensions","View","Animated","runOnJS","useAnimatedStyle","useSharedValue","withSpring","Gesture","GestureDetector","GestureHandlerRootView","jsx","_jsx","jsxs","_jsxs","DEFAULT_HEIGHT","DEFAULT_DRAG_HANDLE_HEIGHT","DEFAULT_EXTRA_HEIGHT","DEFAULT_BORDER_RADIUS","DEFAULT_DISMISS_VELOCITY","SPRING_CONFIG","damping","stiffness","mass","overshootClamping","BottomSheetModal","visible","onDismiss","children","backgroundColor","height","backdropColor","closeOnBackdropPress","enablePanDownToClose","dragHandleHeight","extraHeight","borderRadius","dismissThreshold","dismissVelocity","keyboardBehavior","OS","keyboardVerticalOffset","keyboardAvoidingEnabled","containerStyle","backdropStyle","dragHandleStyle","contentContainerStyle","testID","backdropAccessibilityLabel","screenHeight","translateY","isDragging","setIsDragging","isClosingRef","resolvedHeight","Math","max","Number","isFinite","resolvedHandleHeight","resolvedExtraHeight","resolvedThreshold","min","finishDismiss","current","restoreOpenPosition","value","animateDismiss","finished","animatedStyle","transform","panGesture","Pan","enabled","onBegin","onUpdate","event","translationY","onEnd","shouldDismiss","velocityY","onFinalize","_event","success","handleBackdropPress","transparent","animationType","statusBarTranslucent","onRequestClose","style","styles","flex","behavior","modalBackdrop","accessibilityRole","accessibilityLabel","backdrop","onPress","pointerEvents","content","borderTopLeftRadius","borderTopRightRadius","gesture","dragHandle","childrenContainer","create","justifyContent","absoluteFill","elevation","overflow","zIndex","width"],"sourceRoot":"../../src","sources":["BottomSheetModal.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["BottomSheetModal","default"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAQ,uBAAoB;AACrD,SAASC,OAAO,QAAQ,uBAAoB","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
import { type KeyboardAvoidingViewProps, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
export type BottomSheetModalProps = {
|
|
4
|
+
/** Controls whether the modal is visible. */
|
|
5
|
+
visible: boolean;
|
|
6
|
+
/** Called after a user dismisses the sheet. Set visible to false here. */
|
|
7
|
+
onDismiss: () => void;
|
|
8
|
+
/** Content rendered inside the sheet. */
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
/** Visible sheet height in logical pixels. */
|
|
11
|
+
height?: number;
|
|
12
|
+
/** Sheet background color. Defaults to transparent to match the original component. */
|
|
13
|
+
backgroundColor?: string;
|
|
14
|
+
/** Backdrop color. */
|
|
15
|
+
backdropColor?: string;
|
|
16
|
+
/** Allows tapping the backdrop to dismiss the sheet. */
|
|
17
|
+
closeOnBackdropPress?: boolean;
|
|
18
|
+
/** Allows dragging the top area downward to dismiss the sheet. */
|
|
19
|
+
enablePanDownToClose?: boolean;
|
|
20
|
+
/** Height of the draggable top area. */
|
|
21
|
+
dragHandleHeight?: number;
|
|
22
|
+
/** Extra hidden height rendered below the screen. */
|
|
23
|
+
extraHeight?: number;
|
|
24
|
+
/** Top-left and top-right corner radius. */
|
|
25
|
+
borderRadius?: number;
|
|
26
|
+
/** Drag distance ratio required to dismiss. */
|
|
27
|
+
dismissThreshold?: number;
|
|
28
|
+
/** Downward gesture velocity required to dismiss. */
|
|
29
|
+
dismissVelocity?: number;
|
|
30
|
+
/** KeyboardAvoidingView behavior. */
|
|
31
|
+
keyboardBehavior?: KeyboardAvoidingViewProps['behavior'];
|
|
32
|
+
/** KeyboardAvoidingView vertical offset. */
|
|
33
|
+
keyboardVerticalOffset?: number;
|
|
34
|
+
/** Enables KeyboardAvoidingView. */
|
|
35
|
+
keyboardAvoidingEnabled?: boolean;
|
|
36
|
+
/** Style applied to the bottom sheet container. */
|
|
37
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
38
|
+
/** Style applied to the backdrop. */
|
|
39
|
+
backdropStyle?: StyleProp<ViewStyle>;
|
|
40
|
+
/** Style applied to the draggable top area. */
|
|
41
|
+
dragHandleStyle?: StyleProp<ViewStyle>;
|
|
42
|
+
/** Style applied to the children container. */
|
|
43
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
44
|
+
/** Optional test id applied to the sheet. */
|
|
45
|
+
testID?: string;
|
|
46
|
+
/** Accessibility label for the backdrop close button. */
|
|
47
|
+
backdropAccessibilityLabel?: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* A spring-animated React Native bottom sheet modal powered by Reanimated and
|
|
51
|
+
* React Native Gesture Handler.
|
|
52
|
+
*
|
|
53
|
+
* The default layout intentionally matches the original component: a 30px
|
|
54
|
+
* draggable top area, 30px top radius, transparent sheet background, and an
|
|
55
|
+
* extra 200px section rendered below the screen.
|
|
56
|
+
*/
|
|
57
|
+
export declare function BottomSheetModal({ visible, onDismiss, children, backgroundColor, height, backdropColor, closeOnBackdropPress, enablePanDownToClose, dragHandleHeight, extraHeight, borderRadius, dismissThreshold, dismissVelocity, keyboardBehavior, keyboardVerticalOffset, keyboardAvoidingEnabled, containerStyle, backdropStyle, dragHandleStyle, contentContainerStyle, testID, backdropAccessibilityLabel, }: BottomSheetModalProps): React.JSX.Element;
|
|
58
|
+
export default BottomSheetModal;
|
|
59
|
+
//# sourceMappingURL=BottomSheetModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BottomSheetModal.d.ts","sourceRoot":"","sources":["../../src/BottomSheetModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AACf,OAAO,EAEL,KAAK,yBAAyB,EAI9B,KAAK,SAAS,EAId,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AA0BtB,MAAM,MAAM,qBAAqB,GAAG;IAClC,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IAEjB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,IAAI,CAAC;IAEtB,yCAAyC;IACzC,QAAQ,EAAE,SAAS,CAAC;IAEpB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,sBAAsB;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,wDAAwD;IACxD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B,kEAAkE;IAClE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qCAAqC;IACrC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC,UAAU,CAAC,CAAC;IAEzD,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC,oCAAoC;IACpC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,mDAAmD;IACnD,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEtC,qCAAqC;IACrC,aAAa,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAErC,+CAA+C;IAC/C,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEvC,+CAA+C;IAC/C,qBAAqB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7C,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,yDAAyD;IACzD,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,EACT,QAAQ,EACR,eAA+B,EAC/B,MAAuB,EACvB,aAAoC,EACpC,oBAA2B,EAC3B,oBAA2B,EAC3B,gBAA6C,EAC7C,WAAkC,EAClC,YAAoC,EACpC,gBAAsB,EACtB,eAA0C,EAC1C,gBAA+D,EAC/D,sBAA0B,EAC1B,uBAA8B,EAC9B,cAAc,EACd,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,MAAM,EACN,0BAAiD,GAClD,EAAE,qBAAqB,qBAuMvB;AAyBD,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAoB,CAAC;AAC7C,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-bottom-sheet-modal-lite",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A spring-animated bottom sheet modal for React Native using Reanimated and Gesture Handler.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react-native",
|
|
7
|
+
"bottom-sheet",
|
|
8
|
+
"modal",
|
|
9
|
+
"gesture",
|
|
10
|
+
"reanimated",
|
|
11
|
+
"gesture-handler",
|
|
12
|
+
"typescript",
|
|
13
|
+
"ios",
|
|
14
|
+
"android"
|
|
15
|
+
],
|
|
16
|
+
"author": "Nattawat Virunsuntornkul",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"main": "./lib/module/index.js",
|
|
19
|
+
"module": "./lib/module/index.js",
|
|
20
|
+
"types": "./lib/typescript/index.d.ts",
|
|
21
|
+
"react-native": "./src/index.ts",
|
|
22
|
+
"source": "./src/index.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"source": "./src/index.ts",
|
|
26
|
+
"types": "./lib/typescript/index.d.ts",
|
|
27
|
+
"default": "./lib/module/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"lib",
|
|
33
|
+
"src",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"CHANGELOG.md"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"scripts": {
|
|
40
|
+
"clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
|
|
41
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
42
|
+
"build": "bob build",
|
|
43
|
+
"prepare": "npm run clean && npm run build",
|
|
44
|
+
"pack:check": "npm pack --dry-run"
|
|
45
|
+
},
|
|
46
|
+
"react-native-builder-bob": {
|
|
47
|
+
"source": "src",
|
|
48
|
+
"output": "lib",
|
|
49
|
+
"targets": [
|
|
50
|
+
[
|
|
51
|
+
"module",
|
|
52
|
+
{
|
|
53
|
+
"esm": true
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
"typescript",
|
|
58
|
+
{
|
|
59
|
+
"project": "tsconfig.build.json"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"react": ">=18.2.0",
|
|
66
|
+
"react-native": ">=0.72.0",
|
|
67
|
+
"react-native-reanimated": ">=3.0.0 <5.0.0",
|
|
68
|
+
"react-native-gesture-handler": ">=2.9.0 <4.0.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@types/react": "^19.2.14",
|
|
72
|
+
"react": "19.2.7",
|
|
73
|
+
"react-native": "0.86.0",
|
|
74
|
+
"react-native-builder-bob": "^0.42.1",
|
|
75
|
+
"typescript": "^6.0.3",
|
|
76
|
+
"react-native-reanimated": "^4.4.1",
|
|
77
|
+
"react-native-gesture-handler": "^3.0.1",
|
|
78
|
+
"react-native-worklets": "^0.9.2"
|
|
79
|
+
},
|
|
80
|
+
"publishConfig": {
|
|
81
|
+
"access": "public"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
type ReactNode,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import {
|
|
10
|
+
KeyboardAvoidingView,
|
|
11
|
+
type KeyboardAvoidingViewProps,
|
|
12
|
+
Modal,
|
|
13
|
+
Platform,
|
|
14
|
+
Pressable,
|
|
15
|
+
type StyleProp,
|
|
16
|
+
StyleSheet,
|
|
17
|
+
useWindowDimensions,
|
|
18
|
+
View,
|
|
19
|
+
type ViewStyle,
|
|
20
|
+
} from 'react-native';
|
|
21
|
+
import Animated, {
|
|
22
|
+
runOnJS,
|
|
23
|
+
useAnimatedStyle,
|
|
24
|
+
useSharedValue,
|
|
25
|
+
withSpring,
|
|
26
|
+
} from 'react-native-reanimated';
|
|
27
|
+
import {
|
|
28
|
+
Gesture,
|
|
29
|
+
GestureDetector,
|
|
30
|
+
GestureHandlerRootView,
|
|
31
|
+
} from 'react-native-gesture-handler';
|
|
32
|
+
|
|
33
|
+
const DEFAULT_HEIGHT = 300;
|
|
34
|
+
const DEFAULT_DRAG_HANDLE_HEIGHT = 30;
|
|
35
|
+
const DEFAULT_EXTRA_HEIGHT = 200;
|
|
36
|
+
const DEFAULT_BORDER_RADIUS = 30;
|
|
37
|
+
const DEFAULT_DISMISS_VELOCITY = 900;
|
|
38
|
+
|
|
39
|
+
const SPRING_CONFIG = {
|
|
40
|
+
damping: 28,
|
|
41
|
+
stiffness: 300,
|
|
42
|
+
mass: 0.4,
|
|
43
|
+
overshootClamping: true,
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
export type BottomSheetModalProps = {
|
|
47
|
+
/** Controls whether the modal is visible. */
|
|
48
|
+
visible: boolean;
|
|
49
|
+
|
|
50
|
+
/** Called after a user dismisses the sheet. Set visible to false here. */
|
|
51
|
+
onDismiss: () => void;
|
|
52
|
+
|
|
53
|
+
/** Content rendered inside the sheet. */
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
|
|
56
|
+
/** Visible sheet height in logical pixels. */
|
|
57
|
+
height?: number;
|
|
58
|
+
|
|
59
|
+
/** Sheet background color. Defaults to transparent to match the original component. */
|
|
60
|
+
backgroundColor?: string;
|
|
61
|
+
|
|
62
|
+
/** Backdrop color. */
|
|
63
|
+
backdropColor?: string;
|
|
64
|
+
|
|
65
|
+
/** Allows tapping the backdrop to dismiss the sheet. */
|
|
66
|
+
closeOnBackdropPress?: boolean;
|
|
67
|
+
|
|
68
|
+
/** Allows dragging the top area downward to dismiss the sheet. */
|
|
69
|
+
enablePanDownToClose?: boolean;
|
|
70
|
+
|
|
71
|
+
/** Height of the draggable top area. */
|
|
72
|
+
dragHandleHeight?: number;
|
|
73
|
+
|
|
74
|
+
/** Extra hidden height rendered below the screen. */
|
|
75
|
+
extraHeight?: number;
|
|
76
|
+
|
|
77
|
+
/** Top-left and top-right corner radius. */
|
|
78
|
+
borderRadius?: number;
|
|
79
|
+
|
|
80
|
+
/** Drag distance ratio required to dismiss. */
|
|
81
|
+
dismissThreshold?: number;
|
|
82
|
+
|
|
83
|
+
/** Downward gesture velocity required to dismiss. */
|
|
84
|
+
dismissVelocity?: number;
|
|
85
|
+
|
|
86
|
+
/** KeyboardAvoidingView behavior. */
|
|
87
|
+
keyboardBehavior?: KeyboardAvoidingViewProps['behavior'];
|
|
88
|
+
|
|
89
|
+
/** KeyboardAvoidingView vertical offset. */
|
|
90
|
+
keyboardVerticalOffset?: number;
|
|
91
|
+
|
|
92
|
+
/** Enables KeyboardAvoidingView. */
|
|
93
|
+
keyboardAvoidingEnabled?: boolean;
|
|
94
|
+
|
|
95
|
+
/** Style applied to the bottom sheet container. */
|
|
96
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
97
|
+
|
|
98
|
+
/** Style applied to the backdrop. */
|
|
99
|
+
backdropStyle?: StyleProp<ViewStyle>;
|
|
100
|
+
|
|
101
|
+
/** Style applied to the draggable top area. */
|
|
102
|
+
dragHandleStyle?: StyleProp<ViewStyle>;
|
|
103
|
+
|
|
104
|
+
/** Style applied to the children container. */
|
|
105
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
106
|
+
|
|
107
|
+
/** Optional test id applied to the sheet. */
|
|
108
|
+
testID?: string;
|
|
109
|
+
|
|
110
|
+
/** Accessibility label for the backdrop close button. */
|
|
111
|
+
backdropAccessibilityLabel?: string;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A spring-animated React Native bottom sheet modal powered by Reanimated and
|
|
116
|
+
* React Native Gesture Handler.
|
|
117
|
+
*
|
|
118
|
+
* The default layout intentionally matches the original component: a 30px
|
|
119
|
+
* draggable top area, 30px top radius, transparent sheet background, and an
|
|
120
|
+
* extra 200px section rendered below the screen.
|
|
121
|
+
*/
|
|
122
|
+
export function BottomSheetModal({
|
|
123
|
+
visible,
|
|
124
|
+
onDismiss,
|
|
125
|
+
children,
|
|
126
|
+
backgroundColor = 'transparent',
|
|
127
|
+
height = DEFAULT_HEIGHT,
|
|
128
|
+
backdropColor = 'rgba(0, 0, 0, 0.5)',
|
|
129
|
+
closeOnBackdropPress = true,
|
|
130
|
+
enablePanDownToClose = true,
|
|
131
|
+
dragHandleHeight = DEFAULT_DRAG_HANDLE_HEIGHT,
|
|
132
|
+
extraHeight = DEFAULT_EXTRA_HEIGHT,
|
|
133
|
+
borderRadius = DEFAULT_BORDER_RADIUS,
|
|
134
|
+
dismissThreshold = 0.5,
|
|
135
|
+
dismissVelocity = DEFAULT_DISMISS_VELOCITY,
|
|
136
|
+
keyboardBehavior = Platform.OS === 'ios' ? 'padding' : 'height',
|
|
137
|
+
keyboardVerticalOffset = 0,
|
|
138
|
+
keyboardAvoidingEnabled = true,
|
|
139
|
+
containerStyle,
|
|
140
|
+
backdropStyle,
|
|
141
|
+
dragHandleStyle,
|
|
142
|
+
contentContainerStyle,
|
|
143
|
+
testID,
|
|
144
|
+
backdropAccessibilityLabel = 'Close bottom sheet',
|
|
145
|
+
}: BottomSheetModalProps) {
|
|
146
|
+
const { height: screenHeight } = useWindowDimensions();
|
|
147
|
+
const translateY = useSharedValue(screenHeight);
|
|
148
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
149
|
+
const isClosingRef = useRef(false);
|
|
150
|
+
|
|
151
|
+
const resolvedHeight = useMemo(
|
|
152
|
+
() => Math.max(Number.isFinite(height) ? height : DEFAULT_HEIGHT, 0),
|
|
153
|
+
[height]
|
|
154
|
+
);
|
|
155
|
+
const resolvedHandleHeight = useMemo(
|
|
156
|
+
() => Math.max(Number.isFinite(dragHandleHeight) ? dragHandleHeight : 0, 0),
|
|
157
|
+
[dragHandleHeight]
|
|
158
|
+
);
|
|
159
|
+
const resolvedExtraHeight = useMemo(
|
|
160
|
+
() => Math.max(Number.isFinite(extraHeight) ? extraHeight : 0, 0),
|
|
161
|
+
[extraHeight]
|
|
162
|
+
);
|
|
163
|
+
const resolvedThreshold = useMemo(
|
|
164
|
+
() => Math.min(Math.max(dismissThreshold, 0), 1),
|
|
165
|
+
[dismissThreshold]
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const finishDismiss = useCallback(() => {
|
|
169
|
+
isClosingRef.current = false;
|
|
170
|
+
setIsDragging(false);
|
|
171
|
+
onDismiss();
|
|
172
|
+
}, [onDismiss]);
|
|
173
|
+
|
|
174
|
+
const restoreOpenPosition = useCallback(() => {
|
|
175
|
+
translateY.value = withSpring(0, SPRING_CONFIG);
|
|
176
|
+
setIsDragging(false);
|
|
177
|
+
}, [translateY]);
|
|
178
|
+
|
|
179
|
+
const animateDismiss = useCallback(() => {
|
|
180
|
+
if (isClosingRef.current) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
isClosingRef.current = true;
|
|
185
|
+
translateY.value = withSpring(screenHeight, SPRING_CONFIG, (finished) => {
|
|
186
|
+
if (finished) {
|
|
187
|
+
runOnJS(finishDismiss)();
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}, [finishDismiss, screenHeight, translateY]);
|
|
191
|
+
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (visible) {
|
|
194
|
+
isClosingRef.current = false;
|
|
195
|
+
translateY.value = withSpring(0, SPRING_CONFIG);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
translateY.value = withSpring(screenHeight, SPRING_CONFIG);
|
|
200
|
+
setIsDragging(false);
|
|
201
|
+
}, [screenHeight, translateY, visible]);
|
|
202
|
+
|
|
203
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
204
|
+
height: resolvedHeight + resolvedExtraHeight,
|
|
205
|
+
transform: [
|
|
206
|
+
{
|
|
207
|
+
translateY: translateY.value + resolvedExtraHeight,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
}));
|
|
211
|
+
|
|
212
|
+
const panGesture = useMemo(
|
|
213
|
+
() =>
|
|
214
|
+
Gesture.Pan()
|
|
215
|
+
.enabled(enablePanDownToClose)
|
|
216
|
+
.onBegin(() => {
|
|
217
|
+
runOnJS(setIsDragging)(true);
|
|
218
|
+
})
|
|
219
|
+
.onUpdate((event) => {
|
|
220
|
+
translateY.value = Math.max(
|
|
221
|
+
0,
|
|
222
|
+
Math.min(resolvedHeight, event.translationY)
|
|
223
|
+
);
|
|
224
|
+
})
|
|
225
|
+
.onEnd((event) => {
|
|
226
|
+
const shouldDismiss =
|
|
227
|
+
event.translationY > resolvedHeight * resolvedThreshold ||
|
|
228
|
+
event.velocityY > dismissVelocity;
|
|
229
|
+
|
|
230
|
+
if (shouldDismiss) {
|
|
231
|
+
translateY.value = withSpring(
|
|
232
|
+
screenHeight,
|
|
233
|
+
SPRING_CONFIG,
|
|
234
|
+
(finished) => {
|
|
235
|
+
if (finished) {
|
|
236
|
+
runOnJS(finishDismiss)();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
} else {
|
|
241
|
+
translateY.value = withSpring(0, SPRING_CONFIG);
|
|
242
|
+
runOnJS(setIsDragging)(false);
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
.onFinalize((_event, success) => {
|
|
246
|
+
if (!success) {
|
|
247
|
+
runOnJS(restoreOpenPosition)();
|
|
248
|
+
}
|
|
249
|
+
}),
|
|
250
|
+
[
|
|
251
|
+
dismissVelocity,
|
|
252
|
+
enablePanDownToClose,
|
|
253
|
+
finishDismiss,
|
|
254
|
+
resolvedHeight,
|
|
255
|
+
resolvedThreshold,
|
|
256
|
+
restoreOpenPosition,
|
|
257
|
+
screenHeight,
|
|
258
|
+
translateY,
|
|
259
|
+
]
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
const handleBackdropPress = useCallback(() => {
|
|
263
|
+
if (!closeOnBackdropPress || isDragging) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
animateDismiss();
|
|
268
|
+
}, [animateDismiss, closeOnBackdropPress, isDragging]);
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<Modal
|
|
272
|
+
visible={visible}
|
|
273
|
+
transparent
|
|
274
|
+
animationType="fade"
|
|
275
|
+
statusBarTranslucent
|
|
276
|
+
onRequestClose={animateDismiss}
|
|
277
|
+
>
|
|
278
|
+
<KeyboardAvoidingView
|
|
279
|
+
style={styles.flex}
|
|
280
|
+
enabled={keyboardAvoidingEnabled}
|
|
281
|
+
behavior={keyboardBehavior}
|
|
282
|
+
keyboardVerticalOffset={keyboardVerticalOffset}
|
|
283
|
+
>
|
|
284
|
+
<GestureHandlerRootView style={styles.modalBackdrop}>
|
|
285
|
+
<Pressable
|
|
286
|
+
accessibilityRole="button"
|
|
287
|
+
accessibilityLabel={backdropAccessibilityLabel}
|
|
288
|
+
style={[
|
|
289
|
+
styles.backdrop,
|
|
290
|
+
{ backgroundColor: backdropColor },
|
|
291
|
+
backdropStyle,
|
|
292
|
+
]}
|
|
293
|
+
onPress={handleBackdropPress}
|
|
294
|
+
pointerEvents={isDragging ? 'none' : 'auto'}
|
|
295
|
+
/>
|
|
296
|
+
|
|
297
|
+
<Animated.View
|
|
298
|
+
testID={testID}
|
|
299
|
+
style={[
|
|
300
|
+
styles.content,
|
|
301
|
+
{
|
|
302
|
+
backgroundColor,
|
|
303
|
+
borderTopLeftRadius: borderRadius,
|
|
304
|
+
borderTopRightRadius: borderRadius,
|
|
305
|
+
},
|
|
306
|
+
animatedStyle,
|
|
307
|
+
containerStyle,
|
|
308
|
+
]}
|
|
309
|
+
>
|
|
310
|
+
<GestureDetector gesture={panGesture}>
|
|
311
|
+
<View
|
|
312
|
+
style={[
|
|
313
|
+
styles.dragHandle,
|
|
314
|
+
{
|
|
315
|
+
height: resolvedHandleHeight,
|
|
316
|
+
borderTopLeftRadius: borderRadius,
|
|
317
|
+
borderTopRightRadius: borderRadius,
|
|
318
|
+
},
|
|
319
|
+
dragHandleStyle,
|
|
320
|
+
]}
|
|
321
|
+
/>
|
|
322
|
+
</GestureDetector>
|
|
323
|
+
|
|
324
|
+
<View
|
|
325
|
+
style={[
|
|
326
|
+
styles.childrenContainer,
|
|
327
|
+
{
|
|
328
|
+
height: Math.max(
|
|
329
|
+
resolvedHeight - resolvedHandleHeight,
|
|
330
|
+
0
|
|
331
|
+
),
|
|
332
|
+
transform: [{ translateY: -resolvedHandleHeight }],
|
|
333
|
+
},
|
|
334
|
+
contentContainerStyle,
|
|
335
|
+
]}
|
|
336
|
+
>
|
|
337
|
+
{children}
|
|
338
|
+
</View>
|
|
339
|
+
</Animated.View>
|
|
340
|
+
</GestureHandlerRootView>
|
|
341
|
+
</KeyboardAvoidingView>
|
|
342
|
+
</Modal>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const styles = StyleSheet.create({
|
|
347
|
+
flex: {
|
|
348
|
+
flex: 1,
|
|
349
|
+
},
|
|
350
|
+
modalBackdrop: {
|
|
351
|
+
flex: 1,
|
|
352
|
+
justifyContent: 'flex-end',
|
|
353
|
+
},
|
|
354
|
+
backdrop: {
|
|
355
|
+
...StyleSheet.absoluteFill,
|
|
356
|
+
},
|
|
357
|
+
content: {
|
|
358
|
+
elevation: 5,
|
|
359
|
+
overflow: 'hidden',
|
|
360
|
+
},
|
|
361
|
+
dragHandle: {
|
|
362
|
+
zIndex: 100,
|
|
363
|
+
},
|
|
364
|
+
childrenContainer: {
|
|
365
|
+
width: '100%',
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
export default BottomSheetModal;
|
package/src/index.ts
ADDED