react-native-inapp-inspector 1.1.21 → 1.1.23

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 (49) 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 +89 -97
  4. package/dist/commonjs/components/ErrorBoundary.js +17 -8
  5. package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -0
  6. package/dist/commonjs/components/Inspector/BundleTab.js +607 -685
  7. package/dist/commonjs/components/Inspector/LogDetail.js +12 -6
  8. package/dist/commonjs/components/Inspector/PerformanceTab.js +195 -254
  9. package/dist/commonjs/components/Inspector/ReduxDetail.js +2 -2
  10. package/dist/commonjs/components/Inspector/ReduxTab.js +9 -6
  11. package/dist/commonjs/components/NetworkIcons.d.ts +12 -0
  12. package/dist/commonjs/components/NetworkIcons.js +92 -1
  13. package/dist/commonjs/components/TreeNode.js +1 -1
  14. package/dist/commonjs/constants/version.d.ts +1 -1
  15. package/dist/commonjs/constants/version.js +1 -1
  16. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +115 -0
  17. package/dist/commonjs/customHooks/bundleAnalyzer.js +561 -0
  18. package/dist/commonjs/customHooks/performanceTracker.d.ts +84 -0
  19. package/dist/commonjs/customHooks/performanceTracker.js +541 -0
  20. package/dist/commonjs/helpers/index.d.ts +15 -0
  21. package/dist/commonjs/helpers/index.js +112 -1
  22. package/dist/commonjs/i18n/locales/en.json +225 -2
  23. package/dist/commonjs/styles/AppColors.d.ts +110 -0
  24. package/dist/commonjs/styles/AppColors.js +114 -0
  25. package/dist/esm/components/AnalyticsDetail.js +5 -3
  26. package/dist/esm/components/AnalyticsEventCard.d.ts +0 -1
  27. package/dist/esm/components/AnalyticsEventCard.js +89 -96
  28. package/dist/esm/components/ErrorBoundary.js +17 -8
  29. package/dist/esm/components/Inspector/BundleTab.d.ts +1 -0
  30. package/dist/esm/components/Inspector/BundleTab.js +612 -690
  31. package/dist/esm/components/Inspector/LogDetail.js +13 -7
  32. package/dist/esm/components/Inspector/PerformanceTab.js +196 -255
  33. package/dist/esm/components/Inspector/ReduxDetail.js +2 -2
  34. package/dist/esm/components/Inspector/ReduxTab.js +10 -7
  35. package/dist/esm/components/NetworkIcons.d.ts +12 -0
  36. package/dist/esm/components/NetworkIcons.js +79 -0
  37. package/dist/esm/components/TreeNode.js +2 -2
  38. package/dist/esm/constants/version.d.ts +1 -1
  39. package/dist/esm/constants/version.js +1 -1
  40. package/dist/esm/customHooks/bundleAnalyzer.d.ts +115 -0
  41. package/dist/esm/customHooks/bundleAnalyzer.js +554 -0
  42. package/dist/esm/customHooks/performanceTracker.d.ts +84 -0
  43. package/dist/esm/customHooks/performanceTracker.js +537 -0
  44. package/dist/esm/helpers/index.d.ts +15 -0
  45. package/dist/esm/helpers/index.js +107 -0
  46. package/dist/esm/i18n/locales/en.json +225 -2
  47. package/dist/esm/styles/AppColors.d.ts +110 -0
  48. package/dist/esm/styles/AppColors.js +114 -0
  49. 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,26 +142,97 @@ 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
  };
