react-native-inapp-inspector 1.1.21 → 1.1.22

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 (37) hide show
  1. package/dist/commonjs/components/AnalyticsDetail.js +5 -3
  2. package/dist/commonjs/components/AnalyticsEventCard.d.ts +0 -1
  3. package/dist/commonjs/components/AnalyticsEventCard.js +85 -96
  4. package/dist/commonjs/components/Inspector/BundleTab.js +486 -651
  5. package/dist/commonjs/components/Inspector/PerformanceTab.js +185 -244
  6. package/dist/commonjs/components/Inspector/ReduxDetail.js +2 -2
  7. package/dist/commonjs/components/Inspector/ReduxTab.js +3 -3
  8. package/dist/commonjs/constants/version.d.ts +1 -1
  9. package/dist/commonjs/constants/version.js +1 -1
  10. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +115 -0
  11. package/dist/commonjs/customHooks/bundleAnalyzer.js +561 -0
  12. package/dist/commonjs/customHooks/performanceTracker.d.ts +84 -0
  13. package/dist/commonjs/customHooks/performanceTracker.js +541 -0
  14. package/dist/commonjs/helpers/index.d.ts +15 -0
  15. package/dist/commonjs/helpers/index.js +112 -1
  16. package/dist/commonjs/i18n/locales/en.json +225 -2
  17. package/dist/commonjs/styles/AppColors.d.ts +110 -0
  18. package/dist/commonjs/styles/AppColors.js +114 -0
  19. package/dist/esm/components/AnalyticsDetail.js +5 -3
  20. package/dist/esm/components/AnalyticsEventCard.d.ts +0 -1
  21. package/dist/esm/components/AnalyticsEventCard.js +85 -95
  22. package/dist/esm/components/Inspector/BundleTab.js +489 -654
  23. package/dist/esm/components/Inspector/PerformanceTab.js +185 -244
  24. package/dist/esm/components/Inspector/ReduxDetail.js +2 -2
  25. package/dist/esm/components/Inspector/ReduxTab.js +3 -3
  26. package/dist/esm/constants/version.d.ts +1 -1
  27. package/dist/esm/constants/version.js +1 -1
  28. package/dist/esm/customHooks/bundleAnalyzer.d.ts +115 -0
  29. package/dist/esm/customHooks/bundleAnalyzer.js +554 -0
  30. package/dist/esm/customHooks/performanceTracker.d.ts +84 -0
  31. package/dist/esm/customHooks/performanceTracker.js +537 -0
  32. package/dist/esm/helpers/index.d.ts +15 -0
  33. package/dist/esm/helpers/index.js +107 -0
  34. package/dist/esm/i18n/locales/en.json +225 -2
  35. package/dist/esm/styles/AppColors.d.ts +110 -0
  36. package/dist/esm/styles/AppColors.js +114 -0
  37. package/package.json +1 -1
@@ -46,6 +46,7 @@ const AppColors_1 = require("../../styles/AppColors");
46
46
  const AppFonts_1 = require("../../styles/AppFonts");
47
47
  const NetworkIcons_1 = require("../NetworkIcons");
48
48
  const react_native_svg_1 = __importStar(require("react-native-svg"));
49
+ const bundleAnalyzer_1 = require("../../customHooks/bundleAnalyzer");
49
50
  // ─── High-Fidelity Vector Package & NPM Logos ────────────────────────────────
50
51
  const PackageLogoRenderer = ({ name, size = 28 }) => {
51
52
  const lowerName = name.toLowerCase();
@@ -57,13 +58,13 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
57
58
  !lowerName.includes('gradient'))) {
58
59
  return (<react_native_1.View style={[
59
60
  bundleStyles.pkgLogoWrap,
60
- { width: size, height: size, backgroundColor: '#20232A' },
61
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.npmDark },
61
62
  ]}>
62
63
  <react_native_svg_1.default width={size - 6} height={size - 6} viewBox="0 0 100 100" fill="none">
63
- <react_native_svg_1.Circle cx="50" cy="50" r="9" fill="#61DAFB"/>
64
- <react_native_svg_1.Ellipse cx="50" cy="50" rx="42" ry="16" stroke="#61DAFB" strokeWidth="6"/>
65
- <react_native_svg_1.Ellipse cx="50" cy="50" rx="42" ry="16" stroke="#61DAFB" strokeWidth="6" transform="rotate(60 50 50)"/>
66
- <react_native_svg_1.Ellipse cx="50" cy="50" rx="42" ry="16" stroke="#61DAFB" strokeWidth="6" transform="rotate(120 50 50)"/>
64
+ <react_native_svg_1.Circle cx="50" cy="50" r="9" fill={AppColors_1.AppColors.reactCyan}/>
65
+ <react_native_svg_1.Ellipse cx="50" cy="50" rx="42" ry="16" stroke={AppColors_1.AppColors.reactCyan} strokeWidth="6"/>
66
+ <react_native_svg_1.Ellipse cx="50" cy="50" rx="42" ry="16" stroke={AppColors_1.AppColors.reactCyan} strokeWidth="6" transform="rotate(60 50 50)"/>
67
+ <react_native_svg_1.Ellipse cx="50" cy="50" rx="42" ry="16" stroke={AppColors_1.AppColors.reactCyan} strokeWidth="6" transform="rotate(120 50 50)"/>
67
68
  </react_native_svg_1.default>
68
69
  </react_native_1.View>);
69
70
  }
@@ -71,12 +72,12 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
71
72
  if (lowerName.includes('navigation')) {
72
73
  return (<react_native_1.View style={[
73
74
  bundleStyles.pkgLogoWrap,
74
- { width: size, height: size, backgroundColor: '#5B44E0' },
75
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.hermesPurple },
75
76
  ]}>
76
77
  <react_native_svg_1.default width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
77
- <react_native_svg_1.Circle cx="50" cy="50" r="38" stroke="#FFFFFF" strokeWidth="8"/>
78
- <react_native_svg_1.Path d="M50 20 L68 50 L50 80 L32 50 Z" fill="#61DAFB"/>
79
- <react_native_svg_1.Circle cx="50" cy="50" r="6" fill="#FFFFFF"/>
78
+ <react_native_svg_1.Circle cx="50" cy="50" r="38" stroke={AppColors_1.AppColors.white} strokeWidth="8"/>
79
+ <react_native_svg_1.Path d="M50 20 L68 50 L50 80 L32 50 Z" fill={AppColors_1.AppColors.reactCyan}/>
80
+ <react_native_svg_1.Circle cx="50" cy="50" r="6" fill={AppColors_1.AppColors.white}/>
80
81
  </react_native_svg_1.default>
81
82
  </react_native_1.View>);
82
83
  }
@@ -84,13 +85,13 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
84
85
  if (lowerName.includes('svg')) {
85
86
  return (<react_native_1.View style={[
86
87
  bundleStyles.pkgLogoWrap,
87
- { width: size, height: size, backgroundColor: '#F472B6' },
88
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.pink400 },
88
89
  ]}>
89
90
  <react_native_svg_1.default width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
90
- <react_native_svg_1.Path d="M20 75 C35 25, 65 25, 80 75" stroke="#FFFFFF" strokeWidth="10" strokeLinecap="round"/>
91
- <react_native_svg_1.Circle cx="20" cy="75" r="8" fill="#FFFFFF"/>
92
- <react_native_svg_1.Circle cx="80" cy="75" r="8" fill="#FFFFFF"/>
93
- <react_native_svg_1.Circle cx="50" cy="38" r="7" fill="#FCE7F3" stroke="#FFFFFF" strokeWidth="3"/>
91
+ <react_native_svg_1.Path d="M20 75 C35 25, 65 25, 80 75" stroke={AppColors_1.AppColors.white} strokeWidth="10" strokeLinecap="round"/>
92
+ <react_native_svg_1.Circle cx="20" cy="75" r="8" fill={AppColors_1.AppColors.white}/>
93
+ <react_native_svg_1.Circle cx="80" cy="75" r="8" fill={AppColors_1.AppColors.white}/>
94
+ <react_native_svg_1.Circle cx="50" cy="38" r="7" fill="#FCE7F3" stroke={AppColors_1.AppColors.white} strokeWidth="3"/>
94
95
  </react_native_svg_1.default>
95
96
  </react_native_1.View>);
96
97
  }
@@ -98,11 +99,11 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
98
99
  if (lowerName.includes('axios')) {
99
100
  return (<react_native_1.View style={[
100
101
  bundleStyles.pkgLogoWrap,
101
- { width: size, height: size, backgroundColor: '#5A29E4' },
102
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.expoViolet },
102
103
  ]}>
103
104
  <react_native_svg_1.default width={size - 6} height={size - 6} viewBox="0 0 100 100" fill="none">
104
- <react_native_svg_1.Path d="M22 75 L50 20 L78 75 M33 58 L67 58" stroke="#FFFFFF" strokeWidth="12" strokeLinecap="round" strokeLinejoin="round"/>
105
- <react_native_svg_1.Circle cx="50" cy="20" r="7" fill="#61DAFB"/>
105
+ <react_native_svg_1.Path d="M22 75 L50 20 L78 75 M33 58 L67 58" stroke={AppColors_1.AppColors.white} strokeWidth="12" strokeLinecap="round" strokeLinejoin="round"/>
106
+ <react_native_svg_1.Circle cx="50" cy="20" r="7" fill={AppColors_1.AppColors.reactCyan}/>
106
107
  </react_native_svg_1.default>
107
108
  </react_native_1.View>);
108
109
  }
@@ -110,11 +111,11 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
110
111
  if (lowerName.includes('screens') || lowerName.includes('software-mansion')) {
111
112
  return (<react_native_1.View style={[
112
113
  bundleStyles.pkgLogoWrap,
113
- { width: size, height: size, backgroundColor: '#001A72' },
114
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.reanimatedNavy },
114
115
  ]}>
115
116
  <react_native_svg_1.default width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
116
- <react_native_svg_1.Path d="M50 15 L88 35 L50 55 L12 35 Z" fill="#38BDF8"/>
117
- <react_native_svg_1.Path d="M12 50 L50 70 L88 50" stroke="#FFFFFF" strokeWidth="8" strokeLinecap="round"/>
117
+ <react_native_svg_1.Path d="M50 15 L88 35 L50 55 L12 35 Z" fill={AppColors_1.AppColors.sky400}/>
118
+ <react_native_svg_1.Path d="M12 50 L50 70 L88 50" stroke={AppColors_1.AppColors.white} strokeWidth="8" strokeLinecap="round"/>
118
119
  <react_native_svg_1.Path d="M12 65 L50 85 L88 65" stroke="#93C5FD" strokeWidth="8" strokeLinecap="round"/>
119
120
  </react_native_svg_1.default>
120
121
  </react_native_1.View>);
@@ -123,7 +124,7 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
123
124
  if (lowerName.includes('gradient')) {
124
125
  return (<react_native_1.View style={[
125
126
  bundleStyles.pkgLogoWrap,
126
- { width: size, height: size, backgroundColor: '#FB7185' },
127
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.rose600 },
127
128
  ]}>
128
129
  <react_native_svg_1.default width={size - 4} height={size - 4} viewBox="0 0 100 100" fill="none">
129
130
  <react_native_svg_1.Defs>
@@ -141,23 +142,23 @@ const PackageLogoRenderer = ({ name, size = 28 }) => {
141
142
  if (lowerName.includes('i18n')) {
142
143
  return (<react_native_1.View style={[
143
144
  bundleStyles.pkgLogoWrap,
144
- { width: size, height: size, backgroundColor: '#059669' },
145
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.emerald600 },
145
146
  ]}>
146
147
  <react_native_svg_1.default width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
147
- <react_native_svg_1.Circle cx="50" cy="50" r="38" stroke="#FFFFFF" strokeWidth="8"/>
148
- <react_native_svg_1.Ellipse cx="50" cy="50" rx="18" ry="38" stroke="#FFFFFF" strokeWidth="6"/>
149
- <react_native_svg_1.Path d="M14 50 L86 50" stroke="#FFFFFF" strokeWidth="7"/>
148
+ <react_native_svg_1.Circle cx="50" cy="50" r="38" stroke={AppColors_1.AppColors.white} strokeWidth="8"/>
149
+ <react_native_svg_1.Ellipse cx="50" cy="50" rx="18" ry="38" stroke={AppColors_1.AppColors.white} strokeWidth="6"/>
150
+ <react_native_svg_1.Path d="M14 50 L86 50" stroke={AppColors_1.AppColors.white} strokeWidth="7"/>
150
151
  </react_native_svg_1.default>
151
152
  </react_native_1.View>);
152
153
  }
153
154
  // 8. Official Red NPM Logo Box (Universal Default NPM Branding)
154
155
  return (<react_native_1.View style={[
155
156
  bundleStyles.pkgLogoWrap,
156
- { width: size, height: size, backgroundColor: '#CB3837' },
157
+ { width: size, height: size, backgroundColor: AppColors_1.AppColors.npmRed },
157
158
  ]}>
158
159
  <react_native_svg_1.default width={size - 4} height={size - 4} viewBox="0 0 100 100" fill="none">
159
- <react_native_svg_1.Rect width="100" height="100" rx="14" fill="#CB3837"/>
160
- <react_native_svg_1.Path d="M18 24 H82 V76 H50 V40 H38 V76 H18 Z" fill="#FFFFFF"/>
160
+ <react_native_svg_1.Rect width="100" height="100" rx="14" fill={AppColors_1.AppColors.npmRed}/>
161
+ <react_native_svg_1.Path d="M18 24 H82 V76 H50 V40 H38 V76 H18 Z" fill={AppColors_1.AppColors.white}/>
161
162
  </react_native_svg_1.default>
162
163
  </react_native_1.View>);
163
164
  };
