react-native-inapp-inspector 1.1.11 → 1.1.13

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 (53) hide show
  1. package/dist/commonjs/components/AnalyticsDetail.js +93 -479
  2. package/dist/commonjs/components/AnalyticsEventCard.js +25 -25
  3. package/dist/commonjs/components/ConsoleLogCard.js +3 -1
  4. package/dist/commonjs/components/HighlightText.js +1 -1
  5. package/dist/commonjs/components/JsonViewer.d.ts +3 -1
  6. package/dist/commonjs/components/JsonViewer.js +327 -9
  7. package/dist/commonjs/components/MetaAccordion.d.ts +10 -1
  8. package/dist/commonjs/components/MetaAccordion.js +121 -24
  9. package/dist/commonjs/components/NetworkIcons.d.ts +1 -0
  10. package/dist/commonjs/components/NetworkIcons.js +8 -1
  11. package/dist/commonjs/components/ReduxTreeView.d.ts +12 -17
  12. package/dist/commonjs/components/ReduxTreeView.js +1045 -632
  13. package/dist/commonjs/components/SectionHeader.d.ts +1 -1
  14. package/dist/commonjs/components/SectionHeader.js +7 -1
  15. package/dist/commonjs/components/TouchableScale.js +8 -0
  16. package/dist/commonjs/constants/version.d.ts +1 -1
  17. package/dist/commonjs/constants/version.js +1 -1
  18. package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
  19. package/dist/commonjs/customHooks/reduxLogger.js +2 -0
  20. package/dist/commonjs/helpers/index.d.ts +3 -0
  21. package/dist/commonjs/helpers/index.js +103 -1
  22. package/dist/commonjs/helpers/settingsStore.d.ts +1 -0
  23. package/dist/commonjs/helpers/settingsStore.js +4 -0
  24. package/dist/commonjs/index.js +385 -339
  25. package/dist/commonjs/types/index.d.ts +3 -0
  26. package/dist/esm/components/AnalyticsDetail.js +94 -480
  27. package/dist/esm/components/AnalyticsEventCard.js +25 -25
  28. package/dist/esm/components/ConsoleLogCard.js +3 -1
  29. package/dist/esm/components/HighlightText.js +3 -3
  30. package/dist/esm/components/JsonViewer.d.ts +3 -1
  31. package/dist/esm/components/JsonViewer.js +295 -10
  32. package/dist/esm/components/MetaAccordion.d.ts +10 -1
  33. package/dist/esm/components/MetaAccordion.js +90 -26
  34. package/dist/esm/components/NetworkIcons.d.ts +1 -0
  35. package/dist/esm/components/NetworkIcons.js +6 -0
  36. package/dist/esm/components/ReduxTreeView.d.ts +12 -17
  37. package/dist/esm/components/ReduxTreeView.js +1047 -629
  38. package/dist/esm/components/SectionHeader.d.ts +1 -1
  39. package/dist/esm/components/SectionHeader.js +8 -2
  40. package/dist/esm/components/TouchableScale.js +9 -1
  41. package/dist/esm/constants/version.d.ts +1 -1
  42. package/dist/esm/constants/version.js +1 -1
  43. package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
  44. package/dist/esm/customHooks/reduxLogger.js +2 -0
  45. package/dist/esm/helpers/index.d.ts +3 -0
  46. package/dist/esm/helpers/index.js +100 -1
  47. package/dist/esm/helpers/settingsStore.d.ts +1 -0
  48. package/dist/esm/helpers/settingsStore.js +3 -0
  49. package/dist/esm/index.js +389 -343
  50. package/dist/esm/types/index.d.ts +3 -0
  51. package/example/package-lock.json +33 -74
  52. package/example/package.json +1 -1
  53. package/package.json +1 -1
@@ -36,769 +36,1182 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.ReduxActionTimeline = exports.ReduxTreeView = exports.ReduxTreeIcon = exports.ReduxTimelineIcon = exports.ReduxBoltIcon = exports.ReduxStoreIcon = void 0;
39
+ exports.ReduxTreeView = void 0;
40
40
  const react_1 = __importStar(require("react"));
41
41
  const react_native_1 = require("react-native");
42
42
  const AppColors_1 = require("../styles/AppColors");
43
43
  const AppFonts_1 = require("../styles/AppFonts");
44
44
  const NetworkIcons_1 = require("./NetworkIcons");
45
- const react_native_svg_1 = __importStar(require("react-native-svg"));
46
- const AnimatedEntrance_1 = __importDefault(require("./AnimatedEntrance"));
45
+ const JsonViewer_1 = __importDefault(require("./JsonViewer"));
46
+ const DiffViewer_1 = __importDefault(require("./DiffViewer"));
47
+ const TouchableScale_1 = __importDefault(require("./TouchableScale"));
47
48
  const helpers_1 = require("../helpers");
48
- // #15 copy-to-clipboard control for a single dispatched action
49
- const ActionCopyButton = ({ value }) => {
50
- const [copied, setCopied] = (0, react_1.useState)(false);
51
- return (<react_native_1.Pressable hitSlop={10} onPress={() => {
52
- (0, helpers_1.copyToClipboard)(value(), 'Action');
53
- setCopied(true);
54
- setTimeout(() => setCopied(false), 1200);
55
- }} style={{
56
- width: 26,
57
- height: 26,
58
- borderRadius: 7,
59
- alignItems: 'center',
60
- justifyContent: 'center',
61
- backgroundColor: copied
62
- ? `${AppColors_1.AppColors.greenColor}1A`
63
- : AppColors_1.AppColors.grayBackground,
64
- borderWidth: 1,
65
- borderColor: AppColors_1.AppColors.dividerColor,
66
- }}>
67
- {copied ? (<NetworkIcons_1.CheckIcon color={AppColors_1.AppColors.greenColor} size={13}/>) : (<NetworkIcons_1.CopyIcon color={AppColors_1.AppColors.grayTextWeak} size={13}/>)}
68
- </react_native_1.Pressable>);
49
+ const settingsStore_1 = require("../helpers/settingsStore");
50
+ // Enable LayoutAnimation for Android
51
+ if (react_native_1.Platform.OS === 'android') {
52
+ react_native_1.UIManager.setLayoutAnimationEnabledExperimental?.(true);
53
+ }
54
+ const animateLayout = () => {
55
+ react_native_1.LayoutAnimation.configureNext(react_native_1.LayoutAnimation.Presets.easeInEaseOut);
69
56
  };
70
- // #15 derive the redux module / folder name from an action type.
71
- // Supports RTK slice convention ("booking/setDate" -> "Booking") and
72
- // falls back to the first affected slice.
73
- const getActionModule = (type, affectedSlices) => {
74
- if (type && type.includes('/')) {
75
- const prefix = type.split('/')[0];
76
- if (prefix)
77
- return prefix.charAt(0).toUpperCase() + prefix.slice(1);
57
+ // Chevron pointing left (for back buttons)
58
+ const BackChevronIcon = ({ color = AppColors_1.AppColors.purple, size = 12 }) => (<react_native_1.View style={{ transform: [{ rotate: '180deg' }], marginRight: 4 }}>
59
+ <NetworkIcons_1.ChevronIcon color={color} size={size}/>
60
+ </react_native_1.View>);
61
+ // Chevron pointing right (for list items)
62
+ const ForwardChevronIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12 }) => (<react_native_1.View style={{ transform: [{ rotate: '0deg' }], marginLeft: 'auto' }}>
63
+ <NetworkIcons_1.ChevronIcon color={color} size={size}/>
64
+ </react_native_1.View>);
65
+ // Helper: check if a value recursively contains a string term
66
+ const valueContainsTerm = (val, term) => {
67
+ if (!term)
68
+ return true;
69
+ const t = term.toLowerCase();
70
+ if (val === null || val === undefined)
71
+ return false;
72
+ if (typeof val !== 'object') {
73
+ return String(val).toLowerCase().includes(t);
78
74
  }
79
- if (affectedSlices && affectedSlices.length > 0) {
80
- const s = affectedSlices[0];
81
- return s.charAt(0).toUpperCase() + s.slice(1);
75
+ if (Array.isArray(val)) {
76
+ return val.some(item => valueContainsTerm(item, term));
82
77
  }
83
- return null;
84
- };
85
- // Custom icons
86
- const DatabaseIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12 }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
87
- <react_native_svg_1.Path d="M12 2C6.5 2 2 4.2 2 7v10c0 2.8 4.5 5 10 5s10-2.2 10-5V7c0-2.8-4.5-5-10-5z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
88
- <react_native_svg_1.Path d="M2 12c0 2.8 4.5 5 10 5s10-2.2 10-5" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
89
- <react_native_svg_1.Path d="M2 7c0 2.8 4.5 5 10 5s10-2.2 10-5" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
90
- </react_native_svg_1.default>);
91
- const BoltIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12 }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
92
- <react_native_svg_1.Path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill={color} stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
93
- </react_native_svg_1.default>);
94
- const FolderIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12 }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
95
- <react_native_svg_1.Path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
96
- </react_native_svg_1.default>);
97
- // Exported icons so the Redux tab's section headers and sub-tab buttons can
98
- // render real vector icons instead of emoji (which fail to render on some
99
- // Android/font setups).
100
- const ReduxStoreIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12, }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
101
- <react_native_svg_1.Path d="M3 9l1.5-5h15L21 9M3 9v10a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V9M3 9h18M7 9v3a2 2 0 0 0 4 0V9m2 0v3a2 2 0 0 0 4 0V9" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
102
- </react_native_svg_1.default>);
103
- exports.ReduxStoreIcon = ReduxStoreIcon;
104
- const ReduxBoltIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12, }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
105
- <react_native_svg_1.Path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill={color} stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
106
- </react_native_svg_1.default>);
107
- exports.ReduxBoltIcon = ReduxBoltIcon;
108
- // Action Timeline — a history/clock icon reads as "sequence over time".
109
- const ReduxTimelineIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12, }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
110
- <react_native_svg_1.Path d="M3 3v5h5" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
111
- <react_native_svg_1.Path d="M3.05 13A9 9 0 1 0 6 5.3L3 8" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
112
- <react_native_svg_1.Path d="M12 7v5l3 2" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
113
- </react_native_svg_1.default>);
114
- exports.ReduxTimelineIcon = ReduxTimelineIcon;
115
- // Store Tree — a node hierarchy icon reads as "nested tree structure".
116
- const ReduxTreeIcon = ({ color = AppColors_1.AppColors.grayTextWeak, size = 12, }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
117
- <react_native_svg_1.Path d="M9 4h6v4H9zM3 16h6v4H3zm12 0h6v4h-6z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
118
- <react_native_svg_1.Path d="M12 8v4M6 16v-2h12v2" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
119
- </react_native_svg_1.default>);
120
- exports.ReduxTreeIcon = ReduxTreeIcon;
121
- const animateTreeLayout = () => {
122
- react_native_1.LayoutAnimation.configureNext(react_native_1.LayoutAnimation.Presets.easeInEaseOut);
78
+ return Object.keys(val).some(key => key.toLowerCase().includes(t) || valueContainsTerm(val[key], term));
123
79
  };
