react-native-inapp-inspector 1.0.4 → 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.
- package/README.md +3 -3
- package/dist/commonjs/components/AnalyticsEventCard.js +10 -10
- package/dist/commonjs/components/CodeSnippet.js +233 -10
- package/dist/commonjs/components/ConsoleLogCard.js +55 -9
- package/dist/commonjs/components/CopyButton.js +2 -1
- package/dist/commonjs/components/ErrorBoundary.d.ts +20 -0
- package/dist/commonjs/components/ErrorBoundary.js +332 -0
- package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
- package/dist/commonjs/components/NetworkIcons.js +45 -1
- package/dist/commonjs/customHooks/reduxLogger.d.ts +4 -0
- package/dist/commonjs/customHooks/reduxLogger.js +30 -0
- package/dist/commonjs/customHooks/webViewLogger.d.ts +2 -0
- package/dist/commonjs/customHooks/webViewLogger.js +281 -246
- package/dist/commonjs/helpers/index.js +2 -1
- package/dist/commonjs/index.d.ts +5 -3
- package/dist/commonjs/index.js +685 -911
- package/dist/commonjs/styles/AppColors.d.ts +29 -1
- package/dist/commonjs/styles/AppColors.js +38 -2
- package/dist/commonjs/styles/index.d.ts +438 -229
- package/dist/commonjs/styles/index.js +448 -209
- package/dist/commonjs/types/index.d.ts +2 -2
- package/dist/esm/components/AnalyticsEventCard.js +10 -10
- package/dist/esm/components/CodeSnippet.js +232 -12
- package/dist/esm/components/ConsoleLogCard.js +55 -9
- package/dist/esm/components/CopyButton.js +2 -1
- package/dist/esm/components/ErrorBoundary.d.ts +20 -0
- package/dist/esm/components/ErrorBoundary.js +295 -0
- package/dist/esm/components/NetworkIcons.d.ts +5 -0
- package/dist/esm/components/NetworkIcons.js +39 -0
- package/dist/esm/customHooks/reduxLogger.d.ts +4 -0
- package/dist/esm/customHooks/reduxLogger.js +23 -0
- package/dist/esm/customHooks/webViewLogger.d.ts +2 -0
- package/dist/esm/customHooks/webViewLogger.js +281 -246
- package/dist/esm/helpers/index.js +2 -1
- package/dist/esm/index.d.ts +5 -3
- package/dist/esm/index.js +683 -914
- package/dist/esm/styles/AppColors.d.ts +29 -1
- package/dist/esm/styles/AppColors.js +35 -1
- package/dist/esm/styles/index.d.ts +438 -229
- package/dist/esm/styles/index.js +412 -209
- package/dist/esm/types/index.d.ts +2 -2
- package/example/App.tsx +351 -127
- package/example/ios/Podfile.lock +26 -0
- package/example/package-lock.json +20 -4
- package/example/package.json +4 -3
- 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
|
|
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:
|
|
214
|
-
paddingVertical:
|
|
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:
|
|
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:
|
|
243
|
+
marginBottom: 6,
|
|
244
244
|
},
|
|
245
245
|
nameBadge: {
|
|
246
|
-
paddingHorizontal:
|
|
247
|
-
paddingVertical:
|
|
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:
|
|
283
|
-
paddingVertical:
|
|
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:
|
|
304
|
-
paddingVertical:
|
|
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]*?\*\/)|("(?:\\.|[
|
|
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:-]+>?)|("(?:\\.|[
|
|
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
|
|
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,
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
284
|
-
paddingVertical:
|
|
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:
|
|
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:
|
|
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:
|
|
385
|
+
marginTop: 6,
|
|
340
386
|
backgroundColor: '#FFFFFF',
|
|
341
|
-
paddingHorizontal:
|
|
342
|
-
paddingVertical:
|
|
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
|
-
|
|
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;
|