@buoy-gg/shared-ui 1.7.7 → 1.7.8

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 (91) hide show
  1. package/lib/commonjs/clipboard/clipboard-impl.js +1 -1
  2. package/lib/commonjs/clipboard/copyToClipboard.js +0 -2
  3. package/lib/commonjs/dataViewer/diffThemes.js +35 -32
  4. package/lib/commonjs/history/HistoryProvider.js +246 -0
  5. package/lib/commonjs/history/components/HistoryEntryRow.js +146 -0
  6. package/lib/commonjs/history/components/HistoryList.js +174 -0
  7. package/lib/commonjs/history/components/index.js +25 -0
  8. package/lib/commonjs/history/index.js +61 -0
  9. package/lib/commonjs/history/types.js +5 -0
  10. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  11. package/lib/commonjs/index.js +37 -11
  12. package/lib/commonjs/license/FeatureGate.js +13 -42
  13. package/lib/commonjs/license/index.js +43 -1
  14. package/lib/commonjs/ui/components/CopyButton.js +11 -24
  15. package/lib/commonjs/ui/components/EventHistoryViewer/EventHistoryViewer.js +2 -1
  16. package/lib/commonjs/ui/components/ExpandablePopover.js +7 -7
  17. package/lib/commonjs/utils/formatting/httpFormatting.js +0 -6
  18. package/lib/module/clipboard/clipboard-impl.js +1 -1
  19. package/lib/module/clipboard/copyToClipboard.js +0 -2
  20. package/lib/module/dataViewer/diffThemes.js +35 -32
  21. package/lib/module/history/HistoryProvider.js +237 -0
  22. package/lib/module/history/components/HistoryEntryRow.js +142 -0
  23. package/lib/module/history/components/HistoryList.js +169 -0
  24. package/lib/module/history/components/index.js +8 -0
  25. package/lib/module/history/index.js +15 -0
  26. package/lib/module/history/types.js +3 -0
  27. package/lib/module/hooks/safe-area-impl.js +1 -1
  28. package/lib/module/index.js +4 -1
  29. package/lib/module/license/FeatureGate.js +11 -40
  30. package/lib/module/license/index.js +41 -1
  31. package/lib/module/ui/components/CopyButton.js +9 -23
  32. package/lib/module/ui/components/EventHistoryViewer/EventHistoryViewer.js +2 -1
  33. package/lib/module/ui/components/ExpandablePopover.js +8 -8
  34. package/lib/module/utils/formatting/httpFormatting.js +0 -6
  35. package/lib/typescript/commonjs/clipboard/clipboard-impl.d.ts +1 -1
  36. package/lib/typescript/commonjs/clipboard/copyToClipboard.d.ts.map +1 -1
  37. package/lib/typescript/commonjs/dataViewer/diffThemes.d.ts +1 -1
  38. package/lib/typescript/commonjs/dataViewer/diffThemes.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/history/HistoryProvider.d.ts +56 -0
  40. package/lib/typescript/commonjs/history/HistoryProvider.d.ts.map +1 -0
  41. package/lib/typescript/commonjs/history/components/HistoryEntryRow.d.ts +22 -0
  42. package/lib/typescript/commonjs/history/components/HistoryEntryRow.d.ts.map +1 -0
  43. package/lib/typescript/commonjs/history/components/HistoryList.d.ts +47 -0
  44. package/lib/typescript/commonjs/history/components/HistoryList.d.ts.map +1 -0
  45. package/lib/typescript/commonjs/history/components/index.d.ts +6 -0
  46. package/lib/typescript/commonjs/history/components/index.d.ts.map +1 -0
  47. package/lib/typescript/commonjs/history/index.d.ts +9 -0
  48. package/lib/typescript/commonjs/history/index.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/history/types.d.ts +171 -0
  50. package/lib/typescript/commonjs/history/types.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  52. package/lib/typescript/commonjs/index.d.ts +2 -1
  53. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/license/LicenseEntryModal.d.ts +5 -0
  56. package/lib/typescript/commonjs/license/LicenseEntryModal.d.ts.map +1 -1
  57. package/lib/typescript/commonjs/license/index.d.ts +15 -0
  58. package/lib/typescript/commonjs/license/index.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/ui/components/CopyButton.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/ui/components/EventHistoryViewer/EventHistoryViewer.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/utils/formatting/httpFormatting.d.ts.map +1 -1
  62. package/lib/typescript/module/clipboard/clipboard-impl.d.ts +1 -1
  63. package/lib/typescript/module/clipboard/copyToClipboard.d.ts.map +1 -1
  64. package/lib/typescript/module/dataViewer/diffThemes.d.ts +1 -1
  65. package/lib/typescript/module/dataViewer/diffThemes.d.ts.map +1 -1
  66. package/lib/typescript/module/history/HistoryProvider.d.ts +56 -0
  67. package/lib/typescript/module/history/HistoryProvider.d.ts.map +1 -0
  68. package/lib/typescript/module/history/components/HistoryEntryRow.d.ts +22 -0
  69. package/lib/typescript/module/history/components/HistoryEntryRow.d.ts.map +1 -0
  70. package/lib/typescript/module/history/components/HistoryList.d.ts +47 -0
  71. package/lib/typescript/module/history/components/HistoryList.d.ts.map +1 -0
  72. package/lib/typescript/module/history/components/index.d.ts +6 -0
  73. package/lib/typescript/module/history/components/index.d.ts.map +1 -0
  74. package/lib/typescript/module/history/index.d.ts +9 -0
  75. package/lib/typescript/module/history/index.d.ts.map +1 -0
  76. package/lib/typescript/module/history/types.d.ts +171 -0
  77. package/lib/typescript/module/history/types.d.ts.map +1 -0
  78. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  79. package/lib/typescript/module/index.d.ts +2 -1
  80. package/lib/typescript/module/index.d.ts.map +1 -1
  81. package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
  82. package/lib/typescript/module/license/LicenseEntryModal.d.ts +5 -0
  83. package/lib/typescript/module/license/LicenseEntryModal.d.ts.map +1 -1
  84. package/lib/typescript/module/license/index.d.ts +15 -0
  85. package/lib/typescript/module/license/index.d.ts.map +1 -1
  86. package/lib/typescript/module/ui/components/CopyButton.d.ts.map +1 -1
  87. package/lib/typescript/module/ui/components/EventHistoryViewer/EventHistoryViewer.d.ts.map +1 -1
  88. package/lib/typescript/module/utils/formatting/httpFormatting.d.ts.map +1 -1
  89. package/package.json +31 -7
  90. package/scripts/detect-clipboard.js +63 -1
  91. package/scripts/detect-safe-area.js +63 -1