@@ -169,25 +170,25 @@ const MediaPreviewThumbnail = ({ file }) => {
169
170
  return (<react_native_1.View style={[
170
171
  bundleStyles.mediaThumbWrap,
171
172
  {
172
- backgroundColor: '#FFF1F2',
173
+ backgroundColor: AppColors_1.AppColors.errorCardBg,
173
174
  alignItems: 'center',
174
175
  justifyContent: 'center',
175
- borderColor: '#FECDD3',
176
+ borderColor: AppColors_1.AppColors.errorBorder,
176
177
  },
177
178
  ]}>
178
179
  <react_native_svg_1.default width={22} height={22} viewBox="0 0 100 100" fill="none">
179
180
  <react_native_svg_1.Defs>
180
181
  <react_native_svg_1.LinearGradient id="svgGradThumb" x1="0" y1="0" x2="100" y2="100" gradientUnits="userSpaceOnUse">
181
- <react_native_svg_1.Stop offset="0" stopColor="#F43F5E"/>
182
- <react_native_svg_1.Stop offset="1" stopColor="#FB7185"/>
182
+ <react_native_svg_1.Stop offset="0" stopColor={AppColors_1.AppColors.rose500}/>
183
+ <react_native_svg_1.Stop offset="1" stopColor={AppColors_1.AppColors.rose600}/>
183
184
  </react_native_svg_1.LinearGradient>
184
185
  </react_native_svg_1.Defs>
185
186
  <react_native_svg_1.Circle cx="50" cy="50" r="44" fill="url(#svgGradThumb)"/>
186
187
  {/* Vector bezier path pen graphic */}
187
- <react_native_svg_1.Path d="M25 70 C35 30, 65 30, 75 70" stroke="#FFFFFF" strokeWidth="8" strokeLinecap="round"/>
188
- <react_native_svg_1.Circle cx="25" cy="70" r="7" fill="#FFFFFF"/>
189
- <react_native_svg_1.Circle cx="75" cy="70" r="7" fill="#FFFFFF"/>
190
- <react_native_svg_1.Circle cx="50" cy="40" r="6" fill="#FFE4E6" stroke="#FFFFFF" strokeWidth="2"/>
188
+ <react_native_svg_1.Path d="M25 70 C35 30, 65 30, 75 70" stroke={AppColors_1.AppColors.white} strokeWidth="8" strokeLinecap="round"/>
189
+ <react_native_svg_1.Circle cx="25" cy="70" r="7" fill={AppColors_1.AppColors.white}/>
190
+ <react_native_svg_1.Circle cx="75" cy="70" r="7" fill={AppColors_1.AppColors.white}/>
191
+ <react_native_svg_1.Circle cx="50" cy="40" r="6" fill="#FFE4E6" stroke={AppColors_1.AppColors.white} strokeWidth="2"/>
191
192
  </react_native_svg_1.default>
192
193
  </react_native_1.View>);
193
194
  }
@@ -285,7 +286,7 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
285
286
  <HighlightText_1.default text={node.name + '/'} search={search} style={bundleStyles.treeFolderName} highlightStyle={bundleStyles.searchHighlight}/>
286
287
  <react_native_1.View style={bundleStyles.treeCountBadge}>
287
288
  <react_native_1.Text style={bundleStyles.treeCountBadgeText}>
288
- {node.fileCount} {node.fileCount === 1 ? 'file' : 'files'}
289
+ {node.fileCount} {node.fileCount === 1 ? (0, i18n_1.t)('bundle.file') : (0, i18n_1.t)('bundle.files')}
289
290
  </react_native_1.Text>
290
291
  </react_native_1.View>
291
292
  </react_native_1.View>
@@ -293,14 +294,14 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
293
294
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
294
295
  <react_native_1.Text style={bundleStyles.treeFolderSize}>
295
296
  {node.sizeKb >= 1024
296
- ? `${(node.sizeKb / 1024).toFixed(2)} MB`
297
- : `${node.sizeKb} KB`}
297
+ ? (0, i18n_1.t)('bundle.fileSizeMb', { size: (node.sizeKb / 1024).toFixed(2) })
298
+ : (0, i18n_1.t)('bundle.fileSizeKb', { size: node.sizeKb })}
298
299
  </react_native_1.Text>
299
300
  <CopyButton_1.default value={() => ({
300
301
  folder: node.fullPath,
301
302
  sizeKb: node.sizeKb,
302
303
  fileCount: node.fileCount,
303
- })} label={`Copy ${node.name} Info`}/>
304
+ })} label={(0, i18n_1.t)('bundle.copyFileInfo', { name: node.name })}/>
304
305
  </react_native_1.View>
305
306
  </TouchableScale_1.default>
306
307
 
@@ -329,9 +330,9 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
329
330
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
330
331
  <HighlightText_1.default text={file.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
331
332
  {isUnused ? (<react_native_1.View style={bundleStyles.unusedBadge}>
332
- <react_native_1.Text style={bundleStyles.unusedBadgeText}>🚫 Not Consumed</react_native_1.Text>
333
+ <react_native_1.Text style={bundleStyles.unusedBadgeText}>{(0, i18n_1.t)('bundle.notConsumed')}</react_native_1.Text>
333
334
  </react_native_1.View>) : (<react_native_1.View style={bundleStyles.consumedBadge}>
334
- <react_native_1.Text style={bundleStyles.consumedBadgeText}>⚡ Consumed</react_native_1.Text>
335
+ <react_native_1.Text style={bundleStyles.consumedBadgeText}>{(0, i18n_1.t)('bundle.consumed')}</react_native_1.Text>
335
336
  </react_native_1.View>)}
336
337
  </react_native_1.View>
337
338
  <react_native_1.Text style={bundleStyles.filePath} numberOfLines={1}>
@@ -341,14 +342,14 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
341
342
 
342
343
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
343
344
  <react_native_1.View style={bundleStyles.fileSizeBox}>
344
- <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: '#B45309' }]}>
345
+ <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: AppColors_1.AppColors.amber800Warm }]}>
345
346
  {file.sizeKb >= 1024
346
- ? `${(file.sizeKb / 1024).toFixed(2)} MB`
347
- : `${file.sizeKb} KB`}
347
+ ? (0, i18n_1.t)('bundle.fileSizeMb', { size: (file.sizeKb / 1024).toFixed(2) })
348
+ : (0, i18n_1.t)('bundle.fileSizeKb', { size: file.sizeKb })}
348
349
  </react_native_1.Text>
349
350
  <react_native_1.Text style={bundleStyles.filePercent}>{pctOfTotal}%</react_native_1.Text>
350
351
  </react_native_1.View>
351
- <CopyButton_1.default value={() => file} label="File Details JSON"/>
352
+ <CopyButton_1.default value={() => file} label={(0, i18n_1.t)('bundle.fileDetailsJson')}/>
352
353
  </react_native_1.View>
353
354
  </react_native_1.View>
354
355
 
@@ -361,9 +362,9 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
361
362
  ]}>
362
363
  <react_native_1.Text style={[
363
364
  bundleStyles.adviceText,
364
- file.status === 'warning' && { color: '#B45309' },
365
- file.status === 'optimal' && { color: '#047857' },
366
- isUnused && { color: '#DC2626' },
365
+ file.status === 'warning' && { color: AppColors_1.AppColors.amber800Warm },
366
+ file.status === 'optimal' && { color: AppColors_1.AppColors.emerald700 },
367
+ isUnused && { color: AppColors_1.AppColors.red600 },
367
368
  ]}>
368
369
  {isUnused ? '🗑️ ' : file.status === 'warning' ? '💡 ' : '✨ '}
369
370
  {file.advice}
@@ -371,417 +372,48 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
371
372
  </react_native_1.View>)}
372
373
  </react_native_1.View>);
373
374
  };
