react-native-inapp-inspector 1.1.18 → 1.1.19

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 (291) hide show
  1. package/dist/commonjs/constants/version.d.ts +1 -1
  2. package/dist/commonjs/constants/version.js +1 -1
  3. package/dist/esm/constants/version.d.ts +1 -1
  4. package/dist/esm/constants/version.js +1 -1
  5. package/package.json +2 -4
  6. package/assets/banner_dark.svg +0 -186
  7. package/assets/banner_light.svg +0 -186
  8. package/assets/icon_circle.svg +0 -148
  9. package/assets/icon_square.svg +0 -148
  10. package/assets/social_preview.png +0 -0
  11. package/assets/walkthrough.gif +0 -0
  12. package/dist/commonjs/assets/svgAssets.d.ts +0 -3
  13. package/dist/commonjs/assets/svgAssets.js +0 -17
  14. package/dist/commonjs/components/AnalyticsTabView.d.ts +0 -15
  15. package/dist/commonjs/components/AnalyticsTabView.js +0 -157
  16. package/dist/commonjs/components/ApiDetailView.d.ts +0 -22
  17. package/dist/commonjs/components/ApiDetailView.js +0 -304
  18. package/dist/commonjs/components/ApisTabView.d.ts +0 -33
  19. package/dist/commonjs/components/ApisTabView.js +0 -235
  20. package/dist/commonjs/components/ConsoleLogDetailView.d.ts +0 -9
  21. package/dist/commonjs/components/ConsoleLogDetailView.js +0 -278
  22. package/dist/commonjs/components/ConsoleLogsTabView.d.ts +0 -24
  23. package/dist/commonjs/components/ConsoleLogsTabView.js +0 -354
  24. package/dist/commonjs/components/FloatingBubble.d.ts +0 -14
  25. package/dist/commonjs/components/FloatingBubble.js +0 -75
  26. package/dist/commonjs/components/Inspector/InsightsDashboard.d.ts +0 -3
  27. package/dist/commonjs/components/Inspector/InsightsDashboard.js +0 -619
  28. package/dist/commonjs/components/Inspector/WebViewTab.d.ts +0 -3
  29. package/dist/commonjs/components/Inspector/WebViewTab.js +0 -757
  30. package/dist/commonjs/components/InspectorHeader.d.ts +0 -19
  31. package/dist/commonjs/components/InspectorHeader.js +0 -329
  32. package/dist/commonjs/components/InspectorTabBar.d.ts +0 -16
  33. package/dist/commonjs/components/InspectorTabBar.js +0 -90
  34. package/dist/commonjs/components/NavigationTracker.d.ts +0 -7
  35. package/dist/commonjs/components/NavigationTracker.js +0 -76
  36. package/dist/commonjs/components/ReduxTabView.d.ts +0 -9
  37. package/dist/commonjs/components/ReduxTabView.js +0 -56
  38. package/dist/commonjs/components/ReduxTreeView.d.ts +0 -16
  39. package/dist/commonjs/components/ReduxTreeView.js +0 -1257
  40. package/dist/commonjs/components/SettingsView.d.ts +0 -13
  41. package/dist/commonjs/components/SettingsView.js +0 -328
  42. package/dist/commonjs/customHooks/webViewLogger.d.ts +0 -24
  43. package/dist/commonjs/customHooks/webViewLogger.js +0 -452
  44. package/dist/commonjs/enums/index.d.ts +0 -39
  45. package/dist/commonjs/enums/index.js +0 -50
  46. package/dist/commonjs/i18n/en.json +0 -144
  47. package/dist/esm/assets/svgAssets.d.ts +0 -3
  48. package/dist/esm/assets/svgAssets.js +0 -14
  49. package/dist/esm/components/AnalyticsTabView.d.ts +0 -15
  50. package/dist/esm/components/AnalyticsTabView.js +0 -151
  51. package/dist/esm/components/ApiDetailView.d.ts +0 -22
  52. package/dist/esm/components/ApiDetailView.js +0 -264
  53. package/dist/esm/components/ApisTabView.d.ts +0 -33
  54. package/dist/esm/components/ApisTabView.js +0 -196
  55. package/dist/esm/components/ConsoleLogDetailView.d.ts +0 -9
  56. package/dist/esm/components/ConsoleLogDetailView.js +0 -271
  57. package/dist/esm/components/ConsoleLogsTabView.d.ts +0 -24
  58. package/dist/esm/components/ConsoleLogsTabView.js +0 -348
  59. package/dist/esm/components/FloatingBubble.d.ts +0 -14
  60. package/dist/esm/components/FloatingBubble.js +0 -68
  61. package/dist/esm/components/Inspector/InsightsDashboard.d.ts +0 -3
  62. package/dist/esm/components/Inspector/InsightsDashboard.js +0 -614
  63. package/dist/esm/components/Inspector/WebViewTab.d.ts +0 -3
  64. package/dist/esm/components/Inspector/WebViewTab.js +0 -752
  65. package/dist/esm/components/InspectorHeader.d.ts +0 -19
  66. package/dist/esm/components/InspectorHeader.js +0 -323
  67. package/dist/esm/components/InspectorTabBar.d.ts +0 -16
  68. package/dist/esm/components/InspectorTabBar.js +0 -84
  69. package/dist/esm/components/NavigationTracker.d.ts +0 -7
  70. package/dist/esm/components/NavigationTracker.js +0 -39
  71. package/dist/esm/components/ReduxTabView.d.ts +0 -9
  72. package/dist/esm/components/ReduxTabView.js +0 -50
  73. package/dist/esm/components/ReduxTreeView.d.ts +0 -16
  74. package/dist/esm/components/ReduxTreeView.js +0 -1218
  75. package/dist/esm/components/SettingsView.d.ts +0 -13
  76. package/dist/esm/components/SettingsView.js +0 -321
  77. package/dist/esm/customHooks/webViewLogger.d.ts +0 -24
  78. package/dist/esm/customHooks/webViewLogger.js +0 -405
  79. package/dist/esm/enums/index.d.ts +0 -39
  80. package/dist/esm/enums/index.js +0 -47
  81. package/dist/esm/i18n/en.json +0 -144
  82. package/example/.bundle/config +0 -2
  83. package/example/.eslintrc.js +0 -4
  84. package/example/.prettierrc.js +0 -5
  85. package/example/.watchmanconfig +0 -1
  86. package/example/App.tsx +0 -879
  87. package/example/Gemfile +0 -17
  88. package/example/README.md +0 -53
  89. package/example/__tests__/App.test.tsx +0 -13
  90. package/example/android/app/build.gradle +0 -147
  91. package/example/android/app/debug.keystore +0 -0
  92. package/example/android/app/proguard-rules.pro +0 -10
  93. package/example/android/app/src/main/AndroidManifest.xml +0 -27
  94. package/example/android/app/src/main/java/com/example/MainActivity.kt +0 -22
  95. package/example/android/app/src/main/java/com/example/MainApplication.kt +0 -52
  96. package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
  97. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  98. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  99. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  100. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  101. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  102. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  103. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  104. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  105. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  106. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  107. package/example/android/app/src/main/res/values/strings.xml +0 -3
  108. package/example/android/app/src/main/res/values/styles.xml +0 -9
  109. package/example/android/build.gradle +0 -48
  110. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  111. package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  112. package/example/android/gradle.properties +0 -45
  113. package/example/android/gradlew +0 -248
  114. package/example/android/gradlew.bat +0 -98
  115. package/example/android/settings.gradle +0 -25
  116. package/example/app.json +0 -4
  117. package/example/assets/app_icon.png +0 -0
  118. package/example/babel.config.js +0 -3
  119. package/example/guidance/Video-WalkThrough.mp4 +0 -0
  120. package/example/index.js +0 -9
  121. package/example/ios/.xcode.env +0 -11
  122. package/example/ios/Podfile +0 -34
  123. package/example/ios/Podfile.lock +0 -2303
  124. package/example/ios/example/AppDelegate.swift +0 -48
  125. package/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json +0 -62
  126. package/example/ios/example/Images.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  127. package/example/ios/example/Images.xcassets/Contents.json +0 -6
  128. package/example/ios/example/Info.plist +0 -60
  129. package/example/ios/example/LaunchScreen.storyboard +0 -47
  130. package/example/ios/example/PrivacyInfo.xcprivacy +0 -37
  131. package/example/ios/example.xcodeproj/project.pbxproj +0 -498
  132. package/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme +0 -88
  133. package/example/ios/example.xcworkspace/contents.xcworkspacedata +0 -10
  134. package/example/jest.config.js +0 -3
  135. package/example/metro.config.js +0 -45
  136. package/example/package-lock.json +0 -13508
  137. package/example/package.json +0 -54
  138. package/example/polyfill.js +0 -13
  139. package/example/tsconfig.json +0 -8
  140. package/fonts/Inter/Inter.ttc +0 -0
  141. package/fonts/Inter/InterVariable-Italic.ttf +0 -0
  142. package/fonts/Inter/InterVariable.ttf +0 -0
  143. package/fonts/Inter/LICENSE.txt +0 -92
  144. package/fonts/Inter/extras/otf/Inter-Black.otf +0 -0
  145. package/fonts/Inter/extras/otf/Inter-BlackItalic.otf +0 -0
  146. package/fonts/Inter/extras/otf/Inter-Bold.otf +0 -0
  147. package/fonts/Inter/extras/otf/Inter-BoldItalic.otf +0 -0
  148. package/fonts/Inter/extras/otf/Inter-ExtraBold.otf +0 -0
  149. package/fonts/Inter/extras/otf/Inter-ExtraBoldItalic.otf +0 -0
  150. package/fonts/Inter/extras/otf/Inter-ExtraLight.otf +0 -0
  151. package/fonts/Inter/extras/otf/Inter-ExtraLightItalic.otf +0 -0
  152. package/fonts/Inter/extras/otf/Inter-Italic.otf +0 -0
  153. package/fonts/Inter/extras/otf/Inter-Light.otf +0 -0
  154. package/fonts/Inter/extras/otf/Inter-LightItalic.otf +0 -0
  155. package/fonts/Inter/extras/otf/Inter-Medium.otf +0 -0
  156. package/fonts/Inter/extras/otf/Inter-MediumItalic.otf +0 -0
  157. package/fonts/Inter/extras/otf/Inter-Regular.otf +0 -0
  158. package/fonts/Inter/extras/otf/Inter-SemiBold.otf +0 -0
  159. package/fonts/Inter/extras/otf/Inter-SemiBoldItalic.otf +0 -0
  160. package/fonts/Inter/extras/otf/Inter-Thin.otf +0 -0
  161. package/fonts/Inter/extras/otf/Inter-ThinItalic.otf +0 -0
  162. package/fonts/Inter/extras/otf/InterDisplay-Black.otf +0 -0
  163. package/fonts/Inter/extras/otf/InterDisplay-BlackItalic.otf +0 -0
  164. package/fonts/Inter/extras/otf/InterDisplay-Bold.otf +0 -0
  165. package/fonts/Inter/extras/otf/InterDisplay-BoldItalic.otf +0 -0
  166. package/fonts/Inter/extras/otf/InterDisplay-ExtraBold.otf +0 -0
  167. package/fonts/Inter/extras/otf/InterDisplay-ExtraBoldItalic.otf +0 -0
  168. package/fonts/Inter/extras/otf/InterDisplay-ExtraLight.otf +0 -0
  169. package/fonts/Inter/extras/otf/InterDisplay-ExtraLightItalic.otf +0 -0
  170. package/fonts/Inter/extras/otf/InterDisplay-Italic.otf +0 -0
  171. package/fonts/Inter/extras/otf/InterDisplay-Light.otf +0 -0
  172. package/fonts/Inter/extras/otf/InterDisplay-LightItalic.otf +0 -0
  173. package/fonts/Inter/extras/otf/InterDisplay-Medium.otf +0 -0
  174. package/fonts/Inter/extras/otf/InterDisplay-MediumItalic.otf +0 -0
  175. package/fonts/Inter/extras/otf/InterDisplay-Regular.otf +0 -0
  176. package/fonts/Inter/extras/otf/InterDisplay-SemiBold.otf +0 -0
  177. package/fonts/Inter/extras/otf/InterDisplay-SemiBoldItalic.otf +0 -0
  178. package/fonts/Inter/extras/otf/InterDisplay-Thin.otf +0 -0
  179. package/fonts/Inter/extras/otf/InterDisplay-ThinItalic.otf +0 -0
  180. package/fonts/Inter/extras/ttf/Inter-Black.ttf +0 -0
  181. package/fonts/Inter/extras/ttf/Inter-BlackItalic.ttf +0 -0
  182. package/fonts/Inter/extras/ttf/Inter-Bold.ttf +0 -0
  183. package/fonts/Inter/extras/ttf/Inter-BoldItalic.ttf +0 -0
  184. package/fonts/Inter/extras/ttf/Inter-ExtraBold.ttf +0 -0
  185. package/fonts/Inter/extras/ttf/Inter-ExtraBoldItalic.ttf +0 -0
  186. package/fonts/Inter/extras/ttf/Inter-ExtraLight.ttf +0 -0
  187. package/fonts/Inter/extras/ttf/Inter-ExtraLightItalic.ttf +0 -0
  188. package/fonts/Inter/extras/ttf/Inter-Italic.ttf +0 -0
  189. package/fonts/Inter/extras/ttf/Inter-Light.ttf +0 -0
  190. package/fonts/Inter/extras/ttf/Inter-LightItalic.ttf +0 -0
  191. package/fonts/Inter/extras/ttf/Inter-Medium.ttf +0 -0
  192. package/fonts/Inter/extras/ttf/Inter-MediumItalic.ttf +0 -0
  193. package/fonts/Inter/extras/ttf/Inter-Regular.ttf +0 -0
  194. package/fonts/Inter/extras/ttf/Inter-SemiBold.ttf +0 -0
  195. package/fonts/Inter/extras/ttf/Inter-SemiBoldItalic.ttf +0 -0
  196. package/fonts/Inter/extras/ttf/Inter-Thin.ttf +0 -0
  197. package/fonts/Inter/extras/ttf/Inter-ThinItalic.ttf +0 -0
  198. package/fonts/Inter/extras/ttf/InterDisplay-Black.ttf +0 -0
  199. package/fonts/Inter/extras/ttf/InterDisplay-BlackItalic.ttf +0 -0
  200. package/fonts/Inter/extras/ttf/InterDisplay-Bold.ttf +0 -0
  201. package/fonts/Inter/extras/ttf/InterDisplay-BoldItalic.ttf +0 -0
  202. package/fonts/Inter/extras/ttf/InterDisplay-ExtraBold.ttf +0 -0
  203. package/fonts/Inter/extras/ttf/InterDisplay-ExtraBoldItalic.ttf +0 -0
  204. package/fonts/Inter/extras/ttf/InterDisplay-ExtraLight.ttf +0 -0
  205. package/fonts/Inter/extras/ttf/InterDisplay-ExtraLightItalic.ttf +0 -0
  206. package/fonts/Inter/extras/ttf/InterDisplay-Italic.ttf +0 -0
  207. package/fonts/Inter/extras/ttf/InterDisplay-Light.ttf +0 -0
  208. package/fonts/Inter/extras/ttf/InterDisplay-LightItalic.ttf +0 -0
  209. package/fonts/Inter/extras/ttf/InterDisplay-Medium.ttf +0 -0
  210. package/fonts/Inter/extras/ttf/InterDisplay-MediumItalic.ttf +0 -0
  211. package/fonts/Inter/extras/ttf/InterDisplay-Regular.ttf +0 -0
  212. package/fonts/Inter/extras/ttf/InterDisplay-SemiBold.ttf +0 -0
  213. package/fonts/Inter/extras/ttf/InterDisplay-SemiBoldItalic.ttf +0 -0
  214. package/fonts/Inter/extras/ttf/InterDisplay-Thin.ttf +0 -0
  215. package/fonts/Inter/extras/ttf/InterDisplay-ThinItalic.ttf +0 -0
  216. package/fonts/Inter/extras/woff-hinted/Inter-Black.woff2 +0 -0
  217. package/fonts/Inter/extras/woff-hinted/Inter-BlackItalic.woff2 +0 -0
  218. package/fonts/Inter/extras/woff-hinted/Inter-Bold.woff2 +0 -0
  219. package/fonts/Inter/extras/woff-hinted/Inter-BoldItalic.woff2 +0 -0
  220. package/fonts/Inter/extras/woff-hinted/Inter-ExtraBold.woff2 +0 -0
  221. package/fonts/Inter/extras/woff-hinted/Inter-ExtraBoldItalic.woff2 +0 -0
  222. package/fonts/Inter/extras/woff-hinted/Inter-ExtraLight.woff2 +0 -0
  223. package/fonts/Inter/extras/woff-hinted/Inter-ExtraLightItalic.woff2 +0 -0
  224. package/fonts/Inter/extras/woff-hinted/Inter-Italic.woff2 +0 -0
  225. package/fonts/Inter/extras/woff-hinted/Inter-Light.woff2 +0 -0
  226. package/fonts/Inter/extras/woff-hinted/Inter-LightItalic.woff2 +0 -0
  227. package/fonts/Inter/extras/woff-hinted/Inter-Medium.woff2 +0 -0
  228. package/fonts/Inter/extras/woff-hinted/Inter-MediumItalic.woff2 +0 -0
  229. package/fonts/Inter/extras/woff-hinted/Inter-Regular.woff2 +0 -0
  230. package/fonts/Inter/extras/woff-hinted/Inter-SemiBold.woff2 +0 -0
  231. package/fonts/Inter/extras/woff-hinted/Inter-SemiBoldItalic.woff2 +0 -0
  232. package/fonts/Inter/extras/woff-hinted/Inter-Thin.woff2 +0 -0
  233. package/fonts/Inter/extras/woff-hinted/Inter-ThinItalic.woff2 +0 -0
  234. package/fonts/Inter/extras/woff-hinted/InterDisplay-Black.woff2 +0 -0
  235. package/fonts/Inter/extras/woff-hinted/InterDisplay-BlackItalic.woff2 +0 -0
  236. package/fonts/Inter/extras/woff-hinted/InterDisplay-Bold.woff2 +0 -0
  237. package/fonts/Inter/extras/woff-hinted/InterDisplay-BoldItalic.woff2 +0 -0
  238. package/fonts/Inter/extras/woff-hinted/InterDisplay-ExtraBold.woff2 +0 -0
  239. package/fonts/Inter/extras/woff-hinted/InterDisplay-ExtraBoldItalic.woff2 +0 -0
  240. package/fonts/Inter/extras/woff-hinted/InterDisplay-ExtraLight.woff2 +0 -0
  241. package/fonts/Inter/extras/woff-hinted/InterDisplay-ExtraLightItalic.woff2 +0 -0
  242. package/fonts/Inter/extras/woff-hinted/InterDisplay-Italic.woff2 +0 -0
  243. package/fonts/Inter/extras/woff-hinted/InterDisplay-Light.woff2 +0 -0
  244. package/fonts/Inter/extras/woff-hinted/InterDisplay-LightItalic.woff2 +0 -0
  245. package/fonts/Inter/extras/woff-hinted/InterDisplay-Medium.woff2 +0 -0
  246. package/fonts/Inter/extras/woff-hinted/InterDisplay-MediumItalic.woff2 +0 -0
  247. package/fonts/Inter/extras/woff-hinted/InterDisplay-Regular.woff2 +0 -0
  248. package/fonts/Inter/extras/woff-hinted/InterDisplay-SemiBold.woff2 +0 -0
  249. package/fonts/Inter/extras/woff-hinted/InterDisplay-SemiBoldItalic.woff2 +0 -0
  250. package/fonts/Inter/extras/woff-hinted/InterDisplay-Thin.woff2 +0 -0
  251. package/fonts/Inter/extras/woff-hinted/InterDisplay-ThinItalic.woff2 +0 -0
  252. package/fonts/Inter/help.txt +0 -165
  253. package/fonts/Inter/web/Inter-Black.woff2 +0 -0
  254. package/fonts/Inter/web/Inter-BlackItalic.woff2 +0 -0
  255. package/fonts/Inter/web/Inter-Bold.woff2 +0 -0
  256. package/fonts/Inter/web/Inter-BoldItalic.woff2 +0 -0
  257. package/fonts/Inter/web/Inter-ExtraBold.woff2 +0 -0
  258. package/fonts/Inter/web/Inter-ExtraBoldItalic.woff2 +0 -0
  259. package/fonts/Inter/web/Inter-ExtraLight.woff2 +0 -0
  260. package/fonts/Inter/web/Inter-ExtraLightItalic.woff2 +0 -0
  261. package/fonts/Inter/web/Inter-Italic.woff2 +0 -0
  262. package/fonts/Inter/web/Inter-Light.woff2 +0 -0
  263. package/fonts/Inter/web/Inter-LightItalic.woff2 +0 -0
  264. package/fonts/Inter/web/Inter-Medium.woff2 +0 -0
  265. package/fonts/Inter/web/Inter-MediumItalic.woff2 +0 -0
  266. package/fonts/Inter/web/Inter-Regular.woff2 +0 -0
  267. package/fonts/Inter/web/Inter-SemiBold.woff2 +0 -0
  268. package/fonts/Inter/web/Inter-SemiBoldItalic.woff2 +0 -0
  269. package/fonts/Inter/web/Inter-Thin.woff2 +0 -0
  270. package/fonts/Inter/web/Inter-ThinItalic.woff2 +0 -0
  271. package/fonts/Inter/web/InterDisplay-Black.woff2 +0 -0
  272. package/fonts/Inter/web/InterDisplay-BlackItalic.woff2 +0 -0
  273. package/fonts/Inter/web/InterDisplay-Bold.woff2 +0 -0
  274. package/fonts/Inter/web/InterDisplay-BoldItalic.woff2 +0 -0
  275. package/fonts/Inter/web/InterDisplay-ExtraBold.woff2 +0 -0
  276. package/fonts/Inter/web/InterDisplay-ExtraBoldItalic.woff2 +0 -0
  277. package/fonts/Inter/web/InterDisplay-ExtraLight.woff2 +0 -0
  278. package/fonts/Inter/web/InterDisplay-ExtraLightItalic.woff2 +0 -0
  279. package/fonts/Inter/web/InterDisplay-Italic.woff2 +0 -0
  280. package/fonts/Inter/web/InterDisplay-Light.woff2 +0 -0
  281. package/fonts/Inter/web/InterDisplay-LightItalic.woff2 +0 -0
  282. package/fonts/Inter/web/InterDisplay-Medium.woff2 +0 -0
  283. package/fonts/Inter/web/InterDisplay-MediumItalic.woff2 +0 -0
  284. package/fonts/Inter/web/InterDisplay-Regular.woff2 +0 -0
  285. package/fonts/Inter/web/InterDisplay-SemiBold.woff2 +0 -0
  286. package/fonts/Inter/web/InterDisplay-SemiBoldItalic.woff2 +0 -0
  287. package/fonts/Inter/web/InterDisplay-Thin.woff2 +0 -0
  288. package/fonts/Inter/web/InterDisplay-ThinItalic.woff2 +0 -0
  289. package/fonts/Inter/web/InterVariable-Italic.woff2 +0 -0
  290. package/fonts/Inter/web/InterVariable.woff2 +0 -0
  291. package/fonts/Inter/web/inter.css +0 -148
