@buoy-gg/route-events 1.7.2

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 (79) hide show
  1. package/README.md +654 -0
  2. package/lib/commonjs/RouteObserver.js +54 -0
  3. package/lib/commonjs/RouteParser.js +310 -0
  4. package/lib/commonjs/RouteTracker.js +39 -0
  5. package/lib/commonjs/components/NavigationStack.js +584 -0
  6. package/lib/commonjs/components/RouteEventDetailContent.js +492 -0
  7. package/lib/commonjs/components/RouteEventExpandedContent.js +187 -0
  8. package/lib/commonjs/components/RouteEventItemCompact.js +175 -0
  9. package/lib/commonjs/components/RouteEventsModalWithTabs.js +560 -0
  10. package/lib/commonjs/components/RouteEventsTimeline.js +82 -0
  11. package/lib/commonjs/components/RouteFilterViewV2.js +42 -0
  12. package/lib/commonjs/components/RoutesSitemap.js +948 -0
  13. package/lib/commonjs/expoRouterStore.js +104 -0
  14. package/lib/commonjs/index.js +99 -0
  15. package/lib/commonjs/package.json +1 -0
  16. package/lib/commonjs/preset.js +83 -0
  17. package/lib/commonjs/useNavigationStack.js +241 -0
  18. package/lib/commonjs/useRouteObserver.js +73 -0
  19. package/lib/commonjs/useRouteSitemap.js +234 -0
  20. package/lib/commonjs/utils/safeExpoRouter.js +129 -0
  21. package/lib/commonjs/utils/safeReactNavigation.js +104 -0
  22. package/lib/module/RouteObserver.js +49 -0
  23. package/lib/module/RouteParser.js +305 -0
  24. package/lib/module/RouteTracker.js +35 -0
  25. package/lib/module/components/NavigationStack.js +580 -0
  26. package/lib/module/components/RouteEventDetailContent.js +487 -0
  27. package/lib/module/components/RouteEventExpandedContent.js +183 -0
  28. package/lib/module/components/RouteEventItemCompact.js +171 -0
  29. package/lib/module/components/RouteEventsModalWithTabs.js +557 -0
  30. package/lib/module/components/RouteEventsTimeline.js +78 -0
  31. package/lib/module/components/RouteFilterViewV2.js +38 -0
  32. package/lib/module/components/RoutesSitemap.js +944 -0
  33. package/lib/module/expoRouterStore.js +98 -0
  34. package/lib/module/index.js +23 -0
  35. package/lib/module/preset.js +79 -0
  36. package/lib/module/useNavigationStack.js +238 -0
  37. package/lib/module/useRouteObserver.js +70 -0
  38. package/lib/module/useRouteSitemap.js +229 -0
  39. package/lib/module/utils/safeExpoRouter.js +120 -0
  40. package/lib/module/utils/safeReactNavigation.js +98 -0
  41. package/lib/typescript/RouteObserver.d.ts +37 -0
  42. package/lib/typescript/RouteObserver.d.ts.map +1 -0
  43. package/lib/typescript/RouteParser.d.ts +129 -0
  44. package/lib/typescript/RouteParser.d.ts.map +1 -0
  45. package/lib/typescript/RouteTracker.d.ts +29 -0
  46. package/lib/typescript/RouteTracker.d.ts.map +1 -0
  47. package/lib/typescript/components/NavigationStack.d.ts +11 -0
  48. package/lib/typescript/components/NavigationStack.d.ts.map +1 -0
  49. package/lib/typescript/components/RouteEventDetailContent.d.ts +21 -0
  50. package/lib/typescript/components/RouteEventDetailContent.d.ts.map +1 -0
  51. package/lib/typescript/components/RouteEventExpandedContent.d.ts +16 -0
  52. package/lib/typescript/components/RouteEventExpandedContent.d.ts.map +1 -0
  53. package/lib/typescript/components/RouteEventItemCompact.d.ts +15 -0
  54. package/lib/typescript/components/RouteEventItemCompact.d.ts.map +1 -0
  55. package/lib/typescript/components/RouteEventsModalWithTabs.d.ts +15 -0
  56. package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +1 -0
  57. package/lib/typescript/components/RouteEventsTimeline.d.ts +17 -0
  58. package/lib/typescript/components/RouteEventsTimeline.d.ts.map +1 -0
  59. package/lib/typescript/components/RouteFilterViewV2.d.ts +9 -0
  60. package/lib/typescript/components/RouteFilterViewV2.d.ts.map +1 -0
  61. package/lib/typescript/components/RoutesSitemap.d.ts +15 -0
  62. package/lib/typescript/components/RoutesSitemap.d.ts.map +1 -0
  63. package/lib/typescript/expoRouterStore.d.ts +28 -0
  64. package/lib/typescript/expoRouterStore.d.ts.map +1 -0
  65. package/lib/typescript/index.d.ts +18 -0
  66. package/lib/typescript/index.d.ts.map +1 -0
  67. package/lib/typescript/preset.d.ts +76 -0
  68. package/lib/typescript/preset.d.ts.map +1 -0
  69. package/lib/typescript/useNavigationStack.d.ts +48 -0
  70. package/lib/typescript/useNavigationStack.d.ts.map +1 -0
  71. package/lib/typescript/useRouteObserver.d.ts +27 -0
  72. package/lib/typescript/useRouteObserver.d.ts.map +1 -0
  73. package/lib/typescript/useRouteSitemap.d.ts +102 -0
  74. package/lib/typescript/useRouteSitemap.d.ts.map +1 -0
  75. package/lib/typescript/utils/safeExpoRouter.d.ts +13 -0
  76. package/lib/typescript/utils/safeExpoRouter.d.ts.map +1 -0
  77. package/lib/typescript/utils/safeReactNavigation.d.ts +10 -0
  78. package/lib/typescript/utils/safeReactNavigation.d.ts.map +1 -0
  79. package/package.json +72 -0
