@buoy-gg/redux 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 (40) hide show
  1. package/lib/commonjs/preset.js +14 -22
  2. package/lib/commonjs/redux/components/ReduxActionButton.js +1 -1
  3. package/lib/commonjs/redux/components/ReduxActionDetailContent.js +5 -5
  4. package/lib/commonjs/redux/components/ReduxActionDetailView.js +3 -3
  5. package/lib/commonjs/redux/components/ReduxActionInfoView.js +16 -68
  6. package/lib/commonjs/redux/components/ReduxActionItem.js +65 -119
  7. package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +15 -109
  8. package/lib/commonjs/redux/components/ReduxModal.js +25 -70
  9. package/lib/commonjs/redux/hooks/useReduxActions.js +16 -33
  10. package/lib/commonjs/redux/sync/reduxSyncAdapter.js +11 -29
  11. package/lib/commonjs/redux/utils/reduxActionStore.js +24 -94
  12. package/lib/commonjs/redux/utils/snapshotProvider.js +17 -80
  13. package/lib/module/preset.js +13 -20
  14. package/lib/module/redux/components/ReduxActionButton.js +2 -2
  15. package/lib/module/redux/components/ReduxActionDetailContent.js +6 -6
  16. package/lib/module/redux/components/ReduxActionDetailView.js +4 -4
  17. package/lib/module/redux/components/ReduxActionInfoView.js +9 -61
  18. package/lib/module/redux/components/ReduxActionItem.js +66 -120
  19. package/lib/module/redux/components/ReduxDetailViewToggle.js +17 -111
  20. package/lib/module/redux/components/ReduxModal.js +27 -72
  21. package/lib/module/redux/hooks/useReduxActions.js +17 -34
  22. package/lib/module/redux/sync/reduxSyncAdapter.js +12 -30
  23. package/lib/module/redux/utils/reduxActionStore.js +25 -95
  24. package/lib/module/redux/utils/snapshotProvider.js +18 -81
  25. package/lib/typescript/preset.d.ts +3 -9
  26. package/lib/typescript/preset.d.ts.map +1 -1
  27. package/lib/typescript/redux/components/ReduxActionDetailContent.d.ts.map +1 -1
  28. package/lib/typescript/redux/components/ReduxActionDetailView.d.ts.map +1 -1
  29. package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +1 -1
  30. package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +1 -1
  31. package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts +2 -1
  32. package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +1 -1
  33. package/lib/typescript/redux/components/ReduxModal.d.ts.map +1 -1
  34. package/lib/typescript/redux/hooks/useReduxActions.d.ts +3 -0
  35. package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +1 -1
  36. package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts +68 -82
  37. package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts.map +1 -1
  38. package/lib/typescript/redux/utils/reduxActionStore.d.ts +2 -29
  39. package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +1 -1
  40. package/package.json +4 -4
