insyd-bottom-sheet 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/SmoothSheet.tsx +64 -58
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insyd-bottom-sheet",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A smooth, physics-based bottom sheet for React Native — by Ishan Gupta. Works with Expo Go, bare workflow, and React Native CLI.",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -1,7 +1,8 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useEffect, useState } from "react";
2
2
  import {
3
3
  Dimensions,
4
4
  KeyboardAvoidingView,
5
+ Modal,
5
6
  Platform,
6
7
  Pressable,
7
8
  StyleSheet,
@@ -10,6 +11,7 @@ import {
10
11
  import {
11
12
  Gesture,
12
13
  GestureDetector,
14
+ GestureHandlerRootView,
13
15
  } from "react-native-gesture-handler";
14
16
  import Animated, {
15
17
  runOnJS,
@@ -101,27 +103,28 @@ export function SmoothSheet({
101
103
 
102
104
  const translateY = useSharedValue(SCREEN_HEIGHT);
103
105
  const backdropOpacity = useSharedValue(0);
106
+ // Keep Modal mounted during the closing animation so the sheet can slide out
107
+ const [modalVisible, setModalVisible] = useState(isVisible);
104
108
 
105
109
  useEffect(() => {
106
110
  if (isVisible) {
111
+ setModalVisible(true);
107
112
  translateY.value = withSpring(0, spring);
108
113
  backdropOpacity.value = withTiming(1, { duration: 250 });
109
114
  } else {
110
115
  translateY.value = withSpring(SCREEN_HEIGHT, spring);
111
- backdropOpacity.value = withTiming(0, { duration: 200 });
116
+ backdropOpacity.value = withTiming(0, { duration: 200 }, () => {
117
+ runOnJS(setModalVisible)(false);
118
+ });
112
119
  }
113
120
  // eslint-disable-next-line react-hooks/exhaustive-deps
114
121
  }, [isVisible]);
115
122
 
116
123
  function dismiss() {
117
124
  translateY.value = withSpring(SCREEN_HEIGHT, spring);
118
- backdropOpacity.value = withTiming(
119
- 0,
120
- { duration: 200 },
121
- () => {
122
- runOnJS(onDismiss)();
123
- },
124
- );
125
+ backdropOpacity.value = withTiming(0, { duration: 200 }, () => {
126
+ runOnJS(onDismiss)();
127
+ });
125
128
  }
126
129
 
127
130
  const panGesture = Gesture.Pan()
@@ -149,57 +152,60 @@ export function SmoothSheet({
149
152
  opacity: backdropOpacity.value,
150
153
  }));
151
154
 
152
- if (!isVisible && translateY.value === SCREEN_HEIGHT) {
153
- return null;
154
- }
155
-
156
155
  return (
157
- <View style={StyleSheet.absoluteFill} pointerEvents="box-none">
158
- {/* Backdrop */}
159
- <Animated.View
160
- style={[
161
- StyleSheet.absoluteFill,
162
- { backgroundColor: backdropColor },
163
- backdropStyle,
164
- ]}
165
- pointerEvents={isVisible ? "auto" : "none"}
166
- >
167
- <Pressable style={StyleSheet.absoluteFill} onPress={dismiss} />
168
- </Animated.View>
169
-
170
- {/* Sheet */}
171
- <Animated.View
172
- style={[
173
- styles.sheet,
174
- {
175
- borderTopLeftRadius: borderRadius,
176
- borderTopRightRadius: borderRadius,
177
- backgroundColor,
178
- minHeight: SCREEN_HEIGHT * minHeightFraction,
179
- maxHeight: SCREEN_HEIGHT * maxHeightFraction,
180
- },
181
- sheetStyle,
182
- ]}
183
- pointerEvents="box-none"
184
- >
185
- {/* Drag handle */}
186
- <GestureDetector gesture={panGesture}>
187
- <View style={styles.handleArea}>
188
- <View
189
- style={[styles.handle, { backgroundColor: handleColor }]}
190
- />
191
- </View>
192
- </GestureDetector>
193
-
194
- {/* Content */}
195
- <KeyboardAvoidingView
196
- behavior={Platform.OS === "ios" ? "padding" : "height"}
197
- style={styles.content}
156
+ <Modal
157
+ visible={modalVisible}
158
+ transparent
159
+ animationType="none"
160
+ statusBarTranslucent
161
+ onRequestClose={dismiss}
162
+ >
163
+ <GestureHandlerRootView style={StyleSheet.absoluteFill}>
164
+ {/* Backdrop */}
165
+ <Animated.View
166
+ style={[
167
+ StyleSheet.absoluteFill,
168
+ { backgroundColor: backdropColor },
169
+ backdropStyle,
170
+ ]}
171
+ >
172
+ <Pressable style={StyleSheet.absoluteFill} onPress={dismiss} />
173
+ </Animated.View>
174
+
175
+ {/* Sheet */}
176
+ <Animated.View
177
+ style={[
178
+ styles.sheet,
179
+ {
180
+ borderTopLeftRadius: borderRadius,
181
+ borderTopRightRadius: borderRadius,
182
+ backgroundColor,
183
+ minHeight: SCREEN_HEIGHT * minHeightFraction,
184
+ maxHeight: SCREEN_HEIGHT * maxHeightFraction,
185
+ },
186
+ sheetStyle,
187
+ ]}
188
+ pointerEvents="box-none"
198
189
  >
199
- {children}
200
- </KeyboardAvoidingView>
201
- </Animated.View>
202
- </View>
190
+ {/* Drag handle */}
191
+ <GestureDetector gesture={panGesture}>
192
+ <View style={styles.handleArea}>
193
+ <View
194
+ style={[styles.handle, { backgroundColor: handleColor }]}
195
+ />
196
+ </View>
197
+ </GestureDetector>
198
+
199
+ {/* Content */}
200
+ <KeyboardAvoidingView
201
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
202
+ style={styles.content}
203
+ >
204
+ {children}
205
+ </KeyboardAvoidingView>
206
+ </Animated.View>
207
+ </GestureHandlerRootView>
208
+ </Modal>
203
209
  );
204
210
  }
205
211