react-native-inapp-inspector 1.0.14 β†’ 1.0.16

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.
package/README.md CHANGED
@@ -8,66 +8,75 @@
8
8
  </picture>
9
9
  </p>
10
10
 
11
- A premium, self-contained, and interactive in-app debugger for React Native applications. Inspect network requests, console logs, analytics events, and WebView states directly from your device.
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/react-native-inapp-inspector"><img src="https://img.shields.io/npm/v/react-native-inapp-inspector?color=6366f1&label=npm" alt="npm version" /></a>
13
+ <a href="https://github.com/vengatmacuser/react-native-inapp-inspector/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="license" /></a>
14
+ <a href="https://github.com/vengatmacuser/react-native-inapp-inspector"><img src="https://img.shields.io/badge/platform-iOS%20%7C%20Android-blue" alt="platform" /></a>
15
+ </p>
16
+
17
+ A self-contained in-app debugging overlay for React Native. Inspect network traffic, console output, analytics events, Redux state, and WebView activity directly inside your app.
18
+
19
+ ---
12
20
 
13
21
  ## Features
14
22
 
15
- - **🌐 Network Inspector**: Intercept and view HTTP requests and responses, track latency, export as cURL or Fetch, search logs, and view differences between subsequent requests.
16
- - **πŸ’» Console Logger**: In-app terminal displaying your `console.log`, `console.warn`, and `console.error` logs with customizable filters.
17
- - **πŸ“Š Analytics Event Tracker**: Real-time logging and analytics debugging (e.g. Firebase Analytics, GA events).
18
- - **πŸ•ΈοΈ WebView Inspector**: Live tracking of navigation history, console logs, and inspection of HTML, CSS, and JS inside your `WebView` components.
19
- - **πŸ“ˆ Embedded Visualizations**: Built-in mini charts visualizing metrics like latency, payload size, and errors over time.
20
- - **🎨 Modern Dark UI**: Sleek, glassmorphism-inspired dark design with smooth micro-animations.
23
+ | Feature | Description |
24
+ |---|---|
25
+ | Network inspector | Captures `fetch` and axios `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` calls with URL, method, status, headers, body, response, duration, caller, cURL, and fetch snippets. |
26
+ | Insights dashboard | Shows request totals, status breakdowns, latency, payload size, slow requests, and recent activity charts. |
27
+ | Console logger | Captures `console.log`, `console.info`, `console.warn`, and `console.error` with source method and caller details. |
28
+ | Analytics tracker | Captures manual analytics events and patched `@react-native-firebase/analytics` calls including `logEvent`, `logScreenView`, user properties, and user id. |
29
+ | Redux inspector | Connects to a Redux store, displays the live state tree, tracks dispatched actions, affected slices, and action history. |
30
+ | WebView inspector | Provides an instrumented `WebView` with console capture, navigation history, HTML/CSS/JS snapshots, and optional loading overlay. |
31
+ | Error boundary | Exports an `ErrorBoundary` for catching React errors and wrapping the inspector safely. |
21
32
 
22
33
  ---
23
34
 
24
35
  ## Video Walkthrough
25
36
 
