react-native-inapp-inspector 2.3.5 → 2.3.6

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 (226) hide show
  1. package/dist/commonjs/analytics.d.ts +0 -4
  2. package/dist/commonjs/analytics.js +0 -4
  3. package/dist/commonjs/bundle.d.ts +0 -4
  4. package/dist/commonjs/bundle.js +0 -4
  5. package/dist/commonjs/components/AnalyticsDetail.js +18 -27
  6. package/dist/commonjs/components/AnalyticsEventCard.js +9 -12
  7. package/dist/commonjs/components/AnalyticsGraph.js +10 -15
  8. package/dist/commonjs/components/AppHeaderLogo.js +0 -3
  9. package/dist/commonjs/components/BrandCircleIcon.js +15 -15
  10. package/dist/commonjs/components/BrandSquareIcon.js +20 -20
  11. package/dist/commonjs/components/CodeSnippet.js +6 -19
  12. package/dist/commonjs/components/ConsoleLogCard.js +0 -1
  13. package/dist/commonjs/components/CopyButton.js +0 -4
  14. package/dist/commonjs/components/DiffViewer.js +0 -2
  15. package/dist/commonjs/components/DomainHeader.js +0 -4
  16. package/dist/commonjs/components/EmptyState.js +0 -3
  17. package/dist/commonjs/components/ErrorBoundary.js +5 -10
  18. package/dist/commonjs/components/HeadersSection.js +0 -5
  19. package/dist/commonjs/components/HighlightText.js +1 -4
  20. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +11 -26
  21. package/dist/commonjs/components/Inspector/AnalyticsTab.js +34 -40
  22. package/dist/commonjs/components/Inspector/BundleTab.js +56 -84
  23. package/dist/commonjs/components/Inspector/ConsoleTab.js +7 -7
  24. package/dist/commonjs/components/Inspector/CrashDetail.js +18 -20
  25. package/dist/commonjs/components/Inspector/CrashFilterModal.js +0 -1
  26. package/dist/commonjs/components/Inspector/CrashTab.js +11 -20
  27. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +12 -24
  28. package/dist/commonjs/components/Inspector/FabLauncher.js +1 -1
  29. package/dist/commonjs/components/Inspector/InspectorContext.js +0 -2
  30. package/dist/commonjs/components/Inspector/InspectorHeader.js +7 -8
  31. package/dist/commonjs/components/Inspector/LogDetail.js +27 -29
  32. package/dist/commonjs/components/Inspector/MainScreen.js +9 -10
  33. package/dist/commonjs/components/Inspector/NetworkDetail.js +10 -11
  34. package/dist/commonjs/components/Inspector/NetworkTab.js +14 -14
  35. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +6 -9
  36. package/dist/commonjs/components/Inspector/PerformanceTab.js +30 -43
  37. package/dist/commonjs/components/Inspector/ReduxDetail.js +18 -34
  38. package/dist/commonjs/components/Inspector/ReduxTab.js +11 -20
  39. package/dist/commonjs/components/Inspector/SettingsPanel.js +32 -36
  40. package/dist/commonjs/components/Inspector/SkeletonPlaceholder.js +6 -6
  41. package/dist/commonjs/components/Inspector/StorageTab.js +14 -26
  42. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +5 -6
  43. package/dist/commonjs/components/JsonViewer.js +3 -10
  44. package/dist/commonjs/components/LogCard.js +7 -7
  45. package/dist/commonjs/components/MetaAccordion.js +1 -7
  46. package/dist/commonjs/components/NetworkIcons.js +12 -16
  47. package/dist/commonjs/components/SectionHeader.js +0 -4
  48. package/dist/commonjs/components/SkeletonPlaceholder.js +6 -6
  49. package/dist/commonjs/components/Slider.js +6 -6
  50. package/dist/commonjs/components/SourcePageCard.js +0 -4
  51. package/dist/commonjs/components/TreeNode.js +0 -4
  52. package/dist/commonjs/console.d.ts +0 -4
  53. package/dist/commonjs/console.js +0 -4
  54. package/dist/commonjs/constants/index.js +6 -9
  55. package/dist/commonjs/constants/telemetryConfig.d.ts +7 -0
  56. package/dist/commonjs/constants/telemetryConfig.js +10 -0
  57. package/dist/commonjs/constants/version.d.ts +1 -1
  58. package/dist/commonjs/constants/version.js +1 -3
  59. package/dist/commonjs/crash.d.ts +0 -4
  60. package/dist/commonjs/crash.js +0 -4
  61. package/dist/commonjs/customHooks/analyticsLogger.d.ts +0 -7
  62. package/dist/commonjs/customHooks/analyticsLogger.js +3 -59
  63. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +0 -9
  64. package/dist/commonjs/customHooks/bundleAnalyzer.js +3 -86
  65. package/dist/commonjs/customHooks/consoleLogger.js +0 -16
  66. package/dist/commonjs/customHooks/crashHandler.d.ts +0 -28
  67. package/dist/commonjs/customHooks/crashHandler.js +0 -55
  68. package/dist/commonjs/customHooks/logFilters.d.ts +0 -4
  69. package/dist/commonjs/customHooks/logFilters.js +0 -11
  70. package/dist/commonjs/customHooks/networkLogger.js +2 -13
  71. package/dist/commonjs/customHooks/performanceTracker.d.ts +0 -27
  72. package/dist/commonjs/customHooks/performanceTracker.js +0 -31
  73. package/dist/commonjs/customHooks/reduxLogger.d.ts +0 -12
  74. package/dist/commonjs/customHooks/reduxLogger.js +0 -51
  75. package/dist/commonjs/customHooks/storageInspector.d.ts +0 -40
  76. package/dist/commonjs/customHooks/storageInspector.js +1 -56
  77. package/dist/commonjs/decorators/index.d.ts +0 -37
  78. package/dist/commonjs/decorators/index.js +0 -42
  79. package/dist/commonjs/helpers/gaAnalyticsRegistry.d.ts +0 -10
  80. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +0 -26
  81. package/dist/commonjs/helpers/index.d.ts +0 -7
  82. package/dist/commonjs/helpers/index.js +1 -42
  83. package/dist/commonjs/helpers/memoryManager.d.ts +0 -11
  84. package/dist/commonjs/helpers/memoryManager.js +0 -13
  85. package/dist/commonjs/helpers/searchQueryParser.d.ts +0 -4
  86. package/dist/commonjs/helpers/searchQueryParser.js +0 -18
  87. package/dist/commonjs/helpers/settingsStore.js +0 -8
  88. package/dist/commonjs/helpers/telemetry.d.ts +2 -0
  89. package/dist/commonjs/helpers/telemetry.js +302 -0
  90. package/dist/commonjs/i18n/index.d.ts +0 -9
  91. package/dist/commonjs/i18n/index.js +0 -15
  92. package/dist/commonjs/index.js +15 -97
  93. package/dist/commonjs/native/NativeInspector.d.ts +0 -54
  94. package/dist/commonjs/native/NativeInspector.js +0 -56
  95. package/dist/commonjs/network.d.ts +0 -4
  96. package/dist/commonjs/network.js +0 -4
  97. package/dist/commonjs/performance.d.ts +0 -4
  98. package/dist/commonjs/performance.js +0 -4
  99. package/dist/commonjs/redux.d.ts +0 -4
  100. package/dist/commonjs/redux.js +0 -4
  101. package/dist/commonjs/storage.d.ts +0 -4
  102. package/dist/commonjs/storage.js +0 -4
  103. package/dist/commonjs/styles/AppColors.d.ts +0 -3
  104. package/dist/commonjs/styles/AppColors.js +15 -30
  105. package/dist/commonjs/styles/AppFonts.d.ts +0 -4
  106. package/dist/commonjs/styles/AppFonts.js +0 -4
  107. package/dist/commonjs/styles/common.js +0 -11
  108. package/dist/commonjs/styles/index.js +0 -8
  109. package/dist/commonjs/types/enums.js +0 -3
  110. package/dist/commonjs/types/interfaces.d.ts +3 -3
  111. package/dist/esm/analytics.d.ts +0 -4
  112. package/dist/esm/analytics.js +0 -4
  113. package/dist/esm/bundle.d.ts +0 -4
  114. package/dist/esm/bundle.js +0 -4
  115. package/dist/esm/components/AnalyticsDetail.js +18 -27
  116. package/dist/esm/components/AnalyticsEventCard.js +9 -12
  117. package/dist/esm/components/AnalyticsGraph.js +10 -15
  118. package/dist/esm/components/AppHeaderLogo.js +0 -3
  119. package/dist/esm/components/BrandCircleIcon.js +15 -15
  120. package/dist/esm/components/BrandSquareIcon.js +20 -20
  121. package/dist/esm/components/CodeSnippet.js +6 -19
  122. package/dist/esm/components/ConsoleLogCard.js +0 -1
  123. package/dist/esm/components/CopyButton.js +0 -4
  124. package/dist/esm/components/DiffViewer.js +0 -2
  125. package/dist/esm/components/DomainHeader.js +0 -4
  126. package/dist/esm/components/EmptyState.js +0 -3
  127. package/dist/esm/components/ErrorBoundary.js +5 -10
  128. package/dist/esm/components/HeadersSection.js +0 -5
  129. package/dist/esm/components/HighlightText.js +1 -4
  130. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +11 -26
  131. package/dist/esm/components/Inspector/AnalyticsTab.js +34 -40
  132. package/dist/esm/components/Inspector/BundleTab.js +56 -84
  133. package/dist/esm/components/Inspector/ConsoleTab.js +7 -7
  134. package/dist/esm/components/Inspector/CrashDetail.js +18 -20
  135. package/dist/esm/components/Inspector/CrashFilterModal.js +0 -1
  136. package/dist/esm/components/Inspector/CrashTab.js +11 -20
  137. package/dist/esm/components/Inspector/DeviceInfoTab.js +12 -24
  138. package/dist/esm/components/Inspector/FabLauncher.js +1 -1
  139. package/dist/esm/components/Inspector/InspectorContext.js +0 -2
  140. package/dist/esm/components/Inspector/InspectorHeader.js +7 -8
  141. package/dist/esm/components/Inspector/LogDetail.js +27 -29
  142. package/dist/esm/components/Inspector/MainScreen.js +9 -10
  143. package/dist/esm/components/Inspector/NetworkDetail.js +10 -11
  144. package/dist/esm/components/Inspector/NetworkTab.js +14 -14
  145. package/dist/esm/components/Inspector/NpmUpdateToast.js +6 -9
  146. package/dist/esm/components/Inspector/PerformanceTab.js +30 -43
  147. package/dist/esm/components/Inspector/ReduxDetail.js +18 -34
  148. package/dist/esm/components/Inspector/ReduxTab.js +11 -20
  149. package/dist/esm/components/Inspector/SettingsPanel.js +32 -36
  150. package/dist/esm/components/Inspector/SkeletonPlaceholder.js +6 -6
  151. package/dist/esm/components/Inspector/StorageTab.js +14 -26
  152. package/dist/esm/components/Inspector/UpdateAvailableModal.js +5 -6
  153. package/dist/esm/components/JsonViewer.js +3 -10
  154. package/dist/esm/components/LogCard.js +7 -7
  155. package/dist/esm/components/MetaAccordion.js +1 -7
  156. package/dist/esm/components/NetworkIcons.js +12 -16
  157. package/dist/esm/components/SectionHeader.js +0 -4
  158. package/dist/esm/components/SkeletonPlaceholder.js +6 -6
  159. package/dist/esm/components/Slider.js +6 -6
  160. package/dist/esm/components/SourcePageCard.js +0 -4
  161. package/dist/esm/components/TreeNode.js +0 -4
  162. package/dist/esm/console.d.ts +0 -4
  163. package/dist/esm/console.js +0 -4
  164. package/dist/esm/constants/index.js +6 -9
  165. package/dist/esm/constants/telemetryConfig.d.ts +7 -0
  166. package/dist/esm/constants/telemetryConfig.js +7 -0
  167. package/dist/esm/constants/version.d.ts +1 -1
  168. package/dist/esm/constants/version.js +1 -3
  169. package/dist/esm/crash.d.ts +0 -4
  170. package/dist/esm/crash.js +0 -4
  171. package/dist/esm/customHooks/analyticsLogger.d.ts +0 -7
  172. package/dist/esm/customHooks/analyticsLogger.js +3 -59
  173. package/dist/esm/customHooks/bundleAnalyzer.d.ts +0 -9
  174. package/dist/esm/customHooks/bundleAnalyzer.js +3 -86
  175. package/dist/esm/customHooks/consoleLogger.js +0 -16
  176. package/dist/esm/customHooks/crashHandler.d.ts +0 -28
  177. package/dist/esm/customHooks/crashHandler.js +0 -55
  178. package/dist/esm/customHooks/logFilters.d.ts +0 -4
  179. package/dist/esm/customHooks/logFilters.js +0 -11
  180. package/dist/esm/customHooks/networkLogger.js +2 -13
  181. package/dist/esm/customHooks/performanceTracker.d.ts +0 -27
  182. package/dist/esm/customHooks/performanceTracker.js +0 -31
  183. package/dist/esm/customHooks/reduxLogger.d.ts +0 -12
  184. package/dist/esm/customHooks/reduxLogger.js +0 -51
  185. package/dist/esm/customHooks/storageInspector.d.ts +0 -40
  186. package/dist/esm/customHooks/storageInspector.js +1 -56
  187. package/dist/esm/decorators/index.d.ts +0 -37
  188. package/dist/esm/decorators/index.js +0 -42
  189. package/dist/esm/helpers/gaAnalyticsRegistry.d.ts +0 -10
  190. package/dist/esm/helpers/gaAnalyticsRegistry.js +0 -26
  191. package/dist/esm/helpers/index.d.ts +0 -7
  192. package/dist/esm/helpers/index.js +1 -42
  193. package/dist/esm/helpers/memoryManager.d.ts +0 -11
  194. package/dist/esm/helpers/memoryManager.js +0 -13
  195. package/dist/esm/helpers/searchQueryParser.d.ts +0 -4
  196. package/dist/esm/helpers/searchQueryParser.js +0 -18
  197. package/dist/esm/helpers/settingsStore.js +0 -8
  198. package/dist/esm/helpers/telemetry.d.ts +2 -0
  199. package/dist/esm/helpers/telemetry.js +298 -0
  200. package/dist/esm/i18n/index.d.ts +0 -9
  201. package/dist/esm/i18n/index.js +0 -15
  202. package/dist/esm/index.js +15 -97
  203. package/dist/esm/native/NativeInspector.d.ts +0 -54
  204. package/dist/esm/native/NativeInspector.js +0 -56
  205. package/dist/esm/network.d.ts +0 -4
  206. package/dist/esm/network.js +0 -4
  207. package/dist/esm/performance.d.ts +0 -4
  208. package/dist/esm/performance.js +0 -4
  209. package/dist/esm/redux.d.ts +0 -4
  210. package/dist/esm/redux.js +0 -4
  211. package/dist/esm/storage.d.ts +0 -4
  212. package/dist/esm/storage.js +0 -4
  213. package/dist/esm/styles/AppColors.d.ts +0 -3
  214. package/dist/esm/styles/AppColors.js +15 -30
  215. package/dist/esm/styles/AppFonts.d.ts +0 -4
  216. package/dist/esm/styles/AppFonts.js +0 -4
  217. package/dist/esm/styles/common.js +0 -11
  218. package/dist/esm/styles/index.js +0 -8
  219. package/dist/esm/types/enums.js +0 -3
  220. package/dist/esm/types/interfaces.d.ts +3 -3
  221. package/package.json +2 -2
  222. package/src/constants/telemetryConfig.ts +16 -0
  223. package/src/constants/version.ts +1 -1
  224. package/src/helpers/telemetry.ts +341 -0
  225. package/src/index.tsx +15 -1
  226. package/src/types/interfaces.ts +3 -0
