@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
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * useRouteSitemap - React hooks for accessing parsed route information
5
+ *
6
+ * Provides access to the Expo Router route tree with parsing, filtering,
7
+ * and search capabilities.
8
+ */
9
+
10
+ import { useState, useEffect, useMemo, useCallback } from "react";
11
+ import { RouteParser } from "./RouteParser";
12
+ import { getRouteNodeMetadata, loadRouteNode } from "./expoRouterStore";
13
+
14
+ // Type-only definition to avoid Metro resolution issues
15
+
16
+ /**
17
+ * Extract all routes from the navigation state recursively
18
+ * This builds a RouteNode-like structure from React Navigation's state
19
+ */
20
+ function buildRouteNodeFromNavigationState(state) {
21
+ if (!state || !state.routes) return null;
22
+
23
+ // Find the app directory structure from the navigation state
24
+ // The root route usually contains the file-based routing structure
25
+ const rootRoute = state.routes?.[0];
26
+ if (!rootRoute) return null;
27
+
28
+ // Build a simple route node structure
29
+ // This will work with the RouteParser
30
+ const routeNode = {
31
+ type: 'route',
32
+ route: '',
33
+ dynamic: null,
34
+ children: [],
35
+ contextKey: '_app'
36
+ };
37
+
38
+ // Recursively collect all routes from the state
39
+ function collectRoutes(navState, parent, pathPrefix = '') {
40
+ if (!navState || !navState.routes) return;
41
+ navState.routes.forEach(route => {
42
+ const routeName = route.name;
43
+
44
+ // Skip internal routes
45
+ if (routeName.startsWith('__') || routeName.includes('_layout') || routeName.startsWith('+not-found')) {
46
+ return;
47
+ }
48
+
49
+ // Create a route node
50
+ const node = {
51
+ type: routeName === 'index' ? 'route' : 'route',
52
+ route: routeName === 'index' ? '' : routeName,
53
+ dynamic: routeName.includes('[') ? [routeName.match(/\[([^\]]+)\]/)?.[1] || ''] : null,
54
+ children: [],
55
+ contextKey: `app/${routeName}`
56
+ };
57
+ parent.children.push(node);
58
+
59
+ // If this route has nested state, recurse
60
+ if (route.state) {
61
+ collectRoutes(route.state, node, `${pathPrefix}/${routeName}`);
62
+ }
63
+ });
64
+ }
65
+ collectRoutes(state, routeNode);
66
+ return routeNode.children.length > 0 ? routeNode : null;
67
+ }
68
+
69
+ // ============================================================================
70
+ // Hook Options & Return Types
71
+ // ============================================================================
72
+
73
+ // ============================================================================
74
+ // Main Hook
75
+ // ============================================================================
76
+
77
+ /**
78
+ * Hook to access and parse Expo Router's route tree
79
+ *
80
+ * @example
81
+ * ```tsx
82
+ * const { routes, groups, stats, filteredRoutes } = useRouteSitemap({
83
+ * searchQuery: 'pokemon',
84
+ * sortBy: 'path',
85
+ * autoRefresh: true
86
+ * });
87
+ * ```
88
+ */
89
+ export function useRouteSitemap(options = {}) {
90
+ const {
91
+ searchQuery = "",
92
+ sortBy = "path",
93
+ autoRefresh = false,
94
+ refreshInterval = 1000
95
+ } = options;
96
+ const [routeTreeState, setRouteTreeState] = useState(() => {
97
+ const node = loadRouteNode();
98
+ const metadata = getRouteNodeMetadata();
99
+ return {
100
+ node,
101
+ version: 0,
102
+ lastUpdatedAt: metadata.lastLoadedAt,
103
+ source: metadata.source
104
+ };
105
+ });
106
+ const routeNode = routeTreeState.node;
107
+ const routeNodeVersion = routeTreeState.version;
108
+ const lastUpdatedAt = routeTreeState.lastUpdatedAt;
109
+ const source = routeTreeState.source;
110
+ const refresh = useCallback(() => {
111
+ setRouteTreeState(previous => {
112
+ const node = loadRouteNode();
113
+ const metadata = getRouteNodeMetadata();
114
+ return {
115
+ node,
116
+ version: previous.version + 1,
117
+ lastUpdatedAt: metadata.lastLoadedAt,
118
+ source: metadata.source
119
+ };
120
+ });
121
+ }, []);
122
+
123
+ // When the route tree isn't available yet (e.g., Expo Router still mounting),
124
+ // poll until it becomes ready. Use a more aggressive retry since the store
125
+ // is a singleton that gets populated asynchronously.
126
+ useEffect(() => {
127
+ if (routeNode) {
128
+ return;
129
+ }
130
+ let retryCount = 0;
131
+ const maxRetries = 100; // 10 seconds max
132
+
133
+ const poll = () => {
134
+ retryCount++;
135
+ refresh();
136
+ if (retryCount < maxRetries) {
137
+ timeoutRef = setTimeout(poll, 100);
138
+ }
139
+ };
140
+ let timeoutRef = setTimeout(poll, 100);
141
+ return () => clearTimeout(timeoutRef);
142
+ }, [routeNode, refresh]);
143
+
144
+ // Optional auto-refresh hook for callers that want periodic updates
145
+ useEffect(() => {
146
+ if (!autoRefresh) return;
147
+ const interval = setInterval(refresh, refreshInterval);
148
+ return () => clearInterval(interval);
149
+ }, [autoRefresh, refreshInterval, refresh]);
150
+ const isLoaded = !!routeNode;
151
+
152
+ // Parse routes
153
+ const routes = useMemo(() => {
154
+ if (!routeNode) return [];
155
+ return RouteParser.parseRouteTree(routeNode);
156
+ }, [routeNode, routeNodeVersion]);
157
+
158
+ // Sort routes
159
+ const sortedRoutes = useMemo(() => {
160
+ return RouteParser.sortRoutes(routes, sortBy);
161
+ }, [routes, sortBy]);
162
+
163
+ // Filter routes by search query
164
+ const filteredRoutes = useMemo(() => {
165
+ if (!searchQuery) return sortedRoutes;
166
+ return RouteParser.filterRoutes(sortedRoutes, searchQuery);
167
+ }, [sortedRoutes, searchQuery]);
168
+
169
+ // Organize into groups
170
+ const groups = useMemo(() => {
171
+ return RouteParser.organizeRoutes(filteredRoutes);
172
+ }, [filteredRoutes]);
173
+
174
+ // Calculate stats
175
+ const stats = useMemo(() => {
176
+ return RouteParser.getRouteStats(routes);
177
+ }, [routes]);
178
+
179
+ // Helper functions
180
+ const findRoute = path => RouteParser.findRouteByPath(routes, path);
181
+ const getParents = path => RouteParser.getParentRoutes(routes, path);
182
+ return {
183
+ routes: sortedRoutes,
184
+ groups,
185
+ stats,
186
+ filteredRoutes,
187
+ isLoaded,
188
+ refresh,
189
+ findRoute,
190
+ getParents,
191
+ lastUpdatedAt,
192
+ source
193
+ };
194
+ }
195
+
196
+ // ============================================================================
197
+ // Helper Hooks
198
+ // ============================================================================
199
+
200
+ /**
201
+ * Get a specific route by path
202
+ *
203
+ * @example
204
+ * ```tsx
205
+ * const pokemonRoute = useRoute('/pokemon/[id]');
206
+ * ```
207
+ */
208
+ export function useRoute(path) {
209
+ const {
210
+ findRoute
211
+ } = useRouteSitemap();
212
+ return useMemo(() => findRoute(path), [findRoute, path]);
213
+ }
214
+
215
+ /**
216
+ * Get all parent routes for a given path
217
+ *
218
+ * @example
219
+ * ```tsx
220
+ * const parents = useParentRoutes('/pokemon/[id]');
221
+ * // Returns: [{ path: '/pokemon', ... }]
222
+ * ```
223
+ */
224
+ export function useParentRoutes(path) {
225
+ const {
226
+ getParents
227
+ } = useRouteSitemap();
228
+ return useMemo(() => getParents(path), [getParents, path]);
229
+ }
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Safe wrapper for expo-router
5
+ *
6
+ * Provides optional imports for expo-router hooks and utilities.
7
+ * Falls back to no-op implementations when expo-router is not installed.
8
+ */
9
+
10
+ let expoRouter = null;
11
+ let isAvailable = false;
12
+ let checkedAvailability = false;
13
+ function checkExpoRouterAvailability() {
14
+ if (checkedAvailability) return isAvailable;
15
+ try {
16
+ expoRouter = require("expo-router");
17
+ isAvailable = expoRouter != null;
18
+ } catch (error) {
19
+ isAvailable = false;
20
+ expoRouter = null;
21
+ }
22
+ checkedAvailability = true;
23
+ return isAvailable;
24
+ }
25
+
26
+ // ============================================================================
27
+ // No-op implementations when expo-router is not available
28
+ // ============================================================================
29
+
30
+ function noOpUseRouter() {
31
+ return {
32
+ push: () => console.warn("[route-events] expo-router not installed: push() unavailable"),
33
+ replace: () => console.warn("[route-events] expo-router not installed: replace() unavailable"),
34
+ back: () => console.warn("[route-events] expo-router not installed: back() unavailable"),
35
+ canGoBack: () => false,
36
+ setParams: () => console.warn("[route-events] expo-router not installed: setParams() unavailable"),
37
+ navigate: () => console.warn("[route-events] expo-router not installed: navigate() unavailable")
38
+ };
39
+ }
40
+ function noOpUsePathname() {
41
+ return "/";
42
+ }
43
+ function noOpUseSegments() {
44
+ return [];
45
+ }
46
+ function noOpUseGlobalSearchParams() {
47
+ return {};
48
+ }
49
+
50
+ // ============================================================================
51
+ // Safe hook exports
52
+ // ============================================================================
53
+
54
+ export function useSafeRouter() {
55
+ if (!checkExpoRouterAvailability()) {
56
+ return noOpUseRouter();
57
+ }
58
+ try {
59
+ return expoRouter.useRouter();
60
+ } catch (error) {
61
+ console.warn("[route-events] Failed to use expo-router.useRouter:", error);
62
+ return noOpUseRouter();
63
+ }
64
+ }
65
+ export function useSafePathname() {
66
+ if (!checkExpoRouterAvailability()) {
67
+ return noOpUsePathname();
68
+ }
69
+ try {
70
+ return expoRouter.usePathname();
71
+ } catch (error) {
72
+ console.warn("[route-events] Failed to use expo-router.usePathname:", error);
73
+ return noOpUsePathname();
74
+ }
75
+ }
76
+ export function useSafeSegments() {
77
+ if (!checkExpoRouterAvailability()) {
78
+ return noOpUseSegments();
79
+ }
80
+ try {
81
+ return expoRouter.useSegments();
82
+ } catch (error) {
83
+ console.warn("[route-events] Failed to use expo-router.useSegments:", error);
84
+ return noOpUseSegments();
85
+ }
86
+ }
87
+ export function useSafeGlobalSearchParams() {
88
+ if (!checkExpoRouterAvailability()) {
89
+ return noOpUseGlobalSearchParams();
90
+ }
91
+ try {
92
+ return expoRouter.useGlobalSearchParams();
93
+ } catch (error) {
94
+ console.warn("[route-events] Failed to use expo-router.useGlobalSearchParams:", error);
95
+ return noOpUseGlobalSearchParams();
96
+ }
97
+ }
98
+
99
+ // ============================================================================
100
+ // Router instance getter (for imperative navigation)
101
+ // ============================================================================
102
+
103
+ export function getSafeRouter() {
104
+ if (!checkExpoRouterAvailability()) {
105
+ return null;
106
+ }
107
+ try {
108
+ return expoRouter.router || null;
109
+ } catch (error) {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ // ============================================================================
115
+ // Availability check
116
+ // ============================================================================
117
+
118
+ export function isExpoRouterAvailable() {
119
+ return checkExpoRouterAvailability();
120
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Safe wrapper for @react-navigation/native
5
+ *
6
+ * Provides optional imports for React Navigation hooks.
7
+ * Falls back to no-op implementations when @react-navigation/native is not installed.
8
+ */
9
+
10
+ import { useMemo } from "react";
11
+ let reactNavigation = null;
12
+ let isAvailable = false;
13
+ let checkedAvailability = false;
14
+ function checkReactNavigationAvailability() {
15
+ if (checkedAvailability) return isAvailable;
16
+ try {
17
+ reactNavigation = require("@react-navigation/native");
18
+ isAvailable = reactNavigation != null;
19
+ } catch (error) {
20
+ isAvailable = false;
21
+ reactNavigation = null;
22
+ }
23
+ checkedAvailability = true;
24
+ return isAvailable;
25
+ }
26
+
27
+ // ============================================================================
28
+ // No-op implementations when @react-navigation/native is not available
29
+ // ============================================================================
30
+
31
+ function noOpUseNavigation() {
32
+ return useMemo(() => ({
33
+ navigate: () => console.warn("[route-events] @react-navigation/native not installed: navigate() unavailable"),
34
+ goBack: () => console.warn("[route-events] @react-navigation/native not installed: goBack() unavailable"),
35
+ canGoBack: () => false,
36
+ reset: () => console.warn("[route-events] @react-navigation/native not installed: reset() unavailable"),
37
+ setParams: () => console.warn("[route-events] @react-navigation/native not installed: setParams() unavailable"),
38
+ dispatch: () => console.warn("[route-events] @react-navigation/native not installed: dispatch() unavailable"),
39
+ isFocused: () => true,
40
+ addListener: () => () => {},
41
+ removeListener: () => {},
42
+ getParent: () => undefined,
43
+ getState: () => undefined,
44
+ getId: () => undefined
45
+ }), []);
46
+ }
47
+ function noOpUseNavigationState(selector) {
48
+ return useMemo(() => {
49
+ // Return a minimal state structure
50
+ const emptyState = {
51
+ key: "default",
52
+ index: 0,
53
+ routeNames: [],
54
+ routes: [],
55
+ type: "stack"
56
+ };
57
+ try {
58
+ return selector ? selector(emptyState) : emptyState;
59
+ } catch {
60
+ return emptyState;
61
+ }
62
+ }, [selector]);
63
+ }
64
+
65
+ // ============================================================================
66
+ // Safe hook exports
67
+ // ============================================================================
68
+
69
+ export function useSafeNavigation() {
70
+ if (!checkReactNavigationAvailability()) {
71
+ return noOpUseNavigation();
72
+ }
73
+ try {
74
+ return reactNavigation.useNavigation();
75
+ } catch (error) {
76
+ console.warn("[route-events] Failed to use @react-navigation/native.useNavigation:", error);
77
+ return noOpUseNavigation();
78
+ }
79
+ }
80
+ export function useSafeNavigationState(selector) {
81
+ if (!checkReactNavigationAvailability()) {
82
+ return noOpUseNavigationState(selector);
83
+ }
84
+ try {
85
+ return reactNavigation.useNavigationState(selector);
86
+ } catch (error) {
87
+ console.warn("[route-events] Failed to use @react-navigation/native.useNavigationState:", error);
88
+ return noOpUseNavigationState(selector);
89
+ }
90
+ }
91
+
92
+ // ============================================================================
93
+ // Availability check
94
+ // ============================================================================
95
+
96
+ export function isReactNavigationAvailable() {
97
+ return checkReactNavigationAvailability();
98
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * RouteObserver - Tracks route changes in Expo Router
3
+ *
4
+ * Note: This is a simple event emitter that works with the useRouteObserver hook
5
+ * The actual route tracking happens in the hook using public Expo Router APIs
6
+ */
7
+ export interface RouteChangeEvent {
8
+ pathname: string;
9
+ params: Record<string, string | string[]>;
10
+ segments: string[];
11
+ timestamp: number;
12
+ previousPathname?: string;
13
+ timeSincePrevious?: number;
14
+ }
15
+ export declare class RouteObserver {
16
+ private listeners;
17
+ /**
18
+ * Emit a route change event
19
+ * Called by the useRouteObserver hook
20
+ */
21
+ emit(event: RouteChangeEvent): void;
22
+ /**
23
+ * Add listener for route changes
24
+ * @returns Cleanup function to remove the listener
25
+ */
26
+ addListener(callback: (event: RouteChangeEvent) => void): () => boolean;
27
+ /**
28
+ * Remove a specific listener
29
+ */
30
+ removeListener(callback: (event: RouteChangeEvent) => void): void;
31
+ }
32
+ /**
33
+ * Singleton instance of RouteObserver
34
+ * Use this for all route tracking to ensure events are centralized
35
+ */
36
+ export declare const routeObserver: RouteObserver;
37
+ //# sourceMappingURL=RouteObserver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteObserver.d.ts","sourceRoot":"","sources":["../../src/RouteObserver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAqD;IAEtE;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,gBAAgB;IAW5B;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI;IAKvD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI;CAG3D;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,eAAsB,CAAC"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * RouteParser - Extract and organize routes from Expo Router's RouteNode tree
3
+ *
4
+ * Based on research findings in:
5
+ * - docs/routing/expo/ROUTENODE_TYPE_DEFINITION.md
6
+ * - docs/routing/expo/ROUTES_SITEMAP_RESEARCH.md
7
+ */
8
+ type RouteNode = {
9
+ type: 'route' | 'api' | 'layout' | 'redirect' | 'rewrite';
10
+ route: string;
11
+ contextKey: string;
12
+ children: RouteNode[];
13
+ dynamic: null | Array<{
14
+ name: string;
15
+ deep: boolean;
16
+ notFound?: boolean;
17
+ }>;
18
+ internal?: boolean;
19
+ generated?: boolean;
20
+ initialRouteName?: string;
21
+ };
22
+ /**
23
+ * Route type classification
24
+ */
25
+ export type RouteType = 'static' | 'dynamic' | 'catch-all' | 'index' | 'layout' | 'group' | 'not-found';
26
+ /**
27
+ * Parsed route information
28
+ */
29
+ export interface RouteInfo {
30
+ /** Full path (e.g., "/pokemon/[id]") */
31
+ path: string;
32
+ /** Route name/segment (e.g., "[id]") */
33
+ name: string;
34
+ /** Route type classification */
35
+ type: RouteType;
36
+ /** Dynamic parameter names (e.g., ["id"]) */
37
+ params: string[];
38
+ /** Original RouteNode type */
39
+ nodeType: RouteNode['type'];
40
+ /** File path/context key */
41
+ contextKey: string;
42
+ /** Is this route internal/generated? */
43
+ isInternal: boolean;
44
+ /** Children routes */
45
+ children: RouteInfo[];
46
+ /** Depth in route tree (0 = root) */
47
+ depth: number;
48
+ }
49
+ /**
50
+ * Grouped routes for display
51
+ */
52
+ export interface RouteGroup {
53
+ title: string;
54
+ icon: string;
55
+ description?: string;
56
+ routes: RouteInfo[];
57
+ }
58
+ /**
59
+ * Route statistics
60
+ */
61
+ export interface RouteStats {
62
+ total: number;
63
+ static: number;
64
+ dynamic: number;
65
+ catchAll: number;
66
+ layouts: number;
67
+ groups: number;
68
+ }
69
+ export declare class RouteParser {
70
+ /**
71
+ * Parse RouteNode tree and extract all routes
72
+ */
73
+ static parseRouteTree(rootNode: RouteNode | null): RouteInfo[];
74
+ /**
75
+ * Recursively traverse RouteNode tree
76
+ */
77
+ private static traverseNode;
78
+ /**
79
+ * Build full path for a route node
80
+ */
81
+ private static buildPath;
82
+ /**
83
+ * Detect the route type classification
84
+ */
85
+ private static detectRouteType;
86
+ /**
87
+ * Extract dynamic parameter names from route
88
+ */
89
+ private static extractParams;
90
+ /**
91
+ * Determine if route should be included in results
92
+ */
93
+ private static shouldIncludeRoute;
94
+ /**
95
+ * Organize routes into groups for display
96
+ */
97
+ static organizeRoutes(routes: RouteInfo[]): RouteGroup[];
98
+ /**
99
+ * Flatten nested routes into a single array
100
+ */
101
+ private static flattenRoutes;
102
+ /**
103
+ * Get route statistics
104
+ */
105
+ static getRouteStats(routes: RouteInfo[]): RouteStats;
106
+ /**
107
+ * Search/filter routes by query
108
+ */
109
+ static filterRoutes(routes: RouteInfo[], query: string): RouteInfo[];
110
+ /**
111
+ * Build a visual tree string representation
112
+ */
113
+ static buildTreeString(routes: RouteInfo[], depth?: number): string;
114
+ private static buildTreePrefix;
115
+ /**
116
+ * Sort routes by various criteria
117
+ */
118
+ static sortRoutes(routes: RouteInfo[], sortBy?: 'path' | 'type' | 'name'): RouteInfo[];
119
+ /**
120
+ * Get route by path
121
+ */
122
+ static findRouteByPath(routes: RouteInfo[], path: string): RouteInfo | null;
123
+ /**
124
+ * Get all parent routes for a given route
125
+ */
126
+ static getParentRoutes(routes: RouteInfo[], targetPath: string): RouteInfo[];
127
+ }
128
+ export {};
129
+ //# sourceMappingURL=RouteParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteParser.d.ts","sourceRoot":"","sources":["../../src/RouteParser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,OAAO,EAAE,IAAI,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAMF;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,QAAQ,GACR,SAAS,GACT,WAAW,GACX,OAAO,GACP,QAAQ,GACR,OAAO,GACP,WAAW,CAAC;AAEhB;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IAEb,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IAEb,gCAAgC;IAChC,IAAI,EAAE,SAAS,CAAC;IAEhB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB,8BAA8B;IAC9B,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAE5B,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IAEnB,wCAAwC;IACxC,UAAU,EAAE,OAAO,CAAC;IAEpB,sBAAsB;IACtB,QAAQ,EAAE,SAAS,EAAE,CAAC;IAEtB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD,qBAAa,WAAW;IACtB;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EAAE;IAU9D;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IA+B3B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAsBxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IA8B9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAQ5B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAOjC;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE;IA6CxD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAY5B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU;IAarD;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE;IAkBpE;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM;IAuBtE,OAAO,CAAC,MAAM,CAAC,eAAe;IAU9B;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,GAAE,MAAM,GAAG,MAAM,GAAG,MAAe,GAAG,SAAS,EAAE;IAe9F;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAK3E;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE;CAsB7E"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * RouteTracker - A component to place inside your navigation tree
3
+ *
4
+ * This component calls useRouteObserver() which uses expo-router hooks
5
+ * (usePathname, useSegments, etc.) to track navigation changes.
6
+ *
7
+ * IMPORTANT: This component MUST be placed inside your navigation tree
8
+ * (as a child of Stack, Tabs, or Slot) for route tracking to work.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // In your _layout.tsx
13
+ * import { RouteTracker } from '@buoy-gg/route-events';
14
+ *
15
+ * export default function RootLayout() {
16
+ * return (
17
+ * <>
18
+ * <Stack>
19
+ * <Stack.Screen name="(tabs)" />
20
+ * </Stack>
21
+ * <RouteTracker />
22
+ * <FloatingDevTools ... />
23
+ * </>
24
+ * );
25
+ * }
26
+ * ```
27
+ */
28
+ export declare function RouteTracker(): null;
29
+ //# sourceMappingURL=RouteTracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteTracker.d.ts","sourceRoot":"","sources":["../../src/RouteTracker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,wBAAgB,YAAY,IAAI,IAAI,CAGnC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * NavigationStack - Visual representation of current navigation stack
3
+ *
4
+ * Shows all screens currently mounted in memory, which one is visible,
5
+ * and provides controls to manipulate the stack.
6
+ */
7
+ export interface NavigationStackProps {
8
+ style?: any;
9
+ }
10
+ export declare function NavigationStack({ style }: NavigationStackProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=NavigationStack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavigationStack.d.ts","sourceRoot":"","sources":["../../../src/components/NavigationStack.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoDH,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAMD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,oBAAoB,+BAmZ9D"}
@@ -0,0 +1,21 @@
1
+ import type { RouteChangeEvent } from "../RouteObserver";
2
+ interface RouteConversation {
3
+ pathname: string;
4
+ lastEvent: RouteChangeEvent;
5
+ events: RouteChangeEvent[];
6
+ totalNavigations: number;
7
+ }
8
+ interface RouteEventDetailContentProps {
9
+ conversation: RouteConversation;
10
+ selectedEventIndex?: number;
11
+ onEventIndexChange?: (index: number) => void;
12
+ disableInternalFooter?: boolean;
13
+ }
14
+ export declare function RouteEventDetailContent({ conversation, selectedEventIndex, onEventIndexChange, disableInternalFooter, }: RouteEventDetailContentProps): import("react").JSX.Element;
15
+ export declare function RouteEventDetailFooter({ conversation, selectedEventIndex, onEventIndexChange, }: {
16
+ conversation: RouteConversation;
17
+ selectedEventIndex?: number;
18
+ onEventIndexChange?: (index: number) => void;
19
+ }): import("react").JSX.Element | null;
20
+ export {};
21
+ //# sourceMappingURL=RouteEventDetailContent.d.ts.map