react-native-inapp-inspector 1.1.32 → 1.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/components/Inspector/BundleTab.js +282 -39
- package/dist/commonjs/components/Inspector/ReduxDetail.js +574 -75
- package/dist/commonjs/components/Inspector/ReduxTab.js +59 -180
- package/dist/commonjs/components/NetworkIcons.d.ts +2 -0
- package/dist/commonjs/components/NetworkIcons.js +14 -1
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +5 -2
- package/dist/commonjs/customHooks/bundleAnalyzer.js +229 -216
- package/dist/commonjs/customHooks/consoleLogger.js +7 -2
- package/dist/commonjs/helpers/index.js +19 -2
- package/dist/esm/components/Inspector/BundleTab.js +283 -40
- package/dist/esm/components/Inspector/ReduxDetail.js +575 -76
- package/dist/esm/components/Inspector/ReduxTab.js +60 -181
- package/dist/esm/components/NetworkIcons.d.ts +2 -0
- package/dist/esm/components/NetworkIcons.js +11 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/bundleAnalyzer.d.ts +5 -2
- package/dist/esm/customHooks/bundleAnalyzer.js +227 -215
- package/dist/esm/customHooks/consoleLogger.js +7 -2
- package/dist/esm/helpers/index.js +19 -2
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import { AppFonts } from '../../styles/AppFonts';
|
|
|
9
9
|
import { copyToClipboard } from '../../helpers';
|
|
10
10
|
import { PackageIcon, SearchIcon, ClearIcon, CircleAlertIcon, LayersIcon, TimelineIcon, LiveStateIcon, StorageIcon, MetadataIcon, FolderIcon, FolderOpenIcon, TrashIcon, LightbulbIcon, SparkleIcon, ClockIcon, RefreshCcwIcon, ExternalLinkIcon, DownloadIcon, } from '../NetworkIcons';
|
|
11
11
|
import Svg, { Path, Rect, Circle, Ellipse, G, Defs, LinearGradient, Stop, } from 'react-native-svg';
|
|
12
|
-
import { analyzeHostAppBundle, getCachedBundleAnalysis, } from '../../customHooks/bundleAnalyzer';
|
|
12
|
+
import { analyzeHostAppBundle, getCachedBundleAnalysis, getInitialBundleAnalysis, getHostScriptURL, } from '../../customHooks/bundleAnalyzer';
|
|
13
13
|
// ─── High-Fidelity Vector Package & NPM Logos ────────────────────────────────
|
|
14
14
|
const PackageLogoRenderer = ({ name, size = 28 }) => {
|
|
15
15
|
const lowerName = name.toLowerCase();
|
|
@@ -307,22 +307,25 @@ function buildBundleFileTree(files) {
|
|
|
307
307
|
}
|
|
308
308
|
export const downloadBundleFile = async (file, scriptURL) => {
|
|
309
309
|
let content = '';
|
|
310
|
-
// 1. Attempt to fetch real source code from Metro dev server
|
|
310
|
+
// 1. Attempt to fetch real source code from Metro dev server dynamically
|
|
311
311
|
try {
|
|
312
|
-
let devServerOrigin = '
|
|
313
|
-
|
|
314
|
-
|
|
312
|
+
let devServerOrigin = '';
|
|
313
|
+
const activeUrl = scriptURL || getHostScriptURL();
|
|
314
|
+
if (activeUrl && activeUrl.startsWith('http')) {
|
|
315
|
+
const match = activeUrl.match(/^(https?:\/\/[^/]+)/);
|
|
315
316
|
if (match) {
|
|
316
317
|
devServerOrigin = match[1];
|
|
317
318
|
}
|
|
318
319
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
320
|
+
if (devServerOrigin) {
|
|
321
|
+
const cleanPath = file.path.replace(/^\/+/, '');
|
|
322
|
+
const url = `${devServerOrigin}/${cleanPath}`;
|
|
323
|
+
const res = await fetch(url);
|
|
324
|
+
if (res.ok) {
|
|
325
|
+
const text = await res.text();
|
|
326
|
+
if (text && text.length > 0) {
|
|
327
|
+
content = text;
|
|
328
|
+
}
|
|
326
329
|
}
|
|
327
330
|
}
|
|
328
331
|
}
|
|
@@ -483,22 +486,32 @@ const BundleTab = React.memo(() => {
|
|
|
483
486
|
const [search, setSearch] = useState('');
|
|
484
487
|
const [activeCategory, setActiveCategory] = useState('ALL');
|
|
485
488
|
// ─── Live Host App Bundle Analysis (fetched from Metro / runtime) ─────────
|
|
486
|
-
const [analysis, setAnalysis] = useState(() => getCachedBundleAnalysis());
|
|
487
|
-
const [isAnalyzing, setIsAnalyzing] = useState(
|
|
489
|
+
const [analysis, setAnalysis] = useState(() => getCachedBundleAnalysis() || getInitialBundleAnalysis());
|
|
490
|
+
const [isAnalyzing, setIsAnalyzing] = useState(false);
|
|
488
491
|
const refreshAnalysis = useCallback(() => {
|
|
489
492
|
setIsAnalyzing(true);
|
|
490
|
-
analyzeHostAppBundle(true)
|
|
493
|
+
analyzeHostAppBundle(true)
|
|
494
|
+
.then(result => {
|
|
491
495
|
setAnalysis(result);
|
|
492
496
|
setIsAnalyzing(false);
|
|
497
|
+
})
|
|
498
|
+
.catch(() => {
|
|
499
|
+
setIsAnalyzing(false);
|
|
493
500
|
});
|
|
494
501
|
}, []);
|
|
495
502
|
useEffect(() => {
|
|
496
503
|
let mounted = true;
|
|
497
|
-
analyzeHostAppBundle()
|
|
504
|
+
analyzeHostAppBundle()
|
|
505
|
+
.then(result => {
|
|
498
506
|
if (mounted) {
|
|
499
507
|
setAnalysis(result);
|
|
500
508
|
setIsAnalyzing(false);
|
|
501
509
|
}
|
|
510
|
+
})
|
|
511
|
+
.catch(() => {
|
|
512
|
+
if (mounted) {
|
|
513
|
+
setIsAnalyzing(false);
|
|
514
|
+
}
|
|
502
515
|
});
|
|
503
516
|
return () => {
|
|
504
517
|
mounted = false;
|
|
@@ -752,21 +765,10 @@ const BundleTab = React.memo(() => {
|
|
|
752
765
|
</TouchableScale>
|
|
753
766
|
</View>
|
|
754
767
|
|
|
755
|
-
{/* ─── Live Bundle Analysis Loading State ─── */}
|
|
756
|
-
{isAnalyzing && (<View style={bundleStyles.analyzingContainer}>
|
|
757
|
-
<ActivityIndicator size="small" color={AppColors.brandPurple}/>
|
|
758
|
-
<Text style={bundleStyles.analyzingText}>
|
|
759
|
-
{t('bundle.analyzingTitle')}
|
|
760
|
-
</Text>
|
|
761
|
-
<Text style={bundleStyles.analyzingHint}>
|
|
762
|
-
{t('bundle.analyzingHint')}
|
|
763
|
-
</Text>
|
|
764
|
-
</View>)}
|
|
765
|
-
|
|
766
768
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
767
769
|
{/* ── 1. TAB: OVERVIEW & TREEMAP ───────────────────────────────────────── */}
|
|
768
770
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
769
|
-
{activeSubTab === 'overview' &&
|
|
771
|
+
{activeSubTab === 'overview' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
770
772
|
|
|
771
773
|
{/* Hero Overview Card */}
|
|
772
774
|
<View style={bundleStyles.heroCard}>
|
|
@@ -1084,19 +1086,168 @@ const BundleTab = React.memo(() => {
|
|
|
1084
1086
|
</View>
|
|
1085
1087
|
</View>
|
|
1086
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>
|
|
1087
1238
|
</ScrollView>)}
|
|
1088
1239
|
|
|
1089
1240
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1090
1241
|
{/* ── 2. TAB: PRODUCTION BUILDS & PLATFORMS ───────────────────────────── */}
|
|
1091
1242
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1092
|
-
{activeSubTab === 'production' &&
|
|
1243
|
+
{activeSubTab === 'production' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1093
1244
|
|
|
1094
1245
|
{/* Platform Segmented Switcher (Horizontally Scrollable) */}
|
|
1095
1246
|
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={bundleStyles.prodPlatformScroll}>
|
|
1096
1247
|
{[
|
|
1097
|
-
{ key: 'ios', label: 'iOS App (.ipa)', badge: `${analysis?.production.ios.
|
|
1098
|
-
{ key: 'androidAab', label: 'Android AAB (.aab)', badge: `${analysis?.production.androidAab.
|
|
1099
|
-
{ key: 'androidApk', label: 'Universal APK (.apk)', badge: `${analysis?.production.androidApk.totalInstallMb ||
|
|
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` },
|
|
1100
1251
|
].map(tab => {
|
|
1101
1252
|
const isSelected = prodPlatform === tab.key;
|
|
1102
1253
|
return (<TouchableScale key={tab.key} onPress={() => setProdPlatform(tab.key)} style={[
|
|
@@ -1207,6 +1358,33 @@ const BundleTab = React.memo(() => {
|
|
|
1207
1358
|
<CopyButton value={() => analysis.production[prodPlatform].components} label="Components JSON"/>
|
|
1208
1359
|
</View>
|
|
1209
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
|
+
|
|
1210
1388
|
{analysis.production[prodPlatform].components.map((comp, idx) => (<View key={idx} style={bundleStyles.catRowCard}>
|
|
1211
1389
|
<View style={bundleStyles.catRowTop}>
|
|
1212
1390
|
<View style={[
|
|
@@ -1317,7 +1495,7 @@ const BundleTab = React.memo(() => {
|
|
|
1317
1495
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1318
1496
|
{/* ── 2. TAB: FILES BREAKDOWN ─────────────────────────────────────────── */}
|
|
1319
1497
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1320
|
-
{activeSubTab === 'files' &&
|
|
1498
|
+
{activeSubTab === 'files' && (<View style={{ flex: 1 }}>
|
|
1321
1499
|
{/* Search & Category Filter */}
|
|
1322
1500
|
<View style={bundleStyles.filterContainer}>
|
|
1323
1501
|
<View style={bundleStyles.searchRow}>
|
|
@@ -1511,7 +1689,7 @@ const BundleTab = React.memo(() => {
|
|
|
1511
1689
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1512
1690
|
{/* ── 3. TAB: PACKAGES & NODE_MODULES ─────────────────────────────────── */}
|
|
1513
1691
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1514
|
-
{activeSubTab === 'packages' &&
|
|
1692
|
+
{activeSubTab === 'packages' && (<View style={{ flex: 1 }}>
|
|
1515
1693
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1516
1694
|
|
|
1517
1695
|
<View style={bundleStyles.filterContainer}>
|
|
@@ -1665,7 +1843,7 @@ const BundleTab = React.memo(() => {
|
|
|
1665
1843
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1666
1844
|
{/* ── 4. TAB: MEDIA & ASSET AUDITOR ───────────────────────────────────── */}
|
|
1667
1845
|
{/* ══════════════════════════════════════════════════════════════════════ */}
|
|
1668
|
-
{activeSubTab === 'media' &&
|
|
1846
|
+
{activeSubTab === 'media' && (<View style={{ flex: 1 }}>
|
|
1669
1847
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
|
|
1670
1848
|
|
|
1671
1849
|
<View style={bundleStyles.tipsCard}>
|
|
@@ -2082,29 +2260,94 @@ const bundleStyles = StyleSheet.create({
|
|
|
2082
2260
|
marginBottom: 12,
|
|
2083
2261
|
backgroundColor: AppColors.slate200,
|
|
2084
2262
|
},
|
|
2263
|
+
prodTreemapBar: {
|
|
2264
|
+
flexDirection: 'row',
|
|
2265
|
+
borderRadius: 6,
|
|
2266
|
+
overflow: 'hidden',
|
|
2267
|
+
height: 16,
|
|
2268
|
+
marginBottom: 12,
|
|
2269
|
+
backgroundColor: AppColors.slate200,
|
|
2270
|
+
},
|
|
2085
2271
|
legendGrid: {
|
|
2086
2272
|
flexDirection: 'row',
|
|
2087
2273
|
flexWrap: 'wrap',
|
|
2088
|
-
|
|
2089
|
-
rowGap: 8,
|
|
2090
|
-
columnGap: 10,
|
|
2274
|
+
gap: 8,
|
|
2091
2275
|
},
|
|
2092
2276
|
legendItem: {
|
|
2093
2277
|
flexDirection: 'row',
|
|
2094
2278
|
alignItems: 'center',
|
|
2095
2279
|
gap: 6,
|
|
2096
|
-
|
|
2280
|
+
paddingHorizontal: 8,
|
|
2281
|
+
paddingVertical: 5,
|
|
2282
|
+
borderRadius: 8,
|
|
2283
|
+
backgroundColor: `${AppColors.slate200}40`,
|
|
2284
|
+
borderWidth: 1,
|
|
2285
|
+
borderColor: `${AppColors.dividerColor}`,
|
|
2286
|
+
flexShrink: 0,
|
|
2097
2287
|
},
|
|
2098
2288
|
legendText: {
|
|
2099
2289
|
fontFamily: AppFonts.interMedium,
|
|
2100
2290
|
fontSize: 11,
|
|
2101
2291
|
color: AppColors.grayTextStrong,
|
|
2102
|
-
flex: 1,
|
|
2103
2292
|
},
|
|
2104
2293
|
legendVal: {
|
|
2105
2294
|
fontFamily: AppFonts.interBold,
|
|
2106
2295
|
color: AppColors.primaryBlack,
|
|
2107
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
|
+
},
|
|
2108
2351
|
catRowCard: {
|
|
2109
2352
|
backgroundColor: AppColors.grayBackground,
|
|
2110
2353
|
borderRadius: 12,
|