package/README.md ADDED
@@ -0,0 +1,654 @@
1
+ # @buoy/route-events
2
+
3
+ A comprehensive route tracking and visualization toolkit for Expo Router applications. Monitor route changes, inspect navigation state, explore your route sitemap, and visualize the navigation stack.
4
+
5
+ ## Features
6
+
7
+ - **Route Event Tracking**: Automatically track all route changes with detailed event information
8
+ - **Route Sitemap**: Browse all available routes in your app with search and navigation
9
+ - **Navigation Stack Viewer**: Inspect the current navigation stack in real-time
10
+ - **Event Timeline**: View a chronological timeline of all route changes
11
+ - **Filtering & Search**: Filter events by pathname patterns and search through routes
12
+ - **Persistent State**: Remembers your monitoring preferences and filters
13
+ - **Full Modal UI**: Beautiful, production-ready modal interface for all features
14
+
15
+ ## Installation
16
+
17
+ This package is part of the React Buoy monorepo and is automatically available to other packages and the example app.
18
+
19
+ For external projects:
20
+
21
+ ```bash
22
+ npm install @buoy/route-events
23
+ # or
24
+ pnpm add @buoy/route-events
25
+ # or
26
+ yarn add @buoy/route-events
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ### Simplest Setup - Just 1 Line!
32
+
33
+ **Import the preset and add it to your tools array. Done!**
34
+
35
+ ```typescript
36
+ import { routeEventsToolPreset } from '@buoy/route-events';
37
+ import { FloatingDevTools } from '@buoy/core';
38
+
39
+ const installedApps = [
40
+ routeEventsToolPreset, // That's it! One line.
41
+ // ...your other tools
42
+ ];
43
+
44
+ function App() {
45
+ return (
46
+ <FloatingDevTools
47
+ apps={installedApps}
48
+ environment="local"
49
+ userRole="admin"
50
+ />
51
+ );
52
+ }
53
+ ```
54
+
55
+ **Done!** The preset automatically:
56
+ - ✅ Starts tracking routes when opened
57
+ - ✅ Uses the built-in route observer singleton
58
+ - ✅ Provides all three tabs (Routes, Events, Stack)
59
+ - ✅ No configuration, no props, no hooks to call
60
+
61
+ ## Requirements
62
+
63
+ `@buoy/route-events` relies on the same core libraries as Expo Router itself:
64
+
65
+ - `expo-router` ≥ 2.0.0 (the Routes tab reads `store.routeNode` directly)
66
+ - `@react-navigation/native` ≥ 7.x (Stack tab + Expo Router routing hooks)
67
+ - `@react-native-async-storage/async-storage` (state persistence)
68
+ - `react` / `react-native`
69
+
70
+ These packages are declared as `peerDependencies`, so your app decides the exact versions. When a dependency is missing or not initialized, the devtool logs a clear `[RouteEvents] ...` console message (in dev builds) and gracefully disables the affected feature instead of crashing. See `packages/route-events/docs/ROUTES_SITEMAP_ACCESS_GUIDE.md` for the full data-flow and troubleshooting guide.
71
+
72
+ ### Alternative: Manual Setup
73
+
74
+ If you're not using FloatingDevTools or want more control:
75
+
76
+ ```typescript
77
+ import { RouteEventsModalWithTabs } from '@buoy/route-events';
78
+
79
+ function App() {
80
+ const [showRoutes, setShowRoutes] = useState(false);
81
+
82
+ return (
83
+ <>
84
+ <Button onPress={() => setShowRoutes(true)}>
85
+ Open Route Inspector
86
+ </Button>
87
+
88
+ <RouteEventsModalWithTabs
89
+ visible={showRoutes}
90
+ onClose={() => setShowRoutes(false)}
91
+ />
92
+ </>
93
+ );
94
+ }
95
+ ```
96
+
97
+ ## API Reference
98
+
99
+ ### Core Components
100
+
101
+ #### `RouteEventsModalWithTabs`
102
+
103
+ The main modal interface with three tabs: Routes, Events, and Stack.
104
+
105
+ **Props:**
106
+
107
+ ```typescript
108
+ interface RouteEventsModalWithTabsProps {
109
+ /** Whether the modal is visible */
110
+ visible: boolean;
111
+ /** Callback when modal is closed */
112
+ onClose: () => void;
113
+ /** Optional back button handler */
114
+ onBack?: () => void;
115
+ /** Whether to use shared modal dimensions */
116
+ enableSharedModalDimensions?: boolean;
117
+ /**
118
+ * Optional route observer instance.
119
+ * If not provided, uses the default singleton (recommended).
120
+ * Route tracking starts automatically when the modal is opened.
121
+ */
122
+ routeObserver?: RouteObserver;
123
+ }
124
+ ```
125
+
126
+ **Example:**
127
+
128
+ ```typescript
129
+ <RouteEventsModalWithTabs
130
+ visible={isVisible}
131
+ onClose={handleClose}
132
+ />
133
+ ```
134
+
135
+ **Advanced Example (with custom observer):**
136
+
137
+ Only needed if you want to use a custom route observer instance:
138
+
139
+ ```typescript
140
+ import { RouteEventsModalWithTabs, routeObserver } from '@buoy/route-events';
141
+
142
+ <RouteEventsModalWithTabs
143
+ visible={isVisible}
144
+ onClose={handleClose}
145
+ routeObserver={routeObserver} // Optional - uses default if not provided
146
+ />
147
+ ```
148
+
149
+ #### `RoutesSitemap`
150
+
151
+ Standalone component for browsing all routes in your application.
152
+
153
+ **Props:**
154
+
155
+ ```typescript
156
+ interface RoutesSitemapProps {
157
+ style?: StyleProp<ViewStyle>;
158
+ }
159
+ ```
160
+
161
+ **Example:**
162
+
163
+ ```typescript
164
+ import { RoutesSitemap } from '@buoy/route-events';
165
+
166
+ function RoutesScreen() {
167
+ return <RoutesSitemap />;
168
+ }
169
+ ```
170
+
171
+ #### `NavigationStack`
172
+
173
+ Standalone component for visualizing the current navigation stack.
174
+
175
+ **Props:**
176
+
177
+ ```typescript
178
+ interface NavigationStackProps {
179
+ style?: StyleProp<ViewStyle>;
180
+ }
181
+ ```
182
+
183
+ **Example:**
184
+
185
+ ```typescript
186
+ import { NavigationStack } from '@buoy/route-events';
187
+
188
+ function DebugScreen() {
189
+ return <NavigationStack />;
190
+ }
191
+ ```
192
+
193
+ ### Hooks
194
+
195
+ #### `useRouteObserver`
196
+
197
+ Hook to track route changes and emit events to the global observer.
198
+
199
+ **Note:** You typically don't need to use this hook directly - the `RouteEventsModalWithTabs` component starts tracking automatically. This hook is only needed for advanced use cases like custom analytics.
200
+
201
+ **Signature:**
202
+
203
+ ```typescript
204
+ function useRouteObserver(
205
+ callback?: (event: RouteChangeEvent) => void
206
+ ): void
207
+ ```
208
+
209
+ **Examples:**
210
+
211
+ ```typescript
212
+ // Only needed for custom analytics - modal handles tracking automatically!
213
+ import { useRouteObserver } from '@buoy/route-events';
214
+
215
+ export default function RootLayout() {
216
+ useRouteObserver((event) => {
217
+ analytics.trackPageView(event.pathname);
218
+ });
219
+
220
+ return <Stack />;
221
+ }
222
+ ```
223
+
224
+ #### `useRouteSitemap`
225
+
226
+ Access route information from your app's file-based routing structure.
227
+
228
+ **Signature:**
229
+
230
+ ```typescript
231
+ function useRouteSitemap(
232
+ options?: UseRouteSitemapOptions
233
+ ): UseRouteSitemapResult
234
+ ```
235
+
236
+ **Options:**
237
+
238
+ ```typescript
239
+ interface UseRouteSitemapOptions {
240
+ /** Whether to include layout routes */
241
+ includeLayouts?: boolean;
242
+ /** Whether to include route groups */
243
+ includeGroups?: boolean;
244
+ }
245
+ ```
246
+
247
+ **Result:**
248
+
249
+ ```typescript
250
+ interface UseRouteSitemapResult {
251
+ /** All routes in the application */
252
+ routes: RouteInfo[];
253
+ /** Routes grouped by directory */
254
+ groups: RouteGroup[];
255
+ /** Statistics about the routes */
256
+ stats: RouteStats;
257
+ /** Get a specific route by path */
258
+ getRoute: (path: string) => RouteInfo | undefined;
259
+ /** Get all parent routes of a path */
260
+ getParents: (path: string) => RouteInfo[];
261
+ }
262
+ ```
263
+
264
+ **Example:**
265
+
266
+ ```typescript
267
+ import { useRouteSitemap } from '@buoy/route-events';
268
+
269
+ function RouteDebugger() {
270
+ const { routes, stats, getRoute } = useRouteSitemap();
271
+
272
+ console.log(`Total routes: ${stats.total}`);
273
+ console.log(`Dynamic routes: ${stats.byType.dynamic}`);
274
+
275
+ const homeRoute = getRoute('/');
276
+ // { path: '/', type: 'index', ... }
277
+
278
+ return (
279
+ <View>
280
+ {routes.map(route => (
281
+ <Text key={route.path}>{route.path}</Text>
282
+ ))}
283
+ </View>
284
+ );
285
+ }
286
+ ```
287
+
288
+ #### `useNavigationStack`
289
+
290
+ Access and control the current navigation stack.
291
+
292
+ **Signature:**
293
+
294
+ ```typescript
295
+ function useNavigationStack(): UseNavigationStackResult
296
+ ```
297
+
298
+ **Result:**
299
+
300
+ ```typescript
301
+ interface UseNavigationStackResult {
302
+ /** The current navigation stack */
303
+ stack: StackDisplayItem[];
304
+ /** Whether the data is loading */
305
+ loading: boolean;
306
+ /** Navigate to a specific stack index */
307
+ navigateToIndex: (index: number) => void;
308
+ /** Pop back to a specific index */
309
+ popToIndex: (index: number) => void;
310
+ /** Go back one screen */
311
+ goBack: () => void;
312
+ /** Go to the root of the stack */
313
+ popToTop: () => void;
314
+ }
315
+ ```
316
+
317
+ **Example:**
318
+
319
+ ```typescript
320
+ import { useNavigationStack } from '@buoy/route-events';
321
+
322
+ function NavigationDebugger() {
323
+ const { stack, goBack, popToTop } = useNavigationStack();
324
+
325
+ return (
326
+ <View>
327
+ <Text>Stack Depth: {stack.length}</Text>
328
+ <Button onPress={goBack}>Go Back</Button>
329
+ <Button onPress={popToTop}>Go to Root</Button>
330
+
331
+ {stack.map((item, index) => (
332
+ <Text key={item.key}>
333
+ {index}: {item.displayPath}
334
+ </Text>
335
+ ))}
336
+ </View>
337
+ );
338
+ }
339
+ ```
340
+
341
+ ### Utilities
342
+
343
+ #### `RouteObserver`
344
+
345
+ Singleton instance for observing route changes.
346
+
347
+ **Methods:**
348
+
349
+ ```typescript
350
+ class RouteObserver {
351
+ /** Emit a route change event */
352
+ emit(event: RouteChangeEvent): void;
353
+
354
+ /** Add a listener for route changes */
355
+ addListener(callback: (event: RouteChangeEvent) => void): () => void;
356
+
357
+ /** Remove a listener */
358
+ removeListener(callback: (event: RouteChangeEvent) => void): void;
359
+ }
360
+ ```
361
+
362
+ **Example:**
363
+
364
+ ```typescript
365
+ import { routeObserver } from '@buoy/route-events';
366
+
367
+ // Add listener
368
+ const unsubscribe = routeObserver.addListener((event) => {
369
+ console.log('Route changed:', event.pathname);
370
+ });
371
+
372
+ // Later, remove listener
373
+ unsubscribe();
374
+ ```
375
+
376
+ #### `RouteParser`
377
+
378
+ Utility for parsing Expo Router's route structure.
379
+
380
+ **Methods:**
381
+
382
+ ```typescript
383
+ class RouteParser {
384
+ /** Get all routes from the router */
385
+ static getRoutes(options?: {
386
+ includeLayouts?: boolean;
387
+ includeGroups?: boolean;
388
+ }): RouteInfo[];
389
+
390
+ /** Group routes by directory */
391
+ static groupRoutes(routes: RouteInfo[]): RouteGroup[];
392
+
393
+ /** Get statistics about routes */
394
+ static getStats(routes: RouteInfo[]): RouteStats;
395
+ }
396
+ ```
397
+
398
+ ### Types
399
+
400
+ #### `RouteChangeEvent`
401
+
402
+ ```typescript
403
+ interface RouteChangeEvent {
404
+ /** Current pathname */
405
+ pathname: string;
406
+ /** Route parameters */
407
+ params: Record<string, string | string[]>;
408
+ /** Route segments */
409
+ segments: string[];
410
+ /** Timestamp of the change */
411
+ timestamp: number;
412
+ /** Previous pathname (if available) */
413
+ previousPathname?: string;
414
+ /** Time since previous navigation in ms */
415
+ timeSincePrevious?: number;
416
+ }
417
+ ```
418
+
419
+ #### `RouteInfo`
420
+
421
+ ```typescript
422
+ interface RouteInfo {
423
+ /** Full path of the route */
424
+ path: string;
425
+ /** Route type */
426
+ type: RouteType;
427
+ /** Route name/file */
428
+ name: string;
429
+ /** Dynamic parameters */
430
+ params: string[];
431
+ /** Whether it's a layout */
432
+ isLayout: boolean;
433
+ /** Whether it's a route group */
434
+ isGroup: boolean;
435
+ /** Parent path */
436
+ parent?: string;
437
+ }
438
+ ```
439
+
440
+ #### `RouteType`
441
+
442
+ ```typescript
443
+ type RouteType =
444
+ | 'index' // index routes (/)
445
+ | 'static' // static routes (/about)
446
+ | 'dynamic' // dynamic routes (/user/[id])
447
+ | 'catch-all' // catch-all routes (/docs/[...path])
448
+ | 'layout' // layout routes (_layout.tsx)
449
+ | 'group'; // route groups ((tabs))
450
+ ```
451
+
452
+ ## Use Cases
453
+
454
+ ### Analytics Integration
455
+
456
+ ```typescript
457
+ import { useRouteObserver } from '@buoy/route-events';
458
+
459
+ export default function RootLayout() {
460
+ useRouteObserver((event) => {
461
+ // Track page views
462
+ analytics.trackPageView({
463
+ path: event.pathname,
464
+ params: event.params,
465
+ previousPath: event.previousPathname,
466
+ timeSpent: event.timeSincePrevious,
467
+ });
468
+ });
469
+
470
+ return <Stack />;
471
+ }
472
+ ```
473
+
474
+ ### Performance Monitoring
475
+
476
+ ```typescript
477
+ import { useRouteObserver } from '@buoy/route-events';
478
+
479
+ export default function RootLayout() {
480
+ useRouteObserver((event) => {
481
+ if (event.timeSincePrevious && event.timeSincePrevious > 1000) {
482
+ // Log slow navigations
483
+ console.warn('Slow navigation:', {
484
+ from: event.previousPathname,
485
+ to: event.pathname,
486
+ duration: event.timeSincePrevious,
487
+ });
488
+ }
489
+ });
490
+
491
+ return <Stack />;
492
+ }
493
+ ```
494
+
495
+ ### Development Tools
496
+
497
+ ```typescript
498
+ import { RouteEventsModalWithTabs, routeObserver } from '@buoy/route-events';
499
+
500
+ function DevTools() {
501
+ const [visible, setVisible] = useState(false);
502
+
503
+ // Only show in development
504
+ if (__DEV__) {
505
+ return (
506
+ <>
507
+ <TouchableOpacity
508
+ style={styles.devButton}
509
+ onPress={() => setVisible(true)}
510
+ >
511
+ <Text>🧭 Routes</Text>
512
+ </TouchableOpacity>
513
+
514
+ <RouteEventsModalWithTabs
515
+ visible={visible}
516
+ onClose={() => setVisible(false)}
517
+ routeObserver={routeObserver}
518
+ />
519
+ </>
520
+ );
521
+ }
522
+
523
+ return null;
524
+ }
525
+ ```
526
+
527
+ ### Route Documentation
528
+
529
+ ```typescript
530
+ import { useRouteSitemap } from '@buoy/route-events';
531
+
532
+ function RouteDocumentation() {
533
+ const { routes, groups, stats } = useRouteSitemap({
534
+ includeLayouts: false,
535
+ includeGroups: false,
536
+ });
537
+
538
+ return (
539
+ <ScrollView>
540
+ <Text>Total Routes: {stats.total}</Text>
541
+
542
+ {groups.map(group => (
543
+ <View key={group.name}>
544
+ <Text>{group.name} ({group.routes.length})</Text>
545
+ {group.routes.map(route => (
546
+ <Text key={route.path}>
547
+ {route.path} - {route.type}
548
+ </Text>
549
+ ))}
550
+ </View>
551
+ ))}
552
+ </ScrollView>
553
+ );
554
+ }
555
+ ```
556
+
557
+ ## Features in Detail
558
+
559
+ ### Routes Tab
560
+
561
+ - Browse all routes in your application
562
+ - Search routes by path or name
563
+ - View route types (static, dynamic, catch-all)
564
+ - Navigate to any route directly
565
+ - Handles dynamic route parameters with prompts
566
+ - Group and layout route identification
567
+
568
+ ### Events Tab
569
+
570
+ - Real-time route change monitoring
571
+ - Toggle monitoring on/off
572
+ - Event timeline with timestamps
573
+ - Filter events by pathname patterns
574
+ - Search through event history
575
+ - View detailed event information
576
+ - Compare route changes (diff view)
577
+ - Clear event history
578
+ - Persistent filter preferences
579
+
580
+ ### Stack Tab
581
+
582
+ - Real-time navigation stack visualization
583
+ - Stack depth indicator
584
+ - Navigate to any stack level
585
+ - Pop to specific stack index
586
+ - Quick navigation controls
587
+ - Route parameter display
588
+
589
+ ## Dependencies
590
+
591
+ - `@buoy/shared-ui` - Common UI components and utilities
592
+ - `expo-router` - Expo Router integration (peer dependency)
593
+ - `@react-navigation/native` - React Navigation integration (peer dependency)
594
+ - `@react-native-async-storage/async-storage` - For persistent preferences (peer dependency)
595
+ - React and React Native (peer dependencies)
596
+
597
+ ## Development
598
+
599
+ ### Building
600
+
601
+ ```bash
602
+ pnpm build
603
+ ```
604
+
605
+ ### Type Checking
606
+
607
+ ```bash
608
+ pnpm typecheck
609
+ ```
610
+
611
+ ### Clean Build
612
+
613
+ ```bash
614
+ pnpm clean
615
+ ```
616
+
617
+ ## Package Structure
618
+
619
+ ```
620
+ route-events/
621
+ ├── src/
622
+ │ ├── components/ # UI components
623
+ │ │ ├── RouteEventsModalWithTabs.tsx
624
+ │ │ ├── RoutesSitemap.tsx
625
+ │ │ ├── NavigationStack.tsx
626
+ │ │ ├── RouteEventsTimeline.tsx
627
+ │ │ ├── RouteEventItemCompact.tsx
628
+ │ │ ├── RouteEventDetailContent.tsx
629
+ │ │ ├── RouteEventExpandedContent.tsx
630
+ │ │ └── RouteFilterViewV2.tsx
631
+ │ ├── RouteObserver.ts # Event system
632
+ │ ├── RouteParser.ts # Route parsing utilities
633
+ │ ├── useRouteObserver.ts # Route tracking hook
634
+ │ ├── useRouteSitemap.ts # Sitemap access hook
635
+ │ ├── useNavigationStack.ts # Stack access hook
636
+ │ └── index.tsx # Main exports
637
+ ├── lib/ # Built output (git ignored)
638
+ ├── package.json
639
+ ├── tsconfig.json
640
+ ├── tsconfig.build.json
641
+ └── README.md
642
+ ```
643
+
644
+ ## License
645
+
646
+ MIT
647
+
648
+ ## Contributing
649
+
650
+ See the main repository [CONTRIBUTING.md](../../CONTRIBUTING.md) for contribution guidelines.
651
+
652
+ ## Support
653
+
654
+ For issues and feature requests, please visit the [GitHub repository](https://github.com/LovesWorking/react-native-buoy/issues).
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.routeObserver = exports.RouteObserver = void 0;
7
+ /**
8
+ * RouteObserver - Tracks route changes in Expo Router
9
+ *
10
+ * Note: This is a simple event emitter that works with the useRouteObserver hook
11
+ * The actual route tracking happens in the hook using public Expo Router APIs
12
+ */
13
+
14
+ class RouteObserver {
15
+ listeners = new Set();
16
+
17
+ /**
18
+ * Emit a route change event
19
+ * Called by the useRouteObserver hook
20
+ */
21
+ emit(event) {
22
+ // Notify all listeners
23
+ this.listeners.forEach(listener => {
24
+ try {
25
+ listener(event);
26
+ } catch (error) {
27
+ console.error("[RouteObserver] Error in listener:", error);
28
+ }
29
+ });
30
+ }
31
+
32
+ /**
33
+ * Add listener for route changes
34
+ * @returns Cleanup function to remove the listener
35
+ */
36
+ addListener(callback) {
37
+ this.listeners.add(callback);
38
+ return () => this.listeners.delete(callback);
39
+ }
40
+
41
+ /**
42
+ * Remove a specific listener
43
+ */
44
+ removeListener(callback) {
45
+ this.listeners.delete(callback);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Singleton instance of RouteObserver
51
+ * Use this for all route tracking to ensure events are centralized
52
+ */
53
+ exports.RouteObserver = RouteObserver;
54
+ const routeObserver = exports.routeObserver = new RouteObserver();