rn-backstage 1.2.1 → 1.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.
Files changed (99) hide show
  1. package/README.md +109 -2
  2. package/lib/commonjs/Backstage.js +19 -2
  3. package/lib/commonjs/Backstage.js.map +1 -1
  4. package/lib/commonjs/bug-report.js +173 -0
  5. package/lib/commonjs/bug-report.js.map +1 -0
  6. package/lib/commonjs/components/BackstagePanel.js +100 -17
  7. package/lib/commonjs/components/BackstagePanel.js.map +1 -1
  8. package/lib/commonjs/components/BugReportComposer.js +510 -0
  9. package/lib/commonjs/components/BugReportComposer.js.map +1 -0
  10. package/lib/commonjs/components/FlagsTab.js +21 -11
  11. package/lib/commonjs/components/FlagsTab.js.map +1 -1
  12. package/lib/commonjs/components/FloatingPill.js +82 -22
  13. package/lib/commonjs/components/FloatingPill.js.map +1 -1
  14. package/lib/commonjs/components/InfoTab.js +5 -1
  15. package/lib/commonjs/components/InfoTab.js.map +1 -1
  16. package/lib/commonjs/components/LogItem.js +6 -0
  17. package/lib/commonjs/components/LogItem.js.map +1 -1
  18. package/lib/commonjs/components/LogsTab.js +3 -3
  19. package/lib/commonjs/components/LogsTab.js.map +1 -1
  20. package/lib/commonjs/components/NetworkTab.js +3 -2
  21. package/lib/commonjs/components/NetworkTab.js.map +1 -1
  22. package/lib/commonjs/components/StorageTab.js +672 -0
  23. package/lib/commonjs/components/StorageTab.js.map +1 -0
  24. package/lib/commonjs/constants.js +88 -6
  25. package/lib/commonjs/constants.js.map +1 -1
  26. package/lib/commonjs/index.js +84 -0
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/types.js +2 -0
  29. package/lib/commonjs/types.js.map +1 -1
  30. package/lib/module/Backstage.js +19 -2
  31. package/lib/module/Backstage.js.map +1 -1
  32. package/lib/module/bug-report.js +164 -0
  33. package/lib/module/bug-report.js.map +1 -0
  34. package/lib/module/components/BackstagePanel.js +101 -18
  35. package/lib/module/components/BackstagePanel.js.map +1 -1
  36. package/lib/module/components/BugReportComposer.js +505 -0
  37. package/lib/module/components/BugReportComposer.js.map +1 -0
  38. package/lib/module/components/FlagsTab.js +23 -13
  39. package/lib/module/components/FlagsTab.js.map +1 -1
  40. package/lib/module/components/FloatingPill.js +86 -26
  41. package/lib/module/components/FloatingPill.js.map +1 -1
  42. package/lib/module/components/InfoTab.js +6 -2
  43. package/lib/module/components/InfoTab.js.map +1 -1
  44. package/lib/module/components/LogItem.js +7 -1
  45. package/lib/module/components/LogItem.js.map +1 -1
  46. package/lib/module/components/LogsTab.js +3 -3
  47. package/lib/module/components/LogsTab.js.map +1 -1
  48. package/lib/module/components/NetworkTab.js +3 -2
  49. package/lib/module/components/NetworkTab.js.map +1 -1
  50. package/lib/module/components/StorageTab.js +667 -0
  51. package/lib/module/components/StorageTab.js.map +1 -0
  52. package/lib/module/constants.js +88 -6
  53. package/lib/module/constants.js.map +1 -1
  54. package/lib/module/index.js +14 -0
  55. package/lib/module/index.js.map +1 -1
  56. package/lib/module/types.js +4 -0
  57. package/lib/module/types.js.map +1 -1
  58. package/lib/typescript/Backstage.d.ts.map +1 -1
  59. package/lib/typescript/bug-report.d.ts +12 -0
  60. package/lib/typescript/bug-report.d.ts.map +1 -0
  61. package/lib/typescript/components/BackstagePanel.d.ts +4 -1
  62. package/lib/typescript/components/BackstagePanel.d.ts.map +1 -1
  63. package/lib/typescript/components/BugReportComposer.d.ts +17 -0
  64. package/lib/typescript/components/BugReportComposer.d.ts.map +1 -0
  65. package/lib/typescript/components/FlagsTab.d.ts.map +1 -1
  66. package/lib/typescript/components/FloatingPill.d.ts +2 -0
  67. package/lib/typescript/components/FloatingPill.d.ts.map +1 -1
  68. package/lib/typescript/components/InfoTab.d.ts.map +1 -1
  69. package/lib/typescript/components/LogItem.d.ts.map +1 -1
  70. package/lib/typescript/components/LogsTab.d.ts.map +1 -1
  71. package/lib/typescript/components/NetworkTab.d.ts.map +1 -1
  72. package/lib/typescript/components/StorageTab.d.ts +9 -0
  73. package/lib/typescript/components/StorageTab.d.ts.map +1 -0
  74. package/lib/typescript/constants.d.ts +74 -4
  75. package/lib/typescript/constants.d.ts.map +1 -1
  76. package/lib/typescript/index.d.ts +13 -1
  77. package/lib/typescript/index.d.ts.map +1 -1
  78. package/lib/typescript/types.d.ts +55 -0
  79. package/lib/typescript/types.d.ts.map +1 -1
  80. package/package.json +7 -6
  81. package/src/Backstage.tsx +0 -209
  82. package/src/ThemeContext.tsx +0 -38
  83. package/src/components/BackstagePanel.tsx +0 -258
  84. package/src/components/FlagsTab.tsx +0 -198
  85. package/src/components/FloatingPill.tsx +0 -153
  86. package/src/components/InfoTab.tsx +0 -230
  87. package/src/components/JsonTreeView.tsx +0 -239
  88. package/src/components/LogItem.tsx +0 -144
  89. package/src/components/LogsTab.tsx +0 -217
  90. package/src/components/NetworkItem.tsx +0 -425
  91. package/src/components/NetworkTab.tsx +0 -240
  92. package/src/components/TabBar.tsx +0 -154
  93. package/src/constants.ts +0 -114
  94. package/src/index.ts +0 -18
  95. package/src/log-interceptor.ts +0 -148
  96. package/src/network-interceptor.ts +0 -468
  97. package/src/types.ts +0 -213
  98. package/src/utils/formatTimestamp.ts +0 -22
  99. package/src/utils/stringify.ts +0 -90
