react-native-debug-toolkit 0.3.0 → 0.4.0

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.
@@ -0,0 +1,199 @@
1
+ import React, { useState, useMemo } from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ FlatList,
7
+ TouchableOpacity,
8
+ } from 'react-native'
9
+ import NavigationLogDetails from './NavigationLogDetails'
10
+ import { getNavigationActionColor } from '../utils/DebugConst'
11
+
12
+ const SubViewNavigationLogs = ({ logs = [] }) => {
13
+ const [selectedLog, setSelectedLog] = useState(null)
14
+
15
+ // Memoize the sorted logs
16
+ const sortedLogs = useMemo(() => {
17
+ // Create a stable copy before sorting if FlatList relies on reference equality
18
+ return [...logs].sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));
19
+ }, [logs]);
20
+
21
+ // Helper to format navigation data for preview
22
+ const formatNavigationPreview = (action, from, to) => {
23
+ const fromName = from?.name || 'Unknown';
24
+ const toName = to?.name || 'Unknown';
25
+
26
+ let preview = `${action || 'Navigate'}: ${fromName} → ${toName}`;
27
+
28
+ // Add params summary if available
29
+ if (to?.params) {
30
+ try {
31
+ const paramsStr = JSON.stringify(to.params);
32
+ const shortParams = paramsStr.length > 30 ? paramsStr.substring(0, 27) + '...' : paramsStr;
33
+ preview += ` ${shortParams}`;
34
+ } catch (e) {
35
+ preview += ' [with params]';
36
+ }
37
+ }
38
+
39
+ return preview;
40
+ };
41
+
42
+ const renderLogItem = ({ item }) => {
43
+ const action = item.action || 'navigate';
44
+ const actionColor = getNavigationActionColor(action);
45
+ const previewText = formatNavigationPreview(action, item.from, item.to);
46
+ const timestamp = item.timestamp
47
+ ? new Date(item.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })
48
+ : '';
49
+
50
+ return (
51
+ <TouchableOpacity
52
+ style={styles.logItem}
53
+ onPress={() => setSelectedLog(item)}>
54
+ <View style={styles.logItemContainer}>
55
+ <View
56
+ style={[styles.actionIndicator, { backgroundColor: actionColor }]}
57
+ />
58
+
59
+ <View style={styles.logContent}>
60
+ <View style={styles.logHeader}>
61
+ <Text style={[styles.actionText, { color: actionColor }]}>
62
+ {action.toUpperCase()}
63
+ </Text>
64
+ <Text style={styles.time}>{timestamp}</Text>
65
+ </View>
66
+
67
+ <Text style={styles.logMessage} numberOfLines={2}>
68
+ {previewText}
69
+ </Text>
70
+
71
+ {item.duration && (
72
+ <Text style={styles.duration}>{`${item.duration} ms`}</Text>
73
+ )}
74
+ </View>
75
+ </View>
76
+ </TouchableOpacity>
77
+ )
78
+ }
79
+
80
+ // If a log is selected, show the details view
81
+ if (selectedLog) {
82
+ return (
83
+ <View style={styles.container}>
84
+ <View style={styles.detailsHeader}>
85
+ <TouchableOpacity
86
+ style={styles.backButton}
87
+ onPress={() => setSelectedLog(null)}>
88
+ <Text style={styles.backButtonText}>← Back</Text>
89
+ </TouchableOpacity>
90
+ <Text style={styles.headerTitle}>Navigation Details</Text>
91
+ </View>
92
+ <NavigationLogDetails log={selectedLog} />
93
+ </View>
94
+ )
95
+ }
96
+
97
+ // Otherwise show the list view
98
+ return (
99
+ <View style={styles.container}>
100
+ {sortedLogs.length === 0 ? (
101
+ <Text style={styles.emptyText}>No navigation events logged yet</Text>
102
+ ) : (
103
+ <FlatList
104
+ data={sortedLogs}
105
+ renderItem={renderLogItem}
106
+ keyExtractor={(item, index) => `${item.timestamp}-${index}`}
107
+ style={styles.list}
108
+ />
109
+ )}
110
+ </View>
111
+ )
112
+ }
113
+
114
+ // Adapted styles from SubViewConsoleLogs
115
+ const styles = StyleSheet.create({
116
+ container: {
117
+ flex: 1,
118
+ backgroundColor: '#fff',
119
+ },
120
+ list: {
121
+ flex: 1,
122
+ },
123
+ emptyText: {
124
+ textAlign: 'center',
125
+ color: '#999',
126
+ marginTop: 20,
127
+ },
128
+ logItem: {
129
+ borderBottomWidth: 1,
130
+ borderBottomColor: '#eee',
131
+ },
132
+ logItemContainer: {
133
+ flexDirection: 'row',
134
+ paddingVertical: 10,
135
+ paddingHorizontal: 12,
136
+ },
137
+ actionIndicator: {
138
+ width: 4,
139
+ borderRadius: 2,
140
+ marginRight: 10,
141
+ },
142
+ logContent: {
143
+ flex: 1,
144
+ },
145
+ logHeader: {
146
+ flexDirection: 'row',
147
+ justifyContent: 'space-between',
148
+ alignItems: 'center',
149
+ marginBottom: 5,
150
+ },
151
+ actionText: {
152
+ fontSize: 13,
153
+ fontWeight: 'bold',
154
+ },
155
+ time: {
156
+ fontSize: 12,
157
+ color: '#888',
158
+ },
159
+ logMessage: {
160
+ fontSize: 14,
161
+ color: '#333',
162
+ lineHeight: 18,
163
+ fontFamily: 'monospace',
164
+ },
165
+ duration: {
166
+ fontSize: 12,
167
+ color: '#888',
168
+ marginTop: 4,
169
+ },
170
+ // Details Header Styles
171
+ detailsHeader: {
172
+ flexDirection: 'row',
173
+ alignItems: 'center',
174
+ paddingVertical: 10,
175
+ paddingHorizontal: 15,
176
+ borderBottomWidth: 1,
177
+ borderBottomColor: '#eee',
178
+ backgroundColor: '#f8f9fa',
179
+ },
180
+ backButton: {
181
+ paddingHorizontal: 10,
182
+ paddingVertical: 5,
183
+ borderRadius: 4,
184
+ backgroundColor: '#eee',
185
+ marginRight: 15,
186
+ },
187
+ backButtonText: {
188
+ color: '#333',
189
+ fontWeight: '500',
190
+ fontSize: 14,
191
+ },
192
+ headerTitle: {
193
+ fontSize: 16,
194
+ fontWeight: 'bold',
195
+ color: '#333',
196
+ },
197
+ })
198
+
199
+ export default SubViewNavigationLogs
@@ -0,0 +1,239 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ FlatList,
7
+ TouchableOpacity,
8
+ TextInput,
9
+ Platform,
10
+ } from 'react-native';
11
+
12
+ const SubViewThirdPartyLibs = ({ libraries = [] }) => {
13
+ const [expandedLibs, setExpandedLibs] = useState(new Set());
14
+ const [actionParams, setActionParams] = useState({});
15
+
16
+ // Set all libraries to expanded by default and set default product ID
17
+ useEffect(() => {
18
+ // Create a set of all library IDs to set them as expanded
19
+ const allLibIds = new Set(libraries.map(lib => lib.id));
20
+ setExpandedLibs(allLibIds);
21
+
22
+ // Initialize default product ID for all actions that might need it
23
+ const defaultParams = {};
24
+ libraries.forEach(lib => {
25
+ lib.actions.forEach(action => {
26
+ if (action.hasParam) {
27
+ defaultParams[`${lib.id}_${action.id}`] = 'default';
28
+ }
29
+ });
30
+ });
31
+ setActionParams(defaultParams);
32
+ }, [libraries]);
33
+
34
+ // Handle lib expansion/collapse
35
+ const toggleLibExpand = (libId) => {
36
+ setExpandedLibs(prev => {
37
+ const newSet = new Set(prev);
38
+ if (newSet.has(libId)) {
39
+ newSet.delete(libId);
40
+ } else {
41
+ newSet.add(libId);
42
+ }
43
+ return newSet;
44
+ });
45
+ };
46
+
47
+ // Execute library action
48
+ const executeAction = (action, libId) => {
49
+ try {
50
+ if (action.hasParam) {
51
+ // Get parameter value (if needed)
52
+ const paramValue = actionParams[`${libId}_${action.id}`] || 'default';
53
+ action.method(paramValue);
54
+ } else {
55
+ action.method();
56
+ }
57
+ // No alerts shown as per requirement
58
+ } catch (error) {
59
+ // Silent error handling as per requirement
60
+ console.error(`Failed to execute ${action.label}:`, error);
61
+ }
62
+ };
63
+
64
+ // Handle param input change
65
+ const handleParamChange = (libId, actionId, value) => {
66
+ setActionParams({
67
+ ...actionParams,
68
+ [`${libId}_${actionId}`]: value,
69
+ });
70
+ };
71
+
72
+ // Render a single library card
73
+ const renderLibraryItem = ({ item }) => {
74
+ const isExpanded = expandedLibs.has(item.id);
75
+ const isPlatformSupported = item.platform === 'both' ||
76
+ item.platform === Platform.OS;
77
+
78
+ if (!isPlatformSupported) return null;
79
+
80
+ return (
81
+ <View style={styles.libraryCard}>
82
+ <TouchableOpacity
83
+ style={styles.libraryHeader}
84
+ onPress={() => toggleLibExpand(item.id)}>
85
+ <View style={styles.libraryTitle}>
86
+ <Text style={styles.libraryName}>{item.name}</Text>
87
+ <Text style={styles.platformBadge}>
88
+ {item.platform === 'both' ? 'iOS & Android' : item.platform}
89
+ </Text>
90
+ </View>
91
+ <Text style={styles.expandIcon}>{isExpanded ? '▼' : '▶'}</Text>
92
+ </TouchableOpacity>
93
+
94
+ <Text style={styles.libraryDescription}>{item.description}</Text>
95
+
96
+ {isExpanded && (
97
+ <View style={styles.actionsContainer}>
98
+ {item.actions.map((action) => (
99
+ <View key={action.id} style={styles.actionItem}>
100
+ {action.hasParam && (
101
+ <TextInput
102
+ style={styles.paramInput}
103
+ placeholder={action.paramPlaceholder || 'Parameter'}
104
+ value={actionParams[`${item.id}_${action.id}`] || 'default'}
105
+ onChangeText={(text) =>
106
+ handleParamChange(item.id, action.id, text)
107
+ }
108
+ />
109
+ )}
110
+ <TouchableOpacity
111
+ style={styles.actionButton}
112
+ onPress={() => executeAction(action, item.id)}>
113
+ <Text style={styles.actionButtonText}>{action.label}</Text>
114
+ </TouchableOpacity>
115
+ </View>
116
+ ))}
117
+ </View>
118
+ )}
119
+ </View>
120
+ );
121
+ };
122
+
123
+ // Filter platform-supported libraries
124
+ const supportedLibraries = libraries.filter(
125
+ lib => lib.platform === 'both' || lib.platform === Platform.OS
126
+ );
127
+
128
+ return (
129
+ <View style={styles.container}>
130
+ {supportedLibraries.length === 0 ? (
131
+ <Text style={styles.emptyText}>
132
+ No debug libraries available for this platform
133
+ </Text>
134
+ ) : (
135
+ <FlatList
136
+ data={supportedLibraries}
137
+ renderItem={renderLibraryItem}
138
+ keyExtractor={(item) => item.id}
139
+ contentContainerStyle={styles.listContent}
140
+ />
141
+ )}
142
+ </View>
143
+ );
144
+ };
145
+
146
+ const styles = StyleSheet.create({
147
+ container: {
148
+ flex: 1,
149
+ backgroundColor: '#fff',
150
+ },
151
+ listContent: {
152
+ padding: 12,
153
+ },
154
+ emptyText: {
155
+ textAlign: 'center',
156
+ color: '#999',
157
+ marginTop: 20,
158
+ fontSize: 16,
159
+ },
160
+ libraryCard: {
161
+ backgroundColor: '#f8f9fa',
162
+ borderRadius: 8,
163
+ borderWidth: 1,
164
+ borderColor: '#e9ecef',
165
+ marginBottom: 16,
166
+ padding: 12,
167
+ elevation: 1,
168
+ shadowColor: '#000',
169
+ shadowOffset: { width: 0, height: 1 },
170
+ shadowOpacity: 0.1,
171
+ shadowRadius: 1,
172
+ },
173
+ libraryHeader: {
174
+ flexDirection: 'row',
175
+ justifyContent: 'space-between',
176
+ alignItems: 'center',
177
+ },
178
+ libraryTitle: {
179
+ flexDirection: 'row',
180
+ alignItems: 'center',
181
+ flex: 1,
182
+ },
183
+ libraryName: {
184
+ fontSize: 18,
185
+ fontWeight: 'bold',
186
+ color: '#333',
187
+ marginRight: 8,
188
+ },
189
+ platformBadge: {
190
+ fontSize: 12,
191
+ color: '#666',
192
+ backgroundColor: '#e9ecef',
193
+ paddingHorizontal: 8,
194
+ paddingVertical: 2,
195
+ borderRadius: 12,
196
+ overflow: 'hidden',
197
+ },
198
+ expandIcon: {
199
+ fontSize: 14,
200
+ color: '#666',
201
+ },
202
+ libraryDescription: {
203
+ marginTop: 8,
204
+ marginBottom: 12,
205
+ color: '#666',
206
+ fontSize: 14,
207
+ lineHeight: 20,
208
+ },
209
+ actionsContainer: {
210
+ marginTop: 8,
211
+ borderTopWidth: 1,
212
+ borderTopColor: '#eee',
213
+ paddingTop: 12,
214
+ },
215
+ actionItem: {
216
+ marginBottom: 8,
217
+ },
218
+ paramInput: {
219
+ borderWidth: 1,
220
+ borderColor: '#ddd',
221
+ borderRadius: 4,
222
+ padding: 8,
223
+ marginBottom: 8,
224
+ fontSize: 14,
225
+ },
226
+ actionButton: {
227
+ backgroundColor: '#0D96F2',
228
+ padding: 10,
229
+ borderRadius: 4,
230
+ alignItems: 'center',
231
+ },
232
+ actionButtonText: {
233
+ color: '#fff',
234
+ fontWeight: '500',
235
+ fontSize: 14,
236
+ },
237
+ });
238
+
239
+ export default SubViewThirdPartyLibs;
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "react-native-debug-toolkit",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A simple yet powerful debugging toolkit for React Native with a convenient floating UI for development",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
+ "podspec": "react-native-debug-toolkit.podspec",
7
8
  "scripts": {
8
9
  "test": "echo \"Error: no test specified\" && exit 1",
9
10
  "bundle": "react-native bundle --platform ios --dev false --entry-file index.js --bundle-output dist/main.jsbundle --assets-dest dist"
@@ -0,0 +1,25 @@
1
+ require 'json'
2
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
3
+
4
+ Pod::Spec.new do |s|
5
+ s.name = "react-native-debug-toolkit"
6
+ s.version = package['version']
7
+ s.summary = package['description']
8
+ s.homepage = package['repository']['url']
9
+ s.license = package['license']
10
+ s.author = package['author']
11
+ s.platform = :ios, "11.0"
12
+ s.source = { :git => package['repository']['url'], :tag => "#{s.version}" }
13
+ s.source_files = "ios/**/*.{h,m}"
14
+
15
+ s.dependency "React-Core"
16
+
17
+ # FLEX is only needed for debug builds
18
+ s.dependency "FLEX", "~> 5.0"
19
+
20
+ # DoraemonKit is only needed for debug builds
21
+ s.dependency "DoraemonKit/Core", "~> 3.0"
22
+
23
+ # This ensures FLEX and DoraemonKit are only included in debug builds
24
+ s.pod_target_xcconfig = { 'OTHER_CFLAGS' => '-DDebug=$(CONFIGURATION)' }
25
+ end
@@ -2,4 +2,14 @@
2
2
 
3
3
  module.exports = {
4
4
  // Let React Native's auto-linking handle all dependencies normally
5
+ dependencies: {
6
+ "react-native-debug-toolkit": {
7
+ platforms: {
8
+ ios: {
9
+ podspecPath: "./react-native-debug-toolkit.podspec",
10
+ sourceDir: "./ios"
11
+ }
12
+ }
13
+ }
14
+ }
5
15
  };