react-native-inapp-inspector 2.3.18 → 2.3.20

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 (358) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +57 -0
  2. package/dist/commonjs/analytics.js +1 -24
  3. package/dist/commonjs/bundle.js +1 -16
  4. package/dist/commonjs/capture.d.ts +2 -0
  5. package/dist/commonjs/capture.js +1 -32
  6. package/dist/commonjs/components/AnalyticsDetail.js +92 -623
  7. package/dist/commonjs/components/AnalyticsEventCard.js +54 -350
  8. package/dist/commonjs/components/AnalyticsGraph.js +70 -370
  9. package/dist/commonjs/components/AnimatedEntrance.js +1 -11
  10. package/dist/commonjs/components/AppHeaderLogo.js +7 -134
  11. package/dist/commonjs/components/BrandCircleIcon.js +73 -118
  12. package/dist/commonjs/components/BrandSquareIcon.js +63 -108
  13. package/dist/commonjs/components/CodeSnippet.js +48 -623
  14. package/dist/commonjs/components/ConsoleLogCard.js +63 -537
  15. package/dist/commonjs/components/CopyButton.js +3 -89
  16. package/dist/commonjs/components/DiffViewer.js +19 -83
  17. package/dist/commonjs/components/DomainHeader.js +27 -127
  18. package/dist/commonjs/components/EmptyState.d.ts +1 -0
  19. package/dist/commonjs/components/EmptyState.js +10 -87
  20. package/dist/commonjs/components/EndOfListFooter.js +7 -81
  21. package/dist/commonjs/components/ErrorBoundary.js +72 -566
  22. package/dist/commonjs/components/HeadersSection.js +31 -110
  23. package/dist/commonjs/components/HighlightText.js +17 -58
  24. package/dist/commonjs/components/Inspector/AboutModal.d.ts +6 -0
  25. package/dist/commonjs/components/Inspector/AboutModal.js +351 -0
  26. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +98 -797
  27. package/dist/commonjs/components/Inspector/AnalyticsTab.js +284 -930
  28. package/dist/commonjs/components/Inspector/BundleTab.js +551 -2918
  29. package/dist/commonjs/components/Inspector/ConsoleTab.js +79 -492
  30. package/dist/commonjs/components/Inspector/CrashDetail.js +123 -672
  31. package/dist/commonjs/components/Inspector/CrashFilterModal.js +66 -498
  32. package/dist/commonjs/components/Inspector/CrashTab.js +98 -670
  33. package/dist/commonjs/components/Inspector/DebuggingTab.js +64 -871
  34. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +143 -907
  35. package/dist/commonjs/components/Inspector/FabLauncher.js +85 -54
  36. package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.js +6 -99
  37. package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +9 -0
  38. package/dist/commonjs/components/Inspector/FeedbackModal.js +167 -521
  39. package/dist/commonjs/components/Inspector/InspectorContext.js +1 -21
  40. package/dist/commonjs/components/Inspector/InspectorHeader.js +219 -1093
  41. package/dist/commonjs/components/Inspector/LogDetail.js +168 -994
  42. package/dist/commonjs/components/Inspector/MainScreen.js +60 -332
  43. package/dist/commonjs/components/Inspector/MediaGalleryTab.js +136 -278
  44. package/dist/commonjs/components/Inspector/MediaPreviewModal.js +134 -361
  45. package/dist/commonjs/components/Inspector/NavigationTracker.js +1 -12
  46. package/dist/commonjs/components/Inspector/NetworkDetail.js +96 -432
  47. package/dist/commonjs/components/Inspector/NetworkFilterModal.js +60 -576
  48. package/dist/commonjs/components/Inspector/NetworkTab.js +84 -514
  49. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +17 -433
  50. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +25 -298
  51. package/dist/commonjs/components/Inspector/PerformanceTab.js +182 -1397
  52. package/dist/commonjs/components/Inspector/ReduxDetail.js +188 -1089
  53. package/dist/commonjs/components/Inspector/ReduxTab.js +85 -701
  54. package/dist/commonjs/components/Inspector/SettingsPanel.js +431 -3431
  55. package/dist/commonjs/components/Inspector/SkeletonPlaceholder.js +11 -180
  56. package/dist/commonjs/components/Inspector/StorageTab.js +93 -826
  57. package/dist/commonjs/components/Inspector/TabBar.js +47 -183
  58. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +34 -408
  59. package/dist/commonjs/components/JsonViewer.js +168 -380
  60. package/dist/commonjs/components/LogCard.js +57 -567
  61. package/dist/commonjs/components/LogSyntaxHighlighter.js +11 -130
  62. package/dist/commonjs/components/MetaAccordion.js +69 -238
  63. package/dist/commonjs/components/MiniBarChart.js +3 -56
  64. package/dist/commonjs/components/MiniLineChart.js +3 -58
  65. package/dist/commonjs/components/NetworkIcons.d.ts +7 -0
  66. package/dist/commonjs/components/NetworkIcons.js +479 -997
  67. package/dist/commonjs/components/QRCodeView.js +5 -79
  68. package/dist/commonjs/components/SectionHeader.js +15 -37
  69. package/dist/commonjs/components/SegmentedTabs.js +7 -61
  70. package/dist/commonjs/components/SkeletonPlaceholder.js +11 -180
  71. package/dist/commonjs/components/Slider.js +15 -243
  72. package/dist/commonjs/components/SourcePageCard.js +30 -89
  73. package/dist/commonjs/components/Toast.js +5 -147
  74. package/dist/commonjs/components/TouchableScale.js +3 -24
  75. package/dist/commonjs/components/TreeNode.js +55 -130
  76. package/dist/commonjs/console.js +1 -16
  77. package/dist/commonjs/constants/index.js +1 -32
  78. package/dist/commonjs/constants/telemetryConfig.js +1 -6
  79. package/dist/commonjs/constants/version.d.ts +1 -1
  80. package/dist/commonjs/constants/version.js +1 -4
  81. package/dist/commonjs/crash.js +1 -23
  82. package/dist/commonjs/customHooks/analyticsLogger.js +1 -250
  83. package/dist/commonjs/customHooks/bundleAnalyzer.js +1 -957
  84. package/dist/commonjs/customHooks/consoleLogger.js +6 -445
  85. package/dist/commonjs/customHooks/crashHandler.js +7 -656
  86. package/dist/commonjs/customHooks/logFilters.js +1 -23
  87. package/dist/commonjs/customHooks/networkLogger.js +2 -536
  88. package/dist/commonjs/customHooks/performanceTracker.js +63 -750
  89. package/dist/commonjs/customHooks/reduxLogger.js +2 -313
  90. package/dist/commonjs/customHooks/storageInspector.js +1 -435
  91. package/dist/commonjs/customHooks/useAccordion.js +1 -18
  92. package/dist/commonjs/decorators/index.js +1 -100
  93. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +1 -148
  94. package/dist/commonjs/helpers/index.js +8 -921
  95. package/dist/commonjs/helpers/memoryManager.js +1 -99
  96. package/dist/commonjs/helpers/qrGenerator.js +1 -367
  97. package/dist/commonjs/helpers/remoteConfig.js +1 -165
  98. package/dist/commonjs/helpers/searchQueryParser.js +1 -62
  99. package/dist/commonjs/helpers/settingsStore.js +1 -144
  100. package/dist/commonjs/helpers/telemetry.js +1 -501
  101. package/dist/commonjs/helpers/toast.js +1 -20
  102. package/dist/commonjs/i18n/index.js +1 -90
  103. package/dist/commonjs/i18n/locales/en.json +1 -1122
  104. package/dist/commonjs/index.js +5 -2153
  105. package/dist/commonjs/metro.js +6 -468
  106. package/dist/commonjs/native/NativeInspector.d.ts +3 -0
  107. package/dist/commonjs/native/NativeInspector.js +1 -402
  108. package/dist/commonjs/native/NativeNetworkInspector.d.ts +1 -0
  109. package/dist/commonjs/native/NativeNetworkInspector.js +1 -4
  110. package/dist/commonjs/network.js +1 -13
  111. package/dist/commonjs/performance.js +1 -29
  112. package/dist/commonjs/redux.js +1 -20
  113. package/dist/commonjs/storage.js +1 -14
  114. package/dist/commonjs/styles/AppColors.js +1 -423
  115. package/dist/commonjs/styles/AppFonts.js +1 -17
  116. package/dist/commonjs/styles/common.js +1 -190
  117. package/dist/commonjs/styles/index.d.ts +6 -0
  118. package/dist/commonjs/styles/index.js +1 -1589
  119. package/dist/commonjs/types/enums.d.ts +2 -1
  120. package/dist/commonjs/types/enums.js +1 -150
  121. package/dist/commonjs/types/index.js +1 -18
  122. package/dist/commonjs/types/interfaces.d.ts +7 -0
  123. package/dist/commonjs/types/interfaces.js +1 -2
  124. package/dist/esm/analytics.js +1 -2
  125. package/dist/esm/bundle.js +1 -2
  126. package/dist/esm/capture.d.ts +2 -0
  127. package/dist/esm/capture.js +1 -29
  128. package/dist/esm/components/AnalyticsDetail.js +171 -664
  129. package/dist/esm/components/AnalyticsEventCard.js +77 -335
  130. package/dist/esm/components/AnalyticsGraph.js +95 -357
  131. package/dist/esm/components/AnimatedEntrance.js +1 -6
  132. package/dist/esm/components/AppHeaderLogo.js +7 -94
  133. package/dist/esm/components/BrandCircleIcon.js +114 -119
  134. package/dist/esm/components/BrandSquareIcon.js +73 -78
  135. package/dist/esm/components/CodeSnippet.js +58 -595
  136. package/dist/esm/components/ConsoleLogCard.js +91 -526
  137. package/dist/esm/components/CopyButton.js +3 -51
  138. package/dist/esm/components/DiffViewer.js +22 -48
  139. package/dist/esm/components/DomainHeader.js +43 -138
  140. package/dist/esm/components/EmptyState.d.ts +1 -0
  141. package/dist/esm/components/EmptyState.js +17 -56
  142. package/dist/esm/components/EndOfListFooter.js +15 -83
  143. package/dist/esm/components/ErrorBoundary.js +125 -582
  144. package/dist/esm/components/HeadersSection.js +52 -93
  145. package/dist/esm/components/HighlightText.js +17 -53
  146. package/dist/esm/components/Inspector/AboutModal.d.ts +6 -0
  147. package/dist/esm/components/Inspector/AboutModal.js +351 -0
  148. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +225 -886
  149. package/dist/esm/components/Inspector/AnalyticsTab.js +296 -904
  150. package/dist/esm/components/Inspector/BundleTab.js +1175 -3502
  151. package/dist/esm/components/Inspector/ConsoleTab.js +113 -488
  152. package/dist/esm/components/Inspector/CrashDetail.js +236 -747
  153. package/dist/esm/components/Inspector/CrashFilterModal.js +149 -541
  154. package/dist/esm/components/Inspector/CrashTab.js +177 -711
  155. package/dist/esm/components/Inspector/DebuggingTab.js +156 -923
  156. package/dist/esm/components/Inspector/DeviceInfoTab.js +199 -924
  157. package/dist/esm/components/Inspector/FabLauncher.js +85 -49
  158. package/dist/esm/components/Inspector/FeatureUnderDevNotice.js +14 -70
  159. package/dist/esm/components/Inspector/FeedbackModal.d.ts +9 -0
  160. package/dist/esm/components/Inspector/FeedbackModal.js +182 -499
  161. package/dist/esm/components/Inspector/InspectorContext.js +1 -12
  162. package/dist/esm/components/Inspector/InspectorHeader.js +309 -1145
  163. package/dist/esm/components/Inspector/LogDetail.js +235 -1023
  164. package/dist/esm/components/Inspector/MainScreen.js +86 -320
  165. package/dist/esm/components/Inspector/MediaGalleryTab.js +157 -259
  166. package/dist/esm/components/Inspector/MediaPreviewModal.js +153 -340
  167. package/dist/esm/components/Inspector/NavigationTracker.js +1 -10
  168. package/dist/esm/components/Inspector/NetworkDetail.js +141 -472
  169. package/dist/esm/components/Inspector/NetworkFilterModal.js +122 -597
  170. package/dist/esm/components/Inspector/NetworkTab.js +125 -517
  171. package/dist/esm/components/Inspector/NpmStarPrompt.js +58 -434
  172. package/dist/esm/components/Inspector/NpmUpdateToast.js +45 -281
  173. package/dist/esm/components/Inspector/PerformanceTab.js +393 -1570
  174. package/dist/esm/components/Inspector/ReduxDetail.js +307 -1170
  175. package/dist/esm/components/Inspector/ReduxTab.js +144 -722
  176. package/dist/esm/components/Inspector/SettingsPanel.js +647 -3609
  177. package/dist/esm/components/Inspector/SkeletonPlaceholder.js +30 -163
  178. package/dist/esm/components/Inspector/StorageTab.js +172 -866
  179. package/dist/esm/components/Inspector/TabBar.js +52 -183
  180. package/dist/esm/components/Inspector/UpdateAvailableModal.js +79 -416
  181. package/dist/esm/components/JsonViewer.js +179 -353
  182. package/dist/esm/components/LogCard.js +93 -565
  183. package/dist/esm/components/LogSyntaxHighlighter.js +11 -123
  184. package/dist/esm/components/MetaAccordion.js +136 -267
  185. package/dist/esm/components/MiniBarChart.js +3 -18
  186. package/dist/esm/components/MiniLineChart.js +3 -20
  187. package/dist/esm/components/NetworkIcons.d.ts +7 -0
  188. package/dist/esm/components/NetworkIcons.js +481 -817
  189. package/dist/esm/components/QRCodeView.js +8 -45
  190. package/dist/esm/components/SectionHeader.js +22 -39
  191. package/dist/esm/components/SegmentedTabs.js +8 -57
  192. package/dist/esm/components/SkeletonPlaceholder.js +30 -163
  193. package/dist/esm/components/Slider.js +24 -213
  194. package/dist/esm/components/SourcePageCard.js +65 -86
  195. package/dist/esm/components/Toast.js +10 -117
  196. package/dist/esm/components/TouchableScale.js +3 -19
  197. package/dist/esm/components/TreeNode.js +58 -95
  198. package/dist/esm/console.js +1 -2
  199. package/dist/esm/constants/index.js +1 -28
  200. package/dist/esm/constants/telemetryConfig.js +1 -3
  201. package/dist/esm/constants/version.d.ts +1 -1
  202. package/dist/esm/constants/version.js +1 -1
  203. package/dist/esm/crash.js +1 -2
  204. package/dist/esm/customHooks/analyticsLogger.js +1 -230
  205. package/dist/esm/customHooks/bundleAnalyzer.js +1 -944
  206. package/dist/esm/customHooks/consoleLogger.js +6 -432
  207. package/dist/esm/customHooks/crashHandler.js +7 -630
  208. package/dist/esm/customHooks/logFilters.js +1 -20
  209. package/dist/esm/customHooks/networkLogger.js +2 -519
  210. package/dist/esm/customHooks/performanceTracker.js +63 -723
  211. package/dist/esm/customHooks/reduxLogger.js +2 -293
  212. package/dist/esm/customHooks/storageInspector.js +1 -418
  213. package/dist/esm/customHooks/useAccordion.js +1 -16
  214. package/dist/esm/decorators/index.js +1 -95
  215. package/dist/esm/helpers/gaAnalyticsRegistry.js +1 -143
  216. package/dist/esm/helpers/index.js +8 -861
  217. package/dist/esm/helpers/memoryManager.js +1 -91
  218. package/dist/esm/helpers/qrGenerator.js +1 -364
  219. package/dist/esm/helpers/remoteConfig.js +1 -160
  220. package/dist/esm/helpers/searchQueryParser.js +1 -59
  221. package/dist/esm/helpers/settingsStore.js +1 -134
  222. package/dist/esm/helpers/telemetry.js +1 -489
  223. package/dist/esm/helpers/toast.js +1 -15
  224. package/dist/esm/i18n/index.js +1 -78
  225. package/dist/esm/i18n/locales/en.json +1 -1122
  226. package/dist/esm/index.js +7 -1967
  227. package/dist/esm/metro.js +6 -459
  228. package/dist/esm/native/NativeInspector.d.ts +3 -0
  229. package/dist/esm/native/NativeInspector.js +1 -370
  230. package/dist/esm/native/NativeNetworkInspector.d.ts +1 -0
  231. package/dist/esm/native/NativeNetworkInspector.js +1 -2
  232. package/dist/esm/network.js +1 -1
  233. package/dist/esm/performance.js +1 -2
  234. package/dist/esm/redux.js +1 -1
  235. package/dist/esm/storage.js +1 -1
  236. package/dist/esm/styles/AppColors.js +1 -417
  237. package/dist/esm/styles/AppFonts.js +1 -13
  238. package/dist/esm/styles/common.js +1 -186
  239. package/dist/esm/styles/index.d.ts +6 -0
  240. package/dist/esm/styles/index.js +1 -1551
  241. package/dist/esm/types/enums.d.ts +2 -1
  242. package/dist/esm/types/enums.js +1 -147
  243. package/dist/esm/types/index.js +1 -2
  244. package/dist/esm/types/interfaces.d.ts +7 -0
  245. package/dist/esm/types/interfaces.js +1 -1
  246. package/ios/NetworkInspectorModule.mm +253 -136
  247. package/package.json +5 -3
  248. package/react-native-inapp-inspector.podspec +1 -1
  249. package/src/native/NativeInspector.ts +17 -0
  250. package/src/native/NativeNetworkInspector.ts +1 -0
  251. package/src/analytics.ts +0 -35
  252. package/src/bundle.ts +0 -25
  253. package/src/capture.ts +0 -101
  254. package/src/components/AnalyticsDetail.tsx +0 -870
  255. package/src/components/AnalyticsEventCard.tsx +0 -444
  256. package/src/components/AnalyticsGraph.tsx +0 -583
  257. package/src/components/AnimatedEntrance.tsx +0 -20
  258. package/src/components/AppHeaderLogo.tsx +0 -143
  259. package/src/components/BrandCircleIcon.tsx +0 -144
  260. package/src/components/BrandSquareIcon.tsx +0 -184
  261. package/src/components/CodeSnippet.tsx +0 -725
  262. package/src/components/ConsoleLogCard.tsx +0 -679
  263. package/src/components/CopyButton.tsx +0 -87
  264. package/src/components/DiffViewer.tsx +0 -82
  265. package/src/components/DomainHeader.tsx +0 -224
  266. package/src/components/EmptyState.tsx +0 -95
  267. package/src/components/EndOfListFooter.tsx +0 -100
  268. package/src/components/ErrorBoundary.tsx +0 -688
  269. package/src/components/HeadersSection.tsx +0 -172
  270. package/src/components/HighlightText.tsx +0 -100
  271. package/src/components/Inspector/AnalyticsFilterModal.tsx +0 -1250
  272. package/src/components/Inspector/AnalyticsTab.tsx +0 -1362
  273. package/src/components/Inspector/BundleTab.tsx +0 -4768
  274. package/src/components/Inspector/ConsoleTab.tsx +0 -726
  275. package/src/components/Inspector/CrashDetail.tsx +0 -997
  276. package/src/components/Inspector/CrashFilterModal.tsx +0 -721
  277. package/src/components/Inspector/CrashTab.tsx +0 -933
  278. package/src/components/Inspector/DebuggingTab.tsx +0 -1103
  279. package/src/components/Inspector/DeviceInfoTab.tsx +0 -1397
  280. package/src/components/Inspector/FabLauncher.tsx +0 -80
  281. package/src/components/Inspector/FeatureUnderDevNotice.tsx +0 -94
  282. package/src/components/Inspector/FeedbackModal.tsx +0 -626
  283. package/src/components/Inspector/InspectorContext.tsx +0 -28
  284. package/src/components/Inspector/InspectorHeader.tsx +0 -1545
  285. package/src/components/Inspector/LogDetail.tsx +0 -1431
  286. package/src/components/Inspector/MainScreen.tsx +0 -459
  287. package/src/components/Inspector/MediaGalleryTab.tsx +0 -355
  288. package/src/components/Inspector/MediaPreviewModal.tsx +0 -435
  289. package/src/components/Inspector/NavigationTracker.tsx +0 -13
  290. package/src/components/Inspector/NetworkDetail.tsx +0 -795
  291. package/src/components/Inspector/NetworkFilterModal.tsx +0 -730
  292. package/src/components/Inspector/NetworkTab.tsx +0 -820
  293. package/src/components/Inspector/NpmStarPrompt.tsx +0 -532
  294. package/src/components/Inspector/NpmUpdateToast.tsx +0 -387
  295. package/src/components/Inspector/PerformanceTab.tsx +0 -1967
  296. package/src/components/Inspector/ReduxDetail.tsx +0 -1651
  297. package/src/components/Inspector/ReduxTab.tsx +0 -987
  298. package/src/components/Inspector/SettingsPanel.tsx +0 -4580
  299. package/src/components/Inspector/SkeletonPlaceholder.tsx +0 -206
  300. package/src/components/Inspector/StorageTab.tsx +0 -1159
  301. package/src/components/Inspector/TabBar.tsx +0 -263
  302. package/src/components/Inspector/UpdateAvailableModal.tsx +0 -555
  303. package/src/components/JsonViewer.tsx +0 -547
  304. package/src/components/LogCard.tsx +0 -694
  305. package/src/components/LogSyntaxHighlighter.tsx +0 -178
  306. package/src/components/MetaAccordion.tsx +0 -355
  307. package/src/components/MiniBarChart.tsx +0 -42
  308. package/src/components/MiniLineChart.tsx +0 -33
  309. package/src/components/NetworkIcons.tsx +0 -2599
  310. package/src/components/QRCodeView.tsx +0 -75
  311. package/src/components/SectionHeader.tsx +0 -101
  312. package/src/components/SegmentedTabs.tsx +0 -83
  313. package/src/components/SkeletonPlaceholder.tsx +0 -206
  314. package/src/components/Slider.tsx +0 -300
  315. package/src/components/SourcePageCard.tsx +0 -150
  316. package/src/components/Toast.tsx +0 -131
  317. package/src/components/TouchableScale.tsx +0 -61
  318. package/src/components/TreeNode.tsx +0 -171
  319. package/src/console.ts +0 -24
  320. package/src/constants/index.ts +0 -41
  321. package/src/constants/telemetryConfig.ts +0 -4
  322. package/src/constants/version.ts +0 -3
  323. package/src/crash.ts +0 -32
  324. package/src/customHooks/analyticsLogger.ts +0 -336
  325. package/src/customHooks/bundleAnalyzer.ts +0 -1256
  326. package/src/customHooks/consoleLogger.ts +0 -530
  327. package/src/customHooks/crashHandler.ts +0 -944
  328. package/src/customHooks/logFilters.ts +0 -32
  329. package/src/customHooks/networkLogger.ts +0 -624
  330. package/src/customHooks/performanceTracker.ts +0 -1014
  331. package/src/customHooks/reduxLogger.ts +0 -406
  332. package/src/customHooks/storageInspector.ts +0 -513
  333. package/src/customHooks/useAccordion.tsx +0 -27
  334. package/src/decorators/index.ts +0 -184
  335. package/src/helpers/gaAnalyticsRegistry.ts +0 -204
  336. package/src/helpers/index.ts +0 -1092
  337. package/src/helpers/memoryManager.ts +0 -138
  338. package/src/helpers/qrGenerator.ts +0 -430
  339. package/src/helpers/remoteConfig.ts +0 -212
  340. package/src/helpers/searchQueryParser.ts +0 -84
  341. package/src/helpers/settingsStore.ts +0 -171
  342. package/src/helpers/telemetry.ts +0 -568
  343. package/src/helpers/toast.ts +0 -17
  344. package/src/i18n/index.ts +0 -104
  345. package/src/i18n/locales/en.json +0 -1125
  346. package/src/index.tsx +0 -2635
  347. package/src/metro.ts +0 -598
  348. package/src/network.ts +0 -22
  349. package/src/performance.ts +0 -38
  350. package/src/redux.ts +0 -23
  351. package/src/storage.ts +0 -18
  352. package/src/styles/AppColors.ts +0 -455
  353. package/src/styles/AppFonts.ts +0 -26
  354. package/src/styles/common.ts +0 -209
  355. package/src/styles/index.ts +0 -1606
  356. package/src/types/enums.ts +0 -208
  357. package/src/types/index.ts +0 -34
  358. package/src/types/interfaces.ts +0 -530
