react-native-in-app-debugger 1.0.1 → 1.0.2

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 (4) hide show
  1. package/Api.jsx +131 -62
  2. package/README.md +3 -119
  3. package/index.jsx +116 -50
  4. package/package.json +6 -3
package/Api.jsx CHANGED
@@ -1,11 +1,25 @@
1
- import React, { useState } from 'react';
2
- import { Text, SectionList, TextInput, View, Alert, StyleSheet, TouchableOpacity } from 'react-native';
3
- import Clipboard from '@react-native-clipboard/clipboard';
1
+ import React, { useState } from "react";
2
+ import {
3
+ Text,
4
+ SectionList,
5
+ TextInput,
6
+ View,
7
+ Alert,
8
+ StyleSheet,
9
+ TouchableOpacity,
10
+ } from "react-native";
11
+ // import Clipboard from '@react-native-clipboard/clipboard';
12
+ let Clipboard;
13
+ try {
14
+ Clipboard = require("@react-native-clipboard/clipboard");
15
+ } catch (error) {
16
+ console.error("Error importing Clipboard:", error);
17
+ }
4
18
 
5
19
  const MAX_URL_LENGTH = 100;
6
20
 
7
21
  const Row = ({ item }) => {
8
- const [tab, setTab] = useState('response-body');
22
+ const [tab, setTab] = useState("response-body");
9
23
  const hasResponse = item.response;
10
24
  const Tab = ({ value, label }) => {
11
25
  const isSelected = value === tab;
@@ -13,32 +27,49 @@ const Row = ({ item }) => {
13
27
  <TouchableOpacity
14
28
  activeOpacity={isSelected ? 1 : 0.7}
15
29
  onPress={() => setTab(value)}
16
- style={[styles.selectionTab, { backgroundColor: isSelected ? 'white' : undefined }]}
30
+ style={[
31
+ styles.selectionTab,
32
+ { backgroundColor: isSelected ? "white" : undefined },
33
+ ]}
17
34
  >
18
- <Text style={{ color: isSelected ? '#000' : '#fff', textAlign: 'center' }}>{label}</Text>
35
+ <Text
36
+ style={{ color: isSelected ? "#000" : "#fff", textAlign: "center" }}
37
+ >
38
+ {label}
39
+ </Text>
19
40
  </TouchableOpacity>
20
41
  );
21
42
  };
22
43
  return (
23
44
  <View style={styles.details}>
24
45
  {item.request.url.length > MAX_URL_LENGTH && (
25
- <Text style={{ color: '#ffffff99', paddingVertical: 20 }}>{item.request.url}</Text>
46
+ <Text style={{ color: "#ffffff99", paddingVertical: 20 }}>
47
+ {item.request.url}
48
+ </Text>
26
49
  )}
27
50
  <View>
28
- <View style={{ flexDirection: 'row' }}>
29
- <Tab value='response-body' label='Response Body' />
30
- {!!item.request.data && <Tab value='request-body' label='Request Body' />}
31
- <Tab value='request-header' label='Request Header' />
51
+ <View style={{ flexDirection: "row" }}>
52
+ <Tab value="response-body" label="Response Body" />
53
+ {!!item.request.data && (
54
+ <Tab value="request-body" label="Request Body" />
55
+ )}
56
+ <Tab value="request-header" label="Request Header" />
32
57
  </View>
33
58
 
34
- {tab === 'response-body' && hasResponse && (
35
- <Text style={{ color: 'white' }}>{JSON.stringify(item.response.data, undefined, 4)}</Text>
59
+ {tab === "response-body" && hasResponse && (
60
+ <Text style={{ color: "white" }}>
61
+ {JSON.stringify(item.response.data, undefined, 4)}
62
+ </Text>
36
63
  )}
37
- {tab === 'request-body' && (
38
- <Text style={{ color: 'white' }}>{JSON.stringify(item.request.data, undefined, 4)}</Text>
64
+ {tab === "request-body" && (
65
+ <Text style={{ color: "white" }}>
66
+ {JSON.stringify(item.request.data, undefined, 4)}
67
+ </Text>
39
68
  )}
40
- {tab === 'request-header' && (
41
- <Text style={{ color: 'white' }}>{JSON.stringify(item.request.headers, undefined, 4)}</Text>
69
+ {tab === "request-header" && (
70
+ <Text style={{ color: "white" }}>
71
+ {JSON.stringify(item.request.headers, undefined, 4)}
72
+ </Text>
42
73
  )}
43
74
  </View>
44
75
  </View>
@@ -46,48 +77,74 @@ const Row = ({ item }) => {
46
77
  };
47
78
 
48
79
  export default (props) => {
49
- const [filter, setFilter] = useState('');
80
+ const [filter, setFilter] = useState("");
50
81
  const [errorOnly, setErrorOnly] = useState(false);
51
82
  const [filterUrlOnly, setFilterUrlOnly] = useState(true);
52
83
  const [expands, setExpands] = useState({});
53
- const apis = props.apis.filter((a) => !errorOnly || a.response?.status < 200 || a.response?.status >= 400);
84
+ const apis = props.apis.filter(
85
+ (a) => !errorOnly || a.response?.status < 200 || a.response?.status >= 400
86
+ );
54
87
 
55
- const hasError = apis.some((a) => a.response?.status < 200 || a.response?.status >= 400);
88
+ const hasError = apis.some(
89
+ (a) => a.response?.status < 200 || a.response?.status >= 400
90
+ );
56
91
 
57
92
  return (
58
93
  <>
59
- <View style={{ flexDirection: 'row', paddingLeft: 5, alignItems: 'center', gap: 5 }}>
94
+ <View
95
+ style={{
96
+ flexDirection: "row",
97
+ paddingLeft: 5,
98
+ alignItems: "center",
99
+ gap: 5,
100
+ }}
101
+ >
60
102
  {!!apis.length && !filter && (
61
103
  <TouchableOpacity
62
- style={{ padding: 5, backgroundColor: 'white', borderRadius: 5 }}
104
+ style={{ padding: 5, backgroundColor: "white", borderRadius: 5 }}
63
105
  onPress={() =>
64
- Alert.alert('Are you sure', 'You want to clear all logs', [
65
- { text: 'Delete', onPress: props.clear, style: 'cancel' },
66
- { text: 'Cancel' },
106
+ Alert.alert("Are you sure", "You want to clear all logs", [
107
+ { text: "Delete", onPress: props.clear, style: "cancel" },
108
+ { text: "Cancel" },
67
109
  ])
68
110
  }
69
111
  >
70
- <Text style={{ color: 'black' }}>Clear {apis.length} APIs</Text>
112
+ <Text style={{ color: "black" }}>Clear {apis.length} APIs</Text>
71
113
  </TouchableOpacity>
72
114
  )}
73
115
  {hasError && !filter && (
74
- <TouchableOpacity style={{ padding: 5 }} onPress={() => setErrorOnly((v) => !v)}>
75
- <Text style={{ color: 'red', textDecorationLine: errorOnly ? 'line-through' : undefined }}>Error Only</Text>
116
+ <TouchableOpacity
117
+ style={{ padding: 5 }}
118
+ onPress={() => setErrorOnly((v) => !v)}
119
+ >
120
+ <Text
121
+ style={{
122
+ color: "red",
123
+ textDecorationLine: errorOnly ? "line-through" : undefined,
124
+ }}
125
+ >
126
+ Error Only
127
+ </Text>
76
128
  </TouchableOpacity>
77
129
  )}
78
- <View style={{ flexDirection: 'row', flex: 1 }}>
130
+ <View style={{ flexDirection: "row", flex: 1 }}>
79
131
  <TextInput
80
132
  value={filter}
81
- placeholder='Filter...'
82
- clearButtonMode='always'
83
- placeholderTextColor='grey'
84
- style={{ paddingHorizontal: 5, color: 'white', flex: 1 }}
133
+ placeholder="Filter..."
134
+ clearButtonMode="always"
135
+ placeholderTextColor="grey"
136
+ style={{ paddingHorizontal: 5, color: "white", flex: 1 }}
85
137
  onChangeText={(t) => setFilter(t.toLowerCase())}
86
138
  />
87
139
  </View>
88
140
  {!!filter && (
89
- <TouchableOpacity style={{ padding: 5 }} onPress={() => setFilterUrlOnly((v) => !v)}>
90
- <Text style={{ color: '#ffffff88' }}>{filterUrlOnly ? 'by URL' : 'by URL & body'}</Text>
141
+ <TouchableOpacity
142
+ style={{ padding: 5 }}
143
+ onPress={() => setFilterUrlOnly((v) => !v)}
144
+ >
145
+ <Text style={{ color: "#ffffff88" }}>
146
+ {filterUrlOnly ? "by URL" : "by URL & body"}
147
+ </Text>
91
148
  </TouchableOpacity>
92
149
  )}
93
150
  </View>
@@ -99,22 +156,24 @@ export default (props) => {
99
156
  .filter((a) =>
100
157
  !filter || filterUrlOnly
101
158
  ? a.request.url.includes(filter)
102
- : JSON.stringify(a).toLowerCase().includes(filter),
159
+ : JSON.stringify(a).toLowerCase().includes(filter)
103
160
  )
104
161
  .map((data) => ({ data: [data], id: data.id }))}
105
- renderItem={(i) => (expands[i.item.id] ? <Row {...i} /> : <View style={{ height: 20 }} />)}
162
+ renderItem={(i) =>
163
+ expands[i.item.id] ? <Row {...i} /> : <View style={{ height: 20 }} />
164
+ }
106
165
  renderSectionHeader={({ section: { data } }) => {
107
166
  const item = data[0];
108
167
  const hasResponse = !!item.response;
109
168
 
110
169
  let duration = 0;
111
170
  if (item.response?.datetime) {
112
- let [hr, min, sec] = item.request.datetime.split(' ')[0].split(':');
171
+ let [hr, min, sec] = item.request.datetime.split(" ")[0].split(":");
113
172
  const start = new Date();
114
173
  start.setHours(hr);
115
174
  start.setMinutes(min);
116
175
  start.setSeconds(sec);
117
- [hr, min, sec] = item.response.datetime.split(' ')[0].split(':');
176
+ [hr, min, sec] = item.response.datetime.split(" ")[0].split(":");
118
177
  const end = new Date();
119
178
  end.setHours(hr);
120
179
  end.setMinutes(min);
@@ -128,20 +187,24 @@ export default (props) => {
128
187
  selectable
129
188
  style={{
130
189
  flex: 1,
131
- color: hasResponse ? (item.response.error ? 'red' : 'white') : 'yellow',
190
+ color: hasResponse
191
+ ? item.response.error
192
+ ? "red"
193
+ : "white"
194
+ : "yellow",
132
195
  marginVertical: 10,
133
196
  }}
134
197
  >
135
198
  <Text style={{ opacity: 0.7 }}>
136
199
  {item.request.method +
137
- ` (${item.response?.status ?? 'no response'})` +
138
- ' - ' +
200
+ ` (${item.response?.status ?? "no response"})` +
201
+ " - " +
139
202
  item.request.datetime +
140
- (hasResponse ? ' - ' + duration + ' second(s)' : '') +
141
- '\n'}
203
+ (hasResponse ? " - " + duration + " second(s)" : "") +
204
+ "\n"}
142
205
  </Text>
143
206
  {item.request.url.slice(0, MAX_URL_LENGTH)}
144
- {item.request.url.length > MAX_URL_LENGTH && '.......'}
207
+ {item.request.url.length > MAX_URL_LENGTH && "......."}
145
208
  </Text>
146
209
  <View style={{ gap: 4 }}>
147
210
  <TouchableOpacity
@@ -155,18 +218,24 @@ export default (props) => {
155
218
  }
156
219
  style={styles.actionButton}
157
220
  >
158
- <Text style={{ color: 'black' }}>{isExpand ? 'Hide' : 'Show'}</Text>
159
- </TouchableOpacity>
160
- <TouchableOpacity
161
- onPress={() => {
162
- const content = { ...item };
163
- delete content.id;
164
- Clipboard.setString(JSON.stringify(content, undefined, 4));
165
- }}
166
- style={styles.actionButton}
167
- >
168
- <Text style={{ color: 'black' }}>Copy</Text>
221
+ <Text style={{ color: "black" }}>
222
+ {isExpand ? "Hide" : "Show"}
223
+ </Text>
169
224
  </TouchableOpacity>
225
+ {!!Clipboard && (
226
+ <TouchableOpacity
227
+ onPress={() => {
228
+ const content = { ...item };
229
+ delete content.id;
230
+ Clipboard.setString(
231
+ JSON.stringify(content, undefined, 4)
232
+ );
233
+ }}
234
+ style={styles.actionButton}
235
+ >
236
+ <Text style={{ color: "black" }}>Copy</Text>
237
+ </TouchableOpacity>
238
+ )}
170
239
  </View>
171
240
  </View>
172
241
  );
@@ -179,18 +248,18 @@ export default (props) => {
179
248
  const styles = StyleSheet.create({
180
249
  details: {
181
250
  padding: 5,
182
- backgroundColor: '#171717',
251
+ backgroundColor: "#171717",
183
252
  paddingTop: 10,
184
253
  paddingBottom: 40,
185
254
  },
186
- actionButton: { backgroundColor: 'white', borderRadius: 5, padding: 4 },
255
+ actionButton: { backgroundColor: "white", borderRadius: 5, padding: 4 },
187
256
  rowHeader: {
188
- flexDirection: 'row',
257
+ flexDirection: "row",
189
258
  gap: 5,
190
- backgroundColor: 'black',
259
+ backgroundColor: "black",
191
260
  padding: 5,
192
261
  paddingTop: 20,
193
- shadowColor: 'black',
262
+ shadowColor: "black",
194
263
  shadowOffset: {
195
264
  width: 0,
196
265
  height: 2,
@@ -202,7 +271,7 @@ const styles = StyleSheet.create({
202
271
  zIndex: 99,
203
272
  },
204
273
  selectionTab: {
205
- borderBottomColor: 'white',
274
+ borderBottomColor: "white",
206
275
  borderBottomWidth: 2,
207
276
  flex: 1,
208
277
  borderTopEndRadius: 10,
package/README.md CHANGED
@@ -1,80 +1,15 @@
1
1
  # react-native-in-app-debugger
2
2
 
3
- Extended version of react native flat list with many built in function such as search, pull to refresh, no data available message if empty row
3
+ summary
4
4
 
5
- Caution:
6
-
7
- `renderItem` props return `item` and `index` parameters
8
- `item` parameter returns a single element in `item` array. But if search text is not empty dan `highlightColor` props is set to any color, `item` parameter will return new structure of JSON object (in order to render highlighted text in jsx). This might break your logic. Therefore, if you want to access original structure of your data, it will be under `item.cleanData`. Remember, `item.cleanData` only exist if `highlightColor` props and search textfield is not empty (user is searching)
9
5
 
10
6
  Usage :
11
7
 
12
8
  ```
13
- import React, {useRef} from 'react';
14
- import { Text, SafeAreaView, TouchableOpacity } from 'react-native';
15
- import CompleteFlatList from 'react-native-complete-flatlist';
16
-
17
- const list = [
18
- { name: 'Fattah', status: 'Active', time: '8:10 PM', date: '1 Jan 2018' },
19
- { name: 'Syah', status: 'Active', time: '9:14 PM', date: '1 Dec 2018' },
20
- { name: 'Izzat', status: 'Active', time: '8:15 PM', date: '1 Jan 2018' },
21
- { name: 'Ali', status: 'Active', time: '8:10 PM', date: '1 Jan 2018' },
22
- { name: 'Abu', status: 'Active', time: '8:11 PM', date: '1 Jan 2018' },
23
- { name: 'Fitri', status: 'Active', time: '8:20 PM', date: '1 Jan 2018' },
24
- { name: 'Armi', status: 'Active', time: '8:33 PM', date: '1 Jan 2018' },
25
- { name: 'Eidit', status: 'Active', time: '9:10 PM', date: '1 Jan 2018' },
26
- { name: 'Hamdan', status: 'Active', time: '10:10 PM', date: '1 Jan 2018' },
27
- {
28
- name: 'Muhyiddeen',
29
- status: 'Blocked',
30
- time: '10:10 PM',
31
- date: '9 Feb 2018',
32
- },
33
- ];
34
-
35
- const App = () => {
36
- const ref = useRef();
37
- const renderItem = ({item, index}) => {
38
- const data = item.cleanData ? item.cleanData : item;
39
-
40
- console.log('item (if search bar is not empty and prop highlightColor is not empty, item will contains extra data to enable highlight feature)', item);
41
- console.log('cleanData (if search bar is not empty and prop highlightColor is not empty, cleanData will contain original data structure without extra data)', item.cleanData);
42
-
43
-
44
- console.log('this is index number : ' + index);
45
-
46
- console.log(data + ' this is original data');
47
-
48
- return <Text>{item.name}</Text>;
49
- };
50
-
51
- return (
52
- <SafeAreaView style={{ flex: 1 }}>
53
- <CompleteFlatList
54
- searchKey={['name', 'status', 'time', 'date']}
55
- pullToRefreshCallback={() => console.log('refreshing')}
56
- data={list}
57
- // renderSeparator={null}
58
- ref={ref}
59
- highlightColor="yellow"
60
- renderItem={renderItem}
61
- />
62
- <TouchableOpacity onPress={() => ref.current.clearSearch()} style={{ padding: 5 }}>
63
- <Text>Clear Search</Text>
64
- </TouchableOpacity>
65
- </SafeAreaView>
66
- );
67
- };
68
-
69
- export default App;
70
-
71
-
9
+ import React from 'react';
72
10
 
73
11
  ```
74
12
 
75
- ### Upgrading from V 1.x.x to V 2.x.x
76
-
77
- Change from `renderItem={(data, index) => {} }` to `renderItem={({item, index, separators}) => {} }` (similar like the on in Original Flatlist)
78
13
 
79
14
  ### Properties
80
15
 
@@ -82,56 +17,5 @@ All FlatList props should work plus props mentioned below
82
17
 
83
18
  | Prop | Type | Description | Default | Required |
84
19
  | ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
85
- | `showSearch` | boolean | If `true` (and `searchKey` prop is defined), search bar will be shown. | true | Optional |
86
- | `isJelly` | boolean | If `true`, when user scroll, the list will expand a lil bit, and when user stop drag, the list will back to original size (iMessage on iPhone style) | false | Optional |
87
- | `slide` | string | Animation how every items come into the list. Can be "none", "left" or "right" | `none` | Optional |
88
- | `data` | array of objects | Data to be rendered in the list | [] | Required (come on, ofcourse u need data for this) |
89
- | `backgroundStyles` | style object | Style of the flatlist background | null | Optional |
90
- | `searchBarBackgroundStyles` | style object | Style of the searchbar background | null | Optional |
91
- | `pullToRefreshCallback` | function | Callback function when user pull to refresh | null | Optional (Pull to refresh will not be available if this is not supplied |
92
- | `isLoading` | boolean | if true, the loading will be shown on top of the list. | false | Optional |
93
- | `renderItem` | function that return a JSX element (Just like RN's ListView and FlatList) | Template of a row in the Flat List | null (open for PR if anyone wish to make default template for this) | Required (since I dont do default template yet) |
94
- | `renderSeparator` | function that return a JSX element to be rendered between rows(Just like RN's ListView and FlatList) | Template of separator in the Flat List | `() => <View style={{ height: 1, width: "80%", alignSelf: "center", backgroundColor: "#f2f2f2" }} />` | Optional |
95
- | `placeholder` | string | Placeholder of search field | "Search ..." | Optional |
96
- | `searchTextInputStyle` | object (style for React Native's TextInput component) | style for search field | null | Optional |
97
- | `highlightColor` | color | color of higlighted words background when match search keyword. Please read the pre caution if using this prop on top of the readme | yellow | Optional |
98
- | `searchKey` | array of string | This should be name of keys available in data which will be use to search. If this prop is not supplied, search text input will not be rendered. `**Warning: nested key not yet supported` | [] | Optional (if not supplied, search field will not appear) |
99
- | `elementBetweenSearchAndList` | JSX element | What to render between searchbar and the list | null | Optional |
100
- | `refreshOnLoad` | boolean | If `true`, prop `pullToRefreshCallback` will be called if available | true | Optional |
101
- | `onSearch` | function that will replace `pullToRefreshCallback` | If exist, `pullToRefreshCallback` will be overrided. This will not triggered on key press, but on return key pressed. This props is introduced if search trigger result from API. If you just want local search (search from existing array), this props is not needed. `onSearch` will automatic get `keyword` parameter | ()=>null | Optional |
102
-
103
- ### Methods
104
-
105
- If you have `ref` to the component,
106
- ```
107
- const completeFlatList = useRef();
108
- ...
109
- <CompleteFlatList
110
- ...
111
- ref={completeFlatList}
112
- ...
113
- />
114
-
115
- ```
116
-
117
- or in component based
118
-
119
- ```
120
-
121
- <CompleteFlatList
122
- ...
123
- ref={c => this.completeFlatList = c}
124
- ...
125
- />
126
- ```
127
-
128
- you can use any method(s) below:
129
- ```completeFlatList.current.methodName()```
130
-
131
- or in component based
132
-
133
- ```this.completeFlatList.methodName()```
20
+ | `env` | string | Any text | | Optional |
134
21
 
135
- | Method | Description |
136
- | ----------- | ----------------------------------- |
137
- | clearSearch | Clear search input programmatically |
package/index.jsx CHANGED
@@ -1,38 +1,76 @@
1
1
  /* eslint-disable react-hooks/rules-of-hooks */
2
2
  // hooks are prevented to be called conditionally, but in this case, bundle id / package name will never changed in run time, so it is safe to call the hooks under that condition
3
3
 
4
- import useAnimation from './useAnimation';
5
- import React, { useState } from 'react';
6
- import { Animated, Text, StyleSheet, TouchableOpacity, View, SafeAreaView, Dimensions } from 'react-native';
7
- import DeviceInfo from 'react-native-device-info';
8
- import Variables from './Variables';
9
- import Api from './Api';
10
- import useApiInterceptor from './useApiInterceptor';
4
+ import React, { useState } from "react";
5
+ import {
6
+ Animated,
7
+ Text,
8
+ StyleSheet,
9
+ TouchableOpacity,
10
+ View,
11
+ SafeAreaView,
12
+ Dimensions,
13
+ } from "react-native";
14
+ // const DeviceInfo = React.lazy(() =>
15
+ // import("react-native-device-info").catch(() => ({ default: null }))
16
+ // );
11
17
 
12
- const dimension = Dimensions.get('window');
18
+ let DeviceInfo;
19
+ try {
20
+ DeviceInfo = require("react-native-device-info");
21
+ } catch (error) {
22
+ console.error("Error importing DeviceInfo:", error);
23
+ }
13
24
 
14
- const Label = (props) => <Text {...props} numberOfLines={1} ellipsizeMode='tail' style={[styles.label, props.style]} />;
25
+ import useAnimation from "./useAnimation";
26
+ import Variables from "./Variables";
27
+ import Api from "./Api";
28
+ import useApiInterceptor from "./useApiInterceptor";
29
+
30
+ const dimension = Dimensions.get("window");
31
+
32
+ const version = DeviceInfo?.getReadableVersion() || "";
33
+
34
+ const Label = (props) => (
35
+ <Text
36
+ {...props}
37
+ numberOfLines={1}
38
+ ellipsizeMode="tail"
39
+ style={[styles.label, props.style]}
40
+ />
41
+ );
15
42
 
16
43
  export default ({ variables, env }) => {
17
44
  const { apis, clear } = useApiInterceptor();
18
45
 
19
- const [tab, setTab] = useState('api');
46
+ const [tab, setTab] = useState("api");
20
47
 
21
48
  const errors = apis.filter((a) => a.response?.error).length;
22
49
  const numPendingApiCalls = apis.filter((a) => !a.response).length;
23
- let badgeHeight = 30;
24
- if (variables.GIT_BRANCH) badgeHeight += 10;
25
- if (variables.BUILD_DATE_TIME) badgeHeight += 10;
50
+ let badgeHeight = 20;
51
+ if (variables?.GIT_BRANCH) badgeHeight += 10;
52
+ if (variables?.BUILD_DATE_TIME) badgeHeight += 10;
53
+ const hasEnvOrVersion = !!env || !!version;
54
+ if (hasEnvOrVersion) badgeHeight += 10;
55
+ if (DeviceInfo) badgeHeight += 10;
26
56
 
27
- const { translateX, translateY, borderRadius, width, height, isOpen, panResponder, setIsOpen } =
28
- useAnimation(badgeHeight);
57
+ const {
58
+ translateX,
59
+ translateY,
60
+ borderRadius,
61
+ width,
62
+ height,
63
+ isOpen,
64
+ panResponder,
65
+ setIsOpen,
66
+ } = useAnimation(badgeHeight);
29
67
  return (
30
68
  <Animated.View
31
69
  style={{
32
70
  transform: [{ translateX }, { translateY }],
33
- position: 'absolute',
71
+ position: "absolute",
34
72
  borderRadius,
35
- backgroundColor: '#000000' + (isOpen ? 'dd' : 'bb'),
73
+ backgroundColor: "#000000" + (isOpen ? "dd" : "bb"),
36
74
  height,
37
75
  width,
38
76
  }}
@@ -42,46 +80,69 @@ export default ({ variables, env }) => {
42
80
  <TouchableOpacity onPress={() => setIsOpen(true)} style={styles.box}>
43
81
  <View style={styles.badgeContainer}>
44
82
  {!!numPendingApiCalls && (
45
- <View style={[styles.badge, { backgroundColor: 'orange' }]}>
46
- <Text style={{ fontSize: 8, color: 'white' }}>{numPendingApiCalls}</Text>
83
+ <View style={[styles.badge, { backgroundColor: "orange" }]}>
84
+ <Text style={{ fontSize: 8, color: "white" }}>
85
+ {numPendingApiCalls}
86
+ </Text>
47
87
  </View>
48
88
  )}
49
89
  {!!errors && (
50
- <View style={[styles.badge, { backgroundColor: 'red' }]}>
51
- <Text style={{ fontSize: 8, color: 'white' }}>{errors}</Text>
90
+ <View style={[styles.badge, { backgroundColor: "red" }]}>
91
+ <Text style={{ fontSize: 8, color: "white" }}>{errors}</Text>
52
92
  </View>
53
93
  )}
54
94
  </View>
55
- <Label>{env + ' ' + DeviceInfo.getReadableVersion()}</Label>
56
- <Label style={{ fontSize: 6 }}>{DeviceInfo.getDeviceId() + ' ' + DeviceInfo.getSystemVersion()}</Label>
57
- <Label style={{ fontSize: 6 }}>{dimension.width + 'x' + dimension.height}</Label>
58
- {variables.GIT_BRANCH && <Label style={{ fontSize: 6 }}>{variables.GIT_BRANCH}</Label>}
59
- {variables.BUILD_DATE_TIME && <Label style={{ fontSize: 6 }}>{variables.BUILD_DATE_TIME}</Label>}
95
+ {(!!env || !!version) && (
96
+ <Label>{(env || "") + (env ? " " : "") + version}</Label>
97
+ )}
98
+ {!!DeviceInfo && (
99
+ <Label style={{ fontSize: 6 }}>
100
+ {DeviceInfo.getDeviceId() + " " + DeviceInfo.getSystemVersion()}
101
+ </Label>
102
+ )}
103
+ <Label style={{ fontSize: 6 }}>
104
+ {dimension.width + "x" + dimension.height}
105
+ </Label>
106
+ {variables?.GIT_BRANCH && (
107
+ <Label style={{ fontSize: 6 }}>{variables.GIT_BRANCH}</Label>
108
+ )}
109
+ {variables?.BUILD_DATE_TIME && (
110
+ <Label style={{ fontSize: 6 }}>{variables.BUILD_DATE_TIME}</Label>
111
+ )}
60
112
  </TouchableOpacity>
61
113
  ) : (
62
114
  <SafeAreaView style={{ flex: 1 }}>
63
- <View style={{ flexDirection: 'row', padding: 5 }}>
64
- <View style={{ flex: 1, flexDirection: 'row' }}>
65
- {['api', 'env'].map((t) => {
66
- const isSelected = t === tab;
67
- return (
68
- <TouchableOpacity
69
- onPress={() => setTab(t)}
70
- activeOpacity={isSelected ? 1 : 0.7}
71
- key={t}
72
- style={{ flex: 1, borderBottomWidth: +isSelected, borderColor: 'white' }}
73
- >
74
- <Text style={{ color: 'white', textAlign: 'center' }}>{t.toUpperCase()}</Text>
75
- </TouchableOpacity>
76
- );
77
- })}
115
+ <View style={{ flexDirection: "row", padding: 5 }}>
116
+ <View style={{ flex: 1, flexDirection: "row" }}>
117
+ {!!variables &&
118
+ ["api", "variables"].map((t) => {
119
+ const isSelected = t === tab;
120
+ return (
121
+ <TouchableOpacity
122
+ onPress={() => setTab(t)}
123
+ activeOpacity={isSelected ? 1 : 0.7}
124
+ key={t}
125
+ style={{
126
+ flex: 1,
127
+ borderBottomWidth: +isSelected,
128
+ borderColor: "white",
129
+ }}
130
+ >
131
+ <Text style={{ color: "white", textAlign: "center" }}>
132
+ {t.toUpperCase()}
133
+ </Text>
134
+ </TouchableOpacity>
135
+ );
136
+ })}
78
137
  </View>
79
138
  <TouchableOpacity onPress={() => setIsOpen(false)}>
80
139
  <Text style={styles.close}>X</Text>
81
140
  </TouchableOpacity>
82
141
  </View>
83
- {tab === 'env' && <Variables variables={variables} />}
84
- {tab === 'api' && <Api apis={apis} clear={clear} />}
142
+ {tab === "variables" && !!variables && (
143
+ <Variables variables={variables} />
144
+ )}
145
+ {tab === "api" && <Api apis={apis} clear={clear} />}
85
146
  </SafeAreaView>
86
147
  )}
87
148
  </Animated.View>
@@ -90,22 +151,27 @@ export default ({ variables, env }) => {
90
151
 
91
152
  const styles = StyleSheet.create({
92
153
  box: {
93
- justifyContent: 'center',
94
- width: '100%',
95
- height: '100%',
154
+ justifyContent: "center",
155
+ width: "100%",
156
+ height: "100%",
96
157
  },
97
- label: { color: 'white', textAlign: 'center', fontSize: 8 },
158
+ label: { color: "white", textAlign: "center", fontSize: 8 },
98
159
  badgeContainer: {
99
160
  gap: 3,
100
- flexDirection: 'row',
161
+ flexDirection: "row",
101
162
  top: -8,
102
163
  right: -3,
103
- position: 'absolute',
164
+ position: "absolute",
104
165
  zIndex: 999,
105
166
  },
106
167
  badge: {
107
168
  padding: 4,
108
169
  borderRadius: 999,
109
170
  },
110
- close: { color: 'white', fontWeight: 'bold', fontSize: 16, paddingHorizontal: 10 },
171
+ close: {
172
+ color: "white",
173
+ fontWeight: "bold",
174
+ fontSize: 16,
175
+ paddingHorizontal: 10,
176
+ },
111
177
  });
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "react-native-in-app-debugger",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "index.jsx",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1",
8
- "publish": "npm publish --access=public"
8
+ "deploy": "npm publish --access=public"
9
9
  },
10
- "keywords": ["debugger"],
10
+ "devDependencies": {},
11
+ "keywords": [
12
+ "debugger"
13
+ ],
11
14
  "author": "Fattah Muhyiddeen <fattahmuhyiddeen@gmail.com>",
12
15
  "license": "MIT"
13
16
  }