26
- Watch the library in action, demonstrating network inspection, Redux state tree analysis, WebView debugging, and console logging:
27
-
28
- [🎬 Download or watch the Video Walkthrough](https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/example/guidance/Video-WalkThrough.mp4)
37
+ [Download or watch the Video Walkthrough](https://raw.githubusercontent.com/vengatmacuser/react-native-inapp-inspector/main/example/guidance/Video-WalkThrough.mp4)
29
38
 
30
39
  ---
31
40
 
32
41
  ## Installation
33
42
 
34
- Install the package as a development dependency in your React Native project:
43
+ ```bash
44
+ npm install --save-dev react-native-inapp-inspector axios
45
+ ```
35
46
 
36
47
  ```bash
37
- npm install --save-dev react-native-inapp-inspector
38
- # OR
39
- yarn add -D react-native-inapp-inspector
48
+ yarn add -D react-native-inapp-inspector axios
40
49
  ```
41
50
 
42
- The package will automatically install its dependencies (`@react-navigation/native`, `react-native-linear-gradient`, and `react-native-svg`).
51
+ The package has React and React Native as peer dependencies. It depends on `@react-navigation/native`, `react-native-linear-gradient`, and `react-native-svg`. The current network logger imports `axios` for axios interception, so install `axios` even if most of your requests use `fetch`.
52
+
53
+ Install optional integrations when you use WebView or Firebase Analytics capture:
43
54
 
44
- For iOS projects, don't forget to run pod install:
45
55
  ```bash
46
- cd ios && pod install
56
+ npm install react-native-webview @react-native-firebase/analytics
47
57
  ```
48
58
 
49
- ### Dependency Isolation
59
+ For iOS, install pods after adding native dependencies:
50
60
 
51
- This package is designed to operate in strict isolation. If the host application already uses `@react-navigation/native`, `react-native-linear-gradient`, or `react-native-svg`, the package's dependencies will not conflict with the application's runtime. The bundler (Metro/Webpack) and autolink systems automatically resolve duplicate native module links without affecting your main application environment.
61
+ ```bash
62
+ cd ios && pod install
63
+ ```
52
64
 
53
65
  ---
54
66
 
55
- ## Integration
67
+ ## Basic Setup
56
68
 
57
- ### 1. Embed the Inspector Component
58
- Place the `<NetworkInspector />` component at the root level of your application (usually in `App.tsx` or your root navigation container):
69
+ Mount the inspector once near the root of your app.
59
70
 
60
71
  ```tsx
61
72
  import React from 'react';
62
- import { SafeAreaView } from 'react-native';
73
+ import {SafeAreaView} from 'react-native';
63
74
  import NetworkInspector from 'react-native-inapp-inspector';
64
75
 
65
76
  const App = () => {
66
77
  return (
67
- <SafeAreaView style={{ flex: 1 }}>
68
- {/* Your application components */}
69
-
70
- {/* Floating Inspector overlay */}
78
+ <SafeAreaView style={{flex: 1}}>
79
+ {/* Your app */}
71
80
  <NetworkInspector />
72
81
  </SafeAreaView>
73
82
  );
@@ -76,38 +85,188 @@ const App = () => {
76
85
  export default App;
77
86
  ```
78
87
 
79
- ### 2. Auto-Intercept Network Requests (Axios / Fetch)
80
- The library automatically intercepts standard `fetch` and `XMLHttpRequest` requests when loaded. If you are using `axios`, you can register it to intercept requests:
88
+ When mounted, the inspector sets up network logging, clears previous network logs, patches console logging, and attempts Firebase Analytics auto-setup if `@react-native-firebase/analytics` is installed.
89
+
90
+ If you need to capture requests that happen before the component mounts, call `setupNetworkLogger()` at module level in your app entry file.
91
+
92
+ ```tsx
93
+ import NetworkInspector, {setupNetworkLogger} from 'react-native-inapp-inspector';
94
+
95
+ setupNetworkLogger();
96
+ ```
97
+
98
+ You can disable the overlay without removing it from your tree:
99
+
100
+ ```tsx
101
+ <NetworkInspector enabled={false} />
102
+ ```
103
+
104
+ ---
81
105
 
82
- ```typescript
106
+ ## Network Logging
107
+
108
+ `setupNetworkLogger()` patches global `fetch`, the default axios instance, and future axios instances created with `axios.create()`.
109
+
110
+ ```tsx
83
111
  import axios from 'axios';
84
- import { addAxiosInterceptors } from 'react-native-inapp-inspector';
112
+ import {setupNetworkLogger} from 'react-native-inapp-inspector';
85
113
 
86
- const api = axios.create({
87
- baseURL: 'https://api.example.com',
88
- });
114
+ setupNetworkLogger();
115
+
116
+ const api = axios.create({baseURL: 'https://api.example.com'});
117
+
118
+ await fetch('https://api.example.com/users');
119
+ await api.post('/login', {email, password});
120
+ ```
121
+
122
+ If an axios instance was created before `setupNetworkLogger()` ran, attach interceptors manually:
123
+
124
+ ```tsx
125
+ import {addAxiosInterceptors} from 'react-native-inapp-inspector';
89
126
 
90
- // Register the interceptor
91
127
  addAxiosInterceptors(api);
92
128
  ```
93
129
 
94
- ### 3. Log Analytics Events
95
- Subscribe to and log custom analytics events:
130
+ Network logs are capped at 100 entries and ignore React Native symbolication requests.
131
+
132
+ ---
96
133
 
97
- ```typescript
98
- import { subscribeAnalyticsEvents } from 'react-native-inapp-inspector';
134
+ ## Console Logging
99
135
 
100
- // Log your custom events
101
- subscribeAnalyticsEvents((events) => {
102
- // Access and analyze logged events
136
+ The inspector captures console output automatically when mounted. You can also set it up manually:
137
+
138
+ ```tsx
139
+ import {setupConsoleLogger} from 'react-native-inapp-inspector';
140
+
141
+ setupConsoleLogger();
142
+ ```
143
+
144
+ Captured levels are `log`, `info`, `warn`, and `error`.
145
+
146
+ ---
147
+
148
+ ## Analytics Logging
149
+
150
+ Manual events can be pushed into the Analytics tab:
151
+
152
+ ```tsx
153
+ import {logAnalyticsEvent} from 'react-native-inapp-inspector';
154
+
155
+ logAnalyticsEvent('purchase_completed', {
156
+ item_id: 'SKU-42',
157
+ value: 29.99,
158
+ currency: 'USD',
103
159
  });
104
160
  ```
105
161
 
162
+ For Firebase Analytics, pass the result of `analytics()` to `setupAnalyticsLogger()` before analytics calls begin:
163
+
164
+ ```tsx
165
+ import analytics from '@react-native-firebase/analytics';
166
+ import {setupAnalyticsLogger} from 'react-native-inapp-inspector';
167
+
168
+ setupAnalyticsLogger(analytics());
169
+ ```
170
+
171
+ The logger patches `logEvent`, `logScreenView`, `setUserProperty`, `setUserProperties`, and `setUserId`. Analytics events are capped at 200 entries.
172
+
173
+ ---
174
+
175
+ ## Redux Inspection
176
+
177
+ Connect your Redux store once during app startup.
178
+
179
+ ```tsx
180
+ import {connectReduxStore} from 'react-native-inapp-inspector';
181
+ import store from './store';
182
+
183
+ connectReduxStore(store);
184
+ ```
185
+
186
+ The Redux tab shows the latest state tree, recent dispatches, payloads, and changed top-level state slices. Action history is capped at 50 entries.
187
+
188
+ ---
189
+
190
+ ## WebView Inspection
191
+
192
+ Use the exported `WebView` as a drop-in wrapper around `react-native-webview`.
193
+
194
+ ```tsx
195
+ import {WebView} from 'react-native-inapp-inspector';
196
+
197
+ <WebView source={{uri: 'https://example.com'}} />;
198
+ ```
199
+
200
+ The wrapper forwards your props and ref, preserves your `onMessage`, `onNavigationStateChange`, `onLoadStart`, and `onLoadEnd` handlers, and injects scripts for WebView console logs, navigation history, and source snapshots.
201
+
202
+ Disable the loading overlay with `showLoader={false}`:
203
+
204
+ ```tsx
205
+ <WebView source={{uri: 'https://example.com'}} showLoader={false} />
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Error Boundary
211
+
212
+ ```tsx
213
+ import {ErrorBoundary} from 'react-native-inapp-inspector';
214
+
215
+ <ErrorBoundary>
216
+ <YourComponent />
217
+ </ErrorBoundary>
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Public API
223
+
224
+ | Export | Type | Description |
225
+ |---|---|---|
226
+ | `NetworkInspector` | default component | Floating inspector overlay. Mount once near the root of the app. |
227
+ | `setupNetworkLogger()` | function | Patches `fetch`, default axios, and future `axios.create()` instances. |
228
+ | `addAxiosInterceptors(instance)` | function | Manually attaches axios interceptors to an existing instance. |
229
+ | `clearNetworkLogs()` | function | Clears captured network logs. |
230
+ | `subscribeNetworkLogs(callback)` | function | Subscribes to network log updates and returns an unsubscribe function. |
231
+ | `setupConsoleLogger()` | function | Patches console methods. |
232
+ | `clearConsoleLogs()` | function | Clears captured console logs. |
233
+ | `subscribeConsoleLogs(callback)` | function | Subscribes to console log updates and returns an unsubscribe function. |
234
+ | `setupAnalyticsLogger(instance)` | function | Patches a Firebase Analytics instance. |
235
+ | `logAnalyticsEvent(name, params?, userProperties?)` | function | Adds a manual analytics event to the inspector. |
236
+ | `clearAnalyticsEvents()` | function | Clears captured analytics events. |
237
+ | `subscribeAnalyticsEvents(callback)` | function | Subscribes to analytics event updates and returns an unsubscribe function. |
238
+ | `connectReduxStore(store)` | function | Connects a Redux store for live state and action inspection. |
239
+ | `getReduxState()` | function | Returns the latest captured Redux state. |
240
+ | `subscribeReduxState(callback)` | function | Subscribes to Redux state updates and returns an unsubscribe function. |
241
+ | `WebView` | component | Instrumented WebView wrapper. |
242
+ | `getWebViewLogs()` | function | Returns captured WebView console logs. |
243
+ | `getWebViewNavHistory()` | function | Returns captured WebView navigation history. |
244
+ | `getWebViewHtml()` | function | Returns the latest captured WebView HTML. |
245
+ | `getWebViewCss()` | function | Returns the latest captured WebView CSS. |
246
+ | `getWebViewJs()` | function | Returns the latest captured WebView JavaScript. |
247
+ | `getWebViewHtmlUrl()` | function | Returns the URL for the latest captured WebView source snapshot. |
248
+ | `clearWebViewData()` | function | Clears captured WebView logs, navigation, and source data. |
249
+ | `subscribeWebView(callback)` | function | Subscribes to WebView data changes and returns an unsubscribe function. |
250
+ | `ErrorBoundary` | component | React error boundary component. |
251
+
252
+ ---
253
+
254
+ ## Example App
255
+
256
+ The `example` directory contains a React Native sample app and video walkthrough.
257
+
258
+ ```bash
259
+ cd example
260
+ npm install
261
+ cd ios && pod install && cd ..
262
+ npm run ios
263
+ ```
264
+
106
265
  ---
107
266
 
108
267
  ## Support
109
268
 
110
- If you find this project useful, consider sponsoring its development on GitHub Sponsors:
269
+ If you find this project useful, consider sponsoring its development:
111
270
 
112
271
  [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-@vengatmacuser-ea4aaa?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/vengatmacuser)
113
272
 
@@ -115,4 +274,4 @@ If you find this project useful, consider sponsoring its development on GitHub S
115
274
 
116
275
  ## License
117
276
 
118
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
277
+ MIT - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ interface AnimatedEntranceProps {
4
+ children: React.ReactNode;
5
+ delay?: number;
6
+ distance?: number;
7
+ duration?: number;
8
+ index?: number;
9
+ style?: ViewStyle | ViewStyle[];
10
+ }
11
+ declare const AnimatedEntrance: ({ children, delay, distance, duration, index, style, }: AnimatedEntranceProps) => React.JSX.Element;
12
+ export default AnimatedEntrance;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const react_1 = __importStar(require("react"));
37
+ const react_native_1 = require("react-native");
38
+ const AnimatedEntrance = ({ children, delay = 0, distance = 10, duration = 220, index = 0, style, }) => {
39
+ const progress = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
40
+ (0, react_1.useEffect)(() => {
41
+ progress.setValue(0);
42
+ react_native_1.Animated.timing(progress, {
43
+ toValue: 1,
44
+ duration,
45
+ delay: delay + Math.min(index, 12) * 18,
46
+ useNativeDriver: true,
47
+ }).start();
48
+ }, [delay, duration, index, progress]);
49
+ return (<react_native_1.Animated.View style={[
50
+ style,
51
+ {
52
+ opacity: progress,
53
+ transform: [
54
+ {
55
+ translateY: progress.interpolate({
56
+ inputRange: [0, 1],
57
+ outputRange: [distance, 0],
58
+ }),
59
+ },
60
+ {
61
+ scale: progress.interpolate({
62
+ inputRange: [0, 1],
63
+ outputRange: [0.985, 1],
64
+ }),
65
+ },
66
+ ],
67
+ },
68
+ ]}>
69
+ {children}
70
+ </react_native_1.Animated.View>);
71
+ };
72
+ exports.default = AnimatedEntrance;
@@ -109,7 +109,10 @@ const getLogMessageWithBadges = (message, searchStr, textStyle, highlightStyle,
109
109
  const remainingText = message.substring(fullPrefix.length);
110
110
  const tags = fullPrefix.match(/\[[^\]]+\]/g) || [];
111
111
  const getTagColor = (tag) => {
112
- const cleanTag = tag.replace(/[\[\]]/g, '').trim().toUpperCase();
112
+ const cleanTag = tag
113
+ .replace(/[\[\]]/g, '')
114
+ .trim()
115
+ .toUpperCase();
113
116
  if (cleanTag === 'API')
114
117
  return '#0284C7';
115
118
  if (cleanTag === 'TEST')
@@ -126,7 +129,14 @@ const getLogMessageWithBadges = (message, searchStr, textStyle, highlightStyle,
126
129
  for (let i = 0; i < cleanTag.length; i++) {
127
130
  hash = cleanTag.charCodeAt(i) + ((hash << 5) - hash);
128
131
  }
129
- const colors = ['#0891B2', '#0D9488', '#2563EB', '#D97706', '#E11D48', '#8B5CF6'];
132
+ const colors = [
133
+ '#0891B2',
134
+ '#0D9488',
135
+ '#2563EB',
136
+ '#D97706',
137
+ '#E11D48',
138
+ '#8B5CF6',
139
+ ];
130
140
  return colors[Math.abs(hash) % colors.length];
131
141
  };
132
142
  return (<react_native_1.Text style={textStyle} numberOfLines={numberOfLines}>
@@ -147,6 +157,7 @@ const getLogMessageWithBadges = (message, searchStr, textStyle, highlightStyle,
147
157
  };
148
158
  exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, searchStr = '', isWebView = false, }) {
149
159
  const [expanded, setExpanded] = (0, react_1.useState)(false);
160
+ const chevronAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
150
161
  const jsonContent = getJsonContent(item.message);
151
162
  const isAnalyticsError = item.message
152
163
  .toLowerCase()
@@ -230,6 +241,26 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
230
241
  }
231
242
  };
232
243
  const colors = getLogColors();
244
+ (0, react_1.useEffect)(() => {
245
+ if (react_native_1.Platform.OS === 'android') {
246
+ react_native_1.UIManager.setLayoutAnimationEnabledExperimental?.(true);
247
+ }
248
+ }, []);
249
+ (0, react_1.useEffect)(() => {
250
+ react_native_1.Animated.timing(chevronAnim, {
251
+ toValue: expanded ? 1 : 0,
252
+ duration: 180,
253
+ useNativeDriver: true,
254
+ }).start();
255
+ }, [chevronAnim, expanded]);
256
+ const toggleExpanded = () => {
257
+ react_native_1.LayoutAnimation.configureNext(react_native_1.LayoutAnimation.Presets.easeInEaseOut);
258
+ setExpanded(prev => !prev);
259
+ };
260
+ const chevronRotate = chevronAnim.interpolate({
261
+ inputRange: [0, 1],
262
+ outputRange: ['0deg', '180deg'],
263
+ });
233
264
  // Show limited lines unless expanded
234
265
  const numLines = expanded ? undefined : 5;
235
266
  const hasLongMessage = jsonContent
@@ -250,10 +281,8 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
250
281
  paddingRight: 4,
251
282
  },
252
283
  ]}>