124
- const AnimatedChevron = ({ color, expanded, size, style, }) => {
125
- const progress = (0, react_1.useRef)(new react_native_1.Animated.Value(expanded ? 1 : 0)).current;
126
- (0, react_1.useEffect)(() => {
127
- react_native_1.Animated.timing(progress, {
128
- toValue: expanded ? 1 : 0,
129
- duration: 180,
130
- useNativeDriver: true,
131
- }).start();
132
- }, [expanded, progress]);
133
- const rotate = progress.interpolate({
134
- inputRange: [0, 1],
135
- outputRange: ['0deg', '90deg'],
136
- });
137
- return (<react_native_1.Animated.View style={[style, { transform: [{ rotate }] }]}>
138
- <NetworkIcons_1.ChevronIcon color={color} size={size}/>
139
- </react_native_1.Animated.View>);
140
- };
141
- const ReduxValueNode = ({ name, value, level, search }) => {
142
- const [expanded, setExpanded] = (0, react_1.useState)(level < 1);
143
- const isObject = typeof value === 'object' && value !== null;
144
- const isArray = Array.isArray(value);
145
- const nameStr = String(name);
146
- // Filter check if search query matches key or value
147
- const matchesSearch = (k, val) => {
148
- if (!search)
149
- return true;
150
- const s = search.toLowerCase();
151
- if (k.toLowerCase().includes(s))
152
- return true;
153
- if (typeof val !== 'object' && String(val).toLowerCase().includes(s))
154
- return true;
155
- if (typeof val === 'object' && val !== null) {
156
- return Object.keys(val).some(key => matchesSearch(key, val[key]));
157
- }
158
- return false;
80
+ const ReduxTreeView = ({ state, actionHistory = [], lastActionMap = {}, search = '', onSearchChange, autoRefresh = true, onToggleAutoRefresh, onClearHistory, onDetailOpenChange, selectedSliceKey = null, onSelectSliceKey, selectedActionId = null, onSelectActionId, }) => {
81
+ const [activeTab, setActiveTab] = (0, react_1.useState)('state');
82
+ const [actionSubTab, setActionSubTab] = (0, react_1.useState)('payload');
83
+ // local fallbacks if props are not provided
84
+ const [localSliceKey, setLocalSliceKey] = (0, react_1.useState)(null);
85
+ const [localActionId, setLocalActionId] = (0, react_1.useState)(null);
86
+ const activeSliceKey = onSelectSliceKey ? selectedSliceKey : localSliceKey;
87
+ const activeActionId = onSelectActionId ? selectedActionId : localActionId;
88
+ const setActiveSliceKey = (key) => {
89
+ if (onSelectSliceKey)
90
+ onSelectSliceKey(key);
91
+ else
92
+ setLocalSliceKey(key);
159
93
  };
160
- if (!matchesSearch(nameStr, value)) {
161
- return null;
162
- }
163
- if (!isObject) {
164
- const valStr = value === null
165
- ? 'null'
166
- : value === undefined
167
- ? 'undefined'
168
- : String(value);
169
- // Pick different colors for primitives
170
- let valColor = '#0D9488'; // String
171
- if (value === null || value === undefined) {
172
- valColor = AppColors_1.AppColors.grayTextWeak;
173
- }
174
- else if (typeof value === 'number') {
175
- valColor = '#D97706';
94
+ const setActiveActionId = (id) => {
95
+ if (onSelectActionId)
96
+ onSelectActionId(id);
97
+ else
98
+ setLocalActionId(id);
99
+ };
100
+ // Expand / collapse all states for detail views
101
+ const [sliceForceOpen, setSliceForceOpen] = (0, react_1.useState)(undefined);
102
+ const [actionForceOpen, setActionForceOpen] = (0, react_1.useState)(undefined);
103
+ const [searchModeType, setSearchModeType] = (0, react_1.useState)(true);
104
+ const [searchModeData, setSearchModeData] = (0, react_1.useState)(true);
105
+ // Sorting directions
106
+ const [stateSortAsc, setStateSortAsc] = (0, react_1.useState)(true);
107
+ const [actionSortAsc, setActionSortAsc] = (0, react_1.useState)(false);
108
+ // Persistence-related states for State Slice details
109
+ const [sliceDetailTab, setSliceDetailTab] = (0, react_1.useState)('live');
110
+ const [isPersisted, setIsPersisted] = (0, react_1.useState)(false);
111
+ const [persistedData, setPersistedData] = (0, react_1.useState)(null);
112
+ (0, react_1.useEffect)(() => {
113
+ if (activeSliceKey === null) {
114
+ setIsPersisted(false);
115
+ setPersistedData(null);
116
+ setSliceDetailTab('live');
117
+ return;
176
118
  }
177
- else if (typeof value === 'boolean') {
178
- valColor = '#4F46E5';
119
+ async function checkPersistence() {
120
+ try {
121
+ const storage = (0, settingsStore_1.getCustomStorage)();
122
+ if (!storage) {
123
+ setIsPersisted(false);
124
+ setPersistedData(null);
125
+ return;
126
+ }
127
+ // Check direct key: persist:sliceKey
128
+ let raw = await storage.getItem(`persist:${activeSliceKey}`);
129
+ if (raw) {
130
+ try {
131
+ setPersistedData(JSON.parse(raw));
132
+ }
133
+ catch {
134
+ setPersistedData(raw);
135
+ }
136
+ setIsPersisted(true);
137
+ return;
138
+ }
139
+ // Check root key: persist:root
140
+ let rootRaw = await storage.getItem('persist:root');
141
+ if (rootRaw) {
142
+ const parsedRoot = JSON.parse(rootRaw);
143
+ if (parsedRoot && parsedRoot[activeSliceKey] !== undefined) {
144
+ const nested = parsedRoot[activeSliceKey];
145
+ try {
146
+ setPersistedData(typeof nested === 'string' ? JSON.parse(nested) : nested);
147
+ }
148
+ catch {
149
+ setPersistedData(nested);
150
+ }
151
+ setIsPersisted(true);
152
+ return;
153
+ }
154
+ }
155
+ }
156
+ catch (e) {
157
+ console.log('Error checking Redux persistence:', e);
158
+ }
159
+ setIsPersisted(false);
160
+ setPersistedData(null);
179
161
  }
180
- return (<react_native_1.View style={[reduxValueStyles.treeRow, { paddingLeft: 12 }]}>
181
- <react_native_1.View style={reduxValueStyles.treeLeafConnector}/>
182
- <react_native_1.Text style={reduxValueStyles.keyText} selectable={true}>
183
- {nameStr}
184
- <react_native_1.Text style={reduxValueStyles.colonText}>: </react_native_1.Text>
185
- <react_native_1.Text style={[reduxValueStyles.valText, { color: valColor }]} selectable={true}>
186
- {valStr}
187
- </react_native_1.Text>
188
- </react_native_1.Text>
189
- </react_native_1.View>);
190
- }
191
- const keys = Object.keys(value);
192
- const summaryText = isArray
193
- ? `Array [${keys.length}]`
194
- : `Object {${keys.length}}`;
195
- return (<react_native_1.View style={reduxValueStyles.treeNodeBlock}>
196
- <react_native_1.Pressable onPress={() => {
197
- animateTreeLayout();
198
- setExpanded(!expanded);
199
- }} style={reduxValueStyles.treeRow}>
200
- <react_native_1.View style={reduxValueStyles.treeLeafConnector}/>
201
- <AnimatedChevron color={AppColors_1.AppColors.grayTextWeak} expanded={expanded} size={10} style={reduxValueStyles.chevronWrap}/>
202
- <react_native_1.Text style={reduxValueStyles.keyText} selectable={true}>
203
- {nameStr}
204
- <react_native_1.Text style={reduxValueStyles.colonText}>: </react_native_1.Text>
205
- <react_native_1.Text style={reduxValueStyles.summaryText}>{summaryText}</react_native_1.Text>
206
- </react_native_1.Text>
207
- </react_native_1.Pressable>
208
- {expanded && (<react_native_1.View style={reduxValueStyles.treeChildrenContainer}>
209
- {keys.map(key => (<ReduxValueNode key={key} name={key} value={value[key]} level={level + 1} search={search}/>))}
210
- </react_native_1.View>)}
211
- </react_native_1.View>);
212
- };
213
- const ReduxTreeView = ({ state, lastActionMap, search, }) => {
214
- const [storeExpanded, setStoreExpanded] = (0, react_1.useState)(true);
215
- const [reducerExpanded, setReducerExpanded] = (0, react_1.useState)({});
162
+ checkPersistence();
163
+ }, [activeSliceKey]);
164
+ const handleClearPersistence = () => {
165
+ react_native_1.Alert.alert('Clear Persisted State', `Are you sure you want to delete the persisted storage item for the slice "${activeSliceKey}"? This will clear the value from device storage, but the current active in-memory Redux state will remain unchanged until the next app reload.`, [
166
+ { text: 'Cancel', style: 'cancel' },
167
+ {
168
+ text: 'Delete',
169
+ style: 'destructive',
170
+ onPress: async () => {
171
+ try {
172
+ const storage = (0, settingsStore_1.getCustomStorage)();
173
+ if (!storage)
174
+ return;
175
+ // Delete direct key
176
+ if (typeof storage.removeItem === 'function') {
177
+ await storage.removeItem(`persist:${activeSliceKey}`);
178
+ }
179
+ else {
180
+ await storage.setItem(`persist:${activeSliceKey}`, '');
181
+ }
182
+ // Delete from root key
183
+ let rootRaw = await storage.getItem('persist:root');
184
+ if (rootRaw) {
185
+ const parsed = JSON.parse(rootRaw);
186
+ if (parsed && parsed[activeSliceKey] !== undefined) {
187
+ delete parsed[activeSliceKey];
188
+ await storage.setItem('persist:root', JSON.stringify(parsed));
189
+ }
190
+ }
191
+ setIsPersisted(false);
192
+ setPersistedData(null);
193
+ setSliceDetailTab('live');
194
+ if (react_native_1.Platform.OS === 'android') {
195
+ react_native_1.ToastAndroid.show('Persisted state cleared', react_native_1.ToastAndroid.SHORT);
196
+ }
197
+ else {
198
+ react_native_1.Alert.alert('Cleared', 'Persisted state has been cleared from device storage.');
199
+ }
200
+ }
201
+ catch (err) {
202
+ react_native_1.Alert.alert('Error', 'Failed to clear persisted state.');
203
+ }
204
+ }
205
+ }
206
+ ]);
207
+ };
208
+ const isSearching = search.trim().length > 0;
216
209
  (0, react_1.useEffect)(() => {
217
- if (react_native_1.Platform.OS === 'android') {
218
- react_native_1.UIManager.setLayoutAnimationEnabledExperimental?.(true);
210
+ onDetailOpenChange?.(activeSliceKey !== null || activeActionId !== null);
211
+ return () => {
212
+ onDetailOpenChange?.(false);
213
+ };
214
+ }, [activeSliceKey, activeActionId, onDetailOpenChange]);
215
+ // Reset details view when tab changes
216
+ const switchTab = (tab) => {
217
+ animateLayout();
218
+ setActiveTab(tab);
219
+ setActiveSliceKey(null);
220
+ setActiveActionId(null);
221
+ setSliceForceOpen(undefined);
222
+ setActionForceOpen(undefined);
223
+ };
224
+ const handleGoBackSlice = () => {
225
+ animateLayout();
226
+ setActiveSliceKey(null);
227
+ setSliceForceOpen(undefined);
228
+ };
229
+ const handleGoBackAction = () => {
230
+ animateLayout();
231
+ setActiveActionId(null);
232
+ setActionForceOpen(undefined);
233
+ };
234
+ // Filtered state keys based on search query
235
+ const filteredStateKeys = (0, react_1.useMemo)(() => {
236
+ if (!state || typeof state !== 'object')
237
+ return [];
238
+ const keys = Object.keys(state);
239
+ let result = keys;
240
+ if (isSearching) {
241
+ result = keys.filter(key => {
242
+ const typeMatch = searchModeType && key.toLowerCase().includes(search.toLowerCase());
243
+ const dataMatch = searchModeData && valueContainsTerm(state[key], search);
244
+ return typeMatch || dataMatch;
245
+ });
246
+ }
247
+ return [...result].sort((a, b) => {
248
+ const comparison = a.localeCompare(b);
249
+ return stateSortAsc ? comparison : -comparison;
250
+ });
251
+ }, [state, search, isSearching, searchModeType, searchModeData, stateSortAsc]);
252
+ // Filtered action history based on search query
253
+ const filteredActionHistory = (0, react_1.useMemo)(() => {
254
+ if (!actionHistory)
255
+ return [];
256
+ let result = actionHistory;
257
+ if (isSearching) {
258
+ result = actionHistory.filter(action => {
259
+ const typeMatch = searchModeType && action.type.toLowerCase().includes(search.toLowerCase());
260
+ const payloadMatch = searchModeData && action.payload && valueContainsTerm(action.payload, search);
261
+ return typeMatch || payloadMatch;
262
+ });
219
263
  }
220
- }, []);
264
+ return [...result].sort((a, b) => {
265
+ const comparison = a.id - b.id;
266
+ return actionSortAsc ? comparison : -comparison;
267
+ });
268
+ }, [actionHistory, search, isSearching, searchModeType, searchModeData, actionSortAsc]);
269
+ // Find currently selected action object
270
+ const selectedAction = (0, react_1.useMemo)(() => {
271
+ if (activeActionId === null)
272
+ return null;
273
+ return actionHistory.find(a => a.id === activeActionId) || null;
274
+ }, [activeActionId, actionHistory]);
221
275
  if (!state || typeof state !== 'object') {
222
- return (<react_native_1.Text style={{
223
- fontFamily: AppFonts_1.AppFonts.interRegular,
224
- fontSize: 12,
225
- color: AppColors_1.AppColors.grayTextWeak,
226
- padding: 12,
227
- }}>
228
- No state object to display.
229
- </react_native_1.Text>);
276
+ return (<react_native_1.View style={styles.errorContainer}>
277
+ <react_native_1.Text style={styles.errorText}>No connected Redux store state found.</react_native_1.Text>
278
+ </react_native_1.View>);
230
279
  }
231
- const reducers = Object.keys(state);
232
- const toggleReducer = (key) => {
233
- animateTreeLayout();
234
- setReducerExpanded(prev => ({
235
- ...prev,
236
- [key]: !prev[key],
237
- }));
238
- };
239
- return (<react_native_1.View style={styles.container}>
240
- {/* Root Node: Store */}
241
- <react_native_1.Pressable onPress={() => {
242
- animateTreeLayout();
243
- setStoreExpanded(!storeExpanded);
244
- }} style={styles.storeHeader}>
245
- <AnimatedChevron color="#FFFFFF" expanded={storeExpanded} size={12} style={styles.chevronWrap}/>
246
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
247
- <exports.ReduxStoreIcon color="#FFFFFF" size={14}/>
248
- <react_native_1.Text style={styles.storeTitle}>Redux Store</react_native_1.Text>
280
+ // ── Render Detail View: State Slice ──
281
+ if (activeTab === 'state' && activeSliceKey !== null) {
282
+ const sliceData = state[activeSliceKey];
283
+ const fieldsCount = typeof sliceData === 'object' && sliceData !== null
284
+ ? Object.keys(sliceData).length
285
+ : 1;
286
+ return (<react_native_1.View style={{ flex: 1 }}>
287
+ {/* Non-scrollable header */}
288
+ <react_native_1.View style={{ paddingHorizontal: 6, paddingTop: 4 }}>
289
+ <react_native_1.View style={styles.apiLikeInfoBar}>
290
+ <react_native_1.View style={styles.apiBadgeRow}>
291
+ <react_native_1.View style={[styles.apiMethodBadge, { backgroundColor: AppColors_1.AppColors.purple }]}>
292
+ <react_native_1.Text style={styles.apiMethodBadgeText}>REDUX</react_native_1.Text>
293
+ </react_native_1.View>
294
+ <react_native_1.View style={[styles.apiMethodBadge, { backgroundColor: AppColors_1.AppColors.purpleShade50, borderWidth: 1, borderColor: AppColors_1.AppColors.purple + '30' }]}>
295
+ <react_native_1.Text style={[styles.apiMethodBadgeText, { color: AppColors_1.AppColors.purple }]}>SLICE</react_native_1.Text>
296
+ </react_native_1.View>
297
+ {isPersisted && (<react_native_1.View style={[styles.apiMethodBadge, { backgroundColor: '#10B981' }]}>
298
+ <react_native_1.Text style={styles.apiMethodBadgeText}>PERSISTED</react_native_1.Text>
299
+ </react_native_1.View>)}
300
+ <react_native_1.View style={styles.apiChip}>
301
+ <react_native_1.Text style={styles.apiChipText}>{(0, helpers_1.getSize)(sliceData)}</react_native_1.Text>
302
+ </react_native_1.View>
303
+ <react_native_1.View style={styles.apiChip}>
304
+ <react_native_1.Text style={styles.apiChipText}>{fieldsCount} {fieldsCount === 1 ? 'field' : 'fields'}</react_native_1.Text>
305
+ </react_native_1.View>
306
+ </react_native_1.View>
307
+
308
+ <react_native_1.Text style={styles.apiTitleText} selectable={true}>{activeSliceKey}</react_native_1.Text>
309
+
310
+ <react_native_1.View style={styles.apiMetaRow}>
311
+ <NetworkIcons_1.ClockIcon color={AppColors_1.AppColors.grayTextWeak} size={10}/>
312
+ <react_native_1.Text style={styles.apiMetaText}>
313
+ Last updated: {lastActionMap[activeSliceKey] ? lastActionMap[activeSliceKey].timestamp : 'Initial'}
314
+ </react_native_1.Text>
315
+ </react_native_1.View>
316
+ </react_native_1.View>
249
317
  </react_native_1.View>
250
- <react_native_1.View style={styles.badge}>
251
- <react_native_1.Text style={styles.badgeText}>{reducers.length} Reducers</react_native_1.Text>
318
+
319
+ {/* Segment Control */}
320
+ <react_native_1.View style={{
321
+ flexDirection: 'row',
322
+ backgroundColor: AppColors_1.AppColors.grayBackground,
323
+ borderRadius: 10,
324
+ padding: 3,
325
+ marginHorizontal: 6,
326
+ marginBottom: 10,
327
+ marginTop: 6,
328
+ borderWidth: 1,
329
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
330
+ }}>
331
+ {(isPersisted ? ['live', 'persisted'] : ['live']).map(tab => {
332
+ const isActive = sliceDetailTab === tab;
333
+ const getLabel = () => {
334
+ if (tab === 'live')
335
+ return 'Live State';
336
+ return `Persisted (${(0, helpers_1.getSize)(persistedData)})`;
337
+ };
338
+ const getIcon = () => {
339
+ const iconColor = isActive ? '#FFFFFF' : AppColors_1.AppColors.grayText;
340
+ if (tab === 'live')
341
+ return <NetworkIcons_1.LayersIcon color={iconColor} size={11}/>;
342
+ return <NetworkIcons_1.CalendarIcon color={iconColor} size={11}/>;
343
+ };
344
+ return (<react_native_1.Pressable key={tab} onPress={() => {
345
+ animateLayout();
346
+ setSliceDetailTab(tab);
347
+ }} style={{
348
+ flex: 1,
349
+ paddingVertical: 6,
350
+ flexDirection: 'row',
351
+ alignItems: 'center',
352
+ justifyContent: 'center',
353
+ borderRadius: 8,
354
+ backgroundColor: isActive ? AppColors_1.AppColors.purple : 'transparent',
355
+ gap: 4,
356
+ }}>
357
+ {getIcon()}
358
+ <react_native_1.Text style={{
359
+ fontFamily: AppFonts_1.AppFonts.interBold,
360
+ fontSize: 10,
361
+ color: isActive ? '#FFFFFF' : AppColors_1.AppColors.grayText,
362
+ }}>
363
+ {getLabel()}
364
+ </react_native_1.Text>
365
+ </react_native_1.Pressable>);
366
+ })}
252
367
  </react_native_1.View>
253
- </react_native_1.Pressable>
254
368
 
255
- {storeExpanded && (<react_native_1.View style={styles.storeChildren}>
256
- {reducers.map((reducerKey, index) => {
257
- const isLastReducer = index === reducers.length - 1;
258
- const isExpanded = !!reducerExpanded[reducerKey];
259
- const sliceData = state[reducerKey];
260
- const lastAction = lastActionMap[reducerKey];
261
- return (<react_native_1.View key={reducerKey} style={styles.reducerContainer}>
262
- {/* Visual Branch Line for Reducer */}
263
- <react_native_1.View style={[
264
- styles.reducerVerticalLine,
265
- isLastReducer && { bottom: '50%' },
266
- ]}/>
369
+ {/* Scrollable Tab Content */}
370
+ <react_native_1.View style={{ flex: 1, paddingHorizontal: 6 }}>
371
+ {/* Back button + controls */}
372
+ <react_native_1.View style={styles.contentDetailSubHeader}>
373
+ <TouchableScale_1.default onPress={handleGoBackSlice} style={styles.backBtn} hitSlop={12}>
374
+ <BackChevronIcon color={AppColors_1.AppColors.purple} size={11}/>
375
+ <react_native_1.Text style={styles.backBtnText}>State Slices</react_native_1.Text>
376
+ </TouchableScale_1.default>
267
377
 
268
- {/* Reducer Header */}
269
- <react_native_1.Pressable onPress={() => toggleReducer(reducerKey)} style={styles.reducerHeader}>
270
- <react_native_1.View style={styles.reducerHorizontalLine}/>
271
- <AnimatedChevron color={AppColors_1.AppColors.purple} expanded={isExpanded} size={10} style={styles.chevronWrap}/>
272
- <react_native_1.View style={styles.iconWrap}>
273
- <FolderIcon color={AppColors_1.AppColors.purple} size={11}/>
274
- </react_native_1.View>
275
- <react_native_1.Text style={styles.reducerText}>{reducerKey}</react_native_1.Text>
276
- </react_native_1.Pressable>
378
+ <react_native_1.View style={styles.detailHeaderActions}>
379
+ {isPersisted && sliceDetailTab === 'persisted' && (<TouchableScale_1.default onPress={handleClearPersistence} style={[styles.detailHeaderBtn, { marginRight: 8 }]} hitSlop={8}>
380
+ <NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.errorColor} size={14}/>
381
+ </TouchableScale_1.default>)}
277
382
 
278
- {isExpanded && (<react_native_1.View style={styles.reducerChildren}>
279
- {/* Vertical line connecting children */}
280
- <react_native_1.View style={styles.childrenVerticalLine}/>
383
+ <TouchableScale_1.default onPress={() => {
384
+ animateLayout();
385
+ setSliceForceOpen(prev => (prev === true ? false : prev === false ? undefined : true));
386
+ }} style={styles.detailHeaderBtn} hitSlop={8}>
387
+ <NetworkIcons_1.ExpandCollapseIcon expanded={sliceForceOpen !== false} color={AppColors_1.AppColors.purple} size={14}/>
388
+ </TouchableScale_1.default>
281
389
 
282
- {/* Node 1: Last Action */}
283
- <react_native_1.View style={styles.childItem}>
284
- <react_native_1.View style={styles.childHorizontalLine}/>
285
- <react_native_1.View style={[styles.iconWrap, { backgroundColor: '#FDF2F8' }]}>
286
- <BoltIcon color="#DB2777" size={11}/>
287
- </react_native_1.View>
288
- <react_native_1.View style={{ flex: 1 }}>
289
- <react_native_1.View style={{
290
- flexDirection: 'row',
291
- alignItems: 'center',
292
- flexWrap: 'wrap',
293
- gap: 6,
294
- }}>
295
- <react_native_1.Text style={styles.childLabel}>Last Action:</react_native_1.Text>
296
- {lastAction ? (<react_native_1.View style={styles.actionTypeBadge}>
297
- <react_native_1.Text style={styles.actionTypeText}>
298
- {lastAction.type}
299
- </react_native_1.Text>
300
- </react_native_1.View>) : (<react_native_1.Text style={styles.noActionText}>
301
- None dispatched
302
- </react_native_1.Text>)}
303
- </react_native_1.View>
304
- {lastAction && (<react_native_1.Text style={styles.timestampText}>
305
- Dispatched: {lastAction.timestamp}
306
- </react_native_1.Text>)}
307
- {lastAction && lastAction.payload !== null && (<react_native_1.View style={{ marginTop: 6 }}>
308
- <ReduxValueNode name="payload" value={lastAction.payload} level={0} search={search}/>
309
- </react_native_1.View>)}
310
- </react_native_1.View>
311
- </react_native_1.View>
390
+ <TouchableScale_1.default onPress={() => {
391
+ const dataToCopy = sliceDetailTab === 'live' ? sliceData : persistedData;
392
+ (0, helpers_1.copyToClipboard)(dataToCopy, `Redux Slice '${activeSliceKey}' (${sliceDetailTab})`);
393
+ }} style={styles.detailHeaderBtn} hitSlop={8}>
394
+ <NetworkIcons_1.CopyIcon color={AppColors_1.AppColors.purple} size={14}/>
395
+ </TouchableScale_1.default>
396
+ </react_native_1.View>
397
+ </react_native_1.View>
312
398
 
313
- {/* Node 2: State Data */}
314
- <react_native_1.View style={styles.childItem}>
315
- <react_native_1.View style={[styles.childHorizontalLine, { bottom: '50%' }]}/>
316
- <react_native_1.View style={[styles.iconWrap, { backgroundColor: '#ECFDF5' }]}>
317
- <DatabaseIcon color="#059669" size={11}/>
318
- </react_native_1.View>
319
- <react_native_1.View style={{ flex: 1 }}>
320
- <react_native_1.Text style={styles.childLabel}>State Slice Data</react_native_1.Text>
321
- <react_native_1.View style={{ marginTop: 6 }}>
322
- <ReduxValueNode name="state" value={sliceData} level={0} search={search}/>
323
- </react_native_1.View>
324
- </react_native_1.View>
325
- </react_native_1.View>
326
- </react_native_1.View>)}
327
- </react_native_1.View>);
328
- })}
329
- </react_native_1.View>)}
330
- </react_native_1.View>);
331
- };
332
- exports.ReduxTreeView = ReduxTreeView;
333
- const ReduxActionTimeline = ({ history, onClear, search, }) => {
334
- const [expandedActionId, setExpandedActionId] = (0, react_1.useState)(null);
335
- const toggleExpand = (id) => {
336
- animateTreeLayout();
337
- setExpandedActionId(prev => (prev === id ? null : id));
338
- };
339
- const filteredHistory = history.filter(action => {
340
- if (!search)
341
- return true;
342
- const s = search.toLowerCase();
343
- if (action.type.toLowerCase().includes(s))
344
- return true;
345
- if (action.affectedSlices.some(slice => slice.toLowerCase().includes(s)))
346
- return true;
347
- if (action.payload && typeof action.payload === 'object') {
348
- return JSON.stringify(action.payload).toLowerCase().includes(s);
349
- }
350
- return false;
351
- });
352
- return (<react_native_1.View style={timelineStyles.container}>
353
- <react_native_1.View style={timelineStyles.headerRow}>
354
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
355
- <exports.ReduxBoltIcon color={AppColors_1.AppColors.purple} size={15}/>
356
- <react_native_1.Text style={timelineStyles.headerTitle}>
357
- Dispatched Actions ({filteredHistory.length})
358
- </react_native_1.Text>
399
+ <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingBottom: 24 }} showsVerticalScrollIndicator={true}>
400
+ <react_native_1.View style={{ padding: 12 }}>
401
+ <JsonViewer_1.default data={sliceDetailTab === 'live' ? sliceData : (persistedData ?? 'No persisted data')} search={search} forceOpen={sliceForceOpen !== undefined ? sliceForceOpen : (isSearching ? true : undefined)} fullHeight={true}/>
402
+ </react_native_1.View>
403
+ </react_native_1.ScrollView>
359
404
  </react_native_1.View>
360
- {history.length > 0 && (<react_native_1.Pressable onPress={onClear} style={timelineStyles.clearBtn}>
361
- <react_native_1.Text style={timelineStyles.clearBtnText}>Clear Log</react_native_1.Text>
362
- </react_native_1.Pressable>)}
363
- </react_native_1.View>
405
+ </react_native_1.View>);
406
+ }
407
+ // ── Render Detail View: Timeline Action ──
408
+ if (activeTab === 'timeline' && selectedAction !== null) {
409
+ const affectedSlices = selectedAction.affectedSlices || [];
410
+ return (<react_native_1.View style={{ flex: 1 }}>
411
+ {/* Non-scrollable header */}
412
+ <react_native_1.View style={{ paddingHorizontal: 6, paddingTop: 4 }}>
413
+ <react_native_1.View style={styles.apiLikeInfoBar}>
414
+ <react_native_1.View style={styles.apiBadgeRow}>
415
+ <react_native_1.View style={[styles.apiMethodBadge, { backgroundColor: AppColors_1.AppColors.purple }]}>
416
+ <react_native_1.Text style={styles.apiMethodBadgeText}>REDUX</react_native_1.Text>
417
+ </react_native_1.View>
418
+ <react_native_1.View style={[styles.apiMethodBadge, { backgroundColor: '#F59E0B' }]}>
419
+ <react_native_1.Text style={styles.apiMethodBadgeText}>ACTION</react_native_1.Text>
420
+ </react_native_1.View>
421
+ <react_native_1.View style={styles.apiChip}>
422
+ <react_native_1.Text style={styles.apiChipText}>#{selectedAction.id}</react_native_1.Text>
423
+ </react_native_1.View>
424
+ <react_native_1.View style={styles.apiChip}>
425
+ <react_native_1.Text style={styles.apiChipText}>{(0, helpers_1.getSize)(selectedAction.payload)}</react_native_1.Text>
426
+ </react_native_1.View>
427
+ </react_native_1.View>
364
428
 
365
- {filteredHistory.length === 0 ? (<react_native_1.View style={timelineStyles.emptyContainer}>
366
- <react_native_1.Text style={timelineStyles.emptyText}>
367
- {history.length === 0
368
- ? 'No actions dispatched yet.\nDispatch actions in your application to see the timeline.'
369
- : 'No matching actions found.'}
370
- </react_native_1.Text>
371
- </react_native_1.View>) : (<react_native_1.View style={timelineStyles.listContainer}>
372
- {filteredHistory.map((item, index) => {
373
- const isLast = index === filteredHistory.length - 1;
374
- const isExpanded = expandedActionId === item.id;
375
- return (<AnimatedEntrance_1.default key={item.id} index={index} distance={8} style={timelineStyles.timelineItem}>
376
- {/* Visual Line */}
377
- <react_native_1.View style={[
378
- timelineStyles.verticalLine,
379
- isLast && { bottom: '50%' },
380
- ]}/>
381
- <react_native_1.View style={timelineStyles.circleIndicator}>
382
- <react_native_1.View style={timelineStyles.circleInner}/>
383
- </react_native_1.View>
429
+ <react_native_1.Text style={styles.apiTitleText} selectable={true}>{selectedAction.type}</react_native_1.Text>
384
430
 
385
- {/* Card */}
386
- <react_native_1.Pressable onPress={() => toggleExpand(item.id)} style={[
387
- timelineStyles.card,
388
- isExpanded && {
389
- borderColor: AppColors_1.AppColors.purple,
390
- backgroundColor: AppColors_1.AppColors.purpleShade50,
391
- },
392
- ]}>
393
- <react_native_1.View style={timelineStyles.cardHeader}>
394
- <react_native_1.View style={{
395
- flexDirection: 'row',
396
- alignItems: 'center',
397
- gap: 6,
431
+ <react_native_1.View style={styles.apiMetaRow}>
432
+ <NetworkIcons_1.ClockIcon color={AppColors_1.AppColors.grayTextWeak} size={10}/>
433
+ <react_native_1.Text style={styles.apiMetaText}>Dispatched: {selectedAction.timestamp}</react_native_1.Text>
434
+ </react_native_1.View>
435
+ </react_native_1.View>
436
+ </react_native_1.View>
437
+
438
+ {/* Affected Slices Tags list */}
439
+ {affectedSlices.length > 0 && (<react_native_1.View style={styles.detailAffectedTags}>
440
+ <react_native_1.Text style={styles.affectedTagsLabel}>AFFECTED SLICES:</react_native_1.Text>
441
+ <react_native_1.View style={styles.detailTagsList}>
442
+ {affectedSlices.map(slice => (<react_native_1.View key={slice} style={styles.sliceTag}>
443
+ <react_native_1.Text style={styles.sliceTagText}>{slice}</react_native_1.Text>
444
+ </react_native_1.View>))}
445
+ </react_native_1.View>
446
+ </react_native_1.View>)}
447
+
448
+ {/* Segment Control */}
449
+ <react_native_1.View style={{
450
+ flexDirection: 'row',
451
+ backgroundColor: AppColors_1.AppColors.grayBackground,
452
+ borderRadius: 10,
453
+ padding: 3,
454
+ marginHorizontal: 6,
455
+ marginBottom: 10,
456
+ marginTop: 6,
457
+ borderWidth: 1,
458
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
459
+ }}>
460
+ {['payload', 'diff', 'state'].map(tab => {
461
+ const isActive = actionSubTab === tab;
462
+ const getLabel = () => {
463
+ if (tab === 'payload')
464
+ return 'Payload';
465
+ if (tab === 'diff')
466
+ return 'Diff Changes';
467
+ return 'Snapshot';
468
+ };
469
+ const getIcon = () => {
470
+ const iconColor = isActive ? '#FFFFFF' : AppColors_1.AppColors.grayText;
471
+ if (tab === 'payload')
472
+ return <NetworkIcons_1.RequestIcon color={iconColor} size={11}/>;
473
+ if (tab === 'diff')
474
+ return <NetworkIcons_1.DiffIcon color={iconColor} size={11}/>;
475
+ return <NetworkIcons_1.LayersIcon color={iconColor} size={11}/>;
476
+ };
477
+ return (<react_native_1.Pressable key={tab} onPress={() => {
478
+ animateLayout();
479
+ setActionSubTab(tab);
480
+ }} style={{
398
481
  flex: 1,
399
- }}>
400
- {(() => {
401
- const moduleName = getActionModule(item.type, item.affectedSlices);
402
- return moduleName ? (<react_native_1.View style={{
403
- paddingHorizontal: 7,
404
- paddingVertical: 2,
405
- borderRadius: 6,
406
- backgroundColor: `${AppColors_1.AppColors.purple}14`,
407
- borderWidth: 1,
408
- borderColor: `${AppColors_1.AppColors.purple}33`,
409
- }}>
410
- <react_native_1.Text style={{
411
- fontFamily: AppFonts_1.AppFonts.interBold,
412
- fontSize: 9.5,
413
- color: AppColors_1.AppColors.purple,
414
- letterSpacing: 0.2,
415
- }}>
416
- {moduleName}
417
- </react_native_1.Text>
418
- </react_native_1.View>) : null;
419
- })()}
420
- <react_native_1.View style={timelineStyles.typeBadge}>
421
- <react_native_1.Text style={timelineStyles.typeText}>{item.type}</react_native_1.Text>
422
- </react_native_1.View>
423
- </react_native_1.View>
424
- <react_native_1.View style={{
482
+ paddingVertical: 6,
425
483
  flexDirection: 'row',
426
484
  alignItems: 'center',
427
- gap: 8,
485
+ justifyContent: 'center',
486
+ borderRadius: 8,
487
+ backgroundColor: isActive ? AppColors_1.AppColors.purple : 'transparent',
488
+ gap: 4,
428
489
  }}>
429
- <react_native_1.Text style={timelineStyles.timestamp}>
430
- {item.timestamp}
431
- </react_native_1.Text>
432
- <ActionCopyButton value={() => ({
433
- type: item.type,
434
- payload: item.payload,
435
- })}/>
436
- </react_native_1.View>
437
- </react_native_1.View>
490
+ {getIcon()}
491
+ <react_native_1.Text style={{
492
+ fontFamily: AppFonts_1.AppFonts.interBold,
493
+ fontSize: 10,
494
+ color: isActive ? '#FFFFFF' : AppColors_1.AppColors.grayText,
495
+ }}>
496
+ {getLabel()}
497
+ </react_native_1.Text>
498
+ </react_native_1.Pressable>);
499
+ })}
500
+ </react_native_1.View>
438
501
 
439
- {item.affectedSlices.length > 0 && (<react_native_1.View style={timelineStyles.slicesRow}>
440
- <react_native_1.Text style={timelineStyles.slicesLabel}>Affected:</react_native_1.Text>
441
- {item.affectedSlices.map(slice => (<react_native_1.View key={slice} style={timelineStyles.slicePill}>
442
- <react_native_1.Text style={timelineStyles.sliceText}>{slice}</react_native_1.Text>
443
- </react_native_1.View>))}
444
- </react_native_1.View>)}
502
+ {/* Scrollable Tab Content */}
503
+ <react_native_1.View style={{ flex: 1, paddingHorizontal: 6 }}>
504
+ {/* Back button + controls */}
505
+ <react_native_1.View style={styles.contentDetailSubHeader}>
506
+ <TouchableScale_1.default onPress={handleGoBackAction} style={styles.backBtn} hitSlop={12}>
507
+ <BackChevronIcon color={AppColors_1.AppColors.purple} size={11}/>
508
+ <react_native_1.Text style={styles.backBtnText}>Actions</react_native_1.Text>
509
+ </TouchableScale_1.default>
445
510
 
446
- {isExpanded && (<react_native_1.View style={timelineStyles.payloadContainer}>
447
- <react_native_1.Text style={timelineStyles.payloadTitle}>Payload</react_native_1.Text>
448
- {item.payload !== null &&
449
- typeof item.payload === 'object' ? (<ReduxValueNode name="action.payload" value={item.payload} level={0} search={search}/>) : (<react_native_1.Text style={timelineStyles.primitivePayload}>
450
- {item.payload === null
451
- ? 'null'
452
- : String(item.payload)}
453
- </react_native_1.Text>)}
454
- </react_native_1.View>)}
455
- </react_native_1.Pressable>
456
- </AnimatedEntrance_1.default>);
457
- })}
511
+ {(actionSubTab === 'payload' || actionSubTab === 'state') && (<react_native_1.View style={styles.detailHeaderActions}>
512
+ <TouchableScale_1.default onPress={() => {
513
+ animateLayout();
514
+ setActionForceOpen(prev => (prev === true ? false : prev === false ? undefined : true));
515
+ }} style={styles.detailHeaderBtn} hitSlop={8}>
516
+ <NetworkIcons_1.ExpandCollapseIcon expanded={actionForceOpen !== false} color={AppColors_1.AppColors.purple} size={14}/>
517
+ </TouchableScale_1.default>
518
+
519
+ <TouchableScale_1.default onPress={() => {
520
+ const dataToCopy = actionSubTab === 'payload' ? selectedAction.payload : selectedAction.nextState;
521
+ (0, helpers_1.copyToClipboard)(dataToCopy, actionSubTab === 'payload' ? 'Action payload' : 'State snapshot');
522
+ }} style={styles.detailHeaderBtn} hitSlop={8}>
523
+ <NetworkIcons_1.CopyIcon color={AppColors_1.AppColors.purple} size={14}/>
524
+ </TouchableScale_1.default>
525
+ </react_native_1.View>)}
526
+ </react_native_1.View>
527
+
528
+ <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingBottom: 24 }} showsVerticalScrollIndicator={true}>
529
+ {actionSubTab === 'payload' && (<react_native_1.View style={{ padding: 12 }}>
530
+ <JsonViewer_1.default data={selectedAction.payload ?? 'No payload data'} wrap forceOpen={actionForceOpen !== undefined ? actionForceOpen : undefined} fullHeight={true}/>
531
+ </react_native_1.View>)}
532
+
533
+ {actionSubTab === 'diff' && (<react_native_1.View style={{ padding: 12 }}>
534
+ <DiffViewer_1.default oldData={selectedAction.prevState} newData={selectedAction.nextState}/>
535
+ </react_native_1.View>)}
536
+
537
+ {actionSubTab === 'state' && (<react_native_1.View style={{ padding: 12 }}>
538
+ <JsonViewer_1.default data={selectedAction.nextState} wrap forceOpen={actionForceOpen !== undefined ? actionForceOpen : undefined} fullHeight={true}/>
539
+ </react_native_1.View>)}
540
+ </react_native_1.ScrollView>
541
+ </react_native_1.View>
542
+ </react_native_1.View>);
543
+ }
544
+ // ── Render List Views (Default) ──
545
+ return (<react_native_1.View style={styles.container}>
546
+ {/* ── Control Bar ── */}
547
+ <react_native_1.View style={styles.toolbar}>
548
+ <react_native_1.View style={styles.statusSection}>
549
+ <react_native_1.View style={[styles.statusBadge, autoRefresh ? styles.statusBadgeActive : styles.statusBadgePaused]}>
550
+ <react_native_1.View style={[styles.statusDot, autoRefresh ? styles.statusDotActive : styles.statusDotPaused]}/>
551
+ <react_native_1.Text style={[styles.statusBadgeText, autoRefresh ? styles.statusTextActive : styles.statusTextPaused]}>
552
+ {autoRefresh ? 'LIVE' : 'PAUSED'}
553
+ </react_native_1.Text>
554
+ </react_native_1.View>
555
+ </react_native_1.View>
556
+
557
+ <react_native_1.View style={styles.toolbarActions}>
558
+ {/* Sorting Toggle Button */}
559
+ <TouchableScale_1.default onPress={() => {
560
+ animateLayout();
561
+ if (activeTab === 'state') {
562
+ setStateSortAsc(prev => !prev);
563
+ }
564
+ else {
565
+ setActionSortAsc(prev => !prev);
566
+ }
567
+ }} style={styles.iconBtn} hitSlop={8}>
568
+ <NetworkIcons_1.SortIcon ascending={activeTab === 'state' ? stateSortAsc : actionSortAsc} color={AppColors_1.AppColors.purple} size={15}/>
569
+ </TouchableScale_1.default>
570
+
571
+ {onToggleAutoRefresh && (<TouchableScale_1.default onPress={onToggleAutoRefresh} style={styles.iconBtn} hitSlop={8}>
572
+ <NetworkIcons_1.HeaderPauseIcon isPaused={!autoRefresh} color={AppColors_1.AppColors.purple} size={15}/>
573
+ </TouchableScale_1.default>)}
574
+ {onClearHistory && (<TouchableScale_1.default onPress={onClearHistory} style={[styles.iconBtn, { borderColor: AppColors_1.AppColors.errorColor + '40', backgroundColor: AppColors_1.AppColors.errorColor + '08' }]} hitSlop={8}>
575
+ <NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.errorColor} size={15}/>
576
+ </TouchableScale_1.default>)}
577
+ </react_native_1.View>
578
+ </react_native_1.View>
579
+
580
+ {/* ── Search Bar ── */}
581
+ {onSearchChange && (<react_native_1.View style={styles.searchContainer}>
582
+ <react_native_1.View style={styles.searchBar}>
583
+ <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
584
+ <react_native_1.TextInput placeholder="Search keys, values, or action payloads..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={onSearchChange} style={styles.searchInput} autoCorrect={false} autoCapitalize="none"/>
585
+ {search.length > 0 && (<TouchableScale_1.default onPress={() => onSearchChange('')} hitSlop={10}>
586
+ <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
587
+ </TouchableScale_1.default>)}
588
+ </react_native_1.View>
589
+ <react_native_1.View style={styles.filterChipRow}>
590
+ <react_native_1.Text style={styles.filterChipLabel}>FILTER BY:</react_native_1.Text>
591
+ <react_native_1.Pressable onPress={() => {
592
+ animateLayout();
593
+ if (searchModeType && !searchModeData)
594
+ return; // Prevent disabling both
595
+ setSearchModeType(!searchModeType);
596
+ }} style={[styles.filterChip, searchModeType && styles.filterChipActive]}>
597
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
598
+ <NetworkIcons_1.SignalIcon color={searchModeType ? AppColors_1.AppColors.purple : AppColors_1.AppColors.grayText} size={11}/>
599
+ <react_native_1.Text style={[styles.filterChipText, searchModeType && styles.filterChipTextActive]}>
600
+ Type / Key
601
+ </react_native_1.Text>
602
+ </react_native_1.View>
603
+ </react_native_1.Pressable>
604
+ <react_native_1.Pressable onPress={() => {
605
+ animateLayout();
606
+ if (!searchModeType && searchModeData)
607
+ return; // Prevent disabling both
608
+ setSearchModeData(!searchModeData);
609
+ }} style={[styles.filterChip, searchModeData && styles.filterChipActive]}>
610
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
611
+ <NetworkIcons_1.LayersIcon color={searchModeData ? AppColors_1.AppColors.purple : AppColors_1.AppColors.grayText} size={11}/>
612
+ <react_native_1.Text style={[styles.filterChipText, searchModeData && styles.filterChipTextActive]}>
613
+ Payload Data
614
+ </react_native_1.Text>
615
+ </react_native_1.View>
616
+ </react_native_1.Pressable>
617
+ </react_native_1.View>
458
618
  </react_native_1.View>)}
619
+
620
+ {/* ── Tab Selector ── */}
621
+ <react_native_1.View style={styles.tabContainer}>
622
+ <react_native_1.Pressable style={[styles.tabButton, activeTab === 'state' && styles.tabButtonActive]} onPress={() => switchTab('state')}>
623
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
624
+ <NetworkIcons_1.LayersIcon color={activeTab === 'state' ? AppColors_1.AppColors.purple : AppColors_1.AppColors.grayText} size={12}/>
625
+ <react_native_1.Text style={[styles.tabButtonText, activeTab === 'state' && styles.tabButtonTextActive]}>
626
+ State Slices ({filteredStateKeys.length})
627
+ </react_native_1.Text>
628
+ </react_native_1.View>
629
+ </react_native_1.Pressable>
630
+ <react_native_1.Pressable style={[styles.tabButton, activeTab === 'timeline' && styles.tabButtonActive]} onPress={() => switchTab('timeline')}>
631
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
632
+ <NetworkIcons_1.TerminalIcon color={activeTab === 'timeline' ? AppColors_1.AppColors.purple : AppColors_1.AppColors.grayText} size={12}/>
633
+ <react_native_1.Text style={[styles.tabButtonText, activeTab === 'timeline' && styles.tabButtonTextActive]}>
634
+ Actions ({filteredActionHistory.length})
635
+ </react_native_1.Text>
636
+ </react_native_1.View>
637
+ </react_native_1.Pressable>
638
+ </react_native_1.View>
639
+
640
+ {/* ── State List View ── */}
641
+ {activeTab === 'state' && (<react_native_1.ScrollView style={styles.scrollList} contentContainerStyle={styles.scrollContent}>
642
+ {filteredStateKeys.length === 0 ? (<react_native_1.View style={styles.emptyState}>
643
+ <react_native_1.Text style={styles.emptyStateText}>
644
+ {isSearching ? 'No store slices match your search.' : 'Redux store contains no state.'}
645
+ </react_native_1.Text>
646
+ </react_native_1.View>) : (filteredStateKeys.map(reducerKey => {
647
+ const sliceData = state[reducerKey];
648
+ const fieldsCount = typeof sliceData === 'object' && sliceData !== null
649
+ ? Object.keys(sliceData).length
650
+ : 1;
651
+ const lastAction = lastActionMap[reducerKey];
652
+ const lastUpdatedTime = lastAction ? lastAction.timestamp : 'Initial';
653
+ return (<TouchableScale_1.default key={reducerKey} onPress={() => {
654
+ animateLayout();
655
+ setActiveSliceKey(reducerKey);
656
+ }} style={styles.listRow}>
657
+ <react_native_1.View style={styles.sliceIcon}>
658
+ <NetworkIcons_1.FolderIcon color={AppColors_1.AppColors.purple} size={11}/>
659
+ </react_native_1.View>
660
+ <react_native_1.View style={styles.rowMain}>
661
+ <react_native_1.Text style={styles.rowTitle}>{reducerKey}</react_native_1.Text>
662
+ <react_native_1.Text style={styles.rowSub}>
663
+ {(0, helpers_1.getSize)(sliceData)} • {fieldsCount} {fieldsCount === 1 ? 'field' : 'fields'} • Updated: {lastUpdatedTime}
664
+ </react_native_1.Text>
665
+ </react_native_1.View>
666
+ <ForwardChevronIcon color={AppColors_1.AppColors.grayTextWeak} size={10}/>
667
+ </TouchableScale_1.default>);
668
+ }))}
669
+ </react_native_1.ScrollView>)}
670
+
671
+ {/* ── Timeline List View ── */}
672
+ {activeTab === 'timeline' && (<react_native_1.ScrollView style={styles.scrollList} contentContainerStyle={styles.scrollContent}>
673
+ {filteredActionHistory.length === 0 ? (<react_native_1.View style={styles.emptyState}>
674
+ <react_native_1.Text style={styles.emptyStateText}>
675
+ {isSearching
676
+ ? 'No actions match your search.'
677
+ : 'No actions dispatched yet. Trigger an action in the app to populate history.'}
678
+ </react_native_1.Text>
679
+ </react_native_1.View>) : (filteredActionHistory.map((action, index) => {
680
+ const id = action.id;
681
+ const affectedSlices = action.affectedSlices || [];
682
+ return (<TouchableScale_1.default key={id} onPress={() => {
683
+ animateLayout();
684
+ setActiveActionId(id);
685
+ }} style={styles.listRow}>
686
+ <react_native_1.View style={styles.seqBadge}>
687
+ <react_native_1.Text style={styles.seqText}>#{action.id}</react_native_1.Text>
688
+ </react_native_1.View>
689
+ <react_native_1.View style={styles.rowMain}>
690
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
691
+ <NetworkIcons_1.TerminalIcon color={AppColors_1.AppColors.purple} size={11}/>
692
+ <react_native_1.Text style={styles.actionTitleText} numberOfLines={1}>{action.type}</react_native_1.Text>
693
+ </react_native_1.View>
694
+ <react_native_1.View style={styles.actionMetaRow}>
695
+ <NetworkIcons_1.ClockIcon color={AppColors_1.AppColors.grayTextWeak} size={9}/>
696
+ <react_native_1.Text style={styles.actionTimeText}>{action.timestamp} • {(0, helpers_1.getSize)(action.payload)}</react_native_1.Text>
697
+ </react_native_1.View>
698
+ {affectedSlices.length > 0 && (<react_native_1.View style={styles.tagsContainer}>
699
+ {affectedSlices.map(slice => (<react_native_1.View key={slice} style={styles.sliceTagMini}>
700
+ <react_native_1.Text style={styles.sliceTagMiniText}>{slice}</react_native_1.Text>
701
+ </react_native_1.View>))}
702
+ </react_native_1.View>)}
703
+ </react_native_1.View>
704
+ <ForwardChevronIcon color={AppColors_1.AppColors.grayTextWeak} size={10}/>
705
+ </TouchableScale_1.default>);
706
+ }))}
707
+ </react_native_1.ScrollView>)}
459
708
  </react_native_1.View>);
460
709
  };
461
- exports.ReduxActionTimeline = ReduxActionTimeline;
462
- const reduxValueStyles = react_native_1.StyleSheet.create({
463
- treeNodeBlock: {
464
- marginTop: 4,
710
+ exports.ReduxTreeView = ReduxTreeView;
711
+ const styles = react_native_1.StyleSheet.create({
712
+ container: {
713
+ flex: 1,
714
+ backgroundColor: AppColors_1.AppColors.grayBackground,
465
715
  },
466
- treeRow: {
716
+ scrollList: {
717
+ flex: 1,
718
+ },
719
+ errorContainer: {
720
+ padding: 24,
721
+ alignItems: 'center',
722
+ },
723
+ errorText: {
724
+ fontFamily: AppFonts_1.AppFonts.interRegular,
725
+ fontSize: 12,
726
+ color: AppColors_1.AppColors.grayTextWeak,
727
+ },
728
+ toolbar: {
467
729
  flexDirection: 'row',
468
730
  alignItems: 'center',
469
- paddingVertical: 3,
470
- gap: 4,
471
- position: 'relative',
472
- },
473
- treeLeafConnector: {
474
- position: 'absolute',
475
- left: -12,
476
- top: '50%',
477
- width: 8,
478
- height: 1,
731
+ justifyContent: 'space-between',
732
+ paddingHorizontal: 12,
733
+ paddingVertical: 10,
734
+ backgroundColor: AppColors_1.AppColors.primaryLight,
479
735
  borderBottomWidth: 1,
480
736
  borderBottomColor: AppColors_1.AppColors.dividerColor,
481
- opacity: 0.5,
482
737
  },
483
- treeChildrenContainer: {
484
- paddingLeft: 14,
485
- borderLeftWidth: 1,
486
- borderLeftColor: AppColors_1.AppColors.dividerColor,
487
- marginLeft: 6,
738
+ statusSection: {
739
+ flexDirection: 'row',
740
+ alignItems: 'center',
488
741
  },
489
- chevronWrap: {
490
- width: 10,
491
- height: 10,
742
+ statusBadge: {
743
+ flexDirection: 'row',
492
744
  alignItems: 'center',
493
- justifyContent: 'center',
745
+ paddingHorizontal: 8,
746
+ paddingVertical: 3,
747
+ borderRadius: 12,
748
+ borderWidth: 1,
494
749
  },
495
- keyText: {
496
- fontFamily: AppFonts_1.AppFonts.interMedium,
497
- fontSize: 11.5,
498
- color: AppColors_1.AppColors.grayTextStrong,
750
+ statusBadgeActive: {
751
+ backgroundColor: AppColors_1.AppColors.greenStatus,
752
+ borderColor: AppColors_1.AppColors.greenColor + '30',
499
753
  },
500
- colonText: {
501
- color: AppColors_1.AppColors.grayTextWeak,
754
+ statusBadgePaused: {
755
+ backgroundColor: AppColors_1.AppColors.grayBackground,
756
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
502
757
  },
503
- valText: {
504
- fontFamily: AppFonts_1.AppFonts.interRegular,
505
- fontSize: 11.5,
758
+ statusDot: {
759
+ width: 6,
760
+ height: 6,
761
+ borderRadius: 3,
762
+ marginRight: 6,
506
763
  },
507
- summaryText: {
508
- fontFamily: AppFonts_1.AppFonts.interRegular,
509
- fontSize: 11,
510
- color: AppColors_1.AppColors.grayTextWeak,
764
+ statusDotActive: {
765
+ backgroundColor: AppColors_1.AppColors.greenBaggageText,
511
766
  },
512
- });
513
- const timelineStyles = react_native_1.StyleSheet.create({
514
- container: {
515
- flex: 1,
767
+ statusDotPaused: {
768
+ backgroundColor: AppColors_1.AppColors.grayTextWeak,
769
+ },
770
+ statusBadgeText: {
771
+ fontFamily: AppFonts_1.AppFonts.interBold,
772
+ fontSize: 9,
773
+ letterSpacing: 0.5,
516
774
  },
517
- headerRow: {
775
+ statusTextActive: {
776
+ color: AppColors_1.AppColors.greenBaggageText,
777
+ },
778
+ statusTextPaused: {
779
+ color: AppColors_1.AppColors.grayText,
780
+ },
781
+ toolbarActions: {
518
782
  flexDirection: 'row',
519
783
  alignItems: 'center',
520
- justifyContent: 'space-between',
521
- marginBottom: 12,
784
+ gap: 8,
522
785
  },
523
- headerTitle: {
524
- fontFamily: AppFonts_1.AppFonts.interBold,
525
- fontSize: 14,
526
- color: AppColors_1.AppColors.primaryBlack,
786
+ iconBtn: {
787
+ width: 28,
788
+ height: 28,
789
+ borderRadius: 6,
790
+ borderWidth: 1,
791
+ borderColor: AppColors_1.AppColors.purple + '40',
792
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
793
+ alignItems: 'center',
794
+ justifyContent: 'center',
527
795
  },
528
- clearBtn: {
529
- backgroundColor: 'rgba(239, 68, 68, 0.08)',
530
- borderColor: 'rgba(239, 68, 68, 0.2)',
796
+ searchContainer: {
797
+ backgroundColor: AppColors_1.AppColors.primaryLight,
798
+ borderBottomWidth: 1,
799
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
800
+ paddingBottom: 10,
801
+ },
802
+ searchBar: {
803
+ flexDirection: 'row',
804
+ alignItems: 'center',
805
+ backgroundColor: AppColors_1.AppColors.grayBackground,
806
+ borderRadius: 8,
807
+ marginHorizontal: 12,
808
+ marginTop: 10,
809
+ marginBottom: 8,
810
+ paddingHorizontal: 10,
531
811
  borderWidth: 1,
532
- paddingHorizontal: 8,
533
- paddingVertical: 4,
534
- borderRadius: 6,
812
+ borderColor: AppColors_1.AppColors.dividerColor,
813
+ height: 36,
535
814
  },
536
- clearBtnText: {
815
+ filterChipRow: {
816
+ flexDirection: 'row',
817
+ alignItems: 'center',
818
+ paddingHorizontal: 12,
819
+ gap: 8,
820
+ },
821
+ filterChipLabel: {
537
822
  fontFamily: AppFonts_1.AppFonts.interBold,
823
+ fontSize: 9,
824
+ color: AppColors_1.AppColors.grayTextWeak,
825
+ letterSpacing: 0.5,
826
+ marginRight: 2,
827
+ },
828
+ filterChip: {
829
+ paddingHorizontal: 10,
830
+ paddingVertical: 4,
831
+ borderRadius: 12,
832
+ backgroundColor: AppColors_1.AppColors.grayBackground,
833
+ borderWidth: 1,
834
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
835
+ },
836
+ filterChipActive: {
837
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
838
+ borderColor: AppColors_1.AppColors.purple,
839
+ },
840
+ filterChipText: {
841
+ fontFamily: AppFonts_1.AppFonts.interMedium,
538
842
  fontSize: 10,
539
- color: '#EF4444',
843
+ color: AppColors_1.AppColors.grayText,
844
+ },
845
+ filterChipTextActive: {
846
+ color: AppColors_1.AppColors.purple,
847
+ fontFamily: AppFonts_1.AppFonts.interBold,
848
+ },
849
+ searchInput: {
850
+ flex: 1,
851
+ fontFamily: AppFonts_1.AppFonts.interRegular,
852
+ fontSize: 12,
853
+ color: AppColors_1.AppColors.grayTextStrong,
854
+ marginLeft: 6,
855
+ padding: 0,
856
+ },
857
+ tabContainer: {
858
+ flexDirection: 'row',
859
+ backgroundColor: AppColors_1.AppColors.dividerColor,
860
+ borderRadius: 8,
861
+ padding: 3,
862
+ marginHorizontal: 12,
863
+ marginTop: 10,
864
+ marginBottom: 10,
540
865
  },
541
- emptyContainer: {
542
- paddingVertical: 32,
866
+ tabButton: {
867
+ flex: 1,
868
+ paddingVertical: 7,
543
869
  alignItems: 'center',
544
870
  justifyContent: 'center',
871
+ borderRadius: 6,
872
+ },
873
+ tabButtonActive: {
874
+ backgroundColor: AppColors_1.AppColors.primaryLight,
875
+ shadowColor: AppColors_1.AppColors.shadowColorString,
876
+ shadowOffset: { width: 0, height: 1 },
877
+ shadowOpacity: 0.08,
878
+ shadowRadius: 2,
879
+ elevation: 2,
545
880
  },
546
- emptyText: {
881
+ tabButtonText: {
882
+ fontFamily: AppFonts_1.AppFonts.interMedium,
883
+ fontSize: 12,
884
+ color: AppColors_1.AppColors.grayText,
885
+ },
886
+ tabButtonTextActive: {
887
+ color: AppColors_1.AppColors.purple,
888
+ fontFamily: AppFonts_1.AppFonts.interBold,
889
+ },
890
+ scrollContent: {
891
+ paddingBottom: 24,
892
+ paddingHorizontal: 12,
893
+ },
894
+ emptyState: {
895
+ padding: 24,
896
+ alignItems: 'center',
897
+ },
898
+ emptyStateText: {
547
899
  fontFamily: AppFonts_1.AppFonts.interRegular,
548
900
  fontSize: 12,
549
901
  color: AppColors_1.AppColors.grayTextWeak,
550
902
  textAlign: 'center',
551
- lineHeight: 18,
552
- },
553
- listContainer: {
554
- paddingLeft: 12,
555
- },
556
- timelineItem: {
557
- position: 'relative',
558
- paddingLeft: 20,
559
- marginBottom: 12,
560
- },
561
- verticalLine: {
562
- position: 'absolute',
563
- left: 4,
564
- top: 0,
565
- bottom: -12,
566
- width: 1,
567
- backgroundColor: AppColors_1.AppColors.dividerColor,
568
903
  },
569
- circleIndicator: {
570
- position: 'absolute',
571
- left: 0,
572
- top: 10,
573
- width: 9,
574
- height: 9,
575
- borderRadius: 4.5,
904
+ listRow: {
905
+ flexDirection: 'row',
906
+ alignItems: 'center',
907
+ backgroundColor: AppColors_1.AppColors.primaryLight,
908
+ paddingHorizontal: 12,
909
+ paddingVertical: 14,
910
+ borderRadius: 10,
911
+ borderWidth: 1,
912
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
913
+ marginBottom: 8,
914
+ shadowColor: AppColors_1.AppColors.shadowColorString,
915
+ shadowOffset: { width: 0, height: 1 },
916
+ shadowOpacity: 0.03,
917
+ shadowRadius: 2,
918
+ elevation: 1,
919
+ },
920
+ rowMain: {
921
+ flex: 1,
922
+ marginLeft: 10,
923
+ },
924
+ rowTitle: {
925
+ fontFamily: AppFonts_1.AppFonts.interBold,
926
+ fontSize: 13.5,
927
+ color: AppColors_1.AppColors.primaryBlack,
928
+ },
929
+ rowSub: {
930
+ fontFamily: AppFonts_1.AppFonts.interRegular,
931
+ fontSize: 10,
932
+ color: AppColors_1.AppColors.grayTextWeak,
933
+ marginTop: 2,
934
+ },
935
+ sliceIcon: {
936
+ width: 22,
937
+ height: 22,
938
+ borderRadius: 6,
576
939
  backgroundColor: AppColors_1.AppColors.purpleShade50,
940
+ alignItems: 'center',
941
+ justifyContent: 'center',
942
+ },
943
+ seqBadge: {
944
+ backgroundColor: AppColors_1.AppColors.grayBackground,
945
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
577
946
  borderWidth: 1,
578
- borderColor: AppColors_1.AppColors.purple,
947
+ borderRadius: 4,
948
+ paddingHorizontal: 5,
949
+ paddingVertical: 2,
579
950
  alignItems: 'center',
580
951
  justifyContent: 'center',
952
+ minWidth: 28,
581
953
  },
582
- circleInner: {
583
- width: 3,
584
- height: 3,
585
- borderRadius: 1.5,
586
- backgroundColor: AppColors_1.AppColors.purple,
954
+ seqText: {
955
+ fontFamily: AppFonts_1.AppFonts.interBold,
956
+ fontSize: 9.5,
957
+ color: AppColors_1.AppColors.grayText,
587
958
  },
588
- card: {
589
- backgroundColor: AppColors_1.AppColors.primaryLight,
590
- borderWidth: 1,
591
- borderColor: AppColors_1.AppColors.grayBorderSecondary,
592
- borderRadius: 8,
593
- padding: 10,
959
+ actionTitleText: {
960
+ fontFamily: AppFonts_1.AppFonts.interBold,
961
+ fontSize: 13,
962
+ color: AppColors_1.AppColors.purple,
594
963
  },
595
- cardHeader: {
964
+ actionMetaRow: {
596
965
  flexDirection: 'row',
597
966
  alignItems: 'center',
598
- justifyContent: 'space-between',
599
- gap: 12,
967
+ gap: 4,
968
+ marginTop: 2,
969
+ },
970
+ actionTimeText: {
971
+ fontFamily: AppFonts_1.AppFonts.interRegular,
972
+ fontSize: 9.5,
973
+ color: AppColors_1.AppColors.grayTextWeak,
600
974
  },
601
- typeBadge: {
602
- backgroundColor: 'rgba(104,75,155,0.08)',
603
- borderColor: 'rgba(104,75,155,0.18)',
975
+ tagsContainer: {
976
+ flexDirection: 'row',
977
+ flexWrap: 'wrap',
978
+ gap: 4,
979
+ marginTop: 4,
980
+ },
981
+ sliceTagMini: {
982
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
983
+ borderColor: AppColors_1.AppColors.purple + '20',
604
984
  borderWidth: 1,
605
- borderRadius: 6,
606
- paddingHorizontal: 6,
607
- paddingVertical: 2.5,
608
- flexShrink: 1,
985
+ borderRadius: 3,
986
+ paddingHorizontal: 4,
987
+ paddingVertical: 0.5,
988
+ },
989
+ sliceTagMiniText: {
990
+ fontFamily: AppFonts_1.AppFonts.interMedium,
991
+ fontSize: 8.5,
992
+ color: AppColors_1.AppColors.purple,
993
+ },
994
+ // ── Detail Views Styles ──
995
+ detailHeaderBar: {
996
+ flexDirection: 'row',
997
+ alignItems: 'center',
998
+ paddingHorizontal: 12,
999
+ paddingVertical: 12,
1000
+ backgroundColor: AppColors_1.AppColors.primaryLight,
1001
+ borderBottomWidth: 1,
1002
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
1003
+ },
1004
+ backBtn: {
1005
+ flexDirection: 'row',
1006
+ alignItems: 'center',
1007
+ paddingVertical: 6,
1008
+ paddingRight: 8,
609
1009
  },
610
- typeText: {
1010
+ backBtnText: {
611
1011
  fontFamily: AppFonts_1.AppFonts.interBold,
612
- fontSize: 11,
1012
+ fontSize: 12.5,
613
1013
  color: AppColors_1.AppColors.purple,
614
1014
  },
615
- timestamp: {
1015
+ detailHeaderInfo: {
1016
+ flex: 1,
1017
+ marginLeft: 10,
1018
+ marginRight: 10,
1019
+ },
1020
+ detailTitle: {
1021
+ fontFamily: AppFonts_1.AppFonts.interBold,
1022
+ fontSize: 13.5,
1023
+ color: AppColors_1.AppColors.primaryBlack,
1024
+ },
1025
+ detailSub: {
616
1026
  fontFamily: AppFonts_1.AppFonts.interRegular,
617
1027
  fontSize: 10,
618
1028
  color: AppColors_1.AppColors.grayTextWeak,
1029
+ marginTop: 2,
619
1030
  },
620
- slicesRow: {
1031
+ detailHeaderActions: {
1032
+ flexDirection: 'row',
1033
+ alignItems: 'center',
1034
+ gap: 6,
1035
+ },
1036
+ detailHeaderBtn: {
1037
+ padding: 6,
1038
+ borderRadius: 6,
1039
+ borderWidth: 1,
1040
+ borderColor: AppColors_1.AppColors.purple + '20',
1041
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
1042
+ alignItems: 'center',
1043
+ justifyContent: 'center',
1044
+ width: 28,
1045
+ height: 28,
1046
+ },
1047
+ detailCopyBtn: {
1048
+ padding: 6,
1049
+ borderRadius: 6,
1050
+ borderWidth: 1,
1051
+ borderColor: AppColors_1.AppColors.purple + '20',
1052
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
1053
+ },
1054
+ detailTimeRow: {
621
1055
  flexDirection: 'row',
622
1056
  alignItems: 'center',
623
- flexWrap: 'wrap',
624
1057
  gap: 4,
625
- marginTop: 6,
1058
+ marginTop: 1,
626
1059
  },
627
- slicesLabel: {
628
- fontFamily: AppFonts_1.AppFonts.interMedium,
1060
+ detailTimeText: {
1061
+ fontFamily: AppFonts_1.AppFonts.interRegular,
629
1062
  fontSize: 10,
630
1063
  color: AppColors_1.AppColors.grayTextWeak,
631
- marginRight: 2,
632
1064
  },
633
- slicePill: {
1065
+ detailAffectedTags: {
1066
+ paddingHorizontal: 12,
1067
+ paddingVertical: 8,
634
1068
  backgroundColor: AppColors_1.AppColors.grayBackground,
635
- borderColor: AppColors_1.AppColors.dividerColor,
636
- borderWidth: 1,
637
- borderRadius: 4,
638
- paddingHorizontal: 4,
639
- paddingVertical: 1,
640
- },
641
- sliceText: {
642
- fontFamily: AppFonts_1.AppFonts.interMedium,
643
- fontSize: 9,
644
- color: AppColors_1.AppColors.grayText,
645
- },
646
- payloadContainer: {
647
- marginTop: 10,
648
- borderTopWidth: 1,
649
- borderTopColor: AppColors_1.AppColors.dividerColor,
650
- paddingTop: 8,
1069
+ borderBottomWidth: 1,
1070
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
651
1071
  },
652
- payloadTitle: {
1072
+ affectedTagsLabel: {
653
1073
  fontFamily: AppFonts_1.AppFonts.interBold,
654
- fontSize: 10,
1074
+ fontSize: 9,
655
1075
  color: AppColors_1.AppColors.grayTextWeak,
656
- textTransform: 'uppercase',
1076
+ letterSpacing: 0.5,
657
1077
  marginBottom: 4,
658
1078
  },
659
- primitivePayload: {
660
- fontFamily: AppFonts_1.AppFonts.interRegular,
661
- fontSize: 11,
662
- color: AppColors_1.AppColors.grayTextStrong,
1079
+ detailTagsList: {
1080
+ flexDirection: 'row',
1081
+ flexWrap: 'wrap',
1082
+ gap: 4,
663
1083
  },
664
- });
665
- const styles = react_native_1.StyleSheet.create({
666
- container: {
667
- flex: 1,
1084
+ sliceTag: {
1085
+ backgroundColor: AppColors_1.AppColors.purpleShade50,
1086
+ borderColor: AppColors_1.AppColors.purple + '20',
1087
+ borderWidth: 1,
1088
+ borderRadius: 4,
1089
+ paddingHorizontal: 6,
1090
+ paddingVertical: 1.5,
668
1091
  },
669
- storeHeader: {
1092
+ sliceTagText: {
1093
+ fontFamily: AppFonts_1.AppFonts.interMedium,
1094
+ fontSize: 9.5,
1095
+ color: AppColors_1.AppColors.purple,
1096
+ },
1097
+ subTabRow: {
670
1098
  flexDirection: 'row',
671
- alignItems: 'center',
672
- backgroundColor: AppColors_1.AppColors.purple,
673
- borderRadius: 8,
674
- paddingVertical: 10,
675
- paddingHorizontal: 12,
1099
+ padding: 8,
676
1100
  gap: 8,
1101
+ backgroundColor: AppColors_1.AppColors.primaryLight,
1102
+ borderBottomWidth: 1,
1103
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
677
1104
  },
678
- chevronWrap: {
679
- width: 12,
680
- height: 12,
681
- alignItems: 'center',
682
- justifyContent: 'center',
1105
+ subTabPill: {
1106
+ paddingHorizontal: 12,
1107
+ paddingVertical: 5,
1108
+ borderRadius: 12,
1109
+ backgroundColor: AppColors_1.AppColors.grayBackground,
1110
+ borderWidth: 1,
1111
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
683
1112
  },
684
- storeTitle: {
685
- fontFamily: AppFonts_1.AppFonts.interBold,
686
- fontSize: 14,
687
- color: '#FFFFFF',
1113
+ subTabPillActive: {
1114
+ backgroundColor: AppColors_1.AppColors.purple,
1115
+ borderColor: AppColors_1.AppColors.purple,
688
1116
  },
689
- badge: {
690
- backgroundColor: 'rgba(255,255,255,0.2)',
691
- paddingHorizontal: 8,
692
- paddingVertical: 2,
693
- borderRadius: 12,
694
- marginLeft: 'auto',
1117
+ subTabPillText: {
1118
+ fontFamily: AppFonts_1.AppFonts.interMedium,
1119
+ fontSize: 10.5,
1120
+ color: AppColors_1.AppColors.grayText,
695
1121
  },
696
- badgeText: {
697
- fontFamily: AppFonts_1.AppFonts.interBold,
698
- fontSize: 10,
1122
+ subTabPillTextActive: {
699
1123
  color: '#FFFFFF',
1124
+ fontFamily: AppFonts_1.AppFonts.interBold,
700
1125
  },
701
- storeChildren: {
702
- paddingLeft: 12,
703
- marginTop: 4,
1126
+ detailScrollContent: {
1127
+ paddingBottom: 24,
704
1128
  },
705
- reducerContainer: {
706
- position: 'relative',
707
- paddingLeft: 16,
708
- paddingVertical: 4,
1129
+ jsonViewerContainer: {
1130
+ paddingHorizontal: 12,
1131
+ paddingVertical: 8,
709
1132
  },
710
- reducerVerticalLine: {
711
- position: 'absolute',
712
- left: 0,
713
- top: 0,
714
- bottom: 0,
715
- width: 1,
716
- backgroundColor: AppColors_1.AppColors.dividerColor,
1133
+ detailBox: {
1134
+ padding: 10,
717
1135
  },
718
- reducerHorizontalLine: {
719
- position: 'absolute',
720
- left: -16,
721
- top: '50%',
722
- width: 16,
723
- height: 1,
724
- backgroundColor: AppColors_1.AppColors.dividerColor,
1136
+ detailBoxHeader: {
1137
+ flexDirection: 'row',
1138
+ alignItems: 'center',
1139
+ justifyContent: 'space-between',
1140
+ marginBottom: 8,
1141
+ paddingHorizontal: 4,
1142
+ },
1143
+ detailBoxTitle: {
1144
+ fontFamily: AppFonts_1.AppFonts.interBold,
1145
+ fontSize: 10,
1146
+ color: AppColors_1.AppColors.grayTextWeak,
1147
+ letterSpacing: 0.5,
1148
+ textTransform: 'uppercase',
1149
+ },
1150
+ apiLikeInfoBar: {
1151
+ paddingHorizontal: 16,
1152
+ paddingVertical: 14,
1153
+ backgroundColor: AppColors_1.AppColors.primaryLight,
1154
+ borderBottomWidth: 1,
1155
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
725
1156
  },
726
- reducerHeader: {
1157
+ apiBadgeRow: {
727
1158
  flexDirection: 'row',
728
1159
  alignItems: 'center',
729
- paddingVertical: 6,
730
1160
  gap: 6,
1161
+ marginBottom: 8,
731
1162
  },
732
- iconWrap: {
733
- width: 18,
734
- height: 18,
1163
+ apiMethodBadge: {
1164
+ paddingHorizontal: 8,
1165
+ paddingVertical: 2,
735
1166
  borderRadius: 4,
736
- backgroundColor: AppColors_1.AppColors.purpleShade50,
737
1167
  alignItems: 'center',
738
1168
  justifyContent: 'center',
739
1169
  },
740
- reducerText: {
1170
+ apiMethodBadgeText: {
741
1171
  fontFamily: AppFonts_1.AppFonts.interBold,
742
- fontSize: 13,
743
- color: AppColors_1.AppColors.primaryBlack,
744
- },
745
- reducerChildren: {
746
- paddingLeft: 20,
747
- position: 'relative',
748
- marginTop: 4,
749
- gap: 10,
750
- },
751
- childrenVerticalLine: {
752
- position: 'absolute',
753
- left: 8,
754
- top: 0,
755
- bottom: 16,
756
- width: 1,
757
- backgroundColor: AppColors_1.AppColors.dividerColor,
1172
+ fontSize: 9.5,
1173
+ color: '#FFFFFF',
1174
+ letterSpacing: 0.5,
758
1175
  },
759
- childItem: {
760
- flexDirection: 'row',
761
- alignItems: 'flex-start',
762
- gap: 8,
763
- position: 'relative',
764
- paddingLeft: 12,
765
- },
766
- childHorizontalLine: {
767
- position: 'absolute',
768
- left: -12,
769
- top: 10,
770
- width: 12,
771
- height: 1,
772
- backgroundColor: AppColors_1.AppColors.dividerColor,
1176
+ apiChip: {
1177
+ paddingHorizontal: 7,
1178
+ paddingVertical: 2,
1179
+ borderRadius: 4,
1180
+ backgroundColor: 'rgba(104,75,155,0.06)',
1181
+ borderWidth: 1,
1182
+ borderColor: 'rgba(104,75,155,0.15)',
1183
+ alignItems: 'center',
1184
+ justifyContent: 'center',
773
1185
  },
774
- childLabel: {
1186
+ apiChipText: {
775
1187
  fontFamily: AppFonts_1.AppFonts.interBold,
776
- fontSize: 11.5,
777
- color: AppColors_1.AppColors.grayText,
778
- marginTop: 2,
779
- },
780
- actionTypeBadge: {
781
- backgroundColor: '#FCE7F3',
782
- borderColor: '#FBCFE8',
783
- borderWidth: 1,
784
- borderRadius: 6,
785
- paddingHorizontal: 6,
786
- paddingVertical: 2,
1188
+ fontSize: 9.5,
1189
+ color: AppColors_1.AppColors.purple,
787
1190
  },
788
- actionTypeText: {
1191
+ apiTitleText: {
789
1192
  fontFamily: AppFonts_1.AppFonts.interBold,
790
- fontSize: 10.5,
791
- color: '#BE185D',
1193
+ fontSize: 16,
1194
+ color: AppColors_1.AppColors.primaryBlack,
1195
+ marginBottom: 8,
792
1196
  },
793
- noActionText: {
1197
+ apiMetaRow: {
1198
+ flexDirection: 'row',
1199
+ alignItems: 'center',
1200
+ gap: 4,
1201
+ },
1202
+ apiMetaText: {
794
1203
  fontFamily: AppFonts_1.AppFonts.interRegular,
795
1204
  fontSize: 11,
796
1205
  color: AppColors_1.AppColors.grayTextWeak,
797
1206
  },
798
- timestampText: {
799
- fontFamily: AppFonts_1.AppFonts.interRegular,
800
- fontSize: 9.5,
801
- color: AppColors_1.AppColors.grayTextWeak,
802
- marginTop: 2,
1207
+ contentDetailSubHeader: {
1208
+ flexDirection: 'row',
1209
+ alignItems: 'center',
1210
+ justifyContent: 'space-between',
1211
+ paddingHorizontal: 12,
1212
+ paddingVertical: 10,
1213
+ borderBottomWidth: 1,
1214
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
1215
+ backgroundColor: AppColors_1.AppColors.primaryLight,
803
1216
  },
804
1217
  });