@umituz/react-native-bottom-sheet 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.
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Bottom Sheet Component
3
+ *
4
+ * Main bottom sheet wrapper using @gorhom/bottom-sheet library.
5
+ * Provides a clean, theme-aware API for bottom sheets across the app.
6
+ *
7
+ * Features:
8
+ * - Snap point support (percentage, fixed, dynamic)
9
+ * - Backdrop with tap-to-close
10
+ * - Keyboard handling (interactive, fillParent, extend)
11
+ * - Theme-aware colors
12
+ * - Handle indicator
13
+ * - Pan down to close
14
+ * - Smooth animations with Reanimated v3
15
+ *
16
+ * Usage:
17
+ * ```tsx
18
+ * const sheetRef = useRef<BottomSheetRef>(null);
19
+ *
20
+ * <BottomSheet
21
+ * ref={sheetRef}
22
+ * preset="medium"
23
+ * onClose={() => console.log('Closed')}
24
+ * >
25
+ * <View>
26
+ * <Text>Bottom Sheet Content</Text>
27
+ * </View>
28
+ * </BottomSheet>
29
+ * ```
30
+ */
31
+
32
+ import React, { forwardRef, useCallback, useMemo } from 'react';
33
+ import { StyleSheet } from 'react-native';
34
+ import GorhomBottomSheet, {
35
+ BottomSheetView,
36
+ BottomSheetBackdrop,
37
+ type BottomSheetBackdropProps,
38
+ } from '@gorhom/bottom-sheet';
39
+ import { useAppDesignTokens } from '@umituz/react-native-design-system';
40
+ import type {
41
+ BottomSheetConfig,
42
+ BottomSheetPreset,
43
+ SnapPoint,
44
+ KeyboardBehavior,
45
+ } from '../../domain/entities/BottomSheet';
46
+ import { BottomSheetUtils } from '../../domain/entities/BottomSheet';
47
+
48
+ /**
49
+ * Bottom sheet ref methods
50
+ */
51
+ export interface BottomSheetRef {
52
+ snapToIndex: (index: number) => void;
53
+ snapToPosition: (position: string | number) => void;
54
+ expand: () => void;
55
+ collapse: () => void;
56
+ close: () => void;
57
+ }
58
+
59
+ /**
60
+ * Bottom sheet component props
61
+ */
62
+ export interface BottomSheetProps {
63
+ /**
64
+ * Bottom sheet content
65
+ */
66
+ children: React.ReactNode;
67
+
68
+ /**
69
+ * Preset configuration (small, medium, large, full)
70
+ */
71
+ preset?: BottomSheetPreset;
72
+
73
+ /**
74
+ * Custom snap points (overrides preset)
75
+ */
76
+ snapPoints?: SnapPoint[];
77
+
78
+ /**
79
+ * Initial snap point index
80
+ */
81
+ initialIndex?: number;
82
+
83
+ /**
84
+ * Enable backdrop
85
+ */
86
+ enableBackdrop?: boolean;
87
+
88
+ /**
89
+ * Backdrop appears at this snap index
90
+ */
91
+ backdropAppearsOnIndex?: number;
92
+
93
+ /**
94
+ * Backdrop disappears at this snap index
95
+ */
96
+ backdropDisappearsOnIndex?: number;
97
+
98
+ /**
99
+ * Keyboard behavior strategy
100
+ */
101
+ keyboardBehavior?: KeyboardBehavior;
102
+
103
+ /**
104
+ * Enable handle indicator
105
+ */
106
+ enableHandleIndicator?: boolean;
107
+
108
+ /**
109
+ * Enable pan down to close
110
+ */
111
+ enablePanDownToClose?: boolean;
112
+
113
+ /**
114
+ * Enable dynamic sizing
115
+ */
116
+ enableDynamicSizing?: boolean;
117
+
118
+ /**
119
+ * Callback when sheet changes position
120
+ */
121
+ onChange?: (index: number) => void;
122
+
123
+ /**
124
+ * Callback when sheet closes
125
+ */
126
+ onClose?: () => void;
127
+ }
128
+
129
+ /**
130
+ * Bottom Sheet Component
131
+ *
132
+ * Modern, performant bottom sheet for React Native.
133
+ * Uses @gorhom/bottom-sheet with Reanimated v3.
134
+ */
135
+ export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
136
+ (
137
+ {
138
+ children,
139
+ preset = 'medium',
140
+ snapPoints: customSnapPoints,
141
+ initialIndex,
142
+ enableBackdrop = true,
143
+ backdropAppearsOnIndex,
144
+ backdropDisappearsOnIndex,
145
+ keyboardBehavior = 'interactive',
146
+ enableHandleIndicator = true,
147
+ enablePanDownToClose = true,
148
+ enableDynamicSizing = false,
149
+ onChange,
150
+ onClose,
151
+ },
152
+ ref
153
+ ) => {
154
+ const tokens = useAppDesignTokens();
155
+
156
+ // Get configuration from preset or custom
157
+ const config: BottomSheetConfig = useMemo(() => {
158
+ if (customSnapPoints) {
159
+ return BottomSheetUtils.createConfig({
160
+ snapPoints: customSnapPoints,
161
+ initialIndex,
162
+ enableBackdrop,
163
+ backdropAppearsOnIndex,
164
+ backdropDisappearsOnIndex,
165
+ keyboardBehavior,
166
+ enableHandleIndicator,
167
+ enablePanDownToClose,
168
+ enableDynamicSizing,
169
+ });
170
+ }
171
+ return BottomSheetUtils.getPreset(preset);
172
+ }, [
173
+ preset,
174
+ customSnapPoints,
175
+ initialIndex,
176
+ enableBackdrop,
177
+ backdropAppearsOnIndex,
178
+ backdropDisappearsOnIndex,
179
+ keyboardBehavior,
180
+ enableHandleIndicator,
181
+ enablePanDownToClose,
182
+ enableDynamicSizing,
183
+ ]);
184
+
185
+ // Render backdrop component
186
+ const renderBackdrop = useCallback(
187
+ (props: BottomSheetBackdropProps) =>
188
+ enableBackdrop ? (
189
+ <BottomSheetBackdrop
190
+ {...props}
191
+ appearsOnIndex={config.backdropAppearsOnIndex ?? 0}
192
+ disappearsOnIndex={config.backdropDisappearsOnIndex ?? -1}
193
+ opacity={0.5}
194
+ pressBehavior="close"
195
+ />
196
+ ) : null,
197
+ [enableBackdrop, config.backdropAppearsOnIndex, config.backdropDisappearsOnIndex]
198
+ );
199
+
200
+ // Handle sheet changes
201
+ const handleSheetChange = useCallback(
202
+ (index: number) => {
203
+ onChange?.(index);
204
+ if (index === -1) {
205
+ onClose?.();
206
+ }
207
+ },
208
+ [onChange, onClose]
209
+ );
210
+
211
+ return (
212
+ <GorhomBottomSheet
213
+ ref={ref as any}
214
+ index={config.initialIndex ?? 0}
215
+ snapPoints={config.snapPoints}
216
+ enableDynamicSizing={config.enableDynamicSizing}
217
+ backdropComponent={renderBackdrop}
218
+ keyboardBehavior={config.keyboardBehavior}
219
+ enableHandlePanningGesture={config.enableHandleIndicator}
220
+ enablePanDownToClose={config.enablePanDownToClose}
221
+ onChange={handleSheetChange}
222
+ backgroundStyle={[
223
+ styles.background,
224
+ { backgroundColor: tokens.colors.surface },
225
+ ]}
226
+ handleIndicatorStyle={[
227
+ styles.handleIndicator,
228
+ { backgroundColor: tokens.colors.border },
229
+ ]}
230
+ >
231
+ <BottomSheetView style={styles.contentContainer}>
232
+ {children}
233
+ </BottomSheetView>
234
+ </GorhomBottomSheet>
235
+ );
236
+ }
237
+ );
238
+
239
+ BottomSheet.displayName = 'BottomSheet';
240
+
241
+ const styles = StyleSheet.create({
242
+ background: {
243
+ borderTopLeftRadius: 16,
244
+ borderTopRightRadius: 16,
245
+ },
246
+ handleIndicator: {
247
+ width: 40,
248
+ height: 4,
249
+ borderRadius: 2,
250
+ },
251
+ contentContainer: {
252
+ flex: 1,
253
+ },
254
+ });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * useBottomSheet Hook
3
+ *
4
+ * React hook for managing bottom sheet state and interactions.
5
+ * Provides a clean API for common bottom sheet operations.
6
+ *
7
+ * Features:
8
+ * - Open/close bottom sheet
9
+ * - Snap to specific index
10
+ * - Expand to max height
11
+ * - Collapse to min height
12
+ * - Track current position
13
+ * - Preset configurations
14
+ *
15
+ * Usage:
16
+ * ```tsx
17
+ * const { sheetRef, open, close, expand, collapse } = useBottomSheet();
18
+ *
19
+ * return (
20
+ * <>
21
+ * <Button onPress={open}>Open Sheet</Button>
22
+ * <BottomSheet ref={sheetRef} preset="medium">
23
+ * <Text>Content</Text>
24
+ * </BottomSheet>
25
+ * </>
26
+ * );
27
+ * ```
28
+ */
29
+
30
+ import { useRef, useCallback } from 'react';
31
+ import type { BottomSheetRef } from '../components/BottomSheet';
32
+
33
+ /**
34
+ * Return type for useBottomSheet hook
35
+ */
36
+ export interface UseBottomSheetReturn {
37
+ /**
38
+ * Ref to attach to BottomSheet component
39
+ */
40
+ sheetRef: React.RefObject<BottomSheetRef>;
41
+
42
+ /**
43
+ * Open bottom sheet to initial index
44
+ */
45
+ open: () => void;
46
+
47
+ /**
48
+ * Close bottom sheet completely
49
+ */
50
+ close: () => void;
51
+
52
+ /**
53
+ * Expand to maximum height
54
+ */
55
+ expand: () => void;
56
+
57
+ /**
58
+ * Collapse to minimum height
59
+ */
60
+ collapse: () => void;
61
+
62
+ /**
63
+ * Snap to specific index
64
+ */
65
+ snapToIndex: (index: number) => void;
66
+
67
+ /**
68
+ * Snap to specific position
69
+ */
70
+ snapToPosition: (position: string | number) => void;
71
+ }
72
+
73
+ /**
74
+ * useBottomSheet Hook
75
+ *
76
+ * Hook for managing bottom sheet state and interactions.
77
+ * Provides imperative methods for controlling the sheet.
78
+ */
79
+ export const useBottomSheet = (): UseBottomSheetReturn => {
80
+ const sheetRef = useRef<BottomSheetRef>(null);
81
+
82
+ /**
83
+ * Open bottom sheet to first snap point
84
+ */
85
+ const open = useCallback(() => {
86
+ sheetRef.current?.snapToIndex(0);
87
+ }, []);
88
+
89
+ /**
90
+ * Close bottom sheet completely
91
+ */
92
+ const close = useCallback(() => {
93
+ sheetRef.current?.close();
94
+ }, []);
95
+
96
+ /**
97
+ * Expand to maximum height (last snap point)
98
+ */
99
+ const expand = useCallback(() => {
100
+ sheetRef.current?.expand();
101
+ }, []);
102
+
103
+ /**
104
+ * Collapse to minimum height (first snap point)
105
+ */
106
+ const collapse = useCallback(() => {
107
+ sheetRef.current?.collapse();
108
+ }, []);
109
+
110
+ /**
111
+ * Snap to specific index
112
+ */
113
+ const snapToIndex = useCallback((index: number) => {
114
+ sheetRef.current?.snapToIndex(index);
115
+ }, []);
116
+
117
+ /**
118
+ * Snap to specific position (percentage or fixed)
119
+ */
120
+ const snapToPosition = useCallback((position: string | number) => {
121
+ sheetRef.current?.snapToPosition(position);
122
+ }, []);
123
+
124
+ return {
125
+ sheetRef,
126
+ open,
127
+ close,
128
+ expand,
129
+ collapse,
130
+ snapToIndex,
131
+ snapToPosition,
132
+ };
133
+ };