@buoy-gg/react-query 7.0.33 → 7.0.35

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 (49) hide show
  1. package/lib/commonjs/react-query/components/DataEditorMode.js +2 -2
  2. package/lib/commonjs/react-query/components/FilterStatusBadge.js +1 -1
  3. package/lib/commonjs/react-query/components/MutationEditorMode.js +2 -2
  4. package/lib/commonjs/react-query/components/modals/MutationBrowserFooter.js +7 -19
  5. package/lib/commonjs/react-query/components/modals/QueryBrowserFooter.js +7 -19
  6. package/lib/commonjs/react-query/components/modals/ReactQueryModalHeader.js +23 -71
  7. package/lib/commonjs/react-query/components/query-browser/MutationButton.js +2 -2
  8. package/lib/commonjs/react-query/components/query-browser/MutationDetails.js +4 -4
  9. package/lib/commonjs/react-query/components/query-browser/MutationDetailsChips.js +1 -1
  10. package/lib/commonjs/react-query/components/query-browser/MutationInformation.js +1 -1
  11. package/lib/commonjs/react-query/components/query-browser/MutationStatusCount.js +51 -87
  12. package/lib/commonjs/react-query/components/query-browser/MutationsList.js +1 -1
  13. package/lib/commonjs/react-query/components/query-browser/QueryBrowser.js +3 -12
  14. package/lib/commonjs/react-query/components/query-browser/QueryDetails.js +4 -4
  15. package/lib/commonjs/react-query/components/query-browser/QueryDetailsChip.js +1 -1
  16. package/lib/commonjs/react-query/components/query-browser/QueryStatusCount.js +66 -112
  17. package/lib/commonjs/react-query/components/query-browser/StorageStatusCount.js +22 -67
  18. package/lib/commonjs/react-query/stores/reactQueryEventStore.js +13 -22
  19. package/lib/commonjs/react-query/sync/snapshotProvider.js +17 -62
  20. package/lib/module/react-query/components/DataEditorMode.js +3 -3
  21. package/lib/module/react-query/components/FilterStatusBadge.js +2 -2
  22. package/lib/module/react-query/components/MutationEditorMode.js +3 -3
  23. package/lib/module/react-query/components/modals/MutationBrowserFooter.js +8 -20
  24. package/lib/module/react-query/components/modals/QueryBrowserFooter.js +8 -20
  25. package/lib/module/react-query/components/modals/ReactQueryModalHeader.js +25 -73
  26. package/lib/module/react-query/components/query-browser/MutationButton.js +3 -3
  27. package/lib/module/react-query/components/query-browser/MutationDetails.js +5 -5
  28. package/lib/module/react-query/components/query-browser/MutationDetailsChips.js +2 -2
  29. package/lib/module/react-query/components/query-browser/MutationInformation.js +2 -2
  30. package/lib/module/react-query/components/query-browser/MutationStatusCount.js +51 -87
  31. package/lib/module/react-query/components/query-browser/MutationsList.js +2 -2
  32. package/lib/module/react-query/components/query-browser/QueryBrowser.js +4 -13
  33. package/lib/module/react-query/components/query-browser/QueryDetails.js +5 -5
  34. package/lib/module/react-query/components/query-browser/QueryDetailsChip.js +2 -2
  35. package/lib/module/react-query/components/query-browser/QueryStatusCount.js +66 -112
  36. package/lib/module/react-query/components/query-browser/StorageStatusCount.js +22 -67
  37. package/lib/module/react-query/stores/reactQueryEventStore.js +13 -22
  38. package/lib/module/react-query/sync/snapshotProvider.js +18 -63
  39. package/lib/typescript/react-query/components/modals/MutationBrowserFooter.d.ts.map +1 -1
  40. package/lib/typescript/react-query/components/modals/QueryBrowserFooter.d.ts.map +1 -1
  41. package/lib/typescript/react-query/components/modals/ReactQueryModalHeader.d.ts.map +1 -1
  42. package/lib/typescript/react-query/components/query-browser/MutationStatusCount.d.ts.map +1 -1
  43. package/lib/typescript/react-query/components/query-browser/QueryBrowser.d.ts.map +1 -1
  44. package/lib/typescript/react-query/components/query-browser/QueryStatusCount.d.ts.map +1 -1
  45. package/lib/typescript/react-query/components/query-browser/StorageStatusCount.d.ts.map +1 -1
  46. package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts +3 -8
  47. package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts.map +1 -1
  48. package/lib/typescript/react-query/sync/snapshotProvider.d.ts.map +1 -1
  49. package/package.json +3 -3
