@buoy-gg/redux 5.0.0 → 6.0.1
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/README.md +50 -34
- package/lib/commonjs/redux/components/ReduxActionItem.js +12 -5
- package/lib/commonjs/redux/components/ReduxModal.js +9 -4
- package/lib/module/redux/components/ReduxActionItem.js +12 -5
- package/lib/module/redux/components/ReduxModal.js +9 -4
- package/lib/typescript/redux/components/ReduxActionItem.d.ts +1 -1
- package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxModal.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,55 +1,71 @@
|
|
|
1
1
|
# @buoy-gg/redux
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@buoy-gg/redux) [](https://www.npmjs.com/package/@buoy-gg/redux)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Redux DevTools on the device — action log, state diffs, and time travel with zero store changes.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and it auto-appears in the floating menu from [`@buoy-gg/core`](https://www.npmjs.com/package/@buoy-gg/core).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Install
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
```bash
|
|
12
|
+
npm install @buoy-gg/core @buoy-gg/redux
|
|
13
|
+
```
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
import { ReduxComponent } from '@buoy-gg/redux';
|
|
15
|
+
## Quick start
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
<ReduxComponent title="Hello World" />
|
|
18
|
-
```
|
|
17
|
+
Zero config. Your existing store works as-is — no middleware, no wrapper. The tool auto-instruments the store when `FloatingDevTools` mounts.
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
```tsx
|
|
20
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
21
|
+
import { Provider } from 'react-redux';
|
|
22
|
+
import { FloatingDevTools } from '@buoy-gg/core';
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
const store = configureStore({ reducer: rootReducer }); // unchanged
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
export default function App() {
|
|
27
|
+
return (
|
|
28
|
+
<Provider store={store}>
|
|
29
|
+
<YourApp />
|
|
30
|
+
<FloatingDevTools />
|
|
31
|
+
</Provider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
26
34
|
```
|
|
27
35
|
|
|
28
|
-
###
|
|
36
|
+
### Optional: full time travel
|
|
29
37
|
|
|
30
|
-
|
|
31
|
-
pnpm typecheck
|
|
32
|
-
```
|
|
38
|
+
To jump back to past states (not just view them), wrap your reducer:
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
```tsx
|
|
41
|
+
import { withBuoyDevTools } from '@buoy-gg/redux';
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
const store = configureStore({
|
|
44
|
+
reducer: withBuoyDevTools(rootReducer),
|
|
45
|
+
});
|
|
38
46
|
```
|
|
39
47
|
|
|
40
|
-
##
|
|
48
|
+
## What you get
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
- **Every action, captured** — type, payload, timestamp, and a diff summary (`+added -removed ~modified`) per dispatch
|
|
51
|
+
- **Frame-budget warnings** — actions taking longer than 16ms are flagged so slow reducers can't hide
|
|
52
|
+
- **RTK async thunk linking** — pending → fulfilled/rejected automatically connected by Request ID, with a visual timeline and per-request durations
|
|
53
|
+
- **Time travel** — jump to the state after any action, or replay an action to re-test your reducers
|
|
54
|
+
- **Three-tab detail view** — full action payload, full state tree, and a side-by-side diff (tree or split view)
|
|
55
|
+
- **Search & filter** — find actions by type, or show only actions that actually changed state
|
|
56
|
+
- **Export & copy** — dump action history as JSON for bug reports or test fixtures
|
|
57
|
+
- **Recording toggle** — pause capture when you need to focus, resume when ready
|
|
58
|
+
|
|
59
|
+
## Desktop & AI
|
|
60
|
+
|
|
61
|
+
The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) (free, macOS/Windows/Linux) and to Claude Code or Cursor via the [Buoy MCP server](https://buoy.gg/buoy/latest/docs/mcp).
|
|
62
|
+
|
|
63
|
+
## Free vs Pro
|
|
64
|
+
|
|
65
|
+
Every tool is free. [Pro](https://buoy.gg/pricing) unlocks production builds, the MCP server, and unlimited capture. Every weekend, Pro features unlock free for everyone.
|
|
66
|
+
|
|
67
|
+
---
|
|
51
68
|
|
|
52
|
-
|
|
69
|
+
📚 [Full docs](https://buoy.gg/buoy/latest/docs/tools/redux) · [All Buoy tools](https://github.com/Buoy-gg/buoy)
|
|
53
70
|
|
|
54
|
-
|
|
55
|
-
- React and React Native as peer dependencies
|
|
71
|
+
Proprietary software. © Buoy LLC. [Terms](https://buoy.gg/terms)
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.ReduxActionItem =
|
|
6
|
+
exports.ReduxActionItem = void 0;
|
|
7
|
+
var _react = require("react");
|
|
7
8
|
var _reactNative = require("react-native");
|
|
8
9
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
9
10
|
var _reduxActionStore = require("../utils/reduxActionStore");
|
|
@@ -206,11 +207,15 @@ function getPrimaryText(action) {
|
|
|
206
207
|
}
|
|
207
208
|
return action.type;
|
|
208
209
|
}
|
|
209
|
-
|
|
210
|
+
|
|
211
|
+
// Memo justified by profiling (tool-bench 2026-07-06): ReduxActionItem
|
|
212
|
+
// x172 renders during a 5s idle dwell at 200 seeded actions. The relative
|
|
213
|
+
// timestamp is delegated to the shared <RelativeTime/> leaf so the 5s
|
|
214
|
+
// tick re-renders only that Text, not this row.
|
|
215
|
+
const ReduxActionItem = exports.ReduxActionItem = /*#__PURE__*/(0, _react.memo)(function ReduxActionItem({
|
|
210
216
|
action,
|
|
211
217
|
onPress
|
|
212
218
|
}) {
|
|
213
|
-
const relativeTime = (0, _sharedUi.useRelativeTime)(action.timestamp);
|
|
214
219
|
const sliceName = action.sliceName ?? undefined;
|
|
215
220
|
const statusColor = getStatusColor(action.category, action.hasStateChange, sliceName);
|
|
216
221
|
const statusLabel = getStatusLabel(action.category, sliceName);
|
|
@@ -323,7 +328,9 @@ function ReduxActionItem({
|
|
|
323
328
|
statusLabel: statusLabel,
|
|
324
329
|
statusSublabel: sublabel,
|
|
325
330
|
primaryText: primaryText,
|
|
326
|
-
bottomRightText:
|
|
331
|
+
bottomRightText: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RelativeTime, {
|
|
332
|
+
timestamp: action.timestamp
|
|
333
|
+
})
|
|
327
334
|
// Use customBadge if we have special indicators, otherwise show action badge as text
|
|
328
335
|
,
|
|
329
336
|
customBadge: customBadge,
|
|
@@ -332,7 +339,7 @@ function ReduxActionItem({
|
|
|
332
339
|
showChevron: true,
|
|
333
340
|
onPress: () => onPress(action)
|
|
334
341
|
});
|
|
335
|
-
}
|
|
342
|
+
});
|
|
336
343
|
const styles = _reactNative.StyleSheet.create({
|
|
337
344
|
badgeContainer: {
|
|
338
345
|
flexDirection: "row",
|
|
@@ -281,6 +281,10 @@ function ReduxModal({
|
|
|
281
281
|
onIndexChange: handleIndexChange
|
|
282
282
|
}) : null;
|
|
283
283
|
const footerHeight = selectedAction && visibleActions.length > 1 ? 68 : 0;
|
|
284
|
+
|
|
285
|
+
// The action list owns its scrolling so FlatList virtualization works
|
|
286
|
+
// (see ZustandModal — same pattern, same tool-bench evidence).
|
|
287
|
+
const listOwnsScroll = selectedAction == null;
|
|
284
288
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.TickProvider, {
|
|
285
289
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
|
|
286
290
|
visible: visible,
|
|
@@ -295,6 +299,7 @@ function ReduxModal({
|
|
|
295
299
|
enablePersistence: true,
|
|
296
300
|
initialMode: "bottomSheet",
|
|
297
301
|
enableGlitchEffects: true,
|
|
302
|
+
disableScrollWrapper: listOwnsScroll,
|
|
298
303
|
styles: {},
|
|
299
304
|
footer: footerNode,
|
|
300
305
|
footerHeight: footerHeight,
|
|
@@ -350,10 +355,10 @@ function ReduxModal({
|
|
|
350
355
|
contentContainerStyle: styles.listContent,
|
|
351
356
|
showsVerticalScrollIndicator: true,
|
|
352
357
|
removeClippedSubviews: true,
|
|
353
|
-
initialNumToRender:
|
|
354
|
-
maxToRenderPerBatch:
|
|
355
|
-
windowSize:
|
|
356
|
-
|
|
358
|
+
initialNumToRender: 12,
|
|
359
|
+
maxToRenderPerBatch: 8,
|
|
360
|
+
windowSize: 5,
|
|
361
|
+
updateCellsBatchingPeriod: 50
|
|
357
362
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
|
|
358
363
|
isEnabled: isEnabled
|
|
359
364
|
})]
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* Uses shared CompactRow for consistent styling with React Query devtools
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { memo } from "react";
|
|
8
9
|
import { View, Text, StyleSheet } from "react-native";
|
|
9
|
-
import { CompactRow, buoyColors, Zap, AlertCircle, Clock,
|
|
10
|
+
import { CompactRow, buoyColors, Zap, AlertCircle, Clock, RelativeTime } from "@buoy-gg/shared-ui";
|
|
10
11
|
import { reduxActionStore } from "../utils/reduxActionStore";
|
|
11
12
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
12
13
|
/**
|
|
@@ -202,11 +203,15 @@ function getPrimaryText(action) {
|
|
|
202
203
|
}
|
|
203
204
|
return action.type;
|
|
204
205
|
}
|
|
205
|
-
|
|
206
|
+
|
|
207
|
+
// Memo justified by profiling (tool-bench 2026-07-06): ReduxActionItem
|
|
208
|
+
// x172 renders during a 5s idle dwell at 200 seeded actions. The relative
|
|
209
|
+
// timestamp is delegated to the shared <RelativeTime/> leaf so the 5s
|
|
210
|
+
// tick re-renders only that Text, not this row.
|
|
211
|
+
export const ReduxActionItem = /*#__PURE__*/memo(function ReduxActionItem({
|
|
206
212
|
action,
|
|
207
213
|
onPress
|
|
208
214
|
}) {
|
|
209
|
-
const relativeTime = useRelativeTime(action.timestamp);
|
|
210
215
|
const sliceName = action.sliceName ?? undefined;
|
|
211
216
|
const statusColor = getStatusColor(action.category, action.hasStateChange, sliceName);
|
|
212
217
|
const statusLabel = getStatusLabel(action.category, sliceName);
|
|
@@ -319,7 +324,9 @@ export function ReduxActionItem({
|
|
|
319
324
|
statusLabel: statusLabel,
|
|
320
325
|
statusSublabel: sublabel,
|
|
321
326
|
primaryText: primaryText,
|
|
322
|
-
bottomRightText:
|
|
327
|
+
bottomRightText: /*#__PURE__*/_jsx(RelativeTime, {
|
|
328
|
+
timestamp: action.timestamp
|
|
329
|
+
})
|
|
323
330
|
// Use customBadge if we have special indicators, otherwise show action badge as text
|
|
324
331
|
,
|
|
325
332
|
customBadge: customBadge,
|
|
@@ -328,7 +335,7 @@ export function ReduxActionItem({
|
|
|
328
335
|
showChevron: true,
|
|
329
336
|
onPress: () => onPress(action)
|
|
330
337
|
});
|
|
331
|
-
}
|
|
338
|
+
});
|
|
332
339
|
const styles = StyleSheet.create({
|
|
333
340
|
badgeContainer: {
|
|
334
341
|
flexDirection: "row",
|
|
@@ -276,6 +276,10 @@ export function ReduxModal({
|
|
|
276
276
|
onIndexChange: handleIndexChange
|
|
277
277
|
}) : null;
|
|
278
278
|
const footerHeight = selectedAction && visibleActions.length > 1 ? 68 : 0;
|
|
279
|
+
|
|
280
|
+
// The action list owns its scrolling so FlatList virtualization works
|
|
281
|
+
// (see ZustandModal — same pattern, same tool-bench evidence).
|
|
282
|
+
const listOwnsScroll = selectedAction == null;
|
|
279
283
|
return /*#__PURE__*/_jsxs(TickProvider, {
|
|
280
284
|
children: [/*#__PURE__*/_jsx(JsModal, {
|
|
281
285
|
visible: visible,
|
|
@@ -290,6 +294,7 @@ export function ReduxModal({
|
|
|
290
294
|
enablePersistence: true,
|
|
291
295
|
initialMode: "bottomSheet",
|
|
292
296
|
enableGlitchEffects: true,
|
|
297
|
+
disableScrollWrapper: listOwnsScroll,
|
|
293
298
|
styles: {},
|
|
294
299
|
footer: footerNode,
|
|
295
300
|
footerHeight: footerHeight,
|
|
@@ -345,10 +350,10 @@ export function ReduxModal({
|
|
|
345
350
|
contentContainerStyle: styles.listContent,
|
|
346
351
|
showsVerticalScrollIndicator: true,
|
|
347
352
|
removeClippedSubviews: true,
|
|
348
|
-
initialNumToRender:
|
|
349
|
-
maxToRenderPerBatch:
|
|
350
|
-
windowSize:
|
|
351
|
-
|
|
353
|
+
initialNumToRender: 12,
|
|
354
|
+
maxToRenderPerBatch: 8,
|
|
355
|
+
windowSize: 5,
|
|
356
|
+
updateCellsBatchingPeriod: 50
|
|
352
357
|
}) : /*#__PURE__*/_jsx(EmptyState, {
|
|
353
358
|
isEnabled: isEnabled
|
|
354
359
|
})]
|
|
@@ -7,6 +7,6 @@ interface ReduxActionItemProps {
|
|
|
7
7
|
action: ReduxAction;
|
|
8
8
|
onPress: (action: ReduxAction) => void;
|
|
9
9
|
}
|
|
10
|
-
export declare
|
|
10
|
+
export declare const ReduxActionItem: import("react").NamedExoticComponent<ReduxActionItemProps>;
|
|
11
11
|
export {};
|
|
12
12
|
//# sourceMappingURL=ReduxActionItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxActionItem.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionItem.tsx"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"ReduxActionItem.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionItem.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,UAAU,CAAC;AAG5D,UAAU,oBAAoB;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC;AAmKD,eAAO,MAAM,eAAe,4DAkG1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxModal.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2CH,yCAAyC;AACzC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAgBD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,GACpC,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"ReduxModal.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2CH,yCAAyC;AACzC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAgBD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,GACpC,EAAE,eAAe,sCAiYjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/redux",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "Redux Toolkit DevTools for React Native",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
],
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@buoy-gg/
|
|
30
|
-
"@buoy-gg/
|
|
31
|
-
"@buoy-gg/
|
|
29
|
+
"@buoy-gg/license": "6.0.1",
|
|
30
|
+
"@buoy-gg/floating-tools-core": "6.0.1",
|
|
31
|
+
"@buoy-gg/shared-ui": "6.0.1"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@reduxjs/toolkit": ">=2.0.0",
|