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