374
- // ─── Sample Bundle Files Data ────────────────────────────────────────────────
375
- const BUNDLE_FILES_DATA = [
376
- // ── Images & Media ──
377
- {
378
- id: 'img-1',
379
- name: 'banner_dark.png',
380
- path: 'assets/images/banner_dark.png',
381
- ext: 'PNG',
382
- category: 'image',
383
- sizeKb: 460,
384
- meta: '1200×630px @2x • Raster Image',
385
- color: '#EC4899',
386
- status: 'warning',
387
- advice: 'Convert to .webp to save ~65% (160 KB)',
388
- previewUri: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=200&auto=format&fit=crop&q=80',
389
- },
390
- {
391
- id: 'img-2',
392
- name: 'banner_light.svg',
393
- path: 'assets/images/banner_light.svg',
394
- ext: 'SVG',
395
- category: 'image',
396
- sizeKb: 34,
397
- meta: 'Scalable Vector Graphic',
398
- color: '#F43F5E',
399
- status: 'optimal',
400
- advice: 'Optimal vector format for sharp rendering',
401
- previewUri: 'https://images.unsplash.com/photo-1579783902614-a3fb3927b675?w=200&auto=format&fit=crop&q=80',
402
- },
403
- {
404
- id: 'img-3',
405
- name: 'logo_hero@3x.png',
406
- path: 'assets/brand/logo_hero@3x.png',
407
- ext: 'PNG',
408
- category: 'image',
409
- sizeKb: 285,
410
- meta: '768×768px @3x Retina Asset',
411
- color: '#EC4899',
412
- status: 'warning',
413
- advice: 'High density PNG. Consider tintable SVG vector',
414
- previewUri: 'https://images.unsplash.com/photo-1634017839464-5c339ebe3cb4?w=200&auto=format&fit=crop&q=80',
415
- },
416
- {
417
- id: 'img-4',
418
- name: 'avatar_placeholder.webp',
419
- path: 'assets/placeholders/avatar_placeholder.webp',
420
- ext: 'WEBP',
421
- category: 'image',
422
- sizeKb: 28,
423
- meta: '256×256px Lossy WebP',
424
- color: '#F472B6',
425
- status: 'warning',
426
- advice: 'Unused in bundle: 0 active imports detected (28 KB unused)',
427
- previewUri: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200&auto=format&fit=crop&q=80',
428
- isConsumed: false,
429
- },
430
- {
431
- id: 'img-5',
432
- name: 'walkthrough_thumb.jpg',
433
- path: 'assets/previews/walkthrough_thumb.jpg',
434
- ext: 'JPG',
435
- category: 'image',
436
- sizeKb: 175,
437
- meta: '1080×600px Progressive JPEG',
438
- color: '#FB7185',
439
- status: 'warning',
440
- advice: 'Dead asset: 0 component references (175 KB unused)',
441
- previewUri: 'https://images.unsplash.com/photo-1550745165-9bc0b252726f?w=200&auto=format&fit=crop&q=80',
442
- isConsumed: false,
443
- },
444
- // ── TypeScript & JSX ──
445
- {
446
- id: 'ts-1',
447
- name: 'LogDetail.tsx',
448
- path: 'src/components/Inspector/LogDetail.tsx',
449
- ext: 'TSX',
450
- category: 'typescript',
451
- sizeKb: 44,
452
- meta: '1,238 lines • React Component',
453
- color: '#38BDF8',
454
- status: 'optimal',
455
- advice: 'Clean React.memo and useCallback optimization',
456
- },
457
- {
458
- id: 'ts-2',
459
- name: 'ReduxDetail.tsx',
460
- path: 'src/components/Inspector/ReduxDetail.tsx',
461
- ext: 'TSX',
462
- category: 'typescript',
463
- sizeKb: 38,
464
- meta: '680 lines • Slice state tree & action timeline',
465
- color: '#38BDF8',
466
- status: 'optimal',
467
- advice: 'Multi-tab subview with live state diffing',
468
- },
469
- {
470
- id: 'ts-3',
471
- name: 'NetworkTab.tsx',
472
- path: 'src/components/Inspector/NetworkTab.tsx',
473
- ext: 'TSX',
474
- category: 'typescript',
475
- sizeKb: 15,
476
- meta: '486 lines • Network request virtualization list',
477
- color: '#0EA5E9',
478
- status: 'optimal',
479
- advice: 'FlatList windowSize=7 tuned for 60fps',
480
- },
481
- {
482
- id: 'ts-4',
483
- name: 'SettingsPanel.tsx',
484
- path: 'src/components/Inspector/SettingsPanel.tsx',
485
- ext: 'TSX',
486
- category: 'typescript',
487
- sizeKb: 65,
488
- meta: '1,845 lines • Preferences & storage manager',
489
- color: '#38BDF8',
490
- status: 'info',
491
- advice: 'Self-contained settings subviews',
492
- },
493
- {
494
- id: 'ts-5',
495
- name: 'consoleLogger.ts',
496
- path: 'src/customHooks/consoleLogger.ts',
497
- ext: 'TS',
498
- category: 'typescript',
499
- sizeKb: 12,
500
- meta: '360 lines • Metro symbolication bridge',
501
- color: '#0284C7',
502
- status: 'optimal',
503
- advice: 'Zero-overhead in-memory stack capture',
504
- },
505
- {
506
- id: 'ts-6',
507
- name: 'App.tsx (Playground)',
508
- path: 'example/App.tsx',
509
- ext: 'TSX',
510
- category: 'typescript',
511
- sizeKb: 25,
512
- meta: '820 lines • Interactive test scenarios',
513
- color: '#38BDF8',
514
- status: 'optimal',
515
- advice: 'Sample harness for logs, APIs, and Redux',
516
- },
517
- // ── JavaScript & Node Modules ──
518
- {
519
- id: 'js-1',
520
- name: 'react-native/Libraries/Renderer',
521
- path: 'node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js',
522
- ext: 'JS',
523
- category: 'javascript',
524
- sizeKb: 480,
525
- meta: 'Fabric & Paper UI reconciler bundle',
526
- color: '#6366F1',
527
- status: 'optimal',
528
- advice: 'AOT compiled with Hermes Bytecode',
529
- },
530
- {
531
- id: 'js-2',
532
- name: '@react-navigation/native-stack',
533
- path: 'node_modules/@react-navigation/native-stack/lib/module/index.js',
534
- ext: 'JS',
535
- category: 'javascript',
536
- sizeKb: 195,
537
- meta: 'Native screen animation & transition engine',
538
- color: '#818CF8',
539
- status: 'optimal',
540
- advice: 'Optimized modular ES bundle',
541
- },
542
- {
543
- id: 'js-3',
544
- name: 'axios/dist/esm/axios.js',
545
- path: 'node_modules/axios/dist/esm/axios.js',
546
- ext: 'JS',
547
- category: 'javascript',
548
- sizeKb: 88,
549
- meta: 'HTTP client core with interceptors',
550
- color: '#F59E0B',
551
- status: 'optimal',
552
- advice: 'Standard lightweight network adapter',
553
- },
554
- {
555
- id: 'js-4',
556
- name: 'react-native-svg',
557
- path: 'node_modules/react-native-svg/lib/module/index.js',
558
- ext: 'JS',
559
- category: 'javascript',
560
- sizeKb: 140,
561
- meta: 'Native SVG drawing and vector paths',
562
- color: '#4F46E5',
563
- status: 'optimal',
564
- advice: 'Native Fabric/Paper vector bridge',
565
- },
566
- // ── Fonts & Typography ──
567
- {
568
- id: 'font-1',
569
- name: 'Inter-Bold.ttf',
570
- path: 'fonts/Inter-Bold.ttf',
571
- ext: 'TTF',
572
- category: 'font',
573
- sizeKb: 165,
574
- meta: 'Custom UI Font • Full Latin Charset (480 glyphs)',
575
- color: '#8B5CF6',
576
- status: 'info',
577
- advice: 'High readability modern typography',
578
- },
579
- {
580
- id: 'font-2',
581
- name: 'Inter-Regular.ttf',
582
- path: 'fonts/Inter-Regular.ttf',
583
- ext: 'TTF',
584
- category: 'font',
585
- sizeKb: 160,
586
- meta: 'Custom Body Font • 400 Weight (480 glyphs)',
587
- color: '#8B5CF6',
588
- status: 'info',
589
- advice: 'Applied across inspector UI cards and text',
590
- },
591
- {
592
- id: 'font-3',
593
- name: 'JetBrainsMono-Regular.ttf',
594
- path: 'fonts/JetBrainsMono-Regular.ttf',
595
- ext: 'TTF',
596
- category: 'font',
597
- sizeKb: 95,
598
- meta: 'Monospace Code Font • Raw / Table / Stack Traces',
599
- color: '#A855F7',
600
- status: 'optimal',
601
- advice: 'Crisp font for code snippets and stack traces',
602
- },
603
- // ── JSON & Localizations ──
604
- {
605
- id: 'json-1',
606
- name: 'en.json (i18n Translations)',
607
- path: 'src/i18n/locales/en.json',
608
- ext: 'JSON',
609
- category: 'json',
610
- sizeKb: 18,
611
- meta: '124 localization translation keys',
612
- color: '#10B981',
613
- status: 'optimal',
614
- advice: 'Static JSON locale dictionary',
615
- },
616
- {
617
- id: 'json-2',
618
- name: 'package.json',
619
- path: 'package.json',
620
- ext: 'JSON',
621
- category: 'json',
622
- sizeKb: 3,
623
- meta: 'Manifest & peer dependencies config',
624
- color: '#059669',
625
- status: 'optimal',
626
- advice: 'Stripped during production bundle export',
627
- },
628
- ];
629
- // ─── Packages / Node Modules Breakdown Data ──────────────────────────────────
630
- const BUNDLE_PACKAGES_DATA = [
631
- {
632
- id: 'pkg-1',
633
- name: 'react-native',
634
- version: '0.85.3',
635
- latestVersion: '0.85.3',
636
- sizeKb: 680,
637
- percentage: 38.5,
638
- type: 'direct',
639
- category: 'core',
640
- color: '#38BDF8',
641
- description: 'React Native runtime, Fabric UI engine, Native Bridge, and Turbomodules.',
642
- logoUri: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/512px-React-icon.svg.png',
643
- lastActive: '3 days ago',
644
- npmUrl: 'https://www.npmjs.com/package/react-native',
645
- isDeprecated: false,
646
- },
647
- {
648
- id: 'pkg-2',
649
- name: '@react-navigation/native-stack',
650
- version: '^7.16.0',
651
- latestVersion: '7.16.0',
652
- sizeKb: 245,
653
- percentage: 13.9,
654
- type: 'direct',
655
- category: 'navigation',
656
- color: '#818CF8',
657
- description: 'Native screen router, UIViewController / Fragment animations and transitions.',
658
- logoUri: 'https://reactnavigation.org/img/spiro.svg',
659
- lastActive: '1 week ago',
660
- npmUrl: 'https://www.npmjs.com/package/@react-navigation/native-stack',
661
- isDeprecated: false,
662
- },
663
- {
664
- id: 'pkg-3',
665
- name: 'react',
666
- version: '19.2.3',
667
- latestVersion: '19.2.3',
668
- sizeKb: 185,
669
- percentage: 10.5,
670
- type: 'direct',
671
- category: 'core',
672
- color: '#06B6D4',
673
- description: 'React core virtual DOM reconciler, hooks engine, and JSX runtime.',
674
- logoUri: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/512px-React-icon.svg.png',
675
- lastActive: '5 days ago',
676
- npmUrl: 'https://www.npmjs.com/package/react',
677
- isDeprecated: false,
678
- },
679
- {
680
- id: 'pkg-4',
681
- name: 'react-native-svg',
682
- version: '^15.15.5',
683
- latestVersion: '15.16.0',
684
- sizeKb: 140,
685
- percentage: 7.9,
686
- type: 'direct',
687
- category: 'ui',
688
- color: '#F472B6',
689
- description: 'Scalable Vector Graphics XML parser and native canvas path rasterizer.',
690
- logoUri: 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/SVG_logo.svg/512px-SVG_logo.svg.png',
691
- lastActive: '2 days ago',
692
- npmUrl: 'https://www.npmjs.com/package/react-native-svg',
693
- isDeprecated: false,
694
- },
695
- {
696
- id: 'pkg-5',
697
- name: 'react-native-screens',
698
- version: '^4.25.2',
699
- latestVersion: '4.25.2',
700
- sizeKb: 110,
701
- percentage: 6.2,
702
- type: 'transitive',
703
- category: 'navigation',
704
- color: '#A78BFA',
705
- description: 'Native navigation container primitives for iOS and Android memory management.',
706
- logoUri: 'https://reactnavigation.org/img/spiro.svg',
707
- lastActive: '2 weeks ago',
708
- npmUrl: 'https://www.npmjs.com/package/react-native-screens',
709
- isDeprecated: false,
710
- },
711
- {
712
- id: 'pkg-6',
713
- name: 'axios',
714
- version: '^1.17.0',
715
- latestVersion: '1.18.0',
716
- sizeKb: 88,
717
- percentage: 5.0,
718
- type: 'direct',
719
- category: 'network',
720
- color: '#F59E0B',
721
- description: 'HTTP client, request/response interceptors, and adapter pipelines.',
722
- logoUri: 'https://axios-http.com/assets/logo.svg',
723
- lastActive: '4 days ago',
724
- npmUrl: 'https://www.npmjs.com/package/axios',
725
- isDeprecated: false,
726
- },
727
- {
728
- id: 'pkg-7',
729
- name: 'react-native-linear-gradient',
730
- version: '^2.8.3',
731
- latestVersion: '2.8.3',
732
- sizeKb: 45,
733
- percentage: 2.5,
734
- type: 'direct',
735
- category: 'ui',
736
- color: '#FB7185',
737
- description: 'Hardware accelerated native gradient drawing shaders.',
738
- logoUri: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/512px-React-icon.svg.png',
739
- lastActive: '2 years ago',
740
- npmUrl: 'https://www.npmjs.com/package/react-native-linear-gradient',
741
- isDeprecated: true,
742
- deprecationReason: 'Package maintenance is in transition. Consider expo-linear-gradient or @react-native-community/linear-gradient for Fabric support.',
743
- },
744
- {
745
- id: 'pkg-8',
746
- name: 'i18next & react-i18next',
747
- version: '^26.3.6',
748
- latestVersion: '26.3.6',
749
- sizeKb: 62,
750
- percentage: 3.5,
751
- type: 'direct',
752
- category: 'utils',
753
- color: '#10B981',
754
- description: 'Internationalization framework, language interpolator, and locale switcher.',
755
- logoUri: 'https://raw.githubusercontent.com/i18next/i18next/master/assets/i18next-logo.png',
756
- lastActive: '6 days ago',
757
- npmUrl: 'https://www.npmjs.com/package/i18next',
758
- isDeprecated: false,
759
- },
760
- ];
761
375
  const CATEGORY_TABS = [
762
- { key: 'ALL', label: 'All Files', icon: '📁' },
763
- { key: 'UNUSED', label: 'Not Consumed (Dead)', icon: '🚫' },
764
- { key: 'CONSUMED', label: 'In-Use / Active', icon: '⚡' },
765
- { key: 'image', label: 'Images & Media', icon: '🖼️' },
766
- { key: 'typescript', label: 'TypeScript / TSX', icon: '📜' },
767
- { key: 'javascript', label: 'JS & Node Modules', icon: '⚙️' },
768
- { key: 'font', label: 'Fonts & Glyphs', icon: '🔤' },
769
- { key: 'json', label: 'JSON & Data', icon: '📄' },
376
+ { key: 'ALL', labelKey: 'bundle.catAll', icon: '📁' },
377
+ { key: 'UNUSED', labelKey: 'bundle.catUnused', icon: '🚫' },
378
+ { key: 'CONSUMED', labelKey: 'bundle.catConsumed', icon: '⚡' },
379
+ { key: 'image', labelKey: 'bundle.catImages', icon: '🖼️' },
380
+ { key: 'typescript', labelKey: 'bundle.catTypescript', icon: '📜' },
381
+ { key: 'javascript', labelKey: 'bundle.catJavascript', icon: '⚙️' },
382
+ { key: 'font', labelKey: 'bundle.catFonts', icon: '🔤' },
383
+ { key: 'json', labelKey: 'bundle.catJson', icon: '📄' },
770
384
  ];
771
385
  const CATEGORY_COLORS = {
772
- image: { label: 'Images & Media', color: '#EC4899', bg: '#FCE7F3' },
773
- typescript: { label: 'TypeScript', color: '#0EA5E9', bg: '#E0F2FE' },
774
- javascript: { label: 'JavaScript', color: '#6366F1', bg: '#EEF2FF' },
775
- font: { label: 'Fonts', color: '#8B5CF6', bg: '#F3E8FF' },
776
- json: { label: 'JSON / Data', color: '#10B981', bg: '#D1FAE5' },
386
+ image: { label: 'Images & Media', color: AppColors_1.AppColors.pink500, bg: AppColors_1.AppColors.pink100 },
387
+ typescript: { label: 'TypeScript', color: AppColors_1.AppColors.sky500, bg: AppColors_1.AppColors.sky100 },
388
+ javascript: { label: 'JavaScript', color: AppColors_1.AppColors.indigo500, bg: AppColors_1.AppColors.indigo50 },
389
+ font: { label: 'Fonts', color: AppColors_1.AppColors.purple500, bg: AppColors_1.AppColors.purple100 },
390
+ json: { label: 'JSON / Data', color: AppColors_1.AppColors.emerald500, bg: AppColors_1.AppColors.emerald100 },
777
391
  };
