react-native-inapp-inspector 1.0.8 → 1.0.10

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 (52) hide show
  1. package/README.md +5 -6
  2. package/assets/social_preview.png +0 -0
  3. package/dist/commonjs/components/AnalyticsDetail.js +28 -23
  4. package/dist/commonjs/components/AnalyticsEventCard.js +9 -9
  5. package/dist/commonjs/components/BrandCircleIcon.d.ts +5 -0
  6. package/dist/commonjs/components/BrandCircleIcon.js +180 -0
  7. package/dist/commonjs/components/BrandSquareIcon.d.ts +5 -0
  8. package/dist/commonjs/components/BrandSquareIcon.js +180 -0
  9. package/dist/commonjs/components/CodeSnippet.js +32 -24
  10. package/dist/commonjs/components/ConsoleLogCard.js +127 -70
  11. package/dist/commonjs/components/JsonViewer.d.ts +2 -1
  12. package/dist/commonjs/components/JsonViewer.js +2 -2
  13. package/dist/commonjs/components/MetaAccordion.d.ts +1 -1
  14. package/dist/commonjs/components/MetaAccordion.js +45 -2
  15. package/dist/commonjs/components/NetworkIcons.d.ts +8 -0
  16. package/dist/commonjs/components/NetworkIcons.js +44 -1
  17. package/dist/commonjs/components/ReduxTreeView.d.ts +6 -0
  18. package/dist/commonjs/components/ReduxTreeView.js +403 -0
  19. package/dist/commonjs/components/TouchableScale.js +15 -1
  20. package/dist/commonjs/components/TreeNode.js +3 -3
  21. package/dist/commonjs/customHooks/reduxLogger.d.ts +4 -0
  22. package/dist/commonjs/customHooks/reduxLogger.js +48 -2
  23. package/dist/commonjs/index.js +1520 -506
  24. package/dist/commonjs/styles/index.d.ts +11 -1
  25. package/dist/commonjs/styles/index.js +19 -9
  26. package/dist/commonjs/types/index.d.ts +4 -0
  27. package/dist/esm/components/AnalyticsDetail.js +28 -23
  28. package/dist/esm/components/AnalyticsEventCard.js +9 -9
  29. package/dist/esm/components/BrandCircleIcon.d.ts +5 -0
  30. package/dist/esm/components/BrandCircleIcon.js +140 -0
  31. package/dist/esm/components/BrandSquareIcon.d.ts +5 -0
  32. package/dist/esm/components/BrandSquareIcon.js +140 -0
  33. package/dist/esm/components/CodeSnippet.js +32 -24
  34. package/dist/esm/components/ConsoleLogCard.js +127 -70
  35. package/dist/esm/components/JsonViewer.d.ts +2 -1
  36. package/dist/esm/components/JsonViewer.js +2 -2
  37. package/dist/esm/components/MetaAccordion.d.ts +1 -1
  38. package/dist/esm/components/MetaAccordion.js +46 -3
  39. package/dist/esm/components/NetworkIcons.d.ts +8 -0
  40. package/dist/esm/components/NetworkIcons.js +35 -0
  41. package/dist/esm/components/ReduxTreeView.d.ts +6 -0
  42. package/dist/esm/components/ReduxTreeView.js +366 -0
  43. package/dist/esm/components/TouchableScale.js +16 -2
  44. package/dist/esm/components/TreeNode.js +3 -3
  45. package/dist/esm/customHooks/reduxLogger.d.ts +4 -0
  46. package/dist/esm/customHooks/reduxLogger.js +43 -1
  47. package/dist/esm/index.js +1523 -509
  48. package/dist/esm/styles/index.d.ts +11 -1
  49. package/dist/esm/styles/index.js +19 -9
  50. package/dist/esm/types/index.d.ts +4 -0
  51. package/example/App.tsx +46 -0
  52. package/package.json +7 -5
@@ -224,7 +224,7 @@ const getStyleForType = (type) => {
224
224
  case 'value':
225
225
  return styles.value;
226
226
  default:
227
- return styles.plain;
227
+ return [styles.plain, { color: AppColors.primaryBlack }];
228
228
  }
229
229
  };
