@buoy-gg/storage 7.0.17 → 7.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/lib/commonjs/index.js +12 -0
  2. package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +5 -602
  3. package/lib/commonjs/storage/components/StorageModalWithTabs.js +17 -1
  4. package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +13 -10
  5. package/lib/commonjs/storage/hooks/useMMKVKeys.js +28 -23
  6. package/lib/commonjs/storage/stores/storageEventStore.js +85 -1
  7. package/lib/commonjs/storage/sync/storageSyncAdapter.js +214 -6
  8. package/lib/commonjs/storage/utils/requiredStorageKeyScope.js +17 -0
  9. package/lib/commonjs/storage/utils/snapshotProvider.js +173 -5
  10. package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +17 -3
  11. package/lib/module/index.js +6 -1
  12. package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +7 -603
  13. package/lib/module/storage/components/StorageModalWithTabs.js +17 -1
  14. package/lib/module/storage/hooks/useAsyncStorageKeys.js +13 -10
  15. package/lib/module/storage/hooks/useMMKVKeys.js +28 -23
  16. package/lib/module/storage/stores/storageEventStore.js +81 -0
  17. package/lib/module/storage/sync/storageSyncAdapter.js +215 -7
  18. package/lib/module/storage/utils/requiredStorageKeyScope.js +13 -0
  19. package/lib/module/storage/utils/snapshotProvider.js +173 -5
  20. package/lib/module/storage/utils/storageTimeTravelUtils.js +17 -3
  21. package/lib/typescript/index.d.ts +2 -1
  22. package/lib/typescript/index.d.ts.map +1 -1
  23. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +7 -18
  24. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -1
  25. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +8 -1
  26. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
  27. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -1
  28. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -1
  29. package/lib/typescript/storage/stores/storageEventStore.d.ts +26 -0
  30. package/lib/typescript/storage/stores/storageEventStore.d.ts.map +1 -1
  31. package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +80 -14
  32. package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -1
  33. package/lib/typescript/storage/types.d.ts +9 -9
  34. package/lib/typescript/storage/types.d.ts.map +1 -1
  35. package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts +10 -0
  36. package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts.map +1 -0
  37. package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +1 -1
  38. package/package.json +11 -6
@@ -93,6 +93,12 @@ Object.defineProperty(exports, "StorageTypeFilterBar", {
93
93
  return _StorageTypeFilterBar.StorageTypeFilterBar;
94
94
  }
95
95
  });
