@buoy-gg/redux 7.0.38 → 7.0.39
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/index.js +256 -1
- package/lib/commonjs/preset.js +90 -1
- package/lib/commonjs/redux/components/ReduxActionButton.js +131 -1
- package/lib/commonjs/redux/components/ReduxActionDetailContent.js +437 -1
- package/lib/commonjs/redux/components/ReduxActionDetailView.js +401 -1
- package/lib/commonjs/redux/components/ReduxActionInfoView.js +836 -1
- package/lib/commonjs/redux/components/ReduxActionItem.js +334 -1
- package/lib/commonjs/redux/components/ReduxAutoInstrument.js +20 -1
- package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +50 -1
- package/lib/commonjs/redux/components/ReduxIcon.js +18 -1
- package/lib/commonjs/redux/components/ReduxModal.js +703 -1
- package/lib/commonjs/redux/hooks/useAutoInstrumentRedux.js +187 -1
- package/lib/commonjs/redux/hooks/useReduxActions.js +58 -1
- package/lib/commonjs/redux/sync/reduxSyncAdapter.js +191 -1
- package/lib/commonjs/redux/utils/activeStoreRegistry.js +104 -1
- package/lib/commonjs/redux/utils/autoInstrument.js +231 -1
- package/lib/commonjs/redux/utils/buoyReduxMiddleware.js +202 -1
- package/lib/commonjs/redux/utils/createReduxHistoryAdapter.js +146 -1
- package/lib/commonjs/redux/utils/devtoolsHook.js +152 -1
- package/lib/commonjs/redux/utils/reduxActionStore.js +473 -1
- package/lib/commonjs/redux/utils/snapshotProvider.js +158 -1
- package/lib/commonjs/redux/utils/testIDs.js +75 -1
- package/lib/module/index.js +125 -1
- package/lib/module/preset.js +87 -1
- package/lib/module/redux/components/ReduxActionButton.js +128 -1
- package/lib/module/redux/components/ReduxActionDetailContent.js +433 -1
- package/lib/module/redux/components/ReduxActionDetailView.js +397 -1
- package/lib/module/redux/components/ReduxActionInfoView.js +831 -1
- package/lib/module/redux/components/ReduxActionItem.js +330 -1
- package/lib/module/redux/components/ReduxAutoInstrument.js +17 -1
- package/lib/module/redux/components/ReduxDetailViewToggle.js +45 -1
- package/lib/module/redux/components/ReduxIcon.js +8 -1
- package/lib/module/redux/components/ReduxModal.js +698 -1
- package/lib/module/redux/hooks/useAutoInstrumentRedux.js +183 -1
- package/lib/module/redux/hooks/useReduxActions.js +54 -1
- package/lib/module/redux/sync/reduxSyncAdapter.js +188 -1
- package/lib/module/redux/utils/activeStoreRegistry.js +92 -1
- package/lib/module/redux/utils/autoInstrument.js +201 -1
- package/lib/module/redux/utils/buoyReduxMiddleware.js +188 -1
- package/lib/module/redux/utils/createReduxHistoryAdapter.js +142 -1
- package/lib/module/redux/utils/devtoolsHook.js +145 -1
- package/lib/module/redux/utils/reduxActionStore.js +465 -1
- package/lib/module/redux/utils/snapshotProvider.js +157 -1
- package/lib/module/redux/utils/testIDs.js +68 -1
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxActionButton.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxActionDetailContent.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxActionDetailView.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxAutoInstrument.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxIcon.d.ts.map +1 -0
- package/lib/typescript/redux/components/ReduxModal.d.ts.map +1 -0
- package/lib/typescript/redux/hooks/useAutoInstrumentRedux.d.ts.map +1 -0
- package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +1 -0
- package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts.map +1 -0
- package/lib/typescript/redux/types/index.d.ts.map +1 -0
- package/lib/typescript/redux/utils/activeStoreRegistry.d.ts.map +1 -0
- package/lib/typescript/redux/utils/autoInstrument.d.ts.map +1 -0
- package/lib/typescript/redux/utils/buoyReduxMiddleware.d.ts.map +1 -0
- package/lib/typescript/redux/utils/createReduxHistoryAdapter.d.ts.map +1 -0
- package/lib/typescript/redux/utils/devtoolsHook.d.ts.map +1 -0
- package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +1 -0
- package/lib/typescript/redux/utils/snapshotProvider.d.ts.map +1 -0
- package/lib/typescript/redux/utils/testIDs.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -1 +1,433 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ReduxActionDetailContent
|
|
5
|
+
*
|
|
6
|
+
* Enhanced detail view for a Redux action with 3 view modes:
|
|
7
|
+
* - ACTION: View action details, payload, meta, error
|
|
8
|
+
* - STATE: View current state after action
|
|
9
|
+
* - DIFF: Compare prev vs next state
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { View, Text, StyleSheet, ScrollView } from "react-native";
|
|
13
|
+
import { useState, useCallback, useMemo } from "react";
|
|
14
|
+
import { macOSColors, night, EventStepperFooter, formatRelativeTime, parseValue, monoFont } from "@buoy-gg/shared-ui";
|
|
15
|
+
import { DataViewer, SplitDiffViewer, TreeDiffViewer, diffThemes } from "@buoy-gg/shared-ui/dataViewer";
|
|
16
|
+
import { ReduxDetailViewToggle } from "./ReduxDetailViewToggle";
|
|
17
|
+
import { ReduxActionInfoView } from "./ReduxActionInfoView";
|
|
18
|
+
import { DiffModeTabs, CompareBar } from "@buoy-gg/shared-ui";
|
|
19
|
+
import { REDUX_TEST_ID } from "../utils/testIDs";
|
|
20
|
+
import { isEvictedState, STATE_RETENTION_LIMIT } from "../utils/reduxActionStore";
|
|
21
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
+
/**
|
|
23
|
+
* Get color for action type
|
|
24
|
+
*/
|
|
25
|
+
function getActionColor(type) {
|
|
26
|
+
if (type.includes("/pending")) return macOSColors.semantic.warning;
|
|
27
|
+
if (type.includes("/fulfilled")) return macOSColors.semantic.success;
|
|
28
|
+
if (type.includes("/rejected")) return macOSColors.semantic.error;
|
|
29
|
+
if (type.startsWith("@@")) return macOSColors.text.muted;
|
|
30
|
+
return macOSColors.semantic.info;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get short action label
|
|
35
|
+
*/
|
|
36
|
+
function getActionLabel(type) {
|
|
37
|
+
if (type.includes("/pending")) return "PENDING";
|
|
38
|
+
if (type.includes("/fulfilled")) return "FULFILLED";
|
|
39
|
+
if (type.includes("/rejected")) return "REJECTED";
|
|
40
|
+
if (type.startsWith("@@")) return "INTERNAL";
|
|
41
|
+
const parts = type.split("/");
|
|
42
|
+
return parts[parts.length - 1]?.toUpperCase() || "ACTION";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the type (object, array, string, etc.)
|
|
47
|
+
*/
|
|
48
|
+
function getValueType(value) {
|
|
49
|
+
if (value === null) return "null";
|
|
50
|
+
if (value === undefined) return "undefined";
|
|
51
|
+
if (Array.isArray(value)) return "array";
|
|
52
|
+
return typeof value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Format timestamp for display
|
|
57
|
+
*/
|
|
58
|
+
function formatTimestamp(timestamp) {
|
|
59
|
+
const date = new Date(timestamp);
|
|
60
|
+
return date.toLocaleTimeString("en-US", {
|
|
61
|
+
hour12: false,
|
|
62
|
+
hour: "2-digit",
|
|
63
|
+
minute: "2-digit",
|
|
64
|
+
second: "2-digit"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Diff mode tabs configuration
|
|
70
|
+
*/
|
|
71
|
+
const DIFF_MODE_TABS = [{
|
|
72
|
+
key: "tree",
|
|
73
|
+
label: "TREE VIEW"
|
|
74
|
+
}, {
|
|
75
|
+
key: "split",
|
|
76
|
+
label: "SPLIT VIEW"
|
|
77
|
+
}];
|
|
78
|
+
export function ReduxActionDetailContent({
|
|
79
|
+
action,
|
|
80
|
+
actions,
|
|
81
|
+
selectedIndex,
|
|
82
|
+
onIndexChange,
|
|
83
|
+
disableInternalFooter = false,
|
|
84
|
+
initialView = "action"
|
|
85
|
+
}) {
|
|
86
|
+
// View state (initialView seeds it once; taps own it afterwards)
|
|
87
|
+
const [activeView, setActiveView] = useState(initialView);
|
|
88
|
+
const [diffMode, setDiffMode] = useState("tree");
|
|
89
|
+
const totalActions = actions.length;
|
|
90
|
+
/**
|
|
91
|
+
* The state trees this action was recorded with are gone.
|
|
92
|
+
*
|
|
93
|
+
* Not a failure: the store keeps raw prev/next state for the most recent
|
|
94
|
+
* actions only, because with structural sharing broken (a store switch, a
|
|
95
|
+
* rehydration) each retained action pins a distinct multi-MB subtree and a
|
|
96
|
+
* few dozen of them are enough to OOM-kill a large app. But it has to be
|
|
97
|
+
* SAID. The sentinel left behind is an ordinary object, so a state view that
|
|
98
|
+
* just rendered it showed `{ __buoyStateEvicted: true, … }` under the
|
|
99
|
+
* heading "STATE AFTER ACTION" — which reads as the app's actual state — and
|
|
100
|
+
* a diff of two identical sentinels reported "no changes", which is a lie
|
|
101
|
+
* about the app rather than about the recording.
|
|
102
|
+
*/
|
|
103
|
+
const stateEvicted = isEvictedState(action.nextState);
|
|
104
|
+
const actionColor = getActionColor(action.type);
|
|
105
|
+
const actionLabel = getActionLabel(action.type);
|
|
106
|
+
const stateType = getValueType(parseValue(action.nextState));
|
|
107
|
+
|
|
108
|
+
// Actions are in reverse chronological order (newest first, oldest last)
|
|
109
|
+
const chronologicalNumber = totalActions - selectedIndex;
|
|
110
|
+
const prevChronologicalNumber = chronologicalNumber - 1;
|
|
111
|
+
|
|
112
|
+
// Get the previous action in chronological order (which is the NEXT index in the array)
|
|
113
|
+
const prevActionIndex = selectedIndex < totalActions - 1 ? selectedIndex + 1 : null;
|
|
114
|
+
const prevAction = prevActionIndex !== null ? actions[prevActionIndex] : null;
|
|
115
|
+
|
|
116
|
+
// Compare bar info for diff view
|
|
117
|
+
const leftEvent = useMemo(() => ({
|
|
118
|
+
index: prevActionIndex ?? 0,
|
|
119
|
+
label: prevChronologicalNumber > 0 ? `#${prevChronologicalNumber}` : "Initial",
|
|
120
|
+
timestamp: prevAction ? formatTimestamp(prevAction.timestamp) : "",
|
|
121
|
+
relativeTime: prevAction ? formatRelativeTime(new Date(prevAction.timestamp)) : "state",
|
|
122
|
+
badge: prevAction ? /*#__PURE__*/_jsx(View, {
|
|
123
|
+
style: [styles.actionBadgeSmall, {
|
|
124
|
+
backgroundColor: `${getActionColor(prevAction.type)}20`
|
|
125
|
+
}],
|
|
126
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
127
|
+
style: [styles.actionTextSmall, {
|
|
128
|
+
color: getActionColor(prevAction.type)
|
|
129
|
+
}],
|
|
130
|
+
children: getActionLabel(prevAction.type)
|
|
131
|
+
})
|
|
132
|
+
}) : undefined
|
|
133
|
+
}), [prevActionIndex, prevAction, prevChronologicalNumber]);
|
|
134
|
+
const rightEvent = useMemo(() => ({
|
|
135
|
+
index: selectedIndex,
|
|
136
|
+
label: `#${chronologicalNumber}`,
|
|
137
|
+
timestamp: formatTimestamp(action.timestamp),
|
|
138
|
+
relativeTime: formatRelativeTime(new Date(action.timestamp)),
|
|
139
|
+
badge: /*#__PURE__*/_jsx(View, {
|
|
140
|
+
style: [styles.actionBadgeSmall, {
|
|
141
|
+
backgroundColor: `${actionColor}20`
|
|
142
|
+
}],
|
|
143
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
144
|
+
style: [styles.actionTextSmall, {
|
|
145
|
+
color: actionColor
|
|
146
|
+
}],
|
|
147
|
+
children: actionLabel
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
}), [selectedIndex, action.timestamp, actionColor, actionLabel, chronologicalNumber]);
|
|
151
|
+
|
|
152
|
+
// Render state view
|
|
153
|
+
const renderStateView = useCallback(() => {
|
|
154
|
+
if (stateEvicted) {
|
|
155
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
156
|
+
style: styles.contentCard,
|
|
157
|
+
testID: `${REDUX_TEST_ID}-state-evicted`,
|
|
158
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
159
|
+
style: styles.valueHeader,
|
|
160
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
161
|
+
style: styles.valueLabel,
|
|
162
|
+
children: "STATE AFTER ACTION"
|
|
163
|
+
})
|
|
164
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
165
|
+
style: styles.evictedText,
|
|
166
|
+
children: `Not retained. Raw state is kept for the ${STATE_RETENTION_LIMIT} most recent actions, so this action's before/after trees have been released.`
|
|
167
|
+
})]
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const parsed = parseValue(action.nextState);
|
|
171
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
172
|
+
style: styles.contentCard,
|
|
173
|
+
testID: `${REDUX_TEST_ID}-state-card`,
|
|
174
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
175
|
+
style: styles.valueHeader,
|
|
176
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
177
|
+
style: styles.valueLabel,
|
|
178
|
+
children: "STATE AFTER ACTION"
|
|
179
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
180
|
+
style: styles.valueHeaderBadges,
|
|
181
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
182
|
+
style: [styles.actionBadge, {
|
|
183
|
+
backgroundColor: `${actionColor}20`
|
|
184
|
+
}],
|
|
185
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
186
|
+
style: [styles.actionText, {
|
|
187
|
+
color: actionColor
|
|
188
|
+
}],
|
|
189
|
+
children: actionLabel
|
|
190
|
+
})
|
|
191
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
192
|
+
style: styles.typeBadge,
|
|
193
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
194
|
+
style: styles.typeText,
|
|
195
|
+
testID: `${REDUX_TEST_ID}-state-type`,
|
|
196
|
+
children: stateType.toUpperCase()
|
|
197
|
+
})
|
|
198
|
+
})]
|
|
199
|
+
})]
|
|
200
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
201
|
+
style: styles.dataViewerContainer,
|
|
202
|
+
children: /*#__PURE__*/_jsx(DataViewer, {
|
|
203
|
+
title: "",
|
|
204
|
+
data: parsed,
|
|
205
|
+
showTypeFilter: true,
|
|
206
|
+
rawMode: true,
|
|
207
|
+
initialExpanded: true
|
|
208
|
+
})
|
|
209
|
+
})]
|
|
210
|
+
});
|
|
211
|
+
}, [action.nextState, actionColor, actionLabel, stateType, stateEvicted]);
|
|
212
|
+
|
|
213
|
+
// Render diff content
|
|
214
|
+
const renderDiffContent = useCallback(() => {
|
|
215
|
+
const prevState = parseValue(action.prevState);
|
|
216
|
+
const nextState = parseValue(action.nextState);
|
|
217
|
+
if (diffMode === "split") {
|
|
218
|
+
return /*#__PURE__*/_jsx(ScrollView, {
|
|
219
|
+
style: {
|
|
220
|
+
flex: 1
|
|
221
|
+
},
|
|
222
|
+
showsVerticalScrollIndicator: true,
|
|
223
|
+
children: /*#__PURE__*/_jsx(SplitDiffViewer, {
|
|
224
|
+
oldValue: prevState,
|
|
225
|
+
newValue: nextState,
|
|
226
|
+
theme: diffThemes.devToolsDefault,
|
|
227
|
+
options: {
|
|
228
|
+
hideLineNumbers: false,
|
|
229
|
+
disableWordDiff: false,
|
|
230
|
+
showDiffOnly: false,
|
|
231
|
+
compareMethod: "words",
|
|
232
|
+
contextLines: 3
|
|
233
|
+
},
|
|
234
|
+
showThemeName: false
|
|
235
|
+
})
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return /*#__PURE__*/_jsx(TreeDiffViewer, {
|
|
239
|
+
oldValue: prevState,
|
|
240
|
+
newValue: nextState
|
|
241
|
+
});
|
|
242
|
+
}, [action.prevState, action.nextState, diffMode]);
|
|
243
|
+
|
|
244
|
+
// Navigation handlers
|
|
245
|
+
const handleFooterPrevious = useCallback(() => {
|
|
246
|
+
onIndexChange(Math.min(totalActions - 1, selectedIndex + 1));
|
|
247
|
+
}, [selectedIndex, totalActions, onIndexChange]);
|
|
248
|
+
const handleFooterNext = useCallback(() => {
|
|
249
|
+
onIndexChange(Math.max(0, selectedIndex - 1));
|
|
250
|
+
}, [selectedIndex, onIndexChange]);
|
|
251
|
+
|
|
252
|
+
// A diff needs two real trees, and both live on THIS action
|
|
253
|
+
// (prevState/nextState) — no siblings needed, so the action count says
|
|
254
|
+
// nothing (gating on it greyed DIFF out for every redux event opened from
|
|
255
|
+
// the Events timeline, which passes a one-element array). Eviction of
|
|
256
|
+
// EITHER side does disable it: two identical sentinels diff cleanly to
|
|
257
|
+
// "no changes", which reads as a lie.
|
|
258
|
+
const diffDisabled = stateEvicted || isEvictedState(action.prevState) || action.prevState === undefined;
|
|
259
|
+
const showInternalFooter = !disableInternalFooter && totalActions > 1;
|
|
260
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
261
|
+
style: styles.container,
|
|
262
|
+
children: [/*#__PURE__*/_jsx(ReduxDetailViewToggle, {
|
|
263
|
+
activeView: activeView,
|
|
264
|
+
onViewChange: setActiveView,
|
|
265
|
+
diffDisabled: diffDisabled
|
|
266
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
267
|
+
style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
|
|
268
|
+
children: [activeView === "action" && /*#__PURE__*/_jsx(ReduxActionInfoView, {
|
|
269
|
+
action: action
|
|
270
|
+
}), activeView === "state" && /*#__PURE__*/_jsx(View, {
|
|
271
|
+
style: styles.stateContainer,
|
|
272
|
+
children: renderStateView()
|
|
273
|
+
}), activeView === "diff" && /*#__PURE__*/_jsxs(View, {
|
|
274
|
+
style: styles.diffContainer,
|
|
275
|
+
testID: `${REDUX_TEST_ID}-diff`,
|
|
276
|
+
children: [/*#__PURE__*/_jsx(DiffModeTabs, {
|
|
277
|
+
tabs: DIFF_MODE_TABS,
|
|
278
|
+
activeTab: diffMode,
|
|
279
|
+
onTabChange: setDiffMode,
|
|
280
|
+
testIDPrefix: `${REDUX_TEST_ID}-diff-tab`
|
|
281
|
+
}), /*#__PURE__*/_jsx(CompareBar, {
|
|
282
|
+
leftEvent: leftEvent,
|
|
283
|
+
rightEvent: rightEvent
|
|
284
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
285
|
+
style: styles.diffContent,
|
|
286
|
+
testID: `${REDUX_TEST_ID}-diff-content`,
|
|
287
|
+
children: renderDiffContent()
|
|
288
|
+
})]
|
|
289
|
+
})]
|
|
290
|
+
}), showInternalFooter && /*#__PURE__*/_jsx(EventStepperFooter, {
|
|
291
|
+
currentIndex: chronologicalNumber - 1,
|
|
292
|
+
totalItems: totalActions,
|
|
293
|
+
onPrevious: handleFooterPrevious,
|
|
294
|
+
onNext: handleFooterNext,
|
|
295
|
+
itemLabel: "Action",
|
|
296
|
+
subtitle: formatRelativeTime(new Date(action.timestamp)),
|
|
297
|
+
absolute: true
|
|
298
|
+
})]
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* External footer component for modal use
|
|
304
|
+
*/
|
|
305
|
+
export function ReduxActionDetailFooter({
|
|
306
|
+
action,
|
|
307
|
+
actions,
|
|
308
|
+
selectedIndex,
|
|
309
|
+
onIndexChange
|
|
310
|
+
}) {
|
|
311
|
+
const totalActions = actions.length;
|
|
312
|
+
if (totalActions <= 1) return null;
|
|
313
|
+
const chronologicalNumber = totalActions - selectedIndex;
|
|
314
|
+
return /*#__PURE__*/_jsx(EventStepperFooter, {
|
|
315
|
+
currentIndex: chronologicalNumber - 1,
|
|
316
|
+
totalItems: totalActions,
|
|
317
|
+
onPrevious: () => onIndexChange(Math.min(totalActions - 1, selectedIndex + 1)),
|
|
318
|
+
onNext: () => onIndexChange(Math.max(0, selectedIndex - 1)),
|
|
319
|
+
itemLabel: "Action",
|
|
320
|
+
subtitle: formatRelativeTime(new Date(action.timestamp))
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const styles = StyleSheet.create({
|
|
324
|
+
container: {
|
|
325
|
+
flex: 1,
|
|
326
|
+
// Transparent so the night sheet's star field shows through.
|
|
327
|
+
backgroundColor: "transparent"
|
|
328
|
+
},
|
|
329
|
+
contentArea: {
|
|
330
|
+
flex: 1
|
|
331
|
+
},
|
|
332
|
+
// Clearance for the absolute EventStepperFooter — only when it renders,
|
|
333
|
+
// otherwise hosts like the Events tool get a dead band at the sheet bottom.
|
|
334
|
+
contentAreaFooterPad: {
|
|
335
|
+
paddingBottom: 96
|
|
336
|
+
},
|
|
337
|
+
// State view styles
|
|
338
|
+
stateContainer: {
|
|
339
|
+
flex: 1,
|
|
340
|
+
padding: 14
|
|
341
|
+
},
|
|
342
|
+
contentCard: {
|
|
343
|
+
backgroundColor: night.color.surface,
|
|
344
|
+
borderRadius: 14,
|
|
345
|
+
padding: 14,
|
|
346
|
+
borderWidth: 1,
|
|
347
|
+
borderColor: night.color.border
|
|
348
|
+
},
|
|
349
|
+
valueHeader: {
|
|
350
|
+
flexDirection: "row",
|
|
351
|
+
alignItems: "center",
|
|
352
|
+
justifyContent: "space-between",
|
|
353
|
+
marginBottom: 8
|
|
354
|
+
},
|
|
355
|
+
valueLabel: {
|
|
356
|
+
fontSize: 10,
|
|
357
|
+
color: night.color.textSecondary,
|
|
358
|
+
fontFamily: monoFont,
|
|
359
|
+
letterSpacing: 0.5,
|
|
360
|
+
fontWeight: "600"
|
|
361
|
+
},
|
|
362
|
+
valueHeaderBadges: {
|
|
363
|
+
flexDirection: "row",
|
|
364
|
+
alignItems: "center",
|
|
365
|
+
gap: 6
|
|
366
|
+
},
|
|
367
|
+
actionBadge: {
|
|
368
|
+
paddingHorizontal: 8,
|
|
369
|
+
paddingVertical: 2,
|
|
370
|
+
borderRadius: 4
|
|
371
|
+
},
|
|
372
|
+
actionText: {
|
|
373
|
+
fontSize: 9,
|
|
374
|
+
fontWeight: "700",
|
|
375
|
+
fontFamily: monoFont,
|
|
376
|
+
letterSpacing: 0.3
|
|
377
|
+
},
|
|
378
|
+
typeBadge: {
|
|
379
|
+
paddingHorizontal: 8,
|
|
380
|
+
paddingVertical: 2,
|
|
381
|
+
borderRadius: 4,
|
|
382
|
+
backgroundColor: night.color.surfaceElevated
|
|
383
|
+
},
|
|
384
|
+
typeText: {
|
|
385
|
+
fontSize: 9,
|
|
386
|
+
fontWeight: "600",
|
|
387
|
+
color: night.color.textTertiary,
|
|
388
|
+
fontFamily: monoFont
|
|
389
|
+
},
|
|
390
|
+
valueBox: {
|
|
391
|
+
// Inset code box — darker than the card, the night track color.
|
|
392
|
+
backgroundColor: night.color.bg,
|
|
393
|
+
borderRadius: 6,
|
|
394
|
+
borderWidth: 1,
|
|
395
|
+
borderColor: night.color.border,
|
|
396
|
+
padding: 8
|
|
397
|
+
},
|
|
398
|
+
evictedText: {
|
|
399
|
+
fontSize: 12,
|
|
400
|
+
color: night.color.textSecondary,
|
|
401
|
+
lineHeight: 18
|
|
402
|
+
},
|
|
403
|
+
valueText: {
|
|
404
|
+
fontSize: 12,
|
|
405
|
+
color: night.color.text,
|
|
406
|
+
fontFamily: monoFont,
|
|
407
|
+
lineHeight: 18
|
|
408
|
+
},
|
|
409
|
+
// Diff view styles
|
|
410
|
+
diffContainer: {
|
|
411
|
+
flex: 1
|
|
412
|
+
},
|
|
413
|
+
diffContent: {
|
|
414
|
+
flex: 1,
|
|
415
|
+
paddingHorizontal: 14
|
|
416
|
+
},
|
|
417
|
+
// Action badges for compare bar
|
|
418
|
+
actionBadgeSmall: {
|
|
419
|
+
paddingHorizontal: 6,
|
|
420
|
+
paddingVertical: 1,
|
|
421
|
+
borderRadius: 3
|
|
422
|
+
},
|
|
423
|
+
actionTextSmall: {
|
|
424
|
+
fontSize: 8,
|
|
425
|
+
fontWeight: "700",
|
|
426
|
+
fontFamily: monoFont
|
|
427
|
+
},
|
|
428
|
+
dataViewerContainer: {
|
|
429
|
+
marginTop: -12,
|
|
430
|
+
marginHorizontal: -12,
|
|
431
|
+
marginBottom: -12
|
|
432
|
+
}
|
|
433
|
+
});
|