@@ -4,8 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = require("react");
8
- var _reactNative = require("react-native");
7
+ var _sharedUi = require("@buoy-gg/shared-ui");
9
8
  var _QueryStatus = _interopRequireDefault(require("./QueryStatus"));
10
9
  var _useQueryStatusCounts = _interopRequireDefault(require("../../hooks/useQueryStatusCounts"));
11
10
  var _jsxRuntime = require("react/jsx-runtime");
@@ -25,122 +24,77 @@ const QueryStatusCount = ({
25
24
  paused,
26
25
  inactive
27
26
  } = (0, _useQueryStatusCounts.default)();
28
-
29
- // Scroll state management like ChipTabs
30
- const [isScrolling, setIsScrolling] = (0, _react.useState)(false);
31
- const touchStartX = (0, _react.useRef)(0);
32
- const touchStartY = (0, _react.useRef)(0);
27
+ const {
28
+ scrollProps,
29
+ onTouchStart: handleTouchStart,
30
+ isTap
31
+ } = (0, _sharedUi.useChipTap)();
33
32
  const handleFilterClick = (filter, event) => {
34
- if (event) {
35
- // Calculate distance moved during touch (like ChipTabs)
36
- const dx = Math.abs(event.nativeEvent.pageX - touchStartX.current);
37
- const dy = Math.abs(event.nativeEvent.pageY - touchStartY.current);
38
-
39
- // If touch moved more than 5px in any direction, it's a swipe, not a tap
40
- if (dx > 5 || dy > 5 || isScrolling) {
41
- return; // Don't trigger filter change
42
- }
43
- }
33
+ if (!isTap(event)) return;
44
34
  if (onFilterChange) {
45
35
  // Toggle filter: if already active, clear it; otherwise set it
46
36
  onFilterChange(activeFilter === filter ? null : filter);
47
37
  }
48
38
  };
49
- const handleTouchStart = event => {
50
- touchStartX.current = event.nativeEvent.pageX;
51
- touchStartY.current = event.nativeEvent.pageY;
52
- };
53
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
54
- style: styles.queryStatusContainer,
55
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
56
- "sentry-label": "ignore devtools query status count scroll",
57
- horizontal: true,
58
- showsHorizontalScrollIndicator: false,
59
- style: styles.scrollView,
60
- contentContainerStyle: styles.scrollContent,
61
- onScrollBeginDrag: () => setIsScrolling(true),
62
- onScrollEndDrag: () => setTimeout(() => setIsScrolling(false), 300),
63
- onMomentumScrollBegin: () => setIsScrolling(true),
64
- onMomentumScrollEnd: () => setTimeout(() => setIsScrolling(false), 300),
65
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
66
- label: "Fresh",
67
- color: "green",
68
- count: fresh,
69
- isActive: activeFilter === "fresh",
70
- onPress: event => handleFilterClick("fresh", event),
71
- onTouchStart: handleTouchStart,
72
- testID: "buoy-rq-status-fresh",
73
- showLabel: true // Always show labels now
74
- ,
75
- size: size
76
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
77
- label: "Loading",
78
- color: "blue",
79
- count: fetching,
80
- isActive: activeFilter === "fetching",
81
- onPress: event => handleFilterClick("fetching", event),
82
- onTouchStart: handleTouchStart,
83
- testID: "buoy-rq-status-fetching",
84
- showLabel: true // Always show labels now
85
- ,
86
- size: size
87
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
88
- label: "Paused",
89
- color: "purple",
90
- count: paused,
91
- isActive: activeFilter === "paused",
92
- onPress: event => handleFilterClick("paused", event),
93
- onTouchStart: handleTouchStart,
94
- testID: "buoy-rq-status-paused",
95
- showLabel: true // Always show labels now
96
- ,
97
- size: size
98
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
99
- label: "Stale",
100
- color: "yellow",
101
- count: stale,
102
- isActive: activeFilter === "stale",
103
- onPress: event => handleFilterClick("stale", event),
104
- onTouchStart: handleTouchStart,
105
- testID: "buoy-rq-status-stale",
106
- showLabel: true // Always show labels now
107
- ,
108
- size: size
109
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
110
- label: "Idle",
111
- color: "gray",
112
- count: inactive,
113
- isActive: activeFilter === "inactive",
114
- onPress: event => handleFilterClick("inactive", event),
115
- onTouchStart: handleTouchStart,
116
- testID: "buoy-rq-status-inactive",
117
- showLabel: true // Always show labels now
118
- ,
119
- size: size
120
- })]
121
- })
39
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ChipStrip, {
40
+ scrollProps: scrollProps,
41
+ sentryLabel: "ignore devtools query status count scroll",
42
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
43
+ label: "Fresh",
44
+ color: "green",
45
+ count: fresh,
46
+ isActive: activeFilter === "fresh",
47
+ onPress: event => handleFilterClick("fresh", event),
48
+ onTouchStart: handleTouchStart,
49
+ testID: "buoy-rq-status-fresh",
50
+ showLabel: true // Always show labels now
51
+ ,
52
+ size: size
53
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
54
+ label: "Loading",
55
+ color: "blue",
56
+ count: fetching,
57
+ isActive: activeFilter === "fetching",
58
+ onPress: event => handleFilterClick("fetching", event),
59
+ onTouchStart: handleTouchStart,
60
+ testID: "buoy-rq-status-fetching",
61
+ showLabel: true // Always show labels now
62
+ ,
63
+ size: size
64
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
65
+ label: "Paused",
66
+ color: "purple",
67
+ count: paused,
68
+ isActive: activeFilter === "paused",
69
+ onPress: event => handleFilterClick("paused", event),
70
+ onTouchStart: handleTouchStart,
71
+ testID: "buoy-rq-status-paused",
72
+ showLabel: true // Always show labels now
73
+ ,
74
+ size: size
75
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
76
+ label: "Stale",
77
+ color: "yellow",
78
+ count: stale,
79
+ isActive: activeFilter === "stale",
80
+ onPress: event => handleFilterClick("stale", event),
81
+ onTouchStart: handleTouchStart,
82
+ testID: "buoy-rq-status-stale",
83
+ showLabel: true // Always show labels now
84
+ ,
85
+ size: size
86
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
87
+ label: "Idle",
88
+ color: "gray",
89
+ count: inactive,
90
+ isActive: activeFilter === "inactive",
91
+ onPress: event => handleFilterClick("inactive", event),
92
+ onTouchStart: handleTouchStart,
93
+ testID: "buoy-rq-status-inactive",
94
+ showLabel: true // Always show labels now
95
+ ,
96
+ size: size
97
+ })]
122
98
  });