@@ -1,3624 +1,1297 @@
1
- import React, { useState, useEffect, useMemo, useCallback } from 'react';
2
- import { ActivityIndicator, Image, Linking, Platform, Pressable, ScrollView, Share, StyleSheet, Text, TextInput, View, } from 'react-native';
3
- import { useTranslation, t } from '../../i18n';
4
- import TouchableScale from '../TouchableScale';
5
- import CopyButton from '../CopyButton';
6
- import HighlightText from '../HighlightText';
7
- import FeatureUnderDevNotice from './FeatureUnderDevNotice';
8
- import { AppColors } from '../../styles/AppColors';
9
- import { AppFonts } from '../../styles/AppFonts';
10
- import { copyToClipboard } from '../../helpers';
11
- import { PackageIcon, SearchIcon, ClearIcon, CircleAlertIcon, LayersIcon, TimelineIcon, LiveStateIcon, StorageIcon, MetadataIcon, FolderIcon, FolderOpenIcon, TrashIcon, LightbulbIcon, SparkleIcon, ClockIcon, RefreshCcwIcon, ExternalLinkIcon, DownloadIcon, ChevronIcon, } from '../NetworkIcons';
12
- import Svg, { Path, Rect, Circle, Ellipse, G, Defs, LinearGradient, Stop, } from 'react-native-svg';
13
- import { analyzeHostAppBundle, getCachedBundleAnalysis, getInitialBundleAnalysis, getHostScriptURL, } from '../../customHooks/bundleAnalyzer';
14
- const PackageLogoRenderer = ({ name, size = 28 }) => {
15
- const lowerName = name.toLowerCase();
16
- if (lowerName === 'react' ||
17
- (lowerName.includes('react-native') &&
18
- !lowerName.includes('svg') &&
19
- !lowerName.includes('screens') &&
20
- !lowerName.includes('gradient'))) {
21
- return (<View style={[
22
- bundleStyles.pkgLogoWrap,
23
- { width: size, height: size, backgroundColor: AppColors.npmDark },
24
- ]}>
25
- <Svg width={size - 6} height={size - 6} viewBox="0 0 100 100" fill="none">
26
- <Circle cx="50" cy="50" r="9" fill={AppColors.reactCyan}/>
27
- <Ellipse cx="50" cy="50" rx="42" ry="16" stroke={AppColors.reactCyan} strokeWidth="6"/>
28
- <Ellipse cx="50" cy="50" rx="42" ry="16" stroke={AppColors.reactCyan} strokeWidth="6" transform="rotate(60 50 50)"/>
29
- <Ellipse cx="50" cy="50" rx="42" ry="16" stroke={AppColors.reactCyan} strokeWidth="6" transform="rotate(120 50 50)"/>
30
- </Svg>
31
- </View>);
32
- }
33
- if (lowerName.includes('navigation')) {
34
- return (<View style={[
35
- bundleStyles.pkgLogoWrap,
36
- { width: size, height: size, backgroundColor: AppColors.hermesPurple },
37
- ]}>
38
- <Svg width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
39
- <Circle cx="50" cy="50" r="38" stroke={AppColors.white} strokeWidth="8"/>
40
- <Path d="M50 20 L68 50 L50 80 L32 50 Z" fill={AppColors.reactCyan}/>
41
- <Circle cx="50" cy="50" r="6" fill={AppColors.white}/>
42
- </Svg>
43
- </View>);
44
- }
45
- if (lowerName.includes('svg')) {
46
- return (<View style={[
47
- bundleStyles.pkgLogoWrap,
48
- { width: size, height: size, backgroundColor: AppColors.pink400 },
49
- ]}>
50
- <Svg width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
51
- <Path d="M20 75 C35 25, 65 25, 80 75" stroke={AppColors.white} strokeWidth="10" strokeLinecap="round"/>
52
- <Circle cx="20" cy="75" r="8" fill={AppColors.white}/>
53
- <Circle cx="80" cy="75" r="8" fill={AppColors.white}/>
54
- <Circle cx="50" cy="38" r="7" fill="#FCE7F3" stroke={AppColors.white} strokeWidth="3"/>
55
- </Svg>
56
- </View>);
57
- }
58
- if (lowerName.includes('axios')) {
59
- return (<View style={[
60
- bundleStyles.pkgLogoWrap,
61
- { width: size, height: size, backgroundColor: AppColors.expoViolet },
62
- ]}>
63
- <Svg width={size - 6} height={size - 6} viewBox="0 0 100 100" fill="none">
64
- <Path d="M22 75 L50 20 L78 75 M33 58 L67 58" stroke={AppColors.white} strokeWidth="12" strokeLinecap="round" strokeLinejoin="round"/>
65
- <Circle cx="50" cy="20" r="7" fill={AppColors.reactCyan}/>
66
- </Svg>
67
- </View>);
68
- }
69
- if (lowerName.includes('screens') || lowerName.includes('software-mansion')) {
70
- return (<View style={[
71
- bundleStyles.pkgLogoWrap,
72
- {
73
- width: size,
74
- height: size,
75
- backgroundColor: AppColors.reanimatedNavy,
76
- },
77
- ]}>
78
- <Svg width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
79
- <Path d="M50 15 L88 35 L50 55 L12 35 Z" fill={AppColors.sky400}/>
80
- <Path d="M12 50 L50 70 L88 50" stroke={AppColors.white} strokeWidth="8" strokeLinecap="round"/>
81
- <Path d="M12 65 L50 85 L88 65" stroke="#93C5FD" strokeWidth="8" strokeLinecap="round"/>
82
- </Svg>
83
- </View>);
84
- }
85
- if (lowerName.includes('gradient')) {
86
- return (<View style={[
87
- bundleStyles.pkgLogoWrap,
88
- { width: size, height: size, backgroundColor: AppColors.rose600 },
89
- ]}>
90
- <Svg width={size - 4} height={size - 4} viewBox="0 0 100 100" fill="none">
91
- <Defs>
92
- <LinearGradient id="pkgGrad" x1="0" y1="0" x2="100" y2="100" gradientUnits="userSpaceOnUse">
93
- <Stop offset="0" stopColor="#FF0080"/>
94
- <Stop offset="0.5" stopColor="#7928CA"/>
95
- <Stop offset="1" stopColor="#0070F3"/>
96
- </LinearGradient>
97
- </Defs>
98
- <Rect width="100" height="100" rx="18" fill="url(#pkgGrad)"/>
99
- </Svg>
100
- </View>);
101
- }
102
- if (lowerName.includes('i18n')) {
103
- return (<View style={[
104
- bundleStyles.pkgLogoWrap,
105
- { width: size, height: size, backgroundColor: AppColors.emerald600 },
106
- ]}>
107
- <Svg width={size - 8} height={size - 8} viewBox="0 0 100 100" fill="none">
108
- <Circle cx="50" cy="50" r="38" stroke={AppColors.white} strokeWidth="8"/>
109
- <Ellipse cx="50" cy="50" rx="18" ry="38" stroke={AppColors.white} strokeWidth="6"/>
110
- <Path d="M14 50 L86 50" stroke={AppColors.white} strokeWidth="7"/>
111
- </Svg>
112
- </View>);
113
- }
114
- return (<View style={[
115
- bundleStyles.pkgLogoWrap,
116
- { width: size, height: size, backgroundColor: AppColors.npmRed },
117
- ]}>
118
- <Svg width={size - 4} height={size - 4} viewBox="0 0 100 100" fill="none">
119
- <Rect width="100" height="100" rx="14" fill={AppColors.npmRed}/>
120
- <Path d="M18 24 H82 V76 H50 V40 H38 V76 H18 Z" fill={AppColors.white}/>
121
- </Svg>
122
- </View>);
123
- };
124
- const BundleCategoryIcon = ({ type, size = 16, color = AppColors.purple }) => {
125
- const stroke = {
126
- stroke: color,
127
- strokeWidth: 1.7,
128
- strokeLinecap: 'round',
129
- strokeLinejoin: 'round',
130
- };
131
- const renderGlyph = () => {
132
- switch (type) {
133
- case 'folder':
134
- return (<G>
135
- <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}/>
136
- </G>);
137
- case 'ban':
138
- return (<G>
139
- <Circle cx="12" cy="12" r="8.5" {...stroke}/>
140
- <Path d="M5.5 5.5 18.5 18.5" {...stroke}/>
141
- </G>);
142
- case 'bolt':
143
- return (<G>
144
- <Path d="M13 2 4.5 13.5 H10.5 L9 22 19.5 9.5 H13.5 Z" {...stroke}/>
145
- </G>);
146
- case 'source':
147
- return (<G>
148
- <Path d="M8.5 7 L4 12 L8.5 17" {...stroke}/>
149
- <Path d="M15.5 7 L20 12 L15.5 17" {...stroke}/>
150
- <Path d="M13.5 4.5 L10.5 19.5" {...stroke}/>
151
- </G>);
152
- case 'deps':
153
- return (<G>
154
- <Rect x="4" y="4" width="16" height="16" rx="2.5" {...stroke}/>
155
- <Path d="M4 9.5 H20" {...stroke}/>
156
- <Path d="M9.5 9.5 V20" {...stroke}/>
157
- </G>);
158
- case 'media':
159
- case 'image':
160
- return (<G>
161
- <Rect x="3.5" y="4.5" width="17" height="15" rx="2" {...stroke}/>
162
- <Circle cx="9" cy="10" r="1.5" {...stroke}/>
163
- <Path d="M3.5 17.5 L9.5 12.5 L14 16.5 L17 13.5 L20.5 17.5" {...stroke}/>
164
- </G>);
165
- case 'overhead':
166
- return (<G>
167
- <Circle cx="12" cy="12" r="3.2" {...stroke}/>
168
- <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}/>
169
- </G>);
170
- case 'typescript':
171
- return (<G>
172
- <Path d="M6.5 3.5 H14 L18.5 8 V20.5 H6.5 Z" {...stroke}/>
173
- <Path d="M14 3.5 V8 H18.5" {...stroke}/>
174
- <Path d="M9.5 13.5 H15 M12 13.5 V16.5 M9.5 16.5 H13" {...stroke}/>
175
- </G>);
176
- case 'javascript':
177
- return (<G>
178
- <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}/>
179
- <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}/>
180
- </G>);
181
- case 'font':
182
- return (<G>
183
- <Path d="M8 19 L12 5.5 L16 19" {...stroke}/>
184
- <Path d="M9.4 14.5 H14.6" {...stroke}/>
185
- </G>);
186
- case 'json':
187
- return (<G>
188
- <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}/>
189
- <Circle cx="12" cy="12" r="1.1" fill={color}/>
190
- <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}/>
191
- </G>);
192
- default:
193
- return null;
194
- }
195
- };
196
- return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
197
- {renderGlyph()}
198
- </Svg>);
199
- };
200
- const MediaPreviewThumbnail = ({ file }) => {
201
- const [loadError, setLoadError] = useState(false);
202
- if (file.ext === 'SVG' || file.name.toLowerCase().endsWith('.svg')) {
203
- return (<View style={[
204
- bundleStyles.mediaThumbWrap,
205
- {
206
- backgroundColor: AppColors.errorCardBg,
207
- alignItems: 'center',
208
- justifyContent: 'center',
209
- borderColor: AppColors.errorBorder,
210
- },
211
- ]}>
212
- <Svg width={22} height={22} viewBox="0 0 100 100" fill="none">
213
- <Defs>
214
- <LinearGradient id="svgGradThumb" x1="0" y1="0" x2="100" y2="100" gradientUnits="userSpaceOnUse">
215
- <Stop offset="0" stopColor={AppColors.rose500}/>
216
- <Stop offset="1" stopColor={AppColors.rose600}/>
217
- </LinearGradient>
218
- </Defs>
219
- <Circle cx="50" cy="50" r="44" fill="url(#svgGradThumb)"/>
1
+ import Ot,{useState as Q,useEffect as tt,useMemo as q,useCallback as Ae}from"react";import{ActivityIndicator as Tt,Image as Ut,Linking as Ct,Platform as kt,Pressable as He,ScrollView as Te,Share as Nt,StyleSheet as je,Text as C,TextInput as St,View as T}from"react-native";import{useTranslation as jt,t as Ce}from"../../i18n";import G from"../TouchableScale";import K from"../CopyButton";import Ie from"../HighlightText";import Gt from"./FeatureUnderDevNotice";import{AppColors as t}from"../../styles/AppColors";import{AppFonts as S}from"../../styles/AppFonts";import{copyToClipboard as Et}from"../../helpers";import{PackageIcon as Pe,SearchIcon as Bt,ClearIcon as Vt,CircleAlertIcon as Ge,LayersIcon as Mt,TimelineIcon as Jt,LiveStateIcon as Zt,StorageIcon as Ee,MetadataIcon as _t,FolderIcon as Xt,FolderOpenIcon as Yt,TrashIcon as Qt,LightbulbIcon as Je,SparkleIcon as Pt,ClockIcon as To,RefreshCcwIcon as Rt,ExternalLinkIcon as Co,DownloadIcon as Ze,ChevronIcon as So}from"../NetworkIcons";import X,{Path as F,Rect as Ke,Circle as $,Ellipse as $e,G as _,Defs as It,LinearGradient as Ft,Stop as Fe}from"react-native-svg";import{analyzeHostAppBundle as Lt,getCachedBundleAnalysis as Bo,getInitialBundleAnalysis as Vo,getHostScriptURL as vo}from"../../customHooks/bundleAnalyzer";const Mo=({name:k,size:M=28})=>{const R=k.toLowerCase();return R==="react"||R.includes("react-native")&&!R.includes("svg")&&!R.includes("screens")&&!R.includes("gradient")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.npmDark}]}>
2
+ <X width={M-6}height={M-6}viewBox="0 0 100 100"fill="none">
3
+ <$ cx="50"cy="50"r="9"fill={t.reactCyan}/>
4
+ <$e cx="50"cy="50"rx="42"ry="16"stroke={t.reactCyan}strokeWidth="6"/>
5
+ <$e cx="50"cy="50"rx="42"ry="16"stroke={t.reactCyan}strokeWidth="6"transform="rotate(60 50 50)"/>
6
+ <$e cx="50"cy="50"rx="42"ry="16"stroke={t.reactCyan}strokeWidth="6"transform="rotate(120 50 50)"/>
7
+ </X>
8
+ </T>:R.includes("navigation")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.hermesPurple}]}>
9
+ <X width={M-8}height={M-8}viewBox="0 0 100 100"fill="none">
10
+ <$ cx="50"cy="50"r="38"stroke={t.white}strokeWidth="8"/>
11
+ <F d="M50 20 L68 50 L50 80 L32 50 Z"fill={t.reactCyan}/>
12
+ <$ cx="50"cy="50"r="6"fill={t.white}/>
13
+ </X>
14
+ </T>:R.includes("svg")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.pink400}]}>
15
+ <X width={M-8}height={M-8}viewBox="0 0 100 100"fill="none">
16
+ <F d="M20 75 C35 25, 65 25, 80 75"stroke={t.white}strokeWidth="10"strokeLinecap="round"/>
17
+ <$ cx="20"cy="75"r="8"fill={t.white}/>
18
+ <$ cx="80"cy="75"r="8"fill={t.white}/>
19
+ <$ cx="50"cy="38"r="7"fill="#FCE7F3"stroke={t.white}strokeWidth="3"/>
20
+ </X>
21
+ </T>:R.includes("axios")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.expoViolet}]}>
22
+ <X width={M-6}height={M-6}viewBox="0 0 100 100"fill="none">
23
+ <F d="M22 75 L50 20 L78 75 M33 58 L67 58"stroke={t.white}strokeWidth="12"strokeLinecap="round"strokeLinejoin="round"/>
24
+ <$ cx="50"cy="20"r="7"fill={t.reactCyan}/>
25
+ </X>
26
+ </T>:R.includes("screens")||R.includes("software-mansion")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.reanimatedNavy}]}>
27
+ <X width={M-8}height={M-8}viewBox="0 0 100 100"fill="none">
28
+ <F d="M50 15 L88 35 L50 55 L12 35 Z"fill={t.sky400}/>
29
+ <F d="M12 50 L50 70 L88 50"stroke={t.white}strokeWidth="8"strokeLinecap="round"/>
30
+ <F d="M12 65 L50 85 L88 65"stroke="#93C5FD"strokeWidth="8"strokeLinecap="round"/>
31
+ </X>
32
+ </T>:R.includes("gradient")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.rose600}]}>
33
+ <X width={M-4}height={M-4}viewBox="0 0 100 100"fill="none">
34
+ <It>
35
+ <Ft id="pkgGrad"x1="0"y1="0"x2="100"y2="100"gradientUnits="userSpaceOnUse">
36
+ <Fe offset="0"stopColor="#FF0080"/>
37
+ <Fe offset="0.5"stopColor="#7928CA"/>
38
+ <Fe offset="1"stopColor="#0070F3"/>
39
+ </Ft>
40
+ </It>
41
+ <Ke width="100"height="100"rx="18"fill="url(#pkgGrad)"/>
42
+ </X>
43
+ </T>:R.includes("i18n")?<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.emerald600}]}>
44
+ <X width={M-8}height={M-8}viewBox="0 0 100 100"fill="none">
45
+ <$ cx="50"cy="50"r="38"stroke={t.white}strokeWidth="8"/>
46
+ <$e cx="50"cy="50"rx="18"ry="38"stroke={t.white}strokeWidth="6"/>
47
+ <F d="M14 50 L86 50"stroke={t.white}strokeWidth="7"/>
48
+ </X>
49
+ </T>:<T style={[e.pkgLogoWrap,{width:M,height:M,backgroundColor:t.npmRed}]}>
50
+ <X width={M-4}height={M-4}viewBox="0 0 100 100"fill="none">
51
+ <Ke width="100"height="100"rx="14"fill={t.npmRed}/>
52
+ <F d="M18 24 H82 V76 H50 V40 H38 V76 H18 Z"fill={t.white}/>
53
+ </X>
54
+ </T>},Z=({type:k,size:M=16,color:R=t.purple})=>{const v={stroke:R,strokeWidth:1.7,strokeLinecap:"round",strokeLinejoin:"round"},U=()=>{switch(k){case"folder":return<_>
55
+ <F 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"{...v}/>
56
+ </_>;case"ban":return<_>
57
+ <$ cx="12"cy="12"r="8.5"{...v}/>
58
+ <F d="M5.5 5.5 18.5 18.5"{...v}/>
59
+ </_>;case"bolt":return<_>
60
+ <F d="M13 2 4.5 13.5 H10.5 L9 22 19.5 9.5 H13.5 Z"{...v}/>
61
+ </_>;case"source":return<_>
62
+ <F d="M8.5 7 L4 12 L8.5 17"{...v}/>
63
+ <F d="M15.5 7 L20 12 L15.5 17"{...v}/>
64
+ <F d="M13.5 4.5 L10.5 19.5"{...v}/>
65
+ </_>;case"deps":return<_>
66
+ <Ke x="4"y="4"width="16"height="16"rx="2.5"{...v}/>
67
+ <F d="M4 9.5 H20"{...v}/>
68
+ <F d="M9.5 9.5 V20"{...v}/>
69
+ </_>;case"media":case"image":return<_>
70
+ <Ke x="3.5"y="4.5"width="17"height="15"rx="2"{...v}/>
71
+ <$ cx="9"cy="10"r="1.5"{...v}/>
72
+ <F d="M3.5 17.5 L9.5 12.5 L14 16.5 L17 13.5 L20.5 17.5"{...v}/>
73
+ </_>;case"overhead":return<_>
74
+ <$ cx="12"cy="12"r="3.2"{...v}/>
75
+ <F 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"{...v}/>
76
+ </_>;case"typescript":return<_>
77
+ <F d="M6.5 3.5 H14 L18.5 8 V20.5 H6.5 Z"{...v}/>
78
+ <F d="M14 3.5 V8 H18.5"{...v}/>
79
+ <F d="M9.5 13.5 H15 M12 13.5 V16.5 M9.5 16.5 H13"{...v}/>
80
+ </_>;case"javascript":return<_>
81
+ <F 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"{...v}/>
82
+ <F 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"{...v}/>
83
+ </_>;case"font":return<_>
84
+ <F d="M8 19 L12 5.5 L16 19"{...v}/>
85
+ <F d="M9.4 14.5 H14.6"{...v}/>
86
+ </_>;case"json":return<_>
87
+ <F 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"{...v}/>
88
+ <$ cx="12"cy="12"r="1.1"fill={R}/>
89
+ <F 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"{...v}/>
90
+ </_>;default:return null}};return<X width={M}height={M}viewBox="0 0 24 24"fill="none">
91
+ {U()}
92
+ </X>},_e=({file:k})=>{const[M,R]=Q(!1);if(k.ext==="SVG"||k.name.toLowerCase().endsWith(".svg"))return<T style={[e.mediaThumbWrap,{backgroundColor:t.errorCardBg,alignItems:"center",justifyContent:"center",borderColor:t.errorBorder}]}>
93
+ <X width={22}height={22}viewBox="0 0 100 100"fill="none">
94
+ <It>
95
+ <Ft id="svgGradThumb"x1="0"y1="0"x2="100"y2="100"gradientUnits="userSpaceOnUse">
96
+ <Fe offset="0"stopColor={t.rose500}/>
97
+ <Fe offset="1"stopColor={t.rose600}/>
98
+ </Ft>
99
+ </It>
100
+ <$ cx="50"cy="50"r="44"fill="url(#svgGradThumb)"/>
220
101
 
221
- <Path d="M25 70 C35 30, 65 30, 75 70" stroke={AppColors.white} strokeWidth="8" strokeLinecap="round"/>
222
- <Circle cx="25" cy="70" r="7" fill={AppColors.white}/>
223
- <Circle cx="75" cy="70" r="7" fill={AppColors.white}/>
224
- <Circle cx="50" cy="40" r="6" fill="#FFE4E6" stroke={AppColors.white} strokeWidth="2"/>
225
- </Svg>
226
- </View>);
227
- }
228
- if (file.category === 'image' && file.previewUri && !loadError) {
229
- return (<View style={bundleStyles.mediaThumbWrap}>
230
- <Image source={{ uri: file.previewUri }} style={bundleStyles.mediaThumbImg} resizeMode="cover" onError={() => setLoadError(true)}/>
231
- </View>);
232
- }
233
- const categoryMeta = CATEGORY_COLORS[file.category] || CATEGORY_COLORS.typescript;
234
- return (<View style={[
235
- bundleStyles.extChip,
236
- {
237
- backgroundColor: categoryMeta.bg,
238
- borderColor: `${categoryMeta.color}40`,
239
- },
240
- ]}>
241
- <Text style={[bundleStyles.extChipText, { color: categoryMeta.color }]}>
242
- {file.ext}
243
- </Text>
244
- </View>);
245
- };
246
- function buildBundleFileTree(files) {
247
- const rootMap = new Map();
248
- for (const file of files) {
249
- const cleanPath = file.path.replace(/^\/+/, '');
250
- const parts = cleanPath.split('/').filter(Boolean);
251
- if (parts.length === 0)
252
- continue;
253
- let currentLevel = rootMap;
254
- for (let i = 0; i < parts.length; i++) {
255
- const part = parts[i];
256
- const isFile = i === parts.length - 1;
257
- if (!currentLevel.has(part)) {
258
- currentLevel.set(part, {
259
- name: part,
260
- fullPath: parts.slice(0, i + 1).join('/'),
261
- isFile,
262
- fileItem: isFile ? file : undefined,
263
- children: new Map(),
264
- });
265
- }
266
- if (!isFile) {
267
- currentLevel = currentLevel.get(part).children;
268
- }
269
- }
270
- }
271
- function convertMapToNodes(map) {
272
- const nodes = [];
273
- for (const [, val] of map.entries()) {
274
- const children = convertMapToNodes(val.children);
275
- const isFolder = !val.isFile;
276
- const fileCount = isFolder
277
- ? children.reduce((acc, c) => acc + (c.isFolder ? c.fileCount : 1), 0)
278
- : 1;
279
- const sizeKb = isFolder
280
- ? children.reduce((acc, c) => acc + c.sizeKb, 0)
281
- : val.fileItem
282
- ? val.fileItem.sizeKb
283
- : 0;
284
- nodes.push({
285
- id: val.fullPath,
286
- name: val.name,
287
- fullPath: val.fullPath,
288
- isFolder,
289
- fileItem: val.fileItem,
290
- sizeKb,
291
- fileCount,
292
- children,
293
- });
294
- }
295
- return nodes.sort((a, b) => {
296
- if (a.isFolder && !b.isFolder)
297
- return -1;
298
- if (!a.isFolder && b.isFolder)
299
- return 1;
300
- return a.name.localeCompare(b.name);
301
- });
302
- }
303
- return convertMapToNodes(rootMap);
304
- }
305
- export const downloadBundleFile = async (file, scriptURL) => {
306
- let content = '';
307
- try {
308
- let devServerOrigin = '';
309
- const activeUrl = scriptURL || getHostScriptURL();
310
- if (activeUrl && activeUrl.startsWith('http')) {
311
- const match = activeUrl.match(/^(https?:\/\/[^/]+)/);
312
- if (match) {
313
- devServerOrigin = match[1];
314
- }
315
- }
316
- if (devServerOrigin) {
317
- const cleanPath = file.path.replace(/^\/+/, '');
318
- const url = `${devServerOrigin}/${cleanPath}`;
319
- const res = await fetch(url);
320
- if (res.ok) {
321
- const text = await res.text();
322
- if (text && text.length > 0) {
323
- content = text;
324
- }
325
- }
326
- }
327
- }
328
- catch { }
329
- if (!content) {
330
- content = `// ─────────────────────────────────────────────────────────────
331
- // File: ${file.name}
332
- // Path: ${file.path}
333
- // Category: ${file.category.toUpperCase()}
334
- // Size: ${file.sizeKb} KB
335
- // Status: ${file.status === 'optimal'
336
- ? 'Active in Dependency Graph'
337
- : 'Not consumed / Static'}
338
- // Meta: ${file.meta}
339
- // ─────────────────────────────────────────────────────────────
102
+ <F d="M25 70 C35 30, 65 30, 75 70"stroke={t.white}strokeWidth="8"strokeLinecap="round"/>
103
+ <$ cx="25"cy="70"r="7"fill={t.white}/>
104
+ <$ cx="75"cy="70"r="7"fill={t.white}/>
105
+ <$ cx="50"cy="40"r="6"fill="#FFE4E6"stroke={t.white}strokeWidth="2"/>
106
+ </X>
107
+ </T>;if(k.category==="image"&&k.previewUri&&!M)return<T style={e.mediaThumbWrap}>
108
+ <Ut source={{uri:k.previewUri}}style={e.mediaThumbImg}resizeMode="cover"onError={()=>R(!0)}/>
109
+ </T>;const v=Oe[k.category]||Oe.typescript;return<T style={[e.extChip,{backgroundColor:v.bg,borderColor:`${v.color}40`}]}>
110
+ <C style={[e.extChipText,{color:v.color}]}>
111
+ {k.ext}
112
+ </C>
113
+ </T>};function Po(k){const M=new Map;for(const v of k){const P=v.path.replace(/^\/+/,"").split("/").filter(Boolean);if(P.length===0)continue;let W=M;for(let D=0;D<P.length;D++){const O=P[D],V=D===P.length-1;W.has(O)||W.set(O,{name:O,fullPath:P.slice(0,D+1).join("/"),isFile:V,fileItem:V?v:void 0,children:new Map}),V||(W=W.get(O).children)}}function R(v){const U=[];for(const[,P]of v.entries()){const W=R(P.children),D=!P.isFile,O=D?W.reduce((Y,A)=>Y+(A.isFolder?A.fileCount:1),0):1,V=D?W.reduce((Y,A)=>Y+A.sizeKb,0):P.fileItem?P.fileItem.sizeKb:0;U.push({id:P.fullPath,name:P.name,fullPath:P.fullPath,isFolder:D,fileItem:P.fileItem,sizeKb:V,fileCount:O,children:W})}return U.sort((P,W)=>P.isFolder&&!W.isFolder?-1:!P.isFolder&&W.isFolder?1:P.name.localeCompare(W.name))}return R(M)}export const downloadBundleFile=async(k,M)=>{let R="";try{let v="";const U=M||vo();if(U&&U.startsWith("http")){const P=U.match(/^(https?:\/\/[^/]+)/);P&&(v=P[1])}if(v){const P=k.path.replace(/^\/+/,""),W=`${v}/${P}`,D=await fetch(W);if(D.ok){const O=await D.text();O&&O.length>0&&(R=O)}}}catch{}R||(R=`// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
114
+ // File: ${k.name}
115
+ // Path: ${k.path}
116
+ // Category: ${k.category.toUpperCase()}
117
+ // Size: ${k.sizeKb} KB
118
+ // Status: ${k.status==="optimal"?"Active in Dependency Graph":"Not consumed / Static"}
119
+ // Meta: ${k.meta}
120
+ // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
340
121
 
341
122
  export default {
342
- id: ${JSON.stringify(file.id)},
343
- name: ${JSON.stringify(file.name)},
344
- path: ${JSON.stringify(file.path)},
345
- category: ${JSON.stringify(file.category)},
346
- sizeKb: ${file.sizeKb},
347
- meta: ${JSON.stringify(file.meta)},
348
- status: ${JSON.stringify(file.status || 'optimal')},
349
- };
350
- `;
351
- }
352
- try {
353
- await Share.share(Platform.OS === 'ios'
354
- ? {
355
- title: file.name,
356
- message: content,
357
- }
358
- : {
359
- title: `Download ${file.name}`,
360
- message: content,
361
- }, {
362
- dialogTitle: `Download / Save ${file.name}`,
363
- });
364
- }
365
- catch { }
366
- try {
367
- copyToClipboard(content, file.name);
368
- }
369
- catch { }
370
- };
371
- const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolders, toggleFolder, isLastChild, onDownload, }) => {
372
- const isExpanded = search ? true : !!expandedFolders[node.fullPath];
373
- const isCollapsed = !isExpanded;
374
- const indentLeft = level * 16 + 10;
375
- if (node.isFolder) {
376
- return (<View style={bundleStyles.treeFolderBlock}>
377
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Folder ${node.name}, ${node.fileCount} ${node.fileCount === 1 ? 'file' : 'files'}, ${node.sizeKb >= 1024
378
- ? `${(node.sizeKb / 1024).toFixed(2)} MB`
379
- : `${node.sizeKb} KB`}`} accessibilityState={{ expanded: isExpanded }} accessibilityHint="Double tap to expand or collapse folder" onPress={() => toggleFolder(node.fullPath)} style={[bundleStyles.treeFolderRow, { paddingLeft: indentLeft }]}>
380
- <View style={bundleStyles.treeRowLeft}>
381
- <View style={{ marginRight: 4 }}>
382
- <ChevronIcon direction={isCollapsed ? 'right' : 'down'} size={12} color={AppColors.grayTextWeak}/>
383
- </View>
384
- {isCollapsed ? (<FolderIcon color={AppColors.amber500} size={15}/>) : (<FolderOpenIcon color={AppColors.amber500} size={15}/>)}
385
- <HighlightText text={node.name + '/'} search={search} style={bundleStyles.treeFolderName} highlightStyle={bundleStyles.searchHighlight}/>
386
- <View style={bundleStyles.treeCountBadge}>
387
- <Text style={bundleStyles.treeCountBadgeText}>
388
- {node.fileCount}{' '}
389
- {node.fileCount === 1 ? t('bundle.file') : t('bundle.files')}
390
- </Text>
391
- </View>
392
- </View>
393
-
394
- <View style={bundleStyles.treeRowRight}>
395
- <Text style={bundleStyles.treeFolderSize}>
396
- {node.sizeKb >= 1024
397
- ? t('bundle.fileSizeMb', {
398
- size: (node.sizeKb / 1024).toFixed(2),
399
- })
400
- : t('bundle.fileSizeKb', { size: node.sizeKb })}
401
- </Text>
402
- <CopyButton value={() => ({
403
- folder: node.fullPath,
404
- sizeKb: node.sizeKb,
405
- fileCount: node.fileCount,
406
- })} label={t('bundle.copyFileInfo', { name: node.name })}/>
407
- </View>
408
- </TouchableScale>
409
-
410
- {!isCollapsed && (<View style={bundleStyles.treeChildrenContainer}>
411
- {node.children.map((child, cIdx) => (<BundleTreeNodeView key={child.id} node={child} level={level + 1} search={search} totalBundleKb={totalBundleKb} expandedFolders={expandedFolders} toggleFolder={toggleFolder} isLastChild={cIdx === node.children.length - 1} onDownload={onDownload}/>))}
412
- </View>)}
413
- </View>);
414
- }
415
- const file = node.fileItem;
416
- if (!file)
417
- return null;
418
- const pctOfTotal = totalBundleKb > 0 ? ((file.sizeKb / totalBundleKb) * 100).toFixed(1) : '0';
419
- const isUnused = file.isConsumed === false;
420
- return (<View style={[
421
- bundleStyles.treeFileRow,
422
- { paddingLeft: indentLeft },
423
- isUnused && bundleStyles.treeFileRowUnused,
424
- ]}>
425
- <View style={bundleStyles.treeRowLeft}>
426
- <View style={bundleStyles.treeBranchGuide}>
427
- <Text style={bundleStyles.treeBranchGuideText}>
428
- {isLastChild ? '└' : '├'}
429
- </Text>
430
- </View>
431
-
432
- <MediaPreviewThumbnail file={file}/>
433
-
434
- <HighlightText text={file.name} search={search} style={bundleStyles.treeFileName} highlightStyle={bundleStyles.searchHighlight}/>
435
-
436
- {isUnused && (<View style={bundleStyles.treeUnusedPill}>
437
- <Text style={bundleStyles.treeUnusedPillText}>
438
- {t('bundle.notConsumed')}
439
- </Text>
440
- </View>)}
441
- </View>
442
-
443
- <View style={bundleStyles.treeRowRight}>
444
- <View style={bundleStyles.treeFileSizeGroup}>
445
- <Text style={[
446
- bundleStyles.treeFileSizeText,
447
- isUnused && { color: AppColors.red600 },
448
- ]}>
449
- {file.sizeKb >= 1024
450
- ? t('bundle.fileSizeMb', { size: (file.sizeKb / 1024).toFixed(2) })
451
- : t('bundle.fileSizeKb', { size: file.sizeKb })}
452
- </Text>
453
- <Text style={bundleStyles.treeFilePctText}>{pctOfTotal}%</Text>
454
- </View>
455
-
456
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
457
- {onDownload && (<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Download source code for ${file.name}`} accessibilityHint="Fetches module source code from Metro dev server" onPress={() => onDownload(file)} style={bundleStyles.treeActionBtn} hitSlop={8}>
458
- <DownloadIcon size={13} color={AppColors.sky500}/>
459
- </TouchableScale>)}
460
-
461
- <CopyButton value={() => file} label={t('bundle.fileDetailsJson')}/>
462
- </View>
463
- </View>
464
- </View>);
465
- };
466
- const CATEGORY_TABS = [
467
- { key: 'ALL', labelKey: 'bundle.catAll', iconType: 'folder' },
468
- { key: 'UNUSED', labelKey: 'bundle.catUnused', iconType: 'ban' },
469
- { key: 'CONSUMED', labelKey: 'bundle.catConsumed', iconType: 'bolt' },
470
- { key: 'image', labelKey: 'bundle.catImages', iconType: 'image' },
471
- {
472
- key: 'typescript',
473
- labelKey: 'bundle.catTypescript',
474
- iconType: 'typescript',
475
- },
476
- {
477
- key: 'javascript',
478
- labelKey: 'bundle.catJavascript',
479
- iconType: 'javascript',
480
- },
481
- { key: 'font', labelKey: 'bundle.catFonts', iconType: 'font' },
482
- { key: 'json', labelKey: 'bundle.catJson', iconType: 'json' },
483
- ];
484
- const CATEGORY_COLORS = {
485
- image: {
486
- label: 'Images & Media',
487
- color: AppColors.pink500,
488
- bg: AppColors.pink100,
489
- },
490
- typescript: {
491
- label: 'TypeScript',
492
- color: AppColors.sky500,
493
- bg: AppColors.sky100,
494
- },
495
- javascript: {
496
- label: 'JavaScript',
497
- color: AppColors.indigo500,
498
- bg: AppColors.indigo50,
499
- },
500
- font: { label: 'Fonts', color: AppColors.purple500, bg: AppColors.purple100 },
501
- json: {
502
- label: 'JSON / Data',
503
- color: AppColors.emerald500,
504
- bg: AppColors.emerald100,
505
- },
123
+ id: ${JSON.stringify(k.id)},
124
+ name: ${JSON.stringify(k.name)},
125
+ path: ${JSON.stringify(k.path)},
126
+ category: ${JSON.stringify(k.category)},
127
+ sizeKb: ${k.sizeKb},
128
+ meta: ${JSON.stringify(k.meta)},
129
+ status: ${JSON.stringify(k.status||"optimal")},
506
130
  };
507
- const BundleTab = React.memo(() => {
508
- const { t } = useTranslation();
509
- const [activeSubTab, setActiveSubTab] = useState('overview');
510
- const [prodPlatform, setProdPlatform] = useState('ios');
511
- const [search, setSearch] = useState('');
512
- const [activeCategory, setActiveCategory] = useState('ALL');
513
- const [analysis, setAnalysis] = useState(() => getCachedBundleAnalysis() || getInitialBundleAnalysis());
514
- const [isAnalyzing, setIsAnalyzing] = useState(false);
515
- const refreshAnalysis = useCallback(() => {
516
- setIsAnalyzing(true);
517
- analyzeHostAppBundle(true)
518
- .then(result => {
519
- setAnalysis(result);
520
- setIsAnalyzing(false);
521
- })
522
- .catch(() => {
523
- setIsAnalyzing(false);
524
- });
525
- }, []);
526
- useEffect(() => {
527
- let mounted = true;
528
- analyzeHostAppBundle()
529
- .then(result => {
530
- if (mounted) {
531
- setAnalysis(result);
532
- setIsAnalyzing(false);
533
- }
534
- })
535
- .catch(() => {
536
- if (mounted) {
537
- setIsAnalyzing(false);
538
- }
539
- });
540
- return () => {
541
- mounted = false;
542
- };
543
- }, []);
544
- const isHermes = Boolean(global.HermesInternal);
545
- const bundleFiles = useMemo(() => (analysis ? analysis.files : []), [analysis]);
546
- const bundlePackages = useMemo(() => (analysis ? analysis.packages : []), [analysis]);
547
- const summary = useMemo(() => {
548
- const totalKb = analysis?.totalDevKb ||
549
- (analysis?.totalDevBytes
550
- ? Math.round(analysis.totalDevBytes / 1024)
551
- : 6144);
552
- const totalMb = analysis?.totalDevMb
553
- ? analysis.totalDevMb.toFixed(2)
554
- : (totalKb / 1024).toFixed(2);
555
- const nodeModulesKb = analysis?.splitUp?.nodeModules?.kb || Math.round(totalKb * 0.52);
556
- const nodeModulesPct = analysis?.splitUp?.nodeModules?.pct || 52.0;
557
- const metroKb = analysis?.splitUp?.metroDevOverhead?.kb || Math.round(totalKb * 0.21);
558
- const metroPct = analysis?.splitUp?.metroDevOverhead?.pct || 21.0;
559
- const appSourceKb = analysis?.splitUp?.appSource?.kb || Math.round(totalKb * 0.15);
560
- const appSourcePct = analysis?.splitUp?.appSource?.pct || 15.0;
561
- const assetsMediaKb = analysis?.splitUp?.assetsMedia?.kb || Math.round(totalKb * 0.12);
562
- const assetsMediaPct = analysis?.splitUp?.assetsMedia?.pct || 12.0;
563
- const categories = [
564
- {
565
- key: 'node_modules',
566
- iconType: 'javascript',
567
- title: 'NPM Dependencies',
568
- targetTab: 'packages',
569
- count: analysis?.packageCount || bundlePackages.length || 53,
570
- sizeKb: nodeModulesKb,
571
- sizeMb: (nodeModulesKb / 1024).toFixed(2),
572
- pct: nodeModulesPct,
573
- color: AppColors.indigo500,
574
- desc: `${analysis?.packageCount || bundlePackages.length || 53} node_modules packages (React Native, React, navigation, axios)`,
575
- },
576
- {
577
- key: 'metro_runtime',
578
- iconType: 'bolt',
579
- title: 'Metro Dev Runtime',
580
- targetTab: 'optimizer',
581
- count: 1,
582
- sizeKb: metroKb,
583
- sizeMb: (metroKb / 1024).toFixed(2),
584
- pct: metroPct,
585
- color: AppColors.amber500,
586
- desc: 'Module loader, polyfills, HMR client, and prelude runtime',
587
- },
588
- {
589
- key: 'app_source',
590
- iconType: 'typescript',
591
- title: 'App Source Code (TSX/JS)',
592
- targetTab: 'files',
593
- count: bundleFiles.filter(f => f.category === 'typescript' || f.category === 'javascript').length || 7,
594
- sizeKb: appSourceKb,
595
- sizeMb: (appSourceKb / 1024).toFixed(2),
596
- pct: appSourcePct,
597
- color: AppColors.sky500,
598
- desc: 'Screens, components, navigation, Redux store, and hooks',
599
- },
600
- {
601
- key: 'assets_media',
602
- iconType: 'image',
603
- title: 'Images & Static Media',
604
- targetTab: 'media',
605
- count: bundleFiles.filter(f => f.category === 'image' ||
606
- f.category === 'font' ||
607
- f.category === 'json').length || 3,
608
- sizeKb: assetsMediaKb,
609
- sizeMb: (assetsMediaKb / 1024).toFixed(2),
610
- pct: assetsMediaPct,
611
- color: AppColors.pink500,
612
- desc: 'Bundled PNG/JPG/SVG drawables, custom fonts, and JSON assets',
613
- },
614
- ];
615
- return {
616
- totalKb,
617
- totalMb,
618
- totalCount: (analysis?.packageCount || 53) + bundleFiles.length + 1,
619
- categories,
620
- nodeModulesKb,
621
- nodeModulesPct,
622
- metroKb,
623
- metroPct,
624
- appSourceKb,
625
- appSourcePct,
626
- assetsMediaKb,
627
- assetsMediaPct,
628
- images: {
629
- count: bundleFiles.filter(f => f.category === 'image').length,
630
- kb: assetsMediaKb,
631
- pct: assetsMediaPct,
632
- },
633
- ts: {
634
- count: bundleFiles.filter(f => f.category === 'typescript').length,
635
- kb: appSourceKb,
636
- pct: appSourcePct,
637
- },
638
- js: {
639
- count: (analysis?.packageCount || 53) + 1,
640
- kb: nodeModulesKb + metroKb,
641
- pct: Number((nodeModulesPct + metroPct).toFixed(1)),
642
- },
643
- fonts: {
644
- count: bundleFiles.filter(f => f.category === 'font').length,
645
- kb: 0,
646
- pct: 0,
647
- },
648
- json: {
649
- count: bundleFiles.filter(f => f.category === 'json').length,
650
- kb: Math.round(assetsMediaKb * 0.1),
651
- pct: Number((assetsMediaPct * 0.1).toFixed(1)),
652
- },
653
- };
654
- }, [analysis, bundleFiles, bundlePackages]);
655
- const filteredFiles = useMemo(() => {
656
- return bundleFiles.filter(file => {
657
- const matchSearch = !search ||
658
- file.name.toLowerCase().includes(search.toLowerCase()) ||
659
- file.path.toLowerCase().includes(search.toLowerCase()) ||
660
- file.ext.toLowerCase().includes(search.toLowerCase()) ||
661
- file.meta.toLowerCase().includes(search.toLowerCase());
662
- const matchCategory = activeCategory === 'ALL'
663
- ? true
664
- : activeCategory === 'UNUSED'
665
- ? file.isConsumed === false
666
- : activeCategory === 'CONSUMED'
667
- ? file.isConsumed !== false
668
- : file.category === activeCategory;
669
- return matchSearch && matchCategory;
670
- });
671
- }, [search, activeCategory, bundleFiles]);
672
- const filteredTotalKb = useMemo(() => {
673
- return filteredFiles.reduce((acc, f) => acc + f.sizeKb, 0);
674
- }, [filteredFiles]);
675
- const [filesViewMode, setFilesViewMode] = useState('tree');
676
- const [expandedFolders, setExpandedFolders] = useState({});
677
- const fileTreeNodes = useMemo(() => {
678
- return buildBundleFileTree(filteredFiles);
679
- }, [filteredFiles]);
680
- useEffect(() => {
681
- if (fileTreeNodes.length > 0 && Object.keys(expandedFolders).length === 0) {
682
- const initial = {};
683
- fileTreeNodes.forEach(node => {
684
- if (node.isFolder) {
685
- initial[node.fullPath] = true;
686
- node.children.forEach(child => {
687
- if (child.isFolder) {
688
- initial[child.fullPath] = true;
689
- }
690
- });
691
- }
692
- });
693
- setExpandedFolders(initial);
694
- }
695
- }, [fileTreeNodes]);
696
- const toggleFolder = useCallback((path) => {
697
- setExpandedFolders(prev => ({
698
- ...prev,
699
- [path]: !prev[path],
700
- }));
701
- }, []);
702
- const expandAllFolders = useCallback(() => {
703
- const all = {};
704
- function collect(nodes) {
705
- for (const n of nodes) {
706
- if (n.isFolder) {
707
- all[n.fullPath] = true;
708
- collect(n.children);
709
- }
710
- }
711
- }
712
- collect(fileTreeNodes);
713
- setExpandedFolders(all);
714
- }, [fileTreeNodes]);
715
- const collapseAllFolders = useCallback(() => {
716
- setExpandedFolders({});
717
- }, []);
718
- const filteredPackages = useMemo(() => {
719
- if (!search)
720
- return bundlePackages;
721
- const q = search.toLowerCase();
722
- return bundlePackages.filter(pkg => pkg.name.toLowerCase().includes(q) ||
723
- pkg.description.toLowerCase().includes(q) ||
724
- pkg.category.toLowerCase().includes(q));
725
- }, [search, bundlePackages]);
726
- const packagesTotalKb = useMemo(() => {
727
- return filteredPackages.reduce((acc, p) => acc + p.sizeKb, 0);
728
- }, [filteredPackages]);
729
- const mediaFiles = useMemo(() => {
730
- return bundleFiles.filter(f => f.category === 'image' || f.category === 'font');
731
- }, [bundleFiles]);
732
- const mediaTotalKb = useMemo(() => {
733
- return mediaFiles.reduce((acc, m) => acc + m.sizeKb, 0);
734
- }, [mediaFiles]);
735
- const subTabs = [
736
- {
737
- key: 'overview',
738
- label: t('bundle.tabOverview'),
739
- icon: (isActive) => (<LiveStateIcon color={isActive ? AppColors.white : AppColors.purple} size={12}/>),
740
- },
741
- {
742
- key: 'production',
743
- label: t('bundle.tabProduction', { count: 3 }),
744
- icon: (isActive) => (<TimelineIcon color={isActive ? AppColors.white : AppColors.purple} size={12}/>),
745
- },
746
- {
747
- key: 'files',
748
- label: t('bundle.tabFiles', { count: bundleFiles.length }),
749
- icon: (isActive) => (<LayersIcon color={isActive ? AppColors.white : AppColors.purple} size={12}/>),
750
- },
751
- {
752
- key: 'packages',
753
- label: t('bundle.tabPackages', { count: bundlePackages.length }),
754
- icon: (isActive) => (<PackageIcon color={isActive ? AppColors.white : AppColors.purple} size={12}/>),
755
- },
756
- {
757
- key: 'media',
758
- label: t('bundle.tabMedia', { count: mediaFiles.length }),
759
- icon: (isActive) => (<StorageIcon color={isActive ? AppColors.white : AppColors.purple} size={12}/>),
760
- },
761
- {
762
- key: 'optimizer',
763
- label: t('bundle.tabOptimizer'),
764
- icon: (isActive) => (<MetadataIcon color={isActive ? AppColors.white : AppColors.purple} size={12}/>),
765
- },
766
- ];
767
- return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
131
+ `);try{await Nt.share(kt.OS==="ios"?{title:k.name,message:R}:{title:`Download ${k.name}`,message:R},{dialogTitle:`Download / Save ${k.name}`})}catch{}try{Et(R,k.name)}catch{}};const Dt=({node:k,level:M,search:R,totalBundleKb:v,expandedFolders:U,toggleFolder:P,isLastChild:W,onDownload:D})=>{const O=R?!0:!!U[k.fullPath],V=!O,Y=M*16+10;if(k.isFolder)return<T style={e.treeFolderBlock}>
132
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel={`Folder ${k.name}, ${k.fileCount} ${k.fileCount===1?"file":"files"}, ${k.sizeKb>=1024?`${(k.sizeKb/1024).toFixed(2)} MB`:`${k.sizeKb} KB`}`}accessibilityState={{expanded:O}}accessibilityHint="Double tap to expand or collapse folder"onPress={()=>P(k.fullPath)}style={[e.treeFolderRow,{paddingLeft:Y}]}>
133
+ <T style={e.treeRowLeft}>
134
+ <T style={{marginRight:4}}>
135
+ <So direction={V?"right":"down"}size={12}color={t.grayTextWeak}/>
136
+ </T>
137
+ {V?<Xt color={t.amber500}size={15}/>:<Yt color={t.amber500}size={15}/>}
138
+ <Ie text={k.name+"/"}search={R}style={e.treeFolderName}highlightStyle={e.searchHighlight}/>
139
+ <T style={e.treeCountBadge}>
140
+ <C style={e.treeCountBadgeText}>
141
+ {k.fileCount}{" "}
142
+ {k.fileCount===1?Ce("bundle.file"):Ce("bundle.files")}
143
+ </C>
144
+ </T>
145
+ </T>
146
+
147
+ <T style={e.treeRowRight}>
148
+ <C style={e.treeFolderSize}>
149
+ {k.sizeKb>=1024?Ce("bundle.fileSizeMb",{size:(k.sizeKb/1024).toFixed(2)}):Ce("bundle.fileSizeKb",{size:k.sizeKb})}
150
+ </C>
151
+ <K value={()=>({folder:k.fullPath,sizeKb:k.sizeKb,fileCount:k.fileCount})}label={Ce("bundle.copyFileInfo",{name:k.name})}/>
152
+ </T>
153
+ </G>
154
+
155
+ {!V&&<T style={e.treeChildrenContainer}>
156
+ {k.children.map((E,I)=><Dt key={E.id}node={E}level={M+1}search={R}totalBundleKb={v}expandedFolders={U}toggleFolder={P}isLastChild={I===k.children.length-1}onDownload={D}/>)}
157
+ </T>}
158
+ </T>;const A=k.fileItem;if(!A)return null;const Be=v>0?(A.sizeKb/v*100).toFixed(1):"0",ze=A.isConsumed===!1;return<T style={[e.treeFileRow,{paddingLeft:Y},ze&&e.treeFileRowUnused]}>
159
+ <T style={e.treeRowLeft}>
160
+ <T style={e.treeBranchGuide}>
161
+ <C style={e.treeBranchGuideText}>
162
+ {W?"\u2514":"\u251C"}
163
+ </C>
164
+ </T>
165
+
166
+ <_e file={A}/>
167
+
168
+ <Ie text={A.name}search={R}style={e.treeFileName}highlightStyle={e.searchHighlight}/>
169
+
170
+ {ze&&<T style={e.treeUnusedPill}>
171
+ <C style={e.treeUnusedPillText}>
172
+ {Ce("bundle.notConsumed")}
173
+ </C>
174
+ </T>}
175
+ </T>
176
+
177
+ <T style={e.treeRowRight}>
178
+ <T style={e.treeFileSizeGroup}>
179
+ <C style={[e.treeFileSizeText,ze&&{color:t.red600}]}>
180
+ {A.sizeKb>=1024?Ce("bundle.fileSizeMb",{size:(A.sizeKb/1024).toFixed(2)}):Ce("bundle.fileSizeKb",{size:A.sizeKb})}
181
+ </C>
182
+ <C style={e.treeFilePctText}>{Be}%</C>
183
+ </T>
184
+
185
+ <T style={{flexDirection:"row",alignItems:"center",gap:5}}>
186
+ {D&&<G accessible={!0}accessibilityRole="button"accessibilityLabel={`Download source code for ${A.name}`}accessibilityHint="Fetches module source code from Metro dev server"onPress={()=>D(A)}style={e.treeActionBtn}hitSlop={8}>
187
+ <Ze size={13}color={t.sky500}/>
188
+ </G>}
189
+
190
+ <K value={()=>A}label={Ce("bundle.fileDetailsJson")}/>
191
+ </T>
192
+ </T>
193
+ </T>},Ro=[{key:"ALL",labelKey:"bundle.catAll",iconType:"folder"},{key:"UNUSED",labelKey:"bundle.catUnused",iconType:"ban"},{key:"CONSUMED",labelKey:"bundle.catConsumed",iconType:"bolt"},{key:"image",labelKey:"bundle.catImages",iconType:"image"},{key:"typescript",labelKey:"bundle.catTypescript",iconType:"typescript"},{key:"javascript",labelKey:"bundle.catJavascript",iconType:"javascript"},{key:"font",labelKey:"bundle.catFonts",iconType:"font"},{key:"json",labelKey:"bundle.catJson",iconType:"json"}],Oe={image:{label:"Images & Media",color:t.pink500,bg:t.pink100},typescript:{label:"TypeScript",color:t.sky500,bg:t.sky100},javascript:{label:"JavaScript",color:t.indigo500,bg:t.indigo50},font:{label:"Fonts",color:t.purple500,bg:t.purple100},json:{label:"JSON / Data",color:t.emerald500,bg:t.emerald100}},Io=Ot.memo(()=>{const{t:k}=jt(),[M,R]=Q("overview"),[v,U]=Q("ios"),[P,W]=Q(""),[D,O]=Q("ALL"),[V,Y]=Q(()=>Bo()||Vo()),[A,Be]=Q(!1),ze=Ae(()=>{Be(!0),Lt(!0).then(o=>{Y(o),Be(!1)}).catch(()=>{Be(!1)})},[]);tt(()=>{let o=!0;return Lt().then(z=>{o&&(Y(z),Be(!1))}).catch(()=>{o&&Be(!1)}),()=>{o=!1}},[]);const E=!!global.HermesInternal,I=q(()=>V?V.files:[],[V]),J=q(()=>V?V.packages:[],[V]),B=q(()=>{const o=V?.totalDevKb||(V?.totalDevBytes?Math.round(V.totalDevBytes/1024):6144),z=V?.totalDevMb?V.totalDevMb.toFixed(2):(o/1024).toFixed(2),L=V?.splitUp?.nodeModules?.kb||Math.round(o*.52),H=V?.splitUp?.nodeModules?.pct||52,N=V?.splitUp?.metroDevOverhead?.kb||Math.round(o*.21),Ue=V?.splitUp?.metroDevOverhead?.pct||21,De=V?.splitUp?.appSource?.kb||Math.round(o*.15),Ne=V?.splitUp?.appSource?.pct||15,Re=V?.splitUp?.assetsMedia?.kb||Math.round(o*.12),We=V?.splitUp?.assetsMedia?.pct||12,$t=[{key:"node_modules",iconType:"javascript",title:"NPM Dependencies",targetTab:"packages",count:V?.packageCount||J.length||53,sizeKb:L,sizeMb:(L/1024).toFixed(2),pct:H,color:t.indigo500,desc:`${V?.packageCount||J.length||53} node_modules packages (React Native, React, navigation, axios)`},{key:"metro_runtime",iconType:"bolt",title:"Metro Dev Runtime",targetTab:"optimizer",count:1,sizeKb:N,sizeMb:(N/1024).toFixed(2),pct:Ue,color:t.amber500,desc:"Module loader, polyfills, HMR client, and prelude runtime"},{key:"app_source",iconType:"typescript",title:"App Source Code (TSX/JS)",targetTab:"files",count:I.filter(j=>j.category==="typescript"||j.category==="javascript").length||7,sizeKb:De,sizeMb:(De/1024).toFixed(2),pct:Ne,color:t.sky500,desc:"Screens, components, navigation, Redux store, and hooks"},{key:"assets_media",iconType:"image",title:"Images & Static Media",targetTab:"media",count:I.filter(j=>j.category==="image"||j.category==="font"||j.category==="json").length||3,sizeKb:Re,sizeMb:(Re/1024).toFixed(2),pct:We,color:t.pink500,desc:"Bundled PNG/JPG/SVG drawables, custom fonts, and JSON assets"}];return{totalKb:o,totalMb:z,totalCount:(V?.packageCount||53)+I.length+1,categories:$t,nodeModulesKb:L,nodeModulesPct:H,metroKb:N,metroPct:Ue,appSourceKb:De,appSourcePct:Ne,assetsMediaKb:Re,assetsMediaPct:We,images:{count:I.filter(j=>j.category==="image").length,kb:Re,pct:We},ts:{count:I.filter(j=>j.category==="typescript").length,kb:De,pct:Ne},js:{count:(V?.packageCount||53)+1,kb:L+N,pct:Number((H+Ue).toFixed(1))},fonts:{count:I.filter(j=>j.category==="font").length,kb:0,pct:0},json:{count:I.filter(j=>j.category==="json").length,kb:Math.round(Re*.1),pct:Number((We*.1).toFixed(1))}}},[V,I,J]),ke=q(()=>I.filter(o=>{const z=!P||o.name.toLowerCase().includes(P.toLowerCase())||o.path.toLowerCase().includes(P.toLowerCase())||o.ext.toLowerCase().includes(P.toLowerCase())||o.meta.toLowerCase().includes(P.toLowerCase()),L=D==="ALL"?!0:D==="UNUSED"?o.isConsumed===!1:D==="CONSUMED"?o.isConsumed!==!1:o.category===D;return z&&L}),[P,D,I]),qe=q(()=>ke.reduce((o,z)=>o+z.sizeKb,0),[ke]),[Se,Xe]=Q("tree"),[Ye,Le]=Q({}),Ve=q(()=>Po(ke),[ke]);tt(()=>{if(Ve.length>0&&Object.keys(Ye).length===0){const o={};Ve.forEach(z=>{z.isFolder&&(o[z.fullPath]=!0,z.children.forEach(L=>{L.isFolder&&(o[L.fullPath]=!0)}))}),Le(o)}},[Ve]);const Wt=Ae(o=>{Le(z=>({...z,[o]:!z[o]}))},[]),At=Ae(()=>{const o={};function z(L){for(const H of L)H.isFolder&&(o[H.fullPath]=!0,z(H.children))}z(Ve),Le(o)},[Ve]),Ht=Ae(()=>{Le({})},[]),Me=q(()=>{if(!P)return J;const o=P.toLowerCase();return J.filter(z=>z.name.toLowerCase().includes(o)||z.description.toLowerCase().includes(o)||z.category.toLowerCase().includes(o))},[P,J]),Qe=q(()=>Me.reduce((o,z)=>o+z.sizeKb,0),[Me]),ve=q(()=>I.filter(o=>o.category==="image"||o.category==="font"),[I]),et=q(()=>ve.reduce((o,z)=>o+z.sizeKb,0),[ve]),Kt=[{key:"overview",label:k("bundle.tabOverview"),icon:o=><Zt color={o?t.white:t.purple}size={12}/>},{key:"production",label:k("bundle.tabProduction",{count:3}),icon:o=><Jt color={o?t.white:t.purple}size={12}/>},{key:"files",label:k("bundle.tabFiles",{count:I.length}),icon:o=><Mt color={o?t.white:t.purple}size={12}/>},{key:"packages",label:k("bundle.tabPackages",{count:J.length}),icon:o=><Pe color={o?t.white:t.purple}size={12}/>},{key:"media",label:k("bundle.tabMedia",{count:ve.length}),icon:o=><Ee color={o?t.white:t.purple}size={12}/>},{key:"optimizer",label:k("bundle.tabOptimizer"),icon:o=><_t color={o?t.white:t.purple}size={12}/>}];return<T style={{flex:1,backgroundColor:t.grayBackground}}>
768
194
 
769
- <View style={bundleStyles.topTabWrap}>
770
- <ScrollView horizontal showsHorizontalScrollIndicator={false} style={{ flex: 1 }} contentContainerStyle={bundleStyles.subTabsScroll}>
771
- {subTabs.map(tab => {
772
- const isActive = activeSubTab === tab.key;
773
- return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={`${tab.label} tab`} accessibilityState={{ selected: isActive }} accessibilityHint={`Switches to ${tab.label} tab`} onPress={() => setActiveSubTab(tab.key)} style={[
774
- bundleStyles.subTabPill,
775
- isActive && bundleStyles.subTabPillActive,
776
- ]}>
777
- {tab.icon(isActive)}
778
- <Text style={[
779
- bundleStyles.subTabPillText,
780
- isActive && bundleStyles.subTabPillTextActive,
781
- ]}>
782
- {tab.label}
783
- </Text>
784
- </TouchableScale>);
785
- })}
786
- </ScrollView>
787
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={isAnalyzing ? 'Analyzing Metro bundle' : 'Reload bundle analysis'} accessibilityHint="Re-probes Metro dev server and refreshes bundle statistics" onPress={refreshAnalysis} style={bundleStyles.reloadButton} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
788
- {isAnalyzing ? (<ActivityIndicator size="small" color={AppColors.brandPurple}/>) : (<RefreshCcwIcon color={AppColors.brandPurple} size={14}/>)}
789
- </TouchableScale>
790
- </View>
791
-
792
- <FeatureUnderDevNotice featureName="Metro Bundle Analyzer"/>
195
+ <T style={e.topTabWrap}>
196
+ <Te horizontal showsHorizontalScrollIndicator={!1}style={{flex:1}}contentContainerStyle={e.subTabsScroll}>
197
+ {Kt.map(o=>{const z=M===o.key;return<G key={o.key}accessible={!0}accessibilityRole="tab"accessibilityLabel={`${o.label} tab`}accessibilityState={{selected:z}}accessibilityHint={`Switches to ${o.label} tab`}onPress={()=>R(o.key)}style={[e.subTabPill,z&&e.subTabPillActive]}>
198
+ {o.icon(z)}
199
+ <C style={[e.subTabPillText,z&&e.subTabPillTextActive]}>
200
+ {o.label}
201
+ </C>
202
+ </G>})}
203
+ </Te>
204
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel={A?"Analyzing Metro bundle":"Reload bundle analysis"}accessibilityHint="Re-probes Metro dev server and refreshes bundle statistics"onPress={ze}style={e.reloadButton}hitSlop={{top:8,bottom:8,left:8,right:8}}>
205
+ {A?<Tt size="small"color={t.brandPurple}/>:<Rt color={t.brandPurple}size={14}/>}
206
+ </G>
207
+ </T>
208
+
209
+ <Gt featureName="Metro Bundle Analyzer"/>
793
210
 
794
211
 
795
212
 
796
213
 
797
- {activeSubTab === 'overview' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
214
+ {M==="overview"&&<Te style={{flex:1}}contentContainerStyle={e.contentContainer}keyboardShouldPersistTaps="handled">
798
215
 
799
- <View style={bundleStyles.heroCard}>
800
- <View style={bundleStyles.heroTopRow}>
801
- <View style={bundleStyles.heroIconWrap}>
802
- <PackageIcon color={AppColors.brandPurple} size={24}/>
803
- </View>
804
- <View style={{ flex: 1 }}>
805
- <Text style={bundleStyles.heroTitle}>
806
- {t('bundle.heroTitle')}
807
- </Text>
808
- {analysis?.isLive && analysis.scriptURL ? (<View style={{ marginTop: 4, gap: 4 }}>
809
- <Text style={bundleStyles.heroSubtitle}>
810
- {t('bundle.heroSubtitle')}
811
- </Text>
812
- <Pressable accessible={true} accessibilityRole="link" accessibilityLabel={`Live Metro bundle URL: ${analysis.scriptURL}`} accessibilityHint="Opens Metro bundle script in browser" style={{
813
- backgroundColor: `${AppColors.skyBlue}10`,
814
- borderColor: `${AppColors.skyBlue}30`,
815
- borderWidth: 1,
816
- borderRadius: 8,
817
- padding: 8,
818
- marginTop: 2,
819
- }} onPress={() => Linking.openURL(analysis.scriptURL)}>
820
- <View style={{
821
- flexDirection: 'row',
822
- alignItems: 'center',
823
- justifyContent: 'space-between',
824
- marginBottom: 3,
825
- }}>
826
- <View style={{
827
- flexDirection: 'row',
828
- alignItems: 'center',
829
- gap: 4,
830
- }}>
831
- <ExternalLinkIcon color={AppColors.skyBlue} size={11}/>
832
- <Text style={{
833
- fontFamily: AppFonts.interBold,
834
- fontSize: 9.5,
835
- color: AppColors.skyBlue,
836
- letterSpacing: 0.3,
837
- textTransform: 'uppercase',
838
- }}>
216
+ <T style={e.heroCard}>
217
+ <T style={e.heroTopRow}>
218
+ <T style={e.heroIconWrap}>
219
+ <Pe color={t.brandPurple}size={24}/>
220
+ </T>
221
+ <T style={{flex:1}}>
222
+ <C style={e.heroTitle}>
223
+ {k("bundle.heroTitle")}
224
+ </C>
225
+ {V?.isLive&&V.scriptURL?<T style={{marginTop:4,gap:4}}>
226
+ <C style={e.heroSubtitle}>
227
+ {k("bundle.heroSubtitle")}
228
+ </C>
229
+ <He accessible={!0}accessibilityRole="link"accessibilityLabel={`Live Metro bundle URL: ${V.scriptURL}`}accessibilityHint="Opens Metro bundle script in browser"style={{backgroundColor:`${t.skyBlue}10`,borderColor:`${t.skyBlue}30`,borderWidth:1,borderRadius:8,padding:8,marginTop:2}}onPress={()=>Ct.openURL(V.scriptURL)}>
230
+ <T style={{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:3}}>
231
+ <T style={{flexDirection:"row",alignItems:"center",gap:4}}>
232
+ <Co color={t.skyBlue}size={11}/>
233
+ <C style={{fontFamily:S.interBold,fontSize:9.5,color:t.skyBlue,letterSpacing:.3,textTransform:"uppercase"}}>
839
234
  Live Metro URL
840
- </Text>
841
- </View>
842
- <Text style={{
843
- fontFamily: AppFonts.interRegular,
844
- fontSize: 9.5,
845
- color: AppColors.grayTextWeak,
846
- }}>
847
- {analysis.scriptURL.length} chars
848
- </Text>
849
- </View>
850
- <Text selectable={true} numberOfLines={1} ellipsizeMode="tail" style={{
851
- fontFamily: AppFonts.interMedium,
852
- fontSize: 11,
853
- color: AppColors.skyBlue,
854
- textDecorationLine: 'underline',
855
- lineHeight: 16,
856
- }}>
857
- {analysis.scriptURL}
858
- </Text>
859
- </Pressable>
860
- </View>) : (<Text style={bundleStyles.heroSubtitle}>
861
- {t('bundle.heroSubtitle')}
862
- </Text>)}
863
- </View>
864
- <CopyButton value={() => ({ ...summary, bundle: analysis })} label={t('bundle.bundleOverviewJson')}/>
865
- </View>
235
+ </C>
236
+ </T>
237
+ <C style={{fontFamily:S.interRegular,fontSize:9.5,color:t.grayTextWeak}}>
238
+ {V.scriptURL.length} chars
239
+ </C>
240
+ </T>
241
+ <C selectable={!0}numberOfLines={1}ellipsizeMode="tail"style={{fontFamily:S.interMedium,fontSize:11,color:t.skyBlue,textDecorationLine:"underline",lineHeight:16}}>
242
+ {V.scriptURL}
243
+ </C>
244
+ </He>
245
+ </T>:<C style={e.heroSubtitle}>
246
+ {k("bundle.heroSubtitle")}
247
+ </C>}
248
+ </T>
249
+ <K value={()=>({...B,bundle:V})}label={k("bundle.bundleOverviewJson")}/>
250
+ </T>
866
251
 
867
252
 
868
- <View style={bundleStyles.metricsGrid}>
869
- <View style={bundleStyles.metricBox}>
870
- <Text style={bundleStyles.metricLabel}>
871
- {t('bundle.devBundleSize')}
872
- </Text>
873
- <Text style={bundleStyles.metricValue}>
874
- {t('bundle.mbValue', {
875
- size: analysis ? analysis.totalDevMb : summary.totalMb,
876
- })}
877
- </Text>
878
- <Text style={bundleStyles.metricHint}>
879
- {analysis
880
- ? t('bundle.devBundleHint', {
881
- kb: analysis.totalDevKb,
882
- modules: analysis.moduleCount,
883
- })
884
- : t('bundle.trackedFilesHint', { count: bundleFiles.length })}
885
- </Text>
886
- </View>
887
-
888
- <View style={bundleStyles.metricBox}>
889
- <Text style={bundleStyles.metricLabel}>
890
- {t('bundle.imagesMedia')}
891
- </Text>
892
- <Text style={[
893
- bundleStyles.metricValue,
894
- { color: AppColors.pink500 },
895
- ]}>
896
- {t('bundle.fileSizeKb', { size: summary.images.kb })}
897
- </Text>
898
- <Text style={bundleStyles.metricHint}>
899
- {t('bundle.pctOfTrackedAssets', { pct: summary.images.pct })}
900
- </Text>
901
- </View>
902
-
903
- <View style={bundleStyles.metricBox}>
904
- <Text style={bundleStyles.metricLabel}>
905
- {t('bundle.tsJsSource')}
906
- </Text>
907
- <Text style={[bundleStyles.metricValue, { color: AppColors.sky500 }]}>
908
- {t('bundle.fileSizeKb', {
909
- size: summary.ts.kb + summary.js.kb,
910
- })}
911
- </Text>
912
- <Text style={bundleStyles.metricHint}>
913
- {t('bundle.pctOfTrackedAssets', {
914
- pct: (summary.ts.pct + summary.js.pct).toFixed(1),
915
- })}
916
- </Text>
917
- </View>
918
-
919
- <View style={bundleStyles.metricBox}>
920
- <Text style={bundleStyles.metricLabel}>
921
- {t('bundle.jsEngine')}
922
- </Text>
923
- <View style={{
924
- flexDirection: 'row',
925
- alignItems: 'center',
926
- gap: 5,
927
- marginTop: 2,
928
- }}>
929
- <View style={[
930
- bundleStyles.statusIndicator,
931
- {
932
- backgroundColor: isHermes
933
- ? AppColors.greenColor
934
- : AppColors.darkOrange,
935
- },
936
- ]}/>
937
- <Text style={bundleStyles.metricValue}>
938
- {isHermes ? 'Hermes' : 'JSC'}
939
- </Text>
940
- </View>
941
- <Text style={bundleStyles.metricHint}>
942
- {isHermes ? t('bundle.bytecodeAot') : t('bundle.standard')}
943
- </Text>
944
- </View>
945
- </View>
946
- </View>
253
+ <T style={e.metricsGrid}>
254
+ <T style={e.metricBox}>
255
+ <C style={e.metricLabel}>
256
+ {k("bundle.devBundleSize")}
257
+ </C>
258
+ <C style={e.metricValue}>
259
+ {k("bundle.mbValue",{size:V?V.totalDevMb:B.totalMb})}
260
+ </C>
261
+ <C style={e.metricHint}>
262
+ {V?k("bundle.devBundleHint",{kb:V.totalDevKb,modules:V.moduleCount}):k("bundle.trackedFilesHint",{count:I.length})}
263
+ </C>
264
+ </T>
265
+
266
+ <T style={e.metricBox}>
267
+ <C style={e.metricLabel}>
268
+ {k("bundle.imagesMedia")}
269
+ </C>
270
+ <C style={[e.metricValue,{color:t.pink500}]}>
271
+ {k("bundle.fileSizeKb",{size:B.images.kb})}
272
+ </C>
273
+ <C style={e.metricHint}>
274
+ {k("bundle.pctOfTrackedAssets",{pct:B.images.pct})}
275
+ </C>
276
+ </T>
277
+
278
+ <T style={e.metricBox}>
279
+ <C style={e.metricLabel}>
280
+ {k("bundle.tsJsSource")}
281
+ </C>
282
+ <C style={[e.metricValue,{color:t.sky500}]}>
283
+ {k("bundle.fileSizeKb",{size:B.ts.kb+B.js.kb})}
284
+ </C>
285
+ <C style={e.metricHint}>
286
+ {k("bundle.pctOfTrackedAssets",{pct:(B.ts.pct+B.js.pct).toFixed(1)})}
287
+ </C>
288
+ </T>
289
+
290
+ <T style={e.metricBox}>
291
+ <C style={e.metricLabel}>
292
+ {k("bundle.jsEngine")}
293
+ </C>
294
+ <T style={{flexDirection:"row",alignItems:"center",gap:5,marginTop:2}}>
295
+ <T style={[e.statusIndicator,{backgroundColor:E?t.greenColor:t.darkOrange}]}/>
296
+ <C style={e.metricValue}>
297
+ {E?"Hermes":"JSC"}
298
+ </C>
299
+ </T>
300
+ <C style={e.metricHint}>
301
+ {k(E?"bundle.bytecodeAot":"bundle.standard")}
302
+ </C>
303
+ </T>
304
+ </T>
305
+ </T>
947
306
 
948
307
 
949
- {analysis && !analysis.isLive && (<View style={bundleStyles.liveWarningCard}>
950
- <View style={{
951
- flexDirection: 'row',
952
- alignItems: 'center',
953
- gap: 6,
954
- flex: 1,
955
- }}>
956
- <CircleAlertIcon color={AppColors.amber700} size={16}/>
957
- <View style={{ flex: 1 }}>
958
- <Text style={bundleStyles.liveWarningTitle}>
959
- {t('bundle.liveAnalysisUnavailable')}
960
- </Text>
961
- <Text style={bundleStyles.liveWarningDesc}>
962
- {t('bundle.liveAnalysisUnavailableSub')}
963
- </Text>
964
- </View>
965
- <TouchableScale onPress={refreshAnalysis} style={{
966
- backgroundColor: `${AppColors.amber700}18`,
967
- paddingHorizontal: 8,
968
- paddingVertical: 5,
969
- borderRadius: 6,
970
- borderWidth: 1,
971
- borderColor: `${AppColors.amber700}30`,
972
- flexDirection: 'row',
973
- alignItems: 'center',
974
- gap: 4,
975
- }}>
976
- {isAnalyzing ? (<ActivityIndicator size="small" color={AppColors.amber700}/>) : (<>
977
- <RefreshCcwIcon color={AppColors.amber700} size={11}/>
978
- <Text style={{
979
- fontSize: 10.5,
980
- fontFamily: AppFonts.interBold,
981
- color: AppColors.amber700,
982
- }}>
308
+ {V&&!V.isLive&&<T style={e.liveWarningCard}>
309
+ <T style={{flexDirection:"row",alignItems:"center",gap:6,flex:1}}>
310
+ <Ge color={t.amber700}size={16}/>
311
+ <T style={{flex:1}}>
312
+ <C style={e.liveWarningTitle}>
313
+ {k("bundle.liveAnalysisUnavailable")}
314
+ </C>
315
+ <C style={e.liveWarningDesc}>
316
+ {k("bundle.liveAnalysisUnavailableSub")}
317
+ </C>
318
+ </T>
319
+ <G onPress={ze}style={{backgroundColor:`${t.amber700}18`,paddingHorizontal:8,paddingVertical:5,borderRadius:6,borderWidth:1,borderColor:`${t.amber700}30`,flexDirection:"row",alignItems:"center",gap:4}}>
320
+ {A?<Tt size="small"color={t.amber700}/>:<>
321
+ <Rt color={t.amber700}size={11}/>
322
+ <C style={{fontSize:10.5,fontFamily:S.interBold,color:t.amber700}}>
983
323
  Retry
984
- </Text>
985
- </>)}
986
- </TouchableScale>
987
- </View>
988
- </View>)}
324
+ </C>
325
+ </>}
326
+ </G>
327
+ </T>
328
+ </T>}
989
329
 
990
330
 
991
- <View style={bundleStyles.sectionCard}>
992
- <View style={bundleStyles.sectionHeaderRow}>
993
- <View style={{ flex: 1, paddingRight: 4 }}>
994
- <Text style={bundleStyles.sectionTitle}>
995
- {t('bundle.treemapTitle')}
996
- </Text>
997
- <Text style={bundleStyles.sectionSub}>
998
- {t('bundle.treemapSub', { mb: summary.totalMb })}
999
- </Text>
1000
- </View>
1001
- <CopyButton value={() => ({
1002
- totalMb: summary.totalMb,
1003
- totalKb: summary.totalKb,
1004
- nodeModules: {
1005
- kb: summary.nodeModulesKb,
1006
- pct: summary.nodeModulesPct,
1007
- },
1008
- metroRuntime: { kb: summary.metroKb, pct: summary.metroPct },
1009
- appSource: {
1010
- kb: summary.appSourceKb,
1011
- pct: summary.appSourcePct,
1012
- },
1013
- assetsMedia: {
1014
- kb: summary.assetsMediaKb,
1015
- pct: summary.assetsMediaPct,
1016
- },
1017
- })} label={t('bundle.treemapJson')}/>
1018
- </View>
331
+ <T style={e.sectionCard}>
332
+ <T style={e.sectionHeaderRow}>
333
+ <T style={{flex:1,paddingRight:4}}>
334
+ <C style={e.sectionTitle}>
335
+ {k("bundle.treemapTitle")}
336
+ </C>
337
+ <C style={e.sectionSub}>
338
+ {k("bundle.treemapSub",{mb:B.totalMb})}
339
+ </C>
340
+ </T>
341
+ <K value={()=>({totalMb:B.totalMb,totalKb:B.totalKb,nodeModules:{kb:B.nodeModulesKb,pct:B.nodeModulesPct},metroRuntime:{kb:B.metroKb,pct:B.metroPct},appSource:{kb:B.appSourceKb,pct:B.appSourcePct},assetsMedia:{kb:B.assetsMediaKb,pct:B.assetsMediaPct}})}label={k("bundle.treemapJson")}/>
342
+ </T>
1019
343
 
1020
344
 
1021
- <View style={bundleStyles.treemapBar}>
1022
- <View style={{
1023
- flex: summary.nodeModulesPct,
1024
- backgroundColor: AppColors.indigo500,
1025
- height: 16,
1026
- }}/>
1027
- <View style={{
1028
- flex: summary.metroPct,
1029
- backgroundColor: AppColors.amber500,
1030
- height: 16,
1031
- }}/>
1032
- <View style={{
1033
- flex: summary.appSourcePct,
1034
- backgroundColor: AppColors.sky500,
1035
- height: 16,
1036
- }}/>
1037
- <View style={{
1038
- flex: summary.assetsMediaPct,
1039
- backgroundColor: AppColors.pink500,
1040
- height: 16,
1041
- }}/>
1042
- </View>
345
+ <T style={e.treemapBar}>
346
+ <T style={{flex:B.nodeModulesPct,backgroundColor:t.indigo500,height:16}}/>
347
+ <T style={{flex:B.metroPct,backgroundColor:t.amber500,height:16}}/>
348
+ <T style={{flex:B.appSourcePct,backgroundColor:t.sky500,height:16}}/>
349
+ <T style={{flex:B.assetsMediaPct,backgroundColor:t.pink500,height:16}}/>
350
+ </T>
1043
351
 
1044
352
 
1045
- <View style={bundleStyles.legendGrid}>
1046
- <View style={bundleStyles.legendItem}>
1047
- <BundleCategoryIcon type="javascript" size={13} color={AppColors.indigo500}/>
1048
- <Text style={bundleStyles.legendText}>
1049
- Node Modules{' '}
1050
- <Text style={bundleStyles.legendVal}>
1051
- {summary.nodeModulesKb >= 1024
1052
- ? `${(summary.nodeModulesKb / 1024).toFixed(1)} MB`
1053
- : `${summary.nodeModulesKb} KB`}{' '}
1054
- ({summary.nodeModulesPct}%)
1055
- </Text>
1056
- </Text>
1057
- </View>
1058
- <View style={bundleStyles.legendItem}>
1059
- <BundleCategoryIcon type="overhead" size={13} color={AppColors.amber500}/>
1060
- <Text style={bundleStyles.legendText}>
1061
- Metro Runtime{' '}
1062
- <Text style={bundleStyles.legendVal}>
1063
- {summary.metroKb >= 1024
1064
- ? `${(summary.metroKb / 1024).toFixed(1)} MB`
1065
- : `${summary.metroKb} KB`}{' '}
1066
- ({summary.metroPct}%)
1067
- </Text>
1068
- </Text>
1069
- </View>
1070
- <View style={bundleStyles.legendItem}>
1071
- <BundleCategoryIcon type="typescript" size={13} color={AppColors.sky500}/>
1072
- <Text style={bundleStyles.legendText}>
1073
- App Source{' '}
1074
- <Text style={bundleStyles.legendVal}>
1075
- {summary.appSourceKb >= 1024
1076
- ? `${(summary.appSourceKb / 1024).toFixed(1)} MB`
1077
- : `${summary.appSourceKb} KB`}{' '}
1078
- ({summary.appSourcePct}%)
1079
- </Text>
1080
- </Text>
1081
- </View>
1082
- <View style={bundleStyles.legendItem}>
1083
- <BundleCategoryIcon type="image" size={13} color={AppColors.pink500}/>
1084
- <Text style={bundleStyles.legendText}>
1085
- Assets & Media{' '}
1086
- <Text style={bundleStyles.legendVal}>
1087
- {summary.assetsMediaKb >= 1024
1088
- ? `${(summary.assetsMediaKb / 1024).toFixed(1)} MB`
1089
- : `${summary.assetsMediaKb} KB`}{' '}
1090
- ({summary.assetsMediaPct}%)
1091
- </Text>
1092
- </Text>
1093
- </View>
1094
- </View>
1095
- </View>
353
+ <T style={e.legendGrid}>
354
+ <T style={e.legendItem}>
355
+ <Z type="javascript"size={13}color={t.indigo500}/>
356
+ <C style={e.legendText}>
357
+ Node Modules{" "}
358
+ <C style={e.legendVal}>
359
+ {B.nodeModulesKb>=1024?`${(B.nodeModulesKb/1024).toFixed(1)} MB`:`${B.nodeModulesKb} KB`}{" "}
360
+ ({B.nodeModulesPct}%)
361
+ </C>
362
+ </C>
363
+ </T>
364
+ <T style={e.legendItem}>
365
+ <Z type="overhead"size={13}color={t.amber500}/>
366
+ <C style={e.legendText}>
367
+ Metro Runtime{" "}
368
+ <C style={e.legendVal}>
369
+ {B.metroKb>=1024?`${(B.metroKb/1024).toFixed(1)} MB`:`${B.metroKb} KB`}{" "}
370
+ ({B.metroPct}%)
371
+ </C>
372
+ </C>
373
+ </T>
374
+ <T style={e.legendItem}>
375
+ <Z type="typescript"size={13}color={t.sky500}/>
376
+ <C style={e.legendText}>
377
+ App Source{" "}
378
+ <C style={e.legendVal}>
379
+ {B.appSourceKb>=1024?`${(B.appSourceKb/1024).toFixed(1)} MB`:`${B.appSourceKb} KB`}{" "}
380
+ ({B.appSourcePct}%)
381
+ </C>
382
+ </C>
383
+ </T>
384
+ <T style={e.legendItem}>
385
+ <Z type="image"size={13}color={t.pink500}/>
386
+ <C style={e.legendText}>
387
+ Assets & Media{" "}
388
+ <C style={e.legendVal}>
389
+ {B.assetsMediaKb>=1024?`${(B.assetsMediaKb/1024).toFixed(1)} MB`:`${B.assetsMediaKb} KB`}{" "}
390
+ ({B.assetsMediaPct}%)
391
+ </C>
392
+ </C>
393
+ </T>
394
+ </T>
395
+ </T>
1096
396
 
1097
397
 
1098
- <View style={bundleStyles.sectionCard}>
1099
- <View style={bundleStyles.sectionHeaderRow}>
1100
- <Text style={bundleStyles.sectionTitle}>
1101
- {t('bundle.categoryBreakdown')}
1102
- </Text>
1103
- <CopyButton value={() => summary} label={t('bundle.categoriesJson')}/>
1104
- </View>
1105
-
1106
- {summary.categories.map((cat, cIdx) => (<Pressable key={cIdx} accessible={true} accessibilityRole="button" accessibilityLabel={`${cat.title}, ${cat.sizeKb >= 1024 ? `${cat.sizeMb} MB` : `${cat.sizeKb} KB`}, ${cat.pct}% of bundle`} accessibilityHint={`Double tap to view ${cat.title} details`} style={({ pressed }) => [
1107
- bundleStyles.catRowCard,
1108
- pressed && { opacity: 0.85, transform: [{ scale: 0.99 }] },
1109
- ]} onPress={() => setActiveSubTab(cat.targetTab)}>
1110
- <View style={bundleStyles.catRowTop}>
1111
- <View style={[
1112
- bundleStyles.catIconBox,
1113
- {
1114
- backgroundColor: `${cat.color}15`,
1115
- borderColor: `${cat.color}30`,
1116
- },
1117
- ]}>
1118
- <BundleCategoryIcon type={cat.iconType} size={18} color={cat.color}/>
1119
- </View>
1120
-
1121
- <View style={bundleStyles.catRowTitleWrap}>
1122
- <View style={{
1123
- flexDirection: 'row',
1124
- alignItems: 'center',
1125
- justifyContent: 'space-between',
1126
- gap: 6,
1127
- }}>
1128
- <Text style={bundleStyles.catRowTitle} numberOfLines={1}>
1129
- {cat.title}
1130
- </Text>
1131
- <View style={{
1132
- flexDirection: 'row',
1133
- alignItems: 'center',
1134
- gap: 6,
1135
- }}>
1136
- <Text style={bundleStyles.catRowSize}>
1137
- {cat.sizeKb >= 1024
1138
- ? `${cat.sizeMb} MB`
1139
- : `${cat.sizeKb} KB`}
1140
- </Text>
1141
- <View style={[
1142
- bundleStyles.catPctPill,
1143
- { backgroundColor: `${cat.color}18` },
1144
- ]}>
1145
- <Text style={[
1146
- bundleStyles.catPctText,
1147
- { color: cat.color },
1148
- ]}>
1149
- {cat.pct}%
1150
- </Text>
1151
- </View>
1152
- </View>
1153
- </View>
1154
-
1155
- <Text style={bundleStyles.catRowDesc} numberOfLines={2}>
1156
- {cat.count} items • {cat.desc}
1157
- </Text>
1158
- </View>
1159
- </View>
398
+ <T style={e.sectionCard}>
399
+ <T style={e.sectionHeaderRow}>
400
+ <C style={e.sectionTitle}>
401
+ {k("bundle.categoryBreakdown")}
402
+ </C>
403
+ <K value={()=>B}label={k("bundle.categoriesJson")}/>
404
+ </T>
405
+
406
+ {B.categories.map((o,z)=><He key={z}accessible={!0}accessibilityRole="button"accessibilityLabel={`${o.title}, ${o.sizeKb>=1024?`${o.sizeMb} MB`:`${o.sizeKb} KB`}, ${o.pct}% of bundle`}accessibilityHint={`Double tap to view ${o.title} details`}style={({pressed:L})=>[e.catRowCard,L&&{opacity:.85,transform:[{scale:.99}]}]}onPress={()=>R(o.targetTab)}>
407
+ <T style={e.catRowTop}>
408
+ <T style={[e.catIconBox,{backgroundColor:`${o.color}15`,borderColor:`${o.color}30`}]}>
409
+ <Z type={o.iconType}size={18}color={o.color}/>
410
+ </T>
411
+
412
+ <T style={e.catRowTitleWrap}>
413
+ <T style={{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:6}}>
414
+ <C style={e.catRowTitle}numberOfLines={1}>
415
+ {o.title}
416
+ </C>
417
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
418
+ <C style={e.catRowSize}>
419
+ {o.sizeKb>=1024?`${o.sizeMb} MB`:`${o.sizeKb} KB`}
420
+ </C>
421
+ <T style={[e.catPctPill,{backgroundColor:`${o.color}18`}]}>
422
+ <C style={[e.catPctText,{color:o.color}]}>
423
+ {o.pct}%
424
+ </C>
425
+ </T>
426
+ </T>
427
+ </T>
428
+
429
+ <C style={e.catRowDesc}numberOfLines={2}>
430
+ {o.count} items • {o.desc}
431
+ </C>
432
+ </T>
433
+ </T>
1160
434
 
1161
435
 
1162
- <View style={bundleStyles.catProgressTrack}>
1163
- <View style={[
1164
- bundleStyles.catProgressBar,
1165
- { width: `${cat.pct}%`, backgroundColor: cat.color },
1166
- ]}/>
1167
- </View>
1168
- </Pressable>))}
436
+ <T style={e.catProgressTrack}>
437
+ <T style={[e.catProgressBar,{width:`${o.pct}%`,backgroundColor:o.color}]}/>
438
+ </T>
439
+ </He>)}
1169
440
 
1170
441
 
1171
- <View style={bundleStyles.totalSummaryCard}>
1172
- <View style={bundleStyles.totalSummaryRow}>
1173
- <View style={bundleStyles.totalSummaryLabelWrap}>
1174
- <View style={bundleStyles.totalIconBadge}>
1175
- <PackageIcon color={AppColors.brandPurple} size={16}/>
1176
- </View>
1177
- <View>
1178
- <Text style={bundleStyles.totalSummaryLabel}>
442
+ <T style={e.totalSummaryCard}>
443
+ <T style={e.totalSummaryRow}>
444
+ <T style={e.totalSummaryLabelWrap}>
445
+ <T style={e.totalIconBadge}>
446
+ <Pe color={t.brandPurple}size={16}/>
447
+ </T>
448
+ <T>
449
+ <C style={e.totalSummaryLabel}>
1179
450
  TOTAL BUNDLE ASSETS
1180
- </Text>
1181
- <Text style={bundleStyles.totalSummarySub}>
1182
- {summary.totalCount} Tracked Modules & Media Assets
1183
- </Text>
1184
- </View>
1185
- </View>
1186
- <View style={{ alignItems: 'flex-end' }}>
1187
- <Text style={bundleStyles.totalSummaryValue}>
1188
- {summary.totalMb} MB
1189
- </Text>
1190
- <Text style={bundleStyles.totalSummaryKb}>
1191
- {summary.totalKb.toLocaleString()} KB
1192
- </Text>
1193
- </View>
1194
- </View>
451
+ </C>
452
+ <C style={e.totalSummarySub}>
453
+ {B.totalCount} Tracked Modules & Media Assets
454
+ </C>
455
+ </T>
456
+ </T>
457
+ <T style={{alignItems:"flex-end"}}>
458
+ <C style={e.totalSummaryValue}>
459
+ {B.totalMb} MB
460
+ </C>
461
+ <C style={e.totalSummaryKb}>
462
+ {B.totalKb.toLocaleString()} KB
463
+ </C>
464
+ </T>
465
+ </T>
1195
466
 
1196
467
 
1197
- <View style={bundleStyles.totalFormulaGrid}>
1198
- <View style={bundleStyles.totalChip}>
1199
- <View style={[
1200
- bundleStyles.totalDot,
1201
- { backgroundColor: AppColors.indigo500 },
1202
- ]}/>
1203
- <Text style={bundleStyles.totalChipText}>
1204
- NPM: {(summary.nodeModulesKb / 1024).toFixed(1)}M (
1205
- {summary.nodeModulesPct}%)
1206
- </Text>
1207
- </View>
1208
- <View style={bundleStyles.totalChip}>
1209
- <View style={[
1210
- bundleStyles.totalDot,
1211
- { backgroundColor: AppColors.amber500 },
1212
- ]}/>
1213
- <Text style={bundleStyles.totalChipText}>
1214
- Metro: {(summary.metroKb / 1024).toFixed(1)}M (
1215
- {summary.metroPct}%)
1216
- </Text>
1217
- </View>
1218
- <View style={bundleStyles.totalChip}>
1219
- <View style={[
1220
- bundleStyles.totalDot,
1221
- { backgroundColor: AppColors.sky500 },
1222
- ]}/>
1223
- <Text style={bundleStyles.totalChipText}>
1224
- Source: {(summary.appSourceKb / 1024).toFixed(1)}M (
1225
- {summary.appSourcePct}%)
1226
- </Text>
1227
- </View>
1228
- <View style={bundleStyles.totalChip}>
1229
- <View style={[
1230
- bundleStyles.totalDot,
1231
- { backgroundColor: AppColors.pink500 },
1232
- ]}/>
1233
- <Text style={bundleStyles.totalChipText}>
1234
- Media: {summary.assetsMediaKb}K ({summary.assetsMediaPct}%)
1235
- </Text>
1236
- </View>
1237
- </View>
1238
- </View>
1239
- </View>
468
+ <T style={e.totalFormulaGrid}>
469
+ <T style={e.totalChip}>
470
+ <T style={[e.totalDot,{backgroundColor:t.indigo500}]}/>
471
+ <C style={e.totalChipText}>
472
+ NPM: {(B.nodeModulesKb/1024).toFixed(1)}M (
473
+ {B.nodeModulesPct}%)
474
+ </C>
475
+ </T>
476
+ <T style={e.totalChip}>
477
+ <T style={[e.totalDot,{backgroundColor:t.amber500}]}/>
478
+ <C style={e.totalChipText}>
479
+ Metro: {(B.metroKb/1024).toFixed(1)}M (
480
+ {B.metroPct}%)
481
+ </C>
482
+ </T>
483
+ <T style={e.totalChip}>
484
+ <T style={[e.totalDot,{backgroundColor:t.sky500}]}/>
485
+ <C style={e.totalChipText}>
486
+ Source: {(B.appSourceKb/1024).toFixed(1)}M (
487
+ {B.appSourcePct}%)
488
+ </C>
489
+ </T>
490
+ <T style={e.totalChip}>
491
+ <T style={[e.totalDot,{backgroundColor:t.pink500}]}/>
492
+ <C style={e.totalChipText}>
493
+ Media: {B.assetsMediaKb}K ({B.assetsMediaPct}%)
494
+ </C>
495
+ </T>
496
+ </T>
497
+ </T>
498
+ </T>
1240
499
 
1241
500
 
1242
- <View style={bundleStyles.sectionCard}>
1243
- <View style={bundleStyles.sectionHeaderRow}>
1244
- <View style={{ flex: 1, paddingRight: 4 }}>
1245
- <Text style={bundleStyles.sectionTitle}>
501
+ <T style={e.sectionCard}>
502
+ <T style={e.sectionHeaderRow}>
503
+ <T style={{flex:1,paddingRight:4}}>
504
+ <C style={e.sectionTitle}>
1246
505
  Bundle Subsystem Breakdown
1247
- </Text>
1248
- <Text style={bundleStyles.sectionSub}>
506
+ </C>
507
+ <C style={e.sectionSub}>
1249
508
  Granular analysis of packages, application source, engine
1250
509
  runtime & assets
1251
- </Text>
1252
- </View>
1253
- <CopyButton value={() => ({
1254
- directPackages: bundlePackages.filter(p => p.type === 'direct').length,
1255
- transitivePackages: bundlePackages.filter(p => p.type !== 'direct').length,
1256
- hermesEngine: isHermes ? 'Hermes (Bytecode)' : 'JSC (Source)',
1257
- jsDevKb: summary.totalKb,
1258
- jsHermesReleaseKb: Math.round(summary.totalKb * 0.38),
1259
- appSourceFiles: bundleFiles.filter(f => f.category === 'typescript' ||
1260
- f.category === 'javascript').length,
1261
- mediaAssets: bundleFiles.filter(f => f.category === 'image' ||
1262
- f.category === 'font' ||
1263
- f.category === 'json').length,
1264
- })} label="Subsystem Split JSON"/>
1265
- </View>
510
+ </C>
511
+ </T>
512
+ <K value={()=>({directPackages:J.filter(o=>o.type==="direct").length,transitivePackages:J.filter(o=>o.type!=="direct").length,hermesEngine:E?"Hermes (Bytecode)":"JSC (Source)",jsDevKb:B.totalKb,jsHermesReleaseKb:Math.round(B.totalKb*.38),appSourceFiles:I.filter(o=>o.category==="typescript"||o.category==="javascript").length,mediaAssets:I.filter(o=>o.category==="image"||o.category==="font"||o.category==="json").length})}label="Subsystem Split JSON"/>
513
+ </T>
1266
514
 
1267
515
 
1268
- <View style={bundleStyles.subsystemCard}>
1269
- <View style={bundleStyles.subsystemHeader}>
1270
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1271
- <BundleCategoryIcon type="deps" size={16} color={AppColors.indigo500}/>
1272
- <Text style={bundleStyles.subsystemTitle}>
516
+ <T style={e.subsystemCard}>
517
+ <T style={e.subsystemHeader}>
518
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
519
+ <Z type="deps"size={16}color={t.indigo500}/>
520
+ <C style={e.subsystemTitle}>
1273
521
  NPM & Third-Party Dependencies
1274
- </Text>
1275
- </View>
1276
- <View style={[
1277
- bundleStyles.subsystemBadge,
1278
- { backgroundColor: `${AppColors.indigo500}18` },
1279
- ]}>
1280
- <Text style={[
1281
- bundleStyles.subsystemBadgeText,
1282
- { color: AppColors.indigo500 },
1283
- ]}>
1284
- {(summary.nodeModulesKb / 1024).toFixed(1)} MB •{' '}
1285
- {summary.nodeModulesPct}%
1286
- </Text>
1287
- </View>
1288
- </View>
1289
- <View style={bundleStyles.subsystemGrid}>
1290
- <View style={bundleStyles.subsystemItem}>
1291
- <Text style={bundleStyles.subsystemItemText}>
1292
- Direct:{' '}
1293
- <Text style={bundleStyles.subsystemItemVal}>
1294
- {bundlePackages.filter(p => p.type === 'direct').length ||
1295
- 12}{' '}
522
+ </C>
523
+ </T>
524
+ <T style={[e.subsystemBadge,{backgroundColor:`${t.indigo500}18`}]}>
525
+ <C style={[e.subsystemBadgeText,{color:t.indigo500}]}>
526
+ {(B.nodeModulesKb/1024).toFixed(1)} MB •{" "}
527
+ {B.nodeModulesPct}%
528
+ </C>
529
+ </T>
530
+ </T>
531
+ <T style={e.subsystemGrid}>
532
+ <T style={e.subsystemItem}>
533
+ <C style={e.subsystemItemText}>
534
+ Direct:{" "}
535
+ <C style={e.subsystemItemVal}>
536
+ {J.filter(o=>o.type==="direct").length||12}{" "}
1296
537
  pkgs
1297
- </Text>
1298
- </Text>
1299
- </View>
1300
- <View style={bundleStyles.subsystemItem}>
1301
- <Text style={bundleStyles.subsystemItemText}>
1302
- Transitive:{' '}
1303
- <Text style={bundleStyles.subsystemItemVal}>
1304
- {bundlePackages.filter(p => p.type !== 'direct').length ||
1305
- 41}{' '}
538
+ </C>
539
+ </C>
540
+ </T>
541
+ <T style={e.subsystemItem}>
542
+ <C style={e.subsystemItemText}>
543
+ Transitive:{" "}
544
+ <C style={e.subsystemItemVal}>
545
+ {J.filter(o=>o.type!=="direct").length||41}{" "}
1306
546
  pkgs
1307
- </Text>
1308
- </Text>
1309
- </View>
1310
- <View style={bundleStyles.subsystemItem}>
1311
- <Text style={bundleStyles.subsystemItemText}>
1312
- Top Package:{' '}
1313
- <Text style={bundleStyles.subsystemItemVal}>
1314
- {bundlePackages[0]?.name || 'react-native'} (
1315
- {bundlePackages[0]?.sizeKb || 1240} KB)
1316
- </Text>
1317
- </Text>
1318
- </View>
1319
- </View>
1320
- </View>
547
+ </C>
548
+ </C>
549
+ </T>
550
+ <T style={e.subsystemItem}>
551
+ <C style={e.subsystemItemText}>
552
+ Top Package:{" "}
553
+ <C style={e.subsystemItemVal}>
554
+ {J[0]?.name||"react-native"} (
555
+ {J[0]?.sizeKb||1240} KB)
556
+ </C>
557
+ </C>
558
+ </T>
559
+ </T>
560
+ </T>
1321
561
 
1322
562
 
1323
- <View style={bundleStyles.subsystemCard}>
1324
- <View style={bundleStyles.subsystemHeader}>
1325
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1326
- <BundleCategoryIcon type="source" size={16} color={AppColors.sky500}/>
1327
- <Text style={bundleStyles.subsystemTitle}>
563
+ <T style={e.subsystemCard}>
564
+ <T style={e.subsystemHeader}>
565
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
566
+ <Z type="source"size={16}color={t.sky500}/>
567
+ <C style={e.subsystemTitle}>
1328
568
  Application Source Code
1329
- </Text>
1330
- </View>
1331
- <View style={[
1332
- bundleStyles.subsystemBadge,
1333
- { backgroundColor: `${AppColors.sky500}18` },
1334
- ]}>
1335
- <Text style={[
1336
- bundleStyles.subsystemBadgeText,
1337
- { color: AppColors.sky500 },
1338
- ]}>
1339
- {(summary.appSourceKb / 1024).toFixed(1)} MB •{' '}
1340
- {summary.appSourcePct}%
1341
- </Text>
1342
- </View>
1343
- </View>
1344
- <View style={bundleStyles.subsystemGrid}>
1345
- <View style={bundleStyles.subsystemItem}>
1346
- <Text style={bundleStyles.subsystemItemText}>
1347
- TypeScript/TSX:{' '}
1348
- <Text style={bundleStyles.subsystemItemVal}>
1349
- {bundleFiles.filter(f => f.category === 'typescript')
1350
- .length || 14}{' '}
569
+ </C>
570
+ </T>
571
+ <T style={[e.subsystemBadge,{backgroundColor:`${t.sky500}18`}]}>
572
+ <C style={[e.subsystemBadgeText,{color:t.sky500}]}>
573
+ {(B.appSourceKb/1024).toFixed(1)} MB •{" "}
574
+ {B.appSourcePct}%
575
+ </C>
576
+ </T>
577
+ </T>
578
+ <T style={e.subsystemGrid}>
579
+ <T style={e.subsystemItem}>
580
+ <C style={e.subsystemItemText}>
581
+ TypeScript/TSX:{" "}
582
+ <C style={e.subsystemItemVal}>
583
+ {I.filter(o=>o.category==="typescript").length||14}{" "}
1351
584
  files
1352
- </Text>
1353
- </Text>
1354
- </View>
1355
- <View style={bundleStyles.subsystemItem}>
1356
- <Text style={bundleStyles.subsystemItemText}>
1357
- JavaScript/JSX:{' '}
1358
- <Text style={bundleStyles.subsystemItemVal}>
1359
- {bundleFiles.filter(f => f.category === 'javascript')
1360
- .length || 3}{' '}
585
+ </C>
586
+ </C>
587
+ </T>
588
+ <T style={e.subsystemItem}>
589
+ <C style={e.subsystemItemText}>
590
+ JavaScript/JSX:{" "}
591
+ <C style={e.subsystemItemVal}>
592
+ {I.filter(o=>o.category==="javascript").length||3}{" "}
1361
593
  files
1362
- </Text>
1363
- </Text>
1364
- </View>
1365
- <View style={bundleStyles.subsystemItem}>
1366
- <Text style={bundleStyles.subsystemItemText}>
1367
- Tracked Modules:{' '}
1368
- <Text style={bundleStyles.subsystemItemVal}>
1369
- {bundleFiles.length || 18} files
1370
- </Text>
1371
- </Text>
1372
- </View>
1373
- </View>
1374
- </View>
594
+ </C>
595
+ </C>
596
+ </T>
597
+ <T style={e.subsystemItem}>
598
+ <C style={e.subsystemItemText}>
599
+ Tracked Modules:{" "}
600
+ <C style={e.subsystemItemVal}>
601
+ {I.length||18} files
602
+ </C>
603
+ </C>
604
+ </T>
605
+ </T>
606
+ </T>
1375
607
 
1376
608
 
1377
- <View style={bundleStyles.subsystemCard}>
1378
- <View style={bundleStyles.subsystemHeader}>
1379
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1380
- <BundleCategoryIcon type="bolt" size={16} color={AppColors.emerald600}/>
1381
- <Text style={bundleStyles.subsystemTitle}>
609
+ <T style={e.subsystemCard}>
610
+ <T style={e.subsystemHeader}>
611
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
612
+ <Z type="bolt"size={16}color={t.emerald600}/>
613
+ <C style={e.subsystemTitle}>
1382
614
  Hermes Bytecode Engine
1383
- </Text>
1384
- </View>
1385
- <View style={[
1386
- bundleStyles.subsystemBadge,
1387
- { backgroundColor: `${AppColors.emerald500}18` },
1388
- ]}>
1389
- <Text style={[
1390
- bundleStyles.subsystemBadgeText,
1391
- { color: AppColors.emerald700 },
1392
- ]}>
615
+ </C>
616
+ </T>
617
+ <T style={[e.subsystemBadge,{backgroundColor:`${t.emerald500}18`}]}>
618
+ <C style={[e.subsystemBadgeText,{color:t.emerald700}]}>
1393
619
  ~62% AOT Compression
1394
- </Text>
1395
- </View>
1396
- </View>
1397
- <View style={bundleStyles.subsystemGrid}>
1398
- <View style={bundleStyles.subsystemItem}>
1399
- <Text style={bundleStyles.subsystemItemText}>
1400
- Dev JS Size:{' '}
1401
- <Text style={bundleStyles.subsystemItemVal}>
1402
- {summary.totalMb} MB
1403
- </Text>
1404
- </Text>
1405
- </View>
1406
- <View style={bundleStyles.subsystemItem}>
1407
- <Text style={bundleStyles.subsystemItemText}>
1408
- Hermes Bytecode:{' '}
1409
- <Text style={bundleStyles.subsystemItemVal}>
1410
- {((summary.totalKb * 0.38) / 1024).toFixed(2)} MB
1411
- </Text>
1412
- </Text>
1413
- </View>
1414
- <View style={bundleStyles.subsystemItem}>
1415
- <Text style={bundleStyles.subsystemItemText}>
1416
- Execution:{' '}
1417
- <Text style={bundleStyles.subsystemItemVal}>
1418
- {isHermes ? 'Hermes JSI Direct' : 'JSC Standard'}
1419
- </Text>
1420
- </Text>
1421
- </View>
1422
- </View>
1423
- </View>
620
+ </C>
621
+ </T>
622
+ </T>
623
+ <T style={e.subsystemGrid}>
624
+ <T style={e.subsystemItem}>
625
+ <C style={e.subsystemItemText}>
626
+ Dev JS Size:{" "}
627
+ <C style={e.subsystemItemVal}>
628
+ {B.totalMb} MB
629
+ </C>
630
+ </C>
631
+ </T>
632
+ <T style={e.subsystemItem}>
633
+ <C style={e.subsystemItemText}>
634
+ Hermes Bytecode:{" "}
635
+ <C style={e.subsystemItemVal}>
636
+ {(B.totalKb*.38/1024).toFixed(2)} MB
637
+ </C>
638
+ </C>
639
+ </T>
640
+ <T style={e.subsystemItem}>
641
+ <C style={e.subsystemItemText}>
642
+ Execution:{" "}
643
+ <C style={e.subsystemItemVal}>
644
+ {E?"Hermes JSI Direct":"JSC Standard"}
645
+ </C>
646
+ </C>
647
+ </T>
648
+ </T>
649
+ </T>
1424
650
 
1425
651
 
1426
- <View style={bundleStyles.subsystemCard}>
1427
- <View style={bundleStyles.subsystemHeader}>
1428
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
1429
- <BundleCategoryIcon type="media" size={16} color={AppColors.pink500}/>
1430
- <Text style={bundleStyles.subsystemTitle}>
652
+ <T style={e.subsystemCard}>
653
+ <T style={e.subsystemHeader}>
654
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
655
+ <Z type="media"size={16}color={t.pink500}/>
656
+ <C style={e.subsystemTitle}>
1431
657
  Images, Fonts & Static Assets
1432
- </Text>
1433
- </View>
1434
- <View style={[
1435
- bundleStyles.subsystemBadge,
1436
- { backgroundColor: `${AppColors.pink500}18` },
1437
- ]}>
1438
- <Text style={[
1439
- bundleStyles.subsystemBadgeText,
1440
- { color: AppColors.pink500 },
1441
- ]}>
1442
- {summary.assetsMediaKb} KB • {summary.assetsMediaPct}%
1443
- </Text>
1444
- </View>
1445
- </View>
1446
- <View style={bundleStyles.subsystemGrid}>
1447
- <View style={bundleStyles.subsystemItem}>
1448
- <Text style={bundleStyles.subsystemItemText}>
1449
- Images & Icons:{' '}
1450
- <Text style={bundleStyles.subsystemItemVal}>
1451
- {bundleFiles.filter(f => f.category === 'image').length ||
1452
- 2}{' '}
658
+ </C>
659
+ </T>
660
+ <T style={[e.subsystemBadge,{backgroundColor:`${t.pink500}18`}]}>
661
+ <C style={[e.subsystemBadgeText,{color:t.pink500}]}>
662
+ {B.assetsMediaKb} KB • {B.assetsMediaPct}%
663
+ </C>
664
+ </T>
665
+ </T>
666
+ <T style={e.subsystemGrid}>
667
+ <T style={e.subsystemItem}>
668
+ <C style={e.subsystemItemText}>
669
+ Images & Icons:{" "}
670
+ <C style={e.subsystemItemVal}>
671
+ {I.filter(o=>o.category==="image").length||2}{" "}
1453
672
  assets
1454
- </Text>
1455
- </Text>
1456
- </View>
1457
- <View style={bundleStyles.subsystemItem}>
1458
- <Text style={bundleStyles.subsystemItemText}>
1459
- JSON Data:{' '}
1460
- <Text style={bundleStyles.subsystemItemVal}>
1461
- {bundleFiles.filter(f => f.category === 'json').length ||
1462
- 1}{' '}
673
+ </C>
674
+ </C>
675
+ </T>
676
+ <T style={e.subsystemItem}>
677
+ <C style={e.subsystemItemText}>
678
+ JSON Data:{" "}
679
+ <C style={e.subsystemItemVal}>
680
+ {I.filter(o=>o.category==="json").length||1}{" "}
1463
681
  files
1464
- </Text>
1465
- </Text>
1466
- </View>
1467
- <View style={bundleStyles.subsystemItem}>
1468
- <Text style={bundleStyles.subsystemItemText}>
1469
- Custom Fonts:{' '}
1470
- <Text style={bundleStyles.subsystemItemVal}>
1471
- {bundleFiles.filter(f => f.category === 'font').length ||
1472
- 0}{' '}
682
+ </C>
683
+ </C>
684
+ </T>
685
+ <T style={e.subsystemItem}>
686
+ <C style={e.subsystemItemText}>
687
+ Custom Fonts:{" "}
688
+ <C style={e.subsystemItemVal}>
689
+ {I.filter(o=>o.category==="font").length||0}{" "}
1473
690
  fonts
1474
- </Text>
1475
- </Text>
1476
- </View>
1477
- </View>
1478
- </View>
1479
- </View>
1480
- </ScrollView>)}
691
+ </C>
692
+ </C>
693
+ </T>
694
+ </T>
695
+ </T>
696
+ </T>
697
+ </Te>}
1481
698
 
1482
699
 
1483
700
 
1484
701
 
1485
- {activeSubTab === 'production' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
702
+ {M==="production"&&<Te style={{flex:1}}contentContainerStyle={e.contentContainer}keyboardShouldPersistTaps="handled">
1486
703
 
1487
- <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={bundleStyles.prodPlatformScroll}>
1488
- {[
1489
- {
1490
- key: 'ios',
1491
- label: 'iOS App (.ipa)',
1492
- badge: `${analysis?.production.ios.totalDownloadMb || 111.9} MB`,
1493
- },
1494
- {
1495
- key: 'androidAab',
1496
- label: 'Android AAB (.aab)',
1497
- badge: `${analysis?.production.androidAab.totalDownloadMb || 38.5} MB`,
1498
- },
1499
- {
1500
- key: 'androidApk',
1501
- label: 'Universal APK (.apk)',
1502
- badge: `${analysis?.production.androidApk.totalInstallMb || 364.0} MB`,
1503
- },
1504
- ].map(tab => {
1505
- const isSelected = prodPlatform === tab.key;
1506
- return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={`${tab.label}, ${tab.badge}`} accessibilityState={{ selected: isSelected }} accessibilityHint={`Switches production estimate to ${tab.label}`} onPress={() => setProdPlatform(tab.key)} style={[
1507
- bundleStyles.prodPlatformBtn,
1508
- isSelected && bundleStyles.prodPlatformBtnActive,
1509
- ]}>
1510
- <Text style={[
1511
- bundleStyles.prodPlatformBtnText,
1512
- isSelected && bundleStyles.prodPlatformBtnTextActive,
1513
- ]}>
1514
- {tab.label}
1515
- </Text>
1516
- <View style={[
1517
- bundleStyles.prodPlatformBadge,
1518
- isSelected && bundleStyles.prodPlatformBadgeActive,
1519
- ]}>
1520
- <Text style={[
1521
- bundleStyles.prodPlatformBadgeText,
1522
- isSelected && bundleStyles.prodPlatformBadgeTextActive,
1523
- ]}>
1524
- {tab.badge}
1525
- </Text>
1526
- </View>
1527
- </TouchableScale>);
1528
- })}
1529
- </ScrollView>
704
+ <Te horizontal showsHorizontalScrollIndicator={!1}contentContainerStyle={e.prodPlatformScroll}>
705
+ {[{key:"ios",label:"iOS App (.ipa)",badge:`${V?.production.ios.totalDownloadMb||111.9} MB`},{key:"androidAab",label:"Android AAB (.aab)",badge:`${V?.production.androidAab.totalDownloadMb||38.5} MB`},{key:"androidApk",label:"Universal APK (.apk)",badge:`${V?.production.androidApk.totalInstallMb||364} MB`}].map(o=>{const z=v===o.key;return<G key={o.key}accessible={!0}accessibilityRole="tab"accessibilityLabel={`${o.label}, ${o.badge}`}accessibilityState={{selected:z}}accessibilityHint={`Switches production estimate to ${o.label}`}onPress={()=>U(o.key)}style={[e.prodPlatformBtn,z&&e.prodPlatformBtnActive]}>
706
+ <C style={[e.prodPlatformBtnText,z&&e.prodPlatformBtnTextActive]}>
707
+ {o.label}
708
+ </C>
709
+ <T style={[e.prodPlatformBadge,z&&e.prodPlatformBadgeActive]}>
710
+ <C style={[e.prodPlatformBadgeText,z&&e.prodPlatformBadgeTextActive]}>
711
+ {o.badge}
712
+ </C>
713
+ </T>
714
+ </G>})}
715
+ </Te>
1530
716
 
1531
717
 
1532
- {analysis && (<View style={bundleStyles.heroCard}>
1533
- <View style={bundleStyles.heroTopRow}>
1534
- <View style={bundleStyles.heroIconWrap}>
1535
- <PackageIcon color={AppColors.brandPurple} size={24}/>
1536
- </View>
1537
- <View style={{ flex: 1 }}>
1538
- <Text style={bundleStyles.heroTitle}>
1539
- {prodPlatform === 'ios'
1540
- ? 'iOS Production Binary Footprint'
1541
- : prodPlatform === 'androidAab'
1542
- ? 'Google Play App Bundle (.aab)'
1543
- : 'Universal Standalone APK (.apk)'}
1544
- </Text>
1545
- <Text style={bundleStyles.heroSubtitle}>
1546
- {prodPlatform === 'ios'
1547
- ? 'App Store install & over-the-air cellular download estimates'
1548
- : prodPlatform === 'androidAab'
1549
- ? 'Optimized per-device dynamic delivery split APK architecture'
1550
- : 'Multi-ABI universal install archive for sideloading & direct distribution'}
1551
- </Text>
1552
- </View>
1553
- <CopyButton value={() => analysis.production[prodPlatform]} label="Production Binary JSON"/>
1554
- </View>
718
+ {V&&<T style={e.heroCard}>
719
+ <T style={e.heroTopRow}>
720
+ <T style={e.heroIconWrap}>
721
+ <Pe color={t.brandPurple}size={24}/>
722
+ </T>
723
+ <T style={{flex:1}}>
724
+ <C style={e.heroTitle}>
725
+ {v==="ios"?"iOS Production Binary Footprint":v==="androidAab"?"Google Play App Bundle (.aab)":"Universal Standalone APK (.apk)"}
726
+ </C>
727
+ <C style={e.heroSubtitle}>
728
+ {v==="ios"?"App Store install & over-the-air cellular download estimates":v==="androidAab"?"Optimized per-device dynamic delivery split APK architecture":"Multi-ABI universal install archive for sideloading & direct distribution"}
729
+ </C>
730
+ </T>
731
+ <K value={()=>V.production[v]}label="Production Binary JSON"/>
732
+ </T>
1555
733
 
1556
734
 
1557
- <View style={bundleStyles.metricsGrid}>
1558
- <View style={bundleStyles.metricBox}>
1559
- <Text style={bundleStyles.metricLabel}>INSTALL SIZE</Text>
1560
- <Text style={[
1561
- bundleStyles.metricValue,
1562
- { color: AppColors.purple },
1563
- ]}>
1564
- {analysis.production[prodPlatform].totalInstallMb} MB
1565
- </Text>
1566
- <Text style={bundleStyles.metricHint}>
735
+ <T style={e.metricsGrid}>
736
+ <T style={e.metricBox}>
737
+ <C style={e.metricLabel}>INSTALL SIZE</C>
738
+ <C style={[e.metricValue,{color:t.purple}]}>
739
+ {V.production[v].totalInstallMb} MB
740
+ </C>
741
+ <C style={e.metricHint}>
1567
742
  On-device uncompressed footprint
1568
- </Text>
1569
- </View>
1570
-
1571
- <View style={bundleStyles.metricBox}>
1572
- <Text style={bundleStyles.metricLabel}>DOWNLOAD SIZE</Text>
1573
- <Text style={[
1574
- bundleStyles.metricValue,
1575
- { color: AppColors.emerald600 },
1576
- ]}>
1577
- ~{analysis.production[prodPlatform].totalDownloadMb} MB
1578
- </Text>
1579
- <Text style={bundleStyles.metricHint}>
743
+ </C>
744
+ </T>
745
+
746
+ <T style={e.metricBox}>
747
+ <C style={e.metricLabel}>DOWNLOAD SIZE</C>
748
+ <C style={[e.metricValue,{color:t.emerald600}]}>
749
+ ~{V.production[v].totalDownloadMb} MB
750
+ </C>
751
+ <C style={e.metricHint}>
1580
752
  Store network transfer payload
1581
- </Text>
1582
- </View>
1583
-
1584
- <View style={bundleStyles.metricBox}>
1585
- <Text style={bundleStyles.metricLabel}>COMPRESSION</Text>
1586
- <Text style={[
1587
- bundleStyles.metricValue,
1588
- { color: AppColors.sky500 },
1589
- ]}>
1590
- {analysis.production[prodPlatform].compressionRatioPct}%
1591
- </Text>
1592
- <Text style={bundleStyles.metricHint}>
753
+ </C>
754
+ </T>
755
+
756
+ <T style={e.metricBox}>
757
+ <C style={e.metricLabel}>COMPRESSION</C>
758
+ <C style={[e.metricValue,{color:t.sky500}]}>
759
+ {V.production[v].compressionRatioPct}%
760
+ </C>
761
+ <C style={e.metricHint}>
1593
762
  Bytecode & asset ratio
1594
- </Text>
1595
- </View>
763
+ </C>
764
+ </T>
1596
765
 
1597
- <View style={bundleStyles.metricBox}>
1598
- <Text style={bundleStyles.metricLabel}>
766
+ <T style={e.metricBox}>
767
+ <C style={e.metricLabel}>
1599
768
  FORMAT ARCHITECTURE
1600
- </Text>
1601
- <Text style={[
1602
- bundleStyles.metricValue,
1603
- { color: AppColors.amber700 },
1604
- ]}>
1605
- {prodPlatform === 'ios'
1606
- ? 'Mach-O 64-bit'
1607
- : prodPlatform === 'androidAab'
1608
- ? 'Split APKs'
1609
- : 'FAT Multi-ABI'}
1610
- </Text>
1611
- <Text style={bundleStyles.metricHint}>
1612
- {prodPlatform === 'ios'
1613
- ? 'Apple ARM64 runtime'
1614
- : prodPlatform === 'androidAab'
1615
- ? 'Dynamic Google Play delivery'
1616
- : 'Sideload universal package'}
1617
- </Text>
1618
- </View>
1619
- </View>
1620
- </View>)}
769
+ </C>
770
+ <C style={[e.metricValue,{color:t.amber700}]}>
771
+ {v==="ios"?"Mach-O 64-bit":v==="androidAab"?"Split APKs":"FAT Multi-ABI"}
772
+ </C>
773
+ <C style={e.metricHint}>
774
+ {v==="ios"?"Apple ARM64 runtime":v==="androidAab"?"Dynamic Google Play delivery":"Sideload universal package"}
775
+ </C>
776
+ </T>
777
+ </T>
778
+ </T>}
1621
779
 
1622
780
 
1623
- {analysis && (<View style={bundleStyles.sectionCard}>
1624
- <View style={bundleStyles.sectionHeaderRow}>
1625
- <View style={{ flex: 1, paddingRight: 4 }}>
1626
- <Text style={bundleStyles.sectionTitle}>
781
+ {V&&<T style={e.sectionCard}>
782
+ <T style={e.sectionHeaderRow}>
783
+ <T style={{flex:1,paddingRight:4}}>
784
+ <C style={e.sectionTitle}>
1627
785
  Binary Component Architecture
1628
- </Text>
1629
- <Text style={bundleStyles.sectionSub}>
786
+ </C>
787
+ <C style={e.sectionSub}>
1630
788
  Compiled native libraries, runtime bytecodes, assets, and
1631
789
  signature blocks
1632
- </Text>
1633
- </View>
1634
- <CopyButton value={() => analysis.production[prodPlatform].components} label="Components JSON"/>
1635
- </View>
790
+ </C>
791
+ </T>
792
+ <K value={()=>V.production[v].components}label="Components JSON"/>
793
+ </T>
1636
794
 
1637
795
 
1638
- <View style={bundleStyles.prodTreemapBar}>
1639
- {analysis.production[prodPlatform].components.map((comp, cIdx) => (<View key={cIdx} style={{
1640
- flex: Math.max(comp.pct, 2),
1641
- backgroundColor: comp.color,
1642
- height: 16,
1643
- }}/>))}
1644
- </View>
796
+ <T style={e.prodTreemapBar}>
797
+ {V.production[v].components.map((o,z)=><T key={z}style={{flex:Math.max(o.pct,2),backgroundColor:o.color,height:16}}/>)}
798
+ </T>
1645
799
 
1646
800
 
1647
- <View style={[bundleStyles.legendGrid, { marginBottom: 12 }]}>
1648
- {analysis.production[prodPlatform].components.map((comp, cIdx) => (<View key={cIdx} style={bundleStyles.legendItem}>
1649
- <View style={{
1650
- width: 8,
1651
- height: 8,
1652
- borderRadius: 4,
1653
- backgroundColor: comp.color,
1654
- }}/>
1655
- <Text style={bundleStyles.legendText} numberOfLines={1}>
1656
- {comp.name}{' '}
1657
- <Text style={bundleStyles.legendVal}>
1658
- {comp.sizeMb} MB ({comp.pct}%)
1659
- </Text>
1660
- </Text>
1661
- </View>))}
1662
- </View>
1663
-
1664
- {analysis.production[prodPlatform].components.map((comp, idx) => (<View key={idx} style={bundleStyles.catRowCard}>
1665
- <View style={bundleStyles.catRowTop}>
1666
- <View style={[
1667
- bundleStyles.catIconBox,
1668
- {
1669
- backgroundColor: `${comp.color}15`,
1670
- borderColor: `${comp.color}30`,
1671
- },
1672
- ]}>
1673
- <BundleCategoryIcon type={comp.category === 'native'
1674
- ? 'source'
1675
- : comp.category === 'frameworks'
1676
- ? 'deps'
1677
- : comp.category === 'assets'
1678
- ? 'media'
1679
- : comp.category === 'js'
1680
- ? 'javascript'
1681
- : 'overhead'} size={18} color={comp.color}/>
1682
- </View>
1683
-
1684
- <View style={bundleStyles.catRowTitleWrap}>
1685
- <View style={{
1686
- flexDirection: 'row',
1687
- alignItems: 'center',
1688
- justifyContent: 'space-between',
1689
- gap: 6,
1690
- }}>
1691
- <Text style={bundleStyles.catRowTitle} numberOfLines={1}>
1692
- {comp.name}
1693
- </Text>
1694
- <View style={{
1695
- flexDirection: 'row',
1696
- alignItems: 'center',
1697
- gap: 6,
1698
- }}>
1699
- <Text style={bundleStyles.catRowSize}>
1700
- {comp.sizeMb} MB
1701
- </Text>
1702
- <View style={[
1703
- bundleStyles.catPctPill,
1704
- { backgroundColor: `${comp.color}18` },
1705
- ]}>
1706
- <Text style={[
1707
- bundleStyles.catPctText,
1708
- { color: comp.color },
1709
- ]}>
1710
- {comp.pct}%
1711
- </Text>
1712
- </View>
1713
- </View>
1714
- </View>
1715
-
1716
- <Text style={bundleStyles.catRowDesc} numberOfLines={2}>
1717
- {comp.description}
1718
- </Text>
1719
- </View>
1720
- </View>
1721
-
1722
- <View style={bundleStyles.catProgressTrack}>
1723
- <View style={[
1724
- bundleStyles.catProgressBar,
1725
- { width: `${comp.pct}%`, backgroundColor: comp.color },
1726
- ]}/>
1727
- </View>
1728
-
1729
- {comp.advice ? (<View style={[
1730
- bundleStyles.adviceBadge,
1731
- bundleStyles.adviceOptimal,
1732
- { marginTop: 6 },
1733
- ]}>
1734
- <LightbulbIcon color={AppColors.emerald700} size={13}/>
1735
- <Text style={[
1736
- bundleStyles.adviceText,
1737
- { color: AppColors.emerald700, flex: 1, marginLeft: 4 },
1738
- ]}>
1739
- {comp.advice}
1740
- </Text>
1741
- </View>) : null}
1742
- </View>))}
801
+ <T style={[e.legendGrid,{marginBottom:12}]}>
802
+ {V.production[v].components.map((o,z)=><T key={z}style={e.legendItem}>
803
+ <T style={{width:8,height:8,borderRadius:4,backgroundColor:o.color}}/>
804
+ <C style={e.legendText}numberOfLines={1}>
805
+ {o.name}{" "}
806
+ <C style={e.legendVal}>
807
+ {o.sizeMb} MB ({o.pct}%)
808
+ </C>
809
+ </C>
810
+ </T>)}
811
+ </T>
812
+
813
+ {V.production[v].components.map((o,z)=><T key={z}style={e.catRowCard}>
814
+ <T style={e.catRowTop}>
815
+ <T style={[e.catIconBox,{backgroundColor:`${o.color}15`,borderColor:`${o.color}30`}]}>
816
+ <Z type={o.category==="native"?"source":o.category==="frameworks"?"deps":o.category==="assets"?"media":o.category==="js"?"javascript":"overhead"}size={18}color={o.color}/>
817
+ </T>
818
+
819
+ <T style={e.catRowTitleWrap}>
820
+ <T style={{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:6}}>
821
+ <C style={e.catRowTitle}numberOfLines={1}>
822
+ {o.name}
823
+ </C>
824
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
825
+ <C style={e.catRowSize}>
826
+ {o.sizeMb} MB
827
+ </C>
828
+ <T style={[e.catPctPill,{backgroundColor:`${o.color}18`}]}>
829
+ <C style={[e.catPctText,{color:o.color}]}>
830
+ {o.pct}%
831
+ </C>
832
+ </T>
833
+ </T>
834
+ </T>
835
+
836
+ <C style={e.catRowDesc}numberOfLines={2}>
837
+ {o.description}
838
+ </C>
839
+ </T>
840
+ </T>
841
+
842
+ <T style={e.catProgressTrack}>
843
+ <T style={[e.catProgressBar,{width:`${o.pct}%`,backgroundColor:o.color}]}/>
844
+ </T>
845
+
846
+ {o.advice?<T style={[e.adviceBadge,e.adviceOptimal,{marginTop:6}]}>
847
+ <Je color={t.emerald700}size={13}/>
848
+ <C style={[e.adviceText,{color:t.emerald700,flex:1,marginLeft:4}]}>
849
+ {o.advice}
850
+ </C>
851
+ </T>:null}
852
+ </T>)}
1743
853
 
1744
854
 
1745
- <View style={bundleStyles.totalSummaryCard}>
1746
- <View style={bundleStyles.totalSummaryRow}>
1747
- <View style={bundleStyles.totalSummaryLabelWrap}>
1748
- <View style={bundleStyles.totalIconBadge}>
1749
- <PackageIcon color={AppColors.brandPurple} size={16}/>
1750
- </View>
1751
- <View>
1752
- <Text style={bundleStyles.totalSummaryLabel}>
1753
- {prodPlatform === 'ios'
1754
- ? 'TOTAL IOS APP BINARY'
1755
- : prodPlatform === 'androidAab'
1756
- ? 'TOTAL ANDROID AAB BUNDLE'
1757
- : 'TOTAL UNIVERSAL APK'}
1758
- </Text>
1759
- <Text style={bundleStyles.totalSummarySub}>
1760
- {prodPlatform === 'ios'
1761
- ? 'App Store install & cellular download estimates'
1762
- : prodPlatform === 'androidAab'
1763
- ? 'Google Play dynamic delivery split APK'
1764
- : 'Universal standalone sideload package'}
1765
- </Text>
1766
- </View>
1767
- </View>
1768
- </View>
855
+ <T style={e.totalSummaryCard}>
856
+ <T style={e.totalSummaryRow}>
857
+ <T style={e.totalSummaryLabelWrap}>
858
+ <T style={e.totalIconBadge}>
859
+ <Pe color={t.brandPurple}size={16}/>
860
+ </T>
861
+ <T>
862
+ <C style={e.totalSummaryLabel}>
863
+ {v==="ios"?"TOTAL IOS APP BINARY":v==="androidAab"?"TOTAL ANDROID AAB BUNDLE":"TOTAL UNIVERSAL APK"}
864
+ </C>
865
+ <C style={e.totalSummarySub}>
866
+ {v==="ios"?"App Store install & cellular download estimates":v==="androidAab"?"Google Play dynamic delivery split APK":"Universal standalone sideload package"}
867
+ </C>
868
+ </T>
869
+ </T>
870
+ </T>
1769
871
 
1770
872
 
1771
- <View style={bundleStyles.totalFormulaGrid}>
1772
- <View style={bundleStyles.totalChip}>
1773
- <View style={[
1774
- bundleStyles.totalDot,
1775
- { backgroundColor: AppColors.purple },
1776
- ]}/>
1777
- <Text style={bundleStyles.totalChipText}>
1778
- Install:{' '}
1779
- {analysis.production[prodPlatform].totalInstallMb} MB
1780
- </Text>
1781
- </View>
1782
- <View style={bundleStyles.totalChip}>
1783
- <View style={[
1784
- bundleStyles.totalDot,
1785
- { backgroundColor: AppColors.sky500 },
1786
- ]}/>
1787
- <Text style={bundleStyles.totalChipText}>
873
+ <T style={e.totalFormulaGrid}>
874
+ <T style={e.totalChip}>
875
+ <T style={[e.totalDot,{backgroundColor:t.purple}]}/>
876
+ <C style={e.totalChipText}>
877
+ Install:{" "}
878
+ {V.production[v].totalInstallMb} MB
879
+ </C>
880
+ </T>
881
+ <T style={e.totalChip}>
882
+ <T style={[e.totalDot,{backgroundColor:t.sky500}]}/>
883
+ <C style={e.totalChipText}>
1788
884
  Download: ~
1789
- {analysis.production[prodPlatform].totalDownloadMb} MB
1790
- </Text>
1791
- </View>
1792
- <View style={bundleStyles.totalChip}>
1793
- <View style={[
1794
- bundleStyles.totalDot,
1795
- { backgroundColor: AppColors.emerald500 },
1796
- ]}/>
1797
- <Text style={bundleStyles.totalChipText}>
1798
- Compression:{' '}
1799
- {analysis.production[prodPlatform].compressionRatioPct}%
1800
- </Text>
1801
- </View>
1802
- </View>
1803
- </View>
1804
- </View>)}
1805
- </ScrollView>)}
885
+ {V.production[v].totalDownloadMb} MB
886
+ </C>
887
+ </T>
888
+ <T style={e.totalChip}>
889
+ <T style={[e.totalDot,{backgroundColor:t.emerald500}]}/>
890
+ <C style={e.totalChipText}>
891
+ Compression:{" "}
892
+ {V.production[v].compressionRatioPct}%
893
+ </C>
894
+ </T>
895
+ </T>
896
+ </T>
897
+ </T>}
898
+ </Te>}
1806
899
 
