react-native-inapp-inspector 1.0.3 → 1.0.5

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 (47) hide show
  1. package/README.md +3 -3
  2. package/dist/commonjs/components/AnalyticsEventCard.js +10 -10
  3. package/dist/commonjs/components/CodeSnippet.js +233 -10
  4. package/dist/commonjs/components/ConsoleLogCard.js +55 -9
  5. package/dist/commonjs/components/CopyButton.js +2 -1
  6. package/dist/commonjs/components/ErrorBoundary.d.ts +20 -0
  7. package/dist/commonjs/components/ErrorBoundary.js +332 -0
  8. package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
  9. package/dist/commonjs/components/NetworkIcons.js +45 -1
  10. package/dist/commonjs/customHooks/reduxLogger.d.ts +4 -0
  11. package/dist/commonjs/customHooks/reduxLogger.js +30 -0
  12. package/dist/commonjs/customHooks/webViewLogger.d.ts +2 -0
  13. package/dist/commonjs/customHooks/webViewLogger.js +281 -246
  14. package/dist/commonjs/helpers/index.js +2 -1
  15. package/dist/commonjs/index.d.ts +5 -3
  16. package/dist/commonjs/index.js +685 -911
  17. package/dist/commonjs/styles/AppColors.d.ts +29 -1
  18. package/dist/commonjs/styles/AppColors.js +38 -2
  19. package/dist/commonjs/styles/index.d.ts +438 -229
  20. package/dist/commonjs/styles/index.js +448 -209
  21. package/dist/commonjs/types/index.d.ts +2 -2
  22. package/dist/esm/components/AnalyticsEventCard.js +10 -10
  23. package/dist/esm/components/CodeSnippet.js +232 -12
  24. package/dist/esm/components/ConsoleLogCard.js +55 -9
  25. package/dist/esm/components/CopyButton.js +2 -1
  26. package/dist/esm/components/ErrorBoundary.d.ts +20 -0
  27. package/dist/esm/components/ErrorBoundary.js +295 -0
  28. package/dist/esm/components/NetworkIcons.d.ts +5 -0
  29. package/dist/esm/components/NetworkIcons.js +39 -0
  30. package/dist/esm/customHooks/reduxLogger.d.ts +4 -0
  31. package/dist/esm/customHooks/reduxLogger.js +23 -0
  32. package/dist/esm/customHooks/webViewLogger.d.ts +2 -0
  33. package/dist/esm/customHooks/webViewLogger.js +281 -246
  34. package/dist/esm/helpers/index.js +2 -1
  35. package/dist/esm/index.d.ts +5 -3
  36. package/dist/esm/index.js +683 -914
  37. package/dist/esm/styles/AppColors.d.ts +29 -1
  38. package/dist/esm/styles/AppColors.js +35 -1
  39. package/dist/esm/styles/index.d.ts +438 -229
  40. package/dist/esm/styles/index.js +412 -209
  41. package/dist/esm/types/index.d.ts +2 -2
  42. package/example/App.tsx +351 -127
  43. package/example/ios/Podfile.lock +26 -0
  44. package/example/metro.config.js +1 -1
  45. package/example/package-lock.json +20 -4
  46. package/example/package.json +4 -3
  47. package/package.json +1 -1
package/README.md CHANGED
@@ -17,12 +17,12 @@ A premium, self-contained, and interactive in-app debugger for React Native appl
17
17
 
18
18
  ## Installation
19
19
 
20
- Install the package and its peer dependencies in your React Native project:
20
+ Install the package as a development dependency in your React Native project:
21
21
 
22
22
  ```bash
23
- npm install react-native-inapp-inspector
23
+ npm install --save-dev react-native-inapp-inspector
24
24
  # OR
25
- yarn add react-native-inapp-inspector
25
+ yarn add -D react-native-inapp-inspector
26
26
  ```
27
27
 
28
28
  ### Peer Dependencies
