rn-backstage 1.2.0 → 1.3.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.
Files changed (110) hide show
  1. package/README.md +84 -2
  2. package/lib/commonjs/Backstage.js +46 -33
  3. package/lib/commonjs/Backstage.js.map +1 -1
  4. package/lib/commonjs/ThemeContext.js +43 -0
  5. package/lib/commonjs/ThemeContext.js.map +1 -0
  6. package/lib/commonjs/components/BackstagePanel.js +35 -12
  7. package/lib/commonjs/components/BackstagePanel.js.map +1 -1
  8. package/lib/commonjs/components/FlagsTab.js +60 -57
  9. package/lib/commonjs/components/FlagsTab.js.map +1 -1
  10. package/lib/commonjs/components/FloatingPill.js +86 -24
  11. package/lib/commonjs/components/FloatingPill.js.map +1 -1
  12. package/lib/commonjs/components/InfoTab.js +77 -107
  13. package/lib/commonjs/components/InfoTab.js.map +1 -1
  14. package/lib/commonjs/components/JsonTreeView.js +39 -34
  15. package/lib/commonjs/components/JsonTreeView.js.map +1 -1
  16. package/lib/commonjs/components/LogItem.js +39 -29
  17. package/lib/commonjs/components/LogItem.js.map +1 -1
  18. package/lib/commonjs/components/LogsTab.js +39 -42
  19. package/lib/commonjs/components/LogsTab.js.map +1 -1
  20. package/lib/commonjs/components/NetworkItem.js +111 -135
  21. package/lib/commonjs/components/NetworkItem.js.map +1 -1
  22. package/lib/commonjs/components/NetworkTab.js +50 -49
  23. package/lib/commonjs/components/NetworkTab.js.map +1 -1
  24. package/lib/commonjs/components/StorageTab.js +655 -0
  25. package/lib/commonjs/components/StorageTab.js.map +1 -0
  26. package/lib/commonjs/components/TabBar.js +8 -5
  27. package/lib/commonjs/components/TabBar.js.map +1 -1
  28. package/lib/commonjs/constants.js +96 -7
  29. package/lib/commonjs/constants.js.map +1 -1
  30. package/lib/commonjs/index.js +96 -0
  31. package/lib/commonjs/index.js.map +1 -1
  32. package/lib/commonjs/types.js +1 -0
  33. package/lib/commonjs/types.js.map +1 -1
  34. package/lib/module/Backstage.js +46 -33
  35. package/lib/module/Backstage.js.map +1 -1
  36. package/lib/module/ThemeContext.js +37 -0
  37. package/lib/module/ThemeContext.js.map +1 -0
  38. package/lib/module/components/BackstagePanel.js +37 -14
  39. package/lib/module/components/BackstagePanel.js.map +1 -1
  40. package/lib/module/components/FlagsTab.js +61 -58
  41. package/lib/module/components/FlagsTab.js.map +1 -1
  42. package/lib/module/components/FloatingPill.js +90 -28
  43. package/lib/module/components/FloatingPill.js.map +1 -1
  44. package/lib/module/components/InfoTab.js +77 -107
  45. package/lib/module/components/InfoTab.js.map +1 -1
  46. package/lib/module/components/JsonTreeView.js +42 -38
  47. package/lib/module/components/JsonTreeView.js.map +1 -1
  48. package/lib/module/components/LogItem.js +41 -31
  49. package/lib/module/components/LogItem.js.map +1 -1
  50. package/lib/module/components/LogsTab.js +40 -43
  51. package/lib/module/components/LogsTab.js.map +1 -1
  52. package/lib/module/components/NetworkItem.js +113 -137
  53. package/lib/module/components/NetworkItem.js.map +1 -1
  54. package/lib/module/components/NetworkTab.js +51 -50
  55. package/lib/module/components/NetworkTab.js.map +1 -1
  56. package/lib/module/components/StorageTab.js +650 -0
  57. package/lib/module/components/StorageTab.js.map +1 -0
  58. package/lib/module/components/TabBar.js +10 -7
  59. package/lib/module/components/TabBar.js.map +1 -1
  60. package/lib/module/constants.js +95 -6
  61. package/lib/module/constants.js.map +1 -1
  62. package/lib/module/index.js +14 -0
  63. package/lib/module/index.js.map +1 -1
  64. package/lib/module/types.js +2 -0
  65. package/lib/module/types.js.map +1 -1
  66. package/lib/typescript/Backstage.d.ts.map +1 -1
  67. package/lib/typescript/ThemeContext.d.ts +11 -0
  68. package/lib/typescript/ThemeContext.d.ts.map +1 -0
  69. package/lib/typescript/components/BackstagePanel.d.ts +3 -1
  70. package/lib/typescript/components/BackstagePanel.d.ts.map +1 -1
  71. package/lib/typescript/components/FlagsTab.d.ts.map +1 -1
  72. package/lib/typescript/components/FloatingPill.d.ts +2 -0
  73. package/lib/typescript/components/FloatingPill.d.ts.map +1 -1
  74. package/lib/typescript/components/InfoTab.d.ts +1 -0
  75. package/lib/typescript/components/InfoTab.d.ts.map +1 -1
  76. package/lib/typescript/components/JsonTreeView.d.ts.map +1 -1
  77. package/lib/typescript/components/LogItem.d.ts +1 -0
  78. package/lib/typescript/components/LogItem.d.ts.map +1 -1
  79. package/lib/typescript/components/LogsTab.d.ts +1 -0
  80. package/lib/typescript/components/LogsTab.d.ts.map +1 -1
  81. package/lib/typescript/components/NetworkItem.d.ts +1 -0
  82. package/lib/typescript/components/NetworkItem.d.ts.map +1 -1
  83. package/lib/typescript/components/NetworkTab.d.ts +1 -0
  84. package/lib/typescript/components/NetworkTab.d.ts.map +1 -1
  85. package/lib/typescript/components/StorageTab.d.ts +9 -0
  86. package/lib/typescript/components/StorageTab.d.ts.map +1 -0
  87. package/lib/typescript/components/TabBar.d.ts.map +1 -1
  88. package/lib/typescript/constants.d.ts +60 -4
  89. package/lib/typescript/constants.d.ts.map +1 -1
  90. package/lib/typescript/index.d.ts +14 -1
  91. package/lib/typescript/index.d.ts.map +1 -1
  92. package/lib/typescript/types.d.ts +20 -0
  93. package/lib/typescript/types.d.ts.map +1 -1
  94. package/package.json +6 -4
  95. package/src/Backstage.tsx +45 -33
  96. package/src/ThemeContext.tsx +38 -0
  97. package/src/components/BackstagePanel.tsx +89 -61
  98. package/src/components/FlagsTab.tsx +125 -174
  99. package/src/components/FloatingPill.tsx +127 -30
  100. package/src/components/InfoTab.tsx +153 -186
  101. package/src/components/JsonTreeView.tsx +53 -73
  102. package/src/components/LogItem.tsx +64 -100
  103. package/src/components/LogsTab.tsx +110 -132
  104. package/src/components/NetworkItem.tsx +306 -417
  105. package/src/components/NetworkTab.tsx +129 -163
  106. package/src/components/StorageTab.tsx +607 -0
  107. package/src/components/TabBar.tsx +51 -47
  108. package/src/constants.ts +103 -4
  109. package/src/index.ts +17 -0
  110. package/src/types.ts +28 -0
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useRef, useEffect } from 'react'
1
+ import React, { useCallback, useMemo, useRef, useEffect } from 'react'
2
2
  import {
3
3
  Animated,
4
4
  LayoutChangeEvent,
@@ -8,7 +8,8 @@ import {
8
8
  TouchableOpacity,
9
9
  View,
10
10
  } from 'react-native'
11
- import { DarkTheme, MonospaceFont } from '../constants'
11
+ import { MonospaceFont } from '../constants'
12
+ import { useBackstageTheme } from '../ThemeContext'
12
13
 
13
14
  // ─── Types ───────────────────────────────────────────────────────────────────
14
15
 
@@ -27,6 +28,8 @@ interface TabBarProps {
27
28
  // ─── Component ───────────────────────────────────────────────────────────────
28
29
 
29
30
  export const TabBar: React.FC<TabBarProps> = ({ tabs, activeTab, onTabChange }) => {
31
+ const theme = useBackstageTheme()
32
+ const styles = useMemo(() => createStyles(theme), [theme])
30
33
  const indicatorAnim = useRef(new Animated.Value(0)).current
31
34
  const tabWidths = useRef<Record<string, number>>({})
32
35
  const tabOffsets = useRef<Record<string, number>>({})
@@ -103,48 +106,49 @@ export const TabBar: React.FC<TabBarProps> = ({ tabs, activeTab, onTabChange })
103
106
 
104
107
  // ─── Styles ──────────────────────────────────────────────────────────────────
105
108
 
106
- const styles = StyleSheet.create({
107
- container: {
108
- borderBottomWidth: 1,
109
- borderBottomColor: DarkTheme.border,
110
- },
111
- scrollContent: {
112
- flexDirection: 'row',
113
- position: 'relative',
114
- paddingBottom: 0,
115
- },
116
- tab: {
117
- flexDirection: 'row',
118
- alignItems: 'center',
119
- justifyContent: 'center',
120
- paddingHorizontal: 20,
121
- paddingVertical: 14,
122
- minWidth: 80,
123
- },
124
- tabIcon: {
125
- fontSize: 14,
126
- marginRight: 6,
127
- opacity: 0.5,
128
- },
129
- tabIconActive: {
130
- opacity: 1,
131
- },
132
- tabText: {
133
- fontFamily: MonospaceFont,
134
- fontSize: 13,
135
- fontWeight: '600',
136
- color: DarkTheme.textMuted,
137
- textTransform: 'uppercase',
138
- letterSpacing: 1,
139
- },
140
- tabTextActive: {
141
- color: DarkTheme.accent,
142
- },
143
- indicator: {
144
- position: 'absolute',
145
- bottom: 0,
146
- height: 2,
147
- backgroundColor: DarkTheme.accent,
148
- borderRadius: 1,
149
- },
150
- })
109
+ const createStyles = (t: import('../types').BackstageTheme) =>
110
+ StyleSheet.create({
111
+ container: {
112
+ borderBottomWidth: 1,
113
+ borderBottomColor: t.border,
114
+ },
115
+ scrollContent: {
116
+ flexDirection: 'row',
117
+ position: 'relative',
118
+ paddingBottom: 0,
119
+ },
120
+ tab: {
121
+ flexDirection: 'row',
122
+ alignItems: 'center',
123
+ justifyContent: 'center',
124
+ paddingHorizontal: 20,
125
+ paddingVertical: 14,
126
+ minWidth: 80,
127
+ },
128
+ tabIcon: {
129
+ fontSize: 14,
130
+ marginRight: 6,
131
+ opacity: 0.5,
132
+ },
133
+ tabIconActive: {
134
+ opacity: 1,
135
+ },
136
+ tabText: {
137
+ fontFamily: MonospaceFont,
138
+ fontSize: 13,
139
+ fontWeight: '600',
140
+ color: t.textMuted,
141
+ textTransform: 'uppercase',
142
+ letterSpacing: 1,
143
+ },
144
+ tabTextActive: {
145
+ color: t.accent,
146
+ },
147
+ indicator: {
148
+ position: 'absolute',
149
+ bottom: 0,
150
+ height: 2,
151
+ backgroundColor: t.accent,
152
+ borderRadius: 1,
153
+ },
154
+ })
package/src/constants.ts CHANGED
@@ -41,6 +41,29 @@ export const DarkTheme: BackstageTheme = {
41
41
  debugDim: 'rgba(167, 139, 250, 0.12)',
42
42
  }
43
43
 
44
+ // ─── Light Theme ─────────────────────────────────────────────────────────────
45
+
46
+ export const LightTheme: BackstageTheme = {
47
+ background: '#F5F5F7',
48
+ surface: '#FFFFFF',
49
+ surfaceElevated: '#F0F0F4',
50
+ border: '#D8D8DC',
51
+ text: '#1C1C1E',
52
+ textSecondary: '#636366',
53
+ textMuted: '#AEAEB2',
54
+ accent: '#6A3DE8',
55
+ accentDim: 'rgba(106, 61, 232, 0.10)',
56
+ error: '#E5325F',
57
+ errorDim: 'rgba(229, 50, 95, 0.10)',
58
+ warning: '#E09400',
59
+ warningDim: 'rgba(224, 148, 0, 0.10)',
60
+ success: '#28A770',
61
+ info: '#0E8AD6',
62
+ infoDim: 'rgba(14, 138, 214, 0.10)',
63
+ debugColor: '#7C4DFF',
64
+ debugDim: 'rgba(124, 77, 255, 0.10)',
65
+ }
66
+
44
67
  export const DEFAULT_MAX_LOGS = 500
45
68
 
46
69
  // ─── Network Defaults ────────────────────────────────────────────────────────
@@ -58,34 +81,110 @@ export const MonospaceFont = Platform.select({
58
81
  // ─── Test IDs ────────────────────────────────────────────────────────────────
59
82
 
60
83
  export const TestIDs = {
84
+ // ── Floating Pill ──────────────────────────────
61
85
  floatingPill: 'backstage.floating-pill',
86
+ floatingPillText: 'backstage.floating-pill.text',
87
+
88
+ // ── Panel ──────────────────────────────────────
62
89
  panel: 'backstage.panel',
90
+ panelModal: 'backstage.panel.modal',
91
+
92
+ // ── Header ─────────────────────────────────────
63
93
  header: {
64
94
  container: 'backstage.header',
65
95
  title: 'backstage.header.title',
66
96
  closeButton: 'backstage.header.close',
67
97
  },
98
+
99
+ // ── Tab Bar ────────────────────────────────────
68
100
  tabBar: 'backstage.tab-bar',
69
101
  tabs: {
70
102
  info: 'backstage.tab.info',
103
+ network: 'backstage.tab.network',
104
+ flags: 'backstage.tab.flags',
105
+ storage: 'backstage.tab.storage',
71
106
  logs: 'backstage.tab.logs',
72
107
  },
108
+
109
+ // ── Info Tab ───────────────────────────────────
73
110
  infoTab: {
74
- section: 'backstage.info',
111
+ container: 'backstage.info',
75
112
  deviceInfo: 'backstage.info.device',
76
113
  stateTree: 'backstage.info.state-tree',
77
114
  quickActions: 'backstage.info.quick-actions',
115
+ /** Dynamic: backstage.info.action.{index} */
116
+ actionButton: (index: number) => `backstage.info.action.${index}`,
78
117
  },
118
+
119
+ // ── Logs Tab ───────────────────────────────────
79
120
  logsTab: {
80
- section: 'backstage.logs',
121
+ container: 'backstage.logs',
81
122
  searchInput: 'backstage.logs.search',
82
123
  copyButton: 'backstage.logs.copy',
83
124
  list: 'backstage.logs.list',
125
+ statsBar: 'backstage.logs.stats',
126
+ },
127
+
128
+ // ── Log Item ───────────────────────────────────
129
+ logItem: {
130
+ /** Dynamic: backstage.log-item.{id} */
131
+ container: (id: string) => `backstage.log-item.${id}`,
132
+ badge: (id: string) => `backstage.log-item.${id}.badge`,
133
+ message: (id: string) => `backstage.log-item.${id}.message`,
134
+ timestamp: (id: string) => `backstage.log-item.${id}.timestamp`,
135
+ dataContainer: (id: string) => `backstage.log-item.${id}.data`,
136
+ copyButton: (id: string) => `backstage.log-item.${id}.copy`,
84
137
  },
138
+
139
+ // ── Network Tab ────────────────────────────────
85
140
  networkTab: {
86
- section: 'backstage.network',
141
+ container: 'backstage.network',
87
142
  searchInput: 'backstage.network.search',
88
- list: 'backstage.network.list',
89
143
  clearButton: 'backstage.network.clear',
144
+ list: 'backstage.network.list',
145
+ statsBar: 'backstage.network.stats',
146
+ },
147
+
148
+ // ── Network Item ───────────────────────────────
149
+ networkItem: {
150
+ /** Dynamic: backstage.network-item.{id} */
151
+ container: (id: string) => `backstage.network-item.${id}`,
152
+ methodBadge: (id: string) => `backstage.network-item.${id}.method`,
153
+ statusBadge: (id: string) => `backstage.network-item.${id}.status`,
154
+ url: (id: string) => `backstage.network-item.${id}.url`,
155
+ sectionTab: (id: string, section: string) => `backstage.network-item.${id}.section.${section}`,
156
+ curlButton: (id: string) => `backstage.network-item.${id}.curl`,
157
+ },
158
+
159
+ // ── Flags Tab ──────────────────────────────────
160
+ flagsTab: {
161
+ container: 'backstage.flags',
162
+ searchInput: 'backstage.flags.search',
163
+ statsBar: 'backstage.flags.stats',
164
+ list: 'backstage.flags.list',
165
+ /** Dynamic: backstage.flag.{key} — applied to the Switch */
166
+ flagSwitch: (key: string) => `backstage.flag.${key}`,
167
+ flagLabel: (key: string) => `backstage.flag.${key}.label`,
168
+ flagRow: (key: string) => `backstage.flag.${key}.row`,
169
+ },
170
+
171
+ // ── Storage Tab ────────────────────────────────
172
+ storageTab: {
173
+ container: 'backstage.storage',
174
+ searchInput: 'backstage.storage.search',
175
+ addButton: 'backstage.storage.add-button',
176
+ addForm: 'backstage.storage.add-form',
177
+ addKeyInput: 'backstage.storage.add-form.key',
178
+ addValueInput: 'backstage.storage.add-form.value',
179
+ addSubmitButton: 'backstage.storage.add-form.submit',
180
+ statsBar: 'backstage.storage.stats',
181
+ list: 'backstage.storage.list',
182
+ /** Dynamic: backstage.storage.entry.{key} */
183
+ entryRow: (key: string) => `backstage.storage.entry.${key}`,
184
+ entryEditButton: (key: string) => `backstage.storage.entry.${key}.edit`,
185
+ entryDeleteButton: (key: string) => `backstage.storage.entry.${key}.delete`,
186
+ entryEditInput: (key: string) => `backstage.storage.entry.${key}.edit-input`,
187
+ entrySaveButton: (key: string) => `backstage.storage.entry.${key}.save`,
188
+ entryCancelButton: (key: string) => `backstage.storage.entry.${key}.cancel`,
90
189
  },
91
190
  }
package/src/index.ts CHANGED
@@ -8,9 +8,26 @@ export type {
8
8
  BackstageTheme,
9
9
  QuickAction,
10
10
  FeatureFlag,
11
+ StorageAdapter,
11
12
  AppInfoItem,
12
13
  LogEntry,
13
14
  NetworkEntry,
14
15
  } from './types'
15
16
 
16
17
  export { LogLevel, NetworkState } from './types'
18
+ export { TestIDs, DarkTheme, LightTheme } from './constants'
19
+ export type { ThemePreference } from './ThemeContext'
20
+
21
+ // ─── Individual Components ───────────────────────────────────────────────────
22
+
23
+ export { BackstagePanel } from './components/BackstagePanel'
24
+ export { FloatingPill } from './components/FloatingPill'
25
+ export { TabBar } from './components/TabBar'
26
+ export { InfoTab } from './components/InfoTab'
27
+ export { LogsTab } from './components/LogsTab'
28
+ export { LogItem } from './components/LogItem'
29
+ export { NetworkTab } from './components/NetworkTab'
30
+ export { NetworkItem } from './components/NetworkItem'
31
+ export { FlagsTab } from './components/FlagsTab'
32
+ export { StorageTab } from './components/StorageTab'
33
+ export { JsonTreeView } from './components/JsonTreeView'
package/src/types.ts CHANGED
@@ -76,6 +76,19 @@ export interface FeatureFlag {
76
76
  description?: string
77
77
  }
78
78
 
79
+ // ─── Storage Adapter ─────────────────────────────────────────────────────────
80
+
81
+ export interface StorageAdapter {
82
+ /** Return all stored keys */
83
+ getAllKeys: () => Promise<string[]>
84
+ /** Get value for a key. Return null if not found */
85
+ getItem: (key: string) => Promise<string | null>
86
+ /** Set a value for a key */
87
+ setItem: (key: string, value: string) => Promise<void>
88
+ /** Remove an entry by key */
89
+ removeItem: (key: string) => Promise<void>
90
+ }
91
+
79
92
  // ─── Extensible Tabs ─────────────────────────────────────────────────────────
80
93
 
81
94
  export interface BackstageTab {
@@ -114,6 +127,9 @@ export interface BackstageProps {
114
127
  /** Whether the floating pill trigger is visible. Default: true */
115
128
  visible?: boolean
116
129
 
130
+ /** Theme preference: 'light', 'dark', or 'auto' (follows device setting). Default: 'auto' */
131
+ theme?: 'light' | 'dark' | 'auto'
132
+
117
133
  /** App version string (e.g., "1.2.3") */
118
134
  appVersion?: string
119
135
 
@@ -138,6 +154,9 @@ export interface BackstageProps {
138
154
  /** Callback when a feature flag is toggled */
139
155
  onToggleFeatureFlag?: (key: string, value: boolean) => void
140
156
 
157
+ /** Storage adapter for the Storage Viewer tab (AsyncStorage, MMKV, etc.) */
158
+ storageAdapter?: StorageAdapter
159
+
141
160
  /** Maximum number of logs to retain in memory. Default: 500 */
142
161
  maxLogs?: number
143
162
 
@@ -165,6 +184,12 @@ export interface BackstageProps {
165
184
  /** Text displayed on the floating pill. Defaults to appVersion or "DEV" */
166
185
  pillText?: string
167
186
 
187
+ /** Width of the floating pill. Default: 60 */
188
+ pillWidth?: number
189
+
190
+ /** Height of the floating pill. Default: 32 */
191
+ pillHeight?: number
192
+
168
193
  /** Whether to enable network request interception. Default: true */
169
194
  enableNetworkInspector?: boolean
170
195
 
@@ -179,6 +204,9 @@ export interface BackstageProps {
179
204
 
180
205
  /** Auto-filter console.logs from network callbacks (e.g., Axios interceptors) out of the Logs tab. Default: true */
181
206
  autoFilterNetworkLogs?: boolean
207
+
208
+ /** Max nesting depth for JSON tree views (state tree, log data, network bodies). Default: 10 */
209
+ jsonMaxDepth?: number
182
210
  }
183
211
 
184
212
  export interface BackstageStyleOverrides {