@buoy-gg/jotai 7.0.35 → 7.0.38
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 +32 -5
- package/lib/commonjs/index.js +1 -112
- package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +1 -199
- package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +1 -85
- 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 -67
- package/lib/commonjs/jotai/sync/jotaiSyncAdapter.js +1 -149
- 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 -162
- 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 -81
- 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 -63
- package/lib/module/jotai/sync/jotaiSyncAdapter.js +1 -146
- 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 -157
- package/lib/module/jotai/utils/writeSemantics.js +1 -43
- package/lib/module/preset.js +1 -87
- package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts +52 -2
- package/package.json +4 -4
- 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/lib/module/index.js
CHANGED
|
@@ -1,85 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @buoy-gg/jotai
|
|
5
|
-
*
|
|
6
|
-
* Jotai Atom DevTools for React Native
|
|
7
|
-
*
|
|
8
|
-
* PUBLIC API - Only these exports are supported for external use.
|
|
9
|
-
*
|
|
10
|
-
* @example Recommended setup (one line, pass your atoms)
|
|
11
|
-
* ```tsx
|
|
12
|
-
* import { getDefaultStore } from 'jotai';
|
|
13
|
-
* import { watchAtoms } from '@buoy-gg/jotai';
|
|
14
|
-
* import { countAtom } from './atoms/count';
|
|
15
|
-
* import { authAtom } from './atoms/auth';
|
|
16
|
-
*
|
|
17
|
-
* // One call, anywhere at module scope or in your root layout:
|
|
18
|
-
* watchAtoms(getDefaultStore(), {
|
|
19
|
-
* countAtom,
|
|
20
|
-
* authAtom,
|
|
21
|
-
* });
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* @example With a custom store (Provider-based)
|
|
25
|
-
* ```tsx
|
|
26
|
-
* import { createStore } from 'jotai';
|
|
27
|
-
* import { watchAtoms } from '@buoy-gg/jotai';
|
|
28
|
-
*
|
|
29
|
-
* const myStore = createStore();
|
|
30
|
-
*
|
|
31
|
-
* watchAtoms(myStore, { countAtom, authAtom });
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
// Side-effect: registers the Time Machine snapshot provider
|
|
36
|
-
import "./jotai/utils/snapshotProvider";
|
|
37
|
-
|
|
38
|
-
// =============================================================================
|
|
39
|
-
// PRESET (Primary entry point for FloatingDevTools)
|
|
40
|
-
// =============================================================================
|
|
41
|
-
export { jotaiToolPreset, createJotaiTool } from "./preset";
|
|
42
|
-
|
|
43
|
-
// =============================================================================
|
|
44
|
-
// WATCH ATOMS (Recommended — subscribe-only, non-intrusive)
|
|
45
|
-
// =============================================================================
|
|
46
|
-
export { watchAtoms } from "./jotai/utils/watchAtoms";
|
|
47
|
-
|
|
48
|
-
// =============================================================================
|
|
49
|
-
// CONVENIENCE (Default store shortcut)
|
|
50
|
-
// =============================================================================
|
|
51
|
-
export { watchDefaultStoreAtoms } from "./jotai/utils/watchAtoms";
|
|
52
|
-
|
|
53
|
-
// =============================================================================
|
|
54
|
-
// UTILITIES
|
|
55
|
-
// =============================================================================
|
|
56
|
-
export { isAtomWatched } from "./jotai/utils/watchAtoms";
|
|
57
|
-
// =============================================================================
|
|
58
|
-
// HOOKS (For consuming Jotai atom data)
|
|
59
|
-
// =============================================================================
|
|
60
|
-
export { useJotaiAtomChanges } from "./jotai/hooks/useJotaiAtomChanges";
|
|
61
|
-
// =============================================================================
|
|
62
|
-
// COMPONENTS (For custom UI implementations)
|
|
63
|
-
// =============================================================================
|
|
64
|
-
// `JotaiToolView` is the same tool rendered inline (header bar + body + footer)
|
|
65
|
-
// instead of inside a JsModal — for hosts that show tools in a panel.
|
|
66
|
-
export { JotaiModal, JotaiToolView } from "./jotai/components/JotaiModal";
|
|
67
|
-
export { JotaiAtomChangeItem } from "./jotai/components/JotaiAtomChangeItem";
|
|
68
|
-
export { JotaiAtomDetailContent, JotaiAtomDetailFooter } from "./jotai/components/JotaiAtomDetailContent";
|
|
69
|
-
export { JotaiAtomValueDetailContent } from "./jotai/components/JotaiAtomValueDetailContent";
|
|
70
|
-
export { JotaiIcon, JOTAI_ICON_COLOR } from "./jotai/components/JotaiIcon";
|
|
71
|
-
|
|
72
|
-
// =============================================================================
|
|
73
|
-
// EXTERNAL SYNC (Adapter for @buoy-gg/external-sync's useExternalSync)
|
|
74
|
-
// =============================================================================
|
|
75
|
-
export { jotaiSyncAdapter } from "./jotai/sync/jotaiSyncAdapter";
|
|
76
|
-
|
|
77
|
-
// =============================================================================
|
|
78
|
-
// TYPES
|
|
79
|
-
// =============================================================================
|
|
80
|
-
|
|
81
|
-
// =============================================================================
|
|
82
|
-
// INTERNAL EXPORTS (For @buoy-gg/* packages only - not part of public API)
|
|
83
|
-
// =============================================================================
|
|
84
|
-
/** @internal */
|
|
85
|
-
export { jotaiStateStore } from "./jotai/utils/jotaiStateStore";
|
|
1
|
+
"use strict";import"./jotai/utils/snapshotProvider";export{jotaiToolPreset,createJotaiTool}from"./preset";export{watchAtoms}from"./jotai/utils/watchAtoms";export{watchDefaultStoreAtoms}from"./jotai/utils/watchAtoms";export{isAtomWatched}from"./jotai/utils/watchAtoms";export{useJotaiAtomChanges}from"./jotai/hooks/useJotaiAtomChanges";export{JotaiModal,JotaiToolView}from"./jotai/components/JotaiModal";export{JotaiAtomChangeItem}from"./jotai/components/JotaiAtomChangeItem";export{JotaiAtomDetailContent,JotaiAtomDetailFooter}from"./jotai/components/JotaiAtomDetailContent";export{JotaiAtomValueDetailContent}from"./jotai/components/JotaiAtomValueDetailContent";export{JotaiIcon,JOTAI_ICON_COLOR}from"./jotai/components/JotaiIcon";export{jotaiSyncAdapter}from"./jotai/sync/jotaiSyncAdapter";export{jotaiStateStore}from"./jotai/utils/jotaiStateStore";
|
|
@@ -1,195 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* JotaiAtomBrowser
|
|
5
|
-
*
|
|
6
|
-
* Atoms tab — shows all registered Jotai atoms and their current value.
|
|
7
|
-
* Mirrors ZustandStoreBrowser.tsx from @buoy-gg/zustand: tapping a card
|
|
8
|
-
* NAVIGATES to the atom's detail screen (live editor + details + read-only
|
|
9
|
-
* tree) rather than expanding in place — the modal owns that selection.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { useMemo } from "react";
|
|
13
|
-
import { View, Text, StyleSheet, ScrollView } from "react-native";
|
|
14
|
-
import { CompactRow, night, ToolEmptyState, resolveListEmptyState, monoFont } from "@buoy-gg/shared-ui";
|
|
15
|
-
import { jotaiStateStore } from "../utils/jotaiStateStore";
|
|
16
|
-
import { JOTAI_TEST_ID, atomRowTestID } from "../utils/testIDs";
|
|
17
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
-
function getValuePreview(atom) {
|
|
19
|
-
try {
|
|
20
|
-
const value = atom.getValue();
|
|
21
|
-
if (value && typeof value === "object" && value.__buoyValueOnDevice === true) {
|
|
22
|
-
return "on device";
|
|
23
|
-
}
|
|
24
|
-
if (value === undefined) return "undefined";
|
|
25
|
-
if (value === null) return "null";
|
|
26
|
-
if (Array.isArray(value)) {
|
|
27
|
-
if (value.length === 0) return "[]";
|
|
28
|
-
return `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
29
|
-
}
|
|
30
|
-
if (typeof value === "object") {
|
|
31
|
-
const keys = Object.keys(value);
|
|
32
|
-
if (keys.length === 0) return "{}";
|
|
33
|
-
if (keys.length <= 3) return keys.join(", ");
|
|
34
|
-
return `${keys.slice(0, 2).join(", ")} +${keys.length - 2}`;
|
|
35
|
-
}
|
|
36
|
-
return String(value).slice(0, 40);
|
|
37
|
-
} catch {
|
|
38
|
-
return "";
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* The card's categorical slot — the atom's write story, mirroring the
|
|
44
|
-
* zustand card's "persisted"/"in-memory" backing label.
|
|
45
|
-
*/
|
|
46
|
-
function getWriteKindLabel(atom) {
|
|
47
|
-
if (atom.writeKind === "value") return "primitive";
|
|
48
|
-
if (atom.writeKind === "action") return "custom write";
|
|
49
|
-
return atom.setValue ? "writable" : "derived";
|
|
50
|
-
}
|
|
51
|
-
function EmptyBrowserState() {
|
|
52
|
-
return /*#__PURE__*/_jsx(ToolEmptyState, {
|
|
53
|
-
testID: `${JOTAI_TEST_ID}-atoms-empty`
|
|
54
|
-
// scanning = "scanning for targets… and finding none". The registry is
|
|
55
|
-
// discovered, not configured, so an empty one is a scan result.
|
|
56
|
-
,
|
|
57
|
-
otto: "scanning",
|
|
58
|
-
title: "No atoms registered",
|
|
59
|
-
message: "Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
export function JotaiAtomBrowser({
|
|
63
|
-
atoms,
|
|
64
|
-
searchQuery,
|
|
65
|
-
onOpenAtom
|
|
66
|
-
}) {
|
|
67
|
-
const filteredAtoms = useMemo(() => {
|
|
68
|
-
if (!searchQuery) return atoms;
|
|
69
|
-
const search = searchQuery.toLowerCase();
|
|
70
|
-
return atoms.filter(a => a.label.toLowerCase().includes(search));
|
|
71
|
-
}, [atoms, searchQuery]);
|
|
72
|
-
if (filteredAtoms.length === 0 && !searchQuery) {
|
|
73
|
-
return /*#__PURE__*/_jsx(EmptyBrowserState, {});
|
|
74
|
-
}
|
|
75
|
-
if (filteredAtoms.length === 0 && searchQuery) {
|
|
76
|
-
return /*#__PURE__*/_jsx(ToolEmptyState, {
|
|
77
|
-
testID: `${JOTAI_TEST_ID}-atoms-no-match`,
|
|
78
|
-
...resolveListEmptyState({
|
|
79
|
-
subject: "atoms",
|
|
80
|
-
verb: "registered",
|
|
81
|
-
search: searchQuery,
|
|
82
|
-
total: atoms.length,
|
|
83
|
-
waiting: {
|
|
84
|
-
otto: "scanning",
|
|
85
|
-
title: "No atoms registered",
|
|
86
|
-
message: "Use watchAtoms() to register your Jotai atoms."
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return /*#__PURE__*/_jsxs(ScrollView, {
|
|
92
|
-
style: styles.container,
|
|
93
|
-
contentContainerStyle: styles.scrollContent,
|
|
94
|
-
showsVerticalScrollIndicator: true,
|
|
95
|
-
testID: `${JOTAI_TEST_ID}-atoms-scroll`,
|
|
96
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
97
|
-
style: styles.sectionHeader,
|
|
98
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
99
|
-
style: styles.sectionTitle,
|
|
100
|
-
children: "ATOMS"
|
|
101
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
102
|
-
style: styles.sectionCountBadge,
|
|
103
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
104
|
-
style: styles.sectionCountText,
|
|
105
|
-
testID: `${JOTAI_TEST_ID}-atoms-count`,
|
|
106
|
-
children: filteredAtoms.length
|
|
107
|
-
})
|
|
108
|
-
})]
|
|
109
|
-
}), filteredAtoms.map(atom => {
|
|
110
|
-
const valuePreview = getValuePreview(atom);
|
|
111
|
-
const atomColor = jotaiStateStore.getAtomColor(atom.label);
|
|
112
|
-
const rowID = atomRowTestID(atom.label);
|
|
113
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
114
|
-
style: styles.atomRowWrapper,
|
|
115
|
-
children: [/*#__PURE__*/_jsx(CompactRow, {
|
|
116
|
-
statusDotColor: atomColor,
|
|
117
|
-
statusLabel: getWriteKindLabel(atom),
|
|
118
|
-
primaryText: atom.label,
|
|
119
|
-
secondaryText: valuePreview || undefined,
|
|
120
|
-
showChevron: true,
|
|
121
|
-
onPress: () => onOpenAtom(atom.label),
|
|
122
|
-
testID: rowID,
|
|
123
|
-
statusTestID: `${rowID}-kind`,
|
|
124
|
-
primaryTestID: `${rowID}-name`,
|
|
125
|
-
secondaryTestID: `${rowID}-preview`
|
|
126
|
-
}), atom.changeCount > 0 && /*#__PURE__*/_jsx(View, {
|
|
127
|
-
style: [styles.absCountBadge, {
|
|
128
|
-
backgroundColor: atomColor + "22",
|
|
129
|
-
borderColor: atomColor + "55"
|
|
130
|
-
}],
|
|
131
|
-
pointerEvents: "none",
|
|
132
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
133
|
-
style: [styles.absCountText, {
|
|
134
|
-
color: atomColor
|
|
135
|
-
}],
|
|
136
|
-
testID: `${rowID}-count`,
|
|
137
|
-
children: String(atom.changeCount)
|
|
138
|
-
})
|
|
139
|
-
})]
|
|
140
|
-
}, atom.label);
|
|
141
|
-
})]
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
const styles = StyleSheet.create({
|
|
145
|
-
container: {
|
|
146
|
-
flex: 1
|
|
147
|
-
},
|
|
148
|
-
atomRowWrapper: {
|
|
149
|
-
position: "relative"
|
|
150
|
-
},
|
|
151
|
-
absCountBadge: {
|
|
152
|
-
position: "absolute",
|
|
153
|
-
top: 4,
|
|
154
|
-
right: 10,
|
|
155
|
-
paddingHorizontal: 5,
|
|
156
|
-
paddingVertical: 1,
|
|
157
|
-
borderRadius: 4,
|
|
158
|
-
borderWidth: 1,
|
|
159
|
-
zIndex: 1
|
|
160
|
-
},
|
|
161
|
-
absCountText: {
|
|
162
|
-
fontSize: 9,
|
|
163
|
-
fontWeight: "700",
|
|
164
|
-
fontFamily: monoFont
|
|
165
|
-
},
|
|
166
|
-
scrollContent: {
|
|
167
|
-
paddingTop: 8,
|
|
168
|
-
paddingBottom: 20
|
|
169
|
-
},
|
|
170
|
-
sectionHeader: {
|
|
171
|
-
flexDirection: "row",
|
|
172
|
-
alignItems: "center",
|
|
173
|
-
paddingHorizontal: 16,
|
|
174
|
-
paddingVertical: 8,
|
|
175
|
-
gap: 8
|
|
176
|
-
},
|
|
177
|
-
sectionTitle: {
|
|
178
|
-
fontSize: 11,
|
|
179
|
-
fontWeight: "700",
|
|
180
|
-
letterSpacing: 0.5,
|
|
181
|
-
color: night.color.textTertiary
|
|
182
|
-
},
|
|
183
|
-
sectionCountBadge: {
|
|
184
|
-
backgroundColor: night.color.accentFill,
|
|
185
|
-
paddingHorizontal: 8,
|
|
186
|
-
paddingVertical: 2,
|
|
187
|
-
borderRadius: 4
|
|
188
|
-
},
|
|
189
|
-
sectionCountText: {
|
|
190
|
-
fontSize: 10,
|
|
191
|
-
fontWeight: "700",
|
|
192
|
-
color: night.color.accent,
|
|
193
|
-
fontFamily: monoFont
|
|
194
|
-
}
|
|
195
|
-
});
|
|
1
|
+
"use strict";import{useMemo}from"react";import{View,Text,StyleSheet,ScrollView}from"react-native";import{CompactRow,night,ToolEmptyState,resolveListEmptyState,monoFont}from"@buoy-gg/shared-ui";import{jotaiStateStore}from"../utils/jotaiStateStore";import{JOTAI_TEST_ID,atomRowTestID}from"../utils/testIDs";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function getValuePreview(t){try{const e=t.getValue();if(e&&"object"==typeof e&&!0===e.__buoyValueOnDevice)return"on device";if(void 0===e)return"undefined";if(null===e)return"null";if(Array.isArray(e))return 0===e.length?"[]":`[${e.length} item${1===e.length?"":"s"}]`;if("object"==typeof e){const t=Object.keys(e);return 0===t.length?"{}":t.length<=3?t.join(", "):`${t.slice(0,2).join(", ")} +${t.length-2}`}return String(e).slice(0,40)}catch{return""}}function getWriteKindLabel(t){return"value"===t.writeKind?"primitive":"action"===t.writeKind?"custom write":t.setValue?"writable":"derived"}function EmptyBrowserState(){return _jsx(ToolEmptyState,{testID:`${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."})}export function JotaiAtomBrowser({atoms:t,searchQuery:e,onOpenAtom:o}){const r=useMemo(()=>{if(!e)return t;const o=e.toLowerCase();return t.filter(t=>t.label.toLowerCase().includes(o))},[t,e]);return 0!==r.length||e?0===r.length&&e?_jsx(ToolEmptyState,{testID:`${JOTAI_TEST_ID}-atoms-no-match`,...resolveListEmptyState({subject:"atoms",verb:"registered",search:e,total:t.length,waiting:{otto:"scanning",title:"No atoms registered",message:"Use watchAtoms() to register your Jotai atoms."}})}):_jsxs(ScrollView,{style:styles.container,contentContainerStyle:styles.scrollContent,showsVerticalScrollIndicator:!0,testID:`${JOTAI_TEST_ID}-atoms-scroll`,children:[_jsxs(View,{style:styles.sectionHeader,children:[_jsx(Text,{style:styles.sectionTitle,children:"ATOMS"}),_jsx(View,{style:styles.sectionCountBadge,children:_jsx(Text,{style:styles.sectionCountText,testID:`${JOTAI_TEST_ID}-atoms-count`,children:r.length})})]}),r.map(t=>{const e=getValuePreview(t),r=jotaiStateStore.getAtomColor(t.label),n=atomRowTestID(t.label);return _jsxs(View,{style:styles.atomRowWrapper,children:[_jsx(CompactRow,{statusDotColor:r,statusLabel:getWriteKindLabel(t),primaryText:t.label,secondaryText:e||void 0,showChevron:!0,onPress:()=>o(t.label),testID:n,statusTestID:`${n}-kind`,primaryTestID:`${n}-name`,secondaryTestID:`${n}-preview`}),t.changeCount>0&&_jsx(View,{style:[styles.absCountBadge,{backgroundColor:r+"22",borderColor:r+"55"}],pointerEvents:"none",children:_jsx(Text,{style:[styles.absCountText,{color:r}],testID:`${n}-count`,children:String(t.changeCount)})})]},t.label)})]}):_jsx(EmptyBrowserState,{})}const styles=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: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:night.color.textTertiary},sectionCountBadge:{backgroundColor:night.color.accentFill,paddingHorizontal:8,paddingVertical:2,borderRadius:4},sectionCountText:{fontSize:10,fontWeight:"700",color:night.color.accent,fontFamily:monoFont}});
|
|
@@ -1,81 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Compact list item for displaying a Jotai atom change
|
|
5
|
-
*
|
|
6
|
-
* Mirrors ZustandStateChangeItem.tsx — uses shared CompactRow for consistent styling
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { memo } from "react";
|
|
10
|
-
import { ChangeRow, night } from "@buoy-gg/shared-ui";
|
|
11
|
-
import { jotaiStateStore } from "../utils/jotaiStateStore";
|
|
12
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
-
function getStatusLabel(category, atomLabel) {
|
|
14
|
-
if (category === "initial") return "Initial";
|
|
15
|
-
return atomLabel.charAt(0).toUpperCase() + atomLabel.slice(1);
|
|
16
|
-
}
|
|
17
|
-
function getCategoryColor(category, atomLabel) {
|
|
18
|
-
if (category === "initial") return night.color.textTertiary;
|
|
19
|
-
return jotaiStateStore.getAtomColor(atomLabel);
|
|
20
|
-
}
|
|
21
|
-
function formatCompact(value, maxLen = 20) {
|
|
22
|
-
if (value === undefined) return "undefined";
|
|
23
|
-
if (value === null) return "null";
|
|
24
|
-
if (typeof value === "boolean") return String(value);
|
|
25
|
-
if (typeof value === "number") return String(value);
|
|
26
|
-
if (typeof value === "string") {
|
|
27
|
-
const truncated = value.length > maxLen ? value.slice(0, maxLen - 1) + "…" : value;
|
|
28
|
-
return `"${truncated}"`;
|
|
29
|
-
}
|
|
30
|
-
if (Array.isArray(value)) {
|
|
31
|
-
return value.length === 0 ? "[]" : `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
32
|
-
}
|
|
33
|
-
if (typeof value === "object") {
|
|
34
|
-
const keys = Object.keys(value);
|
|
35
|
-
if (keys.length === 0) return "{}";
|
|
36
|
-
return `{${keys.slice(0, 2).join(", ")}${keys.length > 2 ? "…" : ""}}`;
|
|
37
|
-
}
|
|
38
|
-
return String(value).slice(0, maxLen);
|
|
39
|
-
}
|
|
40
|
-
function getSublabel(change) {
|
|
41
|
-
if (!change.hasValueChange) return "no change";
|
|
42
|
-
return `${formatCompact(change.prevValue)} → ${formatCompact(change.nextValue)}`;
|
|
43
|
-
}
|
|
44
|
-
function getBadgeText(change) {
|
|
45
|
-
if (change.category === "initial") return "INIT";
|
|
46
|
-
return "WRITE";
|
|
47
|
-
}
|
|
48
|
-
function getPrimaryText(change) {
|
|
49
|
-
if (change.changedKeys.length > 0 && change.changedKeys.length <= 3) {
|
|
50
|
-
return change.changedKeys.join(", ");
|
|
51
|
-
}
|
|
52
|
-
if (change.changedKeys.length > 3) {
|
|
53
|
-
return `${change.changedKeys.slice(0, 2).join(", ")} +${change.changedKeys.length - 2}`;
|
|
54
|
-
}
|
|
55
|
-
return change.valuePreview || "atom()";
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Memo justified by profiling (tool-bench 2026-07-06) — see
|
|
59
|
-
// ZustandStateChangeItem (same pattern).
|
|
60
|
-
export const JotaiAtomChangeItem = /*#__PURE__*/memo(function JotaiAtomChangeItem({
|
|
61
|
-
change,
|
|
62
|
-
onPress,
|
|
63
|
-
testID
|
|
64
|
-
}) {
|
|
65
|
-
const statusColor = getCategoryColor(change.category, change.atomLabel);
|
|
66
|
-
const statusLabel = getStatusLabel(change.category, change.atomLabel);
|
|
67
|
-
const sublabel = getSublabel(change);
|
|
68
|
-
const primaryText = getPrimaryText(change);
|
|
69
|
-
const badgeText = getBadgeText(change);
|
|
70
|
-
return /*#__PURE__*/_jsx(ChangeRow, {
|
|
71
|
-
statusColor: statusColor,
|
|
72
|
-
statusLabel: statusLabel,
|
|
73
|
-
sublabel: sublabel,
|
|
74
|
-
primaryText: primaryText,
|
|
75
|
-
timestamp: change.timestamp,
|
|
76
|
-
badgeText: badgeText,
|
|
77
|
-
changed: change.hasValueChange,
|
|
78
|
-
onPress: () => onPress(change),
|
|
79
|
-
testID: testID
|
|
80
|
-
});
|
|
81
|
-
});
|
|
1
|
+
"use strict";import{memo}from"react";import{ChangeRow,night}from"@buoy-gg/shared-ui";import{jotaiStateStore}from"../utils/jotaiStateStore";import{jsx as _jsx}from"react/jsx-runtime";function getStatusLabel(t,e){return"initial"===t?"Initial":e.charAt(0).toUpperCase()+e.slice(1)}function getCategoryColor(t,e){return"initial"===t?night.color.textTertiary:jotaiStateStore.getAtomColor(e)}function formatCompact(t,e=20){if(void 0===t)return"undefined";if(null===t)return"null";if("boolean"==typeof t)return String(t);if("number"==typeof t)return String(t);if("string"==typeof t)return`"${t.length>e?t.slice(0,e-1)+"…":t}"`;if(Array.isArray(t))return 0===t.length?"[]":`[${t.length} item${1===t.length?"":"s"}]`;if("object"==typeof t){const e=Object.keys(t);return 0===e.length?"{}":`{${e.slice(0,2).join(", ")}${e.length>2?"…":""}}`}return String(t).slice(0,e)}function getSublabel(t){return t.hasValueChange?`${formatCompact(t.prevValue)} → ${formatCompact(t.nextValue)}`:"no change"}function getBadgeText(t){return"initial"===t.category?"INIT":"WRITE"}function getPrimaryText(t){return t.changedKeys.length>0&&t.changedKeys.length<=3?t.changedKeys.join(", "):t.changedKeys.length>3?`${t.changedKeys.slice(0,2).join(", ")} +${t.changedKeys.length-2}`:t.valuePreview||"atom()"}export const JotaiAtomChangeItem=memo(function({change:t,onPress:e,testID:r}){const n=getCategoryColor(t.category,t.atomLabel),a=getStatusLabel(t.category,t.atomLabel),o=getSublabel(t),i=getPrimaryText(t),g=getBadgeText(t);return _jsx(ChangeRow,{statusColor:n,statusLabel:a,sublabel:o,primaryText:i,timestamp:t.timestamp,badgeText:g,changed:t.hasValueChange,onPress:()=>e(t),testID:r})});
|