778
392
  const BundleTab = react_1.default.memo(() => {
779
393
  const { t } = (0, i18n_1.useTranslation)();
780
394
  const [activeSubTab, setActiveSubTab] = (0, react_1.useState)('overview');
781
395
  const [search, setSearch] = (0, react_1.useState)('');
782
396
  const [activeCategory, setActiveCategory] = (0, react_1.useState)('ALL');
397
+ // ─── Live Host App Bundle Analysis (fetched from Metro / runtime) ─────────
398
+ const [analysis, setAnalysis] = (0, react_1.useState)(() => (0, bundleAnalyzer_1.getCachedBundleAnalysis)());
399
+ const [isAnalyzing, setIsAnalyzing] = (0, react_1.useState)(!(0, bundleAnalyzer_1.getCachedBundleAnalysis)());
400
+ (0, react_1.useEffect)(() => {
401
+ let mounted = true;
402
+ (0, bundleAnalyzer_1.analyzeHostAppBundle)().then(result => {
403
+ if (mounted) {
404
+ setAnalysis(result);
405
+ setIsAnalyzing(false);
406
+ }
407
+ });
408
+ return () => {
409
+ mounted = false;
410
+ };
411
+ }, []);
783
412
  // Check if Hermes is running
784
413
  const isHermes = Boolean(global.HermesInternal);
414
+ // Dynamic files & packages derived from the analyzed host bundle
415
+ const bundleFiles = (0, react_1.useMemo)(() => (analysis ? analysis.files : []), [analysis]);
416
+ const bundlePackages = (0, react_1.useMemo)(() => (analysis ? analysis.packages : []), [analysis]);
785
417
  // Group summary calculations
786
418
  const summary = (0, react_1.useMemo)(() => {
787
419
  let imagesKb = 0;
@@ -794,7 +426,7 @@ const BundleTab = react_1.default.memo(() => {
794
426
  let jsCount = 0;
795
427
  let fontsCount = 0;
796
428
  let jsonCount = 0;
797
- BUNDLE_FILES_DATA.forEach(f => {
429
+ bundleFiles.forEach(f => {
798
430
  if (f.category === 'image') {
799
431
  imagesKb += f.sizeKb;
800
432
  imagesCount++;
@@ -820,37 +452,37 @@ const BundleTab = react_1.default.memo(() => {
820
452
  return {
821
453
  totalKb,
822
454
  totalMb: (totalKb / 1024).toFixed(2),
823
- totalCount: BUNDLE_FILES_DATA.length,
455
+ totalCount: bundleFiles.length,
824
456
  images: {
825
457
  count: imagesCount,
826
458
  kb: imagesKb,
827
- pct: Number(((imagesKb / totalKb) * 100).toFixed(1)),
459
+ pct: totalKb ? Number(((imagesKb / totalKb) * 100).toFixed(1)) : 0,
828
460
  },
829
461
  ts: {
830
462
  count: tsCount,
831
463
  kb: tsKb,
832
- pct: Number(((tsKb / totalKb) * 100).toFixed(1)),
464
+ pct: totalKb ? Number(((tsKb / totalKb) * 100).toFixed(1)) : 0,
833
465
  },
834
466
  js: {
835
467
  count: jsCount,
836
468
  kb: jsKb,
837
- pct: Number(((jsKb / totalKb) * 100).toFixed(1)),
469
+ pct: totalKb ? Number(((jsKb / totalKb) * 100).toFixed(1)) : 0,
838
470
  },
839
471
  fonts: {
840
472
  count: fontsCount,
841
473
  kb: fontsKb,
842
- pct: Number(((fontsKb / totalKb) * 100).toFixed(1)),
474
+ pct: totalKb ? Number(((fontsKb / totalKb) * 100).toFixed(1)) : 0,
843
475
  },
844
476
  json: {
845
477
  count: jsonCount,
846
478
  kb: jsonKb,
847
- pct: Number(((jsonKb / totalKb) * 100).toFixed(1)),
479
+ pct: totalKb ? Number(((jsonKb / totalKb) * 100).toFixed(1)) : 0,
848
480
  },
849
481
  };
850
- }, []);
482
+ }, [bundleFiles]);
851
483
  // Filtered files
852
484
  const filteredFiles = (0, react_1.useMemo)(() => {
853
- return BUNDLE_FILES_DATA.filter(file => {
485
+ return bundleFiles.filter(file => {
854
486
  const matchSearch = !search ||
855
487
  file.name.toLowerCase().includes(search.toLowerCase()) ||
856
488
  file.path.toLowerCase().includes(search.toLowerCase()) ||
@@ -865,7 +497,7 @@ const BundleTab = react_1.default.memo(() => {
865
497
  : file.category === activeCategory;
866
498
  return matchSearch && matchCategory;
867
499
  });
868
- }, [search, activeCategory]);
500
+ }, [search, activeCategory, bundleFiles]);
869
501
  const filteredTotalKb = (0, react_1.useMemo)(() => {
870
502
  return filteredFiles.reduce((acc, f) => acc + f.sizeKb, 0);
871
503
  }, [filteredFiles]);
@@ -900,46 +532,46 @@ const BundleTab = react_1.default.memo(() => {
900
532
  // Filtered Packages
901
533
  const filteredPackages = (0, react_1.useMemo)(() => {
902
534
  if (!search)
903
- return BUNDLE_PACKAGES_DATA;
535
+ return bundlePackages;
904
536
  const q = search.toLowerCase();
905
- return BUNDLE_PACKAGES_DATA.filter(pkg => pkg.name.toLowerCase().includes(q) ||
537
+ return bundlePackages.filter(pkg => pkg.name.toLowerCase().includes(q) ||
906
538
  pkg.description.toLowerCase().includes(q) ||
907
539
  pkg.category.toLowerCase().includes(q));
908
- }, [search]);
540
+ }, [search, bundlePackages]);
909
541
  const packagesTotalKb = (0, react_1.useMemo)(() => {
910
542
  return filteredPackages.reduce((acc, p) => acc + p.sizeKb, 0);
911
543
  }, [filteredPackages]);
912
544
  // Media files (Images + Fonts)
913
545
  const mediaFiles = (0, react_1.useMemo)(() => {
914
- return BUNDLE_FILES_DATA.filter(f => f.category === 'image' || f.category === 'font');
915
- }, []);
546
+ return bundleFiles.filter(f => f.category === 'image' || f.category === 'font');
547
+ }, [bundleFiles]);
916
548
  const mediaTotalKb = (0, react_1.useMemo)(() => {
917
549
  return mediaFiles.reduce((acc, m) => acc + m.sizeKb, 0);
918
550
  }, [mediaFiles]);
919
551
  const subTabs = [
920
552
  {
921
553
  key: 'overview',
922
- label: 'Overview',
554
+ label: t('bundle.tabOverview'),
923
555
  icon: (isActive) => (<NetworkIcons_1.LiveStateIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
924
556
  },
925
557
  {
926
558
  key: 'files',
927
- label: `Files (${BUNDLE_FILES_DATA.length})`,
559
+ label: t('bundle.tabFiles', { count: bundleFiles.length }),
928
560
  icon: (isActive) => (<NetworkIcons_1.LayersIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
929
561
  },
930
562
  {
931
563
  key: 'packages',
932
- label: `Packages (${BUNDLE_PACKAGES_DATA.length})`,
564
+ label: t('bundle.tabPackages', { count: bundlePackages.length }),
933
565
  icon: (isActive) => (<NetworkIcons_1.PackageIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
934
566
  },
935
567
  {
936
568
  key: 'media',
937
- label: `Media (${mediaFiles.length})`,
569
+ label: t('bundle.tabMedia', { count: mediaFiles.length }),
938
570
  icon: (isActive) => (<NetworkIcons_1.StorageIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
939
571
  },
940
572
  {
941
573
  key: 'optimizer',
942
- label: 'Optimizer',
574
+ label: t('bundle.tabOptimizer'),
943
575
  icon: (isActive) => (<NetworkIcons_1.MetadataIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
944
576
  },
945
577
  ];
@@ -965,10 +597,21 @@ const BundleTab = react_1.default.memo(() => {
965
597
  </react_native_1.ScrollView>
966
598
  </react_native_1.View>
967
599
 
600
+ {/* ─── Live Bundle Analysis Loading State ─── */}
601
+ {isAnalyzing && (<react_native_1.View style={bundleStyles.analyzingContainer}>
602
+ <react_native_1.ActivityIndicator size="small" color={AppColors_1.AppColors.brandPurple}/>
603
+ <react_native_1.Text style={bundleStyles.analyzingText}>
604
+ {t('bundle.analyzingTitle')}
605
+ </react_native_1.Text>
606
+ <react_native_1.Text style={bundleStyles.analyzingHint}>
607
+ {t('bundle.analyzingHint')}
608
+ </react_native_1.Text>
609
+ </react_native_1.View>)}
610
+
968
611
  {/* ══════════════════════════════════════════════════════════════════════ */}
969
612
  {/* ── 1. TAB: OVERVIEW & TREEMAP ───────────────────────────────────────── */}
970
613
  {/* ══════════════════════════════════════════════════════════════════════ */}
971
- {activeSubTab === 'overview' && (<react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
614
+ {activeSubTab === 'overview' && !isAnalyzing && (<react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
972
615
 
973
616
  {/* Hero Overview Card */}
974
617
  <react_native_1.View style={bundleStyles.heroCard}>
@@ -977,42 +620,59 @@ const BundleTab = react_1.default.memo(() => {
977
620
  <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.brandPurple} size={24}/>
978
621
  </react_native_1.View>
979
622
  <react_native_1.View style={{ flex: 1 }}>
980
- <react_native_1.Text style={bundleStyles.heroTitle}>Bundle & Asset Architecture</react_native_1.Text>
623
+ <react_native_1.Text style={bundleStyles.heroTitle}>{t('bundle.heroTitle')}</react_native_1.Text>
981
624
  <react_native_1.Text style={bundleStyles.heroSubtitle}>
982
- Real-time size breakdown across all assets, code, and dependencies
625
+ {analysis?.isLive
626
+ ? t('bundle.heroSubtitleLive', { scriptUrl: analysis.scriptURL })
627
+ : t('bundle.heroSubtitle')}
983
628
  </react_native_1.Text>
984
629
  </react_native_1.View>
985
- <CopyButton_1.default value={() => summary} label="Bundle Overview JSON"/>
630
+ <CopyButton_1.default value={() => ({ ...summary, bundle: analysis })} label={t('bundle.bundleOverviewJson')}/>
986
631
  </react_native_1.View>
987
632
 
988
633
  {/* 4-Stat Metric Grid */}
989
634
  <react_native_1.View style={bundleStyles.metricsGrid}>
990
635
  <react_native_1.View style={bundleStyles.metricBox}>
991
- <react_native_1.Text style={bundleStyles.metricLabel}>TOTAL BUNDLE ASSETS</react_native_1.Text>
992
- <react_native_1.Text style={bundleStyles.metricValue}>~{summary.totalMb} MB</react_native_1.Text>
993
- <react_native_1.Text style={bundleStyles.metricHint}>{BUNDLE_FILES_DATA.length} Tracked files</react_native_1.Text>
636
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.devBundleSize')}</react_native_1.Text>
637
+ <react_native_1.Text style={bundleStyles.metricValue}>
638
+ {t('bundle.mbValue', {
639
+ size: analysis ? analysis.totalDevMb : summary.totalMb,
640
+ })}
641
+ </react_native_1.Text>
642
+ <react_native_1.Text style={bundleStyles.metricHint}>
643
+ {analysis
644
+ ? t('bundle.devBundleHint', {
645
+ kb: analysis.totalDevKb,
646
+ modules: analysis.moduleCount,
647
+ })
648
+ : t('bundle.trackedFilesHint', { count: bundleFiles.length })}
649
+ </react_native_1.Text>
994
650
  </react_native_1.View>
995
651
 
996
652
  <react_native_1.View style={bundleStyles.metricBox}>
997
- <react_native_1.Text style={bundleStyles.metricLabel}>IMAGES & MEDIA</react_native_1.Text>
998
- <react_native_1.Text style={[bundleStyles.metricValue, { color: '#EC4899' }]}>
999
- {summary.images.kb} KB
653
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.imagesMedia')}</react_native_1.Text>
654
+ <react_native_1.Text style={[bundleStyles.metricValue, { color: AppColors_1.AppColors.pink500 }]}>
655
+ {t('bundle.fileSizeKb', { size: summary.images.kb })}
656
+ </react_native_1.Text>
657
+ <react_native_1.Text style={bundleStyles.metricHint}>
658
+ {t('bundle.pctOfTrackedAssets', { pct: summary.images.pct })}
1000
659
  </react_native_1.Text>
1001
- <react_native_1.Text style={bundleStyles.metricHint}>{summary.images.pct}% of package</react_native_1.Text>
1002
660
  </react_native_1.View>
1003
661
 
1004
662
  <react_native_1.View style={bundleStyles.metricBox}>
1005
- <react_native_1.Text style={bundleStyles.metricLabel}>TS / JS SOURCE</react_native_1.Text>
1006
- <react_native_1.Text style={[bundleStyles.metricValue, { color: '#0EA5E9' }]}>
1007
- {summary.ts.kb + summary.js.kb} KB
663
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.tsJsSource')}</react_native_1.Text>
664
+ <react_native_1.Text style={[bundleStyles.metricValue, { color: AppColors_1.AppColors.sky500 }]}>
665
+ {t('bundle.fileSizeKb', { size: summary.ts.kb + summary.js.kb })}
1008
666
  </react_native_1.Text>
1009
667
  <react_native_1.Text style={bundleStyles.metricHint}>
1010
- {(summary.ts.pct + summary.js.pct).toFixed(1)}% of package
668
+ {t('bundle.pctOfTrackedAssets', {
669
+ pct: (summary.ts.pct + summary.js.pct).toFixed(1),
670
+ })}
1011
671
  </react_native_1.Text>
1012
672
  </react_native_1.View>
1013
673
 
1014
674
  <react_native_1.View style={bundleStyles.metricBox}>
1015
- <react_native_1.Text style={bundleStyles.metricLabel}>JS ENGINE</react_native_1.Text>
675
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.jsEngine')}</react_native_1.Text>
1016
676
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 5, marginTop: 2 }}>
1017
677
  <react_native_1.View style={[
1018
678
  bundleStyles.statusIndicator,
@@ -1022,17 +682,105 @@ const BundleTab = react_1.default.memo(() => {
1022
682
  {isHermes ? 'Hermes' : 'JSC'}
1023
683
  </react_native_1.Text>
1024
684
  </react_native_1.View>
1025
- <react_native_1.Text style={bundleStyles.metricHint}>{isHermes ? 'Bytecode AOT' : 'Standard'}</react_native_1.Text>
685
+ <react_native_1.Text style={bundleStyles.metricHint}>
686
+ {isHermes ? t('bundle.bytecodeAot') : t('bundle.standard')}
687
+ </react_native_1.Text>
1026
688
  </react_native_1.View>
1027
689
  </react_native_1.View>
1028
690
  </react_native_1.View>
1029
691
 
692
+ {/* Development Bundle Split-Up (derived from the real running bundle) */}
693
+ {analysis && (<react_native_1.View style={bundleStyles.sectionCard}>
694
+ <react_native_1.View style={bundleStyles.sectionHeaderRow}>
695
+ <react_native_1.View>
696
+ <react_native_1.Text style={bundleStyles.sectionTitle}>{t('bundle.splitUpTitle')}</react_native_1.Text>
697
+ <react_native_1.Text style={bundleStyles.sectionSub}>
698
+ {t('bundle.splitUpSub', {
699
+ mb: analysis.totalDevMb,
700
+ files: analysis.filesCount,
701
+ packages: analysis.packageCount,
702
+ })}
703
+ </react_native_1.Text>
704
+ </react_native_1.View>
705
+ <CopyButton_1.default value={() => analysis.splitUp} label={t('bundle.splitUpJson')}/>
706
+ </react_native_1.View>
707
+
708
+ {[
709
+ {
710
+ label: t('bundle.splitAppSource'),
711
+ color: AppColors_1.AppColors.sky500,
712
+ ...analysis.splitUp.appSource,
713
+ },
714
+ {
715
+ label: t('bundle.splitNodeModules'),
716
+ color: AppColors_1.AppColors.indigo500,
717
+ ...analysis.splitUp.nodeModules,
718
+ },
719
+ {
720
+ label: t('bundle.splitAssetsMedia'),
721
+ color: AppColors_1.AppColors.pink500,
722
+ ...analysis.splitUp.assetsMedia,
723
+ },
724
+ {
725
+ label: t('bundle.splitMetroOverhead'),
726
+ color: AppColors_1.AppColors.amber500,
727
+ ...analysis.splitUp.metroDevOverhead,
728
+ },
729
+ ].map((part, idx) => (<react_native_1.View key={idx} style={bundleStyles.catRowCard}>
730
+ <react_native_1.View style={bundleStyles.catRowTop}>
731
+ <react_native_1.Text style={bundleStyles.catRowIcon}>{['📦', '🧩', '🖼️', '⚙️'][idx]}</react_native_1.Text>
732
+ <react_native_1.View style={{ flex: 1 }}>
733
+ <react_native_1.Text style={bundleStyles.catRowTitle}>{part.label}</react_native_1.Text>
734
+ <react_native_1.Text style={bundleStyles.catRowDesc}>
735
+ {t('bundle.splitSize', { kb: part.kb, mb: part.mb })}
736
+ </react_native_1.Text>
737
+ </react_native_1.View>
738
+ <react_native_1.View style={{ alignItems: 'flex-end' }}>
739
+ <react_native_1.Text style={bundleStyles.catRowSize}>{part.pct}%</react_native_1.Text>
740
+ </react_native_1.View>
741
+ </react_native_1.View>
742
+ <react_native_1.View style={bundleStyles.catProgressTrack}>
743
+ <react_native_1.View style={[
744
+ bundleStyles.catProgressBar,
745
+ { width: `${part.pct}%`, backgroundColor: part.color },
746
+ ]}/>
747
+ </react_native_1.View>
748
+ </react_native_1.View>))}
749
+
750
+ {/* Production Binary Footprint */}
751
+ <react_native_1.View style={bundleStyles.totalSummaryCard}>
752
+ <react_native_1.View style={bundleStyles.totalSummaryRow}>
753
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
754
+ <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.purple} size={16}/>
755
+ <react_native_1.Text style={bundleStyles.totalSummaryLabel}>
756
+ {t('bundle.productionFootprint')}
757
+ </react_native_1.Text>
758
+ </react_native_1.View>
759
+ <react_native_1.Text style={bundleStyles.totalSummaryValue}>
760
+ {t('bundle.productionValue', {
761
+ ios: analysis.production.ios.totalInstallMb,
762
+ android: analysis.production.android.totalInstallMb,
763
+ })}
764
+ </react_native_1.Text>
765
+ </react_native_1.View>
766
+ <react_native_1.Text style={bundleStyles.totalSummaryFormula}>
767
+ {t('bundle.productionDownload', {
768
+ ios: analysis.production.ios.totalDownloadMb,
769
+ aab: analysis.production.androidAab.totalDownloadMb,
770
+ apk: analysis.production.androidApk.totalDownloadMb,
771
+ })}
772
+ </react_native_1.Text>
773
+ </react_native_1.View>
774
+ </react_native_1.View>)}
775
+
1030
776
  {/* Visual Type Distribution Ratio Bar */}
1031
777
  <react_native_1.View style={bundleStyles.sectionCard}>
1032
778
  <react_native_1.View style={bundleStyles.sectionHeaderRow}>
1033
779
  <react_native_1.View>
1034
- <react_native_1.Text style={bundleStyles.sectionTitle}>Asset & File Type Ratio Treemap</react_native_1.Text>
1035
- <react_native_1.Text style={bundleStyles.sectionSub}>Total ~{summary.totalMb} MB</react_native_1.Text>
780
+ <react_native_1.Text style={bundleStyles.sectionTitle}>{t('bundle.treemapTitle')}</react_native_1.Text>
781
+ <react_native_1.Text style={bundleStyles.sectionSub}>
782
+ {t('bundle.treemapSub', { mb: summary.totalMb })}
783
+ </react_native_1.Text>
1036
784
  </react_native_1.View>
1037
785
  <CopyButton_1.default value={() => ({
1038
786
  totalMb: summary.totalMb,
@@ -1042,48 +790,63 @@ const BundleTab = react_1.default.memo(() => {
1042
790
  js: summary.js,
1043
791
  fonts: summary.fonts,
1044
792
  json: summary.json,
1045
- })} label="Ratio Treemap JSON"/>
793
+ })} label={t('bundle.treemapJson')}/>
1046
794
  </react_native_1.View>
1047
795
 
1048
796
  {/* Stacked Colored Bar */}
1049
797
  <react_native_1.View style={bundleStyles.treemapBar}>
1050
- <react_native_1.View style={{ flex: summary.images.pct, backgroundColor: '#EC4899', height: 16 }}/>
1051
- <react_native_1.View style={{ flex: summary.ts.pct, backgroundColor: '#0EA5E9', height: 16 }}/>
1052
- <react_native_1.View style={{ flex: summary.js.pct, backgroundColor: '#6366F1', height: 16 }}/>
1053
- <react_native_1.View style={{ flex: summary.fonts.pct, backgroundColor: '#8B5CF6', height: 16 }}/>
1054
- <react_native_1.View style={{ flex: summary.json.pct, backgroundColor: '#10B981', height: 16 }}/>
798
+ <react_native_1.View style={{ flex: summary.images.pct, backgroundColor: AppColors_1.AppColors.pink500, height: 16 }}/>
799
+ <react_native_1.View style={{ flex: summary.ts.pct, backgroundColor: AppColors_1.AppColors.sky500, height: 16 }}/>
800
+ <react_native_1.View style={{ flex: summary.js.pct, backgroundColor: AppColors_1.AppColors.indigo500, height: 16 }}/>
801
+ <react_native_1.View style={{ flex: summary.fonts.pct, backgroundColor: AppColors_1.AppColors.purple500, height: 16 }}/>
802
+ <react_native_1.View style={{ flex: summary.json.pct, backgroundColor: AppColors_1.AppColors.emerald500, height: 16 }}/>
1055
803
  </react_native_1.View>
1056
804
 
1057
805
  {/* Legend Grid */}
1058
806
  <react_native_1.View style={bundleStyles.legendGrid}>
1059
807
  <react_native_1.View style={bundleStyles.legendItem}>
1060
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#EC4899' }]}/>
808
+ <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: AppColors_1.AppColors.pink500 }]}/>
1061
809
  <react_native_1.Text style={bundleStyles.legendText}>
1062
- 🖼️ Images: <react_native_1.Text style={bundleStyles.legendVal}>{summary.images.kb} KB ({summary.images.pct}%)</react_native_1.Text>
810
+ {t('bundle.legendImages')}{' '}
811
+ <react_native_1.Text style={bundleStyles.legendVal}>
812
+ {t('bundle.legendValue', { kb: summary.images.kb, pct: summary.images.pct })}
813
+ </react_native_1.Text>
1063
814
  </react_native_1.Text>
1064
815
  </react_native_1.View>
1065
816
  <react_native_1.View style={bundleStyles.legendItem}>
1066
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#0EA5E9' }]}/>
817
+ <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: AppColors_1.AppColors.sky500 }]}/>
1067
818
  <react_native_1.Text style={bundleStyles.legendText}>
1068
- 📜 TS/TSX: <react_native_1.Text style={bundleStyles.legendVal}>{summary.ts.kb} KB ({summary.ts.pct}%)</react_native_1.Text>
819
+ {t('bundle.legendTs')}{' '}
820
+ <react_native_1.Text style={bundleStyles.legendVal}>
821
+ {t('bundle.legendValue', { kb: summary.ts.kb, pct: summary.ts.pct })}
822
+ </react_native_1.Text>
1069
823
  </react_native_1.Text>
1070
824
  </react_native_1.View>
1071
825
  <react_native_1.View style={bundleStyles.legendItem}>
1072
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#6366F1' }]}/>
826
+ <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: AppColors_1.AppColors.indigo500 }]}/>
1073
827
  <react_native_1.Text style={bundleStyles.legendText}>
1074
- ⚙️ JS Libs: <react_native_1.Text style={bundleStyles.legendVal}>{summary.js.kb} KB ({summary.js.pct}%)</react_native_1.Text>
828
+ {t('bundle.legendJs')}{' '}
829
+ <react_native_1.Text style={bundleStyles.legendVal}>
830
+ {t('bundle.legendValue', { kb: summary.js.kb, pct: summary.js.pct })}
831
+ </react_native_1.Text>
1075
832
  </react_native_1.Text>
1076
833
  </react_native_1.View>
1077
834
  <react_native_1.View style={bundleStyles.legendItem}>
1078
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#8B5CF6' }]}/>
835
+ <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: AppColors_1.AppColors.purple500 }]}/>
1079
836
  <react_native_1.Text style={bundleStyles.legendText}>
1080
- 🔤 Fonts: <react_native_1.Text style={bundleStyles.legendVal}>{summary.fonts.kb} KB ({summary.fonts.pct}%)</react_native_1.Text>
837
+ {t('bundle.legendFonts')}{' '}
838
+ <react_native_1.Text style={bundleStyles.legendVal}>
839
+ {t('bundle.legendValue', { kb: summary.fonts.kb, pct: summary.fonts.pct })}
840
+ </react_native_1.Text>
1081
841
  </react_native_1.Text>
1082
842
  </react_native_1.View>
1083
843
  <react_native_1.View style={bundleStyles.legendItem}>
1084
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#10B981' }]}/>
844
+ <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: AppColors_1.AppColors.emerald500 }]}/>
1085
845
  <react_native_1.Text style={bundleStyles.legendText}>
1086
- 📄 JSON: <react_native_1.Text style={bundleStyles.legendVal}>{summary.json.kb} KB ({summary.json.pct}%)</react_native_1.Text>
846
+ {t('bundle.legendJson')}{' '}
847
+ <react_native_1.Text style={bundleStyles.legendVal}>
848
+ {t('bundle.legendValue', { kb: summary.json.kb, pct: summary.json.pct })}
849
+ </react_native_1.Text>
1087
850
  </react_native_1.Text>
1088
851
  </react_native_1.View>
1089
852
  </react_native_1.View>
@@ -1092,7 +855,7 @@ const BundleTab = react_1.default.memo(() => {
1092
855
  {/* Detailed Category Footprint Cards */}
1093
856
  <react_native_1.View style={bundleStyles.sectionCard}>
1094
857
  <react_native_1.View style={bundleStyles.sectionHeaderRow}>
1095
- <react_native_1.Text style={bundleStyles.sectionTitle}>Category Breakdown</react_native_1.Text>
858
+ <react_native_1.Text style={bundleStyles.sectionTitle}>{t('bundle.categoryBreakdown')}</react_native_1.Text>
1096
859
  <CopyButton_1.default value={() => ({
1097
860
  totalAssets: summary.totalCount,
1098
861
  totalSizeKb: summary.totalKb,
@@ -1103,61 +866,66 @@ const BundleTab = react_1.default.memo(() => {
1103
866
  typescript: summary.ts,
1104
867
  json: summary.json,
1105
868
  },
1106
- })} label="Categories Breakdown JSON"/>
869
+ })} label={t('bundle.categoriesJson')}/>
1107
870
  </react_native_1.View>
1108
871
 
1109
872
  {[
1110
873
  {
1111
874
  icon: '🖼️',
1112
- title: 'Images & Media Assets',
875
+ title: t('bundle.catImagesTitle'),
1113
876
  count: summary.images.count,
1114
- size: `${summary.images.kb} KB`,
877
+ size: t('bundle.fileSizeKb', { size: summary.images.kb }),
1115
878
  pct: summary.images.pct,
1116
- color: '#EC4899',
1117
- desc: 'PNG, WebP, SVG, and JPG assets in bundle',
879
+ color: AppColors_1.AppColors.pink500,
880
+ desc: t('bundle.catImagesDesc'),
1118
881
  },
1119
882
  {
1120
883
  icon: '⚙️',
1121
- title: 'Compiled Node Modules & JS',
884
+ title: t('bundle.catJsTitle'),
1122
885
  count: summary.js.count,
1123
- size: `${summary.js.kb} KB`,
886
+ size: t('bundle.fileSizeKb', { size: summary.js.kb }),
1124
887
  pct: summary.js.pct,
1125
- color: '#6366F1',
1126
- desc: 'Third-party dependencies and native bridges',
888
+ color: AppColors_1.AppColors.indigo500,
889
+ desc: t('bundle.catJsDesc'),
1127
890
  },
1128
891
  {
1129
892
  icon: '🔤',
1130
- title: 'Custom Fonts & Vector Glyphs',
893
+ title: t('bundle.catFontsTitle'),
1131
894
  count: summary.fonts.count,
1132
- size: `${summary.fonts.kb} KB`,
895
+ size: t('bundle.fileSizeKb', { size: summary.fonts.kb }),
1133
896
  pct: summary.fonts.pct,
1134
- color: '#8B5CF6',
1135
- desc: 'Inter, JetBrainsMono, and UI typography fonts',
897
+ color: AppColors_1.AppColors.purple500,
898
+ desc: bundleFiles
899
+ .filter(f => f.category === 'font')
900
+ .map(f => f.name)
901
+ .join(', ') || t('bundle.catFontsDesc'),
1136
902
  },
1137
903
  {
1138
904
  icon: '📜',
1139
- title: 'TypeScript & JSX Components',
905
+ title: t('bundle.catTsTitle'),
1140
906
  count: summary.ts.count,
1141
- size: `${summary.ts.kb} KB`,
907
+ size: t('bundle.fileSizeKb', { size: summary.ts.kb }),
1142
908
  pct: summary.ts.pct,
1143
- color: '#0EA5E9',
1144
- desc: 'App screen components, hooks, and business logic',
909
+ color: AppColors_1.AppColors.sky500,
910
+ desc: t('bundle.catTsDesc'),
1145
911
  },
1146
912
  {
1147
913
  icon: '📄',
1148
- title: 'JSON Data & Localizations',
914
+ title: t('bundle.catJsonTitle'),
1149
915
  count: summary.json.count,
1150
- size: `${summary.json.kb} KB`,
916
+ size: t('bundle.fileSizeKb', { size: summary.json.kb }),
1151
917
  pct: summary.json.pct,
1152
- color: '#10B981',
1153
- desc: 'i18n translation dictionaries and static configs',
918
+ color: AppColors_1.AppColors.emerald500,
919
+ desc: t('bundle.catJsonDesc'),
1154
920
  },
1155
921
  ].map((cat, cIdx) => (<react_native_1.View key={cIdx} style={bundleStyles.catRowCard}>
1156
922
  <react_native_1.View style={bundleStyles.catRowTop}>
1157
923
  <react_native_1.Text style={bundleStyles.catRowIcon}>{cat.icon}</react_native_1.Text>
1158
924
  <react_native_1.View style={{ flex: 1 }}>
1159
925
  <react_native_1.Text style={bundleStyles.catRowTitle}>{cat.title}</react_native_1.Text>
1160
- <react_native_1.Text style={bundleStyles.catRowDesc}>{cat.count} items • {cat.desc}</react_native_1.Text>
926
+ <react_native_1.Text style={bundleStyles.catRowDesc}>
927
+ {t('bundle.catRowSub', { count: cat.count, desc: cat.desc })}
928
+ </react_native_1.Text>
1161
929
  </react_native_1.View>
1162
930
  <react_native_1.View style={{ alignItems: 'flex-end' }}>
1163
931
  <react_native_1.Text style={bundleStyles.catRowSize}>{cat.size}</react_native_1.Text>
@@ -1177,14 +945,24 @@ const BundleTab = react_1.default.memo(() => {
1177
945
  <react_native_1.View style={bundleStyles.totalSummaryRow}>
1178
946
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1179
947
  <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.purple} size={16}/>
1180
- <react_native_1.Text style={bundleStyles.totalSummaryLabel}>TOTAL BUNDLE ASSETS</react_native_1.Text>
948
+ <react_native_1.Text style={bundleStyles.totalSummaryLabel}>
949
+ {t('bundle.totalBundleAssets')}
950
+ </react_native_1.Text>
1181
951
  </react_native_1.View>
1182
952
  <react_native_1.Text style={bundleStyles.totalSummaryValue}>
1183
- {summary.totalKb} KB (~{summary.totalMb} MB)
953
+ {t('bundle.totalBundleValue', { kb: summary.totalKb, mb: summary.totalMb })}
1184
954
  </react_native_1.Text>
1185
955
  </react_native_1.View>
1186
956
  <react_native_1.Text style={bundleStyles.totalSummaryFormula}>
1187
- Sum: {summary.images.kb} KB + {summary.js.kb} KB + {summary.fonts.kb} KB + {summary.ts.kb} KB + {summary.json.kb} KB = {summary.totalKb} KB ({summary.totalCount} items • 100%)
957
+ {t('bundle.totalFormula', {
958
+ images: summary.images.kb,
959
+ js: summary.js.kb,
960
+ fonts: summary.fonts.kb,
961
+ ts: summary.ts.kb,
962
+ json: summary.json.kb,
963
+ total: summary.totalKb,
964
+ count: summary.totalCount,
965
+ })}
1188
966
  </react_native_1.Text>
1189
967
  </react_native_1.View>
1190
968
  </react_native_1.View>
@@ -1193,16 +971,16 @@ const BundleTab = react_1.default.memo(() => {
1193
971
  {/* ══════════════════════════════════════════════════════════════════════ */}
1194
972
  {/* ── 2. TAB: FILES BREAKDOWN ─────────────────────────────────────────── */}
1195
973
  {/* ══════════════════════════════════════════════════════════════════════ */}
1196
- {activeSubTab === 'files' && (<react_native_1.View style={{ flex: 1 }}>
974
+ {activeSubTab === 'files' && !isAnalyzing && (<react_native_1.View style={{ flex: 1 }}>
1197
975
  {/* Search & Category Filter */}
1198
976
  <react_native_1.View style={bundleStyles.filterContainer}>
1199
977
  <react_native_1.View style={bundleStyles.searchRow}>
1200
978
  <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={15}/>
1201
- <react_native_1.TextInput placeholder="Search by file name (.png, .tsx, .ttf, path)..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
979
+ <react_native_1.TextInput placeholder={t('bundle.searchFilesPlaceholder')} placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1202
980
  {search.length > 0 && (<react_native_1.Pressable onPress={() => setSearch('')} hitSlop={10}>
1203
981
  <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
1204
982
  </react_native_1.Pressable>)}
1205
- <CopyButton_1.default value={() => filteredFiles} label="Filtered Files JSON"/>
983
+ <CopyButton_1.default value={() => filteredFiles} label={t('bundle.filteredFilesJson')}/>
1206
984
  </react_native_1.View>
1207
985
 
1208
986
  {/* Category Filter Chips */}
@@ -1210,24 +988,24 @@ const BundleTab = react_1.default.memo(() => {
1210
988
  {CATEGORY_TABS.map(tab => {
1211
989
  const isActive = activeCategory === tab.key;
1212
990
  const count = tab.key === 'ALL'
1213
- ? BUNDLE_FILES_DATA.length
991
+ ? bundleFiles.length
1214
992
  : tab.key === 'UNUSED'
1215
- ? BUNDLE_FILES_DATA.filter(f => f.isConsumed === false).length
993
+ ? bundleFiles.filter(f => f.isConsumed === false).length
1216
994
  : tab.key === 'CONSUMED'
1217
- ? BUNDLE_FILES_DATA.filter(f => f.isConsumed !== false).length
1218
- : BUNDLE_FILES_DATA.filter(f => f.category === tab.key).length;
995
+ ? bundleFiles.filter(f => f.isConsumed !== false).length
996
+ : bundleFiles.filter(f => f.category === tab.key).length;
1219
997
  return (<TouchableScale_1.default key={tab.key} onPress={() => setActiveCategory(tab.key)} style={[
1220
998
  bundleStyles.catPill,
1221
999
  isActive && bundleStyles.catPillActive,
1222
- tab.key === 'UNUSED' && isActive && { backgroundColor: '#EF4444', borderColor: '#DC2626' },
1223
- tab.key === 'CONSUMED' && isActive && { backgroundColor: '#059669', borderColor: '#047857' },
1000
+ tab.key === 'UNUSED' && isActive && { backgroundColor: AppColors_1.AppColors.red500, borderColor: AppColors_1.AppColors.red600 },
1001
+ tab.key === 'CONSUMED' && isActive && { backgroundColor: AppColors_1.AppColors.emerald600, borderColor: AppColors_1.AppColors.emerald700 },
1224
1002
  ]}>
1225
1003
  <react_native_1.Text style={bundleStyles.catPillIcon}>{tab.icon}</react_native_1.Text>
1226
1004
  <react_native_1.Text style={[
1227
1005
  bundleStyles.catPillText,
1228
1006
  isActive && bundleStyles.catPillTextActive,
1229
1007
  ]}>
1230
- {tab.label} ({count})
1008
+ {t(tab.labelKey)} ({count})
1231
1009
  </react_native_1.Text>
1232
1010
  </TouchableScale_1.default>);
1233
1011
  })}
@@ -1248,7 +1026,7 @@ const BundleTab = react_1.default.memo(() => {
1248
1026
  bundleStyles.viewModeBtnText,
1249
1027
  filesViewMode === 'tree' && bundleStyles.viewModeBtnTextActive,
1250
1028
  ]}>
1251
- 🌳 Tree View
1029
+ {t('bundle.treeView')}
1252
1030
  </react_native_1.Text>
1253
1031
  </TouchableScale_1.default>
1254
1032
  <TouchableScale_1.default onPress={() => setFilesViewMode('list')} style={[
@@ -1259,21 +1037,24 @@ const BundleTab = react_1.default.memo(() => {
1259
1037
  bundleStyles.viewModeBtnText,
1260
1038
  filesViewMode === 'list' && bundleStyles.viewModeBtnTextActive,
1261
1039
  ]}>
1262
- 📄 Flat List
1040
+ {t('bundle.flatList')}
1263
1041
  </react_native_1.Text>
1264
1042
  </TouchableScale_1.default>
1265
1043
  </react_native_1.View>
1266
1044
 
1267
1045
  {filesViewMode === 'tree' ? (<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1268
1046
  <TouchableScale_1.default onPress={expandAllFolders}>
1269
- <react_native_1.Text style={bundleStyles.treeActionLink}>Expand</react_native_1.Text>
1047
+ <react_native_1.Text style={bundleStyles.treeActionLink}>{t('bundle.expand')}</react_native_1.Text>
1270
1048
  </TouchableScale_1.default>
1271
1049
  <react_native_1.Text style={{ color: AppColors_1.AppColors.grayTextWeak, fontSize: 11 }}>•</react_native_1.Text>
1272
1050
  <TouchableScale_1.default onPress={collapseAllFolders}>
1273
- <react_native_1.Text style={bundleStyles.treeActionLink}>Collapse</react_native_1.Text>
1051
+ <react_native_1.Text style={bundleStyles.treeActionLink}>{t('bundle.collapse')}</react_native_1.Text>
1274
1052
  </TouchableScale_1.default>
1275
1053
  </react_native_1.View>) : (<react_native_1.Text style={bundleStyles.listHeaderCount}>
1276
- Showing {filteredFiles.length} of {BUNDLE_FILES_DATA.length} files
1054
+ {t('bundle.showingFilesOf', {
1055
+ shown: filteredFiles.length,
1056
+ total: bundleFiles.length,
1057
+ })}
1277
1058
  </react_native_1.Text>)}
1278
1059
  </react_native_1.View>
1279
1060
 
@@ -1298,9 +1079,9 @@ const BundleTab = react_1.default.memo(() => {
1298
1079
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
1299
1080
  <HighlightText_1.default text={file.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
1300
1081
  {isUnused ? (<react_native_1.View style={bundleStyles.unusedBadge}>
1301
- <react_native_1.Text style={bundleStyles.unusedBadgeText}>🚫 Not Consumed</react_native_1.Text>
1082
+ <react_native_1.Text style={bundleStyles.unusedBadgeText}>{t('bundle.notConsumed')}</react_native_1.Text>
1302
1083
  </react_native_1.View>) : (<react_native_1.View style={bundleStyles.consumedBadge}>
1303
- <react_native_1.Text style={bundleStyles.consumedBadgeText}>⚡ Consumed</react_native_1.Text>
1084
+ <react_native_1.Text style={bundleStyles.consumedBadgeText}>{t('bundle.consumed')}</react_native_1.Text>
1304
1085
  </react_native_1.View>)}
1305
1086
  </react_native_1.View>
1306
1087
  <HighlightText_1.default text={file.path} search={search} style={bundleStyles.filePath} highlightStyle={bundleStyles.searchHighlight} numberOfLines={1}/>
@@ -1308,14 +1089,14 @@ const BundleTab = react_1.default.memo(() => {
1308
1089
 
1309
1090
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1310
1091
  <react_native_1.View style={bundleStyles.fileSizeBox}>
1311
- <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: '#B45309' }]}>
1092
+ <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: AppColors_1.AppColors.amber800Warm }]}>
1312
1093
  {file.sizeKb >= 1024
1313
- ? `${(file.sizeKb / 1024).toFixed(2)} MB`
1314
- : `${file.sizeKb} KB`}
1094
+ ? t('bundle.fileSizeMb', { size: (file.sizeKb / 1024).toFixed(2) })
1095
+ : t('bundle.fileSizeKb', { size: file.sizeKb })}
1315
1096
  </react_native_1.Text>
1316
1097
  <react_native_1.Text style={bundleStyles.filePercent}>{pctOfTotal}%</react_native_1.Text>
1317
1098
  </react_native_1.View>
1318
- <CopyButton_1.default value={() => file} label="File Details JSON"/>
1099
+ <CopyButton_1.default value={() => file} label={t('bundle.fileDetailsJson')}/>
1319
1100
  </react_native_1.View>
1320
1101
  </react_native_1.View>
1321
1102
 
@@ -1324,7 +1105,7 @@ const BundleTab = react_1.default.memo(() => {
1324
1105
  bundleStyles.fileProgressBar,
1325
1106
  {
1326
1107
  width: `${Math.min(100, Math.max(4, Number(pctOfTotal) * 4))}%`,
1327
- backgroundColor: isUnused ? '#EF4444' : categoryMeta.color,
1108
+ backgroundColor: isUnused ? AppColors_1.AppColors.red500 : categoryMeta.color,
1328
1109
  },
1329
1110
  ]}/>
1330
1111
  </react_native_1.View>
@@ -1339,9 +1120,9 @@ const BundleTab = react_1.default.memo(() => {
1339
1120
  ]}>
1340
1121
  <react_native_1.Text style={[
1341
1122
  bundleStyles.adviceText,
1342
- file.status === 'warning' && { color: '#B45309' },
1343
- file.status === 'optimal' && { color: '#047857' },
1344
- isUnused && { color: '#DC2626' },
1123
+ file.status === 'warning' && { color: AppColors_1.AppColors.amber800Warm },
1124
+ file.status === 'optimal' && { color: AppColors_1.AppColors.emerald700 },
1125
+ isUnused && { color: AppColors_1.AppColors.red600 },
1345
1126
  ]}>
1346
1127
  {isUnused ? '🗑️ ' : file.status === 'warning' ? '💡 ' : '✨ '}
1347
1128
  {file.advice}
@@ -1357,11 +1138,17 @@ const BundleTab = react_1.default.memo(() => {
1357
1138
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1358
1139
  <NetworkIcons_1.LayersIcon color={AppColors_1.AppColors.purple} size={14}/>
1359
1140
  <react_native_1.Text style={bundleStyles.footerTitle}>
1360
- {filteredFiles.length} of {summary.totalCount} Files
1141
+ {t('bundle.filesOf', {
1142
+ count: filteredFiles.length,
1143
+ total: summary.totalCount,
1144
+ })}
1361
1145
  </react_native_1.Text>
1362
1146
  </react_native_1.View>
1363
1147
  <react_native_1.Text style={bundleStyles.footerSizeVal}>
1364
- {filteredTotalKb} KB ({(filteredTotalKb / 1024).toFixed(2)} MB)
1148
+ {t('bundle.kbMbValue', {
1149
+ kb: filteredTotalKb,
1150
+ mb: (filteredTotalKb / 1024).toFixed(2),
1151
+ })}
1365
1152
  </react_native_1.Text>
1366
1153
  </react_native_1.View>
1367
1154
  </react_native_1.View>)}
@@ -1369,28 +1156,29 @@ const BundleTab = react_1.default.memo(() => {
1369
1156
  {/* ══════════════════════════════════════════════════════════════════════ */}
1370
1157
  {/* ── 3. TAB: PACKAGES & NODE_MODULES ─────────────────────────────────── */}
1371
1158
  {/* ══════════════════════════════════════════════════════════════════════ */}
1372
- {activeSubTab === 'packages' && (<react_native_1.View style={{ flex: 1 }}>
1159
+ {activeSubTab === 'packages' && !isAnalyzing && (<react_native_1.View style={{ flex: 1 }}>
1373
1160
  <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
1374
1161
 
1375
1162
  <react_native_1.View style={bundleStyles.filterContainer}>
1376
1163
  <react_native_1.View style={bundleStyles.searchRow}>
1377
1164
  <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={15}/>
1378
- <react_native_1.TextInput placeholder="Search package (react-native, axios, navigation)..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1165
+ <react_native_1.TextInput placeholder={t('bundle.searchPackagesPlaceholder')} placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1379
1166
  {search.length > 0 && (<react_native_1.Pressable onPress={() => setSearch('')} hitSlop={10}>
1380
1167
  <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
1381
1168
  </react_native_1.Pressable>)}
1382
- <CopyButton_1.default value={() => filteredPackages} label="Dependencies JSON"/>
1169
+ <CopyButton_1.default value={() => filteredPackages} label={t('bundle.dependenciesJson')}/>
1383
1170
  </react_native_1.View>
1384
1171
  </react_native_1.View>
1385
1172
 
1386
1173
  <react_native_1.Text style={bundleStyles.listHeaderCount}>
1387
- Showing {filteredPackages.length} dependencies
1174
+ {t('bundle.showingDependencies', { count: filteredPackages.length })}
1388
1175
  </react_native_1.Text>
1389
1176
 
1390
1177
  {filteredPackages.map((pkg, index) => {
1391
- const cleanInstalledVersion = pkg.version.replace(/^\^/, '');
1392
- const hasUpdate = pkg.latestVersion && pkg.latestVersion !== cleanInstalledVersion;
1393
- return (<react_native_1.View key={pkg.id} style={[bundleStyles.fileCard, pkg.isDeprecated && { borderColor: '#FECDD3', backgroundColor: '#FFFDFD' }]}>
1178
+ const cleanInstalledVersion = pkg.version ? pkg.version.replace(/^\^/, '') : '';
1179
+ const hasUpdate = !!pkg.latestVersion && !!cleanInstalledVersion &&
1180
+ pkg.latestVersion !== cleanInstalledVersion;
1181
+ return (<react_native_1.View key={pkg.id} style={[bundleStyles.fileCard, pkg.isDeprecated && { borderColor: AppColors_1.AppColors.errorBorder, backgroundColor: '#FFFDFD' }]}>
1394
1182
  {/* Header Row: #s.no + Logo + Package Name + Version Pill + Update/Deprecated Badges + Size & Copy */}
1395
1183
  <react_native_1.View style={bundleStyles.fileCardTop}>
1396
1184
  <react_native_1.View style={bundleStyles.sNoBadge}>
@@ -1404,26 +1192,40 @@ const BundleTab = react_1.default.memo(() => {
1404
1192
  <HighlightText_1.default text={pkg.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
1405
1193
  <react_native_1.View style={bundleStyles.versionPill}>
1406
1194
  <react_native_1.Text style={bundleStyles.versionPillText}>
1407
- v{cleanInstalledVersion}
1195
+ {cleanInstalledVersion
1196
+ ? t('bundle.versionPrefix', { version: cleanInstalledVersion })
1197
+ : t('bundle.bundled')}
1408
1198
  </react_native_1.Text>
1409
1199
  </react_native_1.View>
1410
1200
 
1411
1201
  {pkg.isDeprecated ? (<react_native_1.View style={bundleStyles.deprecatedBadge}>
1412
- <react_native_1.Text style={bundleStyles.deprecatedBadgeText}>⚠️ DEPRECATED</react_native_1.Text>
1202
+ <react_native_1.Text style={bundleStyles.deprecatedBadgeText}>
1203
+ {t('bundle.deprecated')}
1204
+ </react_native_1.Text>
1413
1205
  </react_native_1.View>) : hasUpdate ? (<react_native_1.View style={bundleStyles.updateBadge}>
1414
- <react_native_1.Text style={bundleStyles.updateBadgeText}>⚡ Update: v{pkg.latestVersion}</react_native_1.Text>
1415
- </react_native_1.View>) : (<react_native_1.View style={[bundleStyles.updateBadge, { backgroundColor: '#F3F4F6', borderColor: '#E5E7EB' }]}>
1416
- <react_native_1.Text style={[bundleStyles.updateBadgeText, { color: '#4B5563' }]}>✨ Up to date</react_native_1.Text>
1206
+ <react_native_1.Text style={bundleStyles.updateBadgeText}>
1207
+ {t('bundle.updateAvailable', { version: pkg.latestVersion })}
1208
+ </react_native_1.Text>
1209
+ </react_native_1.View>) : cleanInstalledVersion ? (<react_native_1.View style={[bundleStyles.updateBadge, { backgroundColor: AppColors_1.AppColors.gray100, borderColor: AppColors_1.AppColors.gray200 }]}>
1210
+ <react_native_1.Text style={[bundleStyles.updateBadgeText, { color: AppColors_1.AppColors.gray600 }]}>
1211
+ {t('bundle.upToDate')}
1212
+ </react_native_1.Text>
1213
+ </react_native_1.View>) : (<react_native_1.View style={[bundleStyles.updateBadge, { backgroundColor: AppColors_1.AppColors.gray100, borderColor: AppColors_1.AppColors.gray200 }]}>
1214
+ <react_native_1.Text style={[bundleStyles.updateBadgeText, { color: AppColors_1.AppColors.gray600 }]}>
1215
+ {t('bundle.bundledBadge')}
1216
+ </react_native_1.Text>
1417
1217
  </react_native_1.View>)}
1418
1218
  </react_native_1.View>
1419
1219
  </react_native_1.View>
1420
1220
 
1421
1221
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1422
1222
  <react_native_1.View style={bundleStyles.fileSizeBox}>
1423
- <react_native_1.Text style={bundleStyles.fileSizeKb}>{pkg.sizeKb} KB</react_native_1.Text>
1223
+ <react_native_1.Text style={bundleStyles.fileSizeKb}>
1224
+ {t('bundle.fileSizeKb', { size: pkg.sizeKb })}
1225
+ </react_native_1.Text>
1424
1226
  <react_native_1.Text style={bundleStyles.filePercent}>{pkg.percentage}%</react_native_1.Text>
1425
1227
  </react_native_1.View>
1426
- <CopyButton_1.default value={() => pkg} label="Package Details JSON"/>
1228
+ <CopyButton_1.default value={() => pkg} label={t('bundle.packageDetailsJson')}/>
1427
1229
  </react_native_1.View>
1428
1230
  </react_native_1.View>
1429
1231
 
@@ -1449,7 +1251,7 @@ const BundleTab = react_1.default.memo(() => {
1449
1251
  <react_native_1.View style={bundleStyles.fileProgressTrack}>
1450
1252
  <react_native_1.View style={[
1451
1253
  bundleStyles.fileProgressBar,
1452
- { width: `${pkg.percentage * 2}%`, backgroundColor: pkg.isDeprecated ? '#EF4444' : pkg.color },
1254
+ { width: `${pkg.percentage * 2}%`, backgroundColor: pkg.isDeprecated ? AppColors_1.AppColors.red500 : pkg.color },
1453
1255
  ]}/>
1454
1256
  </react_native_1.View>
1455
1257
 
@@ -1458,7 +1260,7 @@ const BundleTab = react_1.default.memo(() => {
1458
1260
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1459
1261
  <react_native_1.View style={bundleStyles.typeTag}>
1460
1262
  <react_native_1.Text style={bundleStyles.typeTagText}>
1461
- {pkg.type === 'direct' ? '📦 Direct' : '🔗 Transitive'}
1263
+ {pkg.type === 'direct' ? t('bundle.direct') : t('bundle.transitive')}
1462
1264
  </react_native_1.Text>
1463
1265
  </react_native_1.View>
1464
1266
  {pkg.lastActive && (<react_native_1.Text style={bundleStyles.lastActiveText}>
@@ -1468,13 +1270,13 @@ const BundleTab = react_1.default.memo(() => {
1468
1270
 
1469
1271
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1470
1272
  <react_native_1.Text style={bundleStyles.fileMetaText}>
1471
- ~{pkg.sizeKb} KB minified
1273
+ {t('bundle.minified', { size: pkg.sizeKb })}
1472
1274
  </react_native_1.Text>
1473
1275
  <TouchableScale_1.default onPress={() => {
1474
1276
  const url = pkg.npmUrl || `https://www.npmjs.com/package/${pkg.name}`;
1475
1277
  react_native_1.Linking.openURL(url).catch(() => { });
1476
1278
  }} style={bundleStyles.npmLinkBtn}>
1477
- <react_native_1.Text style={bundleStyles.npmLinkText}>npm ↗</react_native_1.Text>
1279
+ <react_native_1.Text style={bundleStyles.npmLinkText}>{t('bundle.npmLink')}</react_native_1.Text>
1478
1280
  </TouchableScale_1.default>
1479
1281
  </react_native_1.View>
1480
1282
  </react_native_1.View>
@@ -1487,11 +1289,14 @@ const BundleTab = react_1.default.memo(() => {
1487
1289
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1488
1290
  <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.purple} size={14}/>
1489
1291
  <react_native_1.Text style={bundleStyles.footerTitle}>
1490
- {filteredPackages.length} Dependencies
1292
+ {t('bundle.dependenciesCount', { count: filteredPackages.length })}
1491
1293
  </react_native_1.Text>
1492
1294
  </react_native_1.View>
1493
1295
  <react_native_1.Text style={bundleStyles.footerSizeVal}>
1494
- {packagesTotalKb} KB ({(packagesTotalKb / 1024).toFixed(2)} MB)
1296
+ {t('bundle.kbMbValue', {
1297
+ kb: packagesTotalKb,
1298
+ mb: (packagesTotalKb / 1024).toFixed(2),
1299
+ })}
1495
1300
  </react_native_1.Text>
1496
1301
  </react_native_1.View>
1497
1302
  </react_native_1.View>)}
@@ -1499,24 +1304,32 @@ const BundleTab = react_1.default.memo(() => {
1499
1304
  {/* ══════════════════════════════════════════════════════════════════════ */}
1500
1305
  {/* ── 4. TAB: MEDIA & ASSET AUDITOR ───────────────────────────────────── */}
1501
1306
  {/* ══════════════════════════════════════════════════════════════════════ */}
1502
- {activeSubTab === 'media' && (<react_native_1.View style={{ flex: 1 }}>
1307
+ {activeSubTab === 'media' && !isAnalyzing && (<react_native_1.View style={{ flex: 1 }}>
1503
1308
  <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
1504
1309
 
1505
1310
  <react_native_1.View style={bundleStyles.tipsCard}>
1506
1311
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
1507
1312
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1508
1313
  <NetworkIcons_1.StorageIcon color={AppColors_1.AppColors.purple} size={18}/>
1509
- <react_native_1.Text style={bundleStyles.tipsHeading}>Media Compression Auditor</react_native_1.Text>
1314
+ <react_native_1.Text style={bundleStyles.tipsHeading}>{t('bundle.mediaAuditorTitle')}</react_native_1.Text>
1510
1315
  </react_native_1.View>
1511
- <CopyButton_1.default value={() => mediaFiles} label="Media Assets JSON"/>
1316
+ <CopyButton_1.default value={() => mediaFiles} label={t('bundle.mediaAssetsJson')}/>
1512
1317
  </react_native_1.View>
1513
1318
  <react_native_1.Text style={bundleStyles.tipDesc}>
1514
- Images & Fonts constitute <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.purple }}>{summary.images.pct + summary.fonts.pct}%</react_native_1.Text> of total assets (~{summary.images.kb + summary.fonts.kb} KB). Converting PNGs to WebP and font subsetting can reduce size by up to <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, color: '#047857' }}>540 KB</react_native_1.Text>.
1319
+ {t('bundle.mediaAuditorPrefix')}{' '}
1320
+ <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.purple }}>
1321
+ {summary.images.pct + summary.fonts.pct}%
1322
+ </react_native_1.Text>{' '}
1323
+ {t('bundle.mediaAuditorMid', { kb: summary.images.kb + summary.fonts.kb })}{' '}
1324
+ <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.emerald700 }}>
1325
+ {t('bundle.mediaSavings', { size: 540 })}
1326
+ </react_native_1.Text>{' '}
1327
+ {t('bundle.mediaAuditorSuffix')}
1515
1328
  </react_native_1.Text>
1516
1329
  </react_native_1.View>
1517
1330
 
1518
1331
  <react_native_1.Text style={bundleStyles.listHeaderCount}>
1519
- Media Assets & Fonts ({mediaFiles.length} items)
1332
+ {t('bundle.mediaAssetsList', { count: mediaFiles.length })}
1520
1333
  </react_native_1.Text>
1521
1334
 
1522
1335
  {mediaFiles.map((file, index) => (<react_native_1.View key={file.id} style={bundleStyles.fileCard}>
@@ -1534,9 +1347,11 @@ const BundleTab = react_1.default.memo(() => {
1534
1347
 
1535
1348
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1536
1349
  <react_native_1.View style={bundleStyles.fileSizeBox}>
1537
- <react_native_1.Text style={bundleStyles.fileSizeKb}>{file.sizeKb} KB</react_native_1.Text>
1350
+ <react_native_1.Text style={bundleStyles.fileSizeKb}>
1351
+ {t('bundle.fileSizeKb', { size: file.sizeKb })}
1352
+ </react_native_1.Text>
1538
1353
  </react_native_1.View>
1539
- <CopyButton_1.default value={() => file} label="Media Item JSON"/>
1354
+ <CopyButton_1.default value={() => file} label={t('bundle.mediaItemJson')}/>
1540
1355
  </react_native_1.View>
1541
1356
  </react_native_1.View>
1542
1357
 
@@ -1549,8 +1364,8 @@ const BundleTab = react_1.default.memo(() => {
1549
1364
  ]}>
1550
1365
  <react_native_1.Text style={[
1551
1366
  bundleStyles.adviceText,
1552
- file.status === 'warning' && { color: '#B45309' },
1553
- file.status === 'optimal' && { color: '#047857' },
1367
+ file.status === 'warning' && { color: AppColors_1.AppColors.amber800Warm },
1368
+ file.status === 'optimal' && { color: AppColors_1.AppColors.emerald700 },
1554
1369
  ]}>
1555
1370
  {file.status === 'warning' ? '💡 ' : '✨ '}
1556
1371
  {file.advice}
@@ -1565,11 +1380,14 @@ const BundleTab = react_1.default.memo(() => {
1565
1380
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1566
1381
  <NetworkIcons_1.StorageIcon color={AppColors_1.AppColors.purple} size={14}/>
1567
1382
  <react_native_1.Text style={bundleStyles.footerTitle}>
1568
- {mediaFiles.length} Media & Fonts
1383
+ {t('bundle.mediaAndFonts', { count: mediaFiles.length })}
1569
1384
  </react_native_1.Text>
1570
1385
  </react_native_1.View>
1571
1386
  <react_native_1.Text style={bundleStyles.footerSizeVal}>
1572
- {mediaTotalKb} KB ({(mediaTotalKb / 1024).toFixed(2)} MB)
1387
+ {t('bundle.kbMbValue', {
1388
+ kb: mediaTotalKb,
1389
+ mb: (mediaTotalKb / 1024).toFixed(2),
1390
+ })}
1573
1391
  </react_native_1.Text>
1574
1392
  </react_native_1.View>
1575
1393
  </react_native_1.View>)}
@@ -1583,49 +1401,49 @@ const BundleTab = react_1.default.memo(() => {
1583
1401
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
1584
1402
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1585
1403
  <NetworkIcons_1.CircleAlertIcon color={AppColors_1.AppColors.purple} size={18}/>
1586
- <react_native_1.Text style={bundleStyles.tipsHeading}>React Native Bundle Optimization Checklist</react_native_1.Text>
1404
+ <react_native_1.Text style={bundleStyles.tipsHeading}>{t('bundle.optimizerTitle')}</react_native_1.Text>
1587
1405
  </react_native_1.View>
1588
1406
  <CopyButton_1.default value={() => [
1589
- 'Convert Heavy PNGs to WebP / SVGs (High Impact)',
1590
- `Enable Hermes Bytecode Engine (${isHermes ? 'Active' : 'Action Required'})`,
1591
- 'Font Subsetting & Weight Pruning (Medium Impact)',
1592
- 'Selective Path Imports Tree-shaking (Best Practice)',
1593
- 'Screen Lazy-Loading (Best Practice)',
1594
- ]} label="Optimization Checklist"/>
1407
+ t('bundle.optTip1Title'),
1408
+ `${t('bundle.optTip2Title')} (${isHermes ? t('bundle.active') : t('bundle.actionRequired')})`,
1409
+ t('bundle.optTip3Title'),
1410
+ t('bundle.optTip4Title'),
1411
+ t('bundle.optTip5Title'),
1412
+ ]} label={t('bundle.optimizationChecklist')}/>
1595
1413
  </react_native_1.View>
1596
1414
 
1597
1415
  {[
1598
1416
  {
1599
- title: '🖼️ Convert Heavy PNGs to WebP / SVGs',
1600
- desc: 'Images account for >40% of final app download size. Converting 2x/3x raster PNGs to WebP saves 60-70% size with no visible fidelity loss.',
1601
- badge: 'High Impact',
1602
- badgeColor: '#EC4899',
1417
+ title: t('bundle.optTip1Title'),
1418
+ desc: t('bundle.optTip1Desc'),
1419
+ badge: t('bundle.highImpact'),
1420
+ badgeColor: AppColors_1.AppColors.pink500,
1603
1421
  },
1604
1422
  {
1605
- title: '📜 Enable Hermes Bytecode Engine',
1423
+ title: t('bundle.optTip2Title'),
1606
1424
  desc: isHermes
1607
- ? '✅ Hermes is active! JavaScript is compiled into optimized bytecode Ahead-Of-Time.'
1608
- : '⚠️ Hermes is disabled. Enable hermes in your app config for ~40% smaller payload and instant TTI startup.',
1609
- badge: isHermes ? 'Active' : 'Action Required',
1610
- badgeColor: isHermes ? '#10B981' : '#F59E0B',
1425
+ ? t('bundle.optTip2DescActive')
1426
+ : t('bundle.optTip2DescInactive'),
1427
+ badge: isHermes ? t('bundle.active') : t('bundle.actionRequired'),
1428
+ badgeColor: isHermes ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.amber500,
1611
1429
  },
1612
1430
  {
1613
- title: '🔤 Font Subsetting & Weight Pruning',
1614
- desc: 'Include only the font weights you actively use (e.g. Regular & Bold). Remove unused glyph ranges to save 100KB+ per font file.',
1615
- badge: 'Medium Impact',
1616
- badgeColor: '#8B5CF6',
1431
+ title: t('bundle.optTip3Title'),
1432
+ desc: t('bundle.optTip3Desc'),
1433
+ badge: t('bundle.mediumImpact'),
1434
+ badgeColor: AppColors_1.AppColors.purple500,
1617
1435
  },
1618
1436
  {
1619
- title: '🌲 Selective Path Imports (Tree-shaking)',
1620
- desc: 'Import from specific subpaths (e.g. lodash/get or specific vector icon sets) instead of importing large monolithic packages.',
1621
- badge: 'Best Practice',
1622
- badgeColor: '#0EA5E9',
1437
+ title: t('bundle.optTip4Title'),
1438
+ desc: t('bundle.optTip4Desc'),
1439
+ badge: t('bundle.bestPractice'),
1440
+ badgeColor: AppColors_1.AppColors.sky500,
1623
1441
  },
1624
1442
  {
1625
- title: '⚡ Screen Lazy-Loading',
1626
- desc: 'Lazy load secondary screens and heavy modal sheets using dynamic imports and InteractionManager to reduce initial bundle evaluation.',
1627
- badge: 'Best Practice',
1628
- badgeColor: '#6366F1',
1443
+ title: t('bundle.optTip5Title'),
1444
+ desc: t('bundle.optTip5Desc'),
1445
+ badge: t('bundle.bestPractice'),
1446
+ badgeColor: AppColors_1.AppColors.indigo500,
1629
1447
  },
1630
1448
  ].map((tip, tIdx) => (<react_native_1.View key={tIdx} style={bundleStyles.tipItem}>
1631
1449
  <react_native_1.View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 2 }}>
@@ -1641,7 +1459,7 @@ const BundleTab = react_1.default.memo(() => {
1641
1459
  {tip.badge}
1642
1460
  </react_native_1.Text>
1643
1461
  </react_native_1.View>
1644
- <CopyButton_1.default value={() => tip} label="Tip Details"/>
1462
+ <CopyButton_1.default value={() => tip} label={t('bundle.tipDetails')}/>
1645
1463
  </react_native_1.View>
1646
1464
  </react_native_1.View>
1647
1465
  <react_native_1.Text style={bundleStyles.tipDesc}>{tip.desc}</react_native_1.Text>
@@ -1657,6 +1475,23 @@ const bundleStyles = react_native_1.StyleSheet.create({
1657
1475
  borderBottomWidth: 1,
1658
1476
  borderBottomColor: AppColors_1.AppColors.dividerColor,
1659
1477
  },
1478
+ analyzingContainer: {
1479
+ flex: 1,
1480
+ alignItems: 'center',
1481
+ justifyContent: 'center',
1482
+ gap: 8,
1483
+ padding: 24,
1484
+ },
1485
+ analyzingText: {
1486
+ fontFamily: AppFonts_1.AppFonts.interBold,
1487
+ fontSize: 13,
1488
+ color: AppColors_1.AppColors.primaryBlack,
1489
+ },
1490
+ analyzingHint: {
1491
+ fontFamily: AppFonts_1.AppFonts.interRegular,
1492
+ fontSize: 11,
1493
+ color: AppColors_1.AppColors.grayTextWeak,
1494
+ },
1660
1495
  subTabsScroll: {
1661
1496
  paddingHorizontal: 12,
1662
1497
  gap: 8,
@@ -2212,41 +2047,41 @@ const bundleStyles = react_native_1.StyleSheet.create({
2212
2047
  paddingHorizontal: 7,
2213
2048
  paddingVertical: 2,
2214
2049
  borderRadius: 5,
2215
- backgroundColor: '#CB383714',
2050
+ backgroundColor: AppColors_1.AppColors.npmRedTint,
2216
2051
  borderWidth: 1,
2217
- borderColor: '#CB383733',
2052
+ borderColor: AppColors_1.AppColors.npmRedBorder,
2218
2053
  },
2219
2054
  npmLinkText: {
2220
2055
  fontFamily: AppFonts_1.AppFonts.interBold,
2221
2056
  fontSize: 9.5,
2222
- color: '#CB3837',
2057
+ color: AppColors_1.AppColors.npmRed,
2223
2058
  },
2224
2059
  deprecatedBadge: {
2225
2060
  paddingHorizontal: 6,
2226
2061
  paddingVertical: 1.5,
2227
2062
  borderRadius: 4,
2228
- backgroundColor: '#FEE2E2',
2063
+ backgroundColor: AppColors_1.AppColors.red100,
2229
2064
  borderWidth: 1,
2230
- borderColor: '#FECACA',
2065
+ borderColor: AppColors_1.AppColors.errorBorder,
2231
2066
  },
2232
2067
  deprecatedBadgeText: {
2233
2068
  fontFamily: AppFonts_1.AppFonts.interBold,
2234
2069
  fontSize: 9,
2235
- color: '#DC2626',
2070
+ color: AppColors_1.AppColors.red600,
2236
2071
  letterSpacing: 0.3,
2237
2072
  },
2238
2073
  updateBadge: {
2239
2074
  paddingHorizontal: 6,
2240
2075
  paddingVertical: 1.5,
2241
2076
  borderRadius: 4,
2242
- backgroundColor: '#DCFCE7',
2077
+ backgroundColor: AppColors_1.AppColors.green100,
2243
2078
  borderWidth: 1,
2244
- borderColor: '#BBF7D0',
2079
+ borderColor: AppColors_1.AppColors.greenBorder,
2245
2080
  },
2246
2081
  updateBadgeText: {
2247
2082
  fontFamily: AppFonts_1.AppFonts.interBold,
2248
2083
  fontSize: 9,
2249
- color: '#047857',
2084
+ color: AppColors_1.AppColors.emerald700,
2250
2085
  },
2251
2086
  lastActiveText: {
2252
2087
  fontFamily: AppFonts_1.AppFonts.interRegular,
@@ -2254,45 +2089,45 @@ const bundleStyles = react_native_1.StyleSheet.create({
2254
2089
  color: AppColors_1.AppColors.grayTextWeak,
2255
2090
  },
2256
2091
  deprecationBox: {
2257
- backgroundColor: '#FFF1F2',
2092
+ backgroundColor: AppColors_1.AppColors.errorCardBg,
2258
2093
  borderRadius: 6,
2259
2094
  paddingHorizontal: 8,
2260
2095
  paddingVertical: 5,
2261
2096
  borderWidth: 1,
2262
- borderColor: '#FECDD3',
2097
+ borderColor: AppColors_1.AppColors.errorBorder,
2263
2098
  marginTop: 3,
2264
2099
  },
2265
2100
  deprecationText: {
2266
2101
  fontFamily: AppFonts_1.AppFonts.interMedium,
2267
2102
  fontSize: 10.5,
2268
- color: '#BE123C',
2103
+ color: AppColors_1.AppColors.rose700,
2269
2104
  lineHeight: 14,
2270
2105
  },
2271
2106
  unusedBadge: {
2272
2107
  paddingHorizontal: 6,
2273
2108
  paddingVertical: 1.5,
2274
2109
  borderRadius: 4,
2275
- backgroundColor: '#FEE2E2',
2110
+ backgroundColor: AppColors_1.AppColors.red100,
2276
2111
  borderWidth: 1,
2277
- borderColor: '#FECACA',
2112
+ borderColor: AppColors_1.AppColors.errorBorder,
2278
2113
  },
2279
2114
  unusedBadgeText: {
2280
2115
  fontFamily: AppFonts_1.AppFonts.interBold,
2281
2116
  fontSize: 9.5,
2282
- color: '#DC2626',
2117
+ color: AppColors_1.AppColors.red600,
2283
2118
  },
2284
2119
  consumedBadge: {
2285
2120
  paddingHorizontal: 6,
2286
2121
  paddingVertical: 1.5,
2287
2122
  borderRadius: 4,
2288
- backgroundColor: '#DCFCE7',
2123
+ backgroundColor: AppColors_1.AppColors.green100,
2289
2124
  borderWidth: 1,
2290
- borderColor: '#BBF7D0',
2125
+ borderColor: AppColors_1.AppColors.greenBorder,
2291
2126
  },
2292
2127
  consumedBadgeText: {
2293
2128
  fontFamily: AppFonts_1.AppFonts.interBold,
2294
2129
  fontSize: 9.5,
2295
- color: '#059669',
2130
+ color: AppColors_1.AppColors.emerald600,
2296
2131
  },
2297
2132
  treeFolderChevronWrap: {
2298
2133
  width: 18,
@@ -2303,13 +2138,13 @@ const bundleStyles = react_native_1.StyleSheet.create({
2303
2138
  justifyContent: 'center',
2304
2139
  },
2305
2140
  treeFileCardUnused: {
2306
- borderColor: '#FECACA',
2307
- backgroundColor: '#FFFBFB',
2141
+ borderColor: AppColors_1.AppColors.errorBorder,
2142
+ backgroundColor: AppColors_1.AppColors.red50,
2308
2143
  },
2309
2144
  adviceUnused: {
2310
- backgroundColor: '#FEF2F2',
2145
+ backgroundColor: AppColors_1.AppColors.errorCardBg,
2311
2146
  borderWidth: 1,
2312
- borderColor: '#FECACA',
2147
+ borderColor: AppColors_1.AppColors.errorBorder,
2313
2148
  },
2314
2149
  adviceBadge: {
2315
2150
  paddingHorizontal: 8,
@@ -2318,14 +2153,14 @@ const bundleStyles = react_native_1.StyleSheet.create({
2318
2153
  marginTop: 2,
2319
2154
  },
2320
2155
  adviceWarning: {
2321
- backgroundColor: '#FEF3C7',
2156
+ backgroundColor: AppColors_1.AppColors.amber100,
2322
2157
  borderWidth: 1,
2323
- borderColor: '#FDE68A',
2158
+ borderColor: AppColors_1.AppColors.amber200,
2324
2159
  },
2325
2160
  adviceOptimal: {
2326
- backgroundColor: '#DCFCE7',
2161
+ backgroundColor: AppColors_1.AppColors.green100,
2327
2162
  borderWidth: 1,
2328
- borderColor: '#BBF7D0',
2163
+ borderColor: AppColors_1.AppColors.greenBorder,
2329
2164
  },
2330
2165
  adviceText: {
2331
2166
  fontFamily: AppFonts_1.AppFonts.interMedium,
@@ -2343,21 +2178,21 @@ const bundleStyles = react_native_1.StyleSheet.create({
2343
2178
  fontSize: 9,
2344
2179
  },
2345
2180
  searchHighlight: {
2346
- backgroundColor: '#FEF08A',
2347
- color: '#854D0E',
2181
+ backgroundColor: AppColors_1.AppColors.yellow200,
2182
+ color: AppColors_1.AppColors.yellow800,
2348
2183
  fontFamily: AppFonts_1.AppFonts.interBold,
2349
2184
  },
2350
2185
  tipsCard: {
2351
- backgroundColor: '#FAF5FF',
2186
+ backgroundColor: AppColors_1.AppColors.purple50,
2352
2187
  borderRadius: 14,
2353
2188
  padding: 14,
2354
2189
  borderWidth: 1,
2355
- borderColor: '#E9D5FF',
2190
+ borderColor: AppColors_1.AppColors.purple200,
2356
2191
  },
2357
2192
  tipsHeading: {
2358
2193
  fontFamily: AppFonts_1.AppFonts.interBold,
2359
2194
  fontSize: 13.5,
2360
- color: '#6B21A8',
2195
+ color: AppColors_1.AppColors.purple800,
2361
2196
  },
2362
2197
  totalSummaryCard: {
2363
2198
  marginTop: 10,
@@ -2421,17 +2256,17 @@ const bundleStyles = react_native_1.StyleSheet.create({
2421
2256
  padding: 10,
2422
2257
  borderRadius: 8,
2423
2258
  borderWidth: 1,
2424
- borderColor: '#E9D5FF',
2259
+ borderColor: AppColors_1.AppColors.purple200,
2425
2260
  },
2426
2261
  tipTitle: {
2427
2262
  fontFamily: AppFonts_1.AppFonts.interBold,
2428
2263
  fontSize: 12,
2429
- color: '#581C87',
2264
+ color: AppColors_1.AppColors.purple900,
2430
2265
  },
2431
2266
  tipDesc: {
2432
2267
  fontFamily: AppFonts_1.AppFonts.interRegular,
2433
2268
  fontSize: 11,
2434
- color: '#6B7280',
2269
+ color: AppColors_1.AppColors.gray500,
2435
2270
  lineHeight: 16,
2436
2271
  marginTop: 4,
2437
2272
  },