165
+ const BundleCategoryIcon = ({ type, size = 16, color = AppColors_1.AppColors.purple }) => {
166
+ const stroke = { stroke: color, strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' };
167
+ const renderGlyph = () => {
168
+ switch (type) {
169
+ case 'folder':
170
+ return (<react_native_svg_1.G>
171
+ <react_native_svg_1.Path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" {...stroke}/>
172
+ </react_native_svg_1.G>);
173
+ case 'ban':
174
+ return (<react_native_svg_1.G>
175
+ <react_native_svg_1.Circle cx="12" cy="12" r="8.5" {...stroke}/>
176
+ <react_native_svg_1.Path d="M5.5 5.5 18.5 18.5" {...stroke}/>
177
+ </react_native_svg_1.G>);
178
+ case 'bolt':
179
+ return (<react_native_svg_1.G>
180
+ <react_native_svg_1.Path d="M13 2 4.5 13.5 H10.5 L9 22 19.5 9.5 H13.5 Z" {...stroke}/>
181
+ </react_native_svg_1.G>);
182
+ case 'source':
183
+ return (<react_native_svg_1.G>
184
+ <react_native_svg_1.Path d="M8.5 7 L4 12 L8.5 17" {...stroke}/>
185
+ <react_native_svg_1.Path d="M15.5 7 L20 12 L15.5 17" {...stroke}/>
186
+ <react_native_svg_1.Path d="M13.5 4.5 L10.5 19.5" {...stroke}/>
187
+ </react_native_svg_1.G>);
188
+ case 'deps':
189
+ return (<react_native_svg_1.G>
190
+ <react_native_svg_1.Rect x="4" y="4" width="16" height="16" rx="2.5" {...stroke}/>
191
+ <react_native_svg_1.Path d="M4 9.5 H20" {...stroke}/>
192
+ <react_native_svg_1.Path d="M9.5 9.5 V20" {...stroke}/>
193
+ </react_native_svg_1.G>);
194
+ case 'media':
195
+ case 'image':
196
+ return (<react_native_svg_1.G>
197
+ <react_native_svg_1.Rect x="3.5" y="4.5" width="17" height="15" rx="2" {...stroke}/>
198
+ <react_native_svg_1.Circle cx="9" cy="10" r="1.5" {...stroke}/>
199
+ <react_native_svg_1.Path d="M3.5 17.5 L9.5 12.5 L14 16.5 L17 13.5 L20.5 17.5" {...stroke}/>
200
+ </react_native_svg_1.G>);
201
+ case 'overhead':
202
+ return (<react_native_svg_1.G>
203
+ <react_native_svg_1.Circle cx="12" cy="12" r="3.2" {...stroke}/>
204
+ <react_native_svg_1.Path d="M12 2.5 V5.5 M12 18.5 V21.5 M2.5 12 H5.5 M18.5 12 H21.5 M5.3 5.3 L7.4 7.4 M16.6 16.6 L18.7 18.7 M18.7 5.3 L16.6 7.4 M7.4 16.6 L5.3 18.7" {...stroke}/>
205
+ </react_native_svg_1.G>);
206
+ case 'typescript':
207
+ return (<react_native_svg_1.G>
208
+ <react_native_svg_1.Path d="M6.5 3.5 H14 L18.5 8 V20.5 H6.5 Z" {...stroke}/>
209
+ <react_native_svg_1.Path d="M14 3.5 V8 H18.5" {...stroke}/>
210
+ <react_native_svg_1.Path d="M9.5 13.5 H15 M12 13.5 V16.5 M9.5 16.5 H13" {...stroke}/>
211
+ </react_native_svg_1.G>);
212
+ case 'javascript':
213
+ return (<react_native_svg_1.G>
214
+ <react_native_svg_1.Path d="M9.5 3.5 C7.5 3.5 7.5 6.5 7.5 9 C7.5 11 6.5 12 5 12 C6.5 12 7.5 13 7.5 15 C7.5 17.5 7.5 20.5 9.5 20.5" {...stroke}/>
215
+ <react_native_svg_1.Path d="M14.5 3.5 C16.5 3.5 16.5 6.5 16.5 9 C16.5 11 17.5 12 19 12 C17.5 12 16.5 13 16.5 15 C16.5 17.5 16.5 20.5 14.5 20.5" {...stroke}/>
216
+ </react_native_svg_1.G>);
217
+ case 'font':
218
+ return (<react_native_svg_1.G>
219
+ <react_native_svg_1.Path d="M8 19 L12 5.5 L16 19" {...stroke}/>
220
+ <react_native_svg_1.Path d="M9.4 14.5 H14.6" {...stroke}/>
221
+ </react_native_svg_1.G>);
222
+ case 'json':
223
+ return (<react_native_svg_1.G>
224
+ <react_native_svg_1.Path d="M9 3.5 C7 3.5 7 6 7 8.5 C7 10.5 6 11.5 5 12 C6 12.5 7 13.5 7 15.5 C7 18 7 20.5 9 20.5" {...stroke}/>
225
+ <react_native_svg_1.Circle cx="12" cy="12" r="1.1" fill={color}/>
226
+ <react_native_svg_1.Path d="M15 3.5 C17 3.5 17 6 17 8.5 C17 10.5 18 11.5 19 12 C18 12.5 17 13.5 17 15.5 C17 18 17 20.5 15 20.5" {...stroke}/>
227
+ </react_native_svg_1.G>);
228
+ default:
229
+ return null;
230
+ }
231
+ };
232
+ return (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
233
+ {renderGlyph()}
234
+ </react_native_svg_1.default>);
235
+ };
164
236
  // ─── Media File Thumbnail Component ──────────────────────────────────────────
165
237
  const MediaPreviewThumbnail = ({ file }) => {
166
238
  const [loadError, setLoadError] = (0, react_1.useState)(false);
@@ -169,25 +241,25 @@ const MediaPreviewThumbnail = ({ file }) => {
169
241
  return (<react_native_1.View style={[
170
242
  bundleStyles.mediaThumbWrap,
171
243
  {
172
- backgroundColor: '#FFF1F2',
244
+ backgroundColor: AppColors_1.AppColors.errorCardBg,
173
245
  alignItems: 'center',
174
246
  justifyContent: 'center',
175
- borderColor: '#FECDD3',
247
+ borderColor: AppColors_1.AppColors.errorBorder,
176
248
  },
177
249
  ]}>
178
250
  <react_native_svg_1.default width={22} height={22} viewBox="0 0 100 100" fill="none">
179
251
  <react_native_svg_1.Defs>
180
252
  <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"/>
253
+ <react_native_svg_1.Stop offset="0" stopColor={AppColors_1.AppColors.rose500}/>
254
+ <react_native_svg_1.Stop offset="1" stopColor={AppColors_1.AppColors.rose600}/>
183
255
  </react_native_svg_1.LinearGradient>
184
256
  </react_native_svg_1.Defs>
185
257
  <react_native_svg_1.Circle cx="50" cy="50" r="44" fill="url(#svgGradThumb)"/>
186
258
  {/* 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"/>
259
+ <react_native_svg_1.Path d="M25 70 C35 30, 65 30, 75 70" stroke={AppColors_1.AppColors.white} strokeWidth="8" strokeLinecap="round"/>
260
+ <react_native_svg_1.Circle cx="25" cy="70" r="7" fill={AppColors_1.AppColors.white}/>
261
+ <react_native_svg_1.Circle cx="75" cy="70" r="7" fill={AppColors_1.AppColors.white}/>
262
+ <react_native_svg_1.Circle cx="50" cy="40" r="6" fill="#FFE4E6" stroke={AppColors_1.AppColors.white} strokeWidth="2"/>
191
263
  </react_native_svg_1.default>
192
264
  </react_native_1.View>);
193
265
  }
@@ -281,11 +353,11 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
281
353
  {isCollapsed ? '▶' : '▼'}
282
354
  </react_native_1.Text>
283
355
  </react_native_1.View>
284
- <react_native_1.Text style={{ fontSize: 16 }}>{isCollapsed ? '📁' : '📂'}</react_native_1.Text>
356
+ {isCollapsed ? (<NetworkIcons_1.FolderIcon color={AppColors_1.AppColors.amber500} size={16}/>) : (<NetworkIcons_1.FolderOpenIcon color={AppColors_1.AppColors.amber500} size={16}/>)}
285
357
  <HighlightText_1.default text={node.name + '/'} search={search} style={bundleStyles.treeFolderName} highlightStyle={bundleStyles.searchHighlight}/>
286
358
  <react_native_1.View style={bundleStyles.treeCountBadge}>
287
359
  <react_native_1.Text style={bundleStyles.treeCountBadgeText}>
288
- {node.fileCount} {node.fileCount === 1 ? 'file' : 'files'}
360
+ {node.fileCount} {node.fileCount === 1 ? (0, i18n_1.t)('bundle.file') : (0, i18n_1.t)('bundle.files')}
289
361
  </react_native_1.Text>
290
362
  </react_native_1.View>
291
363
  </react_native_1.View>
@@ -293,14 +365,14 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
293
365
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
294
366
  <react_native_1.Text style={bundleStyles.treeFolderSize}>
295
367
  {node.sizeKb >= 1024
296
- ? `${(node.sizeKb / 1024).toFixed(2)} MB`
297
- : `${node.sizeKb} KB`}
368
+ ? (0, i18n_1.t)('bundle.fileSizeMb', { size: (node.sizeKb / 1024).toFixed(2) })
369
+ : (0, i18n_1.t)('bundle.fileSizeKb', { size: node.sizeKb })}
298
370
  </react_native_1.Text>
299
371
  <CopyButton_1.default value={() => ({
300
372
  folder: node.fullPath,
301
373
  sizeKb: node.sizeKb,
302
374
  fileCount: node.fileCount,
303
- })} label={`Copy ${node.name} Info`}/>
375
+ })} label={(0, i18n_1.t)('bundle.copyFileInfo', { name: node.name })}/>
304
376
  </react_native_1.View>
305
377
  </TouchableScale_1.default>
306
378
 
@@ -329,9 +401,9 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
329
401
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
330
402
  <HighlightText_1.default text={file.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
331
403
  {isUnused ? (<react_native_1.View style={bundleStyles.unusedBadge}>
332
- <react_native_1.Text style={bundleStyles.unusedBadgeText}>🚫 Not Consumed</react_native_1.Text>
404
+ <react_native_1.Text style={bundleStyles.unusedBadgeText}>{(0, i18n_1.t)('bundle.notConsumed')}</react_native_1.Text>
333
405
  </react_native_1.View>) : (<react_native_1.View style={bundleStyles.consumedBadge}>
334
- <react_native_1.Text style={bundleStyles.consumedBadgeText}>⚡ Consumed</react_native_1.Text>
406
+ <react_native_1.Text style={bundleStyles.consumedBadgeText}>{(0, i18n_1.t)('bundle.consumed')}</react_native_1.Text>
335
407
  </react_native_1.View>)}
336
408
  </react_native_1.View>
337
409
  <react_native_1.Text style={bundleStyles.filePath} numberOfLines={1}>
@@ -341,14 +413,14 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
341
413
 
342
414
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
343
415
  <react_native_1.View style={bundleStyles.fileSizeBox}>
344
- <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: '#B45309' }]}>
416
+ <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: AppColors_1.AppColors.amber800Warm }]}>
345
417
  {file.sizeKb >= 1024
346
- ? `${(file.sizeKb / 1024).toFixed(2)} MB`
347
- : `${file.sizeKb} KB`}
418
+ ? (0, i18n_1.t)('bundle.fileSizeMb', { size: (file.sizeKb / 1024).toFixed(2) })
419
+ : (0, i18n_1.t)('bundle.fileSizeKb', { size: file.sizeKb })}
348
420
  </react_native_1.Text>
349
421
  <react_native_1.Text style={bundleStyles.filePercent}>{pctOfTotal}%</react_native_1.Text>
350
422
  </react_native_1.View>
351
- <CopyButton_1.default value={() => file} label="File Details JSON"/>
423
+ <CopyButton_1.default value={() => file} label={(0, i18n_1.t)('bundle.fileDetailsJson')}/>
352
424
  </react_native_1.View>
353
425
  </react_native_1.View>
354
426
 
@@ -359,429 +431,62 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, collapsedFolde
359
431
  isUnused && bundleStyles.adviceUnused,
360
432
  { marginLeft: 26, marginTop: 4 },
361
433
  ]}>
362
- <react_native_1.Text style={[
434
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'flex-start', gap: 5 }}>
435
+ {isUnused ? (<NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.red600} size={12}/>) : file.status === 'warning' ? (<NetworkIcons_1.LightbulbIcon color={AppColors_1.AppColors.amber800Warm} size={12}/>) : (<NetworkIcons_1.SparkleIcon color={AppColors_1.AppColors.emerald700} size={12}/>)}
436
+ <react_native_1.Text style={[
363
437
  bundleStyles.adviceText,
364
- file.status === 'warning' && { color: '#B45309' },
365
- file.status === 'optimal' && { color: '#047857' },
366
- isUnused && { color: '#DC2626' },
438
+ file.status === 'warning' && { color: AppColors_1.AppColors.amber800Warm },
439
+ file.status === 'optimal' && { color: AppColors_1.AppColors.emerald700 },
440
+ isUnused && { color: AppColors_1.AppColors.red600 },
367
441
  ]}>
368
- {isUnused ? '🗑️ ' : file.status === 'warning' ? '💡 ' : '✨ '}
369
- {file.advice}
370
- </react_native_1.Text>
442
+ {file.advice}
443
+ </react_native_1.Text>
444
+ </react_native_1.View>
371
445
  </react_native_1.View>)}
372
446
  </react_native_1.View>);
373
447
  };
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
448
  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: '📄' },
449
+ { key: 'ALL', labelKey: 'bundle.catAll', iconType: 'folder' },
450
+ { key: 'UNUSED', labelKey: 'bundle.catUnused', iconType: 'ban' },
451
+ { key: 'CONSUMED', labelKey: 'bundle.catConsumed', iconType: 'bolt' },
452
+ { key: 'image', labelKey: 'bundle.catImages', iconType: 'image' },
453
+ { key: 'typescript', labelKey: 'bundle.catTypescript', iconType: 'typescript' },
454
+ { key: 'javascript', labelKey: 'bundle.catJavascript', iconType: 'javascript' },
455
+ { key: 'font', labelKey: 'bundle.catFonts', iconType: 'font' },
456
+ { key: 'json', labelKey: 'bundle.catJson', iconType: 'json' },
770
457
  ];
771
458
  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' },
459
+ image: { label: 'Images & Media', color: AppColors_1.AppColors.pink500, bg: AppColors_1.AppColors.pink100 },
460
+ typescript: { label: 'TypeScript', color: AppColors_1.AppColors.sky500, bg: AppColors_1.AppColors.sky100 },
461
+ javascript: { label: 'JavaScript', color: AppColors_1.AppColors.indigo500, bg: AppColors_1.AppColors.indigo50 },
462
+ font: { label: 'Fonts', color: AppColors_1.AppColors.purple500, bg: AppColors_1.AppColors.purple100 },
463
+ json: { label: 'JSON / Data', color: AppColors_1.AppColors.emerald500, bg: AppColors_1.AppColors.emerald100 },
777
464
  };
778
465
  const BundleTab = react_1.default.memo(() => {
779
466
  const { t } = (0, i18n_1.useTranslation)();
780
467
  const [activeSubTab, setActiveSubTab] = (0, react_1.useState)('overview');
781
468
  const [search, setSearch] = (0, react_1.useState)('');
782
469
  const [activeCategory, setActiveCategory] = (0, react_1.useState)('ALL');
470
+ // ─── Live Host App Bundle Analysis (fetched from Metro / runtime) ─────────
471
+ const [analysis, setAnalysis] = (0, react_1.useState)(() => (0, bundleAnalyzer_1.getCachedBundleAnalysis)());
472
+ const [isAnalyzing, setIsAnalyzing] = (0, react_1.useState)(!(0, bundleAnalyzer_1.getCachedBundleAnalysis)());
473
+ (0, react_1.useEffect)(() => {
474
+ let mounted = true;
475
+ (0, bundleAnalyzer_1.analyzeHostAppBundle)().then(result => {
476
+ if (mounted) {
477
+ setAnalysis(result);
478
+ setIsAnalyzing(false);
479
+ }
480
+ });
481
+ return () => {
482
+ mounted = false;
483
+ };
484
+ }, []);
783
485
  // Check if Hermes is running
784
486
  const isHermes = Boolean(global.HermesInternal);
487
+ // Dynamic files & packages derived from the analyzed host bundle
488
+ const bundleFiles = (0, react_1.useMemo)(() => (analysis ? analysis.files : []), [analysis]);
489
+ const bundlePackages = (0, react_1.useMemo)(() => (analysis ? analysis.packages : []), [analysis]);
785
490
  // Group summary calculations
786
491
  const summary = (0, react_1.useMemo)(() => {
787
492
  let imagesKb = 0;
@@ -794,7 +499,7 @@ const BundleTab = react_1.default.memo(() => {
794
499
  let jsCount = 0;
795
500
  let fontsCount = 0;
796
501
  let jsonCount = 0;
797
- BUNDLE_FILES_DATA.forEach(f => {
502
+ bundleFiles.forEach(f => {
798
503
  if (f.category === 'image') {
799
504
  imagesKb += f.sizeKb;
800
505
  imagesCount++;
@@ -820,37 +525,37 @@ const BundleTab = react_1.default.memo(() => {
820
525
  return {
821
526
  totalKb,
822
527
  totalMb: (totalKb / 1024).toFixed(2),
823
- totalCount: BUNDLE_FILES_DATA.length,
528
+ totalCount: bundleFiles.length,
824
529
  images: {
825
530
  count: imagesCount,
826
531
  kb: imagesKb,
827
- pct: Number(((imagesKb / totalKb) * 100).toFixed(1)),
532
+ pct: totalKb ? Number(((imagesKb / totalKb) * 100).toFixed(1)) : 0,
828
533
  },
829
534
  ts: {
830
535
  count: tsCount,
831
536
  kb: tsKb,
832
- pct: Number(((tsKb / totalKb) * 100).toFixed(1)),
537
+ pct: totalKb ? Number(((tsKb / totalKb) * 100).toFixed(1)) : 0,
833
538
  },
834
539
  js: {
835
540
  count: jsCount,
836
541
  kb: jsKb,
837
- pct: Number(((jsKb / totalKb) * 100).toFixed(1)),
542
+ pct: totalKb ? Number(((jsKb / totalKb) * 100).toFixed(1)) : 0,
838
543
  },
839
544
  fonts: {
840
545
  count: fontsCount,
841
546
  kb: fontsKb,
842
- pct: Number(((fontsKb / totalKb) * 100).toFixed(1)),
547
+ pct: totalKb ? Number(((fontsKb / totalKb) * 100).toFixed(1)) : 0,
843
548
  },
844
549
  json: {
845
550
  count: jsonCount,
846
551
  kb: jsonKb,
847
- pct: Number(((jsonKb / totalKb) * 100).toFixed(1)),
552
+ pct: totalKb ? Number(((jsonKb / totalKb) * 100).toFixed(1)) : 0,
848
553
  },
849
554
  };
850
- }, []);
555
+ }, [bundleFiles]);
851
556
  // Filtered files
852
557
  const filteredFiles = (0, react_1.useMemo)(() => {
853
- return BUNDLE_FILES_DATA.filter(file => {
558
+ return bundleFiles.filter(file => {
854
559
  const matchSearch = !search ||
855
560
  file.name.toLowerCase().includes(search.toLowerCase()) ||
856
561
  file.path.toLowerCase().includes(search.toLowerCase()) ||
@@ -865,7 +570,7 @@ const BundleTab = react_1.default.memo(() => {
865
570
  : file.category === activeCategory;
866
571
  return matchSearch && matchCategory;
867
572
  });
868
- }, [search, activeCategory]);
573
+ }, [search, activeCategory, bundleFiles]);
869
574
  const filteredTotalKb = (0, react_1.useMemo)(() => {
870
575
  return filteredFiles.reduce((acc, f) => acc + f.sizeKb, 0);
871
576
  }, [filteredFiles]);
@@ -900,46 +605,46 @@ const BundleTab = react_1.default.memo(() => {
900
605
  // Filtered Packages
901
606
  const filteredPackages = (0, react_1.useMemo)(() => {
902
607
  if (!search)
903
- return BUNDLE_PACKAGES_DATA;
608
+ return bundlePackages;
904
609
  const q = search.toLowerCase();
905
- return BUNDLE_PACKAGES_DATA.filter(pkg => pkg.name.toLowerCase().includes(q) ||
610
+ return bundlePackages.filter(pkg => pkg.name.toLowerCase().includes(q) ||
906
611
  pkg.description.toLowerCase().includes(q) ||
907
612
  pkg.category.toLowerCase().includes(q));
908
- }, [search]);
613
+ }, [search, bundlePackages]);
909
614
  const packagesTotalKb = (0, react_1.useMemo)(() => {
910
615
  return filteredPackages.reduce((acc, p) => acc + p.sizeKb, 0);
911
616
  }, [filteredPackages]);
912
617
  // Media files (Images + Fonts)
913
618
  const mediaFiles = (0, react_1.useMemo)(() => {
914
- return BUNDLE_FILES_DATA.filter(f => f.category === 'image' || f.category === 'font');
915
- }, []);
619
+ return bundleFiles.filter(f => f.category === 'image' || f.category === 'font');
620
+ }, [bundleFiles]);
916
621
  const mediaTotalKb = (0, react_1.useMemo)(() => {
917
622
  return mediaFiles.reduce((acc, m) => acc + m.sizeKb, 0);
918
623
  }, [mediaFiles]);
919
624
  const subTabs = [
920
625
  {
921
626
  key: 'overview',
922
- label: 'Overview',
627
+ label: t('bundle.tabOverview'),
923
628
  icon: (isActive) => (<NetworkIcons_1.LiveStateIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
924
629
  },
925
630
  {
926
631
  key: 'files',
927
- label: `Files (${BUNDLE_FILES_DATA.length})`,
632
+ label: t('bundle.tabFiles', { count: bundleFiles.length }),
928
633
  icon: (isActive) => (<NetworkIcons_1.LayersIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
929
634
  },
930
635
  {
931
636
  key: 'packages',
932
- label: `Packages (${BUNDLE_PACKAGES_DATA.length})`,
637
+ label: t('bundle.tabPackages', { count: bundlePackages.length }),
933
638
  icon: (isActive) => (<NetworkIcons_1.PackageIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
934
639
  },
935
640
  {
936
641
  key: 'media',
937
- label: `Media (${mediaFiles.length})`,
642
+ label: t('bundle.tabMedia', { count: mediaFiles.length }),
938
643
  icon: (isActive) => (<NetworkIcons_1.StorageIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
939
644
  },
940
645
  {
941
646
  key: 'optimizer',
942
- label: 'Optimizer',
647
+ label: t('bundle.tabOptimizer'),
943
648
  icon: (isActive) => (<NetworkIcons_1.MetadataIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={12}/>),
944
649
  },
945
650
  ];
@@ -965,10 +670,21 @@ const BundleTab = react_1.default.memo(() => {
965
670
  </react_native_1.ScrollView>
966
671
  </react_native_1.View>
967
672
 
673
+ {/* ─── Live Bundle Analysis Loading State ─── */}
674
+ {isAnalyzing && (<react_native_1.View style={bundleStyles.analyzingContainer}>
675
+ <react_native_1.ActivityIndicator size="small" color={AppColors_1.AppColors.brandPurple}/>
676
+ <react_native_1.Text style={bundleStyles.analyzingText}>
677
+ {t('bundle.analyzingTitle')}
678
+ </react_native_1.Text>
679
+ <react_native_1.Text style={bundleStyles.analyzingHint}>
680
+ {t('bundle.analyzingHint')}
681
+ </react_native_1.Text>
682
+ </react_native_1.View>)}
683
+
968
684
  {/* ══════════════════════════════════════════════════════════════════════ */}
969
685
  {/* ── 1. TAB: OVERVIEW & TREEMAP ───────────────────────────────────────── */}
970
686
  {/* ══════════════════════════════════════════════════════════════════════ */}
971
- {activeSubTab === 'overview' && (<react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
687
+ {activeSubTab === 'overview' && !isAnalyzing && (<react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
972
688
 
973
689
  {/* Hero Overview Card */}
974
690
  <react_native_1.View style={bundleStyles.heroCard}>
@@ -977,42 +693,59 @@ const BundleTab = react_1.default.memo(() => {
977
693
  <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.brandPurple} size={24}/>
978
694
  </react_native_1.View>
979
695
  <react_native_1.View style={{ flex: 1 }}>
980
- <react_native_1.Text style={bundleStyles.heroTitle}>Bundle & Asset Architecture</react_native_1.Text>
696
+ <react_native_1.Text style={bundleStyles.heroTitle}>{t('bundle.heroTitle')}</react_native_1.Text>
981
697
  <react_native_1.Text style={bundleStyles.heroSubtitle}>
982
- Real-time size breakdown across all assets, code, and dependencies
698
+ {analysis?.isLive
699
+ ? t('bundle.heroSubtitleLive', { scriptUrl: analysis.scriptURL })
700
+ : t('bundle.heroSubtitle')}
983
701
  </react_native_1.Text>
984
702
  </react_native_1.View>
985
- <CopyButton_1.default value={() => summary} label="Bundle Overview JSON"/>
703
+ <CopyButton_1.default value={() => ({ ...summary, bundle: analysis })} label={t('bundle.bundleOverviewJson')}/>
986
704
  </react_native_1.View>
987
705
 
988
706
  {/* 4-Stat Metric Grid */}
989
707
  <react_native_1.View style={bundleStyles.metricsGrid}>
990
708
  <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>
709
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.devBundleSize')}</react_native_1.Text>
710
+ <react_native_1.Text style={bundleStyles.metricValue}>
711
+ {t('bundle.mbValue', {
712
+ size: analysis ? analysis.totalDevMb : summary.totalMb,
713
+ })}
714
+ </react_native_1.Text>
715
+ <react_native_1.Text style={bundleStyles.metricHint}>
716
+ {analysis
717
+ ? t('bundle.devBundleHint', {
718
+ kb: analysis.totalDevKb,
719
+ modules: analysis.moduleCount,
720
+ })
721
+ : t('bundle.trackedFilesHint', { count: bundleFiles.length })}
722
+ </react_native_1.Text>
994
723
  </react_native_1.View>
995
724
 
996
725
  <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
726
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.imagesMedia')}</react_native_1.Text>
727
+ <react_native_1.Text style={[bundleStyles.metricValue, { color: AppColors_1.AppColors.pink500 }]}>
728
+ {t('bundle.fileSizeKb', { size: summary.images.kb })}
729
+ </react_native_1.Text>
730
+ <react_native_1.Text style={bundleStyles.metricHint}>
731
+ {t('bundle.pctOfTrackedAssets', { pct: summary.images.pct })}
1000
732
  </react_native_1.Text>
1001
- <react_native_1.Text style={bundleStyles.metricHint}>{summary.images.pct}% of package</react_native_1.Text>
1002
733
  </react_native_1.View>
1003
734
 
1004
735
  <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
736
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.tsJsSource')}</react_native_1.Text>
737
+ <react_native_1.Text style={[bundleStyles.metricValue, { color: AppColors_1.AppColors.sky500 }]}>
738
+ {t('bundle.fileSizeKb', { size: summary.ts.kb + summary.js.kb })}
1008
739
  </react_native_1.Text>
1009
740
  <react_native_1.Text style={bundleStyles.metricHint}>
1010
- {(summary.ts.pct + summary.js.pct).toFixed(1)}% of package
741
+ {t('bundle.pctOfTrackedAssets', {
742
+ pct: (summary.ts.pct + summary.js.pct).toFixed(1),
743
+ })}
1011
744
  </react_native_1.Text>
1012
745
  </react_native_1.View>
1013
746
 
1014
747
  <react_native_1.View style={bundleStyles.metricBox}>
1015
- <react_native_1.Text style={bundleStyles.metricLabel}>JS ENGINE</react_native_1.Text>
748
+ <react_native_1.Text style={bundleStyles.metricLabel}>{t('bundle.jsEngine')}</react_native_1.Text>
1016
749
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 5, marginTop: 2 }}>
1017
750
  <react_native_1.View style={[
1018
751
  bundleStyles.statusIndicator,
@@ -1022,17 +755,109 @@ const BundleTab = react_1.default.memo(() => {
1022
755
  {isHermes ? 'Hermes' : 'JSC'}
1023
756
  </react_native_1.Text>
1024
757
  </react_native_1.View>
1025
- <react_native_1.Text style={bundleStyles.metricHint}>{isHermes ? 'Bytecode AOT' : 'Standard'}</react_native_1.Text>
758
+ <react_native_1.Text style={bundleStyles.metricHint}>
759
+ {isHermes ? t('bundle.bytecodeAot') : t('bundle.standard')}
760
+ </react_native_1.Text>
1026
761
  </react_native_1.View>
1027
762
  </react_native_1.View>
1028
763
  </react_native_1.View>
1029
764
 
765
+ {/* Development Bundle Split-Up (derived from the real running bundle) */}
766
+ {analysis && (<react_native_1.View style={bundleStyles.sectionCard}>
767
+ <react_native_1.View style={bundleStyles.sectionHeaderRow}>
768
+ <react_native_1.View>
769
+ <react_native_1.Text style={bundleStyles.sectionTitle}>{t('bundle.splitUpTitle')}</react_native_1.Text>
770
+ <react_native_1.Text style={bundleStyles.sectionSub}>
771
+ {t('bundle.splitUpSub', {
772
+ mb: analysis.totalDevMb,
773
+ files: analysis.filesCount,
774
+ packages: analysis.packageCount,
775
+ })}
776
+ </react_native_1.Text>
777
+ </react_native_1.View>
778
+ <CopyButton_1.default value={() => analysis.splitUp} label={t('bundle.splitUpJson')}/>
779
+ </react_native_1.View>
780
+
781
+ {[
782
+ {
783
+ iconType: 'source',
784
+ label: t('bundle.splitAppSource'),
785
+ color: AppColors_1.AppColors.sky500,
786
+ ...analysis.splitUp.appSource,
787
+ },
788
+ {
789
+ iconType: 'deps',
790
+ label: t('bundle.splitNodeModules'),
791
+ color: AppColors_1.AppColors.indigo500,
792
+ ...analysis.splitUp.nodeModules,
793
+ },
794
+ {
795
+ iconType: 'media',
796
+ label: t('bundle.splitAssetsMedia'),
797
+ color: AppColors_1.AppColors.pink500,
798
+ ...analysis.splitUp.assetsMedia,
799
+ },
800
+ {
801
+ iconType: 'overhead',
802
+ label: t('bundle.splitMetroOverhead'),
803
+ color: AppColors_1.AppColors.amber500,
804
+ ...analysis.splitUp.metroDevOverhead,
805
+ },
806
+ ].map((part, idx) => (<react_native_1.View key={idx} style={bundleStyles.catRowCard}>
807
+ <react_native_1.View style={bundleStyles.catRowTop}>
808
+ <BundleCategoryIcon type={part.iconType} size={18} color={part.color}/>
809
+ <react_native_1.View style={{ flex: 1 }}>
810
+ <react_native_1.Text style={bundleStyles.catRowTitle}>{part.label}</react_native_1.Text>
811
+ <react_native_1.Text style={bundleStyles.catRowDesc}>
812
+ {t('bundle.splitSize', { kb: part.kb, mb: part.mb })}
813
+ </react_native_1.Text>
814
+ </react_native_1.View>
815
+ <react_native_1.View style={{ alignItems: 'flex-end' }}>
816
+ <react_native_1.Text style={bundleStyles.catRowSize}>{part.pct}%</react_native_1.Text>
817
+ </react_native_1.View>
818
+ </react_native_1.View>
819
+ <react_native_1.View style={bundleStyles.catProgressTrack}>
820
+ <react_native_1.View style={[
821
+ bundleStyles.catProgressBar,
822
+ { width: `${part.pct}%`, backgroundColor: part.color },
823
+ ]}/>
824
+ </react_native_1.View>
825
+ </react_native_1.View>))}
826
+
827
+ {/* Production Binary Footprint */}
828
+ <react_native_1.View style={bundleStyles.totalSummaryCard}>
829
+ <react_native_1.View style={bundleStyles.totalSummaryRow}>
830
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
831
+ <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.purple} size={16}/>
832
+ <react_native_1.Text style={bundleStyles.totalSummaryLabel}>
833
+ {t('bundle.productionFootprint')}
834
+ </react_native_1.Text>
835
+ </react_native_1.View>
836
+ <react_native_1.Text style={bundleStyles.totalSummaryValue}>
837
+ {t('bundle.productionValue', {
838
+ ios: analysis.production.ios.totalInstallMb,
839
+ android: analysis.production.android.totalInstallMb,
840
+ })}
841
+ </react_native_1.Text>
842
+ </react_native_1.View>
843
+ <react_native_1.Text style={bundleStyles.totalSummaryFormula}>
844
+ {t('bundle.productionDownload', {
845
+ ios: analysis.production.ios.totalDownloadMb,
846
+ aab: analysis.production.androidAab.totalDownloadMb,
847
+ apk: analysis.production.androidApk.totalDownloadMb,
848
+ })}
849
+ </react_native_1.Text>
850
+ </react_native_1.View>
851
+ </react_native_1.View>)}
852
+
1030
853
  {/* Visual Type Distribution Ratio Bar */}
1031
854
  <react_native_1.View style={bundleStyles.sectionCard}>
1032
855
  <react_native_1.View style={bundleStyles.sectionHeaderRow}>
1033
856
  <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>
857
+ <react_native_1.Text style={bundleStyles.sectionTitle}>{t('bundle.treemapTitle')}</react_native_1.Text>
858
+ <react_native_1.Text style={bundleStyles.sectionSub}>
859
+ {t('bundle.treemapSub', { mb: summary.totalMb })}
860
+ </react_native_1.Text>
1036
861
  </react_native_1.View>
1037
862
  <CopyButton_1.default value={() => ({
1038
863
  totalMb: summary.totalMb,
@@ -1042,48 +867,63 @@ const BundleTab = react_1.default.memo(() => {
1042
867
  js: summary.js,
1043
868
  fonts: summary.fonts,
1044
869
  json: summary.json,
1045
- })} label="Ratio Treemap JSON"/>
870
+ })} label={t('bundle.treemapJson')}/>
1046
871
  </react_native_1.View>
1047
872
 
1048
873
  {/* Stacked Colored Bar */}
1049
874
  <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 }}/>
875
+ <react_native_1.View style={{ flex: summary.images.pct, backgroundColor: AppColors_1.AppColors.pink500, height: 16 }}/>
876
+ <react_native_1.View style={{ flex: summary.ts.pct, backgroundColor: AppColors_1.AppColors.sky500, height: 16 }}/>
877
+ <react_native_1.View style={{ flex: summary.js.pct, backgroundColor: AppColors_1.AppColors.indigo500, height: 16 }}/>
878
+ <react_native_1.View style={{ flex: summary.fonts.pct, backgroundColor: AppColors_1.AppColors.purple500, height: 16 }}/>
879
+ <react_native_1.View style={{ flex: summary.json.pct, backgroundColor: AppColors_1.AppColors.emerald500, height: 16 }}/>
1055
880
  </react_native_1.View>
1056
881
 
1057
882
  {/* Legend Grid */}
1058
883
  <react_native_1.View style={bundleStyles.legendGrid}>
1059
884
  <react_native_1.View style={bundleStyles.legendItem}>
1060
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#EC4899' }]}/>
885
+ <BundleCategoryIcon type="image" size={13} color={AppColors_1.AppColors.pink500}/>
1061
886
  <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>
887
+ {t('bundle.legendImages')}{' '}
888
+ <react_native_1.Text style={bundleStyles.legendVal}>
889
+ {t('bundle.legendValue', { kb: summary.images.kb, pct: summary.images.pct })}
890
+ </react_native_1.Text>
1063
891
  </react_native_1.Text>
1064
892
  </react_native_1.View>
1065
893
  <react_native_1.View style={bundleStyles.legendItem}>
1066
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#0EA5E9' }]}/>
894
+ <BundleCategoryIcon type="typescript" size={13} color={AppColors_1.AppColors.sky500}/>
1067
895
  <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>
896
+ {t('bundle.legendTs')}{' '}
897
+ <react_native_1.Text style={bundleStyles.legendVal}>
898
+ {t('bundle.legendValue', { kb: summary.ts.kb, pct: summary.ts.pct })}
899
+ </react_native_1.Text>
1069
900
  </react_native_1.Text>
1070
901
  </react_native_1.View>
1071
902
  <react_native_1.View style={bundleStyles.legendItem}>
1072
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#6366F1' }]}/>
903
+ <BundleCategoryIcon type="javascript" size={13} color={AppColors_1.AppColors.indigo500}/>
1073
904
  <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>
905
+ {t('bundle.legendJs')}{' '}
906
+ <react_native_1.Text style={bundleStyles.legendVal}>
907
+ {t('bundle.legendValue', { kb: summary.js.kb, pct: summary.js.pct })}
908
+ </react_native_1.Text>
1075
909
  </react_native_1.Text>
1076
910
  </react_native_1.View>
1077
911
  <react_native_1.View style={bundleStyles.legendItem}>
1078
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#8B5CF6' }]}/>
912
+ <BundleCategoryIcon type="font" size={13} color={AppColors_1.AppColors.purple500}/>
1079
913
  <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>
914
+ {t('bundle.legendFonts')}{' '}
915
+ <react_native_1.Text style={bundleStyles.legendVal}>
916
+ {t('bundle.legendValue', { kb: summary.fonts.kb, pct: summary.fonts.pct })}
917
+ </react_native_1.Text>
1081
918
  </react_native_1.Text>
1082
919
  </react_native_1.View>
1083
920
  <react_native_1.View style={bundleStyles.legendItem}>
1084
- <react_native_1.View style={[bundleStyles.legendDot, { backgroundColor: '#10B981' }]}/>
921
+ <BundleCategoryIcon type="json" size={13} color={AppColors_1.AppColors.emerald500}/>
1085
922
  <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>
923
+ {t('bundle.legendJson')}{' '}
924
+ <react_native_1.Text style={bundleStyles.legendVal}>
925
+ {t('bundle.legendValue', { kb: summary.json.kb, pct: summary.json.pct })}
926
+ </react_native_1.Text>
1087
927
  </react_native_1.Text>
1088
928
  </react_native_1.View>
1089
929
  </react_native_1.View>
@@ -1092,7 +932,7 @@ const BundleTab = react_1.default.memo(() => {
1092
932
  {/* Detailed Category Footprint Cards */}
1093
933
  <react_native_1.View style={bundleStyles.sectionCard}>
1094
934
  <react_native_1.View style={bundleStyles.sectionHeaderRow}>
1095
- <react_native_1.Text style={bundleStyles.sectionTitle}>Category Breakdown</react_native_1.Text>
935
+ <react_native_1.Text style={bundleStyles.sectionTitle}>{t('bundle.categoryBreakdown')}</react_native_1.Text>
1096
936
  <CopyButton_1.default value={() => ({
1097
937
  totalAssets: summary.totalCount,
1098
938
  totalSizeKb: summary.totalKb,
@@ -1103,61 +943,66 @@ const BundleTab = react_1.default.memo(() => {
1103
943
  typescript: summary.ts,
1104
944
  json: summary.json,
1105
945
  },
1106
- })} label="Categories Breakdown JSON"/>
946
+ })} label={t('bundle.categoriesJson')}/>
1107
947
  </react_native_1.View>
1108
948
 
1109
949
  {[
1110
950
  {
1111
- icon: '🖼️',
1112
- title: 'Images & Media Assets',
951
+ iconType: 'image',
952
+ title: t('bundle.catImagesTitle'),
1113
953
  count: summary.images.count,
1114
- size: `${summary.images.kb} KB`,
954
+ size: t('bundle.fileSizeKb', { size: summary.images.kb }),
1115
955
  pct: summary.images.pct,
1116
- color: '#EC4899',
1117
- desc: 'PNG, WebP, SVG, and JPG assets in bundle',
956
+ color: AppColors_1.AppColors.pink500,
957
+ desc: t('bundle.catImagesDesc'),
1118
958
  },
1119
959
  {
1120
- icon: '⚙️',
1121
- title: 'Compiled Node Modules & JS',
960
+ iconType: 'javascript',
961
+ title: t('bundle.catJsTitle'),
1122
962
  count: summary.js.count,
1123
- size: `${summary.js.kb} KB`,
963
+ size: t('bundle.fileSizeKb', { size: summary.js.kb }),
1124
964
  pct: summary.js.pct,
1125
- color: '#6366F1',
1126
- desc: 'Third-party dependencies and native bridges',
965
+ color: AppColors_1.AppColors.indigo500,
966
+ desc: t('bundle.catJsDesc'),
1127
967
  },
1128
968
  {
1129
- icon: '🔤',
1130
- title: 'Custom Fonts & Vector Glyphs',
969
+ iconType: 'font',
970
+ title: t('bundle.catFontsTitle'),
1131
971
  count: summary.fonts.count,
1132
- size: `${summary.fonts.kb} KB`,
972
+ size: t('bundle.fileSizeKb', { size: summary.fonts.kb }),
1133
973
  pct: summary.fonts.pct,
1134
- color: '#8B5CF6',
1135
- desc: 'Inter, JetBrainsMono, and UI typography fonts',
974
+ color: AppColors_1.AppColors.purple500,
975
+ desc: bundleFiles
976
+ .filter(f => f.category === 'font')
977
+ .map(f => f.name)
978
+ .join(', ') || t('bundle.catFontsDesc'),
1136
979
  },
1137
980
  {
1138
- icon: '📜',
1139
- title: 'TypeScript & JSX Components',
981
+ iconType: 'typescript',
982
+ title: t('bundle.catTsTitle'),
1140
983
  count: summary.ts.count,
1141
- size: `${summary.ts.kb} KB`,
984
+ size: t('bundle.fileSizeKb', { size: summary.ts.kb }),
1142
985
  pct: summary.ts.pct,
1143
- color: '#0EA5E9',
1144
- desc: 'App screen components, hooks, and business logic',
986
+ color: AppColors_1.AppColors.sky500,
987
+ desc: t('bundle.catTsDesc'),
1145
988
  },
1146
989
  {
1147
- icon: '📄',
1148
- title: 'JSON Data & Localizations',
990
+ iconType: 'json',
991
+ title: t('bundle.catJsonTitle'),
1149
992
  count: summary.json.count,
1150
- size: `${summary.json.kb} KB`,
993
+ size: t('bundle.fileSizeKb', { size: summary.json.kb }),
1151
994
  pct: summary.json.pct,
1152
- color: '#10B981',
1153
- desc: 'i18n translation dictionaries and static configs',
995
+ color: AppColors_1.AppColors.emerald500,
996
+ desc: t('bundle.catJsonDesc'),
1154
997
  },
1155
998
  ].map((cat, cIdx) => (<react_native_1.View key={cIdx} style={bundleStyles.catRowCard}>
1156
999
  <react_native_1.View style={bundleStyles.catRowTop}>
1157
- <react_native_1.Text style={bundleStyles.catRowIcon}>{cat.icon}</react_native_1.Text>
1000
+ <BundleCategoryIcon type={cat.iconType} size={18} color={cat.color}/>
1158
1001
  <react_native_1.View style={{ flex: 1 }}>
1159
1002
  <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>
1003
+ <react_native_1.Text style={bundleStyles.catRowDesc}>
1004
+ {t('bundle.catRowSub', { count: cat.count, desc: cat.desc })}
1005
+ </react_native_1.Text>
1161
1006
  </react_native_1.View>
1162
1007
  <react_native_1.View style={{ alignItems: 'flex-end' }}>
1163
1008
  <react_native_1.Text style={bundleStyles.catRowSize}>{cat.size}</react_native_1.Text>
@@ -1177,14 +1022,24 @@ const BundleTab = react_1.default.memo(() => {
1177
1022
  <react_native_1.View style={bundleStyles.totalSummaryRow}>
1178
1023
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1179
1024
  <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>
1025
+ <react_native_1.Text style={bundleStyles.totalSummaryLabel}>
1026
+ {t('bundle.totalBundleAssets')}
1027
+ </react_native_1.Text>
1181
1028
  </react_native_1.View>
1182
1029
  <react_native_1.Text style={bundleStyles.totalSummaryValue}>
1183
- {summary.totalKb} KB (~{summary.totalMb} MB)
1030
+ {t('bundle.totalBundleValue', { kb: summary.totalKb, mb: summary.totalMb })}
1184
1031
  </react_native_1.Text>
1185
1032
  </react_native_1.View>
1186
1033
  <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%)
1034
+ {t('bundle.totalFormula', {
1035
+ images: summary.images.kb,
1036
+ js: summary.js.kb,
1037
+ fonts: summary.fonts.kb,
1038
+ ts: summary.ts.kb,
1039
+ json: summary.json.kb,
1040
+ total: summary.totalKb,
1041
+ count: summary.totalCount,
1042
+ })}
1188
1043
  </react_native_1.Text>
1189
1044
  </react_native_1.View>
1190
1045
  </react_native_1.View>
@@ -1193,16 +1048,16 @@ const BundleTab = react_1.default.memo(() => {
1193
1048
  {/* ══════════════════════════════════════════════════════════════════════ */}
1194
1049
  {/* ── 2. TAB: FILES BREAKDOWN ─────────────────────────────────────────── */}
1195
1050
  {/* ══════════════════════════════════════════════════════════════════════ */}
1196
- {activeSubTab === 'files' && (<react_native_1.View style={{ flex: 1 }}>
1051
+ {activeSubTab === 'files' && !isAnalyzing && (<react_native_1.View style={{ flex: 1 }}>
1197
1052
  {/* Search & Category Filter */}
1198
1053
  <react_native_1.View style={bundleStyles.filterContainer}>
1199
1054
  <react_native_1.View style={bundleStyles.searchRow}>
1200
1055
  <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"/>
1056
+ <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
1057
  {search.length > 0 && (<react_native_1.Pressable onPress={() => setSearch('')} hitSlop={10}>
1203
1058
  <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
1204
1059
  </react_native_1.Pressable>)}
1205
- <CopyButton_1.default value={() => filteredFiles} label="Filtered Files JSON"/>
1060
+ <CopyButton_1.default value={() => filteredFiles} label={t('bundle.filteredFilesJson')}/>
1206
1061
  </react_native_1.View>
1207
1062
 
1208
1063
  {/* Category Filter Chips */}
@@ -1210,24 +1065,24 @@ const BundleTab = react_1.default.memo(() => {
1210
1065
  {CATEGORY_TABS.map(tab => {
1211
1066
  const isActive = activeCategory === tab.key;
1212
1067
  const count = tab.key === 'ALL'
1213
- ? BUNDLE_FILES_DATA.length
1068
+ ? bundleFiles.length
1214
1069
  : tab.key === 'UNUSED'
1215
- ? BUNDLE_FILES_DATA.filter(f => f.isConsumed === false).length
1070
+ ? bundleFiles.filter(f => f.isConsumed === false).length
1216
1071
  : tab.key === 'CONSUMED'
1217
- ? BUNDLE_FILES_DATA.filter(f => f.isConsumed !== false).length
1218
- : BUNDLE_FILES_DATA.filter(f => f.category === tab.key).length;
1072
+ ? bundleFiles.filter(f => f.isConsumed !== false).length
1073
+ : bundleFiles.filter(f => f.category === tab.key).length;
1219
1074
  return (<TouchableScale_1.default key={tab.key} onPress={() => setActiveCategory(tab.key)} style={[
1220
1075
  bundleStyles.catPill,
1221
1076
  isActive && bundleStyles.catPillActive,
1222
- tab.key === 'UNUSED' && isActive && { backgroundColor: '#EF4444', borderColor: '#DC2626' },
1223
- tab.key === 'CONSUMED' && isActive && { backgroundColor: '#059669', borderColor: '#047857' },
1077
+ tab.key === 'UNUSED' && isActive && { backgroundColor: AppColors_1.AppColors.red500, borderColor: AppColors_1.AppColors.red600 },
1078
+ tab.key === 'CONSUMED' && isActive && { backgroundColor: AppColors_1.AppColors.emerald600, borderColor: AppColors_1.AppColors.emerald700 },
1224
1079
  ]}>
1225
- <react_native_1.Text style={bundleStyles.catPillIcon}>{tab.icon}</react_native_1.Text>
1080
+ <BundleCategoryIcon type={tab.iconType} size={12} color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayTextStrong}/>
1226
1081
  <react_native_1.Text style={[
1227
1082
  bundleStyles.catPillText,
1228
1083
  isActive && bundleStyles.catPillTextActive,
1229
1084
  ]}>
1230
- {tab.label} ({count})
1085
+ {t(tab.labelKey)} ({count})
1231
1086
  </react_native_1.Text>
1232
1087
  </TouchableScale_1.default>);
1233
1088
  })}
@@ -1248,7 +1103,7 @@ const BundleTab = react_1.default.memo(() => {
1248
1103
  bundleStyles.viewModeBtnText,
1249
1104
  filesViewMode === 'tree' && bundleStyles.viewModeBtnTextActive,
1250
1105
  ]}>
1251
- 🌳 Tree View
1106
+ {t('bundle.treeView')}
1252
1107
  </react_native_1.Text>
1253
1108
  </TouchableScale_1.default>
1254
1109
  <TouchableScale_1.default onPress={() => setFilesViewMode('list')} style={[
@@ -1259,21 +1114,24 @@ const BundleTab = react_1.default.memo(() => {
1259
1114
  bundleStyles.viewModeBtnText,
1260
1115
  filesViewMode === 'list' && bundleStyles.viewModeBtnTextActive,
1261
1116
  ]}>
1262
- 📄 Flat List
1117
+ {t('bundle.flatList')}
1263
1118
  </react_native_1.Text>
1264
1119
  </TouchableScale_1.default>
1265
1120
  </react_native_1.View>
1266
1121
 
1267
1122
  {filesViewMode === 'tree' ? (<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1268
1123
  <TouchableScale_1.default onPress={expandAllFolders}>
1269
- <react_native_1.Text style={bundleStyles.treeActionLink}>Expand</react_native_1.Text>
1124
+ <react_native_1.Text style={bundleStyles.treeActionLink}>{t('bundle.expand')}</react_native_1.Text>
1270
1125
  </TouchableScale_1.default>
1271
1126
  <react_native_1.Text style={{ color: AppColors_1.AppColors.grayTextWeak, fontSize: 11 }}>•</react_native_1.Text>
1272
1127
  <TouchableScale_1.default onPress={collapseAllFolders}>
1273
- <react_native_1.Text style={bundleStyles.treeActionLink}>Collapse</react_native_1.Text>
1128
+ <react_native_1.Text style={bundleStyles.treeActionLink}>{t('bundle.collapse')}</react_native_1.Text>
1274
1129
  </TouchableScale_1.default>
1275
1130
  </react_native_1.View>) : (<react_native_1.Text style={bundleStyles.listHeaderCount}>
1276
- Showing {filteredFiles.length} of {BUNDLE_FILES_DATA.length} files
1131
+ {t('bundle.showingFilesOf', {
1132
+ shown: filteredFiles.length,
1133
+ total: bundleFiles.length,
1134
+ })}
1277
1135
  </react_native_1.Text>)}
1278
1136
  </react_native_1.View>
1279
1137
 
@@ -1298,9 +1156,9 @@ const BundleTab = react_1.default.memo(() => {
1298
1156
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
1299
1157
  <HighlightText_1.default text={file.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
1300
1158
  {isUnused ? (<react_native_1.View style={bundleStyles.unusedBadge}>
1301
- <react_native_1.Text style={bundleStyles.unusedBadgeText}>🚫 Not Consumed</react_native_1.Text>
1159
+ <react_native_1.Text style={bundleStyles.unusedBadgeText}>{t('bundle.notConsumed')}</react_native_1.Text>
1302
1160
  </react_native_1.View>) : (<react_native_1.View style={bundleStyles.consumedBadge}>
1303
- <react_native_1.Text style={bundleStyles.consumedBadgeText}>⚡ Consumed</react_native_1.Text>
1161
+ <react_native_1.Text style={bundleStyles.consumedBadgeText}>{t('bundle.consumed')}</react_native_1.Text>
1304
1162
  </react_native_1.View>)}
1305
1163
  </react_native_1.View>
1306
1164
  <HighlightText_1.default text={file.path} search={search} style={bundleStyles.filePath} highlightStyle={bundleStyles.searchHighlight} numberOfLines={1}/>
@@ -1308,14 +1166,14 @@ const BundleTab = react_1.default.memo(() => {
1308
1166
 
1309
1167
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1310
1168
  <react_native_1.View style={bundleStyles.fileSizeBox}>
1311
- <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: '#B45309' }]}>
1169
+ <react_native_1.Text style={[bundleStyles.fileSizeKb, isUnused && { color: AppColors_1.AppColors.amber800Warm }]}>
1312
1170
  {file.sizeKb >= 1024
1313
- ? `${(file.sizeKb / 1024).toFixed(2)} MB`
1314
- : `${file.sizeKb} KB`}
1171
+ ? t('bundle.fileSizeMb', { size: (file.sizeKb / 1024).toFixed(2) })
1172
+ : t('bundle.fileSizeKb', { size: file.sizeKb })}
1315
1173
  </react_native_1.Text>
1316
1174
  <react_native_1.Text style={bundleStyles.filePercent}>{pctOfTotal}%</react_native_1.Text>
1317
1175
  </react_native_1.View>
1318
- <CopyButton_1.default value={() => file} label="File Details JSON"/>
1176
+ <CopyButton_1.default value={() => file} label={t('bundle.fileDetailsJson')}/>
1319
1177
  </react_native_1.View>
1320
1178
  </react_native_1.View>
1321
1179
 
@@ -1324,7 +1182,7 @@ const BundleTab = react_1.default.memo(() => {
1324
1182
  bundleStyles.fileProgressBar,
1325
1183
  {
1326
1184
  width: `${Math.min(100, Math.max(4, Number(pctOfTotal) * 4))}%`,
1327
- backgroundColor: isUnused ? '#EF4444' : categoryMeta.color,
1185
+ backgroundColor: isUnused ? AppColors_1.AppColors.red500 : categoryMeta.color,
1328
1186
  },
1329
1187
  ]}/>
1330
1188
  </react_native_1.View>
@@ -1337,15 +1195,17 @@ const BundleTab = react_1.default.memo(() => {
1337
1195
  file.status === 'optimal' && bundleStyles.adviceOptimal,
1338
1196
  isUnused && bundleStyles.adviceUnused,
1339
1197
  ]}>
1198
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'flex-start', gap: 5 }}>
1199
+ {isUnused ? (<NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.red600} size={12}/>) : file.status === 'warning' ? (<NetworkIcons_1.LightbulbIcon color={AppColors_1.AppColors.amber800Warm} size={12}/>) : (<NetworkIcons_1.SparkleIcon color={AppColors_1.AppColors.emerald700} size={12}/>)}
1340
1200
  <react_native_1.Text style={[
1341
1201
  bundleStyles.adviceText,
1342
- file.status === 'warning' && { color: '#B45309' },
1343
- file.status === 'optimal' && { color: '#047857' },
1344
- isUnused && { color: '#DC2626' },
1202
+ file.status === 'warning' && { color: AppColors_1.AppColors.amber800Warm },
1203
+ file.status === 'optimal' && { color: AppColors_1.AppColors.emerald700 },
1204
+ isUnused && { color: AppColors_1.AppColors.red600 },
1345
1205
  ]}>
1346
- {isUnused ? '🗑️ ' : file.status === 'warning' ? '💡 ' : '✨ '}
1347
1206
  {file.advice}
1348
1207
  </react_native_1.Text>
1208
+ </react_native_1.View>
1349
1209
  </react_native_1.View>)}
1350
1210
  </react_native_1.View>
1351
1211
  </react_native_1.View>);
@@ -1357,11 +1217,17 @@ const BundleTab = react_1.default.memo(() => {
1357
1217
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1358
1218
  <NetworkIcons_1.LayersIcon color={AppColors_1.AppColors.purple} size={14}/>
1359
1219
  <react_native_1.Text style={bundleStyles.footerTitle}>
1360
- {filteredFiles.length} of {summary.totalCount} Files
1220
+ {t('bundle.filesOf', {
1221
+ count: filteredFiles.length,
1222
+ total: summary.totalCount,
1223
+ })}
1361
1224
  </react_native_1.Text>
1362
1225
  </react_native_1.View>
1363
1226
  <react_native_1.Text style={bundleStyles.footerSizeVal}>
1364
- {filteredTotalKb} KB ({(filteredTotalKb / 1024).toFixed(2)} MB)
1227
+ {t('bundle.kbMbValue', {
1228
+ kb: filteredTotalKb,
1229
+ mb: (filteredTotalKb / 1024).toFixed(2),
1230
+ })}
1365
1231
  </react_native_1.Text>
1366
1232
  </react_native_1.View>
1367
1233
  </react_native_1.View>)}
@@ -1369,28 +1235,29 @@ const BundleTab = react_1.default.memo(() => {
1369
1235
  {/* ══════════════════════════════════════════════════════════════════════ */}
1370
1236
  {/* ── 3. TAB: PACKAGES & NODE_MODULES ─────────────────────────────────── */}
1371
1237
  {/* ══════════════════════════════════════════════════════════════════════ */}
1372
- {activeSubTab === 'packages' && (<react_native_1.View style={{ flex: 1 }}>
1238
+ {activeSubTab === 'packages' && !isAnalyzing && (<react_native_1.View style={{ flex: 1 }}>
1373
1239
  <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
1374
1240
 
1375
1241
  <react_native_1.View style={bundleStyles.filterContainer}>
1376
1242
  <react_native_1.View style={bundleStyles.searchRow}>
1377
1243
  <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"/>
1244
+ <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
1245
  {search.length > 0 && (<react_native_1.Pressable onPress={() => setSearch('')} hitSlop={10}>
1380
1246
  <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={14}/>
1381
1247
  </react_native_1.Pressable>)}
1382
- <CopyButton_1.default value={() => filteredPackages} label="Dependencies JSON"/>
1248
+ <CopyButton_1.default value={() => filteredPackages} label={t('bundle.dependenciesJson')}/>
1383
1249
  </react_native_1.View>
1384
1250
  </react_native_1.View>
1385
1251
 
1386
1252
  <react_native_1.Text style={bundleStyles.listHeaderCount}>
1387
- Showing {filteredPackages.length} dependencies
1253
+ {t('bundle.showingDependencies', { count: filteredPackages.length })}
1388
1254
  </react_native_1.Text>
1389
1255
 
1390
1256
  {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' }]}>
1257
+ const cleanInstalledVersion = pkg.version ? pkg.version.replace(/^\^/, '') : '';
1258
+ const hasUpdate = !!pkg.latestVersion && !!cleanInstalledVersion &&
1259
+ pkg.latestVersion !== cleanInstalledVersion;
1260
+ return (<react_native_1.View key={pkg.id} style={[bundleStyles.fileCard, pkg.isDeprecated && { borderColor: AppColors_1.AppColors.errorBorder, backgroundColor: '#FFFDFD' }]}>
1394
1261
  {/* Header Row: #s.no + Logo + Package Name + Version Pill + Update/Deprecated Badges + Size & Copy */}
1395
1262
  <react_native_1.View style={bundleStyles.fileCardTop}>
1396
1263
  <react_native_1.View style={bundleStyles.sNoBadge}>
@@ -1404,26 +1271,40 @@ const BundleTab = react_1.default.memo(() => {
1404
1271
  <HighlightText_1.default text={pkg.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
1405
1272
  <react_native_1.View style={bundleStyles.versionPill}>
1406
1273
  <react_native_1.Text style={bundleStyles.versionPillText}>
1407
- v{cleanInstalledVersion}
1274
+ {cleanInstalledVersion
1275
+ ? t('bundle.versionPrefix', { version: cleanInstalledVersion })
1276
+ : t('bundle.bundled')}
1408
1277
  </react_native_1.Text>
1409
1278
  </react_native_1.View>
1410
1279
 
1411
1280
  {pkg.isDeprecated ? (<react_native_1.View style={bundleStyles.deprecatedBadge}>
1412
- <react_native_1.Text style={bundleStyles.deprecatedBadgeText}>⚠️ DEPRECATED</react_native_1.Text>
1281
+ <react_native_1.Text style={bundleStyles.deprecatedBadgeText}>
1282
+ {t('bundle.deprecated')}
1283
+ </react_native_1.Text>
1413
1284
  </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>
1285
+ <react_native_1.Text style={bundleStyles.updateBadgeText}>
1286
+ {t('bundle.updateAvailable', { version: pkg.latestVersion })}
1287
+ </react_native_1.Text>
1288
+ </react_native_1.View>) : cleanInstalledVersion ? (<react_native_1.View style={[bundleStyles.updateBadge, { backgroundColor: AppColors_1.AppColors.gray100, borderColor: AppColors_1.AppColors.gray200 }]}>
1289
+ <react_native_1.Text style={[bundleStyles.updateBadgeText, { color: AppColors_1.AppColors.gray600 }]}>
1290
+ {t('bundle.upToDate')}
1291
+ </react_native_1.Text>
1292
+ </react_native_1.View>) : (<react_native_1.View style={[bundleStyles.updateBadge, { backgroundColor: AppColors_1.AppColors.gray100, borderColor: AppColors_1.AppColors.gray200 }]}>
1293
+ <react_native_1.Text style={[bundleStyles.updateBadgeText, { color: AppColors_1.AppColors.gray600 }]}>
1294
+ {t('bundle.bundledBadge')}
1295
+ </react_native_1.Text>
1417
1296
  </react_native_1.View>)}
1418
1297
  </react_native_1.View>
1419
1298
  </react_native_1.View>
1420
1299
 
1421
1300
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1422
1301
  <react_native_1.View style={bundleStyles.fileSizeBox}>
1423
- <react_native_1.Text style={bundleStyles.fileSizeKb}>{pkg.sizeKb} KB</react_native_1.Text>
1302
+ <react_native_1.Text style={bundleStyles.fileSizeKb}>
1303
+ {t('bundle.fileSizeKb', { size: pkg.sizeKb })}
1304
+ </react_native_1.Text>
1424
1305
  <react_native_1.Text style={bundleStyles.filePercent}>{pkg.percentage}%</react_native_1.Text>
1425
1306
  </react_native_1.View>
1426
- <CopyButton_1.default value={() => pkg} label="Package Details JSON"/>
1307
+ <CopyButton_1.default value={() => pkg} label={t('bundle.packageDetailsJson')}/>
1427
1308
  </react_native_1.View>
1428
1309
  </react_native_1.View>
1429
1310
 
@@ -1441,15 +1322,18 @@ const BundleTab = react_1.default.memo(() => {
1441
1322
 
1442
1323
  {/* Deprecation Warning Banner if deprecated */}
1443
1324
  {pkg.isDeprecated && pkg.deprecationReason && (<react_native_1.View style={bundleStyles.deprecationBox}>
1444
- <react_native_1.Text style={bundleStyles.deprecationText}>
1445
- ⚠️ {pkg.deprecationReason}
1446
- </react_native_1.Text>
1325
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
1326
+ <NetworkIcons_1.CircleAlertIcon color={AppColors_1.AppColors.errorColor} size={12}/>
1327
+ <react_native_1.Text style={bundleStyles.deprecationText}>
1328
+ {pkg.deprecationReason}
1329
+ </react_native_1.Text>
1330
+ </react_native_1.View>
1447
1331
  </react_native_1.View>)}
1448
1332
 
1449
1333
  <react_native_1.View style={bundleStyles.fileProgressTrack}>
1450
1334
  <react_native_1.View style={[
1451
1335
  bundleStyles.fileProgressBar,
1452
- { width: `${pkg.percentage * 2}%`, backgroundColor: pkg.isDeprecated ? '#EF4444' : pkg.color },
1336
+ { width: `${pkg.percentage * 2}%`, backgroundColor: pkg.isDeprecated ? AppColors_1.AppColors.red500 : pkg.color },
1453
1337
  ]}/>
1454
1338
  </react_native_1.View>
1455
1339
 
@@ -1458,23 +1342,26 @@ const BundleTab = react_1.default.memo(() => {
1458
1342
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1459
1343
  <react_native_1.View style={bundleStyles.typeTag}>
1460
1344
  <react_native_1.Text style={bundleStyles.typeTagText}>
1461
- {pkg.type === 'direct' ? '📦 Direct' : '🔗 Transitive'}
1345
+ {pkg.type === 'direct' ? t('bundle.direct') : t('bundle.transitive')}
1462
1346
  </react_native_1.Text>
1463
1347
  </react_native_1.View>
1464
- {pkg.lastActive && (<react_native_1.Text style={bundleStyles.lastActiveText}>
1465
- 🕒 {pkg.lastActive}
1466
- </react_native_1.Text>)}
1348
+ {pkg.lastActive && (<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
1349
+ <NetworkIcons_1.ClockIcon color={AppColors_1.AppColors.grayTextWeak} size={11}/>
1350
+ <react_native_1.Text style={bundleStyles.lastActiveText}>
1351
+ {pkg.lastActive}
1352
+ </react_native_1.Text>
1353
+ </react_native_1.View>)}
1467
1354
  </react_native_1.View>
1468
1355
 
1469
1356
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1470
1357
  <react_native_1.Text style={bundleStyles.fileMetaText}>
1471
- ~{pkg.sizeKb} KB minified
1358
+ {t('bundle.minified', { size: pkg.sizeKb })}
1472
1359
  </react_native_1.Text>
1473
1360
  <TouchableScale_1.default onPress={() => {
1474
1361
  const url = pkg.npmUrl || `https://www.npmjs.com/package/${pkg.name}`;
1475
1362
  react_native_1.Linking.openURL(url).catch(() => { });
1476
1363
  }} style={bundleStyles.npmLinkBtn}>
1477
- <react_native_1.Text style={bundleStyles.npmLinkText}>npm ↗</react_native_1.Text>
1364
+ <react_native_1.Text style={bundleStyles.npmLinkText}>{t('bundle.npmLink')}</react_native_1.Text>
1478
1365
  </TouchableScale_1.default>
1479
1366
  </react_native_1.View>
1480
1367
  </react_native_1.View>
@@ -1487,11 +1374,14 @@ const BundleTab = react_1.default.memo(() => {
1487
1374
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1488
1375
  <NetworkIcons_1.PackageIcon color={AppColors_1.AppColors.purple} size={14}/>
1489
1376
  <react_native_1.Text style={bundleStyles.footerTitle}>
1490
- {filteredPackages.length} Dependencies
1377
+ {t('bundle.dependenciesCount', { count: filteredPackages.length })}
1491
1378
  </react_native_1.Text>
1492
1379
  </react_native_1.View>
1493
1380
  <react_native_1.Text style={bundleStyles.footerSizeVal}>
1494
- {packagesTotalKb} KB ({(packagesTotalKb / 1024).toFixed(2)} MB)
1381
+ {t('bundle.kbMbValue', {
1382
+ kb: packagesTotalKb,
1383
+ mb: (packagesTotalKb / 1024).toFixed(2),
1384
+ })}
1495
1385
  </react_native_1.Text>
1496
1386
  </react_native_1.View>
1497
1387
  </react_native_1.View>)}
@@ -1499,24 +1389,32 @@ const BundleTab = react_1.default.memo(() => {
1499
1389
  {/* ══════════════════════════════════════════════════════════════════════ */}
1500
1390
  {/* ── 4. TAB: MEDIA & ASSET AUDITOR ───────────────────────────────────── */}
1501
1391
  {/* ══════════════════════════════════════════════════════════════════════ */}
1502
- {activeSubTab === 'media' && (<react_native_1.View style={{ flex: 1 }}>
1392
+ {activeSubTab === 'media' && !isAnalyzing && (<react_native_1.View style={{ flex: 1 }}>
1503
1393
  <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
1504
1394
 
1505
1395
  <react_native_1.View style={bundleStyles.tipsCard}>
1506
1396
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
1507
1397
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1508
1398
  <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>
1399
+ <react_native_1.Text style={bundleStyles.tipsHeading}>{t('bundle.mediaAuditorTitle')}</react_native_1.Text>
1510
1400
  </react_native_1.View>
1511
- <CopyButton_1.default value={() => mediaFiles} label="Media Assets JSON"/>
1401
+ <CopyButton_1.default value={() => mediaFiles} label={t('bundle.mediaAssetsJson')}/>
1512
1402
  </react_native_1.View>
1513
1403
  <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>.
1404
+ {t('bundle.mediaAuditorPrefix')}{' '}
1405
+ <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.purple }}>
1406
+ {summary.images.pct + summary.fonts.pct}%
1407
+ </react_native_1.Text>{' '}
1408
+ {t('bundle.mediaAuditorMid', { kb: summary.images.kb + summary.fonts.kb })}{' '}
1409
+ <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, color: AppColors_1.AppColors.emerald700 }}>
1410
+ {t('bundle.mediaSavings', { size: 540 })}
1411
+ </react_native_1.Text>{' '}
1412
+ {t('bundle.mediaAuditorSuffix')}
1515
1413
  </react_native_1.Text>
1516
1414
  </react_native_1.View>
1517
1415
 
1518
1416
  <react_native_1.Text style={bundleStyles.listHeaderCount}>
1519
- Media Assets & Fonts ({mediaFiles.length} items)
1417
+ {t('bundle.mediaAssetsList', { count: mediaFiles.length })}
1520
1418
  </react_native_1.Text>
1521
1419
 
1522
1420
  {mediaFiles.map((file, index) => (<react_native_1.View key={file.id} style={bundleStyles.fileCard}>
@@ -1534,9 +1432,11 @@ const BundleTab = react_1.default.memo(() => {
1534
1432
 
1535
1433
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1536
1434
  <react_native_1.View style={bundleStyles.fileSizeBox}>
1537
- <react_native_1.Text style={bundleStyles.fileSizeKb}>{file.sizeKb} KB</react_native_1.Text>
1435
+ <react_native_1.Text style={bundleStyles.fileSizeKb}>
1436
+ {t('bundle.fileSizeKb', { size: file.sizeKb })}
1437
+ </react_native_1.Text>
1538
1438
  </react_native_1.View>
1539
- <CopyButton_1.default value={() => file} label="Media Item JSON"/>
1439
+ <CopyButton_1.default value={() => file} label={t('bundle.mediaItemJson')}/>
1540
1440
  </react_native_1.View>
1541
1441
  </react_native_1.View>
1542
1442
 
@@ -1547,14 +1447,16 @@ const BundleTab = react_1.default.memo(() => {
1547
1447
  file.status === 'warning' && bundleStyles.adviceWarning,
1548
1448
  file.status === 'optimal' && bundleStyles.adviceOptimal,
1549
1449
  ]}>
1550
- <react_native_1.Text style={[
1450
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'flex-start', gap: 5 }}>
1451
+ {file.status === 'warning' ? (<NetworkIcons_1.LightbulbIcon color={AppColors_1.AppColors.amber800Warm} size={12}/>) : (<NetworkIcons_1.SparkleIcon color={AppColors_1.AppColors.emerald700} size={12}/>)}
1452
+ <react_native_1.Text style={[
1551
1453
  bundleStyles.adviceText,
1552
- file.status === 'warning' && { color: '#B45309' },
1553
- file.status === 'optimal' && { color: '#047857' },
1454
+ file.status === 'warning' && { color: AppColors_1.AppColors.amber800Warm },
1455
+ file.status === 'optimal' && { color: AppColors_1.AppColors.emerald700 },
1554
1456
  ]}>
1555
- {file.status === 'warning' ? '💡 ' : '✨ '}
1556
- {file.advice}
1557
- </react_native_1.Text>
1457
+ {file.advice}
1458
+ </react_native_1.Text>
1459
+ </react_native_1.View>
1558
1460
  </react_native_1.View>)}
1559
1461
  </react_native_1.View>
1560
1462
  </react_native_1.View>))}
@@ -1565,11 +1467,14 @@ const BundleTab = react_1.default.memo(() => {
1565
1467
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1566
1468
  <NetworkIcons_1.StorageIcon color={AppColors_1.AppColors.purple} size={14}/>
1567
1469
  <react_native_1.Text style={bundleStyles.footerTitle}>
1568
- {mediaFiles.length} Media & Fonts
1470
+ {t('bundle.mediaAndFonts', { count: mediaFiles.length })}
1569
1471
  </react_native_1.Text>
1570
1472
  </react_native_1.View>
1571
1473
  <react_native_1.Text style={bundleStyles.footerSizeVal}>
1572
- {mediaTotalKb} KB ({(mediaTotalKb / 1024).toFixed(2)} MB)
1474
+ {t('bundle.kbMbValue', {
1475
+ kb: mediaTotalKb,
1476
+ mb: (mediaTotalKb / 1024).toFixed(2),
1477
+ })}
1573
1478
  </react_native_1.Text>
1574
1479
  </react_native_1.View>
1575
1480
  </react_native_1.View>)}
@@ -1583,49 +1488,59 @@ const BundleTab = react_1.default.memo(() => {
1583
1488
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
1584
1489
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1585
1490
  <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>
1491
+ <react_native_1.Text style={bundleStyles.tipsHeading}>{t('bundle.optimizerTitle')}</react_native_1.Text>
1587
1492
  </react_native_1.View>
1588
1493
  <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"/>
1494
+ t('bundle.optTip1Title'),
1495
+ `${t('bundle.optTip2Title')} (${isHermes ? t('bundle.active') : t('bundle.actionRequired')})`,
1496
+ t('bundle.optTip3Title'),
1497
+ t('bundle.optTip4Title'),
1498
+ t('bundle.optTip5Title'),
1499
+ ]} label={t('bundle.optimizationChecklist')}/>
1595
1500
  </react_native_1.View>
1596
1501
 
1597
1502
  {[
1598
1503
  {
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',
1504
+ iconType: 'image',
1505
+ iconColor: AppColors_1.AppColors.pink500,
1506
+ title: t('bundle.optTip1Title'),
1507
+ desc: t('bundle.optTip1Desc'),
1508
+ badge: t('bundle.highImpact'),
1509
+ badgeColor: AppColors_1.AppColors.pink500,
1603
1510
  },
1604
1511
  {
1605
- title: '📜 Enable Hermes Bytecode Engine',
1512
+ iconType: 'bolt',
1513
+ iconColor: isHermes ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.amber500,
1514
+ title: t('bundle.optTip2Title'),
1606
1515
  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',
1516
+ ? t('bundle.optTip2DescActive')
1517
+ : t('bundle.optTip2DescInactive'),
1518
+ badge: isHermes ? t('bundle.active') : t('bundle.actionRequired'),
1519
+ badgeColor: isHermes ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.amber500,
1611
1520
  },
1612
1521
  {
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',
1522
+ iconType: 'font',
1523
+ iconColor: AppColors_1.AppColors.purple500,
1524
+ title: t('bundle.optTip3Title'),
1525
+ desc: t('bundle.optTip3Desc'),
1526
+ badge: t('bundle.mediumImpact'),
1527
+ badgeColor: AppColors_1.AppColors.purple500,
1617
1528
  },
1618
1529
  {
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',
1530
+ iconType: 'source',
1531
+ iconColor: AppColors_1.AppColors.sky500,
1532
+ title: t('bundle.optTip4Title'),
1533
+ desc: t('bundle.optTip4Desc'),
1534
+ badge: t('bundle.bestPractice'),
1535
+ badgeColor: AppColors_1.AppColors.sky500,
1623
1536
  },
1624
1537
  {
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',
1538
+ iconType: 'overhead',
1539
+ iconColor: AppColors_1.AppColors.indigo500,
1540
+ title: t('bundle.optTip5Title'),
1541
+ desc: t('bundle.optTip5Desc'),
1542
+ badge: t('bundle.bestPractice'),
1543
+ badgeColor: AppColors_1.AppColors.indigo500,
1629
1544
  },
1630
1545
  ].map((tip, tIdx) => (<react_native_1.View key={tIdx} style={bundleStyles.tipItem}>
1631
1546
  <react_native_1.View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 2 }}>
@@ -1633,6 +1548,7 @@ const BundleTab = react_1.default.memo(() => {
1633
1548
  <react_native_1.View style={bundleStyles.sNoBadge}>
1634
1549
  <react_native_1.Text style={bundleStyles.sNoText}>#{tIdx + 1}</react_native_1.Text>
1635
1550
  </react_native_1.View>
1551
+ <BundleCategoryIcon type={tip.iconType} size={14} color={tip.iconColor}/>
1636
1552
  <react_native_1.Text style={bundleStyles.tipTitle}>{tip.title}</react_native_1.Text>
1637
1553
  </react_native_1.View>
1638
1554
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
@@ -1641,7 +1557,7 @@ const BundleTab = react_1.default.memo(() => {
1641
1557
  {tip.badge}
1642
1558
  </react_native_1.Text>
1643
1559
  </react_native_1.View>
1644
- <CopyButton_1.default value={() => tip} label="Tip Details"/>
1560
+ <CopyButton_1.default value={() => tip} label={t('bundle.tipDetails')}/>
1645
1561
  </react_native_1.View>
1646
1562
  </react_native_1.View>
1647
1563
  <react_native_1.Text style={bundleStyles.tipDesc}>{tip.desc}</react_native_1.Text>
@@ -1657,6 +1573,23 @@ const bundleStyles = react_native_1.StyleSheet.create({
1657
1573
  borderBottomWidth: 1,
1658
1574
  borderBottomColor: AppColors_1.AppColors.dividerColor,
1659
1575
  },
1576
+ analyzingContainer: {
1577
+ flex: 1,
1578
+ alignItems: 'center',
1579
+ justifyContent: 'center',
1580
+ gap: 8,
1581
+ padding: 24,
1582
+ },
1583
+ analyzingText: {
1584
+ fontFamily: AppFonts_1.AppFonts.interBold,
1585
+ fontSize: 13,
1586
+ color: AppColors_1.AppColors.primaryBlack,
1587
+ },
1588
+ analyzingHint: {
1589
+ fontFamily: AppFonts_1.AppFonts.interRegular,
1590
+ fontSize: 11,
1591
+ color: AppColors_1.AppColors.grayTextWeak,
1592
+ },
1660
1593
  subTabsScroll: {
1661
1594
  paddingHorizontal: 12,
1662
1595
  gap: 8,
@@ -1815,11 +1748,6 @@ const bundleStyles = react_native_1.StyleSheet.create({
1815
1748
  gap: 5,
1816
1749
  minWidth: '45%',
1817
1750
  },
1818
- legendDot: {
1819
- width: 8,
1820
- height: 8,
1821
- borderRadius: 4,
1822
- },
1823
1751
  legendText: {
1824
1752
  fontFamily: AppFonts_1.AppFonts.interMedium,
1825
1753
  fontSize: 11,
@@ -1843,9 +1771,6 @@ const bundleStyles = react_native_1.StyleSheet.create({
1843
1771
  gap: 8,
1844
1772
  marginBottom: 8,
1845
1773
  },
1846
- catRowIcon: {
1847
- fontSize: 16,
1848
- },
1849
1774
  catRowTitle: {
1850
1775
  fontFamily: AppFonts_1.AppFonts.interBold,
1851
1776
  fontSize: 12,
@@ -1921,9 +1846,6 @@ const bundleStyles = react_native_1.StyleSheet.create({
1921
1846
  backgroundColor: AppColors_1.AppColors.brandPurple,
1922
1847
  borderColor: AppColors_1.AppColors.brandPurple,
1923
1848
  },
1924
- catPillIcon: {
1925
- fontSize: 11,
1926
- },
1927
1849
  catPillText: {
1928
1850
  fontFamily: AppFonts_1.AppFonts.interMedium,
1929
1851
  fontSize: 11,
@@ -2212,41 +2134,41 @@ const bundleStyles = react_native_1.StyleSheet.create({
2212
2134
  paddingHorizontal: 7,
2213
2135
  paddingVertical: 2,
2214
2136
  borderRadius: 5,
2215
- backgroundColor: '#CB383714',
2137
+ backgroundColor: AppColors_1.AppColors.npmRedTint,
2216
2138
  borderWidth: 1,
2217
- borderColor: '#CB383733',
2139
+ borderColor: AppColors_1.AppColors.npmRedBorder,
2218
2140
  },
2219
2141
  npmLinkText: {
2220
2142
  fontFamily: AppFonts_1.AppFonts.interBold,
2221
2143
  fontSize: 9.5,
2222
- color: '#CB3837',
2144
+ color: AppColors_1.AppColors.npmRed,
2223
2145
  },
2224
2146
  deprecatedBadge: {
2225
2147
  paddingHorizontal: 6,
2226
2148
  paddingVertical: 1.5,
2227
2149
  borderRadius: 4,
2228
- backgroundColor: '#FEE2E2',
2150
+ backgroundColor: AppColors_1.AppColors.red100,
2229
2151
  borderWidth: 1,
2230
- borderColor: '#FECACA',
2152
+ borderColor: AppColors_1.AppColors.errorBorder,
2231
2153
  },
2232
2154
  deprecatedBadgeText: {
2233
2155
  fontFamily: AppFonts_1.AppFonts.interBold,
2234
2156
  fontSize: 9,
2235
- color: '#DC2626',
2157
+ color: AppColors_1.AppColors.red600,
2236
2158
  letterSpacing: 0.3,
2237
2159
  },
2238
2160
  updateBadge: {
2239
2161
  paddingHorizontal: 6,
2240
2162
  paddingVertical: 1.5,
2241
2163
  borderRadius: 4,
2242
- backgroundColor: '#DCFCE7',
2164
+ backgroundColor: AppColors_1.AppColors.green100,
2243
2165
  borderWidth: 1,
2244
- borderColor: '#BBF7D0',
2166
+ borderColor: AppColors_1.AppColors.greenBorder,
2245
2167
  },
2246
2168
  updateBadgeText: {
2247
2169
  fontFamily: AppFonts_1.AppFonts.interBold,
2248
2170
  fontSize: 9,
2249
- color: '#047857',
2171
+ color: AppColors_1.AppColors.emerald700,
2250
2172
  },
2251
2173
  lastActiveText: {
2252
2174
  fontFamily: AppFonts_1.AppFonts.interRegular,
@@ -2254,45 +2176,45 @@ const bundleStyles = react_native_1.StyleSheet.create({
2254
2176
  color: AppColors_1.AppColors.grayTextWeak,
2255
2177
  },
2256
2178
  deprecationBox: {
2257
- backgroundColor: '#FFF1F2',
2179
+ backgroundColor: AppColors_1.AppColors.errorCardBg,
2258
2180
  borderRadius: 6,
2259
2181
  paddingHorizontal: 8,
2260
2182
  paddingVertical: 5,
2261
2183
  borderWidth: 1,
2262
- borderColor: '#FECDD3',
2184
+ borderColor: AppColors_1.AppColors.errorBorder,
2263
2185
  marginTop: 3,
2264
2186
  },
2265
2187
  deprecationText: {
2266
2188
  fontFamily: AppFonts_1.AppFonts.interMedium,
2267
2189
  fontSize: 10.5,
2268
- color: '#BE123C',
2190
+ color: AppColors_1.AppColors.rose700,
2269
2191
  lineHeight: 14,
2270
2192
  },
2271
2193
  unusedBadge: {
2272
2194
  paddingHorizontal: 6,
2273
2195
  paddingVertical: 1.5,
2274
2196
  borderRadius: 4,
2275
- backgroundColor: '#FEE2E2',
2197
+ backgroundColor: AppColors_1.AppColors.red100,
2276
2198
  borderWidth: 1,
2277
- borderColor: '#FECACA',
2199
+ borderColor: AppColors_1.AppColors.errorBorder,
2278
2200
  },
2279
2201
  unusedBadgeText: {
2280
2202
  fontFamily: AppFonts_1.AppFonts.interBold,
2281
2203
  fontSize: 9.5,
2282
- color: '#DC2626',
2204
+ color: AppColors_1.AppColors.red600,
2283
2205
  },
2284
2206
  consumedBadge: {
2285
2207
  paddingHorizontal: 6,
2286
2208
  paddingVertical: 1.5,
2287
2209
  borderRadius: 4,
2288
- backgroundColor: '#DCFCE7',
2210
+ backgroundColor: AppColors_1.AppColors.green100,
2289
2211
  borderWidth: 1,
2290
- borderColor: '#BBF7D0',
2212
+ borderColor: AppColors_1.AppColors.greenBorder,
2291
2213
  },
2292
2214
  consumedBadgeText: {
2293
2215
  fontFamily: AppFonts_1.AppFonts.interBold,
2294
2216
  fontSize: 9.5,
2295
- color: '#059669',
2217
+ color: AppColors_1.AppColors.emerald600,
2296
2218
  },
2297
2219
  treeFolderChevronWrap: {
2298
2220
  width: 18,
@@ -2303,13 +2225,13 @@ const bundleStyles = react_native_1.StyleSheet.create({
2303
2225
  justifyContent: 'center',
2304
2226
  },
2305
2227
  treeFileCardUnused: {
2306
- borderColor: '#FECACA',
2307
- backgroundColor: '#FFFBFB',
2228
+ borderColor: AppColors_1.AppColors.errorBorder,
2229
+ backgroundColor: AppColors_1.AppColors.red50,
2308
2230
  },
2309
2231
  adviceUnused: {
2310
- backgroundColor: '#FEF2F2',
2232
+ backgroundColor: AppColors_1.AppColors.errorCardBg,
2311
2233
  borderWidth: 1,
2312
- borderColor: '#FECACA',
2234
+ borderColor: AppColors_1.AppColors.errorBorder,
2313
2235
  },
2314
2236
  adviceBadge: {
2315
2237
  paddingHorizontal: 8,
@@ -2318,14 +2240,14 @@ const bundleStyles = react_native_1.StyleSheet.create({
2318
2240
  marginTop: 2,
2319
2241
  },
2320
2242
  adviceWarning: {
2321
- backgroundColor: '#FEF3C7',
2243
+ backgroundColor: AppColors_1.AppColors.amber100,
2322
2244
  borderWidth: 1,
2323
- borderColor: '#FDE68A',
2245
+ borderColor: AppColors_1.AppColors.amber200,
2324
2246
  },
2325
2247
  adviceOptimal: {
2326
- backgroundColor: '#DCFCE7',
2248
+ backgroundColor: AppColors_1.AppColors.green100,
2327
2249
  borderWidth: 1,
2328
- borderColor: '#BBF7D0',
2250
+ borderColor: AppColors_1.AppColors.greenBorder,
2329
2251
  },
2330
2252
  adviceText: {
2331
2253
  fontFamily: AppFonts_1.AppFonts.interMedium,
@@ -2343,21 +2265,21 @@ const bundleStyles = react_native_1.StyleSheet.create({
2343
2265
  fontSize: 9,
2344
2266
  },
2345
2267
  searchHighlight: {
2346
- backgroundColor: '#FEF08A',
2347
- color: '#854D0E',
2268
+ backgroundColor: AppColors_1.AppColors.yellow200,
2269
+ color: AppColors_1.AppColors.yellow800,
2348
2270
  fontFamily: AppFonts_1.AppFonts.interBold,
2349
2271
  },
2350
2272
  tipsCard: {
2351
- backgroundColor: '#FAF5FF',
2273
+ backgroundColor: AppColors_1.AppColors.purple50,
2352
2274
  borderRadius: 14,
2353
2275
  padding: 14,
2354
2276
  borderWidth: 1,
2355
- borderColor: '#E9D5FF',
2277
+ borderColor: AppColors_1.AppColors.purple200,
2356
2278
  },
2357
2279
  tipsHeading: {
2358
2280
  fontFamily: AppFonts_1.AppFonts.interBold,
2359
2281
  fontSize: 13.5,
2360
- color: '#6B21A8',
2282
+ color: AppColors_1.AppColors.purple800,
2361
2283
  },
2362
2284
  totalSummaryCard: {
2363
2285
  marginTop: 10,
@@ -2421,17 +2343,17 @@ const bundleStyles = react_native_1.StyleSheet.create({
2421
2343
  padding: 10,
2422
2344
  borderRadius: 8,
2423
2345
  borderWidth: 1,
2424
- borderColor: '#E9D5FF',
2346
+ borderColor: AppColors_1.AppColors.purple200,
2425
2347
  },
2426
2348
  tipTitle: {
2427
2349
  fontFamily: AppFonts_1.AppFonts.interBold,
2428
2350
  fontSize: 12,
2429
- color: '#581C87',
2351
+ color: AppColors_1.AppColors.purple900,
2430
2352
  },
2431
2353
  tipDesc: {
2432
2354
  fontFamily: AppFonts_1.AppFonts.interRegular,
2433
2355
  fontSize: 11,
2434
- color: '#6B7280',
2356
+ color: AppColors_1.AppColors.gray500,
2435
2357
  lineHeight: 16,
2436
2358
  marginTop: 4,
2437
2359
  },