@buoy-gg/route-events 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +654 -0
  2. package/lib/commonjs/RouteObserver.js +54 -0
  3. package/lib/commonjs/RouteParser.js +310 -0
  4. package/lib/commonjs/RouteTracker.js +39 -0
  5. package/lib/commonjs/components/NavigationStack.js +584 -0
  6. package/lib/commonjs/components/RouteEventDetailContent.js +492 -0
  7. package/lib/commonjs/components/RouteEventExpandedContent.js +187 -0
  8. package/lib/commonjs/components/RouteEventItemCompact.js +175 -0
  9. package/lib/commonjs/components/RouteEventsModalWithTabs.js +560 -0
  10. package/lib/commonjs/components/RouteEventsTimeline.js +82 -0
  11. package/lib/commonjs/components/RouteFilterViewV2.js +42 -0
  12. package/lib/commonjs/components/RoutesSitemap.js +948 -0
  13. package/lib/commonjs/expoRouterStore.js +104 -0
  14. package/lib/commonjs/index.js +99 -0
  15. package/lib/commonjs/package.json +1 -0
  16. package/lib/commonjs/preset.js +83 -0
  17. package/lib/commonjs/useNavigationStack.js +241 -0
  18. package/lib/commonjs/useRouteObserver.js +73 -0
  19. package/lib/commonjs/useRouteSitemap.js +234 -0
  20. package/lib/commonjs/utils/safeExpoRouter.js +129 -0
  21. package/lib/commonjs/utils/safeReactNavigation.js +104 -0
  22. package/lib/module/RouteObserver.js +49 -0
  23. package/lib/module/RouteParser.js +305 -0
  24. package/lib/module/RouteTracker.js +35 -0
  25. package/lib/module/components/NavigationStack.js +580 -0
  26. package/lib/module/components/RouteEventDetailContent.js +487 -0
  27. package/lib/module/components/RouteEventExpandedContent.js +183 -0
  28. package/lib/module/components/RouteEventItemCompact.js +171 -0
  29. package/lib/module/components/RouteEventsModalWithTabs.js +557 -0
  30. package/lib/module/components/RouteEventsTimeline.js +78 -0
  31. package/lib/module/components/RouteFilterViewV2.js +38 -0
  32. package/lib/module/components/RoutesSitemap.js +944 -0
  33. package/lib/module/expoRouterStore.js +98 -0
  34. package/lib/module/index.js +23 -0
  35. package/lib/module/preset.js +79 -0
  36. package/lib/module/useNavigationStack.js +238 -0
  37. package/lib/module/useRouteObserver.js +70 -0
  38. package/lib/module/useRouteSitemap.js +229 -0
  39. package/lib/module/utils/safeExpoRouter.js +120 -0
  40. package/lib/module/utils/safeReactNavigation.js +98 -0
  41. package/lib/typescript/RouteObserver.d.ts +37 -0
  42. package/lib/typescript/RouteObserver.d.ts.map +1 -0
  43. package/lib/typescript/RouteParser.d.ts +129 -0
  44. package/lib/typescript/RouteParser.d.ts.map +1 -0
  45. package/lib/typescript/RouteTracker.d.ts +29 -0
  46. package/lib/typescript/RouteTracker.d.ts.map +1 -0
  47. package/lib/typescript/components/NavigationStack.d.ts +11 -0
  48. package/lib/typescript/components/NavigationStack.d.ts.map +1 -0
  49. package/lib/typescript/components/RouteEventDetailContent.d.ts +21 -0
  50. package/lib/typescript/components/RouteEventDetailContent.d.ts.map +1 -0
  51. package/lib/typescript/components/RouteEventExpandedContent.d.ts +16 -0
  52. package/lib/typescript/components/RouteEventExpandedContent.d.ts.map +1 -0
  53. package/lib/typescript/components/RouteEventItemCompact.d.ts +15 -0
  54. package/lib/typescript/components/RouteEventItemCompact.d.ts.map +1 -0
  55. package/lib/typescript/components/RouteEventsModalWithTabs.d.ts +15 -0
  56. package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +1 -0
  57. package/lib/typescript/components/RouteEventsTimeline.d.ts +17 -0
  58. package/lib/typescript/components/RouteEventsTimeline.d.ts.map +1 -0
  59. package/lib/typescript/components/RouteFilterViewV2.d.ts +9 -0
  60. package/lib/typescript/components/RouteFilterViewV2.d.ts.map +1 -0
  61. package/lib/typescript/components/RoutesSitemap.d.ts +15 -0
  62. package/lib/typescript/components/RoutesSitemap.d.ts.map +1 -0
  63. package/lib/typescript/expoRouterStore.d.ts +28 -0
  64. package/lib/typescript/expoRouterStore.d.ts.map +1 -0
  65. package/lib/typescript/index.d.ts +18 -0
  66. package/lib/typescript/index.d.ts.map +1 -0
  67. package/lib/typescript/preset.d.ts +76 -0
  68. package/lib/typescript/preset.d.ts.map +1 -0
  69. package/lib/typescript/useNavigationStack.d.ts +48 -0
  70. package/lib/typescript/useNavigationStack.d.ts.map +1 -0
  71. package/lib/typescript/useRouteObserver.d.ts +27 -0
  72. package/lib/typescript/useRouteObserver.d.ts.map +1 -0
  73. package/lib/typescript/useRouteSitemap.d.ts +102 -0
  74. package/lib/typescript/useRouteSitemap.d.ts.map +1 -0
  75. package/lib/typescript/utils/safeExpoRouter.d.ts +13 -0
  76. package/lib/typescript/utils/safeExpoRouter.d.ts.map +1 -0
  77. package/lib/typescript/utils/safeReactNavigation.d.ts +10 -0
  78. package/lib/typescript/utils/safeReactNavigation.d.ts.map +1 -0
  79. package/package.json +72 -0