96
+ Object.defineProperty(exports, "batchPairsOf", {
97
+ enumerable: true,
98
+ get: function () {
99
+ return _storageEventStore.batchPairsOf;
100
+ }
101
+ });
96
102
  Object.defineProperty(exports, "canUndo", {
97
103
  enumerable: true,
98
104
  get: function () {
@@ -165,6 +171,12 @@ Object.defineProperty(exports, "isTypeMatch", {
165
171
  return _mmkvTypeDetection.isTypeMatch;
166
172
  }
167
173
  });
174
+ Object.defineProperty(exports, "isValueOnDevice", {
175
+ enumerable: true,
176
+ get: function () {
177
+ return _storageEventStore.isValueOnDevice;
178
+ }
179
+ });
168
180
  Object.defineProperty(exports, "jumpToState", {
169
181
  enumerable: true,
170
182
  get: function () {
@@ -3,607 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ThemedSplitView = ThemedSplitView;
7
- var _react = require("react");
8
- var _reactNative = require("react-native");
9
- var _lineDiff = require("../../../utils/lineDiff");
10
- var _DiffSummary = require("../components/DiffSummary");
11
- var _jsxRuntime = require("react/jsx-runtime");
12
- const DEFAULT_OPTIONS = {
13
- hideLineNumbers: false,
14
- disableWordDiff: false,
15
- showDiffOnly: false,
16
- compareMethod: "words",
17
- contextLines: 3,
18
- lineOffset: 0
19
- };
20
- function ThemedSplitView({
21
- oldValue,
22
- newValue,
23
- theme,
24
- options = DEFAULT_OPTIONS,
25
- showThemeName = false,
26
- scrollEnabled = true
27
- }) {
28
- // Inline mode drops the fixed 400pt pane so the container grows with the
29
- // rows; the ancestor ScrollView is what scrolls them.
30
- const dynamicStyles = (0, _react.useMemo)(() => createDynamicStyles(theme, scrollEnabled), [theme, scrollEnabled]);
31
- const diffComputeOptions = (0, _react.useMemo)(() => ({
32
- compareMethod: options.compareMethod,
33
- disableWordDiff: options.disableWordDiff,
34
- showDiffOnly: options.showDiffOnly,
35
- contextLines: options.contextLines
36
- }), [options.compareMethod, options.disableWordDiff, options.showDiffOnly, options.contextLines]);
37
- const lineDiffs = (0, _react.useMemo)(() => (0, _lineDiff.computeLineDiff)(oldValue, newValue, diffComputeOptions), [oldValue, newValue, diffComputeOptions]);
38
-
39
- // One pass for the summary instead of three .filter() calls per render.
40
- const summary = (0, _react.useMemo)(() => {
41
- let added = 0;
42
- let removed = 0;
43
- let modified = 0;
44
- for (const d of lineDiffs) {
45
- if (d.type === _lineDiff.DiffType.ADDED) added++;else if (d.type === _lineDiff.DiffType.REMOVED) removed++;else if (d.type === _lineDiff.DiffType.MODIFIED) modified++;
46
- }
47
- return {
48
- added,
49
- removed,
50
- modified
51
- };
52
- }, [lineDiffs]);
53
-
54
- // Auto-collapse runs of unchanged lines that aren't near a change. Keeps
55
- // CONTEXT_LINES on either side of every change visible (GitHub-style), folds
56
- // the rest into a tappable header.
57
- const [expandedFolds, setExpandedFolds] = (0, _react.useState)(() => new Set());
58
-
59
- // Reset fold expansion when the user actually switches comparisons. Parent
60
- // memoizes oldValue/newValue, so this only fires on a real change — not on
61
- // every re-render. First run is a no-op (initial state is already empty).
62
- const hasMountedRef = (0, _react.useRef)(false);
63
- (0, _react.useEffect)(() => {
64
- if (!hasMountedRef.current) {
65
- hasMountedRef.current = true;
66
- return;
67
- }
68
- setExpandedFolds(new Set());
69
- }, [oldValue, newValue]);
70
- const items = (0, _react.useMemo)(() => buildSplitItems(lineDiffs, expandedFolds), [lineDiffs, expandedFolds]);
71
- const toggleFold = (0, _react.useCallback)(foldId => {
72
- setExpandedFolds(prev => {
73
- const next = new Set(prev);
74
- if (next.has(foldId)) next.delete(foldId);else next.add(foldId);
75
- return next;
76
- });
77
- }, []);
78
- const keyExtractor = (0, _react.useCallback)(item => item.kind === "row" ? `r:${item.diffIndex}` : `f:${item.foldId}`, []);
79
- const renderSplitItem = (0, _react.useCallback)(item => {
80
- if (item.kind === "fold") {
81
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(FoldHeader, {
82
- foldId: item.foldId,
83
- count: item.count,
84
- expanded: item.expanded,
85
- theme: theme,
86
- styles: dynamicStyles,
87
- onToggle: toggleFold
88
- });
89
- }
90
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(DiffRow, {
91
- diff: item.diff,
92
- showSeparator: false,
93
- theme: theme,
94
- options: options,
95
- styles: dynamicStyles
96
- });
97
- }, [theme, options, dynamicStyles, toggleFold]);
98
- const renderItem = (0, _react.useCallback)(({
99
- item
100
- }) => renderSplitItem(item), [renderSplitItem]);
101
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
102
- style: [dynamicStyles.container, theme.glowColor && {
103
- shadowColor: theme.glowColor,
104
- shadowOffset: {
105
- width: 0,
106
- height: 0
107
- },
108
- shadowOpacity: theme.neonIntensity && theme.neonIntensity > 0.7 ? 0.5 : theme.neonIntensity && theme.neonIntensity > 0.3 ? 0.3 : 0.1,
109
- shadowRadius: theme.neonIntensity && theme.neonIntensity > 0.7 ? 10 : theme.neonIntensity && theme.neonIntensity > 0.3 ? 5 : 2
110
- }],
111
- children: [showThemeName && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
112
- style: dynamicStyles.themeBadge,
113
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
114
- style: dynamicStyles.themeName,
115
- children: theme.name
116
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
117
- style: dynamicStyles.themeDescription,
118
- children: theme.description
119
- })]
120
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
121
- style: dynamicStyles.header,
122
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
123
- style: dynamicStyles.headerLeft,
124
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
125
- style: dynamicStyles.headerTitle,
126
- children: "PREV"
127
- })
128
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
129
- style: dynamicStyles.divider
130
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
131
- style: dynamicStyles.headerRight,
132
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
133
- style: dynamicStyles.headerTitle,
134
- children: "CUR"
135
- })
136
- })]
137
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_DiffSummary.DiffSummary, {
138
- added: summary.added,
139
- removed: summary.removed,
140
- modified: summary.modified,
141
- theme: theme
142
- }), lineDiffs.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
143
- style: dynamicStyles.emptyState,
144
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
145
- style: dynamicStyles.emptyText,
146
- children: options.showDiffOnly ? "No differences found" : "No content to display"
147
- })
148
- }) : scrollEnabled ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
149
- style: dynamicStyles.scrollView,
150
- contentContainerStyle: dynamicStyles.scrollContent,
151
- data: items,
152
- renderItem: renderItem,
153
- keyExtractor: keyExtractor,
154
- showsVerticalScrollIndicator: false,
155
- initialNumToRender: 20,
156
- maxToRenderPerBatch: 20,
157
- windowSize: 7,
158
- removeClippedSubviews: true
159
- }) :
160
- /*#__PURE__*/
161
- // A FlatList can't virtualize inside a page ScrollView — it has no
162
- // viewport of its own to measure against — so render the rows directly.
163
- // Folding already keeps this list short (unchanged runs collapse).
164
- (0, _jsxRuntime.jsx)(_reactNative.View, {
165
- style: dynamicStyles.scrollContent,
166
- children: items.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.Fragment, {
167
- children: renderSplitItem(item)
168
- }, keyExtractor(item)))
169
- })]
170
- });
171
- }
172
-
173
- // Number of context lines kept visible on either side of every change.
174
- const CONTEXT_LINES = 3;
175
- // Don't bother folding tiny gaps — toggling them is more friction than scroll.
176
- const MIN_FOLD_SIZE = 4;
177
- function buildSplitItems(lineDiffs, expandedFolds) {
178
- const n = lineDiffs.length;
179
- if (n === 0) return [];
180
-
181
- // Mark every line that should always be visible: any change, plus
182
- // CONTEXT_LINES on either side of it.
183
- const visible = new Array(n).fill(false);
184
- for (let i = 0; i < n; i++) {
185
- if (lineDiffs[i].type !== _lineDiff.DiffType.DEFAULT) {
186
- const start = Math.max(0, i - CONTEXT_LINES);
187
- const end = Math.min(n - 1, i + CONTEXT_LINES);
188
- for (let k = start; k <= end; k++) visible[k] = true;
189
- }
6
+ Object.defineProperty(exports, "ThemedSplitView", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _dataViewer.ThemedSplitView;
190
10
  }
191
- const items = [];
192
- let foldId = 0;
193
- let i = 0;
194
- while (i < n) {
195
- if (visible[i]) {
196
- items.push({
197
- kind: "row",
198
- diff: lineDiffs[i],
199
- diffIndex: i
200
- });
201
- i++;
202
- continue;
203
- }
204
- let j = i;
205
- while (j < n && !visible[j]) j++;
206
- const runLength = j - i;
207
- if (runLength < MIN_FOLD_SIZE) {
208
- for (let k = i; k < j; k++) {
209
- items.push({
210
- kind: "row",
211
- diff: lineDiffs[k],
212
- diffIndex: k
213
- });
214
- }
215
- } else {
216
- const id = foldId++;
217
- const expanded = expandedFolds.has(id);
218
- items.push({
219
- kind: "fold",
220
- foldId: id,
221
- count: runLength,
222
- expanded
223
- });
224
- if (expanded) {
225
- for (let k = i; k < j; k++) {
226
- items.push({
227
- kind: "row",
228
- diff: lineDiffs[k],
229
- diffIndex: k
230
- });
231
- }
232
- }
233
- }
234
- i = j;
235
- }
236
- return items;
237
- }
238
- const FoldHeader = /*#__PURE__*/(0, _react.memo)(function FoldHeader({
239
- foldId,
240
- count,
241
- expanded,
242
- theme,
243
- styles,
244
- onToggle
245
- }) {
246
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
247
- style: [styles.foldHeader, {
248
- backgroundColor: theme.separatorBackground
249
- }],
250
- onPress: () => onToggle(foldId),
251
- activeOpacity: 0.7,
252
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
253
- style: [styles.foldHeaderText, {
254
- color: theme.separatorText
255
- }],
256
- children: expanded ? `▼ ${count} unchanged line${count === 1 ? "" : "s"} — tap to hide` : `▶ ${count} unchanged line${count === 1 ? "" : "s"} — tap to expand`
257
- })
258
- });
259
- });
260
- const DiffRow = /*#__PURE__*/(0, _react.memo)(function DiffRow({
261
- diff,
262
- showSeparator,
263
- theme,
264
- options,
265
- styles
266
- }) {
267
- const isRemoved = diff.type === _lineDiff.DiffType.REMOVED;
268
- const isAdded = diff.type === _lineDiff.DiffType.ADDED;
269
- const isModified = diff.type === _lineDiff.DiffType.MODIFIED;
270
- const isDefault = diff.type === _lineDiff.DiffType.DEFAULT;
271
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, {
272
- children: [showSeparator && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
273
- style: styles.separator,
274
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
275
- style: styles.separatorText,
276
- children: "\u2022 \u2022 \u2022"
277
- })
278
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
279
- style: styles.row,
280
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
281
- style: styles.leftSide,
282
- children: isRemoved || isModified || isDefault ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LineSide, {
283
- lineNumber: diff.leftLineNumber,
284
- content: diff.leftContent,
285
- type: isModified ? _lineDiff.DiffType.REMOVED : diff.type,
286
- marker: isRemoved || isModified ? "-" : " ",
287
- theme: theme,
288
- options: options,
289
- styles: styles
290
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyLineSide, {
291
- options: options,
292
- styles: styles
293
- })
294
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
295
- style: styles.centerDivider
296
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
297
- style: styles.rightSide,
298
- children: isAdded || isModified || isDefault ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LineSide, {
299
- lineNumber: diff.rightLineNumber,
300
- content: diff.rightContent,
301
- type: isModified ? _lineDiff.DiffType.ADDED : diff.type,
302
- marker: isAdded || isModified ? "+" : " ",
303
- theme: theme,
304
- options: options,
305
- styles: styles
306
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyLineSide, {
307
- options: options,
308
- styles: styles
309
- })
310
- })]
311
- })]
312
- });
313
11
  });