@@ -238,16 +238,9 @@ function extractMeta(action) {
238
238
  // Redux Action Store
239
239
  // ============================================
240
240
 
241
- class ReduxActionStore {
242
- actions = [];
243
- listeners = new Set();
244
- clearListeners = new Set();
245
- maxActions = 200;
246
- idCounter = 0;
247
- isEnabled = true;
248
- captureSuppressed = false;
241
+ class ReduxActionStore extends _sharedUi.ChangeLog {
249
242
  addAction(action, prevState, nextState, duration) {
250
- if (!this.isEnabled || this.captureSuppressed) {
243
+ if (!this.canRecord()) {
251
244
  return;
252
245
  }
253
246
  const actionType = action.type || "";
@@ -273,7 +266,7 @@ class ReduxActionStore {
273
266
  const isSlowAction = (duration ?? 0) > 16; // Frame budget
274
267
 
275
268
  const reduxAction = {
276
- id: `${Date.now()}-${++this.idCounter}`,
269
+ id: this.nextId(),
277
270
  type: actionType,
278
271
  payload: action.payload,
279
272
  action,
@@ -293,7 +286,7 @@ class ReduxActionStore {
293
286
  changedKeysCount,
294
287
  isSlowAction
295
288
  };
296
- this.actions = [reduxAction, ...this.actions].slice(0, this.maxActions);
289
+ this.push(reduxAction);
297
290
 
298
291
  // Bound raw-state retention. Every action holds prevState/nextState by
299
292
  // reference; with structural sharing that's normally cheap, but when a
@@ -302,8 +295,8 @@ class ReduxActionStore {
302
295
  // pinned by 50 slice-replacing actions, enough to OOM-kill enterprise
303
296
  // apps. Detail view + time travel realistically use recent actions, so
304
297
  // older ones keep their diff metadata but drop the raw trees.
305
- for (let i = STATE_RETENTION_LIMIT; i < this.actions.length; i++) {
306
- const a = this.actions[i];
298
+ for (let i = STATE_RETENTION_LIMIT; i < this.items.length; i++) {
299
+ const a = this.items[i];
307
300
  if (a.prevState !== STATE_EVICTED) {
308
301
  a.prevState = STATE_EVICTED;
309
302
  a.nextState = STATE_EVICTED;
@@ -314,63 +307,26 @@ class ReduxActionStore {
314
307
  this.notifyListeners();
315
308
  }
316
309
  getActions() {
317
- return [...this.actions];
310
+ return this.getAll();
318
311
  }
319
312
  getActionById(id) {
320
- return this.actions.find(a => a.id === id);
313
+ return this.getById(id);
321
314
  }
322
315
  clearActions() {
323
- this.actions = [];
324
- this.notifyListeners();
325
- this.clearListeners.forEach(listener => {
326
- try {
327
- listener();
328
- } catch {
329
- // Ignore listener errors
330
- }
331
- });
332
- }
333
-
334
- /**
335
- * Listen for clearActions() calls. Used in remote mirror mode to forward a
336
- * clear performed in the dashboard UI to the synced device.
337
- */
338
- onClear(listener) {
339
- this.clearListeners.add(listener);
340
- return () => {
341
- this.clearListeners.delete(listener);
342
- };
316
+ this.clear();
343
317
  }
344
318
 
345
319
  // ============================================
346
320
  // Remote Mirror Mode
347
321
  // ============================================
348
322
 
349
- /**
350
- * Permanently suppress local capture. Use when this store acts as a mirror
351
- * of a remote device's actions (e.g. the desktop dashboard): actions arrive
352
- * via replaceActions() and local instrumentation must never record.
353
- */
354
- disableCapture() {
355
- this.captureSuppressed = true;
356
- }
357
-
358
- /**
359
- * Whether the store is in remote mirror mode (capture suppressed). The UI
360
- * uses this to skip local-instrumentation affordances like the
361
- * "react-redux not installed" banner.
362
- */
363
- isCaptureSuppressed() {
364
- return this.captureSuppressed;
365
- }
366
-
367
323
  /**
368
324
  * Replace the entire action list and notify listeners. Used in remote
369
325
  * mirror mode where full snapshots arrive from a synced device. Respects
370
326
  * the enabled flag so the UI's pause button freezes the mirror.
371
327
  */
372
328
  replaceActions(actions) {
373
- if (!this.isEnabled) {
329
+ if (!this.getEnabled()) {
374
330
  return;
375
331
  }
376
332
  // Preserve any trees a remote mirror already hydrated via
@@ -378,12 +334,12 @@ class ReduxActionStore {
378
334
  // full snapshot arriving after a detail fetch must not blank the detail
379
335
  // pane back out.
380
336
  const hydrated = new Map();
381
- for (const existing of this.actions) {
337
+ for (const existing of this.items) {
382
338
  if (existing.prevState !== undefined && !isEvictedState(existing.prevState)) {
383
339
  hydrated.set(existing.id, existing);
384
340
  }
385
341
  }
386
- this.actions = actions.slice(0, this.maxActions).map(a => {
342
+ const merged = actions.slice(0, this.max).map(a => {
387
343
  const h = hydrated.get(a.id);
388
344
  if (!h || !isEvictedState(a.prevState)) return a;
389
345
  return {
@@ -396,7 +352,7 @@ class ReduxActionStore {
396
352
  error: isPayloadOnDevice(a.error) ? h.error : a.error
397
353
  };
398
354
  });
399
- this.notifyListeners();
355
+ this.setItems(merged);
400
356
  }
401
357
 
402
358
  /**
@@ -405,44 +361,18 @@ class ReduxActionStore {
405
361
  * `getActionDetail` action. Remote-mirror (desktop) use only.
406
362
  */
407
363
  hydrateAction(id, patch) {
408
- const index = this.actions.findIndex(a => a.id === id);
409
- if (index === -1) return;
410
- this.actions = [...this.actions.slice(0, index), {
411
- ...this.actions[index],
412
- ...patch
413
- }, ...this.actions.slice(index + 1)];
414
- this.notifyListeners();
415
- }
416
- setEnabled(enabled) {
417
- this.isEnabled = enabled;
418
- }
419
- getEnabled() {
420
- return this.isEnabled;
421
- }
422
- subscribe(listener) {
423
- this.listeners.add(listener);
424
- return () => {
425
- this.listeners.delete(listener);
426
- };
427
- }
428
- notifyListeners() {
429
- const actions = this.getActions();
430
- this.listeners.forEach(listener => listener(actions));
364
+ this.hydrateById(id, patch);
431
365
  }
432
366
  setMaxActions(max) {
433
- this.maxActions = max;
434
- if (this.actions.length > max) {
435
- this.actions = this.actions.slice(0, max);
436
- this.notifyListeners();
437
- }
367
+ this.setMax(max);
438
368
  }
439
369
  getStats() {
440
- const total = this.actions.length;
441
- const withChanges = this.actions.filter(a => a.hasStateChange).length;
442
- const actionTypes = new Set(this.actions.map(a => a.type));
370
+ const total = this.items.length;
371
+ const withChanges = this.items.filter(a => a.hasStateChange).length;
372
+ const actionTypes = new Set(this.items.map(a => a.type));
443
373
 
444
374
  // Calculate average duration
445
- const durations = this.actions.filter(a => a.duration !== undefined).map(a => a.duration);
375
+ const durations = this.items.filter(a => a.duration !== undefined).map(a => a.duration);
446
376
  const avgDuration = durations.length > 0 ? durations.reduce((sum, d) => sum + d, 0) / durations.length : 0;
447
377
  return {
448
378
  totalActions: total,
@@ -453,7 +383,7 @@ class ReduxActionStore {
453
383
  };
454
384
  }
455
385
  filterActions(filter) {
456
- let filtered = [...this.actions];
386
+ let filtered = [...this.items];
457
387
  if (filter.searchText) {
458
388
  const search = filter.searchText.toLowerCase();
459
389
  filtered = filtered.filter(a => a.type.toLowerCase().includes(search));
@@ -467,14 +397,14 @@ class ReduxActionStore {
467
397
  return filtered;
468
398
  }
469
399
  getUniqueActionTypes() {
470
- return Array.from(new Set(this.actions.map(a => a.type))).sort();
400
+ return Array.from(new Set(this.items.map(a => a.type))).sort();
471
401
  }
472
402
 
473
403
  /**
474
404
  * Find related async actions by requestId
475
405
  */
476
406
  getRelatedActions(requestId) {
477
- return this.actions.filter(a => a.meta?.requestId === requestId).sort((a, b) => a.timestamp - b.timestamp); // Sort chronologically
407
+ return this.items.filter(a => a.meta?.requestId === requestId).sort((a, b) => a.timestamp - b.timestamp); // Sort chronologically
478
408
  }
479
409
 
480
410
  /**
@@ -490,7 +420,7 @@ class ReduxActionStore {
490
420
  */
491
421
  getLinkedActionsCount(action) {
492
422
  if (!action.meta?.requestId) return 0;
493
- return this.actions.filter(a => a.meta?.requestId === action.meta?.requestId).length;
423
+ return this.items.filter(a => a.meta?.requestId === action.meta?.requestId).length;
494
424
  }
495
425
 
496
426
  /**
@@ -528,7 +458,7 @@ class ReduxActionStore {
528
458
  getAsyncOperationIndex(requestId) {
529
459
  // Get all unique requestIds with their first timestamp
530
460
  const requestIdTimestamps = new Map();
531
- for (const action of this.actions) {
461
+ for (const action of this.items) {
532
462
  if (action.meta?.requestId && !requestIdTimestamps.has(action.meta.requestId)) {
533
463
  requestIdTimestamps.set(action.meta.requestId, action.timestamp);
534
464
  }
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
 
3
3
  var _sharedUi = require("@buoy-gg/shared-ui");
4
- var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
5
4
  var _activeStoreRegistry = require("./activeStoreRegistry");
6
5
  var _buoyReduxMiddleware = require("./buoyReduxMiddleware");
7
6
  /**
@@ -65,36 +64,19 @@ async function restore(data, options) {
65
64
  const snapshot = data;
66
65
  const store = (0, _activeStoreRegistry.getActiveStore)();
67
66
  if (!store || snapshot === undefined || snapshot === null) {
68
- return {
69
- ok: false,
70
- applied: 0,
71
- skipped: [{
72
- id: "redux",
73
- reason: store ? "empty redux snapshot" : "no Redux store instrumented"
74
- }],
75
- warnings: []
76
- };
67
+ return (0, _sharedUi.skippedRestore)("redux", store ? "empty redux snapshot" : "no Redux store instrumented");
77
68
  }
78
69
  const {
79
70
  mechanism
80
71
  } = (0, _activeStoreRegistry.getInstrumentationStatus)();
81
72
  if (mechanism === "patch") {
82
- return {
83
- ok: false,
84
- applied: 0,
85
- skipped: [{
86
- id: "redux",
87
- reason: `restore unavailable on auto-instrumented stores — ${ENABLE_HINT}`
88
- }],
89
- warnings: []
90
- };
73
+ return (0, _sharedUi.skippedRestore)("redux", `restore unavailable on auto-instrumented stores — ${ENABLE_HINT}`);
91
74
  }
92
75
  // Untouched slices keep their LIVE values inside the jump payload, so the
93
76
  // full-state replace leaves them alone. A slice is untouched when it's
94
77
  // explicitly excluded OR outside the includeKeys scope.
95
- const excludedSet = new Set(options?.excludeKeys ?? []);
96
- const includedSet = options?.includeKeys ? new Set(options.includeKeys) : null;
97
- const excluded = Object.keys(snapshot.state ?? {}).filter(k => excludedSet.has(k) || includedSet && !includedSet.has(k));
78
+ const scope = (0, _sharedUi.createRestoreScope)(options);
79
+ const excluded = Object.keys(snapshot.state ?? {}).filter(k => !scope.touch(k));
98
80
  let payload = snapshot.state;
99
81
  if (excluded.length > 0) {
100
82
  const live = store.getState();
@@ -120,17 +102,8 @@ async function restore(data, options) {
120
102
  warnings
121
103
  };
122
104
  }
123
- return {
124
- ok: false,
125
- applied: 0,
126
- skipped: [{
127
- id: "redux",
128
- reason: `store ignored the state jump — ${ENABLE_HINT}`
129
- }],
130
- warnings: []
131
- };
105
+ return (0, _sharedUi.skippedRestore)("redux", `store ignored the state jump — ${ENABLE_HINT}`);
132
106
  }
133
- const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
134
107
 
135
108
  /** Per-slice restore preview. `base` omitted = compare against the live store. */
136
109
  async function previewItems(target, base) {
@@ -155,54 +128,18 @@ async function previewItems(target, base) {
155
128
  }
156
129
  const oldObj = baseState ?? {};
157
130
  const newObj = targetState ?? {};
158
- const keys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);
159
- for (const key of keys) {
160
- const inOld = Object.prototype.hasOwnProperty.call(oldObj, key);
161
- const inNew = Object.prototype.hasOwnProperty.call(newObj, key);
162
- let item;
163
- if (!inNew) {
164
- item = {
165
- key,
166
- label: key,
167
- verdict: "removed",
168
- oldValue: oldObj[key]
169
- };
170
- } else if (!inOld) {
171
- item = {
172
- key,
173
- label: key,
174
- verdict: "added",
175
- newValue: newObj[key]
176
- };
177
- } else if ((0, _dataViewer.boundedDeepEqual)(oldObj[key], newObj[key])) {
178
- item = {
179
- key,
180
- label: key,
181
- verdict: "unchanged"
182
- };
183
- } else if ((0, _dataViewer.jsonLikelyLargerThan)(oldObj[key], ITEM_RENDER_BYTE_LIMIT) || (0, _dataViewer.jsonLikelyLargerThan)(newObj[key], ITEM_RENDER_BYTE_LIMIT)) {
184
- item = {
185
- key,
186
- label: key,
187
- verdict: "too-large",
188
- reason: "slice too large to render a diff — restore still applies it"
189
- };
190
- } else {
191
- item = {
192
- key,
193
- label: key,
194
- verdict: "changed",
195
- oldValue: oldObj[key],
196
- newValue: newObj[key]
197
- };
198
- }
199
- if (wontApplyReason && item.verdict !== "unchanged") {
200
- item = {
201
- ...item,
202
- verdict: "wont-apply",
203
- reason: wontApplyReason
204
- };
205
- }
131
+ for (const key of (0, _sharedUi.unionKeys)(oldObj, newObj)) {
132
+ let item = (0, _sharedUi.classifyPreviewItem)({
133
+ key,
134
+ label: key,
135
+ oldValue: oldObj[key],
136
+ newValue: newObj[key],
137
+ inOld: Object.prototype.hasOwnProperty.call(oldObj, key),
138
+ inNew: Object.prototype.hasOwnProperty.call(newObj, key)
139
+ }, {
140
+ tooLargeReason: "slice too large to render a diff — restore still applies it"
141
+ });
142
+ if (wontApplyReason) item = (0, _sharedUi.wontApply)(item, wontApplyReason);
206
143
  items.push(item);
207
144
  }
208
145
  if (wontApplyReason) notes.push(`Redux restore unavailable: ${wontApplyReason}`);
@@ -34,6 +34,7 @@
34
34
 
35
35
  import { ReduxModal } from "./redux/components/ReduxModal";
36
36
  import { ReduxIcon } from "./redux/components/ReduxIcon";
37
+ import { createToolFactory, defineToolPreset } from "@buoy-gg/shared-ui";
37
38
 
38
39
  /**
39
40
  * Pre-configured Redux DevTools preset for FloatingDevTools.
@@ -44,7 +45,7 @@ import { ReduxIcon } from "./redux/components/ReduxIcon";
44
45
  * - Filter by action type
45
46
  */
46
47
  import { jsx as _jsx } from "react/jsx-runtime";
47
- export const reduxToolPreset = {
48
+ export const reduxToolPreset = defineToolPreset({
48
49
  id: "redux",
49
50
  name: "REDUX",
50
51
  description: "Redux action & state inspector",
@@ -58,7 +59,7 @@ export const reduxToolPreset = {
58
59
  props: {
59
60
  enableSharedModalDimensions: false
60
61
  }
61
- };
62
+ });
62
63
 
63
64
  /**
64
65
  * Create a custom Redux DevTools configuration.
@@ -74,21 +75,13 @@ export const reduxToolPreset = {
74
75
  * });
75
76
  * ```
76
77
  */
77
- export function createReduxTool(options) {
78
- return {
79
- id: options?.id || "redux",
80
- name: options?.name || "REDUX",
81
- description: options?.description || "Redux action & state inspector",
82
- slot: "both",
83
- icon: ({
84
- size
85
- }) => /*#__PURE__*/_jsx(ReduxIcon, {
86
- size: size,
87
- color: options?.iconColor
88
- }),
89
- component: ReduxModal,
90
- props: {
91
- enableSharedModalDimensions: options?.enableSharedModalDimensions !== undefined ? options.enableSharedModalDimensions : false
92
- }
93
- };
94
- }
78
+ export const createReduxTool = createToolFactory(reduxToolPreset, options => ({
79
+ enableSharedModalDimensions: options.enableSharedModalDimensions ?? false
80
+ }), options => ({
81
+ icon: ({
82
+ size
83
+ }) => /*#__PURE__*/_jsx(ReduxIcon, {
84
+ size: size,
85
+ color: options.iconColor
86
+ })
87
+ }));
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { TouchableOpacity, Text, View, StyleSheet } from "react-native";
11
- import { night } from "@buoy-gg/shared-ui";
11
+ import { night, monoFont } from "@buoy-gg/shared-ui";
12
12
 
13
13
  // Button color configurations matching React Query pattern
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -122,7 +122,7 @@ const styles = StyleSheet.create({
122
122
  fontWeight: "600",
123
123
  letterSpacing: 0.5,
124
124
  textTransform: "uppercase",
125
- fontFamily: "monospace",
125
+ fontFamily: monoFont,
126
126
  height: 12
127
127
  }
128
128
  });
@@ -11,7 +11,7 @@
11
11
 
12
12
  import { View, Text, StyleSheet, ScrollView } from "react-native";
13
13
  import { useState, useCallback, useMemo } from "react";
14
- import { macOSColors, night, EventStepperFooter, formatRelativeTime, parseValue } from "@buoy-gg/shared-ui";
14
+ import { macOSColors, night, EventStepperFooter, formatRelativeTime, parseValue, monoFont } from "@buoy-gg/shared-ui";
15
15
  import { DataViewer, SplitDiffViewer, TreeDiffViewer, diffThemes } from "@buoy-gg/shared-ui/dataViewer";
16
16
  import { ReduxDetailViewToggle } from "./ReduxDetailViewToggle";
17
17
  import { ReduxActionInfoView } from "./ReduxActionInfoView";
@@ -355,7 +355,7 @@ const styles = StyleSheet.create({
355
355
  valueLabel: {
356
356
  fontSize: 10,
357
357
  color: night.color.textSecondary,
358
- fontFamily: "monospace",
358
+ fontFamily: monoFont,
359
359
  letterSpacing: 0.5,
360
360
  fontWeight: "600"
361
361
  },
@@ -372,7 +372,7 @@ const styles = StyleSheet.create({
372
372
  actionText: {
373
373
  fontSize: 9,
374
374
  fontWeight: "700",
375
- fontFamily: "monospace",
375
+ fontFamily: monoFont,
376
376
  letterSpacing: 0.3
377
377
  },
378
378
  typeBadge: {
@@ -385,7 +385,7 @@ const styles = StyleSheet.create({
385
385
  fontSize: 9,
386
386
  fontWeight: "600",
387
387
  color: night.color.textTertiary,
388
- fontFamily: "monospace"
388
+ fontFamily: monoFont
389
389
  },
390
390
  valueBox: {
391
391
  // Inset code box — darker than the card, the night track color.
@@ -403,7 +403,7 @@ const styles = StyleSheet.create({
403
403
  valueText: {
404
404
  fontSize: 12,
405
405
  color: night.color.text,
406
- fontFamily: "monospace",
406
+ fontFamily: monoFont,
407
407
  lineHeight: 18
408
408
  },
409
409
  // Diff view styles
@@ -423,7 +423,7 @@ const styles = StyleSheet.create({
423
423
  actionTextSmall: {
424
424
  fontSize: 8,
425
425
  fontWeight: "700",
426
- fontFamily: "monospace"
426
+ fontFamily: monoFont
427
427
  },
428
428
  dataViewerContainer: {
429
429
  marginTop: -12,
@@ -6,7 +6,7 @@
6
6
 
7
7
  import { useState } from "react";
8
8
  import { View, Text, StyleSheet, ScrollView } from "react-native";
9
- import { macOSColors, night, TabSelector, DataInspector, CollapsibleSection, CopyButton } from "@buoy-gg/shared-ui";
9
+ import { macOSColors, night, TabSelector, DataInspector, CollapsibleSection, CopyButton, monoFont } from "@buoy-gg/shared-ui";
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  export function ReduxActionDetailView({
12
12
  action
@@ -298,7 +298,7 @@ const styles = StyleSheet.create({
298
298
  fontSize: 14,
299
299
  fontWeight: "600",
300
300
  color: night.color.text,
301
- fontFamily: "monospace",
301
+ fontFamily: monoFont,
302
302
  marginBottom: 6
303
303
  },
304
304
  headerMeta: {
@@ -313,7 +313,7 @@ const styles = StyleSheet.create({
313
313
  durationText: {
314
314
  fontSize: 11,
315
315
  color: night.color.textTertiary,
316
- fontFamily: "monospace"
316
+ fontFamily: monoFont
317
317
  },
318
318
  changeBadge: {
319
319
  backgroundColor: macOSColors.semantic.warningBackground,
@@ -379,7 +379,7 @@ const styles = StyleSheet.create({
379
379
  diffPath: {
380
380
  fontSize: 12,
381
381
  color: night.color.text,
382
- fontFamily: "monospace"
382
+ fontFamily: monoFont
383
383
  },
384
384
  diffValues: {
385
385
  padding: 8,
@@ -12,7 +12,7 @@
12
12
 
13
13
  import React, { memo, useMemo, useCallback, useState, useEffect } from "react";
14
14
  import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
15
- import { buoyColors, night, Clock, AlertTriangle, Zap, Hash, Info, Box, AlertCircle, FileText, parseValue, ProUpgradeModal, copyToClipboard } from "@buoy-gg/shared-ui";
15
+ import { buoyColors, night, Clock, AlertTriangle, Zap, Hash, Info, Box, AlertCircle, FileText, parseValue, ProUpgradeModal, copyToClipboard, InfoRow, monoFont } from "@buoy-gg/shared-ui";
16
16
  import { useIsPro } from "@buoy-gg/license";
17
17
  import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
18
18
  import { reduxActionStore, isEvictedState } from "../utils/reduxActionStore";
@@ -104,37 +104,6 @@ function SectionHeader({
104
104
  });
105
105
  }
106
106
 
107
- /**
108
- * Info row component for key-value display
109
- */
110
- function InfoRow({
111
- label,
112
- value,
113
- valueColor,
114
- mono = false,
115
- testID
116
- }) {
117
- return /*#__PURE__*/_jsxs(View, {
118
- style: styles.infoRow,
119
- children: [/*#__PURE__*/_jsx(Text, {
120
- style: styles.infoLabel,
121
- children: label
122
- }), /*#__PURE__*/_jsx(Text, {
123
- style: [styles.infoValue, mono && styles.infoValueMono, valueColor && {
124
- color: valueColor
125
- }]
126
- // `ellipsizeMode="middle"` truncates the RENDERED text and iOS reports
127
- // the truncated string back, so anything a test reads off one of these
128
- // rows has to be short enough to fit on the line.
129
- ,
130
- numberOfLines: 1,
131
- ellipsizeMode: "middle",
132
- testID: testID,
133
- children: value
134
- })]
135
- });
136
- }
137
-
138
107
  /**
139
108
  * Format timestamp for display
140
109
  */
@@ -598,33 +567,12 @@ const styles = StyleSheet.create({
598
567
  fontWeight: "600",
599
568
  letterSpacing: 0.5,
600
569
  color: night.color.accent,
601
- fontFamily: "monospace"
570
+ fontFamily: monoFont
602
571
  },
603
572
  cardContent: {
604
573
  padding: 14,
605
574
  gap: 10
606
575
  },
607
- infoRow: {
608
- flexDirection: "row",
609
- alignItems: "center",
610
- justifyContent: "space-between"
611
- },
612
- infoLabel: {
613
- fontSize: 11,
614
- color: night.color.textTertiary,
615
- fontWeight: "500"
616
- },
617
- infoValue: {
618
- fontSize: 11,
619
- color: night.color.text,
620
- fontWeight: "500",
621
- flex: 1,
622
- textAlign: "right",
623
- marginLeft: 12
624
- },
625
- infoValueMono: {
626
- fontFamily: "monospace"
627
- },
628
576
  badgeRow: {
629
577
  flexDirection: "row",
630
578
  flexWrap: "wrap",
@@ -657,7 +605,7 @@ const styles = StyleSheet.create({
657
605
  fontSize: 9,
658
606
  fontWeight: "600",
659
607
  color: night.color.textSecondary,
660
- fontFamily: "monospace"
608
+ fontFamily: monoFont
661
609
  },
662
610
  durationTextSlow: {
663
611
  color: buoyColors.error
@@ -697,7 +645,7 @@ const styles = StyleSheet.create({
697
645
  fontSize: 8,
698
646
  fontWeight: "600",
699
647
  color: night.color.textTertiary,
700
- fontFamily: "monospace"
648
+ fontFamily: monoFont
701
649
  },
702
650
  dataViewerContainer: {
703
651
  backgroundColor: night.color.bg,
@@ -722,7 +670,7 @@ const styles = StyleSheet.create({
722
670
  argValue: {
723
671
  fontSize: 11,
724
672
  color: night.color.text,
725
- fontFamily: "monospace",
673
+ fontFamily: monoFont,
726
674
  padding: 10
727
675
  },
728
676
  errorBadge: {
@@ -740,7 +688,7 @@ const styles = StyleSheet.create({
740
688
  errorText: {
741
689
  fontSize: 12,
742
690
  color: buoyColors.error,
743
- fontFamily: "monospace",
691
+ fontFamily: monoFont,
744
692
  padding: 14
745
693
  },
746
694
  // Async Operation / Related Actions styles
@@ -760,7 +708,7 @@ const styles = StyleSheet.create({
760
708
  fontSize: 12,
761
709
  fontWeight: "600",
762
710
  color: night.color.text,
763
- fontFamily: "monospace",
711
+ fontFamily: monoFont,
764
712
  marginBottom: 8
765
713
  },
766
714
  totalDurationRow: {
@@ -781,7 +729,7 @@ const styles = StyleSheet.create({
781
729
  fontSize: 14,
782
730
  fontWeight: "700",
783
731
  color: buoyColors.success,
784
- fontFamily: "monospace"
732
+ fontFamily: monoFont
785
733
  },
786
734
  timeline: {
787
735
  gap: 0
@@ -847,7 +795,7 @@ const styles = StyleSheet.create({
847
795
  timelineTime: {
848
796
  fontSize: 10,
849
797
  color: night.color.textTertiary,
850
- fontFamily: "monospace"
798
+ fontFamily: monoFont
851
799
  },
852
800
  // Action footer - matches React Query DevTools
853
801
  actionFooter: {