123
99
  };
124
- const styles = _reactNative.StyleSheet.create({
125
- queryStatusContainer: {
126
- // Container for ScrollView - take full width
127
- flex: 1,
128
- minWidth: 0
129
- },
130
- scrollView: {
131
- // ScrollView itself styles
132
- flex: 1
133
- },
134
- scrollContent: {
135
- // ScrollView content styles
136
- flexDirection: "row",
137
- alignItems: "center",
138
- gap: 8,
139
- // Spacing between chips
140
- paddingHorizontal: 4,
141
- // Small padding on ends
142
- paddingVertical: 4,
143
- flexGrow: 1 // Allow content to grow to fill available space
144
- }
145
- });
146
100
  var _default = exports.default = QueryStatusCount;
@@ -4,8 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = require("react");
8
- var _reactNative = require("react-native");
7
+ var _sharedUi = require("@buoy-gg/shared-ui");
9
8
  var _QueryStatus = _interopRequireDefault(require("./QueryStatus"));
10
9
  var _storageQueryUtils = require("../../utils/storageQueryUtils");
11
10
  var _jsxRuntime = require("react/jsx-runtime");
@@ -24,21 +23,13 @@ const StorageStatusCount = ({
24
23
  onStorageTypesChange,
25
24
  counts
26
25
  }) => {
27
- // Scroll state management like QueryStatusCount
28
- const [isScrolling, setIsScrolling] = (0, _react.useState)(false);
29
- const touchStartX = (0, _react.useRef)(0);
30
- const touchStartY = (0, _react.useRef)(0);
26
+ const {
27
+ scrollProps,
28
+ onTouchStart: handleTouchStart,
29
+ isTap
30
+ } = (0, _sharedUi.useChipTap)();
31
31
  const handleStorageTypeToggle = (storageType, event) => {
32
- if (event) {
33
- // Calculate distance moved during touch (like QueryStatusCount)
34
- const dx = Math.abs(event.nativeEvent.pageX - touchStartX.current);
35
- const dy = Math.abs(event.nativeEvent.pageY - touchStartY.current);
36
-
37
- // If touch moved more than 5px in any direction, it's a swipe, not a tap
38
- if (dx > 5 || dy > 5 || isScrolling) {
39
- return; // Don't trigger filter change
40
- }
41
- }
32
+ if (!isTap(event)) return;
42
33
  if (onStorageTypesChange) {
43
34
  const newStorageTypes = new Set(activeStorageTypes);
44
35
  if (newStorageTypes.has(storageType)) {
@@ -49,58 +40,22 @@ const StorageStatusCount = ({
49
40
  onStorageTypesChange(newStorageTypes);
50
41
  }
51
42
  };
52
- const handleTouchStart = event => {
53
- touchStartX.current = event.nativeEvent.pageX;
54
- touchStartY.current = event.nativeEvent.pageY;
55
- };
56
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
57
- style: styles.storageStatusContainer,
58
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
59
- "sentry-label": "ignore devtools storage status count scroll",
60
- horizontal: true,
61
- showsHorizontalScrollIndicator: false,
62
- style: styles.scrollView,
63
- contentContainerStyle: styles.scrollContent,
64
- onScrollBeginDrag: () => setIsScrolling(true),
65
- onScrollEndDrag: () => setTimeout(() => setIsScrolling(false), 300),
66
- onMomentumScrollBegin: () => setIsScrolling(true),
67
- onMomentumScrollEnd: () => setTimeout(() => setIsScrolling(false), 300),
68
- children: allStorageTypes.map(storageType => {
69
- const count = counts?.[storageType] ?? 0;
70
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
71
- label: (0, _storageQueryUtils.getStorageTypeLabel)(storageType),
72
- color: (0, _storageQueryUtils.getStorageTypeColor)(storageType),
73
- count: count // Show actual storage query counts
74
- ,
75
- isActive: activeStorageTypes.has(storageType),
76
- onPress: event => handleStorageTypeToggle(storageType, event),
77
- onTouchStart: handleTouchStart,
78
- showLabel: true
79
- }, storageType);
80
- })
43
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChipStrip, {
44
+ scrollProps: scrollProps,
45
+ sentryLabel: "ignore devtools storage status count scroll",
46
+ children: allStorageTypes.map(storageType => {
47
+ const count = counts?.[storageType] ?? 0;
48
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_QueryStatus.default, {
49
+ label: (0, _storageQueryUtils.getStorageTypeLabel)(storageType),
50
+ color: (0, _storageQueryUtils.getStorageTypeColor)(storageType),
51
+ count: count // Show actual storage query counts
52
+ ,
53
+ isActive: activeStorageTypes.has(storageType),
54
+ onPress: event => handleStorageTypeToggle(storageType, event),
55
+ onTouchStart: handleTouchStart,
56
+ showLabel: true
57
+ }, storageType);
81
58
  })
82
59
  });
