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