1807
900
 
1808
901
 
1809
902
 
1810
- {activeSubTab === 'files' && (<View style={{ flex: 1 }}>
903
+ {M==="files"&&<T style={{flex:1}}>
1811
904
 
1812
- <View style={bundleStyles.filterContainer}>
1813
- <View style={bundleStyles.searchRow}>
1814
- <SearchIcon color={AppColors.grayTextWeak} size={15}/>
1815
- <TextInput accessible={true} accessibilityRole="search" accessibilityLabel="Search files" accessibilityHint="Type a filename, path, or extension to filter" placeholder={t('bundle.searchFilesPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
1816
- {search.length > 0 && (<Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Clear search input" onPress={() => setSearch('')} hitSlop={10}>
1817
- <ClearIcon color={AppColors.grayTextWeak} size={14}/>
1818
- </Pressable>)}
1819
- <CopyButton value={() => filteredFiles} label={t('bundle.filteredFilesJson')}/>
1820
- </View>
905
+ <T style={e.filterContainer}>
906
+ <T style={e.searchRow}>
907
+ <Bt color={t.grayTextWeak}size={15}/>
908
+ <St accessible={!0}accessibilityRole="search"accessibilityLabel="Search files"accessibilityHint="Type a filename, path, or extension to filter"placeholder={k("bundle.searchFilesPlaceholder")}placeholderTextColor={t.grayTextWeak}value={P}onChangeText={W}style={e.searchInput}autoCorrect={!1}autoCapitalize="none"/>
909
+ {P.length>0&&<He accessible={!0}accessibilityRole="button"accessibilityLabel="Clear search input"onPress={()=>W("")}hitSlop={10}>
910
+ <Vt color={t.grayTextWeak}size={14}/>
911
+ </He>}
912
+ <K value={()=>ke}label={k("bundle.filteredFilesJson")}/>
913
+ </T>
1821
914
 
1822
915
 
1823
- <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={bundleStyles.categoryPillsScroll}>
1824
- {CATEGORY_TABS.map(tab => {
1825
- const isActive = activeCategory === tab.key;
1826
- const count = tab.key === 'ALL'
1827
- ? bundleFiles.length
1828
- : tab.key === 'UNUSED'
1829
- ? bundleFiles.filter(f => f.isConsumed === false).length
1830
- : tab.key === 'CONSUMED'
1831
- ? bundleFiles.filter(f => f.isConsumed !== false).length
1832
- : bundleFiles.filter(f => f.category === tab.key).length;
1833
- return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="button" accessibilityLabel={`Filter by ${t(tab.labelKey)}, ${count} items`} accessibilityState={{ selected: isActive }} accessibilityHint={`Filters files list to ${t(tab.labelKey)}`} onPress={() => setActiveCategory(tab.key)} style={[
1834
- bundleStyles.catPill,
1835
- isActive && bundleStyles.catPillActive,
1836
- tab.key === 'UNUSED' &&
1837
- isActive && {
1838
- backgroundColor: AppColors.red500,
1839
- borderColor: AppColors.red600,
1840
- },
1841
- tab.key === 'CONSUMED' &&
1842
- isActive && {
1843
- backgroundColor: AppColors.emerald600,
1844
- borderColor: AppColors.emerald700,
1845
- },
1846
- ]}>
1847
- <BundleCategoryIcon type={tab.iconType} size={12} color={isActive ? AppColors.white : AppColors.grayTextStrong}/>
1848
- <Text style={[
1849
- bundleStyles.catPillText,
1850
- isActive && bundleStyles.catPillTextActive,
1851
- ]}>
1852
- {t(tab.labelKey)} ({count})
1853
- </Text>
1854
- </TouchableScale>);
1855
- })}
1856
- </ScrollView>
1857
- </View>
916
+ <Te horizontal showsHorizontalScrollIndicator={!1}contentContainerStyle={e.categoryPillsScroll}>
917
+ {Ro.map(o=>{const z=D===o.key,L=o.key==="ALL"?I.length:o.key==="UNUSED"?I.filter(H=>H.isConsumed===!1).length:o.key==="CONSUMED"?I.filter(H=>H.isConsumed!==!1).length:I.filter(H=>H.category===o.key).length;return<G key={o.key}accessible={!0}accessibilityRole="button"accessibilityLabel={`Filter by ${k(o.labelKey)}, ${L} items`}accessibilityState={{selected:z}}accessibilityHint={`Filters files list to ${k(o.labelKey)}`}onPress={()=>O(o.key)}style={[e.catPill,z&&e.catPillActive,o.key==="UNUSED"&&z&&{backgroundColor:t.red500,borderColor:t.red600},o.key==="CONSUMED"&&z&&{backgroundColor:t.emerald600,borderColor:t.emerald700}]}>
918
+ <Z type={o.iconType}size={12}color={z?t.white:t.grayTextStrong}/>
919
+ <C style={[e.catPillText,z&&e.catPillTextActive]}>
920
+ {k(o.labelKey)} ({L})
921
+ </C>
922
+ </G>})}
923
+ </Te>
924
+ </T>
1858
925
 
1859
926
 
1860
- <ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
927
+ <Te style={{flex:1}}contentContainerStyle={e.contentContainer}keyboardShouldPersistTaps="handled">
1861
928
 
1862
- <View style={bundleStyles.treeHeaderRow}>
1863
- <View style={bundleStyles.viewModeToggleGroup}>
1864
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Tree folder view" accessibilityState={{ selected: filesViewMode === 'tree' }} onPress={() => setFilesViewMode('tree')} style={[
1865
- bundleStyles.viewModeBtn,
1866
- filesViewMode === 'tree' && bundleStyles.viewModeBtnActive,
1867
- ]}>
1868
- <Text style={[
1869
- bundleStyles.viewModeBtnText,
1870
- filesViewMode === 'tree' &&
1871
- bundleStyles.viewModeBtnTextActive,
1872
- ]}>
1873
- {t('bundle.treeView')}
1874
- </Text>
1875
- </TouchableScale>
1876
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Flat list view" accessibilityState={{ selected: filesViewMode === 'list' }} onPress={() => setFilesViewMode('list')} style={[
1877
- bundleStyles.viewModeBtn,
1878
- filesViewMode === 'list' && bundleStyles.viewModeBtnActive,
1879
- ]}>
1880
- <Text style={[
1881
- bundleStyles.viewModeBtnText,
1882
- filesViewMode === 'list' &&
1883
- bundleStyles.viewModeBtnTextActive,
1884
- ]}>
1885
- {t('bundle.flatList')}
1886
- </Text>
1887
- </TouchableScale>
1888
- </View>
1889
-
1890
- {filesViewMode === 'tree' ? (<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
1891
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Expand all folders" onPress={expandAllFolders}>
1892
- <Text style={bundleStyles.treeActionLink}>
1893
- {t('bundle.expand')}
1894
- </Text>
1895
- </TouchableScale>
1896
- <Text style={{ color: AppColors.grayTextWeak, fontSize: 11 }}>
929
+ <T style={e.treeHeaderRow}>
930
+ <T style={e.viewModeToggleGroup}>
931
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel="Tree folder view"accessibilityState={{selected:Se==="tree"}}onPress={()=>Xe("tree")}style={[e.viewModeBtn,Se==="tree"&&e.viewModeBtnActive]}>
932
+ <C style={[e.viewModeBtnText,Se==="tree"&&e.viewModeBtnTextActive]}>
933
+ {k("bundle.treeView")}
934
+ </C>
935
+ </G>
936
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel="Flat list view"accessibilityState={{selected:Se==="list"}}onPress={()=>Xe("list")}style={[e.viewModeBtn,Se==="list"&&e.viewModeBtnActive]}>
937
+ <C style={[e.viewModeBtnText,Se==="list"&&e.viewModeBtnTextActive]}>
938
+ {k("bundle.flatList")}
939
+ </C>
940
+ </G>
941
+ </T>
942
+
943
+ {Se==="tree"?<T style={{flexDirection:"row",alignItems:"center",gap:8}}>
944
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel="Expand all folders"onPress={At}>
945
+ <C style={e.treeActionLink}>
946
+ {k("bundle.expand")}
947
+ </C>
948
+ </G>
949
+ <C style={{color:t.grayTextWeak,fontSize:11}}>
1897
950
  •
1898
- </Text>
1899
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Collapse all folders" onPress={collapseAllFolders}>
1900
- <Text style={bundleStyles.treeActionLink}>
1901
- {t('bundle.collapse')}
1902
- </Text>
1903
- </TouchableScale>
1904
- </View>) : (<Text style={bundleStyles.listHeaderCount}>
1905
- {t('bundle.showingFilesOf', {
1906
- shown: filteredFiles.length,
1907
- total: bundleFiles.length,
1908
- })}
1909
- </Text>)}
1910
- </View>
951
+ </C>
952
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel="Collapse all folders"onPress={Ht}>
953
+ <C style={e.treeActionLink}>
954
+ {k("bundle.collapse")}
955
+ </C>
956
+ </G>
957
+ </T>:<C style={e.listHeaderCount}>
958
+ {k("bundle.showingFilesOf",{shown:ke.length,total:I.length})}
959
+ </C>}
960
+ </T>
1911
961
 