83
60
  };
84
- const styles = _reactNative.StyleSheet.create({
85
- storageStatusContainer: {
86
- // Container for ScrollView - take full width
87
- flex: 1,
88
- minWidth: 0
89
- },
90
- scrollView: {
91
- // ScrollView itself styles
92
- flex: 1
93
- },
94
- scrollContent: {
95
- // ScrollView content styles
96
- flexDirection: "row",
97
- alignItems: "center",
98
- gap: 8,
99
- // Spacing between chips
100
- paddingHorizontal: 4,
101
- // Small padding on ends
102
- paddingVertical: 4,
103
- flexGrow: 1 // Allow content to grow to fill available space
104
- }
105
- });
106
61
  var _default = exports.default = StorageStatusCount;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.subscribeToReactQueryEvents = exports.setQueryClient = exports.reactQueryEventStore = exports.isReactQueryConnected = exports.getReactQueryEvents = exports.disconnectQueryClient = exports.clearReactQueryEvents = void 0;
7
+ var _sharedUi = require("@buoy-gg/shared-ui");
7
8
  var _storageQueryUtils = require("../utils/storageQueryUtils");
8
9
  /**
9
10
  * React Query Event Store
@@ -29,13 +30,15 @@ let eventIdCounter = 0;
29
30
  function generateEventId() {
30
31
  return `rq-${Date.now()}-${++eventIdCounter}`;
31
32
  }
32
- class ReactQueryEventStore {
33
- events = [];
34
- listeners = new Set();
33
+ class ReactQueryEventStore extends _sharedUi.ChangeLog {
35
34
  queryClient = null;
36
35
  queryUnsubscribe = null;
37
36
  mutationUnsubscribe = null;
38
- maxEvents = 200;
37
+ constructor() {
38
+ super({
39
+ max: 200
40
+ });
41
+ }
39
42
 
40
43
  // Track fetch start times for duration calculation
41
44
  fetchStartTimes = new Map();
@@ -246,43 +249,31 @@ class ReactQueryEventStore {
246
249
  * Add an event to the store
247
250
  */
