@buoy-gg/route-events 2.1.2 → 2.1.3
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/components/RouteEventsModalWithTabs.js +27 -45
- package/lib/commonjs/hooks/useRouteEvents.js +79 -0
- package/lib/commonjs/index.js +15 -1
- package/lib/commonjs/stores/routeEventStore.js +97 -0
- package/lib/module/components/RouteEventsModalWithTabs.js +28 -46
- package/lib/module/hooks/useRouteEvents.js +76 -0
- package/lib/module/index.js +4 -1
- package/lib/module/stores/routeEventStore.js +89 -0
- package/lib/typescript/components/RouteEventsModalWithTabs.d.ts +1 -7
- package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/hooks/useRouteEvents.d.ts +43 -0
- package/lib/typescript/hooks/useRouteEvents.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +5 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/stores/routeEventStore.d.ts +55 -0
- package/lib/typescript/stores/routeEventStore.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -9,7 +9,7 @@ var _reactNative = require("react-native");
|
|
|
9
9
|
var _expoRouter = require("expo-router");
|
|
10
10
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
11
11
|
var _license = require("@buoy-gg/license");
|
|
12
|
-
var
|
|
12
|
+
var _useRouteEvents = require("../hooks/useRouteEvents");
|
|
13
13
|
var _RouteFilterViewV = require("./RouteFilterViewV2");
|
|
14
14
|
var _RoutesSitemap = require("./RoutesSitemap");
|
|
15
15
|
var _NavigationStack = require("./NavigationStack");
|
|
@@ -22,8 +22,7 @@ function RouteEventsModalWithTabs({
|
|
|
22
22
|
onClose,
|
|
23
23
|
onBack,
|
|
24
24
|
onMinimize,
|
|
25
|
-
enableSharedModalDimensions = false
|
|
26
|
-
routeObserver = _RouteObserver.routeObserver
|
|
25
|
+
enableSharedModalDimensions = false
|
|
27
26
|
}) {
|
|
28
27
|
const router = (0, _expoRouter.useRouter)();
|
|
29
28
|
const [activeTab, setActiveTab] = (0, _react.useState)("events");
|
|
@@ -43,9 +42,21 @@ function RouteEventsModalWithTabs({
|
|
|
43
42
|
// The useRouteObserver hook uses expo-router hooks that only work inside Stack/Tabs/Slot.
|
|
44
43
|
// See the RouteTracker component export for easy setup.
|
|
45
44
|
|
|
46
|
-
//
|
|
47
|
-
const [
|
|
48
|
-
|
|
45
|
+
// Local state to control subscription (true = subscribed, false = unsubscribed)
|
|
46
|
+
const [isListeningEnabled, setIsListeningEnabled] = (0, _react.useState)(true);
|
|
47
|
+
|
|
48
|
+
// Event Listener state - using centralized store via hook
|
|
49
|
+
// Pass enabled option to control subscription
|
|
50
|
+
const {
|
|
51
|
+
events,
|
|
52
|
+
clearEvents: clearRouteEvents,
|
|
53
|
+
isListening: isStoreListening
|
|
54
|
+
} = (0, _useRouteEvents.useRouteEvents)({
|
|
55
|
+
enabled: isListeningEnabled
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// isListening = enabled and store is listening
|
|
59
|
+
const isListening = isListeningEnabled && isStoreListening;
|
|
49
60
|
const [showFilters, setShowFilters] = (0, _react.useState)(false);
|
|
50
61
|
const [searchQuery, setSearchQuery] = (0, _react.useState)("");
|
|
51
62
|
const [ignoredPatterns, setIgnoredPatterns] = (0, _react.useState)(new Set(["/_sitemap", "/api", "/__dev"]));
|
|
@@ -89,7 +100,7 @@ function RouteEventsModalWithTabs({
|
|
|
89
100
|
const storedMonitoring = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.routeEvents.isMonitoring());
|
|
90
101
|
if (storedMonitoring !== null) {
|
|
91
102
|
const shouldMonitor = storedMonitoring === "true";
|
|
92
|
-
|
|
103
|
+
setIsListeningEnabled(shouldMonitor);
|
|
93
104
|
}
|
|
94
105
|
hasLoadedMonitoringState.current = true;
|
|
95
106
|
} catch (error) {
|
|
@@ -157,24 +168,11 @@ function RouteEventsModalWithTabs({
|
|
|
157
168
|
saveFilters();
|
|
158
169
|
}, [ignoredPatterns]);
|
|
159
170
|
|
|
160
|
-
// Event listener
|
|
161
|
-
(0, _react.useEffect)(() => {
|
|
162
|
-
if (!isListening) return;
|
|
171
|
+
// Event listener is now managed by useRouteEvents hook
|
|
163
172
|
|
|
164
|
-
// Set up event listener
|
|
165
|
-
const unsubscribe = routeObserver.addListener(event => {
|
|
166
|
-
lastEventRef.current = event;
|
|
167
|
-
setEvents(prev => {
|
|
168
|
-
const updated = [event, ...prev];
|
|
169
|
-
return updated.slice(0, 500);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
return () => {
|
|
173
|
-
unsubscribe();
|
|
174
|
-
};
|
|
175
|
-
}, [isListening, routeObserver]);
|
|
176
173
|
const handleToggleListening = (0, _react.useCallback)(() => {
|
|
177
|
-
|
|
174
|
+
// Toggle subscription - this actually subscribes/unsubscribes from the store
|
|
175
|
+
setIsListeningEnabled(prev => !prev);
|
|
178
176
|
}, []);
|
|
179
177
|
const handleClearEvents = (0, _react.useCallback)(() => {
|
|
180
178
|
if (events.length === 0) return;
|
|
@@ -184,15 +182,8 @@ function RouteEventsModalWithTabs({
|
|
|
184
182
|
setShowUpgradeModal(true);
|
|
185
183
|
return;
|
|
186
184
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
style: "cancel"
|
|
190
|
-
}, {
|
|
191
|
-
text: "Clear",
|
|
192
|
-
style: "destructive",
|
|
193
|
-
onPress: () => setEvents([])
|
|
194
|
-
}]);
|
|
195
|
-
}, [events.length, isPro]);
|
|
185
|
+
clearRouteEvents();
|
|
186
|
+
}, [events.length, isPro, clearRouteEvents]);
|
|
196
187
|
const handleTogglePattern = (0, _react.useCallback)(pattern => {
|
|
197
188
|
setIgnoredPatterns(prev => {
|
|
198
189
|
const next = new Set(prev);
|
|
@@ -425,16 +416,10 @@ function RouteEventsModalWithTabs({
|
|
|
425
416
|
size: 14,
|
|
426
417
|
color: ignoredPatterns.size > 0 ? _sharedUi.buoyColors.primary : _sharedUi.buoyColors.textSecondary
|
|
427
418
|
})
|
|
428
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
size: 14,
|
|
433
|
-
color: _sharedUi.buoyColors.success
|
|
434
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Play, {
|
|
435
|
-
size: 14,
|
|
436
|
-
color: _sharedUi.buoyColors.success
|
|
437
|
-
})
|
|
419
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
|
|
420
|
+
isEnabled: isListening,
|
|
421
|
+
onToggle: handleToggleListening,
|
|
422
|
+
accessibilityLabel: "Toggle route event monitoring"
|
|
438
423
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
439
424
|
onPress: handleClearEvents,
|
|
440
425
|
style: styles.iconButton,
|
|
@@ -467,9 +452,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
467
452
|
borderRadius: 6,
|
|
468
453
|
backgroundColor: _sharedUi.buoyColors.input
|
|
469
454
|
},
|
|
470
|
-
activeButton: {
|
|
471
|
-
backgroundColor: _sharedUi.buoyColors.success + "1A"
|
|
472
|
-
},
|
|
473
455
|
activeFilterButton: {
|
|
474
456
|
backgroundColor: _sharedUi.buoyColors.primary + "1A"
|
|
475
457
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useRouteEvents = useRouteEvents;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _routeEventStore = require("../stores/routeEventStore");
|
|
9
|
+
/**
|
|
10
|
+
* useRouteEvents Hook
|
|
11
|
+
*
|
|
12
|
+
* React hook for subscribing to route events from the centralized store.
|
|
13
|
+
* Uses self-managing Subscribable pattern - the store automatically
|
|
14
|
+
* subscribes to routeObserver when this hook mounts and unsubscribes
|
|
15
|
+
* when all subscribers unmount.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* function MyComponent() {
|
|
20
|
+
* const { events, clearEvents, isListening } = useRouteEvents();
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <View>
|
|
24
|
+
* {events.map((event) => (
|
|
25
|
+
* <Text key={event.timestamp.toString()}>
|
|
26
|
+
* {event.pathname}
|
|
27
|
+
* </Text>
|
|
28
|
+
* ))}
|
|
29
|
+
* </View>
|
|
30
|
+
* );
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
// Re-export RouteChangeEvent for convenience
|
|
36
|
+
|
|
37
|
+
function useRouteEvents(options = {}) {
|
|
38
|
+
const {
|
|
39
|
+
maxEvents = 500,
|
|
40
|
+
enabled = true
|
|
41
|
+
} = options;
|
|
42
|
+
const [events, setEvents] = (0, _react.useState)([]);
|
|
43
|
+
// Track listening state locally so it updates reactively with the subscription
|
|
44
|
+
const [isListening, setIsListening] = (0, _react.useState)(enabled);
|
|
45
|
+
|
|
46
|
+
// Subscribe to store - this automatically starts/stops listening
|
|
47
|
+
// based on subscriber count (Subscribable pattern from TanStack Query)
|
|
48
|
+
// Only subscribe when enabled is true
|
|
49
|
+
(0, _react.useEffect)(() => {
|
|
50
|
+
if (!enabled) {
|
|
51
|
+
setIsListening(false);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const unsubscribe = _routeEventStore.routeEventStore.subscribeToEvents(allEvents => {
|
|
55
|
+
// Limit events
|
|
56
|
+
if (allEvents.length > maxEvents) {
|
|
57
|
+
setEvents(allEvents.slice(0, maxEvents));
|
|
58
|
+
} else {
|
|
59
|
+
setEvents(allEvents);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Mark as listening after successful subscription
|
|
64
|
+
setIsListening(true);
|
|
65
|
+
return () => {
|
|
66
|
+
unsubscribe();
|
|
67
|
+
// Note: Don't set isListening=false here because we might be
|
|
68
|
+
// re-subscribing due to dependency change, not actually stopping
|
|
69
|
+
};
|
|
70
|
+
}, [maxEvents, enabled]);
|
|
71
|
+
const clearEvents = (0, _react.useCallback)(() => {
|
|
72
|
+
_routeEventStore.routeEventStore.clearEvents();
|
|
73
|
+
}, []);
|
|
74
|
+
return {
|
|
75
|
+
events,
|
|
76
|
+
clearEvents,
|
|
77
|
+
isListening
|
|
78
|
+
};
|
|
79
|
+
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -57,6 +57,12 @@ Object.defineProperty(exports, "createRouteEventsTool", {
|
|
|
57
57
|
return _preset.createRouteEventsTool;
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
+
Object.defineProperty(exports, "routeEventStore", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function () {
|
|
63
|
+
return _routeEventStore.routeEventStore;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
60
66
|
Object.defineProperty(exports, "routeEventsToolPreset", {
|
|
61
67
|
enumerable: true,
|
|
62
68
|
get: function () {
|
|
@@ -87,6 +93,12 @@ Object.defineProperty(exports, "useRoute", {
|
|
|
87
93
|
return _useRouteSitemap.useRoute;
|
|
88
94
|
}
|
|
89
95
|
});
|
|
96
|
+
Object.defineProperty(exports, "useRouteEvents", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
get: function () {
|
|
99
|
+
return _useRouteEvents.useRouteEvents;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
90
102
|
Object.defineProperty(exports, "useRouteObserver", {
|
|
91
103
|
enumerable: true,
|
|
92
104
|
get: function () {
|
|
@@ -107,7 +119,9 @@ var _NavigationStack = require("./components/NavigationStack");
|
|
|
107
119
|
var _RouteEventItemCompact = require("./components/RouteEventItemCompact");
|
|
108
120
|
var _RouteEventExpandedContent = require("./components/RouteEventExpandedContent");
|
|
109
121
|
var _useRouteObserver = require("./useRouteObserver");
|
|
122
|
+
var _useRouteEvents = require("./hooks/useRouteEvents");
|
|
110
123
|
var _useRouteSitemap = require("./useRouteSitemap");
|
|
111
124
|
var _useNavigationStack = require("./useNavigationStack");
|
|
112
125
|
var _RouteParser = require("./RouteParser");
|
|
113
|
-
var _RouteObserver = require("./RouteObserver");
|
|
126
|
+
var _RouteObserver = require("./RouteObserver");
|
|
127
|
+
var _routeEventStore = require("./stores/routeEventStore");
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.subscribeToRouteEvents = exports.routeEventStore = exports.onRouteEvent = exports.isRouteListening = exports.getRouteEvents = exports.clearRouteEvents = void 0;
|
|
7
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
8
|
+
var _RouteObserver = require("../RouteObserver");
|
|
9
|
+
/**
|
|
10
|
+
* Route Event Store
|
|
11
|
+
*
|
|
12
|
+
* Centralized store that aggregates route change events from the RouteObserver.
|
|
13
|
+
* Uses BaseEventStore pattern - the store automatically subscribes to routeObserver
|
|
14
|
+
* when the first subscriber joins and unsubscribes when the last subscriber leaves.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { routeEventStore } from '@buoy-gg/route-events';
|
|
19
|
+
*
|
|
20
|
+
* // Subscribe to route events - automatically starts listening!
|
|
21
|
+
* const unsubscribe = routeEventStore.subscribeToEvents((events) => {
|
|
22
|
+
* console.log('Route events:', events);
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Later, clean up - automatically stops if no other subscribers
|
|
26
|
+
* unsubscribe();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// Re-export types for convenience
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Listener callback type for route events array
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Listener callback for individual new events
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
class RouteEventStore extends _sharedUi.BaseEventStore {
|
|
41
|
+
// Unsubscribe function for routeObserver
|
|
42
|
+
routeObserverUnsubscribe = null;
|
|
43
|
+
constructor() {
|
|
44
|
+
super({
|
|
45
|
+
storeName: "route-events",
|
|
46
|
+
maxEvents: 500
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Start listening to route changes from routeObserver
|
|
52
|
+
*/
|
|
53
|
+
startCapturing() {
|
|
54
|
+
if (!this.routeObserverUnsubscribe) {
|
|
55
|
+
this.routeObserverUnsubscribe = _RouteObserver.routeObserver.addListener(event => {
|
|
56
|
+
this.addEvent(event);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Stop listening to route changes
|
|
63
|
+
*/
|
|
64
|
+
stopCapturing() {
|
|
65
|
+
if (this.routeObserverUnsubscribe) {
|
|
66
|
+
this.routeObserverUnsubscribe();
|
|
67
|
+
this.routeObserverUnsubscribe = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if currently listening (has subscribers)
|
|
73
|
+
*/
|
|
74
|
+
isCapturing() {
|
|
75
|
+
return this.routeObserverUnsubscribe !== null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Alias for backwards compatibility
|
|
79
|
+
isListening() {
|
|
80
|
+
return this.isCapturing();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Singleton instance
|
|
85
|
+
const routeEventStore = exports.routeEventStore = new RouteEventStore();
|
|
86
|
+
|
|
87
|
+
// Convenience exports
|
|
88
|
+
const subscribeToRouteEvents = listener => routeEventStore.subscribeToEvents(listener);
|
|
89
|
+
exports.subscribeToRouteEvents = subscribeToRouteEvents;
|
|
90
|
+
const onRouteEvent = callback => routeEventStore.onEvent(callback);
|
|
91
|
+
exports.onRouteEvent = onRouteEvent;
|
|
92
|
+
const getRouteEvents = () => routeEventStore.getEvents();
|
|
93
|
+
exports.getRouteEvents = getRouteEvents;
|
|
94
|
+
const clearRouteEvents = () => routeEventStore.clearEvents();
|
|
95
|
+
exports.clearRouteEvents = clearRouteEvents;
|
|
96
|
+
const isRouteListening = () => routeEventStore.isListening();
|
|
97
|
+
exports.isRouteListening = isRouteListening;
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
import { useState, useCallback, useEffect, useRef, useMemo } from "react";
|
|
4
4
|
import { Text, View, TouchableOpacity, StyleSheet, Alert } from "react-native";
|
|
5
5
|
import { useRouter } from "expo-router";
|
|
6
|
-
import { JsModal, ModalHeader, TabSelector, formatRelativeTime, devToolsStorageKeys, Navigation,
|
|
6
|
+
import { JsModal, ModalHeader, TabSelector, formatRelativeTime, devToolsStorageKeys, Navigation, Trash2, Filter, SearchBar, persistentStorage, ToolbarCopyButton, Lock, ProUpgradeModal, PowerToggleButton, buoyColors } from "@buoy-gg/shared-ui";
|
|
7
7
|
import { useIsPro } from "@buoy-gg/license";
|
|
8
8
|
|
|
9
9
|
// Free tier limit for route events
|
|
10
10
|
const FREE_TIER_EVENT_LIMIT = 3;
|
|
11
|
-
import {
|
|
11
|
+
import { useRouteEvents } from "../hooks/useRouteEvents";
|
|
12
12
|
import { RouteFilterViewV2 } from "./RouteFilterViewV2";
|
|
13
13
|
import { RoutesSitemap } from "./RoutesSitemap";
|
|
14
14
|
import { NavigationStack } from "./NavigationStack";
|
|
@@ -19,8 +19,7 @@ export function RouteEventsModalWithTabs({
|
|
|
19
19
|
onClose,
|
|
20
20
|
onBack,
|
|
21
21
|
onMinimize,
|
|
22
|
-
enableSharedModalDimensions = false
|
|
23
|
-
routeObserver = defaultRouteObserver
|
|
22
|
+
enableSharedModalDimensions = false
|
|
24
23
|
}) {
|
|
25
24
|
const router = useRouter();
|
|
26
25
|
const [activeTab, setActiveTab] = useState("events");
|
|
@@ -40,9 +39,21 @@ export function RouteEventsModalWithTabs({
|
|
|
40
39
|
// The useRouteObserver hook uses expo-router hooks that only work inside Stack/Tabs/Slot.
|
|
41
40
|
// See the RouteTracker component export for easy setup.
|
|
42
41
|
|
|
43
|
-
//
|
|
44
|
-
const [
|
|
45
|
-
|
|
42
|
+
// Local state to control subscription (true = subscribed, false = unsubscribed)
|
|
43
|
+
const [isListeningEnabled, setIsListeningEnabled] = useState(true);
|
|
44
|
+
|
|
45
|
+
// Event Listener state - using centralized store via hook
|
|
46
|
+
// Pass enabled option to control subscription
|
|
47
|
+
const {
|
|
48
|
+
events,
|
|
49
|
+
clearEvents: clearRouteEvents,
|
|
50
|
+
isListening: isStoreListening
|
|
51
|
+
} = useRouteEvents({
|
|
52
|
+
enabled: isListeningEnabled
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// isListening = enabled and store is listening
|
|
56
|
+
const isListening = isListeningEnabled && isStoreListening;
|
|
46
57
|
const [showFilters, setShowFilters] = useState(false);
|
|
47
58
|
const [searchQuery, setSearchQuery] = useState("");
|
|
48
59
|
const [ignoredPatterns, setIgnoredPatterns] = useState(new Set(["/_sitemap", "/api", "/__dev"]));
|
|
@@ -86,7 +97,7 @@ export function RouteEventsModalWithTabs({
|
|
|
86
97
|
const storedMonitoring = await persistentStorage.getItem(devToolsStorageKeys.routeEvents.isMonitoring());
|
|
87
98
|
if (storedMonitoring !== null) {
|
|
88
99
|
const shouldMonitor = storedMonitoring === "true";
|
|
89
|
-
|
|
100
|
+
setIsListeningEnabled(shouldMonitor);
|
|
90
101
|
}
|
|
91
102
|
hasLoadedMonitoringState.current = true;
|
|
92
103
|
} catch (error) {
|
|
@@ -154,24 +165,11 @@ export function RouteEventsModalWithTabs({
|
|
|
154
165
|
saveFilters();
|
|
155
166
|
}, [ignoredPatterns]);
|
|
156
167
|
|
|
157
|
-
// Event listener
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
if (!isListening) return;
|
|
168
|
+
// Event listener is now managed by useRouteEvents hook
|
|
160
169
|
|
|
161
|
-
// Set up event listener
|
|
162
|
-
const unsubscribe = routeObserver.addListener(event => {
|
|
163
|
-
lastEventRef.current = event;
|
|
164
|
-
setEvents(prev => {
|
|
165
|
-
const updated = [event, ...prev];
|
|
166
|
-
return updated.slice(0, 500);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
return () => {
|
|
170
|
-
unsubscribe();
|
|
171
|
-
};
|
|
172
|
-
}, [isListening, routeObserver]);
|
|
173
170
|
const handleToggleListening = useCallback(() => {
|
|
174
|
-
|
|
171
|
+
// Toggle subscription - this actually subscribes/unsubscribes from the store
|
|
172
|
+
setIsListeningEnabled(prev => !prev);
|
|
175
173
|
}, []);
|
|
176
174
|
const handleClearEvents = useCallback(() => {
|
|
177
175
|
if (events.length === 0) return;
|
|
@@ -181,15 +179,8 @@ export function RouteEventsModalWithTabs({
|
|
|
181
179
|
setShowUpgradeModal(true);
|
|
182
180
|
return;
|
|
183
181
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
style: "cancel"
|
|
187
|
-
}, {
|
|
188
|
-
text: "Clear",
|
|
189
|
-
style: "destructive",
|
|
190
|
-
onPress: () => setEvents([])
|
|
191
|
-
}]);
|
|
192
|
-
}, [events.length, isPro]);
|
|
182
|
+
clearRouteEvents();
|
|
183
|
+
}, [events.length, isPro, clearRouteEvents]);
|
|
193
184
|
const handleTogglePattern = useCallback(pattern => {
|
|
194
185
|
setIgnoredPatterns(prev => {
|
|
195
186
|
const next = new Set(prev);
|
|
@@ -422,16 +413,10 @@ export function RouteEventsModalWithTabs({
|
|
|
422
413
|
size: 14,
|
|
423
414
|
color: ignoredPatterns.size > 0 ? buoyColors.primary : buoyColors.textSecondary
|
|
424
415
|
})
|
|
425
|
-
}), /*#__PURE__*/_jsx(
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
size: 14,
|
|
430
|
-
color: buoyColors.success
|
|
431
|
-
}) : /*#__PURE__*/_jsx(Play, {
|
|
432
|
-
size: 14,
|
|
433
|
-
color: buoyColors.success
|
|
434
|
-
})
|
|
416
|
+
}), /*#__PURE__*/_jsx(PowerToggleButton, {
|
|
417
|
+
isEnabled: isListening,
|
|
418
|
+
onToggle: handleToggleListening,
|
|
419
|
+
accessibilityLabel: "Toggle route event monitoring"
|
|
435
420
|
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
436
421
|
onPress: handleClearEvents,
|
|
437
422
|
style: styles.iconButton,
|
|
@@ -464,9 +449,6 @@ const styles = StyleSheet.create({
|
|
|
464
449
|
borderRadius: 6,
|
|
465
450
|
backgroundColor: buoyColors.input
|
|
466
451
|
},
|
|
467
|
-
activeButton: {
|
|
468
|
-
backgroundColor: buoyColors.success + "1A"
|
|
469
|
-
},
|
|
470
452
|
activeFilterButton: {
|
|
471
453
|
backgroundColor: buoyColors.primary + "1A"
|
|
472
454
|
},
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useRouteEvents Hook
|
|
5
|
+
*
|
|
6
|
+
* React hook for subscribing to route events from the centralized store.
|
|
7
|
+
* Uses self-managing Subscribable pattern - the store automatically
|
|
8
|
+
* subscribes to routeObserver when this hook mounts and unsubscribes
|
|
9
|
+
* when all subscribers unmount.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* function MyComponent() {
|
|
14
|
+
* const { events, clearEvents, isListening } = useRouteEvents();
|
|
15
|
+
*
|
|
16
|
+
* return (
|
|
17
|
+
* <View>
|
|
18
|
+
* {events.map((event) => (
|
|
19
|
+
* <Text key={event.timestamp.toString()}>
|
|
20
|
+
* {event.pathname}
|
|
21
|
+
* </Text>
|
|
22
|
+
* ))}
|
|
23
|
+
* </View>
|
|
24
|
+
* );
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { useState, useEffect, useCallback } from "react";
|
|
30
|
+
import { routeEventStore } from "../stores/routeEventStore";
|
|
31
|
+
|
|
32
|
+
// Re-export RouteChangeEvent for convenience
|
|
33
|
+
|
|
34
|
+
export function useRouteEvents(options = {}) {
|
|
35
|
+
const {
|
|
36
|
+
maxEvents = 500,
|
|
37
|
+
enabled = true
|
|
38
|
+
} = options;
|
|
39
|
+
const [events, setEvents] = useState([]);
|
|
40
|
+
// Track listening state locally so it updates reactively with the subscription
|
|
41
|
+
const [isListening, setIsListening] = useState(enabled);
|
|
42
|
+
|
|
43
|
+
// Subscribe to store - this automatically starts/stops listening
|
|
44
|
+
// based on subscriber count (Subscribable pattern from TanStack Query)
|
|
45
|
+
// Only subscribe when enabled is true
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!enabled) {
|
|
48
|
+
setIsListening(false);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const unsubscribe = routeEventStore.subscribeToEvents(allEvents => {
|
|
52
|
+
// Limit events
|
|
53
|
+
if (allEvents.length > maxEvents) {
|
|
54
|
+
setEvents(allEvents.slice(0, maxEvents));
|
|
55
|
+
} else {
|
|
56
|
+
setEvents(allEvents);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Mark as listening after successful subscription
|
|
61
|
+
setIsListening(true);
|
|
62
|
+
return () => {
|
|
63
|
+
unsubscribe();
|
|
64
|
+
// Note: Don't set isListening=false here because we might be
|
|
65
|
+
// re-subscribing due to dependency change, not actually stopping
|
|
66
|
+
};
|
|
67
|
+
}, [maxEvents, enabled]);
|
|
68
|
+
const clearEvents = useCallback(() => {
|
|
69
|
+
routeEventStore.clearEvents();
|
|
70
|
+
}, []);
|
|
71
|
+
return {
|
|
72
|
+
events,
|
|
73
|
+
clearEvents,
|
|
74
|
+
isListening
|
|
75
|
+
};
|
|
76
|
+
}
|
package/lib/module/index.js
CHANGED
|
@@ -34,6 +34,7 @@ export { RouteEventExpandedContent } from "./components/RouteEventExpandedConten
|
|
|
34
34
|
// HOOKS (For consuming route data)
|
|
35
35
|
// =============================================================================
|
|
36
36
|
export { useRouteObserver } from "./useRouteObserver";
|
|
37
|
+
export { useRouteEvents } from "./hooks/useRouteEvents";
|
|
37
38
|
export { useRouteSitemap, useRoute, useParentRoutes } from "./useRouteSitemap";
|
|
38
39
|
export { useNavigationStack } from "./useNavigationStack";
|
|
39
40
|
|
|
@@ -51,4 +52,6 @@ export { RouteObserver } from "./RouteObserver";
|
|
|
51
52
|
// INTERNAL EXPORTS (For @buoy-gg/* packages only - not part of public API)
|
|
52
53
|
// =============================================================================
|
|
53
54
|
/** @internal - Singleton instance for cross-package communication */
|
|
54
|
-
export { routeObserver } from "./RouteObserver";
|
|
55
|
+
export { routeObserver } from "./RouteObserver";
|
|
56
|
+
/** @internal - Event store for centralized route event management */
|
|
57
|
+
export { routeEventStore } from "./stores/routeEventStore";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Route Event Store
|
|
5
|
+
*
|
|
6
|
+
* Centralized store that aggregates route change events from the RouteObserver.
|
|
7
|
+
* Uses BaseEventStore pattern - the store automatically subscribes to routeObserver
|
|
8
|
+
* when the first subscriber joins and unsubscribes when the last subscriber leaves.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { routeEventStore } from '@buoy-gg/route-events';
|
|
13
|
+
*
|
|
14
|
+
* // Subscribe to route events - automatically starts listening!
|
|
15
|
+
* const unsubscribe = routeEventStore.subscribeToEvents((events) => {
|
|
16
|
+
* console.log('Route events:', events);
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Later, clean up - automatically stops if no other subscribers
|
|
20
|
+
* unsubscribe();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { BaseEventStore } from "@buoy-gg/shared-ui";
|
|
25
|
+
import { routeObserver } from "../RouteObserver";
|
|
26
|
+
|
|
27
|
+
// Re-export types for convenience
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Listener callback type for route events array
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Listener callback for individual new events
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
class RouteEventStore extends BaseEventStore {
|
|
38
|
+
// Unsubscribe function for routeObserver
|
|
39
|
+
routeObserverUnsubscribe = null;
|
|
40
|
+
constructor() {
|
|
41
|
+
super({
|
|
42
|
+
storeName: "route-events",
|
|
43
|
+
maxEvents: 500
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Start listening to route changes from routeObserver
|
|
49
|
+
*/
|
|
50
|
+
startCapturing() {
|
|
51
|
+
if (!this.routeObserverUnsubscribe) {
|
|
52
|
+
this.routeObserverUnsubscribe = routeObserver.addListener(event => {
|
|
53
|
+
this.addEvent(event);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Stop listening to route changes
|
|
60
|
+
*/
|
|
61
|
+
stopCapturing() {
|
|
62
|
+
if (this.routeObserverUnsubscribe) {
|
|
63
|
+
this.routeObserverUnsubscribe();
|
|
64
|
+
this.routeObserverUnsubscribe = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if currently listening (has subscribers)
|
|
70
|
+
*/
|
|
71
|
+
isCapturing() {
|
|
72
|
+
return this.routeObserverUnsubscribe !== null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Alias for backwards compatibility
|
|
76
|
+
isListening() {
|
|
77
|
+
return this.isCapturing();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Singleton instance
|
|
82
|
+
export const routeEventStore = new RouteEventStore();
|
|
83
|
+
|
|
84
|
+
// Convenience exports
|
|
85
|
+
export const subscribeToRouteEvents = listener => routeEventStore.subscribeToEvents(listener);
|
|
86
|
+
export const onRouteEvent = callback => routeEventStore.onEvent(callback);
|
|
87
|
+
export const getRouteEvents = () => routeEventStore.getEvents();
|
|
88
|
+
export const clearRouteEvents = () => routeEventStore.clearEvents();
|
|
89
|
+
export const isRouteListening = () => routeEventStore.isListening();
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import { routeObserver as defaultRouteObserver } from "../RouteObserver";
|
|
2
1
|
export interface RouteEventsModalWithTabsProps {
|
|
3
2
|
visible: boolean;
|
|
4
3
|
onClose: () => void;
|
|
5
4
|
onBack?: () => void;
|
|
6
5
|
onMinimize?: (modalState: any) => void;
|
|
7
6
|
enableSharedModalDimensions?: boolean;
|
|
8
|
-
/**
|
|
9
|
-
* Optional route observer instance. If not provided, uses the default singleton.
|
|
10
|
-
* Route tracking will start automatically when the modal is opened.
|
|
11
|
-
*/
|
|
12
|
-
routeObserver?: typeof defaultRouteObserver;
|
|
13
7
|
}
|
|
14
|
-
export declare function RouteEventsModalWithTabs({ visible, onClose, onBack, onMinimize, enableSharedModalDimensions,
|
|
8
|
+
export declare function RouteEventsModalWithTabs({ visible, onClose, onBack, onMinimize, enableSharedModalDimensions, }: RouteEventsModalWithTabsProps): import("react").JSX.Element | null;
|
|
15
9
|
//# sourceMappingURL=RouteEventsModalWithTabs.d.ts.map
|
|
@@ -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":"AA8CA,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;CACvC;AAID,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,GACpC,EAAE,6BAA6B,sCAigB/B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useRouteEvents Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for subscribing to route events from the centralized store.
|
|
5
|
+
* Uses self-managing Subscribable pattern - the store automatically
|
|
6
|
+
* subscribes to routeObserver when this hook mounts and unsubscribes
|
|
7
|
+
* when all subscribers unmount.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* function MyComponent() {
|
|
12
|
+
* const { events, clearEvents, isListening } = useRouteEvents();
|
|
13
|
+
*
|
|
14
|
+
* return (
|
|
15
|
+
* <View>
|
|
16
|
+
* {events.map((event) => (
|
|
17
|
+
* <Text key={event.timestamp.toString()}>
|
|
18
|
+
* {event.pathname}
|
|
19
|
+
* </Text>
|
|
20
|
+
* ))}
|
|
21
|
+
* </View>
|
|
22
|
+
* );
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { type RouteChangeEvent } from "../stores/routeEventStore";
|
|
27
|
+
export type { RouteChangeEvent } from "../stores/routeEventStore";
|
|
28
|
+
export interface UseRouteEventsOptions {
|
|
29
|
+
/** Maximum number of events to keep in state */
|
|
30
|
+
maxEvents?: number;
|
|
31
|
+
/** Whether to subscribe to events (default: true). Set to false to unsubscribe. */
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface UseRouteEventsResult {
|
|
35
|
+
/** All route events (newest first) */
|
|
36
|
+
events: RouteChangeEvent[];
|
|
37
|
+
/** Clear all events */
|
|
38
|
+
clearEvents: () => void;
|
|
39
|
+
/** Whether events are being listened to (has subscribers) */
|
|
40
|
+
isListening: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare function useRouteEvents(options?: UseRouteEventsOptions): UseRouteEventsResult;
|
|
43
|
+
//# sourceMappingURL=useRouteEvents.d.ts.map
|
|
@@ -0,0 +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,CA4CtB"}
|
|
@@ -19,6 +19,8 @@ export type { RouteEventItemCompactProps } from "./components/RouteEventItemComp
|
|
|
19
19
|
export { RouteEventExpandedContent } from "./components/RouteEventExpandedContent";
|
|
20
20
|
export type { RouteEventExpandedContentProps } from "./components/RouteEventExpandedContent";
|
|
21
21
|
export { useRouteObserver } from "./useRouteObserver";
|
|
22
|
+
export { useRouteEvents } from "./hooks/useRouteEvents";
|
|
23
|
+
export type { UseRouteEventsOptions, UseRouteEventsResult, } from "./hooks/useRouteEvents";
|
|
22
24
|
export { useRouteSitemap, useRoute, useParentRoutes } from "./useRouteSitemap";
|
|
23
25
|
export type { UseRouteSitemapOptions, UseRouteSitemapResult, } from "./useRouteSitemap";
|
|
24
26
|
export { useNavigationStack } from "./useNavigationStack";
|
|
@@ -29,4 +31,7 @@ export { RouteParser } from "./RouteParser";
|
|
|
29
31
|
export { RouteObserver } from "./RouteObserver";
|
|
30
32
|
/** @internal - Singleton instance for cross-package communication */
|
|
31
33
|
export { routeObserver } from "./RouteObserver";
|
|
34
|
+
/** @internal - Event store for centralized route event management */
|
|
35
|
+
export { routeEventStore } from "./stores/routeEventStore";
|
|
36
|
+
export type { RouteEventListener, RouteEventCallback, } from "./stores/routeEventStore";
|
|
32
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAKxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,YAAY,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AAK3F,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,YAAY,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AAK7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/E,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAK9B,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,eAAe,CAAC;AAKvB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKhD,qEAAqE;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAKxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,YAAY,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AAK3F,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,YAAY,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AAK7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EACV,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/E,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EACV,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAK9B,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,eAAe,CAAC;AAKvB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKhD,qEAAqE;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,qEAAqE;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,YAAY,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Event Store
|
|
3
|
+
*
|
|
4
|
+
* Centralized store that aggregates route change events from the RouteObserver.
|
|
5
|
+
* Uses BaseEventStore pattern - the store automatically subscribes to routeObserver
|
|
6
|
+
* when the first subscriber joins and unsubscribes when the last subscriber leaves.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { routeEventStore } from '@buoy-gg/route-events';
|
|
11
|
+
*
|
|
12
|
+
* // Subscribe to route events - automatically starts listening!
|
|
13
|
+
* const unsubscribe = routeEventStore.subscribeToEvents((events) => {
|
|
14
|
+
* console.log('Route events:', events);
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Later, clean up - automatically stops if no other subscribers
|
|
18
|
+
* unsubscribe();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import { BaseEventStore } from "@buoy-gg/shared-ui";
|
|
22
|
+
import { type RouteChangeEvent } from "../RouteObserver";
|
|
23
|
+
export type { RouteChangeEvent } from "../RouteObserver";
|
|
24
|
+
/**
|
|
25
|
+
* Listener callback type for route events array
|
|
26
|
+
*/
|
|
27
|
+
export type RouteEventListener = (events: RouteChangeEvent[]) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Listener callback for individual new events
|
|
30
|
+
*/
|
|
31
|
+
export type RouteEventCallback = (event: RouteChangeEvent) => void;
|
|
32
|
+
declare class RouteEventStore extends BaseEventStore<RouteChangeEvent> {
|
|
33
|
+
private routeObserverUnsubscribe;
|
|
34
|
+
constructor();
|
|
35
|
+
/**
|
|
36
|
+
* Start listening to route changes from routeObserver
|
|
37
|
+
*/
|
|
38
|
+
protected startCapturing(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Stop listening to route changes
|
|
41
|
+
*/
|
|
42
|
+
protected stopCapturing(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Check if currently listening (has subscribers)
|
|
45
|
+
*/
|
|
46
|
+
isCapturing(): boolean;
|
|
47
|
+
isListening(): boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare const routeEventStore: RouteEventStore;
|
|
50
|
+
export declare const subscribeToRouteEvents: (listener: RouteEventListener) => () => void;
|
|
51
|
+
export declare const onRouteEvent: (callback: RouteEventCallback) => () => void;
|
|
52
|
+
export declare const getRouteEvents: () => RouteChangeEvent[];
|
|
53
|
+
export declare const clearRouteEvents: () => void;
|
|
54
|
+
export declare const isRouteListening: () => boolean;
|
|
55
|
+
//# sourceMappingURL=routeEventStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeEventStore.d.ts","sourceRoot":"","sources":["../../../src/stores/routeEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEnE,cAAM,eAAgB,SAAQ,cAAc,CAAC,gBAAgB,CAAC;IAE5D,OAAO,CAAC,wBAAwB,CAA6B;;IAS7D;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAQhC;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAO/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAKtB,WAAW,IAAI,OAAO;CAGvB;AAGD,eAAO,MAAM,eAAe,iBAAwB,CAAC;AAGrD,eAAO,MAAM,sBAAsB,GAAI,UAAU,kBAAkB,eACtB,CAAC;AAC9C,eAAO,MAAM,YAAY,GAAI,UAAU,kBAAkB,eACtB,CAAC;AACpC,eAAO,MAAM,cAAc,0BAAoC,CAAC;AAChE,eAAO,MAAM,gBAAgB,YAAsC,CAAC;AACpE,eAAO,MAAM,gBAAgB,eAAsC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/route-events",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "route-events package",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
],
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@buoy-gg/floating-tools-core": "2.1.
|
|
30
|
-
"@buoy-gg/shared-ui": "2.1.
|
|
29
|
+
"@buoy-gg/floating-tools-core": "2.1.3",
|
|
30
|
+
"@buoy-gg/shared-ui": "2.1.3"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@buoy-gg/license": "*",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@types/react-native": "^0.73.0",
|
|
50
50
|
"expo-router": "~5.0.7",
|
|
51
51
|
"typescript": "~5.8.3",
|
|
52
|
-
"@buoy-gg/license": "2.1.
|
|
52
|
+
"@buoy-gg/license": "2.1.3"
|
|
53
53
|
},
|
|
54
54
|
"react-native-builder-bob": {
|
|
55
55
|
"source": "src",
|