253
-
254
284
  {/* Left Content Area */}
255
- <react_native_1.Pressable onPress={() => setExpanded(prev => !prev)} style={{ flex: 1, paddingRight: 6 }}>
256
-
285
+ <react_native_1.Pressable onPress={toggleExpanded} style={{ flex: 1, paddingRight: 6 }}>
257
286
  <react_native_1.View style={styles.cardHeader}>
258
287
  <react_native_1.View style={styles.headerLeft}>
259
288
  <CopyButton_1.default value={item.message} label="Log message"/>
@@ -271,7 +300,10 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
271
300
  },
272
301
  ]}>
273
302
  <react_native_1.Text style={[styles.badgeText, { color: '#6B4EFF' }]}>
274
- console.{('sourceMethod' in item ? item.sourceMethod : undefined) || item.type || 'log'}
303
+ console.
304
+ {('sourceMethod' in item ? item.sourceMethod : undefined) ||
305
+ item.type ||
306
+ 'log'}
275
307
  </react_native_1.Text>
276
308
  </react_native_1.View>
277
309
  {jsonContent && (<react_native_1.View style={[
@@ -283,7 +315,9 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
283
315
  },
284
316
  ]}>
285
317
  <react_native_1.Text style={[styles.badgeText, { color: '#0D9488' }]}>
286
- {Array.isArray(jsonContent.data) ? `Array[${jsonContent.data.length}]` : `Object{${Object.keys(jsonContent.data).length}}`}
318
+ {Array.isArray(jsonContent.data)
319
+ ? `Array[${jsonContent.data.length}]`
320
+ : `Object{${Object.keys(jsonContent.data).length}}`}
287
321
  </react_native_1.Text>
288
322
  </react_native_1.View>)}
