@buoy-gg/jotai 7.0.41 → 7.0.42
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 +11 -80
- package/lib/commonjs/index.js +1 -112
- package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +1 -199
- package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +1 -95
- package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +1 -715
- package/lib/commonjs/jotai/components/JotaiAtomValueDetailContent.js +1 -444
- package/lib/commonjs/jotai/components/JotaiEventFilterView.js +1 -43
- package/lib/commonjs/jotai/components/JotaiIcon.js +1 -18
- package/lib/commonjs/jotai/components/JotaiModal.js +1 -743
- package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +1 -69
- package/lib/commonjs/jotai/sync/jotaiSyncAdapter.js +1 -306
- package/lib/commonjs/jotai/types/index.js +1 -1
- package/lib/commonjs/jotai/utils/jotaiStateStore.js +1 -321
- package/lib/commonjs/jotai/utils/snapshotProvider.js +1 -215
- package/lib/commonjs/jotai/utils/testIDs.js +1 -90
- package/lib/commonjs/jotai/utils/watchAtoms.js +1 -143
- package/lib/commonjs/jotai/utils/writeSemantics.js +1 -47
- package/lib/commonjs/preset.js +1 -90
- package/lib/module/index.js +1 -85
- package/lib/module/jotai/components/JotaiAtomBrowser.js +1 -195
- package/lib/module/jotai/components/JotaiAtomChangeItem.js +1 -91
- package/lib/module/jotai/components/JotaiAtomDetailContent.js +1 -710
- package/lib/module/jotai/components/JotaiAtomValueDetailContent.js +1 -442
- package/lib/module/jotai/components/JotaiEventFilterView.js +1 -39
- package/lib/module/jotai/components/JotaiIcon.js +1 -11
- package/lib/module/jotai/components/JotaiModal.js +1 -738
- package/lib/module/jotai/hooks/useJotaiAtomChanges.js +1 -65
- package/lib/module/jotai/sync/jotaiSyncAdapter.js +1 -303
- package/lib/module/jotai/types/index.js +1 -1
- package/lib/module/jotai/utils/jotaiStateStore.js +1 -317
- package/lib/module/jotai/utils/snapshotProvider.js +1 -214
- package/lib/module/jotai/utils/testIDs.js +1 -82
- package/lib/module/jotai/utils/watchAtoms.js +1 -138
- package/lib/module/jotai/utils/writeSemantics.js +1 -43
- package/lib/module/preset.js +1 -87
- package/lib/web/index.mjs +2 -3
- package/package.json +3 -3
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomValueDetailContent.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiIcon.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiModal.d.ts.map +0 -1
- package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +0 -1
- package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/jotai/types/index.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/snapshotProvider.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/testIDs.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/watchAtoms.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/writeSemantics.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,96 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# @buoy-gg/jotai
|
|
4
4
|
|
|
5
5
|
Inspect registered Jotai atoms and their captured changes, with live values and per-atom history.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<a href="https://buoy.gg/buoy/latest/docs/tools/jotai"><b>Jotai guide</b></a> · <a href="https://buoy.gg">buoy.gg</a> · <a href="https://github.com/Buoy-gg/buoy">All tools</a>
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/@buoy-gg/jotai) [](https://www.npmjs.com/package/@buoy-gg/jotai)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
npm install @buoy-gg/core @buoy-gg/jotai
|
|
13
|
-
```
|
|
11
|
+
<a href="https://buoy.gg/buoy/latest/docs/tools/jotai"><img src="https://raw.githubusercontent.com/Buoy-gg/buoy/main/.github/readme/tools/jotai.png" alt="Watch the Jotai film on buoy.gg" width="640" /></a>
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
</div>
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
## Install
|
|
18
16
|
|
|
19
17
|
```bash
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
For Expo, initialize Buoy before rendering the menu:
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
import { Buoy } from "@buoy-gg/core";
|
|
27
|
-
|
|
28
|
-
Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY });
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The login command writes the Expo key to `.env.local`. For React Native CLI, pass the key from your app’s environment configuration; React Native does not load `.env.local` automatically. Mount `FloatingDevTools` inside the same providers as your screens and restart the development server after installation. The [Quick Start](https://buoy.gg/buoy/latest/docs/quick-start) shows the complete root component setup.
|
|
32
|
-
|
|
33
|
-
## Quick start
|
|
34
|
-
|
|
35
|
-
One `watchAtoms(store, atoms)` call at module scope — pass your Jotai store and a named map of atoms. No wrappers, no `atomWithDevTools`, no changes to existing atoms; observation is subscribe-only.
|
|
36
|
-
|
|
37
|
-
```tsx
|
|
38
|
-
import { getDefaultStore } from 'jotai';
|
|
39
|
-
import { watchAtoms } from '@buoy-gg/jotai';
|
|
40
|
-
import { countAtom } from './atoms/count';
|
|
41
|
-
import { authAtom } from './atoms/auth';
|
|
42
|
-
import { cartAtom } from './atoms/cart';
|
|
43
|
-
|
|
44
|
-
watchAtoms(getDefaultStore(), {
|
|
45
|
-
countAtom,
|
|
46
|
-
authAtom,
|
|
47
|
-
cartAtom,
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Using a `<Provider>` with a custom store? Pass it instead:
|
|
52
|
-
|
|
53
|
-
```tsx
|
|
54
|
-
import { createStore, Provider } from "jotai";
|
|
55
|
-
|
|
56
|
-
const myStore = createStore();
|
|
57
|
-
watchAtoms(myStore, { countAtom, authAtom });
|
|
58
|
-
|
|
59
|
-
// Use this same store in the provider around your app and Buoy menu.
|
|
60
|
-
<Provider store={myStore}>{/* Existing app and FloatingDevTools */}</Provider>;
|
|
18
|
+
npm install @buoy-gg/core @buoy-gg/jotai
|
|
61
19
|
```
|
|
62
20
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Check the integration
|
|
66
|
-
|
|
67
|
-
Change a registered atom through your app and inspect its history. Use the same store as your Jotai provider. Whether an atom can be edited depends on whether it is writable; a derived atom can also be writable.
|
|
21
|
+
Call `watchAtoms(store, atoms)` once at module scope with your Jotai store and a named map of atoms. Existing atoms stay as they are.
|
|
68
22
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- **`prev → next` on every event** — see `0 → 5` or `null → {name, email}` at a glance, no tapping in for simple updates
|
|
72
|
-
- **Live Atoms tab** — every registered atom with its current value, value type, and change count, updated in real time
|
|
73
|
-
- **Per-atom history** — jump from any atom straight to its filtered event timeline to trace one piece of state through a flow
|
|
74
|
-
- **No-change flags** — writes that fired but didn't actually change the value are called out
|
|
75
|
-
- **Three-tab detail view** — change metadata, full value tree, and a side-by-side before/after diff
|
|
76
|
-
- **Atom color coding** — each atom keeps a consistent color across tabs and detail views
|
|
77
|
-
- **Search & filter** — find events by atom name or value content; hide noisy atoms everywhere at once
|
|
78
|
-
- **Recording toggle** — pause atom capture when you need to focus, resume when ready
|
|
79
|
-
|
|
80
|
-
## Desktop & AI
|
|
81
|
-
|
|
82
|
-
To connect a React Native app to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) or MCP, install `@buoy-gg/external-sync` and follow the [Desktop connection guide](https://buoy.gg/buoy/latest/docs/desktop). Sign in to Desktop separately. [MCP setup](https://buoy.gg/buoy/latest/docs/mcp) also requires a process account and Pro access. Available remote actions depend on the tool and app integration.
|
|
83
|
-
|
|
84
|
-
## Account and plan requirements
|
|
85
|
-
|
|
86
|
-
Use a Free or Pro Buoy account. History limits and paid features vary by tool; see [pricing](https://buoy.gg/pricing). Production access requires Pro where supported. Development-only hooks and actions remain unavailable in release builds.
|
|
23
|
+
The [Jotai guide](https://buoy.gg/buoy/latest/docs/tools/jotai) covers setup, what it captures and its limits. New to Buoy? Start with the [Quick start](https://buoy.gg/buoy/latest/docs/quick-start).
|
|
87
24
|
|
|
88
25
|
---
|
|
89
26
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
Proprietary software. © Buoy LLC. [Terms](https://buoy.gg/terms)
|
|
93
|
-
|
|
94
|
-
## Web support (unreleased)
|
|
95
|
-
|
|
96
|
-
Register the app’s atoms and store with watchAtoms. The shared panel and snapshot provider use those registrations. The browser build is available in this checkout and has not been published yet. See the [web setup guide](https://buoy.gg/buoy/latest/docs/web-preview) for registration, dependencies, and browser boundaries.
|
|
27
|
+
<sub>Part of <a href="https://buoy.gg">Buoy</a>, developer tools that live inside your app. Proprietary software. © Buoy LLC. <a href="https://buoy.gg/terms">Terms</a></sub>
|
package/lib/commonjs/index.js
CHANGED
|
@@ -1,112 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "JOTAI_ICON_COLOR", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _JotaiIcon.JOTAI_ICON_COLOR;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(exports, "JotaiAtomChangeItem", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () {
|
|
15
|
-
return _JotaiAtomChangeItem.JotaiAtomChangeItem;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
Object.defineProperty(exports, "JotaiAtomDetailContent", {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
get: function () {
|
|
21
|
-
return _JotaiAtomDetailContent.JotaiAtomDetailContent;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
Object.defineProperty(exports, "JotaiAtomDetailFooter", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () {
|
|
27
|
-
return _JotaiAtomDetailContent.JotaiAtomDetailFooter;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
Object.defineProperty(exports, "JotaiAtomValueDetailContent", {
|
|
31
|
-
enumerable: true,
|
|
32
|
-
get: function () {
|
|
33
|
-
return _JotaiAtomValueDetailContent.JotaiAtomValueDetailContent;
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
Object.defineProperty(exports, "JotaiIcon", {
|
|
37
|
-
enumerable: true,
|
|
38
|
-
get: function () {
|
|
39
|
-
return _JotaiIcon.JotaiIcon;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
Object.defineProperty(exports, "JotaiModal", {
|
|
43
|
-
enumerable: true,
|
|
44
|
-
get: function () {
|
|
45
|
-
return _JotaiModal.JotaiModal;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
Object.defineProperty(exports, "JotaiToolView", {
|
|
49
|
-
enumerable: true,
|
|
50
|
-
get: function () {
|
|
51
|
-
return _JotaiModal.JotaiToolView;
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
Object.defineProperty(exports, "createJotaiTool", {
|
|
55
|
-
enumerable: true,
|
|
56
|
-
get: function () {
|
|
57
|
-
return _preset.createJotaiTool;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
Object.defineProperty(exports, "isAtomWatched", {
|
|
61
|
-
enumerable: true,
|
|
62
|
-
get: function () {
|
|
63
|
-
return _watchAtoms.isAtomWatched;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
Object.defineProperty(exports, "jotaiStateStore", {
|
|
67
|
-
enumerable: true,
|
|
68
|
-
get: function () {
|
|
69
|
-
return _jotaiStateStore.jotaiStateStore;
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
Object.defineProperty(exports, "jotaiSyncAdapter", {
|
|
73
|
-
enumerable: true,
|
|
74
|
-
get: function () {
|
|
75
|
-
return _jotaiSyncAdapter.jotaiSyncAdapter;
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
Object.defineProperty(exports, "jotaiToolPreset", {
|
|
79
|
-
enumerable: true,
|
|
80
|
-
get: function () {
|
|
81
|
-
return _preset.jotaiToolPreset;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
Object.defineProperty(exports, "useJotaiAtomChanges", {
|
|
85
|
-
enumerable: true,
|
|
86
|
-
get: function () {
|
|
87
|
-
return _useJotaiAtomChanges.useJotaiAtomChanges;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
Object.defineProperty(exports, "watchAtoms", {
|
|
91
|
-
enumerable: true,
|
|
92
|
-
get: function () {
|
|
93
|
-
return _watchAtoms.watchAtoms;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
Object.defineProperty(exports, "watchDefaultStoreAtoms", {
|
|
97
|
-
enumerable: true,
|
|
98
|
-
get: function () {
|
|
99
|
-
return _watchAtoms.watchDefaultStoreAtoms;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
require("./jotai/utils/snapshotProvider");
|
|
103
|
-
var _preset = require("./preset");
|
|
104
|
-
var _watchAtoms = require("./jotai/utils/watchAtoms");
|
|
105
|
-
var _useJotaiAtomChanges = require("./jotai/hooks/useJotaiAtomChanges");
|
|
106
|
-
var _JotaiModal = require("./jotai/components/JotaiModal");
|
|
107
|
-
var _JotaiAtomChangeItem = require("./jotai/components/JotaiAtomChangeItem");
|
|
108
|
-
var _JotaiAtomDetailContent = require("./jotai/components/JotaiAtomDetailContent");
|
|
109
|
-
var _JotaiAtomValueDetailContent = require("./jotai/components/JotaiAtomValueDetailContent");
|
|
110
|
-
var _JotaiIcon = require("./jotai/components/JotaiIcon");
|
|
111
|
-
var _jotaiSyncAdapter = require("./jotai/sync/jotaiSyncAdapter");
|
|
112
|
-
var _jotaiStateStore = require("./jotai/utils/jotaiStateStore");
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"JOTAI_ICON_COLOR",{enumerable:true,get:function(){return _JotaiIcon.JOTAI_ICON_COLOR}});Object.defineProperty(exports,"JotaiAtomChangeItem",{enumerable:true,get:function(){return _JotaiAtomChangeItem.JotaiAtomChangeItem}});Object.defineProperty(exports,"JotaiAtomDetailContent",{enumerable:true,get:function(){return _JotaiAtomDetailContent.JotaiAtomDetailContent}});Object.defineProperty(exports,"JotaiAtomDetailFooter",{enumerable:true,get:function(){return _JotaiAtomDetailContent.JotaiAtomDetailFooter}});Object.defineProperty(exports,"JotaiAtomValueDetailContent",{enumerable:true,get:function(){return _JotaiAtomValueDetailContent.JotaiAtomValueDetailContent}});Object.defineProperty(exports,"JotaiIcon",{enumerable:true,get:function(){return _JotaiIcon.JotaiIcon}});Object.defineProperty(exports,"JotaiModal",{enumerable:true,get:function(){return _JotaiModal.JotaiModal}});Object.defineProperty(exports,"JotaiToolView",{enumerable:true,get:function(){return _JotaiModal.JotaiToolView}});Object.defineProperty(exports,"createJotaiTool",{enumerable:true,get:function(){return _preset.createJotaiTool}});Object.defineProperty(exports,"isAtomWatched",{enumerable:true,get:function(){return _watchAtoms.isAtomWatched}});Object.defineProperty(exports,"jotaiStateStore",{enumerable:true,get:function(){return _jotaiStateStore.jotaiStateStore}});Object.defineProperty(exports,"jotaiSyncAdapter",{enumerable:true,get:function(){return _jotaiSyncAdapter.jotaiSyncAdapter}});Object.defineProperty(exports,"jotaiToolPreset",{enumerable:true,get:function(){return _preset.jotaiToolPreset}});Object.defineProperty(exports,"useJotaiAtomChanges",{enumerable:true,get:function(){return _useJotaiAtomChanges.useJotaiAtomChanges}});Object.defineProperty(exports,"watchAtoms",{enumerable:true,get:function(){return _watchAtoms.watchAtoms}});Object.defineProperty(exports,"watchDefaultStoreAtoms",{enumerable:true,get:function(){return _watchAtoms.watchDefaultStoreAtoms}});require("./jotai/utils/snapshotProvider");var _preset=require("./preset");var _watchAtoms=require("./jotai/utils/watchAtoms");var _useJotaiAtomChanges=require("./jotai/hooks/useJotaiAtomChanges");var _JotaiModal=require("./jotai/components/JotaiModal");var _JotaiAtomChangeItem=require("./jotai/components/JotaiAtomChangeItem");var _JotaiAtomDetailContent=require("./jotai/components/JotaiAtomDetailContent");var _JotaiAtomValueDetailContent=require("./jotai/components/JotaiAtomValueDetailContent");var _JotaiIcon=require("./jotai/components/JotaiIcon");var _jotaiSyncAdapter=require("./jotai/sync/jotaiSyncAdapter");var _jotaiStateStore=require("./jotai/utils/jotaiStateStore");
|
|
@@ -1,199 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.JotaiAtomBrowser = JotaiAtomBrowser;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _reactNative = require("react-native");
|
|
9
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
-
var _jotaiStateStore = require("../utils/jotaiStateStore");
|
|
11
|
-
var _testIDs = require("../utils/testIDs");
|
|
12
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
-
/**
|
|
14
|
-
* JotaiAtomBrowser
|
|
15
|
-
*
|
|
16
|
-
* Atoms tab — shows all registered Jotai atoms and their current value.
|
|
17
|
-
* Mirrors ZustandStoreBrowser.tsx from @buoy-gg/zustand: tapping a card
|
|
18
|
-
* NAVIGATES to the atom's detail screen (live editor + details + read-only
|
|
19
|
-
* tree) rather than expanding in place — the modal owns that selection.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
function getValuePreview(atom) {
|
|
23
|
-
try {
|
|
24
|
-
const value = atom.getValue();
|
|
25
|
-
if (value && typeof value === "object" && value.__buoyValueOnDevice === true) {
|
|
26
|
-
return "on device";
|
|
27
|
-
}
|
|
28
|
-
if (value === undefined) return "undefined";
|
|
29
|
-
if (value === null) return "null";
|
|
30
|
-
if (Array.isArray(value)) {
|
|
31
|
-
if (value.length === 0) return "[]";
|
|
32
|
-
return `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
33
|
-
}
|
|
34
|
-
if (typeof value === "object") {
|
|
35
|
-
const keys = Object.keys(value);
|
|
36
|
-
if (keys.length === 0) return "{}";
|
|
37
|
-
if (keys.length <= 3) return keys.join(", ");
|
|
38
|
-
return `${keys.slice(0, 2).join(", ")} +${keys.length - 2}`;
|
|
39
|
-
}
|
|
40
|
-
return String(value).slice(0, 40);
|
|
41
|
-
} catch {
|
|
42
|
-
return "";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* The card's categorical slot — the atom's write story, mirroring the
|
|
48
|
-
* zustand card's "persisted"/"in-memory" backing label.
|
|
49
|
-
*/
|
|
50
|
-
function getWriteKindLabel(atom) {
|
|
51
|
-
if (atom.writeKind === "value") return "primitive";
|
|
52
|
-
if (atom.writeKind === "action") return "custom write";
|
|
53
|
-
return atom.setValue ? "writable" : "derived";
|
|
54
|
-
}
|
|
55
|
-
function EmptyBrowserState() {
|
|
56
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
57
|
-
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-empty`
|
|
58
|
-
// scanning = "scanning for targets… and finding none". The registry is
|
|
59
|
-
// discovered, not configured, so an empty one is a scan result.
|
|
60
|
-
,
|
|
61
|
-
otto: "scanning",
|
|
62
|
-
title: "No atoms registered",
|
|
63
|
-
message: "Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
function JotaiAtomBrowser({
|
|
67
|
-
atoms,
|
|
68
|
-
searchQuery,
|
|
69
|
-
onOpenAtom
|
|
70
|
-
}) {
|
|
71
|
-
const filteredAtoms = (0, _react.useMemo)(() => {
|
|
72
|
-
if (!searchQuery) return atoms;
|
|
73
|
-
const search = searchQuery.toLowerCase();
|
|
74
|
-
return atoms.filter(a => a.label.toLowerCase().includes(search));
|
|
75
|
-
}, [atoms, searchQuery]);
|
|
76
|
-
if (filteredAtoms.length === 0 && !searchQuery) {
|
|
77
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyBrowserState, {});
|
|
78
|
-
}
|
|
79
|
-
if (filteredAtoms.length === 0 && searchQuery) {
|
|
80
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
81
|
-
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-no-match`,
|
|
82
|
-
...(0, _sharedUi.resolveListEmptyState)({
|
|
83
|
-
subject: "atoms",
|
|
84
|
-
verb: "registered",
|
|
85
|
-
search: searchQuery,
|
|
86
|
-
total: atoms.length,
|
|
87
|
-
waiting: {
|
|
88
|
-
otto: "scanning",
|
|
89
|
-
title: "No atoms registered",
|
|
90
|
-
message: "Use watchAtoms() to register your Jotai atoms."
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
96
|
-
style: styles.container,
|
|
97
|
-
contentContainerStyle: styles.scrollContent,
|
|
98
|
-
showsVerticalScrollIndicator: true,
|
|
99
|
-
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-scroll`,
|
|
100
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
101
|
-
style: styles.sectionHeader,
|
|
102
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
103
|
-
style: styles.sectionTitle,
|
|
104
|
-
children: "ATOMS"
|
|
105
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
106
|
-
style: styles.sectionCountBadge,
|
|
107
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
108
|
-
style: styles.sectionCountText,
|
|
109
|
-
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-count`,
|
|
110
|
-
children: filteredAtoms.length
|
|
111
|
-
})
|
|
112
|
-
})]
|
|
113
|
-
}), filteredAtoms.map(atom => {
|
|
114
|
-
const valuePreview = getValuePreview(atom);
|
|
115
|
-
const atomColor = _jotaiStateStore.jotaiStateStore.getAtomColor(atom.label);
|
|
116
|
-
const rowID = (0, _testIDs.atomRowTestID)(atom.label);
|
|
117
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
118
|
-
style: styles.atomRowWrapper,
|
|
119
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
|
|
120
|
-
statusDotColor: atomColor,
|
|
121
|
-
statusLabel: getWriteKindLabel(atom),
|
|
122
|
-
primaryText: atom.label,
|
|
123
|
-
secondaryText: valuePreview || undefined,
|
|
124
|
-
showChevron: true,
|
|
125
|
-
onPress: () => onOpenAtom(atom.label),
|
|
126
|
-
testID: rowID,
|
|
127
|
-
statusTestID: `${rowID}-kind`,
|
|
128
|
-
primaryTestID: `${rowID}-name`,
|
|
129
|
-
secondaryTestID: `${rowID}-preview`
|
|
130
|
-
}), atom.changeCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
131
|
-
style: [styles.absCountBadge, {
|
|
132
|
-
backgroundColor: atomColor + "22",
|
|
133
|
-
borderColor: atomColor + "55"
|
|
134
|
-
}],
|
|
135
|
-
pointerEvents: "none",
|
|
136
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
137
|
-
style: [styles.absCountText, {
|
|
138
|
-
color: atomColor
|
|
139
|
-
}],
|
|
140
|
-
testID: `${rowID}-count`,
|
|
141
|
-
children: String(atom.changeCount)
|
|
142
|
-
})
|
|
143
|
-
})]
|
|
144
|
-
}, atom.label);
|
|
145
|
-
})]
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
const styles = _reactNative.StyleSheet.create({
|
|
149
|
-
container: {
|
|
150
|
-
flex: 1
|
|
151
|
-
},
|
|
152
|
-
atomRowWrapper: {
|
|
153
|
-
position: "relative"
|
|
154
|
-
},
|
|
155
|
-
absCountBadge: {
|
|
156
|
-
position: "absolute",
|
|
157
|
-
top: 4,
|
|
158
|
-
right: 10,
|
|
159
|
-
paddingHorizontal: 5,
|
|
160
|
-
paddingVertical: 1,
|
|
161
|
-
borderRadius: 4,
|
|
162
|
-
borderWidth: 1,
|
|
163
|
-
zIndex: 1
|
|
164
|
-
},
|
|
165
|
-
absCountText: {
|
|
166
|
-
fontSize: 9,
|
|
167
|
-
fontWeight: "700",
|
|
168
|
-
fontFamily: _sharedUi.monoFont
|
|
169
|
-
},
|
|
170
|
-
scrollContent: {
|
|
171
|
-
paddingTop: 8,
|
|
172
|
-
paddingBottom: 20
|
|
173
|
-
},
|
|
174
|
-
sectionHeader: {
|
|
175
|
-
flexDirection: "row",
|
|
176
|
-
alignItems: "center",
|
|
177
|
-
paddingHorizontal: 16,
|
|
178
|
-
paddingVertical: 8,
|
|
179
|
-
gap: 8
|
|
180
|
-
},
|
|
181
|
-
sectionTitle: {
|
|
182
|
-
fontSize: 11,
|
|
183
|
-
fontWeight: "700",
|
|
184
|
-
letterSpacing: 0.5,
|
|
185
|
-
color: _sharedUi.night.color.textTertiary
|
|
186
|
-
},
|
|
187
|
-
sectionCountBadge: {
|
|
188
|
-
backgroundColor: _sharedUi.night.color.accentFill,
|
|
189
|
-
paddingHorizontal: 8,
|
|
190
|
-
paddingVertical: 2,
|
|
191
|
-
borderRadius: 4
|
|
192
|
-
},
|
|
193
|
-
sectionCountText: {
|
|
194
|
-
fontSize: 10,
|
|
195
|
-
fontWeight: "700",
|
|
196
|
-
color: _sharedUi.night.color.accent,
|
|
197
|
-
fontFamily: _sharedUi.monoFont
|
|
198
|
-
}
|
|
199
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.JotaiAtomBrowser=JotaiAtomBrowser;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _jotaiStateStore=require("../utils/jotaiStateStore");var _testIDs=require("../utils/testIDs");var _jsxRuntime=require("react/jsx-runtime");function getValuePreview(r){try{const e=r.getValue();if(e&&typeof e==="object"&&e.__buoyValueOnDevice===true){return"on device"}if(e===void 0)return"undefined";if(e===null)return"null";if(Array.isArray(e)){if(e.length===0)return"[]";return`[${e.length} item${e.length===1?"":"s"}]`}if(typeof e==="object"){const o=Object.keys(e);if(o.length===0)return"{}";if(o.length<=3)return o.join(", ");return`${o.slice(0,2).join(", ")} +${o.length-2}`}return String(e).slice(0,40)}catch{return""}}function getWriteKindLabel(r){if(r.writeKind==="value")return"primitive";if(r.writeKind==="action")return"custom write";return r.setValue?"writable":"derived"}function EmptyBrowserState(){return(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:`${_testIDs.JOTAI_TEST_ID}-atoms-empty`,otto:"scanning",title:"No atoms registered",message:"Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."})}function JotaiAtomBrowser({atoms:r,searchQuery:e,onOpenAtom:o}){const i=(0,_react.useMemo)(()=>{if(!e)return r;const t=e.toLowerCase();return r.filter(a=>a.label.toLowerCase().includes(t))},[r,e]);if(i.length===0&&!e){return(0,_jsxRuntime.jsx)(EmptyBrowserState,{})}if(i.length===0&&e){return(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:`${_testIDs.JOTAI_TEST_ID}-atoms-no-match`,...(0,_sharedUi.resolveListEmptyState)({subject:"atoms",verb:"registered",search:e,total:r.length,waiting:{otto:"scanning",title:"No atoms registered",message:"Use watchAtoms() to register your Jotai atoms."}})})}return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.container,contentContainerStyle:styles.scrollContent,showsVerticalScrollIndicator:true,testID:`${_testIDs.JOTAI_TEST_ID}-atoms-scroll`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sectionHeader,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionTitle,children:"ATOMS"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sectionCountBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionCountText,testID:`${_testIDs.JOTAI_TEST_ID}-atoms-count`,children:i.length})})]}),i.map(t=>{const a=getValuePreview(t);const s=_jotaiStateStore.jotaiStateStore.getAtomColor(t.label);const n=(0,_testIDs.atomRowTestID)(t.label);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.atomRowWrapper,children:[(0,_jsxRuntime.jsx)(_sharedUi.CompactRow,{statusDotColor:s,statusLabel:getWriteKindLabel(t),primaryText:t.label,secondaryText:a||void 0,showChevron:true,onPress:()=>o(t.label),testID:n,statusTestID:`${n}-kind`,primaryTestID:`${n}-name`,secondaryTestID:`${n}-preview`}),t.changeCount>0&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.absCountBadge,{backgroundColor:s+"22",borderColor:s+"55"}],pointerEvents:"none",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.absCountText,{color:s}],testID:`${n}-count`,children:String(t.changeCount)})})]},t.label)})]})}const styles=_reactNative.StyleSheet.create({container:{flex:1},atomRowWrapper:{position:"relative"},absCountBadge:{position:"absolute",top:4,right:10,paddingHorizontal:5,paddingVertical:1,borderRadius:4,borderWidth:1,zIndex:1},absCountText:{fontSize:9,fontWeight:"700",fontFamily:_sharedUi.monoFont},scrollContent:{paddingTop:8,paddingBottom:20},sectionHeader:{flexDirection:"row",alignItems:"center",paddingHorizontal:16,paddingVertical:8,gap:8},sectionTitle:{fontSize:11,fontWeight:"700",letterSpacing:.5,color:_sharedUi.night.color.textTertiary},sectionCountBadge:{backgroundColor:_sharedUi.night.color.accentFill,paddingHorizontal:8,paddingVertical:2,borderRadius:4},sectionCountText:{fontSize:10,fontWeight:"700",color:_sharedUi.night.color.accent,fontFamily:_sharedUi.monoFont}});
|
|
@@ -1,95 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.JotaiAtomChangeItem = void 0;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
9
|
-
var _jotaiStateStore = require("../utils/jotaiStateStore");
|
|
10
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
-
/**
|
|
12
|
-
* Compact list item for displaying a Jotai atom change
|
|
13
|
-
*
|
|
14
|
-
* Mirrors ZustandStateChangeItem.tsx — uses shared CompactRow for consistent styling
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The atom's name, exactly as registered. INIT rows used to read "Initial",
|
|
19
|
-
* so five registrations were five identical rows, and the name was
|
|
20
|
-
* capitalized ("VisibleCountAtom") into something the code doesn't contain.
|
|
21
|
-
* The INIT badge already says what kind of event it is.
|
|
22
|
-
*/
|
|
23
|
-
function getStatusLabel(_category, atomLabel) {
|
|
24
|
-
return atomLabel;
|
|
25
|
-
}
|
|
26
|
-
function getCategoryColor(category, atomLabel) {
|
|
27
|
-
if (category === "initial") return _sharedUi.night.color.textTertiary;
|
|
28
|
-
return _jotaiStateStore.jotaiStateStore.getAtomColor(atomLabel);
|
|
29
|
-
}
|
|
30
|
-
function formatCompact(value, maxLen = 20) {
|
|
31
|
-
if (value === undefined) return "undefined";
|
|
32
|
-
if (value === null) return "null";
|
|
33
|
-
if (typeof value === "boolean") return String(value);
|
|
34
|
-
if (typeof value === "number") return String(value);
|
|
35
|
-
if (typeof value === "string") {
|
|
36
|
-
const truncated = value.length > maxLen ? value.slice(0, maxLen - 1) + "…" : value;
|
|
37
|
-
return `"${truncated}"`;
|
|
38
|
-
}
|
|
39
|
-
if (Array.isArray(value)) {
|
|
40
|
-
return value.length === 0 ? "[]" : `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
41
|
-
}
|
|
42
|
-
if (typeof value === "object") {
|
|
43
|
-
const keys = Object.keys(value);
|
|
44
|
-
if (keys.length === 0) return "{}";
|
|
45
|
-
return `{${keys.slice(0, 2).join(", ")}${keys.length > 2 ? "…" : ""}}`;
|
|
46
|
-
}
|
|
47
|
-
return String(value).slice(0, maxLen);
|
|
48
|
-
}
|
|
49
|
-
function getSublabel(change) {
|
|
50
|
-
if (!change.hasValueChange) return "no change";
|
|
51
|
-
return `${formatCompact(change.prevValue)} → ${formatCompact(change.nextValue)}`;
|
|
52
|
-
}
|
|
53
|
-
function getBadgeText(change) {
|
|
54
|
-
if (change.category === "initial") return "INIT";
|
|
55
|
-
return "WRITE";
|
|
56
|
-
}
|
|
57
|
-
function getPrimaryText(change) {
|
|
58
|
-
// Changed keys only mean something for a plain object. For an array they
|
|
59
|
-
// are indices ("15, 16 +18"), so show the new value instead.
|
|
60
|
-
const next = change.nextValue;
|
|
61
|
-
const isPlainObject = typeof next === "object" && next !== null && !Array.isArray(next);
|
|
62
|
-
if (!isPlainObject) return formatCompact(next);
|
|
63
|
-
if (change.changedKeys.length > 0 && change.changedKeys.length <= 3) {
|
|
64
|
-
return change.changedKeys.join(", ");
|
|
65
|
-
}
|
|
66
|
-
if (change.changedKeys.length > 3) {
|
|
67
|
-
return `${change.changedKeys.slice(0, 2).join(", ")} +${change.changedKeys.length - 2}`;
|
|
68
|
-
}
|
|
69
|
-
return change.valuePreview || "atom()";
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Memo justified by profiling (tool-bench 2026-07-06) — see
|
|
73
|
-
// ZustandStateChangeItem (same pattern).
|
|
74
|
-
const JotaiAtomChangeItem = exports.JotaiAtomChangeItem = /*#__PURE__*/(0, _react.memo)(function JotaiAtomChangeItem({
|
|
75
|
-
change,
|
|
76
|
-
onPress,
|
|
77
|
-
testID
|
|
78
|
-
}) {
|
|
79
|
-
const statusColor = getCategoryColor(change.category, change.atomLabel);
|
|
80
|
-
const statusLabel = getStatusLabel(change.category, change.atomLabel);
|
|
81
|
-
const sublabel = getSublabel(change);
|
|
82
|
-
const primaryText = getPrimaryText(change);
|
|
83
|
-
const badgeText = getBadgeText(change);
|
|
84
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChangeRow, {
|
|
85
|
-
statusColor: statusColor,
|
|
86
|
-
statusLabel: statusLabel,
|
|
87
|
-
sublabel: sublabel,
|
|
88
|
-
primaryText: primaryText,
|
|
89
|
-
timestamp: change.timestamp,
|
|
90
|
-
badgeText: badgeText,
|
|
91
|
-
changed: change.hasValueChange,
|
|
92
|
-
onPress: () => onPress(change),
|
|
93
|
-
testID: testID
|
|
94
|
-
});
|
|
95
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.JotaiAtomChangeItem=void 0;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _jotaiStateStore=require("../utils/jotaiStateStore");var _jsxRuntime=require("react/jsx-runtime");function getStatusLabel(t,e){return e}function getCategoryColor(t,e){if(t==="initial")return _sharedUi.night.color.textTertiary;return _jotaiStateStore.jotaiStateStore.getAtomColor(e)}function formatCompact(t,e=20){if(t===void 0)return"undefined";if(t===null)return"null";if(typeof t==="boolean")return String(t);if(typeof t==="number")return String(t);if(typeof t==="string"){const r=t.length>e?t.slice(0,e-1)+"\u2026":t;return`"${r}"`}if(Array.isArray(t)){return t.length===0?"[]":`[${t.length} item${t.length===1?"":"s"}]`}if(typeof t==="object"){const r=Object.keys(t);if(r.length===0)return"{}";return`{${r.slice(0,2).join(", ")}${r.length>2?"\u2026":""}}`}return String(t).slice(0,e)}function getSublabel(t){if(!t.hasValueChange)return"no change";return`${formatCompact(t.prevValue)} \u2192 ${formatCompact(t.nextValue)}`}function getBadgeText(t){if(t.category==="initial")return"INIT";return"WRITE"}function getPrimaryText(t){const e=t.nextValue;const r=typeof e==="object"&&e!==null&&!Array.isArray(e);if(!r)return formatCompact(e);if(t.changedKeys.length>0&&t.changedKeys.length<=3){return t.changedKeys.join(", ")}if(t.changedKeys.length>3){return`${t.changedKeys.slice(0,2).join(", ")} +${t.changedKeys.length-2}`}return t.valuePreview||"atom()"}const JotaiAtomChangeItem=exports.JotaiAtomChangeItem=(0,_react.memo)(function t({change:e,onPress:r,testID:n}){const o=getCategoryColor(e.category,e.atomLabel);const i=getStatusLabel(e.category,e.atomLabel);const s=getSublabel(e);const a=getPrimaryText(e);const u=getBadgeText(e);return(0,_jsxRuntime.jsx)(_sharedUi.ChangeRow,{statusColor:o,statusLabel:i,sublabel:s,primaryText:a,timestamp:e.timestamp,badgeText:u,changed:e.hasValueChange,onPress:()=>r(e),testID:n})});
|