rn-backstage 1.1.0 → 1.2.1
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 +41 -19
- package/lib/commonjs/Backstage.js +42 -31
- package/lib/commonjs/Backstage.js.map +1 -1
- package/lib/commonjs/ThemeContext.js +43 -0
- package/lib/commonjs/ThemeContext.js.map +1 -0
- package/lib/commonjs/components/BackstagePanel.js +38 -16
- package/lib/commonjs/components/BackstagePanel.js.map +1 -1
- package/lib/commonjs/components/FlagsTab.js +256 -0
- package/lib/commonjs/components/FlagsTab.js.map +1 -0
- package/lib/commonjs/components/FloatingPill.js +4 -2
- package/lib/commonjs/components/FloatingPill.js.map +1 -1
- package/lib/commonjs/components/InfoTab.js +73 -107
- package/lib/commonjs/components/InfoTab.js.map +1 -1
- package/lib/commonjs/components/JsonTreeView.js +39 -34
- package/lib/commonjs/components/JsonTreeView.js.map +1 -1
- package/lib/commonjs/components/LogItem.js +33 -29
- package/lib/commonjs/components/LogItem.js.map +1 -1
- package/lib/commonjs/components/LogsTab.js +37 -42
- package/lib/commonjs/components/LogsTab.js.map +1 -1
- package/lib/commonjs/components/NetworkItem.js +111 -135
- package/lib/commonjs/components/NetworkItem.js.map +1 -1
- package/lib/commonjs/components/NetworkTab.js +48 -49
- package/lib/commonjs/components/NetworkTab.js.map +1 -1
- package/lib/commonjs/components/TabBar.js +8 -5
- package/lib/commonjs/components/TabBar.js.map +1 -1
- package/lib/commonjs/constants.js +24 -1
- package/lib/commonjs/constants.js.map +1 -1
- package/lib/commonjs/index.js +19 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.js +1 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/Backstage.js +42 -31
- package/lib/module/Backstage.js.map +1 -1
- package/lib/module/ThemeContext.js +37 -0
- package/lib/module/ThemeContext.js.map +1 -0
- package/lib/module/components/BackstagePanel.js +40 -18
- package/lib/module/components/BackstagePanel.js.map +1 -1
- package/lib/module/components/FlagsTab.js +251 -0
- package/lib/module/components/FlagsTab.js.map +1 -0
- package/lib/module/components/FloatingPill.js +5 -3
- package/lib/module/components/FloatingPill.js.map +1 -1
- package/lib/module/components/InfoTab.js +73 -107
- package/lib/module/components/InfoTab.js.map +1 -1
- package/lib/module/components/JsonTreeView.js +42 -38
- package/lib/module/components/JsonTreeView.js.map +1 -1
- package/lib/module/components/LogItem.js +35 -31
- package/lib/module/components/LogItem.js.map +1 -1
- package/lib/module/components/LogsTab.js +38 -43
- package/lib/module/components/LogsTab.js.map +1 -1
- package/lib/module/components/NetworkItem.js +113 -137
- package/lib/module/components/NetworkItem.js.map +1 -1
- package/lib/module/components/NetworkTab.js +49 -50
- package/lib/module/components/NetworkTab.js.map +1 -1
- package/lib/module/components/TabBar.js +10 -7
- package/lib/module/components/TabBar.js.map +1 -1
- package/lib/module/constants.js +23 -0
- package/lib/module/constants.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/Backstage.d.ts.map +1 -1
- package/lib/typescript/ThemeContext.d.ts +11 -0
- package/lib/typescript/ThemeContext.d.ts.map +1 -0
- package/lib/typescript/components/BackstagePanel.d.ts +4 -1
- package/lib/typescript/components/BackstagePanel.d.ts.map +1 -1
- package/lib/typescript/components/FlagsTab.d.ts +9 -0
- package/lib/typescript/components/FlagsTab.d.ts.map +1 -0
- package/lib/typescript/components/FloatingPill.d.ts.map +1 -1
- package/lib/typescript/components/InfoTab.d.ts +1 -0
- package/lib/typescript/components/InfoTab.d.ts.map +1 -1
- package/lib/typescript/components/JsonTreeView.d.ts.map +1 -1
- package/lib/typescript/components/LogItem.d.ts +1 -0
- package/lib/typescript/components/LogItem.d.ts.map +1 -1
- package/lib/typescript/components/LogsTab.d.ts +1 -0
- package/lib/typescript/components/LogsTab.d.ts.map +1 -1
- package/lib/typescript/components/NetworkItem.d.ts +1 -0
- package/lib/typescript/components/NetworkItem.d.ts.map +1 -1
- package/lib/typescript/components/NetworkTab.d.ts +1 -0
- package/lib/typescript/components/NetworkTab.d.ts.map +1 -1
- package/lib/typescript/components/TabBar.d.ts.map +1 -1
- package/lib/typescript/constants.d.ts +1 -0
- package/lib/typescript/constants.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +3 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +18 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Backstage.tsx +41 -31
- package/src/ThemeContext.tsx +38 -0
- package/src/components/BackstagePanel.tsx +84 -56
- package/src/components/FlagsTab.tsx +198 -0
- package/src/components/FloatingPill.tsx +6 -3
- package/src/components/InfoTab.tsx +152 -186
- package/src/components/JsonTreeView.tsx +53 -73
- package/src/components/LogItem.tsx +55 -100
- package/src/components/LogsTab.tsx +110 -132
- package/src/components/NetworkItem.tsx +306 -417
- package/src/components/NetworkTab.tsx +129 -163
- package/src/components/TabBar.tsx +51 -47
- package/src/constants.ts +23 -0
- package/src/index.ts +3 -0
- package/src/types.ts +25 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useState } from 'react'
|
|
1
|
+
import React, { useCallback, useMemo, useState } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
LayoutAnimation,
|
|
4
4
|
Platform,
|
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
UIManager,
|
|
9
9
|
View,
|
|
10
10
|
} from 'react-native'
|
|
11
|
-
import {
|
|
11
|
+
import { MonospaceFont } from '../constants'
|
|
12
|
+
import { useBackstageTheme } from '../ThemeContext'
|
|
13
|
+
import type { BackstageTheme } from '../types'
|
|
12
14
|
|
|
13
15
|
// Enable LayoutAnimation on Android
|
|
14
16
|
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
|
|
@@ -35,12 +37,12 @@ interface JsonNodeProps {
|
|
|
35
37
|
|
|
36
38
|
// ─── Color Mapping ───────────────────────────────────────────────────────────
|
|
37
39
|
|
|
38
|
-
function getValueColor(value: unknown): string {
|
|
39
|
-
if (value === null || value === undefined) return
|
|
40
|
-
if (typeof value === 'string') return '#98C379'
|
|
41
|
-
if (typeof value === 'number') return '#61AFEF'
|
|
42
|
-
if (typeof value === 'boolean') return '#C678DD'
|
|
43
|
-
return
|
|
40
|
+
function getValueColor(value: unknown, t: BackstageTheme): string {
|
|
41
|
+
if (value === null || value === undefined) return t.textMuted
|
|
42
|
+
if (typeof value === 'string') return '#98C379'
|
|
43
|
+
if (typeof value === 'number') return '#61AFEF'
|
|
44
|
+
if (typeof value === 'boolean') return '#C678DD'
|
|
45
|
+
return t.text
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
function getPreview(value: unknown): string {
|
|
@@ -79,7 +81,9 @@ const JsonNode: React.FC<JsonNodeProps> = ({
|
|
|
79
81
|
isLast,
|
|
80
82
|
hideKey = false,
|
|
81
83
|
}) => {
|
|
82
|
-
const
|
|
84
|
+
const theme = useBackstageTheme()
|
|
85
|
+
const s = useMemo(() => createStyles(theme), [theme])
|
|
86
|
+
const [expanded, setExpanded] = useState(false)
|
|
83
87
|
const expandable = isExpandable(value)
|
|
84
88
|
const reachedMaxDepth = depth >= maxDepth
|
|
85
89
|
|
|
@@ -95,18 +99,18 @@ const JsonNode: React.FC<JsonNodeProps> = ({
|
|
|
95
99
|
const displayValue = reachedMaxDepth && expandable ? getPreview(value) : formatValue(value)
|
|
96
100
|
|
|
97
101
|
return (
|
|
98
|
-
<View style={[
|
|
99
|
-
{!hideKey && keyName !== null && <Text style={
|
|
102
|
+
<View style={[s.row, { paddingLeft: indent }]}>
|
|
103
|
+
{!hideKey && keyName !== null && <Text style={s.key}>{`${keyName}: `}</Text>}
|
|
100
104
|
<Text
|
|
101
105
|
style={[
|
|
102
|
-
|
|
103
|
-
{ color: reachedMaxDepth ?
|
|
106
|
+
s.value,
|
|
107
|
+
{ color: reachedMaxDepth ? theme.textMuted : getValueColor(value, theme) },
|
|
104
108
|
]}
|
|
105
109
|
numberOfLines={3}
|
|
106
110
|
>
|
|
107
111
|
{displayValue}
|
|
108
112
|
</Text>
|
|
109
|
-
{!isLast && <Text style={
|
|
113
|
+
{!isLast && <Text style={s.comma}>,</Text>}
|
|
110
114
|
</View>
|
|
111
115
|
)
|
|
112
116
|
}
|
|
@@ -124,16 +128,16 @@ const JsonNode: React.FC<JsonNodeProps> = ({
|
|
|
124
128
|
<TouchableOpacity
|
|
125
129
|
onPress={toggleExpand}
|
|
126
130
|
activeOpacity={0.7}
|
|
127
|
-
style={[
|
|
131
|
+
style={[s.row, { paddingLeft: indent }]}
|
|
128
132
|
>
|
|
129
|
-
<Text style={
|
|
130
|
-
{!hideKey && keyName !== null && <Text style={
|
|
131
|
-
<Text style={
|
|
133
|
+
<Text style={s.chevron}>{expanded ? '▼' : '▶'}</Text>
|
|
134
|
+
{!hideKey && keyName !== null && <Text style={s.key}>{`${keyName}: `}</Text>}
|
|
135
|
+
<Text style={s.bracket}>{bracketOpen}</Text>
|
|
132
136
|
{!expanded && (
|
|
133
137
|
<>
|
|
134
|
-
<Text style={
|
|
135
|
-
<Text style={
|
|
136
|
-
{!isLast && <Text style={
|
|
138
|
+
<Text style={s.preview}>{` ${getPreview(value)} `}</Text>
|
|
139
|
+
<Text style={s.bracket}>{bracketClose}</Text>
|
|
140
|
+
{!isLast && <Text style={s.comma}>,</Text>}
|
|
137
141
|
</>
|
|
138
142
|
)}
|
|
139
143
|
</TouchableOpacity>
|
|
@@ -150,9 +154,9 @@ const JsonNode: React.FC<JsonNodeProps> = ({
|
|
|
150
154
|
isLast={i === entries.length - 1}
|
|
151
155
|
/>
|
|
152
156
|
))}
|
|
153
|
-
<View style={[
|
|
154
|
-
<Text style={
|
|
155
|
-
{!isLast && <Text style={
|
|
157
|
+
<View style={[s.row, { paddingLeft: indent }]}>
|
|
158
|
+
<Text style={s.bracket}>{bracketClose}</Text>
|
|
159
|
+
{!isLast && <Text style={s.comma}>,</Text>}
|
|
156
160
|
</View>
|
|
157
161
|
</>
|
|
158
162
|
)}
|
|
@@ -167,12 +171,15 @@ export const JsonTreeView: React.FC<JsonTreeViewProps> = ({
|
|
|
167
171
|
hideRoot = false,
|
|
168
172
|
maxDepth = 10,
|
|
169
173
|
}) => {
|
|
174
|
+
const theme = useBackstageTheme()
|
|
175
|
+
const s = useMemo(() => createStyles(theme), [theme])
|
|
176
|
+
|
|
170
177
|
if (data === null || data === undefined) {
|
|
171
|
-
return <Text style={[
|
|
178
|
+
return <Text style={[s.value, { color: theme.textMuted }]}>{String(data)}</Text>
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
if (!isExpandable(data)) {
|
|
175
|
-
return <Text style={[
|
|
182
|
+
return <Text style={[s.value, { color: getValueColor(data, theme) }]}>{formatValue(data)}</Text>
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
if (hideRoot) {
|
|
@@ -181,7 +188,7 @@ export const JsonTreeView: React.FC<JsonTreeViewProps> = ({
|
|
|
181
188
|
: Object.entries(data as Record<string, unknown>)
|
|
182
189
|
|
|
183
190
|
return (
|
|
184
|
-
<View style={
|
|
191
|
+
<View style={s.container}>
|
|
185
192
|
{entries.map(([k, v], i) => (
|
|
186
193
|
<JsonNode
|
|
187
194
|
key={`${k}_${i}`}
|
|
@@ -197,7 +204,7 @@ export const JsonTreeView: React.FC<JsonTreeViewProps> = ({
|
|
|
197
204
|
}
|
|
198
205
|
|
|
199
206
|
return (
|
|
200
|
-
<View style={
|
|
207
|
+
<View style={s.container}>
|
|
201
208
|
<JsonNode
|
|
202
209
|
keyName={null}
|
|
203
210
|
value={data}
|
|
@@ -212,48 +219,21 @@ export const JsonTreeView: React.FC<JsonTreeViewProps> = ({
|
|
|
212
219
|
|
|
213
220
|
// ─── Styles ──────────────────────────────────────────────────────────────────
|
|
214
221
|
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
paddingVertical: 4,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
fontSize:
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
key: {
|
|
234
|
-
fontFamily: MonospaceFont,
|
|
235
|
-
fontSize: 13,
|
|
236
|
-
color: '#E06C75', // red-ish for keys
|
|
237
|
-
},
|
|
238
|
-
value: {
|
|
239
|
-
fontFamily: MonospaceFont,
|
|
240
|
-
fontSize: 13,
|
|
241
|
-
flexShrink: 1,
|
|
242
|
-
},
|
|
243
|
-
bracket: {
|
|
244
|
-
fontFamily: MonospaceFont,
|
|
245
|
-
fontSize: 13,
|
|
246
|
-
color: DarkTheme.textSecondary,
|
|
247
|
-
},
|
|
248
|
-
preview: {
|
|
249
|
-
fontFamily: MonospaceFont,
|
|
250
|
-
fontSize: 13,
|
|
251
|
-
color: DarkTheme.textMuted,
|
|
252
|
-
fontStyle: 'italic',
|
|
253
|
-
},
|
|
254
|
-
comma: {
|
|
255
|
-
fontFamily: MonospaceFont,
|
|
256
|
-
fontSize: 13,
|
|
257
|
-
color: DarkTheme.textMuted,
|
|
258
|
-
},
|
|
259
|
-
})
|
|
222
|
+
const createStyles = (t: BackstageTheme) =>
|
|
223
|
+
StyleSheet.create({
|
|
224
|
+
container: { paddingVertical: 4 },
|
|
225
|
+
row: { flexDirection: 'row', alignItems: 'flex-start', paddingVertical: 2, flexWrap: 'wrap' },
|
|
226
|
+
chevron: {
|
|
227
|
+
fontFamily: MonospaceFont,
|
|
228
|
+
fontSize: 10,
|
|
229
|
+
color: t.textMuted,
|
|
230
|
+
marginRight: 6,
|
|
231
|
+
marginTop: 2,
|
|
232
|
+
width: 12,
|
|
233
|
+
},
|
|
234
|
+
key: { fontFamily: MonospaceFont, fontSize: 13, color: '#E06C75' },
|
|
235
|
+
value: { fontFamily: MonospaceFont, fontSize: 13, flexShrink: 1 },
|
|
236
|
+
bracket: { fontFamily: MonospaceFont, fontSize: 13, color: t.textSecondary },
|
|
237
|
+
preview: { fontFamily: MonospaceFont, fontSize: 13, color: t.textMuted, fontStyle: 'italic' },
|
|
238
|
+
comma: { fontFamily: MonospaceFont, fontSize: 13, color: t.textMuted },
|
|
239
|
+
})
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import React, { useCallback, useState } from 'react'
|
|
1
|
+
import React, { useCallback, useMemo, useState } from 'react'
|
|
2
2
|
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
|
3
|
-
import {
|
|
3
|
+
import { MonospaceFont } from '../constants'
|
|
4
|
+
import { useBackstageTheme } from '../ThemeContext'
|
|
4
5
|
import { LogLevel } from '../types'
|
|
5
|
-
import type { LogEntry, BackstageStyleOverrides } from '../types'
|
|
6
|
+
import type { LogEntry, BackstageStyleOverrides, BackstageTheme } from '../types'
|
|
6
7
|
import { formatTimestamp } from '../utils/formatTimestamp'
|
|
7
8
|
import { JsonTreeView } from './JsonTreeView'
|
|
8
9
|
|
|
@@ -11,50 +12,39 @@ import { JsonTreeView } from './JsonTreeView'
|
|
|
11
12
|
interface LogItemProps {
|
|
12
13
|
item: LogEntry
|
|
13
14
|
onCopy?: (text: string) => void
|
|
15
|
+
jsonMaxDepth?: number
|
|
14
16
|
styles?: BackstageStyleOverrides
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
// ─── Badge Colors ────────────────────────────────────────────────────────────
|
|
18
20
|
|
|
19
|
-
function getBadgeConfig(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
rowBg: string
|
|
24
|
-
} {
|
|
21
|
+
function getBadgeConfig(
|
|
22
|
+
level: LogLevel,
|
|
23
|
+
t: BackstageTheme,
|
|
24
|
+
): { label: string; color: string; bgColor: string; rowBg: string } {
|
|
25
25
|
switch (level) {
|
|
26
26
|
case LogLevel.error:
|
|
27
27
|
return {
|
|
28
28
|
label: 'ERROR',
|
|
29
|
-
color:
|
|
30
|
-
bgColor:
|
|
29
|
+
color: t.error,
|
|
30
|
+
bgColor: t.errorDim,
|
|
31
31
|
rowBg: 'rgba(255, 77, 106, 0.06)',
|
|
32
32
|
}
|
|
33
33
|
case LogLevel.warn:
|
|
34
34
|
return {
|
|
35
35
|
label: 'WARN',
|
|
36
|
-
color:
|
|
37
|
-
bgColor:
|
|
36
|
+
color: t.warning,
|
|
37
|
+
bgColor: t.warningDim,
|
|
38
38
|
rowBg: 'rgba(255, 178, 36, 0.06)',
|
|
39
39
|
}
|
|
40
40
|
case LogLevel.info:
|
|
41
|
-
return {
|
|
42
|
-
label: 'INFO',
|
|
43
|
-
color: DarkTheme.info,
|
|
44
|
-
bgColor: DarkTheme.infoDim,
|
|
45
|
-
rowBg: 'transparent',
|
|
46
|
-
}
|
|
41
|
+
return { label: 'INFO', color: t.info, bgColor: t.infoDim, rowBg: 'transparent' }
|
|
47
42
|
case LogLevel.debug:
|
|
48
|
-
return {
|
|
49
|
-
label: 'DEBUG',
|
|
50
|
-
color: DarkTheme.debugColor,
|
|
51
|
-
bgColor: DarkTheme.debugDim,
|
|
52
|
-
rowBg: 'transparent',
|
|
53
|
-
}
|
|
43
|
+
return { label: 'DEBUG', color: t.debugColor, bgColor: t.debugDim, rowBg: 'transparent' }
|
|
54
44
|
default:
|
|
55
45
|
return {
|
|
56
46
|
label: 'LOG',
|
|
57
|
-
color:
|
|
47
|
+
color: t.textSecondary,
|
|
58
48
|
bgColor: 'rgba(160, 160, 176, 0.1)',
|
|
59
49
|
rowBg: 'transparent',
|
|
60
50
|
}
|
|
@@ -64,9 +54,11 @@ function getBadgeConfig(level: LogLevel): {
|
|
|
64
54
|
// ─── Component ───────────────────────────────────────────────────────────────
|
|
65
55
|
|
|
66
56
|
export const LogItem: React.FC<LogItemProps> = React.memo(
|
|
67
|
-
({ item, onCopy, styles: propStyles }) => {
|
|
57
|
+
({ item, onCopy, jsonMaxDepth, styles: propStyles }) => {
|
|
58
|
+
const theme = useBackstageTheme()
|
|
59
|
+
const s = useMemo(() => createStyles(theme), [theme])
|
|
68
60
|
const [expanded, setExpanded] = useState(false)
|
|
69
|
-
const badge = getBadgeConfig(item.level)
|
|
61
|
+
const badge = getBadgeConfig(item.level, theme)
|
|
70
62
|
const hasData = item.data !== undefined
|
|
71
63
|
|
|
72
64
|
const toggleExpand = useCallback(() => {
|
|
@@ -82,47 +74,43 @@ export const LogItem: React.FC<LogItemProps> = React.memo(
|
|
|
82
74
|
|
|
83
75
|
return (
|
|
84
76
|
<TouchableOpacity
|
|
85
|
-
style={[
|
|
77
|
+
style={[s.container, { backgroundColor: badge.rowBg }]}
|
|
86
78
|
onPress={hasData ? toggleExpand : undefined}
|
|
87
79
|
onLongPress={handleCopy}
|
|
88
80
|
activeOpacity={hasData ? 0.7 : 1}
|
|
89
81
|
>
|
|
90
|
-
{
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<Text style={[styles.badgeText, { color: badge.color }]}>{badge.label}</Text>
|
|
82
|
+
<View style={s.headerRow}>
|
|
83
|
+
<View style={[s.badge, { backgroundColor: badge.bgColor }]}>
|
|
84
|
+
<Text style={[s.badgeText, { color: badge.color }]}>{badge.label}</Text>
|
|
94
85
|
</View>
|
|
95
|
-
<Text style={[
|
|
86
|
+
<Text style={[s.timestamp, propStyles?.logTimestampStyle]}>
|
|
96
87
|
{formatTimestamp(item.timestamp)}
|
|
97
88
|
</Text>
|
|
98
89
|
{onCopy && (
|
|
99
90
|
<TouchableOpacity
|
|
100
|
-
style={
|
|
91
|
+
style={s.copyButton}
|
|
101
92
|
onPress={handleCopy}
|
|
102
93
|
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
103
94
|
>
|
|
104
|
-
<Text style={
|
|
95
|
+
<Text style={s.copyButtonText}>⧉</Text>
|
|
105
96
|
</TouchableOpacity>
|
|
106
97
|
)}
|
|
107
98
|
</View>
|
|
108
99
|
|
|
109
|
-
{/* Message */}
|
|
110
100
|
<Text
|
|
111
|
-
style={[
|
|
101
|
+
style={[s.message, propStyles?.logMessageStyle]}
|
|
112
102
|
numberOfLines={expanded ? undefined : 3}
|
|
113
103
|
>
|
|
114
104
|
{item.message}
|
|
115
105
|
</Text>
|
|
116
106
|
|
|
117
|
-
{/* Expandable data */}
|
|
118
107
|
{expanded && hasData && (
|
|
119
|
-
<View style={
|
|
120
|
-
<JsonTreeView data={item.data} hideRoot maxDepth={
|
|
108
|
+
<View style={s.dataContainer}>
|
|
109
|
+
<JsonTreeView data={item.data} hideRoot maxDepth={jsonMaxDepth} />
|
|
121
110
|
</View>
|
|
122
111
|
)}
|
|
123
112
|
|
|
124
|
-
{
|
|
125
|
-
{hasData && !expanded && <Text style={styles.expandHint}>tap to expand ▾</Text>}
|
|
113
|
+
{hasData && !expanded && <Text style={s.expandHint}>tap to expand ▾</Text>}
|
|
126
114
|
</TouchableOpacity>
|
|
127
115
|
)
|
|
128
116
|
},
|
|
@@ -130,60 +118,27 @@ export const LogItem: React.FC<LogItemProps> = React.memo(
|
|
|
130
118
|
|
|
131
119
|
// ─── Styles ──────────────────────────────────────────────────────────────────
|
|
132
120
|
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
flexDirection: 'row',
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
timestamp: {
|
|
158
|
-
fontFamily: MonospaceFont,
|
|
159
|
-
fontSize: 11,
|
|
160
|
-
color: DarkTheme.textMuted,
|
|
161
|
-
flex: 1,
|
|
162
|
-
},
|
|
163
|
-
copyButton: {
|
|
164
|
-
padding: 4,
|
|
165
|
-
},
|
|
166
|
-
copyButtonText: {
|
|
167
|
-
fontSize: 16,
|
|
168
|
-
color: DarkTheme.textMuted,
|
|
169
|
-
},
|
|
170
|
-
message: {
|
|
171
|
-
fontFamily: MonospaceFont,
|
|
172
|
-
fontSize: 12,
|
|
173
|
-
color: DarkTheme.text,
|
|
174
|
-
lineHeight: 18,
|
|
175
|
-
},
|
|
176
|
-
dataContainer: {
|
|
177
|
-
marginTop: 8,
|
|
178
|
-
paddingTop: 8,
|
|
179
|
-
borderTopWidth: 1,
|
|
180
|
-
borderTopColor: DarkTheme.border,
|
|
181
|
-
},
|
|
182
|
-
expandHint: {
|
|
183
|
-
fontFamily: MonospaceFont,
|
|
184
|
-
fontSize: 10,
|
|
185
|
-
color: DarkTheme.textMuted,
|
|
186
|
-
marginTop: 4,
|
|
187
|
-
fontStyle: 'italic',
|
|
188
|
-
},
|
|
189
|
-
})
|
|
121
|
+
const createStyles = (t: BackstageTheme) =>
|
|
122
|
+
StyleSheet.create({
|
|
123
|
+
container: {
|
|
124
|
+
paddingHorizontal: 14,
|
|
125
|
+
paddingVertical: 10,
|
|
126
|
+
borderBottomWidth: 1,
|
|
127
|
+
borderBottomColor: t.border,
|
|
128
|
+
},
|
|
129
|
+
headerRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 4 },
|
|
130
|
+
badge: { borderRadius: 4, paddingHorizontal: 6, paddingVertical: 2, marginRight: 8 },
|
|
131
|
+
badgeText: { fontFamily: MonospaceFont, fontSize: 10, fontWeight: '800', letterSpacing: 0.5 },
|
|
132
|
+
timestamp: { fontFamily: MonospaceFont, fontSize: 11, color: t.textMuted, flex: 1 },
|
|
133
|
+
copyButton: { padding: 4 },
|
|
134
|
+
copyButtonText: { fontSize: 16, color: t.textMuted },
|
|
135
|
+
message: { fontFamily: MonospaceFont, fontSize: 12, color: t.text, lineHeight: 18 },
|
|
136
|
+
dataContainer: { marginTop: 8, paddingTop: 8, borderTopWidth: 1, borderTopColor: t.border },
|
|
137
|
+
expandHint: {
|
|
138
|
+
fontFamily: MonospaceFont,
|
|
139
|
+
fontSize: 10,
|
|
140
|
+
color: t.textMuted,
|
|
141
|
+
marginTop: 4,
|
|
142
|
+
fontStyle: 'italic',
|
|
143
|
+
},
|
|
144
|
+
})
|