289
323
  {isAnalyticsError && (<react_native_1.View style={[
@@ -302,7 +336,10 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
302
336
  borderWidth: 1,
303
337
  },
304
338
  ]}>
305
- <react_native_1.Text style={[styles.badgeText, { color: AppColors_1.AppColors.grayTextStrong }]}>
339
+ <react_native_1.Text style={[
340
+ styles.badgeText,
341
+ { color: AppColors_1.AppColors.grayTextStrong },
342
+ ]}>
306
343
  user-log
307
344
  </react_native_1.Text>
308
345
  </react_native_1.View>)}
@@ -318,43 +355,92 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
318
355
  webview
319
356
  </react_native_1.Text>
320
357
  </react_native_1.View>)}
321
- <react_native_1.Text style={[styles.serialNumber, { color: AppColors_1.AppColors.grayTextWeak }]}>#{item.id + 1}</react_native_1.Text>
322
- <react_native_1.Text style={[styles.timestamp, { color: AppColors_1.AppColors.grayTextWeak }]}>{formatTime(item.timestamp)}</react_native_1.Text>
358
+ <react_native_1.Text style={[styles.serialNumber, { color: AppColors_1.AppColors.grayTextWeak }]}>
359
+ #{item.id + 1}
360
+ </react_native_1.Text>
361
+ <react_native_1.Text style={[styles.timestamp, { color: AppColors_1.AppColors.grayTextWeak }]}>
362
+ {formatTime(item.timestamp)}
363
+ </react_native_1.Text>
323
364
  </react_native_1.View>
