@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.
- package/lib/commonjs/clipboard/clipboard-impl.js +1 -1
- package/lib/commonjs/clipboard/copyToClipboard.js +0 -2
- package/lib/commonjs/dataViewer/diffThemes.js +35 -32
- package/lib/commonjs/history/HistoryProvider.js +246 -0
- package/lib/commonjs/history/components/HistoryEntryRow.js +146 -0
- package/lib/commonjs/history/components/HistoryList.js +174 -0
- package/lib/commonjs/history/components/index.js +25 -0
- package/lib/commonjs/history/index.js +61 -0
- package/lib/commonjs/history/types.js +5 -0
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/index.js +37 -11
- package/lib/commonjs/license/FeatureGate.js +13 -42
- package/lib/commonjs/license/index.js +43 -1
- package/lib/commonjs/ui/components/CopyButton.js +11 -24
- package/lib/commonjs/ui/components/EventHistoryViewer/EventHistoryViewer.js +2 -1
- package/lib/commonjs/ui/components/ExpandablePopover.js +7 -7
- package/lib/commonjs/utils/formatting/httpFormatting.js +0 -6
- package/lib/module/clipboard/clipboard-impl.js +1 -1
- package/lib/module/clipboard/copyToClipboard.js +0 -2
- package/lib/module/dataViewer/diffThemes.js +35 -32
- package/lib/module/history/HistoryProvider.js +237 -0
- package/lib/module/history/components/HistoryEntryRow.js +142 -0
- package/lib/module/history/components/HistoryList.js +169 -0
- package/lib/module/history/components/index.js +8 -0
- package/lib/module/history/index.js +15 -0
- package/lib/module/history/types.js +3 -0
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/index.js +4 -1
- package/lib/module/license/FeatureGate.js +11 -40
- package/lib/module/license/index.js +41 -1
- package/lib/module/ui/components/CopyButton.js +9 -23
- package/lib/module/ui/components/EventHistoryViewer/EventHistoryViewer.js +2 -1
- package/lib/module/ui/components/ExpandablePopover.js +8 -8
- package/lib/module/utils/formatting/httpFormatting.js +0 -6
- package/lib/typescript/commonjs/clipboard/clipboard-impl.d.ts +1 -1
- package/lib/typescript/commonjs/clipboard/copyToClipboard.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/diffThemes.d.ts +1 -1
- package/lib/typescript/commonjs/dataViewer/diffThemes.d.ts.map +1 -1
- package/lib/typescript/commonjs/history/HistoryProvider.d.ts +56 -0
- package/lib/typescript/commonjs/history/HistoryProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/history/components/HistoryEntryRow.d.ts +22 -0
- package/lib/typescript/commonjs/history/components/HistoryEntryRow.d.ts.map +1 -0
- package/lib/typescript/commonjs/history/components/HistoryList.d.ts +47 -0
- package/lib/typescript/commonjs/history/components/HistoryList.d.ts.map +1 -0
- package/lib/typescript/commonjs/history/components/index.d.ts +6 -0
- package/lib/typescript/commonjs/history/components/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/history/index.d.ts +9 -0
- package/lib/typescript/commonjs/history/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/history/types.d.ts +171 -0
- package/lib/typescript/commonjs/history/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/LicenseEntryModal.d.ts +5 -0
- package/lib/typescript/commonjs/license/LicenseEntryModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/index.d.ts +15 -0
- package/lib/typescript/commonjs/license/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/CopyButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/EventHistoryViewer.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/formatting/httpFormatting.d.ts.map +1 -1
- package/lib/typescript/module/clipboard/clipboard-impl.d.ts +1 -1
- package/lib/typescript/module/clipboard/copyToClipboard.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/diffThemes.d.ts +1 -1
- package/lib/typescript/module/dataViewer/diffThemes.d.ts.map +1 -1
- package/lib/typescript/module/history/HistoryProvider.d.ts +56 -0
- package/lib/typescript/module/history/HistoryProvider.d.ts.map +1 -0
- package/lib/typescript/module/history/components/HistoryEntryRow.d.ts +22 -0
- package/lib/typescript/module/history/components/HistoryEntryRow.d.ts.map +1 -0
- package/lib/typescript/module/history/components/HistoryList.d.ts +47 -0
- package/lib/typescript/module/history/components/HistoryList.d.ts.map +1 -0
- package/lib/typescript/module/history/components/index.d.ts +6 -0
- package/lib/typescript/module/history/components/index.d.ts.map +1 -0
- package/lib/typescript/module/history/index.d.ts +9 -0
- package/lib/typescript/module/history/index.d.ts.map +1 -0
- package/lib/typescript/module/history/types.d.ts +171 -0
- package/lib/typescript/module/history/types.d.ts.map +1 -0
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/index.d.ts +2 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
- package/lib/typescript/module/license/LicenseEntryModal.d.ts +5 -0
- package/lib/typescript/module/license/LicenseEntryModal.d.ts.map +1 -1
- package/lib/typescript/module/license/index.d.ts +15 -0
- package/lib/typescript/module/license/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/CopyButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/EventHistoryViewer.d.ts.map +1 -1
- package/lib/typescript/module/utils/formatting/httpFormatting.d.ts.map +1 -1
- package/package.json +31 -7
- package/scripts/detect-clipboard.js +63 -1
- 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-
|
|
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
|
|
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
|
|
60
|
-
//
|
|
61
|
-
background: "#
|
|
62
|
-
panelBackground: "#
|
|
63
|
-
headerBackground: "#
|
|
64
|
-
// Diff colors
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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: "#
|
|
72
|
-
removedText: "#
|
|
73
|
-
modifiedText: "#
|
|
74
|
-
unchangedText: "#
|
|
74
|
+
addedText: "#20C997",
|
|
75
|
+
removedText: "#EF4444",
|
|
76
|
+
modifiedText: "#9B70E0",
|
|
77
|
+
unchangedText: "#E0E0E0",
|
|
75
78
|
// Word-level highlights
|
|
76
|
-
addedWordHighlight: "rgba(
|
|
77
|
-
removedWordHighlight: "rgba(
|
|
79
|
+
addedWordHighlight: "rgba(32, 201, 151, 0.3)",
|
|
80
|
+
removedWordHighlight: "rgba(239, 68, 68, 0.3)",
|
|
78
81
|
// UI elements
|
|
79
|
-
lineNumberBackground: "#
|
|
80
|
-
lineNumberText: "#
|
|
81
|
-
lineNumberBorder: "#
|
|
82
|
+
lineNumberBackground: "#121212",
|
|
83
|
+
lineNumberText: "#A0A0A0",
|
|
84
|
+
lineNumberBorder: "#333333",
|
|
82
85
|
// Markers
|
|
83
|
-
markerAddedBackground: "rgba(
|
|
84
|
-
markerRemovedBackground: "rgba(
|
|
85
|
-
markerModifiedBackground: "rgba(
|
|
86
|
-
markerText: "#
|
|
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: "#
|
|
89
|
-
dividerColor: "#
|
|
91
|
+
borderColor: "#333333",
|
|
92
|
+
dividerColor: "#333333",
|
|
90
93
|
// Summary bar
|
|
91
|
-
summaryBackground: "#
|
|
92
|
-
summaryAddedText: "#
|
|
93
|
-
summaryRemovedText: "#
|
|
94
|
-
summaryModifiedText: "#
|
|
94
|
+
summaryBackground: "#1A1A1A",
|
|
95
|
+
summaryAddedText: "#20C997",
|
|
96
|
+
summaryRemovedText: "#EF4444",
|
|
97
|
+
summaryModifiedText: "#9B70E0",
|
|
95
98
|
// Empty state
|
|
96
|
-
emptyStateText: "#
|
|
99
|
+
emptyStateText: "#888888",
|
|
97
100
|
// Separator
|
|
98
|
-
separatorBackground: "#
|
|
99
|
-
separatorText: "#
|
|
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");
|