@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.
Files changed (102) hide show
  1. package/README.md +11 -64
  2. package/lib/commonjs/RouteObserver.js +1 -54
  3. package/lib/commonjs/RouteParser.js +1 -314
  4. package/lib/commonjs/RouteTracker.js +1 -112
  5. package/lib/commonjs/RouteTracker.web.js +1 -12
  6. package/lib/commonjs/browserRouteRegistry.js +1 -30
  7. package/lib/commonjs/browserRoutes.js +1 -96
  8. package/lib/commonjs/components/NavigationStack.js +2 -572
  9. package/lib/commonjs/components/ReactNavigationRoutes.js +1 -836
  10. package/lib/commonjs/components/ReactNavigationRoutes.web.js +1 -12
  11. package/lib/commonjs/components/RouteEventDetail.js +1 -97
  12. package/lib/commonjs/components/RouteEventExpandedContent.js +1 -204
  13. package/lib/commonjs/components/RouteEventItemCompact.js +1 -191
  14. package/lib/commonjs/components/RouteEventsModalWithTabs.js +1 -734
  15. package/lib/commonjs/components/RouteEventsTimeline.js +1 -107
  16. package/lib/commonjs/components/RouteFilterViewV2.js +1 -42
  17. package/lib/commonjs/components/RoutesSitemap.js +2 -1035
  18. package/lib/commonjs/expoRouterStore.js +1 -121
  19. package/lib/commonjs/expoRouterStore.web.js +1 -44
  20. package/lib/commonjs/hooks/useRouteEvents.js +1 -57
  21. package/lib/commonjs/index.js +1 -168
  22. package/lib/commonjs/preset.js +1 -69
  23. package/lib/commonjs/stores/navigationStackStore.js +1 -45
  24. package/lib/commonjs/stores/routeEventStore.js +1 -136
  25. package/lib/commonjs/sync/routeEventsSyncAdapter.js +1 -275
  26. package/lib/commonjs/useNavigationStack.js +1 -408
  27. package/lib/commonjs/useNavigationStack.web.js +1 -32
  28. package/lib/commonjs/useRouteObserver.js +1 -73
  29. package/lib/commonjs/useRouteObserverReactNavigation.js +1 -109
  30. package/lib/commonjs/useRouteSitemap.js +1 -255
  31. package/lib/commonjs/utils/routeTemplate.js +1 -79
  32. package/lib/commonjs/utils/safeReactNavigation.js +1 -194
  33. package/lib/commonjs/utils/safeReactNavigation.web.js +1 -36
  34. package/lib/commonjs/utils/testIDs.js +1 -63
  35. package/lib/module/RouteObserver.js +1 -49
  36. package/lib/module/RouteParser.js +1 -309
  37. package/lib/module/RouteTracker.js +1 -109
  38. package/lib/module/RouteTracker.web.js +1 -8
  39. package/lib/module/browserRouteRegistry.js +1 -24
  40. package/lib/module/browserRoutes.js +1 -92
  41. package/lib/module/components/NavigationStack.js +2 -568
  42. package/lib/module/components/ReactNavigationRoutes.js +1 -832
  43. package/lib/module/components/ReactNavigationRoutes.web.js +1 -3
  44. package/lib/module/components/RouteEventDetail.js +1 -93
  45. package/lib/module/components/RouteEventExpandedContent.js +1 -200
  46. package/lib/module/components/RouteEventItemCompact.js +1 -187
  47. package/lib/module/components/RouteEventsModalWithTabs.js +1 -731
  48. package/lib/module/components/RouteEventsTimeline.js +1 -103
  49. package/lib/module/components/RouteFilterViewV2.js +1 -38
  50. package/lib/module/components/RoutesSitemap.js +2 -1033
  51. package/lib/module/expoRouterStore.js +1 -114
  52. package/lib/module/expoRouterStore.web.js +1 -37
  53. package/lib/module/hooks/useRouteEvents.js +1 -54
  54. package/lib/module/index.js +1 -70
  55. package/lib/module/preset.js +1 -66
  56. package/lib/module/stores/navigationStackStore.js +1 -41
  57. package/lib/module/stores/routeEventStore.js +1 -128
  58. package/lib/module/sync/routeEventsSyncAdapter.js +1 -273
  59. package/lib/module/useNavigationStack.js +1 -404
  60. package/lib/module/useNavigationStack.web.js +1 -28
  61. package/lib/module/useRouteObserver.js +1 -70
  62. package/lib/module/useRouteObserverReactNavigation.js +1 -106
  63. package/lib/module/useRouteSitemap.js +1 -250
  64. package/lib/module/utils/routeTemplate.js +1 -73
  65. package/lib/module/utils/safeReactNavigation.js +1 -185
  66. package/lib/module/utils/safeReactNavigation.web.js +1 -27
  67. package/lib/module/utils/testIDs.js +1 -55
  68. package/lib/web/index.mjs +4 -5
  69. package/package.json +6 -11
  70. package/lib/typescript/RouteObserver.d.ts.map +0 -1
  71. package/lib/typescript/RouteParser.d.ts.map +0 -1
  72. package/lib/typescript/RouteTracker.d.ts.map +0 -1
  73. package/lib/typescript/RouteTracker.web.d.ts.map +0 -1
  74. package/lib/typescript/browserRouteRegistry.d.ts.map +0 -1
  75. package/lib/typescript/browserRoutes.d.ts.map +0 -1
  76. package/lib/typescript/components/NavigationStack.d.ts.map +0 -1
  77. package/lib/typescript/components/ReactNavigationRoutes.d.ts.map +0 -1
  78. package/lib/typescript/components/ReactNavigationRoutes.web.d.ts.map +0 -1
  79. package/lib/typescript/components/RouteEventDetail.d.ts.map +0 -1
  80. package/lib/typescript/components/RouteEventExpandedContent.d.ts.map +0 -1
  81. package/lib/typescript/components/RouteEventItemCompact.d.ts.map +0 -1
  82. package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +0 -1
  83. package/lib/typescript/components/RouteEventsTimeline.d.ts.map +0 -1
  84. package/lib/typescript/components/RouteFilterViewV2.d.ts.map +0 -1
  85. package/lib/typescript/components/RoutesSitemap.d.ts.map +0 -1
  86. package/lib/typescript/expoRouterStore.d.ts.map +0 -1
  87. package/lib/typescript/expoRouterStore.web.d.ts.map +0 -1
  88. package/lib/typescript/hooks/useRouteEvents.d.ts.map +0 -1
  89. package/lib/typescript/index.d.ts.map +0 -1
  90. package/lib/typescript/preset.d.ts.map +0 -1
  91. package/lib/typescript/stores/navigationStackStore.d.ts.map +0 -1
  92. package/lib/typescript/stores/routeEventStore.d.ts.map +0 -1
  93. package/lib/typescript/sync/routeEventsSyncAdapter.d.ts.map +0 -1
  94. package/lib/typescript/useNavigationStack.d.ts.map +0 -1
  95. package/lib/typescript/useNavigationStack.web.d.ts.map +0 -1
  96. package/lib/typescript/useRouteObserver.d.ts.map +0 -1
  97. package/lib/typescript/useRouteObserverReactNavigation.d.ts.map +0 -1
  98. package/lib/typescript/useRouteSitemap.d.ts.map +0 -1
  99. package/lib/typescript/utils/routeTemplate.d.ts.map +0 -1
  100. package/lib/typescript/utils/safeReactNavigation.d.ts.map +0 -1
  101. package/lib/typescript/utils/safeReactNavigation.web.d.ts.map +0 -1
  102. package/lib/typescript/utils/testIDs.d.ts.map +0 -1
@@ -1,3 +1 @@
1
- "use strict";
2
-
3
- export { RoutesSitemap as ReactNavigationRoutes } from './RoutesSitemap';
1
+ "use strict";export{RoutesSitemap as ReactNavigationRoutes}from"./RoutesSitemap";
@@ -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}});