324
-
325
- {caller && caller !== 'Unknown' && (<react_native_1.Text style={[styles.callerText, { color: AppColors_1.AppColors.grayTextWeak, marginRight: 4 }]} numberOfLines={1} ellipsizeMode="middle">
365
+
366
+ {caller && caller !== 'Unknown' && (<react_native_1.Text style={[
367
+ styles.callerText,
368
+ { color: AppColors_1.AppColors.grayTextWeak, marginRight: 4 },
369
+ ]} numberOfLines={1} ellipsizeMode="middle">
326
370
  {caller.split('/').pop() || caller}
327
371
  </react_native_1.Text>)}
328
372
  </react_native_1.View>
329
373
 
330
- <react_native_1.View style={[styles.cardBody, { backgroundColor: AppColors_1.AppColors.primaryLight, borderColor: AppColors_1.AppColors.dividerColor }]}>
374
+ <react_native_1.View style={[
375
+ styles.cardBody,
376
+ {
377
+ backgroundColor: AppColors_1.AppColors.primaryLight,
378
+ borderColor: AppColors_1.AppColors.dividerColor,
379
+ },
380
+ ]}>
331
381
  {jsonContent ? (<>
332
- {jsonContent.header ? (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)}>
382
+ {jsonContent.header ? (<react_native_1.Pressable onPress={toggleExpanded}>
333
383
  {getLogMessageWithBadges(jsonContent.header, searchStr, [styles.messageText, { color: AppColors_1.AppColors.primaryBlack }], styles.highlight, numLines)}
334
384
  </react_native_1.Pressable>) : null}
335
- {expanded ? (<react_native_1.View style={[styles.jsonContainer, { backgroundColor: AppColors_1.AppColors.grayBackground, borderColor: AppColors_1.AppColors.dividerColor }]}>
385
+ {expanded ? (<react_native_1.View style={[
386
+ styles.jsonContainer,
387
+ {
388
+ backgroundColor: AppColors_1.AppColors.grayBackground,
389
+ borderColor: AppColors_1.AppColors.dividerColor,
390
+ },
391
+ ]}>
336
392
  <JsonViewer_1.default data={jsonContent.data} search={searchStr} forceOpen={expanded}/>
337
- </react_native_1.View>) : (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)} style={[styles.jsonPreviewContainer, { backgroundColor: AppColors_1.AppColors.grayBackground, borderColor: AppColors_1.AppColors.dividerColor }]}>
338
- <HighlightText_1.default text={getJsonPreviewText(jsonContent.data).text} search={searchStr} style={[styles.jsonPreviewText, { color: AppColors_1.AppColors.primaryBlack }]} highlightStyle={styles.highlight} detectLinks={true}/>
393
+ </react_native_1.View>) : (<react_native_1.Pressable onPress={toggleExpanded} style={[
394
+ styles.jsonPreviewContainer,
395
+ {
396
+ backgroundColor: AppColors_1.AppColors.grayBackground,
397
+ borderColor: AppColors_1.AppColors.dividerColor,
398
+ },
399
+ ]}>
400
+ <HighlightText_1.default text={getJsonPreviewText(jsonContent.data).text} search={searchStr} style={[
401
+ styles.jsonPreviewText,
402
+ { color: AppColors_1.AppColors.primaryBlack },
403
+ ]} highlightStyle={styles.highlight} detectLinks={true}/>
339
404
  </react_native_1.Pressable>)}
340
- </>) : (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)}>
405
+ </>) : (<react_native_1.Pressable onPress={toggleExpanded}>
341
406
  {getLogMessageWithBadges(item.message, searchStr, [styles.messageText, { color: AppColors_1.AppColors.primaryBlack }], styles.highlight, numLines)}
342
407
  </react_native_1.Pressable>)}