1912
962
 
1913
- {filesViewMode === 'tree' ? (<View style={bundleStyles.treeRootCard}>
1914
- {fileTreeNodes.map((node, nIdx) => (<BundleTreeNodeView key={node.id} node={node} level={0} search={search} totalBundleKb={summary.totalKb} expandedFolders={expandedFolders} toggleFolder={toggleFolder} isLastChild={nIdx === fileTreeNodes.length - 1} onDownload={f => downloadBundleFile(f, analysis?.scriptURL)}/>))}
1915
- </View>) : (filteredFiles.map((file, index) => {
1916
- const categoryMeta = CATEGORY_COLORS[file.category] || CATEGORY_COLORS.typescript;
1917
- const pctOfTotal = ((file.sizeKb / summary.totalKb) *
1918
- 100).toFixed(1);
1919
- const isUnused = file.isConsumed === false;
1920
- return (<View key={file.id} style={[
1921
- bundleStyles.fileCard,
1922
- isUnused && bundleStyles.treeFileCardUnused,
1923
- ]}>
1924
- <View style={bundleStyles.fileCardTop}>
1925
- <View style={bundleStyles.sNoBadge}>
1926
- <Text style={bundleStyles.sNoText}>#{index + 1}</Text>
1927
- </View>
1928
-
1929
- <MediaPreviewThumbnail file={file}/>
1930
-
1931
- <View style={{ flex: 1, paddingHorizontal: 4 }}>
1932
- <View style={{
1933
- flexDirection: 'row',
1934
- alignItems: 'center',
1935
- gap: 6,
1936
- flexWrap: 'wrap',
1937
- }}>
1938
- <HighlightText text={file.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
1939
- {isUnused ? (<View style={bundleStyles.unusedBadge}>
1940
- <Text style={bundleStyles.unusedBadgeText}>
1941
- {t('bundle.notConsumed')}
1942
- </Text>
1943
- </View>) : (<View style={bundleStyles.consumedBadge}>
1944
- <Text style={bundleStyles.consumedBadgeText}>
1945
- {t('bundle.consumed')}
1946
- </Text>
1947
- </View>)}
1948
- </View>
1949
- <HighlightText text={file.path} search={search} style={bundleStyles.filePath} highlightStyle={bundleStyles.searchHighlight} numberOfLines={1}/>
1950
- </View>
1951
-
1952
- <View style={{
1953
- flexDirection: 'row',
1954
- alignItems: 'center',
1955
- gap: 6,
1956
- }}>
1957
- <View style={bundleStyles.fileSizeBox}>
1958
- <Text style={[
1959
- bundleStyles.fileSizeKb,
1960
- isUnused && { color: AppColors.amber800Warm },
1961
- ]}>
1962
- {file.sizeKb >= 1024
1963
- ? t('bundle.fileSizeMb', {
1964
- size: (file.sizeKb / 1024).toFixed(2),
1965
- })
1966
- : t('bundle.fileSizeKb', { size: file.sizeKb })}
1967
- </Text>
1968
- <Text style={bundleStyles.filePercent}>
1969
- {pctOfTotal}%
1970
- </Text>
1971
- </View>
1972
- <TouchableScale onPress={() => downloadBundleFile(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
1973
- <DownloadIcon size={14} color={AppColors.sky500}/>
1974
- </TouchableScale>
1975
- <CopyButton value={() => file} label={t('bundle.fileDetailsJson')}/>
1976
- </View>
1977
- </View>
1978
-
1979
- <View style={bundleStyles.fileProgressTrack}>
1980
- <View style={[
1981
- bundleStyles.fileProgressBar,
1982
- {
1983
- width: `${Math.min(100, Math.max(4, Number(pctOfTotal) * 4))}%`,
1984
- backgroundColor: isUnused
1985
- ? AppColors.red500
1986
- : categoryMeta.color,
1987
- },
1988
- ]}/>
1989
- </View>
1990
-
1991
- <View style={bundleStyles.fileCardBottom}>
1992
- <Text style={bundleStyles.fileMetaText}>{file.meta}</Text>
1993
- {file.advice && (<View style={[
1994
- bundleStyles.adviceBadge,
1995
- file.status === 'warning' &&
1996
- bundleStyles.adviceWarning,
1997
- file.status === 'optimal' &&
1998
- bundleStyles.adviceOptimal,
1999
- isUnused && bundleStyles.adviceUnused,
2000
- ]}>
2001
- {isUnused ? (<TrashIcon color={AppColors.red600} size={12}/>) : file.status === 'warning' ? (<LightbulbIcon color={AppColors.amber800Warm} size={12}/>) : (<SparkleIcon color={AppColors.emerald700} size={12}/>)}
2002
- <Text style={[
2003
- bundleStyles.adviceText,
2004
- file.status === 'warning' && {
2005
- color: AppColors.amber800Warm,
2006
- },
2007
- file.status === 'optimal' && {
2008
- color: AppColors.emerald700,
2009
- },
2010
- isUnused && { color: AppColors.red600 },
2011
- ]}>
2012
- {file.advice}
2013
- </Text>
2014
- </View>)}
2015
- </View>
2016
- </View>);
2017
- }))}
2018
- </ScrollView>
963
+ {Se==="tree"?<T style={e.treeRootCard}>
964
+ {Ve.map((o,z)=><Dt key={o.id}node={o}level={0}search={P}totalBundleKb={B.totalKb}expandedFolders={Ye}toggleFolder={Wt}isLastChild={z===Ve.length-1}onDownload={L=>downloadBundleFile(L,V?.scriptURL)}/>)}
965
+ </T>:ke.map((o,z)=>{const L=Oe[o.category]||Oe.typescript,H=(o.sizeKb/B.totalKb*100).toFixed(1),N=o.isConsumed===!1;return<T key={o.id}style={[e.fileCard,N&&e.treeFileCardUnused]}>
966
+ <T style={e.fileCardTop}>
967
+ <T style={e.sNoBadge}>
968
+ <C style={e.sNoText}>#{z+1}</C>
969
+ </T>
970
+
971
+ <_e file={o}/>
972
+
973
+ <T style={{flex:1,paddingHorizontal:4}}>
974
+ <T style={{flexDirection:"row",alignItems:"center",gap:6,flexWrap:"wrap"}}>
975
+ <Ie text={o.name}search={P}style={e.fileName}highlightStyle={e.searchHighlight}/>
976
+ {N?<T style={e.unusedBadge}>
977
+ <C style={e.unusedBadgeText}>
978
+ {k("bundle.notConsumed")}
979
+ </C>
980
+ </T>:<T style={e.consumedBadge}>
981
+ <C style={e.consumedBadgeText}>
982
+ {k("bundle.consumed")}
983
+ </C>
984
+ </T>}
985
+ </T>
986
+ <Ie text={o.path}search={P}style={e.filePath}highlightStyle={e.searchHighlight}numberOfLines={1}/>
987
+ </T>
988
+
989
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
990
+ <T style={e.fileSizeBox}>
991
+ <C style={[e.fileSizeKb,N&&{color:t.amber800Warm}]}>
992
+ {o.sizeKb>=1024?k("bundle.fileSizeMb",{size:(o.sizeKb/1024).toFixed(2)}):k("bundle.fileSizeKb",{size:o.sizeKb})}
993
+ </C>
994
+ <C style={e.filePercent}>
995
+ {H}%
996
+ </C>
997
+ </T>
998
+ <G onPress={()=>downloadBundleFile(o,V?.scriptURL)}style={e.downloadFileBtn}hitSlop={8}>
999
+ <Ze size={14}color={t.sky500}/>
1000
+ </G>
1001
+ <K value={()=>o}label={k("bundle.fileDetailsJson")}/>
1002
+ </T>
1003
+ </T>
1004
+
1005
+ <T style={e.fileProgressTrack}>
1006
+ <T style={[e.fileProgressBar,{width:`${Math.min(100,Math.max(4,Number(H)*4))}%`,backgroundColor:N?t.red500:L.color}]}/>
1007
+ </T>
1008
+
1009
+ <T style={e.fileCardBottom}>
1010
+ <C style={e.fileMetaText}>{o.meta}</C>
1011
+ {o.advice&&<T style={[e.adviceBadge,o.status==="warning"&&e.adviceWarning,o.status==="optimal"&&e.adviceOptimal,N&&e.adviceUnused]}>
1012
+ {N?<Qt color={t.red600}size={12}/>:o.status==="warning"?<Je color={t.amber800Warm}size={12}/>:<Pt color={t.emerald700}size={12}/>}
1013
+ <C style={[e.adviceText,o.status==="warning"&&{color:t.amber800Warm},o.status==="optimal"&&{color:t.emerald700},N&&{color:t.red600}]}>
1014
+ {o.advice}
1015
+ </C>
1016
+ </T>}
1017
+ </T>
1018
+ </T>})}
1019
+ </Te>
2019
1020
 
2020
1021
 
2021
- <View style={bundleStyles.stickyFooterBar}>
2022
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
2023
- <LayersIcon color={AppColors.purple} size={14}/>
2024
- <Text style={bundleStyles.footerTitle}>
2025
- {t('bundle.filesOf', {
2026
- count: filteredFiles.length,
2027
- total: summary.totalCount,
2028
- })}
2029
- </Text>
2030
- </View>
2031
- <Text style={bundleStyles.footerSizeVal}>
2032
- {t('bundle.kbMbValue', {
2033
- kb: filteredTotalKb,
2034
- mb: (filteredTotalKb / 1024).toFixed(2),
2035
- })}
2036
- </Text>
2037
- </View>
2038
- </View>)}
1022
+ <T style={e.stickyFooterBar}>
1023
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1024
+ <Mt color={t.purple}size={14}/>
1025
+ <C style={e.footerTitle}>
1026
+ {k("bundle.filesOf",{count:ke.length,total:B.totalCount})}
1027
+ </C>
1028
+ </T>
1029
+ <C style={e.footerSizeVal}>
1030
+ {k("bundle.kbMbValue",{kb:qe,mb:(qe/1024).toFixed(2)})}
1031
+ </C>
1032
+ </T>
1033
+ </T>}
2039
1034
 