@@ -210,8 +210,8 @@ const AnalyticsEventCard = react_1.default.memo(function AnalyticsEventCard({ ev
210
210
  // ─── Styles ───────────────────────────────────────────────────────────────────
211
211
  const cardStyles = react_native_1.StyleSheet.create({
212
212
  container: {
213
- paddingHorizontal: 16,
214
- paddingVertical: 4,
213
+ paddingHorizontal: 12,
214
+ paddingVertical: 3,
215
215
  },
216
216
  gapContainer: {
217
217
  alignItems: 'center',
@@ -228,7 +228,7 @@ const cardStyles = react_native_1.StyleSheet.create({
228
228
  borderRadius: 8,
229
229
  borderWidth: 1,
230
230
  borderColor: '#EFEFEF',
231
- padding: 12,
231
+ padding: 8,
232
232
  shadowColor: '#000',
233
233
  shadowOpacity: 0.03,
234
234
  shadowRadius: 3,
@@ -240,11 +240,11 @@ const cardStyles = react_native_1.StyleSheet.create({
240
240
  flexDirection: 'row',
241
241
  justifyContent: 'space-between',
242
242
  alignItems: 'center',
243
- marginBottom: 8,
243
+ marginBottom: 6,
244
244
  },
245
245
  nameBadge: {
246
- paddingHorizontal: 8,
247
- paddingVertical: 4,
246
+ paddingHorizontal: 6,
247
+ paddingVertical: 2.5,
248
248
  borderRadius: 6,
249
249
  borderWidth: 1,
250
250
  },
@@ -279,8 +279,8 @@ const cardStyles = react_native_1.StyleSheet.create({
279
279
  flexDirection: 'row',
280
280
  alignItems: 'center',
281
281
  backgroundColor: AppColors_1.AppColors.grayBackground,
282
- paddingHorizontal: 6,
283
- paddingVertical: 3,
282
+ paddingHorizontal: 5,
283
+ paddingVertical: 2,
284
284
  borderRadius: 4,
285
285
  borderWidth: 1,
286
286
  borderColor: AppColors_1.AppColors.grayBorderSecondary,
@@ -300,8 +300,8 @@ const cardStyles = react_native_1.StyleSheet.create({
300
300
  backgroundColor: '#FFE4E6',
301
301
  borderColor: '#FCC2D7',
302
302
  borderWidth: 1,
303
- paddingHorizontal: 6,
304
- paddingVertical: 3,
303
+ paddingHorizontal: 5,
304
+ paddingVertical: 2,
305
305
  borderRadius: 4,
306
306
  },
307
307
  duplicateText: {
@@ -32,9 +32,18 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
35
38
  Object.defineProperty(exports, "__esModule", { value: true });
36
39
  const react_1 = __importStar(require("react"));
37
40
  const react_native_1 = require("react-native");
41
+ const react_native_svg_1 = __importStar(require("react-native-svg"));
42
+ const NetworkIcons_1 = require("./NetworkIcons");
43
+ const CopyButton_1 = __importDefault(require("./CopyButton"));
44
+ const TouchableScale_1 = __importDefault(require("./TouchableScale"));
45
+ const AppColors_1 = require("../styles/AppColors");
46
+ const AppFonts_1 = require("../styles/AppFonts");
38
47
  const escapeRegExp = (string) => {
39
48
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
40
49
  };
@@ -135,7 +144,7 @@ const formatJS = (js) => {
135
144
  };
136
145
  const tokenizeJS = (text) => {
137
146
  const tokens = [];
138
- const regex = /(\/\/.*|\/\*[\s\S]*?\*\/)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)|(\b(?:const|let|var|function|return|if|else|for|while|import|export|class|try|catch|new|this|async|await|break|continue|switch|case|default|throw|typeof|yield|let)\b)|(\b(?:console|window|document|fetch|global|require|module|exports|Promise|Map|Set|Array|Object|String|Number|Boolean)\b)|(\b\d+(?:\.\d+)?\b)/g;
147
+ const regex = /(\/\/.*|\/\*[\s\S]*?\*\/)|(\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\'|\`(?:\\.|[^\`\\])*\`)|(\b(const|let|var|function|return|if|else|for|while|import|export|class|try|catch|new|this|async|await|break|continue|switch|case|default|throw|typeof|yield)\b)|(\b(console|window|document|fetch|global|require|module|exports|Promise|Map|Set|Array|Object|String|Number|Boolean)\b)|(\b\d+(?:\.\d+)?\b)/g;
139
148
  let lastIndex = 0;
140
149
  let match;
141
150
  while ((match = regex.exec(text)) !== null) {
@@ -201,7 +210,7 @@ const tokenizeCSS = (text) => {
201
210
  };
202
211
  const tokenizeHTML = (text) => {
203
212
  const tokens = [];
204
- const regex = /(<!--[\s\S]*?-->)|(<\/?[a-zA-Z0-9:-]+>?)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')|([a-zA-Z0-9:-]+(?=\s*=))/g;
213
+ const regex = /(<!--[\s\S]*?-->)|(<\/?[a-zA-Z0-9:-]+>?)|(\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\')|([a-zA-Z0-9:-]+(?=\s*=))/g;
205
214
  let lastIndex = 0;
206
215
  let match;
207
216
  while ((match = regex.exec(text)) !== null) {
@@ -256,7 +265,13 @@ const getStyleForType = (type) => {
256
265
  return styles.plain;
257
266
  }
258
267
  };
259
- const CodeSnippetLine = react_1.default.memo(({ line, lineIndex, language, search, }) => {
268
+ const ArrowUpIcon = ({ color = '#64748B', size = 16 }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
269
+ <react_native_svg_1.Path d="M18 15l-6-6-6 6" stroke={color} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
270
+ </react_native_svg_1.default>);
271
+ const ArrowDownIcon = ({ color = '#64748B', size = 16 }) => (<react_native_svg_1.default width={size} height={size} viewBox="0 0 24 24" fill="none">
272
+ <react_native_svg_1.Path d="M6 9l6 6 6-6" stroke={color} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
273
+ </react_native_svg_1.default>);
274
+ const CodeSnippetLine = react_1.default.memo(({ line, lineIndex, language, search, isActiveMatch, }) => {
260
275
  const tokens = (0, react_1.useMemo)(() => {
261
276
  if (language === 'html')
262
277
  return tokenizeHTML(line);
@@ -279,10 +294,10 @@ const CodeSnippetLine = react_1.default.memo(({ line, lineIndex, language, searc
279
294
  })}
280
295
  </react_native_1.Text>);
281
296
  };
282
- return (<react_native_1.View style={styles.lineRow}>
297
+ return (<react_native_1.View style={[styles.lineRow, isActiveMatch && styles.activeMatchRow]}>
283
298
  {/* Gutter Line Number */}
284
- <react_native_1.View style={styles.gutter}>
285
- <react_native_1.Text style={styles.lineNumber}>{lineIndex + 1}</react_native_1.Text>
299
+ <react_native_1.View style={[styles.gutter, isActiveMatch && styles.activeMatchGutter]}>
300
+ <react_native_1.Text style={[styles.lineNumber, isActiveMatch && styles.activeMatchLineNumber]}>{lineIndex + 1}</react_native_1.Text>
286
301
  </react_native_1.View>
287
302
 
288
303
  {/* Highlighted Code Line */}
@@ -295,10 +310,27 @@ const CodeSnippetLine = react_1.default.memo(({ line, lineIndex, language, searc
295
310
  </react_native_1.View>
296
311
  </react_native_1.View>);
297
312
  });
298
- const CodeSnippet = ({ code, language, search = '', }) => {
313
+ const CodeSnippet = ({ code, language, }) => {
314
+ const [searchQuery, setSearchQuery] = (0, react_1.useState)('');
315
+ const [debouncedQuery, setDebouncedQuery] = (0, react_1.useState)('');
316
+ const [currentMatchIdx, setCurrentMatchIdx] = (0, react_1.useState)(-1);
317
+ const [visibleLinesCount, setVisibleLinesCount] = (0, react_1.useState)(200);
318
+ const flatListRef = (0, react_1.useRef)(null);
319
+ // Debounce search query updates
320
+ (0, react_1.useEffect)(() => {
321
+ const timer = setTimeout(() => {
322
+ setDebouncedQuery(searchQuery);
323
+ }, 300);
324
+ return () => clearTimeout(timer);
325
+ }, [searchQuery]);
326
+ // If code is extremely large (e.g. > 150KB), skip the pretty printers
327
+ // to avoid blocking the single JS thread.
299
328
  const formattedCode = (0, react_1.useMemo)(() => {
300
329
  if (!code)
301
330
  return '';
331
+ if (code.length > 150000) {
332
+ return code;
333
+ }
302
334
  if (language === 'html')
303
335
  return formatHTML(code);
304
336
  if (language === 'css')
@@ -312,9 +344,135 @@ const CodeSnippet = ({ code, language, search = '', }) => {
312
344
  return [];
313
345
  return formattedCode.split(/\r?\n/);
314
346
  }, [formattedCode]);
315
- const renderLine = ({ item, index }) => (<CodeSnippetLine line={item} lineIndex={index} language={language} search={search}/>);
316
- return (<react_native_1.View style={styles.container}>
317
- <react_native_1.FlatList data={lines} renderItem={renderLine} keyExtractor={(_, index) => String(index)} maxToRenderPerBatch={50} windowSize={10} initialNumToRender={30} removeClippedSubviews={react_native_1.Platform.OS === 'android'}/>
347
+ // Find all line indices matching the search query
348
+ const matches = (0, react_1.useMemo)(() => {
349
+ if (!debouncedQuery.trim() || debouncedQuery.length < 2)
350
+ return [];
351
+ const query = debouncedQuery.toLowerCase();
352
+ const indices = [];
353
+ for (let i = 0; i < lines.length; i++) {
354
+ if (lines[i].toLowerCase().includes(query)) {
355
+ indices.push(i);
356
+ }
357
+ }
358
+ return indices;
359
+ }, [debouncedQuery, lines]);
360
+ // Reset scroll and states on code/language changes
361
+ (0, react_1.useEffect)(() => {
362
+ setVisibleLinesCount(200);
363
+ setSearchQuery('');
364
+ setCurrentMatchIdx(-1);
365
+ }, [code, language]);
366
+ // Auto-scroll to the first match when search query returns matches
367
+ (0, react_1.useEffect)(() => {
368
+ if (matches.length > 0) {
369
+ setCurrentMatchIdx(0);
370
+ scrollToMatch(0);
371
+ }
372
+ else {
373
+ setCurrentMatchIdx(-1);
374
+ }
375
+ }, [matches]);
376
+ const scrollToMatch = (matchIdx) => {
377
+ if (matches.length === 0 || matchIdx < 0 || matchIdx >= matches.length)
378
+ return;
379
+ const lineIdx = matches[matchIdx];
380
+ // Ensure the targeted index is loaded in FlatList
381
+ if (lineIdx >= visibleLinesCount) {
382
+ setVisibleLinesCount(lineIdx + 100);
383
+ }
384
+ // Schedule scroll after state has applied
385
+ setTimeout(() => {
386
+ try {
387
+ flatListRef.current?.scrollToIndex({
388
+ index: lineIdx,
389
+ animated: true,
390
+ viewPosition: 0.5,
391
+ });
392
+ }
393
+ catch (e) {
394
+ // Fallback recovery is handled by onScrollToIndexFailed
395
+ }
396
+ }, 100);
397
+ };
398
+ const onScrollToIndexFailed = (error) => {
399
+ flatListRef.current?.scrollToOffset({
400
+ offset: error.averageItemLength * error.index,
401
+ animated: true,
402
+ });
403
+ setTimeout(() => {
404
+ try {
405
+ flatListRef.current?.scrollToIndex({
406
+ index: error.index,
407
+ animated: true,
408
+ viewPosition: 0.5,
409
+ });
410
+ }
411
+ catch (err) {
412
+ console.warn('Scroll to line index failed after fallback retry:', err);
413
+ }
414
+ }, 120);
415
+ };
416
+ const handleNextMatch = () => {
417
+ if (matches.length === 0)
418
+ return;
419
+ const nextIdx = (currentMatchIdx + 1) % matches.length;
420
+ setCurrentMatchIdx(nextIdx);
421
+ scrollToMatch(nextIdx);
422
+ };
423
+ const handlePrevMatch = () => {
424
+ if (matches.length === 0)
425
+ return;
426
+ const prevIdx = (currentMatchIdx - 1 + matches.length) % matches.length;
427
+ setCurrentMatchIdx(prevIdx);
428
+ scrollToMatch(prevIdx);
429
+ };
430
+ const visibleLines = (0, react_1.useMemo)(() => {
431
+ return lines.slice(0, visibleLinesCount);
432
+ }, [lines, visibleLinesCount]);
433
+ const handleEndReached = () => {
434
+ if (visibleLinesCount < lines.length) {
435
+ setVisibleLinesCount(prev => Math.min(prev + 150, lines.length));
436
+ }
437
+ };
438
+ const renderLine = ({ item, index }) => {
439
+ const isActiveMatch = matches.length > 0 && currentMatchIdx >= 0 && index === matches[currentMatchIdx];
440
+ return (<CodeSnippetLine line={item} lineIndex={index} language={language} search={debouncedQuery} isActiveMatch={isActiveMatch}/>);
441
+ };
442
+ return (<react_native_1.View style={{ flex: 1 }}>
443
+ {/* Search Header Row */}
444
+ <react_native_1.View style={styles.searchRow}>
445
+ <react_native_1.View style={styles.searchBar}>
446
+ <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={15}/>
447
+ <react_native_1.TextInput placeholder={`Search ${language.toUpperCase()}...`} placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={searchQuery} onChangeText={setSearchQuery} style={styles.searchInput} autoCorrect={false} autoCapitalize="none"/>
448
+
449
+ {/* Matches Info */}
450
+ {debouncedQuery.length >= 2 && (<react_native_1.Text style={styles.matchCountText}>
451
+ {matches.length > 0 ? `${currentMatchIdx + 1}/${matches.length}` : '0/0'}
452
+ </react_native_1.Text>)}
453
+
454
+ {searchQuery.length > 0 && (<react_native_1.Pressable onPress={() => setSearchQuery('')} hitSlop={8} style={styles.clearBtn}>
455
+ <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={12}/>
456
+ </react_native_1.Pressable>)}
457
+ </react_native_1.View>
458
+
459
+ {/* Up / Down Arrow Navigation Buttons */}
460
+ {matches.length > 0 && (<react_native_1.View style={styles.navArrowsGroup}>
461
+ <TouchableScale_1.default onPress={handlePrevMatch} hitSlop={8} style={styles.navArrowBtn}>
462
+ <ArrowUpIcon color="#475569" size={14}/>
463
+ </TouchableScale_1.default>
464
+ <TouchableScale_1.default onPress={handleNextMatch} hitSlop={8} style={styles.navArrowBtn}>
465
+ <ArrowDownIcon color="#475569" size={14}/>
466
+ </TouchableScale_1.default>
467
+ </react_native_1.View>)}
468
+
469
+ <CopyButton_1.default value={code} label={`${language.toUpperCase()} Source`}/>
470
+ </react_native_1.View>
471
+
472
+ {/* Code Snippet list container */}
473
+ <react_native_1.View style={styles.container}>
474
+ <react_native_1.FlatList ref={flatListRef} data={visibleLines} renderItem={renderLine} keyExtractor={(_, index) => String(index)} maxToRenderPerBatch={30} windowSize={5} initialNumToRender={50} removeClippedSubviews={react_native_1.Platform.OS === 'android'} onEndReached={handleEndReached} onEndReachedThreshold={0.5} onScrollToIndexFailed={onScrollToIndexFailed}/>
475
+ </react_native_1.View>
318
476
  </react_native_1.View>);
319
477
  };
320
478
  const monoFont = react_native_1.Platform.OS === 'ios' ? 'Menlo' : 'monospace';
@@ -327,12 +485,69 @@ const styles = react_native_1.StyleSheet.create({
327
485
  borderColor: '#E2E8F0',
328
486
  overflow: 'hidden',
329
487
  },
488
+ searchRow: {
489
+ flexDirection: 'row',
490
+ alignItems: 'center',
491
+ marginBottom: 6,
492
+ gap: 8,
493
+ },
494
+ searchBar: {
495
+ flex: 1,
496
+ flexDirection: 'row',
497
+ alignItems: 'center',
498
+ backgroundColor: '#FFFFFF',
499
+ borderRadius: 8,
500
+ borderWidth: 1,
501
+ borderColor: '#E2E8F0',
502
+ paddingHorizontal: 8,
503
+ height: 32,
504
+ },
505
+ searchInput: {
506
+ flex: 1,
507
+ fontFamily: AppFonts_1.AppFonts.interRegular,
508
+ fontSize: 12,
509
+ color: '#0F172A',
510
+ marginLeft: 6,
511
+ paddingVertical: 0,
512
+ },
513
+ matchCountText: {
514
+ fontFamily: AppFonts_1.AppFonts.interMedium,
515
+ fontSize: 10,
516
+ color: '#64748B',
517
+ marginHorizontal: 6,
518
+ backgroundColor: '#F1F5F9',
519
+ paddingHorizontal: 6,
520
+ paddingVertical: 2,
521
+ borderRadius: 4,
522
+ },
523
+ clearBtn: {
524
+ padding: 4,
525
+ },
526
+ navArrowsGroup: {
527
+ flexDirection: 'row',
528
+ alignItems: 'center',
529
+ backgroundColor: '#FFFFFF',
530
+ borderRadius: 8,
531
+ borderWidth: 1,
532
+ borderColor: '#E2E8F0',
533
+ height: 32,
534
+ paddingHorizontal: 2,
535
+ },
536
+ navArrowBtn: {
537
+ padding: 5,
538
+ borderRadius: 6,
539
+ alignItems: 'center',
540
+ justifyContent: 'center',
541
+ },
330
542
  lineRow: {
331
543
  flexDirection: 'row',
332
544
  alignItems: 'stretch',
333
545
  minHeight: 20,
334
546
  paddingVertical: 1,
335
547
  },
548
+ activeMatchRow: {
549
+ backgroundColor: 'rgba(234, 179, 8, 0.15)',
550
+ },
336
551
  gutter: {
337
552
  width: 40,
338
553
  backgroundColor: '#F1F5F9',
@@ -343,11 +558,19 @@ const styles = react_native_1.StyleSheet.create({
343
558
  paddingRight: 6,
344
559
  paddingTop: 1,
345
560
  },
561
+ activeMatchGutter: {
562
+ backgroundColor: 'rgba(234, 179, 8, 0.25)',
563
+ borderRightColor: 'rgba(234, 179, 8, 0.4)',
564
+ },
346
565
  lineNumber: {
347
566
  fontFamily: monoFont,
348
567
  fontSize: 9,
349
568
  color: '#94A3B8',
350
569
  },
570
+ activeMatchLineNumber: {
571
+ color: '#854D0E',
572
+ fontWeight: 'bold',
573
+ },
351
574
  codeLine: {
352
575
  flex: 1,
353
576
  paddingLeft: 10,
@@ -99,6 +99,52 @@ const getJsonPreviewText = (data) => {
99
99
  };
100
100
  }
101
101
  };
102
+ const getLogMessageWithBadges = (message, searchStr, textStyle, highlightStyle, numberOfLines) => {
103
+ if (!message)
104
+ return null;
105
+ const prefixRegex = /^((?:\[[^\]]+\]\s*)+)/;
106
+ const match = message.match(prefixRegex);
107
+ if (match) {
108
+ const fullPrefix = match[1];
109
+ const remainingText = message.substring(fullPrefix.length);
110
+ const tags = fullPrefix.match(/\[[^\]]+\]/g) || [];
111
+ const getTagColor = (tag) => {
112
+ const cleanTag = tag.replace(/[\[\]]/g, '').trim().toUpperCase();
113
+ if (cleanTag === 'API')
114
+ return '#0284C7';
115
+ if (cleanTag === 'TEST')
116
+ return '#16A34A';
117
+ if (cleanTag === 'APP')
118
+ return '#4F46E5';
119
+ if (cleanTag === 'DETAILS')
120
+ return '#7C3AED';
121
+ if (cleanTag === 'WEBVIEW')
122
+ return '#EA580C';
123
+ if (cleanTag === 'MOCK REDUX' || cleanTag === 'REDUX')
124
+ return '#DB2777';
125
+ let hash = 0;
126
+ for (let i = 0; i < cleanTag.length; i++) {
127
+ hash = cleanTag.charCodeAt(i) + ((hash << 5) - hash);
128
+ }
129
+ const colors = ['#0891B2', '#0D9488', '#2563EB', '#D97706', '#E11D48', '#8B5CF6'];
130
+ return colors[Math.abs(hash) % colors.length];
131
+ };
132
+ return (<react_native_1.Text style={textStyle} numberOfLines={numberOfLines}>
133
+ {tags.map((tag, idx) => {
134
+ const color = getTagColor(tag);
135
+ return (<react_native_1.Text key={idx} style={{
136
+ fontWeight: 'bold',
137
+ color: color,
138
+ fontFamily: AppFonts_1.AppFonts.interBold,
139
+ }}>
140
+ {tag}{' '}
141
+ </react_native_1.Text>);
142
+ })}
143
+ <HighlightText_1.default text={remainingText} search={searchStr} style={textStyle} highlightStyle={highlightStyle} detectLinks={true}/>
144
+ </react_native_1.Text>);
145
+ }
146
+ return (<HighlightText_1.default text={message} search={searchStr} style={textStyle} highlightStyle={highlightStyle} numberOfLines={numberOfLines} detectLinks={true}/>);
147
+ };
102
148
  exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, searchStr = '', isWebView = false, }) {
103
149
  const [expanded, setExpanded] = (0, react_1.useState)(false);
104
150
  const jsonContent = getJsonContent(item.message);
@@ -255,7 +301,7 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
255
301
  <react_native_1.View style={styles.cardBody}>
256
302
  {jsonContent ? (<>
257
303
  {jsonContent.header ? (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)}>
258
- <HighlightText_1.default text={jsonContent.header} search={searchStr} style={styles.messageText} highlightStyle={styles.highlight} numberOfLines={numLines} detectLinks={true}/>
304
+ {getLogMessageWithBadges(jsonContent.header, searchStr, styles.messageText, styles.highlight, numLines)}
259
305
  </react_native_1.Pressable>) : null}
260
306
  {expanded ? (<react_native_1.View style={styles.jsonContainer}>
261
307
  <JsonViewer_1.default data={jsonContent.data} search={searchStr} forceOpen={expanded}/>
@@ -263,7 +309,7 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
263
309
  <HighlightText_1.default text={getJsonPreviewText(jsonContent.data).text} search={searchStr} style={styles.jsonPreviewText} highlightStyle={styles.highlight} detectLinks={true}/>
264
310
  </react_native_1.Pressable>)}
265
311
  </>) : (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)}>
266
- <HighlightText_1.default text={item.message} search={searchStr} style={styles.messageText} highlightStyle={styles.highlight} numberOfLines={numLines} detectLinks={true}/>
312
+ {getLogMessageWithBadges(item.message, searchStr, styles.messageText, styles.highlight, numLines)}
267
313
  </react_native_1.Pressable>)}
268
314
  {hasLongMessage && (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)} style={styles.seeMoreBtn} hitSlop={8}>
269
315
  <react_native_1.Text style={styles.seeMoreText}>
@@ -280,8 +326,8 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
280
326
  });
281
327
  const styles = react_native_1.StyleSheet.create({
282
328
  container: {
283
- paddingHorizontal: 16,
284
- paddingVertical: 4,
329
+ paddingHorizontal: 12,
330
+ paddingVertical: 3,
285
331
  },
286
332
  card: {
287
333
  alignSelf: 'stretch',
@@ -289,7 +335,7 @@ const styles = react_native_1.StyleSheet.create({
289
335
  borderRadius: 8,
290
336
  borderWidth: 1,
291
337
  borderColor: '#EFEFEF',
292
- padding: 12,
338
+ padding: 8,
293
339
  shadowColor: '#000',
294
340
  shadowOpacity: 0.03,
295
341
  shadowRadius: 3,
@@ -302,7 +348,7 @@ const styles = react_native_1.StyleSheet.create({
302
348
  flexDirection: 'row',
303
349
  justifyContent: 'space-between',
304
350
  alignItems: 'center',
305
- marginBottom: 8,
351
+ marginBottom: 6,
306
352
  },
307
353
  headerLeft: {
308
354
  flexDirection: 'row',
@@ -336,10 +382,10 @@ const styles = react_native_1.StyleSheet.create({
336
382
  maxWidth: '50%',
337
383
  },
338
384
  cardBody: {
339
- marginTop: 8,
385
+ marginTop: 6,
340
386
  backgroundColor: '#FFFFFF',
341
- paddingHorizontal: 10,
342
- paddingVertical: 8,
387
+ paddingHorizontal: 8,
388
+ paddingVertical: 5,
343
389
  borderRadius: 6,
344
390
  borderWidth: 1,
345
391
  borderColor: '#EBECEF',
@@ -49,7 +49,8 @@ const styles_1 = __importDefault(require("../styles"));
49
49
  const CopyButton = ({ value, label, iconType = 'copy' }) => {
50
50
  const [copied, setCopied] = (0, react_1.useState)(false);
51
51
  const handlePress = () => {
52
- (0, helpers_1.copyToClipboard)(value, label);
52
+ const resolvedValue = typeof value === 'function' ? value() : value;
53
+ (0, helpers_1.copyToClipboard)(resolvedValue, label);
53
54
  setCopied(true);
54
55
  setTimeout(() => setCopied(false), 1200);
55
56
  };
@@ -0,0 +1,20 @@
1
+ import React, { Component, ErrorInfo, ReactNode } from 'react';
2
+ interface Props {
3
+ children: ReactNode;
4
+ onClose?: () => void;
5
+ onReset?: () => void;
6
+ fallbackType?: 'modal' | 'inline';
7
+ }
8
+ interface State {
9
+ hasError: boolean;
10
+ error: Error | null;
11
+ }
12
+ export declare class ErrorBoundary extends Component<Props, State> {
13
+ state: State;
14
+ static getDerivedStateFromError(error: Error): State;
15
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
16
+ private handleReset;
17
+ private handleCopyTrace;
18
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode>> | React.JSX.Element;
19
+ }
20
+ export default ErrorBoundary;