343
- {hasLongMessage && (<react_native_1.Pressable onPress={() => setExpanded(prev => !prev)} style={styles.seeMoreBtn} hitSlop={8}>
408
+ {hasLongMessage && (<react_native_1.Pressable onPress={toggleExpanded} style={styles.seeMoreBtn} hitSlop={8}>
344
409
  <react_native_1.Text style={styles.seeMoreText}>
345
410
  {expanded ? 'See Less' : 'See More'}
346
411
  </react_native_1.Text>
347
412
  </react_native_1.Pressable>)}
348
413
  </react_native_1.View>
349
414
 
350
- {expanded && (<react_native_1.View style={[styles.cardFooter, { borderTopColor: AppColors_1.AppColors.dividerColor, gap: 6 }]}>
351
- <react_native_1.View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
352
- <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interRegular, fontSize: 10.5, color: AppColors_1.AppColors.grayTextWeak }}>
353
- Length: {item.message.length} chars β€’ Size: {encodeURIComponent(item.message).replace(/%[0-9A-F]{2}/g, 'a').length} bytes
415
+ {expanded && (<react_native_1.View style={[
416
+ styles.cardFooter,
417
+ { borderTopColor: AppColors_1.AppColors.dividerColor, gap: 6 },
418
+ ]}>
419
+ <react_native_1.View style={{
420
+ flexDirection: 'row',
421
+ justifyContent: 'space-between',
422
+ alignItems: 'center',
423
+ }}>
424
+ <react_native_1.Text style={{
425
+ fontFamily: AppFonts_1.AppFonts.interRegular,
426
+ fontSize: 10.5,
427
+ color: AppColors_1.AppColors.grayTextWeak,
428
+ }}>
429
+ Length: {item.message.length} chars β€’ Size:{' '}
430
+ {encodeURIComponent(item.message).replace(/%[0-9A-F]{2}/g, 'a').length}{' '}
431
+ bytes
354
432
  </react_native_1.Text>
355
433
  </react_native_1.View>
356
- {caller && caller !== 'Unknown' && (<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 }}>
357
- <react_native_1.Text style={[styles.fullCallerText, { color: AppColors_1.AppColors.grayText, flex: 1, marginRight: 8 }]} numberOfLines={2}>
434
+ {caller && caller !== 'Unknown' && (<react_native_1.View style={{
435
+ flexDirection: 'row',
436
+ alignItems: 'center',
437
+ justifyContent: 'space-between',
438
+ marginTop: 4,
439
+ }}>
440
+ <react_native_1.Text style={[
441
+ styles.fullCallerText,
442
+ { color: AppColors_1.AppColors.grayText, flex: 1, marginRight: 8 },
443
+ ]} numberOfLines={2}>
358
444
  Caller: {caller}
359
445
  </react_native_1.Text>
360
446
  <CopyButton_1.default value={caller} label="Caller stack frame"/>
@@ -363,7 +449,7 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
363
449
  </react_native_1.Pressable>
364
450
 
365
451
  {/* Right Isolated Chevron Area */}
366
- <react_native_1.Pressable onPress={() => setExpanded(prev => !prev)} style={{
452
+ <react_native_1.Pressable onPress={toggleExpanded} style={{
367
453
  width: 28,
368
454
  alignItems: 'center',
369
455
  justifyContent: 'center',
@@ -371,11 +457,10 @@ exports.ConsoleLogCard = react_1.default.memo(function ConsoleLogCard({ item, se
371
457
  marginTop: expanded ? 8 : 0,
372
458
  height: expanded ? 32 : undefined,
373
459
  }} hitSlop={12}>
374
- <react_native_1.View style={{ transform: [{ rotate: expanded ? '180deg' : '0deg' }] }}>
460
+ <react_native_1.Animated.View style={{ transform: [{ rotate: chevronRotate }] }}>
375
461
  <NetworkIcons_1.ChevronIcon size={16} color={AppColors_1.AppColors.grayTextWeak}/>
376
- </react_native_1.View>
462
+ </react_native_1.Animated.View>
377
463
  </react_native_1.Pressable>
378
-
379
464
  </react_native_1.View>
380
465
  </react_native_1.View>);
381
466
  });