248
251
  addEvent(event) {
249
- this.events = [event, ...this.events].slice(0, this.maxEvents);
250
- this.notifyListeners();
252
+ this.record(event);
251
253
  }
252
254
 
253
255
  /**
254
256
  * Get all events
255
257
  */
256
258
  getEvents() {
257
- return this.events;
259
+ return this.items;
258
260
  }
259
261
 
260
262
  /**
261
263
  * Subscribe to event changes
262
264
  */
263
265
  subscribe(listener) {
264
- this.listeners.add(listener);
266
+ const unsubscribe = super.subscribe(listener);
265
267
  // Immediately call with current events
266
- listener(this.events);
267
- return () => {
268
- this.listeners.delete(listener);
269
- };
270
- }
271
-
272
- /**
273
- * Notify all listeners
274
- */
275
- notifyListeners() {
276
- const events = this.events;
277
- this.listeners.forEach(listener => listener(events));
268
+ listener(this.items);
269
+ return unsubscribe;
278
270
  }
279
271
 
280
272
  /**
281
273
  * Clear all events
282
274
  */
283
275
  clearEvents() {
284
- this.events = [];
285
- this.notifyListeners();
276
+ this.clear();
286
277
  }
287
278
 
288
279
  /**
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.createQuerySnapshotProvider = createQuerySnapshotProvider;
7
7
  exports.registerQuerySnapshotProvider = registerQuerySnapshotProvider;
8
8
  var _sharedUi = require("@buoy-gg/shared-ui");
9
- var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
10
9
  var _dehydrate = require("./dehydrate");
11
10
  /**
12
11
  * Time Machine snapshot provider for React Query.
@@ -54,7 +53,6 @@ function queryLabel(queryKey, queryHash) {
54
53
  return queryHash;
55
54
  }
56
55
  }
57
- const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
58
56
 
59
57
  /**
60
58
  * A query `error` (and `fetchFailureReason`) usually holds the live
@@ -156,31 +154,15 @@ function createQuerySnapshotProvider(queryClient) {
156
154
  },
157
155
  async restore(data, options) {
158
156
  const snapshot = data;
159
- const excludedSet = new Set(options?.excludeKeys ?? []);
160
- const includedSet = options?.includeKeys ? new Set(options.includeKeys) : null;
161
- const touch = key => !excludedSet.has(key) && (!includedSet || includedSet.has(key));
162
- let excludedHits = 0;
163
- const result = {
164
- ok: true,
165
- applied: 0,
166
- skipped: [],
167
- warnings: []
168
- };
157
+ const scope = (0, _sharedUi.createRestoreScope)(options);
158
+ const result = (0, _sharedUi.emptyRestoreResult)();
169
159
  if (!snapshot?.queries) {
170
- return {
171
- ok: false,
172
- applied: 0,
173
- skipped: [],
174
- warnings: ["empty query snapshot"]
175
- };
160
+ return (0, _sharedUi.failedRestore)("empty query snapshot");
176
161
  }
177
162
  const cache = queryClient.getQueryCache();
178
163
  const snapHashes = new Set(snapshot.queries.map(q => q.queryHash));
179
164
  for (const snap of snapshot.queries) {
180
- if (!touch(snap.queryHash)) {
181
- excludedHits += 1;
182
- continue;
183
- }
165
+ if (!scope.allows(snap.queryHash)) continue;
184
166
  // Snapshots taken before the raw-capture fix hold a wire placeholder
185
167
  // instead of the data. Writing that into the cache hands the app an
186
168
  // object with none of its fields — leave the live query alone and say
@@ -221,10 +203,7 @@ function createQuerySnapshotProvider(queryClient) {
221
203
  // Cache entries the snapshot doesn't know about get removed; a mounted
222
204
  // observer will rebuild + refetch its query on next interaction.
223
205
  for (const query of cache.getAll().slice()) {
224
- if (!touch(query.queryHash)) {
225
- excludedHits += 1;
226
- continue;
227
- }
206
+ if (!scope.allows(query.queryHash)) continue;
228
207
  if (!snapHashes.has(query.queryHash)) {
229
208
  try {
230
209
  cache.remove(query);
@@ -242,9 +221,8 @@ function createQuerySnapshotProvider(queryClient) {
242
221
  queryClient.getMutationCache().clear();
243
222
  result.warnings.push(`mutation cache cleared (${mutationCount} mutation(s))`);
244
223
  }
245
- if (excludedHits > 0) {
246
- result.warnings.push(`${excludedHits} quer(y/ies) excluded by you`);
247
- }
224
+ const excludedWarning = scope.excludedWarning("quer(y/ies)");
225
+ if (excludedWarning) result.warnings.push(excludedWarning);
248
226
  return result;
249
227
  },
250
228
  /** Per-query restore preview. `base` omitted = compare against live cache. */
