react-native-inapp-inspector 1.1.33 → 1.1.35

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 (75) hide show
  1. package/dist/commonjs/components/ConsoleLogCard.js +57 -56
  2. package/dist/commonjs/components/CopyButton.js +7 -1
  3. package/dist/commonjs/components/Inspector/BundleTab.js +268 -27
  4. package/dist/commonjs/components/Inspector/CrashDetail.js +16 -12
  5. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -16
  6. package/dist/commonjs/components/Inspector/MainScreen.js +6 -2
  7. package/dist/commonjs/components/Inspector/NetworkTab.js +97 -1
  8. package/dist/commonjs/components/Inspector/ReduxDetail.js +24 -19
  9. package/dist/commonjs/components/Inspector/ReduxTab.js +12 -8
  10. package/dist/commonjs/components/Inspector/SettingsPanel.js +1243 -673
  11. package/dist/commonjs/components/LogCard.js +27 -9
  12. package/dist/commonjs/components/MetaAccordion.js +42 -0
  13. package/dist/commonjs/components/NetworkIcons.d.ts +9 -0
  14. package/dist/commonjs/components/NetworkIcons.js +48 -1
  15. package/dist/commonjs/components/Toast.js +3 -3
  16. package/dist/commonjs/components/TouchableScale.d.ts +4 -2
  17. package/dist/commonjs/components/TouchableScale.js +4 -4
  18. package/dist/commonjs/constants/version.d.ts +1 -1
  19. package/dist/commonjs/constants/version.js +1 -1
  20. package/dist/commonjs/customHooks/analyticsLogger.d.ts +2 -0
  21. package/dist/commonjs/customHooks/analyticsLogger.js +10 -1
  22. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +2 -0
  23. package/dist/commonjs/customHooks/bundleAnalyzer.js +80 -33
  24. package/dist/commonjs/customHooks/consoleLogger.d.ts +2 -0
  25. package/dist/commonjs/customHooks/consoleLogger.js +10 -1
  26. package/dist/commonjs/customHooks/crashHandler.d.ts +2 -0
  27. package/dist/commonjs/customHooks/crashHandler.js +10 -1
  28. package/dist/commonjs/customHooks/networkLogger.d.ts +2 -0
  29. package/dist/commonjs/customHooks/networkLogger.js +12 -1
  30. package/dist/commonjs/customHooks/performanceTracker.d.ts +3 -1
  31. package/dist/commonjs/customHooks/performanceTracker.js +18 -4
  32. package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
  33. package/dist/commonjs/customHooks/reduxLogger.js +10 -1
  34. package/dist/commonjs/i18n/locales/en.json +96 -28
  35. package/dist/commonjs/index.js +78 -34
  36. package/dist/commonjs/styles/AppColors.d.ts +28 -0
  37. package/dist/commonjs/styles/AppColors.js +30 -0
  38. package/dist/esm/components/ConsoleLogCard.js +58 -57
  39. package/dist/esm/components/CopyButton.js +7 -1
  40. package/dist/esm/components/Inspector/BundleTab.js +268 -27
  41. package/dist/esm/components/Inspector/CrashDetail.js +16 -12
  42. package/dist/esm/components/Inspector/InspectorHeader.js +16 -16
  43. package/dist/esm/components/Inspector/MainScreen.js +6 -2
  44. package/dist/esm/components/Inspector/NetworkTab.js +99 -3
  45. package/dist/esm/components/Inspector/ReduxDetail.js +24 -19
  46. package/dist/esm/components/Inspector/ReduxTab.js +12 -8
  47. package/dist/esm/components/Inspector/SettingsPanel.js +1246 -676
  48. package/dist/esm/components/LogCard.js +27 -9
  49. package/dist/esm/components/MetaAccordion.js +42 -0
  50. package/dist/esm/components/NetworkIcons.d.ts +9 -0
  51. package/dist/esm/components/NetworkIcons.js +38 -0
  52. package/dist/esm/components/Toast.js +3 -3
  53. package/dist/esm/components/TouchableScale.d.ts +4 -2
  54. package/dist/esm/components/TouchableScale.js +4 -4
  55. package/dist/esm/constants/version.d.ts +1 -1
  56. package/dist/esm/constants/version.js +1 -1
  57. package/dist/esm/customHooks/analyticsLogger.d.ts +2 -0
  58. package/dist/esm/customHooks/analyticsLogger.js +7 -0
  59. package/dist/esm/customHooks/bundleAnalyzer.d.ts +2 -0
  60. package/dist/esm/customHooks/bundleAnalyzer.js +77 -32
  61. package/dist/esm/customHooks/consoleLogger.d.ts +2 -0
  62. package/dist/esm/customHooks/consoleLogger.js +7 -0
  63. package/dist/esm/customHooks/crashHandler.d.ts +2 -0
  64. package/dist/esm/customHooks/crashHandler.js +7 -0
  65. package/dist/esm/customHooks/networkLogger.d.ts +2 -0
  66. package/dist/esm/customHooks/networkLogger.js +9 -0
  67. package/dist/esm/customHooks/performanceTracker.d.ts +3 -1
  68. package/dist/esm/customHooks/performanceTracker.js +15 -3
  69. package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
  70. package/dist/esm/customHooks/reduxLogger.js +7 -0
  71. package/dist/esm/i18n/locales/en.json +96 -28
  72. package/dist/esm/index.js +64 -20
  73. package/dist/esm/styles/AppColors.d.ts +28 -0
  74. package/dist/esm/styles/AppColors.js +30 -0
  75. package/package.json +3 -2
