@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.
- package/LICENSE +22 -0
- package/README.md +101 -0
- package/lib/domain/entities/BottomSheet.d.ts +113 -0
- package/lib/domain/entities/BottomSheet.d.ts.map +1 -0
- package/lib/domain/entities/BottomSheet.js +125 -0
- package/lib/domain/entities/BottomSheet.js.map +1 -0
- package/lib/index.d.ts +75 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +76 -0
- package/lib/index.js.map +1 -0
- package/lib/presentation/components/BottomSheet.d.ts +107 -0
- package/lib/presentation/components/BottomSheet.d.ts.map +1 -0
- package/lib/presentation/components/BottomSheet.js +108 -0
- package/lib/presentation/components/BottomSheet.js.map +1 -0
- package/lib/presentation/hooks/useBottomSheet.d.ts +70 -0
- package/lib/presentation/hooks/useBottomSheet.d.ts.map +1 -0
- package/lib/presentation/hooks/useBottomSheet.js +84 -0
- package/lib/presentation/hooks/useBottomSheet.js.map +1 -0
- package/package.json +61 -0
- package/src/domain/entities/BottomSheet.ts +212 -0
- package/src/index.ts +98 -0
- package/src/presentation/components/BottomSheet.tsx +254 -0
- package/src/presentation/hooks/useBottomSheet.ts +133 -0
|
@@ -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
|
+
};
|