@@ -270,39 +248,16 @@ function createQuerySnapshotProvider(queryClient) {
270
248
  continue;
271
249
  }
272
250
  const baseQ = baseByHash.get(q.queryHash);
273
- if (!baseQ) {
274
- items.push({
275
- key: q.queryHash,
276
- label,
277
- verdict: "added",
278
- newValue: comparableQuery(q)
279
- });
280
- continue;
281
- }
282
- const oldVal = comparableQuery(baseQ);
283
- const newVal = comparableQuery(q);
284
- if ((0, _dataViewer.boundedDeepEqual)(oldVal, newVal)) {
285
- items.push({
286
- key: q.queryHash,
287
- label,
288
- verdict: "unchanged"
289
- });
290
- } else if ((0, _dataViewer.jsonLikelyLargerThan)(oldVal, ITEM_RENDER_BYTE_LIMIT) || (0, _dataViewer.jsonLikelyLargerThan)(newVal, ITEM_RENDER_BYTE_LIMIT)) {
291
- items.push({
292
- key: q.queryHash,
293
- label,
294
- verdict: "too-large",
295
- reason: "query data too large to render a diff — restore still applies it"
296
- });
297
- } else {
298
- items.push({
299
- key: q.queryHash,
300
- label,
301
- verdict: "changed",
302
- oldValue: oldVal,
303
- newValue: newVal
304
- });
305
- }
251
+ items.push((0, _sharedUi.classifyPreviewItem)({
252
+ key: q.queryHash,
253
+ label,
254
+ oldValue: baseQ ? comparableQuery(baseQ) : undefined,
255
+ newValue: comparableQuery(q),
256
+ inOld: baseQ !== undefined,
257
+ inNew: true
258
+ }, {
259
+ tooLargeReason: "query data too large to render a diff — restore still applies it"
260
+ }));
306
261
  }
