@buoy-gg/redux 7.0.40 → 7.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +11 -102
  2. package/lib/commonjs/index.js +1 -256
  3. package/lib/commonjs/preset.js +1 -90
  4. package/lib/commonjs/redux/components/ReduxActionButton.js +1 -131
  5. package/lib/commonjs/redux/components/ReduxActionDetailContent.js +1 -437
  6. package/lib/commonjs/redux/components/ReduxActionDetailView.js +1 -401
  7. package/lib/commonjs/redux/components/ReduxActionInfoView.js +1 -836
  8. package/lib/commonjs/redux/components/ReduxActionItem.js +1 -334
  9. package/lib/commonjs/redux/components/ReduxAutoInstrument.js +1 -20
  10. package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +1 -50
  11. package/lib/commonjs/redux/components/ReduxIcon.js +1 -18
  12. package/lib/commonjs/redux/components/ReduxModal.js +1 -703
  13. package/lib/commonjs/redux/hooks/reduxPeer.js +1 -0
  14. package/lib/commonjs/redux/hooks/reduxPeer.web.js +1 -0
  15. package/lib/commonjs/redux/hooks/useAutoInstrumentRedux.js +1 -187
  16. package/lib/commonjs/redux/hooks/useReduxActions.js +1 -58
  17. package/lib/commonjs/redux/sync/reduxSyncAdapter.js +1 -191
  18. package/lib/commonjs/redux/types/index.js +1 -1
  19. package/lib/commonjs/redux/utils/activeStoreRegistry.js +1 -104
  20. package/lib/commonjs/redux/utils/autoInstrument.js +1 -231
  21. package/lib/commonjs/redux/utils/buoyReduxMiddleware.js +1 -202
  22. package/lib/commonjs/redux/utils/createReduxHistoryAdapter.js +1 -146
  23. package/lib/commonjs/redux/utils/devtoolsHook.js +1 -152
  24. package/lib/commonjs/redux/utils/reduxActionStore.js +1 -473
  25. package/lib/commonjs/redux/utils/snapshotProvider.js +1 -158
  26. package/lib/commonjs/redux/utils/testIDs.js +1 -75
  27. package/lib/module/index.js +1 -125
  28. package/lib/module/preset.js +1 -87
  29. package/lib/module/redux/components/ReduxActionButton.js +1 -128
  30. package/lib/module/redux/components/ReduxActionDetailContent.js +1 -433
  31. package/lib/module/redux/components/ReduxActionDetailView.js +1 -397
  32. package/lib/module/redux/components/ReduxActionInfoView.js +1 -831
  33. package/lib/module/redux/components/ReduxActionItem.js +1 -330
  34. package/lib/module/redux/components/ReduxAutoInstrument.js +1 -17
  35. package/lib/module/redux/components/ReduxDetailViewToggle.js +1 -45
  36. package/lib/module/redux/components/ReduxIcon.js +1 -8
  37. package/lib/module/redux/components/ReduxModal.js +1 -698
  38. package/lib/module/redux/hooks/reduxPeer.js +1 -0
  39. package/lib/module/redux/hooks/reduxPeer.web.js +1 -0
  40. package/lib/module/redux/hooks/useAutoInstrumentRedux.js +1 -183
  41. package/lib/module/redux/hooks/useReduxActions.js +1 -54
  42. package/lib/module/redux/sync/reduxSyncAdapter.js +1 -188
  43. package/lib/module/redux/types/index.js +1 -1
  44. package/lib/module/redux/utils/activeStoreRegistry.js +1 -92
  45. package/lib/module/redux/utils/autoInstrument.js +1 -201
  46. package/lib/module/redux/utils/buoyReduxMiddleware.js +1 -188
  47. package/lib/module/redux/utils/createReduxHistoryAdapter.js +1 -142
  48. package/lib/module/redux/utils/devtoolsHook.js +1 -145
  49. package/lib/module/redux/utils/reduxActionStore.js +1 -465
  50. package/lib/module/redux/utils/snapshotProvider.js +1 -157
  51. package/lib/module/redux/utils/testIDs.js +1 -68
  52. package/lib/typescript/redux/hooks/reduxPeer.d.ts +3 -0
  53. package/lib/typescript/redux/hooks/reduxPeer.web.d.ts +2 -0
  54. package/lib/typescript/redux/hooks/useAutoInstrumentRedux.d.ts +3 -15
  55. package/lib/web/index.mjs +1 -0
  56. package/package.json +36 -13
  57. package/lib/typescript/index.d.ts.map +0 -1
  58. package/lib/typescript/preset.d.ts.map +0 -1
  59. package/lib/typescript/redux/components/ReduxActionButton.d.ts.map +0 -1
  60. package/lib/typescript/redux/components/ReduxActionDetailContent.d.ts.map +0 -1
  61. package/lib/typescript/redux/components/ReduxActionDetailView.d.ts.map +0 -1
  62. package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +0 -1
  63. package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +0 -1
  64. package/lib/typescript/redux/components/ReduxAutoInstrument.d.ts.map +0 -1
  65. package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +0 -1
  66. package/lib/typescript/redux/components/ReduxIcon.d.ts.map +0 -1
  67. package/lib/typescript/redux/components/ReduxModal.d.ts.map +0 -1
  68. package/lib/typescript/redux/hooks/useAutoInstrumentRedux.d.ts.map +0 -1
  69. package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +0 -1
  70. package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts.map +0 -1
  71. package/lib/typescript/redux/types/index.d.ts.map +0 -1
  72. package/lib/typescript/redux/utils/activeStoreRegistry.d.ts.map +0 -1
  73. package/lib/typescript/redux/utils/autoInstrument.d.ts.map +0 -1
  74. package/lib/typescript/redux/utils/buoyReduxMiddleware.d.ts.map +0 -1
  75. package/lib/typescript/redux/utils/createReduxHistoryAdapter.d.ts.map +0 -1
  76. package/lib/typescript/redux/utils/devtoolsHook.d.ts.map +0 -1
  77. package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +0 -1
  78. package/lib/typescript/redux/utils/snapshotProvider.d.ts.map +0 -1
  79. package/lib/typescript/redux/utils/testIDs.d.ts.map +0 -1