@@ -7,7 +7,7 @@ exports.isClipboardAvailable = exports.clipboardType = exports.clipboardFunction
7
7
  /**
8
8
  * Auto-generated clipboard implementation
9
9
  * Detected: none
10
- * Generated at: 2026-01-03T18:51:49.000Z
10
+ * Generated at: 2026-01-09T18:05:40.988Z
11
11
  *
12
12
  * DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
13
13
  *
@@ -26,9 +26,7 @@ async function copyToClipboard(value) {
26
26
  // This is important when used with virtualized lists or React state
27
27
  try {
28
28
  // For simple objects, use structured clone if available
29
- // @ts-expect-error structuredClone is not defined in the browser
30
29
  if (typeof structuredClone === "function") {
31
- // @ts-expect-error tructuredClone is not defined in the browser
32
30
  const cloned = structuredClone(value);
33
31
  return (0, _safeStringify.safeStringify)(cloned, 2, {
34
32
  depthLimit: 100,
@@ -52,51 +52,54 @@ const gitClassicTheme = exports.gitClassicTheme = {
52
52
 
53
53
  /**
54
54
  * Dev Tools Default Theme
55
- * Clean dark theme using our gameUIColors
55
+ * Clean dark theme matching Buoy website brand colors
56
56
  */
57
57
  const devToolsDefaultTheme = exports.devToolsDefaultTheme = {
58
58
  name: "Dev Tools Default",
59
- description: "Clean dark theme with our game UI colors",
60
- // Use our gameUIColors-inspired dark theme
61
- background: "#0A0E1A",
62
- panelBackground: "#0F1420",
63
- headerBackground: "#141925",
64
- // Diff colors with our cyan/yellow/red scheme
65
- addedBackground: "rgba(74, 255, 159, 0.1)",
66
- removedBackground: "rgba(255, 82, 82, 0.1)",
67
- modifiedBackground: "rgba(0, 184, 230, 0.1)",
59
+ description: "Clean dark theme with Buoy brand colors",
60
+ // Surface colors (matching website dark theme)
61
+ background: "#121212",
62
+ panelBackground: "#1A1A1A",
63
+ headerBackground: "#1A1A1A",
64
+ // Diff colors using website's semantic colors
65
+ // Added: Primary teal (#20C997)
66
+ // Removed: Error red (#EF4444)
67
+ // Modified: Secondary purple (#9B70E0)
68
+ addedBackground: "rgba(32, 201, 151, 0.12)",
69
+ removedBackground: "rgba(239, 68, 68, 0.12)",
70
+ modifiedBackground: "rgba(155, 112, 224, 0.12)",
68
71
  unchangedBackground: "transparent",
69
72
  contextBackground: "rgba(255, 255, 255, 0.02)",
70
73
  // Text colors
71
- addedText: "#4AFF9F",
72
- removedText: "#FF5252",
73
- modifiedText: "#00B8E6",
74
- unchangedText: "#B8BFC9",
74
+ addedText: "#20C997",
75
+ removedText: "#EF4444",
76
+ modifiedText: "#9B70E0",
77
+ unchangedText: "#E0E0E0",
75
78
  // Word-level highlights
76
- addedWordHighlight: "rgba(74, 255, 159, 0.3)",
77
- removedWordHighlight: "rgba(255, 82, 82, 0.3)",
79
+ addedWordHighlight: "rgba(32, 201, 151, 0.3)",
80
+ removedWordHighlight: "rgba(239, 68, 68, 0.3)",
78
81
  // UI elements
79
- lineNumberBackground: "#0A0E1A",
80
- lineNumberText: "#7A8599",
81
- lineNumberBorder: "#1F2937",
82
+ lineNumberBackground: "#121212",
83
+ lineNumberText: "#A0A0A0",
84
+ lineNumberBorder: "#333333",
82
85
  // Markers
83
- markerAddedBackground: "rgba(74, 255, 159, 0.2)",
84
- markerRemovedBackground: "rgba(255, 82, 82, 0.2)",
85
- markerModifiedBackground: "rgba(0, 184, 230, 0.2)",
86
- markerText: "#7A8599",
86
+ markerAddedBackground: "rgba(32, 201, 151, 0.2)",
87
+ markerRemovedBackground: "rgba(239, 68, 68, 0.2)",
88
+ markerModifiedBackground: "rgba(155, 112, 224, 0.2)",
89
+ markerText: "#A0A0A0",
87
90
  // Borders and dividers
88
- borderColor: "#1F2937",
89
- dividerColor: "#1F2937",
91
+ borderColor: "#333333",
92
+ dividerColor: "#333333",
90
93
  // Summary bar
91
- summaryBackground: "#0F1420",
92
- summaryAddedText: "#4AFF9F",
93
- summaryRemovedText: "#FF5252",
94
- summaryModifiedText: "#00B8E6",
94
+ summaryBackground: "#1A1A1A",
95
+ summaryAddedText: "#20C997",
96
+ summaryRemovedText: "#EF4444",
97
+ summaryModifiedText: "#9B70E0",
95
98
  // Empty state
96
- emptyStateText: "#7A8599",
99
+ emptyStateText: "#888888",
97
100
  // Separator
98
- separatorBackground: "#141925",
99
- separatorText: "#7A8599"
101
+ separatorBackground: "#1A1A1A",
102
+ separatorText: "#A0A0A0"
100
103
  };
