react-native-inapp-inspector 2.5.12 → 2.5.13

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 (186) hide show
  1. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  2. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  3. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  4. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  5. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  6. package/android/.gradle/8.9/gc.properties +0 -0
  7. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  8. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  9. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  10. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  11. package/android/.gradle/9.2.0/gc.properties +0 -0
  12. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  13. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  14. package/android/.gradle/vcs-1/gc.properties +0 -0
  15. package/android/.settings/org.eclipse.buildship.core.prefs +13 -0
  16. package/android/src/main/AndroidManifest.xml +11 -0
  17. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +379 -19
  18. package/android/src/main/res/xml/inappinspector_file_paths.xml +7 -0
  19. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +47 -49
  20. package/dist/commonjs/components/Inspector/BoxModelVisualizer.d.ts +8 -0
  21. package/dist/commonjs/components/Inspector/BoxModelVisualizer.js +76 -0
  22. package/dist/commonjs/components/Inspector/ConsoleExportModal.js +51 -51
  23. package/dist/commonjs/components/Inspector/CrashTab.js +17 -17
  24. package/dist/commonjs/components/Inspector/DebuggingTab.js +24 -24
  25. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +2 -2
  26. package/dist/commonjs/components/Inspector/FabLauncher.js +2 -2
  27. package/dist/commonjs/components/Inspector/FloatingCaptureWidget.js +2 -2
  28. package/dist/commonjs/components/Inspector/InspectorHeader.js +10 -10
  29. package/dist/commonjs/components/Inspector/MediaGalleryTab.js +10 -10
  30. package/dist/commonjs/components/Inspector/MediaPreviewModal.d.ts +1 -0
  31. package/dist/commonjs/components/Inspector/MediaPreviewModal.js +222 -222
  32. package/dist/commonjs/components/Inspector/NetworkExportModal.d.ts +10 -0
  33. package/dist/commonjs/components/Inspector/NetworkExportModal.js +333 -0
  34. package/dist/commonjs/components/Inspector/NetworkTab.js +48 -41
  35. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +11 -12
  36. package/dist/commonjs/components/Inspector/ReduxDetail.js +17 -19
  37. package/dist/commonjs/components/Inspector/ReduxTab.js +5 -5
  38. package/dist/commonjs/components/Inspector/SettingsPanel.js +3 -6
  39. package/dist/commonjs/components/Inspector/SocketCard.js +2 -2
  40. package/dist/commonjs/components/Inspector/SupportPage.js +5 -5
  41. package/dist/commonjs/components/Inspector/UiA11yAuditPanel.d.ts +7 -0
  42. package/dist/commonjs/components/Inspector/UiA11yAuditPanel.js +97 -0
  43. package/dist/commonjs/components/Inspector/UiInspectorDetail.d.ts +2 -0
  44. package/dist/commonjs/components/Inspector/UiInspectorDetail.js +485 -0
  45. package/dist/commonjs/components/Inspector/UiInspectorOverlay.d.ts +2 -0
  46. package/dist/commonjs/components/Inspector/UiInspectorOverlay.js +199 -0
  47. package/dist/commonjs/components/Inspector/UiInspectorTab.d.ts +2 -0
  48. package/dist/commonjs/components/Inspector/UiInspectorTab.js +117 -0
  49. package/dist/commonjs/components/Inspector/UiLiveStyleTweaker.d.ts +10 -0
  50. package/dist/commonjs/components/Inspector/UiLiveStyleTweaker.js +148 -0
  51. package/dist/commonjs/components/Inspector/index.d.ts +28 -0
  52. package/dist/commonjs/components/Inspector/index.js +1 -0
  53. package/dist/commonjs/components/LogCard.js +9 -7
  54. package/dist/commonjs/constants/index.js +1 -1
  55. package/dist/commonjs/constants/telemetryConfig.d.ts +3 -3
  56. package/dist/commonjs/constants/telemetryConfig.js +1 -1
  57. package/dist/commonjs/constants/version.d.ts +1 -1
  58. package/dist/commonjs/constants/version.js +1 -1
  59. package/dist/commonjs/customHooks/crashHandler.d.ts +1 -1
  60. package/dist/commonjs/customHooks/crashHandler.js +6 -6
  61. package/dist/commonjs/customHooks/uiInspectorManager.d.ts +22 -0
  62. package/dist/commonjs/customHooks/uiInspectorManager.js +1 -0
  63. package/dist/commonjs/helpers/index.js +1 -3
  64. package/dist/commonjs/helpers/searchQueryParser.d.ts +1 -0
  65. package/dist/commonjs/helpers/searchQueryParser.js +7 -5
  66. package/dist/commonjs/helpers/shareFormatter.d.ts +16 -0
  67. package/dist/commonjs/helpers/shareFormatter.js +16 -9
  68. package/dist/commonjs/helpers/uiInspectorEngine.d.ts +62 -0
  69. package/dist/commonjs/helpers/uiInspectorEngine.js +19 -0
  70. package/dist/commonjs/i18n/locales/ar.json +1 -1
  71. package/dist/commonjs/i18n/locales/bn.json +1 -1
  72. package/dist/commonjs/i18n/locales/de.json +1 -1
  73. package/dist/commonjs/i18n/locales/en.json +1 -1
  74. package/dist/commonjs/i18n/locales/es.json +1 -1
  75. package/dist/commonjs/i18n/locales/fr.json +1 -1
  76. package/dist/commonjs/i18n/locales/gu.json +1 -1
  77. package/dist/commonjs/i18n/locales/hi.json +1 -1
  78. package/dist/commonjs/i18n/locales/id.json +1 -1
  79. package/dist/commonjs/i18n/locales/it.json +1 -1
  80. package/dist/commonjs/i18n/locales/ja.json +1 -1
  81. package/dist/commonjs/i18n/locales/kn.json +1 -1
  82. package/dist/commonjs/i18n/locales/ko.json +1 -1
  83. package/dist/commonjs/i18n/locales/ml.json +1 -1
  84. package/dist/commonjs/i18n/locales/mr.json +1 -1
  85. package/dist/commonjs/i18n/locales/nl.json +1 -1
  86. package/dist/commonjs/i18n/locales/pa.json +1 -1
  87. package/dist/commonjs/i18n/locales/pl.json +1 -1
  88. package/dist/commonjs/i18n/locales/pt.json +1 -1
  89. package/dist/commonjs/i18n/locales/ru.json +1 -1
  90. package/dist/commonjs/i18n/locales/ta.json +1 -1
  91. package/dist/commonjs/i18n/locales/te.json +1 -1
  92. package/dist/commonjs/i18n/locales/tr.json +1 -1
  93. package/dist/commonjs/i18n/locales/vi.json +1 -1
  94. package/dist/commonjs/i18n/locales/zh.json +1 -1
  95. package/dist/commonjs/index.d.ts +3 -1
  96. package/dist/commonjs/index.js +3 -3
  97. package/dist/commonjs/native/NativeInspector.d.ts +2 -0
  98. package/dist/commonjs/native/NativeInspector.js +1 -1
  99. package/dist/commonjs/native/NativeNetworkInspector.d.ts +2 -0
  100. package/dist/commonjs/types/editor.d.ts +31 -0
  101. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +73 -75
  102. package/dist/esm/components/Inspector/BoxModelVisualizer.d.ts +8 -0
  103. package/dist/esm/components/Inspector/BoxModelVisualizer.js +76 -0
  104. package/dist/esm/components/Inspector/ConsoleExportModal.js +67 -67
  105. package/dist/esm/components/Inspector/CrashTab.js +58 -58
  106. package/dist/esm/components/Inspector/DebuggingTab.js +89 -89
  107. package/dist/esm/components/Inspector/DeviceInfoTab.js +2 -2
  108. package/dist/esm/components/Inspector/FabLauncher.js +21 -21
  109. package/dist/esm/components/Inspector/FloatingCaptureWidget.js +23 -23
  110. package/dist/esm/components/Inspector/InspectorHeader.js +26 -26
  111. package/dist/esm/components/Inspector/MediaGalleryTab.js +151 -151
  112. package/dist/esm/components/Inspector/MediaPreviewModal.d.ts +1 -0
  113. package/dist/esm/components/Inspector/MediaPreviewModal.js +468 -468
  114. package/dist/esm/components/Inspector/NetworkExportModal.d.ts +10 -0
  115. package/dist/esm/components/Inspector/NetworkExportModal.js +333 -0
  116. package/dist/esm/components/Inspector/NetworkTab.js +118 -111
  117. package/dist/esm/components/Inspector/NpmStarPrompt.js +32 -33
  118. package/dist/esm/components/Inspector/ReduxDetail.js +54 -56
  119. package/dist/esm/components/Inspector/ReduxTab.js +9 -9
  120. package/dist/esm/components/Inspector/SettingsPanel.js +3 -6
  121. package/dist/esm/components/Inspector/SocketCard.js +13 -13
  122. package/dist/esm/components/Inspector/SupportPage.js +5 -5
  123. package/dist/esm/components/Inspector/UiA11yAuditPanel.d.ts +7 -0
  124. package/dist/esm/components/Inspector/UiA11yAuditPanel.js +97 -0
  125. package/dist/esm/components/Inspector/UiInspectorDetail.d.ts +2 -0
  126. package/dist/esm/components/Inspector/UiInspectorDetail.js +422 -0
  127. package/dist/esm/components/Inspector/UiInspectorOverlay.d.ts +2 -0
  128. package/dist/esm/components/Inspector/UiInspectorOverlay.js +138 -0
  129. package/dist/esm/components/Inspector/UiInspectorTab.d.ts +2 -0
  130. package/dist/esm/components/Inspector/UiInspectorTab.js +117 -0
  131. package/dist/esm/components/Inspector/UiLiveStyleTweaker.d.ts +10 -0
  132. package/dist/esm/components/Inspector/UiLiveStyleTweaker.js +148 -0
  133. package/dist/esm/components/Inspector/index.d.ts +28 -0
  134. package/dist/esm/components/Inspector/index.js +1 -0
  135. package/dist/esm/components/LogCard.js +57 -55
  136. package/dist/esm/constants/index.js +1 -1
  137. package/dist/esm/constants/telemetryConfig.d.ts +3 -3
  138. package/dist/esm/constants/telemetryConfig.js +1 -1
  139. package/dist/esm/constants/version.d.ts +1 -1
  140. package/dist/esm/constants/version.js +1 -1
  141. package/dist/esm/customHooks/crashHandler.d.ts +1 -1
  142. package/dist/esm/customHooks/crashHandler.js +6 -6
  143. package/dist/esm/customHooks/uiInspectorManager.d.ts +22 -0
  144. package/dist/esm/customHooks/uiInspectorManager.js +1 -0
  145. package/dist/esm/helpers/index.js +4 -6
  146. package/dist/esm/helpers/searchQueryParser.d.ts +1 -0
  147. package/dist/esm/helpers/searchQueryParser.js +7 -5
  148. package/dist/esm/helpers/shareFormatter.d.ts +16 -0
  149. package/dist/esm/helpers/shareFormatter.js +20 -13
  150. package/dist/esm/helpers/uiInspectorEngine.d.ts +48 -0
  151. package/dist/esm/helpers/uiInspectorEngine.js +19 -0
  152. package/dist/esm/i18n/locales/ar.json +1 -1
  153. package/dist/esm/i18n/locales/bn.json +1 -1
  154. package/dist/esm/i18n/locales/de.json +1 -1
  155. package/dist/esm/i18n/locales/en.json +1 -1
  156. package/dist/esm/i18n/locales/es.json +1 -1
  157. package/dist/esm/i18n/locales/fr.json +1 -1
  158. package/dist/esm/i18n/locales/gu.json +1 -1
  159. package/dist/esm/i18n/locales/hi.json +1 -1
  160. package/dist/esm/i18n/locales/id.json +1 -1
  161. package/dist/esm/i18n/locales/it.json +1 -1
  162. package/dist/esm/i18n/locales/ja.json +1 -1
  163. package/dist/esm/i18n/locales/kn.json +1 -1
  164. package/dist/esm/i18n/locales/ko.json +1 -1
  165. package/dist/esm/i18n/locales/ml.json +1 -1
  166. package/dist/esm/i18n/locales/mr.json +1 -1
  167. package/dist/esm/i18n/locales/nl.json +1 -1
  168. package/dist/esm/i18n/locales/pa.json +1 -1
  169. package/dist/esm/i18n/locales/pl.json +1 -1
  170. package/dist/esm/i18n/locales/pt.json +1 -1
  171. package/dist/esm/i18n/locales/ru.json +1 -1
  172. package/dist/esm/i18n/locales/ta.json +1 -1
  173. package/dist/esm/i18n/locales/te.json +1 -1
  174. package/dist/esm/i18n/locales/tr.json +1 -1
  175. package/dist/esm/i18n/locales/vi.json +1 -1
  176. package/dist/esm/i18n/locales/zh.json +1 -1
  177. package/dist/esm/index.d.ts +3 -1
  178. package/dist/esm/index.js +7 -7
  179. package/dist/esm/native/NativeInspector.d.ts +2 -0
  180. package/dist/esm/native/NativeInspector.js +1 -1
  181. package/dist/esm/native/NativeNetworkInspector.d.ts +2 -0
  182. package/dist/esm/types/editor.d.ts +31 -0
  183. package/ios/NetworkInspectorModule.mm +314 -16
  184. package/package.json +1 -1
  185. package/src/native/NativeInspector.ts +37 -0
  186. package/src/native/NativeNetworkInspector.ts +2 -0
