@buoy-gg/route-events 7.0.32 → 7.0.34
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/lib/commonjs/RouteTracker.js +2 -0
- package/lib/commonjs/components/NavigationStack.js +4 -10
- package/lib/commonjs/components/RouteEventsModalWithTabs.js +36 -117
- package/lib/commonjs/components/RouteEventsTimeline.js +2 -11
- package/lib/commonjs/components/RoutesSitemap.js +8 -8
- package/lib/commonjs/hooks/useRouteEvents.js +12 -43
- package/lib/commonjs/preset.js +7 -21
- package/lib/commonjs/sync/routeEventsSyncAdapter.js +19 -1
- package/lib/commonjs/useNavigationStack.js +27 -0
- package/lib/module/RouteTracker.js +2 -0
- package/lib/module/components/NavigationStack.js +5 -11
- package/lib/module/components/RouteEventsModalWithTabs.js +38 -119
- package/lib/module/components/RouteEventsTimeline.js +3 -12
- package/lib/module/components/RoutesSitemap.js +9 -9
- package/lib/module/hooks/useRouteEvents.js +12 -43
- package/lib/module/preset.js +6 -19
- package/lib/module/sync/routeEventsSyncAdapter.js +19 -1
- package/lib/module/useNavigationStack.js +27 -0
- package/lib/typescript/RouteTracker.d.ts.map +1 -1
- package/lib/typescript/components/NavigationStack.d.ts.map +1 -1
- package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/components/RouteEventsTimeline.d.ts.map +1 -1
- package/lib/typescript/components/RoutesSitemap.d.ts.map +1 -1
- package/lib/typescript/hooks/useRouteEvents.d.ts.map +1 -1
- package/lib/typescript/preset.d.ts +2 -8
- package/lib/typescript/preset.d.ts.map +1 -1
- package/lib/typescript/stores/navigationStackStore.d.ts +2 -0
- package/lib/typescript/stores/navigationStackStore.d.ts.map +1 -1
- package/lib/typescript/sync/routeEventsSyncAdapter.d.ts +5 -0
- package/lib/typescript/sync/routeEventsSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/useNavigationStack.d.ts +7 -0
- package/lib/typescript/useNavigationStack.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -71,6 +71,7 @@ function NavigationStackCapture() {
|
|
|
71
71
|
const {
|
|
72
72
|
stack,
|
|
73
73
|
navigateToIndex,
|
|
74
|
+
navigateToRoute,
|
|
74
75
|
popToIndex,
|
|
75
76
|
goBack,
|
|
76
77
|
popToTop
|
|
@@ -84,6 +85,7 @@ function NavigationStackCapture() {
|
|
|
84
85
|
(0, _react.useEffect)(() => {
|
|
85
86
|
_navigationStackStore.navigationStackStore.setActions({
|
|
86
87
|
navigateToIndex,
|
|
88
|
+
navigateToRoute,
|
|
87
89
|
popToIndex,
|
|
88
90
|
goBack,
|
|
89
91
|
popToTop
|
|
@@ -140,17 +140,11 @@ function NavigationStack({
|
|
|
140
140
|
if (stack.length === 0) {
|
|
141
141
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
142
142
|
style: [styles.container, style],
|
|
143
|
-
children: /*#__PURE__*/(0, _jsxRuntime.
|
|
144
|
-
style: styles.emptyContainer,
|
|
143
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
145
144
|
testID: "buoy-routes-stack-empty",
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
children: "No navigation stack"
|
|
150
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
151
|
-
style: styles.emptySubtext,
|
|
152
|
-
children: "Navigate to a route to see the stack"
|
|
153
|
-
})]
|
|
145
|
+
otto: "walking",
|
|
146
|
+
title: "No navigation stack",
|
|
147
|
+
message: "Navigate to a route to see the stack"
|
|
154
148
|
})
|
|
155
149
|
});
|
|
156
150
|
}
|
|
@@ -25,6 +25,23 @@ const CommonActions = (0, _safeReactNavigation.getCommonActions)();
|
|
|
25
25
|
|
|
26
26
|
// Free tier limit for route events
|
|
27
27
|
|
|
28
|
+
/** Persistence recipes: the tab is stored as its bare name, the flag as "true"/"false". */
|
|
29
|
+
const TAB_PERSISTENCE = {
|
|
30
|
+
// Every tab the selector offers, including "stack": the save side has
|
|
31
|
+
// always written it, so leaving it off this list meant the Stack tab
|
|
32
|
+
// was persisted and then silently discarded on the next launch.
|
|
33
|
+
parse: raw => raw === "routes" || raw === "events" || raw === "stack" ? raw : undefined,
|
|
34
|
+
serialize: tab => tab
|
|
35
|
+
};
|
|
36
|
+
const BOOLEAN_PERSISTENCE = {
|
|
37
|
+
parse: raw => raw === "true",
|
|
38
|
+
serialize: value => value.toString()
|
|
39
|
+
};
|
|
40
|
+
const STRING_SET_PERSISTENCE = {
|
|
41
|
+
parse: raw => new Set(JSON.parse(raw)),
|
|
42
|
+
serialize: set => JSON.stringify(Array.from(set))
|
|
43
|
+
};
|
|
44
|
+
|
|
28
45
|
/**
|
|
29
46
|
* Find the path from root navigation state to a screen by name.
|
|
30
47
|
* Returns array of route names from root to the target, or null if not found.
|
|
@@ -85,7 +102,7 @@ function RouteEventsModalWithTabs({
|
|
|
85
102
|
const router = (0, _sharedUi.useSafeRouter)();
|
|
86
103
|
const containerRef = (0, _safeReactNavigation.useSafeNavigationContainerRef)();
|
|
87
104
|
const hasExpoRouter = (0, _sharedUi.isExpoRouterAvailable)();
|
|
88
|
-
const [activeTab, setActiveTab] = (0,
|
|
105
|
+
const [activeTab, setActiveTab] = (0, _sharedUi.usePersistedState)(_sharedUi.devToolsStorageKeys.routeEvents.activeTab(), "events", TAB_PERSISTENCE);
|
|
89
106
|
const [showUpgradeModal, setShowUpgradeModal] = (0, _react.useState)(false);
|
|
90
107
|
// Serialized stack reported up by NavigationStack so the copy button can live
|
|
91
108
|
// in the shared navbar.
|
|
@@ -107,7 +124,7 @@ function RouteEventsModalWithTabs({
|
|
|
107
124
|
// See the RouteTracker component export for easy setup.
|
|
108
125
|
|
|
109
126
|
// Local state to control subscription (true = subscribed, false = unsubscribed)
|
|
110
|
-
const [isListeningEnabled, setIsListeningEnabled] = (0,
|
|
127
|
+
const [isListeningEnabled, setIsListeningEnabled] = (0, _sharedUi.usePersistedState)(_sharedUi.devToolsStorageKeys.routeEvents.isMonitoring(), true, BOOLEAN_PERSISTENCE);
|
|
111
128
|
|
|
112
129
|
// Event Listener state - using centralized store via hook
|
|
113
130
|
// Pass enabled option to control subscription
|
|
@@ -127,11 +144,8 @@ function RouteEventsModalWithTabs({
|
|
|
127
144
|
const [selectedEvent, setSelectedEvent] = (0, _react.useState)(null);
|
|
128
145
|
const [selectedVisitNumber, setSelectedVisitNumber] = (0, _react.useState)(1);
|
|
129
146
|
const [searchQuery, setSearchQuery] = (0, _react.useState)("");
|
|
130
|
-
const [ignoredPatterns, setIgnoredPatterns] = (0,
|
|
147
|
+
const [ignoredPatterns, setIgnoredPatterns] = (0, _sharedUi.usePersistedState)(_sharedUi.devToolsStorageKeys.routeEvents.eventFilters(), new Set(["/_sitemap", "/api", "/__dev"]), STRING_SET_PERSISTENCE);
|
|
131
148
|
const lastEventRef = (0, _react.useRef)(null);
|
|
132
|
-
const hasLoadedFilters = (0, _react.useRef)(false);
|
|
133
|
-
const hasLoadedTabState = (0, _react.useRef)(false);
|
|
134
|
-
const hasLoadedMonitoringState = (0, _react.useRef)(false);
|
|
135
149
|
const handleModeChange = (0, _react.useCallback)(_mode => {
|
|
136
150
|
// Mode changes handled by JsModal
|
|
137
151
|
}, []);
|
|
@@ -183,103 +197,6 @@ function RouteEventsModalWithTabs({
|
|
|
183
197
|
}
|
|
184
198
|
}, [router, containerRef, hasExpoRouter, remote, isPro]);
|
|
185
199
|
|
|
186
|
-
// Load persisted tab state on mount
|
|
187
|
-
(0, _react.useEffect)(() => {
|
|
188
|
-
if (!visible || hasLoadedTabState.current) return;
|
|
189
|
-
const loadTabState = async () => {
|
|
190
|
-
try {
|
|
191
|
-
const storedTab = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.routeEvents.activeTab());
|
|
192
|
-
// Every tab the selector offers, including "stack": the save side has
|
|
193
|
-
// always written it, so leaving it off this list meant the Stack tab
|
|
194
|
-
// was persisted and then silently discarded on the next launch —
|
|
195
|
-
// you came back to Events having chosen otherwise.
|
|
196
|
-
if (storedTab === "routes" || storedTab === "events" || storedTab === "stack") {
|
|
197
|
-
setActiveTab(storedTab);
|
|
198
|
-
}
|
|
199
|
-
hasLoadedTabState.current = true;
|
|
200
|
-
} catch (error) {
|
|
201
|
-
// Failed to load tab state
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
loadTabState();
|
|
205
|
-
}, [visible]);
|
|
206
|
-
|
|
207
|
-
// Load persisted monitoring state on mount
|
|
208
|
-
(0, _react.useEffect)(() => {
|
|
209
|
-
if (!visible || hasLoadedMonitoringState.current) return;
|
|
210
|
-
const loadMonitoringState = async () => {
|
|
211
|
-
try {
|
|
212
|
-
const storedMonitoring = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.routeEvents.isMonitoring());
|
|
213
|
-
if (storedMonitoring !== null) {
|
|
214
|
-
const shouldMonitor = storedMonitoring === "true";
|
|
215
|
-
setIsListeningEnabled(shouldMonitor);
|
|
216
|
-
}
|
|
217
|
-
hasLoadedMonitoringState.current = true;
|
|
218
|
-
} catch (error) {
|
|
219
|
-
// Failed to load monitoring state
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
loadMonitoringState();
|
|
223
|
-
}, [visible]);
|
|
224
|
-
|
|
225
|
-
// Save tab state when it changes
|
|
226
|
-
(0, _react.useEffect)(() => {
|
|
227
|
-
if (!hasLoadedTabState.current) return;
|
|
228
|
-
const saveTabState = async () => {
|
|
229
|
-
try {
|
|
230
|
-
await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.routeEvents.activeTab(), activeTab);
|
|
231
|
-
} catch (error) {
|
|
232
|
-
// Failed to save tab state
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
saveTabState();
|
|
236
|
-
}, [activeTab]);
|
|
237
|
-
|
|
238
|
-
// Save monitoring state when it changes
|
|
239
|
-
(0, _react.useEffect)(() => {
|
|
240
|
-
if (!hasLoadedMonitoringState.current) return;
|
|
241
|
-
const saveMonitoringState = async () => {
|
|
242
|
-
try {
|
|
243
|
-
await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.routeEvents.isMonitoring(), isListening.toString());
|
|
244
|
-
} catch (error) {
|
|
245
|
-
// Failed to save monitoring state
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
saveMonitoringState();
|
|
249
|
-
}, [isListening]);
|
|
250
|
-
|
|
251
|
-
// Load persisted filters on mount
|
|
252
|
-
(0, _react.useEffect)(() => {
|
|
253
|
-
if (!visible || hasLoadedFilters.current) return;
|
|
254
|
-
const loadFilters = async () => {
|
|
255
|
-
try {
|
|
256
|
-
const storedFilters = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.routeEvents.eventFilters());
|
|
257
|
-
if (storedFilters) {
|
|
258
|
-
const filters = JSON.parse(storedFilters);
|
|
259
|
-
setIgnoredPatterns(new Set(filters));
|
|
260
|
-
}
|
|
261
|
-
hasLoadedFilters.current = true;
|
|
262
|
-
} catch (error) {
|
|
263
|
-
// Failed to load filters
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
loadFilters();
|
|
267
|
-
}, [visible]);
|
|
268
|
-
|
|
269
|
-
// Save filters when they change
|
|
270
|
-
(0, _react.useEffect)(() => {
|
|
271
|
-
if (!hasLoadedFilters.current) return;
|
|
272
|
-
const saveFilters = async () => {
|
|
273
|
-
try {
|
|
274
|
-
const filters = Array.from(ignoredPatterns);
|
|
275
|
-
await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.routeEvents.eventFilters(), JSON.stringify(filters));
|
|
276
|
-
} catch (error) {
|
|
277
|
-
// Failed to save filters
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
saveFilters();
|
|
281
|
-
}, [ignoredPatterns]);
|
|
282
|
-
|
|
283
200
|
// Event listener is now managed by useRouteEvents hook
|
|
284
201
|
|
|
285
202
|
const handleToggleListening = (0, _react.useCallback)(() => {
|
|
@@ -473,21 +390,23 @@ function RouteEventsModalWithTabs({
|
|
|
473
390
|
placeholder: "Search pathname or params...",
|
|
474
391
|
testID: "buoy-routes-search"
|
|
475
392
|
})
|
|
476
|
-
}), /*#__PURE__*/(0, _jsxRuntime.
|
|
477
|
-
style: styles.emptyState,
|
|
393
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
478
394
|
testID: "buoy-routes-empty",
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
395
|
+
...(0, _sharedUi.resolveListEmptyState)({
|
|
396
|
+
subject: "route events",
|
|
397
|
+
search: searchQuery,
|
|
398
|
+
total: events.length,
|
|
399
|
+
capturing: isListening,
|
|
400
|
+
waiting: {
|
|
401
|
+
otto: "walking",
|
|
402
|
+
title: "No route events yet",
|
|
403
|
+
message: "Navigation events will appear here"
|
|
404
|
+
},
|
|
405
|
+
paused: {
|
|
406
|
+
title: "Event listener is paused",
|
|
407
|
+
message: "Press play to start monitoring"
|
|
408
|
+
}
|
|
409
|
+
})
|
|
491
410
|
})]
|
|
492
411
|
});
|
|
493
412
|
}
|
|
@@ -73,17 +73,8 @@ function RouteEventsTimeline({
|
|
|
73
73
|
onPress: handleItemPress,
|
|
74
74
|
onNavigate: onNavigate
|
|
75
75
|
}),
|
|
76
|
-
showsVerticalScrollIndicator: true
|
|
77
|
-
|
|
78
|
-
// screen, so the e2e bundle keeps every mounted row targetable. The
|
|
79
|
-
// env var is inlined at bundle time; guarded so a non-inlining bundler
|
|
80
|
-
// keeps production behaviour.
|
|
81
|
-
,
|
|
82
|
-
removeClippedSubviews: !(typeof process !== "undefined" && process.env?.EXPO_PUBLIC_E2E),
|
|
83
|
-
initialNumToRender: 12,
|
|
84
|
-
maxToRenderPerBatch: 8,
|
|
85
|
-
windowSize: 5,
|
|
86
|
-
updateCellsBatchingPeriod: 50
|
|
76
|
+
showsVerticalScrollIndicator: true,
|
|
77
|
+
..._sharedUi.EVENT_LIST_PRESET
|
|
87
78
|
})
|
|
88
79
|
);
|
|
89
80
|
}
|
|
@@ -408,14 +408,14 @@ function RoutesSitemap({
|
|
|
408
408
|
id: "groups"
|
|
409
409
|
})]
|
|
410
410
|
})]
|
|
411
|
-
}), displayGroups.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
411
|
+
}), displayGroups.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
412
|
+
testID: "buoy-routes-sitemap-empty"
|
|
413
|
+
// map = "route inspector; where am I in the navigator" — the one
|
|
414
|
+
// OTTO_USES sentence written for this screen.
|
|
415
|
+
,
|
|
416
|
+
otto: "map",
|
|
417
|
+
title: "No routes found",
|
|
418
|
+
message: "Nothing in the router matches. Clear the search to see the whole tree."
|
|
419
419
|
}) : displayGroups.map(group => /*#__PURE__*/(0, _jsxRuntime.jsx)(RouteGroupView, {
|
|
420
420
|
group: group,
|
|
421
421
|
isExpanded: searchQuery.length > 0 || expandedGroups.has(group.title),
|
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.useRouteEvents = useRouteEvents;
|
|
7
|
-
var
|
|
7
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
8
8
|
var _routeEventStore = require("../stores/routeEventStore");
|
|
9
9
|
/**
|
|
10
10
|
* useRouteEvents Hook
|
|
@@ -39,50 +39,19 @@ function useRouteEvents(options = {}) {
|
|
|
39
39
|
maxEvents = 500,
|
|
40
40
|
enabled = true
|
|
41
41
|
} = options;
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Frame-coalesced (see network's useNetworkEventList): navigation
|
|
56
|
-
// bursts land as one commit per frame instead of one per emission.
|
|
57
|
-
let rafId = null;
|
|
58
|
-
let pending = null;
|
|
59
|
-
const unsubscribe = _routeEventStore.routeEventStore.subscribeToEvents(allEvents => {
|
|
60
|
-
pending = allEvents;
|
|
61
|
-
if (rafId != null) return;
|
|
62
|
-
rafId = requestAnimationFrame(() => {
|
|
63
|
-
rafId = null;
|
|
64
|
-
if (!pending) return;
|
|
65
|
-
const latest = pending;
|
|
66
|
-
pending = null;
|
|
67
|
-
setEvents(latest.length > maxEvents ? latest.slice(0, maxEvents) : latest);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Mark as listening after successful subscription
|
|
72
|
-
setIsListening(true);
|
|
73
|
-
return () => {
|
|
74
|
-
unsubscribe();
|
|
75
|
-
if (rafId != null) cancelAnimationFrame(rafId);
|
|
76
|
-
// Note: Don't set isListening=false here because we might be
|
|
77
|
-
// re-subscribing due to dependency change, not actually stopping
|
|
78
|
-
};
|
|
79
|
-
}, [maxEvents, enabled]);
|
|
80
|
-
const clearEvents = (0, _react.useCallback)(() => {
|
|
81
|
-
_routeEventStore.routeEventStore.clearEvents();
|
|
82
|
-
}, []);
|
|
42
|
+
// Subscribing auto-starts the route observer (Subscribable pattern), and
|
|
43
|
+
// the shared hook frame-coalesces navigation bursts into one commit.
|
|
44
|
+
const {
|
|
45
|
+
events,
|
|
46
|
+
clearEvents,
|
|
47
|
+
isActive
|
|
48
|
+
} = (0, _sharedUi.useEventStoreEvents)(_routeEventStore.routeEventStore, {
|
|
49
|
+
maxEvents,
|
|
50
|
+
enabled
|
|
51
|
+
});
|
|
83
52
|
return {
|
|
84
53
|
events,
|
|
85
54
|
clearEvents,
|
|
86
|
-
isListening
|
|
55
|
+
isListening: isActive
|
|
87
56
|
};
|
|
88
57
|
}
|
package/lib/commonjs/preset.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.createRouteEventsTool =
|
|
7
|
-
exports.routeEventsToolPreset = void 0;
|
|
6
|
+
exports.routeEventsToolPreset = exports.createRouteEventsTool = void 0;
|
|
8
7
|
var _floatingToolsCore = require("@buoy-gg/floating-tools-core");
|
|
9
8
|
var _RouteEventsModalWithTabs = require("./components/RouteEventsModalWithTabs");
|
|
9
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
10
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
11
|
/**
|
|
12
12
|
* Pre-configured route events tool for FloatingDevTools
|
|
@@ -33,7 +33,7 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
33
33
|
* - Navigation stack visualization
|
|
34
34
|
* - Automatic route tracking (no setup needed)
|
|
35
35
|
*/
|
|
36
|
-
const routeEventsToolPreset = exports.routeEventsToolPreset = {
|
|
36
|
+
const routeEventsToolPreset = exports.routeEventsToolPreset = (0, _sharedUi.defineToolPreset)({
|
|
37
37
|
id: "route-events",
|
|
38
38
|
name: "ROUTES",
|
|
39
39
|
description: "Route tracking & navigation inspector",
|
|
@@ -47,7 +47,7 @@ const routeEventsToolPreset = exports.routeEventsToolPreset = {
|
|
|
47
47
|
props: {
|
|
48
48
|
enableSharedModalDimensions: false
|
|
49
49
|
}
|
|
50
|
-
};
|
|
50
|
+
});
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Create a custom route events tool configuration.
|
|
@@ -64,20 +64,6 @@ const routeEventsToolPreset = exports.routeEventsToolPreset = {
|
|
|
64
64
|
* });
|
|
65
65
|
* ```
|
|
66
66
|
*/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
name: options?.name || "ROUTES",
|
|
71
|
-
description: options?.description || "Route tracking & navigation inspector",
|
|
72
|
-
slot: "both",
|
|
73
|
-
icon: ({
|
|
74
|
-
size
|
|
75
|
-
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.RoutesIcon, {
|
|
76
|
-
size: size
|
|
77
|
-
}),
|
|
78
|
-
component: _RouteEventsModalWithTabs.RouteEventsModalWithTabs,
|
|
79
|
-
props: {
|
|
80
|
-
enableSharedModalDimensions: options?.enableSharedModalDimensions !== undefined ? options.enableSharedModalDimensions : false
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
}
|
|
67
|
+
const createRouteEventsTool = exports.createRouteEventsTool = (0, _sharedUi.createToolFactory)(routeEventsToolPreset, options => ({
|
|
68
|
+
enableSharedModalDimensions: options.enableSharedModalDimensions ?? false
|
|
69
|
+
}));
|
|
@@ -173,7 +173,25 @@ const routeEventsSyncAdapter = exports.routeEventsSyncAdapter = {
|
|
|
173
173
|
}
|
|
174
174
|
const router = (0, _sharedUi.getSafeRouter)();
|
|
175
175
|
if (!router) {
|
|
176
|
-
|
|
176
|
+
// Bare React Navigation: no paths, but the tracker captured the
|
|
177
|
+
// container ref, so navigate by SCREEN NAME — "/Settings" and
|
|
178
|
+
// "Settings" both resolve, and nested navigators are walked via the
|
|
179
|
+
// root state. This is half the market; "throw off expo-router" made
|
|
180
|
+
// navigate a dead verb for every RN CLI app.
|
|
181
|
+
const actions = _navigationStackStore.navigationStackStore.getActions();
|
|
182
|
+
const name = path.replace(/^\//, "");
|
|
183
|
+
if (!actions?.navigateToRoute || !name) {
|
|
184
|
+
throw new Error("expo-router is not available here and no navigation container was captured — is <RouteTracker /> mounted inside your NavigationContainer?");
|
|
185
|
+
}
|
|
186
|
+
const ok = actions.navigateToRoute(name, p?.params);
|
|
187
|
+
if (!ok) {
|
|
188
|
+
throw new Error(`Could not navigate to "${name}" — no navigation container is live.`);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
navigated: path,
|
|
192
|
+
replaced: false,
|
|
193
|
+
via: "react-navigation"
|
|
194
|
+
};
|
|
177
195
|
}
|
|
178
196
|
// Push by default so navigate-then-back flows keep working. Callers that
|
|
179
197
|
// mean "leave this screen" (sitemap Go, agents resetting to home) pass
|
|
@@ -282,6 +282,32 @@ function useNavigationStack() {
|
|
|
282
282
|
console.error("Failed to navigate:", err);
|
|
283
283
|
}
|
|
284
284
|
}, [stack, containerRef]);
|
|
285
|
+
const navigateToRoute = (0, _react.useCallback)((name, params) => {
|
|
286
|
+
if (!containerRef) return false;
|
|
287
|
+
try {
|
|
288
|
+
// Deep path first, so screens inside nested navigators resolve even
|
|
289
|
+
// when their navigator isn't mounted yet.
|
|
290
|
+
const rootState = containerRef.getRootState?.();
|
|
291
|
+
if (!params && rootState) {
|
|
292
|
+
const path = findScreenPath(rootState, name);
|
|
293
|
+
if (path) {
|
|
294
|
+
const action = buildNestedNavigateAction(path);
|
|
295
|
+
if (action) {
|
|
296
|
+
containerRef.dispatch(action);
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
containerRef.dispatch(CommonActions.navigate({
|
|
302
|
+
name,
|
|
303
|
+
params
|
|
304
|
+
}));
|
|
305
|
+
return true;
|
|
306
|
+
} catch (err) {
|
|
307
|
+
console.error("Failed to navigate:", err);
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
}, [containerRef]);
|
|
285
311
|
const popToIndex = (0, _react.useCallback)(index => {
|
|
286
312
|
if (index >= stack.length || index < 0) return;
|
|
287
313
|
const currentIndex = stack.length - 1;
|
|
@@ -336,6 +362,7 @@ function useNavigationStack() {
|
|
|
336
362
|
error,
|
|
337
363
|
refresh,
|
|
338
364
|
navigateToIndex,
|
|
365
|
+
navigateToRoute,
|
|
339
366
|
popToIndex,
|
|
340
367
|
goBack,
|
|
341
368
|
popToTop
|
|
@@ -67,6 +67,7 @@ function NavigationStackCapture() {
|
|
|
67
67
|
const {
|
|
68
68
|
stack,
|
|
69
69
|
navigateToIndex,
|
|
70
|
+
navigateToRoute,
|
|
70
71
|
popToIndex,
|
|
71
72
|
goBack,
|
|
72
73
|
popToTop
|
|
@@ -80,6 +81,7 @@ function NavigationStackCapture() {
|
|
|
80
81
|
useEffect(() => {
|
|
81
82
|
navigationStackStore.setActions({
|
|
82
83
|
navigateToIndex,
|
|
84
|
+
navigateToRoute,
|
|
83
85
|
popToIndex,
|
|
84
86
|
goBack,
|
|
85
87
|
popToTop
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { useState, useMemo, useEffect } from "react";
|
|
11
11
|
import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Alert } from "react-native";
|
|
12
|
-
import { ChevronDown, ChevronRight, InlineCopyButton, ProUpgradeModal, buoyColors, night, useSafeAreaInsets } from "@buoy-gg/shared-ui";
|
|
12
|
+
import { ChevronDown, ChevronRight, InlineCopyButton, ProUpgradeModal, buoyColors, night, useSafeAreaInsets, ToolEmptyState } from "@buoy-gg/shared-ui";
|
|
13
13
|
import { useIsPro } from "@buoy-gg/license";
|
|
14
14
|
import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
|
|
15
15
|
import { useNavigationStack } from "../useNavigationStack";
|
|
@@ -136,17 +136,11 @@ export function NavigationStack({
|
|
|
136
136
|
if (stack.length === 0) {
|
|
137
137
|
return /*#__PURE__*/_jsx(View, {
|
|
138
138
|
style: [styles.container, style],
|
|
139
|
-
children: /*#__PURE__*/
|
|
140
|
-
style: styles.emptyContainer,
|
|
139
|
+
children: /*#__PURE__*/_jsx(ToolEmptyState, {
|
|
141
140
|
testID: "buoy-routes-stack-empty",
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
children: "No navigation stack"
|
|
146
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
147
|
-
style: styles.emptySubtext,
|
|
148
|
-
children: "Navigate to a route to see the stack"
|
|
149
|
-
})]
|
|
141
|
+
otto: "walking",
|
|
142
|
+
title: "No navigation stack",
|
|
143
|
+
message: "Navigate to a route to see the stack"
|
|
150
144
|
})
|
|
151
145
|
});
|
|
152
146
|
}
|
|
@@ -8,8 +8,8 @@ import { getCommonActions, useSafeNavigationContainerRef } from "../utils/safeRe
|
|
|
8
8
|
// (useSafeNavigationContainerRef then yields undefined, so the dispatch
|
|
9
9
|
// paths below never execute).
|
|
10
10
|
const CommonActions = getCommonActions();
|
|
11
|
-
import { useSafeRouter, isExpoRouterAvailable, windowDragProps } from "@buoy-gg/shared-ui";
|
|
12
|
-
import { JsModal, ModalHeader, TabSelector, formatRelativeTime, devToolsStorageKeys,
|
|
11
|
+
import { useSafeRouter, isExpoRouterAvailable, windowDragProps, ToolEmptyState, resolveListEmptyState, usePersistedState } from "@buoy-gg/shared-ui";
|
|
12
|
+
import { JsModal, ModalHeader, TabSelector, formatRelativeTime, devToolsStorageKeys, Trash2, Filter, SearchBar, ToolbarCopyButton, Lock, ProUpgradeModal, PowerToggleButton, buoyColors, night, TickProvider, useLimit } from "@buoy-gg/shared-ui";
|
|
13
13
|
import { useIsPro } from "@buoy-gg/license";
|
|
14
14
|
|
|
15
15
|
// Free tier limit for route events
|
|
@@ -22,6 +22,23 @@ import { ReactNavigationRoutes } from "./ReactNavigationRoutes";
|
|
|
22
22
|
import { NavigationStack } from "./NavigationStack";
|
|
23
23
|
import { RouteEventsTimeline } from "./RouteEventsTimeline";
|
|
24
24
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
25
|
+
/** Persistence recipes: the tab is stored as its bare name, the flag as "true"/"false". */
|
|
26
|
+
const TAB_PERSISTENCE = {
|
|
27
|
+
// Every tab the selector offers, including "stack": the save side has
|
|
28
|
+
// always written it, so leaving it off this list meant the Stack tab
|
|
29
|
+
// was persisted and then silently discarded on the next launch.
|
|
30
|
+
parse: raw => raw === "routes" || raw === "events" || raw === "stack" ? raw : undefined,
|
|
31
|
+
serialize: tab => tab
|
|
32
|
+
};
|
|
33
|
+
const BOOLEAN_PERSISTENCE = {
|
|
34
|
+
parse: raw => raw === "true",
|
|
35
|
+
serialize: value => value.toString()
|
|
36
|
+
};
|
|
37
|
+
const STRING_SET_PERSISTENCE = {
|
|
38
|
+
parse: raw => new Set(JSON.parse(raw)),
|
|
39
|
+
serialize: set => JSON.stringify(Array.from(set))
|
|
40
|
+
};
|
|
41
|
+
|
|
25
42
|
/**
|
|
26
43
|
* Find the path from root navigation state to a screen by name.
|
|
27
44
|
* Returns array of route names from root to the target, or null if not found.
|
|
@@ -82,7 +99,7 @@ export function RouteEventsModalWithTabs({
|
|
|
82
99
|
const router = useSafeRouter();
|
|
83
100
|
const containerRef = useSafeNavigationContainerRef();
|
|
84
101
|
const hasExpoRouter = isExpoRouterAvailable();
|
|
85
|
-
const [activeTab, setActiveTab] =
|
|
102
|
+
const [activeTab, setActiveTab] = usePersistedState(devToolsStorageKeys.routeEvents.activeTab(), "events", TAB_PERSISTENCE);
|
|
86
103
|
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
|
87
104
|
// Serialized stack reported up by NavigationStack so the copy button can live
|
|
88
105
|
// in the shared navbar.
|
|
@@ -104,7 +121,7 @@ export function RouteEventsModalWithTabs({
|
|
|
104
121
|
// See the RouteTracker component export for easy setup.
|
|
105
122
|
|
|
106
123
|
// Local state to control subscription (true = subscribed, false = unsubscribed)
|
|
107
|
-
const [isListeningEnabled, setIsListeningEnabled] =
|
|
124
|
+
const [isListeningEnabled, setIsListeningEnabled] = usePersistedState(devToolsStorageKeys.routeEvents.isMonitoring(), true, BOOLEAN_PERSISTENCE);
|
|
108
125
|
|
|
109
126
|
// Event Listener state - using centralized store via hook
|
|
110
127
|
// Pass enabled option to control subscription
|
|
@@ -124,11 +141,8 @@ export function RouteEventsModalWithTabs({
|
|
|
124
141
|
const [selectedEvent, setSelectedEvent] = useState(null);
|
|
125
142
|
const [selectedVisitNumber, setSelectedVisitNumber] = useState(1);
|
|
126
143
|
const [searchQuery, setSearchQuery] = useState("");
|
|
127
|
-
const [ignoredPatterns, setIgnoredPatterns] =
|
|
144
|
+
const [ignoredPatterns, setIgnoredPatterns] = usePersistedState(devToolsStorageKeys.routeEvents.eventFilters(), new Set(["/_sitemap", "/api", "/__dev"]), STRING_SET_PERSISTENCE);
|
|
128
145
|
const lastEventRef = useRef(null);
|
|
129
|
-
const hasLoadedFilters = useRef(false);
|
|
130
|
-
const hasLoadedTabState = useRef(false);
|
|
131
|
-
const hasLoadedMonitoringState = useRef(false);
|
|
132
146
|
const handleModeChange = useCallback(_mode => {
|
|
133
147
|
// Mode changes handled by JsModal
|
|
134
148
|
}, []);
|
|
@@ -180,103 +194,6 @@ export function RouteEventsModalWithTabs({
|
|
|
180
194
|
}
|
|
181
195
|
}, [router, containerRef, hasExpoRouter, remote, isPro]);
|
|
182
196
|
|
|
183
|
-
// Load persisted tab state on mount
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
if (!visible || hasLoadedTabState.current) return;
|
|
186
|
-
const loadTabState = async () => {
|
|
187
|
-
try {
|
|
188
|
-
const storedTab = await persistentStorage.getItem(devToolsStorageKeys.routeEvents.activeTab());
|
|
189
|
-
// Every tab the selector offers, including "stack": the save side has
|
|
190
|
-
// always written it, so leaving it off this list meant the Stack tab
|
|
191
|
-
// was persisted and then silently discarded on the next launch —
|
|
192
|
-
// you came back to Events having chosen otherwise.
|
|
193
|
-
if (storedTab === "routes" || storedTab === "events" || storedTab === "stack") {
|
|
194
|
-
setActiveTab(storedTab);
|
|
195
|
-
}
|
|
196
|
-
hasLoadedTabState.current = true;
|
|
197
|
-
} catch (error) {
|
|
198
|
-
// Failed to load tab state
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
loadTabState();
|
|
202
|
-
}, [visible]);
|
|
203
|
-
|
|
204
|
-
// Load persisted monitoring state on mount
|
|
205
|
-
useEffect(() => {
|
|
206
|
-
if (!visible || hasLoadedMonitoringState.current) return;
|
|
207
|
-
const loadMonitoringState = async () => {
|
|
208
|
-
try {
|
|
209
|
-
const storedMonitoring = await persistentStorage.getItem(devToolsStorageKeys.routeEvents.isMonitoring());
|
|
210
|
-
if (storedMonitoring !== null) {
|
|
211
|
-
const shouldMonitor = storedMonitoring === "true";
|
|
212
|
-
setIsListeningEnabled(shouldMonitor);
|
|
213
|
-
}
|
|
214
|
-
hasLoadedMonitoringState.current = true;
|
|
215
|
-
} catch (error) {
|
|
216
|
-
// Failed to load monitoring state
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
loadMonitoringState();
|
|
220
|
-
}, [visible]);
|
|
221
|
-
|
|
222
|
-
// Save tab state when it changes
|
|
223
|
-
useEffect(() => {
|
|
224
|
-
if (!hasLoadedTabState.current) return;
|
|
225
|
-
const saveTabState = async () => {
|
|
226
|
-
try {
|
|
227
|
-
await persistentStorage.setItem(devToolsStorageKeys.routeEvents.activeTab(), activeTab);
|
|
228
|
-
} catch (error) {
|
|
229
|
-
// Failed to save tab state
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
saveTabState();
|
|
233
|
-
}, [activeTab]);
|
|
234
|
-
|
|
235
|
-
// Save monitoring state when it changes
|
|
236
|
-
useEffect(() => {
|
|
237
|
-
if (!hasLoadedMonitoringState.current) return;
|
|
238
|
-
const saveMonitoringState = async () => {
|
|
239
|
-
try {
|
|
240
|
-
await persistentStorage.setItem(devToolsStorageKeys.routeEvents.isMonitoring(), isListening.toString());
|
|
241
|
-
} catch (error) {
|
|
242
|
-
// Failed to save monitoring state
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
saveMonitoringState();
|
|
246
|
-
}, [isListening]);
|
|
247
|
-
|
|
248
|
-
// Load persisted filters on mount
|
|
249
|
-
useEffect(() => {
|
|
250
|
-
if (!visible || hasLoadedFilters.current) return;
|
|
251
|
-
const loadFilters = async () => {
|
|
252
|
-
try {
|
|
253
|
-
const storedFilters = await persistentStorage.getItem(devToolsStorageKeys.routeEvents.eventFilters());
|
|
254
|
-
if (storedFilters) {
|
|
255
|
-
const filters = JSON.parse(storedFilters);
|
|
256
|
-
setIgnoredPatterns(new Set(filters));
|
|
257
|
-
}
|
|
258
|
-
hasLoadedFilters.current = true;
|
|
259
|
-
} catch (error) {
|
|
260
|
-
// Failed to load filters
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
loadFilters();
|
|
264
|
-
}, [visible]);
|
|
265
|
-
|
|
266
|
-
// Save filters when they change
|
|
267
|
-
useEffect(() => {
|
|
268
|
-
if (!hasLoadedFilters.current) return;
|
|
269
|
-
const saveFilters = async () => {
|
|
270
|
-
try {
|
|
271
|
-
const filters = Array.from(ignoredPatterns);
|
|
272
|
-
await persistentStorage.setItem(devToolsStorageKeys.routeEvents.eventFilters(), JSON.stringify(filters));
|
|
273
|
-
} catch (error) {
|
|
274
|
-
// Failed to save filters
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
saveFilters();
|
|
278
|
-
}, [ignoredPatterns]);
|
|
279
|
-
|
|
280
197
|
// Event listener is now managed by useRouteEvents hook
|
|
281
198
|
|
|
282
199
|
const handleToggleListening = useCallback(() => {
|
|
@@ -470,21 +387,23 @@ export function RouteEventsModalWithTabs({
|
|
|
470
387
|
placeholder: "Search pathname or params...",
|
|
471
388
|
testID: "buoy-routes-search"
|
|
472
389
|
})
|
|
473
|
-
}), /*#__PURE__*/
|
|
474
|
-
style: styles.emptyState,
|
|
390
|
+
}), /*#__PURE__*/_jsx(ToolEmptyState, {
|
|
475
391
|
testID: "buoy-routes-empty",
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
392
|
+
...resolveListEmptyState({
|
|
393
|
+
subject: "route events",
|
|
394
|
+
search: searchQuery,
|
|
395
|
+
total: events.length,
|
|
396
|
+
capturing: isListening,
|
|
397
|
+
waiting: {
|
|
398
|
+
otto: "walking",
|
|
399
|
+
title: "No route events yet",
|
|
400
|
+
message: "Navigation events will appear here"
|
|
401
|
+
},
|
|
402
|
+
paused: {
|
|
403
|
+
title: "Event listener is paused",
|
|
404
|
+
message: "Press play to start monitoring"
|
|
405
|
+
}
|
|
406
|
+
})
|
|
488
407
|
})]
|
|
489
408
|
});
|
|
490
409
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { useCallback } from "react";
|
|
14
14
|
import { View, Text, FlatList, StyleSheet } from "react-native";
|
|
15
|
-
import { Navigation, night } from "@buoy-gg/shared-ui";
|
|
15
|
+
import { Navigation, night, EVENT_LIST_PRESET } from "@buoy-gg/shared-ui";
|
|
16
16
|
import { RouteEventItemCompact } from "./RouteEventItemCompact";
|
|
17
17
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
18
|
export function RouteEventsTimeline({
|
|
@@ -69,17 +69,8 @@ export function RouteEventsTimeline({
|
|
|
69
69
|
onPress: handleItemPress,
|
|
70
70
|
onNavigate: onNavigate
|
|
71
71
|
}),
|
|
72
|
-
showsVerticalScrollIndicator: true
|
|
73
|
-
|
|
74
|
-
// screen, so the e2e bundle keeps every mounted row targetable. The
|
|
75
|
-
// env var is inlined at bundle time; guarded so a non-inlining bundler
|
|
76
|
-
// keeps production behaviour.
|
|
77
|
-
,
|
|
78
|
-
removeClippedSubviews: !(typeof process !== "undefined" && process.env?.EXPO_PUBLIC_E2E),
|
|
79
|
-
initialNumToRender: 12,
|
|
80
|
-
maxToRenderPerBatch: 8,
|
|
81
|
-
windowSize: 5,
|
|
82
|
-
updateCellsBatchingPeriod: 50
|
|
72
|
+
showsVerticalScrollIndicator: true,
|
|
73
|
+
...EVENT_LIST_PRESET
|
|
83
74
|
})
|
|
84
75
|
);
|
|
85
76
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { useState, useCallback, useMemo, useEffect } from "react";
|
|
15
|
-
import { night } from "@buoy-gg/shared-ui";
|
|
15
|
+
import { night, ToolEmptyState } from "@buoy-gg/shared-ui";
|
|
16
16
|
import { View, Text, TextInput, TouchableOpacity, ScrollView, StyleSheet, Alert, Platform } from "react-native";
|
|
17
17
|
import { useSafeRouter } from "@buoy-gg/shared-ui";
|
|
18
18
|
import { Search, ChevronDown, ChevronRight, Home, InlineCopyButton, CopyButton, RefreshCw, formatRelativeTime, ProUpgradeModal } from "@buoy-gg/shared-ui";
|
|
@@ -406,14 +406,14 @@ export function RoutesSitemap({
|
|
|
406
406
|
id: "groups"
|
|
407
407
|
})]
|
|
408
408
|
})]
|
|
409
|
-
}), displayGroups.length === 0 ? /*#__PURE__*/_jsx(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
409
|
+
}), displayGroups.length === 0 ? /*#__PURE__*/_jsx(ToolEmptyState, {
|
|
410
|
+
testID: "buoy-routes-sitemap-empty"
|
|
411
|
+
// map = "route inspector; where am I in the navigator" — the one
|
|
412
|
+
// OTTO_USES sentence written for this screen.
|
|
413
|
+
,
|
|
414
|
+
otto: "map",
|
|
415
|
+
title: "No routes found",
|
|
416
|
+
message: "Nothing in the router matches. Clear the search to see the whole tree."
|
|
417
417
|
}) : displayGroups.map(group => /*#__PURE__*/_jsx(RouteGroupView, {
|
|
418
418
|
group: group,
|
|
419
419
|
isExpanded: searchQuery.length > 0 || expandedGroups.has(group.title),
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import {
|
|
29
|
+
import { useEventStoreEvents } from "@buoy-gg/shared-ui";
|
|
30
30
|
import { routeEventStore } from "../stores/routeEventStore";
|
|
31
31
|
|
|
32
32
|
// Re-export RouteChangeEvent for convenience
|
|
@@ -36,50 +36,19 @@ export function useRouteEvents(options = {}) {
|
|
|
36
36
|
maxEvents = 500,
|
|
37
37
|
enabled = true
|
|
38
38
|
} = options;
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Frame-coalesced (see network's useNetworkEventList): navigation
|
|
53
|
-
// bursts land as one commit per frame instead of one per emission.
|
|
54
|
-
let rafId = null;
|
|
55
|
-
let pending = null;
|
|
56
|
-
const unsubscribe = routeEventStore.subscribeToEvents(allEvents => {
|
|
57
|
-
pending = allEvents;
|
|
58
|
-
if (rafId != null) return;
|
|
59
|
-
rafId = requestAnimationFrame(() => {
|
|
60
|
-
rafId = null;
|
|
61
|
-
if (!pending) return;
|
|
62
|
-
const latest = pending;
|
|
63
|
-
pending = null;
|
|
64
|
-
setEvents(latest.length > maxEvents ? latest.slice(0, maxEvents) : latest);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Mark as listening after successful subscription
|
|
69
|
-
setIsListening(true);
|
|
70
|
-
return () => {
|
|
71
|
-
unsubscribe();
|
|
72
|
-
if (rafId != null) cancelAnimationFrame(rafId);
|
|
73
|
-
// Note: Don't set isListening=false here because we might be
|
|
74
|
-
// re-subscribing due to dependency change, not actually stopping
|
|
75
|
-
};
|
|
76
|
-
}, [maxEvents, enabled]);
|
|
77
|
-
const clearEvents = useCallback(() => {
|
|
78
|
-
routeEventStore.clearEvents();
|
|
79
|
-
}, []);
|
|
39
|
+
// Subscribing auto-starts the route observer (Subscribable pattern), and
|
|
40
|
+
// the shared hook frame-coalesces navigation bursts into one commit.
|
|
41
|
+
const {
|
|
42
|
+
events,
|
|
43
|
+
clearEvents,
|
|
44
|
+
isActive
|
|
45
|
+
} = useEventStoreEvents(routeEventStore, {
|
|
46
|
+
maxEvents,
|
|
47
|
+
enabled
|
|
48
|
+
});
|
|
80
49
|
return {
|
|
81
50
|
events,
|
|
82
51
|
clearEvents,
|
|
83
|
-
isListening
|
|
52
|
+
isListening: isActive
|
|
84
53
|
};
|
|
85
54
|
}
|
package/lib/module/preset.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { RoutesIcon } from "@buoy-gg/floating-tools-core";
|
|
21
21
|
import { RouteEventsModalWithTabs } from "./components/RouteEventsModalWithTabs";
|
|
22
|
+
import { createToolFactory, defineToolPreset } from "@buoy-gg/shared-ui";
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Pre-configured route events tool for FloatingDevTools.
|
|
@@ -29,7 +30,7 @@ import { RouteEventsModalWithTabs } from "./components/RouteEventsModalWithTabs"
|
|
|
29
30
|
* - Automatic route tracking (no setup needed)
|
|
30
31
|
*/
|
|
31
32
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
32
|
-
export const routeEventsToolPreset = {
|
|
33
|
+
export const routeEventsToolPreset = defineToolPreset({
|
|
33
34
|
id: "route-events",
|
|
34
35
|
name: "ROUTES",
|
|
35
36
|
description: "Route tracking & navigation inspector",
|
|
@@ -43,7 +44,7 @@ export const routeEventsToolPreset = {
|
|
|
43
44
|
props: {
|
|
44
45
|
enableSharedModalDimensions: false
|
|
45
46
|
}
|
|
46
|
-
};
|
|
47
|
+
});
|
|
47
48
|
|
|
48
49
|
/**
|
|
49
50
|
* Create a custom route events tool configuration.
|
|
@@ -60,20 +61,6 @@ export const routeEventsToolPreset = {
|
|
|
60
61
|
* });
|
|
61
62
|
* ```
|
|
62
63
|
*/
|
|
63
|
-
export
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
name: options?.name || "ROUTES",
|
|
67
|
-
description: options?.description || "Route tracking & navigation inspector",
|
|
68
|
-
slot: "both",
|
|
69
|
-
icon: ({
|
|
70
|
-
size
|
|
71
|
-
}) => /*#__PURE__*/_jsx(RoutesIcon, {
|
|
72
|
-
size: size
|
|
73
|
-
}),
|
|
74
|
-
component: RouteEventsModalWithTabs,
|
|
75
|
-
props: {
|
|
76
|
-
enableSharedModalDimensions: options?.enableSharedModalDimensions !== undefined ? options.enableSharedModalDimensions : false
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
64
|
+
export const createRouteEventsTool = createToolFactory(routeEventsToolPreset, options => ({
|
|
65
|
+
enableSharedModalDimensions: options.enableSharedModalDimensions ?? false
|
|
66
|
+
}));
|
|
@@ -171,7 +171,25 @@ export const routeEventsSyncAdapter = {
|
|
|
171
171
|
}
|
|
172
172
|
const router = getSafeRouter();
|
|
173
173
|
if (!router) {
|
|
174
|
-
|
|
174
|
+
// Bare React Navigation: no paths, but the tracker captured the
|
|
175
|
+
// container ref, so navigate by SCREEN NAME — "/Settings" and
|
|
176
|
+
// "Settings" both resolve, and nested navigators are walked via the
|
|
177
|
+
// root state. This is half the market; "throw off expo-router" made
|
|
178
|
+
// navigate a dead verb for every RN CLI app.
|
|
179
|
+
const actions = navigationStackStore.getActions();
|
|
180
|
+
const name = path.replace(/^\//, "");
|
|
181
|
+
if (!actions?.navigateToRoute || !name) {
|
|
182
|
+
throw new Error("expo-router is not available here and no navigation container was captured — is <RouteTracker /> mounted inside your NavigationContainer?");
|
|
183
|
+
}
|
|
184
|
+
const ok = actions.navigateToRoute(name, p?.params);
|
|
185
|
+
if (!ok) {
|
|
186
|
+
throw new Error(`Could not navigate to "${name}" — no navigation container is live.`);
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
navigated: path,
|
|
190
|
+
replaced: false,
|
|
191
|
+
via: "react-navigation"
|
|
192
|
+
};
|
|
175
193
|
}
|
|
176
194
|
// Push by default so navigate-then-back flows keep working. Callers that
|
|
177
195
|
// mean "leave this screen" (sitemap Go, agents resetting to home) pass
|
|
@@ -279,6 +279,32 @@ export function useNavigationStack() {
|
|
|
279
279
|
console.error("Failed to navigate:", err);
|
|
280
280
|
}
|
|
281
281
|
}, [stack, containerRef]);
|
|
282
|
+
const navigateToRoute = useCallback((name, params) => {
|
|
283
|
+
if (!containerRef) return false;
|
|
284
|
+
try {
|
|
285
|
+
// Deep path first, so screens inside nested navigators resolve even
|
|
286
|
+
// when their navigator isn't mounted yet.
|
|
287
|
+
const rootState = containerRef.getRootState?.();
|
|
288
|
+
if (!params && rootState) {
|
|
289
|
+
const path = findScreenPath(rootState, name);
|
|
290
|
+
if (path) {
|
|
291
|
+
const action = buildNestedNavigateAction(path);
|
|
292
|
+
if (action) {
|
|
293
|
+
containerRef.dispatch(action);
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
containerRef.dispatch(CommonActions.navigate({
|
|
299
|
+
name,
|
|
300
|
+
params
|
|
301
|
+
}));
|
|
302
|
+
return true;
|
|
303
|
+
} catch (err) {
|
|
304
|
+
console.error("Failed to navigate:", err);
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
}, [containerRef]);
|
|
282
308
|
const popToIndex = useCallback(index => {
|
|
283
309
|
if (index >= stack.length || index < 0) return;
|
|
284
310
|
const currentIndex = stack.length - 1;
|
|
@@ -333,6 +359,7 @@ export function useNavigationStack() {
|
|
|
333
359
|
error,
|
|
334
360
|
refresh,
|
|
335
361
|
navigateToIndex,
|
|
362
|
+
navigateToRoute,
|
|
336
363
|
popToIndex,
|
|
337
364
|
goBack,
|
|
338
365
|
popToTop
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteTracker.d.ts","sourceRoot":"","sources":["../../src/RouteTracker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;
|
|
1
|
+
{"version":3,"file":"RouteTracker.d.ts","sourceRoot":"","sources":["../../src/RouteTracker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAiDH,wBAAgB,YAAY,gCAQ3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NavigationStack.d.ts","sourceRoot":"","sources":["../../../src/components/NavigationStack.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"NavigationStack.d.ts","sourceRoot":"","sources":["../../../src/components/NavigationStack.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAO/B,uEAAuE;AACvE,MAAM,MAAM,yBAAyB,GACjC,iBAAiB,GACjB,YAAY,GACZ,QAAQ,GACR,UAAU,CAAC;AAEf,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,GAAG,CAAC;IAEZ;;;;OAIG;IACH,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,yBAAyB,EACjC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KACzB,IAAI,CAAC;IAEV;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAMD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,aAAa,EACb,QAAQ,EACR,iBAAiB,GAClB,EAAE,oBAAoB,+BA2dtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteEventsModalWithTabs.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventsModalWithTabs.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RouteEventsModalWithTabs.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventsModalWithTabs.tsx"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAGnE,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE;YACR,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;YAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;SAC/B,CAAC;QACF,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;QAC3B;;;;WAIG;QACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;QAC7C;;;;;WAKG;QACH,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5C,2EAA2E;QAC3E,aAAa,CAAC,EAAE,CACd,MAAM,EAAE,yBAAyB,EACjC,OAAO,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,KACzB,IAAI,CAAC;KACX,CAAC;CACH;AAgED,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,MAAc,EACd,MAAM,GACP,EAAE,6BAA6B,sCAqmB/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,KAAK,GAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAM,+BAKlF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteEventsTimeline.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventsTimeline.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"RouteEventsTimeline.d.ts","sourceRoot":"","sources":["../../../src/components/RouteEventsTimeline.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAcH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD,UAAU,wBAAwB;IAChC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B;wEACoE;IACpE,WAAW,EAAE,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACvE;AAED,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,WAAW,EACX,UAAU,EACV,aAAa,GACd,EAAE,wBAAwB,+BAoD1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RoutesSitemap.d.ts","sourceRoot":"","sources":["../../../src/components/RoutesSitemap.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"RoutesSitemap.d.ts","sourceRoot":"","sources":["../../../src/components/RoutesSitemap.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgCH,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,gBAAgB,CAAC;AAM5D,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,GAAG,CAAC;IAEZ;;;;OAIG;IACH,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC;IAE7B,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;IAExC,8DAA8D;IAC9D,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CAC9C;AAsCD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,eAAe,GAChB,EAAE,kBAAkB,+BAibpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRouteEvents.d.ts","sourceRoot":"","sources":["../../../src/hooks/useRouteEvents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,uBAAuB;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,qBAA0B,GAClC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"useRouteEvents.d.ts","sourceRoot":"","sources":["../../../src/hooks/useRouteEvents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,uBAAuB;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,qBAA0B,GAClC,oBAAoB,CAStB"}
|
|
@@ -51,16 +51,10 @@ export declare const routeEventsToolPreset: {
|
|
|
51
51
|
* });
|
|
52
52
|
* ```
|
|
53
53
|
*/
|
|
54
|
-
export declare
|
|
55
|
-
/** Tool name (default: "ROUTES") */
|
|
56
|
-
name?: string;
|
|
57
|
-
/** Tool description */
|
|
58
|
-
description?: string;
|
|
59
|
-
/** Custom tool ID (default: "route-events") */
|
|
60
|
-
id?: string;
|
|
54
|
+
export declare const createRouteEventsTool: (options?: ({
|
|
61
55
|
/** Enable shared modal dimensions */
|
|
62
56
|
enableSharedModalDimensions?: boolean;
|
|
63
|
-
})
|
|
57
|
+
} & import("@buoy-gg/shared-ui").ToolPresetOverrides) | undefined) => {
|
|
64
58
|
id: string;
|
|
65
59
|
name: string;
|
|
66
60
|
description: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AAGjF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;;qBAKf;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;;;;;CAKjC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB;IAG9B,qCAAqC;kCACP,OAAO;;;;;;qBA1BtB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;;;;;CA8BlC,CAAC"}
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import type { StackDisplayItem } from "../useNavigationStack";
|
|
15
15
|
export interface NavigationStackActions {
|
|
16
16
|
navigateToIndex: (index: number) => void;
|
|
17
|
+
/** Name-based navigation for bare React Navigation. Optional: older trackers don't capture it. */
|
|
18
|
+
navigateToRoute?: (name: string, params?: object) => boolean;
|
|
17
19
|
popToIndex: (index: number) => void;
|
|
18
20
|
goBack: () => void;
|
|
19
21
|
popToTop: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigationStackStore.d.ts","sourceRoot":"","sources":["../../../src/stores/navigationStackStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,cAAM,oBAAoB;IACxB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,SAAS,CAAyB;IAE1C,QAAQ,IAAI,gBAAgB,EAAE;IAI9B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAKzC,UAAU,IAAI,sBAAsB,GAAG,IAAI;IAI3C,UAAU,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,GAAG,IAAI;IAIxD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAM5C;AAED,eAAO,MAAM,oBAAoB,sBAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"navigationStackStore.d.ts","sourceRoot":"","sources":["../../../src/stores/navigationStackStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,kGAAkG;IAClG,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7D,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,cAAM,oBAAoB;IACxB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,SAAS,CAAyB;IAE1C,QAAQ,IAAI,gBAAgB,EAAE;IAI9B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAKzC,UAAU,IAAI,sBAAsB,GAAG,IAAI;IAI3C,UAAU,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,GAAG,IAAI;IAIxD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAM5C;AAED,eAAO,MAAM,oBAAoB,sBAA6B,CAAC"}
|
|
@@ -84,6 +84,11 @@ export declare const routeEventsSyncAdapter: {
|
|
|
84
84
|
navigate: (params?: unknown) => {
|
|
85
85
|
navigated: string;
|
|
86
86
|
replaced: boolean;
|
|
87
|
+
via: string;
|
|
88
|
+
} | {
|
|
89
|
+
navigated: string;
|
|
90
|
+
replaced: boolean;
|
|
91
|
+
via?: undefined;
|
|
87
92
|
};
|
|
88
93
|
stackNavigateToIndex: (params?: unknown) => {
|
|
89
94
|
navigatedToIndex: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeEventsSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/routeEventsSyncAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,QAAY,CAAC;AA4BrD;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,mEAAmE;IACnE,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,oBAAoB,CAAC;IAC9B,8EAA8E;IAC9E,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAWD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB;;uBAEhB,sBAAsB;0BAKjB,MAAM,IAAI;;;QAkC9B;;;;;;;;WAQG;;;;;;;;;;;;;;;;;QAgCH;;;WAGG;4BACiB,OAAO
|
|
1
|
+
{"version":3,"file":"routeEventsSyncAdapter.d.ts","sourceRoot":"","sources":["../../../src/sync/routeEventsSyncAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,QAAY,CAAC;AA4BrD;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,mEAAmE;IACnE,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,oBAAoB,CAAC;IAC9B,8EAA8E;IAC9E,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAWD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB;;uBAEhB,sBAAsB;0BAKjB,MAAM,IAAI;;;QAkC9B;;;;;;;;WAQG;;;;;;;;;;;;;;;;;QAgCH;;;WAGG;4BACiB,OAAO;;;;;;;;;wCAsCK,OAAO;;;mCAUZ,OAAO;;;;;;;;;;CAuBrC,CAAC"}
|
|
@@ -27,6 +27,13 @@ export interface UseNavigationStackResult {
|
|
|
27
27
|
error: Error | null;
|
|
28
28
|
refresh: () => void;
|
|
29
29
|
navigateToIndex: (index: number) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Navigate to a screen by NAME on bare React Navigation — the fallback
|
|
32
|
+
* that makes the `navigate` sync action work off expo-router. Resolves
|
|
33
|
+
* nested navigators via the root state when it can; returns false when no
|
|
34
|
+
* container ref was captured.
|
|
35
|
+
*/
|
|
36
|
+
navigateToRoute: (name: string, params?: object) => boolean;
|
|
30
37
|
popToIndex: (index: number) => void;
|
|
31
38
|
goBack: () => void;
|
|
32
39
|
popToTop: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNavigationStack.d.ts","sourceRoot":"","sources":["../../src/useNavigationStack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA4BH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IAEvC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAGlB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAGpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAuKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,IAAI,wBAAwB,
|
|
1
|
+
{"version":3,"file":"useNavigationStack.d.ts","sourceRoot":"","sources":["../../src/useNavigationStack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA4BH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IAEvC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAGlB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAGpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;;;;;OAKG;IACH,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5D,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAuKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,IAAI,wBAAwB,CAiM7D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/route-events",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.34",
|
|
4
4
|
"description": "Navigation devtool for React Native — live stack, full sitemap, jump to any screen. Expo Router & React Navigation. Part of Buoy devtools.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
],
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@buoy-gg/shared-ui": "^7.0.
|
|
30
|
-
"@buoy-gg/floating-tools-core": "^7.0.
|
|
29
|
+
"@buoy-gg/shared-ui": "^7.0.34",
|
|
30
|
+
"@buoy-gg/floating-tools-core": "^7.0.34"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@buoy-gg/license": "7.0.
|
|
33
|
+
"@buoy-gg/license": "7.0.34",
|
|
34
34
|
"@react-native-async-storage/async-storage": "^2.0.0 || ^3.1.0",
|
|
35
35
|
"@react-navigation/native": "*",
|
|
36
36
|
"expo-router": "*",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@types/react-native": "^0.73.0",
|
|
53
53
|
"expo-router": "~5.0.7",
|
|
54
54
|
"typescript": "~5.8.3",
|
|
55
|
-
"@buoy-gg/license": "^7.0.
|
|
55
|
+
"@buoy-gg/license": "^7.0.34"
|
|
56
56
|
},
|
|
57
57
|
"react-native-builder-bob": {
|
|
58
58
|
"source": "src",
|