101
104
 
102
105
  /**
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.HistoryProvider = HistoryProvider;
7
+ exports.useAllHistoryEntries = useAllHistoryEntries;
8
+ exports.useHistoryAdapter = useHistoryAdapter;
9
+ exports.useHistoryAdapters = useHistoryAdapters;
10
+ exports.useHistoryContext = useHistoryContext;
11
+ exports.useHistoryEntryCounts = useHistoryEntryCounts;
12
+ var _react = require("react");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ /**
15
+ * HistoryProvider - Context for Universal History DevTools
16
+ *
17
+ * Manages registered adapters and provides unified access to history
18
+ * from Redux, Zustand, MMKV, React Query, etc.
19
+ */
20
+
21
+ // =============================================================================
22
+ // CONTEXT VALUE
23
+ // =============================================================================
24
+
25
+ const HistoryContext = /*#__PURE__*/(0, _react.createContext)(null);
26
+
27
+ // =============================================================================
28
+ // PROVIDER
29
+ // =============================================================================
30
+
31
+ function HistoryProvider({
32
+ children,
33
+ initialAdapters = []
34
+ }) {
35
+ // Adapter registry
36
+ const [adapterMap, setAdapterMap] = (0, _react.useState)(() => {
37
+ const map = new Map();
38
+ initialAdapters.forEach(reg => {
39
+ map.set(reg.adapter.id, {
40
+ ...reg,
41
+ enabled: reg.enabled ?? true
42
+ });
43
+ });
44
+ return map;
45
+ });
46
+
47
+ // Selected adapter filter
48
+ const [selectedAdapterId, setSelectedAdapterId] = (0, _react.useState)(null);
49
+
50
+ // Refresh trigger
51
+ const [refreshKey, setRefreshKey] = (0, _react.useState)(0);
52
+ const refresh = (0, _react.useCallback)(() => setRefreshKey(k => k + 1), []);
53
+
54
+ // Subscribe to all adapters
55
+ (0, _react.useEffect)(() => {
56
+ const unsubscribes = [];
57
+ adapterMap.forEach(reg => {
58
+ if (reg.enabled) {
59
+ const unsub = reg.adapter.subscribe(refresh);
60
+ unsubscribes.push(unsub);
61
+ }
62
+ });
63
+ return () => {
64
+ unsubscribes.forEach(unsub => unsub());
65
+ };
66
+ }, [adapterMap, refresh]);
67
+
68
+ // Get sorted adapters list
69
+ const adapters = (0, _react.useMemo)(() => {
70
+ return Array.from(adapterMap.values()).filter(reg => reg.enabled).sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100)).map(reg => reg.adapter);
71
+ }, [adapterMap, refreshKey]);
72
+
73
+ // Get adapter by id
74
+ const getAdapter = (0, _react.useCallback)(id => adapterMap.get(id)?.adapter, [adapterMap]);
75
+
76
+ // Register adapter
77
+ const registerAdapter = (0, _react.useCallback)(registration => {
78
+ setAdapterMap(prev => {
79
+ const next = new Map(prev);
80
+ next.set(registration.adapter.id, {
81
+ ...registration,
82
+ enabled: registration.enabled ?? true
83
+ });
84
+ return next;
85
+ });
86
+ }, []);
87
+
88
+ // Unregister adapter
89
+ const unregisterAdapter = (0, _react.useCallback)(id => {
90
+ setAdapterMap(prev => {
91
+ const next = new Map(prev);
92
+ next.delete(id);
93
+ return next;
94
+ });
95
+ }, []);
96
+
97
+ // Get all entries (combined or filtered)
98
+ const getAllEntries = (0, _react.useCallback)(filter => {
99
+ let entries = [];
100
+
101
+ // Collect from all (or selected) adapters
102
+ const sourceAdapters = selectedAdapterId && filter?.sources === undefined ? adapters.filter(a => a.id === selectedAdapterId) : adapters;
103
+ sourceAdapters.forEach(adapter => {
104
+ // Skip if sources filter excludes this adapter
105
+ if (filter?.sources && !filter.sources.includes(adapter.id)) {
106
+ return;
107
+ }
108
+ entries = entries.concat(adapter.getEntries());
109
+ });
110
+
111
+ // Apply filters
112
+ if (filter) {
113
+ entries = applyFilter(entries, filter);
114
+ }
115
+
116
+ // Sort by timestamp (newest first by default)
117
+ entries.sort((a, b) => b.timestamp - a.timestamp);
118
+ return entries;
119
+ }, [adapters, selectedAdapterId, refreshKey]);
120
+
121
+ // Get entry counts per source
122
+ const getEntryCounts = (0, _react.useCallback)(() => {
123
+ const counts = {};
124
+ adapters.forEach(adapter => {
125
+ counts[adapter.id] = adapter.getEntryCount();
126
+ });
127
+ return counts;
128
+ }, [adapters, refreshKey]);
129
+ const value = (0, _react.useMemo)(() => ({
130
+ adapters,
131
+ getAdapter,
132
+ registerAdapter,
133
+ unregisterAdapter,
134
+ getAllEntries,
135
+ getEntryCounts,
136
+ selectedAdapterId,
137
+ setSelectedAdapterId,
138
+ refresh
139
+ }), [adapters, getAdapter, registerAdapter, unregisterAdapter, getAllEntries, getEntryCounts, selectedAdapterId, refresh]);
140
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(HistoryContext.Provider, {
141
+ value: value,
142
+ children: children
143
+ });
144
+ }
145
+
146
+ // =============================================================================
147
+ // HOOKS
148
+ // =============================================================================
149
+
150
+ /**
151
+ * Get the full history context
152
+ */
153
+ function useHistoryContext() {
154
+ const context = (0, _react.useContext)(HistoryContext);
155
+ if (!context) {
156
+ throw new Error("useHistoryContext must be used within a HistoryProvider");
157
+ }
158
+ return context;
159
+ }
160
+
161
+ /**
162
+ * Get all registered adapters
163
+ */
164
+ function useHistoryAdapters() {
165
+ return useHistoryContext().adapters;
166
+ }
167
+
168
+ /**
169
+ * Get a specific adapter by id
170
+ */
171
+ function useHistoryAdapter(id) {
172
+ return useHistoryContext().getAdapter(id);
173
+ }
174
+
175
+ /**
176
+ * Get combined entries from all adapters
177
+ */
178
+ function useAllHistoryEntries(filter) {
179
+ const {
180
+ getAllEntries
181
+ } = useHistoryContext();
182
+ return getAllEntries(filter);
183
+ }
184
+
185
+ /**
186
+ * Get entry counts per source
187
+ */
188
+ function useHistoryEntryCounts() {
189
+ return useHistoryContext().getEntryCounts();
190
+ }
191
+
192
+ // =============================================================================
193
+ // FILTER HELPER
194
+ // =============================================================================
195
+
196
+ function applyFilter(entries, filter) {
197
+ return entries.filter(entry => {
198
+ // Search text
199
+ if (filter.searchText) {
200
+ const search = filter.searchText.toLowerCase();
201
+ if (!entry.label.toLowerCase().includes(search)) {
202
+ return false;
203
+ }
204
+ }
205
+
206
+ // Only with changes
207
+ if (filter.onlyWithChanges && !entry.hasStateChange) {
208
+ return false;
209
+ }
210
+
211
+ // Only errors
212
+ if (filter.onlyErrors && entry.status !== "error") {
213
+ return false;
214
+ }
215
+
216
+ // Time range
217
+ if (filter.afterTimestamp && entry.timestamp < filter.afterTimestamp) {
218
+ return false;
219
+ }
220
+ if (filter.beforeTimestamp && entry.timestamp > filter.beforeTimestamp) {
221
+ return false;
222
+ }
223
+
224
+ // Ignored patterns
225
+ if (filter.ignoredPatterns?.length) {
226
+ for (const pattern of filter.ignoredPatterns) {
227
+ if (new RegExp(pattern).test(entry.label)) {
228
+ return false;
229
+ }
230
+ }
231
+ }
232
+
233
+ // Included patterns (must match at least one)
234
+ if (filter.includedPatterns?.length) {
235
+ let matched = false;
236
+ for (const pattern of filter.includedPatterns) {
237
+ if (new RegExp(pattern).test(entry.label)) {
238
+ matched = true;
239
+ break;
240
+ }
241
+ }
242
+ if (!matched) return false;
243
+ }
244
+ return true;
245
+ });
246
+ }
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.HistoryEntryRow = HistoryEntryRow;
7
+ var _reactNative = require("react-native");
8
+ var _CompactRow = require("../../ui/components/CompactRow.js");
9
+ var _gameUIColors = require("../../ui/gameUI/constants/gameUIColors.js");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ /**
12
+ * HistoryEntryRow - Universal row component for history entries
13
+ *
14
+ * Wraps CompactRow to display entries from any adapter (Redux, Zustand, MMKV, etc.)
15
+ */
16
+
17
+ /**
18
+ * Format timestamp to relative time
19
+ */
20
+ function formatRelativeTime(timestamp) {
21
+ const now = Date.now();
22
+ const diff = now - timestamp;
23
+ if (diff < 1000) return "just now";
24
+ if (diff < 60000) return `${Math.floor(diff / 1000)}s ago`;
25
+ if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;
26
+ return `${Math.floor(diff / 3600000)}h ago`;
27
+ }
28
+
29
+ /**
30
+ * Get status color based on entry properties
31
+ */
32
+ function getStatusColor(entry, adapter) {
33
+ // Use adapter color if available
34
+ if (adapter?.color) {
35
+ return adapter.color;
36
+ }
37
+
38
+ // Status-based colors (React Query style)
39
+ if (entry.status === "error") return _gameUIColors.buoyColors.error;
40
+ if (entry.status === "pending") return _gameUIColors.buoyColors.warning;
41
+ if (entry.status === "success") return _gameUIColors.buoyColors.success;
42
+
43
+ // Change-based colors
44
+ if (entry.hasStateChange) return _gameUIColors.buoyColors.success;
45
+
46
+ // Skipped entries
47
+ if (entry.isSkipped) return _gameUIColors.buoyColors.textMuted;
48
+
49
+ // Future entries (after current index)
50
+ if (entry.isInFuture) return _gameUIColors.buoyColors.textMuted + "80";
51
+
52
+ // Source-based fallback colors
53
+ switch (entry.source) {
54
+ case "redux":
55
+ return "#764ABC";
56
+ // Redux purple
57
+ case "zustand":
58
+ return "#443E38";
59
+ // Zustand brown
60
+ case "mmkv":
61
+ return "#4CAF50";
62
+ // Green
63
+ case "async-storage":
64
+ return "#2196F3";
65
+ // Blue
66
+ case "react-query":
67
+ return "#FF4154";
68
+ // React Query red
69
+ case "jotai":
70
+ return "#000000";
71
+ // Black
72
+ case "legend-state":
73
+ return "#7C3AED";
74
+ // Purple
75
+ default:
76
+ return _gameUIColors.buoyColors.textSecondary;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Get status label for display
82
+ */
83
+ function getStatusLabel(entry) {
84
+ if (entry.isSkipped) return "Skipped";
85
+ if (entry.isInFuture) return "Future";
86
+ if (entry.status) {
87
+ return entry.status.charAt(0).toUpperCase() + entry.status.slice(1);
88
+ }
89
+ if (entry.hasStateChange) return "Changed";
90
+ return "Action";
91
+ }
92
+
93
+ /**
94
+ * Get sublabel (source or category)
95
+ */
96
+ function getSublabel(entry, adapter) {
97
+ if (adapter?.name) return adapter.name;
98
+ if (entry.category) return entry.category;
99
+ return entry.source;
100
+ }
101
+ function HistoryEntryRow({
102
+ entry,
103
+ adapter,
104
+ isSelected,
105
+ onPress,
106
+ showSource = true,
107
+ showDuration = true
108
+ }) {
109
+ const statusColor = getStatusColor(entry, adapter);
110
+ const statusLabel = getStatusLabel(entry);
111
+ const sublabel = showSource ? getSublabel(entry, adapter) : undefined;
112
+
113
+ // Build bottom right text (timestamp + optional duration)
114
+ let bottomRightText = formatRelativeTime(entry.timestamp);
115
+ if (showDuration && entry.duration !== undefined) {
116
+ bottomRightText = `${entry.duration.toFixed(1)}ms · ${bottomRightText}`;
117
+ }
118
+
119
+ // Custom badge showing change indicator
120
+ const customBadge = entry.hasStateChange ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
121
+ style: styles.changeBadge,
122
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
123
+ style: styles.changeBadgeText,
124
+ children: "\u26A1"
125
+ })
126
+ }) : undefined;
127
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_CompactRow.CompactRow, {
128
+ statusDotColor: statusColor,
129
+ statusLabel: statusLabel,
130
+ statusSublabel: sublabel,
131
+ primaryText: entry.label,
132
+ bottomRightText: bottomRightText,
133
+ customBadge: customBadge,
134
+ isSelected: isSelected,
135
+ onPress: onPress ? () => onPress(entry) : undefined,
136
+ showChevron: !!onPress
137
+ });
138
+ }
139
+ const styles = _reactNative.StyleSheet.create({
140
+ changeBadge: {
141
+ paddingHorizontal: 4
142
+ },
143
+ changeBadgeText: {
144
+ fontSize: 12
145
+ }
146
+ });
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.HistoryList = HistoryList;
7
+ exports.StandaloneHistoryList = StandaloneHistoryList;
8
+ var _react = require("react");
9
+ var _reactNative = require("react-native");
10
+ var _gameUIColors = require("../../ui/gameUI/constants/gameUIColors.js");
11
+ var _HistoryEntryRow = require("./HistoryEntryRow.js");
12
+ var _HistoryProvider = require("../HistoryProvider.js");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ /**
15
+ * HistoryList - Virtualized list of history entries
16
+ *
17
+ * Displays entries from one or all adapters with filtering and search.
18
+ */
19
+
20
+ function HistoryList({
21
+ filter,
22
+ selectedEntryId,
23
+ onSelectEntry,
24
+ showSource = true,
25
+ emptyMessage = "No history entries yet",
26
+ ListHeaderComponent,
27
+ ListFooterComponent
28
+ }) {
29
+ const entries = (0, _HistoryProvider.useAllHistoryEntries)(filter);
30
+ const adapters = (0, _HistoryProvider.useHistoryAdapters)();
31
+
32
+ // Create adapter lookup map
33
+ const adapterMap = (0, _react.useMemo)(() => {
34
+ const map = new Map();
35
+ adapters.forEach(adapter => map.set(adapter.id, adapter));
36
+ return map;
37
+ }, [adapters]);
38
+
39
+ // Stable key extractor
40
+ const keyExtractor = (0, _react.useCallback)(item => `${item.source}-${item.id}`, []);
41
+
42
+ // Render item
43
+ const renderItem = (0, _react.useCallback)(({
44
+ item
45
+ }) => {
46
+ const adapter = adapterMap.get(item.source);
47
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_HistoryEntryRow.HistoryEntryRow, {
48
+ entry: item,
49
+ adapter: adapter,
50
+ isSelected: selectedEntryId === item.id,
51
+ onPress: onSelectEntry,
52
+ showSource: showSource
53
+ });
54
+ }, [adapterMap, selectedEntryId, onSelectEntry, showSource]);
55
+
56
+ // Empty state
57
+ const ListEmptyComponent = (0, _react.useMemo)(() => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
58
+ style: styles.emptyContainer,
59
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
60
+ style: styles.emptyText,
61
+ children: emptyMessage
62
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
63
+ style: styles.emptySubtext,
64
+ children: "Actions will appear here as they happen"
65
+ })]
66
+ }), [emptyMessage]);
67
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
68
+ data: entries,
69
+ keyExtractor: keyExtractor,
70
+ renderItem: renderItem,
71
+ ListEmptyComponent: ListEmptyComponent,
72
+ ListHeaderComponent: ListHeaderComponent,
73
+ ListFooterComponent: ListFooterComponent,
74
+ contentContainerStyle: styles.listContent,
75
+ showsVerticalScrollIndicator: false
76
+ // Performance optimizations
77
+ ,
78
+ removeClippedSubviews: true,
79
+ maxToRenderPerBatch: 15,
80
+ windowSize: 10,
81
+ initialNumToRender: 15,
82
+ getItemLayout: undefined // Dynamic height rows
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Standalone HistoryList that doesn't require HistoryProvider
88
+ * Use this when you want to pass entries directly
89
+ */
90
+
91
+ function StandaloneHistoryList({
92
+ entries,
93
+ adapters = [],
94
+ selectedEntryId,
95
+ onSelectEntry,
96
+ showSource = true,
97
+ emptyMessage = "No history entries yet",
98
+ ListHeaderComponent,
99
+ ListFooterComponent
100
+ }) {
101
+ // Create adapter lookup map
102
+ const adapterMap = (0, _react.useMemo)(() => {
103
+ const map = new Map();
104
+ adapters.forEach(adapter => map.set(adapter.id, adapter));
105
+ return map;
106
+ }, [adapters]);
107
+
108
+ // Stable key extractor
109
+ const keyExtractor = (0, _react.useCallback)(item => `${item.source}-${item.id}`, []);
110
+
111
+ // Render item
112
+ const renderItem = (0, _react.useCallback)(({
113
+ item
114
+ }) => {
115
+ const adapter = adapterMap.get(item.source);
116
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_HistoryEntryRow.HistoryEntryRow, {
117
+ entry: item,
118
+ adapter: adapter,
119
+ isSelected: selectedEntryId === item.id,
120
+ onPress: onSelectEntry,
121
+ showSource: showSource
122
+ });
123
+ }, [adapterMap, selectedEntryId, onSelectEntry, showSource]);
124
+
125
+ // Empty state
126
+ const ListEmptyComponent = (0, _react.useMemo)(() => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
127
+ style: styles.emptyContainer,
128
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
129
+ style: styles.emptyText,
130
+ children: emptyMessage
131
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
132
+ style: styles.emptySubtext,
133
+ children: "Actions will appear here as they happen"
134
+ })]
135
+ }), [emptyMessage]);
136
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
137
+ data: entries,
138
+ keyExtractor: keyExtractor,
139
+ renderItem: renderItem,
140
+ ListEmptyComponent: ListEmptyComponent,
141
+ ListHeaderComponent: ListHeaderComponent,
142
+ ListFooterComponent: ListFooterComponent,
143
+ contentContainerStyle: styles.listContent,
144
+ showsVerticalScrollIndicator: false,
145
+ removeClippedSubviews: true,
146
+ maxToRenderPerBatch: 15,
147
+ windowSize: 10,
148
+ initialNumToRender: 15
149
+ });
150
+ }
151
+ const styles = _reactNative.StyleSheet.create({
152
+ listContent: {
153
+ flexGrow: 1,
154
+ paddingVertical: 4
155
+ },
156
+ emptyContainer: {
157
+ flex: 1,
158
+ alignItems: "center",
159
+ justifyContent: "center",
160
+ paddingVertical: 60,
161
+ paddingHorizontal: 20
162
+ },
163
+ emptyText: {
164
+ fontSize: 16,
165
+ fontWeight: "600",
166
+ color: _gameUIColors.buoyColors.text,
167
+ marginBottom: 8
168
+ },
169
+ emptySubtext: {
170
+ fontSize: 13,
171
+ color: _gameUIColors.buoyColors.textMuted,
172
+ textAlign: "center"
173
+ }
174
+ });
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "HistoryEntryRow", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _HistoryEntryRow.HistoryEntryRow;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "HistoryList", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _HistoryList.HistoryList;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "StandaloneHistoryList", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _HistoryList.StandaloneHistoryList;
22
+ }
23
+ });
24
+ var _HistoryEntryRow = require("./HistoryEntryRow.js");
25
+ var _HistoryList = require("./HistoryList.js");