@umituz/react-native-bottom-sheet 1.3.4 → 1.4.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/package.json +20 -8
- package/src/domain/entities/BottomSheet.ts +60 -3
- package/src/domain/entities/Filter.ts +48 -0
- package/src/index.ts +6 -0
- package/src/presentation/components/BottomSheet.tsx +92 -250
- package/src/presentation/components/BottomSheetModal.tsx +3 -29
- package/src/presentation/components/SafeBottomSheetModalProvider.tsx +5 -30
- package/src/presentation/components/filter/FilterBottomSheet.tsx +166 -0
- package/src/presentation/components/filter/FilterSheet.tsx +115 -0
- package/src/presentation/components/filter/FilterSheetComponents/FilterSheetHeader.tsx +33 -0
- package/src/presentation/components/filter/FilterSheetComponents/FilterSheetOption.tsx +59 -0
- package/src/presentation/hooks/useBottomSheet.ts +9 -126
- package/src/presentation/hooks/useBottomSheetModal.ts +9 -126
- package/src/presentation/hooks/useListFilters.ts +95 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-bottom-sheet",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Modern, performant bottom sheets for React Native with preset configurations, keyboard handling, and
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Modern, performant bottom sheets for React Native with preset configurations, keyboard handling, smooth animations, and advanced filtering capabilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"typecheck": "
|
|
9
|
-
"lint": "
|
|
8
|
+
"typecheck": "tsc --noEmit",
|
|
9
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
10
10
|
"version:patch": "npm version patch -m 'chore: release v%s'",
|
|
11
11
|
"version:minor": "npm version minor -m 'chore: release v%s'",
|
|
12
12
|
"version:major": "npm version major -m 'chore: release v%s'"
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"bottom-sheet",
|
|
17
17
|
"modal",
|
|
18
18
|
"sheet",
|
|
19
|
-
"overlay"
|
|
19
|
+
"overlay",
|
|
20
|
+
"filter",
|
|
21
|
+
"filtering"
|
|
20
22
|
],
|
|
21
23
|
"author": "Ümit UZ <umit@umituz.com>",
|
|
22
24
|
"license": "MIT",
|
|
@@ -26,20 +28,30 @@
|
|
|
26
28
|
},
|
|
27
29
|
"peerDependencies": {
|
|
28
30
|
"@gorhom/bottom-sheet": ">=4.6.0",
|
|
29
|
-
"@umituz/react-native-design-system": "
|
|
31
|
+
"@umituz/react-native-design-system": "2.0.16",
|
|
32
|
+
"@umituz/react-native-localization": "latest",
|
|
30
33
|
"react": ">=18.2.0",
|
|
31
34
|
"react-native": ">=0.74.0",
|
|
32
35
|
"react-native-gesture-handler": ">=2.0.0",
|
|
33
|
-
"react-native-reanimated": ">=3.0.0"
|
|
36
|
+
"react-native-reanimated": ">=3.0.0",
|
|
37
|
+
"react-native-safe-area-context": ">=4.0.0"
|
|
34
38
|
},
|
|
35
39
|
"devDependencies": {
|
|
36
40
|
"@gorhom/bottom-sheet": "^5.0.0",
|
|
37
|
-
"@umituz/react-native-design-system": "latest",
|
|
38
41
|
"@types/react": "~19.1.0",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
43
|
+
"@typescript-eslint/parser": "^8.50.1",
|
|
44
|
+
"@umituz/react-native-design-system": "2.0.16",
|
|
45
|
+
"@umituz/react-native-localization": "^3.5.25",
|
|
46
|
+
"@umituz/react-native-storage": "^2.4.5",
|
|
47
|
+
"eslint": "^9.39.2",
|
|
48
|
+
"eslint-plugin-react": "^7.37.5",
|
|
49
|
+
"eslint-plugin-react-native": "^5.0.0",
|
|
39
50
|
"react": "19.1.0",
|
|
40
51
|
"react-native": "0.81.5",
|
|
41
52
|
"react-native-gesture-handler": "^2.0.0",
|
|
42
53
|
"react-native-reanimated": "^3.0.0",
|
|
54
|
+
"react-native-safe-area-context": "^5.6.2",
|
|
43
55
|
"typescript": "~5.9.2"
|
|
44
56
|
},
|
|
45
57
|
"publishConfig": {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
3
|
export type SnapPoint = string | number;
|
|
4
|
-
|
|
5
4
|
export type BottomSheetPreset = 'small' | 'medium' | 'large' | 'full' | 'custom';
|
|
6
|
-
|
|
7
5
|
export type KeyboardBehavior = 'interactive' | 'extend' | 'fillParent';
|
|
8
6
|
|
|
9
7
|
export interface BottomSheetConfig {
|
|
@@ -18,6 +16,65 @@ export interface BottomSheetConfig {
|
|
|
18
16
|
enableDynamicSizing?: boolean;
|
|
19
17
|
}
|
|
20
18
|
|
|
19
|
+
export interface BottomSheetRef {
|
|
20
|
+
snapToIndex: (index: number) => void;
|
|
21
|
+
snapToPosition: (position: string | number) => void;
|
|
22
|
+
expand: () => void;
|
|
23
|
+
collapse: () => void;
|
|
24
|
+
close: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface BottomSheetModalRef {
|
|
28
|
+
present: () => void;
|
|
29
|
+
dismiss: () => void;
|
|
30
|
+
snapToIndex: (index: number) => void;
|
|
31
|
+
snapToPosition: (position: string | number) => void;
|
|
32
|
+
expand: () => void;
|
|
33
|
+
collapse: () => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface BottomSheetProps {
|
|
37
|
+
children: React.ReactNode;
|
|
38
|
+
preset?: BottomSheetPreset;
|
|
39
|
+
snapPoints?: SnapPoint[];
|
|
40
|
+
initialIndex?: number;
|
|
41
|
+
enableBackdrop?: boolean;
|
|
42
|
+
backdropAppearsOnIndex?: number;
|
|
43
|
+
backdropDisappearsOnIndex?: number;
|
|
44
|
+
keyboardBehavior?: KeyboardBehavior;
|
|
45
|
+
enableHandleIndicator?: boolean;
|
|
46
|
+
enablePanDownToClose?: boolean;
|
|
47
|
+
enableDynamicSizing?: boolean;
|
|
48
|
+
onChange?: (index: number) => void;
|
|
49
|
+
onClose?: () => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface BottomSheetModalProps extends Omit<BottomSheetProps, 'onClose'> {
|
|
53
|
+
onDismiss?: () => void;
|
|
54
|
+
backgroundColor?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface UseBottomSheetReturn {
|
|
58
|
+
sheetRef: React.RefObject<BottomSheetRef | null>;
|
|
59
|
+
open: () => void;
|
|
60
|
+
close: () => void;
|
|
61
|
+
expand: () => void;
|
|
62
|
+
collapse: () => void;
|
|
63
|
+
snapToIndex: (index: number) => void;
|
|
64
|
+
snapToPosition: (position: string | number) => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface UseBottomSheetModalReturn {
|
|
68
|
+
modalRef: React.RefObject<BottomSheetModalRef | null>;
|
|
69
|
+
present: () => void;
|
|
70
|
+
dismiss: () => void;
|
|
71
|
+
snapToIndex: (index: number) => void;
|
|
72
|
+
snapToPosition: (position: string | number) => void;
|
|
73
|
+
expand: () => void;
|
|
74
|
+
collapse: () => void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
21
78
|
export const BottomSheetUtils = {
|
|
22
79
|
getPreset: (preset: BottomSheetPreset): BottomSheetConfig => {
|
|
23
80
|
switch (preset) {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain - Filter Entities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface FilterOption {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
icon?: string;
|
|
9
|
+
type?: string;
|
|
10
|
+
count?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface FilterCategory {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
options: FilterOption[];
|
|
17
|
+
multiSelect?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class FilterUtils {
|
|
21
|
+
static hasActiveFilter(selectedIds: string[], defaultId: string = "all"): boolean {
|
|
22
|
+
if (selectedIds.length === 0) return false;
|
|
23
|
+
if (selectedIds.length === 1 && selectedIds[0] === defaultId) return false;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static toggleFilter(
|
|
28
|
+
selectedIds: string[],
|
|
29
|
+
filterId: string,
|
|
30
|
+
multiSelect: boolean = false,
|
|
31
|
+
defaultId: string = "all"
|
|
32
|
+
): string[] {
|
|
33
|
+
if (filterId === defaultId) {
|
|
34
|
+
return [defaultId];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (multiSelect) {
|
|
38
|
+
const newIds = selectedIds.filter((id) => id !== defaultId);
|
|
39
|
+
if (newIds.includes(filterId)) {
|
|
40
|
+
const filtered = newIds.filter((id) => id !== filterId);
|
|
41
|
+
return filtered.length === 0 ? [defaultId] : filtered;
|
|
42
|
+
}
|
|
43
|
+
return [...newIds, filterId];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return [filterId];
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,3 +4,9 @@ export * from './presentation/components/SafeBottomSheetModalProvider';
|
|
|
4
4
|
export * from './presentation/hooks/useBottomSheet';
|
|
5
5
|
export * from './presentation/hooks/useBottomSheetModal';
|
|
6
6
|
export * from './domain/entities/BottomSheet';
|
|
7
|
+
|
|
8
|
+
// Filter exports
|
|
9
|
+
export * from './domain/entities/Filter';
|
|
10
|
+
export * from './presentation/components/filter/FilterSheet';
|
|
11
|
+
export * from './presentation/components/filter/FilterBottomSheet';
|
|
12
|
+
export * from './presentation/hooks/useListFilters';
|
|
@@ -1,35 +1,4 @@
|
|
|
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';
|
|
1
|
+
import React, { forwardRef, useCallback, useMemo, useImperativeHandle, useRef } from 'react';
|
|
33
2
|
import { StyleSheet } from 'react-native';
|
|
34
3
|
import GorhomBottomSheet, {
|
|
35
4
|
BottomSheetView,
|
|
@@ -39,228 +8,100 @@ import GorhomBottomSheet, {
|
|
|
39
8
|
import { useAppDesignTokens } from '@umituz/react-native-design-system';
|
|
40
9
|
import type {
|
|
41
10
|
BottomSheetConfig,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
KeyboardBehavior,
|
|
11
|
+
BottomSheetRef,
|
|
12
|
+
BottomSheetProps,
|
|
45
13
|
} from '../../domain/entities/BottomSheet';
|
|
46
14
|
import { BottomSheetUtils } from '../../domain/entities/BottomSheet';
|
|
47
15
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*/
|
|
82
|
-
initialIndex?: number;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Enable backdrop
|
|
86
|
-
*/
|
|
87
|
-
enableBackdrop?: boolean;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Backdrop appears at this snap index
|
|
91
|
-
*/
|
|
92
|
-
backdropAppearsOnIndex?: number;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Backdrop disappears at this snap index
|
|
96
|
-
*/
|
|
97
|
-
backdropDisappearsOnIndex?: number;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Keyboard behavior strategy
|
|
101
|
-
*/
|
|
102
|
-
keyboardBehavior?: KeyboardBehavior;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Enable handle indicator
|
|
106
|
-
*/
|
|
107
|
-
enableHandleIndicator?: boolean;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Enable pan down to close
|
|
111
|
-
*/
|
|
112
|
-
enablePanDownToClose?: boolean;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Enable dynamic sizing
|
|
116
|
-
*/
|
|
117
|
-
enableDynamicSizing?: boolean;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Callback when sheet changes position
|
|
121
|
-
*/
|
|
122
|
-
onChange?: (index: number) => void;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Callback when sheet closes
|
|
126
|
-
*/
|
|
127
|
-
onClose?: () => void;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Bottom Sheet Component
|
|
132
|
-
*
|
|
133
|
-
* Modern, performant bottom sheet for React Native.
|
|
134
|
-
* Uses @gorhom/bottom-sheet with Reanimated v3.
|
|
135
|
-
*/
|
|
136
|
-
export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>(
|
|
137
|
-
(
|
|
138
|
-
{
|
|
139
|
-
children,
|
|
140
|
-
preset = 'medium',
|
|
141
|
-
snapPoints: customSnapPoints,
|
|
142
|
-
initialIndex,
|
|
143
|
-
enableBackdrop = true,
|
|
144
|
-
backdropAppearsOnIndex,
|
|
145
|
-
backdropDisappearsOnIndex,
|
|
146
|
-
keyboardBehavior = 'interactive',
|
|
147
|
-
enableHandleIndicator = true,
|
|
148
|
-
enablePanDownToClose = true,
|
|
149
|
-
enableDynamicSizing = false,
|
|
150
|
-
onChange,
|
|
151
|
-
onClose,
|
|
152
|
-
},
|
|
153
|
-
ref
|
|
154
|
-
) => {
|
|
155
|
-
const tokens = useAppDesignTokens();
|
|
156
|
-
const sheetRef = React.useRef<GorhomBottomSheet>(null);
|
|
157
|
-
|
|
158
|
-
// Get configuration from preset or custom (must be before useImperativeHandle)
|
|
159
|
-
const config: BottomSheetConfig = useMemo(() => {
|
|
160
|
-
if (customSnapPoints) {
|
|
161
|
-
return BottomSheetUtils.createConfig({
|
|
162
|
-
snapPoints: customSnapPoints,
|
|
163
|
-
initialIndex,
|
|
164
|
-
enableBackdrop,
|
|
165
|
-
backdropAppearsOnIndex,
|
|
166
|
-
backdropDisappearsOnIndex,
|
|
167
|
-
keyboardBehavior,
|
|
168
|
-
enableHandleIndicator,
|
|
169
|
-
enablePanDownToClose,
|
|
170
|
-
enableDynamicSizing,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
return BottomSheetUtils.getPreset(preset);
|
|
174
|
-
}, [
|
|
175
|
-
preset,
|
|
176
|
-
customSnapPoints,
|
|
177
|
-
initialIndex,
|
|
178
|
-
enableBackdrop,
|
|
179
|
-
backdropAppearsOnIndex,
|
|
180
|
-
backdropDisappearsOnIndex,
|
|
181
|
-
keyboardBehavior,
|
|
182
|
-
enableHandleIndicator,
|
|
183
|
-
enablePanDownToClose,
|
|
184
|
-
enableDynamicSizing,
|
|
185
|
-
]);
|
|
186
|
-
|
|
187
|
-
// Render backdrop component (must be before early return to maintain hook order)
|
|
188
|
-
const renderBackdrop = useCallback(
|
|
189
|
-
(props: BottomSheetBackdropProps) =>
|
|
190
|
-
enableBackdrop ? (
|
|
191
|
-
<BottomSheetBackdrop
|
|
192
|
-
{...props}
|
|
193
|
-
appearsOnIndex={config.backdropAppearsOnIndex ?? 0}
|
|
194
|
-
disappearsOnIndex={config.backdropDisappearsOnIndex ?? -1}
|
|
195
|
-
opacity={0.5}
|
|
196
|
-
pressBehavior="close"
|
|
197
|
-
/>
|
|
198
|
-
) : null,
|
|
199
|
-
[enableBackdrop, config.backdropAppearsOnIndex, config.backdropDisappearsOnIndex]
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
// Handle sheet changes (must be before early return to maintain hook order)
|
|
203
|
-
const handleSheetChange = useCallback(
|
|
204
|
-
(index: number) => {
|
|
205
|
-
onChange?.(index);
|
|
206
|
-
if (index === -1) {
|
|
207
|
-
onClose?.();
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
[onChange, onClose]
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
// Expose ref methods
|
|
214
|
-
React.useImperativeHandle(ref, () => ({
|
|
215
|
-
snapToIndex: (index: number) => {
|
|
216
|
-
sheetRef.current?.snapToIndex(index);
|
|
217
|
-
},
|
|
218
|
-
snapToPosition: (position: string | number) => {
|
|
219
|
-
sheetRef.current?.snapToPosition(position);
|
|
220
|
-
},
|
|
221
|
-
expand: () => {
|
|
222
|
-
sheetRef.current?.expand();
|
|
223
|
-
},
|
|
224
|
-
collapse: () => {
|
|
225
|
-
sheetRef.current?.collapse();
|
|
226
|
-
},
|
|
227
|
-
close: () => {
|
|
228
|
-
sheetRef.current?.close();
|
|
229
|
-
},
|
|
230
|
-
}), []);
|
|
231
|
-
|
|
232
|
-
// Ensure valid config
|
|
233
|
-
if (!config.snapPoints || config.snapPoints.length === 0) {
|
|
234
|
-
return null;
|
|
16
|
+
export const BottomSheet = forwardRef<BottomSheetRef, BottomSheetProps>((props, ref) => {
|
|
17
|
+
const {
|
|
18
|
+
children,
|
|
19
|
+
preset = 'medium',
|
|
20
|
+
snapPoints: customSnapPoints,
|
|
21
|
+
initialIndex,
|
|
22
|
+
enableBackdrop = true,
|
|
23
|
+
backdropAppearsOnIndex,
|
|
24
|
+
backdropDisappearsOnIndex,
|
|
25
|
+
keyboardBehavior = 'interactive',
|
|
26
|
+
enableHandleIndicator = true,
|
|
27
|
+
enablePanDownToClose = true,
|
|
28
|
+
enableDynamicSizing = false,
|
|
29
|
+
onChange,
|
|
30
|
+
onClose,
|
|
31
|
+
} = props;
|
|
32
|
+
|
|
33
|
+
const tokens = useAppDesignTokens();
|
|
34
|
+
const sheetRef = useRef<GorhomBottomSheet>(null);
|
|
35
|
+
|
|
36
|
+
const config: BottomSheetConfig = useMemo(() => {
|
|
37
|
+
if (customSnapPoints) {
|
|
38
|
+
return BottomSheetUtils.createConfig({
|
|
39
|
+
snapPoints: customSnapPoints,
|
|
40
|
+
initialIndex,
|
|
41
|
+
enableBackdrop,
|
|
42
|
+
backdropAppearsOnIndex,
|
|
43
|
+
backdropDisappearsOnIndex,
|
|
44
|
+
keyboardBehavior,
|
|
45
|
+
enableHandleIndicator,
|
|
46
|
+
enablePanDownToClose,
|
|
47
|
+
enableDynamicSizing,
|
|
48
|
+
});
|
|
235
49
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
)
|
|
50
|
+
return BottomSheetUtils.getPreset(preset);
|
|
51
|
+
}, [preset, customSnapPoints, initialIndex, enableBackdrop, backdropAppearsOnIndex, backdropDisappearsOnIndex, keyboardBehavior, enableHandleIndicator, enablePanDownToClose, enableDynamicSizing]);
|
|
52
|
+
|
|
53
|
+
const renderBackdrop = useCallback(
|
|
54
|
+
(backdropProps: BottomSheetBackdropProps) =>
|
|
55
|
+
enableBackdrop ? (
|
|
56
|
+
<BottomSheetBackdrop
|
|
57
|
+
{...backdropProps}
|
|
58
|
+
appearsOnIndex={config.backdropAppearsOnIndex ?? 0}
|
|
59
|
+
disappearsOnIndex={config.backdropDisappearsOnIndex ?? -1}
|
|
60
|
+
opacity={0.5}
|
|
61
|
+
pressBehavior="close"
|
|
62
|
+
/>
|
|
63
|
+
) : null,
|
|
64
|
+
[enableBackdrop, config.backdropAppearsOnIndex, config.backdropDisappearsOnIndex]
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const handleSheetChange = useCallback(
|
|
68
|
+
(index: number) => {
|
|
69
|
+
onChange?.(index);
|
|
70
|
+
if (index === -1) onClose?.();
|
|
71
|
+
},
|
|
72
|
+
[onChange, onClose]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
useImperativeHandle(ref, () => ({
|
|
76
|
+
snapToIndex: (index: number) => sheetRef.current?.snapToIndex(index),
|
|
77
|
+
snapToPosition: (pos: string | number) => sheetRef.current?.snapToPosition(pos),
|
|
78
|
+
expand: () => sheetRef.current?.expand(),
|
|
79
|
+
collapse: () => sheetRef.current?.collapse(),
|
|
80
|
+
close: () => sheetRef.current?.close(),
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
if (!config.snapPoints || config.snapPoints.length === 0) return null;
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<GorhomBottomSheet
|
|
87
|
+
ref={sheetRef}
|
|
88
|
+
index={-1}
|
|
89
|
+
snapPoints={config.snapPoints}
|
|
90
|
+
enableDynamicSizing={config.enableDynamicSizing}
|
|
91
|
+
backdropComponent={renderBackdrop}
|
|
92
|
+
keyboardBehavior={config.keyboardBehavior}
|
|
93
|
+
enableHandlePanningGesture={config.enableHandleIndicator}
|
|
94
|
+
enablePanDownToClose={config.enablePanDownToClose}
|
|
95
|
+
onChange={handleSheetChange}
|
|
96
|
+
backgroundStyle={[styles.background, { backgroundColor: tokens.colors.surface }]}
|
|
97
|
+
handleIndicatorStyle={[styles.handleIndicator, { backgroundColor: tokens.colors.border }]}
|
|
98
|
+
>
|
|
99
|
+
<BottomSheetView style={styles.contentContainer}>
|
|
100
|
+
{children}
|
|
101
|
+
</BottomSheetView>
|
|
102
|
+
</GorhomBottomSheet>
|
|
103
|
+
);
|
|
104
|
+
});
|
|
264
105
|
|
|
265
106
|
BottomSheet.displayName = 'BottomSheet';
|
|
266
107
|
|
|
@@ -278,3 +119,4 @@ const styles = StyleSheet.create({
|
|
|
278
119
|
flex: 1,
|
|
279
120
|
},
|
|
280
121
|
});
|
|
122
|
+
|
|
@@ -9,38 +9,11 @@ import {
|
|
|
9
9
|
import { useAppDesignTokens } from '@umituz/react-native-design-system';
|
|
10
10
|
import type {
|
|
11
11
|
BottomSheetConfig,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
KeyboardBehavior,
|
|
12
|
+
BottomSheetModalRef,
|
|
13
|
+
BottomSheetModalProps,
|
|
15
14
|
} from '../../domain/entities/BottomSheet';
|
|
16
15
|
import { BottomSheetUtils } from '../../domain/entities/BottomSheet';
|
|
17
16
|
|
|
18
|
-
export interface BottomSheetModalRef {
|
|
19
|
-
present: () => void;
|
|
20
|
-
dismiss: () => void;
|
|
21
|
-
snapToIndex: (index: number) => void;
|
|
22
|
-
snapToPosition: (position: string | number) => void;
|
|
23
|
-
expand: () => void;
|
|
24
|
-
collapse: () => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface BottomSheetModalProps {
|
|
28
|
-
children: React.ReactNode;
|
|
29
|
-
preset?: BottomSheetPreset;
|
|
30
|
-
snapPoints?: SnapPoint[];
|
|
31
|
-
initialIndex?: number;
|
|
32
|
-
enableBackdrop?: boolean;
|
|
33
|
-
backdropAppearsOnIndex?: number;
|
|
34
|
-
backdropDisappearsOnIndex?: number;
|
|
35
|
-
keyboardBehavior?: KeyboardBehavior;
|
|
36
|
-
enableHandleIndicator?: boolean;
|
|
37
|
-
enablePanDownToClose?: boolean;
|
|
38
|
-
enableDynamicSizing?: boolean;
|
|
39
|
-
onChange?: (index: number) => void;
|
|
40
|
-
onDismiss?: () => void;
|
|
41
|
-
backgroundColor?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
17
|
export const BottomSheetModal = forwardRef<BottomSheetModalRef, BottomSheetModalProps>((props, ref) => {
|
|
45
18
|
const {
|
|
46
19
|
children,
|
|
@@ -148,3 +121,4 @@ const styles = StyleSheet.create({
|
|
|
148
121
|
flex: 1,
|
|
149
122
|
},
|
|
150
123
|
});
|
|
124
|
+
|
|
@@ -1,36 +1,11 @@
|
|
|
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 from 'react';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
20
2
|
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
|
21
3
|
|
|
22
4
|
interface SafeBottomSheetModalProviderProps {
|
|
23
|
-
children:
|
|
5
|
+
children: ReactNode;
|
|
24
6
|
}
|
|
25
7
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* Wrapper around BottomSheetModalProvider for consistency.
|
|
30
|
-
*/
|
|
31
|
-
export const SafeBottomSheetModalProvider: React.FC<SafeBottomSheetModalProviderProps> = ({
|
|
32
|
-
children,
|
|
33
|
-
}) => {
|
|
34
|
-
return <BottomSheetModalProvider>{children}</BottomSheetModalProvider>;
|
|
35
|
-
};
|
|
8
|
+
export const SafeBottomSheetModalProvider = ({ children }: SafeBottomSheetModalProviderProps) => (
|
|
9
|
+
<BottomSheetModalProvider>{children}</BottomSheetModalProvider>
|
|
10
|
+
);
|
|
36
11
|
|