react-native-storage-inspector 1.0.1 → 1.0.3

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/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import React6, { useState, useMemo, useEffect, useCallback } from 'react';
1
+ import React7, { useState, useMemo, useEffect, useCallback } from 'react';
2
2
  import { StyleSheet, Dimensions, View, ScrollView, RefreshControl, Text, TouchableOpacity, Share, Modal, TextInput } from 'react-native';
3
3
 
4
4
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -35,7 +35,6 @@ function createMMKVAdapter(instance, name) {
35
35
  }
36
36
 
37
37
  // src/adapters/async-storage.ts
38
- var asyncStorage = null;
39
38
  function getAsyncStorageFromRequire() {
40
39
  try {
41
40
  const mod = require("@react-native-async-storage/async-storage");
@@ -44,8 +43,8 @@ function getAsyncStorageFromRequire() {
44
43
  return null;
45
44
  }
46
45
  }
47
- function createAsyncStorageAdapter(instance) {
48
- const getStorage = () => instance ?? (asyncStorage ?? (asyncStorage = getAsyncStorageFromRequire()));
46
+ function createAsyncStorageAdapter() {
47
+ const getStorage = () => getAsyncStorageFromRequire();
49
48
  return {
50
49
  type: "async-storage",
51
50
  name: "Async Storage",
@@ -76,7 +75,6 @@ function createAsyncStorageAdapter(instance) {
76
75
  }
77
76
 
78
77
  // src/adapters/keychain.ts
79
- var keychain = null;
80
78
  function getKeychainFromRequire() {
81
79
  try {
82
80
  return require("react-native-keychain");
@@ -84,14 +82,14 @@ function getKeychainFromRequire() {
84
82
  return null;
85
83
  }
86
84
  }
87
- function createKeychainAdapter(knownKeys = [], instance) {
88
- const getKc = () => instance ?? (keychain ?? (keychain = getKeychainFromRequire()));
85
+ function createKeychainAdapter() {
86
+ const getKc = () => getKeychainFromRequire();
89
87
  return {
90
88
  type: "keychain",
91
89
  name: "Keychain",
92
90
  async getAllKeys() {
93
91
  const kc = getKc();
94
- if (!kc) return [...knownKeys];
92
+ if (!kc) return [];
95
93
  const genericServices = [];
96
94
  if (typeof kc.getAllGenericPasswordServices === "function") {
97
95
  try {
@@ -100,42 +98,32 @@ function createKeychainAdapter(knownKeys = [], instance) {
100
98
  } catch {
101
99
  }
102
100
  }
103
- const merged = /* @__PURE__ */ new Set([...genericServices, ...knownKeys]);
104
- return Array.from(merged);
101
+ return genericServices;
105
102
  },
106
103
  async getItem(key) {
107
104
  const kc = getKc();
108
- if (!kc) return null;
109
- if (typeof kc.getGenericPassword === "function") {
110
- try {
111
- const creds2 = await kc.getGenericPassword({ service: key });
112
- if (creds2 && typeof creds2 === "object" && "password" in creds2) {
113
- return creds2.password;
114
- }
115
- } catch {
105
+ if (!kc?.getGenericPassword) return null;
106
+ try {
107
+ const creds = await kc.getGenericPassword({ service: key });
108
+ if (creds && typeof creds === "object" && "password" in creds) {
109
+ return creds.password;
116
110
  }
111
+ } catch {
117
112
  }
118
- const creds = await kc.getInternetCredentials(key);
119
- return creds?.password ?? null;
113
+ return null;
120
114
  },
121
115
  async setItem(key, value) {
122
116
  const kc = getKc();
123
- if (!kc) throw new Error("react-native-keychain is not available");
124
- if (typeof kc.setGenericPassword === "function") {
125
- const result2 = await kc.setGenericPassword(key, value, { service: key });
126
- if (result2 === false) throw new Error("Keychain set failed");
127
- return;
128
- }
129
- const result = await kc.setInternetCredentials(key, key, value);
117
+ if (!kc?.setGenericPassword)
118
+ throw new Error("react-native-keychain is not available");
119
+ const result = await kc.setGenericPassword(key, value, { service: key });
130
120
  if (result === false) throw new Error("Keychain set failed");
131
121
  },
132
122
  async removeItem(key) {
133
123
  const kc = getKc();
134
- if (!kc) throw new Error("react-native-keychain is not available");
135
- if (typeof kc.resetGenericPassword === "function") {
136
- await kc.resetGenericPassword({ service: key });
137
- }
138
- await kc.resetInternetCredentials(key);
124
+ if (!kc?.resetGenericPassword)
125
+ throw new Error("react-native-keychain is not available");
126
+ await kc.resetGenericPassword({ service: key });
139
127
  },
140
128
  isAvailable() {
141
129
  return getKc() !== null;
@@ -143,8 +131,20 @@ function createKeychainAdapter(knownKeys = [], instance) {
143
131
  };
144
132
  }
145
133
 
134
+ // src/utils.ts
135
+ function parsePersistedKeys(raw) {
136
+ if (raw == null || raw === "") return [];
137
+ try {
138
+ const parsed = JSON.parse(raw);
139
+ if (!Array.isArray(parsed)) return [];
140
+ return parsed.filter((item) => typeof item === "string");
141
+ } catch {
142
+ return [];
143
+ }
144
+ }
145
+
146
146
  // src/adapters/secure-store.ts
147
- var secureStore = null;
147
+ var PERSISTED_KEYS_STORAGE_KEY = "__storage_inspector_secure_store_keys__";
148
148
  function getSecureStoreFromRequire() {
149
149
  try {
150
150
  return require("expo-secure-store");
@@ -152,13 +152,17 @@ function getSecureStoreFromRequire() {
152
152
  return null;
153
153
  }
154
154
  }
155
- function createSecureStoreAdapter(knownKeys = [], instance) {
156
- const getStore = () => instance ?? (secureStore ?? (secureStore = getSecureStoreFromRequire()));
155
+ function createSecureStoreAdapter(knownKeys = []) {
156
+ const getStore = () => getSecureStoreFromRequire();
157
157
  return {
158
158
  type: "expo-secure-store",
159
159
  name: "Secure Store",
160
160
  async getAllKeys() {
161
- return [...knownKeys];
161
+ const store = getStore();
162
+ if (!store) return [];
163
+ const persistedKeysString = await store.getItemAsync(PERSISTED_KEYS_STORAGE_KEY);
164
+ const persistedKeys = parsePersistedKeys(persistedKeysString);
165
+ return [.../* @__PURE__ */ new Set([...knownKeys, ...persistedKeys])];
162
166
  },
163
167
  async getItem(key) {
164
168
  const store = getStore();
@@ -169,11 +173,26 @@ function createSecureStoreAdapter(knownKeys = [], instance) {
169
173
  const store = getStore();
170
174
  if (!store) throw new Error("expo-secure-store is not available");
171
175
  await store.setItemAsync(key, value);
176
+ if (key === PERSISTED_KEYS_STORAGE_KEY) return;
177
+ const persistedKeysString = await store.getItemAsync(PERSISTED_KEYS_STORAGE_KEY);
178
+ const persistedKeys = parsePersistedKeys(persistedKeysString);
179
+ const newPersistedKeys = [.../* @__PURE__ */ new Set([...persistedKeys, key])];
180
+ await store.setItemAsync(
181
+ PERSISTED_KEYS_STORAGE_KEY,
182
+ JSON.stringify(newPersistedKeys)
183
+ );
172
184
  },
173
185
  async removeItem(key) {
174
186
  const store = getStore();
175
187
  if (!store) throw new Error("expo-secure-store is not available");
176
188
  await store.deleteItemAsync(key);
189
+ const persistedKeysString = await store.getItemAsync(PERSISTED_KEYS_STORAGE_KEY);
190
+ const persistedKeys = parsePersistedKeys(persistedKeysString);
191
+ const newPersistedKeys = persistedKeys.filter((k) => k !== key);
192
+ await store.setItemAsync(
193
+ PERSISTED_KEYS_STORAGE_KEY,
194
+ JSON.stringify(newPersistedKeys)
195
+ );
177
196
  },
178
197
  isAvailable() {
179
198
  return getStore() !== null;
@@ -197,7 +216,8 @@ function useStorageItems(adapter) {
197
216
  const pairs = [];
198
217
  for (const key of keys) {
199
218
  const value = await adapter.getItem(key);
200
- pairs.push({ key, value: value ?? "" });
219
+ if (value === null) continue;
220
+ pairs.push({ key, value });
201
221
  }
202
222
  setItems(pairs);
203
223
  } catch (e) {
@@ -224,7 +244,8 @@ var theme = {
224
244
  text: "#000000",
225
245
  textSecondary: "#666666",
226
246
  textMuted: "#999999",
227
- inverted: "#ffffff"
247
+ inverted: "#ffffff",
248
+ overlayBackdrop: "rgba(0,0,0,0.5)"
228
249
  }
229
250
  };
230
251
 
@@ -245,15 +266,11 @@ var ROTATION = {
245
266
  chevronDown: "90deg",
246
267
  chevronUp: "-90deg"
247
268
  };
248
- function Icon({
249
- name,
250
- size = 20,
251
- tintColor = theme.colors.text,
252
- iconStyle
253
- }) {
269
+ function Icon(props) {
270
+ const { name, size = 20, tintColor = theme.colors.text, iconStyle } = props;
254
271
  const glyph = GLYPHS[name] ?? "?";
255
272
  const rotation = ROTATION[name];
256
- return /* @__PURE__ */ React6.createElement(
273
+ return /* @__PURE__ */ React7.createElement(
257
274
  Text,
258
275
  {
259
276
  style: [
@@ -276,7 +293,6 @@ var { width: SCREEN_WIDTH } = Dimensions.get("window");
276
293
  var LAYOUT = {
277
294
  padding: 16,
278
295
  fontSize: 14,
279
- headerHeight: 52,
280
296
  rowMinHeight: 48,
281
297
  sectionHeaderHeight: 48,
282
298
  iconSize: 20,
@@ -290,331 +306,242 @@ var LAYOUT = {
290
306
  sectionRadius: 4,
291
307
  screenWidth: SCREEN_WIDTH
292
308
  };
293
- var { colors } = theme;
309
+
310
+ // src/components/IconButton.tsx
311
+ function IconButton(props) {
312
+ const {
313
+ name,
314
+ onPress,
315
+ size = LAYOUT.iconSize,
316
+ tintColor = theme.colors.text,
317
+ disabled = false,
318
+ hitSlop = LAYOUT.hitSlop,
319
+ style,
320
+ activeOpacity = 0.6
321
+ } = props;
322
+ return /* @__PURE__ */ React7.createElement(
323
+ TouchableOpacity,
324
+ {
325
+ style: [styles2.iconButton, style],
326
+ onPress,
327
+ disabled,
328
+ hitSlop,
329
+ activeOpacity
330
+ },
331
+ /* @__PURE__ */ React7.createElement(
332
+ Icon,
333
+ {
334
+ name,
335
+ size,
336
+ tintColor: disabled ? theme.colors.textMuted : tintColor
337
+ }
338
+ )
339
+ );
340
+ }
294
341
  var styles2 = StyleSheet.create({
295
- container: {
342
+ iconButton: {
343
+ width: LAYOUT.iconButtonSize,
344
+ height: LAYOUT.iconButtonSize,
345
+ alignItems: "center",
346
+ justifyContent: "center"
347
+ }
348
+ });
349
+
350
+ // src/strings.ts
351
+ var strings = {
352
+ // StorageInspector
353
+ noAdapterAvailable: "No storage adapter available. Install at least one of: react-native-mmkv, @react-native-async-storage/async-storage, react-native-keychain, expo-secure-store",
354
+ // StorageSection
355
+ keychainHint: "No generic password items yet. Add a key using + above.",
356
+ secureStoreHint: "Secure Store has no list API. Pass secureStoreKeys prop with known keys, or add a key using + above.",
357
+ loading: "Loading\u2026",
358
+ noItems: "No items",
359
+ valueLabel: "Value",
360
+ charCount: (n) => n === 1 ? "1 char" : `${n} chars`,
361
+ deleteItemTitle: (key) => `Delete ${key}?`,
362
+ deleteItemMessage: (key) => `This will permanently delete the ${key} storage item. Do you wish to continue?`,
363
+ clearAllTitle: (name) => `Clear All ${name}?`,
364
+ clearAllMessage: (count, name) => `This will permanently delete all ${count} ${name} items. Do you wish to continue?`,
365
+ // StorageList
366
+ storageNotAvailable: "This storage is not available.",
367
+ keychainHintShort: "No items yet. Add a key below.",
368
+ edit: "Edit",
369
+ delete: "Delete",
370
+ addItem: "Add item",
371
+ // ItemForm
372
+ keyRequired: "Key is required",
373
+ saveFailed: "Save failed",
374
+ editItemTitle: (key) => `Edit ${key}`,
375
+ addItemTitle: (storageName) => `Add ${storageName} Item`,
376
+ storageTypeLabel: (name) => `Storage Type: ${name}`,
377
+ keyLabel: "Key",
378
+ enterKeyPlaceholder: "Enter key",
379
+ enterValuePlaceholder: "Enter value",
380
+ cancel: "Cancel",
381
+ saving: "Saving\u2026",
382
+ save: "Save",
383
+ add: "Add",
384
+ // ConfirmModal defaults
385
+ confirmDelete: "Yes, delete",
386
+ cancelKeep: "No, keep it"
387
+ };
388
+
389
+ // src/components/ItemForm.tsx
390
+ function ItemForm(props) {
391
+ const { visible, storageName, editingItem, onSave, onCancel } = props;
392
+ const [key, setKey] = useState("");
393
+ const [value, setValue] = useState("");
394
+ const [saving, setSaving] = useState(false);
395
+ const [error, setError] = useState(null);
396
+ const isEdit = editingItem !== null;
397
+ useEffect(() => {
398
+ if (visible) {
399
+ setKey(editingItem?.key ?? "");
400
+ setValue(editingItem?.value ?? "");
401
+ setError(null);
402
+ }
403
+ }, [visible, editingItem]);
404
+ const handleSubmit = async () => {
405
+ const k = key.trim();
406
+ if (!k) {
407
+ setError(strings.keyRequired);
408
+ return;
409
+ }
410
+ setSaving(true);
411
+ setError(null);
412
+ try {
413
+ await onSave(k, value);
414
+ onCancel();
415
+ } catch (e) {
416
+ setError(e instanceof Error ? e.message : strings.saveFailed);
417
+ } finally {
418
+ setSaving(false);
419
+ }
420
+ };
421
+ const title = isEdit ? strings.editItemTitle(editingItem?.key ?? "") : strings.addItemTitle(storageName);
422
+ return /* @__PURE__ */ React7.createElement(Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onCancel }, /* @__PURE__ */ React7.createElement(View, { style: styles3.formOverlay }, /* @__PURE__ */ React7.createElement(
423
+ TouchableOpacity,
424
+ {
425
+ style: { flex: 1, width: "100%" },
426
+ activeOpacity: 1,
427
+ onPress: onCancel
428
+ }
429
+ ), /* @__PURE__ */ React7.createElement(View, { style: styles3.formModal }, /* @__PURE__ */ React7.createElement(View, { style: styles3.formHeader }, /* @__PURE__ */ React7.createElement(Text, { style: styles3.formTitle, numberOfLines: 1 }, title), /* @__PURE__ */ React7.createElement(
430
+ IconButton,
431
+ {
432
+ name: "close",
433
+ onPress: onCancel,
434
+ size: 24,
435
+ tintColor: theme.colors.textSecondary,
436
+ style: styles3.formCloseButton,
437
+ hitSlop: LAYOUT.hitSlopLarge
438
+ }
439
+ )), /* @__PURE__ */ React7.createElement(Text, { style: styles3.formStorageType }, strings.storageTypeLabel(storageName)), /* @__PURE__ */ React7.createElement(Text, { style: styles3.formLabel }, strings.keyLabel), /* @__PURE__ */ React7.createElement(
440
+ TextInput,
441
+ {
442
+ style: [styles3.formInput, isEdit && styles3.formInputDisabled],
443
+ value: key,
444
+ onChangeText: setKey,
445
+ placeholder: strings.enterKeyPlaceholder,
446
+ placeholderTextColor: theme.colors.textMuted,
447
+ editable: !isEdit,
448
+ autoCapitalize: "none",
449
+ multiline: true
450
+ }
451
+ ), /* @__PURE__ */ React7.createElement(Text, { style: styles3.formLabel }, strings.valueLabel), /* @__PURE__ */ React7.createElement(
452
+ TextInput,
453
+ {
454
+ style: styles3.formInput,
455
+ value,
456
+ onChangeText: setValue,
457
+ placeholder: strings.enterValuePlaceholder,
458
+ placeholderTextColor: theme.colors.textMuted,
459
+ multiline: true,
460
+ numberOfLines: 3
461
+ }
462
+ ), error ? /* @__PURE__ */ React7.createElement(Text, { style: [styles3.errorText, { marginBottom: 12 }] }, error) : null, /* @__PURE__ */ React7.createElement(View, { style: styles3.formActions }, /* @__PURE__ */ React7.createElement(
463
+ TouchableOpacity,
464
+ {
465
+ style: [styles3.formButton, styles3.formButtonCancel],
466
+ onPress: onCancel,
467
+ disabled: saving
468
+ },
469
+ /* @__PURE__ */ React7.createElement(Text, { style: [styles3.formButtonText, styles3.formButtonTextCancel] }, strings.cancel)
470
+ ), /* @__PURE__ */ React7.createElement(
471
+ TouchableOpacity,
472
+ {
473
+ style: [styles3.formButton, styles3.formButtonSubmit],
474
+ onPress: handleSubmit,
475
+ disabled: saving
476
+ },
477
+ /* @__PURE__ */ React7.createElement(Text, { style: [styles3.formButtonText, styles3.formButtonTextSubmit] }, saving ? strings.saving : isEdit ? strings.save : strings.add)
478
+ )))));
479
+ }
480
+ var { colors } = theme;
481
+ var styles3 = StyleSheet.create({
482
+ formOverlay: {
296
483
  flex: 1,
297
- width: "100%",
298
- backgroundColor: colors.background
299
- },
300
- content: {
301
- flex: 1
484
+ backgroundColor: colors.overlayBackdrop,
485
+ justifyContent: "flex-end",
486
+ alignItems: "center"
302
487
  },
303
- scroll: {
304
- flex: 1
488
+ formModal: {
489
+ width: "100%",
490
+ maxWidth: LAYOUT.screenWidth,
491
+ backgroundColor: colors.background,
492
+ borderTopLeftRadius: LAYOUT.modalRadius,
493
+ borderTopRightRadius: LAYOUT.modalRadius,
494
+ padding: LAYOUT.padding,
495
+ paddingBottom: LAYOUT.padding + 34
305
496
  },
306
- header: {
307
- height: LAYOUT.headerHeight,
497
+ formHeader: {
308
498
  flexDirection: "row",
309
499
  alignItems: "center",
310
500
  justifyContent: "space-between",
311
- paddingHorizontal: LAYOUT.padding,
312
- borderBottomWidth: StyleSheet.hairlineWidth,
313
- borderBottomColor: colors.border,
314
- backgroundColor: colors.background
315
- },
316
- headerLeft: {
317
- minWidth: 44,
318
- alignItems: "flex-start"
319
- },
320
- headerCenter: {
321
- flex: 1,
322
- alignItems: "center",
323
- justifyContent: "center"
324
- },
325
- headerRight: {
326
- minWidth: 44,
327
- alignItems: "flex-end"
328
- },
329
- sectionHeaderLabelWrap: {
330
- flex: 1
501
+ marginBottom: LAYOUT.padding
331
502
  },
332
- headerTitle: {
503
+ formTitle: {
333
504
  fontSize: 17,
334
505
  fontWeight: "600",
335
- color: colors.text
506
+ color: colors.text,
507
+ flex: 1
336
508
  },
337
- headerButton: {
509
+ formCloseButton: {
338
510
  width: 44,
339
511
  height: 44,
340
- alignItems: "center",
512
+ alignItems: "flex-end",
341
513
  justifyContent: "center"
342
514
  },
343
- scrollContent: {
344
- flexGrow: 1,
345
- paddingBottom: LAYOUT.fabSize + LAYOUT.padding + 20,
346
- paddingTop: LAYOUT.padding
347
- },
348
- sectionHeader: {
349
- height: LAYOUT.sectionHeaderHeight,
350
- flexDirection: "row",
351
- alignItems: "center",
352
- paddingHorizontal: LAYOUT.padding,
353
- borderBottomWidth: StyleSheet.hairlineWidth,
354
- borderBottomColor: colors.border,
355
- backgroundColor: colors.backgroundSecondary,
356
- marginTop: LAYOUT.padding,
357
- marginHorizontal: LAYOUT.padding,
358
- borderRadius: LAYOUT.sectionRadius
515
+ formStorageType: {
516
+ fontSize: 13,
517
+ color: colors.textSecondary,
518
+ marginBottom: 12
359
519
  },
360
- sectionHeaderLabel: {
361
- fontSize: 15,
520
+ formLabel: {
521
+ fontSize: 12,
362
522
  fontWeight: "600",
363
- color: colors.text
364
- },
365
- sectionHeaderCount: {
366
523
  color: colors.textSecondary,
367
- fontWeight: "400"
524
+ marginBottom: 6
368
525
  },
369
- storageRowActions: {
370
- flexDirection: "row",
371
- alignItems: "center",
372
- gap: LAYOUT.iconGap
526
+ formInput: {
527
+ borderWidth: 1,
528
+ borderColor: colors.border,
529
+ borderRadius: 10,
530
+ padding: 12,
531
+ fontSize: LAYOUT.fontSize,
532
+ marginBottom: LAYOUT.padding,
533
+ color: colors.text,
534
+ backgroundColor: colors.background
373
535
  },
374
- iconButton: {
375
- width: LAYOUT.iconButtonSize,
376
- height: LAYOUT.iconButtonSize,
377
- alignItems: "center",
378
- justifyContent: "center"
536
+ formInputDisabled: {
537
+ backgroundColor: colors.backgroundSecondary,
538
+ color: colors.textSecondary
379
539
  },
380
- iconSlot: {
381
- width: LAYOUT.iconButtonSize,
382
- height: LAYOUT.iconButtonSize,
383
- alignItems: "center",
384
- justifyContent: "center"
385
- },
386
- itemRow: {
387
- minHeight: LAYOUT.rowMinHeight,
388
- paddingHorizontal: LAYOUT.padding,
389
- paddingVertical: 12,
390
- borderBottomWidth: StyleSheet.hairlineWidth,
391
- borderBottomColor: colors.borderLight,
392
- backgroundColor: colors.background,
393
- marginHorizontal: LAYOUT.padding,
394
- marginBottom: 4
395
- },
396
- itemRowCollapsed: {
397
- flexDirection: "row",
398
- alignItems: "center",
399
- alignSelf: "stretch"
400
- },
401
- itemKey: {
402
- flex: 1,
403
- fontSize: LAYOUT.fontSize,
404
- fontWeight: "500",
405
- color: colors.text
406
- },
407
- itemChars: {
408
- fontSize: 12,
409
- color: colors.textSecondary,
410
- marginTop: 2
411
- },
412
- itemRowActions: {
413
- flexDirection: "row",
414
- alignItems: "center",
415
- marginLeft: LAYOUT.iconGap,
416
- gap: LAYOUT.iconGap
417
- },
418
- itemRowExpanded: {
419
- paddingTop: 4
420
- },
421
- valueBox: {
422
- backgroundColor: colors.backgroundSecondary,
423
- borderRadius: 8,
424
- padding: 12,
425
- marginTop: 8,
426
- marginBottom: 8,
427
- borderWidth: StyleSheet.hairlineWidth,
428
- borderColor: colors.border
429
- },
430
- valueBoxLabel: {
431
- fontSize: 11,
432
- fontWeight: "600",
433
- color: colors.textSecondary,
434
- marginBottom: 4,
435
- textTransform: "uppercase"
436
- },
437
- valueBoxText: {
438
- fontSize: LAYOUT.fontSize,
439
- color: colors.text
440
- },
441
- empty: {
442
- padding: LAYOUT.padding * 2,
443
- alignItems: "center",
444
- marginHorizontal: LAYOUT.padding
445
- },
446
- emptyText: {
447
- fontSize: LAYOUT.fontSize,
448
- color: colors.textMuted
449
- },
450
- loading: {
451
- padding: LAYOUT.padding * 2,
452
- alignItems: "center",
453
- marginHorizontal: LAYOUT.padding
454
- },
455
- loadingText: {
456
- fontSize: LAYOUT.fontSize,
457
- color: colors.textSecondary
458
- },
459
- error: {
460
- padding: LAYOUT.padding,
461
- backgroundColor: colors.backgroundTertiary,
462
- marginHorizontal: LAYOUT.padding,
463
- marginVertical: 8,
464
- borderRadius: 8
465
- },
466
- errorText: {
467
- fontSize: LAYOUT.fontSize,
468
- color: colors.text
469
- },
470
- keychainHint: {
471
- padding: LAYOUT.padding,
472
- marginHorizontal: LAYOUT.padding,
473
- marginTop: 8,
474
- marginBottom: 4,
475
- backgroundColor: colors.backgroundSecondary,
476
- borderRadius: 8
477
- },
478
- keychainHintText: {
479
- fontSize: LAYOUT.fontSize - 1,
480
- color: colors.textSecondary
481
- },
482
- list: {
483
- flex: 1
484
- },
485
- listContent: {
486
- flexGrow: 1,
487
- paddingBottom: LAYOUT.fabSize + LAYOUT.padding + 20
488
- },
489
- row: {
490
- flexDirection: "row",
491
- alignItems: "center",
492
- minHeight: LAYOUT.rowMinHeight,
493
- paddingHorizontal: LAYOUT.padding,
494
- paddingVertical: 12,
495
- borderBottomWidth: StyleSheet.hairlineWidth,
496
- borderBottomColor: colors.borderLight,
497
- backgroundColor: colors.background,
498
- marginHorizontal: LAYOUT.padding
499
- },
500
- rowKey: {
501
- flex: 1,
502
- fontSize: LAYOUT.fontSize,
503
- fontWeight: "500",
504
- color: colors.text
505
- },
506
- rowValue: {
507
- fontSize: LAYOUT.fontSize - 1,
508
- color: colors.textSecondary
509
- },
510
- rowActions: {
511
- flexDirection: "row",
512
- alignItems: "center",
513
- marginLeft: LAYOUT.iconGap,
514
- gap: LAYOUT.iconGap
515
- },
516
- rowButton: {
517
- paddingVertical: 8,
518
- paddingHorizontal: 12
519
- },
520
- rowButtonText: {
521
- fontSize: 14,
522
- fontWeight: "600",
523
- color: colors.text
524
- },
525
- rowButtonDanger: {
526
- color: colors.text
527
- },
528
- addButton: {
529
- position: "absolute",
530
- bottom: LAYOUT.padding + 16,
531
- right: LAYOUT.padding + 16,
532
- width: LAYOUT.fabSize,
533
- height: LAYOUT.fabSize,
534
- borderRadius: LAYOUT.fabSize / 2,
535
- backgroundColor: colors.text,
536
- alignItems: "center",
537
- justifyContent: "center"
538
- },
539
- addButtonText: {
540
- fontSize: 16,
541
- fontWeight: "600",
542
- color: colors.inverted
543
- },
544
- fab: {
545
- position: "absolute",
546
- bottom: LAYOUT.padding + 16,
547
- right: LAYOUT.padding + 16,
548
- width: LAYOUT.fabSize,
549
- height: LAYOUT.fabSize,
550
- borderRadius: LAYOUT.fabSize / 2,
551
- backgroundColor: colors.text,
552
- alignItems: "center",
553
- justifyContent: "center"
554
- },
555
- formOverlay: {
556
- flex: 1,
557
- backgroundColor: "rgba(0,0,0,0.5)",
558
- justifyContent: "flex-end",
559
- alignItems: "center"
560
- },
561
- formModal: {
562
- width: "100%",
563
- maxWidth: LAYOUT.screenWidth,
564
- backgroundColor: colors.background,
565
- borderTopLeftRadius: LAYOUT.modalRadius,
566
- borderTopRightRadius: LAYOUT.modalRadius,
567
- padding: LAYOUT.padding,
568
- paddingBottom: LAYOUT.padding + 34
569
- },
570
- formHeader: {
571
- flexDirection: "row",
572
- alignItems: "center",
573
- justifyContent: "space-between",
574
- marginBottom: LAYOUT.padding
575
- },
576
- formTitle: {
577
- fontSize: 17,
578
- fontWeight: "600",
579
- color: colors.text,
580
- flex: 1
581
- },
582
- formCloseButton: {
583
- width: 44,
584
- height: 44,
585
- alignItems: "flex-end",
586
- justifyContent: "center"
587
- },
588
- formStorageType: {
589
- fontSize: 13,
590
- color: colors.textSecondary,
591
- marginBottom: 12
592
- },
593
- formLabel: {
594
- fontSize: 12,
595
- fontWeight: "600",
596
- color: colors.textSecondary,
597
- marginBottom: 6
598
- },
599
- formInput: {
600
- borderWidth: 1,
601
- borderColor: colors.border,
602
- borderRadius: 10,
603
- padding: 12,
604
- fontSize: LAYOUT.fontSize,
605
- marginBottom: LAYOUT.padding,
606
- color: colors.text,
607
- backgroundColor: colors.background
608
- },
609
- formInputDisabled: {
610
- backgroundColor: colors.backgroundSecondary,
611
- color: colors.textSecondary
612
- },
613
- formActions: {
614
- flexDirection: "row",
615
- justifyContent: "flex-end",
616
- gap: 12,
617
- marginTop: 8
540
+ formActions: {
541
+ flexDirection: "row",
542
+ justifyContent: "flex-end",
543
+ gap: 12,
544
+ marginTop: 8
618
545
  },
619
546
  formButton: {
620
547
  paddingVertical: 12,
@@ -641,16 +568,79 @@ var styles2 = StyleSheet.create({
641
568
  formButtonTextSubmit: {
642
569
  color: colors.inverted
643
570
  },
571
+ errorText: {
572
+ fontSize: LAYOUT.fontSize,
573
+ color: colors.text
574
+ }
575
+ });
576
+ function ConfirmModal(props) {
577
+ const {
578
+ visible,
579
+ title,
580
+ message,
581
+ confirmLabel = strings.confirmDelete,
582
+ cancelLabel = strings.cancelKeep,
583
+ danger = true,
584
+ onConfirm,
585
+ onCancel
586
+ } = props;
587
+ return /* @__PURE__ */ React7.createElement(Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onCancel }, /* @__PURE__ */ React7.createElement(View, { style: styles4.confirmOverlay }, /* @__PURE__ */ React7.createElement(
588
+ TouchableOpacity,
589
+ {
590
+ style: { flex: 1, width: "100%" },
591
+ activeOpacity: 1,
592
+ onPress: onCancel
593
+ }
594
+ ), /* @__PURE__ */ React7.createElement(View, { style: styles4.confirmModal }, /* @__PURE__ */ React7.createElement(View, { style: styles4.confirmHeader }, /* @__PURE__ */ React7.createElement(Text, { style: styles4.confirmTitle }, title), /* @__PURE__ */ React7.createElement(
595
+ IconButton,
596
+ {
597
+ name: "close",
598
+ onPress: onCancel,
599
+ size: 24,
600
+ tintColor: theme.colors.textSecondary,
601
+ style: styles4.formCloseButton,
602
+ hitSlop: LAYOUT.hitSlopLarge
603
+ }
604
+ )), /* @__PURE__ */ React7.createElement(Text, { style: styles4.confirmMessage }, message), /* @__PURE__ */ React7.createElement(View, { style: styles4.confirmActions }, /* @__PURE__ */ React7.createElement(
605
+ TouchableOpacity,
606
+ {
607
+ style: [styles4.confirmButton, styles4.confirmButtonSecondary],
608
+ onPress: onCancel
609
+ },
610
+ /* @__PURE__ */ React7.createElement(Text, { style: [styles4.confirmButtonText, styles4.confirmButtonTextSecondary] }, cancelLabel)
611
+ ), /* @__PURE__ */ React7.createElement(
612
+ TouchableOpacity,
613
+ {
614
+ style: [
615
+ styles4.confirmButton,
616
+ danger ? styles4.confirmButtonDanger : styles4.formButtonSubmit
617
+ ],
618
+ onPress: onConfirm
619
+ },
620
+ /* @__PURE__ */ React7.createElement(
621
+ Text,
622
+ {
623
+ style: [
624
+ styles4.confirmButtonText,
625
+ danger ? styles4.confirmButtonTextDanger : styles4.formButtonTextSubmit
626
+ ]
627
+ },
628
+ confirmLabel
629
+ )
630
+ )))));
631
+ }
632
+ var { colors: colors2 } = theme;
633
+ var styles4 = StyleSheet.create({
644
634
  confirmOverlay: {
645
635
  flex: 1,
646
- backgroundColor: "rgba(0,0,0,0.5)",
636
+ backgroundColor: colors2.overlayBackdrop,
647
637
  justifyContent: "flex-end",
648
638
  alignItems: "center"
649
639
  },
650
640
  confirmModal: {
651
641
  width: "100%",
652
642
  maxWidth: LAYOUT.screenWidth,
653
- backgroundColor: colors.background,
643
+ backgroundColor: colors2.background,
654
644
  borderTopLeftRadius: LAYOUT.modalRadius,
655
645
  borderTopRightRadius: LAYOUT.modalRadius,
656
646
  padding: LAYOUT.padding,
@@ -665,12 +655,18 @@ var styles2 = StyleSheet.create({
665
655
  confirmTitle: {
666
656
  fontSize: 17,
667
657
  fontWeight: "600",
668
- color: colors.text,
658
+ color: colors2.text,
669
659
  flex: 1
670
660
  },
661
+ formCloseButton: {
662
+ width: 44,
663
+ height: 44,
664
+ alignItems: "flex-end",
665
+ justifyContent: "center"
666
+ },
671
667
  confirmMessage: {
672
668
  fontSize: 15,
673
- color: colors.textSecondary,
669
+ color: colors2.textSecondary,
674
670
  lineHeight: 22,
675
671
  marginBottom: 20
676
672
  },
@@ -683,281 +679,174 @@ var styles2 = StyleSheet.create({
683
679
  paddingVertical: 14,
684
680
  borderRadius: 10,
685
681
  alignItems: "center"
686
- },
687
- confirmButtonSecondary: {
688
- backgroundColor: "transparent",
689
- borderWidth: 1,
690
- borderColor: colors.text
691
- },
692
- confirmButtonDanger: {
693
- backgroundColor: colors.text
694
- },
695
- confirmButtonText: {
696
- fontSize: 16,
697
- fontWeight: "600"
698
- },
699
- confirmButtonTextSecondary: {
700
- color: colors.text
701
- },
702
- confirmButtonTextDanger: {
703
- color: colors.inverted
704
- }
705
- });
706
-
707
- // src/components/IconButton.tsx
708
- function IconButton({
709
- name,
710
- onPress,
711
- size = LAYOUT.iconSize,
712
- tintColor = theme.colors.text,
713
- disabled = false,
714
- hitSlop = LAYOUT.hitSlop,
715
- style,
716
- activeOpacity = 0.6
717
- }) {
718
- return /* @__PURE__ */ React6.createElement(
719
- TouchableOpacity,
720
- {
721
- style: [styles2.iconButton, style],
722
- onPress,
723
- disabled,
724
- hitSlop,
725
- activeOpacity
726
- },
727
- /* @__PURE__ */ React6.createElement(
728
- Icon,
729
- {
730
- name,
731
- size,
732
- tintColor: disabled ? theme.colors.textMuted : tintColor
733
- }
734
- )
735
- );
736
- }
737
-
738
- // src/strings.ts
739
- var strings = {
740
- // StorageInspector
741
- noAdapterAvailable: "No storage adapter available. Install at least one of: react-native-mmkv, @react-native-async-storage/async-storage, react-native-keychain, expo-secure-store",
742
- // StorageSection
743
- keychainHint: "No generic password items yet. Add a key using + above, or pass keychainKeys for internet credentials.",
744
- secureStoreHint: "Secure Store has no list API. Pass secureStoreKeys prop with known keys, or add a key using + above.",
745
- loading: "Loading\u2026",
746
- noItems: "No items",
747
- valueLabel: "Value",
748
- emptyValue: "(empty)",
749
- charCount: (n) => n === 1 ? "1 char" : `${n} chars`,
750
- deleteItemTitle: (key) => `Delete ${key}?`,
751
- deleteItemMessage: (key) => `This will permanently delete the ${key} storage item. Do you wish to continue?`,
752
- clearAllTitle: (name) => `Clear All ${name}?`,
753
- clearAllMessage: (count, name) => `This will permanently delete all ${count} ${name} items. Do you wish to continue?`,
754
- // StorageList
755
- storageNotAvailable: "This storage is not available.",
756
- keychainHintShort: "No items yet. Add a key below, or pass keychainKeys for internet credentials.",
757
- edit: "Edit",
758
- delete: "Delete",
759
- addItem: "Add item",
760
- // ItemForm
761
- keyRequired: "Key is required",
762
- saveFailed: "Save failed",
763
- editItemTitle: (key) => `Edit ${key}`,
764
- addItemTitle: (storageName) => `Add ${storageName} Item`,
765
- storageTypeLabel: (name) => `Storage Type: ${name}`,
766
- keyLabel: "Key",
767
- enterKeyPlaceholder: "Enter key",
768
- enterValuePlaceholder: "Enter value",
769
- cancel: "Cancel",
770
- saving: "Saving\u2026",
771
- save: "Save",
772
- add: "Add",
773
- // ConfirmModal defaults
774
- confirmDelete: "Yes, delete",
775
- cancelKeep: "No, keep it"
776
- };
777
-
778
- // src/components/ItemForm.tsx
779
- function ItemForm({
780
- visible,
781
- storageName,
782
- editingItem,
783
- onSave,
784
- onCancel
785
- }) {
786
- const [key, setKey] = useState("");
787
- const [value, setValue] = useState("");
788
- const [saving, setSaving] = useState(false);
789
- const [error, setError] = useState(null);
790
- const isEdit = editingItem !== null;
791
- useEffect(() => {
792
- if (visible) {
793
- setKey(editingItem?.key ?? "");
794
- setValue(editingItem?.value ?? "");
795
- setError(null);
796
- }
797
- }, [visible, editingItem]);
798
- const handleSubmit = async () => {
799
- const k = key.trim();
800
- if (!k) {
801
- setError(strings.keyRequired);
802
- return;
803
- }
804
- setSaving(true);
805
- setError(null);
806
- try {
807
- await onSave(k, value);
808
- onCancel();
809
- } catch (e) {
810
- setError(e instanceof Error ? e.message : strings.saveFailed);
811
- } finally {
812
- setSaving(false);
813
- }
814
- };
815
- const title = isEdit ? strings.editItemTitle(editingItem?.key ?? "") : strings.addItemTitle(storageName);
816
- return /* @__PURE__ */ React6.createElement(Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onCancel }, /* @__PURE__ */ React6.createElement(View, { style: styles2.formOverlay }, /* @__PURE__ */ React6.createElement(
817
- TouchableOpacity,
818
- {
819
- style: { flex: 1, width: "100%" },
820
- activeOpacity: 1,
821
- onPress: onCancel
822
- }
823
- ), /* @__PURE__ */ React6.createElement(View, { style: styles2.formModal }, /* @__PURE__ */ React6.createElement(View, { style: styles2.formHeader }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.formTitle, numberOfLines: 1 }, title), /* @__PURE__ */ React6.createElement(
824
- IconButton,
825
- {
826
- name: "close",
827
- onPress: onCancel,
828
- size: 24,
829
- tintColor: theme.colors.textSecondary,
830
- style: styles2.formCloseButton,
831
- hitSlop: LAYOUT.hitSlopLarge
832
- }
833
- )), /* @__PURE__ */ React6.createElement(Text, { style: styles2.formStorageType }, strings.storageTypeLabel(storageName)), /* @__PURE__ */ React6.createElement(Text, { style: styles2.formLabel }, strings.keyLabel), /* @__PURE__ */ React6.createElement(
834
- TextInput,
835
- {
836
- style: [styles2.formInput, isEdit && styles2.formInputDisabled],
837
- value: key,
838
- onChangeText: setKey,
839
- placeholder: strings.enterKeyPlaceholder,
840
- placeholderTextColor: theme.colors.textMuted,
841
- editable: !isEdit,
842
- autoCapitalize: "none",
843
- multiline: true
844
- }
845
- ), /* @__PURE__ */ React6.createElement(Text, { style: styles2.formLabel }, strings.valueLabel), /* @__PURE__ */ React6.createElement(
846
- TextInput,
682
+ },
683
+ confirmButtonSecondary: {
684
+ backgroundColor: "transparent",
685
+ borderWidth: 1,
686
+ borderColor: colors2.text
687
+ },
688
+ confirmButtonDanger: {
689
+ backgroundColor: colors2.text
690
+ },
691
+ formButtonSubmit: {
692
+ backgroundColor: colors2.text
693
+ },
694
+ confirmButtonText: {
695
+ fontSize: 16,
696
+ fontWeight: "600"
697
+ },
698
+ confirmButtonTextSecondary: {
699
+ color: colors2.text
700
+ },
701
+ confirmButtonTextDanger: {
702
+ color: colors2.inverted
703
+ },
704
+ formButtonTextSubmit: {
705
+ color: colors2.inverted
706
+ }
707
+ });
708
+ function ItemRowActions(props) {
709
+ const {
710
+ item,
711
+ onCopy,
712
+ onEdit,
713
+ onDelete,
714
+ showChevron = false,
715
+ chevronDirection = "down"
716
+ } = props;
717
+ return /* @__PURE__ */ React7.createElement(View, { style: styles5.itemRowActions }, /* @__PURE__ */ React7.createElement(IconButton, { name: "copy", onPress: () => onCopy(item) }), /* @__PURE__ */ React7.createElement(IconButton, { name: "edit", onPress: () => onEdit(item) }), /* @__PURE__ */ React7.createElement(IconButton, { name: "trash", onPress: () => onDelete(item) }), showChevron && /* @__PURE__ */ React7.createElement(View, { style: styles5.iconSlot }, /* @__PURE__ */ React7.createElement(
718
+ Icon,
847
719
  {
848
- style: styles2.formInput,
849
- value,
850
- onChangeText: setValue,
851
- placeholder: strings.enterValuePlaceholder,
852
- placeholderTextColor: theme.colors.textMuted,
853
- multiline: true,
854
- numberOfLines: 3
720
+ name: chevronDirection === "up" ? "chevronUp" : "chevronDown",
721
+ size: LAYOUT.chevronSize,
722
+ tintColor: theme.colors.text
855
723
  }
856
- ), error ? /* @__PURE__ */ React6.createElement(Text, { style: [styles2.errorText, { marginBottom: 12 }] }, error) : null, /* @__PURE__ */ React6.createElement(View, { style: styles2.formActions }, /* @__PURE__ */ React6.createElement(
857
- TouchableOpacity,
858
- {
859
- style: [styles2.formButton, styles2.formButtonCancel],
860
- onPress: onCancel,
861
- disabled: saving
862
- },
863
- /* @__PURE__ */ React6.createElement(Text, { style: [styles2.formButtonText, styles2.formButtonTextCancel] }, strings.cancel)
864
- ), /* @__PURE__ */ React6.createElement(
865
- TouchableOpacity,
866
- {
867
- style: [styles2.formButton, styles2.formButtonSubmit],
868
- onPress: handleSubmit,
869
- disabled: saving
870
- },
871
- /* @__PURE__ */ React6.createElement(Text, { style: [styles2.formButtonText, styles2.formButtonTextSubmit] }, saving ? strings.saving : isEdit ? strings.save : strings.add)
872
- )))));
724
+ )));
873
725
  }
874
- function ConfirmModal({
875
- visible,
876
- title,
877
- message,
878
- confirmLabel = strings.confirmDelete,
879
- cancelLabel = strings.cancelKeep,
880
- danger = true,
881
- onConfirm,
882
- onCancel
883
- }) {
884
- const handleConfirm = () => {
885
- void Promise.resolve(onConfirm());
726
+ var styles5 = StyleSheet.create({
727
+ itemRowActions: {
728
+ flexDirection: "row",
729
+ alignItems: "center",
730
+ marginLeft: LAYOUT.iconGap,
731
+ gap: LAYOUT.iconGap
732
+ },
733
+ iconSlot: {
734
+ width: LAYOUT.iconButtonSize,
735
+ height: LAYOUT.iconButtonSize,
736
+ alignItems: "center",
737
+ justifyContent: "center"
738
+ }
739
+ });
740
+
741
+ // src/components/StorageList.tsx
742
+ function StorageList(props) {
743
+ const { item, onCopy, onEdit, onDelete } = props;
744
+ const [expandedKeys, setExpandedKeys] = useState(/* @__PURE__ */ new Set());
745
+ const charCount = item.value.length;
746
+ const handleToggleExpanded = () => {
747
+ setExpandedKeys((prev) => {
748
+ const next = new Set(prev);
749
+ if (next.has(item.key)) next.delete(item.key);
750
+ else next.add(item.key);
751
+ return next;
752
+ });
886
753
  };
887
- return /* @__PURE__ */ React6.createElement(Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onCancel }, /* @__PURE__ */ React6.createElement(View, { style: styles2.confirmOverlay }, /* @__PURE__ */ React6.createElement(
888
- TouchableOpacity,
889
- {
890
- style: { flex: 1, width: "100%" },
891
- activeOpacity: 1,
892
- onPress: onCancel
893
- }
894
- ), /* @__PURE__ */ React6.createElement(View, { style: styles2.confirmModal }, /* @__PURE__ */ React6.createElement(View, { style: styles2.confirmHeader }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.confirmTitle }, title), /* @__PURE__ */ React6.createElement(
895
- IconButton,
754
+ const isExpanded = expandedKeys.has(item.key);
755
+ return /* @__PURE__ */ React7.createElement(View, { style: styles6.itemRow }, /* @__PURE__ */ React7.createElement(TouchableOpacity, { onPress: handleToggleExpanded, activeOpacity: 0.7 }, /* @__PURE__ */ React7.createElement(View, { style: styles6.itemRowCollapsed }, /* @__PURE__ */ React7.createElement(View, { style: { flex: 1 } }, /* @__PURE__ */ React7.createElement(Text, { style: styles6.itemKey, numberOfLines: 1 }, item.key), /* @__PURE__ */ React7.createElement(Text, { style: styles6.itemChars }, strings.charCount(charCount))), !isExpanded ? /* @__PURE__ */ React7.createElement(
756
+ ItemRowActions,
896
757
  {
897
- name: "close",
898
- onPress: onCancel,
899
- size: 24,
900
- tintColor: theme.colors.textSecondary,
901
- style: styles2.formCloseButton,
902
- hitSlop: LAYOUT.hitSlopLarge
758
+ item,
759
+ onCopy,
760
+ onEdit,
761
+ onDelete,
762
+ showChevron: true,
763
+ chevronDirection: "down"
903
764
  }
904
- )), /* @__PURE__ */ React6.createElement(Text, { style: styles2.confirmMessage }, message), /* @__PURE__ */ React6.createElement(View, { style: styles2.confirmActions }, /* @__PURE__ */ React6.createElement(
905
- TouchableOpacity,
906
- {
907
- style: [styles2.confirmButton, styles2.confirmButtonSecondary],
908
- onPress: onCancel
909
- },
910
- /* @__PURE__ */ React6.createElement(Text, { style: [styles2.confirmButtonText, styles2.confirmButtonTextSecondary] }, cancelLabel)
911
- ), /* @__PURE__ */ React6.createElement(
912
- TouchableOpacity,
913
- {
914
- style: [
915
- styles2.confirmButton,
916
- danger ? styles2.confirmButtonDanger : styles2.formButtonSubmit
917
- ],
918
- onPress: handleConfirm
919
- },
920
- /* @__PURE__ */ React6.createElement(
921
- Text,
922
- {
923
- style: [
924
- styles2.confirmButtonText,
925
- danger ? styles2.confirmButtonTextDanger : styles2.formButtonTextSubmit
926
- ]
927
- },
928
- confirmLabel
929
- )
930
- )))));
931
- }
932
- function ItemRowActions({
933
- item,
934
- onCopy,
935
- onEdit,
936
- onDelete,
937
- showChevron = false,
938
- chevronDirection = "down"
939
- }) {
940
- return /* @__PURE__ */ React6.createElement(View, { style: styles2.itemRowActions }, /* @__PURE__ */ React6.createElement(IconButton, { name: "copy", onPress: () => onCopy(item) }), /* @__PURE__ */ React6.createElement(IconButton, { name: "edit", onPress: () => onEdit(item) }), /* @__PURE__ */ React6.createElement(IconButton, { name: "trash", onPress: () => onDelete(item) }), showChevron && /* @__PURE__ */ React6.createElement(View, { style: styles2.iconSlot }, /* @__PURE__ */ React6.createElement(
765
+ ) : /* @__PURE__ */ React7.createElement(View, { style: styles6.iconSlot }, /* @__PURE__ */ React7.createElement(
941
766
  Icon,
942
767
  {
943
- name: chevronDirection === "up" ? "chevronUp" : "chevronDown",
768
+ name: "chevronUp",
944
769
  size: LAYOUT.chevronSize,
945
770
  tintColor: theme.colors.text
946
771
  }
772
+ )))), isExpanded && /* @__PURE__ */ React7.createElement(View, { style: styles6.itemRowExpanded }, /* @__PURE__ */ React7.createElement(TouchableOpacity, { onPress: () => onEdit(item), style: styles6.valueBox }, /* @__PURE__ */ React7.createElement(Text, { style: styles6.valueBoxLabel }, strings.valueLabel), /* @__PURE__ */ React7.createElement(Text, { style: styles6.valueBoxText, selectable: true }, item.value)), /* @__PURE__ */ React7.createElement(
773
+ ItemRowActions,
774
+ {
775
+ item,
776
+ onCopy,
777
+ onEdit,
778
+ onDelete
779
+ }
947
780
  )));
948
781
  }
782
+ var { colors: colors3 } = theme;
783
+ var styles6 = StyleSheet.create({
784
+ itemRow: {
785
+ minHeight: LAYOUT.rowMinHeight,
786
+ paddingHorizontal: LAYOUT.padding,
787
+ paddingVertical: 12,
788
+ borderBottomWidth: StyleSheet.hairlineWidth,
789
+ borderBottomColor: colors3.borderLight,
790
+ backgroundColor: colors3.background,
791
+ marginHorizontal: LAYOUT.padding,
792
+ marginBottom: 4
793
+ },
794
+ itemRowCollapsed: {
795
+ flexDirection: "row",
796
+ alignItems: "center",
797
+ alignSelf: "stretch"
798
+ },
799
+ itemKey: {
800
+ flex: 1,
801
+ fontSize: LAYOUT.fontSize,
802
+ fontWeight: "500",
803
+ color: colors3.text
804
+ },
805
+ itemChars: {
806
+ fontSize: 12,
807
+ color: colors3.textSecondary,
808
+ marginTop: 2
809
+ },
810
+ iconSlot: {
811
+ width: LAYOUT.iconButtonSize,
812
+ height: LAYOUT.iconButtonSize,
813
+ alignItems: "center",
814
+ justifyContent: "center"
815
+ },
816
+ itemRowExpanded: {
817
+ paddingTop: 4
818
+ },
819
+ valueBox: {
820
+ backgroundColor: colors3.backgroundSecondary,
821
+ borderRadius: 8,
822
+ padding: 12,
823
+ marginTop: 8,
824
+ marginBottom: 8,
825
+ borderWidth: StyleSheet.hairlineWidth,
826
+ borderColor: colors3.border
827
+ },
828
+ valueBoxLabel: {
829
+ fontSize: 11,
830
+ fontWeight: "600",
831
+ color: colors3.textSecondary,
832
+ marginBottom: 4,
833
+ textTransform: "uppercase"
834
+ },
835
+ valueBoxText: {
836
+ fontSize: LAYOUT.fontSize,
837
+ color: colors3.text
838
+ }
839
+ });
949
840
 
950
841
  // src/components/StorageSection.tsx
951
- function StorageSection({
952
- adapter,
953
- keychainKeys,
954
- onKeychainKeyAdded,
955
- onSecureStoreKeyAdded,
956
- defaultExpanded = true,
957
- expanded: expandedProp,
958
- onToggleExpanded,
959
- refreshTrigger
960
- }) {
842
+ function StorageSection(props) {
843
+ const {
844
+ adapter,
845
+ defaultExpanded = true,
846
+ expanded: expandedProp,
847
+ onToggleExpanded,
848
+ refreshTrigger
849
+ } = props;
961
850
  const { items, loading, error, refresh } = useStorageItems(adapter);
962
851
  const [expandedInternal, setExpandedInternal] = useState(defaultExpanded);
963
852
  const expanded = expandedProp !== void 0 ? expandedProp : expandedInternal;
@@ -968,7 +857,6 @@ function StorageSection({
968
857
  useEffect(() => {
969
858
  if (refreshTrigger !== void 0) refresh();
970
859
  }, [refreshTrigger, refresh]);
971
- const [expandedKeys, setExpandedKeys] = useState(/* @__PURE__ */ new Set());
972
860
  const [formVisible, setFormVisible] = useState(false);
973
861
  const [editingItem, setEditingItem] = useState(null);
974
862
  const [deleteItem, setDeleteItem] = useState(null);
@@ -982,14 +870,7 @@ function StorageSection({
982
870
  setFormVisible(true);
983
871
  };
984
872
  const handleSave = async (key, value) => {
985
- const isNewKey = !editingItem || editingItem.key !== key;
986
873
  await adapter.setItem(key, value);
987
- if (adapter.type === "keychain" && isNewKey) {
988
- onKeychainKeyAdded?.(key);
989
- }
990
- if (adapter.type === "expo-secure-store" && isNewKey) {
991
- onSecureStoreKeyAdded?.(key);
992
- }
993
874
  await refresh();
994
875
  };
995
876
  const handleDeleteItem = async () => {
@@ -1017,25 +898,25 @@ function StorageSection({
1017
898
  };
1018
899
  const isKeychain = adapter.type === "keychain";
1019
900
  const isSecureStore = adapter.type === "expo-secure-store";
1020
- const showKeychainHint = isKeychain && items.length === 0 && (keychainKeys?.length ?? 0) === 0;
901
+ const showKeychainHint = isKeychain && items.length === 0;
1021
902
  const showSecureStoreHint = isSecureStore && items.length === 0;
1022
903
  if (!adapter.isAvailable()) return null;
1023
- return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(
904
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(
1024
905
  TouchableOpacity,
1025
906
  {
1026
- style: styles2.sectionHeader,
907
+ style: styles7.sectionHeader,
1027
908
  onPress: handleToggleExpanded,
1028
909
  activeOpacity: 0.7
1029
910
  },
1030
- /* @__PURE__ */ React6.createElement(View, { style: styles2.sectionHeaderLabelWrap }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.sectionHeaderLabel }, adapter.name, /* @__PURE__ */ React6.createElement(Text, { style: styles2.sectionHeaderCount }, " (", items.length, ")"))),
1031
- /* @__PURE__ */ React6.createElement(View, { style: styles2.storageRowActions }, /* @__PURE__ */ React6.createElement(IconButton, { name: "plus", onPress: handleAdd }), /* @__PURE__ */ React6.createElement(
911
+ /* @__PURE__ */ React7.createElement(View, { style: styles7.sectionHeaderLabelWrap }, /* @__PURE__ */ React7.createElement(Text, { style: styles7.sectionHeaderLabel }, adapter.name, /* @__PURE__ */ React7.createElement(Text, { style: styles7.sectionHeaderCount }, " (", items.length, ")"))),
912
+ /* @__PURE__ */ React7.createElement(View, { style: styles7.storageRowActions }, /* @__PURE__ */ React7.createElement(IconButton, { name: "plus", onPress: handleAdd }), /* @__PURE__ */ React7.createElement(
1032
913
  IconButton,
1033
914
  {
1034
915
  name: "trash",
1035
916
  onPress: () => items.length > 0 && setClearAllVisible(true),
1036
917
  disabled: items.length === 0
1037
918
  }
1038
- ), /* @__PURE__ */ React6.createElement(View, { style: styles2.iconSlot }, /* @__PURE__ */ React6.createElement(
919
+ ), /* @__PURE__ */ React7.createElement(View, { style: styles7.iconSlot }, /* @__PURE__ */ React7.createElement(
1039
920
  Icon,
1040
921
  {
1041
922
  name: expanded ? "chevronUp" : "chevronDown",
@@ -1043,54 +924,16 @@ function StorageSection({
1043
924
  tintColor: theme.colors.text
1044
925
  }
1045
926
  )))
1046
- ), expanded && /* @__PURE__ */ React6.createElement(React6.Fragment, null, showKeychainHint ? /* @__PURE__ */ React6.createElement(View, { style: styles2.keychainHint }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.keychainHintText }, strings.keychainHint)) : null, showSecureStoreHint ? /* @__PURE__ */ React6.createElement(View, { style: styles2.keychainHint }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.keychainHintText }, strings.secureStoreHint)) : null, error ? /* @__PURE__ */ React6.createElement(View, { style: styles2.error }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.errorText }, error)) : null, loading ? /* @__PURE__ */ React6.createElement(View, { style: styles2.loading }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.loadingText }, strings.loading)) : items.map((item) => {
1047
- const isItemExpanded = expandedKeys.has(item.key);
1048
- const charCount = item.value.length;
1049
- const toggleItemExpanded = () => {
1050
- setExpandedKeys((prev) => {
1051
- const next = new Set(prev);
1052
- if (next.has(item.key)) next.delete(item.key);
1053
- else next.add(item.key);
1054
- return next;
1055
- });
1056
- };
1057
- return /* @__PURE__ */ React6.createElement(
1058
- TouchableOpacity,
1059
- {
1060
- key: item.key,
1061
- style: styles2.itemRow,
1062
- onPress: toggleItemExpanded,
1063
- activeOpacity: 0.7
1064
- },
1065
- /* @__PURE__ */ React6.createElement(View, { style: styles2.itemRowCollapsed }, /* @__PURE__ */ React6.createElement(View, { style: { flex: 1 } }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.itemKey, numberOfLines: 1 }, item.key), /* @__PURE__ */ React6.createElement(Text, { style: styles2.itemChars }, strings.charCount(charCount))), !isItemExpanded ? /* @__PURE__ */ React6.createElement(
1066
- ItemRowActions,
1067
- {
1068
- item,
1069
- onCopy: handleCopy,
1070
- onEdit: handleEdit,
1071
- onDelete: setDeleteItem,
1072
- showChevron: true,
1073
- chevronDirection: "down"
1074
- }
1075
- ) : /* @__PURE__ */ React6.createElement(View, { style: styles2.iconSlot }, /* @__PURE__ */ React6.createElement(
1076
- Icon,
1077
- {
1078
- name: "chevronUp",
1079
- size: LAYOUT.chevronSize,
1080
- tintColor: theme.colors.text
1081
- }
1082
- ))),
1083
- isItemExpanded && /* @__PURE__ */ React6.createElement(View, { style: styles2.itemRowExpanded }, /* @__PURE__ */ React6.createElement(View, { style: styles2.valueBox }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.valueBoxLabel }, strings.valueLabel), /* @__PURE__ */ React6.createElement(Text, { style: styles2.valueBoxText, selectable: true }, item.value || strings.emptyValue)), /* @__PURE__ */ React6.createElement(
1084
- ItemRowActions,
1085
- {
1086
- item,
1087
- onCopy: handleCopy,
1088
- onEdit: handleEdit,
1089
- onDelete: setDeleteItem
1090
- }
1091
- ))
1092
- );
1093
- }), !loading && items.length === 0 && !showKeychainHint && !showSecureStoreHint ? /* @__PURE__ */ React6.createElement(View, { style: styles2.empty }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.emptyText }, strings.noItems)) : null), /* @__PURE__ */ React6.createElement(
927
+ ), expanded && /* @__PURE__ */ React7.createElement(React7.Fragment, null, showKeychainHint ? /* @__PURE__ */ React7.createElement(View, { style: styles7.keychainHint }, /* @__PURE__ */ React7.createElement(Text, { style: styles7.keychainHintText }, strings.keychainHint)) : null, showSecureStoreHint ? /* @__PURE__ */ React7.createElement(View, { style: styles7.keychainHint }, /* @__PURE__ */ React7.createElement(Text, { style: styles7.keychainHintText }, strings.secureStoreHint)) : null, error ? /* @__PURE__ */ React7.createElement(View, { style: styles7.error }, /* @__PURE__ */ React7.createElement(Text, { style: styles7.errorText }, error)) : null, loading ? /* @__PURE__ */ React7.createElement(View, { style: styles7.loading }, /* @__PURE__ */ React7.createElement(Text, { style: styles7.loadingText }, strings.loading)) : items.map((item) => /* @__PURE__ */ React7.createElement(
928
+ StorageList,
929
+ {
930
+ key: item.key,
931
+ item,
932
+ onCopy: handleCopy,
933
+ onEdit: handleEdit,
934
+ onDelete: setDeleteItem
935
+ }
936
+ )), !loading && items.length === 0 && !showKeychainHint && !showSecureStoreHint ? /* @__PURE__ */ React7.createElement(View, { style: styles7.empty }, /* @__PURE__ */ React7.createElement(Text, { style: styles7.emptyText }, strings.noItems)) : null), /* @__PURE__ */ React7.createElement(
1094
937
  ItemForm,
1095
938
  {
1096
939
  visible: formVisible,
@@ -1102,7 +945,7 @@ function StorageSection({
1102
945
  setEditingItem(null);
1103
946
  }
1104
947
  }
1105
- ), /* @__PURE__ */ React6.createElement(
948
+ ), /* @__PURE__ */ React7.createElement(
1106
949
  ConfirmModal,
1107
950
  {
1108
951
  visible: deleteItem !== null,
@@ -1111,7 +954,7 @@ function StorageSection({
1111
954
  onConfirm: handleDeleteItem,
1112
955
  onCancel: () => setDeleteItem(null)
1113
956
  }
1114
- ), /* @__PURE__ */ React6.createElement(
957
+ ), /* @__PURE__ */ React7.createElement(
1115
958
  ConfirmModal,
1116
959
  {
1117
960
  visible: clearAllVisible,
@@ -1122,30 +965,92 @@ function StorageSection({
1122
965
  }
1123
966
  ));
1124
967
  }
968
+ var { colors: colors4 } = theme;
969
+ var styles7 = StyleSheet.create({
970
+ sectionHeader: {
971
+ height: LAYOUT.sectionHeaderHeight,
972
+ flexDirection: "row",
973
+ alignItems: "center",
974
+ paddingHorizontal: LAYOUT.padding,
975
+ borderBottomWidth: StyleSheet.hairlineWidth,
976
+ borderBottomColor: colors4.border,
977
+ backgroundColor: colors4.backgroundSecondary,
978
+ marginTop: LAYOUT.padding,
979
+ marginHorizontal: LAYOUT.padding,
980
+ borderRadius: LAYOUT.sectionRadius
981
+ },
982
+ sectionHeaderLabelWrap: {
983
+ flex: 1
984
+ },
985
+ sectionHeaderLabel: {
986
+ fontSize: 15,
987
+ fontWeight: "600",
988
+ color: colors4.text
989
+ },
990
+ sectionHeaderCount: {
991
+ color: colors4.textSecondary,
992
+ fontWeight: "400"
993
+ },
994
+ storageRowActions: {
995
+ flexDirection: "row",
996
+ alignItems: "center",
997
+ gap: LAYOUT.iconGap
998
+ },
999
+ iconSlot: {
1000
+ width: LAYOUT.iconButtonSize,
1001
+ height: LAYOUT.iconButtonSize,
1002
+ alignItems: "center",
1003
+ justifyContent: "center"
1004
+ },
1005
+ keychainHint: {
1006
+ padding: LAYOUT.padding,
1007
+ marginHorizontal: LAYOUT.padding,
1008
+ marginTop: 8,
1009
+ marginBottom: 4,
1010
+ backgroundColor: colors4.backgroundSecondary,
1011
+ borderRadius: 8
1012
+ },
1013
+ keychainHintText: {
1014
+ fontSize: LAYOUT.fontSize - 1,
1015
+ color: colors4.textSecondary
1016
+ },
1017
+ error: {
1018
+ padding: LAYOUT.padding,
1019
+ backgroundColor: colors4.backgroundTertiary,
1020
+ marginHorizontal: LAYOUT.padding,
1021
+ marginVertical: 8,
1022
+ borderRadius: 8
1023
+ },
1024
+ errorText: {
1025
+ fontSize: LAYOUT.fontSize,
1026
+ color: colors4.text
1027
+ },
1028
+ loading: {
1029
+ padding: LAYOUT.padding * 2,
1030
+ alignItems: "center",
1031
+ marginHorizontal: LAYOUT.padding
1032
+ },
1033
+ loadingText: {
1034
+ fontSize: LAYOUT.fontSize,
1035
+ color: colors4.textSecondary
1036
+ },
1037
+ empty: {
1038
+ padding: LAYOUT.padding * 2,
1039
+ alignItems: "center",
1040
+ marginHorizontal: LAYOUT.padding
1041
+ },
1042
+ emptyText: {
1043
+ fontSize: LAYOUT.fontSize,
1044
+ color: colors4.textMuted
1045
+ }
1046
+ });
1125
1047
 
1126
1048
  // src/components/StorageInspector.tsx
1127
- function StorageInspector({
1128
- mmkvInstances = [],
1129
- asyncStorageInstance,
1130
- keychainKeys: keychainKeysProp,
1131
- keychainInstance,
1132
- secureStoreKeys: secureStoreKeysProp,
1133
- secureStoreInstance,
1134
- customAdapters = []
1135
- }) {
1136
- const [keychainKeysAdded, setKeychainKeysAdded] = useState([]);
1137
- const [secureStoreKeysAdded, setSecureStoreKeysAdded] = useState([]);
1049
+ function StorageInspector(props) {
1050
+ const { mmkvInstances = [], secureStoreKeys, customAdapters = [] } = props;
1138
1051
  const [refreshKey, setRefreshKey] = useState(0);
1139
1052
  const [refreshing, setRefreshing] = useState(false);
1140
1053
  const [expandedIndices, setExpandedIndices] = useState(() => /* @__PURE__ */ new Set([0]));
1141
- const keychainKeys = useMemo(
1142
- () => [...keychainKeysProp ?? [], ...keychainKeysAdded],
1143
- [keychainKeysProp, keychainKeysAdded]
1144
- );
1145
- const secureStoreKeys = useMemo(
1146
- () => [...secureStoreKeysProp ?? [], ...secureStoreKeysAdded],
1147
- [secureStoreKeysProp, secureStoreKeysAdded]
1148
- );
1149
1054
  const adapters = useMemo(() => {
1150
1055
  const list = [];
1151
1056
  mmkvInstances.forEach((inst, i) => {
@@ -1153,58 +1058,34 @@ function StorageInspector({
1153
1058
  createMMKVAdapter(inst, mmkvInstances.length > 1 ? `MMKV ${i + 1}` : "MMKV")
1154
1059
  );
1155
1060
  });
1156
- const asyncAdapter = createAsyncStorageAdapter(asyncStorageInstance);
1061
+ const asyncAdapter = createAsyncStorageAdapter();
1157
1062
  if (asyncAdapter.isAvailable()) list.push(asyncAdapter);
1158
- const keychainAdapter = createKeychainAdapter(keychainKeys, keychainInstance);
1063
+ const keychainAdapter = createKeychainAdapter();
1159
1064
  if (keychainAdapter.isAvailable()) list.push(keychainAdapter);
1160
- const secureStoreAdapter = createSecureStoreAdapter(
1161
- secureStoreKeys,
1162
- secureStoreInstance
1163
- );
1065
+ const secureStoreAdapter = createSecureStoreAdapter(secureStoreKeys ?? []);
1164
1066
  if (secureStoreAdapter.isAvailable()) list.push(secureStoreAdapter);
1165
1067
  list.push(...customAdapters);
1166
1068
  return list;
1167
- }, [
1168
- mmkvInstances,
1169
- asyncStorageInstance,
1170
- keychainKeys,
1171
- keychainInstance,
1172
- secureStoreKeys,
1173
- secureStoreInstance,
1174
- customAdapters
1175
- ]);
1176
- const handleKeychainKeyAdded = (key) => {
1177
- setKeychainKeysAdded(
1178
- (prev) => prev.includes(key) ? prev : [...prev, key]
1179
- );
1180
- };
1181
- const handleSecureStoreKeyAdded = (key) => {
1182
- setSecureStoreKeysAdded(
1183
- (prev) => prev.includes(key) ? prev : [...prev, key]
1184
- );
1185
- };
1069
+ }, [mmkvInstances, secureStoreKeys, customAdapters]);
1186
1070
  const handleRefresh = () => {
1187
1071
  setRefreshing(true);
1188
1072
  setRefreshKey((k) => k + 1);
1189
1073
  setTimeout(() => setRefreshing(false), 400);
1190
1074
  };
1191
- return /* @__PURE__ */ React6.createElement(View, { style: styles2.container }, /* @__PURE__ */ React6.createElement(View, { style: styles2.content }, adapters.length > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(
1075
+ return /* @__PURE__ */ React7.createElement(View, { style: styles8.container }, /* @__PURE__ */ React7.createElement(View, { style: styles8.content }, adapters.length > 0 ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(
1192
1076
  ScrollView,
1193
1077
  {
1194
- style: styles2.scroll,
1195
- contentContainerStyle: styles2.scrollContent,
1078
+ style: styles8.scroll,
1079
+ contentContainerStyle: styles8.scrollContent,
1196
1080
  keyboardShouldPersistTaps: "handled",
1197
1081
  showsVerticalScrollIndicator: true,
1198
- refreshControl: /* @__PURE__ */ React6.createElement(RefreshControl, { refreshing, onRefresh: handleRefresh })
1082
+ refreshControl: /* @__PURE__ */ React7.createElement(RefreshControl, { refreshing, onRefresh: handleRefresh })
1199
1083
  },
1200
- adapters.map((adapter, index) => /* @__PURE__ */ React6.createElement(
1084
+ adapters.map((adapter, index) => /* @__PURE__ */ React7.createElement(
1201
1085
  StorageSection,
1202
1086
  {
1203
1087
  key: `${adapter.type}-${index}`,
1204
1088
  adapter,
1205
- keychainKeys: keychainKeysProp,
1206
- onKeychainKeyAdded: handleKeychainKeyAdded,
1207
- onSecureStoreKeyAdded: handleSecureStoreKeyAdded,
1208
1089
  expanded: expandedIndices.has(index),
1209
1090
  onToggleExpanded: () => {
1210
1091
  setExpandedIndices((prev) => {
@@ -1217,18 +1098,57 @@ function StorageInspector({
1217
1098
  refreshTrigger: refreshKey
1218
1099
  }
1219
1100
  ))
1220
- ), /* @__PURE__ */ React6.createElement(
1101
+ ), /* @__PURE__ */ React7.createElement(
1221
1102
  IconButton,
1222
1103
  {
1223
1104
  name: "refresh",
1224
1105
  onPress: handleRefresh,
1225
1106
  size: 24,
1226
1107
  tintColor: theme.colors.inverted,
1227
- style: styles2.fab,
1108
+ style: styles8.fab,
1228
1109
  activeOpacity: 0.85
1229
1110
  }
1230
- )) : /* @__PURE__ */ React6.createElement(View, { style: styles2.empty }, /* @__PURE__ */ React6.createElement(Text, { style: styles2.emptyText }, strings.noAdapterAvailable))));
1111
+ )) : /* @__PURE__ */ React7.createElement(View, { style: styles8.empty }, /* @__PURE__ */ React7.createElement(Text, { style: styles8.emptyText }, strings.noAdapterAvailable))));
1231
1112
  }
1113
+ var { colors: colors5 } = theme;
1114
+ var styles8 = StyleSheet.create({
1115
+ container: {
1116
+ flex: 1,
1117
+ width: "100%",
1118
+ backgroundColor: colors5.background
1119
+ },
1120
+ content: {
1121
+ flex: 1
1122
+ },
1123
+ scroll: {
1124
+ flex: 1
1125
+ },
1126
+ scrollContent: {
1127
+ flexGrow: 1,
1128
+ paddingBottom: LAYOUT.fabSize + LAYOUT.padding + 20,
1129
+ paddingTop: LAYOUT.padding
1130
+ },
1131
+ fab: {
1132
+ position: "absolute",
1133
+ bottom: LAYOUT.padding + 16,
1134
+ right: LAYOUT.padding + 16,
1135
+ width: LAYOUT.fabSize,
1136
+ height: LAYOUT.fabSize,
1137
+ borderRadius: LAYOUT.fabSize / 2,
1138
+ backgroundColor: colors5.text,
1139
+ alignItems: "center",
1140
+ justifyContent: "center"
1141
+ },
1142
+ empty: {
1143
+ padding: LAYOUT.padding * 2,
1144
+ alignItems: "center",
1145
+ marginHorizontal: LAYOUT.padding
1146
+ },
1147
+ emptyText: {
1148
+ fontSize: LAYOUT.fontSize,
1149
+ color: colors5.textMuted
1150
+ }
1151
+ });
1232
1152
 
1233
1153
  export { StorageInspector, createAsyncStorageAdapter, createKeychainAdapter, createMMKVAdapter, createSecureStoreAdapter, strings, theme };
1234
1154
  //# sourceMappingURL=index.mjs.map