@@ -1,433 +1 @@
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
- });
1
+ "use strict";import{View as o,Text as d,StyleSheet as X,ScrollView as q}from"react-native";import{useState as L,useCallback as v,useMemo as B}from"react";import{macOSColors as g,night as l,EventStepperFooter as H,formatRelativeTime as D,parseValue as w,monoFont as h}from"@buoy-gg/shared-ui";import{DataViewer as K,SplitDiffViewer as Q,TreeDiffViewer as Y,diffThemes as Z}from"@buoy-gg/shared-ui/dataViewer";import{ReduxDetailViewToggle as ee}from"./ReduxDetailViewToggle";import{ReduxActionInfoView as te}from"./ReduxActionInfoView";import{DiffModeTabs as re,CompareBar as oe}from"@buoy-gg/shared-ui";import{REDUX_TEST_ID as p}from"../utils/testIDs";import{isEvictedState as M,STATE_RETENTION_LIMIT as ne}from"../utils/reduxActionStore";import{jsx as t,jsxs as c}from"react/jsx-runtime";function F(e){if(e.includes("/pending"))return g.semantic.warning;if(e.includes("/fulfilled"))return g.semantic.success;if(e.includes("/rejected"))return g.semantic.error;if(e.startsWith("@@"))return g.text.muted;return g.semantic.info}function $(e){if(e.includes("/pending"))return"PENDING";if(e.includes("/fulfilled"))return"FULFILLED";if(e.includes("/rejected"))return"REJECTED";if(e.startsWith("@@"))return"INTERNAL";const i=e.split("/");return i[i.length-1]?.toUpperCase()||"ACTION"}function ie(e){if(e===null)return"null";if(e===void 0)return"undefined";if(Array.isArray(e))return"array";return typeof e}function k(e){const i=new Date(e);return i.toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"})}const ae=[{key:"tree",label:"TREE VIEW"},{key:"split",label:"SPLIT VIEW"}];export function ReduxActionDetailContent({action:e,actions:i,selectedIndex:n,onIndexChange:s,disableInternalFooter:f=false,initialView:C="action"}){const[b,z]=L(C);const[E,W]=L("tree");const u=i.length;const A=M(e.nextState);const m=F(e.type);const T=$(e.type);const N=ie(w(e.nextState));const y=u-n;const V=y-1;const S=n<u-1?n+1:null;const a=S!==null?i[S]:null;const P=B(()=>({index:S??0,label:V>0?`#${V}`:"Initial",timestamp:a?k(a.timestamp):"",relativeTime:a?D(new Date(a.timestamp)):"state",badge:a?t(o,{style:[r.actionBadgeSmall,{backgroundColor:`${F(a.type)}20`}],children:t(d,{style:[r.actionTextSmall,{color:F(a.type)}],children:$(a.type)})}):void 0}),[S,a,V]);const _=B(()=>({index:n,label:`#${y}`,timestamp:k(e.timestamp),relativeTime:D(new Date(e.timestamp)),badge:t(o,{style:[r.actionBadgeSmall,{backgroundColor:`${m}20`}],children:t(d,{style:[r.actionTextSmall,{color:m}],children:T})})}),[n,e.timestamp,m,T,y]);const j=v(()=>{if(A){return c(o,{style:r.contentCard,testID:`${p}-state-evicted`,children:[t(o,{style:r.valueHeader,children:t(d,{style:r.valueLabel,children:"STATE AFTER ACTION"})}),t(d,{style:r.evictedText,children:`Not retained. Raw state is kept for the ${ne} most recent actions, so this action's before/after trees have been released.`})]})}const x=w(e.nextState);return c(o,{style:r.contentCard,testID:`${p}-state-card`,children:[c(o,{style:r.valueHeader,children:[t(d,{style:r.valueLabel,children:"STATE AFTER ACTION"}),c(o,{style:r.valueHeaderBadges,children:[t(o,{style:[r.actionBadge,{backgroundColor:`${m}20`}],children:t(d,{style:[r.actionText,{color:m}],children:T})}),t(o,{style:r.typeBadge,children:t(d,{style:r.typeText,testID:`${p}-state-type`,children:N.toUpperCase()})})]})]}),t(o,{style:r.dataViewerContainer,children:t(K,{title:"",data:x,showTypeFilter:true,rawMode:true,initialExpanded:true})})]})},[e.nextState,m,T,N,A]);const O=v(()=>{const x=w(e.prevState);const I=w(e.nextState);if(E==="split"){return t(q,{style:{flex:1},showsVerticalScrollIndicator:true,children:t(Q,{oldValue:x,newValue:I,theme:Z.devToolsDefault,options:{hideLineNumbers:false,disableWordDiff:false,showDiffOnly:false,compareMethod:"words",contextLines:3},showThemeName:false})})}return t(Y,{oldValue:x,newValue:I})},[e.prevState,e.nextState,E]);const U=v(()=>{s(Math.min(u-1,n+1))},[n,u,s]);const G=v(()=>{s(Math.max(0,n-1))},[n,s]);const J=A||M(e.prevState)||e.prevState===void 0;const R=!f&&u>1;return c(o,{style:r.container,children:[t(ee,{activeView:b,onViewChange:z,diffDisabled:J}),c(o,{style:[r.contentArea,R&&r.contentAreaFooterPad],children:[b==="action"&&t(te,{action:e}),b==="state"&&t(o,{style:r.stateContainer,children:j()}),b==="diff"&&c(o,{style:r.diffContainer,testID:`${p}-diff`,children:[t(re,{tabs:ae,activeTab:E,onTabChange:W,testIDPrefix:`${p}-diff-tab`}),t(oe,{leftEvent:P,rightEvent:_}),t(o,{style:r.diffContent,testID:`${p}-diff-content`,children:O()})]})]}),R&&t(H,{currentIndex:y-1,totalItems:u,onPrevious:U,onNext:G,itemLabel:"Action",subtitle:D(new Date(e.timestamp)),absolute:true})]})}export function ReduxActionDetailFooter({action:e,actions:i,selectedIndex:n,onIndexChange:s}){const f=i.length;if(f<=1)return null;const C=f-n;return t(H,{currentIndex:C-1,totalItems:f,onPrevious:()=>s(Math.min(f-1,n+1)),onNext:()=>s(Math.max(0,n-1)),itemLabel:"Action",subtitle:D(new Date(e.timestamp))})}const r=X.create({container:{flex:1,backgroundColor:"transparent"},contentArea:{flex:1},contentAreaFooterPad:{paddingBottom:96},stateContainer:{flex:1,padding:14},contentCard:{backgroundColor:l.color.surface,borderRadius:14,padding:14,borderWidth:1,borderColor:l.color.border},valueHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:8},valueLabel:{fontSize:10,color:l.color.textSecondary,fontFamily:h,letterSpacing:.5,fontWeight:"600"},valueHeaderBadges:{flexDirection:"row",alignItems:"center",gap:6},actionBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4},actionText:{fontSize:9,fontWeight:"700",fontFamily:h,letterSpacing:.3},typeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4,backgroundColor:l.color.surfaceElevated},typeText:{fontSize:9,fontWeight:"600",color:l.color.textTertiary,fontFamily:h},valueBox:{backgroundColor:l.color.bg,borderRadius:6,borderWidth:1,borderColor:l.color.border,padding:8},evictedText:{fontSize:12,color:l.color.textSecondary,lineHeight:18},valueText:{fontSize:12,color:l.color.text,fontFamily:h,lineHeight:18},diffContainer:{flex:1},diffContent:{flex:1,paddingHorizontal:14},actionBadgeSmall:{paddingHorizontal:6,paddingVertical:1,borderRadius:3},actionTextSmall:{fontSize:8,fontWeight:"700",fontFamily:h},dataViewerContainer:{marginTop:-12,marginHorizontal:-12,marginBottom:-12}});