@buoy-gg/route-events 7.0.41 → 7.0.43
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/README.md +11 -64
- package/lib/commonjs/RouteObserver.js +1 -54
- package/lib/commonjs/RouteParser.js +1 -314
- package/lib/commonjs/RouteTracker.js +1 -112
- package/lib/commonjs/RouteTracker.web.js +1 -12
- package/lib/commonjs/browserRouteRegistry.js +1 -30
- package/lib/commonjs/browserRoutes.js +1 -96
- package/lib/commonjs/components/NavigationStack.js +2 -572
- package/lib/commonjs/components/ReactNavigationRoutes.js +1 -836
- package/lib/commonjs/components/ReactNavigationRoutes.web.js +1 -12
- package/lib/commonjs/components/RouteEventDetail.js +1 -97
- package/lib/commonjs/components/RouteEventExpandedContent.js +1 -204
- package/lib/commonjs/components/RouteEventItemCompact.js +1 -191
- package/lib/commonjs/components/RouteEventsModalWithTabs.js +1 -734
- package/lib/commonjs/components/RouteEventsTimeline.js +1 -107
- package/lib/commonjs/components/RouteFilterViewV2.js +1 -42
- package/lib/commonjs/components/RoutesSitemap.js +2 -1035
- package/lib/commonjs/expoRouterStore.js +1 -121
- package/lib/commonjs/expoRouterStore.web.js +1 -44
- package/lib/commonjs/hooks/useRouteEvents.js +1 -57
- package/lib/commonjs/index.js +1 -168
- package/lib/commonjs/preset.js +1 -69
- package/lib/commonjs/stores/navigationStackStore.js +1 -45
- package/lib/commonjs/stores/routeEventStore.js +1 -136
- package/lib/commonjs/sync/routeEventsSyncAdapter.js +1 -275
- package/lib/commonjs/useNavigationStack.js +1 -408
- package/lib/commonjs/useNavigationStack.web.js +1 -32
- package/lib/commonjs/useRouteObserver.js +1 -73
- package/lib/commonjs/useRouteObserverReactNavigation.js +1 -109
- package/lib/commonjs/useRouteSitemap.js +1 -255
- package/lib/commonjs/utils/routeTemplate.js +1 -79
- package/lib/commonjs/utils/safeReactNavigation.js +1 -194
- package/lib/commonjs/utils/safeReactNavigation.web.js +1 -36
- package/lib/commonjs/utils/testIDs.js +1 -63
- package/lib/module/RouteObserver.js +1 -49
- package/lib/module/RouteParser.js +1 -309
- package/lib/module/RouteTracker.js +1 -109
- package/lib/module/RouteTracker.web.js +1 -8
- package/lib/module/browserRouteRegistry.js +1 -24
- package/lib/module/browserRoutes.js +1 -92
- package/lib/module/components/NavigationStack.js +2 -568
- package/lib/module/components/ReactNavigationRoutes.js +1 -832
- package/lib/module/components/ReactNavigationRoutes.web.js +1 -3
- package/lib/module/components/RouteEventDetail.js +1 -93
- package/lib/module/components/RouteEventExpandedContent.js +1 -200
- package/lib/module/components/RouteEventItemCompact.js +1 -187
- package/lib/module/components/RouteEventsModalWithTabs.js +1 -731
- package/lib/module/components/RouteEventsTimeline.js +1 -103
- package/lib/module/components/RouteFilterViewV2.js +1 -38
- package/lib/module/components/RoutesSitemap.js +2 -1033
- package/lib/module/expoRouterStore.js +1 -114
- package/lib/module/expoRouterStore.web.js +1 -37
- package/lib/module/hooks/useRouteEvents.js +1 -54
- package/lib/module/index.js +1 -70
- package/lib/module/preset.js +1 -66
- package/lib/module/stores/navigationStackStore.js +1 -41
- package/lib/module/stores/routeEventStore.js +1 -128
- package/lib/module/sync/routeEventsSyncAdapter.js +1 -273
- package/lib/module/useNavigationStack.js +1 -404
- package/lib/module/useNavigationStack.web.js +1 -28
- package/lib/module/useRouteObserver.js +1 -70
- package/lib/module/useRouteObserverReactNavigation.js +1 -106
- package/lib/module/useRouteSitemap.js +1 -250
- package/lib/module/utils/routeTemplate.js +1 -73
- package/lib/module/utils/safeReactNavigation.js +1 -185
- package/lib/module/utils/safeReactNavigation.web.js +1 -27
- package/lib/module/utils/testIDs.js +1 -55
- package/lib/web/index.mjs +4 -5
- package/package.json +6 -11
- package/lib/typescript/RouteObserver.d.ts.map +0 -1
- package/lib/typescript/RouteParser.d.ts.map +0 -1
- package/lib/typescript/RouteTracker.d.ts.map +0 -1
- package/lib/typescript/RouteTracker.web.d.ts.map +0 -1
- package/lib/typescript/browserRouteRegistry.d.ts.map +0 -1
- package/lib/typescript/browserRoutes.d.ts.map +0 -1
- package/lib/typescript/components/NavigationStack.d.ts.map +0 -1
- package/lib/typescript/components/ReactNavigationRoutes.d.ts.map +0 -1
- package/lib/typescript/components/ReactNavigationRoutes.web.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventDetail.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventExpandedContent.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventItemCompact.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventsTimeline.d.ts.map +0 -1
- package/lib/typescript/components/RouteFilterViewV2.d.ts.map +0 -1
- package/lib/typescript/components/RoutesSitemap.d.ts.map +0 -1
- package/lib/typescript/expoRouterStore.d.ts.map +0 -1
- package/lib/typescript/expoRouterStore.web.d.ts.map +0 -1
- package/lib/typescript/hooks/useRouteEvents.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/stores/navigationStackStore.d.ts.map +0 -1
- package/lib/typescript/stores/routeEventStore.d.ts.map +0 -1
- package/lib/typescript/sync/routeEventsSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/useNavigationStack.d.ts.map +0 -1
- package/lib/typescript/useNavigationStack.web.d.ts.map +0 -1
- package/lib/typescript/useRouteObserver.d.ts.map +0 -1
- package/lib/typescript/useRouteObserverReactNavigation.d.ts.map +0 -1
- package/lib/typescript/useRouteSitemap.d.ts.map +0 -1
- package/lib/typescript/utils/routeTemplate.d.ts.map +0 -1
- package/lib/typescript/utils/safeReactNavigation.d.ts.map +0 -1
- package/lib/typescript/utils/safeReactNavigation.web.d.ts.map +0 -1
- package/lib/typescript/utils/testIDs.d.ts.map +0 -1
|
@@ -1,93 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* RouteEventDetail - Full-screen detail view for a single route event.
|
|
5
|
-
*
|
|
6
|
-
* Mirrors how the Events tool shows a detail page for every other event
|
|
7
|
-
* source: the readable route sections (reusing RouteEventExpandedContent)
|
|
8
|
-
* plus a prominent "Go to route" action. The back header and toolbar copy
|
|
9
|
-
* button are owned by the surrounding modal.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from "react-native";
|
|
13
|
-
import { Navigation, night, monoFont } from "@buoy-gg/shared-ui";
|
|
14
|
-
import { RouteEventExpandedContent } from "./RouteEventExpandedContent";
|
|
15
|
-
import { getRouteTemplate, routeHref } from "../utils/routeTemplate";
|
|
16
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
|
-
export function RouteEventDetail({
|
|
18
|
-
event,
|
|
19
|
-
visitNumber = 1,
|
|
20
|
-
onNavigate
|
|
21
|
-
}) {
|
|
22
|
-
const routeTemplate = getRouteTemplate(event.pathname, event.segments);
|
|
23
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
24
|
-
style: styles.container,
|
|
25
|
-
children: [/*#__PURE__*/_jsx(ScrollView, {
|
|
26
|
-
testID: "buoy-routes-detail-scroll",
|
|
27
|
-
style: styles.scroll,
|
|
28
|
-
contentContainerStyle: styles.scrollContent,
|
|
29
|
-
showsVerticalScrollIndicator: true,
|
|
30
|
-
children: /*#__PURE__*/_jsx(RouteEventExpandedContent, {
|
|
31
|
-
event: event,
|
|
32
|
-
visitNumber: visitNumber,
|
|
33
|
-
routeTemplate: routeTemplate
|
|
34
|
-
})
|
|
35
|
-
}), onNavigate && /*#__PURE__*/_jsx(View, {
|
|
36
|
-
style: styles.footer,
|
|
37
|
-
children: /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
38
|
-
style: styles.goButton,
|
|
39
|
-
onPress: () => onNavigate(routeHref(event.pathname, event.params)),
|
|
40
|
-
activeOpacity: 0.8,
|
|
41
|
-
testID: "buoy-routes-detail-go",
|
|
42
|
-
accessibilityRole: "button",
|
|
43
|
-
accessibilityLabel: `Go to route ${event.pathname}`,
|
|
44
|
-
children: [/*#__PURE__*/_jsx(Navigation, {
|
|
45
|
-
size: 16,
|
|
46
|
-
color: night.color.onAccent
|
|
47
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
48
|
-
style: styles.goButtonText,
|
|
49
|
-
children: "Go to route"
|
|
50
|
-
})]
|
|
51
|
-
})
|
|
52
|
-
})]
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
const styles = StyleSheet.create({
|
|
56
|
-
container: {
|
|
57
|
-
flex: 1,
|
|
58
|
-
// Transparent so the night sheet's star field shows through.
|
|
59
|
-
backgroundColor: "transparent"
|
|
60
|
-
},
|
|
61
|
-
scroll: {
|
|
62
|
-
flex: 1
|
|
63
|
-
},
|
|
64
|
-
scrollContent: {
|
|
65
|
-
padding: 14
|
|
66
|
-
},
|
|
67
|
-
footer: {
|
|
68
|
-
paddingHorizontal: 16,
|
|
69
|
-
paddingVertical: 12,
|
|
70
|
-
// Transparent so the night sheet's star field shows through.
|
|
71
|
-
backgroundColor: "transparent",
|
|
72
|
-
borderTopWidth: 1,
|
|
73
|
-
borderTopColor: night.color.border
|
|
74
|
-
},
|
|
75
|
-
goButton: {
|
|
76
|
-
flexDirection: "row",
|
|
77
|
-
alignItems: "center",
|
|
78
|
-
justifyContent: "center",
|
|
79
|
-
gap: 8,
|
|
80
|
-
backgroundColor: night.color.accent,
|
|
81
|
-
paddingVertical: 12,
|
|
82
|
-
borderRadius: 8
|
|
83
|
-
},
|
|
84
|
-
goButtonText: {
|
|
85
|
-
fontSize: 13,
|
|
86
|
-
fontWeight: "600",
|
|
87
|
-
// Ink on a filled accent surface — the night accent takes dark ink.
|
|
88
|
-
color: night.color.onAccent,
|
|
89
|
-
fontFamily: monoFont,
|
|
90
|
-
textTransform: "uppercase",
|
|
91
|
-
letterSpacing: 0.5
|
|
92
|
-
}
|
|
93
|
-
});
|
|
1
|
+
"use strict";import{View as l,Text as s,StyleSheet as u,TouchableOpacity as p,ScrollView as d}from"react-native";import{Navigation as m,night as r,monoFont as g}from"@buoy-gg/shared-ui";import{RouteEventExpandedContent as f}from"./RouteEventExpandedContent";import{getRouteTemplate as y,routeHref as b}from"../utils/routeTemplate";import{jsx as e,jsxs as i}from"react/jsx-runtime";export function RouteEventDetail({event:t,visitNumber:a=1,onNavigate:n}){const c=y(t.pathname,t.segments);return i(l,{style:o.container,children:[e(d,{testID:"buoy-routes-detail-scroll",style:o.scroll,contentContainerStyle:o.scrollContent,showsVerticalScrollIndicator:true,children:e(f,{event:t,visitNumber:a,routeTemplate:c})}),n&&e(l,{style:o.footer,children:i(p,{style:o.goButton,onPress:()=>n(b(t.pathname,t.params)),activeOpacity:.8,testID:"buoy-routes-detail-go",accessibilityRole:"button",accessibilityLabel:`Go to route ${t.pathname}`,children:[e(m,{size:16,color:r.color.onAccent}),e(s,{style:o.goButtonText,children:"Go to route"})]})})]})}const o=u.create({container:{flex:1,backgroundColor:"transparent"},scroll:{flex:1},scrollContent:{padding:14},footer:{paddingHorizontal:16,paddingVertical:12,backgroundColor:"transparent",borderTopWidth:1,borderTopColor:r.color.border},goButton:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:8,backgroundColor:r.color.accent,paddingVertical:12,borderRadius:8},goButtonText:{fontSize:13,fontWeight:"600",color:r.color.onAccent,fontFamily:g,textTransform:"uppercase",letterSpacing:.5}});
|
|
@@ -1,200 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* RouteEventExpandedContent - Expanded view for route event details
|
|
5
|
-
*
|
|
6
|
-
* Shows 3 organized sections:
|
|
7
|
-
* - Section A: Route Information (Template, From, To)
|
|
8
|
-
* - Section B: Timing Information (Duration, Time)
|
|
9
|
-
* - Section C: Parameters & Metadata (Segments, Parameters, Visit count)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { View, Text, StyleSheet } from "react-native";
|
|
13
|
-
import { InlineCopyButton, night, monoFont } from "@buoy-gg/shared-ui";
|
|
14
|
-
import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
|
|
15
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
16
|
-
// Format duration in milliseconds to human-readable string
|
|
17
|
-
function formatDuration(ms) {
|
|
18
|
-
if (ms < 1000) {
|
|
19
|
-
return `${ms}ms`;
|
|
20
|
-
}
|
|
21
|
-
if (ms < 60000) {
|
|
22
|
-
return `${(ms / 1000).toFixed(1)}s`;
|
|
23
|
-
}
|
|
24
|
-
const minutes = Math.floor(ms / 60000);
|
|
25
|
-
const seconds = (ms % 60000 / 1000).toFixed(0);
|
|
26
|
-
return `${minutes}m ${seconds}s`;
|
|
27
|
-
}
|
|
28
|
-
export function RouteEventExpandedContent({
|
|
29
|
-
event,
|
|
30
|
-
visitNumber,
|
|
31
|
-
routeTemplate
|
|
32
|
-
}) {
|
|
33
|
-
const hasParams = event.params && Object.keys(event.params).length > 0;
|
|
34
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
35
|
-
style: styles.container,
|
|
36
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
37
|
-
style: styles.section,
|
|
38
|
-
children: [routeTemplate && /*#__PURE__*/_jsxs(View, {
|
|
39
|
-
style: styles.detailRow,
|
|
40
|
-
testID: "buoy-routes-detail-template",
|
|
41
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
42
|
-
style: styles.detailLabel,
|
|
43
|
-
children: "Template:"
|
|
44
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
45
|
-
style: styles.detailValue,
|
|
46
|
-
testID: "buoy-routes-detail-template-value",
|
|
47
|
-
children: routeTemplate
|
|
48
|
-
}), /*#__PURE__*/_jsx(InlineCopyButton, {
|
|
49
|
-
value: routeTemplate,
|
|
50
|
-
buttonStyle: styles.copyButton
|
|
51
|
-
})]
|
|
52
|
-
}), event.previousPathname && /*#__PURE__*/_jsxs(View, {
|
|
53
|
-
style: styles.detailRow,
|
|
54
|
-
testID: "buoy-routes-detail-from",
|
|
55
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
56
|
-
style: styles.detailLabel,
|
|
57
|
-
children: "From:"
|
|
58
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
59
|
-
style: styles.detailValue,
|
|
60
|
-
testID: "buoy-routes-detail-from-value",
|
|
61
|
-
children: event.previousPathname
|
|
62
|
-
}), /*#__PURE__*/_jsx(InlineCopyButton, {
|
|
63
|
-
value: event.previousPathname,
|
|
64
|
-
buttonStyle: styles.copyButton
|
|
65
|
-
})]
|
|
66
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
67
|
-
style: styles.detailRow,
|
|
68
|
-
testID: "buoy-routes-detail-to",
|
|
69
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
70
|
-
style: styles.detailLabel,
|
|
71
|
-
children: "To:"
|
|
72
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
73
|
-
style: styles.detailValue,
|
|
74
|
-
testID: "buoy-routes-detail-to-value",
|
|
75
|
-
children: event.pathname
|
|
76
|
-
}), /*#__PURE__*/_jsx(InlineCopyButton, {
|
|
77
|
-
value: event.pathname,
|
|
78
|
-
buttonStyle: styles.copyButton
|
|
79
|
-
})]
|
|
80
|
-
})]
|
|
81
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
82
|
-
style: styles.section,
|
|
83
|
-
children: [event.timeSincePrevious !== undefined && /*#__PURE__*/_jsxs(View, {
|
|
84
|
-
style: styles.detailRow,
|
|
85
|
-
testID: "buoy-routes-detail-duration",
|
|
86
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
87
|
-
style: styles.detailLabel,
|
|
88
|
-
children: "Duration:"
|
|
89
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
90
|
-
style: styles.detailValue,
|
|
91
|
-
testID: "buoy-routes-detail-duration-value",
|
|
92
|
-
children: formatDuration(event.timeSincePrevious)
|
|
93
|
-
})]
|
|
94
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
95
|
-
style: styles.detailRow,
|
|
96
|
-
testID: "buoy-routes-detail-time",
|
|
97
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
98
|
-
style: styles.detailLabel,
|
|
99
|
-
children: "Time:"
|
|
100
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
101
|
-
style: styles.detailValue,
|
|
102
|
-
testID: "buoy-routes-detail-time-value",
|
|
103
|
-
children: new Date(event.timestamp).toLocaleString()
|
|
104
|
-
})]
|
|
105
|
-
})]
|
|
106
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
107
|
-
style: styles.section,
|
|
108
|
-
children: [event.segments && event.segments.length > 0 && /*#__PURE__*/_jsxs(View, {
|
|
109
|
-
style: styles.detailRow,
|
|
110
|
-
testID: "buoy-routes-detail-segments",
|
|
111
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
112
|
-
style: styles.detailLabel,
|
|
113
|
-
children: "Segments:"
|
|
114
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
115
|
-
style: styles.detailValue,
|
|
116
|
-
testID: "buoy-routes-detail-segments-value",
|
|
117
|
-
children: event.segments.join(' → ')
|
|
118
|
-
}), /*#__PURE__*/_jsx(InlineCopyButton, {
|
|
119
|
-
value: JSON.stringify(event.segments),
|
|
120
|
-
buttonStyle: styles.copyButton
|
|
121
|
-
})]
|
|
122
|
-
}), hasParams && /*#__PURE__*/_jsxs(View, {
|
|
123
|
-
style: styles.dataViewerContainer,
|
|
124
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
125
|
-
style: styles.dataViewerHeader,
|
|
126
|
-
children: [/*#__PURE__*/_jsxs(Text, {
|
|
127
|
-
style: styles.dataViewerTitle,
|
|
128
|
-
testID: "buoy-routes-detail-params-title",
|
|
129
|
-
children: ["Parameters (", Object.keys(event.params).length, ")"]
|
|
130
|
-
}), /*#__PURE__*/_jsx(InlineCopyButton, {
|
|
131
|
-
value: JSON.stringify(event.params, null, 2),
|
|
132
|
-
buttonStyle: styles.copyButton
|
|
133
|
-
})]
|
|
134
|
-
}), /*#__PURE__*/_jsx(DataViewer, {
|
|
135
|
-
data: event.params,
|
|
136
|
-
title: "",
|
|
137
|
-
showTypeFilter: true,
|
|
138
|
-
rawMode: true,
|
|
139
|
-
initialExpanded: true
|
|
140
|
-
})]
|
|
141
|
-
}), visitNumber > 1 && /*#__PURE__*/_jsxs(View, {
|
|
142
|
-
style: styles.detailRow,
|
|
143
|
-
testID: "buoy-routes-detail-visited",
|
|
144
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
145
|
-
style: styles.detailLabel,
|
|
146
|
-
children: "Visited:"
|
|
147
|
-
}), /*#__PURE__*/_jsxs(Text, {
|
|
148
|
-
style: styles.detailValue,
|
|
149
|
-
testID: "buoy-routes-detail-visited-value",
|
|
150
|
-
children: [visitNumber, " time", visitNumber !== 1 ? 's' : '']
|
|
151
|
-
})]
|
|
152
|
-
})]
|
|
153
|
-
})]
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
const styles = StyleSheet.create({
|
|
157
|
-
container: {
|
|
158
|
-
gap: 12
|
|
159
|
-
},
|
|
160
|
-
section: {
|
|
161
|
-
gap: 8
|
|
162
|
-
},
|
|
163
|
-
detailRow: {
|
|
164
|
-
flexDirection: "row",
|
|
165
|
-
alignItems: "center",
|
|
166
|
-
gap: 8
|
|
167
|
-
},
|
|
168
|
-
detailLabel: {
|
|
169
|
-
fontSize: 10,
|
|
170
|
-
color: night.color.textSecondary,
|
|
171
|
-
fontFamily: monoFont,
|
|
172
|
-
fontWeight: "600",
|
|
173
|
-
minWidth: 70
|
|
174
|
-
},
|
|
175
|
-
detailValue: {
|
|
176
|
-
fontSize: 11,
|
|
177
|
-
color: night.color.text,
|
|
178
|
-
fontFamily: monoFont,
|
|
179
|
-
flex: 1
|
|
180
|
-
},
|
|
181
|
-
copyButton: {
|
|
182
|
-
padding: 4,
|
|
183
|
-
borderRadius: 4
|
|
184
|
-
},
|
|
185
|
-
dataViewerContainer: {
|
|
186
|
-
marginTop: 4
|
|
187
|
-
},
|
|
188
|
-
dataViewerHeader: {
|
|
189
|
-
flexDirection: "row",
|
|
190
|
-
alignItems: "center",
|
|
191
|
-
justifyContent: "space-between",
|
|
192
|
-
marginBottom: 8
|
|
193
|
-
},
|
|
194
|
-
dataViewerTitle: {
|
|
195
|
-
fontSize: 11,
|
|
196
|
-
color: night.color.textSecondary,
|
|
197
|
-
fontFamily: monoFont,
|
|
198
|
-
fontWeight: "600"
|
|
199
|
-
}
|
|
200
|
-
});
|
|
1
|
+
"use strict";import{View as o,Text as i,StyleSheet as c}from"react-native";import{InlineCopyButton as n,night as d,monoFont as u}from"@buoy-gg/shared-ui";import{DataViewer as m}from"@buoy-gg/shared-ui/dataViewer";import{jsx as l,jsxs as a}from"react/jsx-runtime";function h(t){if(t<1e3){return`${t}ms`}if(t<6e4){return`${(t/1e3).toFixed(1)}s`}const r=Math.floor(t/6e4);const s=(t%6e4/1e3).toFixed(0);return`${r}m ${s}s`}export function RouteEventExpandedContent({event:t,visitNumber:r,routeTemplate:s}){const y=t.params&&Object.keys(t.params).length>0;return a(o,{style:e.container,children:[a(o,{style:e.section,children:[s&&a(o,{style:e.detailRow,testID:"buoy-routes-detail-template",children:[l(i,{style:e.detailLabel,children:"Template:"}),l(i,{style:e.detailValue,testID:"buoy-routes-detail-template-value",children:s}),l(n,{value:s,buttonStyle:e.copyButton})]}),t.previousPathname&&a(o,{style:e.detailRow,testID:"buoy-routes-detail-from",children:[l(i,{style:e.detailLabel,children:"From:"}),l(i,{style:e.detailValue,testID:"buoy-routes-detail-from-value",children:t.previousPathname}),l(n,{value:t.previousPathname,buttonStyle:e.copyButton})]}),a(o,{style:e.detailRow,testID:"buoy-routes-detail-to",children:[l(i,{style:e.detailLabel,children:"To:"}),l(i,{style:e.detailValue,testID:"buoy-routes-detail-to-value",children:t.pathname}),l(n,{value:t.pathname,buttonStyle:e.copyButton})]})]}),a(o,{style:e.section,children:[t.timeSincePrevious!==void 0&&a(o,{style:e.detailRow,testID:"buoy-routes-detail-duration",children:[l(i,{style:e.detailLabel,children:"Duration:"}),l(i,{style:e.detailValue,testID:"buoy-routes-detail-duration-value",children:h(t.timeSincePrevious)})]}),a(o,{style:e.detailRow,testID:"buoy-routes-detail-time",children:[l(i,{style:e.detailLabel,children:"Time:"}),l(i,{style:e.detailValue,testID:"buoy-routes-detail-time-value",children:new Date(t.timestamp).toLocaleString()})]})]}),a(o,{style:e.section,children:[t.segments&&t.segments.length>0&&a(o,{style:e.detailRow,testID:"buoy-routes-detail-segments",children:[l(i,{style:e.detailLabel,children:"Segments:"}),l(i,{style:e.detailValue,testID:"buoy-routes-detail-segments-value",children:t.segments.join(" \u2192 ")}),l(n,{value:JSON.stringify(t.segments),buttonStyle:e.copyButton})]}),y&&a(o,{style:e.dataViewerContainer,children:[a(o,{style:e.dataViewerHeader,children:[a(i,{style:e.dataViewerTitle,testID:"buoy-routes-detail-params-title",children:["Parameters (",Object.keys(t.params).length,")"]}),l(n,{value:JSON.stringify(t.params,null,2),buttonStyle:e.copyButton})]}),l(m,{data:t.params,title:"",showTypeFilter:true,rawMode:true,initialExpanded:true})]}),r>1&&a(o,{style:e.detailRow,testID:"buoy-routes-detail-visited",children:[l(i,{style:e.detailLabel,children:"Visited:"}),a(i,{style:e.detailValue,testID:"buoy-routes-detail-visited-value",children:[r," time",r!==1?"s":""]})]})]})]})}const e=c.create({container:{gap:12},section:{gap:8},detailRow:{flexDirection:"row",alignItems:"center",gap:8},detailLabel:{fontSize:10,color:d.color.textSecondary,fontFamily:u,fontWeight:"600",minWidth:70},detailValue:{fontSize:11,color:d.color.text,fontFamily:u,flex:1},copyButton:{padding:4,borderRadius:4},dataViewerContainer:{marginTop:4},dataViewerHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:8},dataViewerTitle:{fontSize:11,color:d.color.textSecondary,fontFamily:u,fontWeight:"600"}});
|
|
@@ -1,187 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* RouteEventItemCompact - Compact list item for route events
|
|
5
|
-
*
|
|
6
|
-
* Uses CompactRow pattern matching network/storage/redux components
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { memo, useMemo } from "react";
|
|
10
|
-
import { Text, TouchableOpacity, StyleSheet } from "react-native";
|
|
11
|
-
import { CompactRow, RelativeTime, buoyColors, night, monoFont } from "@buoy-gg/shared-ui";
|
|
12
|
-
import { RouteEventExpandedContent } from "./RouteEventExpandedContent";
|
|
13
|
-
import { getRouteTemplate, routeHref } from "../utils/routeTemplate";
|
|
14
|
-
import { eventRowTestID } from "../utils/testIDs";
|
|
15
|
-
|
|
16
|
-
// Route type for color coding
|
|
17
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
-
// Get route type for color coding
|
|
19
|
-
function getRouteType(event) {
|
|
20
|
-
if (event.pathname === "/") {
|
|
21
|
-
return "home";
|
|
22
|
-
}
|
|
23
|
-
if (getRouteTemplate(event.pathname, event.segments)) {
|
|
24
|
-
return "dynamic";
|
|
25
|
-
}
|
|
26
|
-
if (event.params && Object.keys(event.params).length > 0) {
|
|
27
|
-
return "with-params";
|
|
28
|
-
}
|
|
29
|
-
return "default";
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Get color for route type
|
|
33
|
-
function getRouteTypeColor(routeType) {
|
|
34
|
-
switch (routeType) {
|
|
35
|
-
case "home":
|
|
36
|
-
return buoyColors.success;
|
|
37
|
-
case "dynamic":
|
|
38
|
-
return night.color.accent;
|
|
39
|
-
case "with-params":
|
|
40
|
-
return buoyColors.warning;
|
|
41
|
-
default:
|
|
42
|
-
return night.color.textSecondary;
|
|
43
|
-
// More visible than border color
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Get status label (route type name)
|
|
48
|
-
function getStatusLabel(routeType) {
|
|
49
|
-
switch (routeType) {
|
|
50
|
-
case "home":
|
|
51
|
-
return "Home";
|
|
52
|
-
case "dynamic":
|
|
53
|
-
return "Dynamic";
|
|
54
|
-
case "with-params":
|
|
55
|
-
return "Params";
|
|
56
|
-
default:
|
|
57
|
-
return "Static";
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Format duration in human-readable format
|
|
62
|
-
function formatDuration(ms) {
|
|
63
|
-
if (ms < 1000) return `${Math.round(ms)}ms`;
|
|
64
|
-
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
65
|
-
const minutes = Math.floor(ms / 60000);
|
|
66
|
-
const seconds = Math.floor(ms % 60000 / 1000);
|
|
67
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Get status sublabel (time on previous route + depth info)
|
|
71
|
-
function getStatusSublabel(event) {
|
|
72
|
-
const parts = [];
|
|
73
|
-
|
|
74
|
-
// Show time spent on previous route if available
|
|
75
|
-
if (event.timeSincePrevious !== undefined && event.timeSincePrevious > 0) {
|
|
76
|
-
parts.push(formatDuration(event.timeSincePrevious));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Show segment depth (e.g., "depth 2" for /users/profile)
|
|
80
|
-
const depth = event.segments?.length || 0;
|
|
81
|
-
if (depth > 0) {
|
|
82
|
-
parts.push(`depth ${depth}`);
|
|
83
|
-
}
|
|
84
|
-
return parts.join(" · ") || "root";
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Get badge text - only show when there's additional info beyond the status label
|
|
88
|
-
function getBadgeText(event) {
|
|
89
|
-
const hasParams = event.params && Object.keys(event.params).length > 0;
|
|
90
|
-
if (hasParams) {
|
|
91
|
-
const paramCount = Object.keys(event.params).length;
|
|
92
|
-
return `${paramCount} PARAM${paramCount !== 1 ? "S" : ""}`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Don't show badge text - route type is already shown in status label
|
|
96
|
-
return undefined;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Memo justified by profiling (tool-bench 2026-07-06): 400 row renders
|
|
100
|
-
// during a 5s dwell at 500 events (timeline re-renders cascaded into all
|
|
101
|
-
// mounted rows via an inline onPress closure).
|
|
102
|
-
export const RouteEventItemCompact = /*#__PURE__*/memo(function RouteEventItemCompact({
|
|
103
|
-
event,
|
|
104
|
-
visitNumber,
|
|
105
|
-
isExpanded,
|
|
106
|
-
onPress,
|
|
107
|
-
onNavigate,
|
|
108
|
-
index
|
|
109
|
-
}) {
|
|
110
|
-
const routeType = useMemo(() => getRouteType(event), [event]);
|
|
111
|
-
const routeTemplate = useMemo(() => getRouteTemplate(event.pathname, event.segments), [event.pathname, event.segments]);
|
|
112
|
-
const statusColor = useMemo(() => getRouteTypeColor(routeType), [routeType]);
|
|
113
|
-
const statusLabel = useMemo(() => getStatusLabel(routeType), [routeType]);
|
|
114
|
-
const statusSublabel = useMemo(() => getStatusSublabel(event), [event]);
|
|
115
|
-
const badgeText = useMemo(() => getBadgeText(event), [event]);
|
|
116
|
-
const testID = useMemo(() => eventRowTestID(event.pathname, visitNumber), [event.pathname, visitNumber]);
|
|
117
|
-
// Spelled out for assistive tech: the row's whole verdict is a coloured dot
|
|
118
|
-
// and two short words that Fabric merges into the row's container, so
|
|
119
|
-
// VoiceOver would otherwise announce a control it cannot describe.
|
|
120
|
-
const accessibilityLabel = useMemo(() => `${event.pathname}, ${statusLabel}, ${statusSublabel}`, [event.pathname, statusLabel, statusSublabel]);
|
|
121
|
-
const expandedContent = useMemo(() => {
|
|
122
|
-
if (!isExpanded) return undefined;
|
|
123
|
-
return /*#__PURE__*/_jsx(RouteEventExpandedContent, {
|
|
124
|
-
event: event,
|
|
125
|
-
visitNumber: visitNumber,
|
|
126
|
-
routeTemplate: routeTemplate
|
|
127
|
-
});
|
|
128
|
-
}, [isExpanded, event, visitNumber, routeTemplate]);
|
|
129
|
-
|
|
130
|
-
// The Go button lives beside the row, not inside its touchable (see
|
|
131
|
-
// CompactRow.trailingAction), so a press never opens the row as well.
|
|
132
|
-
const goButton = useMemo(() => {
|
|
133
|
-
if (!onNavigate) return undefined;
|
|
134
|
-
return /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
135
|
-
style: styles.goButton,
|
|
136
|
-
onPress: () => onNavigate(routeHref(event.pathname, event.params)),
|
|
137
|
-
testID: `${testID}-go`,
|
|
138
|
-
accessibilityRole: "button",
|
|
139
|
-
accessibilityLabel: `Go to ${event.pathname}`,
|
|
140
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
141
|
-
style: styles.goButtonText,
|
|
142
|
-
children: "Go"
|
|
143
|
-
})
|
|
144
|
-
});
|
|
145
|
-
}, [onNavigate, event.pathname, testID]);
|
|
146
|
-
return /*#__PURE__*/_jsx(CompactRow, {
|
|
147
|
-
statusDotColor: statusColor,
|
|
148
|
-
statusLabel: statusLabel,
|
|
149
|
-
statusSublabel: statusSublabel,
|
|
150
|
-
primaryText: event.pathname,
|
|
151
|
-
badgeText: badgeText,
|
|
152
|
-
badgeColor: statusColor,
|
|
153
|
-
trailingAction: goButton,
|
|
154
|
-
bottomRightText: /*#__PURE__*/_jsx(RelativeTime, {
|
|
155
|
-
timestamp: event.timestamp
|
|
156
|
-
}),
|
|
157
|
-
showChevron: true,
|
|
158
|
-
expandedContent: expandedContent,
|
|
159
|
-
isExpanded: isExpanded,
|
|
160
|
-
expandedGlowColor: statusColor,
|
|
161
|
-
onPress: () => onPress(index),
|
|
162
|
-
testID: testID,
|
|
163
|
-
statusTestID: `${testID}-status`,
|
|
164
|
-
statusSublabelTestID: `${testID}-sublabel`,
|
|
165
|
-
accessibilityLabel: accessibilityLabel
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
const styles = StyleSheet.create({
|
|
169
|
-
badgeText: {
|
|
170
|
-
fontSize: 11,
|
|
171
|
-
fontWeight: "600",
|
|
172
|
-
fontFamily: monoFont
|
|
173
|
-
},
|
|
174
|
-
goButton: {
|
|
175
|
-
backgroundColor: night.color.accent,
|
|
176
|
-
paddingHorizontal: 8,
|
|
177
|
-
paddingVertical: 4,
|
|
178
|
-
borderRadius: 4
|
|
179
|
-
},
|
|
180
|
-
goButtonText: {
|
|
181
|
-
fontSize: 10,
|
|
182
|
-
fontWeight: "600",
|
|
183
|
-
// Ink on a filled accent surface — the night accent takes dark ink.
|
|
184
|
-
color: night.color.onAccent,
|
|
185
|
-
fontFamily: monoFont
|
|
186
|
-
}
|
|
187
|
-
});
|
|
1
|
+
"use strict";import{memo as R,useMemo as a}from"react";import{Text as w,TouchableOpacity as D,StyleSheet as I}from"react-native";import{CompactRow as P,RelativeTime as j,buoyColors as f,night as u,monoFont as d}from"@buoy-gg/shared-ui";import{RouteEventExpandedContent as B}from"./RouteEventExpandedContent";import{getRouteTemplate as g,routeHref as L}from"../utils/routeTemplate";import{eventRowTestID as M}from"../utils/testIDs";import{jsx as n}from"react/jsx-runtime";function k(o){if(o.pathname==="/"){return"home"}if(g(o.pathname,o.segments)){return"dynamic"}if(o.params&&Object.keys(o.params).length>0){return"with-params"}return"default"}function A(o){switch(o){case"home":return f.success;case"dynamic":return u.color.accent;case"with-params":return f.warning;default:return u.color.textSecondary}}function F(o){switch(o){case"home":return"Home";case"dynamic":return"Dynamic";case"with-params":return"Params";default:return"Static"}}function O(o){if(o<1e3)return`${Math.round(o)}ms`;if(o<6e4)return`${(o/1e3).toFixed(1)}s`;const t=Math.floor(o/6e4);const e=Math.floor(o%6e4/1e3);return e>0?`${t}m ${e}s`:`${t}m`}function z(o){const t=[];if(o.timeSincePrevious!==void 0&&o.timeSincePrevious>0){t.push(O(o.timeSincePrevious))}const e=o.segments?.length||0;if(e>0){t.push(`depth ${e}`)}return t.join(" \xB7 ")||"root"}function E(o){const t=o.params&&Object.keys(o.params).length>0;if(t){const e=Object.keys(o.params).length;return`${e} PARAM${e!==1?"S":""}`}return void 0}export const RouteEventItemCompact=R(function o({event:t,visitNumber:e,isExpanded:i,onPress:y,onNavigate:c,index:T}){const s=a(()=>k(t),[t]);const h=a(()=>g(t.pathname,t.segments),[t.pathname,t.segments]);const m=a(()=>A(s),[s]);const l=a(()=>F(s),[s]);const p=a(()=>z(t),[t]);const x=a(()=>E(t),[t]);const r=a(()=>M(t.pathname,e),[t.pathname,e]);const S=a(()=>`${t.pathname}, ${l}, ${p}`,[t.pathname,l,p]);const C=a(()=>{if(!i)return void 0;return n(B,{event:t,visitNumber:e,routeTemplate:h})},[i,t,e,h]);const $=a(()=>{if(!c)return void 0;return n(D,{style:b.goButton,onPress:()=>c(L(t.pathname,t.params)),testID:`${r}-go`,accessibilityRole:"button",accessibilityLabel:`Go to ${t.pathname}`,children:n(w,{style:b.goButtonText,children:"Go"})})},[c,t.pathname,r]);return n(P,{statusDotColor:m,statusLabel:l,statusSublabel:p,primaryText:t.pathname,badgeText:x,badgeColor:m,trailingAction:$,bottomRightText:n(j,{timestamp:t.timestamp}),showChevron:true,expandedContent:C,isExpanded:i,expandedGlowColor:m,onPress:()=>y(T),testID:r,statusTestID:`${r}-status`,statusSublabelTestID:`${r}-sublabel`,accessibilityLabel:S})});const b=I.create({badgeText:{fontSize:11,fontWeight:"600",fontFamily:d},goButton:{backgroundColor:u.color.accent,paddingHorizontal:8,paddingVertical:4,borderRadius:4},goButtonText:{fontSize:10,fontWeight:"600",color:u.color.onAccent,fontFamily:d}});
|