307
262
  for (const q of baseQueries) {
308
263
  if (!targetByHash.has(q.queryHash)) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { View, Text, StyleSheet, ScrollView } from "react-native";
4
4
  import { useQueryClient } from "@tanstack/react-query";
5
- import { useSafeAreaInsets, night } from "@buoy-gg/shared-ui";
5
+ import { useSafeAreaInsets, night, monoFont } from "@buoy-gg/shared-ui";
6
6
  import Explorer from "./query-browser/Explorer";
7
7
  import QueryDetails from "./query-browser/QueryDetails";
8
8
  import ActionButton from "./query-browser/ActionButton";
@@ -270,7 +270,7 @@ const styles = StyleSheet.create({
270
270
  borderBottomColor: night.color.accent + "33",
271
271
  letterSpacing: 0.5,
272
272
  textTransform: "uppercase",
273
- fontFamily: "monospace"
273
+ fontFamily: monoFont
274
274
  },
275
275
  queryExplorerContent: {
276
276
  padding: 8
@@ -303,7 +303,7 @@ const styles = StyleSheet.create({
303
303
  borderBottomColor: night.color.accent + "33",
304
304
  letterSpacing: 0.5,
305
305
  textTransform: "uppercase",
306
- fontFamily: "monospace"
306
+ fontFamily: monoFont
307
307
  },
308
308
  dataContent: {
309
309
  padding: 8
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
4
- import { night } from "@buoy-gg/shared-ui";
4
+ import { night, monoFont } from "@buoy-gg/shared-ui";
5
5
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
6
6
  /**
7
7
  * Compact badge showing filter status (e.g., "Showing 5 of 12")
@@ -46,6 +46,6 @@ const styles = StyleSheet.create({
46
46
  text: {
47
47
  fontSize: 9,
48
48
  color: night.color.textTertiary,
49
- fontFamily: "monospace"
49
+ fontFamily: monoFont
50
50
  }
51
51
  });
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import { View, Text, StyleSheet, ScrollView } from "react-native";
4
- import { useSafeAreaInsets, night } from "@buoy-gg/shared-ui";
4
+ import { useSafeAreaInsets, night, monoFont } from "@buoy-gg/shared-ui";
5
5
  import Explorer from "./query-browser/Explorer";
6
6
  import MutationDetails from "./query-browser/MutationDetails";
7
7
  import ActionButton from "./query-browser/ActionButton";
@@ -230,7 +230,7 @@ const styles = StyleSheet.create({
230
230
  borderBottomColor: night.color.accent + "33",
231
231
  letterSpacing: 0.5,
232
232
  textTransform: "uppercase",
233
- fontFamily: "monospace"
233
+ fontFamily: monoFont
234
234
  },
235
235
  mutationExplorerContent: {
236
236
  padding: 8
@@ -262,7 +262,7 @@ const styles = StyleSheet.create({
262
262
  borderBottomColor: night.color.accent + "33",
263
263
  letterSpacing: 0.5,
264
264
  textTransform: "uppercase",
265
- fontFamily: "monospace"
265
+ fontFamily: monoFont
266
266
  },
267
267
  dataContent: {
268
268
  padding: 8
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import { View, StyleSheet } from "react-native";
4
- import { useSafeAreaInsets, night } from "@buoy-gg/shared-ui";
4
+ import { ToolFooter, useSafeAreaInsets } from "@buoy-gg/shared-ui";
5
5
  import MutationStatusCount from "../query-browser/MutationStatusCount";
6
6
  import { useMemo } from "react";
7
7
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -28,13 +28,12 @@ export function MutationBrowserFooter({
28
28
  const paddingBottom = useMemo(() => {
29
29
  return !isFloatingMode ? insets.bottom : 0;
30
30
  }, [isFloatingMode, insets.bottom]);
31
- return /*#__PURE__*/_jsx(View, {
31
+ return /*#__PURE__*/_jsx(ToolFooter, {
32
32
  // Force re-render with key change
33
- style: [styles.filterFooter, {
34
- paddingBottom
35
- },
36
- // Remove border radius when docked to bottom
37
- !isFloatingMode && styles.dockedFooter],
33
+ floating: isFloatingMode,
34
+ safeArea: false,
35
+ paddingBottom: paddingBottom,
36
+ style: styles.filterFooter,
38
37
  children: /*#__PURE__*/_jsx(View, {
39
38
  style: styles.filterContainer,
40
39
  children: /*#__PURE__*/_jsx(MutationStatusCount, {
@@ -47,19 +46,8 @@ export function MutationBrowserFooter({
47
46
  }
48
47
  const styles = StyleSheet.create({
49
48
  filterFooter: {
50
- borderTopWidth: 1,
51
- borderTopColor: night.color.border,
52
- paddingVertical: 8,
53
- paddingHorizontal: 0,
54
- // Transparent so the night sheet's star field shows through.
55
- // Night glass bar — matches the shared EventStepperFooter backing.
56
- backgroundColor: "rgba(5, 5, 5, 0.92)",
57
- borderBottomLeftRadius: 14,
58
- borderBottomRightRadius: 14
59
- },
60
- dockedFooter: {
61
- borderBottomLeftRadius: 0,
62
- borderBottomRightRadius: 0
49
+ paddingTop: 8,
50
+ paddingHorizontal: 0
63
51
  },
64
52
  filterContainer: {
65
53
  minHeight: 32,