react-native-inapp-inspector 2.3.0 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/components/Inspector/MainScreen.js +7 -11
- package/dist/commonjs/components/Inspector/StorageTab.js +104 -89
- package/dist/commonjs/components/SkeletonPlaceholder.d.ts +6 -0
- package/dist/commonjs/components/SkeletonPlaceholder.js +208 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/storageInspector.d.ts +2 -2
- package/dist/commonjs/customHooks/storageInspector.js +17 -13
- package/dist/commonjs/index.js +28 -24
- package/dist/commonjs/types/interfaces.d.ts +1 -2
- package/dist/esm/components/Inspector/MainScreen.js +8 -12
- package/dist/esm/components/Inspector/StorageTab.js +105 -90
- package/dist/esm/components/SkeletonPlaceholder.d.ts +6 -0
- package/dist/esm/components/SkeletonPlaceholder.js +173 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/storageInspector.d.ts +2 -2
- package/dist/esm/customHooks/storageInspector.js +17 -13
- package/dist/esm/index.js +29 -25
- package/dist/esm/types/interfaces.d.ts +1 -2
- package/package.json +1 -1
- package/src/components/Inspector/MainScreen.tsx +7 -11
- package/src/components/Inspector/StorageTab.tsx +170 -114
- package/src/components/SkeletonPlaceholder.tsx +206 -0
- package/src/constants/version.ts +1 -1
- package/src/customHooks/storageInspector.ts +18 -14
- package/src/index.tsx +35 -26
- package/src/types/interfaces.ts +1 -2
|
@@ -49,6 +49,7 @@ const LogDetail_1 = __importDefault(require("./LogDetail"));
|
|
|
49
49
|
const ConsoleTab_1 = __importDefault(require("./ConsoleTab"));
|
|
50
50
|
const AnalyticsTab_1 = __importDefault(require("./AnalyticsTab"));
|
|
51
51
|
const AnalyticsDetail_1 = __importDefault(require("../AnalyticsDetail"));
|
|
52
|
+
const SkeletonPlaceholder_1 = __importDefault(require("../SkeletonPlaceholder"));
|
|
52
53
|
const ReduxTab_1 = __importDefault(require("./ReduxTab"));
|
|
53
54
|
const ReduxDetail_1 = __importDefault(require("./ReduxDetail"));
|
|
54
55
|
const BundleTab_1 = __importDefault(require("./BundleTab"));
|
|
@@ -64,7 +65,7 @@ const styles_1 = __importDefault(require("../../styles"));
|
|
|
64
65
|
const AppColors_1 = require("../../styles/AppColors");
|
|
65
66
|
const NavigationTracker_1 = __importDefault(require("./NavigationTracker"));
|
|
66
67
|
const MainScreen = () => {
|
|
67
|
-
const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady,
|
|
68
|
+
const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, enabled, useNativeFab, hasNavigationContext, setNavState, } = (0, InspectorContext_1.useInspector)();
|
|
68
69
|
const isDetailActive = (activeTab === 'apis' && selected != null) ||
|
|
69
70
|
(activeTab === 'analytics' && selectedEvent != null) ||
|
|
70
71
|
(activeTab === 'logs' && selectedLog != null) ||
|
|
@@ -106,7 +107,7 @@ const MainScreen = () => {
|
|
|
106
107
|
}, [activeTab]);
|
|
107
108
|
return (<>
|
|
108
109
|
{(react_native_1.Platform.OS === 'ios' || react_native_1.Platform.OS === 'android') &&
|
|
109
|
-
|
|
110
|
+
enabled &&
|
|
110
111
|
!visible &&
|
|
111
112
|
!useNativeFab && <FabLauncher_1.default />}
|
|
112
113
|
<react_native_1.Modal visible={visible} animationType={modalAnimationType} transparent statusBarTranslucent={true}>
|
|
@@ -126,10 +127,10 @@ const MainScreen = () => {
|
|
|
126
127
|
<InspectorHeader_1.default />
|
|
127
128
|
|
|
128
129
|
<react_native_1.View style={{ flex: 1 }}>
|
|
129
|
-
{
|
|
130
|
-
|
|
131
|
-
{!isDetailActive && <TabBar_1.default />}
|
|
130
|
+
{/* ─── Horizontal Scrollable Tab Bar inside Content (Always visible) ─── */}
|
|
131
|
+
{!isDetailActive && <TabBar_1.default />}
|
|
132
132
|
|
|
133
|
+
{isReady ? (<react_native_1.View style={{ flex: 1 }}>
|
|
133
134
|
{/* Persistent List Layer - Never unmounted, preserves 100% native scroll with smooth tab transition */}
|
|
134
135
|
<react_native_1.Animated.View style={[
|
|
135
136
|
{
|
|
@@ -181,12 +182,7 @@ const MainScreen = () => {
|
|
|
181
182
|
{activeTab === 'redux' && <ReduxDetail_1.default />}
|
|
182
183
|
{activeTab === 'crash' && selectedCrash != null && (<CrashDetail_1.default />)}
|
|
183
184
|
</react_native_1.Animated.View>)}
|
|
184
|
-
</react_native_1.View>) : (<
|
|
185
|
-
<react_native_1.ActivityIndicator size="large" color={AppColors_1.AppColors.purple}/>
|
|
186
|
-
<react_native_1.Text style={[styles_1.default.emptySub, { marginTop: 12 }]}>
|
|
187
|
-
Loading logs...
|
|
188
|
-
</react_native_1.Text>
|
|
189
|
-
</react_native_1.View>)}
|
|
185
|
+
</react_native_1.View>) : (<SkeletonPlaceholder_1.default />)}
|
|
190
186
|
|
|
191
187
|
{/* Settings Panel Layer - Rendered on top with smooth slide & spring transition */}
|
|
192
188
|
{settingsPage !== null && (<react_native_1.Animated.View style={[
|
|
@@ -47,6 +47,92 @@ const NetworkIcons_1 = require("../NetworkIcons");
|
|
|
47
47
|
const storageInspector_1 = require("../../customHooks/storageInspector");
|
|
48
48
|
const helpers_1 = require("../../helpers");
|
|
49
49
|
const toast_1 = require("../../helpers/toast");
|
|
50
|
+
const getTypeBadge = (type) => {
|
|
51
|
+
switch (type) {
|
|
52
|
+
case 'json':
|
|
53
|
+
return { label: 'JSON', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}16` };
|
|
54
|
+
case 'number':
|
|
55
|
+
return { label: 'NUM', color: AppColors_1.AppColors.warningIconGold, bg: `${AppColors_1.AppColors.warningIconGold}16` };
|
|
56
|
+
case 'boolean':
|
|
57
|
+
return { label: 'BOOL', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}16` };
|
|
58
|
+
case 'null':
|
|
59
|
+
return { label: 'NULL', color: AppColors_1.AppColors.grayTextWeak, bg: `${AppColors_1.AppColors.grayTextWeak}16` };
|
|
60
|
+
default:
|
|
61
|
+
return { label: 'STR', color: AppColors_1.AppColors.blue500, bg: `${AppColors_1.AppColors.blue500}16` };
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const StorageEntryCard = react_1.default.memo(function StorageEntryCard({ entry, isExpanded, onToggleExpand, onCopy, onEdit, onDelete, badge, }) {
|
|
65
|
+
const formattedBytes = (0, react_1.useMemo)(() => {
|
|
66
|
+
return entry.byteSize < 1024
|
|
67
|
+
? `${entry.byteSize} B`
|
|
68
|
+
: `${(entry.byteSize / 1024).toFixed(1)} KB`;
|
|
69
|
+
}, [entry.byteSize]);
|
|
70
|
+
// Lazy compute displayed value to avoid layout thrashing on large JSON strings
|
|
71
|
+
const displayValue = (0, react_1.useMemo)(() => {
|
|
72
|
+
if (!isExpanded) {
|
|
73
|
+
if (entry.value.length > 250) {
|
|
74
|
+
return entry.value.slice(0, 250) + '...';
|
|
75
|
+
}
|
|
76
|
+
return entry.value;
|
|
77
|
+
}
|
|
78
|
+
if (entry.type === 'json') {
|
|
79
|
+
try {
|
|
80
|
+
const parsed = entry.parsedValue ?? JSON.parse(entry.value);
|
|
81
|
+
return JSON.stringify(parsed, null, 2);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return entry.value;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return entry.value;
|
|
88
|
+
}, [isExpanded, entry.value, entry.type, entry.parsedValue]);
|
|
89
|
+
return (<react_native_1.View style={styles.entryCard}>
|
|
90
|
+
{/* Entry Header: Key name, Type Badge, Size, Actions */}
|
|
91
|
+
<react_native_1.View style={styles.entryHeader}>
|
|
92
|
+
<react_native_1.View style={{ flex: 1, marginRight: 8 }}>
|
|
93
|
+
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
|
|
94
|
+
<react_native_1.Text style={styles.entryKey} numberOfLines={1} selectable>
|
|
95
|
+
{entry.key}
|
|
96
|
+
</react_native_1.Text>
|
|
97
|
+
<react_native_1.View style={[
|
|
98
|
+
styles.typeBadge,
|
|
99
|
+
{ backgroundColor: badge.bg, borderColor: `${badge.color}33` },
|
|
100
|
+
]}>
|
|
101
|
+
<react_native_1.Text style={[styles.typeBadgeText, { color: badge.color }]}>
|
|
102
|
+
{badge.label}
|
|
103
|
+
</react_native_1.Text>
|
|
104
|
+
</react_native_1.View>
|
|
105
|
+
<react_native_1.Text style={styles.sizeText}>{formattedBytes}</react_native_1.Text>
|
|
106
|
+
</react_native_1.View>
|
|
107
|
+
</react_native_1.View>
|
|
108
|
+
|
|
109
|
+
{/* Actions: Copy, Edit, Delete */}
|
|
110
|
+
<react_native_1.View style={styles.entryActions}>
|
|
111
|
+
<TouchableScale_1.default hitSlop={6} onPress={() => onCopy(entry)} style={styles.entryActionBtn}>
|
|
112
|
+
<NetworkIcons_1.CopyIcon size={12} color={AppColors_1.AppColors.grayText}/>
|
|
113
|
+
</TouchableScale_1.default>
|
|
114
|
+
|
|
115
|
+
<TouchableScale_1.default hitSlop={6} onPress={() => onEdit(entry)} style={styles.entryActionBtn}>
|
|
116
|
+
<NetworkIcons_1.PencilIcon size={12} color={AppColors_1.AppColors.purple}/>
|
|
117
|
+
</TouchableScale_1.default>
|
|
118
|
+
|
|
119
|
+
<TouchableScale_1.default hitSlop={6} onPress={() => onDelete(entry.key)} style={[styles.entryActionBtn, { backgroundColor: `${AppColors_1.AppColors.errorColor}12` }]}>
|
|
120
|
+
<NetworkIcons_1.TrashIcon size={12} color={AppColors_1.AppColors.errorColor}/>
|
|
121
|
+
</TouchableScale_1.default>
|
|
122
|
+
</react_native_1.View>
|
|
123
|
+
</react_native_1.View>
|
|
124
|
+
|
|
125
|
+
{/* Entry Value Preview / Viewer */}
|
|
126
|
+
<TouchableScale_1.default onPress={() => onToggleExpand(entry.key)} style={styles.valuePreviewBox}>
|
|
127
|
+
<react_native_1.Text style={styles.valuePreviewText} numberOfLines={isExpanded ? undefined : 3} selectable={isExpanded}>
|
|
128
|
+
{displayValue}
|
|
129
|
+
</react_native_1.Text>
|
|
130
|
+
{entry.value.length > 80 && (<react_native_1.Text style={styles.expandHint}>
|
|
131
|
+
{isExpanded ? '▲ Collapse' : '▼ Expand'}
|
|
132
|
+
</react_native_1.Text>)}
|
|
133
|
+
</TouchableScale_1.default>
|
|
134
|
+
</react_native_1.View>);
|
|
135
|
+
});
|
|
50
136
|
exports.StorageTab = react_1.default.memo(() => {
|
|
51
137
|
const { t } = (0, i18n_1.useTranslation)();
|
|
52
138
|
const [activeDriver, setActiveDriver] = (0, react_1.useState)('asyncStorage');
|
|
@@ -205,20 +291,11 @@ exports.StorageTab = react_1.default.memo(() => {
|
|
|
205
291
|
return `${(totalBytes / 1024).toFixed(1)} KB`;
|
|
206
292
|
return `${(totalBytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
207
293
|
}, [totalBytes]);
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return { label: 'NUM', color: AppColors_1.AppColors.warningIconGold, bg: `${AppColors_1.AppColors.warningIconGold}16` };
|
|
214
|
-
case 'boolean':
|
|
215
|
-
return { label: 'BOOL', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}16` };
|
|
216
|
-
case 'null':
|
|
217
|
-
return { label: 'NULL', color: AppColors_1.AppColors.grayTextWeak, bg: `${AppColors_1.AppColors.grayTextWeak}16` };
|
|
218
|
-
default:
|
|
219
|
-
return { label: 'STR', color: AppColors_1.AppColors.blue500, bg: `${AppColors_1.AppColors.blue500}16` };
|
|
220
|
-
}
|
|
221
|
-
};
|
|
294
|
+
const handleCopyEntry = (0, react_1.useCallback)((entry) => {
|
|
295
|
+
(0, helpers_1.copyToClipboard)(entry.value, entry.key);
|
|
296
|
+
(0, toast_1.showToast)(`Copied value of "${entry.key}"`);
|
|
297
|
+
}, []);
|
|
298
|
+
const renderItem = (0, react_1.useCallback)(({ item }) => (<StorageEntryCard entry={item} isExpanded={Boolean(expandedKeys[item.key])} onToggleExpand={toggleExpand} onCopy={handleCopyEntry} onEdit={handleOpenEdit} onDelete={handleDeleteKey} badge={getTypeBadge(item.type)}/>), [expandedKeys, handleCopyEntry]);
|
|
222
299
|
const isConnected = activeDriver === 'asyncStorage'
|
|
223
300
|
? (0, storageInspector_1.isAsyncStorageConnected)()
|
|
224
301
|
: (0, storageInspector_1.isMMKVConnected)();
|
|
@@ -334,81 +411,19 @@ exports.StorageTab = react_1.default.memo(() => {
|
|
|
334
411
|
{isLoading ? (<react_native_1.View style={styles.loadingContainer}>
|
|
335
412
|
<react_native_1.ActivityIndicator size="small" color={AppColors_1.AppColors.purple}/>
|
|
336
413
|
<react_native_1.Text style={styles.loadingText}>Loading storage entries...</react_native_1.Text>
|
|
337
|
-
</react_native_1.View>) : filteredEntries.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
{filteredEntries.map(entry => {
|
|
351
|
-
const isExpanded = Boolean(expandedKeys[entry.key]);
|
|
352
|
-
const badge = getTypeBadge(entry.type);
|
|
353
|
-
const formattedBytes = entry.byteSize < 1024
|
|
354
|
-
? `${entry.byteSize} B`
|
|
355
|
-
: `${(entry.byteSize / 1024).toFixed(1)} KB`;
|
|
356
|
-
return (<react_native_1.View key={entry.key} style={styles.entryCard}>
|
|
357
|
-
{/* Entry Header: Key name, Type Badge, Size, Actions */}
|
|
358
|
-
<react_native_1.View style={styles.entryHeader}>
|
|
359
|
-
<react_native_1.View style={{ flex: 1, marginRight: 8 }}>
|
|
360
|
-
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
|
|
361
|
-
<react_native_1.Text style={styles.entryKey} numberOfLines={1} selectable>
|
|
362
|
-
{entry.key}
|
|
363
|
-
</react_native_1.Text>
|
|
364
|
-
<react_native_1.View style={[
|
|
365
|
-
styles.typeBadge,
|
|
366
|
-
{ backgroundColor: badge.bg, borderColor: `${badge.color}33` },
|
|
367
|
-
]}>
|
|
368
|
-
<react_native_1.Text style={[styles.typeBadgeText, { color: badge.color }]}>
|
|
369
|
-
{badge.label}
|
|
370
|
-
</react_native_1.Text>
|
|
371
|
-
</react_native_1.View>
|
|
372
|
-
<react_native_1.Text style={styles.sizeText}>{formattedBytes}</react_native_1.Text>
|
|
373
|
-
</react_native_1.View>
|
|
374
|
-
</react_native_1.View>
|
|
375
|
-
|
|
376
|
-
{/* Actions: Copy, Edit, Delete */}
|
|
377
|
-
<react_native_1.View style={styles.entryActions}>
|
|
378
|
-
<TouchableScale_1.default hitSlop={6} onPress={() => {
|
|
379
|
-
(0, helpers_1.copyToClipboard)(entry.value, entry.key);
|
|
380
|
-
(0, toast_1.showToast)(`Copied value of "${entry.key}"`);
|
|
381
|
-
}} style={styles.entryActionBtn}>
|
|
382
|
-
<NetworkIcons_1.CopyIcon size={12} color={AppColors_1.AppColors.grayText}/>
|
|
383
|
-
</TouchableScale_1.default>
|
|
384
|
-
|
|
385
|
-
<TouchableScale_1.default hitSlop={6} onPress={() => handleOpenEdit(entry)} style={styles.entryActionBtn}>
|
|
386
|
-
<NetworkIcons_1.PencilIcon size={12} color={AppColors_1.AppColors.purple}/>
|
|
387
|
-
</TouchableScale_1.default>
|
|
388
|
-
|
|
389
|
-
<TouchableScale_1.default hitSlop={6} onPress={() => handleDeleteKey(entry.key)} style={[styles.entryActionBtn, { backgroundColor: `${AppColors_1.AppColors.errorColor}12` }]}>
|
|
390
|
-
<NetworkIcons_1.TrashIcon size={12} color={AppColors_1.AppColors.errorColor}/>
|
|
391
|
-
</TouchableScale_1.default>
|
|
392
|
-
</react_native_1.View>
|
|
393
|
-
</react_native_1.View>
|
|
394
|
-
|
|
395
|
-
{/* Entry Value Preview / Viewer */}
|
|
396
|
-
<TouchableScale_1.default onPress={() => toggleExpand(entry.key)} style={styles.valuePreviewBox}>
|
|
397
|
-
<react_native_1.Text style={styles.valuePreviewText} numberOfLines={isExpanded ? undefined : 3} selectable>
|
|
398
|
-
{entry.type === 'json' && entry.parsedValue
|
|
399
|
-
? isExpanded
|
|
400
|
-
? JSON.stringify(entry.parsedValue, null, 2)
|
|
401
|
-
: entry.value
|
|
402
|
-
: entry.value}
|
|
403
|
-
</react_native_1.Text>
|
|
404
|
-
{entry.value.length > 80 && (<react_native_1.Text style={styles.expandHint}>
|
|
405
|
-
{isExpanded ? '▲ Collapse' : '▼ Expand'}
|
|
406
|
-
</react_native_1.Text>)}
|
|
407
|
-
</TouchableScale_1.default>
|
|
408
|
-
</react_native_1.View>);
|
|
409
|
-
})}
|
|
410
|
-
<react_native_1.View style={{ height: 60 }}/>
|
|
411
|
-
</react_native_1.ScrollView>)}
|
|
414
|
+
</react_native_1.View>) : (<react_native_1.FlatList data={filteredEntries} keyExtractor={item => item.key} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={react_native_1.Platform.OS === 'android'} style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false} ListEmptyComponent={<react_native_1.View style={styles.emptyContainer}>
|
|
415
|
+
<react_native_1.View style={styles.emptyIconWrap}>
|
|
416
|
+
<NetworkIcons_1.DatabaseIcon size={28} color={AppColors_1.AppColors.grayTextWeak}/>
|
|
417
|
+
</react_native_1.View>
|
|
418
|
+
<react_native_1.Text style={styles.emptyTitle}>
|
|
419
|
+
{search ? 'No matching keys found' : `No ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} Keys`}
|
|
420
|
+
</react_native_1.Text>
|
|
421
|
+
<react_native_1.Text style={styles.emptySubtitle}>
|
|
422
|
+
{search
|
|
423
|
+
? 'Try modifying your search query'
|
|
424
|
+
: `Storage is auto-detected. Tap "+ Add" above to create your first ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} key!`}
|
|
425
|
+
</react_native_1.Text>
|
|
426
|
+
</react_native_1.View>} ListFooterComponent={<react_native_1.View style={{ height: 60 }}/>}/>)}
|
|
412
427
|
|
|
413
428
|
{/* ── Create / Edit Key Modal ── */}
|
|
414
429
|
<react_native_1.Modal visible={modalVisible} transparent animationType="fade" onRequestClose={() => setModalVisible(false)}>
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const react_1 = __importStar(require("react"));
|
|
37
|
+
const react_native_1 = require("react-native");
|
|
38
|
+
const AppColors_1 = require("../styles/AppColors");
|
|
39
|
+
const SkeletonPlaceholder = react_1.default.memo(function SkeletonPlaceholder({ cardCount = 4, }) {
|
|
40
|
+
const shimmerAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0.35)).current;
|
|
41
|
+
(0, react_1.useEffect)(() => {
|
|
42
|
+
const animation = react_native_1.Animated.loop(react_native_1.Animated.sequence([
|
|
43
|
+
react_native_1.Animated.timing(shimmerAnim, {
|
|
44
|
+
toValue: 0.85,
|
|
45
|
+
duration: 750,
|
|
46
|
+
useNativeDriver: true,
|
|
47
|
+
}),
|
|
48
|
+
react_native_1.Animated.timing(shimmerAnim, {
|
|
49
|
+
toValue: 0.35,
|
|
50
|
+
duration: 750,
|
|
51
|
+
useNativeDriver: true,
|
|
52
|
+
}),
|
|
53
|
+
]));
|
|
54
|
+
animation.start();
|
|
55
|
+
return () => animation.stop();
|
|
56
|
+
}, [shimmerAnim]);
|
|
57
|
+
return (<react_native_1.View style={skeletonStyles.container}>
|
|
58
|
+
{/* ─── Search & Scope Toolbar Skeleton ─── */}
|
|
59
|
+
<react_native_1.View style={skeletonStyles.toolbarSkeleton}>
|
|
60
|
+
<react_native_1.Animated.View style={[
|
|
61
|
+
skeletonStyles.searchBarSkeleton,
|
|
62
|
+
{ opacity: shimmerAnim },
|
|
63
|
+
]}/>
|
|
64
|
+
<react_native_1.View style={skeletonStyles.actionButtonsRow}>
|
|
65
|
+
<react_native_1.Animated.View style={[skeletonStyles.iconButtonSkeleton, { opacity: shimmerAnim }]}/>
|
|
66
|
+
<react_native_1.Animated.View style={[skeletonStyles.iconButtonSkeleton, { opacity: shimmerAnim }]}/>
|
|
67
|
+
</react_native_1.View>
|
|
68
|
+
</react_native_1.View>
|
|
69
|
+
|
|
70
|
+
{/* ─── Quick Filter Chips Skeleton Strip ─── */}
|
|
71
|
+
<react_native_1.View style={skeletonStyles.chipStripSkeleton}>
|
|
72
|
+
<react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 48, opacity: shimmerAnim }]}/>
|
|
73
|
+
<react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 68, opacity: shimmerAnim }]}/>
|
|
74
|
+
<react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 76, opacity: shimmerAnim }]}/>
|
|
75
|
+
<react_native_1.Animated.View style={[skeletonStyles.chipSkeleton, { width: 58, opacity: shimmerAnim }]}/>
|
|
76
|
+
</react_native_1.View>
|
|
77
|
+
|
|
78
|
+
{/* ─── List Cards Skeleton ─── */}
|
|
79
|
+
{Array.from({ length: cardCount }).map((_, i) => (<react_native_1.Animated.View key={`skeleton_card_${i}`} style={[skeletonStyles.cardSkeleton, { opacity: shimmerAnim }]}>
|
|
80
|
+
{/* Top row: Status pill + Method + Time */}
|
|
81
|
+
<react_native_1.View style={skeletonStyles.cardTopRow}>
|
|
82
|
+
<react_native_1.View style={skeletonStyles.badgeGroup}>
|
|
83
|
+
<react_native_1.View style={skeletonStyles.statusBadgeSkeleton}/>
|
|
84
|
+
<react_native_1.View style={skeletonStyles.methodBadgeSkeleton}/>
|
|
85
|
+
</react_native_1.View>
|
|
86
|
+
<react_native_1.View style={skeletonStyles.timeSkeleton}/>
|
|
87
|
+
</react_native_1.View>
|
|
88
|
+
|
|
89
|
+
{/* Middle row: URL lines */}
|
|
90
|
+
<react_native_1.View style={skeletonStyles.urlLineLong}/>
|
|
91
|
+
<react_native_1.View style={skeletonStyles.urlLineShort}/>
|
|
92
|
+
|
|
93
|
+
{/* Bottom row: Latency & Size */}
|
|
94
|
+
<react_native_1.View style={skeletonStyles.cardBottomRow}>
|
|
95
|
+
<react_native_1.View style={skeletonStyles.metaPillSkeleton}/>
|
|
96
|
+
<react_native_1.View style={skeletonStyles.metaPillSkeleton}/>
|
|
97
|
+
</react_native_1.View>
|
|
98
|
+
</react_native_1.Animated.View>))}
|
|
99
|
+
</react_native_1.View>);
|
|
100
|
+
});
|
|
101
|
+
const skeletonStyles = react_native_1.StyleSheet.create({
|
|
102
|
+
container: {
|
|
103
|
+
flex: 1,
|
|
104
|
+
paddingHorizontal: 12,
|
|
105
|
+
paddingTop: 8,
|
|
106
|
+
},
|
|
107
|
+
toolbarSkeleton: {
|
|
108
|
+
flexDirection: 'row',
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
gap: 8,
|
|
111
|
+
marginBottom: 8,
|
|
112
|
+
},
|
|
113
|
+
searchBarSkeleton: {
|
|
114
|
+
flex: 1,
|
|
115
|
+
height: 36,
|
|
116
|
+
borderRadius: 8,
|
|
117
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
118
|
+
borderWidth: 1,
|
|
119
|
+
borderColor: AppColors_1.AppColors.dividerColor,
|
|
120
|
+
},
|
|
121
|
+
actionButtonsRow: {
|
|
122
|
+
flexDirection: 'row',
|
|
123
|
+
gap: 6,
|
|
124
|
+
},
|
|
125
|
+
iconButtonSkeleton: {
|
|
126
|
+
width: 36,
|
|
127
|
+
height: 36,
|
|
128
|
+
borderRadius: 8,
|
|
129
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
130
|
+
borderWidth: 1,
|
|
131
|
+
borderColor: AppColors_1.AppColors.dividerColor,
|
|
132
|
+
},
|
|
133
|
+
chipStripSkeleton: {
|
|
134
|
+
flexDirection: 'row',
|
|
135
|
+
gap: 6,
|
|
136
|
+
marginBottom: 10,
|
|
137
|
+
},
|
|
138
|
+
chipSkeleton: {
|
|
139
|
+
height: 24,
|
|
140
|
+
borderRadius: 6,
|
|
141
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
142
|
+
borderWidth: 1,
|
|
143
|
+
borderColor: AppColors_1.AppColors.dividerColor,
|
|
144
|
+
},
|
|
145
|
+
cardSkeleton: {
|
|
146
|
+
backgroundColor: AppColors_1.AppColors.primaryLight,
|
|
147
|
+
borderRadius: 10,
|
|
148
|
+
padding: 12,
|
|
149
|
+
marginBottom: 8,
|
|
150
|
+
borderWidth: 1,
|
|
151
|
+
borderColor: AppColors_1.AppColors.dividerColor,
|
|
152
|
+
},
|
|
153
|
+
cardTopRow: {
|
|
154
|
+
flexDirection: 'row',
|
|
155
|
+
justifyContent: 'space-between',
|
|
156
|
+
alignItems: 'center',
|
|
157
|
+
marginBottom: 8,
|
|
158
|
+
},
|
|
159
|
+
badgeGroup: {
|
|
160
|
+
flexDirection: 'row',
|
|
161
|
+
alignItems: 'center',
|
|
162
|
+
gap: 6,
|
|
163
|
+
},
|
|
164
|
+
statusBadgeSkeleton: {
|
|
165
|
+
width: 38,
|
|
166
|
+
height: 18,
|
|
167
|
+
borderRadius: 4,
|
|
168
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
169
|
+
},
|
|
170
|
+
methodBadgeSkeleton: {
|
|
171
|
+
width: 44,
|
|
172
|
+
height: 18,
|
|
173
|
+
borderRadius: 4,
|
|
174
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
175
|
+
},
|
|
176
|
+
timeSkeleton: {
|
|
177
|
+
width: 48,
|
|
178
|
+
height: 12,
|
|
179
|
+
borderRadius: 4,
|
|
180
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
181
|
+
},
|
|
182
|
+
urlLineLong: {
|
|
183
|
+
height: 13,
|
|
184
|
+
borderRadius: 4,
|
|
185
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
186
|
+
marginBottom: 5,
|
|
187
|
+
width: '90%',
|
|
188
|
+
},
|
|
189
|
+
urlLineShort: {
|
|
190
|
+
height: 11,
|
|
191
|
+
borderRadius: 4,
|
|
192
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
193
|
+
marginBottom: 8,
|
|
194
|
+
width: '55%',
|
|
195
|
+
},
|
|
196
|
+
cardBottomRow: {
|
|
197
|
+
flexDirection: 'row',
|
|
198
|
+
gap: 8,
|
|
199
|
+
marginTop: 2,
|
|
200
|
+
},
|
|
201
|
+
metaPillSkeleton: {
|
|
202
|
+
width: 52,
|
|
203
|
+
height: 14,
|
|
204
|
+
borderRadius: 4,
|
|
205
|
+
backgroundColor: AppColors_1.AppColors.graySurface,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
exports.default = SkeletonPlaceholder;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "2.3.
|
|
1
|
+
export declare const LIB_VERSION = "2.3.2";
|
|
@@ -3,4 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LIB_VERSION = void 0;
|
|
4
4
|
// AUTO-GENERATED FILE — do not edit by hand.
|
|
5
5
|
// Regenerated from package.json on every build by scripts/gen-version.js.
|
|
6
|
-
exports.LIB_VERSION = '2.3.
|
|
6
|
+
exports.LIB_VERSION = '2.3.2';
|
|
@@ -37,11 +37,11 @@ export declare const getRegisteredMMKVInstanceIds: () => string[];
|
|
|
37
37
|
*/
|
|
38
38
|
export declare const calculateByteSize: (str: string) => number;
|
|
39
39
|
/**
|
|
40
|
-
* Determine type and format value safely
|
|
40
|
+
* Determine type and format value safely without blocking JS thread
|
|
41
41
|
*/
|
|
42
42
|
export declare const analyzeStorageValue: (rawVal: any) => {
|
|
43
43
|
strVal: string;
|
|
44
|
-
|
|
44
|
+
parsedValue?: any;
|
|
45
45
|
type: "json" | "string" | "number" | "boolean" | "null";
|
|
46
46
|
byteSize: number;
|
|
47
47
|
};
|
|
@@ -266,34 +266,38 @@ const calculateByteSize = (str) => {
|
|
|
266
266
|
};
|
|
267
267
|
exports.calculateByteSize = calculateByteSize;
|
|
268
268
|
/**
|
|
269
|
-
* Determine type and format value safely
|
|
269
|
+
* Determine type and format value safely without blocking JS thread
|
|
270
270
|
*/
|
|
271
271
|
const analyzeStorageValue = (rawVal) => {
|
|
272
272
|
if (rawVal === null || rawVal === undefined) {
|
|
273
273
|
return { strVal: 'null', type: 'null', byteSize: 4 };
|
|
274
274
|
}
|
|
275
275
|
const strVal = typeof rawVal === 'string' ? rawVal : String(rawVal);
|
|
276
|
-
const byteSize =
|
|
276
|
+
const byteSize = strVal.length * 2;
|
|
277
277
|
if (typeof rawVal === 'number') {
|
|
278
|
-
return { strVal,
|
|
278
|
+
return { strVal, parsedValue: rawVal, type: 'number', byteSize };
|
|
279
279
|
}
|
|
280
280
|
if (typeof rawVal === 'boolean') {
|
|
281
|
-
return { strVal,
|
|
281
|
+
return { strVal, parsedValue: rawVal, type: 'boolean', byteSize };
|
|
282
282
|
}
|
|
283
283
|
const trimmed = strVal.trim();
|
|
284
284
|
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
285
285
|
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
286
|
+
// For small/medium JSON, parse eagerly; for huge payloads (>10KB), parse lazily on expand
|
|
287
|
+
if (trimmed.length < 10000) {
|
|
288
|
+
try {
|
|
289
|
+
const parsed = JSON.parse(trimmed);
|
|
290
|
+
return { strVal, parsedValue: parsed, type: 'json', byteSize };
|
|
291
|
+
}
|
|
292
|
+
catch { }
|
|
289
293
|
}
|
|
290
|
-
|
|
294
|
+
return { strVal, type: 'json', byteSize };
|
|
291
295
|
}
|
|
292
296
|
if (trimmed === 'true' || trimmed === 'false') {
|
|
293
|
-
return { strVal,
|
|
297
|
+
return { strVal, parsedValue: trimmed === 'true', type: 'boolean', byteSize };
|
|
294
298
|
}
|
|
295
299
|
if (!isNaN(Number(trimmed)) && trimmed !== '') {
|
|
296
|
-
return { strVal,
|
|
300
|
+
return { strVal, parsedValue: Number(trimmed), type: 'number', byteSize };
|
|
297
301
|
}
|
|
298
302
|
return { strVal, type: 'string', byteSize };
|
|
299
303
|
};
|
|
@@ -319,7 +323,7 @@ const fetchStorageEntries = async (driver, instanceId) => {
|
|
|
319
323
|
entries.push({
|
|
320
324
|
key: k,
|
|
321
325
|
value: analysis.strVal,
|
|
322
|
-
parsedValue: analysis.
|
|
326
|
+
parsedValue: analysis.parsedValue,
|
|
323
327
|
type: analysis.type,
|
|
324
328
|
byteSize: analysis.byteSize,
|
|
325
329
|
});
|
|
@@ -332,7 +336,7 @@ const fetchStorageEntries = async (driver, instanceId) => {
|
|
|
332
336
|
entries.push({
|
|
333
337
|
key: k,
|
|
334
338
|
value: analysis.strVal,
|
|
335
|
-
parsedValue: analysis.
|
|
339
|
+
parsedValue: analysis.parsedValue,
|
|
336
340
|
type: analysis.type,
|
|
337
341
|
byteSize: analysis.byteSize,
|
|
338
342
|
});
|
|
@@ -373,7 +377,7 @@ const fetchStorageEntries = async (driver, instanceId) => {
|
|
|
373
377
|
entries.push({
|
|
374
378
|
key: k,
|
|
375
379
|
value: analysis.strVal,
|
|
376
|
-
parsedValue: analysis.
|
|
380
|
+
parsedValue: analysis.parsedValue,
|
|
377
381
|
type: analysis.type,
|
|
378
382
|
byteSize: analysis.byteSize,
|
|
379
383
|
});
|