2040
1035
 
2041
1036
 
2042
1037
 
2043
- {activeSubTab === 'packages' && (<View style={{ flex: 1 }}>
2044
- <ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
2045
- <View style={bundleStyles.filterContainer}>
2046
- <View style={bundleStyles.searchRow}>
2047
- <SearchIcon color={AppColors.grayTextWeak} size={15}/>
2048
- <TextInput accessible={true} accessibilityRole="search" accessibilityLabel="Search packages" accessibilityHint="Type a package name or description to filter" placeholder={t('bundle.searchPackagesPlaceholder')} placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={bundleStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
2049
- {search.length > 0 && (<Pressable accessible={true} accessibilityRole="button" accessibilityLabel="Clear search input" onPress={() => setSearch('')} hitSlop={10}>
2050
- <ClearIcon color={AppColors.grayTextWeak} size={14}/>
2051
- </Pressable>)}
2052
- <CopyButton value={() => filteredPackages} label={t('bundle.dependenciesJson')}/>
2053
- </View>
2054
- </View>
2055
-
2056
- <Text style={bundleStyles.listHeaderCount}>
2057
- {t('bundle.showingDependencies', {
2058
- count: filteredPackages.length,
2059
- })}
2060
- </Text>
2061
-
2062
- {filteredPackages.map((pkg, index) => {
2063
- const cleanInstalledVersion = pkg.version
2064
- ? pkg.version.replace(/^\^/, '')
2065
- : '';
2066
- const hasUpdate = !!pkg.latestVersion &&
2067
- !!cleanInstalledVersion &&
2068
- pkg.latestVersion !== cleanInstalledVersion;
2069
- return (<View key={pkg.id} style={[
2070
- bundleStyles.fileCard,
2071
- pkg.isDeprecated && {
2072
- borderColor: AppColors.errorBorder,
2073
- backgroundColor: AppColors.errorCardBg,
2074
- },
2075
- ]}>
1038
+ {M==="packages"&&<T style={{flex:1}}>
1039
+ <Te style={{flex:1}}contentContainerStyle={e.contentContainer}keyboardShouldPersistTaps="handled">
1040
+ <T style={e.filterContainer}>
1041
+ <T style={e.searchRow}>
1042
+ <Bt color={t.grayTextWeak}size={15}/>
1043
+ <St accessible={!0}accessibilityRole="search"accessibilityLabel="Search packages"accessibilityHint="Type a package name or description to filter"placeholder={k("bundle.searchPackagesPlaceholder")}placeholderTextColor={t.grayTextWeak}value={P}onChangeText={W}style={e.searchInput}autoCorrect={!1}autoCapitalize="none"/>
1044
+ {P.length>0&&<He accessible={!0}accessibilityRole="button"accessibilityLabel="Clear search input"onPress={()=>W("")}hitSlop={10}>
1045
+ <Vt color={t.grayTextWeak}size={14}/>
1046
+ </He>}
1047
+ <K value={()=>Me}label={k("bundle.dependenciesJson")}/>
1048
+ </T>
1049
+ </T>
1050
+
1051
+ <C style={e.listHeaderCount}>
1052
+ {k("bundle.showingDependencies",{count:Me.length})}
1053
+ </C>
1054
+
1055
+ {Me.map((o,z)=>{const L=o.version?o.version.replace(/^\^/,""):"",H=!!o.latestVersion&&!!L&&o.latestVersion!==L;return<T key={o.id}style={[e.fileCard,o.isDeprecated&&{borderColor:t.errorBorder,backgroundColor:t.errorCardBg}]}>
2076
1056
 
2077
- <View style={bundleStyles.fileCardTop}>
2078
- <View style={bundleStyles.sNoBadge}>
2079
- <Text style={bundleStyles.sNoText}>#{index + 1}</Text>
2080
- </View>
2081
-
2082
- <PackageLogoRenderer name={pkg.name} color={pkg.color} size={28}/>
2083
-
2084
- <View style={{ flex: 1, paddingHorizontal: 4 }}>
2085
- <View style={{
2086
- flexDirection: 'row',
2087
- alignItems: 'center',
2088
- gap: 6,
2089
- flexWrap: 'wrap',
2090
- }}>
2091
- <HighlightText text={pkg.name} search={search} style={bundleStyles.fileName} highlightStyle={bundleStyles.searchHighlight}/>
2092
- <View style={bundleStyles.versionPill}>
2093
- <Text style={bundleStyles.versionPillText}>
2094
- {cleanInstalledVersion
2095
- ? t('bundle.versionPrefix', {
2096
- version: cleanInstalledVersion,
2097
- })
2098
- : t('bundle.bundled')}
2099
- </Text>
2100
- </View>
2101
-
2102
- {pkg.isDeprecated ? (<View style={bundleStyles.deprecatedBadge}>
2103
- <Text style={bundleStyles.deprecatedBadgeText}>
2104
- {t('bundle.deprecated')}
2105
- </Text>
2106
- </View>) : hasUpdate ? (<View style={bundleStyles.updateBadge}>
2107
- <Text style={bundleStyles.updateBadgeText}>
2108
- {t('bundle.updateAvailable', {
2109
- version: pkg.latestVersion,
2110
- })}
2111
- </Text>
2112
- </View>) : cleanInstalledVersion ? (<View style={[
2113
- bundleStyles.updateBadge,
2114
- {
2115
- backgroundColor: AppColors.gray100,
2116
- borderColor: AppColors.gray200,
2117
- },
2118
- ]}>
2119
- <Text style={[
2120
- bundleStyles.updateBadgeText,
2121
- { color: AppColors.gray600 },
2122
- ]}>
2123
- {t('bundle.upToDate')}
2124
- </Text>
2125
- </View>) : (<View style={[
2126
- bundleStyles.updateBadge,
2127
- {
2128
- backgroundColor: AppColors.gray100,
2129
- borderColor: AppColors.gray200,
2130
- },
2131
- ]}>
2132
- <Text style={[
2133
- bundleStyles.updateBadgeText,
2134
- { color: AppColors.gray600 },
2135
- ]}>
2136
- {t('bundle.bundledBadge')}
2137
- </Text>
2138
- </View>)}
2139
- </View>
2140
- </View>
2141
-
2142
- <View style={{
2143
- flexDirection: 'row',
2144
- alignItems: 'center',
2145
- gap: 6,
2146
- }}>
2147
- <View style={bundleStyles.fileSizeBox}>
2148
- <Text style={bundleStyles.fileSizeKb}>
2149
- {t('bundle.fileSizeKb', { size: pkg.sizeKb })}
2150
- </Text>
2151
- <Text style={bundleStyles.filePercent}>
2152
- {pkg.percentage}%
2153
- </Text>
2154
- </View>
2155
- <CopyButton value={() => pkg} label={t('bundle.packageDetailsJson')}/>
2156
- </View>
2157
- </View>
1057
+ <T style={e.fileCardTop}>
1058
+ <T style={e.sNoBadge}>
1059
+ <C style={e.sNoText}>#{z+1}</C>
1060
+ </T>
1061
+
1062
+ <Mo name={o.name}color={o.color}size={28}/>
1063
+
1064
+ <T style={{flex:1,paddingHorizontal:4}}>
1065
+ <T style={{flexDirection:"row",alignItems:"center",gap:6,flexWrap:"wrap"}}>
1066
+ <Ie text={o.name}search={P}style={e.fileName}highlightStyle={e.searchHighlight}/>
1067
+ <T style={e.versionPill}>
1068
+ <C style={e.versionPillText}>
1069
+ {L?k("bundle.versionPrefix",{version:L}):k("bundle.bundled")}
1070
+ </C>
1071
+ </T>
1072
+
1073
+ {o.isDeprecated?<T style={e.deprecatedBadge}>
1074
+ <C style={e.deprecatedBadgeText}>
1075
+ {k("bundle.deprecated")}
1076
+ </C>
1077
+ </T>:H?<T style={e.updateBadge}>
1078
+ <C style={e.updateBadgeText}>
1079
+ {k("bundle.updateAvailable",{version:o.latestVersion})}
1080
+ </C>
1081
+ </T>:L?<T style={[e.updateBadge,{backgroundColor:t.gray100,borderColor:t.gray200}]}>
1082
+ <C style={[e.updateBadgeText,{color:t.gray600}]}>
1083
+ {k("bundle.upToDate")}
1084
+ </C>
1085
+ </T>:<T style={[e.updateBadge,{backgroundColor:t.gray100,borderColor:t.gray200}]}>
1086
+ <C style={[e.updateBadgeText,{color:t.gray600}]}>
1087
+ {k("bundle.bundledBadge")}
1088
+ </C>
1089
+ </T>}
1090
+ </T>
1091
+ </T>
1092
+
1093
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1094
+ <T style={e.fileSizeBox}>
1095
+ <C style={e.fileSizeKb}>
1096
+ {k("bundle.fileSizeKb",{size:o.sizeKb})}
1097
+ </C>
1098
+ <C style={e.filePercent}>
1099
+ {o.percentage}%
1100
+ </C>
1101
+ </T>
1102
+ <K value={()=>o}label={k("bundle.packageDetailsJson")}/>
1103
+ </T>
1104
+ </T>
2158
1105
 
2159
1106
 
2160
- <View style={{
2161
- flexDirection: 'row',
2162
- alignItems: 'center',
2163
- gap: 6,
2164
- marginTop: 4,
2165
- marginBottom: 2,
2166
- }}>
2167
- <View style={[
2168
- bundleStyles.pkgBadge,
2169
- {
2170
- backgroundColor: `${pkg.color}1F`,
2171
- borderColor: `${pkg.color}4D`,
2172
- },
2173
- ]}>
2174
- <Text style={[bundleStyles.pkgBadgeText, { color: pkg.color }]}>
2175
- {pkg.category.toUpperCase()}
2176
- </Text>
2177
- </View>
2178
- <Text style={[bundleStyles.filePath, { flex: 1, marginTop: 0 }]} numberOfLines={1}>
2179
- {pkg.description}
2180
- </Text>
2181
- </View>
1107
+ <T style={{flexDirection:"row",alignItems:"center",gap:6,marginTop:4,marginBottom:2}}>
1108
+ <T style={[e.pkgBadge,{backgroundColor:`${o.color}1F`,borderColor:`${o.color}4D`}]}>
1109
+ <C style={[e.pkgBadgeText,{color:o.color}]}>
1110
+ {o.category.toUpperCase()}
1111
+ </C>
1112
+ </T>
1113
+ <C style={[e.filePath,{flex:1,marginTop:0}]}numberOfLines={1}>
1114
+ {o.description}
1115
+ </C>
1116
+ </T>
2182
1117
 
2183
1118
 
2184
- {pkg.isDeprecated && pkg.deprecationReason && (<View style={bundleStyles.deprecationBox}>
2185
- <View style={{
2186
- flexDirection: 'row',
2187
- alignItems: 'center',
2188
- gap: 5,
2189
- }}>
2190
- <CircleAlertIcon color={AppColors.errorColor} size={12}/>
2191
- <Text style={bundleStyles.deprecationText}>
2192
- {pkg.deprecationReason}
2193
- </Text>
2194
- </View>
2195
- </View>)}
2196
-
2197
- <View style={bundleStyles.fileProgressTrack}>
2198
- <View style={[
2199
- bundleStyles.fileProgressBar,
2200
- {
2201
- width: `${pkg.percentage * 2}%`,
2202
- backgroundColor: pkg.isDeprecated
2203
- ? AppColors.red500
2204
- : pkg.color,
2205
- },
2206
- ]}/>
2207
- </View>
1119
+ {o.isDeprecated&&o.deprecationReason&&<T style={e.deprecationBox}>
1120
+ <T style={{flexDirection:"row",alignItems:"center",gap:5}}>
1121
+ <Ge color={t.errorColor}size={12}/>
1122
+ <C style={e.deprecationText}>
1123
+ {o.deprecationReason}
1124
+ </C>
1125
+ </T>
1126
+ </T>}
1127
+
1128
+ <T style={e.fileProgressTrack}>
1129
+ <T style={[e.fileProgressBar,{width:`${o.percentage*2}%`,backgroundColor:o.isDeprecated?t.red500:o.color}]}/>
1130
+ </T>
2208
1131
 
2209
1132
 
2210
- <View style={{
2211
- flexDirection: 'row',
2212
- justifyContent: 'space-between',
2213
- alignItems: 'center',
2214
- marginTop: 3,
2215
- }}>
2216
- <View style={{
2217
- flexDirection: 'row',
2218
- alignItems: 'center',
2219
- gap: 8,
2220
- }}>
2221
- <View style={bundleStyles.typeTag}>
2222
- <Text style={bundleStyles.typeTagText}>
2223
- {pkg.type === 'direct'
2224
- ? t('bundle.direct')
2225
- : t('bundle.transitive')}
2226
- </Text>
2227
- </View>
2228
- {pkg.lastActive && (<View style={{
2229
- flexDirection: 'row',
2230
- alignItems: 'center',
2231
- gap: 4,
2232
- }}>
2233
- <ClockIcon color={AppColors.grayTextWeak} size={11}/>
2234
- <Text style={bundleStyles.lastActiveText}>
2235
- {pkg.lastActive}
2236
- </Text>
2237
- </View>)}
2238
- </View>
2239
-
2240
- <View style={{
2241
- flexDirection: 'row',
2242
- alignItems: 'center',
2243
- gap: 8,
2244
- }}>
2245
- <Text style={bundleStyles.fileMetaText}>
2246
- {t('bundle.minified', { size: pkg.sizeKb })}
2247
- </Text>
2248
- <TouchableScale accessible={true} accessibilityRole="link" accessibilityLabel={`Open ${pkg.name} on NPM`} accessibilityHint="Opens NPM package page in browser" onPress={() => {
2249
- const url = pkg.npmUrl ||
2250
- `https://www.npmjs.com/package/${pkg.name}`;
2251
- Linking.openURL(url).catch(() => { });
2252
- }} style={bundleStyles.npmLinkBtn}>
2253
- <Text style={bundleStyles.npmLinkText}>
2254
- {t('bundle.npmLink')}
2255
- </Text>
2256
- </TouchableScale>
2257
- </View>
2258
- </View>
2259
- </View>);
2260
- })}
2261
- </ScrollView>
1133
+ <T style={{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginTop:3}}>
1134
+ <T style={{flexDirection:"row",alignItems:"center",gap:8}}>
1135
+ <T style={e.typeTag}>
1136
+ <C style={e.typeTagText}>
1137
+ {o.type==="direct"?k("bundle.direct"):k("bundle.transitive")}
1138
+ </C>
1139
+ </T>
1140
+ {o.lastActive&&<T style={{flexDirection:"row",alignItems:"center",gap:4}}>
1141
+ <To color={t.grayTextWeak}size={11}/>
1142
+ <C style={e.lastActiveText}>
1143
+ {o.lastActive}
1144
+ </C>
1145
+ </T>}
1146
+ </T>
1147
+
1148
+ <T style={{flexDirection:"row",alignItems:"center",gap:8}}>
1149
+ <C style={e.fileMetaText}>
1150
+ {k("bundle.minified",{size:o.sizeKb})}
1151
+ </C>
1152
+ <G accessible={!0}accessibilityRole="link"accessibilityLabel={`Open ${o.name} on NPM`}accessibilityHint="Opens NPM package page in browser"onPress={()=>{const N=o.npmUrl||`https://www.npmjs.com/package/${o.name}`;Ct.openURL(N).catch(()=>{})}}style={e.npmLinkBtn}>
1153
+ <C style={e.npmLinkText}>
1154
+ {k("bundle.npmLink")}
1155
+ </C>
1156
+ </G>
1157
+ </T>
1158
+ </T>
1159
+ </T>})}
1160
+ </Te>
2262
1161
 
2263
1162
 
2264
- <View style={bundleStyles.stickyFooterBar}>
2265
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
2266
- <PackageIcon color={AppColors.purple} size={14}/>
2267
- <Text style={bundleStyles.footerTitle}>
2268
- {t('bundle.dependenciesCount', {
2269
- count: filteredPackages.length,
2270
- })}
2271
- </Text>
2272
- </View>
2273
- <Text style={bundleStyles.footerSizeVal}>
2274
- {t('bundle.kbMbValue', {
2275
- kb: packagesTotalKb,
2276
- mb: (packagesTotalKb / 1024).toFixed(2),
2277
- })}
2278
- </Text>
2279
- </View>
2280
- </View>)}
1163
+ <T style={e.stickyFooterBar}>
1164
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1165
+ <Pe color={t.purple}size={14}/>
1166
+ <C style={e.footerTitle}>
1167
+ {k("bundle.dependenciesCount",{count:Me.length})}
1168
+ </C>
1169
+ </T>
1170
+ <C style={e.footerSizeVal}>
1171
+ {k("bundle.kbMbValue",{kb:Qe,mb:(Qe/1024).toFixed(2)})}
1172
+ </C>
1173
+ </T>
1174
+ </T>}
2281
1175
 
2282
1176
 
2283
1177
 
2284
1178
 
2285
- {activeSubTab === 'media' && (<View style={{ flex: 1 }}>
2286
- <ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
2287
- <View style={bundleStyles.tipsCard}>
2288
- <View style={{
2289
- flexDirection: 'row',
2290
- alignItems: 'center',
2291
- justifyContent: 'space-between',
2292
- marginBottom: 8,
2293
- }}>
2294
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
2295
- <StorageIcon color={AppColors.purple} size={18}/>
2296
- <Text style={bundleStyles.tipsHeading}>
2297
- {t('bundle.mediaAuditorTitle')}
2298
- </Text>
2299
- </View>
2300
- <CopyButton value={() => mediaFiles} label={t('bundle.mediaAssetsJson')}/>
2301
- </View>
2302
- <Text style={bundleStyles.tipDesc}>
2303
- {t('bundle.mediaAuditorPrefix')}{' '}
2304
- <Text style={{
2305
- fontFamily: AppFonts.interBold,
2306
- color: AppColors.purple,
2307
- }}>
2308
- {summary.images.pct + summary.fonts.pct}%
2309
- </Text>{' '}
2310
- {t('bundle.mediaAuditorMid', {
2311
- kb: summary.images.kb + summary.fonts.kb,
2312
- })}{' '}
2313
- <Text style={{
2314
- fontFamily: AppFonts.interBold,
2315
- color: AppColors.emerald700,
2316
- }}>
2317
- {t('bundle.mediaSavings', { size: 540 })}
2318
- </Text>{' '}
2319
- {t('bundle.mediaAuditorSuffix')}
2320
- </Text>
2321
- </View>
2322
-
2323
- <Text style={bundleStyles.listHeaderCount}>
2324
- {t('bundle.mediaAssetsList', { count: mediaFiles.length })}
2325
- </Text>
2326
-
2327
- {mediaFiles.map((file, index) => (<View key={file.id} style={bundleStyles.fileCard}>
2328
- <View style={bundleStyles.fileCardTop}>
2329
- <View style={bundleStyles.sNoBadge}>
2330
- <Text style={bundleStyles.sNoText}>#{index + 1}</Text>
2331
- </View>
2332
-
2333
- <MediaPreviewThumbnail file={file}/>
2334
-
2335
- <View style={{ flex: 1 }}>
2336
- <Text style={bundleStyles.fileName}>{file.name}</Text>
2337
- <Text style={bundleStyles.filePath}>{file.path}</Text>
2338
- </View>
2339
-
2340
- <View style={{
2341
- flexDirection: 'row',
2342
- alignItems: 'center',
2343
- gap: 6,
2344
- }}>
2345
- <View style={bundleStyles.fileSizeBox}>
2346
- <Text style={bundleStyles.fileSizeKb}>
2347
- {t('bundle.fileSizeKb', { size: file.sizeKb })}
2348
- </Text>
2349
- </View>
2350
- <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Download ${file.name}`} accessibilityHint="Downloads media asset file" onPress={() => downloadBundleFile(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
2351
- <DownloadIcon size={14} color={AppColors.sky500}/>
2352
- </TouchableScale>
2353
- <CopyButton value={() => file} label={t('bundle.mediaItemJson')}/>
2354
- </View>
2355
- </View>
2356
-
2357
- <View style={bundleStyles.fileCardBottom}>
2358
- <Text style={bundleStyles.fileMetaText}>{file.meta}</Text>
2359
- {file.advice && (<View style={[
2360
- bundleStyles.adviceBadge,
2361
- file.status === 'warning' && bundleStyles.adviceWarning,
2362
- file.status === 'optimal' && bundleStyles.adviceOptimal,
2363
- ]}>
2364
- {file.status === 'warning' ? (<LightbulbIcon color={AppColors.amber800Warm} size={12}/>) : (<SparkleIcon color={AppColors.emerald700} size={12}/>)}
2365
- <Text style={[
2366
- bundleStyles.adviceText,
2367
- file.status === 'warning' && {
2368
- color: AppColors.amber800Warm,
2369
- },
2370
- file.status === 'optimal' && {
2371
- color: AppColors.emerald700,
2372
- },
2373
- ]}>
2374
- {file.advice}
2375
- </Text>
2376
- </View>)}
2377
- </View>
2378
- </View>))}
2379
- </ScrollView>
1179
+ {M==="media"&&<T style={{flex:1}}>
1180
+ <Te style={{flex:1}}contentContainerStyle={e.contentContainer}keyboardShouldPersistTaps="handled">
1181
+ <T style={e.tipsCard}>
1182
+ <T style={{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:8}}>
1183
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1184
+ <Ee color={t.purple}size={18}/>
1185
+ <C style={e.tipsHeading}>
1186
+ {k("bundle.mediaAuditorTitle")}
1187
+ </C>
1188
+ </T>
1189
+ <K value={()=>ve}label={k("bundle.mediaAssetsJson")}/>
1190
+ </T>
1191
+ <C style={e.tipDesc}>
1192
+ {k("bundle.mediaAuditorPrefix")}{" "}
1193
+ <C style={{fontFamily:S.interBold,color:t.purple}}>
1194
+ {B.images.pct+B.fonts.pct}%
1195
+ </C>{" "}
1196
+ {k("bundle.mediaAuditorMid",{kb:B.images.kb+B.fonts.kb})}{" "}
1197
+ <C style={{fontFamily:S.interBold,color:t.emerald700}}>
1198
+ {k("bundle.mediaSavings",{size:540})}
1199
+ </C>{" "}
1200
+ {k("bundle.mediaAuditorSuffix")}
1201
+ </C>
1202
+ </T>
1203
+
1204
+ <C style={e.listHeaderCount}>
1205
+ {k("bundle.mediaAssetsList",{count:ve.length})}
1206
+ </C>
1207
+
1208
+ {ve.map((o,z)=><T key={o.id}style={e.fileCard}>
1209
+ <T style={e.fileCardTop}>
1210
+ <T style={e.sNoBadge}>
1211
+ <C style={e.sNoText}>#{z+1}</C>
1212
+ </T>
1213
+
1214
+ <_e file={o}/>
1215
+
1216
+ <T style={{flex:1}}>
1217
+ <C style={e.fileName}>{o.name}</C>
1218
+ <C style={e.filePath}>{o.path}</C>
1219
+ </T>
1220
+
1221
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1222
+ <T style={e.fileSizeBox}>
1223
+ <C style={e.fileSizeKb}>
1224
+ {k("bundle.fileSizeKb",{size:o.sizeKb})}
1225
+ </C>
1226
+ </T>
1227
+ <G accessible={!0}accessibilityRole="button"accessibilityLabel={`Download ${o.name}`}accessibilityHint="Downloads media asset file"onPress={()=>downloadBundleFile(o,V?.scriptURL)}style={e.downloadFileBtn}hitSlop={8}>
1228
+ <Ze size={14}color={t.sky500}/>
1229
+ </G>
1230
+ <K value={()=>o}label={k("bundle.mediaItemJson")}/>
1231
+ </T>
1232
+ </T>
1233
+
1234
+ <T style={e.fileCardBottom}>
1235
+ <C style={e.fileMetaText}>{o.meta}</C>
1236
+ {o.advice&&<T style={[e.adviceBadge,o.status==="warning"&&e.adviceWarning,o.status==="optimal"&&e.adviceOptimal]}>
1237
+ {o.status==="warning"?<Je color={t.amber800Warm}size={12}/>:<Pt color={t.emerald700}size={12}/>}
1238
+ <C style={[e.adviceText,o.status==="warning"&&{color:t.amber800Warm},o.status==="optimal"&&{color:t.emerald700}]}>
1239
+ {o.advice}
1240
+ </C>
1241
+ </T>}
1242
+ </T>
1243
+ </T>)}
1244
+ </Te>
2380
1245
 
2381
1246
 
2382
- <View style={bundleStyles.stickyFooterBar}>
2383
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
2384
- <StorageIcon color={AppColors.purple} size={14}/>
2385
- <Text style={bundleStyles.footerTitle}>
2386
- {t('bundle.mediaAndFonts', { count: mediaFiles.length })}
2387
- </Text>
2388
- </View>
2389
- <Text style={bundleStyles.footerSizeVal}>
2390
- {t('bundle.kbMbValue', {
2391
- kb: mediaTotalKb,
2392
- mb: (mediaTotalKb / 1024).toFixed(2),
2393
- })}
2394
- </Text>
2395
- </View>
2396
- </View>)}
1247
+ <T style={e.stickyFooterBar}>
1248
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1249
+ <Ee color={t.purple}size={14}/>
1250
+ <C style={e.footerTitle}>
1251
+ {k("bundle.mediaAndFonts",{count:ve.length})}
1252
+ </C>
1253
+ </T>
1254
+ <C style={e.footerSizeVal}>
1255
+ {k("bundle.kbMbValue",{kb:et,mb:(et/1024).toFixed(2)})}
1256
+ </C>
1257
+ </T>
1258
+ </T>}
2397
1259
 
2398
1260
 
2399
1261
 
2400
1262
 
2401
- {activeSubTab === 'optimizer' && (<ScrollView style={{ flex: 1 }} contentContainerStyle={bundleStyles.contentContainer} keyboardShouldPersistTaps="handled">
2402
- <View style={bundleStyles.tipsCard}>
2403
- <View style={{
2404
- flexDirection: 'row',
2405
- alignItems: 'center',
2406
- justifyContent: 'space-between',
2407
- marginBottom: 12,
2408
- }}>
2409
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
2410
- <CircleAlertIcon color={AppColors.purple} size={18}/>
2411
- <Text style={bundleStyles.tipsHeading}>
2412
- {t('bundle.optimizerTitle')}
2413
- </Text>
2414
- </View>
2415
- <CopyButton value={() => [
2416
- t('bundle.optTip1Title'),
2417
- `${t('bundle.optTip2Title')} (${isHermes ? t('bundle.active') : t('bundle.actionRequired')})`,
2418
- t('bundle.optTip3Title'),
2419
- t('bundle.optTip4Title'),
2420
- t('bundle.optTip5Title'),
2421
- ]} label={t('bundle.optimizationChecklist')}/>
2422
- </View>
2423
-
2424
- {[
2425
- {
2426
- iconType: 'image',
2427
- iconColor: AppColors.pink500,
2428
- title: t('bundle.optTip1Title'),
2429
- desc: t('bundle.optTip1Desc'),
2430
- badge: t('bundle.highImpact'),
2431
- badgeColor: AppColors.pink500,
2432
- },
2433
- {
2434
- iconType: 'bolt',
2435
- iconColor: isHermes ? AppColors.emerald500 : AppColors.amber500,
2436
- title: t('bundle.optTip2Title'),
2437
- desc: isHermes
2438
- ? t('bundle.optTip2DescActive')
2439
- : t('bundle.optTip2DescInactive'),
2440
- badge: isHermes
2441
- ? t('bundle.active')
2442
- : t('bundle.actionRequired'),
2443
- badgeColor: isHermes
2444
- ? AppColors.emerald500
2445
- : AppColors.amber500,
2446
- },
2447
- {
2448
- iconType: 'font',
2449
- iconColor: AppColors.purple500,
2450
- title: t('bundle.optTip3Title'),
2451
- desc: t('bundle.optTip3Desc'),
2452
- badge: t('bundle.mediumImpact'),
2453
- badgeColor: AppColors.purple500,
2454
- },
2455
- {
2456
- iconType: 'source',
2457
- iconColor: AppColors.sky500,
2458
- title: t('bundle.optTip4Title'),
2459
- desc: t('bundle.optTip4Desc'),
2460
- badge: t('bundle.bestPractice'),
2461
- badgeColor: AppColors.sky500,
2462
- },
2463
- {
2464
- iconType: 'overhead',
2465
- iconColor: AppColors.indigo500,
2466
- title: t('bundle.optTip5Title'),
2467
- desc: t('bundle.optTip5Desc'),
2468
- badge: t('bundle.bestPractice'),
2469
- badgeColor: AppColors.indigo500,
2470
- },
2471
- ].map((tip, tIdx) => (<View key={tIdx} style={bundleStyles.tipItem}>
2472
- <View style={bundleStyles.tipItemHeader}>
2473
- <View style={bundleStyles.tipTitleWrap}>
2474
- <View style={bundleStyles.sNoBadge}>
2475
- <Text style={bundleStyles.sNoText}>#{tIdx + 1}</Text>
2476
- </View>
2477
- <BundleCategoryIcon type={tip.iconType} size={14} color={tip.iconColor}/>
2478
- <Text style={bundleStyles.tipTitle}>{tip.title}</Text>
2479
- </View>
2480
- <View style={bundleStyles.tipActionWrap}>
2481
- <View style={[
2482
- bundleStyles.impactBadge,
2483
- {
2484
- backgroundColor: `${tip.badgeColor}18`,
2485
- borderColor: `${tip.badgeColor}40`,
2486
- },
2487
- ]}>
2488
- <Text style={[
2489
- bundleStyles.impactBadgeText,
2490
- { color: tip.badgeColor },
2491
- ]}>
2492
- {tip.badge}
2493
- </Text>
2494
- </View>
2495
- <CopyButton value={() => tip} label={t('bundle.tipDetails')}/>
2496
- </View>
2497
- </View>
2498
- <Text style={bundleStyles.tipDesc}>{tip.desc}</Text>
2499
- </View>))}
2500
- </View>
2501
- </ScrollView>)}
2502
- </View>);
2503
- });
2504
- const bundleStyles = StyleSheet.create({
2505
- topTabWrap: {
2506
- backgroundColor: AppColors.white,
2507
- paddingVertical: 8,
2508
- borderBottomWidth: 1,
2509
- borderBottomColor: AppColors.dividerColor,
2510
- flexDirection: 'row',
2511
- alignItems: 'center',
2512
- paddingRight: 10,
2513
- },
2514
- reloadButton: {
2515
- padding: 8,
2516
- borderRadius: 20,
2517
- backgroundColor: AppColors.grayBackground,
2518
- borderWidth: 1,
2519
- borderColor: AppColors.dividerColor,
2520
- alignItems: 'center',
2521
- justifyContent: 'center',
2522
- marginLeft: 4,
2523
- },
2524
- analyzingContainer: {
2525
- flex: 1,
2526
- alignItems: 'center',
2527
- justifyContent: 'center',
2528
- gap: 8,
2529
- padding: 24,
2530
- },
2531
- analyzingText: {
2532
- fontFamily: AppFonts.interBold,
2533
- fontSize: 13,
2534
- color: AppColors.primaryBlack,
2535
- },
2536
- analyzingHint: {
2537
- fontFamily: AppFonts.interRegular,
2538
- fontSize: 11,
2539
- color: AppColors.grayTextWeak,
2540
- },
2541
- subTabsScroll: {
2542
- paddingHorizontal: 12,
2543
- gap: 8,
2544
- flexDirection: 'row',
2545
- alignItems: 'center',
2546
- },
2547
- subTabPill: {
2548
- flexDirection: 'row',
2549
- alignItems: 'center',
2550
- gap: 6,
2551
- paddingHorizontal: 12,
2552
- paddingVertical: 7,
2553
- borderRadius: 20,
2554
- backgroundColor: AppColors.grayBackground,
2555
- borderWidth: 1,
2556
- borderColor: AppColors.dividerColor,
2557
- },
2558
- subTabPillActive: {
2559
- backgroundColor: AppColors.brandPurple,
2560
- borderColor: AppColors.brandPurple,
2561
- shadowColor: AppColors.brandPurple,
2562
- shadowOffset: { width: 0, height: 2 },
2563
- shadowOpacity: 0.2,
2564
- shadowRadius: 3,
2565
- elevation: 2,
2566
- },
2567
- subTabPillText: {
2568
- fontFamily: AppFonts.interMedium,
2569
- fontSize: 11.5,
2570
- color: AppColors.grayTextStrong,
2571
- },
2572
- subTabPillTextActive: {
2573
- fontFamily: AppFonts.interBold,
2574
- color: AppColors.white,
2575
- },
2576
- contentContainer: {
2577
- padding: 16,
2578
- paddingBottom: 40,
2579
- gap: 14,
2580
- },
2581
- heroCard: {
2582
- backgroundColor: AppColors.white,
2583
- borderRadius: 14,
2584
- padding: 16,
2585
- borderWidth: 1,
2586
- borderColor: AppColors.dividerColor,
2587
- shadowColor: AppColors.primaryBlack,
2588
- shadowOffset: { width: 0, height: 2 },
2589
- shadowOpacity: 0.04,
2590
- shadowRadius: 6,
2591
- elevation: 2,
2592
- },
2593
- heroTopRow: {
2594
- flexDirection: 'row',
2595
- alignItems: 'flex-start',
2596
- gap: 12,
2597
- marginBottom: 16,
2598
- },
2599
- heroIconWrap: {
2600
- width: 44,
2601
- height: 44,
2602
- borderRadius: 12,
2603
- backgroundColor: `${AppColors.brandPurple}12`,
2604
- alignItems: 'center',
2605
- justifyContent: 'center',
2606
- borderWidth: 1,
2607
- borderColor: `${AppColors.brandPurple}25`,
2608
- },
2609
- heroTitle: {
2610
- fontFamily: AppFonts.interBold,
2611
- fontSize: 16,
2612
- color: AppColors.primaryBlack,
2613
- },
2614
- heroSubtitle: {
2615
- fontFamily: AppFonts.interRegular,
2616
- fontSize: 12,
2617
- color: AppColors.grayTextWeak,
2618
- marginTop: 2,
2619
- },
2620
- metricsGrid: {
2621
- flexDirection: 'row',
2622
- flexWrap: 'wrap',
2623
- gap: 8,
2624
- },
2625
- metricBox: {
2626
- flex: 1,
2627
- minWidth: '45%',
2628
- backgroundColor: AppColors.grayBackground,
2629
- borderRadius: 10,
2630
- padding: 10,
2631
- borderWidth: 1,
2632
- borderColor: AppColors.dividerColor,
2633
- },
2634
- metricLabel: {
2635
- fontFamily: AppFonts.interBold,
2636
- fontSize: 9.5,
2637
- color: AppColors.grayTextWeak,
2638
- letterSpacing: 0.5,
2639
- },
2640
- metricValue: {
2641
- fontFamily: AppFonts.interBold,
2642
- fontSize: 14,
2643
- color: AppColors.primaryBlack,
2644
- marginTop: 3,
2645
- },
2646
- metricHint: {
2647
- fontFamily: AppFonts.interMedium,
2648
- fontSize: 10.5,
2649
- color: AppColors.grayText,
2650
- marginTop: 2,
2651
- },
2652
- statusIndicator: {
2653
- width: 8,
2654
- height: 8,
2655
- borderRadius: 4,
2656
- },
2657
- prodPlatformScroll: {
2658
- flexDirection: 'row',
2659
- alignItems: 'center',
2660
- gap: 8,
2661
- paddingBottom: 4,
2662
- },
2663
- prodPlatformBtn: {
2664
- flexDirection: 'row',
2665
- alignItems: 'center',
2666
- paddingVertical: 7,
2667
- paddingHorizontal: 12,
2668
- borderRadius: 20,
2669
- backgroundColor: AppColors.white,
2670
- borderWidth: 1,
2671
- borderColor: AppColors.dividerColor,
2672
- gap: 6,
2673
- },
2674
- prodPlatformBtnActive: {
2675
- backgroundColor: AppColors.brandPurple,
2676
- borderColor: AppColors.brandPurple,
2677
- shadowColor: AppColors.brandPurple,
2678
- shadowOffset: { width: 0, height: 2 },
2679
- shadowOpacity: 0.18,
2680
- shadowRadius: 3,
2681
- elevation: 2,
2682
- },
2683
- prodPlatformBtnText: {
2684
- fontFamily: AppFonts.interBold,
2685
- fontSize: 11.5,
2686
- color: AppColors.grayTextStrong,
2687
- },
2688
- prodPlatformBtnTextActive: {
2689
- color: AppColors.white,
2690
- },
2691
- prodPlatformBadge: {
2692
- paddingHorizontal: 6,
2693
- paddingVertical: 2,
2694
- borderRadius: 10,
2695
- backgroundColor: `${AppColors.purple}14`,
2696
- },
2697
- prodPlatformBadgeActive: {
2698
- backgroundColor: 'rgba(255, 255, 255, 0.25)',
2699
- },
2700
- prodPlatformBadgeText: {
2701
- fontFamily: AppFonts.interBold,
2702
- fontSize: 9.5,
2703
- color: AppColors.purple,
2704
- },
2705
- prodPlatformBadgeTextActive: {
2706
- color: AppColors.white,
2707
- },
2708
- sectionCard: {
2709
- backgroundColor: AppColors.white,
2710
- borderRadius: 14,
2711
- padding: 14,
2712
- borderWidth: 1,
2713
- borderColor: AppColors.dividerColor,
2714
- overflow: 'hidden',
2715
- },
2716
- sectionHeaderRow: {
2717
- flexDirection: 'row',
2718
- justifyContent: 'space-between',
2719
- alignItems: 'center',
2720
- marginBottom: 10,
2721
- gap: 8,
2722
- },
2723
- sectionTitle: {
2724
- fontFamily: AppFonts.interBold,
2725
- fontSize: 13,
2726
- color: AppColors.primaryBlack,
2727
- },
2728
- sectionSub: {
2729
- fontFamily: AppFonts.interMedium,
2730
- fontSize: 11,
2731
- color: AppColors.grayTextWeak,
2732
- },
2733
- treemapBar: {
2734
- flexDirection: 'row',
2735
- borderRadius: 6,
2736
- overflow: 'hidden',
2737
- height: 16,
2738
- marginBottom: 12,
2739
- backgroundColor: AppColors.slate200,
2740
- },
2741
- prodTreemapBar: {
2742
- flexDirection: 'row',
2743
- borderRadius: 6,
2744
- overflow: 'hidden',
2745
- height: 16,
2746
- marginBottom: 12,
2747
- backgroundColor: AppColors.slate200,
2748
- },
2749
- legendGrid: {
2750
- flexDirection: 'row',
2751
- flexWrap: 'wrap',
2752
- gap: 8,
2753
- },
2754
- legendItem: {
2755
- flexDirection: 'row',
2756
- alignItems: 'center',
2757
- gap: 6,
2758
- paddingHorizontal: 8,
2759
- paddingVertical: 5,
2760
- borderRadius: 8,
2761
- backgroundColor: `${AppColors.slate200}40`,
2762
- borderWidth: 1,
2763
- borderColor: `${AppColors.dividerColor}`,
2764
- flexShrink: 0,
2765
- },
2766
- legendText: {
2767
- fontFamily: AppFonts.interMedium,
2768
- fontSize: 11,
2769
- color: AppColors.grayTextStrong,
2770
- },
2771
- legendVal: {
2772
- fontFamily: AppFonts.interBold,
2773
- color: AppColors.primaryBlack,
2774
- },
2775
- subsystemCard: {
2776
- backgroundColor: AppColors.white,
2777
- borderRadius: 12,
2778
- padding: 12,
2779
- marginBottom: 8,
2780
- borderWidth: 1,
2781
- borderColor: AppColors.dividerColor,
2782
- gap: 8,
2783
- },
2784
- subsystemHeader: {
2785
- flexDirection: 'row',
2786
- alignItems: 'center',
2787
- justifyContent: 'space-between',
2788
- gap: 8,
2789
- },
2790
- subsystemTitle: {
2791
- fontFamily: AppFonts.interBold,
2792
- fontSize: 12.5,
2793
- color: AppColors.primaryBlack,
2794
- },
2795
- subsystemBadge: {
2796
- paddingHorizontal: 6,
2797
- paddingVertical: 2,
2798
- borderRadius: 6,
2799
- },
2800
- subsystemBadgeText: {
2801
- fontFamily: AppFonts.interBold,
2802
- fontSize: 10,
2803
- },
2804
- subsystemGrid: {
2805
- flexDirection: 'row',
2806
- flexWrap: 'wrap',
2807
- gap: 6,
2808
- },
2809
- subsystemItem: {
2810
- flexDirection: 'row',
2811
- alignItems: 'center',
2812
- gap: 5,
2813
- paddingHorizontal: 8,
2814
- paddingVertical: 4,
2815
- borderRadius: 6,
2816
- backgroundColor: AppColors.grayBackground,
2817
- borderWidth: 1,
2818
- borderColor: AppColors.dividerColor,
2819
- },
2820
- subsystemItemText: {
2821
- fontFamily: AppFonts.interMedium,
2822
- fontSize: 10.5,
2823
- color: AppColors.grayTextStrong,
2824
- },
2825
- subsystemItemVal: {
2826
- fontFamily: AppFonts.interBold,
2827
- color: AppColors.primaryBlack,
2828
- },
2829
- catRowCard: {
2830
- backgroundColor: AppColors.grayBackground,
2831
- borderRadius: 12,
2832
- padding: 12,
2833
- marginBottom: 8,
2834
- borderWidth: 1,
2835
- borderColor: AppColors.dividerColor,
2836
- gap: 8,
2837
- },
2838
- catRowTop: {
2839
- flexDirection: 'row',
2840
- alignItems: 'flex-start',
2841
- gap: 10,
2842
- },
2843
- catIconBox: {
2844
- width: 36,
2845
- height: 36,
2846
- borderRadius: 10,
2847
- borderWidth: 1,
2848
- alignItems: 'center',
2849
- justifyContent: 'center',
2850
- flexShrink: 0,
2851
- },
2852
- catRowTitleWrap: {
2853
- flex: 1,
2854
- minWidth: 0,
2855
- gap: 2,
2856
- },
2857
- catRowTitle: {
2858
- fontFamily: AppFonts.interBold,
2859
- fontSize: 13,
2860
- color: AppColors.primaryBlack,
2861
- flex: 1,
2862
- },
2863
- catRowDesc: {
2864
- fontFamily: AppFonts.interRegular,
2865
- fontSize: 10.5,
2866
- color: AppColors.grayTextWeak,
2867
- lineHeight: 14.5,
2868
- },
2869
- catRowSize: {
2870
- fontFamily: AppFonts.interBold,
2871
- fontSize: 12.5,
2872
- color: AppColors.primaryBlack,
2873
- },
2874
- catRowRight: {
2875
- alignItems: 'flex-end',
2876
- justifyContent: 'center',
2877
- flexShrink: 0,
2878
- minWidth: 64,
2879
- },
2880
- catRowPct: {
2881
- fontFamily: AppFonts.interMedium,
2882
- fontSize: 10,
2883
- color: AppColors.grayTextWeak,
2884
- },
2885
- catPctPill: {
2886
- paddingHorizontal: 5.5,
2887
- paddingVertical: 1.5,
2888
- borderRadius: 5,
2889
- },
2890
- catPctText: {
2891
- fontFamily: AppFonts.interBold,
2892
- fontSize: 9.5,
2893
- },
2894
- catProgressTrack: {
2895
- height: 5,
2896
- borderRadius: 2.5,
2897
- backgroundColor: `${AppColors.slate200}`,
2898
- overflow: 'hidden',
2899
- marginTop: 2,
2900
- },
2901
- catProgressBar: {
2902
- height: '100%',
2903
- borderRadius: 2.5,
2904
- },
2905
- filterContainer: {
2906
- backgroundColor: AppColors.white,
2907
- borderRadius: 12,
2908
- padding: 10,
2909
- marginHorizontal: 16,
2910
- marginTop: 12,
2911
- borderWidth: 1,
2912
- borderColor: AppColors.dividerColor,
2913
- gap: 8,
2914
- },
2915
- searchRow: {
2916
- flexDirection: 'row',
2917
- alignItems: 'center',
2918
- backgroundColor: AppColors.grayBackground,
2919
- borderRadius: 8,
2920
- paddingHorizontal: 10,
2921
- height: 36,
2922
- gap: 8,
2923
- },
2924
- searchInput: {
2925
- flex: 1,
2926
- fontFamily: AppFonts.interRegular,
2927
- fontSize: 12,
2928
- color: AppColors.primaryBlack,
2929
- padding: 0,
2930
- },
2931
- categoryPillsScroll: {
2932
- gap: 6,
2933
- paddingVertical: 2,
2934
- },
2935
- catPill: {
2936
- flexDirection: 'row',
2937
- alignItems: 'center',
2938
- gap: 4,
2939
- paddingHorizontal: 10,
2940
- paddingVertical: 5,
2941
- borderRadius: 16,
2942
- backgroundColor: AppColors.grayBackground,
2943
- borderWidth: 1,
2944
- borderColor: AppColors.dividerColor,
2945
- },
2946
- catPillActive: {
2947
- backgroundColor: AppColors.brandPurple,
2948
- borderColor: AppColors.brandPurple,
2949
- },
2950
- catPillText: {
2951
- fontFamily: AppFonts.interMedium,
2952
- fontSize: 11,
2953
- color: AppColors.grayTextStrong,
2954
- },
2955
- catPillTextActive: {
2956
- fontFamily: AppFonts.interBold,
2957
- color: AppColors.white,
2958
- },
2959
- listHeaderCount: {
2960
- fontFamily: AppFonts.interMedium,
2961
- fontSize: 11,
2962
- color: AppColors.grayTextWeak,
2963
- paddingHorizontal: 4,
2964
- },
2965
- treeHeaderRow: {
2966
- flexDirection: 'row',
2967
- alignItems: 'center',
2968
- justifyContent: 'space-between',
2969
- paddingHorizontal: 2,
2970
- marginBottom: 6,
2971
- },
2972
- viewModeToggleGroup: {
2973
- flexDirection: 'row',
2974
- backgroundColor: AppColors.grayBackground,
2975
- borderRadius: 8,
2976
- padding: 2,
2977
- borderWidth: 1,
2978
- borderColor: AppColors.dividerColor,
2979
- },
2980
- viewModeBtn: {
2981
- paddingHorizontal: 10,
2982
- paddingVertical: 5,
2983
- borderRadius: 6,
2984
- },
2985
- viewModeBtnActive: {
2986
- backgroundColor: AppColors.brandPurple,
2987
- shadowColor: AppColors.brandPurple,
2988
- shadowOffset: { width: 0, height: 1 },
2989
- shadowOpacity: 0.2,
2990
- shadowRadius: 2,
2991
- elevation: 2,
2992
- },
2993
- viewModeBtnText: {
2994
- fontFamily: AppFonts.interMedium,
2995
- fontSize: 11,
2996
- color: AppColors.grayTextStrong,
2997
- },
2998
- viewModeBtnTextActive: {
2999
- fontFamily: AppFonts.interBold,
3000
- color: AppColors.white,
3001
- },
3002
- treeActionLink: {
3003
- fontFamily: AppFonts.interBold,
3004
- fontSize: 11.5,
3005
- color: AppColors.purple,
3006
- },
3007
- treeRootCard: {
3008
- backgroundColor: AppColors.white,
3009
- borderRadius: 12,
3010
- borderWidth: 1,
3011
- borderColor: AppColors.dividerColor,
3012
- overflow: 'hidden',
3013
- marginBottom: 16,
3014
- },
3015
- treeFolderBlock: {
3016
- borderBottomWidth: StyleSheet.hairlineWidth,
3017
- borderBottomColor: AppColors.dividerColor,
3018
- },
3019
- treeFolderRow: {
3020
- flexDirection: 'row',
3021
- alignItems: 'center',
3022
- justifyContent: 'space-between',
3023
- paddingVertical: 8,
3024
- paddingRight: 10,
3025
- backgroundColor: `${AppColors.purple}06`,
3026
- },
3027
- treeRowLeft: {
3028
- flexDirection: 'row',
3029
- alignItems: 'center',
3030
- gap: 6,
3031
- flex: 1,
3032
- marginRight: 6,
3033
- },
3034
- treeRowRight: {
3035
- flexDirection: 'row',
3036
- alignItems: 'center',
3037
- gap: 6,
3038
- },
3039
- treeChevron: {
3040
- fontSize: 12,
3041
- color: AppColors.purple,
3042
- fontFamily: AppFonts.interBold,
3043
- width: 12,
3044
- textAlign: 'center',
3045
- },
3046
- treeFolderName: {
3047
- fontFamily: AppFonts.interBold,
3048
- fontSize: 12.5,
3049
- color: AppColors.primaryBlack,
3050
- },
3051
- treeCountBadge: {
3052
- paddingHorizontal: 5,
3053
- paddingVertical: 1,
3054
- borderRadius: 8,
3055
- backgroundColor: `${AppColors.purple}14`,
3056
- },
3057
- treeCountBadgeText: {
3058
- fontFamily: AppFonts.interMedium,
3059
- fontSize: 9.5,
3060
- color: AppColors.purple,
3061
- },
3062
- treeFolderSize: {
3063
- fontFamily: AppFonts.interMedium,
3064
- fontSize: 11,
3065
- color: AppColors.grayTextStrong,
3066
- },
3067
- treeChildrenContainer: {
3068
- backgroundColor: AppColors.white,
3069
- },
3070
- treeFileRow: {
3071
- flexDirection: 'row',
3072
- alignItems: 'center',
3073
- justifyContent: 'space-between',
3074
- paddingVertical: 6,
3075
- paddingRight: 10,
3076
- borderBottomWidth: StyleSheet.hairlineWidth,
3077
- borderBottomColor: `${AppColors.dividerColor}80`,
3078
- backgroundColor: AppColors.white,
3079
- },
3080
- treeFileRowUnused: {
3081
- backgroundColor: `${AppColors.red500}06`,
3082
- },
3083
- treeBranchGuide: {
3084
- width: 12,
3085
- alignItems: 'center',
3086
- justifyContent: 'center',
3087
- },
3088
- treeBranchGuideText: {
3089
- fontFamily: AppFonts.interRegular,
3090
- fontSize: 11,
3091
- color: AppColors.dividerColor,
3092
- },
3093
- treeFileName: {
3094
- fontFamily: AppFonts.interMedium,
3095
- fontSize: 12,
3096
- color: AppColors.primaryBlack,
3097
- flexShrink: 1,
3098
- },
3099
- treeUnusedPill: {
3100
- paddingHorizontal: 5,
3101
- paddingVertical: 1,
3102
- borderRadius: 4,
3103
- backgroundColor: `${AppColors.red500}18`,
3104
- },
3105
- treeUnusedPillText: {
3106
- fontFamily: AppFonts.interBold,
3107
- fontSize: 9,
3108
- color: AppColors.red600,
3109
- },
3110
- treeFileSizeGroup: {
3111
- alignItems: 'flex-end',
3112
- },
3113
- treeFileSizeText: {
3114
- fontFamily: AppFonts.interMedium,
3115
- fontSize: 11,
3116
- color: AppColors.primaryBlack,
3117
- },
3118
- treeFilePctText: {
3119
- fontFamily: AppFonts.interRegular,
3120
- fontSize: 9,
3121
- color: AppColors.grayTextWeak,
3122
- },
3123
- fileCard: {
3124
- backgroundColor: AppColors.white,
3125
- borderRadius: 12,
3126
- padding: 12,
3127
- borderWidth: 1,
3128
- borderColor: AppColors.dividerColor,
3129
- gap: 6,
3130
- marginBottom: 8,
3131
- },
3132
- fileCardTop: {
3133
- flexDirection: 'row',
3134
- alignItems: 'center',
3135
- gap: 8,
3136
- },
3137
- sNoBadge: {
3138
- paddingHorizontal: 6,
3139
- paddingVertical: 2,
3140
- borderRadius: 4,
3141
- backgroundColor: `${AppColors.purple}14`,
3142
- borderWidth: 1,
3143
- borderColor: `${AppColors.purple}30`,
3144
- minWidth: 26,
3145
- alignItems: 'center',
3146
- justifyContent: 'center',
3147
- },
3148
- sNoText: {
3149
- fontFamily: AppFonts.interBold,
3150
- fontSize: 10,
3151
- color: AppColors.purple,
3152
- },
3153
- extChip: {
3154
- paddingHorizontal: 6,
3155
- paddingVertical: 3,
3156
- borderRadius: 5,
3157
- borderWidth: 1,
3158
- },
3159
- extChipText: {
3160
- fontFamily: AppFonts.interBold,
3161
- fontSize: 10,
3162
- letterSpacing: 0.4,
3163
- },
3164
- pkgBadge: {
3165
- paddingHorizontal: 6,
3166
- paddingVertical: 3,
3167
- borderRadius: 5,
3168
- borderWidth: 1,
3169
- },
3170
- pkgBadgeText: {
3171
- fontFamily: AppFonts.interBold,
3172
- fontSize: 9,
3173
- letterSpacing: 0.4,
3174
- },
3175
- pkgLogoWrap: {
3176
- borderRadius: 7,
3177
- borderWidth: 1,
3178
- alignItems: 'center',
3179
- justifyContent: 'center',
3180
- backgroundColor: AppColors.white,
3181
- borderColor: AppColors.dividerColor,
3182
- overflow: 'hidden',
3183
- },
3184
- pkgLogoFallbackText: {
3185
- fontFamily: AppFonts.interBold,
3186
- },
3187
- mediaThumbWrap: {
3188
- width: 32,
3189
- height: 32,
3190
- borderRadius: 6,
3191
- overflow: 'hidden',
3192
- backgroundColor: AppColors.grayBackground,
3193
- borderWidth: 1,
3194
- borderColor: AppColors.dividerColor,
3195
- },
3196
- mediaThumbImg: {
3197
- width: '100%',
3198
- height: '100%',
3199
- },
3200
- fileName: {
3201
- fontFamily: AppFonts.interBold,
3202
- fontSize: 12.5,
3203
- color: AppColors.primaryBlack,
3204
- },
3205
- versionPill: {
3206
- paddingHorizontal: 5,
3207
- paddingVertical: 1,
3208
- borderRadius: 4,
3209
- backgroundColor: `${AppColors.purple}14`,
3210
- borderWidth: 1,
3211
- borderColor: `${AppColors.purple}26`,
3212
- },
3213
- versionPillText: {
3214
- fontFamily: AppFonts.interMedium,
3215
- fontSize: 10,
3216
- color: AppColors.purple,
3217
- },
3218
- pkgVersion: {
3219
- fontFamily: AppFonts.interMedium,
3220
- fontSize: 11,
3221
- color: AppColors.grayTextWeak,
3222
- },
3223
- filePath: {
3224
- fontFamily: AppFonts.interRegular,
3225
- fontSize: 10.5,
3226
- color: AppColors.grayTextWeak,
3227
- marginTop: 1,
3228
- },
3229
- fileSizeBox: {
3230
- alignItems: 'flex-end',
3231
- },
3232
- downloadFileBtn: {
3233
- padding: 6,
3234
- borderRadius: 6,
3235
- backgroundColor: `${AppColors.sky500}14`,
3236
- alignItems: 'center',
3237
- justifyContent: 'center',
3238
- borderWidth: 1,
3239
- borderColor: `${AppColors.sky500}28`,
3240
- },
3241
- treeActionBtn: {
3242
- padding: 4,
3243
- borderRadius: 4,
3244
- backgroundColor: `${AppColors.sky500}14`,
3245
- alignItems: 'center',
3246
- justifyContent: 'center',
3247
- borderWidth: 1,
3248
- borderColor: `${AppColors.sky500}28`,
3249
- },
3250
- fileSizeKb: {
3251
- fontFamily: AppFonts.interBold,
3252
- fontSize: 12,
3253
- color: AppColors.primaryBlack,
3254
- },
3255
- filePercent: {
3256
- fontFamily: AppFonts.interMedium,
3257
- fontSize: 10,
3258
- color: AppColors.grayTextWeak,
3259
- },
3260
- fileProgressTrack: {
3261
- height: 4,
3262
- borderRadius: 2,
3263
- backgroundColor: AppColors.grayBackground,
3264
- overflow: 'hidden',
3265
- marginVertical: 2,
3266
- },
3267
- fileProgressBar: {
3268
- height: '100%',
3269
- borderRadius: 2,
3270
- },
3271
- fileCardBottom: {
3272
- gap: 4,
3273
- },
3274
- fileMetaText: {
3275
- fontFamily: AppFonts.interRegular,
3276
- fontSize: 10.5,
3277
- color: AppColors.grayTextWeak,
3278
- },
3279
- typeTag: {
3280
- backgroundColor: AppColors.grayBackground,
3281
- paddingHorizontal: 6,
3282
- paddingVertical: 2,
3283
- borderRadius: 4,
3284
- borderWidth: 1,
3285
- borderColor: AppColors.dividerColor,
3286
- },
3287
- typeTagText: {
3288
- fontFamily: AppFonts.interMedium,
3289
- fontSize: 9.5,
3290
- color: AppColors.grayText,
3291
- },
3292
- npmLinkBtn: {
3293
- flexDirection: 'row',
3294
- alignItems: 'center',
3295
- gap: 3,
3296
- paddingHorizontal: 7,
3297
- paddingVertical: 2,
3298
- borderRadius: 5,
3299
- backgroundColor: AppColors.npmRedTint,
3300
- borderWidth: 1,
3301
- borderColor: AppColors.npmRedBorder,
3302
- },
3303
- npmLinkText: {
3304
- fontFamily: AppFonts.interBold,
3305
- fontSize: 9.5,
3306
- color: AppColors.npmRed,
3307
- },
3308
- deprecatedBadge: {
3309
- paddingHorizontal: 6,
3310
- paddingVertical: 1.5,
3311
- borderRadius: 4,
3312
- backgroundColor: AppColors.red100,
3313
- borderWidth: 1,
3314
- borderColor: AppColors.errorBorder,
3315
- },
3316
- deprecatedBadgeText: {
3317
- fontFamily: AppFonts.interBold,
3318
- fontSize: 9,
3319
- color: AppColors.red600,
3320
- letterSpacing: 0.3,
3321
- },
3322
- updateBadge: {
3323
- paddingHorizontal: 6,
3324
- paddingVertical: 1.5,
3325
- borderRadius: 4,
3326
- backgroundColor: AppColors.green100,
3327
- borderWidth: 1,
3328
- borderColor: AppColors.greenBorder,
3329
- },
3330
- updateBadgeText: {
3331
- fontFamily: AppFonts.interBold,
3332
- fontSize: 9,
3333
- color: AppColors.emerald700,
3334
- },
3335
- lastActiveText: {
3336
- fontFamily: AppFonts.interRegular,
3337
- fontSize: 10,
3338
- color: AppColors.grayTextWeak,
3339
- },
3340
- deprecationBox: {
3341
- backgroundColor: AppColors.errorCardBg,
3342
- borderRadius: 6,
3343
- paddingHorizontal: 8,
3344
- paddingVertical: 5,
3345
- borderWidth: 1,
3346
- borderColor: AppColors.errorBorder,
3347
- marginTop: 3,
3348
- },
3349
- deprecationText: {
3350
- fontFamily: AppFonts.interMedium,
3351
- fontSize: 10.5,
3352
- color: AppColors.rose700,
3353
- lineHeight: 14,
3354
- },
3355
- unusedBadge: {
3356
- paddingHorizontal: 6,
3357
- paddingVertical: 1.5,
3358
- borderRadius: 4,
3359
- backgroundColor: AppColors.red100,
3360
- borderWidth: 1,
3361
- borderColor: AppColors.errorBorder,
3362
- },
3363
- unusedBadgeText: {
3364
- fontFamily: AppFonts.interBold,
3365
- fontSize: 9.5,
3366
- color: AppColors.red600,
3367
- },
3368
- consumedBadge: {
3369
- paddingHorizontal: 6,
3370
- paddingVertical: 1.5,
3371
- borderRadius: 4,
3372
- backgroundColor: AppColors.green100,
3373
- borderWidth: 1,
3374
- borderColor: AppColors.greenBorder,
3375
- },
3376
- consumedBadgeText: {
3377
- fontFamily: AppFonts.interBold,
3378
- fontSize: 9.5,
3379
- color: AppColors.emerald600,
3380
- },
3381
- treeFolderChevronWrap: {
3382
- width: 18,
3383
- height: 18,
3384
- borderRadius: 9,
3385
- backgroundColor: `${AppColors.purple}14`,
3386
- alignItems: 'center',
3387
- justifyContent: 'center',
3388
- },
3389
- treeFileCardUnused: {
3390
- borderColor: AppColors.errorBorder,
3391
- backgroundColor: AppColors.red50,
3392
- },
3393
- adviceUnused: {
3394
- backgroundColor: AppColors.errorCardBg,
3395
- borderWidth: 1,
3396
- borderColor: AppColors.errorBorder,
3397
- },
3398
- liveWarningCard: {
3399
- flexDirection: 'row',
3400
- alignItems: 'center',
3401
- backgroundColor: AppColors.amber100,
3402
- borderWidth: 1,
3403
- borderColor: AppColors.amber200,
3404
- borderRadius: 10,
3405
- padding: 12,
3406
- marginBottom: 12,
3407
- },
3408
- liveWarningTitle: {
3409
- fontFamily: AppFonts.interBold,
3410
- fontSize: 12,
3411
- color: AppColors.amber800Warm,
3412
- marginBottom: 2,
3413
- },
3414
- liveWarningDesc: {
3415
- fontFamily: AppFonts.interRegular,
3416
- fontSize: 10.5,
3417
- lineHeight: 14,
3418
- color: AppColors.amber800Warm,
3419
- },
3420
- adviceBadge: {
3421
- flexDirection: 'row',
3422
- alignItems: 'center',
3423
- paddingHorizontal: 8,
3424
- paddingVertical: 5,
3425
- borderRadius: 6,
3426
- marginTop: 4,
3427
- gap: 6,
3428
- },
3429
- adviceWarning: {
3430
- backgroundColor: AppColors.amber100,
3431
- borderWidth: 1,
3432
- borderColor: AppColors.amber200,
3433
- },
3434
- adviceOptimal: {
3435
- backgroundColor: AppColors.green100,
3436
- borderWidth: 1,
3437
- borderColor: AppColors.greenBorder,
3438
- },
3439
- adviceText: {
3440
- fontFamily: AppFonts.interMedium,
3441
- fontSize: 10.5,
3442
- lineHeight: 14,
3443
- flex: 1,
3444
- },
3445
- impactBadge: {
3446
- paddingHorizontal: 6,
3447
- paddingVertical: 2,
3448
- borderRadius: 4,
3449
- borderWidth: 1,
3450
- },
3451
- impactBadgeText: {
3452
- fontFamily: AppFonts.interBold,
3453
- fontSize: 9,
3454
- },
3455
- searchHighlight: {
3456
- backgroundColor: AppColors.yellow200,
3457
- color: AppColors.yellow800,
3458
- fontFamily: AppFonts.interBold,
3459
- },
3460
- tipsCard: {
3461
- backgroundColor: AppColors.purple50,
3462
- borderRadius: 14,
3463
- padding: 14,
3464
- borderWidth: 1,
3465
- borderColor: AppColors.purple200,
3466
- },
3467
- tipsHeading: {
3468
- fontFamily: AppFonts.interBold,
3469
- fontSize: 13.5,
3470
- color: AppColors.purple800,
3471
- },
3472
- totalSummaryCard: {
3473
- marginTop: 10,
3474
- backgroundColor: `${AppColors.brandPurple}0B`,
3475
- borderRadius: 12,
3476
- padding: 12,
3477
- borderWidth: 1,
3478
- borderColor: `${AppColors.brandPurple}25`,
3479
- gap: 8,
3480
- },
3481
- totalSummaryRow: {
3482
- flexDirection: 'row',
3483
- justifyContent: 'space-between',
3484
- alignItems: 'center',
3485
- },
3486
- totalSummaryLabelWrap: {
3487
- flexDirection: 'row',
3488
- alignItems: 'center',
3489
- gap: 8,
3490
- },
3491
- totalIconBadge: {
3492
- width: 32,
3493
- height: 32,
3494
- borderRadius: 8,
3495
- backgroundColor: `${AppColors.brandPurple}15`,
3496
- alignItems: 'center',
3497
- justifyContent: 'center',
3498
- },
3499
- totalSummaryLabel: {
3500
- fontFamily: AppFonts.interBold,
3501
- fontSize: 11.5,
3502
- color: AppColors.brandPurple,
3503
- letterSpacing: 0.6,
3504
- },
3505
- totalSummarySub: {
3506
- fontFamily: AppFonts.interRegular,
3507
- fontSize: 10,
3508
- color: AppColors.grayTextWeak,
3509
- marginTop: 1,
3510
- },
3511
- totalSummaryValue: {
3512
- fontFamily: AppFonts.interBold,
3513
- fontSize: 15,
3514
- color: AppColors.primaryBlack,
3515
- },
3516
- totalSummaryKb: {
3517
- fontFamily: AppFonts.interMedium,
3518
- fontSize: 10,
3519
- color: AppColors.grayTextWeak,
3520
- },
3521
- totalFormulaGrid: {
3522
- flexDirection: 'row',
3523
- flexWrap: 'wrap',
3524
- gap: 6,
3525
- paddingTop: 6,
3526
- borderTopWidth: 1,
3527
- borderTopColor: `${AppColors.brandPurple}15`,
3528
- },
3529
- totalChip: {
3530
- flexDirection: 'row',
3531
- alignItems: 'center',
3532
- gap: 4,
3533
- backgroundColor: AppColors.white,
3534
- borderRadius: 6,
3535
- paddingHorizontal: 6,
3536
- paddingVertical: 3,
3537
- borderWidth: 1,
3538
- borderColor: AppColors.dividerColor,
3539
- },
3540
- totalDot: {
3541
- width: 6,
3542
- height: 6,
3543
- borderRadius: 3,
3544
- },
3545
- totalChipText: {
3546
- fontFamily: AppFonts.interBold,
3547
- fontSize: 9.5,
3548
- color: AppColors.primaryBlack,
3549
- },
3550
- totalSummaryFormula: {
3551
- fontFamily: AppFonts.interRegular,
3552
- fontSize: 10.5,
3553
- color: AppColors.grayText,
3554
- lineHeight: 15,
3555
- },
3556
- stickyFooterBar: {
3557
- flexDirection: 'row',
3558
- justifyContent: 'space-between',
3559
- alignItems: 'center',
3560
- backgroundColor: AppColors.white,
3561
- paddingHorizontal: 16,
3562
- paddingTop: 10,
3563
- paddingBottom: Platform.OS === 'ios' ? 24 : 12,
3564
- borderTopWidth: 1,
3565
- borderTopColor: AppColors.dividerColor,
3566
- shadowColor: AppColors.primaryBlack,
3567
- shadowOffset: { width: 0, height: -2 },
3568
- shadowOpacity: 0.05,
3569
- shadowRadius: 4,
3570
- elevation: 3,
3571
- },
3572
- footerTitle: {
3573
- fontFamily: AppFonts.interBold,
3574
- fontSize: 12,
3575
- color: AppColors.primaryBlack,
3576
- },
3577
- footerSizeVal: {
3578
- fontFamily: AppFonts.interBold,
3579
- fontSize: 12.5,
3580
- color: AppColors.purple,
3581
- },
3582
- tipItem: {
3583
- marginBottom: 10,
3584
- backgroundColor: AppColors.white,
3585
- padding: 12,
3586
- borderRadius: 10,
3587
- borderWidth: 1,
3588
- borderColor: AppColors.purple200,
3589
- gap: 6,
3590
- },
3591
- tipItemHeader: {
3592
- flexDirection: 'row',
3593
- alignItems: 'flex-start',
3594
- justifyContent: 'space-between',
3595
- gap: 8,
3596
- },
3597
- tipTitleWrap: {
3598
- flexDirection: 'row',
3599
- alignItems: 'center',
3600
- gap: 6,
3601
- flex: 1,
3602
- flexShrink: 1,
3603
- },
3604
- tipActionWrap: {
3605
- flexDirection: 'row',
3606
- alignItems: 'center',
3607
- gap: 6,
3608
- flexShrink: 0,
3609
- },
3610
- tipTitle: {
3611
- fontFamily: AppFonts.interBold,
3612
- fontSize: 12,
3613
- color: AppColors.purple900,
3614
- flex: 1,
3615
- flexShrink: 1,
3616
- },
3617
- tipDesc: {
3618
- fontFamily: AppFonts.interRegular,
3619
- fontSize: 11,
3620
- color: AppColors.gray500,
3621
- lineHeight: 16,
3622
- },
3623
- });
3624
- export default BundleTab;
1263
+ {M==="optimizer"&&<Te style={{flex:1}}contentContainerStyle={e.contentContainer}keyboardShouldPersistTaps="handled">
1264
+ <T style={e.tipsCard}>
1265
+ <T style={{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:12}}>
1266
+ <T style={{flexDirection:"row",alignItems:"center",gap:6}}>
1267
+ <Ge color={t.purple}size={18}/>
1268
+ <C style={e.tipsHeading}>
1269
+ {k("bundle.optimizerTitle")}
1270
+ </C>
1271
+ </T>
1272
+ <K value={()=>[k("bundle.optTip1Title"),`${k("bundle.optTip2Title")} (${k(E?"bundle.active":"bundle.actionRequired")})`,k("bundle.optTip3Title"),k("bundle.optTip4Title"),k("bundle.optTip5Title")]}label={k("bundle.optimizationChecklist")}/>
1273
+ </T>
1274
+
1275
+ {[{iconType:"image",iconColor:t.pink500,title:k("bundle.optTip1Title"),desc:k("bundle.optTip1Desc"),badge:k("bundle.highImpact"),badgeColor:t.pink500},{iconType:"bolt",iconColor:E?t.emerald500:t.amber500,title:k("bundle.optTip2Title"),desc:k(E?"bundle.optTip2DescActive":"bundle.optTip2DescInactive"),badge:k(E?"bundle.active":"bundle.actionRequired"),badgeColor:E?t.emerald500:t.amber500},{iconType:"font",iconColor:t.purple500,title:k("bundle.optTip3Title"),desc:k("bundle.optTip3Desc"),badge:k("bundle.mediumImpact"),badgeColor:t.purple500},{iconType:"source",iconColor:t.sky500,title:k("bundle.optTip4Title"),desc:k("bundle.optTip4Desc"),badge:k("bundle.bestPractice"),badgeColor:t.sky500},{iconType:"overhead",iconColor:t.indigo500,title:k("bundle.optTip5Title"),desc:k("bundle.optTip5Desc"),badge:k("bundle.bestPractice"),badgeColor:t.indigo500}].map((o,z)=><T key={z}style={e.tipItem}>
1276
+ <T style={e.tipItemHeader}>
1277
+ <T style={e.tipTitleWrap}>
1278
+ <T style={e.sNoBadge}>
1279
+ <C style={e.sNoText}>#{z+1}</C>
1280
+ </T>
1281
+ <Z type={o.iconType}size={14}color={o.iconColor}/>
1282
+ <C style={e.tipTitle}>{o.title}</C>
1283
+ </T>
1284
+ <T style={e.tipActionWrap}>
1285
+ <T style={[e.impactBadge,{backgroundColor:`${o.badgeColor}18`,borderColor:`${o.badgeColor}40`}]}>
1286
+ <C style={[e.impactBadgeText,{color:o.badgeColor}]}>
1287
+ {o.badge}
1288
+ </C>
1289
+ </T>
1290
+ <K value={()=>o}label={k("bundle.tipDetails")}/>
1291
+ </T>
1292
+ </T>
1293
+ <C style={e.tipDesc}>{o.desc}</C>
1294
+ </T>)}
1295
+ </T>
1296
+ </Te>}
1297
+ </T>}),e=je.create({topTabWrap:{backgroundColor:t.white,paddingVertical:8,borderBottomWidth:1,borderBottomColor:t.dividerColor,flexDirection:"row",alignItems:"center",paddingRight:10},reloadButton:{padding:8,borderRadius:20,backgroundColor:t.grayBackground,borderWidth:1,borderColor:t.dividerColor,alignItems:"center",justifyContent:"center",marginLeft:4},analyzingContainer:{flex:1,alignItems:"center",justifyContent:"center",gap:8,padding:24},analyzingText:{fontFamily:S.interBold,fontSize:13,color:t.primaryBlack},analyzingHint:{fontFamily:S.interRegular,fontSize:11,color:t.grayTextWeak},subTabsScroll:{paddingHorizontal:12,gap:8,flexDirection:"row",alignItems:"center"},subTabPill:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:12,paddingVertical:7,borderRadius:20,backgroundColor:t.grayBackground,borderWidth:1,borderColor:t.dividerColor},subTabPillActive:{backgroundColor:t.brandPurple,borderColor:t.brandPurple,shadowColor:t.brandPurple,shadowOffset:{width:0,height:2},shadowOpacity:.2,shadowRadius:3,elevation:2},subTabPillText:{fontFamily:S.interMedium,fontSize:11.5,color:t.grayTextStrong},subTabPillTextActive:{fontFamily:S.interBold,color:t.white},contentContainer:{padding:16,paddingBottom:40,gap:14},heroCard:{backgroundColor:t.white,borderRadius:14,padding:16,borderWidth:1,borderColor:t.dividerColor,shadowColor:t.primaryBlack,shadowOffset:{width:0,height:2},shadowOpacity:.04,shadowRadius:6,elevation:2},heroTopRow:{flexDirection:"row",alignItems:"flex-start",gap:12,marginBottom:16},heroIconWrap:{width:44,height:44,borderRadius:12,backgroundColor:`${t.brandPurple}12`,alignItems:"center",justifyContent:"center",borderWidth:1,borderColor:`${t.brandPurple}25`},heroTitle:{fontFamily:S.interBold,fontSize:16,color:t.primaryBlack},heroSubtitle:{fontFamily:S.interRegular,fontSize:12,color:t.grayTextWeak,marginTop:2},metricsGrid:{flexDirection:"row",flexWrap:"wrap",gap:8},metricBox:{flex:1,minWidth:"45%",backgroundColor:t.grayBackground,borderRadius:10,padding:10,borderWidth:1,borderColor:t.dividerColor},metricLabel:{fontFamily:S.interBold,fontSize:9.5,color:t.grayTextWeak,letterSpacing:.5},metricValue:{fontFamily:S.interBold,fontSize:14,color:t.primaryBlack,marginTop:3},metricHint:{fontFamily:S.interMedium,fontSize:10.5,color:t.grayText,marginTop:2},statusIndicator:{width:8,height:8,borderRadius:4},prodPlatformScroll:{flexDirection:"row",alignItems:"center",gap:8,paddingBottom:4},prodPlatformBtn:{flexDirection:"row",alignItems:"center",paddingVertical:7,paddingHorizontal:12,borderRadius:20,backgroundColor:t.white,borderWidth:1,borderColor:t.dividerColor,gap:6},prodPlatformBtnActive:{backgroundColor:t.brandPurple,borderColor:t.brandPurple,shadowColor:t.brandPurple,shadowOffset:{width:0,height:2},shadowOpacity:.18,shadowRadius:3,elevation:2},prodPlatformBtnText:{fontFamily:S.interBold,fontSize:11.5,color:t.grayTextStrong},prodPlatformBtnTextActive:{color:t.white},prodPlatformBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:10,backgroundColor:`${t.purple}14`},prodPlatformBadgeActive:{backgroundColor:"rgba(255, 255, 255, 0.25)"},prodPlatformBadgeText:{fontFamily:S.interBold,fontSize:9.5,color:t.purple},prodPlatformBadgeTextActive:{color:t.white},sectionCard:{backgroundColor:t.white,borderRadius:14,padding:14,borderWidth:1,borderColor:t.dividerColor,overflow:"hidden"},sectionHeaderRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginBottom:10,gap:8},sectionTitle:{fontFamily:S.interBold,fontSize:13,color:t.primaryBlack},sectionSub:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextWeak},treemapBar:{flexDirection:"row",borderRadius:6,overflow:"hidden",height:16,marginBottom:12,backgroundColor:t.slate200},prodTreemapBar:{flexDirection:"row",borderRadius:6,overflow:"hidden",height:16,marginBottom:12,backgroundColor:t.slate200},legendGrid:{flexDirection:"row",flexWrap:"wrap",gap:8},legendItem:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:8,paddingVertical:5,borderRadius:8,backgroundColor:`${t.slate200}40`,borderWidth:1,borderColor:`${t.dividerColor}`,flexShrink:0},legendText:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextStrong},legendVal:{fontFamily:S.interBold,color:t.primaryBlack},subsystemCard:{backgroundColor:t.white,borderRadius:12,padding:12,marginBottom:8,borderWidth:1,borderColor:t.dividerColor,gap:8},subsystemHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:8},subsystemTitle:{fontFamily:S.interBold,fontSize:12.5,color:t.primaryBlack},subsystemBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:6},subsystemBadgeText:{fontFamily:S.interBold,fontSize:10},subsystemGrid:{flexDirection:"row",flexWrap:"wrap",gap:6},subsystemItem:{flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:8,paddingVertical:4,borderRadius:6,backgroundColor:t.grayBackground,borderWidth:1,borderColor:t.dividerColor},subsystemItemText:{fontFamily:S.interMedium,fontSize:10.5,color:t.grayTextStrong},subsystemItemVal:{fontFamily:S.interBold,color:t.primaryBlack},catRowCard:{backgroundColor:t.grayBackground,borderRadius:12,padding:12,marginBottom:8,borderWidth:1,borderColor:t.dividerColor,gap:8},catRowTop:{flexDirection:"row",alignItems:"flex-start",gap:10},catIconBox:{width:36,height:36,borderRadius:10,borderWidth:1,alignItems:"center",justifyContent:"center",flexShrink:0},catRowTitleWrap:{flex:1,minWidth:0,gap:2},catRowTitle:{fontFamily:S.interBold,fontSize:13,color:t.primaryBlack,flex:1},catRowDesc:{fontFamily:S.interRegular,fontSize:10.5,color:t.grayTextWeak,lineHeight:14.5},catRowSize:{fontFamily:S.interBold,fontSize:12.5,color:t.primaryBlack},catRowRight:{alignItems:"flex-end",justifyContent:"center",flexShrink:0,minWidth:64},catRowPct:{fontFamily:S.interMedium,fontSize:10,color:t.grayTextWeak},catPctPill:{paddingHorizontal:5.5,paddingVertical:1.5,borderRadius:5},catPctText:{fontFamily:S.interBold,fontSize:9.5},catProgressTrack:{height:5,borderRadius:2.5,backgroundColor:`${t.slate200}`,overflow:"hidden",marginTop:2},catProgressBar:{height:"100%",borderRadius:2.5},filterContainer:{backgroundColor:t.white,borderRadius:12,padding:10,marginHorizontal:16,marginTop:12,borderWidth:1,borderColor:t.dividerColor,gap:8},searchRow:{flexDirection:"row",alignItems:"center",backgroundColor:t.grayBackground,borderRadius:8,paddingHorizontal:10,height:36,gap:8},searchInput:{flex:1,fontFamily:S.interRegular,fontSize:12,color:t.primaryBlack,padding:0},categoryPillsScroll:{gap:6,paddingVertical:2},catPill:{flexDirection:"row",alignItems:"center",gap:4,paddingHorizontal:10,paddingVertical:5,borderRadius:16,backgroundColor:t.grayBackground,borderWidth:1,borderColor:t.dividerColor},catPillActive:{backgroundColor:t.brandPurple,borderColor:t.brandPurple},catPillText:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextStrong},catPillTextActive:{fontFamily:S.interBold,color:t.white},listHeaderCount:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextWeak,paddingHorizontal:4},treeHeaderRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:2,marginBottom:6},viewModeToggleGroup:{flexDirection:"row",backgroundColor:t.grayBackground,borderRadius:8,padding:2,borderWidth:1,borderColor:t.dividerColor},viewModeBtn:{paddingHorizontal:10,paddingVertical:5,borderRadius:6},viewModeBtnActive:{backgroundColor:t.brandPurple,shadowColor:t.brandPurple,shadowOffset:{width:0,height:1},shadowOpacity:.2,shadowRadius:2,elevation:2},viewModeBtnText:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextStrong},viewModeBtnTextActive:{fontFamily:S.interBold,color:t.white},treeActionLink:{fontFamily:S.interBold,fontSize:11.5,color:t.purple},treeRootCard:{backgroundColor:t.white,borderRadius:12,borderWidth:1,borderColor:t.dividerColor,overflow:"hidden",marginBottom:16},treeFolderBlock:{borderBottomWidth:je.hairlineWidth,borderBottomColor:t.dividerColor},treeFolderRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingVertical:8,paddingRight:10,backgroundColor:`${t.purple}06`},treeRowLeft:{flexDirection:"row",alignItems:"center",gap:6,flex:1,marginRight:6},treeRowRight:{flexDirection:"row",alignItems:"center",gap:6},treeChevron:{fontSize:12,color:t.purple,fontFamily:S.interBold,width:12,textAlign:"center"},treeFolderName:{fontFamily:S.interBold,fontSize:12.5,color:t.primaryBlack},treeCountBadge:{paddingHorizontal:5,paddingVertical:1,borderRadius:8,backgroundColor:`${t.purple}14`},treeCountBadgeText:{fontFamily:S.interMedium,fontSize:9.5,color:t.purple},treeFolderSize:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextStrong},treeChildrenContainer:{backgroundColor:t.white},treeFileRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingVertical:6,paddingRight:10,borderBottomWidth:je.hairlineWidth,borderBottomColor:`${t.dividerColor}80`,backgroundColor:t.white},treeFileRowUnused:{backgroundColor:`${t.red500}06`},treeBranchGuide:{width:12,alignItems:"center",justifyContent:"center"},treeBranchGuideText:{fontFamily:S.interRegular,fontSize:11,color:t.dividerColor},treeFileName:{fontFamily:S.interMedium,fontSize:12,color:t.primaryBlack,flexShrink:1},treeUnusedPill:{paddingHorizontal:5,paddingVertical:1,borderRadius:4,backgroundColor:`${t.red500}18`},treeUnusedPillText:{fontFamily:S.interBold,fontSize:9,color:t.red600},treeFileSizeGroup:{alignItems:"flex-end"},treeFileSizeText:{fontFamily:S.interMedium,fontSize:11,color:t.primaryBlack},treeFilePctText:{fontFamily:S.interRegular,fontSize:9,color:t.grayTextWeak},fileCard:{backgroundColor:t.white,borderRadius:12,padding:12,borderWidth:1,borderColor:t.dividerColor,gap:6,marginBottom:8},fileCardTop:{flexDirection:"row",alignItems:"center",gap:8},sNoBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:4,backgroundColor:`${t.purple}14`,borderWidth:1,borderColor:`${t.purple}30`,minWidth:26,alignItems:"center",justifyContent:"center"},sNoText:{fontFamily:S.interBold,fontSize:10,color:t.purple},extChip:{paddingHorizontal:6,paddingVertical:3,borderRadius:5,borderWidth:1},extChipText:{fontFamily:S.interBold,fontSize:10,letterSpacing:.4},pkgBadge:{paddingHorizontal:6,paddingVertical:3,borderRadius:5,borderWidth:1},pkgBadgeText:{fontFamily:S.interBold,fontSize:9,letterSpacing:.4},pkgLogoWrap:{borderRadius:7,borderWidth:1,alignItems:"center",justifyContent:"center",backgroundColor:t.white,borderColor:t.dividerColor,overflow:"hidden"},pkgLogoFallbackText:{fontFamily:S.interBold},mediaThumbWrap:{width:32,height:32,borderRadius:6,overflow:"hidden",backgroundColor:t.grayBackground,borderWidth:1,borderColor:t.dividerColor},mediaThumbImg:{width:"100%",height:"100%"},fileName:{fontFamily:S.interBold,fontSize:12.5,color:t.primaryBlack},versionPill:{paddingHorizontal:5,paddingVertical:1,borderRadius:4,backgroundColor:`${t.purple}14`,borderWidth:1,borderColor:`${t.purple}26`},versionPillText:{fontFamily:S.interMedium,fontSize:10,color:t.purple},pkgVersion:{fontFamily:S.interMedium,fontSize:11,color:t.grayTextWeak},filePath:{fontFamily:S.interRegular,fontSize:10.5,color:t.grayTextWeak,marginTop:1},fileSizeBox:{alignItems:"flex-end"},downloadFileBtn:{padding:6,borderRadius:6,backgroundColor:`${t.sky500}14`,alignItems:"center",justifyContent:"center",borderWidth:1,borderColor:`${t.sky500}28`},treeActionBtn:{padding:4,borderRadius:4,backgroundColor:`${t.sky500}14`,alignItems:"center",justifyContent:"center",borderWidth:1,borderColor:`${t.sky500}28`},fileSizeKb:{fontFamily:S.interBold,fontSize:12,color:t.primaryBlack},filePercent:{fontFamily:S.interMedium,fontSize:10,color:t.grayTextWeak},fileProgressTrack:{height:4,borderRadius:2,backgroundColor:t.grayBackground,overflow:"hidden",marginVertical:2},fileProgressBar:{height:"100%",borderRadius:2},fileCardBottom:{gap:4},fileMetaText:{fontFamily:S.interRegular,fontSize:10.5,color:t.grayTextWeak},typeTag:{backgroundColor:t.grayBackground,paddingHorizontal:6,paddingVertical:2,borderRadius:4,borderWidth:1,borderColor:t.dividerColor},typeTagText:{fontFamily:S.interMedium,fontSize:9.5,color:t.grayText},npmLinkBtn:{flexDirection:"row",alignItems:"center",gap:3,paddingHorizontal:7,paddingVertical:2,borderRadius:5,backgroundColor:t.npmRedTint,borderWidth:1,borderColor:t.npmRedBorder},npmLinkText:{fontFamily:S.interBold,fontSize:9.5,color:t.npmRed},deprecatedBadge:{paddingHorizontal:6,paddingVertical:1.5,borderRadius:4,backgroundColor:t.red100,borderWidth:1,borderColor:t.errorBorder},deprecatedBadgeText:{fontFamily:S.interBold,fontSize:9,color:t.red600,letterSpacing:.3},updateBadge:{paddingHorizontal:6,paddingVertical:1.5,borderRadius:4,backgroundColor:t.green100,borderWidth:1,borderColor:t.greenBorder},updateBadgeText:{fontFamily:S.interBold,fontSize:9,color:t.emerald700},lastActiveText:{fontFamily:S.interRegular,fontSize:10,color:t.grayTextWeak},deprecationBox:{backgroundColor:t.errorCardBg,borderRadius:6,paddingHorizontal:8,paddingVertical:5,borderWidth:1,borderColor:t.errorBorder,marginTop:3},deprecationText:{fontFamily:S.interMedium,fontSize:10.5,color:t.rose700,lineHeight:14},unusedBadge:{paddingHorizontal:6,paddingVertical:1.5,borderRadius:4,backgroundColor:t.red100,borderWidth:1,borderColor:t.errorBorder},unusedBadgeText:{fontFamily:S.interBold,fontSize:9.5,color:t.red600},consumedBadge:{paddingHorizontal:6,paddingVertical:1.5,borderRadius:4,backgroundColor:t.green100,borderWidth:1,borderColor:t.greenBorder},consumedBadgeText:{fontFamily:S.interBold,fontSize:9.5,color:t.emerald600},treeFolderChevronWrap:{width:18,height:18,borderRadius:9,backgroundColor:`${t.purple}14`,alignItems:"center",justifyContent:"center"},treeFileCardUnused:{borderColor:t.errorBorder,backgroundColor:t.red50},adviceUnused:{backgroundColor:t.errorCardBg,borderWidth:1,borderColor:t.errorBorder},liveWarningCard:{flexDirection:"row",alignItems:"center",backgroundColor:t.amber100,borderWidth:1,borderColor:t.amber200,borderRadius:10,padding:12,marginBottom:12},liveWarningTitle:{fontFamily:S.interBold,fontSize:12,color:t.amber800Warm,marginBottom:2},liveWarningDesc:{fontFamily:S.interRegular,fontSize:10.5,lineHeight:14,color:t.amber800Warm},adviceBadge:{flexDirection:"row",alignItems:"center",paddingHorizontal:8,paddingVertical:5,borderRadius:6,marginTop:4,gap:6},adviceWarning:{backgroundColor:t.amber100,borderWidth:1,borderColor:t.amber200},adviceOptimal:{backgroundColor:t.green100,borderWidth:1,borderColor:t.greenBorder},adviceText:{fontFamily:S.interMedium,fontSize:10.5,lineHeight:14,flex:1},impactBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:4,borderWidth:1},impactBadgeText:{fontFamily:S.interBold,fontSize:9},searchHighlight:{backgroundColor:t.yellow200,color:t.yellow800,fontFamily:S.interBold},tipsCard:{backgroundColor:t.purple50,borderRadius:14,padding:14,borderWidth:1,borderColor:t.purple200},tipsHeading:{fontFamily:S.interBold,fontSize:13.5,color:t.purple800},totalSummaryCard:{marginTop:10,backgroundColor:`${t.brandPurple}0B`,borderRadius:12,padding:12,borderWidth:1,borderColor:`${t.brandPurple}25`,gap:8},totalSummaryRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},totalSummaryLabelWrap:{flexDirection:"row",alignItems:"center",gap:8},totalIconBadge:{width:32,height:32,borderRadius:8,backgroundColor:`${t.brandPurple}15`,alignItems:"center",justifyContent:"center"},totalSummaryLabel:{fontFamily:S.interBold,fontSize:11.5,color:t.brandPurple,letterSpacing:.6},totalSummarySub:{fontFamily:S.interRegular,fontSize:10,color:t.grayTextWeak,marginTop:1},totalSummaryValue:{fontFamily:S.interBold,fontSize:15,color:t.primaryBlack},totalSummaryKb:{fontFamily:S.interMedium,fontSize:10,color:t.grayTextWeak},totalFormulaGrid:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingTop:6,borderTopWidth:1,borderTopColor:`${t.brandPurple}15`},totalChip:{flexDirection:"row",alignItems:"center",gap:4,backgroundColor:t.white,borderRadius:6,paddingHorizontal:6,paddingVertical:3,borderWidth:1,borderColor:t.dividerColor},totalDot:{width:6,height:6,borderRadius:3},totalChipText:{fontFamily:S.interBold,fontSize:9.5,color:t.primaryBlack},totalSummaryFormula:{fontFamily:S.interRegular,fontSize:10.5,color:t.grayText,lineHeight:15},stickyFooterBar:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",backgroundColor:t.white,paddingHorizontal:16,paddingTop:10,paddingBottom:kt.OS==="ios"?24:12,borderTopWidth:1,borderTopColor:t.dividerColor,shadowColor:t.primaryBlack,shadowOffset:{width:0,height:-2},shadowOpacity:.05,shadowRadius:4,elevation:3},footerTitle:{fontFamily:S.interBold,fontSize:12,color:t.primaryBlack},footerSizeVal:{fontFamily:S.interBold,fontSize:12.5,color:t.purple},tipItem:{marginBottom:10,backgroundColor:t.white,padding:12,borderRadius:10,borderWidth:1,borderColor:t.purple200,gap:6},tipItemHeader:{flexDirection:"row",alignItems:"flex-start",justifyContent:"space-between",gap:8},tipTitleWrap:{flexDirection:"row",alignItems:"center",gap:6,flex:1,flexShrink:1},tipActionWrap:{flexDirection:"row",alignItems:"center",gap:6,flexShrink:0},tipTitle:{fontFamily:S.interBold,fontSize:12,color:t.purple900,flex:1,flexShrink:1},tipDesc:{fontFamily:S.interRegular,fontSize:11,color:t.gray500,lineHeight:16}});export default Io;