314
- function LineSide({
315
- lineNumber,
316
- content,
317
- type,
318
- marker,
319
- theme,
320
- options,
321
- styles
322
- }) {
323
- const colors = getDiffColors(type, theme);
324
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, {
325
- children: [!options.hideLineNumbers && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
326
- style: [styles.gutter, {
327
- backgroundColor: theme.lineNumberBackground
328
- }],
329
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
330
- style: styles.lineNumber,
331
- children: lineNumber || " "
332
- })
333
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
334
- style: [styles.marker, {
335
- backgroundColor: colors.markerBg
336
- }],
337
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
338
- style: [styles.markerText, {
339
- color: theme.markerText
340
- }],
341
- children: marker
342
- })
343
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
344
- style: [styles.contentCell, {
345
- backgroundColor: colors.background
346
- }],
347
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
348
- style: [styles.content, {
349
- color: colors.text
350
- }],
351
- children: Array.isArray(content) ? content.map((word, idx) => {
352
- let backgroundColor = "transparent";
353
- if (word.type === _lineDiff.DiffType.ADDED) {
354
- backgroundColor = theme.addedWordHighlight;
355
- } else if (word.type === _lineDiff.DiffType.REMOVED) {
356
- backgroundColor = theme.removedWordHighlight;
357
- }
358
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
359
- style: [styles.wordDiff, {
360
- backgroundColor
361
- }],
362
- children: word.value
363
- }, idx);
364
- }) : content || " "
365
- })
366
- })]
367
- });
368
- }
369
- function EmptyLineSide({
370
- options,
371
- styles
372
- }) {
373
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, {
374
- children: [!options.hideLineNumbers && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
375
- style: [styles.gutter, styles.emptyGutter],
376
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
377
- style: styles.lineNumber,
378
- children: " "
379
- })
380
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
381
- style: [styles.marker, styles.emptyMarker],
382
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
383
- style: styles.markerText,
384
- children: " "
385
- })
386
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
387
- style: [styles.contentCell, styles.emptyContent],
388
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
389
- style: styles.content,
390
- children: " "
391
- })
392
- })]
393
- });
394
- }
395
- function getDiffColors(type, theme) {
396
- switch (type) {
397
- case _lineDiff.DiffType.ADDED:
398
- return {
399
- background: theme.addedBackground,
400
- text: theme.addedText,
401
- markerBg: theme.markerAddedBackground
402
- };
403
- case _lineDiff.DiffType.REMOVED:
404
- return {
405
- background: theme.removedBackground,
406
- text: theme.removedText,
407
- markerBg: theme.markerRemovedBackground
408
- };
409
- case _lineDiff.DiffType.DEFAULT:
410
- default:
411
- return {
412
- background: theme.unchangedBackground,
413
- text: theme.unchangedText,
414
- markerBg: "transparent"
415
- };
416
- }
417
- }
418
-
419
- // Create dynamic styles based on theme
420
- function createDynamicStyles(theme, scrollEnabled) {
421
- return _reactNative.StyleSheet.create({
422
- container: {
423
- // Fixed pane only when the rows scroll themselves; inline mode sizes to
424
- // content so the page scroll reveals it.
425
- ...(scrollEnabled ? {
426
- height: 400
427
- } : null),
428
- backgroundColor: theme.background,
429
- borderRadius: 8,
430
- overflow: "hidden",
431
- borderWidth: 1,
432
- borderColor: theme.borderColor
433
- },
434
- themeBadge: {
435
- backgroundColor: theme.panelBackground,
436
- paddingHorizontal: 12,
437
- paddingVertical: 8,
438
- borderBottomWidth: 1,
439
- borderBottomColor: theme.borderColor
440
- },
441
- themeName: {
442
- fontSize: 12,
443
- fontWeight: "700",
444
- color: theme.accentColor || theme.unchangedText,
445
- fontFamily: "monospace",
446
- letterSpacing: 0.5
447
- },
448
- themeDescription: {
449
- fontSize: 10,
450
- color: theme.unchangedText,
451
- fontFamily: "monospace",
452
- marginTop: 2,
453
- opacity: 0.8
454
- },
455
- header: {
456
- flexDirection: "row",
457
- backgroundColor: theme.headerBackground,
458
- borderBottomWidth: 1,
459
- borderBottomColor: theme.borderColor
460
- },
461
- headerLeft: {
462
- flex: 1,
463
- paddingVertical: 8,
464
- paddingHorizontal: 12
465
- },
466
- headerRight: {
467
- flex: 1,
468
- paddingVertical: 8,
469
- paddingHorizontal: 12
470
- },
471
- headerTitle: {
472
- fontSize: 10,
473
- fontWeight: "700",
474
- color: theme.accentColor || theme.unchangedText,
475
- fontFamily: "monospace",
476
- letterSpacing: 0.5,
477
- textTransform: "uppercase"
478
- },
479
- divider: {
480
- width: 1,
481
- backgroundColor: theme.dividerColor
482
- },
483
- scrollView: {
484
- flex: 1
485
- },
486
- scrollContent: {
487
- paddingBottom: 10
488
- },
489
- row: {
490
- flexDirection: "row",
491
- minHeight: 20
492
- },
493
- leftSide: {
494
- flex: 1,
495
- flexDirection: "row"
496
- },
497
- rightSide: {
498
- flex: 1,
499
- flexDirection: "row"
500
- },
501
- centerDivider: {
502
- width: 1,
503
- backgroundColor: theme.dividerColor
504
- },
505
- gutter: {
506
- width: 35,
507
- paddingHorizontal: 4,
508
- justifyContent: "center",
509
- alignItems: "flex-end",
510
- backgroundColor: theme.lineNumberBackground,
511
- borderRightWidth: 1,
512
- borderRightColor: theme.lineNumberBorder
513
- },
514
- emptyGutter: {
515
- backgroundColor: theme.contextBackground
516
- },
517
- lineNumber: {
518
- fontSize: 9,
519
- fontFamily: "monospace",
520
- color: theme.lineNumberText
521
- },
522
- marker: {
523
- width: 20,
524
- justifyContent: "center",
525
- alignItems: "center"
526
- },
527
- emptyMarker: {
528
- backgroundColor: theme.contextBackground
529
- },
530
- markerText: {
531
- fontSize: 10,
532
- fontFamily: "monospace",
533
- fontWeight: "600"
534
- },
535
- contentCell: {
536
- flex: 1,
537
- paddingHorizontal: 8,
538
- paddingVertical: 2
539
- },
540
- emptyContent: {
541
- backgroundColor: theme.contextBackground
542
- },
543
- content: {
544
- fontSize: 10,
545
- fontFamily: "monospace",
546
- lineHeight: 16
547
- },
548
- wordDiff: {
549
- fontSize: 10,
550
- fontFamily: "monospace"
551
- },
552
- summaryBar: {
553
- flexDirection: "row",
554
- alignItems: "center",
555
- justifyContent: "center",
556
- gap: 16,
557
- paddingVertical: 6,
558
- backgroundColor: theme.summaryBackground,
559
- borderTopWidth: 1,
560
- borderTopColor: theme.borderColor
561
- },
562
- summaryItem: {
563
- flexDirection: "row",
564
- alignItems: "center"
565
- },
566
- summaryText: {
567
- fontSize: 10,
568
- fontFamily: "monospace",
569
- fontWeight: "700"
570
- },
571
- separator: {
572
- height: 20,
573
- justifyContent: "center",
574
- alignItems: "center",
575
- backgroundColor: theme.separatorBackground
576
- },
577
- separatorText: {
578
- fontSize: 8,
579
- color: theme.separatorText,
580
- fontFamily: "monospace",
581
- letterSpacing: 2
582
- },
583
- foldHeader: {
584
- paddingVertical: 6,
585
- paddingHorizontal: 12,
586
- alignItems: "center",
587
- justifyContent: "center",
588
- borderTopWidth: 1,
589
- borderBottomWidth: 1,
590
- borderColor: theme.borderColor
591
- },
592
- foldHeaderText: {
593
- fontSize: 10,
594
- fontFamily: "monospace",
595
- letterSpacing: 0.5
596
- },
597
- emptyState: {
598
- padding: 40,
599
- alignItems: "center",
600
- justifyContent: "center"
601
- },
602
- emptyText: {
603
- fontSize: 11,
604
- color: theme.emptyStateText,
605
- fontStyle: "italic",
606
- fontFamily: "monospace"
607
- }
608
- });
609
- }
12
+ var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
@@ -34,7 +34,8 @@ function StorageModalWithTabs({
34
34
  requiredStorageKeys = [],
35
35
  inline = false,
36
36
  onTabChange,
37
- onRefresh
37
+ onRefresh,
38
+ onEventSelect
38
39
  }) {
39
40
  const isPro = (0, _license.useIsPro)();
40
41
  const [activeTab, setActiveTab] = (0, _react.useState)("browser");
@@ -462,6 +463,21 @@ function StorageModalWithTabs({
462
463
  return conversations.find(c => c.key === selectedHistoryKey) || null;
463
464
  }, [selectedHistoryKey, conversations]);
464
465
 
466
+ // Wire-form snapshots omit oversized values. Tell a remote host which
467
+ // event(s) are on screen so it can fetch them — selected + previous, because
468
+ // the detail pane diffs those two.
469
+ (0, _react.useEffect)(() => {
470
+ if (!onEventSelect) return;
471
+ const conversation = selectedConversation ? selectedConversation : selectedHistoryEventIndex !== null ? selectedHistoryConversation : null;
472
+ const index = selectedConversation ? selectedEventIndex : selectedHistoryEventIndex;
473
+ if (!conversation || index == null) return;
474
+ const sorted = [...conversation.events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
475
+ const selected = sorted[index];
476
+ const previous = sorted[index - 1];
477
+ if (selected) onEventSelect(selected);
478
+ if (previous) onEventSelect(previous);
479
+ }, [onEventSelect, selectedConversation, selectedEventIndex, selectedHistoryConversation, selectedHistoryEventIndex]);
480
+
465
481
  /**
466
482
  * Events passing everything EXCEPT the backend pills.
467
483
  *