@niibase/bottom-sheet-manager 1.1.0 → 1.3.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/README.md +372 -38
- package/lib/commonjs/events.js +100 -15
- package/lib/commonjs/events.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/manager.js +107 -29
- package/lib/commonjs/manager.js.map +1 -1
- package/lib/commonjs/provider.js +69 -28
- package/lib/commonjs/provider.js.map +1 -1
- package/lib/commonjs/router/index.js +50 -21
- package/lib/commonjs/router/index.js.map +1 -1
- package/lib/commonjs/router/router.js +137 -12
- package/lib/commonjs/router/router.js.map +1 -1
- package/lib/commonjs/router/view.js +194 -84
- package/lib/commonjs/router/view.js.map +1 -1
- package/lib/commonjs/sheet.js +125 -76
- package/lib/commonjs/sheet.js.map +1 -1
- package/lib/module/events.js +100 -15
- package/lib/module/events.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/manager.js +108 -29
- package/lib/module/manager.js.map +1 -1
- package/lib/module/provider.js +65 -25
- package/lib/module/provider.js.map +1 -1
- package/lib/module/router/index.js +34 -18
- package/lib/module/router/index.js.map +1 -1
- package/lib/module/router/router.js +135 -11
- package/lib/module/router/router.js.map +1 -1
- package/lib/module/router/view.js +194 -84
- package/lib/module/router/view.js.map +1 -1
- package/lib/module/sheet.js +127 -78
- package/lib/module/sheet.js.map +1 -1
- package/lib/typescript/events.d.ts +46 -12
- package/lib/typescript/events.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/manager.d.ts +57 -7
- package/lib/typescript/manager.d.ts.map +1 -1
- package/lib/typescript/provider.d.ts +22 -3
- package/lib/typescript/provider.d.ts.map +1 -1
- package/lib/typescript/router/index.d.ts +33 -17
- package/lib/typescript/router/index.d.ts.map +1 -1
- package/lib/typescript/router/router.d.ts +44 -5
- package/lib/typescript/router/router.d.ts.map +1 -1
- package/lib/typescript/router/types.d.ts +113 -17
- package/lib/typescript/router/types.d.ts.map +1 -1
- package/lib/typescript/router/view.d.ts +1 -1
- package/lib/typescript/router/view.d.ts.map +1 -1
- package/lib/typescript/sheet.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +27 -12
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/events.ts +118 -27
- package/src/index.ts +6 -5
- package/src/manager.ts +156 -33
- package/src/provider.tsx +98 -44
- package/src/router/index.tsx +38 -31
- package/src/router/router.ts +184 -15
- package/src/router/types.ts +119 -22
- package/src/router/view.tsx +252 -132
- package/src/sheet.tsx +176 -95
- package/src/types.ts +144 -129
package/README.md
CHANGED
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
# Bottom Sheet Router & Manager
|
|
2
2
|
|
|
3
|
-
A bottom sheet manager inspired by
|
|
3
|
+
A powerful bottom sheet manager and router for React Native, inspired by [react-native-actions-sheet](https://github.com/ammarahm-ed/@repo/bottom-sheet) and built on top of [@gorhom/bottom-sheet](https://github.com/gorhom/react-native-bottom-sheet).
|
|
4
4
|
|
|
5
|
+
## Features
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
- 🎯 **Simple API** - Show/hide sheets from anywhere in your app
|
|
8
|
+
- 🔄 **Stack Behaviors** - Control how sheets stack with `push` (experimental), `switch`, or `replace` behaviors
|
|
9
|
+
- 🧭 **React Navigation Integration** - Full support for React Navigation v6/v7 and Expo Router
|
|
10
|
+
- 📱 **iOS 18 Modal Animation** - Native-like modal sheet animations
|
|
11
|
+
- 🎨 **TypeScript Support** - Full type safety with IntelliSense
|
|
12
|
+
- ⚡ **Performance Optimized** - High-performance event system with O(1) lookups
|
|
13
|
+
- 🔌 **Flexible Hooks** - Rich set of hooks for advanced use cases
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
## Installation
|
|
9
16
|
|
|
10
17
|
```bash
|
|
11
18
|
npm install @niibase/bottom-sheet-manager
|
|
12
19
|
```
|
|
13
20
|
|
|
14
|
-
##
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Basic Usage
|
|
15
24
|
|
|
16
|
-
`SheetManager`
|
|
25
|
+
`SheetManager` helps you save development time by allowing you to reuse modal sheets throughout your app without boilerplate.
|
|
17
26
|
|
|
18
27
|
```tsx
|
|
19
|
-
import { BottomSheet } from '@niibase/bottom-sheet-manager';
|
|
28
|
+
import { BottomSheet, SheetManager } from '@niibase/bottom-sheet-manager';
|
|
29
|
+
import type { SheetProps } from '@niibase/bottom-sheet-manager';
|
|
20
30
|
```
|
|
21
31
|
|
|
22
|
-
Create your BottomSheet component
|
|
32
|
+
Create your BottomSheet component:
|
|
23
33
|
|
|
24
34
|
```tsx
|
|
25
|
-
function ExampleSheet({ id }: SheetProps<"example">) {
|
|
35
|
+
function ExampleSheet({ id }: SheetProps<"example-sheet">) {
|
|
26
36
|
return (
|
|
27
|
-
<BottomSheet
|
|
37
|
+
<BottomSheet
|
|
38
|
+
id={id}
|
|
39
|
+
snapPoints={['50%', '90%']}
|
|
40
|
+
>
|
|
28
41
|
<View>
|
|
29
42
|
<Text>Hello World</Text>
|
|
30
43
|
</View>
|
|
@@ -35,66 +48,87 @@ function ExampleSheet({ id }: SheetProps<"example">) {
|
|
|
35
48
|
export default ExampleSheet;
|
|
36
49
|
```
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
Register your sheet in a `sheets.ts` file:
|
|
39
52
|
|
|
40
53
|
```ts
|
|
41
|
-
import {registerSheet} from '@niibase/bottom-sheet-manager';
|
|
42
|
-
import
|
|
54
|
+
import { registerSheet } from '@niibase/bottom-sheet-manager';
|
|
55
|
+
import type { SheetDefinition } from '@niibase/bottom-sheet-manager';
|
|
56
|
+
import ExampleSheet from './ExampleSheet';
|
|
43
57
|
|
|
44
58
|
registerSheet('example-sheet', ExampleSheet);
|
|
45
59
|
|
|
46
|
-
//
|
|
47
|
-
// across the app for all registered sheets.
|
|
60
|
+
// Extend types for IntelliSense
|
|
48
61
|
declare module '@niibase/bottom-sheet-manager' {
|
|
49
62
|
interface Sheets {
|
|
50
63
|
'example-sheet': SheetDefinition;
|
|
51
64
|
}
|
|
52
65
|
}
|
|
53
|
-
|
|
54
|
-
export {};
|
|
55
66
|
```
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
Wrap your app with `SheetProvider`:
|
|
58
69
|
|
|
59
70
|
```tsx
|
|
60
71
|
import { SheetProvider } from '@niibase/bottom-sheet-manager';
|
|
61
|
-
import 'sheets
|
|
72
|
+
import './sheets';
|
|
62
73
|
|
|
63
74
|
function App() {
|
|
64
75
|
return (
|
|
65
76
|
<SheetProvider>
|
|
66
|
-
{
|
|
67
|
-
// your app components
|
|
68
|
-
}
|
|
77
|
+
{/* your app components */}
|
|
69
78
|
</SheetProvider>
|
|
70
79
|
);
|
|
71
80
|
}
|
|
72
81
|
```
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
Show and hide sheets:
|
|
75
84
|
|
|
76
|
-
```
|
|
85
|
+
```tsx
|
|
86
|
+
// Show a sheet
|
|
77
87
|
SheetManager.show('example-sheet');
|
|
78
|
-
```
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
// Show with payload
|
|
90
|
+
SheetManager.show('example-sheet', { userId: 123 });
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
// Hide a sheet
|
|
83
93
|
SheetManager.hide('example-sheet');
|
|
94
|
+
|
|
95
|
+
// Hide and get return value
|
|
96
|
+
const result = await SheetManager.show('example-sheet');
|
|
84
97
|
```
|
|
85
98
|
|
|
86
|
-
|
|
99
|
+
## Stack Behaviors
|
|
87
100
|
|
|
88
|
-
|
|
101
|
+
Control how sheets behave when opened on top of existing sheets:
|
|
102
|
+
|
|
103
|
+
- **`switch`** (default): Dismisses the current sheet before showing the new one. Previous sheet is restored when new one closes.
|
|
104
|
+
- **`replace`**: Swaps the current sheet's content with smooth crossfade animation. Previous sheet is removed from stack.
|
|
105
|
+
- **`push`** (experimental): Pushes new sheet on top, creating a navigable stack. Previous sheet remains visible underneath.
|
|
89
106
|
|
|
90
107
|
```tsx
|
|
108
|
+
// Set stack behavior per sheet
|
|
109
|
+
<BottomSheet
|
|
110
|
+
id={id}
|
|
111
|
+
stackBehavior="push" // or "switch" or "replace"
|
|
112
|
+
snapPoints={['50%', '90%']}
|
|
113
|
+
>
|
|
114
|
+
{/* content */}
|
|
115
|
+
</BottomSheet>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## React Navigation Integration
|
|
119
|
+
|
|
120
|
+
Full support for React Navigation v6/v7 and Expo Router. The first screen in the navigator is rendered as main content, and subsequent screens are rendered as bottom sheet modals.
|
|
121
|
+
|
|
122
|
+
### With Expo Router
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { Slot, withLayoutContext } from "expo-router";
|
|
91
126
|
import {
|
|
92
127
|
createBottomSheetNavigator,
|
|
93
128
|
BottomSheetNavigationOptions,
|
|
94
129
|
BottomSheetNavigationEventMap,
|
|
95
130
|
BottomSheetNavigationState,
|
|
96
|
-
} from "@
|
|
97
|
-
import { Slot, withLayoutContext } from "expo-router";
|
|
131
|
+
} from "@niibase/bottom-sheet-manager";
|
|
98
132
|
|
|
99
133
|
const { Navigator } = createBottomSheetNavigator();
|
|
100
134
|
const BottomSheet = withLayoutContext<
|
|
@@ -109,23 +143,323 @@ export const unstable_settings = {
|
|
|
109
143
|
};
|
|
110
144
|
|
|
111
145
|
export default function Layout() {
|
|
146
|
+
// SSR guard - navigator doesn't work on server
|
|
112
147
|
if (typeof window === "undefined") return <Slot />;
|
|
148
|
+
|
|
113
149
|
return (
|
|
114
150
|
<BottomSheet
|
|
115
|
-
screenOptions={
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
}
|
|
151
|
+
screenOptions={{
|
|
152
|
+
snapPoints: ['50%', '90%'],
|
|
153
|
+
// See: https://gorhom.github.io/react-native-bottom-sheet/modal/props/
|
|
154
|
+
}}
|
|
121
155
|
/>
|
|
122
156
|
);
|
|
123
157
|
}
|
|
124
158
|
```
|
|
125
159
|
|
|
160
|
+
### With React Navigation
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { createBottomSheetNavigator } from "@niibase/bottom-sheet-manager";
|
|
164
|
+
|
|
165
|
+
const { Navigator, Screen } = createBottomSheetNavigator();
|
|
166
|
+
|
|
167
|
+
function App() {
|
|
168
|
+
return (
|
|
169
|
+
<Navigator>
|
|
170
|
+
<Screen name="Home" component={HomeScreen} />
|
|
171
|
+
<Screen
|
|
172
|
+
name="Details"
|
|
173
|
+
component={DetailsSheet}
|
|
174
|
+
options={{
|
|
175
|
+
snapPoints: ['50%', '100%'],
|
|
176
|
+
iosModalSheetTypeOfAnimation: true,
|
|
177
|
+
}}
|
|
178
|
+
/>
|
|
179
|
+
</Navigator>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Navigation Actions
|
|
185
|
+
|
|
186
|
+
Use the navigation object to control sheets programmatically:
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { useBottomSheetNavigation } from "@niibase/bottom-sheet-manager";
|
|
190
|
+
|
|
191
|
+
function MySheet() {
|
|
192
|
+
const navigation = useBottomSheetNavigation();
|
|
193
|
+
|
|
194
|
+
// Snap to a specific index
|
|
195
|
+
const handleExpand = () => {
|
|
196
|
+
navigation.snapTo(1); // Snap to second snap point
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Dismiss the current sheet
|
|
200
|
+
const handleDismiss = () => {
|
|
201
|
+
navigation.dismiss();
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<View>
|
|
206
|
+
<Button title="Expand" onPress={handleExpand} />
|
|
207
|
+
<Button title="Dismiss" onPress={handleDismiss} />
|
|
208
|
+
</View>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Known Limitations
|
|
214
|
+
|
|
215
|
+
**⚠️ Important:** When using the bottom sheet as a navigator, calling `BottomSheet.Screen` from the `Navigator` will cause the sheet to render immediately.
|
|
216
|
+
|
|
217
|
+
To customize the sheet screen options (e.g., change `snapPoints`), you must do it within the screen component itself using `navigation.setOptions()`:
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import { useBottomSheetNavigation } from "@niibase/bottom-sheet-manager";
|
|
221
|
+
import { useEffect } from "react";
|
|
222
|
+
|
|
223
|
+
export default function ProfileSheet() {
|
|
224
|
+
const navigation = useBottomSheetNavigation();
|
|
225
|
+
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
navigation.setOptions({ snapPoints: ["100%"] });
|
|
228
|
+
}, [navigation]);
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
// Your sheet content
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
This ensures that the sheet options are set after the component mounts, allowing you to customize the behavior per screen.
|
|
237
|
+
|
|
238
|
+
## Hooks
|
|
239
|
+
|
|
240
|
+
### `useBottomSheetNavigation`
|
|
241
|
+
|
|
242
|
+
Access navigation helpers including `snapTo()` and `dismiss()`:
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import { useBottomSheetNavigation } from "@niibase/bottom-sheet-manager";
|
|
246
|
+
|
|
247
|
+
const navigation = useBottomSheetNavigation();
|
|
248
|
+
navigation.snapTo(1);
|
|
249
|
+
navigation.dismiss();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### `useSheetRef`
|
|
253
|
+
|
|
254
|
+
Get a ref to control the sheet instance:
|
|
255
|
+
|
|
256
|
+
```tsx
|
|
257
|
+
import { useSheetRef } from "@niibase/bottom-sheet-manager";
|
|
258
|
+
|
|
259
|
+
function MySheet({ id }: SheetProps<"my-sheet">) {
|
|
260
|
+
const ref = useSheetRef(id);
|
|
261
|
+
|
|
262
|
+
// Control the sheet
|
|
263
|
+
ref.current?.expand();
|
|
264
|
+
ref.current?.collapse();
|
|
265
|
+
ref.current?.snapToIndex(1);
|
|
266
|
+
ref.current?.close({ value: "result" });
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### `useSheetPayload`
|
|
271
|
+
|
|
272
|
+
Access the payload passed when showing the sheet:
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
import { useSheetPayload } from "@niibase/bottom-sheet-manager";
|
|
276
|
+
|
|
277
|
+
function MySheet({ id }: SheetProps<"my-sheet">) {
|
|
278
|
+
const payload = useSheetPayload<"my-sheet">();
|
|
279
|
+
// payload is typed based on your SheetDefinition
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### `useStackBehaviorContext`
|
|
284
|
+
|
|
285
|
+
Get the current stack behavior context:
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
import { useStackBehaviorContext } from "@niibase/bottom-sheet-manager";
|
|
289
|
+
|
|
290
|
+
function MySheet() {
|
|
291
|
+
const stackBehavior = useStackBehaviorContext();
|
|
292
|
+
// Returns: "push" | "replace" | "switch"
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### `useOnSheet`
|
|
297
|
+
|
|
298
|
+
Subscribe to sheet events:
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
import { useOnSheet } from "@niibase/bottom-sheet-manager";
|
|
302
|
+
|
|
303
|
+
function MyComponent() {
|
|
304
|
+
useOnSheet("my-sheet", {
|
|
305
|
+
onShow: (payload) => {
|
|
306
|
+
console.log("Sheet shown with:", payload);
|
|
307
|
+
},
|
|
308
|
+
onHide: (returnValue) => {
|
|
309
|
+
console.log("Sheet hidden with:", returnValue);
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## iOS 18 Modal Animation
|
|
316
|
+
|
|
317
|
+
Enable native-like iOS 18 modal sheet animations:
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
<BottomSheet
|
|
321
|
+
id={id}
|
|
322
|
+
iosModalSheetTypeOfAnimation={true}
|
|
323
|
+
snapPoints={['50%', '90%', '100%']}
|
|
324
|
+
>
|
|
325
|
+
{/* At 90% snap point, content behind scales down with border radius */}
|
|
326
|
+
</BottomSheet>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Or in navigation options:
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
<Screen
|
|
333
|
+
name="Details"
|
|
334
|
+
component={DetailsSheet}
|
|
335
|
+
options={{
|
|
336
|
+
iosModalSheetTypeOfAnimation: true,
|
|
337
|
+
snapPoints: ['50%', '90%', '100%'],
|
|
338
|
+
}}
|
|
339
|
+
/>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Advanced Features
|
|
343
|
+
|
|
344
|
+
### Custom Contexts
|
|
345
|
+
|
|
346
|
+
Use separate contexts for nested sheets or modals:
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
// In a modal or nested sheet
|
|
350
|
+
<SheetProvider context="modal-context">
|
|
351
|
+
{/* Register sheets for this context */}
|
|
352
|
+
{registerSheet('local-sheet', LocalSheet, 'modal-context')}
|
|
353
|
+
</SheetProvider>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Sheet Instance Methods
|
|
357
|
+
|
|
358
|
+
Control sheets programmatically:
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
const instance = SheetManager.get('example-sheet');
|
|
362
|
+
|
|
363
|
+
// Expand to maximum snap point
|
|
364
|
+
instance?.expand();
|
|
365
|
+
|
|
366
|
+
// Collapse to minimum snap point
|
|
367
|
+
instance?.collapse();
|
|
368
|
+
|
|
369
|
+
// Snap to specific index
|
|
370
|
+
instance?.snapToIndex(1);
|
|
371
|
+
|
|
372
|
+
// Snap to specific position
|
|
373
|
+
instance?.snapToPosition('75%');
|
|
374
|
+
|
|
375
|
+
// Close with return value
|
|
376
|
+
instance?.close({ value: { success: true } });
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Animation Configuration
|
|
380
|
+
|
|
381
|
+
Customize animations:
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
instance?.expand({
|
|
385
|
+
animationConfigs: {
|
|
386
|
+
type: 'spring',
|
|
387
|
+
damping: 20,
|
|
388
|
+
stiffness: 90,
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## API Reference
|
|
394
|
+
|
|
395
|
+
### `SheetManager`
|
|
396
|
+
|
|
397
|
+
Global manager for showing and hiding sheets.
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
// Show a sheet
|
|
401
|
+
SheetManager.show<Id extends SheetIds>(
|
|
402
|
+
id: Id,
|
|
403
|
+
payload?: SheetPayload<Id>
|
|
404
|
+
): Promise<SheetReturnValue<Id>>
|
|
405
|
+
|
|
406
|
+
// Hide a sheet
|
|
407
|
+
SheetManager.hide(id: SheetIds): void
|
|
408
|
+
|
|
409
|
+
// Get sheet instance
|
|
410
|
+
SheetManager.get(id: SheetIds): BottomSheetInstance<Id> | undefined
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### `BottomSheet` Props
|
|
414
|
+
|
|
415
|
+
All props from `@gorhom/bottom-sheet` are supported, plus:
|
|
416
|
+
|
|
417
|
+
| Prop | Type | Default | Description |
|
|
418
|
+
|------|------|---------|-------------|
|
|
419
|
+
| `id` | `SheetID<SheetIds>` | - | Unique identifier for the sheet |
|
|
420
|
+
| `stackBehavior` | `"push" \| "replace" \| "switch"` | `"switch"` | How sheets stack when opened (push is experimental) |
|
|
421
|
+
| `iosModalSheetTypeOfAnimation` | `boolean` | `false` | Enable iOS 18 modal animation |
|
|
422
|
+
| `clickThrough` | `boolean` | `false` | Allow tapping through backdrop |
|
|
423
|
+
| `opacity` | `number` | `0.45` | Backdrop opacity |
|
|
424
|
+
| `hardwareBackPressToClose` | `boolean` | `true` | Close on hardware back button |
|
|
425
|
+
| `onClose` | `(data?: unknown) => unknown` | - | Callback when sheet closes |
|
|
426
|
+
| `onBeforeShow` | `(data?: unknown) => void` | - | Callback before sheet shows |
|
|
427
|
+
|
|
428
|
+
### `BottomSheetNavigationOptions`
|
|
429
|
+
|
|
430
|
+
Screen options for navigation-based sheets:
|
|
431
|
+
|
|
432
|
+
| Option | Type | Default | Description |
|
|
433
|
+
|--------|------|---------|-------------|
|
|
434
|
+
| `snapPoints` | `Array<string \| number>` | `['66%']` | Snap points for the sheet |
|
|
435
|
+
| `clickThrough` | `boolean` | `false` | Allow tapping through backdrop |
|
|
436
|
+
| `iosModalSheetTypeOfAnimation` | `boolean` | `false` | Enable iOS 18 modal animation |
|
|
437
|
+
| `opacity` | `number` | `0.45` | Backdrop opacity |
|
|
438
|
+
|
|
439
|
+
### Navigation Actions
|
|
440
|
+
|
|
441
|
+
```tsx
|
|
442
|
+
import { BottomSheetActions } from "@niibase/bottom-sheet-manager";
|
|
443
|
+
|
|
444
|
+
// Snap to index
|
|
445
|
+
navigation.dispatch(BottomSheetActions.snapTo(1));
|
|
446
|
+
|
|
447
|
+
// Dismiss sheet
|
|
448
|
+
navigation.dispatch(BottomSheetActions.dismiss());
|
|
449
|
+
|
|
450
|
+
// Remove from stack
|
|
451
|
+
navigation.dispatch(BottomSheetActions.remove());
|
|
452
|
+
```
|
|
453
|
+
|
|
126
454
|
## Examples
|
|
127
455
|
|
|
128
|
-
The source code for the example (showcase) app is under the [/example](/example/) directory.
|
|
456
|
+
The source code for the example (showcase) app is under the [/example](/example/) directory. It includes:
|
|
457
|
+
|
|
458
|
+
- Basic sheet usage
|
|
459
|
+
- Stack behavior demos (push (experimental), replace, switch)
|
|
460
|
+
- React Navigation integration
|
|
461
|
+
- iOS modal animation examples
|
|
462
|
+
- Navigation actions and hooks usage
|
|
129
463
|
|
|
130
464
|
## Contributing
|
|
131
465
|
|
|
@@ -141,7 +475,7 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
141
475
|
|
|
142
476
|
**Built with ❤️ by [@divineniiquaye](https://github.com/divineniiquaye) using React Native and [@gorhom/bottom-sheet](https://github.com/gorhom/react-native-bottom-sheet).**
|
|
143
477
|
|
|
144
|
-
[⬆ Back to Top](
|
|
478
|
+
[⬆ Back to Top](#bottom-sheet-router--manager)
|
|
145
479
|
|
|
146
480
|
</div>
|
|
147
481
|
|
package/lib/commonjs/events.js
CHANGED
|
@@ -4,32 +4,117 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.eventManager = exports.default = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* High-performance event manager using Maps for O(1) lookups.
|
|
9
|
+
* Replaces React Native's EventEmitter which has significant overhead.
|
|
10
|
+
*/
|
|
9
11
|
|
|
10
12
|
class EventManager {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
_handlers = new Map();
|
|
14
|
+
_nextId = 0;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Subscribe to an event with a handler function.
|
|
18
|
+
* Returns a subscription object with an unsubscribe method.
|
|
19
|
+
*/
|
|
17
20
|
subscribe(name, handler) {
|
|
18
|
-
if (!name ||
|
|
19
|
-
|
|
21
|
+
if (!name || typeof handler !== "function") {
|
|
22
|
+
throw new Error("Event name and handler function are required.");
|
|
23
|
+
}
|
|
24
|
+
const id = this._nextId++;
|
|
25
|
+
const entry = {
|
|
26
|
+
handler: handler,
|
|
27
|
+
id
|
|
28
|
+
};
|
|
29
|
+
const handlers = this._handlers.get(name);
|
|
30
|
+
if (handlers) {
|
|
31
|
+
handlers.push(entry);
|
|
32
|
+
} else {
|
|
33
|
+
this._handlers.set(name, [entry]);
|
|
34
|
+
}
|
|
20
35
|
return {
|
|
21
|
-
unsubscribe: () =>
|
|
36
|
+
unsubscribe: () => {
|
|
37
|
+
const currentHandlers = this._handlers.get(name);
|
|
38
|
+
if (currentHandlers) {
|
|
39
|
+
const index = currentHandlers.findIndex(h => h.id === id);
|
|
40
|
+
if (index !== -1) {
|
|
41
|
+
currentHandlers.splice(index, 1);
|
|
42
|
+
if (currentHandlers.length === 0) {
|
|
43
|
+
this._handlers.delete(name);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
22
48
|
};
|
|
23
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Publish an event with optional arguments.
|
|
53
|
+
* All subscribed handlers will be called synchronously.
|
|
54
|
+
*/
|
|
24
55
|
publish(name, ...args) {
|
|
25
|
-
this.
|
|
56
|
+
const handlers = this._handlers.get(name);
|
|
57
|
+
if (!handlers || handlers.length === 0) return;
|
|
58
|
+
|
|
59
|
+
// Create a copy to avoid issues if handlers modify the list during iteration
|
|
60
|
+
const handlersSnapshot = handlers.slice();
|
|
61
|
+
for (let i = 0; i < handlersSnapshot.length; i++) {
|
|
62
|
+
handlersSnapshot[i].handler(...args);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Publish an event asynchronously using microtasks for better performance.
|
|
68
|
+
* Useful when you don't need immediate execution.
|
|
69
|
+
*/
|
|
70
|
+
publishAsync(name, ...args) {
|
|
71
|
+
queueMicrotask(() => this.publish(name, ...args));
|
|
26
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if an event has any subscribers.
|
|
76
|
+
*/
|
|
77
|
+
hasSubscribers(name) {
|
|
78
|
+
const handlers = this._handlers.get(name);
|
|
79
|
+
return !!handlers && handlers.length > 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get the number of subscribers for an event.
|
|
84
|
+
*/
|
|
85
|
+
subscriberCount(name) {
|
|
86
|
+
return this._handlers.get(name)?.length ?? 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Remove all listeners for the specified event names.
|
|
91
|
+
*/
|
|
27
92
|
remove(...names) {
|
|
28
|
-
for (const
|
|
29
|
-
this.
|
|
93
|
+
for (const name of names) {
|
|
94
|
+
this._handlers.delete(name);
|
|
30
95
|
}
|
|
31
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Remove all event listeners.
|
|
100
|
+
*/
|
|
101
|
+
clear() {
|
|
102
|
+
this._handlers.clear();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Subscribe to an event that will only fire once.
|
|
107
|
+
*/
|
|
108
|
+
once(name, handler) {
|
|
109
|
+
const subscription = this.subscribe(name, (...args) => {
|
|
110
|
+
subscription.unsubscribe();
|
|
111
|
+
handler(...args);
|
|
112
|
+
});
|
|
113
|
+
return subscription;
|
|
114
|
+
}
|
|
32
115
|
}
|
|
33
|
-
|
|
116
|
+
|
|
117
|
+
// Singleton instance for global event management
|
|
34
118
|
const eventManager = exports.eventManager = new EventManager();
|
|
119
|
+
var _default = exports.default = EventManager;
|
|
35
120
|
//# sourceMappingURL=events.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["EventManager","_handlers","Map","_nextId","subscribe","name","handler","Error","id","entry","handlers","get","push","set","unsubscribe","currentHandlers","index","findIndex","h","splice","length","delete","publish","args","handlersSnapshot","slice","i","publishAsync","queueMicrotask","hasSubscribers","subscriberCount","remove","names","clear","once","subscription","eventManager","exports","_default","default"],"sourceRoot":"../../src","sources":["events.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;;AAaA,MAAMA,YAAY,CAAC;EACPC,SAAS,GAAG,IAAIC,GAAG,CAAyB,CAAC;EAC7CC,OAAO,GAAG,CAAC;;EAEnB;AACJ;AACA;AACA;EACIC,SAASA,CACLC,IAAY,EACZC,OAAwB,EACP;IACjB,IAAI,CAACD,IAAI,IAAI,OAAOC,OAAO,KAAK,UAAU,EAAE;MACxC,MAAM,IAAIC,KAAK,CAAC,+CAA+C,CAAC;IACpE;IAEA,MAAMC,EAAE,GAAG,IAAI,CAACL,OAAO,EAAE;IACzB,MAAMM,KAAmB,GAAG;MAAEH,OAAO,EAAEA,OAAuB;MAAEE;IAAG,CAAC;IAEpE,MAAME,QAAQ,GAAG,IAAI,CAACT,SAAS,CAACU,GAAG,CAACN,IAAI,CAAC;IACzC,IAAIK,QAAQ,EAAE;MACVA,QAAQ,CAACE,IAAI,CAACH,KAAK,CAAC;IACxB,CAAC,MAAM;MACH,IAAI,CAACR,SAAS,CAACY,GAAG,CAACR,IAAI,EAAE,CAACI,KAAK,CAAC,CAAC;IACrC;IAEA,OAAO;MACHK,WAAW,EAAEA,CAAA,KAAM;QACf,MAAMC,eAAe,GAAG,IAAI,CAACd,SAAS,CAACU,GAAG,CAACN,IAAI,CAAC;QAChD,IAAIU,eAAe,EAAE;UACjB,MAAMC,KAAK,GAAGD,eAAe,CAACE,SAAS,CAAEC,CAAC,IAAKA,CAAC,CAACV,EAAE,KAAKA,EAAE,CAAC;UAC3D,IAAIQ,KAAK,KAAK,CAAC,CAAC,EAAE;YACdD,eAAe,CAACI,MAAM,CAACH,KAAK,EAAE,CAAC,CAAC;YAChC,IAAID,eAAe,CAACK,MAAM,KAAK,CAAC,EAAE;cAC9B,IAAI,CAACnB,SAAS,CAACoB,MAAM,CAAChB,IAAI,CAAC;YAC/B;UACJ;QACJ;MACJ;IACJ,CAAC;EACL;;EAEA;AACJ;AACA;AACA;EACIiB,OAAOA,CAAkCjB,IAAY,EAAE,GAAGkB,IAAO,EAAQ;IACrE,MAAMb,QAAQ,GAAG,IAAI,CAACT,SAAS,CAACU,GAAG,CAACN,IAAI,CAAC;IACzC,IAAI,CAACK,QAAQ,IAAIA,QAAQ,CAACU,MAAM,KAAK,CAAC,EAAE;;IAExC;IACA,MAAMI,gBAAgB,GAAGd,QAAQ,CAACe,KAAK,CAAC,CAAC;IACzC,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,gBAAgB,CAACJ,MAAM,EAAEM,CAAC,EAAE,EAAE;MAC9CF,gBAAgB,CAACE,CAAC,CAAC,CAACpB,OAAO,CAAC,GAAGiB,IAAI,CAAC;IACxC;EACJ;;EAEA;AACJ;AACA;AACA;EACII,YAAYA,CAAkCtB,IAAY,EAAE,GAAGkB,IAAO,EAAQ;IAC1EK,cAAc,CAAC,MAAM,IAAI,CAACN,OAAO,CAACjB,IAAI,EAAE,GAAGkB,IAAI,CAAC,CAAC;EACrD;;EAEA;AACJ;AACA;EACIM,cAAcA,CAACxB,IAAY,EAAW;IAClC,MAAMK,QAAQ,GAAG,IAAI,CAACT,SAAS,CAACU,GAAG,CAACN,IAAI,CAAC;IACzC,OAAO,CAAC,CAACK,QAAQ,IAAIA,QAAQ,CAACU,MAAM,GAAG,CAAC;EAC5C;;EAEA;AACJ;AACA;EACIU,eAAeA,CAACzB,IAAY,EAAU;IAClC,OAAO,IAAI,CAACJ,SAAS,CAACU,GAAG,CAACN,IAAI,CAAC,EAAEe,MAAM,IAAI,CAAC;EAChD;;EAEA;AACJ;AACA;EACIW,MAAMA,CAAC,GAAGC,KAAe,EAAQ;IAC7B,KAAK,MAAM3B,IAAI,IAAI2B,KAAK,EAAE;MACtB,IAAI,CAAC/B,SAAS,CAACoB,MAAM,CAAChB,IAAI,CAAC;IAC/B;EACJ;;EAEA;AACJ;AACA;EACI4B,KAAKA,CAAA,EAAS;IACV,IAAI,CAAChC,SAAS,CAACgC,KAAK,CAAC,CAAC;EAC1B;;EAEA;AACJ;AACA;EACIC,IAAIA,CACA7B,IAAY,EACZC,OAAwB,EACP;IACjB,MAAM6B,YAAY,GAAG,IAAI,CAAC/B,SAAS,CAAIC,IAAI,EAAE,CAAC,GAAGkB,IAAI,KAAK;MACtDY,YAAY,CAACrB,WAAW,CAAC,CAAC;MAC1BR,OAAO,CAAC,GAAGiB,IAAI,CAAC;IACpB,CAAC,CAAC;IACF,OAAOY,YAAY;EACvB;AACJ;;AAEA;AACO,MAAMC,YAAY,GAAAC,OAAA,CAAAD,YAAA,GAAG,IAAIpC,YAAY,CAAC,CAAC;AAAC,IAAAsC,QAAA,GAAAD,OAAA,CAAAE,OAAA,GAEhCvC,YAAY","ignoreList":[]}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -10,6 +10,7 @@ var _exportNames = {
|
|
|
10
10
|
useSheetPayload: true,
|
|
11
11
|
useSheetRef: true,
|
|
12
12
|
useOnSheet: true,
|
|
13
|
+
useStackBehaviorContext: true,
|
|
13
14
|
registerSheet: true
|
|
14
15
|
};
|
|
15
16
|
Object.defineProperty(exports, "BottomSheet", {
|
|
@@ -54,6 +55,12 @@ Object.defineProperty(exports, "useSheetRef", {
|
|
|
54
55
|
return _provider.useSheetRef;
|
|
55
56
|
}
|
|
56
57
|
});
|
|
58
|
+
Object.defineProperty(exports, "useStackBehaviorContext", {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function () {
|
|
61
|
+
return _provider.useStackBehaviorContext;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
57
64
|
var _sheet = _interopRequireDefault(require("./sheet"));
|
|
58
65
|
var _manager = require("./manager");
|
|
59
66
|
var _router = require("./router");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_sheet","_interopRequireDefault","require","_manager","_router","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_types","_provider","e","__esModule","default"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_sheet","_interopRequireDefault","require","_manager","_router","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_types","_provider","e","__esModule","default"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAAAG,MAAA,CAAAC,IAAA,CAAAF,OAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,OAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,OAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,MAAA,GAAAf,OAAA;AAAAG,MAAA,CAAAC,IAAA,CAAAW,MAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAS,MAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,MAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AACA,IAAAU,SAAA,GAAAhB,OAAA;AAOoB,SAAAD,uBAAAkB,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA","ignoreList":[]}
|