@@ -14,7 +14,6 @@ import { getPerformanceEvents, subscribePerformanceEvents, logPerformanceEvent,
14
14
  import { startNativeFpsMonitoring, stopNativeFpsMonitoring, getNativeFpsMetrics, getNativeSystemMetrics, isNativeModuleAvailable, } from '../../native/NativeInspector';
15
15
  const PerformanceTab = React.memo(() => {
16
16
  const { t } = useTranslation();
17
- // ─── Real-Time FPS Tracking ────────────────────────────────────────────────
18
17
  const [isRecording, setIsRecording] = useState(true);
19
18
  const [currentFps, setCurrentFps] = useState(60);
20
19
  const [minFps, setMinFps] = useState(57);
@@ -23,7 +22,6 @@ const PerformanceTab = React.memo(() => {
23
22
  const [totalFrames, setTotalFrames] = useState(4820);
24
23
  const [jankyFrameCount, setJankyFrameCount] = useState(4);
25
24
  const [jsLagMs, setJsLagMs] = useState(1.2);
26
- // Expanded Event Card IDs
27
25
  const [expandedEventIds, setExpandedEventIds] = useState({
28
26
  'perf-1': true,
29
27
  });
@@ -33,11 +31,9 @@ const PerformanceTab = React.memo(() => {
33
31
  [id]: !prev[id],
34
32
  }));
35
33
  };
36
- // FPS history for sparkline
37
34
  const [fpsHistory, setFpsHistory] = useState([
38
35
  60, 59, 60, 60, 58, 60, 59, 60, 60, 60, 57, 60, 59, 60, 60, 58, 60, 60, 59, 60,
39
36
  ]);
40
- // Performance Log Events (Dynamic live subscription)
41
37
  const [events, setEvents] = useState(() => getPerformanceEvents());
42
38
  const [filterCategory, setFilterCategory] = useState('ALL');
43
39
  const [search, setSearch] = useState('');
@@ -47,7 +43,6 @@ const PerformanceTab = React.memo(() => {
47
43
  });
48
44
  return unsub;
49
45
  }, []);
50
- // ─── Live Frame Measurement Loop (1-Second Batch Interval) ────────────────
51
46
  const lastFrameTimeRef = useRef(Date.now());
52
47
  const rafIdRef = useRef(null);
53
48
  const [systemMetrics, setSystemMetrics] = useState(null);
@@ -87,13 +82,11 @@ const PerformanceTab = React.memo(() => {
87
82
  const now = Date.now();
88
83
  const delta = now - lastFrameTimeRef.current;
89
84
  lastFrameTimeRef.current = now;
90
- // Track peak JS event loop lag during this 1s interval (without triggering re-renders)
91
85
  const lag = Math.max(0, delta - 16.67);
92
86
  if (lag > maxLagInSecond) {
93
87
  maxLagInSecond = lag;
94
88
  }
95
89
  frameCount++;
96
- // Update React state ONCE every 1 second (1000ms) to prevent UI shaking/re-rendering
97
90
  if (now - lastSecond >= 1000) {
98
91
  const elapsed = now - lastSecond;
99
92
  let measuredFps = Math.min(120, Math.max(0, Math.round((frameCount * 1000) / elapsed)));
@@ -120,7 +113,6 @@ const PerformanceTab = React.memo(() => {
120
113
  setAvgFps(Math.round(sum / next.length));
121
114
  return next;
122
115
  });
123
- // Trigger log if noticeable frame drop
124
116
  if (measuredFps < 50) {
125
117
  const durationStr = (1000 / measuredFps).toFixed(1);
126
118
  logPerformanceEvent({
@@ -153,7 +145,6 @@ const PerformanceTab = React.memo(() => {
153
145
  cancelAnimationFrame(rafIdRef.current);
154
146
  };
155
147
  }, [isRecording]);
156
- // Filtered Events
157
148
  const filteredEvents = useMemo(() => {
158
149
  return events.filter(e => {
159
150
  const matchSearch = !search ||
@@ -174,7 +165,6 @@ const PerformanceTab = React.memo(() => {
174
165
  return matchSearch && matchFilter;
175
166
  });
176
167
  }, [events, search, filterCategory]);
177
- // Overall Performance Score
178
168
  const performanceScore = useMemo(() => {
179
169
  if (avgFps >= 58) {
180
170
  return {
@@ -199,7 +189,6 @@ const PerformanceTab = React.memo(() => {
199
189
  bg: AppColors.errorCardBg,
200
190
  };
201
191
  }, [avgFps, t]);
202
- // ─── Dynamic Runtime Environment & Engine Diagnostics ──────────────────────
203
192
  const runtimeDiagnostics = useMemo(() => {
204
193
  const raw = getRuntimeDiagnostics();
205
194
  const engineNameMap = {
@@ -229,7 +218,6 @@ const PerformanceTab = React.memo(() => {
229
218
  totalAllocMb: raw.totalAllocMb,
230
219
  };
231
220
  }, [t]);
232
- // ─── Dynamic 16.67ms Frame Budget Utilization ─────────────────────────────
233
221
  const frameBudgetStats = useMemo(() => {
234
222
  const frameDuration = avgFps > 0 ? 1000 / avgFps : 16.67;
235
223
  const jsTime = Number(Math.max(1.0, Math.min(frameDuration * 0.45, 2.0 + jsLagMs)).toFixed(1));
@@ -246,7 +234,6 @@ const PerformanceTab = React.memo(() => {
246
234
  headroomPercent,
247
235
  };
248
236
  }, [avgFps, jsLagMs]);
249
- // ─── Dynamic SVG FPS Area & Trend Curve Data ────────────────────────────
250
237
  const [selectedFpsPointIdx, setSelectedFpsPointIdx] = useState(null);
251
238
  const svgGraphWidth = 320;
252
239
  const svgGraphHeight = 64;
@@ -329,7 +316,7 @@ const PerformanceTab = React.memo(() => {
329
316
  ? fpsGraphData.coords[selectedFpsPointIdx]
330
317
  : null;
331
318
  return (<View style={perfStyles.container}>
332
- {/* Search & Live Control Header */}
319
+
333
320
  <View style={perfStyles.headerBar}>
334
321
  <View style={perfStyles.searchBox}>
335
322
  <SearchIcon color={AppColors.grayTextWeak} size={15}/>
@@ -339,7 +326,7 @@ const PerformanceTab = React.memo(() => {
339
326
  </TouchableScale>) : null}
340
327
  </View>
341
328
 
342
- {/* Live FPS Telemetry Recorder Toggle */}
329
+
343
330
  <TouchableScale onPress={() => setIsRecording(prev => !prev)} style={[
344
331
  perfStyles.recordToggleBtn,
345
332
  isRecording
@@ -369,7 +356,7 @@ const PerformanceTab = React.memo(() => {
369
356
  </TouchableScale>
370
357
  </View>
371
358
 
372
- {/* Filter Category Tabs Carousel */}
359
+
373
360
  <View style={perfStyles.categoryScrollWrapper}>
374
361
  <ScrollView horizontal showsHorizontalScrollIndicator={false} style={perfStyles.categoryScrollView} contentContainerStyle={perfStyles.categoryScroll}>
375
362
  {[
@@ -423,9 +410,9 @@ const PerformanceTab = React.memo(() => {
423
410
  </ScrollView>
424
411
  </View>
425
412
 
426
- {/* Main Content Scroll View */}
413
+
427
414
  <ScrollView style={perfStyles.scrollBody} contentContainerStyle={perfStyles.scrollContent} showsVerticalScrollIndicator={false}>
428
- {/* ── 1. REAL-TIME FPS SCORECARD & SMOOTH AREA GRAPH ── */}
415
+
429
416
  <View style={perfStyles.heroCard}>
430
417
  <View style={perfStyles.heroHeaderRow}>
431
418
  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
@@ -440,7 +427,7 @@ const PerformanceTab = React.memo(() => {
440
427
  </View>
441
428
  </View>
442
429
 
443
- {/* Health Grade Score Pill */}
430
+
444
431
  <View style={[
445
432
  perfStyles.scorePill,
446
433
  { backgroundColor: performanceScore.bg },
@@ -454,7 +441,7 @@ const PerformanceTab = React.memo(() => {
454
441
  </View>
455
442
  </View>
456
443
 
457
- {/* Primary Gauge Counter */}
444
+
458
445
  <View style={perfStyles.primaryFpsRow}>
459
446
  <View style={perfStyles.fpsBigNumberBox}>
460
447
  <Text style={[
@@ -515,7 +502,7 @@ const PerformanceTab = React.memo(() => {
515
502
  </View>
516
503
  </View>
517
504
 
518
- {/* Interactive Scrub Tooltip */}
505
+
519
506
  {activeScrubPoint && (<View style={perfStyles.graphScrubTooltip}>
520
507
  <Text style={perfStyles.graphScrubTooltipText}>
521
508
  {activeScrubPoint.val} FPS •{' '}
@@ -524,7 +511,7 @@ const PerformanceTab = React.memo(() => {
524
511
  </Text>
525
512
  </View>)}
526
513
 
527
- {/* Real-Time SVG Smooth Area & Trend Wave Graph */}
514
+
528
515
  <View style={perfStyles.svgGraphContainer}>
529
516
  <Svg width="100%" height={svgGraphHeight} viewBox={`0 0 ${svgGraphWidth} ${svgGraphHeight}`} preserveAspectRatio="none">
530
517
  <Defs>
@@ -542,23 +529,23 @@ const PerformanceTab = React.memo(() => {
542
529
  </LinearGradient>
543
530
  </Defs>
544
531
 
545
- {/* 60 FPS Target Baseline */}
532
+
546
533
  <Line x1="0" y1="7" x2={svgGraphWidth} y2="7" stroke={AppColors.emerald500} strokeWidth="1" strokeDasharray="4,4" opacity="0.4"/>
547
534
 
548
- {/* 30 FPS Warning Baseline */}
535
+
549
536
  <Line x1="0" y1={svgGraphHeight / 2} x2={svgGraphWidth} y2={svgGraphHeight / 2} stroke={AppColors.amber500} strokeWidth="0.8" strokeDasharray="3,3" opacity="0.3"/>
550
537
 
551
- {/* Shaded Area Under Curve */}
538
+
552
539
  {fpsGraphData.areaPath ? (<Path d={fpsGraphData.areaPath} fill="url(#fpsAreaGradient)"/>) : null}
553
540
 
554
- {/* Bezier Trend Line */}
541
+
555
542
  {fpsGraphData.linePath ? (<Path d={fpsGraphData.linePath} fill="none" stroke={avgFps >= 55
556
543
  ? AppColors.emerald600
557
544
  : avgFps >= 40
558
545
  ? AppColors.amber600
559
546
  : AppColors.errorColor} strokeWidth="2.2"/>) : null}
560
547
 
561
- {/* Sample Nodes */}
548
+
562
549
  {fpsGraphData.coords.map((c, idx) => {
563
550
  const isSelected = selectedFpsPointIdx === idx;
564
551
  const isDip = c.val < 50;
@@ -573,7 +560,7 @@ const PerformanceTab = React.memo(() => {
573
560
  })}
574
561
  </Svg>
575
562
 
576
- {/* Invisible Touch Column Targets for Interactive Inspection */}
563
+
577
564
  <View style={perfStyles.svgTouchOverlay}>
578
565
  {fpsGraphData.coords.map((_, idx) => (<TouchableOpacity key={idx} style={perfStyles.svgTouchCol} activeOpacity={0.7} onPress={() => setSelectedFpsPointIdx(selectedFpsPointIdx === idx ? null : idx)}/>))}
579
566
  </View>
@@ -589,7 +576,7 @@ const PerformanceTab = React.memo(() => {
589
576
  </View>
590
577
  </View>
591
578
 
592
- {/* ── 1.5 NATIVE HARDWARE HEALTH & SYSTEM TELEMETRY CARD ── */}
579
+
593
580
  <View style={perfStyles.budgetCard}>
594
581
  <View style={perfStyles.budgetHeader}>
595
582
  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
@@ -646,7 +633,7 @@ const PerformanceTab = React.memo(() => {
646
633
  </View>
647
634
  </View>
648
635
 
649
- {/* ── 2. FRAME LATENCY DISTRIBUTION HISTOGRAM CARD ── */}
636
+
650
637
  <View style={perfStyles.budgetCard}>
651
638
  <View style={perfStyles.budgetHeader}>
652
639
  <View>
@@ -693,7 +680,7 @@ const PerformanceTab = React.memo(() => {
693
680
  </View>
694
681
  </View>
695
682
 
696
- {/* ── 3. FRAME BUDGET BREAKDOWN CARD ── */}
683
+
697
684
  <View style={perfStyles.budgetCard}>
698
685
  <View style={perfStyles.budgetHeader}>
699
686
  <Text style={perfStyles.budgetTitle}>{t('performance.budgetUsage')}</Text>
@@ -705,7 +692,7 @@ const PerformanceTab = React.memo(() => {
705
692
  </Text>
706
693
  </View>
707
694
 
708
- {/* Multi-colored segmented frame budget bar */}
695
+
709
696
  <View style={perfStyles.budgetBarContainer}>
710
697
  <View style={[
711
698
  perfStyles.budgetBarSegment,
@@ -753,7 +740,7 @@ const PerformanceTab = React.memo(() => {
753
740
  </View>
754
741
  </View>
755
742
 
756
- {/* ── 3. RUNTIME ENGINE & MEMORY SUMMARY ── */}
743
+
757
744
  <View style={perfStyles.engineSummaryGrid}>
758
745
  <View style={perfStyles.engineSummaryCard}>
759
746
  <Text style={perfStyles.engineSummaryLabel}>{t('performance.jsEngine')}</Text>
@@ -774,7 +761,7 @@ const PerformanceTab = React.memo(() => {
774
761
  </View>
775
762
  </View>
776
763
 
777
- {/* ── 4. PERFORMANCE LOGS & DETAILED EVENTS ── */}
764
+
778
765
  <View style={perfStyles.logsHeaderRow}>
779
766
  <Text style={perfStyles.logsSectionHeading}>
780
767
  {t('performance.recordedEvents')} ({filteredEvents.length})
@@ -813,7 +800,7 @@ const PerformanceTab = React.memo(() => {
813
800
  </Text>
814
801
  </View>
815
802
 
816
- {/* Dropped Frames Badge */}
803
+
817
804
  <View style={[
818
805
  perfStyles.droppedBadge,
819
806
  (event.droppedFrames ?? Math.max(0, 60 - event.fps)) > 0
@@ -832,7 +819,7 @@ const PerformanceTab = React.memo(() => {
832
819
  </Text>
833
820
  </View>
834
821
 
835
- {/* Bottleneck Thread Tag */}
822
+
836
823
  {event.bottleneckThread && (<View style={[perfStyles.bottleneckTag, { flexDirection: 'row', alignItems: 'center', gap: 3 }]}>
837
824
  {event.bottleneckThread === 'JS Thread' && (<BoltIcon size={10} color={AppColors.warningIconGold}/>)}
838
825
  <Text style={perfStyles.bottleneckTagText}>
@@ -851,7 +838,7 @@ const PerformanceTab = React.memo(() => {
851
838
  </View>
852
839
  </View>
853
840
 
854
- {/* Event Label & Meta */}
841
+
855
842
  <View style={{ marginTop: 4 }}>
856
843
  <HighlightText text={event.label} search={search} style={perfStyles.eventLabel} highlightStyle={perfStyles.searchHighlight}/>
857
844
  <View style={perfStyles.eventMetaRow}>
@@ -876,7 +863,7 @@ const PerformanceTab = React.memo(() => {
876
863
  </View>
877
864
  </View>
878
865
 
879
- {/* Visual Frame Time Budget Bar */}
866
+
880
867
  <View style={perfStyles.frameBarTrack}>
881
868
  <View style={[
882
869
  perfStyles.frameBarFill,
@@ -889,9 +876,9 @@ const PerformanceTab = React.memo(() => {
889
876
 
890
877
  <HighlightText text={event.detail} search={search} style={perfStyles.eventDetail} highlightStyle={perfStyles.searchHighlight}/>
891
878
 
892
- {/* ── EXPANDABLE IN-DEPTH METRICS ACCORDION ── */}
879
+
893
880
  {isExpanded && (<View style={perfStyles.expandedDetailBox}>
894
- {/* Screen / Component Context */}
881
+
895
882
  {(event.screenName || event.source) && (<View style={perfStyles.sourceRow}>
896
883
  <Text style={perfStyles.sourceTag}>{t('performance.screenContext')}</Text>
897
884
  <Text style={perfStyles.sourceText} numberOfLines={1}>
@@ -899,7 +886,7 @@ const PerformanceTab = React.memo(() => {
899
886
  </Text>
900
887
  </View>)}
901
888
 
902
- {/* Frame Metrics Grid */}
889
+
903
890
  <View style={perfStyles.fpsMetricsGrid}>
904
891
  <View style={perfStyles.fpsMetricItem}>
905
892
  <Text style={perfStyles.fpsMetricLabel}>{t('performance.target60Fps', { fps: event.fps })}</Text>
@@ -930,7 +917,7 @@ const PerformanceTab = React.memo(() => {
930
917
  </View>
931
918
  </View>
932
919
 
933
- {/* Thread Timing Breakdown */}
920
+
934
921
  {event.breakdown && (<View style={perfStyles.breakdownGrid}>
935
922
  <View style={perfStyles.breakdownCol}>
936
923
  <Text style={perfStyles.breakdownLabel}>{t('performance.jsThread')}</Text>
@@ -961,7 +948,7 @@ const PerformanceTab = React.memo(() => {
961
948
  </View>)}
962
949
  </View>)}
963
950
 
964
- {/* Actionable Optimization Tip */}
951
+
965
952
  {event.advice && (<View style={perfStyles.adviceCard}>
966
953
  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
967
954
  <LightbulbIcon color={AppColors.purpleShade700} size={12}/>
@@ -62,22 +62,16 @@ const getOriginBadge = (originType) => {
62
62
  const ReduxDetail = React.memo(() => {
63
63
  const { t } = useTranslation();
64
64
  const { reduxState, reduxLastActionMap, selectedReduxSlice, selectedReduxAction, setSelectedReduxSlice, } = useInspector();
65
- // Search filter within details
66
65
  const [detailSearch, setDetailSearch] = useState('');
67
- // Sub-tabs for Slice & Action
68
66
  const [sliceTab, setSliceTab] = useState('live');
69
67
  const [actionTab, setActionTab] = useState('payload');
70
68
  const [viewMode, setViewMode] = useState('pretty');
71
- // Selected Action inside Timeline
72
69
  const [expandedActionId, setExpandedActionId] = useState(null);
73
- // Persistence data for active slice
74
70
  const [isPersisted, setIsPersisted] = useState(false);
75
71
  const [persistedData, setPersistedData] = useState(null);
76
- // Fetch Action History
77
72
  const allActionHistory = useMemo(() => {
78
73
  return getActionHistory();
79
74
  }, [reduxLastActionMap]);
80
- // Slices-filtered actions
81
75
  const sliceActions = useMemo(() => {
82
76
  if (!selectedReduxSlice)
83
77
  return allActionHistory;
@@ -87,7 +81,6 @@ const ReduxDetail = React.memo(() => {
87
81
  return action.affectedSlices.includes(selectedReduxSlice);
88
82
  });
89
83
  }, [allActionHistory, selectedReduxSlice]);
90
- // Filtered slice actions by search query in timeline tab
91
84
  const filteredTimelineActions = useMemo(() => {
92
85
  if (!detailSearch.trim())
93
86
  return sliceActions;
@@ -138,7 +131,6 @@ const ReduxDetail = React.memo(() => {
138
131
  }
139
132
  }
140
133
  catch (e) {
141
- // silent catch
142
134
  }
143
135
  setIsPersisted(false);
144
136
  setPersistedData(null);
@@ -181,9 +173,6 @@ const ReduxDetail = React.memo(() => {
181
173
  },
182
174
  ]);
183
175
  };
184
- // ══════════════════════════════════════════════════════════════════════════
185
- // ── 1. RENDER SLICE DETAIL VIEW ───────────────────────────────────────────
186
- // ══════════════════════════════════════════════════════════════════════════
187
176
  if (selectedReduxSlice != null) {
188
177
  const sliceData = reduxState?.[selectedReduxSlice];
189
178
  const fieldsCount = sliceData && typeof sliceData === 'object'
@@ -217,7 +206,7 @@ const ReduxDetail = React.memo(() => {
217
206
  },
218
207
  ];
219
208
  return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
220
- {/* Info Header Bar */}
209
+
221
210
  <View style={reduxDetailStyles.infoBar}>
222
211
  <View style={reduxDetailStyles.infoTopRow}>
223
212
  <View style={{
@@ -257,11 +246,11 @@ const ReduxDetail = React.memo(() => {
257
246
  </View>)}
258
247
  </View>
259
248
 
260
- {/* Copy Button */}
249
+
261
250
  <CopyButton value={() => (sliceTab === 'live' ? sliceData : persistedData)} label={t('redux.sliceJson', 'Slice JSON')}/>
262
251
  </View>
263
252
 
264
- {/* Sub Stats Row */}
253
+
265
254
  <View style={reduxDetailStyles.subStatsRow}>
266
255
  <View style={[
267
256
  reduxDetailStyles.statPill,
@@ -350,11 +339,11 @@ const ReduxDetail = React.memo(() => {
350
339
  </View>)}
351
340
  </View>
352
341
 
353
- {/* Sub-Tabs */}
342
+
354
343
  <SegmentedTabs tabs={sliceTabs} activeKey={sliceTab} onChange={key => setSliceTab(key)} style={{ marginTop: 10 }}/>
355
344
  </View>
356
345
 
357
- {/* Search Bar within slice (for Live, Timeline, Persisted) */}
346
+
358
347
  {sliceTab !== 'metadata' && (<View style={reduxDetailStyles.searchContainer}>
359
348
  <SearchIcon color={AppColors.grayTextWeak} size={14}/>
360
349
  <TextInput placeholder={sliceTab === 'timeline'
@@ -365,7 +354,7 @@ const ReduxDetail = React.memo(() => {
365
354
  </Pressable>)}
366
355
  </View>)}
367
356
 
368
- {/* Content Body */}
357
+
369
358
  {sliceTab === 'timeline' ? (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 12, paddingBottom: 40 }} keyboardShouldPersistTaps="handled">
370
359
  {filteredTimelineActions.length === 0 ? (<View style={reduxDetailStyles.emptyBox}>
371
360
  <TimelineIcon color={AppColors.grayTextWeak} size={28}/>
@@ -396,7 +385,7 @@ const ReduxDetail = React.memo(() => {
396
385
  #{action.id}
397
386
  </Text>
398
387
  </View>
399
- {/* Origin Badge */}
388
+
400
389
  <View style={{
401
390
  flexDirection: 'row',
402
391
  alignItems: 'center',
@@ -430,7 +419,7 @@ const ReduxDetail = React.memo(() => {
430
419
  </View>
431
420
  </View>
432
421
 
433
- {/* Trigger caller preview row */}
422
+
434
423
  {action.callerFile && (<View style={{
435
424
  flexDirection: 'row',
436
425
  alignItems: 'center',
@@ -488,9 +477,9 @@ const ReduxDetail = React.memo(() => {
488
477
  </Pressable>
489
478
  </View>)}
490
479
 
491
- {/* Expanded Payload, Diff Viewer & Call Stack */}
480
+
492
481
  {isExpanded ? (<View style={reduxDetailStyles.expandedContent}>
493
- {/* Call Stack Trace Box */}
482
+
494
483
  {action.stack ? (<View style={{ marginBottom: 12 }}>
495
484
  <Text style={reduxDetailStyles.expandedSectionTitle}>
496
485
  {t('redux.callStack', 'Call Stack Trace')}:
@@ -656,16 +645,11 @@ const ReduxDetail = React.memo(() => {
656
645
  State exists purely in active JavaScript memory.
657
646
  </Text>
658
647
  </View>)}
659
- </View>) : (
660
- /* Live State JsonViewer: Direct flex: 1 with fullHeight to prevent nested scroll conflicts */
661
- <View style={{ flex: 1, padding: 10 }}>
648
+ </View>) : (<View style={{ flex: 1, padding: 10 }}>
662
649
  <JsonViewer data={sliceData} search={detailSearch} forceOpen={detailSearch.length > 0 ? true : undefined} mode={viewMode} onModeChange={setViewMode} fullHeight={true} wrap={true}/>
663
650
  </View>)}
664
651
  </View>);
665
652
  }
666
- // ══════════════════════════════════════════════════════════════════════════
667
- // ── 2. RENDER ACTION DETAIL VIEW (when an action is selected directly) ────
668
- // ══════════════════════════════════════════════════════════════════════════
669
653
  if (selectedReduxAction != null) {
670
654
  const originMeta = getOriginBadge(selectedReduxAction.originType);
671
655
  const callerBasename = selectedReduxAction.callerFile
@@ -694,7 +678,7 @@ const ReduxDetail = React.memo(() => {
694
678
  },
695
679
  ];
696
680
  return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
697
- {/* Top Info Bar */}
681
+
698
682
  <View style={reduxDetailStyles.infoBar}>
699
683
  <View style={reduxDetailStyles.infoTopRow}>
700
684
  <View style={{
@@ -710,7 +694,7 @@ const ReduxDetail = React.memo(() => {
710
694
  #{selectedReduxAction.id}
711
695
  </Text>
712
696
  </View>
713
- {/* Origin Badge */}
697
+
714
698
  <View style={{
715
699
  flexDirection: 'row',
716
700
  alignItems: 'center',
@@ -743,11 +727,11 @@ const ReduxDetail = React.memo(() => {
743
727
  </View>)}
744
728
  </View>
745
729
 
746
- {/* Copy Button */}
730
+
747
731
  <CopyButton value={() => selectedReduxAction} label="Copy Action"/>
748
732
  </View>
749
733
 
750
- {/* Sub Stats Row */}
734
+
751
735
  <View style={reduxDetailStyles.subStatsRow}>
752
736
  {selectedReduxAction.affectedSlices &&
753
737
  selectedReduxAction.affectedSlices.length > 0 && (<View style={[
@@ -793,7 +777,7 @@ const ReduxDetail = React.memo(() => {
793
777
  </View>
794
778
  </View>
795
779
 
796
- {/* Triggered from caller preview row */}
780
+
797
781
  {selectedReduxAction.callerFile && (<View style={{
798
782
  flexDirection: 'row',
799
783
  alignItems: 'center',
@@ -850,11 +834,11 @@ const ReduxDetail = React.memo(() => {
850
834
  </Pressable>
851
835
  </View>)}
852
836
 
853
- {/* Sub-Tabs */}
837
+
854
838
  <SegmentedTabs tabs={actionTabs} activeKey={actionTab} onChange={key => setActionTab(key)} style={{ marginTop: 10 }}/>
855
839
  </View>
856
840
 
857
- {/* Content Body */}
841
+
858
842
  {actionTab === 'payload' ? (<View style={{ flex: 1, padding: 10 }}>
859
843
  {selectedReduxAction.payload !== undefined ? (<JsonViewer data={selectedReduxAction.payload} search={detailSearch} forceOpen={true} fullHeight={true} wrap={true}/>) : (<View style={reduxDetailStyles.emptyBox}>
860
844
  <Text style={reduxDetailStyles.emptyBoxText}>
@@ -60,9 +60,7 @@ const getOriginBadge = (originType) => {
60
60
  const ReduxTab = React.memo(() => {
61
61
  const { t } = useTranslation();
62
62
  const { reduxState, reduxLastActionMap, reduxSearch, setReduxSearch, setSelectedReduxSlice, } = useInspector();
63
- // Sort mode: 'latest' (newest updated first) vs 'alpha' (A-Z)
64
63
  const [sortMode, setSortMode] = useState('latest');
65
- // Pause / Live Auto-Refresh State
66
64
  const [isReduxPaused, setIsReduxPaused] = useState(!getReduxAutoRefresh());
67
65
  const handleTogglePause = useCallback(() => {
68
66
  setIsReduxPaused(prev => {
@@ -71,15 +69,12 @@ const ReduxTab = React.memo(() => {
71
69
  return next;
72
70
  });
73
71
  }, []);
74
- // Total state size calculation
75
72
  const totalStateSize = useMemo(() => {
76
73
  return getSize(reduxState);
77
74
  }, [reduxState]);
78
- // Fetch full action history for timeline counts
79
75
  const allActions = useMemo(() => {
80
76
  return getActionHistory();
81
77
  }, [reduxLastActionMap]);
82
- // Compute slice items with exact timestamps & rich details
83
78
  const sliceItems = useMemo(() => {
84
79
  if (!reduxState || typeof reduxState !== 'object')
85
80
  return [];
@@ -102,7 +97,6 @@ const ReduxTab = React.memo(() => {
102
97
  keysCount = 1;
103
98
  typeLabel = typeof sliceVal;
104
99
  }
105
- // Determine state status
106
100
  let status = 'live';
107
101
  let statusMessage;
108
102
  if (isObject) {
@@ -127,7 +121,6 @@ const ReduxTab = React.memo(() => {
127
121
  }
128
122
  const lastActionRaw = reduxLastActionMap[key];
129
123
  const updatedAt = lastActionRaw?.updatedAt || 0;
130
- // Count actions affecting this slice in timeline
131
124
  const timelineCount = allActions.filter(action => {
132
125
  if (!action.affectedSlices || action.affectedSlices.length === 0)
133
126
  return true;
@@ -173,7 +166,6 @@ const ReduxTab = React.memo(() => {
173
166
  };
174
167
  });
175
168
  }, [reduxState, reduxLastActionMap, allActions]);
176
- // Filter & Sort slices: by default, the most recently updated item is at the FIRST position
177
169
  const filteredSlices = useMemo(() => {
178
170
  let list = sliceItems;
179
171
  if (reduxSearch && reduxSearch.trim().length > 0) {
@@ -194,7 +186,6 @@ const ReduxTab = React.memo(() => {
194
186
  }
195
187
  return [...list].sort((a, b) => {
196
188
  if (sortMode === 'latest') {
197
- // Most recently updated item first
198
189
  if (b.updatedAt !== a.updatedAt) {
199
190
  return b.updatedAt - a.updatedAt;
200
191
  }
@@ -220,7 +211,7 @@ const ReduxTab = React.memo(() => {
220
211
  reduxTabStyles.card,
221
212
  isRecentlyUpdated && reduxTabStyles.cardRecentlyUpdated,
222
213
  ]}>
223
- {/* Top row: Badge + Slice Name + Status + Timestamp + Chevron */}
214
+
224
215
  <View style={reduxTabStyles.cardHeader}>
225
216
  <View style={reduxTabStyles.sliceBadge}>
226
217
  <Text style={reduxTabStyles.sliceBadgeText}>SLICE</Text>
@@ -228,7 +219,7 @@ const ReduxTab = React.memo(() => {
228
219
 
229
220
  <HighlightText text={item.name} search={reduxSearch} style={reduxTabStyles.sliceName} highlightStyle={reduxTabStyles.highlight}/>
230
221
 
231
- {/* Status Badge */}
222
+
232
223
  {item.status === 'loading' ? (<View style={reduxTabStyles.loadingPill}>
233
224
  <LoadingSpinnerIcon color={AppColors.amber800Warm} size={10}/>
234
225
  <Text style={reduxTabStyles.loadingPillText}>Loading</Text>
@@ -252,7 +243,7 @@ const ReduxTab = React.memo(() => {
252
243
  <ForwardChevronIcon color={AppColors.grayTextWeak} size={13}/>
253
244
  </View>
254
245
 
255
- {/* Middle row: Stats pills */}
246
+
256
247
  <View style={reduxTabStyles.statsRow}>
257
248
  <View style={reduxTabStyles.pill}>
258
249
  <LayersIcon color={AppColors.grayTextWeak} size={11}/>
@@ -268,13 +259,13 @@ const ReduxTab = React.memo(() => {
268
259
  </View>)}
269
260
  </View>
270
261
 
271
- {/* Bottom row: Last Dispatched Action with Origin & Trigger Line */}
262
+
272
263
  {item.lastAction && (<View style={reduxTabStyles.lastActionRow}>
273
264
  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 5, flex: 1, minWidth: 0, flexWrap: 'wrap' }}>
274
265
  <BoltIcon color={AppColors.brandPurple} size={12}/>
275
266
  <Text style={reduxTabStyles.lastActionLabel}>{t('redux.last', 'Last')}:</Text>
276
267
 
277
- {/* Origin Badge */}
268
+
278
269
  {item.lastAction.originType && (() => {
279
270
  const origin = getOriginBadge(item.lastAction.originType);
280
271
  return (<View style={{
@@ -302,7 +293,7 @@ const ReduxTab = React.memo(() => {
302
293
 
303
294
  <HighlightText text={item.lastAction.type} search={reduxSearch} style={reduxTabStyles.lastActionValue} highlightStyle={reduxTabStyles.highlight} numberOfLines={1}/>
304
295
 
305
- {/* Triggered from file preview */}
296
+
306
297
  {item.lastAction.callerFile && (<Pressable onPress={() => openInVSCode(item.lastAction.callerFile, item.lastAction.callerLine, item.lastAction.callerCol)} hitSlop={6} style={{
307
298
  flexDirection: 'row',
308
299
  alignItems: 'center',
@@ -344,7 +335,7 @@ const ReduxTab = React.memo(() => {
344
335
  </View>);
345
336
  }
346
337
  return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
347
- {/* ─── Top Stats Overview Card ─── */}
338
+
348
339
  <View style={reduxTabStyles.overviewCard}>
349
340
  <View style={reduxTabStyles.statCol}>
350
341
  <Text style={reduxTabStyles.statHeading}>ACTIVE SLICES</Text>
@@ -390,7 +381,7 @@ const ReduxTab = React.memo(() => {
390
381
  </View>
391
382
  </View>
392
383
 
393
- {/* ─── Search & Sort Bar ─── */}
384
+
394
385
  <View style={reduxTabStyles.toolbarContainer}>
395
386
  <View style={reduxTabStyles.searchRow}>
396
387
  <View style={styles.searchContainer}>
@@ -417,7 +408,7 @@ const ReduxTab = React.memo(() => {
417
408
  </View>)}
418
409
  </View>
419
410
 
420
- {/* Pause / Resume Live Updates Button */}
411
+
421
412
  <TouchableOpacity accessible={true} accessibilityRole="button" accessibilityLabel={isReduxPaused
422
413
  ? 'Resume live Redux updates'
423
414
  : 'Pause live Redux updates'} accessibilityHint="Toggles automatic recording of Redux state updates" style={[
@@ -432,7 +423,7 @@ const ReduxTab = React.memo(() => {
432
423
  : AppColors.grayTextStrong} size={16}/>
433
424
  </TouchableOpacity>
434
425
 
435
- {/* Sort Button */}
426
+
436
427
  <TouchableOpacity accessible={true} accessibilityRole="button" accessibilityLabel={`Sort order: ${sortMode === 'latest'
437
428
  ? 'Recently updated first'
438
429
  : 'Alphabetical A to Z'}`} accessibilityHint="Switches sorting between recently updated and alphabetical" style={[
@@ -461,7 +452,7 @@ const ReduxTab = React.memo(() => {
461
452
  </View>
462
453
  </View>
463
454
 
464
- {/* ─── FlatList of Slices ─── */}
455
+
465
456
  <FlatList data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={reduxSearch.length > 0}/>} ListFooterComponent={filteredSlices.length > 0 ? (<EndOfListFooter count={filteredSlices.length} label="slices"/>) : null} contentContainerStyle={[
466
457
  reduxTabStyles.listContent,
467
458
  filteredSlices.length === 0 && { flexGrow: 1 },