230
230
  const ArrowUpIcon = ({ color = '#64748B', size = 16 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
@@ -258,26 +258,32 @@ const CodeSnippetLine = React.memo(({ line, lineIndex, language, search, isActiv
258
258
  };
259
259
  return (<View style={[styles.lineRow, isActiveMatch && styles.activeMatchRow]}>
260
260
  {/* Gutter Line Number */}
261
- <View style={[styles.gutter, isActiveMatch && styles.activeMatchGutter]}>
262
- <Text style={[styles.lineNumber, isActiveMatch && styles.activeMatchLineNumber]}>{lineIndex + 1}</Text>
261
+ <View style={[styles.gutter, { backgroundColor: AppColors.grayBackground, borderRightColor: AppColors.grayBorderSecondary }, isActiveMatch && styles.activeMatchGutter]}>
262
+ <Text style={[styles.lineNumber, { color: AppColors.grayTextWeak }, isActiveMatch && styles.activeMatchLineNumber]}>{lineIndex + 1}</Text>
263
263
  </View>
264
264
 
265
265
  {/* Highlighted Code Line */}
266
266
  <View style={styles.codeLine}>
267
- <Text style={styles.codeLineText}>
268
- {tokens.length === 0 ? (<Text style={styles.plain}> </Text>) : (tokens.map((token, tokenIdx) => (<React.Fragment key={tokenIdx}>
267
+ <Text style={[styles.codeLineText, { color: AppColors.primaryBlack }]}>
268
+ {tokens.length === 0 ? (<Text style={[styles.plain, { color: AppColors.primaryBlack }]}> </Text>) : (tokens.map((token, tokenIdx) => (<React.Fragment key={tokenIdx}>
269
269
  {renderTokenText(token.text, token.type)}
270
270
  </React.Fragment>)))}
271
271
  </Text>
272
272
  </View>
273
273
  </View>);
274
274
  });
275
- const CodeSnippet = ({ code, language, }) => {
275
+ const CodeSnippet = ({ code, language, search, }) => {
276
276
  const [searchQuery, setSearchQuery] = useState('');
277
277
  const [debouncedQuery, setDebouncedQuery] = useState('');
278
278
  const [currentMatchIdx, setCurrentMatchIdx] = useState(-1);
279
279
  const [visibleLinesCount, setVisibleLinesCount] = useState(200);
280
280
  const flatListRef = useRef(null);
281
+ // Sync prop search to searchQuery
282
+ useEffect(() => {
283
+ if (search !== undefined) {
284
+ setSearchQuery(search);
285
+ }
286
+ }, [search]);
281
287
  // Debounce search query updates
282
288
  useEffect(() => {
283
289
  const timer = setTimeout(() => {
@@ -322,7 +328,7 @@ const CodeSnippet = ({ code, language, }) => {
322
328
  // Reset scroll and states on code/language changes
323
329
  useEffect(() => {
324
330
  setVisibleLinesCount(200);
325
- setSearchQuery('');
331
+ setSearchQuery(search || '');
326
332
  setCurrentMatchIdx(-1);
327
333
  }, [code, language]);
328
334
  // Auto-scroll to the first match when search query returns matches
@@ -348,32 +354,32 @@ const CodeSnippet = ({ code, language, }) => {
348
354
  try {
349
355
  flatListRef.current?.scrollToIndex({
350
356
  index: lineIdx,
351
- animated: true,
352
- viewPosition: 0.5,
357
+ animated: false,
358
+ viewPosition: 0.3,
353
359
  });
354
360
  }
355
361
  catch (e) {
356
362
  // Fallback recovery is handled by onScrollToIndexFailed
357
363
  }
358
- }, 100);
364
+ }, 50);
359
365
  };
360
366
  const onScrollToIndexFailed = (error) => {
361
367
  flatListRef.current?.scrollToOffset({
362
368
  offset: error.averageItemLength * error.index,
363
- animated: true,
369
+ animated: false,
364
370
  });
365
371
  setTimeout(() => {
366
372
  try {
367
373
  flatListRef.current?.scrollToIndex({
368
374
  index: error.index,
369
- animated: true,
370
- viewPosition: 0.5,
375
+ animated: false,
376
+ viewPosition: 0.3,
371
377
  });
372
378
  }
373
379
  catch (err) {
374
380
  console.warn('Scroll to line index failed after fallback retry:', err);
375
381
  }
376
- }, 120);
382
+ }, 60);
377
383
  };
378
384
  const handleNextMatch = () => {
379
385
  if (matches.length === 0)
@@ -404,12 +410,12 @@ const CodeSnippet = ({ code, language, }) => {
404
410
  return (<View style={{ flex: 1 }}>
405
411
  {/* Search Header Row */}
406
412
  <View style={styles.searchRow}>
407
- <View style={styles.searchBar}>
413
+ <View style={[styles.searchBar, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
408
414
  <SearchIcon color={AppColors.grayTextWeak} size={15}/>
409
- <TextInput placeholder={`Search ${language.toUpperCase()}...`} placeholderTextColor={AppColors.grayTextWeak} value={searchQuery} onChangeText={setSearchQuery} style={styles.searchInput} autoCorrect={false} autoCapitalize="none"/>
415
+ <TextInput placeholder={`Search ${language.toUpperCase()}...`} placeholderTextColor={AppColors.grayTextWeak} value={searchQuery} onChangeText={setSearchQuery} style={[styles.searchInput, { color: AppColors.primaryBlack }]} autoCorrect={false} autoCapitalize="none"/>
410
416
 
411
417
  {/* Matches Info */}
412
- {debouncedQuery.length >= 2 && (<Text style={styles.matchCountText}>
418
+ {debouncedQuery.length >= 2 && (<Text style={[styles.matchCountText, { backgroundColor: AppColors.grayBackground, color: AppColors.grayTextWeak }]}>
413
419
  {matches.length > 0 ? `${currentMatchIdx + 1}/${matches.length}` : '0/0'}
414
420
  </Text>)}
415
421
 
@@ -419,12 +425,12 @@ const CodeSnippet = ({ code, language, }) => {
419
425
  </View>
420
426
 
421
427
  {/* Up / Down Arrow Navigation Buttons */}
422
- {matches.length > 0 && (<View style={styles.navArrowsGroup}>
428
+ {matches.length > 0 && (<View style={[styles.navArrowsGroup, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
423
429
  <TouchableScale onPress={handlePrevMatch} hitSlop={8} style={styles.navArrowBtn}>
424
- <ArrowUpIcon color="#475569" size={14}/>
430
+ <ArrowUpIcon color={AppColors.grayTextStrong} size={14}/>
425
431
  </TouchableScale>
426
432
  <TouchableScale onPress={handleNextMatch} hitSlop={8} style={styles.navArrowBtn}>
427
- <ArrowDownIcon color="#475569" size={14}/>
433
+ <ArrowDownIcon color={AppColors.grayTextStrong} size={14}/>
428
434
  </TouchableScale>
429
435
  </View>)}
430
436
 
@@ -432,7 +438,7 @@ const CodeSnippet = ({ code, language, }) => {
432
438
  </View>
433
439
 
434
440
  {/* Code Snippet list container */}
435
- <View style={styles.container}>
441
+ <View style={[styles.container, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
436
442
  <FlatList ref={flatListRef} data={visibleLines} renderItem={renderLine} keyExtractor={(_, index) => String(index)} maxToRenderPerBatch={30} windowSize={5} initialNumToRender={50} removeClippedSubviews={Platform.OS === 'android'} onEndReached={handleEndReached} onEndReachedThreshold={0.5} onScrollToIndexFailed={onScrollToIndexFailed}/>
437
443
  </View>
438
444
  </View>);
@@ -508,7 +514,9 @@ const styles = StyleSheet.create({
508
514
  paddingVertical: 1,
509
515
  },
510
516
  activeMatchRow: {
511
- backgroundColor: 'rgba(234, 179, 8, 0.15)',
517
+ backgroundColor: 'rgba(234, 179, 8, 0.22)',
518
+ borderLeftWidth: 4,
519
+ borderLeftColor: '#EAB308',
512
520
  },
513
521
  gutter: {
514
522
  width: 40,
@@ -521,8 +529,8 @@ const styles = StyleSheet.create({
521
529
  paddingTop: 1,
522
530
  },
523
531
  activeMatchGutter: {
524
- backgroundColor: 'rgba(234, 179, 8, 0.25)',
525
- borderRightColor: 'rgba(234, 179, 8, 0.4)',
532
+ backgroundColor: 'rgba(234, 179, 8, 0.35)',
533
+ borderRightColor: 'rgba(234, 179, 8, 0.5)',
526
534
  },
527
535
  lineNumber: {
528
536
  fontFamily: monoFont,
@@ -115,6 +115,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
115
115
  const isUserLog = !isWebView && item.sourceMethod === 'log';
116
116
  const caller = 'caller' in item ? item.caller : undefined;
117
117
  const getLogColors = () => {
118
+ const isDark = AppColors.primaryLight !== '#FFFFFF';
118
119
  if (isWebView) {
119
120
  const label = item.type.toUpperCase();
120
121
  switch (item.type) {
@@ -124,7 +125,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
124
125
  badgeBg: `${AppColors.errorColor}15`,
125
126
  badgeText: AppColors.errorColor,
126
127
  label,
127
- cardBg: '#FFF5F6',
128
+ cardBg: isDark ? 'rgba(239, 68, 68, 0.15)' : '#FFF5F6',
128
129
  };
129
130
  case 'warn':
130
131
  return {
@@ -132,15 +133,15 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
132
133
  badgeBg: `${AppColors.lightOrange}15`,
133
134
  badgeText: AppColors.darkOrange || AppColors.lightOrange,
134
135
  label,
135
- cardBg: '#FFFDF6',
136
+ cardBg: isDark ? 'rgba(245, 158, 11, 0.15)' : '#FFFDF6',
136
137
  };
137
138
  default:
138
139
  return {
139
140
  border: '#475569',
140
- badgeBg: '#F1F5F9',
141
- badgeText: '#475569',
141
+ badgeBg: isDark ? '#374151' : '#F1F5F9',
142
+ badgeText: isDark ? '#9CA3AF' : '#475569',
142
143
  label,
143
- cardBg: '#F8FAFC',
144
+ cardBg: isDark ? '#1E1E24' : '#F8FAFC',
144
145
  };
145
146
  }
146
147
  }
@@ -150,7 +151,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
150
151
  badgeBg: `${AppColors.skyBlue}15`,
151
152
  badgeText: AppColors.skyBlue,
152
153
  label: 'ERROR',
153
- cardBg: '#E6F2FF', // light sky blue background for analytics errors
154
+ cardBg: isDark ? 'rgba(96, 165, 250, 0.15)' : '#E6F2FF',
154
155
  };
155
156
  }
156
157
  switch (item.type) {
@@ -160,7 +161,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
160
161
  badgeBg: `${AppColors.errorColor}15`,
161
162
  badgeText: AppColors.errorColor,
162
163
  label: 'ERROR',
163
- cardBg: '#FFF5F6', // light red background
164
+ cardBg: isDark ? 'rgba(239, 68, 68, 0.15)' : '#FFF5F6',
164
165
  };
165
166
  case 'warn':
166
167
  return {
@@ -168,16 +169,16 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
168
169
  badgeBg: `${AppColors.lightOrange}15`,
169
170
  badgeText: AppColors.darkOrange || AppColors.lightOrange,
170
171
  label: 'WARN',
171
- cardBg: '#FFFDF6', // light yellow/orange background
172
+ cardBg: isDark ? 'rgba(245, 158, 11, 0.15)' : '#FFFDF6',
172
173
  };
173
174
  default:
174
175
  if (isUserLog) {
175
176
  return {
176
177
  border: '#475569',
177
- badgeBg: '#E2E8F0',
178
- badgeText: '#334155',
178
+ badgeBg: isDark ? '#374151' : '#E2E8F0',
179
+ badgeText: isDark ? '#D1D5DB' : '#334155',
179
180
  label: 'INFO',
180
- cardBg: '#F1F5F9', // slate-blue / steel-blue background for user log
181
+ cardBg: isDark ? '#1E1E24' : '#F1F5F9',
181
182
  };
182
183
  }
183
184
  return {
@@ -185,7 +186,7 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
185
186
  badgeBg: `${AppColors.purple}15`,
186
187
  badgeText: AppColors.purple,
187
188
  label: 'INFO',
188
- cardBg: '#F9F5FF', // light purple background for general info
189
+ cardBg: isDark ? 'rgba(167, 139, 250, 0.12)' : '#F9F5FF',
189
190
  };
190
191
  }
191
192
  };
@@ -204,84 +205,138 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
204
205
  borderLeftWidth: 4,
205
206
  borderLeftColor: colors.border,
206
207
  backgroundColor: colors.cardBg,
208
+ borderColor: AppColors.grayBorderSecondary,
209
+ flexDirection: 'row',
210
+ alignItems: 'center',
211
+ paddingRight: 4,
207
212
  },
208
213
  ]}>
209
- <Pressable onPress={() => setExpanded(prev => !prev)} style={styles.cardHeader}>
210
- <View style={styles.headerLeft}>
211
- <CopyButton value={item.message} label="Log message"/>
212
- <View style={[styles.badge, { backgroundColor: colors.badgeBg }]}>
213
- <Text style={[styles.badgeText, { color: colors.badgeText }]}>
214
- {colors.label}
215
- </Text>
216
- </View>
217
- {isAnalyticsError && (<View style={[
214
+
215
+ {/* Left Content Area */}
216
+ <Pressable onPress={() => setExpanded(prev => !prev)} style={{ flex: 1, paddingRight: 6 }}>
217
+
218
+ <View style={styles.cardHeader}>
219
+ <View style={styles.headerLeft}>
220
+ <CopyButton value={item.message} label="Log message"/>
221
+ <View style={[styles.badge, { backgroundColor: colors.badgeBg }]}>
222
+ <Text style={[styles.badgeText, { color: colors.badgeText }]}>
223
+ {colors.label}
224
+ </Text>
225
+ </View>
226
+ <View style={[
227
+ styles.badge,
228
+ {
229
+ backgroundColor: 'rgba(107, 78, 255, 0.08)',
230
+ borderColor: 'rgba(107, 78, 255, 0.2)',
231
+ borderWidth: 1,
232
+ },
233
+ ]}>
234
+ <Text style={[styles.badgeText, { color: '#6B4EFF' }]}>
235
+ console.{('sourceMethod' in item ? item.sourceMethod : undefined) || item.type || 'log'}
236
+ </Text>
237
+ </View>
238
+ {jsonContent && (<View style={[
239
+ styles.badge,
240
+ {
241
+ backgroundColor: 'rgba(13, 148, 136, 0.08)',
242
+ borderColor: 'rgba(13, 148, 136, 0.18)',
243
+ borderWidth: 1,
244
+ },
245
+ ]}>
246
+ <Text style={[styles.badgeText, { color: '#0D9488' }]}>
247
+ {Array.isArray(jsonContent.data) ? `Array[${jsonContent.data.length}]` : `Object{${Object.keys(jsonContent.data).length}}`}
248
+ </Text>
249
+ </View>)}
250
+ {isAnalyticsError && (<View style={[
218
251
  styles.badge,
219
252
  { backgroundColor: `${AppColors.skyBlue}15` },
220
253
  ]}>
221
- <Text style={[styles.badgeText, { color: AppColors.skyBlue }]}>
222
- Analytics
223
- </Text>
224
- </View>)}
225
- {isUserLog && (<View style={[
254
+ <Text style={[styles.badgeText, { color: AppColors.skyBlue }]}>
255
+ Analytics
256
+ </Text>
257
+ </View>)}
258
+ {isUserLog && (<View style={[
226
259
  styles.badge,
227
260
  {
228
- backgroundColor: '#F3F4F6',
229
- borderColor: '#D1D5DB',
261
+ backgroundColor: AppColors.grayBackground,
262
+ borderColor: AppColors.grayBorderSecondary,
230
263
  borderWidth: 1,
231
264
  },
232
265
  ]}>
233
- <Text style={[styles.badgeText, { color: '#4B5563' }]}>
234
- user-log
235
- </Text>
236
- </View>)}
237
- {isWebView && (<View style={[
266
+ <Text style={[styles.badgeText, { color: AppColors.grayTextStrong }]}>
267
+ user-log
268
+ </Text>
269
+ </View>)}
270
+ {isWebView && (<View style={[
238
271
  styles.badge,
239
272
  {
240
- backgroundColor: '#F1F5F9',
241
- borderColor: '#E2E8F0',
273
+ backgroundColor: AppColors.grayBackground,
274
+ borderColor: AppColors.grayBorderSecondary,
242
275
  borderWidth: 1,
243
276
  },
244
277
  ]}>
245
- <Text style={[styles.badgeText, { color: '#475569' }]}>
246
- webview
247
- </Text>
248
- </View>)}
249
- <Text style={styles.serialNumber}>#{item.id + 1}</Text>
250
- <Text style={styles.timestamp}>{formatTime(item.timestamp)}</Text>
251
- </View>
252
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
253
- {caller && caller !== 'Unknown' && (<Text style={styles.callerText} numberOfLines={1} ellipsizeMode="middle">
278
+ <Text style={[styles.badgeText, { color: AppColors.grayText }]}>
279
+ webview
280
+ </Text>
281
+ </View>)}
282
+ <Text style={[styles.serialNumber, { color: AppColors.grayTextWeak }]}>#{item.id + 1}</Text>
283
+ <Text style={[styles.timestamp, { color: AppColors.grayTextWeak }]}>{formatTime(item.timestamp)}</Text>
284
+ </View>
285
+
286
+ {caller && caller !== 'Unknown' && (<Text style={[styles.callerText, { color: AppColors.grayTextWeak, marginRight: 4 }]} numberOfLines={1} ellipsizeMode="middle">
254
287
  {caller.split('/').pop() || caller}
255
288
  </Text>)}
256
- <View style={{ transform: [{ rotate: expanded ? '180deg' : '0deg' }] }}>
257
- <ChevronIcon size={14} color={AppColors.grayTextWeak}/>
258
- </View>
259
289
  </View>
290
+
291
+ <View style={[styles.cardBody, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.dividerColor }]}>
292
+ {jsonContent ? (<>
293
+ {jsonContent.header ? (<Pressable onPress={() => setExpanded(prev => !prev)}>
294
+ {getLogMessageWithBadges(jsonContent.header, searchStr, [styles.messageText, { color: AppColors.primaryBlack }], styles.highlight, numLines)}
295
+ </Pressable>) : null}
296
+ {expanded ? (<View style={[styles.jsonContainer, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.dividerColor }]}>
297
+ <JsonViewer data={jsonContent.data} search={searchStr} forceOpen={expanded}/>
298
+ </View>) : (<Pressable onPress={() => setExpanded(prev => !prev)} style={[styles.jsonPreviewContainer, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.dividerColor }]}>
299
+ <HighlightText text={getJsonPreviewText(jsonContent.data).text} search={searchStr} style={[styles.jsonPreviewText, { color: AppColors.primaryBlack }]} highlightStyle={styles.highlight} detectLinks={true}/>
300
+ </Pressable>)}
301
+ </>) : (<Pressable onPress={() => setExpanded(prev => !prev)}>
302
+ {getLogMessageWithBadges(item.message, searchStr, [styles.messageText, { color: AppColors.primaryBlack }], styles.highlight, numLines)}
303
+ </Pressable>)}
304
+ {hasLongMessage && (<Pressable onPress={() => setExpanded(prev => !prev)} style={styles.seeMoreBtn} hitSlop={8}>
305
+ <Text style={styles.seeMoreText}>
306
+ {expanded ? 'See Less' : 'See More'}
307
+ </Text>
308
+ </Pressable>)}
309
+ </View>
310
+
311
+ {expanded && (<View style={[styles.cardFooter, { borderTopColor: AppColors.dividerColor, gap: 6 }]}>
312
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
313
+ <Text style={{ fontFamily: AppFonts.interRegular, fontSize: 10.5, color: AppColors.grayTextWeak }}>
314
+ Length: {item.message.length} chars • Size: {encodeURIComponent(item.message).replace(/%[0-9A-F]{2}/g, 'a').length} bytes
315
+ </Text>
316
+ </View>
317
+ {caller && caller !== 'Unknown' && (<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 }}>
318
+ <Text style={[styles.fullCallerText, { color: AppColors.grayText, flex: 1, marginRight: 8 }]} numberOfLines={2}>
319
+ Caller: {caller}
320
+ </Text>
321
+ <CopyButton value={caller} label="Caller stack frame"/>
322
+ </View>)}
323
+ </View>)}
260
324
  </Pressable>
261
325
 
262
- <View style={styles.cardBody}>
263
- {jsonContent ? (<>
264
- {jsonContent.header ? (<Pressable onPress={() => setExpanded(prev => !prev)}>
265
- {getLogMessageWithBadges(jsonContent.header, searchStr, styles.messageText, styles.highlight, numLines)}
266
- </Pressable>) : null}
267
- {expanded ? (<View style={styles.jsonContainer}>
268
- <JsonViewer data={jsonContent.data} search={searchStr} forceOpen={expanded}/>
269
- </View>) : (<Pressable onPress={() => setExpanded(prev => !prev)} style={styles.jsonPreviewContainer}>
270
- <HighlightText text={getJsonPreviewText(jsonContent.data).text} search={searchStr} style={styles.jsonPreviewText} highlightStyle={styles.highlight} detectLinks={true}/>
271
- </Pressable>)}
272
- </>) : (<Pressable onPress={() => setExpanded(prev => !prev)}>
273
- {getLogMessageWithBadges(item.message, searchStr, styles.messageText, styles.highlight, numLines)}
274
- </Pressable>)}
275
- {hasLongMessage && (<Pressable onPress={() => setExpanded(prev => !prev)} style={styles.seeMoreBtn} hitSlop={8}>
276
- <Text style={styles.seeMoreText}>
277
- {expanded ? 'See Less' : 'See More'}
278
- </Text>
279
- </Pressable>)}
280
- </View>
326
+ {/* Right Isolated Chevron Area */}
327
+ <Pressable onPress={() => setExpanded(prev => !prev)} style={{
328
+ width: 28,
329
+ alignItems: 'center',
330
+ justifyContent: 'center',
331
+ alignSelf: expanded ? 'flex-start' : 'center',
332
+ marginTop: expanded ? 8 : 0,
333
+ height: expanded ? 32 : undefined,
334
+ }} hitSlop={12}>
335
+ <View style={{ transform: [{ rotate: expanded ? '180deg' : '0deg' }] }}>
336
+ <ChevronIcon size={16} color={AppColors.grayTextWeak}/>
337
+ </View>
338
+ </Pressable>
281
339
 
282
- {caller && caller !== 'Unknown' && expanded && (<View style={styles.cardFooter}>
283
- <Text style={styles.fullCallerText}>Caller: {caller}</Text>
284
- </View>)}
285
340
  </View>
286
341
  </View>);
287
342
  });
@@ -314,7 +369,9 @@ const styles = StyleSheet.create({
314
369
  headerLeft: {
315
370
  flexDirection: 'row',
316
371
  alignItems: 'center',
317
- gap: 8,
372
+ flexWrap: 'wrap',
373
+ gap: 6,
374
+ flex: 1,
318
375
  },
319
376
  badge: {
320
377
  paddingHorizontal: 6,
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- declare const JsonViewer: ({ data, search, forceOpen, }: {
2
+ declare const JsonViewer: ({ data, search, forceOpen, defaultExpandDepth, }: {
3
3
  data: unknown;
4
4
  search?: string;
5
5
  forceOpen?: boolean;
6
+ defaultExpandDepth?: number;
6
7
  }) => React.JSX.Element;
7
8
  export default JsonViewer;
@@ -4,10 +4,10 @@ import { ScrollView, View } from 'react-native';
4
4
  import TreeNode from './TreeNode';
5
5
  // Stylesheet
6
6
  import styles from '../styles';
7
- const JsonViewer = ({ data, search, forceOpen, }) => {
7
+ const JsonViewer = ({ data, search, forceOpen, defaultExpandDepth, }) => {
8
8
  return (<ScrollView horizontal showsHorizontalScrollIndicator={true} style={styles.codeBlockScroll}>
9
9
  <View style={styles.codeBlock}>
10
- <TreeNode data={data} search={search} forceOpen={forceOpen}/>
10
+ <TreeNode data={data} search={search} forceOpen={forceOpen} defaultExpandDepth={defaultExpandDepth}/>
11
11
  </View>
12
12
  </ScrollView>);
13
13
  };
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { MetaAccordionProps } from '../types';
3
- declare const MetaAccordion: ({ status, statusColor, duration, size, triggeredAt, }: MetaAccordionProps) => React.JSX.Element;
3
+ declare const MetaAccordion: ({ status, statusColor, duration, size, triggeredAt, method, contentType, url, }: MetaAccordionProps) => React.JSX.Element;
4
4
  export default MetaAccordion;
@@ -7,12 +7,13 @@ import useAccordion from '../customHooks/useAccordion';
7
7
  // Helpers
8
8
  import { getDurationColor } from '../helpers';
9
9
  // Assets
10
- import { ChevronIcon, CalendarIcon, StatusIcon, ClockIcon, SizeIcon, } from './NetworkIcons';
10
+ import { ChevronIcon, CalendarIcon, StatusIcon, ClockIcon, SizeIcon, TerminalIcon, GlobeIcon, } from './NetworkIcons';
11
11
  // Stylesheet
12
12
  import { AppColors } from '../styles/AppColors';
13
13
  import styles from '../styles';
14
- const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, }) => {
15
- const { toggleOpen, chevronStyle, bodyStyle } = useAccordion(true, 400, 260);
14
+ import { AppFonts } from '../styles/AppFonts';
15
+ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, method, contentType, url, }) => {
16
+ const { toggleOpen, chevronStyle, bodyStyle } = useAccordion(true, 400, 390);
16
17
  const isFailed = status === 0 || status == null;
17
18
  return (<View style={styles.metaContainer}>
18
19
  <Pressable onPress={toggleOpen} hitSlop={12}>
@@ -39,6 +40,26 @@ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, }) =>
39
40
  </Text>
40
41
  </View>
41
42
  <View style={styles.metaDivider}/>
43
+
44
+ <View style={styles.metaRow}>
45
+ <View style={styles.metaLabelRow}>
46
+ <TerminalIcon color={AppColors.grayTextWeak} size={14}/>
47
+ <Text style={styles.metaLabel}>Method</Text>
48
+ </View>
49
+ <View style={[
50
+ styles.statusChip,
51
+ {
52
+ borderColor: 'rgba(107, 78, 255, 0.25)',
53
+ backgroundColor: 'rgba(107, 78, 255, 0.08)',
54
+ }
55
+ ]}>
56
+ <Text style={[styles.statusText, { color: AppColors.purple, fontFamily: AppFonts.interBold }]}>
57
+ {method || 'GET'}
58
+ </Text>
59
+ </View>
60
+ </View>
61
+ <View style={styles.metaDivider}/>
62
+
42
63
  <View style={styles.metaRow}>
43
64
  <View style={styles.metaLabelRow}>
44
65
  <StatusIcon color={AppColors.grayTextWeak}/>
@@ -64,6 +85,16 @@ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, }) =>
64
85
  </View>
65
86
  </View>
66
87
  <View style={styles.metaDivider}/>
88
+
89
+ <View style={styles.metaRow}>
90
+ <View style={styles.metaLabelRow}>
91
+ <GlobeIcon color={AppColors.grayTextWeak} size={14}/>
92
+ <Text style={styles.metaLabel}>Content Type</Text>
93
+ </View>
94
+ <Text style={styles.metaValue}>{contentType || 'application/json'}</Text>
95
+ </View>
96
+ <View style={styles.metaDivider}/>
97
+
67
98
  <View style={styles.metaRow}>
68
99
  <View style={styles.metaLabelRow}>
69
100
  <ClockIcon color={AppColors.grayTextWeak} size={14}/>
@@ -94,6 +125,7 @@ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, }) =>
94
125
  </View>
95
126
  </View>
96
127
  <View style={styles.metaDivider}/>
128
+
97
129
  <View style={styles.metaRow}>
98
130
  <View style={styles.metaLabelRow}>
99
131
  <SizeIcon color={AppColors.grayTextWeak}/>
@@ -101,6 +133,17 @@ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, }) =>
101
133
  </View>
102
134
  <Text style={styles.metaValue}>{size}</Text>
103
135
  </View>
136
+ <View style={styles.metaDivider}/>
137
+
138
+ <View style={[styles.metaRow, { alignItems: 'flex-start' }]}>
139
+ <View style={styles.metaLabelRow}>
140
+ <GlobeIcon color={AppColors.grayTextWeak} size={14}/>
141
+ <Text style={styles.metaLabel}>Full URL</Text>
142
+ </View>
143
+ <Text selectable={true} numberOfLines={3} ellipsizeMode="tail" style={[styles.metaValue, { fontSize: 11.5, color: AppColors.grayTextWeak, flex: 1, textAlign: 'right', lineHeight: 16 }]}>
144
+ {url || '—'}
145
+ </Text>
146
+ </View>
104
147
  </View>
105
148
  </Animated.View>
106
149
  </View>);
@@ -34,3 +34,11 @@ export declare const InsightsIcon: ({ color, size, }: any) => React.JSX.Element;
34
34
  export declare const DebugIcon: ({ color, size }: any) => React.JSX.Element;
35
35
  export declare const SunIcon: ({ color, size }: any) => React.JSX.Element;
36
36
  export declare const MoonIcon: ({ color, size }: any) => React.JSX.Element;
37
+ export { BrandCircleIcon } from './BrandCircleIcon';
38
+ export { BrandSquareIcon } from './BrandSquareIcon';
39
+ export declare const HtmlIcon: ({ color, size }: any) => React.JSX.Element;
40
+ export declare const CssIcon: ({ color, size }: any) => React.JSX.Element;
41
+ export declare const JsIcon: ({ color, size }: any) => React.JSX.Element;
42
+ export declare const EyeIcon: ({ color, size }: any) => React.JSX.Element;
43
+ export declare const SettingsIcon: ({ color, size }: any) => React.JSX.Element;
44
+ export declare const FolderIcon: ({ color, size }: any) => React.JSX.Element;
@@ -213,3 +213,38 @@ export const MoonIcon = ({ color = '#FFFFFF', size = 16 }) => {
213
213
  <Path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" fill={color} stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
214
214
  </Svg>);
215
215
  };
216
+ export { BrandCircleIcon } from './BrandCircleIcon';
217
+ export { BrandSquareIcon } from './BrandSquareIcon';
218
+ export const HtmlIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => {
219
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
220
+ <Path d="M17.5 8.5L21 12l-3.5 3.5M6.5 8.5L3 12l3.5 3.5M14 4.5l-4 15" stroke={color} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
221
+ </Svg>);
222
+ };
223
+ export const CssIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => {
224
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
225
+ <Path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
226
+ </Svg>);
227
+ };
228
+ export const JsIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => {
229
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
230
+ <Rect x="3" y="3" width="18" height="18" rx="4" stroke={color} strokeWidth="2"/>
231
+ <Path d="M8 12v2.5a1.5 1.5 0 003 0V11M13 15.5a1 1 0 001.5.8h.5a1 1 0 001-1v-.5a1 1 0 00-1-1h-1a1 1 0 01-1-1v-.5a1 1 0 011-1h.5a1 1 0 011.5.8" stroke={color} strokeWidth="2" strokeLinecap="round"/>
232
+ </Svg>);
233
+ };
234
+ export const EyeIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => {
235
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
236
+ <Path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
237
+ <Circle cx="12" cy="12" r="3" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
238
+ </Svg>);
239
+ };
240
+ export const SettingsIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => {
241
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
242
+ <Path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
243
+ <Circle cx="12" cy="12" r="3" stroke={color} strokeWidth="2"/>
244
+ </Svg>);
245
+ };
246
+ export const FolderIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => {
247
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
248
+ <Path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
249
+ </Svg>);
250
+ };
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export declare const ReduxTreeView: ({ state, lastActionMap, search, }: {
3
+ state: any;
4
+ lastActionMap: Record<string, any>;
5
+ search?: string;
6
+ }) => React.JSX.Element;