@@ -1,1218 +0,0 @@
1
- import React, { useEffect, useState, useMemo } from 'react';
2
- import { LayoutAnimation, Platform, Pressable, StyleSheet, Text, TextInput, UIManager, View, ScrollView, ToastAndroid, Alert, } from 'react-native';
3
- import { AppColors } from '../styles/AppColors';
4
- import { AppFonts } from '../styles/AppFonts';
5
- import { ChevronIcon, FolderIcon, TrashIcon, HeaderPauseIcon, SearchIcon, ClearIcon, ClockIcon, SignalIcon, LayersIcon, TerminalIcon, SortIcon, } from './NetworkIcons';
6
- import JsonViewer from './JsonViewer';
7
- import DiffViewer from './DiffViewer';
8
- import TouchableScale from './TouchableScale';
9
- import SegmentedTabs from './SegmentedTabs';
10
- import CopyButton from './CopyButton';
11
- import { getSize } from '../helpers';
12
- import { getCustomStorage } from '../helpers/settingsStore';
13
- // Enable LayoutAnimation for Android
14
- if (Platform.OS === 'android') {
15
- UIManager.setLayoutAnimationEnabledExperimental?.(true);
16
- }
17
- const animateLayout = () => {
18
- LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
19
- };
20
- // Chevron pointing left (for back buttons)
21
- const BackChevronIcon = ({ color = AppColors.purple, size = 12 }) => (<View style={{ transform: [{ rotate: '180deg' }], marginRight: 4 }}>
22
- <ChevronIcon color={color} size={size}/>
23
- </View>);
24
- // Chevron pointing right (for list items)
25
- const ForwardChevronIcon = ({ color = AppColors.grayTextWeak, size = 12 }) => (<View style={{ transform: [{ rotate: '0deg' }], marginLeft: 'auto' }}>
26
- <ChevronIcon color={color} size={size}/>
27
- </View>);
28
- // Helper: check if a value recursively contains a string term
29
- const valueContainsTerm = (val, term) => {
30
- if (!term)
31
- return true;
32
- const t = term.toLowerCase();
33
- if (val === null || val === undefined)
34
- return false;
35
- if (typeof val !== 'object') {
36
- return String(val).toLowerCase().includes(t);
37
- }
38
- if (Array.isArray(val)) {
39
- return val.some(item => valueContainsTerm(item, term));
40
- }
41
- return Object.keys(val).some(key => key.toLowerCase().includes(t) || valueContainsTerm(val[key], term));
42
- };
43
- export const ReduxTreeView = React.memo(({ state, actionHistory = [], lastActionMap = {}, search = '', onSearchChange, autoRefresh = true, onToggleAutoRefresh, onClearHistory, onDetailOpenChange, selectedSliceKey = null, onSelectSliceKey, selectedActionId = null, onSelectActionId, }) => {
44
- const [activeTab, setActiveTab] = useState('state');
45
- const [actionSubTab, setActionSubTab] = useState('payload');
46
- // local fallbacks if props are not provided
47
- const [localSliceKey, setLocalSliceKey] = useState(null);
48
- const [localActionId, setLocalActionId] = useState(null);
49
- const activeSliceKey = onSelectSliceKey ? selectedSliceKey : localSliceKey;
50
- const activeActionId = onSelectActionId ? selectedActionId : localActionId;
51
- const setActiveSliceKey = (key) => {
52
- if (onSelectSliceKey)
53
- onSelectSliceKey(key);
54
- else
55
- setLocalSliceKey(key);
56
- };
57
- const setActiveActionId = (id) => {
58
- if (onSelectActionId)
59
- onSelectActionId(id);
60
- else
61
- setLocalActionId(id);
62
- };
63
- // Expand / collapse all states for detail views
64
- const [sliceForceOpen, setSliceForceOpen] = useState(undefined);
65
- const [actionForceOpen, setActionForceOpen] = useState(undefined);
66
- const [searchModeType, setSearchModeType] = useState(true);
67
- const [searchModeData, setSearchModeData] = useState(true);
68
- // Sorting directions
69
- const [stateSortAsc, setStateSortAsc] = useState(true);
70
- const [actionSortAsc, setActionSortAsc] = useState(false);
71
- // Persistence-related states for State Slice details
72
- const [sliceDetailTab, setSliceDetailTab] = useState('live');
73
- const [isPersisted, setIsPersisted] = useState(false);
74
- const [persistedData, setPersistedData] = useState(null);
75
- useEffect(() => {
76
- if (activeSliceKey === null) {
77
- setIsPersisted(false);
78
- setPersistedData(null);
79
- setSliceDetailTab('live');
80
- return;
81
- }
82
- async function checkPersistence() {
83
- try {
84
- const storage = getCustomStorage();
85
- if (!storage) {
86
- setIsPersisted(false);
87
- setPersistedData(null);
88
- return;
89
- }
90
- // Check direct key: persist:sliceKey
91
- let raw = await storage.getItem(`persist:${activeSliceKey}`);
92
- if (raw) {
93
- try {
94
- setPersistedData(JSON.parse(raw));
95
- }
96
- catch {
97
- setPersistedData(raw);
98
- }
99
- setIsPersisted(true);
100
- return;
101
- }
102
- // Check root key: persist:root
103
- let rootRaw = await storage.getItem('persist:root');
104
- if (rootRaw) {
105
- const parsedRoot = JSON.parse(rootRaw);
106
- if (parsedRoot && parsedRoot[activeSliceKey] !== undefined) {
107
- const nested = parsedRoot[activeSliceKey];
108
- try {
109
- setPersistedData(typeof nested === 'string' ? JSON.parse(nested) : nested);
110
- }
111
- catch {
112
- setPersistedData(nested);
113
- }
114
- setIsPersisted(true);
115
- return;
116
- }
117
- }
118
- }
119
- catch (e) {
120
- console.log('Error checking Redux persistence:', e);
121
- }
122
- setIsPersisted(false);
123
- setPersistedData(null);
124
- }
125
- checkPersistence();
126
- }, [activeSliceKey]);
127
- const handleClearPersistence = () => {
128
- Alert.alert('Clear Persisted State', `Are you sure you want to delete the persisted storage item for the slice "${activeSliceKey}"? This will clear the value from device storage, but the current active in-memory Redux state will remain unchanged until the next app reload.`, [
129
- { text: 'Cancel', style: 'cancel' },
130
- {
131
- text: 'Delete',
132
- style: 'destructive',
133
- onPress: async () => {
134
- try {
135
- const storage = getCustomStorage();
136
- if (!storage)
137
- return;
138
- // Delete direct key
139
- if (typeof storage.removeItem === 'function') {
140
- await storage.removeItem(`persist:${activeSliceKey}`);
141
- }
142
- else {
143
- await storage.setItem(`persist:${activeSliceKey}`, '');
144
- }
145
- // Delete from root key
146
- let rootRaw = await storage.getItem('persist:root');
147
- if (rootRaw) {
148
- const parsed = JSON.parse(rootRaw);
149
- if (parsed && parsed[activeSliceKey] !== undefined) {
150
- delete parsed[activeSliceKey];
151
- await storage.setItem('persist:root', JSON.stringify(parsed));
152
- }
153
- }
154
- setIsPersisted(false);
155
- setPersistedData(null);
156
- setSliceDetailTab('live');
157
- if (Platform.OS === 'android') {
158
- ToastAndroid.show('Persisted state cleared', ToastAndroid.SHORT);
159
- }
160
- else {
161
- Alert.alert('Cleared', 'Persisted state has been cleared from device storage.');
162
- }
163
- }
164
- catch (err) {
165
- Alert.alert('Error', 'Failed to clear persisted state.');
166
- }
167
- }
168
- }
169
- ]);
170
- };
171
- const isSearching = search.trim().length > 0;
172
- useEffect(() => {
173
- onDetailOpenChange?.(activeSliceKey !== null || activeActionId !== null);
174
- return () => {
175
- onDetailOpenChange?.(false);
176
- };
177
- }, [activeSliceKey, activeActionId, onDetailOpenChange]);
178
- // Reset details view when tab changes
179
- const switchTab = (tab) => {
180
- animateLayout();
181
- setActiveTab(tab);
182
- setActiveSliceKey(null);
183
- setActiveActionId(null);
184
- setSliceForceOpen(undefined);
185
- setActionForceOpen(undefined);
186
- };
187
- const handleGoBackSlice = () => {
188
- animateLayout();
189
- setActiveSliceKey(null);
190
- setSliceForceOpen(undefined);
191
- };
192
- const handleGoBackAction = () => {
193
- animateLayout();
194
- setActiveActionId(null);
195
- setActionForceOpen(undefined);
196
- };
197
- // Filtered state keys based on search query
198
- const filteredStateKeys = useMemo(() => {
199
- if (!state || typeof state !== 'object')
200
- return [];
201
- const keys = Object.keys(state);
202
- let result = keys;
203
- if (isSearching) {
204
- result = keys.filter(key => {
205
- const typeMatch = searchModeType && key.toLowerCase().includes(search.toLowerCase());
206
- const dataMatch = searchModeData && valueContainsTerm(state[key], search);
207
- return typeMatch || dataMatch;
208
- });
209
- }
210
- return [...result].sort((a, b) => {
211
- const comparison = a.localeCompare(b);
212
- return stateSortAsc ? comparison : -comparison;
213
- });
214
- }, [state, search, isSearching, searchModeType, searchModeData, stateSortAsc]);
215
- // Filtered action history based on search query
216
- const filteredActionHistory = useMemo(() => {
217
- if (!actionHistory)
218
- return [];
219
- let result = actionHistory;
220
- if (isSearching) {
221
- result = actionHistory.filter(action => {
222
- const typeMatch = searchModeType && action.type.toLowerCase().includes(search.toLowerCase());
223
- const payloadMatch = searchModeData && action.payload && valueContainsTerm(action.payload, search);
224
- return typeMatch || payloadMatch;
225
- });
226
- }
227
- return [...result].sort((a, b) => {
228
- const comparison = a.id - b.id;
229
- return actionSortAsc ? comparison : -comparison;
230
- });
231
- }, [actionHistory, search, isSearching, searchModeType, searchModeData, actionSortAsc]);
232
- // Find currently selected action object
233
- const selectedAction = useMemo(() => {
234
- if (activeActionId === null)
235
- return null;
236
- return actionHistory.find(a => a.id === activeActionId) || null;
237
- }, [activeActionId, actionHistory]);
238
- if (!state || typeof state !== 'object') {
239
- return (<View style={styles.errorContainer}>
240
- <Text style={styles.errorText}>No connected Redux store state found.</Text>
241
- </View>);
242
- }
243
- // ── Render Detail View: State Slice ──
244
- if (activeTab === 'state' && activeSliceKey !== null) {
245
- const sliceData = state[activeSliceKey];
246
- const fieldsCount = typeof sliceData === 'object' && sliceData !== null
247
- ? Object.keys(sliceData).length
248
- : 1;
249
- const sliceTabs = [
250
- { key: 'live', label: 'Live State' },
251
- ...(isPersisted
252
- ? [{ key: 'persisted', label: `Persisted (${getSize(persistedData)})` }]
253
- : []),
254
- { key: 'metadata', label: 'Metadata' },
255
- ];
256
- return (<View style={{ flex: 1 }}>
257
- {/* Detail info header bar */}
258
- <View style={styles.apiLikeInfoBar}>
259
- <View style={{
260
- flexDirection: 'row',
261
- alignItems: 'center',
262
- justifyContent: 'space-between',
263
- marginBottom: 8,
264
- }}>
265
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
266
- <View style={[styles.apiMethodBadge, { backgroundColor: AppColors.purple }]}>
267
- <Text style={styles.apiMethodBadgeText}>REDUX</Text>
268
- </View>
269
- <View style={[
270
- styles.apiMethodBadge,
271
- {
272
- backgroundColor: `${AppColors.brandPurple}18`,
273
- borderWidth: 1,
274
- borderColor: `${AppColors.brandPurple}40`,
275
- },
276
- ]}>
277
- <Text style={[styles.apiMethodBadgeText, { color: AppColors.brandPurple }]}>
278
- SLICE
279
- </Text>
280
- </View>
281
- {isPersisted && (<View style={[styles.apiMethodBadge, { backgroundColor: AppColors.emerald500 }]}>
282
- <Text style={styles.apiMethodBadgeText}>PERSISTED</Text>
283
- </View>)}
284
- <View style={styles.apiChip}>
285
- <Text style={styles.apiChipText}>{getSize(sliceData)}</Text>
286
- </View>
287
- <View style={styles.apiChip}>
288
- <Text style={styles.apiChipText}>
289
- {fieldsCount} {fieldsCount === 1 ? 'field' : 'fields'}
290
- </Text>
291
- </View>
292
- </View>
293
-
294
- <CopyButton value={JSON.stringify(sliceDetailTab === 'live' ? sliceData : persistedData, null, 2)} label={`Slice '${activeSliceKey}'`}/>
295
- </View>
296
-
297
- <Text style={styles.apiTitleText} selectable={true}>
298
- {activeSliceKey}
299
- </Text>
300
-
301
- <View style={styles.apiMetaRow}>
302
- <ClockIcon color={AppColors.grayTextWeak} size={11}/>
303
- <Text style={styles.apiMetaText}>
304
- Last updated: {lastActionMap[activeSliceKey] ? lastActionMap[activeSliceKey].timestamp : 'Initial'}
305
- </Text>
306
- </View>
307
- </View>
308
-
309
- {/* Back button row + sub-tabs */}
310
- <View style={{ paddingHorizontal: 12, paddingTop: 8, paddingBottom: 4 }}>
311
- <View style={{
312
- flexDirection: 'row',
313
- alignItems: 'center',
314
- justifyContent: 'space-between',
315
- marginBottom: 8,
316
- }}>
317
- <TouchableScale onPress={handleGoBackSlice} style={styles.backBtn} hitSlop={12}>
318
- <BackChevronIcon color={AppColors.purple} size={12}/>
319
- <Text style={styles.backBtnText}>State Slices</Text>
320
- </TouchableScale>
321
-
322
- {isPersisted && sliceDetailTab === 'persisted' && (<TouchableScale onPress={handleClearPersistence} style={[styles.detailHeaderBtn, { borderColor: `${AppColors.errorColor}40` }]} hitSlop={8}>
323
- <TrashIcon color={AppColors.errorColor} size={14}/>
324
- </TouchableScale>)}
325
- </View>
326
-
327
- <SegmentedTabs tabs={sliceTabs} activeKey={sliceDetailTab} onChange={key => {
328
- animateLayout();
329
- setSliceDetailTab(key);
330
- }}/>
331
- </View>
332
-
333
- {/* Search row (for live/persisted tabs) */}
334
- {sliceDetailTab !== 'metadata' && (<View style={{ paddingHorizontal: 12, paddingTop: 4, paddingBottom: 4 }}>
335
- <View style={{
336
- flexDirection: 'row',
337
- alignItems: 'center',
338
- backgroundColor: AppColors.purpleShade50,
339
- borderRadius: 8,
340
- paddingHorizontal: 10,
341
- borderWidth: 1,
342
- borderColor: AppColors.dividerColor,
343
- height: 36,
344
- }}>
345
- <SearchIcon color={AppColors.grayTextWeak} size={15}/>
346
- <TextInput placeholder="Search in slice keys or values..." placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={onSearchChange} style={{
347
- flex: 1,
348
- fontFamily: AppFonts.interRegular,
349
- fontSize: 12,
350
- color: AppColors.grayTextStrong,
351
- paddingHorizontal: 8,
352
- paddingVertical: 0,
353
- }} autoCorrect={false} autoCapitalize="none"/>
354
- {search.length > 0 && (<Pressable onPress={() => onSearchChange?.('')} hitSlop={10}>
355
- <ClearIcon color={AppColors.grayTextWeak} size={13}/>
356
- </Pressable>)}
357
- </View>
358
- </View>)}
359
-
360
- {/* Scrollable Tab Content */}
361
- <ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingHorizontal: 12, paddingTop: 6, paddingBottom: 28, flexGrow: 1 }} showsVerticalScrollIndicator={true} keyboardShouldPersistTaps="handled">
362
- {sliceDetailTab === 'metadata' ? (<View style={{
363
- backgroundColor: AppColors.primaryLight,
364
- borderRadius: 10,
365
- borderWidth: 1,
366
- borderColor: AppColors.dividerColor,
367
- overflow: 'hidden',
368
- paddingHorizontal: 12,
369
- paddingVertical: 4,
370
- }}>
371
- {[
372
- { label: 'Slice Name', value: activeSliceKey },
373
- { label: 'Fields Count', value: `${fieldsCount} root keys` },
374
- { label: 'State Size', value: getSize(sliceData) },
375
- {
376
- label: 'Persistence',
377
- value: isPersisted ? `Persisted (${getSize(persistedData)})` : 'Not Persisted',
378
- },
379
- {
380
- label: 'Last Dispatched Action',
381
- value: lastActionMap[activeSliceKey] ? lastActionMap[activeSliceKey].type : 'None',
382
- },
383
- {
384
- label: 'Last Updated At',
385
- value: lastActionMap[activeSliceKey] ? lastActionMap[activeSliceKey].timestamp : 'Initial',
386
- },
387
- ].map((row, rIdx) => (<View key={rIdx} style={{
388
- flexDirection: 'row',
389
- justifyContent: 'space-between',
390
- alignItems: 'center',
391
- paddingVertical: 9,
392
- borderBottomWidth: rIdx < 5 ? 1 : 0,
393
- borderBottomColor: AppColors.grayBorderSecondary,
394
- }}>
395
- <Text style={{ fontFamily: AppFonts.interMedium, fontSize: 11.5, color: AppColors.grayTextWeak }}>
396
- {row.label}
397
- </Text>
398
- <Text selectable style={{
399
- fontFamily: AppFonts.interBold,
400
- fontSize: 11.5,
401
- color: AppColors.primaryBlack,
402
- maxWidth: '60%',
403
- textAlign: 'right',
404
- }}>
405
- {row.value}
406
- </Text>
407
- </View>))}
408
- </View>) : (<JsonViewer data={sliceDetailTab === 'live' ? sliceData : (persistedData ?? 'No persisted data')} search={search} forceOpen={sliceForceOpen !== undefined ? sliceForceOpen : (isSearching ? true : undefined)} fullHeight={true}/>)}
409
- </ScrollView>
410
- </View>);
411
- }
412
- // ── Render Detail View: Timeline Action ──
413
- if (activeTab === 'timeline' && selectedAction !== null) {
414
- const affectedSlices = selectedAction.affectedSlices || [];
415
- const actionTabs = [
416
- { key: 'payload', label: 'Payload' },
417
- { key: 'diff', label: 'Diff Changes' },
418
- { key: 'state', label: 'Snapshot' },
419
- { key: 'metadata', label: 'Metadata' },
420
- ];
421
- return (<View style={{ flex: 1 }}>
422
- {/* Detail info header bar */}
423
- <View style={styles.apiLikeInfoBar}>
424
- <View style={{
425
- flexDirection: 'row',
426
- alignItems: 'center',
427
- justifyContent: 'space-between',
428
- marginBottom: 8,
429
- }}>
430
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
431
- <View style={[styles.apiMethodBadge, { backgroundColor: AppColors.purple }]}>
432
- <Text style={styles.apiMethodBadgeText}>REDUX</Text>
433
- </View>
434
- <View style={[styles.apiMethodBadge, { backgroundColor: AppColors.amber500 }]}>
435
- <Text style={styles.apiMethodBadgeText}>ACTION</Text>
436
- </View>
437
- <View style={styles.apiChip}>
438
- <Text style={styles.apiChipText}>#{selectedAction.id}</Text>
439
- </View>
440
- <View style={styles.apiChip}>
441
- <Text style={styles.apiChipText}>{getSize(selectedAction.payload)}</Text>
442
- </View>
443
- </View>
444
-
445
- <CopyButton value={JSON.stringify(actionSubTab === 'payload'
446
- ? selectedAction.payload
447
- : actionSubTab === 'diff'
448
- ? { prev: selectedAction.prevState, next: selectedAction.nextState }
449
- : selectedAction.nextState, null, 2)} label={actionSubTab === 'payload' ? 'Action Payload' : 'State Snapshot'}/>
450
- </View>
451
-
452
- <Text style={styles.apiTitleText} selectable={true}>
453
- {selectedAction.type}
454
- </Text>
455
-
456
- <View style={styles.apiMetaRow}>
457
- <ClockIcon color={AppColors.grayTextWeak} size={11}/>
458
- <Text style={styles.apiMetaText}>
459
- Dispatched: {selectedAction.timestamp}
460
- </Text>
461
- </View>
462
-
463
- {/* Affected Slices Tags list */}
464
- {affectedSlices.length > 0 && (<View style={[styles.detailAffectedTags, { marginTop: 6, paddingHorizontal: 0, paddingBottom: 0 }]}>
465
- <Text style={styles.affectedTagsLabel}>AFFECTED SLICES:</Text>
466
- <View style={styles.detailTagsList}>
467
- {affectedSlices.map(slice => (<View key={slice} style={styles.sliceTag}>
468
- <Text style={styles.sliceTagText}>{slice}</Text>
469
- </View>))}
470
- </View>
471
- </View>)}
472
- </View>
473
-
474
- {/* Back button row + sub-tabs */}
475
- <View style={{ paddingHorizontal: 12, paddingTop: 8, paddingBottom: 4 }}>
476
- <View style={{
477
- flexDirection: 'row',
478
- alignItems: 'center',
479
- justifyContent: 'space-between',
480
- marginBottom: 8,
481
- }}>
482
- <TouchableScale onPress={handleGoBackAction} style={styles.backBtn} hitSlop={12}>
483
- <BackChevronIcon color={AppColors.purple} size={12}/>
484
- <Text style={styles.backBtnText}>Actions Timeline</Text>
485
- </TouchableScale>
486
- </View>
487
-
488
- <SegmentedTabs tabs={actionTabs} activeKey={actionSubTab} onChange={key => {
489
- animateLayout();
490
- setActionSubTab(key);
491
- }}/>
492
- </View>
493
-
494
- {/* Scrollable Tab Content */}
495
- <ScrollView style={{ flex: 1 }} contentContainerStyle={{ paddingHorizontal: 12, paddingTop: 6, paddingBottom: 28, flexGrow: 1 }} showsVerticalScrollIndicator={true} keyboardShouldPersistTaps="handled">
496
- {actionSubTab === 'payload' && (<JsonViewer data={selectedAction.payload ?? 'No payload data'} wrap forceOpen={actionForceOpen !== undefined ? actionForceOpen : undefined} fullHeight={true}/>)}
497
-
498
- {actionSubTab === 'diff' && (<DiffViewer oldData={selectedAction.prevState} newData={selectedAction.nextState}/>)}
499
-
500
- {actionSubTab === 'state' && (<JsonViewer data={selectedAction.nextState} wrap forceOpen={actionForceOpen !== undefined ? actionForceOpen : undefined} fullHeight={true}/>)}
501
-
502
- {actionSubTab === 'metadata' && (<View style={{
503
- backgroundColor: AppColors.primaryLight,
504
- borderRadius: 10,
505
- borderWidth: 1,
506
- borderColor: AppColors.dividerColor,
507
- overflow: 'hidden',
508
- paddingHorizontal: 12,
509
- paddingVertical: 4,
510
- }}>
511
- {[
512
- { label: 'Action Type', value: selectedAction.type },
513
- { label: 'Action ID', value: `#${selectedAction.id}` },
514
- { label: 'Dispatched At', value: selectedAction.timestamp },
515
- { label: 'Payload Size', value: getSize(selectedAction.payload) },
516
- { label: 'Snapshot Size', value: getSize(selectedAction.nextState) },
517
- {
518
- label: 'Affected Slices',
519
- value: affectedSlices.length > 0 ? affectedSlices.join(', ') : 'None',
520
- },
521
- ].map((row, rIdx) => (<View key={rIdx} style={{
522
- flexDirection: 'row',
523
- justifyContent: 'space-between',
524
- alignItems: 'center',
525
- paddingVertical: 9,
526
- borderBottomWidth: rIdx < 5 ? 1 : 0,
527
- borderBottomColor: AppColors.grayBorderSecondary,
528
- }}>
529
- <Text style={{ fontFamily: AppFonts.interMedium, fontSize: 11.5, color: AppColors.grayTextWeak }}>
530
- {row.label}
531
- </Text>
532
- <Text selectable style={{
533
- fontFamily: AppFonts.interBold,
534
- fontSize: 11.5,
535
- color: AppColors.primaryBlack,
536
- maxWidth: '60%',
537
- textAlign: 'right',
538
- }}>
539
- {row.value}
540
- </Text>
541
- </View>))}
542
- </View>)}
543
- </ScrollView>
544
- </View>);
545
- }
546
- // ── Render List Views (Default) ──
547
- return (<View style={styles.container}>
548
- {/* ── Control Bar ── */}
549
- <View style={styles.toolbar}>
550
- <View style={styles.statusSection}>
551
- <View style={[styles.statusBadge, autoRefresh ? styles.statusBadgeActive : styles.statusBadgePaused]}>
552
- <View style={[styles.statusDot, autoRefresh ? styles.statusDotActive : styles.statusDotPaused]}/>
553
- <Text style={[styles.statusBadgeText, autoRefresh ? styles.statusTextActive : styles.statusTextPaused]}>
554
- {autoRefresh ? 'LIVE' : 'PAUSED'}
555
- </Text>
556
- </View>
557
- </View>
558
-
559
- <View style={styles.toolbarActions}>
560
- {/* Sorting Toggle Button */}
561
- <TouchableScale onPress={() => {
562
- animateLayout();
563
- if (activeTab === 'state') {
564
- setStateSortAsc(prev => !prev);
565
- }
566
- else {
567
- setActionSortAsc(prev => !prev);
568
- }
569
- }} style={styles.iconBtn} hitSlop={8}>
570
- <SortIcon ascending={activeTab === 'state' ? stateSortAsc : actionSortAsc} color={AppColors.purple} size={15}/>
571
- </TouchableScale>
572
-
573
- {onToggleAutoRefresh && (<TouchableScale onPress={onToggleAutoRefresh} style={styles.iconBtn} hitSlop={8}>
574
- <HeaderPauseIcon isPaused={!autoRefresh} color={AppColors.purple} size={15}/>
575
- </TouchableScale>)}
576
- {onClearHistory && (<TouchableScale onPress={onClearHistory} style={[styles.iconBtn, { borderColor: AppColors.errorColor + '40', backgroundColor: AppColors.errorColor + '08' }]} hitSlop={8}>
577
- <TrashIcon color={AppColors.errorColor} size={15}/>
578
- </TouchableScale>)}
579
- </View>
580
- </View>
581
-
582
- {/* ── Search Bar ── */}
583
- {onSearchChange && (<View style={styles.searchContainer}>
584
- <View style={styles.searchBar}>
585
- <SearchIcon color={AppColors.grayTextWeak} size={14}/>
586
- <TextInput placeholder="Search keys, values, or action payloads..." placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={onSearchChange} style={styles.searchInput} autoCorrect={false} autoCapitalize="none"/>
587
- {search.length > 0 && (<TouchableScale onPress={() => onSearchChange('')} hitSlop={10}>
588
- <ClearIcon color={AppColors.grayTextWeak} size={14}/>
589
- </TouchableScale>)}
590
- </View>
591
- <View style={styles.filterChipRow}>
592
- <Text style={styles.filterChipLabel}>FILTER BY:</Text>
593
- <Pressable onPress={() => {
594
- animateLayout();
595
- if (searchModeType && !searchModeData)
596
- return; // Prevent disabling both
597
- setSearchModeType(!searchModeType);
598
- }} style={[styles.filterChip, searchModeType && styles.filterChipActive]}>
599
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
600
- <SignalIcon color={searchModeType ? AppColors.purple : AppColors.grayText} size={11}/>
601
- <Text style={[styles.filterChipText, searchModeType && styles.filterChipTextActive]}>
602
- Type / Key
603
- </Text>
604
- </View>
605
- </Pressable>
606
- <Pressable onPress={() => {
607
- animateLayout();
608
- if (!searchModeType && searchModeData)
609
- return; // Prevent disabling both
610
- setSearchModeData(!searchModeData);
611
- }} style={[styles.filterChip, searchModeData && styles.filterChipActive]}>
612
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 4 }}>
613
- <LayersIcon color={searchModeData ? AppColors.purple : AppColors.grayText} size={11}/>
614
- <Text style={[styles.filterChipText, searchModeData && styles.filterChipTextActive]}>
615
- Payload Data
616
- </Text>
617
- </View>
618
- </Pressable>
619
- </View>
620
- </View>)}
621
-
622
- {/* ── Tab Selector ── */}
623
- <View style={styles.tabContainer}>
624
- <Pressable style={[styles.tabButton, activeTab === 'state' && styles.tabButtonActive]} onPress={() => switchTab('state')}>
625
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
626
- <LayersIcon color={activeTab === 'state' ? AppColors.purple : AppColors.grayText} size={12}/>
627
- <Text style={[styles.tabButtonText, activeTab === 'state' && styles.tabButtonTextActive]}>
628
- State Slices ({filteredStateKeys.length})
629
- </Text>
630
- </View>
631
- </Pressable>
632
- <Pressable style={[styles.tabButton, activeTab === 'timeline' && styles.tabButtonActive]} onPress={() => switchTab('timeline')}>
633
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
634
- <TerminalIcon color={activeTab === 'timeline' ? AppColors.purple : AppColors.grayText} size={12}/>
635
- <Text style={[styles.tabButtonText, activeTab === 'timeline' && styles.tabButtonTextActive]}>
636
- Actions ({filteredActionHistory.length})
637
- </Text>
638
- </View>
639
- </Pressable>
640
- </View>
641
-
642
- {/* ── State List View ── */}
643
- {activeTab === 'state' && (<ScrollView style={styles.scrollList} contentContainerStyle={styles.scrollContent}>
644
- {filteredStateKeys.length === 0 ? (<View style={styles.emptyState}>
645
- <Text style={styles.emptyStateText}>
646
- {isSearching ? 'No store slices match your search.' : 'Redux store contains no state.'}
647
- </Text>
648
- </View>) : (filteredStateKeys.map(reducerKey => {
649
- const sliceData = state[reducerKey];
650
- const fieldsCount = typeof sliceData === 'object' && sliceData !== null
651
- ? Object.keys(sliceData).length
652
- : 1;
653
- const lastAction = lastActionMap[reducerKey];
654
- const lastUpdatedTime = lastAction ? lastAction.timestamp : 'Initial';
655
- return (<TouchableScale key={reducerKey} onPress={() => {
656
- animateLayout();
657
- setActiveSliceKey(reducerKey);
658
- }} style={styles.listRow}>
659
- <View style={styles.sliceIcon}>
660
- <FolderIcon color={AppColors.purple} size={11}/>
661
- </View>
662
- <View style={styles.rowMain}>
663
- <Text style={styles.rowTitle}>{reducerKey}</Text>
664
- <Text style={styles.rowSub}>
665
- {getSize(sliceData)} • {fieldsCount} {fieldsCount === 1 ? 'field' : 'fields'} • Updated: {lastUpdatedTime}
666
- </Text>
667
- </View>
668
- <ForwardChevronIcon color={AppColors.grayTextWeak} size={10}/>
669
- </TouchableScale>);
670
- }))}
671
- </ScrollView>)}
672
-
673
- {/* ── Timeline List View ── */}
674
- {activeTab === 'timeline' && (<ScrollView style={styles.scrollList} contentContainerStyle={styles.scrollContent}>
675
- {filteredActionHistory.length === 0 ? (<View style={styles.emptyState}>
676
- <Text style={styles.emptyStateText}>
677
- {isSearching
678
- ? 'No actions match your search.'
679
- : 'No actions dispatched yet. Trigger an action in the app to populate history.'}
680
- </Text>
681
- </View>) : (filteredActionHistory.map(action => {
682
- const id = action.id;
683
- const affectedSlices = action.affectedSlices || [];
684
- return (<TouchableScale key={id} onPress={() => {
685
- animateLayout();
686
- setActiveActionId(id);
687
- }} style={styles.listRow}>
688
- <View style={styles.seqBadge}>
689
- <Text style={styles.seqText}>#{action.id}</Text>
690
- </View>
691
- <View style={styles.rowMain}>
692
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
693
- <TerminalIcon color={AppColors.purple} size={11}/>
694
- <Text style={styles.actionTitleText} numberOfLines={1}>{action.type}</Text>
695
- </View>
696
- <View style={styles.actionMetaRow}>
697
- <ClockIcon color={AppColors.grayTextWeak} size={9}/>
698
- <Text style={styles.actionTimeText}>{action.timestamp} • {getSize(action.payload)}</Text>
699
- </View>
700
- {affectedSlices.length > 0 && (<View style={styles.tagsContainer}>
701
- {affectedSlices.map(slice => (<View key={slice} style={styles.sliceTagMini}>
702
- <Text style={styles.sliceTagMiniText}>{slice}</Text>
703
- </View>))}
704
- </View>)}
705
- </View>
706
- <ForwardChevronIcon color={AppColors.grayTextWeak} size={10}/>
707
- </TouchableScale>);
708
- }))}
709
- </ScrollView>)}
710
- </View>);
711
- });
712
- const styles = StyleSheet.create({
713
- container: {
714
- flex: 1,
715
- backgroundColor: AppColors.grayBackground,
716
- },
717
- scrollList: {
718
- flex: 1,
719
- },
720
- errorContainer: {
721
- padding: 24,
722
- alignItems: 'center',
723
- },
724
- errorText: {
725
- fontFamily: AppFonts.interRegular,
726
- fontSize: 12,
727
- color: AppColors.grayTextWeak,
728
- },
729
- toolbar: {
730
- flexDirection: 'row',
731
- alignItems: 'center',
732
- justifyContent: 'space-between',
733
- paddingHorizontal: 12,
734
- paddingVertical: 10,
735
- backgroundColor: AppColors.primaryLight,
736
- borderBottomWidth: 1,
737
- borderBottomColor: AppColors.dividerColor,
738
- },
739
- statusSection: {
740
- flexDirection: 'row',
741
- alignItems: 'center',
742
- },
743
- statusBadge: {
744
- flexDirection: 'row',
745
- alignItems: 'center',
746
- paddingHorizontal: 8,
747
- paddingVertical: 3,
748
- borderRadius: 12,
749
- borderWidth: 1,
750
- },
751
- statusBadgeActive: {
752
- backgroundColor: AppColors.greenStatus,
753
- borderColor: AppColors.greenColor + '30',
754
- },
755
- statusBadgePaused: {
756
- backgroundColor: AppColors.grayBackground,
757
- borderColor: AppColors.grayBorderSecondary,
758
- },
759
- statusDot: {
760
- width: 6,
761
- height: 6,
762
- borderRadius: 3,
763
- marginRight: 6,
764
- },
765
- statusDotActive: {
766
- backgroundColor: AppColors.greenBaggageText,
767
- },
768
- statusDotPaused: {
769
- backgroundColor: AppColors.grayTextWeak,
770
- },
771
- statusBadgeText: {
772
- fontFamily: AppFonts.interBold,
773
- fontSize: 9,
774
- letterSpacing: 0.5,
775
- },
776
- statusTextActive: {
777
- color: AppColors.greenBaggageText,
778
- },
779
- statusTextPaused: {
780
- color: AppColors.grayText,
781
- },
782
- toolbarActions: {
783
- flexDirection: 'row',
784
- alignItems: 'center',
785
- gap: 8,
786
- },
787
- iconBtn: {
788
- width: 28,
789
- height: 28,
790
- borderRadius: 6,
791
- borderWidth: 1,
792
- borderColor: AppColors.purple + '40',
793
- backgroundColor: AppColors.purpleShade50,
794
- alignItems: 'center',
795
- justifyContent: 'center',
796
- },
797
- searchContainer: {
798
- backgroundColor: AppColors.primaryLight,
799
- borderBottomWidth: 1,
800
- borderBottomColor: AppColors.dividerColor,
801
- paddingBottom: 10,
802
- },
803
- searchBar: {
804
- flexDirection: 'row',
805
- alignItems: 'center',
806
- backgroundColor: AppColors.grayBackground,
807
- borderRadius: 8,
808
- marginHorizontal: 12,
809
- marginTop: 10,
810
- marginBottom: 8,
811
- paddingHorizontal: 10,
812
- borderWidth: 1,
813
- borderColor: AppColors.dividerColor,
814
- height: 36,
815
- },
816
- filterChipRow: {
817
- flexDirection: 'row',
818
- alignItems: 'center',
819
- paddingHorizontal: 12,
820
- gap: 8,
821
- },
822
- filterChipLabel: {
823
- fontFamily: AppFonts.interBold,
824
- fontSize: 9,
825
- color: AppColors.grayTextWeak,
826
- letterSpacing: 0.5,
827
- marginRight: 2,
828
- },
829
- filterChip: {
830
- paddingHorizontal: 10,
831
- paddingVertical: 4,
832
- borderRadius: 12,
833
- backgroundColor: AppColors.grayBackground,
834
- borderWidth: 1,
835
- borderColor: AppColors.grayBorderSecondary,
836
- },
837
- filterChipActive: {
838
- backgroundColor: AppColors.purpleShade50,
839
- borderColor: AppColors.purple,
840
- },
841
- filterChipText: {
842
- fontFamily: AppFonts.interMedium,
843
- fontSize: 10,
844
- color: AppColors.grayText,
845
- },
846
- filterChipTextActive: {
847
- color: AppColors.purple,
848
- fontFamily: AppFonts.interBold,
849
- },
850
- searchInput: {
851
- flex: 1,
852
- fontFamily: AppFonts.interRegular,
853
- fontSize: 12,
854
- color: AppColors.grayTextStrong,
855
- marginLeft: 6,
856
- padding: 0,
857
- },
858
- tabContainer: {
859
- flexDirection: 'row',
860
- backgroundColor: AppColors.dividerColor,
861
- borderRadius: 8,
862
- padding: 3,
863
- marginHorizontal: 12,
864
- marginTop: 10,
865
- marginBottom: 10,
866
- },
867
- tabButton: {
868
- flex: 1,
869
- paddingVertical: 7,
870
- alignItems: 'center',
871
- justifyContent: 'center',
872
- borderRadius: 6,
873
- },
874
- tabButtonActive: {
875
- backgroundColor: AppColors.primaryLight,
876
- shadowColor: AppColors.shadowColorString,
877
- shadowOffset: { width: 0, height: 1 },
878
- shadowOpacity: 0.08,
879
- shadowRadius: 2,
880
- elevation: 2,
881
- },
882
- tabButtonText: {
883
- fontFamily: AppFonts.interMedium,
884
- fontSize: 12,
885
- color: AppColors.grayText,
886
- },
887
- tabButtonTextActive: {
888
- color: AppColors.purple,
889
- fontFamily: AppFonts.interBold,
890
- },
891
- scrollContent: {
892
- paddingBottom: 24,
893
- paddingHorizontal: 12,
894
- },
895
- emptyState: {
896
- padding: 24,
897
- alignItems: 'center',
898
- },
899
- emptyStateText: {
900
- fontFamily: AppFonts.interRegular,
901
- fontSize: 12,
902
- color: AppColors.grayTextWeak,
903
- textAlign: 'center',
904
- },
905
- listRow: {
906
- flexDirection: 'row',
907
- alignItems: 'center',
908
- backgroundColor: AppColors.primaryLight,
909
- paddingHorizontal: 12,
910
- paddingVertical: 14,
911
- borderRadius: 10,
912
- borderWidth: 1,
913
- borderColor: AppColors.grayBorderSecondary,
914
- marginBottom: 8,
915
- shadowColor: AppColors.shadowColorString,
916
- shadowOffset: { width: 0, height: 1 },
917
- shadowOpacity: 0.03,
918
- shadowRadius: 2,
919
- elevation: 1,
920
- },
921
- rowMain: {
922
- flex: 1,
923
- marginLeft: 10,
924
- },
925
- rowTitle: {
926
- fontFamily: AppFonts.interBold,
927
- fontSize: 13.5,
928
- color: AppColors.primaryBlack,
929
- },
930
- rowSub: {
931
- fontFamily: AppFonts.interRegular,
932
- fontSize: 10,
933
- color: AppColors.grayTextWeak,
934
- marginTop: 2,
935
- },
936
- sliceIcon: {
937
- width: 22,
938
- height: 22,
939
- borderRadius: 6,
940
- backgroundColor: AppColors.purpleShade50,
941
- alignItems: 'center',
942
- justifyContent: 'center',
943
- },
944
- seqBadge: {
945
- backgroundColor: AppColors.grayBackground,
946
- borderColor: AppColors.grayBorderSecondary,
947
- borderWidth: 1,
948
- borderRadius: 4,
949
- paddingHorizontal: 5,
950
- paddingVertical: 2,
951
- alignItems: 'center',
952
- justifyContent: 'center',
953
- minWidth: 28,
954
- },
955
- seqText: {
956
- fontFamily: AppFonts.interBold,
957
- fontSize: 9.5,
958
- color: AppColors.grayText,
959
- },
960
- actionTitleText: {
961
- fontFamily: AppFonts.interBold,
962
- fontSize: 13,
963
- color: AppColors.purple,
964
- },
965
- actionMetaRow: {
966
- flexDirection: 'row',
967
- alignItems: 'center',
968
- gap: 4,
969
- marginTop: 2,
970
- },
971
- actionTimeText: {
972
- fontFamily: AppFonts.interRegular,
973
- fontSize: 9.5,
974
- color: AppColors.grayTextWeak,
975
- },
976
- tagsContainer: {
977
- flexDirection: 'row',
978
- flexWrap: 'wrap',
979
- gap: 4,
980
- marginTop: 4,
981
- },
982
- sliceTagMini: {
983
- backgroundColor: AppColors.purpleShade50,
984
- borderColor: AppColors.purple + '20',
985
- borderWidth: 1,
986
- borderRadius: 3,
987
- paddingHorizontal: 4,
988
- paddingVertical: 0.5,
989
- },
990
- sliceTagMiniText: {
991
- fontFamily: AppFonts.interMedium,
992
- fontSize: 8.5,
993
- color: AppColors.purple,
994
- },
995
- // ── Detail Views Styles ──
996
- detailHeaderBar: {
997
- flexDirection: 'row',
998
- alignItems: 'center',
999
- paddingHorizontal: 12,
1000
- paddingVertical: 12,
1001
- backgroundColor: AppColors.primaryLight,
1002
- borderBottomWidth: 1,
1003
- borderBottomColor: AppColors.dividerColor,
1004
- },
1005
- backBtn: {
1006
- flexDirection: 'row',
1007
- alignItems: 'center',
1008
- paddingVertical: 6,
1009
- paddingRight: 8,
1010
- },
1011
- backBtnText: {
1012
- fontFamily: AppFonts.interBold,
1013
- fontSize: 12.5,
1014
- color: AppColors.purple,
1015
- },
1016
- detailHeaderInfo: {
1017
- flex: 1,
1018
- marginLeft: 10,
1019
- marginRight: 10,
1020
- },
1021
- detailTitle: {
1022
- fontFamily: AppFonts.interBold,
1023
- fontSize: 13.5,
1024
- color: AppColors.primaryBlack,
1025
- },
1026
- detailSub: {
1027
- fontFamily: AppFonts.interRegular,
1028
- fontSize: 10,
1029
- color: AppColors.grayTextWeak,
1030
- marginTop: 2,
1031
- },
1032
- detailHeaderActions: {
1033
- flexDirection: 'row',
1034
- alignItems: 'center',
1035
- gap: 6,
1036
- },
1037
- detailHeaderBtn: {
1038
- padding: 6,
1039
- borderRadius: 6,
1040
- borderWidth: 1,
1041
- borderColor: AppColors.purple + '20',
1042
- backgroundColor: AppColors.purpleShade50,
1043
- alignItems: 'center',
1044
- justifyContent: 'center',
1045
- width: 28,
1046
- height: 28,
1047
- },
1048
- detailCopyBtn: {
1049
- padding: 6,
1050
- borderRadius: 6,
1051
- borderWidth: 1,
1052
- borderColor: AppColors.purple + '20',
1053
- backgroundColor: AppColors.purpleShade50,
1054
- },
1055
- detailTimeRow: {
1056
- flexDirection: 'row',
1057
- alignItems: 'center',
1058
- gap: 4,
1059
- marginTop: 1,
1060
- },
1061
- detailTimeText: {
1062
- fontFamily: AppFonts.interRegular,
1063
- fontSize: 10,
1064
- color: AppColors.grayTextWeak,
1065
- },
1066
- detailAffectedTags: {
1067
- paddingHorizontal: 12,
1068
- paddingVertical: 8,
1069
- backgroundColor: AppColors.grayBackground,
1070
- borderBottomWidth: 1,
1071
- borderBottomColor: AppColors.dividerColor,
1072
- },
1073
- affectedTagsLabel: {
1074
- fontFamily: AppFonts.interBold,
1075
- fontSize: 9,
1076
- color: AppColors.grayTextWeak,
1077
- letterSpacing: 0.5,
1078
- marginBottom: 4,
1079
- },
1080
- detailTagsList: {
1081
- flexDirection: 'row',
1082
- flexWrap: 'wrap',
1083
- gap: 4,
1084
- },
1085
- sliceTag: {
1086
- backgroundColor: AppColors.purpleShade50,
1087
- borderColor: AppColors.purple + '20',
1088
- borderWidth: 1,
1089
- borderRadius: 4,
1090
- paddingHorizontal: 6,
1091
- paddingVertical: 1.5,
1092
- },
1093
- sliceTagText: {
1094
- fontFamily: AppFonts.interMedium,
1095
- fontSize: 9.5,
1096
- color: AppColors.purple,
1097
- },
1098
- subTabRow: {
1099
- flexDirection: 'row',
1100
- padding: 8,
1101
- gap: 8,
1102
- backgroundColor: AppColors.primaryLight,
1103
- borderBottomWidth: 1,
1104
- borderBottomColor: AppColors.dividerColor,
1105
- },
1106
- subTabPill: {
1107
- paddingHorizontal: 12,
1108
- paddingVertical: 5,
1109
- borderRadius: 12,
1110
- backgroundColor: AppColors.grayBackground,
1111
- borderWidth: 1,
1112
- borderColor: AppColors.grayBorderSecondary,
1113
- },
1114
- subTabPillActive: {
1115
- backgroundColor: AppColors.purple,
1116
- borderColor: AppColors.purple,
1117
- },
1118
- subTabPillText: {
1119
- fontFamily: AppFonts.interMedium,
1120
- fontSize: 10.5,
1121
- color: AppColors.grayText,
1122
- },
1123
- subTabPillTextActive: {
1124
- color: AppColors.white,
1125
- fontFamily: AppFonts.interBold,
1126
- },
1127
- detailScrollContent: {
1128
- paddingBottom: 24,
1129
- },
1130
- jsonViewerContainer: {
1131
- paddingHorizontal: 12,
1132
- paddingVertical: 8,
1133
- },
1134
- detailBox: {
1135
- padding: 10,
1136
- },
1137
- detailBoxHeader: {
1138
- flexDirection: 'row',
1139
- alignItems: 'center',
1140
- justifyContent: 'space-between',
1141
- marginBottom: 8,
1142
- paddingHorizontal: 4,
1143
- },
1144
- detailBoxTitle: {
1145
- fontFamily: AppFonts.interBold,
1146
- fontSize: 10,
1147
- color: AppColors.grayTextWeak,
1148
- letterSpacing: 0.5,
1149
- textTransform: 'uppercase',
1150
- },
1151
- apiLikeInfoBar: {
1152
- paddingHorizontal: 16,
1153
- paddingVertical: 14,
1154
- backgroundColor: AppColors.primaryLight,
1155
- borderBottomWidth: 1,
1156
- borderBottomColor: AppColors.dividerColor,
1157
- },
1158
- apiBadgeRow: {
1159
- flexDirection: 'row',
1160
- alignItems: 'center',
1161
- gap: 6,
1162
- marginBottom: 8,
1163
- },
1164
- apiMethodBadge: {
1165
- paddingHorizontal: 8,
1166
- paddingVertical: 2,
1167
- borderRadius: 4,
1168
- alignItems: 'center',
1169
- justifyContent: 'center',
1170
- },
1171
- apiMethodBadgeText: {
1172
- fontFamily: AppFonts.interBold,
1173
- fontSize: 9.5,
1174
- color: AppColors.white,
1175
- letterSpacing: 0.5,
1176
- },
1177
- apiChip: {
1178
- paddingHorizontal: 7,
1179
- paddingVertical: 2,
1180
- borderRadius: 4,
1181
- backgroundColor: `${AppColors.purple}0F`,
1182
- borderWidth: 1,
1183
- borderColor: `${AppColors.purple}26`,
1184
- alignItems: 'center',
1185
- justifyContent: 'center',
1186
- },
1187
- apiChipText: {
1188
- fontFamily: AppFonts.interBold,
1189
- fontSize: 9.5,
1190
- color: AppColors.purple,
1191
- },
1192
- apiTitleText: {
1193
- fontFamily: AppFonts.interBold,
1194
- fontSize: 16,
1195
- color: AppColors.primaryBlack,
1196
- marginBottom: 8,
1197
- },
1198
- apiMetaRow: {
1199
- flexDirection: 'row',
1200
- alignItems: 'center',
1201
- gap: 4,
1202
- },
1203
- apiMetaText: {
1204
- fontFamily: AppFonts.interRegular,
1205
- fontSize: 11,
1206
- color: AppColors.grayTextWeak,
1207
- },
1208
- contentDetailSubHeader: {
1209
- flexDirection: 'row',
1210
- alignItems: 'center',
1211
- justifyContent: 'space-between',
1212
- paddingHorizontal: 12,
1213
- paddingVertical: 10,
1214
- borderBottomWidth: 1,
1215
- borderBottomColor: AppColors.dividerColor,
1216
- backgroundColor: AppColors.primaryLight,
1217
- },
1218
- });