@@ -0,0 +1,672 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StorageTab = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _constants = require("../constants");
10
+ var _ThemeContext = require("../ThemeContext");
11
+ var _JsonTreeView = require("./JsonTreeView");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
+ // ─── Types ───────────────────────────────────────────────────────────────────
15
+
16
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
17
+
18
+ function tryParseJSON(text) {
19
+ try {
20
+ const parsed = JSON.parse(text);
21
+ return typeof parsed === 'object' && parsed !== null ? parsed : null;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ function truncateValue(value, max = 80) {
27
+ if (value.length <= max) return value;
28
+ return value.substring(0, max) + '…';
29
+ }
30
+
31
+ // ─── Editor Modal ────────────────────────────────────────────────────────────
32
+
33
+ const EditorModal = ({
34
+ visible,
35
+ title,
36
+ storageKey,
37
+ storageValue,
38
+ isNewEntry,
39
+ onChangeKey,
40
+ onChangeValue,
41
+ onSave,
42
+ onCancel,
43
+ theme
44
+ }) => {
45
+ const s = (0, _react.useMemo)(() => createStyles(theme), [theme]);
46
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
47
+ visible: visible,
48
+ animationType: "slide",
49
+ transparent: false,
50
+ onRequestClose: onCancel,
51
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.SafeAreaView, {
52
+ style: s.modalContainer,
53
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
54
+ style: s.modalHeader,
55
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
56
+ onPress: onCancel,
57
+ hitSlop: {
58
+ top: 8,
59
+ bottom: 8,
60
+ left: 8,
61
+ right: 8
62
+ },
63
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
64
+ style: s.modalCancelText,
65
+ children: "Cancel"
66
+ })
67
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
68
+ style: s.modalTitle,
69
+ children: title
70
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
71
+ onPress: onSave,
72
+ hitSlop: {
73
+ top: 8,
74
+ bottom: 8,
75
+ left: 8,
76
+ right: 8
77
+ },
78
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
79
+ style: s.modalSaveText,
80
+ children: "Save"
81
+ })
82
+ })]
83
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.KeyboardAvoidingView, {
84
+ style: s.modalBody,
85
+ behavior: _reactNative.Platform.OS === 'ios' ? 'padding' : undefined,
86
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
87
+ contentContainerStyle: s.modalBodyContent,
88
+ keyboardShouldPersistTaps: "handled",
89
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
90
+ style: s.modalLabel,
91
+ children: "Key"
92
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
93
+ style: [s.modalInput, !isNewEntry && s.modalInputDisabled],
94
+ value: storageKey,
95
+ onChangeText: onChangeKey,
96
+ editable: isNewEntry,
97
+ autoCapitalize: "none",
98
+ autoCorrect: false,
99
+ placeholderTextColor: theme.textMuted,
100
+ placeholder: "Storage key"
101
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
102
+ style: [s.modalLabel, {
103
+ marginTop: 16
104
+ }],
105
+ children: "Value"
106
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
107
+ style: [s.modalInput, s.modalValueInput],
108
+ value: storageValue,
109
+ onChangeText: onChangeValue,
110
+ multiline: true,
111
+ autoFocus: !isNewEntry,
112
+ textAlignVertical: "top",
113
+ placeholderTextColor: theme.textMuted,
114
+ placeholder: "Value"
115
+ })]
116
+ })
117
+ })]
118
+ })
119
+ });
120
+ };
121
+
122
+ // ─── Component ───────────────────────────────────────────────────────────────
123
+
124
+ const StorageTab = ({
125
+ adapter,
126
+ jsonMaxDepth
127
+ }) => {
128
+ const theme = (0, _ThemeContext.useBackstageTheme)();
129
+ const s = (0, _react.useMemo)(() => createStyles(theme), [theme]);
130
+ const [entries, setEntries] = (0, _react.useState)([]);
131
+ const [loading, setLoading] = (0, _react.useState)(true);
132
+ const [searchText, setSearchText] = (0, _react.useState)('');
133
+
134
+ // Editor modal state
135
+ const [editorVisible, setEditorVisible] = (0, _react.useState)(false);
136
+ const [editorIsNew, setEditorIsNew] = (0, _react.useState)(false);
137
+ const [editorKey, setEditorKey] = (0, _react.useState)('');
138
+ const [editorValue, setEditorValue] = (0, _react.useState)('');
139
+
140
+ // Expanded entries (for JSON preview)
141
+ const [expandedKeys, setExpandedKeys] = (0, _react.useState)(new Set());
142
+
143
+ // ─── Load Entries ────────────────────────────────────────
144
+ const loadEntries = (0, _react.useCallback)(async () => {
145
+ setLoading(true);
146
+ try {
147
+ const keys = await adapter.getAllKeys();
148
+ const sorted = [...keys].sort((a, b) => a.localeCompare(b));
149
+ const results = [];
150
+ for (const key of sorted) {
151
+ const value = await adapter.getItem(key);
152
+ results.push({
153
+ key,
154
+ value: value ?? ''
155
+ });
156
+ }
157
+ setEntries(results);
158
+ } catch (err) {
159
+ console.error('[Backstage] StorageTab load error:', err);
160
+ } finally {
161
+ setLoading(false);
162
+ }
163
+ }, [adapter]);
164
+ (0, _react.useEffect)(() => {
165
+ loadEntries();
166
+ }, [loadEntries]);
167
+
168
+ // ─── Filter ──────────────────────────────────────────────
169
+ const filteredEntries = (0, _react.useMemo)(() => {
170
+ if (!searchText.trim()) return entries;
171
+ const query = searchText.toLowerCase();
172
+ return entries.filter(e => e.key.toLowerCase().includes(query) || e.value.toLowerCase().includes(query));
173
+ }, [entries, searchText]);
174
+
175
+ // ─── Toggle Expand ───────────────────────────────────────
176
+ const toggleExpand = (0, _react.useCallback)(key => {
177
+ setExpandedKeys(prev => {
178
+ const next = new Set(prev);
179
+ if (next.has(key)) {
180
+ next.delete(key);
181
+ } else {
182
+ next.add(key);
183
+ }
184
+ return next;
185
+ });
186
+ }, []);
187
+
188
+ // ─── Editor ──────────────────────────────────────────────
189
+ const openEditor = (0, _react.useCallback)(entry => {
190
+ setEditorIsNew(false);
191
+ setEditorKey(entry.key);
192
+ setEditorValue(entry.value);
193
+ setEditorVisible(true);
194
+ }, []);
195
+ const openAddEditor = (0, _react.useCallback)(() => {
196
+ setEditorIsNew(true);
197
+ setEditorKey('');
198
+ setEditorValue('');
199
+ setEditorVisible(true);
200
+ }, []);
201
+ const closeEditor = (0, _react.useCallback)(() => {
202
+ setEditorVisible(false);
203
+ setEditorKey('');
204
+ setEditorValue('');
205
+ }, []);
206
+ const saveEditor = (0, _react.useCallback)(async () => {
207
+ const trimmedKey = editorKey.trim();
208
+ if (!trimmedKey) {
209
+ _reactNative.Alert.alert('Error', 'Key cannot be empty');
210
+ return;
211
+ }
212
+ try {
213
+ await adapter.setItem(trimmedKey, editorValue);
214
+ setEntries(prev => {
215
+ const exists = prev.findIndex(e => e.key === trimmedKey);
216
+ if (exists >= 0) {
217
+ const updated = [...prev];
218
+ updated[exists] = {
219
+ key: trimmedKey,
220
+ value: editorValue
221
+ };
222
+ return updated;
223
+ }
224
+ return [...prev, {
225
+ key: trimmedKey,
226
+ value: editorValue
227
+ }].sort((a, b) => a.key.localeCompare(b.key));
228
+ });
229
+ closeEditor();
230
+ } catch (err) {
231
+ _reactNative.Alert.alert('Error', `Failed to save: ${err}`);
232
+ }
233
+ }, [adapter, editorKey, editorValue, closeEditor]);
234
+
235
+ // ─── Delete ──────────────────────────────────────────────
236
+ const confirmDelete = (0, _react.useCallback)(key => {
237
+ _reactNative.Alert.alert('Delete Entry', `Remove "${key}" from storage?`, [{
238
+ text: 'Cancel',
239
+ style: 'cancel'
240
+ }, {
241
+ text: 'Delete',
242
+ style: 'destructive',
243
+ onPress: async () => {
244
+ try {
245
+ await adapter.removeItem(key);
246
+ setEntries(prev => prev.filter(e => e.key !== key));
247
+ setExpandedKeys(prev => {
248
+ const next = new Set(prev);
249
+ next.delete(key);
250
+ return next;
251
+ });
252
+ } catch (err) {
253
+ _reactNative.Alert.alert('Error', `Failed to delete: ${err}`);
254
+ }
255
+ }
256
+ }]);
257
+ }, [adapter]);
258
+
259
+ // ─── Render Entry ────────────────────────────────────────
260
+ const renderItem = (0, _react.useCallback)(({
261
+ item
262
+ }) => {
263
+ const isExpanded = expandedKeys.has(item.key);
264
+ const jsonValue = tryParseJSON(item.value);
265
+ const isJSON = jsonValue !== null;
266
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
267
+ style: s.entryContainer,
268
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
269
+ style: s.entryHeader,
270
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
271
+ style: s.entryKeyContainer,
272
+ onPress: () => toggleExpand(item.key),
273
+ activeOpacity: 0.7,
274
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
275
+ style: s.entryChevron,
276
+ children: isExpanded ? '▼' : '▶'
277
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
278
+ style: s.entryKey,
279
+ numberOfLines: 1,
280
+ children: item.key
281
+ }), isJSON && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
282
+ style: s.jsonBadge,
283
+ children: "JSON"
284
+ })]
285
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
286
+ style: s.entryActions,
287
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
288
+ onPress: () => openEditor(item),
289
+ hitSlop: {
290
+ top: 8,
291
+ bottom: 8,
292
+ left: 8,
293
+ right: 8
294
+ },
295
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
296
+ style: s.actionIcon,
297
+ children: "\u270E"
298
+ })
299
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
300
+ onPress: () => confirmDelete(item.key),
301
+ hitSlop: {
302
+ top: 8,
303
+ bottom: 8,
304
+ left: 8,
305
+ right: 8
306
+ },
307
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
308
+ style: [s.actionIcon, s.deleteIcon],
309
+ children: "\u2715"
310
+ })
311
+ })]
312
+ })]
313
+ }), isExpanded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
314
+ style: s.expandedValue,
315
+ children: isJSON ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
316
+ style: s.jsonContainer,
317
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_JsonTreeView.JsonTreeView, {
318
+ data: jsonValue,
319
+ hideRoot: true,
320
+ maxDepth: jsonMaxDepth
321
+ })
322
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
323
+ style: s.valueText,
324
+ selectable: true,
325
+ children: item.value || '(empty)'
326
+ })
327
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
328
+ onPress: () => toggleExpand(item.key),
329
+ activeOpacity: 0.7,
330
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
331
+ style: s.valuePreview,
332
+ numberOfLines: 1,
333
+ children: truncateValue(item.value) || '(empty)'
334
+ })
335
+ })]
336
+ });
337
+ }, [expandedKeys, jsonMaxDepth, s, toggleExpand, openEditor, confirmDelete]);
338
+ const keyExtractor = (0, _react.useCallback)(item => item.key, []);
339
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
340
+ style: s.container,
341
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
342
+ style: s.searchContainer,
343
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
344
+ style: s.searchInputWrapper,
345
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
346
+ style: s.searchIcon,
347
+ children: "\u2315"
348
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
349
+ style: s.searchInput,
350
+ placeholder: "Filter by key or value...",
351
+ placeholderTextColor: theme.textMuted,
352
+ value: searchText,
353
+ onChangeText: setSearchText,
354
+ autoCapitalize: "none",
355
+ autoCorrect: false,
356
+ clearButtonMode: "while-editing",
357
+ returnKeyType: "search"
358
+ })]
359
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
360
+ style: s.addButton,
361
+ onPress: openAddEditor,
362
+ activeOpacity: 0.7,
363
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
364
+ style: s.addButtonText,
365
+ children: "\uFF0B"
366
+ })
367
+ })]
368
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
369
+ style: s.statsBar,
370
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
371
+ style: s.statText,
372
+ children: filteredEntries.length === entries.length ? `${entries.length} entr${entries.length !== 1 ? 'ies' : 'y'}` : `${filteredEntries.length} of ${entries.length}`
373
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
374
+ style: s.pullHint,
375
+ children: "\u2193 pull to refresh"
376
+ })]
377
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
378
+ data: filteredEntries,
379
+ renderItem: renderItem,
380
+ keyExtractor: keyExtractor,
381
+ refreshing: loading,
382
+ onRefresh: loadEntries,
383
+ style: s.list,
384
+ contentContainerStyle: filteredEntries.length === 0 ? s.emptyContainer : undefined,
385
+ ListEmptyComponent: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
386
+ style: s.emptyState,
387
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
388
+ style: s.emptyIcon,
389
+ children: "\uD83D\uDDC4"
390
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
391
+ style: s.emptyTitle,
392
+ children: loading ? 'Loading…' : 'No entries'
393
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
394
+ style: s.emptySubtitle,
395
+ children: loading ? 'Reading storage keys' : 'Storage is empty or no entries match'
396
+ })]
397
+ }),
398
+ maxToRenderPerBatch: 20,
399
+ windowSize: 10,
400
+ initialNumToRender: 20,
401
+ removeClippedSubviews: true
402
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(EditorModal, {
403
+ visible: editorVisible,
404
+ title: editorIsNew ? 'Add Entry' : `Edit "${editorKey}"`,
405
+ storageKey: editorKey,
406
+ storageValue: editorValue,
407
+ isNewEntry: editorIsNew,
408
+ onChangeKey: setEditorKey,
409
+ onChangeValue: setEditorValue,
410
+ onSave: saveEditor,
411
+ onCancel: closeEditor,
412
+ theme: theme
413
+ })]
414
+ });
415
+ };
416
+
417
+ // ─── Styles ──────────────────────────────────────────────────────────────────
418
+ exports.StorageTab = StorageTab;
419
+ const createStyles = t => _reactNative.StyleSheet.create({
420
+ container: {
421
+ flex: 1
422
+ },
423
+ // ── Search ─────────────────────
424
+ searchContainer: {
425
+ flexDirection: 'row',
426
+ alignItems: 'center',
427
+ paddingHorizontal: 14,
428
+ paddingVertical: 10,
429
+ gap: 10,
430
+ borderBottomWidth: 1,
431
+ borderBottomColor: t.border
432
+ },
433
+ searchInputWrapper: {
434
+ flex: 1,
435
+ flexDirection: 'row',
436
+ alignItems: 'center',
437
+ backgroundColor: t.surfaceElevated,
438
+ borderRadius: 10,
439
+ borderWidth: 1,
440
+ borderColor: t.border,
441
+ paddingHorizontal: 12,
442
+ height: 38
443
+ },
444
+ searchIcon: {
445
+ fontSize: 16,
446
+ color: t.textMuted,
447
+ marginRight: 8
448
+ },
449
+ searchInput: {
450
+ flex: 1,
451
+ fontFamily: _constants.MonospaceFont,
452
+ fontSize: 13,
453
+ color: t.text,
454
+ padding: 0
455
+ },
456
+ addButton: {
457
+ width: 38,
458
+ height: 38,
459
+ borderRadius: 10,
460
+ backgroundColor: t.accentDim,
461
+ borderWidth: 1,
462
+ borderColor: t.accent,
463
+ alignItems: 'center',
464
+ justifyContent: 'center'
465
+ },
466
+ addButtonText: {
467
+ fontSize: 18,
468
+ color: t.accent,
469
+ fontWeight: '700'
470
+ },
471
+ // ── Stats ──────────────────────
472
+ statsBar: {
473
+ flexDirection: 'row',
474
+ justifyContent: 'space-between',
475
+ alignItems: 'center',
476
+ paddingHorizontal: 16,
477
+ paddingVertical: 6,
478
+ backgroundColor: t.surface
479
+ },
480
+ statText: {
481
+ fontFamily: _constants.MonospaceFont,
482
+ fontSize: 11,
483
+ color: t.textMuted
484
+ },
485
+ pullHint: {
486
+ fontFamily: _constants.MonospaceFont,
487
+ fontSize: 10,
488
+ color: t.textMuted,
489
+ fontStyle: 'italic'
490
+ },
491
+ // ── List ───────────────────────
492
+ list: {
493
+ flex: 1
494
+ },
495
+ emptyContainer: {
496
+ flex: 1,
497
+ justifyContent: 'center'
498
+ },
499
+ emptyState: {
500
+ alignItems: 'center',
501
+ justifyContent: 'center',
502
+ padding: 40
503
+ },
504
+ emptyIcon: {
505
+ fontSize: 48,
506
+ marginBottom: 16,
507
+ opacity: 0.5
508
+ },
509
+ emptyTitle: {
510
+ fontFamily: _constants.MonospaceFont,
511
+ fontSize: 16,
512
+ fontWeight: '700',
513
+ color: t.textSecondary,
514
+ marginBottom: 8
515
+ },
516
+ emptySubtitle: {
517
+ fontFamily: _constants.MonospaceFont,
518
+ fontSize: 13,
519
+ color: t.textMuted,
520
+ textAlign: 'center'
521
+ },
522
+ // ── Entry ──────────────────────
523
+ entryContainer: {
524
+ paddingHorizontal: 14,
525
+ paddingVertical: 10,
526
+ borderBottomWidth: 1,
527
+ borderBottomColor: t.border
528
+ },
529
+ entryHeader: {
530
+ flexDirection: 'row',
531
+ alignItems: 'center',
532
+ justifyContent: 'space-between',
533
+ marginBottom: 4
534
+ },
535
+ entryKeyContainer: {
536
+ flex: 1,
537
+ flexDirection: 'row',
538
+ alignItems: 'center'
539
+ },
540
+ entryChevron: {
541
+ fontFamily: _constants.MonospaceFont,
542
+ fontSize: 10,
543
+ color: t.textMuted,
544
+ marginRight: 6,
545
+ width: 12
546
+ },
547
+ entryKey: {
548
+ fontFamily: _constants.MonospaceFont,
549
+ fontSize: 13,
550
+ fontWeight: '700',
551
+ color: t.text,
552
+ flex: 1
553
+ },
554
+ jsonBadge: {
555
+ fontFamily: _constants.MonospaceFont,
556
+ fontSize: 9,
557
+ fontWeight: '800',
558
+ color: t.info,
559
+ backgroundColor: t.infoDim,
560
+ borderRadius: 3,
561
+ paddingHorizontal: 5,
562
+ paddingVertical: 1,
563
+ marginLeft: 6,
564
+ overflow: 'hidden'
565
+ },
566
+ entryActions: {
567
+ flexDirection: 'row',
568
+ alignItems: 'center',
569
+ gap: 12,
570
+ marginLeft: 8
571
+ },
572
+ actionIcon: {
573
+ fontSize: 16,
574
+ color: t.textMuted
575
+ },
576
+ deleteIcon: {
577
+ color: t.error
578
+ },
579
+ // ── Value Preview ──────────────
580
+ valuePreview: {
581
+ fontFamily: _constants.MonospaceFont,
582
+ fontSize: 12,
583
+ color: t.textSecondary,
584
+ paddingLeft: 18,
585
+ lineHeight: 18
586
+ },
587
+ expandedValue: {
588
+ marginTop: 4,
589
+ paddingLeft: 18
590
+ },
591
+ valueText: {
592
+ fontFamily: _constants.MonospaceFont,
593
+ fontSize: 12,
594
+ color: t.text,
595
+ lineHeight: 18
596
+ },
597
+ jsonContainer: {
598
+ backgroundColor: t.surfaceElevated,
599
+ borderRadius: 8,
600
+ borderWidth: 1,
601
+ borderColor: t.border,
602
+ padding: 8
603
+ },
604
+ // ── Editor Modal ───────────────
605
+ modalContainer: {
606
+ flex: 1,
607
+ backgroundColor: t.background
608
+ },
609
+ modalHeader: {
610
+ flexDirection: 'row',
611
+ alignItems: 'center',
612
+ justifyContent: 'space-between',
613
+ paddingHorizontal: 16,
614
+ paddingVertical: 12,
615
+ borderBottomWidth: 1,
616
+ borderBottomColor: t.border
617
+ },
618
+ modalTitle: {
619
+ fontFamily: _constants.MonospaceFont,
620
+ fontSize: 16,
621
+ fontWeight: '700',
622
+ color: t.text,
623
+ flex: 1,
624
+ textAlign: 'center'
625
+ },
626
+ modalCancelText: {
627
+ fontFamily: _constants.MonospaceFont,
628
+ fontSize: 14,
629
+ color: t.textSecondary,
630
+ fontWeight: '600'
631
+ },
632
+ modalSaveText: {
633
+ fontFamily: _constants.MonospaceFont,
634
+ fontSize: 14,
635
+ color: t.accent,
636
+ fontWeight: '700'
637
+ },
638
+ modalBody: {
639
+ flex: 1
640
+ },
641
+ modalBodyContent: {
642
+ padding: 16
643
+ },
644
+ modalLabel: {
645
+ fontFamily: _constants.MonospaceFont,
646
+ fontSize: 12,
647
+ fontWeight: '700',
648
+ color: t.textMuted,
649
+ textTransform: 'uppercase',
650
+ letterSpacing: 0.5,
651
+ marginBottom: 6
652
+ },
653
+ modalInput: {
654
+ fontFamily: _constants.MonospaceFont,
655
+ fontSize: 13,
656
+ color: t.text,
657
+ backgroundColor: t.surfaceElevated,
658
+ borderRadius: 8,
659
+ borderWidth: 1,
660
+ borderColor: t.border,
661
+ paddingHorizontal: 12,
662
+ paddingVertical: 10
663
+ },
664
+ modalInputDisabled: {
665
+ opacity: 0.5
666
+ },
667
+ modalValueInput: {
668
+ minHeight: 160,
669
+ lineHeight: 20
670
+ }
671
+ });
672
+ //# sourceMappingURL=StorageTab.js.map