@shaquillehinds/react-native-bottom-sheet 0.0.1
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 +20 -0
- package/README.md +880 -0
- package/lib/commonjs/BottomSheet/animations/drag.animation.js +72 -0
- package/lib/commonjs/BottomSheet/animations/drag.animation.js.map +1 -0
- package/lib/commonjs/BottomSheet/components/BottomSheet.js +92 -0
- package/lib/commonjs/BottomSheet/components/BottomSheet.js.map +1 -0
- package/lib/commonjs/BottomSheet/components/BottomSheetFlatlist.js +38 -0
- package/lib/commonjs/BottomSheet/components/BottomSheetFlatlist.js.map +1 -0
- package/lib/commonjs/BottomSheet/components/BottomSheetModal.js +34 -0
- package/lib/commonjs/BottomSheet/components/BottomSheetModal.js.map +1 -0
- package/lib/commonjs/BottomSheet/components/BottomSheetScrollView.js +37 -0
- package/lib/commonjs/BottomSheet/components/BottomSheetScrollView.js.map +1 -0
- package/lib/commonjs/BottomSheet/config/bottomSheet.constants.js +35 -0
- package/lib/commonjs/BottomSheet/config/bottomSheet.constants.js.map +1 -0
- package/lib/commonjs/BottomSheet/config/bottomSheet.styles.js +42 -0
- package/lib/commonjs/BottomSheet/config/bottomSheet.styles.js.map +1 -0
- package/lib/commonjs/BottomSheet/config/bottomSheet.types.js +14 -0
- package/lib/commonjs/BottomSheet/config/bottomSheet.types.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/bottomFlatlist.controller.js +69 -0
- package/lib/commonjs/BottomSheet/controller/bottomFlatlist.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/bottomScrollView.controller.js +41 -0
- package/lib/commonjs/BottomSheet/controller/bottomScrollView.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/bottomSheet.controller.js +216 -0
- package/lib/commonjs/BottomSheet/controller/bottomSheet.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/callbacks.controller.js +135 -0
- package/lib/commonjs/BottomSheet/controller/callbacks.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/dragAnimation.controller.js +127 -0
- package/lib/commonjs/BottomSheet/controller/dragAnimation.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetRef.js +60 -0
- package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetRef.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetUtils.js +74 -0
- package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetUtils.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/index.js +17 -0
- package/lib/commonjs/BottomSheet/controller/index.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/keyboardAnimation.controller.js +88 -0
- package/lib/commonjs/BottomSheet/controller/keyboardAnimation.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/controller/scrollContent.controller.js +89 -0
- package/lib/commonjs/BottomSheet/controller/scrollContent.controller.js.map +1 -0
- package/lib/commonjs/BottomSheet/index.js +130 -0
- package/lib/commonjs/BottomSheet/index.js.map +1 -0
- package/lib/commonjs/index.js +17 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/module/BottomSheet/animations/drag.animation.js +68 -0
- package/lib/module/BottomSheet/animations/drag.animation.js.map +1 -0
- package/lib/module/BottomSheet/components/BottomSheet.js +87 -0
- package/lib/module/BottomSheet/components/BottomSheet.js.map +1 -0
- package/lib/module/BottomSheet/components/BottomSheetFlatlist.js +32 -0
- package/lib/module/BottomSheet/components/BottomSheetFlatlist.js.map +1 -0
- package/lib/module/BottomSheet/components/BottomSheetModal.js +30 -0
- package/lib/module/BottomSheet/components/BottomSheetModal.js.map +1 -0
- package/lib/module/BottomSheet/components/BottomSheetScrollView.js +31 -0
- package/lib/module/BottomSheet/components/BottomSheetScrollView.js.map +1 -0
- package/lib/module/BottomSheet/config/bottomSheet.constants.js +30 -0
- package/lib/module/BottomSheet/config/bottomSheet.constants.js.map +1 -0
- package/lib/module/BottomSheet/config/bottomSheet.styles.js +38 -0
- package/lib/module/BottomSheet/config/bottomSheet.styles.js.map +1 -0
- package/lib/module/BottomSheet/config/bottomSheet.types.js +10 -0
- package/lib/module/BottomSheet/config/bottomSheet.types.js.map +1 -0
- package/lib/module/BottomSheet/controller/bottomFlatlist.controller.js +64 -0
- package/lib/module/BottomSheet/controller/bottomFlatlist.controller.js.map +1 -0
- package/lib/module/BottomSheet/controller/bottomScrollView.controller.js +37 -0
- package/lib/module/BottomSheet/controller/bottomScrollView.controller.js.map +1 -0
- package/lib/module/BottomSheet/controller/bottomSheet.controller.js +212 -0
- package/lib/module/BottomSheet/controller/bottomSheet.controller.js.map +1 -0
- package/lib/module/BottomSheet/controller/callbacks.controller.js +130 -0
- package/lib/module/BottomSheet/controller/callbacks.controller.js.map +1 -0
- package/lib/module/BottomSheet/controller/dragAnimation.controller.js +122 -0
- package/lib/module/BottomSheet/controller/dragAnimation.controller.js.map +1 -0
- package/lib/module/BottomSheet/controller/hooks/useBottomSheetRef.js +56 -0
- package/lib/module/BottomSheet/controller/hooks/useBottomSheetRef.js.map +1 -0
- package/lib/module/BottomSheet/controller/hooks/useBottomSheetUtils.js +70 -0
- package/lib/module/BottomSheet/controller/hooks/useBottomSheetUtils.js.map +1 -0
- package/lib/module/BottomSheet/controller/index.js +4 -0
- package/lib/module/BottomSheet/controller/index.js.map +1 -0
- package/lib/module/BottomSheet/controller/keyboardAnimation.controller.js +84 -0
- package/lib/module/BottomSheet/controller/keyboardAnimation.controller.js.map +1 -0
- package/lib/module/BottomSheet/controller/scrollContent.controller.js +84 -0
- package/lib/module/BottomSheet/controller/scrollContent.controller.js.map +1 -0
- package/lib/module/BottomSheet/index.js +112 -0
- package/lib/module/BottomSheet/index.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/animations/drag.animation.d.ts +31 -0
- package/lib/typescript/commonjs/src/BottomSheet/animations/drag.animation.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheet.d.ts +9 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetFlatlist.d.ts +3 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetFlatlist.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetModal.d.ts +8 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetModal.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetScrollView.d.ts +3 -0
- package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetScrollView.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.constants.d.ts +30 -0
- package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.constants.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.styles.d.ts +37 -0
- package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.styles.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.types.d.ts +185 -0
- package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.types.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/bottomFlatlist.controller.d.ts +480 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/bottomFlatlist.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/bottomScrollView.controller.d.ts +338 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/bottomScrollView.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/bottomSheet.controller.d.ts +51 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/bottomSheet.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/callbacks.controller.d.ts +36 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/callbacks.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/dragAnimation.controller.d.ts +27 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/dragAnimation.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts +12 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts +40 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/index.d.ts +2 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/keyboardAnimation.controller.d.ts +15 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/keyboardAnimation.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/scrollContent.controller.d.ts +20 -0
- package/lib/typescript/commonjs/src/BottomSheet/controller/scrollContent.controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BottomSheet/index.d.ts +23 -0
- package/lib/typescript/commonjs/src/BottomSheet/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +2 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/src/BottomSheet/animations/drag.animation.d.ts +31 -0
- package/lib/typescript/module/src/BottomSheet/animations/drag.animation.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheet.d.ts +9 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheetFlatlist.d.ts +3 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheetFlatlist.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheetModal.d.ts +8 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheetModal.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheetScrollView.d.ts +3 -0
- package/lib/typescript/module/src/BottomSheet/components/BottomSheetScrollView.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/config/bottomSheet.constants.d.ts +30 -0
- package/lib/typescript/module/src/BottomSheet/config/bottomSheet.constants.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/config/bottomSheet.styles.d.ts +37 -0
- package/lib/typescript/module/src/BottomSheet/config/bottomSheet.styles.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/config/bottomSheet.types.d.ts +185 -0
- package/lib/typescript/module/src/BottomSheet/config/bottomSheet.types.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/bottomFlatlist.controller.d.ts +480 -0
- package/lib/typescript/module/src/BottomSheet/controller/bottomFlatlist.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/bottomScrollView.controller.d.ts +338 -0
- package/lib/typescript/module/src/BottomSheet/controller/bottomScrollView.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/bottomSheet.controller.d.ts +51 -0
- package/lib/typescript/module/src/BottomSheet/controller/bottomSheet.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/callbacks.controller.d.ts +36 -0
- package/lib/typescript/module/src/BottomSheet/controller/callbacks.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/dragAnimation.controller.d.ts +27 -0
- package/lib/typescript/module/src/BottomSheet/controller/dragAnimation.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts +12 -0
- package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts +40 -0
- package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/index.d.ts +2 -0
- package/lib/typescript/module/src/BottomSheet/controller/index.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/keyboardAnimation.controller.d.ts +15 -0
- package/lib/typescript/module/src/BottomSheet/controller/keyboardAnimation.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/controller/scrollContent.controller.d.ts +20 -0
- package/lib/typescript/module/src/BottomSheet/controller/scrollContent.controller.d.ts.map +1 -0
- package/lib/typescript/module/src/BottomSheet/index.d.ts +23 -0
- package/lib/typescript/module/src/BottomSheet/index.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +2 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -0
- package/package.json +203 -0
- package/src/BottomSheet/animations/drag.animation.ts +86 -0
- package/src/BottomSheet/components/BottomSheet.tsx +157 -0
- package/src/BottomSheet/components/BottomSheetFlatlist.tsx +46 -0
- package/src/BottomSheet/components/BottomSheetModal.tsx +47 -0
- package/src/BottomSheet/components/BottomSheetScrollView.tsx +46 -0
- package/src/BottomSheet/config/bottomSheet.constants.ts +31 -0
- package/src/BottomSheet/config/bottomSheet.styles.ts +42 -0
- package/src/BottomSheet/config/bottomSheet.types.ts +246 -0
- package/src/BottomSheet/controller/bottomFlatlist.controller.ts +87 -0
- package/src/BottomSheet/controller/bottomScrollView.controller.ts +43 -0
- package/src/BottomSheet/controller/bottomSheet.controller.ts +238 -0
- package/src/BottomSheet/controller/callbacks.controller.ts +222 -0
- package/src/BottomSheet/controller/dragAnimation.controller.ts +211 -0
- package/src/BottomSheet/controller/hooks/useBottomSheetRef.ts +73 -0
- package/src/BottomSheet/controller/hooks/useBottomSheetUtils.ts +75 -0
- package/src/BottomSheet/controller/index.ts +1 -0
- package/src/BottomSheet/controller/keyboardAnimation.controller.ts +148 -0
- package/src/BottomSheet/controller/scrollContent.controller.ts +120 -0
- package/src/BottomSheet/index.tsx +139 -0
- package/src/index.tsx +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
# @shaquillehinds/react-native-bottom-sheet
|
|
2
|
+
|
|
3
|
+
A performant, highly customizable bottom sheet component for React Native that just works. Built with React Native Reanimated and Gesture Handler for smooth 60fps animations and natural gesture interactions.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/@shaquillehinds%2Freact-native-bottom-sheet)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🎯 **Multiple Snap Points** - Define custom snap positions as percentages of screen height
|
|
11
|
+
- 📱 **Keyboard Aware** - Intelligent keyboard avoidance with per-input customization
|
|
12
|
+
- 🎨 **Fully Customizable** - Style every aspect from bumper to backdrop
|
|
13
|
+
- 🔄 **Portal Support** - Optional portal rendering for complex navigation hierarchies
|
|
14
|
+
- 📜 **Scrollable Content** - Built-in FlatList and ScrollView components with proper gesture handling
|
|
15
|
+
- ⚡ **High Performance** - Optimized animations using `useImperativeHandle` for render isolation
|
|
16
|
+
- 🎭 **Modal & Inline Modes** - Use as a full modal or inline component
|
|
17
|
+
- 🔒 **Type Safe** - Full TypeScript support with comprehensive type definitions
|
|
18
|
+
- 🌐 **Cross Platform** - iOS and Android support with platform-specific optimizations
|
|
19
|
+
- 🎬 **Flexible Drag Areas** - Configure draggable regions (full, bumper, or none)
|
|
20
|
+
- 💾 **Keep Mounted Option** - Persist component state with partial visibility
|
|
21
|
+
- ⏱️ **Content Loading Strategies** - Delay content rendering for improved performance
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @shaquillehinds/react-native-bottom-sheet
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
or
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
yarn add @shaquillehinds/react-native-bottom-sheet
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Peer Dependencies
|
|
36
|
+
|
|
37
|
+
This package requires the following peer dependencies:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install react-native-reanimated react-native-gesture-handler @shaquillehinds/react-native-essentials
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
### Basic Modal Bottom Sheet
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import React, { useRef, useState } from 'react';
|
|
49
|
+
import { View, Text, Button } from 'react-native';
|
|
50
|
+
import {
|
|
51
|
+
BottomSheetModal,
|
|
52
|
+
useBottomSheetRef,
|
|
53
|
+
} from '@shaquillehinds/react-native-bottom-sheet';
|
|
54
|
+
import type { BottomModalRefObject } from '@shaquillehinds/react-native-bottom-sheet';
|
|
55
|
+
|
|
56
|
+
export default function App() {
|
|
57
|
+
const [showModal, setShowModal] = useState(false);
|
|
58
|
+
const bottomSheetRef = useRef<BottomModalRefObject>(null);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
62
|
+
<Button title="Open Bottom Sheet" onPress={() => setShowModal(true)} />
|
|
63
|
+
|
|
64
|
+
<BottomSheetModal
|
|
65
|
+
ref={bottomSheetRef}
|
|
66
|
+
showModal={showModal}
|
|
67
|
+
setShowModal={setShowModal}
|
|
68
|
+
snapPoints={[50, 75, 90]}
|
|
69
|
+
>
|
|
70
|
+
<View style={{ padding: 20 }}>
|
|
71
|
+
<Text>Bottom Sheet Content</Text>
|
|
72
|
+
</View>
|
|
73
|
+
</BottomSheetModal>
|
|
74
|
+
</View>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Inline Bottom Sheet
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { BottomSheet } from '@shaquillehinds/react-native-bottom-sheet';
|
|
83
|
+
|
|
84
|
+
<BottomSheet
|
|
85
|
+
showModal={showModal}
|
|
86
|
+
setShowModal={setShowModal}
|
|
87
|
+
snapPoints={[30, 60, 90]}
|
|
88
|
+
keepMounted={true}
|
|
89
|
+
bottomOffset={50}
|
|
90
|
+
>
|
|
91
|
+
<YourContent />
|
|
92
|
+
</BottomSheet>;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Core Components
|
|
96
|
+
|
|
97
|
+
### `BottomSheetModal`
|
|
98
|
+
|
|
99
|
+
Full-screen modal with backdrop. Ideal for most use cases.
|
|
100
|
+
|
|
101
|
+
### `BottomSheet`
|
|
102
|
+
|
|
103
|
+
Inline bottom sheet without backdrop. Useful for persistent UI elements.
|
|
104
|
+
|
|
105
|
+
### `BottomSheetFlatlist`
|
|
106
|
+
|
|
107
|
+
Optimized FlatList with proper gesture handling inside bottom sheets.
|
|
108
|
+
|
|
109
|
+
### `BottomSheetScrollView`
|
|
110
|
+
|
|
111
|
+
Optimized ScrollView with proper gesture handling inside bottom sheets.
|
|
112
|
+
|
|
113
|
+
## API Reference
|
|
114
|
+
|
|
115
|
+
### Props
|
|
116
|
+
|
|
117
|
+
#### `BottomSheetProps` (Common to both components)
|
|
118
|
+
|
|
119
|
+
| Prop | Type | Default | Description |
|
|
120
|
+
| ------------------------------- | ----------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| `showModal` | `boolean` | - | Controls visibility of the bottom sheet |
|
|
122
|
+
| `setShowModal` | `(bool: boolean) => void` | - | Callback to update visibility state |
|
|
123
|
+
| `snapPoints` | `(number \| string)[]` | `[25, 50, 75]` | Array of snap positions as percentages of screen height. Accepts numbers or strings (e.g., `[25, "50", "75%"]`) |
|
|
124
|
+
| `dragArea` | `'full' \| 'bumper' \| 'none'` | `'bumper'` | Defines draggable area of the modal |
|
|
125
|
+
| `keepMounted` | `boolean` | `false` | Prevents full unmounting when closed. Use with `bottomOffset` to keep visible |
|
|
126
|
+
| `hideBumper` | `boolean` | `false` | Hides the draggable bumper at top |
|
|
127
|
+
| `avoidKeyboard` | `boolean` | `false` | Adds padding when keyboard is visible |
|
|
128
|
+
| `allowDragWhileKeyboardVisible` | `boolean` | `false` | Allows dragging when keyboard is open (disabled by default to prevent conflicts) |
|
|
129
|
+
| `inputsForKeyboardToAvoid` | `React.RefObject<TextInput>[]` | - | Specific inputs that trigger keyboard avoidance |
|
|
130
|
+
| `bottomOffset` | `number` | `0` | Pushes modal up from bottom. Useful with `keepMounted` |
|
|
131
|
+
| `style` | `StyleProp<ViewStyle>` | - | Style for the modal sheet container |
|
|
132
|
+
| `backgroundColor` | `string` | - | Background color for modal and bumper |
|
|
133
|
+
| `contentContainerStyle` | `StyleProp<ViewStyle>` | - | Style for the content container |
|
|
134
|
+
| `bumperStyle` | `StyleProp<ViewStyle>` | - | Style for the bumper element |
|
|
135
|
+
| `bumperContainerStyle` | `StyleProp<ViewStyle>` | - | Style for the bumper container |
|
|
136
|
+
| `BumperComponent` | `() => React.ReactNode` | - | Custom bumper component |
|
|
137
|
+
| `disablePortal` | `boolean` | `false` | Disables portal rendering |
|
|
138
|
+
| `CustomPortalContext` | `React.Context<PortalContextValue>` | - | Custom portal context for scoped portals |
|
|
139
|
+
|
|
140
|
+
#### `BottomSheetModalProps` (Extends BottomSheetProps)
|
|
141
|
+
|
|
142
|
+
| Prop | Type | Default | Description |
|
|
143
|
+
| ----------------------------- | ----------------- | ------- | ----------------------------------------- |
|
|
144
|
+
| `BackdropComponent` | `React.ReactNode` | - | Custom backdrop component |
|
|
145
|
+
| `onBackDropPress` | `() => void` | - | Callback when backdrop is pressed |
|
|
146
|
+
| `disableCloseOnBackdropPress` | `boolean` | `false` | Prevents closing on backdrop press |
|
|
147
|
+
| `useNativeModal` | `boolean` | `false` | Use React Native's native Modal component |
|
|
148
|
+
|
|
149
|
+
#### Callbacks
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Description |
|
|
152
|
+
| ------------------ | --------------------------------------------------- | -------------------------------------- |
|
|
153
|
+
| `onModalShow` | `() => void \| Promise<void>` | Called when modal finishes mounting |
|
|
154
|
+
| `onModalClose` | `() => void \| Promise<void>` | Called when modal finishes unmounting |
|
|
155
|
+
| `onSnapPointReach` | `(snapPointIndex: number) => void \| Promise<void>` | Called when modal reaches a snap point |
|
|
156
|
+
|
|
157
|
+
#### Performance Optimization
|
|
158
|
+
|
|
159
|
+
| Prop | Type | Description |
|
|
160
|
+
| ------------------ | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
161
|
+
| `showContentDelay` | `{ type?: 'mount' \| 'opacity', timeInMilliSecs: number }` | Delays content rendering for heavy components. Use `'mount'` for better performance with sluggish animations. Provide appropriate `minHeight` when using `'mount'` |
|
|
162
|
+
|
|
163
|
+
### Ref Methods
|
|
164
|
+
|
|
165
|
+
#### `BottomModalRef` (for BottomSheetModal and BottomSheet)
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
const bottomSheetRef = useRef<BottomModalRefObject>(null);
|
|
169
|
+
|
|
170
|
+
// Open modal programmatically
|
|
171
|
+
bottomSheetRef.current?.openModal({
|
|
172
|
+
onOpen: () => console.log('Modal opened'),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Close modal with options
|
|
176
|
+
bottomSheetRef.current?.closeModal({
|
|
177
|
+
skipAnimation: false, // Skip close animation
|
|
178
|
+
isNavigating: false, // Fast close for navigation
|
|
179
|
+
duration: 300, // Custom duration
|
|
180
|
+
easing: Easing.linear, // Custom easing
|
|
181
|
+
onClose: () => console.log('Modal closed'),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Close instantly without animation
|
|
185
|
+
bottomSheetRef.current?.closeWithoutAnimation();
|
|
186
|
+
|
|
187
|
+
// Snap to specific index
|
|
188
|
+
bottomSheetRef.current?.snapToIndex(1);
|
|
189
|
+
|
|
190
|
+
// Snap to percentage
|
|
191
|
+
bottomSheetRef.current?.snapToPercentage(75);
|
|
192
|
+
bottomSheetRef.current?.snapToPercentage('80%');
|
|
193
|
+
|
|
194
|
+
// Get current state
|
|
195
|
+
const state = bottomSheetRef.current?.getModalState();
|
|
196
|
+
// Returns: ModalState.CLOSED | OPENING | OPEN | CLOSING
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### `BottomSheetRef` (for inline BottomSheet with BottomSheetControl)
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
const sheetRef = useRef<BottomSheetRefObject>(null);
|
|
203
|
+
|
|
204
|
+
// Animate close
|
|
205
|
+
sheetRef.current?.animateCloseModal({
|
|
206
|
+
duration: 300,
|
|
207
|
+
easing: Easing.bezier(0.2, 0.32, 0, 1),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Snap to index
|
|
211
|
+
sheetRef.current?.snapToIndex(2);
|
|
212
|
+
|
|
213
|
+
// Snap to percentage
|
|
214
|
+
sheetRef.current?.snapToPercentage(50);
|
|
215
|
+
|
|
216
|
+
// Get state
|
|
217
|
+
const state = sheetRef.current?.getModalState();
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Hook: `useBottomSheetRef`
|
|
221
|
+
|
|
222
|
+
Access the modal ref from within the bottom sheet component tree.
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
import { useBottomSheetRef } from '@shaquillehinds/react-native-bottom-sheet';
|
|
226
|
+
|
|
227
|
+
function ContentComponent() {
|
|
228
|
+
const { modalRef } = useBottomSheetRef();
|
|
229
|
+
|
|
230
|
+
const handleClose = () => {
|
|
231
|
+
modalRef?.current?.closeModal();
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
return <Button title="Close" onPress={handleClose} />;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Advanced Usage
|
|
239
|
+
|
|
240
|
+
### Scrollable Content
|
|
241
|
+
|
|
242
|
+
#### Using BottomSheetFlatlist
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import {
|
|
246
|
+
BottomSheetModal,
|
|
247
|
+
BottomSheetFlatlist,
|
|
248
|
+
} from '@shaquillehinds/react-native-bottom-sheet';
|
|
249
|
+
|
|
250
|
+
<BottomSheetModal
|
|
251
|
+
showModal={showModal}
|
|
252
|
+
setShowModal={setShowModal}
|
|
253
|
+
snapPoints={[50, 90]}
|
|
254
|
+
>
|
|
255
|
+
<BottomSheetFlatlist
|
|
256
|
+
data={items}
|
|
257
|
+
renderItem={({ item }) => <ItemComponent item={item} />}
|
|
258
|
+
keyExtractor={(item) => item.id}
|
|
259
|
+
/>
|
|
260
|
+
</BottomSheetModal>;
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### Using BottomSheetScrollView
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
import {
|
|
267
|
+
BottomSheetModal,
|
|
268
|
+
BottomSheetScrollView,
|
|
269
|
+
} from '@shaquillehinds/react-native-bottom-sheet';
|
|
270
|
+
|
|
271
|
+
<BottomSheetModal showModal={showModal} setShowModal={setShowModal}>
|
|
272
|
+
<BottomSheetScrollView>{/* Your scrollable content */}</BottomSheetScrollView>
|
|
273
|
+
</BottomSheetModal>;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Keyboard Handling
|
|
277
|
+
|
|
278
|
+
#### Global Keyboard Avoidance
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
<BottomSheetModal
|
|
282
|
+
avoidKeyboard={true}
|
|
283
|
+
showModal={showModal}
|
|
284
|
+
setShowModal={setShowModal}
|
|
285
|
+
>
|
|
286
|
+
<TextInput placeholder="Email" />
|
|
287
|
+
<TextInput placeholder="Password" />
|
|
288
|
+
</BottomSheetModal>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### Per-Input Keyboard Avoidance
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
function FormComponent() {
|
|
295
|
+
const emailRef = useRef<TextInput>(null);
|
|
296
|
+
const passwordRef = useRef<TextInput>(null);
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<BottomSheetModal
|
|
300
|
+
inputsForKeyboardToAvoid={[emailRef, passwordRef]}
|
|
301
|
+
showModal={showModal}
|
|
302
|
+
setShowModal={setShowModal}
|
|
303
|
+
>
|
|
304
|
+
<TextInput ref={emailRef} placeholder="Email" />
|
|
305
|
+
<TextInput ref={passwordRef} placeholder="Password" />
|
|
306
|
+
<TextInput placeholder="Not tracked" />
|
|
307
|
+
</BottomSheetModal>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Custom Bumper
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
function CustomBumper() {
|
|
316
|
+
return (
|
|
317
|
+
<View style={{ padding: 20, alignItems: 'center' }}>
|
|
318
|
+
<View
|
|
319
|
+
style={{
|
|
320
|
+
width: 100,
|
|
321
|
+
height: 5,
|
|
322
|
+
backgroundColor: 'blue',
|
|
323
|
+
borderRadius: 3,
|
|
324
|
+
}}
|
|
325
|
+
/>
|
|
326
|
+
<Text style={{ marginTop: 10 }}>Drag me</Text>
|
|
327
|
+
</View>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
<BottomSheetModal
|
|
332
|
+
BumperComponent={CustomBumper}
|
|
333
|
+
showModal={showModal}
|
|
334
|
+
setShowModal={setShowModal}
|
|
335
|
+
>
|
|
336
|
+
<YourContent />
|
|
337
|
+
</BottomSheetModal>;
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Custom Backdrop
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
function CustomBackdrop() {
|
|
344
|
+
return (
|
|
345
|
+
<View
|
|
346
|
+
style={{
|
|
347
|
+
flex: 1,
|
|
348
|
+
backgroundColor: 'rgba(255, 0, 0, 0.3)',
|
|
349
|
+
}}
|
|
350
|
+
/>
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
<BottomSheetModal
|
|
355
|
+
BackdropComponent={<CustomBackdrop />}
|
|
356
|
+
showModal={showModal}
|
|
357
|
+
setShowModal={setShowModal}
|
|
358
|
+
>
|
|
359
|
+
<YourContent />
|
|
360
|
+
</BottomSheetModal>;
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Persistent Bottom Sheet
|
|
364
|
+
|
|
365
|
+
Keep the sheet partially visible when "closed":
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
<BottomSheet
|
|
369
|
+
keepMounted={true}
|
|
370
|
+
bottomOffset={50} // Shows 50px when closed
|
|
371
|
+
snapPoints={[10, 50, 90]}
|
|
372
|
+
showModal={showModal}
|
|
373
|
+
setShowModal={setShowModal}
|
|
374
|
+
>
|
|
375
|
+
<YourContent />
|
|
376
|
+
</BottomSheet>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Performance Optimization for Heavy Content
|
|
380
|
+
|
|
381
|
+
Use `showContentDelay` to improve modal animation performance:
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
<BottomSheetModal
|
|
385
|
+
showModal={showModal}
|
|
386
|
+
setShowModal={setShowModal}
|
|
387
|
+
contentContainerStyle={{ minHeight: 400 }}
|
|
388
|
+
showContentDelay={{
|
|
389
|
+
type: 'mount', // Delays mounting entirely
|
|
390
|
+
timeInMilliSecs: 100,
|
|
391
|
+
}}
|
|
392
|
+
>
|
|
393
|
+
<HeavyComponent />
|
|
394
|
+
</BottomSheetModal>
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Or use opacity animation:
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
<BottomSheetModal
|
|
401
|
+
showContentDelay={{
|
|
402
|
+
type: 'opacity', // Fades in content
|
|
403
|
+
timeInMilliSecs: 200,
|
|
404
|
+
}}
|
|
405
|
+
showModal={showModal}
|
|
406
|
+
setShowModal={setShowModal}
|
|
407
|
+
>
|
|
408
|
+
<YourContent />
|
|
409
|
+
</BottomSheetModal>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Snap Point Callbacks
|
|
413
|
+
|
|
414
|
+
```tsx
|
|
415
|
+
<BottomSheetModal
|
|
416
|
+
snapPoints={[25, 50, 75]}
|
|
417
|
+
onSnapPointReach={(index) => {
|
|
418
|
+
console.log(`Reached snap point: ${index}`);
|
|
419
|
+
if (index === 2) {
|
|
420
|
+
// Reached highest snap point
|
|
421
|
+
}
|
|
422
|
+
}}
|
|
423
|
+
showModal={showModal}
|
|
424
|
+
setShowModal={setShowModal}
|
|
425
|
+
>
|
|
426
|
+
<YourContent />
|
|
427
|
+
</BottomSheetModal>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Drag Configuration
|
|
431
|
+
|
|
432
|
+
#### Full Sheet Dragging
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
<BottomSheetModal
|
|
436
|
+
dragArea="full"
|
|
437
|
+
showModal={showModal}
|
|
438
|
+
setShowModal={setShowModal}
|
|
439
|
+
>
|
|
440
|
+
<YourContent />
|
|
441
|
+
</BottomSheetModal>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
#### Disable Dragging
|
|
445
|
+
|
|
446
|
+
```tsx
|
|
447
|
+
<BottomSheetModal
|
|
448
|
+
dragArea="none"
|
|
449
|
+
showModal={showModal}
|
|
450
|
+
setShowModal={setShowModal}
|
|
451
|
+
>
|
|
452
|
+
<YourContent />
|
|
453
|
+
</BottomSheetModal>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### Allow Dragging with Keyboard
|
|
457
|
+
|
|
458
|
+
```tsx
|
|
459
|
+
<BottomSheetModal
|
|
460
|
+
avoidKeyboard={true}
|
|
461
|
+
allowDragWhileKeyboardVisible={true}
|
|
462
|
+
showModal={showModal}
|
|
463
|
+
setShowModal={setShowModal}
|
|
464
|
+
>
|
|
465
|
+
<TextInput />
|
|
466
|
+
</BottomSheetModal>
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Portal Management
|
|
470
|
+
|
|
471
|
+
By default, the bottom sheet uses a portal to render at the root level. You can customize this:
|
|
472
|
+
|
|
473
|
+
#### Disable Portal
|
|
474
|
+
|
|
475
|
+
```tsx
|
|
476
|
+
<BottomSheetModal
|
|
477
|
+
disablePortal={true}
|
|
478
|
+
showModal={showModal}
|
|
479
|
+
setShowModal={setShowModal}
|
|
480
|
+
>
|
|
481
|
+
<YourContent />
|
|
482
|
+
</BottomSheetModal>
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
#### Custom Portal Context
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
import { createPortalContext } from '@shaquillehinds/react-native-essentials';
|
|
489
|
+
|
|
490
|
+
const MyPortalContext = createPortalContext();
|
|
491
|
+
|
|
492
|
+
// In your app root
|
|
493
|
+
<MyPortalContext.Provider>
|
|
494
|
+
<YourApp />
|
|
495
|
+
</MyPortalContext.Provider>
|
|
496
|
+
|
|
497
|
+
// In your component
|
|
498
|
+
<BottomSheetModal
|
|
499
|
+
CustomPortalContext={MyPortalContext}
|
|
500
|
+
showModal={showModal}
|
|
501
|
+
setShowModal={setShowModal}
|
|
502
|
+
>
|
|
503
|
+
<YourContent />
|
|
504
|
+
</BottomSheetModal>
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Navigation Integration
|
|
508
|
+
|
|
509
|
+
For smooth navigation transitions on Android:
|
|
510
|
+
|
|
511
|
+
```tsx
|
|
512
|
+
const handleNavigateAndClose = () => {
|
|
513
|
+
bottomSheetRef.current?.closeModal({
|
|
514
|
+
isNavigating: true, // Reduces animation to 100ms
|
|
515
|
+
onClose: () => {
|
|
516
|
+
navigation.navigate('NextScreen');
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Or skip animation entirely:
|
|
523
|
+
|
|
524
|
+
```tsx
|
|
525
|
+
bottomSheetRef.current?.closeModal({
|
|
526
|
+
skipAnimation: true,
|
|
527
|
+
onClose: () => navigation.navigate('NextScreen'),
|
|
528
|
+
});
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## TypeScript Support
|
|
532
|
+
|
|
533
|
+
Full TypeScript support with comprehensive type definitions:
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
import type {
|
|
537
|
+
BottomSheetProps,
|
|
538
|
+
BottomSheetModalProps,
|
|
539
|
+
BottomModalRefObject,
|
|
540
|
+
BottomSheetRefObject,
|
|
541
|
+
BottomModalRef,
|
|
542
|
+
BottomSheetRef,
|
|
543
|
+
ModalState,
|
|
544
|
+
AnimateCloseModalProps,
|
|
545
|
+
CloseModalProps,
|
|
546
|
+
OpenModalProps,
|
|
547
|
+
} from '@shaquillehinds/react-native-bottom-sheet';
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
## Examples
|
|
551
|
+
|
|
552
|
+
### Complete Modal Example
|
|
553
|
+
|
|
554
|
+
```tsx
|
|
555
|
+
import React, { useRef, useState } from 'react';
|
|
556
|
+
import { View, Text, Button, TextInput } from 'react-native';
|
|
557
|
+
import {
|
|
558
|
+
BottomSheetModal,
|
|
559
|
+
BottomSheetScrollView,
|
|
560
|
+
useBottomSheetRef,
|
|
561
|
+
} from '@shaquillehinds/react-native-bottom-sheet';
|
|
562
|
+
import type { BottomModalRefObject } from '@shaquillehinds/react-native-bottom-sheet';
|
|
563
|
+
|
|
564
|
+
export default function CompleteExample() {
|
|
565
|
+
const [showModal, setShowModal] = useState(false);
|
|
566
|
+
const bottomSheetRef = useRef<BottomModalRefObject>(null);
|
|
567
|
+
|
|
568
|
+
const handleOpen = () => {
|
|
569
|
+
bottomSheetRef.current?.openModal({
|
|
570
|
+
onOpen: () => console.log('Modal opened!'),
|
|
571
|
+
});
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const handleSnapToTop = () => {
|
|
575
|
+
bottomSheetRef.current?.snapToIndex(2);
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
return (
|
|
579
|
+
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
580
|
+
<Button title="Open Modal" onPress={() => setShowModal(true)} />
|
|
581
|
+
|
|
582
|
+
<BottomSheetModal
|
|
583
|
+
ref={bottomSheetRef}
|
|
584
|
+
showModal={showModal}
|
|
585
|
+
setShowModal={setShowModal}
|
|
586
|
+
snapPoints={[30, 60, 90]}
|
|
587
|
+
backgroundColor="#ffffff"
|
|
588
|
+
avoidKeyboard={true}
|
|
589
|
+
onModalShow={() => console.log('Modal shown')}
|
|
590
|
+
onModalClose={() => console.log('Modal closed')}
|
|
591
|
+
onSnapPointReach={(index) => console.log('Snap point:', index)}
|
|
592
|
+
>
|
|
593
|
+
<BottomSheetScrollView>
|
|
594
|
+
<View style={{ padding: 20 }}>
|
|
595
|
+
<Text style={{ fontSize: 24, marginBottom: 20 }}>My Modal</Text>
|
|
596
|
+
|
|
597
|
+
<TextInput
|
|
598
|
+
placeholder="Enter text..."
|
|
599
|
+
style={{
|
|
600
|
+
borderWidth: 1,
|
|
601
|
+
borderColor: '#ccc',
|
|
602
|
+
padding: 10,
|
|
603
|
+
marginBottom: 20,
|
|
604
|
+
}}
|
|
605
|
+
/>
|
|
606
|
+
|
|
607
|
+
<Button title="Snap to Top" onPress={handleSnapToTop} />
|
|
608
|
+
|
|
609
|
+
<InnerComponent />
|
|
610
|
+
</View>
|
|
611
|
+
</BottomSheetScrollView>
|
|
612
|
+
</BottomSheetModal>
|
|
613
|
+
</View>
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function InnerComponent() {
|
|
618
|
+
const { modalRef } = useBottomSheetRef();
|
|
619
|
+
|
|
620
|
+
return (
|
|
621
|
+
<Button
|
|
622
|
+
title="Close from Inside"
|
|
623
|
+
onPress={() => modalRef?.current?.closeModal()}
|
|
624
|
+
/>
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Form with Validation Example
|
|
630
|
+
|
|
631
|
+
```tsx
|
|
632
|
+
import React, { useRef, useState } from 'react';
|
|
633
|
+
import { View, Text, TextInput, Button } from 'react-native';
|
|
634
|
+
import { BottomSheetModal } from '@shaquillehinds/react-native-bottom-sheet';
|
|
635
|
+
import type { BottomModalRefObject } from '@shaquillehinds/react-native-bottom-sheet';
|
|
636
|
+
|
|
637
|
+
export default function FormExample() {
|
|
638
|
+
const [showModal, setShowModal] = useState(false);
|
|
639
|
+
const [email, setEmail] = useState('');
|
|
640
|
+
const [password, setPassword] = useState('');
|
|
641
|
+
const emailRef = useRef<TextInput>(null);
|
|
642
|
+
const passwordRef = useRef<TextInput>(null);
|
|
643
|
+
const bottomSheetRef = useRef<BottomModalRefObject>(null);
|
|
644
|
+
|
|
645
|
+
const handleSubmit = () => {
|
|
646
|
+
if (email && password) {
|
|
647
|
+
console.log('Submitting:', { email, password });
|
|
648
|
+
bottomSheetRef.current?.closeModal({
|
|
649
|
+
onClose: () => {
|
|
650
|
+
// Clear form after animation
|
|
651
|
+
setEmail('');
|
|
652
|
+
setPassword('');
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
return (
|
|
659
|
+
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
660
|
+
<Button title="Login" onPress={() => setShowModal(true)} />
|
|
661
|
+
|
|
662
|
+
<BottomSheetModal
|
|
663
|
+
ref={bottomSheetRef}
|
|
664
|
+
showModal={showModal}
|
|
665
|
+
setShowModal={setShowModal}
|
|
666
|
+
snapPoints={[60]}
|
|
667
|
+
inputsForKeyboardToAvoid={[emailRef, passwordRef]}
|
|
668
|
+
contentContainerStyle={{ padding: 20 }}
|
|
669
|
+
>
|
|
670
|
+
<Text style={{ fontSize: 24, marginBottom: 20 }}>Login</Text>
|
|
671
|
+
|
|
672
|
+
<TextInput
|
|
673
|
+
ref={emailRef}
|
|
674
|
+
value={email}
|
|
675
|
+
onChangeText={setEmail}
|
|
676
|
+
placeholder="Email"
|
|
677
|
+
keyboardType="email-address"
|
|
678
|
+
autoCapitalize="none"
|
|
679
|
+
style={{
|
|
680
|
+
borderWidth: 1,
|
|
681
|
+
borderColor: '#ccc',
|
|
682
|
+
padding: 10,
|
|
683
|
+
marginBottom: 15,
|
|
684
|
+
}}
|
|
685
|
+
/>
|
|
686
|
+
|
|
687
|
+
<TextInput
|
|
688
|
+
ref={passwordRef}
|
|
689
|
+
value={password}
|
|
690
|
+
onChangeText={setPassword}
|
|
691
|
+
placeholder="Password"
|
|
692
|
+
secureTextEntry
|
|
693
|
+
style={{
|
|
694
|
+
borderWidth: 1,
|
|
695
|
+
borderColor: '#ccc',
|
|
696
|
+
padding: 10,
|
|
697
|
+
marginBottom: 20,
|
|
698
|
+
}}
|
|
699
|
+
/>
|
|
700
|
+
|
|
701
|
+
<Button title="Submit" onPress={handleSubmit} />
|
|
702
|
+
</BottomSheetModal>
|
|
703
|
+
</View>
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
## Performance Best Practices
|
|
709
|
+
|
|
710
|
+
1. **Use `useImperativeHandle` pattern**: This package follows the render isolation pattern to prevent parent re-renders when animating
|
|
711
|
+
|
|
712
|
+
2. **Optimize heavy content**: Use `showContentDelay` with `type: 'mount'` for complex UIs:
|
|
713
|
+
|
|
714
|
+
```tsx
|
|
715
|
+
<BottomSheetModal
|
|
716
|
+
showContentDelay={{ type: 'mount', timeInMilliSecs: 100 }}
|
|
717
|
+
contentContainerStyle={{ minHeight: 400 }}
|
|
718
|
+
>
|
|
719
|
+
<ComplexComponent />
|
|
720
|
+
</BottomSheetModal>
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
3. **Memoize callbacks**: Use `useCallback` for callbacks to prevent unnecessary re-renders:
|
|
724
|
+
|
|
725
|
+
```tsx
|
|
726
|
+
const handleSnapPoint = useCallback((index: number) => {
|
|
727
|
+
console.log('Snap point:', index);
|
|
728
|
+
}, []);
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
4. **Keep snap points stable**: Define snap points outside the component or use `useMemo`:
|
|
732
|
+
```tsx
|
|
733
|
+
const snapPoints = useMemo(() => [30, 60, 90], []);
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
## Common Patterns
|
|
737
|
+
|
|
738
|
+
### Confirmation Dialog
|
|
739
|
+
|
|
740
|
+
```tsx
|
|
741
|
+
function ConfirmDialog() {
|
|
742
|
+
const [show, setShow] = useState(false);
|
|
743
|
+
|
|
744
|
+
return (
|
|
745
|
+
<BottomSheetModal
|
|
746
|
+
showModal={show}
|
|
747
|
+
setShowModal={setShow}
|
|
748
|
+
snapPoints={[30]}
|
|
749
|
+
contentContainerStyle={{ padding: 20 }}
|
|
750
|
+
>
|
|
751
|
+
<Text style={{ fontSize: 18, marginBottom: 20 }}>Are you sure?</Text>
|
|
752
|
+
<View style={{ flexDirection: 'row', gap: 10 }}>
|
|
753
|
+
<Button title="Cancel" onPress={() => setShow(false)} />
|
|
754
|
+
<Button title="Confirm" onPress={handleConfirm} />
|
|
755
|
+
</View>
|
|
756
|
+
</BottomSheetModal>
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Selection List
|
|
762
|
+
|
|
763
|
+
```tsx
|
|
764
|
+
function SelectionList() {
|
|
765
|
+
const [show, setShow] = useState(false);
|
|
766
|
+
|
|
767
|
+
return (
|
|
768
|
+
<BottomSheetModal
|
|
769
|
+
showModal={show}
|
|
770
|
+
setShowModal={setShow}
|
|
771
|
+
snapPoints={[50, 80]}
|
|
772
|
+
>
|
|
773
|
+
<BottomSheetFlatlist
|
|
774
|
+
data={options}
|
|
775
|
+
renderItem={({ item }) => (
|
|
776
|
+
<TouchableOpacity onPress={() => handleSelect(item)}>
|
|
777
|
+
<Text style={{ padding: 15 }}>{item.label}</Text>
|
|
778
|
+
</TouchableOpacity>
|
|
779
|
+
)}
|
|
780
|
+
/>
|
|
781
|
+
</BottomSheetModal>
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Filter Panel
|
|
787
|
+
|
|
788
|
+
```tsx
|
|
789
|
+
function FilterPanel() {
|
|
790
|
+
const [show, setShow] = useState(false);
|
|
791
|
+
|
|
792
|
+
return (
|
|
793
|
+
<BottomSheet
|
|
794
|
+
keepMounted={true}
|
|
795
|
+
bottomOffset={100}
|
|
796
|
+
snapPoints={[10, 70]}
|
|
797
|
+
showModal={show}
|
|
798
|
+
setShowModal={setShow}
|
|
799
|
+
>
|
|
800
|
+
<BottomSheetScrollView>
|
|
801
|
+
<FilterOptions />
|
|
802
|
+
</BottomSheetScrollView>
|
|
803
|
+
</BottomSheet>
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
## Troubleshooting
|
|
809
|
+
|
|
810
|
+
### Modal doesn't appear
|
|
811
|
+
|
|
812
|
+
Ensure you've set up React Native Reanimated and Gesture Handler properly:
|
|
813
|
+
|
|
814
|
+
```tsx
|
|
815
|
+
// babel.config.js
|
|
816
|
+
module.exports = {
|
|
817
|
+
presets: ['module:metro-react-native-babel-preset'],
|
|
818
|
+
plugins: ['react-native-reanimated/plugin'],
|
|
819
|
+
};
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
### Scrolling issues
|
|
823
|
+
|
|
824
|
+
Always use `BottomSheetFlatlist` or `BottomSheetScrollView` for scrollable content inside the bottom sheet.
|
|
825
|
+
|
|
826
|
+
### Keyboard issues
|
|
827
|
+
|
|
828
|
+
Use `avoidKeyboard` or `inputsForKeyboardToAvoid` props and ensure inputs have proper refs.
|
|
829
|
+
|
|
830
|
+
### Android navigation glitches
|
|
831
|
+
|
|
832
|
+
Use `isNavigating` or `skipAnimation` when closing before navigation:
|
|
833
|
+
|
|
834
|
+
```tsx
|
|
835
|
+
bottomSheetRef.current?.closeModal({
|
|
836
|
+
isNavigating: true,
|
|
837
|
+
onClose: () => navigation.navigate('NextScreen'),
|
|
838
|
+
});
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
## Dependencies
|
|
842
|
+
|
|
843
|
+
- `react-native-reanimated` ^3.0.0
|
|
844
|
+
- `react-native-gesture-handler` ^2.0.0
|
|
845
|
+
- `@shaquillehinds/react-native-essentials` ^1.8.0
|
|
846
|
+
|
|
847
|
+
## Contributing
|
|
848
|
+
|
|
849
|
+
Contributions are welcome! Please read the [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
|
850
|
+
|
|
851
|
+
## License
|
|
852
|
+
|
|
853
|
+
MIT © [Shaquille Hinds](https://github.com/shaquillehinds)
|
|
854
|
+
|
|
855
|
+
## Author
|
|
856
|
+
|
|
857
|
+
**Shaquille Hinds**
|
|
858
|
+
|
|
859
|
+
- GitHub: [@shaquillehinds](https://github.com/shaquillehinds)
|
|
860
|
+
- Email: shaqdulove@gmail.com
|
|
861
|
+
|
|
862
|
+
## Related Packages
|
|
863
|
+
|
|
864
|
+
- [@shaquillehinds/react-native-essentials](https://www.npmjs.com/package/@shaquillehinds/react-native-essentials) - Essential utilities and components for React Native
|
|
865
|
+
|
|
866
|
+
## Changelog
|
|
867
|
+
|
|
868
|
+
See [Releases](https://github.com/shaquillehinds/react-native-bottom-sheet/releases) for version history.
|
|
869
|
+
|
|
870
|
+
## Support
|
|
871
|
+
|
|
872
|
+
If you encounter any issues or have questions:
|
|
873
|
+
|
|
874
|
+
- Open an issue on [GitHub](https://github.com/shaquillehinds/react-native-bottom-sheet/issues)
|
|
875
|
+
- Check existing issues for solutions
|
|
876
|
+
- Review the examples in this README
|
|
877
|
+
|
|
878
|
+
## Acknowledgments
|
|
879
|
+
|
|
880
|
+
Built with React Native Reanimated and Gesture Handler for optimal performance and smooth interactions.
|