@@ -2085,6 +2085,36 @@ RCT_EXPORT_METHOD(clearAllCapturedMedia:(RCTPromiseResolveBlock)resolve
2085
2085
  // 100% Native Media Editor: Photo Editing (CoreImage + ImageIO)
2086
2086
  // ─────────────────────────────────────────────────────────────────────────────
2087
2087
 
2088
+ static UIColor *inspectorColorFromHex(NSString *hexString, UIColor *defaultColor) {
2089
+ if (!hexString || ![hexString isKindOfClass:[NSString class]]) {
2090
+ return defaultColor ?: [UIColor redColor];
2091
+ }
2092
+ NSString *cleanHex = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
2093
+ cleanHex = [cleanHex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
2094
+ unsigned int rgbValue = 0;
2095
+ NSScanner *scanner = [NSScanner scannerWithString:cleanHex];
2096
+ [scanner scanHexInt:&rgbValue];
2097
+
2098
+ if (cleanHex.length == 8) {
2099
+ CGFloat r = ((rgbValue & 0xFF000000) >> 24) / 255.0;
2100
+ CGFloat g = ((rgbValue & 0x00FF0000) >> 16) / 255.0;
2101
+ CGFloat b = ((rgbValue & 0x0000FF00) >> 8) / 255.0;
2102
+ CGFloat a = (rgbValue & 0x000000FF) / 255.0;
2103
+ return [UIColor colorWithRed:r green:g blue:b alpha:a];
2104
+ } else if (cleanHex.length == 6) {
2105
+ CGFloat r = ((rgbValue & 0xFF0000) >> 16) / 255.0;
2106
+ CGFloat g = ((rgbValue & 0x00FF00) >> 8) / 255.0;
2107
+ CGFloat b = (rgbValue & 0x0000FF) / 255.0;
2108
+ return [UIColor colorWithRed:r green:g blue:b alpha:1.0];
2109
+ } else if (cleanHex.length == 3) {
2110
+ CGFloat r = (((rgbValue & 0xF00) >> 8) * 17) / 255.0;
2111
+ CGFloat g = (((rgbValue & 0x0F0) >> 4) * 17) / 255.0;
2112
+ CGFloat b = ((rgbValue & 0x00F) * 17) / 255.0;
2113
+ return [UIColor colorWithRed:r green:g blue:b alpha:1.0];
2114
+ }
2115
+ return defaultColor ?: [UIColor redColor];
2116
+ }
2117
+
2088
2118
  RCT_EXPORT_METHOD(editPhoto:(NSDictionary *)options
2089
2119
  resolve:(RCTPromiseResolveBlock)resolve
2090
2120
  reject:(RCTPromiseRejectBlock)reject) {
@@ -2245,34 +2275,223 @@ RCT_EXPORT_METHOD(editPhoto:(NSDictionary *)options
2245
2275
  UIImage *resultImage = [UIImage imageWithCGImage:cgImage];
2246
2276
  CGImageRelease(cgImage);
2247
2277
 
2248
- // 7. Apply Redactions & Annotations Overlay if provided
2278
+ // 7. Apply Redactions, Freehand Drawings, Draggable Texts & Annotations Overlay if provided
2249
2279
  NSArray *redactions = options[@"redactions"];
2250
2280
  NSArray *annotations = options[@"annotations"];
2251
- if ((redactions && [redactions isKindOfClass:[NSArray class]] && redactions.count > 0) ||
2252
- (annotations && [annotations isKindOfClass:[NSArray class]] && annotations.count > 0)) {
2281
+ NSArray *drawings = options[@"drawings"];
2282
+ NSArray *texts = options[@"texts"];
2283
+
2284
+ BOOL hasOverlay = (redactions && [redactions isKindOfClass:[NSArray class]] && redactions.count > 0) ||
2285
+ (annotations && [annotations isKindOfClass:[NSArray class]] && annotations.count > 0) ||
2286
+ (drawings && [drawings isKindOfClass:[NSArray class]] && drawings.count > 0) ||
2287
+ (texts && [texts isKindOfClass:[NSArray class]] && texts.count > 0);
2288
+
2289
+ if (hasOverlay) {
2253
2290
  UIGraphicsBeginImageContextWithOptions(resultImage.size, NO, 1.0);
2254
2291
  [resultImage drawInRect:CGRectMake(0, 0, resultImage.size.width, resultImage.size.height)];
2255
2292
  CGContextRef ctx = UIGraphicsGetCurrentContext();
2256
2293
 
2294
+ CGFloat canvasW = resultImage.size.width;
2295
+ CGFloat canvasH = resultImage.size.height;
2296
+ CGFloat baseScale = MAX(1.0, canvasW / 380.0);
2297
+
2298
+ // A. Redactions (Blackout or Blur/Pixelate Box)
2257
2299
  if (redactions && [redactions isKindOfClass:[NSArray class]]) {
2258
2300
  for (NSDictionary *box in redactions) {
2259
2301
  CGFloat x = [box[@"x"] doubleValue];
2260
2302
  CGFloat y = [box[@"y"] doubleValue];
2261
2303
  CGFloat w = [box[@"width"] doubleValue];
2262
2304
  CGFloat h = [box[@"height"] doubleValue];
2263
- BOOL isNorm = [box[@"isNormalized"] boolValue];
2305
+ BOOL isNorm = box[@"isNormalized"] ? [box[@"isNormalized"] boolValue] : YES;
2264
2306
  if (isNorm) {
2265
- x *= resultImage.size.width;
2266
- y *= resultImage.size.height;
2267
- w *= resultImage.size.width;
2268
- h *= resultImage.size.height;
2307
+ x *= canvasW;
2308
+ y *= canvasH;
2309
+ w *= canvasW;
2310
+ h *= canvasH;
2311
+ }
2312
+ NSString *style = box[@"style"] ?: @"blackout";
2313
+ if ([style isEqualToString:@"blur"] || [style isEqualToString:@"pixelate"]) {
2314
+ CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:0.12 alpha:0.92].CGColor);
2315
+ } else {
2316
+ CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor);
2269
2317
  }
2270
- CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor);
2271
2318
  CGContextFillRect(ctx, CGRectMake(x, y, w, h));
2272
2319
  }
2273
2320
  }
2274
2321
 
2275
- if (annotations && [annotations isKindOfClass:[NSArray class]]) {
2322
+ // B. Freehand Drawings & Vector Shapes (Brush, Highlighter, Arrow, Rect, Circle, Step)
2323
+ if (drawings && [drawings isKindOfClass:[NSArray class]]) {
2324
+ for (NSDictionary *stroke in drawings) {
2325
+ NSString *type = stroke[@"type"] ?: @"brush";
2326
+ NSString *hexColor = stroke[@"color"] ?: @"#EF4444";
2327
+ UIColor *strokeColor = inspectorColorFromHex(hexColor, [UIColor redColor]);
2328
+ CGFloat strokeWidth = stroke[@"strokeWidth"] ? [stroke[@"strokeWidth"] doubleValue] * baseScale : 4.0 * baseScale;
2329
+ BOOL isNorm = stroke[@"isNormalized"] ? [stroke[@"isNormalized"] boolValue] : YES;
2330
+ NSArray *points = stroke[@"points"];
2331
+
2332
+ if ([type isEqualToString:@"brush"]) {
2333
+ if (points && points.count > 1) {
2334
+ CGContextSetStrokeColorWithColor(ctx, strokeColor.CGColor);
2335
+ CGContextSetLineWidth(ctx, strokeWidth);
2336
+ CGContextSetLineCap(ctx, kCGLineCapRound);
2337
+ CGContextSetLineJoin(ctx, kCGLineJoinRound);
2338
+ CGContextBeginPath(ctx);
2339
+ for (NSUInteger pIdx = 0; pIdx < points.count; pIdx++) {
2340
+ NSDictionary *pt = points[pIdx];
2341
+ CGFloat px = [pt[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2342
+ CGFloat py = [pt[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2343
+ if (pIdx == 0) {
2344
+ CGContextMoveToPoint(ctx, px, py);
2345
+ } else {
2346
+ CGContextAddLineToPoint(ctx, px, py);
2347
+ }
2348
+ }
2349
+ CGContextStrokePath(ctx);
2350
+ }
2351
+ } else if ([type isEqualToString:@"highlighter"]) {
2352
+ if (points && points.count > 1) {
2353
+ UIColor *hiColor = [strokeColor colorWithAlphaComponent:0.4];
2354
+ CGContextSetStrokeColorWithColor(ctx, hiColor.CGColor);
2355
+ CGContextSetLineWidth(ctx, strokeWidth * 2.5);
2356
+ CGContextSetLineCap(ctx, kCGLineCapRound);
2357
+ CGContextSetLineJoin(ctx, kCGLineJoinRound);
2358
+ CGContextBeginPath(ctx);
2359
+ for (NSUInteger pIdx = 0; pIdx < points.count; pIdx++) {
2360
+ NSDictionary *pt = points[pIdx];
2361
+ CGFloat px = [pt[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2362
+ CGFloat py = [pt[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2363
+ if (pIdx == 0) {
2364
+ CGContextMoveToPoint(ctx, px, py);
2365
+ } else {
2366
+ CGContextAddLineToPoint(ctx, px, py);
2367
+ }
2368
+ }
2369
+ CGContextStrokePath(ctx);
2370
+ }
2371
+ } else if ([type isEqualToString:@"arrow"]) {
2372
+ if (points && points.count >= 2) {
2373
+ NSDictionary *p0 = points[0];
2374
+ NSDictionary *p1 = points[points.count - 1];
2375
+ CGFloat x0 = [p0[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2376
+ CGFloat y0 = [p0[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2377
+ CGFloat x1 = [p1[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2378
+ CGFloat y1 = [p1[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2379
+
2380
+ CGContextSetStrokeColorWithColor(ctx, strokeColor.CGColor);
2381
+ CGContextSetLineWidth(ctx, strokeWidth);
2382
+ CGContextSetLineCap(ctx, kCGLineCapRound);
2383
+ CGContextBeginPath(ctx);
2384
+ CGContextMoveToPoint(ctx, x0, y0);
2385
+ CGContextAddLineToPoint(ctx, x1, y1);
2386
+ CGContextStrokePath(ctx);
2387
+
2388
+ CGFloat dx = x1 - x0;
2389
+ CGFloat dy = y1 - y0;
2390
+ CGFloat angle = atan2(dy, dx);
2391
+ CGFloat headLen = MAX(14.0 * baseScale, MIN(32.0 * baseScale, strokeWidth * 3.5));
2392
+ CGFloat headAngle = M_PI / 6.0;
2393
+ CGFloat ax1 = x1 - headLen * cos(angle - headAngle);
2394
+ CGFloat ay1 = y1 - headLen * sin(angle - headAngle);
2395
+ CGFloat ax2 = x1 - headLen * cos(angle + headAngle);
2396
+ CGFloat ay2 = y1 - headLen * sin(angle + headAngle);
2397
+
2398
+ CGContextSetFillColorWithColor(ctx, strokeColor.CGColor);
2399
+ CGContextBeginPath(ctx);
2400
+ CGContextMoveToPoint(ctx, x1, y1);
2401
+ CGContextAddLineToPoint(ctx, ax1, ay1);
2402
+ CGContextAddLineToPoint(ctx, ax2, ay2);
2403
+ CGContextClosePath(ctx);
2404
+ CGContextFillPath(ctx);
2405
+ }
2406
+ } else if ([type isEqualToString:@"rect"]) {
2407
+ NSDictionary *p0 = (points && points.count > 0) ? points[0] : nil;
2408
+ NSDictionary *p1 = (points && points.count > 1) ? points[1] : p0;
2409
+ CGFloat x0 = [p0[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2410
+ CGFloat y0 = [p0[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2411
+ CGFloat x1 = [p1[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2412
+ CGFloat y1 = [p1[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2413
+ CGRect rect = CGRectMake(MIN(x0, x1), MIN(y0, y1), ABS(x1 - x0), ABS(y1 - y0));
2414
+ CGContextSetStrokeColorWithColor(ctx, strokeColor.CGColor);
2415
+ CGContextSetLineWidth(ctx, strokeWidth);
2416
+ CGContextStrokeRect(ctx, rect);
2417
+ } else if ([type isEqualToString:@"circle"] || [type isEqualToString:@"spotlight"]) {
2418
+ NSDictionary *p0 = (points && points.count > 0) ? points[0] : nil;
2419
+ NSDictionary *p1 = (points && points.count > 1) ? points[1] : p0;
2420
+ CGFloat x0 = [p0[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2421
+ CGFloat y0 = [p0[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2422
+ CGFloat x1 = [p1[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2423
+ CGFloat y1 = [p1[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2424
+ CGRect rect = CGRectMake(MIN(x0, x1), MIN(y0, y1), ABS(x1 - x0), ABS(y1 - y0));
2425
+ CGContextSetStrokeColorWithColor(ctx, strokeColor.CGColor);
2426
+ CGContextSetLineWidth(ctx, strokeWidth);
2427
+ CGContextStrokeEllipseInRect(ctx, rect);
2428
+ } else if ([type isEqualToString:@"step"]) {
2429
+ NSDictionary *p0 = (points && points.count > 0) ? points[0] : nil;
2430
+ CGFloat cx = [p0[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2431
+ CGFloat cy = [p0[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2432
+ CGFloat radius = 16.0 * baseScale;
2433
+ CGRect badgeRect = CGRectMake(cx - radius, cy - radius, radius * 2, radius * 2);
2434
+
2435
+ CGContextSetFillColorWithColor(ctx, strokeColor.CGColor);
2436
+ CGContextFillEllipseInRect(ctx, badgeRect);
2437
+
2438
+ CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
2439
+ CGContextSetLineWidth(ctx, 2.0 * baseScale);
2440
+ CGContextStrokeEllipseInRect(ctx, badgeRect);
2441
+
2442
+ NSInteger stepNum = stroke[@"stepNumber"] ? [stroke[@"stepNumber"] integerValue] : 1;
2443
+ NSString *stepStr = [NSString stringWithFormat:@"%ld", (long)stepNum];
2444
+ UIFont *font = [UIFont boldSystemFontOfSize:14.0 * baseScale];
2445
+ NSDictionary *attrs = @{
2446
+ NSFontAttributeName: font,
2447
+ NSForegroundColorAttributeName: [UIColor whiteColor]
2448
+ };
2449
+ CGSize strSize = [stepStr sizeWithAttributes:attrs];
2450
+ CGPoint strOrigin = CGPointMake(cx - strSize.width / 2.0, cy - strSize.height / 2.0);
2451
+ [stepStr drawAtPoint:strOrigin withAttributes:attrs];
2452
+ }
2453
+ }
2454
+ }
2455
+
2456
+ // C. Draggable Text Badges / Notes
2457
+ if (texts && [texts isKindOfClass:[NSArray class]]) {
2458
+ for (NSDictionary *tItem in texts) {
2459
+ NSString *textStr = tItem[@"text"] ?: @"";
2460
+ if (textStr.length == 0) continue;
2461
+ BOOL isNorm = tItem[@"isNormalized"] ? [tItem[@"isNormalized"] boolValue] : YES;
2462
+ CGFloat tx = [tItem[@"x"] doubleValue] * (isNorm ? canvasW : 1.0);
2463
+ CGFloat ty = [tItem[@"y"] doubleValue] * (isNorm ? canvasH : 1.0);
2464
+ NSString *textColorHex = tItem[@"color"] ?: @"#FFFFFF";
2465
+ NSString *bgColorHex = tItem[@"bgColor"] ?: @"#EF4444";
2466
+ UIColor *textColor = inspectorColorFromHex(textColorHex, [UIColor whiteColor]);
2467
+ UIColor *bgColor = inspectorColorFromHex(bgColorHex, [UIColor redColor]);
2468
+
2469
+ UIFont *font = [UIFont boldSystemFontOfSize:15.0 * baseScale];
2470
+ NSDictionary *attrs = @{
2471
+ NSFontAttributeName: font,
2472
+ NSForegroundColorAttributeName: textColor
2473
+ };
2474
+ CGSize strSize = [textStr sizeWithAttributes:attrs];
2475
+ CGFloat padH = 12.0 * baseScale;
2476
+ CGFloat padV = 6.0 * baseScale;
2477
+ CGRect pillRect = CGRectMake(tx, ty, strSize.width + padH * 2.0, strSize.height + padV * 2.0);
2478
+ UIBezierPath *roundedPill = [UIBezierPath bezierPathWithRoundedRect:pillRect cornerRadius:pillRect.size.height / 2.0];
2479
+
2480
+ CGContextSetFillColorWithColor(ctx, bgColor.CGColor);
2481
+ CGContextAddPath(ctx, roundedPill.CGPath);
2482
+ CGContextFillPath(ctx);
2483
+
2484
+ CGContextSetStrokeColorWithColor(ctx, [[UIColor whiteColor] colorWithAlphaComponent:0.4].CGColor);
2485
+ CGContextSetLineWidth(ctx, 1.5 * baseScale);
2486
+ CGContextAddPath(ctx, roundedPill.CGPath);
2487
+ CGContextStrokePath(ctx);
2488
+
2489
+ [textStr drawAtPoint:CGPointMake(tx + padH, ty + padV) withAttributes:attrs];
2490
+ }
2491
+ }
2492
+
2493
+ // D. Legacy / Standalone Annotations
2494
+ if (annotations && [annotations isKindOfClass:[NSArray class]] && (!drawings || drawings.count == 0)) {
2276
2495
  for (NSDictionary *ann in annotations) {
2277
2496
  CGFloat x = [ann[@"x"] doubleValue];
2278
2497
  CGFloat y = [ann[@"y"] doubleValue];
@@ -2280,14 +2499,32 @@ RCT_EXPORT_METHOD(editPhoto:(NSDictionary *)options
2280
2499
  CGFloat h = [ann[@"height"] doubleValue];
2281
2500
  BOOL isNorm = [ann[@"isNormalized"] boolValue];
2282
2501
  if (isNorm) {
2283
- x *= resultImage.size.width;
2284
- y *= resultImage.size.height;
2285
- w *= resultImage.size.width;
2286
- h *= resultImage.size.height;
2502
+ x *= canvasW;
2503
+ y *= canvasH;
2504
+ w *= canvasW;
2505
+ h *= canvasH;
2287
2506
  }
2288
- CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
2289
- CGContextSetLineWidth(ctx, 4.0);
2507
+ NSString *annColorHex = ann[@"color"] ?: @"#EF4444";
2508
+ UIColor *annColor = inspectorColorFromHex(annColorHex, [UIColor redColor]);
2509
+ CGContextSetStrokeColorWithColor(ctx, annColor.CGColor);
2510
+ CGContextSetLineWidth(ctx, 4.0 * baseScale);
2290
2511
  CGContextStrokeRect(ctx, CGRectMake(x, y, w, h));
2512
+
2513
+ NSString *label = ann[@"label"];
2514
+ if (label && [label isKindOfClass:[NSString class]] && label.length > 0) {
2515
+ UIFont *font = [UIFont boldSystemFontOfSize:13.0 * baseScale];
2516
+ NSDictionary *attrs = @{
2517
+ NSFontAttributeName: font,
2518
+ NSForegroundColorAttributeName: [UIColor whiteColor]
2519
+ };
2520
+ CGSize strSize = [label sizeWithAttributes:attrs];
2521
+ CGFloat padH = 6.0 * baseScale;
2522
+ CGFloat padV = 3.0 * baseScale;
2523
+ CGRect tagRect = CGRectMake(x, MAX(0, y - strSize.height - padV * 2.0), strSize.width + padH * 2.0, strSize.height + padV * 2.0);
2524
+ CGContextSetFillColorWithColor(ctx, annColor.CGColor);
2525
+ CGContextFillRect(ctx, tagRect);
2526
+ [label drawAtPoint:CGPointMake(tagRect.origin.x + padH, tagRect.origin.y + padV) withAttributes:attrs];
2527
+ }
2291
2528
  }
2292
2529
  }
2293
2530
 
@@ -2600,9 +2837,70 @@ RCT_EXPORT_METHOD(pickMedia:(NSDictionary *)options
2600
2837
  #pragma clang diagnostic pop
2601
2838
  [rootVC presentViewController:picker animated:YES completion:nil];
2602
2839
  }
2840
+ RCT_EXPORT_METHOD(writeExportFile:(NSString *)filename
2841
+ content:(NSString *)content
2842
+ resolve:(RCTPromiseResolveBlock)resolve
2843
+ reject:(RCTPromiseRejectBlock)reject) {
2844
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2845
+ @try {
2846
+ if (!filename || filename.length == 0) {
2847
+ reject(@"INVALID_FILENAME", @"Filename is missing", nil);
2848
+ return;
2849
+ }
2850
+ NSString *dir = [self getCapturesDirectory];
2851
+ NSString *cleanFilename = [filename lastPathComponent];
2852
+ NSString *outPath = [dir stringByAppendingPathComponent:cleanFilename];
2853
+ NSData *data = [(content ?: @"") dataUsingEncoding:NSUTF8StringEncoding];
2854
+ BOOL success = [data writeToFile:outPath atomically:YES];
2855
+ if (success) {
2856
+ resolve([NSURL fileURLWithPath:outPath].absoluteString);
2857
+ } else {
2858
+ reject(@"WRITE_FAILED", @"Failed to write export file", nil);
2859
+ }
2860
+ } @catch (NSException *e) {
2861
+ reject(@"WRITE_ERROR", e.reason, nil);
2862
+ }
2603
2863
  });
2604
2864
  }
2605
2865
 
2866
+ RCT_EXPORT_METHOD(shareFile:(NSString *)filePath
2867
+ mimeType:(NSString *)mimeType
2868
+ title:(NSString *)title
2869
+ resolve:(RCTPromiseResolveBlock)resolve
2870
+ reject:(RCTPromiseRejectBlock)reject) {
2871
+ dispatch_async(dispatch_get_main_queue(), ^{
2872
+ @try {
2873
+ NSString *cleanPath = filePath;
2874
+ if ([cleanPath hasPrefix:@"file://"]) {
2875
+ cleanPath = [cleanPath substringFromIndex:7];
2876
+ }
2877
+ cleanPath = [cleanPath stringByRemovingPercentEncoding];
2878
+ if (![[NSFileManager defaultManager] fileExistsAtPath:cleanPath]) {
2879
+ reject(@"FILE_NOT_FOUND", @"File not found", nil);
2880
+ return;
2881
+ }
2882
+ NSURL *fileUrl = [NSURL fileURLWithPath:cleanPath];
2883
+ UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[fileUrl] applicationActivities:nil];
2884
+ if (title && title.length > 0) {
2885
+ [activityVC setValue:title forKey:@"subject"];
2886
+ }
2887
+ UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
2888
+ while (rootVC.presentedViewController) {
2889
+ rootVC = rootVC.presentedViewController;
2890
+ }
2891
+ if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
2892
+ activityVC.popoverPresentationController.sourceView = rootVC.view;
2893
+ activityVC.popoverPresentationController.sourceRect = CGRectMake(rootVC.view.bounds.size.width / 2.0, rootVC.view.bounds.size.height / 2.0, 1, 1);
2894
+ }
2895
+ activityVC.completionWithItemsHandler = ^(UIActivityType activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
2896
+ resolve(@(completed));
2897
+ };
2898
+ [rootVC presentViewController:activityVC animated:YES completion:nil];
2899
+ } @catch (NSException *e) {
2900
+ reject(@"SHARE_ERROR", e.reason, nil);
2901
+ }
2902
+ });
2903
+ }
2606
2904
 
2607
2905
  #ifdef RCT_NEW_ARCH_ENABLED
2608
2906
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-inapp-inspector",
3
- "version": "2.5.12",
3
+ "version": "2.5.13",
4
4
  "description": "The zero-config, all-in-one in-app debugger & network logger for React Native & Expo (Flipper / Chucker alternative). Inspect Network (fetch/Axios/GraphQL), Console logs with Metro Symbolication, Redux State, Firebase Analytics, Storage (AsyncStorage/MMKV), Hardware Telemetry, and JS Bundle size directly on device.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -741,4 +741,41 @@ export const pickNativeMedia = async (
741
741
  }
742
742
  };
743
743
 
744
+ /**
745
+ * Writes an exported string file to the app's captures/cache directory and returns the absolute file URI.
746
+ */
747
+ export const writeNativeExportFile = async (
748
+ filename: string,
749
+ content: string,
750
+ ): Promise<string | null> => {
751
+ if (!NativeModule || !NativeModule.writeExportFile) {
752
+ return null;
753
+ }
754
+ try {
755
+ const uri = await NativeModule.writeExportFile(filename, content);
756
+ return uri;
757
+ } catch {
758
+ return null;
759
+ }
760
+ };
761
+
762
+ /**
763
+ * Opens native OS share sheet for a file at filePath.
764
+ */
765
+ export const shareNativeFile = async (
766
+ filePath: string,
767
+ mimeType: string = 'text/plain',
768
+ title: string = 'Export',
769
+ ): Promise<boolean> => {
770
+ if (!NativeModule || !NativeModule.shareFile) {
771
+ return false;
772
+ }
773
+ try {
774
+ const success = await NativeModule.shareFile(filePath, mimeType, title);
775
+ return Boolean(success);
776
+ } catch {
777
+ return false;
778
+ }
779
+ };
780
+
744
781
 
@@ -31,6 +31,8 @@ export interface Spec extends TurboModule {
31
31
  trimVideo(options: Object): Promise<Object>;
32
32
  generateFilmstrip(options: Object): Promise<Object>;
33
33
  pickMedia(options: Object): Promise<Object | null>;
34
+ writeExportFile(filename: string, content: string): Promise<string>;
35
+ shareFile(filePath: string, mimeType: string, title: string): Promise<boolean>;
34
36
  addListener(eventName: string): void;
35
37
  removeListeners(count: number): void;
36
38
  }