@@ -0,0 +1,580 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * NavigationStack - Visual representation of current navigation stack
5
+ *
6
+ * Shows all screens currently mounted in memory, which one is visible,
7
+ * and provides controls to manipulate the stack.
8
+ */
9
+
10
+ import { useState, useMemo } from "react";
11
+ import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Alert } from "react-native";
12
+ import { ChevronDown, ChevronRight, Info, InlineCopyButton, ProUpgradeModal, buoyColors } from "@buoy-gg/shared-ui";
13
+
14
+ // Lazy load the license hooks to avoid circular dependencies
15
+ let _useIsPro = null;
16
+ let _licenseLoadAttempted = false;
17
+ function loadLicenseModule() {
18
+ if (_licenseLoadAttempted) return;
19
+ _licenseLoadAttempted = true;
20
+ try {
21
+ const mod = require("@buoy-gg/license");
22
+ if (mod) {
23
+ _useIsPro = mod.useIsPro ?? null;
24
+ }
25
+ } catch {
26
+ // License package not available
27
+ }
28
+ }
29
+ function getUseIsPro() {
30
+ loadLicenseModule();
31
+ return _useIsPro ?? (() => false);
32
+ }
33
+ import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
34
+ import { useNavigationStack } from "../useNavigationStack";
35
+ import { useRouter } from "expo-router";
36
+
37
+ // ============================================================================
38
+ // Types
39
+ // ============================================================================
40
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
41
+ // ============================================================================
42
+ // Main Component
43
+ // ============================================================================
44
+
45
+ export function NavigationStack({
46
+ style
47
+ }) {
48
+ const {
49
+ stack,
50
+ focusedRoute,
51
+ stackDepth,
52
+ isAtRoot,
53
+ isLoaded,
54
+ error,
55
+ navigateToIndex,
56
+ goBack,
57
+ popToTop
58
+ } = useNavigationStack();
59
+ const router = useRouter();
60
+ const [expandedIndex, setExpandedIndex] = useState(null);
61
+ const [showHelp, setShowHelp] = useState(false);
62
+ const [showUpgradeModal, setShowUpgradeModal] = useState(false);
63
+
64
+ // Check Pro status internally
65
+ const useIsPro = getUseIsPro();
66
+ const isPro = useIsPro();
67
+
68
+ // ✅ All hooks must be called BEFORE any conditional returns
69
+ // Prepare stack data for copying
70
+ const stackDataForCopy = useMemo(() => {
71
+ const stackData = stack.map(item => ({
72
+ pathname: item.pathname,
73
+ name: item.name,
74
+ params: item.params,
75
+ isFocused: item.isFocused
76
+ }));
77
+ return JSON.stringify(stackData, null, 2);
78
+ }, [stack]);
79
+
80
+ // Determine which route actions should operate on
81
+ // If a stack item is expanded, actions target that route
82
+ // Otherwise, actions target the focused (visible) route
83
+ const selectedRoute = useMemo(() => {
84
+ if (expandedIndex !== null && stack[expandedIndex]) {
85
+ return stack[expandedIndex];
86
+ }
87
+ return focusedRoute;
88
+ }, [expandedIndex, stack, focusedRoute]);
89
+ const isNonFocusedSelected = useMemo(() => {
90
+ return expandedIndex !== null && stack[expandedIndex] && !stack[expandedIndex].isFocused;
91
+ }, [expandedIndex, stack]);
92
+
93
+ // Loading state
94
+ if (!isLoaded) {
95
+ return /*#__PURE__*/_jsx(View, {
96
+ style: [styles.container, style],
97
+ children: /*#__PURE__*/_jsx(View, {
98
+ style: styles.loadingContainer,
99
+ children: /*#__PURE__*/_jsx(Text, {
100
+ style: styles.loadingText,
101
+ children: "Loading navigation stack..."
102
+ })
103
+ })
104
+ });
105
+ }
106
+
107
+ // Error state
108
+ if (error) {
109
+ return /*#__PURE__*/_jsx(View, {
110
+ style: [styles.container, style],
111
+ children: /*#__PURE__*/_jsxs(View, {
112
+ style: styles.errorContainer,
113
+ children: [/*#__PURE__*/_jsx(Text, {
114
+ style: styles.errorText,
115
+ children: "Error loading stack"
116
+ }), /*#__PURE__*/_jsx(Text, {
117
+ style: styles.errorDetail,
118
+ children: error.message
119
+ })]
120
+ })
121
+ });
122
+ }
123
+
124
+ // Empty state
125
+ if (stack.length === 0) {
126
+ return /*#__PURE__*/_jsx(View, {
127
+ style: [styles.container, style],
128
+ children: /*#__PURE__*/_jsxs(View, {
129
+ style: styles.emptyContainer,
130
+ children: [/*#__PURE__*/_jsx(Text, {
131
+ style: styles.emptyText,
132
+ children: "No navigation stack"
133
+ }), /*#__PURE__*/_jsx(Text, {
134
+ style: styles.emptySubtext,
135
+ children: "Navigate to a route to see the stack"
136
+ })]
137
+ })
138
+ });
139
+ }
140
+
141
+ // Handlers
142
+ const handleGoBack = () => {
143
+ // Gate behind Pro
144
+ if (!isPro) {
145
+ setShowUpgradeModal(true);
146
+ return;
147
+ }
148
+ if (isAtRoot) {
149
+ Alert.alert("Cannot Go Back", "Already at the root of the stack");
150
+ return;
151
+ }
152
+ goBack();
153
+ };
154
+ const handlePopToTop = () => {
155
+ // Gate behind Pro
156
+ if (!isPro) {
157
+ setShowUpgradeModal(true);
158
+ return;
159
+ }
160
+ if (isAtRoot) {
161
+ Alert.alert("Already at Top", "Stack only has one screen");
162
+ return;
163
+ }
164
+ Alert.alert("Pop to Top", "This will remove all screens except the root screen.", [{
165
+ text: "Cancel",
166
+ style: "cancel"
167
+ }, {
168
+ text: "Pop to Top",
169
+ style: "destructive",
170
+ onPress: popToTop
171
+ }]);
172
+ };
173
+ const toggleExpand = index => {
174
+ setExpandedIndex(expandedIndex === index ? null : index);
175
+ };
176
+ const handleGo = () => {
177
+ // Gate behind Pro
178
+ if (!isPro) {
179
+ setShowUpgradeModal(true);
180
+ return;
181
+ }
182
+ if (!selectedRoute) return;
183
+
184
+ // If the selected route is already focused, do nothing
185
+ if (selectedRoute.isFocused) {
186
+ Alert.alert("Already There", "This route is already visible");
187
+ return;
188
+ }
189
+
190
+ // Navigate to the selected route
191
+ navigateToIndex(selectedRoute.index);
192
+ };
193
+ const handlePopTo = () => {
194
+ // Gate behind Pro
195
+ if (!isPro) {
196
+ setShowUpgradeModal(true);
197
+ return;
198
+ }
199
+ if (!selectedRoute) return;
200
+
201
+ // If selected route is the focused one, we can't pop to it
202
+ if (selectedRoute.isFocused) {
203
+ Alert.alert("Cannot Pop", "Selected route is already visible");
204
+ return;
205
+ }
206
+
207
+ // If selected route is at the top of stack, nothing to pop
208
+ if (selectedRoute.index === stackDepth - 1) {
209
+ Alert.alert("Cannot Pop", "No screens above selected route");
210
+ return;
211
+ }
212
+ const screensToRemove = stackDepth - 1 - selectedRoute.index;
213
+ Alert.alert("Pop to Route", `Remove ${screensToRemove} screen${screensToRemove !== 1 ? "s" : ""} above ${selectedRoute.pathname}?`, [{
214
+ text: "Cancel",
215
+ style: "cancel"
216
+ }, {
217
+ text: "Pop",
218
+ style: "destructive",
219
+ onPress: () => {
220
+ // Navigate to the selected route, which effectively pops everything above it
221
+ navigateToIndex(selectedRoute.index);
222
+ }
223
+ }]);
224
+ };
225
+ return /*#__PURE__*/_jsxs(View, {
226
+ style: [styles.container, style],
227
+ children: [/*#__PURE__*/_jsxs(View, {
228
+ style: styles.header,
229
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
230
+ style: [styles.iconButton, showHelp && styles.iconButtonActive],
231
+ onPress: () => setShowHelp(!showHelp),
232
+ children: /*#__PURE__*/_jsx(Info, {
233
+ size: 16,
234
+ color: showHelp ? buoyColors.primary : buoyColors.textSecondary
235
+ })
236
+ }), /*#__PURE__*/_jsx(InlineCopyButton, {
237
+ value: stackDataForCopy,
238
+ buttonStyle: styles.iconButton
239
+ })]
240
+ }), /*#__PURE__*/_jsx(ScrollView, {
241
+ style: styles.stackScroll,
242
+ contentContainerStyle: styles.stackContent,
243
+ children: [...stack].reverse().map((item, reverseIndex) => {
244
+ const actualIndex = stack.length - 1 - reverseIndex;
245
+ const isExpanded = expandedIndex === actualIndex;
246
+ const hasParams = Object.keys(item.params).length > 0;
247
+ return /*#__PURE__*/_jsx(View, {
248
+ style: styles.stackItemWrapper,
249
+ children: /*#__PURE__*/_jsxs(View, {
250
+ style: [styles.stackItem, isExpanded && styles.stackItemSelected],
251
+ children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
252
+ style: styles.stackItemHeader,
253
+ onPress: () => toggleExpand(actualIndex),
254
+ activeOpacity: 0.7,
255
+ children: [/*#__PURE__*/_jsx(View, {
256
+ style: styles.expandIndicator,
257
+ children: isExpanded ? /*#__PURE__*/_jsx(ChevronDown, {
258
+ size: 14,
259
+ color: buoyColors.textSecondary
260
+ }) : /*#__PURE__*/_jsx(ChevronRight, {
261
+ size: 14,
262
+ color: buoyColors.textSecondary
263
+ })
264
+ }), /*#__PURE__*/_jsx(Text, {
265
+ style: styles.stackItemPath,
266
+ numberOfLines: 1,
267
+ children: item.pathname
268
+ }), /*#__PURE__*/_jsx(InlineCopyButton, {
269
+ value: item.pathname,
270
+ buttonStyle: styles.copyRouteButton
271
+ }), item.isFocused ? /*#__PURE__*/_jsx(View, {
272
+ style: styles.focusedBadge,
273
+ children: /*#__PURE__*/_jsx(Text, {
274
+ style: styles.focusedBadgeText,
275
+ children: "VISIBLE"
276
+ })
277
+ }) : /*#__PURE__*/_jsx(View, {
278
+ style: styles.memoryBadge,
279
+ children: /*#__PURE__*/_jsx(Text, {
280
+ style: styles.memoryBadgeText,
281
+ children: "MEMORY"
282
+ })
283
+ })]
284
+ }), isExpanded && /*#__PURE__*/_jsxs(View, {
285
+ style: styles.expandedContent,
286
+ children: [/*#__PURE__*/_jsxs(View, {
287
+ style: styles.detailRow,
288
+ children: [/*#__PURE__*/_jsx(Text, {
289
+ style: styles.detailLabel,
290
+ children: "Route Name:"
291
+ }), /*#__PURE__*/_jsx(Text, {
292
+ style: styles.detailValue,
293
+ children: item.name
294
+ })]
295
+ }), /*#__PURE__*/_jsxs(View, {
296
+ style: styles.detailRow,
297
+ children: [/*#__PURE__*/_jsx(Text, {
298
+ style: styles.detailLabel,
299
+ children: "Position:"
300
+ }), /*#__PURE__*/_jsxs(Text, {
301
+ style: styles.detailValue,
302
+ children: [actualIndex, " / ", stackDepth - 1]
303
+ })]
304
+ }), hasParams && /*#__PURE__*/_jsx(View, {
305
+ style: styles.dataViewerContainer,
306
+ children: /*#__PURE__*/_jsx(DataViewer, {
307
+ title: "Parameters",
308
+ data: item.params,
309
+ showTypeFilter: false
310
+ })
311
+ })]
312
+ })]
313
+ })
314
+ }, `stack-${actualIndex}-${item.key}`);
315
+ })
316
+ }), /*#__PURE__*/_jsx(View, {
317
+ style: styles.actionsContainer,
318
+ children: /*#__PURE__*/_jsxs(View, {
319
+ style: styles.actionsRow,
320
+ children: [/*#__PURE__*/_jsxs(View, {
321
+ style: styles.actionWrapper,
322
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
323
+ style: [styles.actionButton, isAtRoot && styles.actionButtonDisabled],
324
+ onPress: handleGoBack,
325
+ disabled: isAtRoot,
326
+ children: /*#__PURE__*/_jsx(Text, {
327
+ style: [styles.actionButtonText, isAtRoot && styles.actionButtonTextDisabled],
328
+ children: "Back"
329
+ })
330
+ }), showHelp && /*#__PURE__*/_jsx(Text, {
331
+ style: styles.helpText,
332
+ children: "Go back one screen"
333
+ })]
334
+ }), /*#__PURE__*/_jsxs(View, {
335
+ style: styles.actionWrapper,
336
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
337
+ style: [styles.actionButton, selectedRoute?.isFocused && styles.actionButtonDisabled],
338
+ onPress: handleGo,
339
+ disabled: selectedRoute?.isFocused,
340
+ children: /*#__PURE__*/_jsx(Text, {
341
+ style: [styles.actionButtonText, selectedRoute?.isFocused && styles.actionButtonTextDisabled],
342
+ children: "Go"
343
+ })
344
+ }), showHelp && /*#__PURE__*/_jsx(Text, {
345
+ style: styles.helpText,
346
+ children: "Navigate to selected route"
347
+ })]
348
+ }), /*#__PURE__*/_jsxs(View, {
349
+ style: styles.actionWrapper,
350
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
351
+ style: [styles.actionButton, (selectedRoute?.isFocused || selectedRoute?.index === stackDepth - 1) && styles.actionButtonDisabled],
352
+ onPress: handlePopTo,
353
+ disabled: selectedRoute?.isFocused || selectedRoute?.index === stackDepth - 1,
354
+ children: /*#__PURE__*/_jsx(Text, {
355
+ style: [styles.actionButtonText, (selectedRoute?.isFocused || selectedRoute?.index === stackDepth - 1) && styles.actionButtonTextDisabled],
356
+ children: "Pop To"
357
+ })
358
+ }), showHelp && /*#__PURE__*/_jsx(Text, {
359
+ style: styles.helpText,
360
+ children: "Remove screens above selected"
361
+ })]
362
+ })]
363
+ })
364
+ }), /*#__PURE__*/_jsx(ProUpgradeModal, {
365
+ visible: showUpgradeModal,
366
+ onClose: () => setShowUpgradeModal(false),
367
+ featureName: "Stack Navigation"
368
+ })]
369
+ });
370
+ }
371
+
372
+ // ============================================================================
373
+ // Styles
374
+ // ============================================================================
375
+
376
+ const styles = StyleSheet.create({
377
+ container: {
378
+ flex: 1,
379
+ backgroundColor: buoyColors.base
380
+ },
381
+ loadingContainer: {
382
+ flex: 1,
383
+ justifyContent: "center",
384
+ alignItems: "center",
385
+ padding: 32
386
+ },
387
+ loadingText: {
388
+ color: buoyColors.textSecondary,
389
+ fontSize: 14,
390
+ fontFamily: "monospace"
391
+ },
392
+ errorContainer: {
393
+ flex: 1,
394
+ justifyContent: "center",
395
+ alignItems: "center",
396
+ padding: 32
397
+ },
398
+ errorText: {
399
+ color: buoyColors.error,
400
+ fontSize: 16,
401
+ fontWeight: "600",
402
+ fontFamily: "monospace",
403
+ marginBottom: 8
404
+ },
405
+ errorDetail: {
406
+ color: buoyColors.textSecondary,
407
+ fontSize: 12,
408
+ fontFamily: "monospace",
409
+ textAlign: "center"
410
+ },
411
+ emptyContainer: {
412
+ flex: 1,
413
+ justifyContent: "center",
414
+ alignItems: "center",
415
+ padding: 32
416
+ },
417
+ emptyText: {
418
+ color: buoyColors.text,
419
+ fontSize: 16,
420
+ fontWeight: "600",
421
+ fontFamily: "monospace",
422
+ marginBottom: 8
423
+ },
424
+ emptySubtext: {
425
+ color: buoyColors.textSecondary,
426
+ fontSize: 14,
427
+ fontFamily: "monospace",
428
+ textAlign: "center"
429
+ },
430
+ header: {
431
+ flexDirection: "row",
432
+ padding: 8,
433
+ gap: 8,
434
+ borderBottomWidth: 1,
435
+ borderBottomColor: buoyColors.border,
436
+ alignItems: "center",
437
+ justifyContent: "flex-end"
438
+ },
439
+ iconButton: {
440
+ padding: 6,
441
+ borderRadius: 4
442
+ },
443
+ iconButtonActive: {
444
+ backgroundColor: buoyColors.input
445
+ },
446
+ stackScroll: {
447
+ flex: 1
448
+ },
449
+ stackContent: {
450
+ padding: 8
451
+ },
452
+ stackItemWrapper: {
453
+ marginBottom: 6
454
+ },
455
+ stackItem: {
456
+ backgroundColor: buoyColors.card,
457
+ borderRadius: 6,
458
+ borderWidth: 1,
459
+ borderColor: buoyColors.border,
460
+ overflow: "hidden"
461
+ },
462
+ stackItemSelected: {
463
+ borderColor: buoyColors.primary,
464
+ borderWidth: 2
465
+ },
466
+ stackItemHeader: {
467
+ flexDirection: "row",
468
+ alignItems: "center",
469
+ paddingVertical: 10,
470
+ paddingHorizontal: 12,
471
+ gap: 8
472
+ },
473
+ expandIndicator: {
474
+ width: 20,
475
+ alignItems: "center"
476
+ },
477
+ stackItemPath: {
478
+ fontSize: 13,
479
+ fontWeight: "600",
480
+ color: buoyColors.text,
481
+ fontFamily: "monospace",
482
+ flex: 1
483
+ },
484
+ copyRouteButton: {
485
+ padding: 4,
486
+ marginLeft: 4
487
+ },
488
+ focusedBadge: {
489
+ backgroundColor: buoyColors.success,
490
+ paddingHorizontal: 8,
491
+ paddingVertical: 3,
492
+ borderRadius: 4
493
+ },
494
+ focusedBadgeText: {
495
+ fontSize: 9,
496
+ fontWeight: "700",
497
+ color: buoyColors.base,
498
+ fontFamily: "monospace"
499
+ },
500
+ memoryBadge: {
501
+ backgroundColor: buoyColors.input,
502
+ paddingHorizontal: 8,
503
+ paddingVertical: 3,
504
+ borderRadius: 4
505
+ },
506
+ memoryBadgeText: {
507
+ fontSize: 9,
508
+ fontWeight: "600",
509
+ color: buoyColors.textSecondary,
510
+ fontFamily: "monospace"
511
+ },
512
+ expandedContent: {
513
+ paddingHorizontal: 12,
514
+ paddingTop: 8,
515
+ paddingBottom: 12,
516
+ borderTopWidth: 1,
517
+ borderTopColor: buoyColors.border
518
+ },
519
+ detailRow: {
520
+ marginBottom: 8
521
+ },
522
+ detailLabel: {
523
+ fontSize: 10,
524
+ color: buoyColors.textSecondary,
525
+ fontFamily: "monospace",
526
+ marginBottom: 2
527
+ },
528
+ detailValue: {
529
+ fontSize: 12,
530
+ color: buoyColors.text,
531
+ fontFamily: "monospace"
532
+ },
533
+ dataViewerContainer: {
534
+ marginTop: 4,
535
+ marginHorizontal: -12,
536
+ marginBottom: 8
537
+ },
538
+ actionsContainer: {
539
+ borderTopWidth: 1,
540
+ borderTopColor: buoyColors.border,
541
+ paddingHorizontal: 8,
542
+ paddingTop: 8,
543
+ paddingBottom: 8
544
+ },
545
+ actionsRow: {
546
+ flexDirection: "row",
547
+ gap: 6,
548
+ marginBottom: 6
549
+ },
550
+ actionWrapper: {
551
+ flex: 1
552
+ },
553
+ actionButton: {
554
+ backgroundColor: buoyColors.input,
555
+ paddingVertical: 8,
556
+ paddingHorizontal: 8,
557
+ borderRadius: 6,
558
+ alignItems: "center"
559
+ },
560
+ actionButtonDisabled: {
561
+ opacity: 0.5
562
+ },
563
+ actionButtonText: {
564
+ fontSize: 12,
565
+ fontWeight: "600",
566
+ color: buoyColors.text,
567
+ fontFamily: "monospace"
568
+ },
569
+ actionButtonTextDisabled: {
570
+ color: buoyColors.textMuted
571
+ },
572
+ helpText: {
573
+ fontSize: 9,
574
+ color: buoyColors.textSecondary,
575
+ fontFamily: "monospace",
576
+ textAlign: "center",
577
+ marginTop: 4,
578
+ lineHeight: 12
579
+ }
580
+ });