@umituz/react-native-bottom-sheet 1.1.7 → 1.1.9
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-bottom-sheet",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "Modern, performant bottom sheets for React Native with preset configurations, keyboard handling, and smooth animations",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@gorhom/bottom-sheet": ">=5.0.0",
|
|
33
33
|
"@umituz/react-native-design-system": "*",
|
|
34
|
-
"@umituz/react-native-theme": "*",
|
|
34
|
+
"@umituz/react-native-design-system-theme": "*",
|
|
35
35
|
"react": ">=18.2.0",
|
|
36
36
|
"react-native": ">=0.74.0",
|
|
37
37
|
"react-native-gesture-handler": ">=2.16.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@types/react": "^18.2.45",
|
|
44
44
|
"@types/react-native": "^0.73.0",
|
|
45
45
|
"@umituz/react-native-design-system": "latest",
|
|
46
|
-
"@umituz/react-native-theme": "latest",
|
|
46
|
+
"@umituz/react-native-design-system-theme": "latest",
|
|
47
47
|
"react": "^18.2.0",
|
|
48
48
|
"react-native": "^0.74.0",
|
|
49
49
|
"react-native-gesture-handler": "~2.16.1",
|
package/src/index.ts
CHANGED
|
@@ -108,3 +108,8 @@ export {
|
|
|
108
108
|
|
|
109
109
|
// Re-export BottomSheetModalProvider for convenience
|
|
110
110
|
export { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
|
111
|
+
|
|
112
|
+
// Safe provider that ensures Reanimated is ready before rendering
|
|
113
|
+
export {
|
|
114
|
+
SafeBottomSheetModalProvider,
|
|
115
|
+
} from './presentation/components/SafeBottomSheetModalProvider';
|
|
@@ -36,7 +36,7 @@ import GorhomBottomSheet, {
|
|
|
36
36
|
BottomSheetBackdrop,
|
|
37
37
|
type BottomSheetBackdropProps,
|
|
38
38
|
} from '@gorhom/bottom-sheet';
|
|
39
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
39
|
+
import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
|
|
40
40
|
import type {
|
|
41
41
|
BottomSheetConfig,
|
|
42
42
|
BottomSheetPreset,
|
|
@@ -156,66 +156,7 @@ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
|
|
|
156
156
|
const sheetRef = React.useRef<GorhomBottomSheet>(null);
|
|
157
157
|
const [isMounted, setIsMounted] = useState(false);
|
|
158
158
|
|
|
159
|
-
//
|
|
160
|
-
// This prevents layoutState.get errors during initial render
|
|
161
|
-
// @gorhom/bottom-sheet uses useAnimatedDetents which accesses layoutState.get
|
|
162
|
-
// during initialization, so we need to wait for Reanimated to be fully ready
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
// Use a longer delay to ensure Reanimated is fully initialized
|
|
165
|
-
// This is critical because @gorhom/bottom-sheet's internal hooks
|
|
166
|
-
// access layoutState.get immediately when the component renders
|
|
167
|
-
const timer = setTimeout(() => {
|
|
168
|
-
// Use multiple animation frames to ensure Reanimated worklets are ready
|
|
169
|
-
requestAnimationFrame(() => {
|
|
170
|
-
requestAnimationFrame(() => {
|
|
171
|
-
requestAnimationFrame(() => {
|
|
172
|
-
setIsMounted(true);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
}, 300); // Increased delay to 300ms to ensure Reanimated is fully initialized
|
|
177
|
-
|
|
178
|
-
return () => {
|
|
179
|
-
clearTimeout(timer);
|
|
180
|
-
};
|
|
181
|
-
}, []);
|
|
182
|
-
|
|
183
|
-
// Expose ref methods
|
|
184
|
-
React.useImperativeHandle(ref, () => ({
|
|
185
|
-
snapToIndex: (index: number) => {
|
|
186
|
-
if (isMounted) {
|
|
187
|
-
sheetRef.current?.snapToIndex(index);
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
snapToPosition: (position: string | number) => {
|
|
191
|
-
if (isMounted) {
|
|
192
|
-
sheetRef.current?.snapToPosition(position);
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
expand: () => {
|
|
196
|
-
if (isMounted) {
|
|
197
|
-
sheetRef.current?.expand();
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
collapse: () => {
|
|
201
|
-
if (isMounted) {
|
|
202
|
-
sheetRef.current?.collapse();
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
close: () => {
|
|
206
|
-
if (isMounted) {
|
|
207
|
-
sheetRef.current?.close();
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
}));
|
|
211
|
-
|
|
212
|
-
// Don't compute config or callbacks until mounted to prevent early hook execution
|
|
213
|
-
// This ensures @gorhom/bottom-sheet's internal hooks don't run before Reanimated is ready
|
|
214
|
-
if (!isMounted) {
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Get configuration from preset or custom
|
|
159
|
+
// Get configuration from preset or custom (must be before useImperativeHandle)
|
|
219
160
|
const config: BottomSheetConfig = useMemo(() => {
|
|
220
161
|
if (customSnapPoints) {
|
|
221
162
|
return BottomSheetUtils.createConfig({
|
|
@@ -244,7 +185,31 @@ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
|
|
|
244
185
|
enableDynamicSizing,
|
|
245
186
|
]);
|
|
246
187
|
|
|
247
|
-
//
|
|
188
|
+
// Ensure component is mounted after Reanimated is ready
|
|
189
|
+
// This prevents layoutState.get errors during initial render
|
|
190
|
+
// @gorhom/bottom-sheet uses useAnimatedDetents which accesses layoutState.get
|
|
191
|
+
// during initialization, so we need to wait for Reanimated to be fully ready
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
// Use a longer delay to ensure Reanimated is fully initialized
|
|
194
|
+
// This is critical because @gorhom/bottom-sheet's internal hooks
|
|
195
|
+
// access layoutState.get immediately when the component renders
|
|
196
|
+
const timer = setTimeout(() => {
|
|
197
|
+
// Use multiple animation frames to ensure Reanimated worklets are ready
|
|
198
|
+
requestAnimationFrame(() => {
|
|
199
|
+
requestAnimationFrame(() => {
|
|
200
|
+
requestAnimationFrame(() => {
|
|
201
|
+
setIsMounted(true);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}, 500); // Increased delay to 500ms to ensure Reanimated is fully initialized
|
|
206
|
+
|
|
207
|
+
return () => {
|
|
208
|
+
clearTimeout(timer);
|
|
209
|
+
};
|
|
210
|
+
}, []);
|
|
211
|
+
|
|
212
|
+
// Render backdrop component (must be before early return to maintain hook order)
|
|
248
213
|
const renderBackdrop = useCallback(
|
|
249
214
|
(props: BottomSheetBackdropProps) =>
|
|
250
215
|
enableBackdrop ? (
|
|
@@ -259,7 +224,7 @@ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
|
|
|
259
224
|
[enableBackdrop, config.backdropAppearsOnIndex, config.backdropDisappearsOnIndex]
|
|
260
225
|
);
|
|
261
226
|
|
|
262
|
-
// Handle sheet changes
|
|
227
|
+
// Handle sheet changes (must be before early return to maintain hook order)
|
|
263
228
|
const handleSheetChange = useCallback(
|
|
264
229
|
(index: number) => {
|
|
265
230
|
onChange?.(index);
|
|
@@ -270,6 +235,42 @@ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
|
|
|
270
235
|
[onChange, onClose]
|
|
271
236
|
);
|
|
272
237
|
|
|
238
|
+
// Expose ref methods (must be before early return to maintain hook order)
|
|
239
|
+
React.useImperativeHandle(ref, () => ({
|
|
240
|
+
snapToIndex: (index: number) => {
|
|
241
|
+
if (isMounted) {
|
|
242
|
+
sheetRef.current?.snapToIndex(index);
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
snapToPosition: (position: string | number) => {
|
|
246
|
+
if (isMounted) {
|
|
247
|
+
sheetRef.current?.snapToPosition(position);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
expand: () => {
|
|
251
|
+
if (isMounted) {
|
|
252
|
+
sheetRef.current?.expand();
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
collapse: () => {
|
|
256
|
+
if (isMounted) {
|
|
257
|
+
sheetRef.current?.collapse();
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
close: () => {
|
|
261
|
+
if (isMounted) {
|
|
262
|
+
sheetRef.current?.close();
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
}));
|
|
266
|
+
|
|
267
|
+
// Don't render until mounted to prevent early hook execution
|
|
268
|
+
// This ensures @gorhom/bottom-sheet's internal hooks don't run before Reanimated is ready
|
|
269
|
+
// IMPORTANT: All hooks must be called before this early return to maintain hook order
|
|
270
|
+
if (!isMounted) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
|
|
273
274
|
return (
|
|
274
275
|
<GorhomBottomSheet
|
|
275
276
|
ref={sheetRef}
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
BottomSheetBackdrop,
|
|
39
39
|
type BottomSheetBackdropProps,
|
|
40
40
|
} from '@gorhom/bottom-sheet';
|
|
41
|
-
import { useAppDesignTokens } from '@umituz/react-native-theme';
|
|
41
|
+
import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
|
|
42
42
|
import type {
|
|
43
43
|
BottomSheetConfig,
|
|
44
44
|
BottomSheetPreset,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SafeBottomSheetModalProvider
|
|
3
|
+
*
|
|
4
|
+
* Enhanced BottomSheetModalProvider that ensures Reanimated is fully
|
|
5
|
+
* initialized before rendering. This prevents "containerLayoutState.get
|
|
6
|
+
* is not a function" errors that occur when @gorhom/bottom-sheet's
|
|
7
|
+
* internal hooks access Reanimated's layoutState before it's ready.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { SafeBottomSheetModalProvider } from '@umituz/react-native-bottom-sheet';
|
|
12
|
+
*
|
|
13
|
+
* <SafeBottomSheetModalProvider>
|
|
14
|
+
* <App />
|
|
15
|
+
* </SafeBottomSheetModalProvider>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import React, { useState, useEffect } from 'react';
|
|
20
|
+
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
|
21
|
+
|
|
22
|
+
interface SafeBottomSheetModalProviderProps {
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* SafeBottomSheetModalProvider
|
|
28
|
+
*
|
|
29
|
+
* Delays rendering of BottomSheetModalProvider until Reanimated is ready.
|
|
30
|
+
* This prevents layoutState.get errors during initial render.
|
|
31
|
+
*/
|
|
32
|
+
export const SafeBottomSheetModalProvider: React.FC<SafeBottomSheetModalProviderProps> = ({
|
|
33
|
+
children,
|
|
34
|
+
}) => {
|
|
35
|
+
const [isReanimatedReady, setIsReanimatedReady] = useState(false);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
// Wait for Reanimated to be fully initialized
|
|
39
|
+
// @gorhom/bottom-sheet uses useAnimatedDetents which accesses layoutState.get
|
|
40
|
+
// during initialization, so we need to wait for Reanimated to be fully ready
|
|
41
|
+
const timer = setTimeout(() => {
|
|
42
|
+
// Use multiple animation frames to ensure Reanimated worklets are ready
|
|
43
|
+
requestAnimationFrame(() => {
|
|
44
|
+
requestAnimationFrame(() => {
|
|
45
|
+
requestAnimationFrame(() => {
|
|
46
|
+
setIsReanimatedReady(true);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}, 300); // Delay to ensure Reanimated is fully initialized
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
};
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
// Don't render BottomSheetModalProvider until Reanimated is ready
|
|
58
|
+
if (!isReanimatedReady) {
|
|
59
|
+
return <>{children}</>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return <BottomSheetModalProvider>{children}</BottomSheetModalProvider>;
|
|
63
|
+
};
|
|
64
|
+
|