react-native-debug-toolkit
Version:
A simple yet powerful debugging toolkit for React Native with a convenient floating UI for development
302 lines (278 loc) • 7.23 kB
JavaScript
import React from 'react'
import { View, Text, StyleSheet, Clipboard } from 'react-native'
import { ScrollView, Pressable } from 'react-native'
import JSONTree from 'react-native-json-tree'
import { getNavigationActionColor } from '../utils/DebugConst'
// Re-using the theme from ConsoleLogDetails for consistency
const theme = {
scheme: 'monokai',
author: 'wimer hazenberg (http://www.monokai.nl)',
base00: '#272822',
base01: '#383830',
base02: '#49483e',
base03: '#75715e',
base04: '#a59f85',
base05: '#f8f8f2',
base06: '#f5f4f1',
base07: '#f9f8f5',
base08: '#f92672',
base09: '#fd971f',
base0A: '#f4bf75',
base0B: '#a6e22e',
base0C: '#a1efe4',
base0D: '#66d9ef',
base0E: '#ae81ff',
base0F: '#cc6633'
};
const CopyButton = ({ text, style }) => {
const [copied, setCopied] = React.useState(false)
const handleCopy = async () => {
await Clipboard.setString(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<Pressable style={[styles.copyButton, style]} onPress={handleCopy}>
<Text style={styles.copyButtonText}>{copied ? 'Copied!' : 'Copy'}</Text>
</Pressable>
)
}
const CollapsibleSection = ({ title, children, initiallyExpanded = false }) => {
const [expanded, setExpanded] = React.useState(initiallyExpanded)
return (
<View style={styles.collapsibleSection}>
<Pressable
style={styles.sectionHeader}
onPress={() => setExpanded(!expanded)}>
<Text style={styles.sectionTitle}>{title}</Text>
<Text style={styles.expandIcon}>{expanded ? '▼' : '▶'}</Text>
</Pressable>
{expanded && children}
</View>
)
}
// Basic JSONValue renderer
const JSONValue = ({ value }) => {
if (value === null) {
return <Text style={styles.jsonNull}>null</Text>
}
if (value === undefined) {
return <Text style={styles.jsonNull}>undefined</Text>
}
if (typeof value === 'boolean') {
return <Text style={styles.jsonBoolean}>{value.toString()}</Text>
}
if (typeof value === 'number') {
return <Text style={styles.jsonNumber}>{value}</Text>
}
if (typeof value === 'string') {
return (
<Text style={styles.jsonString} selectable={true}>
"{value}"
</Text>
)
}
if (typeof value === 'object') {
return (
<JSONTree
data={value}
theme={theme}
invertTheme={true}
hideRoot={true}
shouldExpandNode={(keyPath, nodeData, currentLevel) => currentLevel < 1}
/>
)
}
return <Text style={styles.jsonOther}>{String(value)}</Text>
}
const NavigationLogDetails = ({ log }) => {
if (!log) {
return (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>Navigation log data is missing</Text>
</View>
)
}
const { action, from, to, timestamp, startTime, duration, debugLog } = log
const actionColor = getNavigationActionColor(action)
// Format the log data for text display and copying
const formatLogForCopy = () => {
try {
return `Navigation: ${action}
From: ${JSON.stringify(from, null, 2)}
To: ${JSON.stringify(to, null, 2)}
Time: ${timestamp ? new Date(timestamp).toLocaleString() : 'Unknown'}
Duration: ${duration || 'N/A'} ms`;
} catch (e) {
return 'Failed to format navigation log';
}
};
return (
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}
showsVerticalScrollIndicator={true}
scrollEventThrottle={16}
keyboardShouldPersistTaps='handled'>
<View style={styles.header}>
<View style={styles.headerInfo}>
<Text style={[styles.actionIndicator, { color: actionColor }]}>
{action?.toUpperCase() || 'UNKNOWN'}
</Text>
<Text style={styles.timestamp}>
{timestamp
? new Date(timestamp).toLocaleString()
: 'Unknown time'}
</Text>
{duration && (
<Text style={styles.duration}>
{`${duration} ms`}
</Text>
)}
</View>
<CopyButton text={formatLogForCopy()} />
</View>
<CollapsibleSection title='From Route' initiallyExpanded={true}>
<View style={styles.dataContentWrapper}>
<View style={styles.dataContent}>
<JSONValue value={from} />
</View>
</View>
</CollapsibleSection>
<CollapsibleSection title='To Route' initiallyExpanded={true}>
<View style={styles.dataContentWrapper}>
<View style={styles.dataContent}>
<JSONValue value={to} />
</View>
</View>
</CollapsibleSection>
<CollapsibleSection title='Debug Log' initiallyExpanded={true}>
<View style={styles.dataContentWrapper}>
<View style={styles.dataContent}>
<JSONValue value={debugLog} />
</View>
</View>
</CollapsibleSection>
</ScrollView>
)
}
// Styles adapted from ConsoleLogDetails
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
contentContainer: {
paddingBottom: 20,
},
header: {
flexDirection: 'row',
padding: 15,
borderBottomWidth: 1,
borderBottomColor: '#eee',
alignItems: 'center',
justifyContent: 'space-between',
},
headerInfo: {
flexShrink: 1,
marginRight: 10,
},
actionIndicator: {
fontSize: 14,
fontWeight: 'bold',
marginBottom: 4,
},
timestamp: {
fontSize: 13,
color: '#666',
marginBottom: 2,
},
duration: {
fontSize: 12,
color: '#888',
},
collapsibleSection: {
marginBottom: 1,
backgroundColor: '#fff',
},
sectionHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 15,
backgroundColor: '#f5f5f5',
},
sectionTitle: {
fontSize: 15,
fontWeight: 'bold',
color: '#333',
},
expandIcon: {
fontSize: 14,
color: '#666',
},
content: {
padding: 15,
},
dataContentWrapper: {
flex: 1,
padding: 10,
},
dataContent: {
backgroundColor: '#f8f9fa',
padding: 10,
borderRadius: 4,
borderWidth: 1,
borderColor: '#e9ecef',
},
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
errorText: {
color: '#ff4444',
fontSize: 16,
},
copyButton: {
backgroundColor: '#e9ecef',
paddingHorizontal: 10,
paddingVertical: 5,
borderRadius: 4,
flexShrink: 0,
},
copyButtonText: {
fontSize: 12,
color: '#666',
},
// JSON Value Styles (reused from ConsoleLogDetails)
jsonString: {
color: '#CB772F',
fontFamily: 'monospace',
fontSize: 13,
},
jsonNumber: {
color: '#AE81FF',
fontFamily: 'monospace',
fontSize: 13,
},
jsonBoolean: {
color: '#66D9EF',
fontWeight: 'bold',
fontFamily: 'monospace',
fontSize: 13,
},
jsonNull: {
color: '#F92672',
fontStyle: 'italic',
fontFamily: 'monospace',
fontSize: 13,
},
jsonOther: {
color: '#75715e',
fontFamily: 'monospace',
fontSize: 13,
},
});
export default NavigationLogDetails