@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.
Files changed (63) hide show
  1. package/README.md +372 -38
  2. package/lib/commonjs/events.js +100 -15
  3. package/lib/commonjs/events.js.map +1 -1
  4. package/lib/commonjs/index.js +7 -0
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/manager.js +107 -29
  7. package/lib/commonjs/manager.js.map +1 -1
  8. package/lib/commonjs/provider.js +69 -28
  9. package/lib/commonjs/provider.js.map +1 -1
  10. package/lib/commonjs/router/index.js +50 -21
  11. package/lib/commonjs/router/index.js.map +1 -1
  12. package/lib/commonjs/router/router.js +137 -12
  13. package/lib/commonjs/router/router.js.map +1 -1
  14. package/lib/commonjs/router/view.js +194 -84
  15. package/lib/commonjs/router/view.js.map +1 -1
  16. package/lib/commonjs/sheet.js +125 -76
  17. package/lib/commonjs/sheet.js.map +1 -1
  18. package/lib/module/events.js +100 -15
  19. package/lib/module/events.js.map +1 -1
  20. package/lib/module/index.js +1 -1
  21. package/lib/module/index.js.map +1 -1
  22. package/lib/module/manager.js +108 -29
  23. package/lib/module/manager.js.map +1 -1
  24. package/lib/module/provider.js +65 -25
  25. package/lib/module/provider.js.map +1 -1
  26. package/lib/module/router/index.js +34 -18
  27. package/lib/module/router/index.js.map +1 -1
  28. package/lib/module/router/router.js +135 -11
  29. package/lib/module/router/router.js.map +1 -1
  30. package/lib/module/router/view.js +194 -84
  31. package/lib/module/router/view.js.map +1 -1
  32. package/lib/module/sheet.js +127 -78
  33. package/lib/module/sheet.js.map +1 -1
  34. package/lib/typescript/events.d.ts +46 -12
  35. package/lib/typescript/events.d.ts.map +1 -1
  36. package/lib/typescript/index.d.ts +1 -1
  37. package/lib/typescript/index.d.ts.map +1 -1
  38. package/lib/typescript/manager.d.ts +57 -7
  39. package/lib/typescript/manager.d.ts.map +1 -1
  40. package/lib/typescript/provider.d.ts +22 -3
  41. package/lib/typescript/provider.d.ts.map +1 -1
  42. package/lib/typescript/router/index.d.ts +33 -17
  43. package/lib/typescript/router/index.d.ts.map +1 -1
  44. package/lib/typescript/router/router.d.ts +44 -5
  45. package/lib/typescript/router/router.d.ts.map +1 -1
  46. package/lib/typescript/router/types.d.ts +113 -17
  47. package/lib/typescript/router/types.d.ts.map +1 -1
  48. package/lib/typescript/router/view.d.ts +1 -1
  49. package/lib/typescript/router/view.d.ts.map +1 -1
  50. package/lib/typescript/sheet.d.ts.map +1 -1
  51. package/lib/typescript/types.d.ts +27 -12
  52. package/lib/typescript/types.d.ts.map +1 -1
  53. package/package.json +1 -1
  54. package/src/events.ts +118 -27
  55. package/src/index.ts +6 -5
  56. package/src/manager.ts +156 -33
  57. package/src/provider.tsx +98 -44
  58. package/src/router/index.tsx +38 -31
  59. package/src/router/router.ts +184 -15
  60. package/src/router/types.ts +119 -22
  61. package/src/router/view.tsx +252 -132
  62. package/src/sheet.tsx +176 -95
  63. 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 package [react-native-actions-sheet](https://github.com/ammarahm-ed/@repo/bottom-sheet) and adapted to package [@gorhom/bottom-sheet](https://github.com/gorhom/react-native-bottom-sheet).
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
- ## Installation
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
- Add it to your project with package.json:
15
+ ## Installation
9
16
 
10
17
  ```bash
11
18
  npm install @niibase/bottom-sheet-manager
12
19
  ```
13
20
 
14
- ## Usage
21
+ ## Quick Start
22
+
23
+ ### Basic Usage
15
24
 
16
- `SheetManager` is great because it helps you save lots of development time. One great feature is that you can reuse the same modal sheet in the app and don't have to create or define it in multiple places. Another is that you don't have to write boilerplate for every component. Everything just works.
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 and export it.
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 id={id}>
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
- Create a `sheets.ts` file and import your sheet then register it.
51
+ Register your sheet in a `sheets.ts` file:
39
52
 
40
53
  ```ts
41
- import {registerSheet} from '@niibase/bottom-sheet-manager';
42
- import ExampleSheet from 'example-sheet';
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
- // We extend some of the types here to give us great intellisense
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
- In `App.js` import `sheets.ts` and wrap your app in `SheetProvider`.
68
+ Wrap your app with `SheetProvider`:
58
69
 
59
70
  ```tsx
60
71
  import { SheetProvider } from '@niibase/bottom-sheet-manager';
61
- import 'sheets.tsx';
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
- Open the modal sheet from anywhere in the app.
83
+ Show and hide sheets:
75
84
 
76
- ```jsx
85
+ ```tsx
86
+ // Show a sheet
77
87
  SheetManager.show('example-sheet');
78
- ```
79
88
 
80
- Hide the modal sheet
89
+ // Show with payload
90
+ SheetManager.show('example-sheet', { userId: 123 });
81
91
 
82
- ```jsx
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
- ### As a React Navigation Screen
99
+ ## Stack Behaviors
87
100
 
88
- Support for React Navigation v6 and v7 is available including expo router support.
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 "@repo/bottom-sheet";
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
- // API Reference: `@niibase/bottom-sheet-manager/router/types.ts`
118
- // And: https://gorhom.github.io/react-native-bottom-sheet/modal/props/
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](#-installation)
478
+ [⬆ Back to Top](#bottom-sheet-router--manager)
145
479
 
146
480
  </div>
147
481
 
@@ -4,32 +4,117 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.eventManager = exports.default = void 0;
7
- var _reactNative = require("react-native");
8
- /* eslint-disable curly */
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
- constructor() {
12
- this._registry = _reactNative.Platform.select({
13
- ios: _reactNative.NativeAppEventEmitter,
14
- android: _reactNative.DeviceEventEmitter
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 || !handler) throw new Error("name and handler are required.");
19
- const event = this._registry?.addListener(name, handler);
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: () => event?.remove()
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._registry?.emit(name, ...args);
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 eventType of names) {
29
- this._registry?.removeAllListeners(eventType);
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
- exports.default = EventManager;
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":["_reactNative","require","EventManager","constructor","_registry","Platform","select","ios","NativeAppEventEmitter","android","DeviceEventEmitter","subscribe","name","handler","Error","event","addListener","unsubscribe","remove","publish","args","emit","names","eventType","removeAllListeners","exports","default","eventManager"],"sourceRoot":"../../src","sources":["events.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAOA;;AAMe,MAAMC,YAAY,CAAC;EAE9BC,WAAWA,CAAA,EAAG;IACV,IAAI,CAACC,SAAS,GAAGC,qBAAQ,CAACC,MAAM,CAAC;MAC7BC,GAAG,EAAEC,kCAAqB;MAC1BC,OAAO,EAAEC;IACb,CAAC,CAAC;EACN;EAEAC,SAASA,CAACC,IAAY,EAAEC,OAAqB,EAAE;IAC3C,IAAI,CAACD,IAAI,IAAI,CAACC,OAAO,EAAE,MAAM,IAAIC,KAAK,CAAC,gCAAgC,CAAC;IACxE,MAAMC,KAAK,GAAG,IAAI,CAACX,SAAS,EAAEY,WAAW,CAACJ,IAAI,EAAEC,OAAO,CAAC;IACxD,OAAO;MAAEI,WAAW,EAAEA,CAAA,KAAMF,KAAK,EAAEG,MAAM,CAAC;IAAE,CAAC;EACjD;EAEAC,OAAOA,CAACP,IAAY,EAAE,GAAGQ,IAAW,EAAE;IAClC,IAAI,CAAChB,SAAS,EAAEiB,IAAI,CAACT,IAAI,EAAE,GAAGQ,IAAI,CAAC;EACvC;EAEAF,MAAMA,CAAC,GAAGI,KAAe,EAAE;IACvB,KAAK,MAAMC,SAAS,IAAID,KAAK,EAAE;MAC3B,IAAI,CAAClB,SAAS,EAAEoB,kBAAkB,CAACD,SAAS,CAAC;IACjD;EACJ;AACJ;AAACE,OAAA,CAAAC,OAAA,GAAAxB,YAAA;AAEM,MAAMyB,YAAY,GAAAF,OAAA,CAAAE,YAAA,GAAG,IAAIzB,YAAY,CAAC,CAAC","ignoreList":[]}
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":"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","ignoreList":[]}
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;AAMoB,SAAAD,uBAAAkB,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA","ignoreList":[]}
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":[]}