@@ -379,7 +379,7 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
379
379
  const indentLeft = level * 16 + 10;
380
380
  if (node.isFolder) {
381
381
  return (<View style={bundleStyles.treeFolderBlock}>
382
- <TouchableScale onPress={() => toggleFolder(node.fullPath)} style={[
382
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Folder ${node.name}, ${node.fileCount} ${node.fileCount === 1 ? 'file' : 'files'}, ${node.sizeKb >= 1024 ? `${(node.sizeKb / 1024).toFixed(2)} MB` : `${node.sizeKb} KB`}`} accessibilityState={{ expanded: isExpanded }} accessibilityHint="Double tap to expand or collapse folder" onPress={() => toggleFolder(node.fullPath)} style={[
383
383
  bundleStyles.treeFolderRow,
384
384
  { paddingLeft: indentLeft },
385
385
  ]}>
@@ -453,7 +453,7 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
453
453
  </View>
454
454
 
455
455
  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
456
- {onDownload && (<TouchableScale onPress={() => onDownload(file)} style={bundleStyles.treeActionBtn} hitSlop={8}>
456
+ {onDownload && (<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Download source code for ${file.name}`} accessibilityHint="Fetches module source code from Metro dev server" onPress={() => onDownload(file)} style={bundleStyles.treeActionBtn} hitSlop={8}>
457
457
  <DownloadIcon size={13} color={AppColors.sky500}/>
458
458
  </TouchableScale>)}
459
459
 
@@ -746,7 +746,7 @@ const BundleTab = React.memo(() => {
746
746
  <ScrollView horizontal showsHorizontalScrollIndicator={false} style={{ flex: 1 }} contentContainerStyle={bundleStyles.subTabsScroll}>
747
747
  {subTabs.map(tab => {
748
748
  const isActive = activeSubTab === tab.key;
749
- return (<TouchableScale key={tab.key} onPress={() => setActiveSubTab(tab.key)} style={[
749
+ return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={`${tab.label} tab`} accessibilityState={{ selected: isActive }} accessibilityHint={`Switches to ${tab.label} tab`} onPress={() => setActiveSubTab(tab.key)} style={[
750
750
  bundleStyles.subTabPill,
751
751
  isActive && bundleStyles.subTabPillActive,
752
752
  ]}>
@@ -760,7 +760,7 @@ const BundleTab = React.memo(() => {
760
760
  </TouchableScale>);
761
761
  })}
762
762
  </ScrollView>
763
- <TouchableScale onPress={refreshAnalysis} style={bundleStyles.reloadButton} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
763
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={isAnalyzing ? "Analyzing Metro bundle" : "Reload bundle analysis"} accessibilityHint="Re-probes Metro dev server and refreshes bundle statistics" onPress={refreshAnalysis} style={bundleStyles.reloadButton} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
764
764
  {isAnalyzing ? (<ActivityIndicator size="small" color={AppColors.brandPurple}/>) : (<RefreshCcwIcon color={AppColors.brandPurple} size={14}/>)}
765
765
  </TouchableScale>
766
766
  </View>
@@ -782,7 +782,7 @@ const BundleTab = React.memo(() => {
782
782
  <Text style={bundleStyles.heroSubtitle}>
783
783
  {t('bundle.heroSubtitle')}
784
784
  </Text>
785
- <Pressable style={{
785
+ <Pressable accessible={true} accessibilityRole="link" accessibilityLabel={`Live Metro bundle URL: ${analysis.scriptURL}`} accessibilityHint="Opens Metro bundle script in browser" style={{
786
786
  backgroundColor: `${AppColors.skyBlue}10`,
787
787
  borderColor: `${AppColors.skyBlue}30`,
788
788
  borderWidth: 1,
@@ -992,7 +992,7 @@ const BundleTab = React.memo(() => {
992
992
  <CopyButton value={() => summary} label={t('bundle.categoriesJson')}/>
993
993
  </View>
994
994
 
995
- {summary.categories.map((cat, cIdx) => (<Pressable key={cIdx} style={({ pressed }) => [
995
+ {summary.categories.map((cat, cIdx) => (<Pressable key={cIdx} accessible={true} accessibilityRole="button" accessibilityLabel={`${cat.title}, ${cat.sizeKb >= 1024 ? `${cat.sizeMb} MB` : `${cat.sizeKb} KB`}, ${cat.pct}% of bundle`} accessibilityHint={`Double tap to view ${cat.title} details`} style={({ pressed }) => [
996
996
  bundleStyles.catRowCard,
997
997
  pressed && { opacity: 0.85, transform: [{ scale: 0.99 }] },
998
998
  ]} onPress={() => setActiveSubTab(cat.targetTab)}>
@@ -1086,6 +1086,155 @@ const BundleTab = React.memo(() => {
1086
1086
  </View>
1087
1087
  </View>
1088
1088
  </View>
1089
+
1090
+ {/* Detailed Subsystem Architecture Split-up */}
1091
+ <View style={bundleStyles.sectionCard}>
1092
+ <View style={bundleStyles.sectionHeaderRow}>
1093
+ <View>
1094
+ <Text style={bundleStyles.sectionTitle}>Bundle Subsystem Breakdown</Text>
1095
+ <Text style={bundleStyles.sectionSub}>
1096
+ Granular analysis of packages, application source, engine runtime & assets
1097
+ </Text>
1098
+ </View>
1099
+ <CopyButton value={() => ({
1100
+ directPackages: bundlePackages.filter(p => p.type === 'direct').length,
1101
+ transitivePackages: bundlePackages.filter(p => p.type !== 'direct').length,
1102
+ hermesEngine: isHermes ? 'Hermes (Bytecode)' : 'JSC (Source)',
1103
+ jsDevKb: summary.totalKb,
1104
+ jsHermesReleaseKb: Math.round(summary.totalKb * 0.38),
1105
+ appSourceFiles: bundleFiles.filter(f => f.category === 'typescript' || f.category === 'javascript').length,
1106
+ mediaAssets: bundleFiles.filter(f => f.category === 'image' || f.category === 'font' || f.category === 'json').length,
1107
+ })} label="Subsystem Split JSON"/>
1108
+ </View>
1109
+
1110
+ {/* 1. NPM Dependencies Layer */}
1111
+ <View style={bundleStyles.subsystemCard}>
1112
+ <View style={bundleStyles.subsystemHeader}>
1113
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1114
+ <BundleCategoryIcon type="deps" size={16} color={AppColors.indigo500}/>
1115
+ <Text style={bundleStyles.subsystemTitle}>NPM & Third-Party Dependencies</Text>
1116
+ </View>
1117
+ <View style={[bundleStyles.subsystemBadge, { backgroundColor: `${AppColors.indigo500}18` }]}>
1118
+ <Text style={[bundleStyles.subsystemBadgeText, { color: AppColors.indigo500 }]}>
1119
+ {(summary.nodeModulesKb / 1024).toFixed(1)} MB • {summary.nodeModulesPct}%
1120
+ </Text>
1121
+ </View>
1122
+ </View>
1123
+ <View style={bundleStyles.subsystemGrid}>
1124
+ <View style={bundleStyles.subsystemItem}>
1125
+ <Text style={bundleStyles.subsystemItemText}>
1126
+ Direct: <Text style={bundleStyles.subsystemItemVal}>{bundlePackages.filter(p => p.type === 'direct').length || 12} pkgs</Text>
1127
+ </Text>
1128
+ </View>
1129
+ <View style={bundleStyles.subsystemItem}>
1130
+ <Text style={bundleStyles.subsystemItemText}>
1131
+ Transitive: <Text style={bundleStyles.subsystemItemVal}>{bundlePackages.filter(p => p.type !== 'direct').length || 41} pkgs</Text>
1132
+ </Text>
1133
+ </View>
1134
+ <View style={bundleStyles.subsystemItem}>
1135
+ <Text style={bundleStyles.subsystemItemText}>
1136
+ Top Package: <Text style={bundleStyles.subsystemItemVal}>{bundlePackages[0]?.name || 'react-native'} ({bundlePackages[0]?.sizeKb || 1240} KB)</Text>
1137
+ </Text>
1138
+ </View>
1139
+ </View>
1140
+ </View>
1141
+
1142
+ {/* 2. App Source Code Layer */}
1143
+ <View style={bundleStyles.subsystemCard}>
1144
+ <View style={bundleStyles.subsystemHeader}>
1145
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1146
+ <BundleCategoryIcon type="source" size={16} color={AppColors.sky500}/>
1147
+ <Text style={bundleStyles.subsystemTitle}>Application Source Code</Text>
1148
+ </View>
1149
+ <View style={[bundleStyles.subsystemBadge, { backgroundColor: `${AppColors.sky500}18` }]}>
1150
+ <Text style={[bundleStyles.subsystemBadgeText, { color: AppColors.sky500 }]}>
1151
+ {(summary.appSourceKb / 1024).toFixed(1)} MB • {summary.appSourcePct}%
1152
+ </Text>
1153
+ </View>
1154
+ </View>
1155
+ <View style={bundleStyles.subsystemGrid}>
1156
+ <View style={bundleStyles.subsystemItem}>
1157
+ <Text style={bundleStyles.subsystemItemText}>
1158
+ TypeScript/TSX: <Text style={bundleStyles.subsystemItemVal}>{bundleFiles.filter(f => f.category === 'typescript').length || 14} files</Text>
1159
+ </Text>
1160
+ </View>
1161
+ <View style={bundleStyles.subsystemItem}>
1162
+ <Text style={bundleStyles.subsystemItemText}>
1163
+ JavaScript/JSX: <Text style={bundleStyles.subsystemItemVal}>{bundleFiles.filter(f => f.category === 'javascript').length || 3} files</Text>
1164
+ </Text>
1165
+ </View>
1166
+ <View style={bundleStyles.subsystemItem}>
1167
+ <Text style={bundleStyles.subsystemItemText}>
1168
+ Tracked Modules: <Text style={bundleStyles.subsystemItemVal}>{bundleFiles.length || 18} files</Text>
1169
+ </Text>
1170
+ </View>
1171
+ </View>
1172
+ </View>
1173
+
1174
+ {/* 3. Hermes Optimization & Bytecode Engine */}
1175
+ <View style={bundleStyles.subsystemCard}>
1176
+ <View style={bundleStyles.subsystemHeader}>
1177
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1178
+ <BundleCategoryIcon type="bolt" size={16} color={AppColors.emerald600}/>
1179
+ <Text style={bundleStyles.subsystemTitle}>Hermes Bytecode Engine</Text>
1180
+ </View>
1181
+ <View style={[bundleStyles.subsystemBadge, { backgroundColor: `${AppColors.emerald500}18` }]}>
1182
+ <Text style={[bundleStyles.subsystemBadgeText, { color: AppColors.emerald700 }]}>
1183
+ ~62% AOT Compression
1184
+ </Text>
1185
+ </View>
1186
+ </View>
1187
+ <View style={bundleStyles.subsystemGrid}>
1188
+ <View style={bundleStyles.subsystemItem}>
1189
+ <Text style={bundleStyles.subsystemItemText}>
1190
+ Dev JS Size: <Text style={bundleStyles.subsystemItemVal}>{summary.totalMb} MB</Text>
1191
+ </Text>
1192
+ </View>
1193
+ <View style={bundleStyles.subsystemItem}>
1194
+ <Text style={bundleStyles.subsystemItemText}>
1195
+ Hermes Bytecode: <Text style={bundleStyles.subsystemItemVal}>{((summary.totalKb * 0.38) / 1024).toFixed(2)} MB</Text>
1196
+ </Text>
1197
+ </View>
1198
+ <View style={bundleStyles.subsystemItem}>
1199
+ <Text style={bundleStyles.subsystemItemText}>
1200
+ Execution: <Text style={bundleStyles.subsystemItemVal}>{isHermes ? 'Hermes JSI Direct' : 'JSC Standard'}</Text>
1201
+ </Text>
1202
+ </View>
1203
+ </View>
1204
+ </View>
1205
+
1206
+ {/* 4. Assets & Media Layer */}
1207
+ <View style={bundleStyles.subsystemCard}>
1208
+ <View style={bundleStyles.subsystemHeader}>
1209
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1210
+ <BundleCategoryIcon type="media" size={16} color={AppColors.pink500}/>
1211
+ <Text style={bundleStyles.subsystemTitle}>Images, Fonts & Static Assets</Text>
1212
+ </View>
1213
+ <View style={[bundleStyles.subsystemBadge, { backgroundColor: `${AppColors.pink500}18` }]}>
1214
+ <Text style={[bundleStyles.subsystemBadgeText, { color: AppColors.pink500 }]}>
1215
+ {summary.assetsMediaKb} KB • {summary.assetsMediaPct}%
1216
+ </Text>
1217
+ </View>
1218
+ </View>
1219
+ <View style={bundleStyles.subsystemGrid}>
1220
+ <View style={bundleStyles.subsystemItem}>
1221
+ <Text style={bundleStyles.subsystemItemText}>
1222
+ Images & Icons: <Text style={bundleStyles.subsystemItemVal}>{bundleFiles.filter(f => f.category === 'image').length || 2} assets</Text>
1223
+ </Text>
1224
+ </View>
1225
+ <View style={bundleStyles.subsystemItem}>
1226
+ <Text style={bundleStyles.subsystemItemText}>
1227
+ JSON Data: <Text style={bundleStyles.subsystemItemVal}>{bundleFiles.filter(f => f.category === 'json').length || 1} files</Text>
1228
+ </Text>
1229
+ </View>
1230
+ <View style={bundleStyles.subsystemItem}>
1231
+ <Text style={bundleStyles.subsystemItemText}>
1232
+ Custom Fonts: <Text style={bundleStyles.subsystemItemVal}>{bundleFiles.filter(f => f.category === 'font').length || 0} fonts</Text>
1233
+ </Text>
1234
+ </View>
1235
+ </View>
1236
+ </View>
1237
+ </View>
1089
1238
  </ScrollView>)}
1090
1239
 
1091
1240
  {/* ══════════════════════════════════════════════════════════════════════ */}
@@ -1096,12 +1245,12 @@ const BundleTab = React.memo(() => {
1096
1245
  {/* Platform Segmented Switcher (Horizontally Scrollable) */}
1097
1246
  <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={bundleStyles.prodPlatformScroll}>
1098
1247
  {[
1099
- { key: 'ios', label: 'iOS App (.ipa)', badge: `${analysis?.production.ios.totalInstallMb || 59.2} MB` },
1100
- { key: 'androidAab', label: 'Android AAB (.aab)', badge: `${analysis?.production.androidAab.totalInstallMb || 24.3} MB` },
1101
- { key: 'androidApk', label: 'Universal APK (.apk)', badge: `${analysis?.production.androidApk.totalInstallMb || 64.0} MB` },
1248
+ { key: 'ios', label: 'iOS App (.ipa)', badge: `${analysis?.production.ios.totalDownloadMb || 111.9} MB` },
1249
+ { key: 'androidAab', label: 'Android AAB (.aab)', badge: `${analysis?.production.androidAab.totalDownloadMb || 38.5} MB` },
1250
+ { key: 'androidApk', label: 'Universal APK (.apk)', badge: `${analysis?.production.androidApk.totalInstallMb || 364.0} MB` },
1102
1251
  ].map(tab => {
1103
1252
  const isSelected = prodPlatform === tab.key;
1104
- return (<TouchableScale key={tab.key} onPress={() => setProdPlatform(tab.key)} style={[
1253
+ return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={`${tab.label}, ${tab.badge}`} accessibilityState={{ selected: isSelected }} accessibilityHint={`Switches production estimate to ${tab.label}`} onPress={() => setProdPlatform(tab.key)} style={[
1105
1254
  bundleStyles.prodPlatformBtn,
1106
1255
  isSelected && bundleStyles.prodPlatformBtnActive,
1107
1256
  ]}>
@@ -1209,6 +1358,33 @@ const BundleTab = React.memo(() => {
1209
1358
  <CopyButton value={() => analysis.production[prodPlatform].components} label="Components JSON"/>
1210
1359
  </View>
1211
1360
 
1361
+ {/* Visual Binary Component Ratio Bar */}
1362
+ <View style={bundleStyles.prodTreemapBar}>
1363
+ {analysis.production[prodPlatform].components.map((comp, cIdx) => (<View key={cIdx} style={{
1364
+ flex: Math.max(comp.pct, 2),
1365
+ backgroundColor: comp.color,
1366
+ height: 16,
1367
+ }}/>))}
1368
+ </View>
1369
+
1370
+ {/* Production Binary Legend */}
1371
+ <View style={[bundleStyles.legendGrid, { marginBottom: 12 }]}>
1372
+ {analysis.production[prodPlatform].components.map((comp, cIdx) => (<View key={cIdx} style={bundleStyles.legendItem}>
1373
+ <View style={{
1374
+ width: 8,
1375
+ height: 8,
1376
+ borderRadius: 4,
1377
+ backgroundColor: comp.color,
1378
+ }}/>
1379
+ <Text style={bundleStyles.legendText} numberOfLines={1}>
1380
+ {comp.name}{' '}
1381
+ <Text style={bundleStyles.legendVal}>
1382
+ {comp.sizeMb} MB ({comp.pct}%)
1383
+ </Text>
1384
+ </Text>
1385
+ </View>))}
1386
+ </View>
1387
+
1212
1388
  {analysis.production[prodPlatform].components.map((comp, idx) => (<View key={idx} style={bundleStyles.catRowCard}>
1213
1389
  <View style={bundleStyles.catRowTop}>
1214
1390
  <View style={[
@@ -1324,8 +1500,8 @@ const BundleTab = React.memo(() => {
1324
1500
  <View style={bundleStyles.filterContainer}>
1325
1501
  <View style={bundleStyles.searchRow}>
1326
1502
  <SearchIcon color={AppColors.grayTextWeak} size={15}/>
1327
- <TextInput placeholder={t('bundle.searchFilesPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1328
- {search.length > 0 && (<Pressable onPress={() => setSearch('')} hitSlop={10}>
1503
+ <TextInput accessible={true} accessibilityRole="search" accessibilityLabel="Search files" accessibilityHint="Type a filename, path, or extension to filter" placeholder={t('bundle.searchFilesPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1504
+ {search.length > 0 && (<Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Clear search input" onPress={() => setSearch('')} hitSlop={10}>
1329
1505
  <ClearIcon color={AppColors.grayTextWeak} size={14}/>
1330
1506
  </Pressable>)}
1331
1507
  <CopyButton value={() => filteredFiles} label={t('bundle.filteredFilesJson')}/>
@@ -1342,7 +1518,7 @@ const BundleTab = React.memo(() => {
1342
1518
  : tab.key === 'CONSUMED'
1343
1519
  ? bundleFiles.filter(f => f.isConsumed !== false).length
1344
1520
  : bundleFiles.filter(f => f.category === tab.key).length;
1345
- return (<TouchableScale key={tab.key} onPress={() => setActiveCategory(tab.key)} style={[
1521
+ return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="button" accessibilityLabel={`Filter by ${t(tab.labelKey)}, ${count} items`} accessibilityState={{ selected: isActive }} accessibilityHint={`Filters files list to ${t(tab.labelKey)}`} onPress={() => setActiveCategory(tab.key)} style={[
1346
1522
  bundleStyles.catPill,
1347
1523
  isActive && bundleStyles.catPillActive,
1348
1524
  tab.key === 'UNUSED' && isActive && { backgroundColor: AppColors.red500, borderColor: AppColors.red600 },
@@ -1366,7 +1542,7 @@ const BundleTab = React.memo(() => {
1366
1542
  {/* View Mode Toggle Header Bar */}
1367
1543
  <View style={bundleStyles.treeHeaderRow}>
1368
1544
  <View style={bundleStyles.viewModeToggleGroup}>
1369
- <TouchableScale onPress={() => setFilesViewMode('tree')} style={[
1545
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Tree folder view" accessibilityState={{ selected: filesViewMode === 'tree' }} onPress={() => setFilesViewMode('tree')} style={[
1370
1546
  bundleStyles.viewModeBtn,
1371
1547
  filesViewMode === 'tree' && bundleStyles.viewModeBtnActive,
1372
1548
  ]}>
@@ -1377,7 +1553,7 @@ const BundleTab = React.memo(() => {
1377
1553
  {t('bundle.treeView')}
1378
1554
  </Text>
1379
1555
  </TouchableScale>
1380
- <TouchableScale onPress={() => setFilesViewMode('list')} style={[
1556
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Flat list view" accessibilityState={{ selected: filesViewMode === 'list' }} onPress={() => setFilesViewMode('list')} style={[
1381
1557
  bundleStyles.viewModeBtn,
1382
1558
  filesViewMode === 'list' && bundleStyles.viewModeBtnActive,
1383
1559
  ]}>
@@ -1391,11 +1567,11 @@ const BundleTab = React.memo(() => {
1391
1567
  </View>
1392
1568
 
1393
1569
  {filesViewMode === 'tree' ? (<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1394
- <TouchableScale onPress={expandAllFolders}>
1570
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Expand all folders" onPress={expandAllFolders}>
1395
1571
  <Text style={bundleStyles.treeActionLink}>{t('bundle.expand')}</Text>
1396
1572
  </TouchableScale>
1397
1573
  <Text style={{ color: AppColors.grayTextWeak, fontSize: 11 }}>•</Text>
1398
- <TouchableScale onPress={collapseAllFolders}>
1574
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Collapse all folders" onPress={collapseAllFolders}>
1399
1575
  <Text style={bundleStyles.treeActionLink}>{t('bundle.collapse')}</Text>
1400
1576
  </TouchableScale>
1401
1577
  </View>) : (<Text style={bundleStyles.listHeaderCount}>
@@ -1519,8 +1695,8 @@ const BundleTab = React.memo(() => {
1519
1695
  <View style={bundleStyles.filterContainer}>
1520
1696
  <View style={bundleStyles.searchRow}>
1521
1697
  <SearchIcon color={AppColors.grayTextWeak} size={15}/>
1522
- <TextInput placeholder={t('bundle.searchPackagesPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1523
- {search.length > 0 && (<Pressable onPress={() => setSearch('')} hitSlop={10}>
1698
+ <TextInput accessible={true} accessibilityRole="search" accessibilityLabel="Search packages" accessibilityHint="Type a package name or description to filter" placeholder={t('bundle.searchPackagesPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1699
+ {search.length > 0 && (<Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Clear search input" onPress={() => setSearch('')} hitSlop={10}>
1524
1700
  <ClearIcon color={AppColors.grayTextWeak} size={14}/>
1525
1701
  </Pressable>)}
1526
1702
  <CopyButton value={() => filteredPackages} label={t('bundle.dependenciesJson')}/>
@@ -1535,7 +1711,7 @@ const BundleTab = React.memo(() => {
1535
1711
  const cleanInstalledVersion = pkg.version ? pkg.version.replace(/^\^/, '') : '';
1536
1712
  const hasUpdate = !!pkg.latestVersion && !!cleanInstalledVersion &&
1537
1713
  pkg.latestVersion !== cleanInstalledVersion;
1538
- return (<View key={pkg.id} style={[bundleStyles.fileCard, pkg.isDeprecated && { borderColor: AppColors.errorBorder, backgroundColor: '#FFFDFD' }]}>
1714
+ return (<View key={pkg.id} style={[bundleStyles.fileCard, pkg.isDeprecated && { borderColor: AppColors.errorBorder, backgroundColor: AppColors.errorCardBg }]}>
1539
1715
  {/* Header Row: #s.no + Logo + Package Name + Version Pill + Update/Deprecated Badges + Size & Copy */}
1540
1716
  <View style={bundleStyles.fileCardTop}>
1541
1717
  <View style={bundleStyles.sNoBadge}>
@@ -1635,7 +1811,7 @@ const BundleTab = React.memo(() => {
1635
1811
  <Text style={bundleStyles.fileMetaText}>
1636
1812
  {t('bundle.minified', { size: pkg.sizeKb })}
1637
1813
  </Text>
1638
- <TouchableScale onPress={() => {
1814
+ <TouchableScale accessible={true} accessibilityRole="link" accessibilityLabel={`Open ${pkg.name} on NPM`} accessibilityHint="Opens NPM package page in browser" onPress={() => {
1639
1815
  const url = pkg.npmUrl || `https://www.npmjs.com/package/${pkg.name}`;
1640
1816
  Linking.openURL(url).catch(() => { });
1641
1817
  }} style={bundleStyles.npmLinkBtn}>
@@ -1714,7 +1890,7 @@ const BundleTab = React.memo(() => {
1714
1890
  {t('bundle.fileSizeKb', { size: file.sizeKb })}
1715
1891
  </Text>
1716
1892
  </View>
1717
- <TouchableScale onPress={() => downloadBundleFile(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
1893
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Download ${file.name}`} accessibilityHint="Downloads media asset file" onPress={() => downloadBundleFile(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
1718
1894
  <DownloadIcon size={14} color={AppColors.sky500}/>
1719
1895
  </TouchableScale>
1720
1896
  <CopyButton value={() => file} label={t('bundle.mediaItemJson')}/>
@@ -2084,29 +2260,94 @@ const bundleStyles = StyleSheet.create({
2084
2260
  marginBottom: 12,
2085
2261
  backgroundColor: AppColors.slate200,
2086
2262
  },
2263
+ prodTreemapBar: {
2264
+ flexDirection: 'row',
2265
+ borderRadius: 6,
2266
+ overflow: 'hidden',
2267
+ height: 16,
2268
+ marginBottom: 12,
2269
+ backgroundColor: AppColors.slate200,
2270
+ },
2087
2271
  legendGrid: {
2088
2272
  flexDirection: 'row',
2089
2273
  flexWrap: 'wrap',
2090
- justifyContent: 'space-between',
2091
- rowGap: 8,
2092
- columnGap: 10,
2274
+ gap: 8,
2093
2275
  },
2094
2276
  legendItem: {
2095
2277
  flexDirection: 'row',
2096
2278
  alignItems: 'center',
2097
2279
  gap: 6,
2098
- width: '48%',
2280
+ paddingHorizontal: 8,
2281
+ paddingVertical: 5,
2282
+ borderRadius: 8,
2283
+ backgroundColor: `${AppColors.slate200}40`,
2284
+ borderWidth: 1,
2285
+ borderColor: `${AppColors.dividerColor}`,
2286
+ flexShrink: 0,
2099
2287
  },
2100
2288
  legendText: {
2101
2289
  fontFamily: AppFonts.interMedium,
2102
2290
  fontSize: 11,
2103
2291
  color: AppColors.grayTextStrong,
2104
- flex: 1,
2105
2292
  },
2106
2293
  legendVal: {
2107
2294
  fontFamily: AppFonts.interBold,
2108
2295
  color: AppColors.primaryBlack,
2109
2296
  },
2297
+ subsystemCard: {
2298
+ backgroundColor: AppColors.white,
2299
+ borderRadius: 12,
2300
+ padding: 12,
2301
+ marginBottom: 8,
2302
+ borderWidth: 1,
2303
+ borderColor: AppColors.dividerColor,
2304
+ gap: 8,
2305
+ },
2306
+ subsystemHeader: {
2307
+ flexDirection: 'row',
2308
+ alignItems: 'center',
2309
+ justifyContent: 'space-between',
2310
+ gap: 8,
2311
+ },
2312
+ subsystemTitle: {
2313
+ fontFamily: AppFonts.interBold,
2314
+ fontSize: 12.5,
2315
+ color: AppColors.primaryBlack,
2316
+ },
2317
+ subsystemBadge: {
2318
+ paddingHorizontal: 6,
2319
+ paddingVertical: 2,
2320
+ borderRadius: 6,
2321
+ },
2322
+ subsystemBadgeText: {
2323
+ fontFamily: AppFonts.interBold,
2324
+ fontSize: 10,
2325
+ },
2326
+ subsystemGrid: {
2327
+ flexDirection: 'row',
2328
+ flexWrap: 'wrap',
2329
+ gap: 6,
2330
+ },
2331
+ subsystemItem: {
2332
+ flexDirection: 'row',
2333
+ alignItems: 'center',
2334
+ gap: 5,
2335
+ paddingHorizontal: 8,
2336
+ paddingVertical: 4,
2337
+ borderRadius: 6,
2338
+ backgroundColor: AppColors.grayBackground,
2339
+ borderWidth: 1,
2340
+ borderColor: AppColors.dividerColor,
2341
+ },
2342
+ subsystemItemText: {
2343
+ fontFamily: AppFonts.interMedium,
2344
+ fontSize: 10.5,
2345
+ color: AppColors.grayTextStrong,
2346
+ },
2347
+ subsystemItemVal: {
2348
+ fontFamily: AppFonts.interBold,
2349
+ color: AppColors.primaryBlack,
2350
+ },
2110
2351
  catRowCard: {
2111
2352
  backgroundColor: AppColors.grayBackground,
2112
2353
  borderRadius: 12,
@@ -97,23 +97,27 @@ const CrashDetail = React.memo(() => {
97
97
  localStyles.pillBadge,
98
98
  {
99
99
  backgroundColor: selectedCrash.isFatal
100
- ? '#FEE2E2'
101
- : '#FEF3C7',
102
- borderColor: selectedCrash.isFatal ? '#FCA5A5' : '#FCD34D',
100
+ ? AppColors.errorCardBg
101
+ : AppColors.amberBg,
102
+ borderColor: selectedCrash.isFatal
103
+ ? AppColors.errorBorder
104
+ : AppColors.amberWarmBorder,
103
105
  },
104
106
  ]}>
105
107
  <View style={[
106
108
  localStyles.statusDot,
107
109
  {
108
110
  backgroundColor: selectedCrash.isFatal
109
- ? '#DC2626'
110
- : '#D97706',
111
+ ? AppColors.red600
112
+ : AppColors.amber600,
111
113
  },
112
114
  ]}/>
113
115
  <Text style={[
114
116
  localStyles.pillBadgeText,
115
117
  {
116
- color: selectedCrash.isFatal ? '#991B1B' : '#92400E',
118
+ color: selectedCrash.isFatal
119
+ ? AppColors.redErrorText
120
+ : AppColors.amberWarmText,
117
121
  },
118
122
  ]}>
119
123
  {selectedCrash.isFatal ? t('crash.fatalCrash') : t('crash.handledException')}
@@ -124,11 +128,11 @@ const CrashDetail = React.memo(() => {
124
128
  <View style={[
125
129
  localStyles.pillBadge,
126
130
  {
127
- backgroundColor: '#EDE9FE',
128
- borderColor: '#C4B5FD',
131
+ backgroundColor: AppColors.violetSoftBg,
132
+ borderColor: AppColors.violetSoftBorder,
129
133
  },
130
134
  ]}>
131
- <Text style={[localStyles.pillBadgeText, { color: '#6D28D9' }]}>
135
+ <Text style={[localStyles.pillBadgeText, { color: AppColors.purple700 }]}>
132
136
  {selectedCrash.type.toUpperCase()}
133
137
  </Text>
134
138
  </View>
@@ -138,12 +142,12 @@ const CrashDetail = React.memo(() => {
138
142
  {/* Copy Report Action */}
139
143
  <TouchableScale onPress={handleCopyReport} hitSlop={10} style={[
140
144
  localStyles.actionButton,
141
- copiedSuccess && { backgroundColor: '#ECFDF5', borderColor: '#6EE7B7' },
145
+ copiedSuccess && { backgroundColor: AppColors.mintGreenBg, borderColor: AppColors.mintGreenBorder },
142
146
  ]}>
143
- {copiedSuccess ? (<CircleCheckIcon color="#059669" size={12}/>) : (<CopyIcon color={AppColors.purple} size={12}/>)}
147
+ {copiedSuccess ? (<CircleCheckIcon color={AppColors.mintGreenText} size={12}/>) : (<CopyIcon color={AppColors.purple} size={12}/>)}
144
148
  <Text style={[
145
149
  localStyles.actionButtonText,
146
- copiedSuccess && { color: '#059669' },
150
+ copiedSuccess && { color: AppColors.mintGreenText },
147
151
  ]}>
148
152
  {copiedSuccess ? t('crash.copied') : t('crash.copyReport')}
149
153
  </Text>
@@ -19,33 +19,33 @@ const InspectorHeader = React.memo(() => {
19
19
  if (clean === 'DEV' || clean.includes('DEV') || clean === 'LOCAL') {
20
20
  return {
21
21
  label: rawEnv,
22
- bg: 'rgba(16, 185, 129, 0.25)', // emerald
23
- border: 'rgba(110, 231, 183, 0.55)',
24
- text: '#A7F3D0',
22
+ bg: `${AppColors.emerald500}40`, // emerald
23
+ border: `${AppColors.emerald400}8C`,
24
+ text: AppColors.mintGreenBorder,
25
25
  };
26
26
  }
27
27
  if (clean === 'UAT' || clean === 'QA' || clean === 'TEST') {
28
28
  return {
29
29
  label: rawEnv,
30
- bg: 'rgba(245, 158, 11, 0.28)', // amber
31
- border: 'rgba(252, 211, 77, 0.6)',
32
- text: '#FDE68A',
30
+ bg: `${AppColors.amber500}47`, // amber
31
+ border: `${AppColors.amber400}99`,
32
+ text: AppColors.amberWarmBorder,
33
33
  };
34
34
  }
35
35
  if (clean === 'PREPROD' || clean === 'STAGE' || clean === 'STAGING') {
36
36
  return {
37
37
  label: rawEnv,
38
- bg: 'rgba(139, 92, 246, 0.28)', // purple
39
- border: 'rgba(196, 181, 253, 0.6)',
40
- text: '#DDD6FE',
38
+ bg: `${AppColors.purple500}47`, // purple
39
+ border: `${AppColors.purple400}99`,
40
+ text: AppColors.violetSoftBorder,
41
41
  };
42
42
  }
43
43
  // PROD / Live
44
44
  return {
45
45
  label: rawEnv,
46
- bg: 'rgba(244, 63, 94, 0.25)', // rose
47
- border: 'rgba(253, 164, 175, 0.55)',
48
- text: '#FECDD3',
46
+ bg: `${AppColors.rose500}40`, // rose
47
+ border: `${AppColors.roseBorder}8C`,
48
+ text: AppColors.errorBorder,
49
49
  };
50
50
  }, [environment]);
51
51
  const isDetailView = (activeTab === 'apis' && selected != null) ||
@@ -446,8 +446,8 @@ const InspectorHeader = React.memo(() => {
446
446
  styles.headerMethodBadge,
447
447
  {
448
448
  backgroundColor: selectedCrash.isFatal
449
- ? '#DC2626'
450
- : '#D97706',
449
+ ? AppColors.red600
450
+ : AppColors.amber600,
451
451
  },
452
452
  ]}>
453
453
  <Text style={styles.headerMethodText}>
@@ -463,8 +463,8 @@ const InspectorHeader = React.memo(() => {
463
463
  styles.headerStatusDot,
464
464
  {
465
465
  backgroundColor: selectedCrash.isFatal
466
- ? '#DC2626'
467
- : '#F59E0B',
466
+ ? AppColors.red600
467
+ : AppColors.amber500,
468
468
  },
469
469
  ]}/>
470
470
  <Text style={styles.headerSubTitle}>
@@ -42,13 +42,17 @@ const MainScreen = () => {
42
42
  (activeTab === 'crash' && selectedCrash != null);
43
43
  return (<>
44
44
  {(Platform.OS === 'ios' || Platform.OS === 'android') && isEnabled && <FabLauncher />}
45
- <Modal visible={visible} animationType={modalAnimationType} transparent>
45
+ <Modal visible={visible} animationType={modalAnimationType} transparent statusBarTranslucent={true}>
46
46
  {visible && (<ErrorBoundary onClose={closeModal}>
47
47
  <View style={styles.modalBackdrop}>
48
48
  <Pressable style={styles.modalBackdropPressable} onPress={closeModal}/>
49
49
  <View style={[
50
50
  styles.modalContentCard,
51
- { height: `${modalHeightPercent}%` },
51
+ {
52
+ height: `${modalHeightPercent}%`,
53
+ borderTopLeftRadius: modalHeightPercent >= 100 ? 0 : 20,
54
+ borderTopRightRadius: modalHeightPercent >= 100 ? 0 : 20,
55
+ },
52
56
  ]}>
53
57
  <StatusBar translucent backgroundColor="transparent" barStyle="light-content"/>
54
58