@buoy-gg/jotai 2.1.11 → 2.1.13
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/LICENSE +58 -0
- package/lib/commonjs/index.js +1 -91
- package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +1 -300
- package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +1 -113
- package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +1 -754
- package/lib/commonjs/jotai/components/JotaiEventFilterView.js +1 -305
- package/lib/commonjs/jotai/components/JotaiIcon.js +1 -35
- package/lib/commonjs/jotai/components/JotaiModal.js +1 -567
- package/lib/commonjs/jotai/components/index.js +1 -59
- package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +1 -83
- package/lib/commonjs/jotai/index.js +1 -85
- package/lib/commonjs/jotai/utils/jotaiStateStore.js +1 -322
- package/lib/commonjs/jotai/utils/watchAtoms.js +1 -149
- package/lib/commonjs/preset.js +1 -98
- package/lib/module/index.js +1 -74
- package/lib/module/jotai/components/JotaiAtomBrowser.js +1 -296
- package/lib/module/jotai/components/JotaiAtomChangeItem.js +1 -109
- package/lib/module/jotai/components/JotaiAtomDetailContent.js +1 -748
- package/lib/module/jotai/components/JotaiEventFilterView.js +1 -301
- package/lib/module/jotai/components/JotaiIcon.js +1 -31
- package/lib/module/jotai/components/JotaiModal.js +1 -563
- package/lib/module/jotai/components/index.js +1 -8
- package/lib/module/jotai/hooks/useJotaiAtomChanges.js +1 -79
- package/lib/module/jotai/index.js +1 -10
- package/lib/module/jotai/utils/jotaiStateStore.js +1 -318
- package/lib/module/jotai/utils/watchAtoms.js +1 -144
- package/lib/module/preset.js +1 -94
- package/package.json +10 -10
- 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/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/components/index.d.ts.map +0 -1
- package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +0 -1
- package/lib/typescript/jotai/index.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/watchAtoms.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
package/lib/commonjs/preset.js
CHANGED
|
@@ -1,98 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.createJotaiTool = createJotaiTool;
|
|
7
|
-
exports.jotaiToolPreset = void 0;
|
|
8
|
-
var _JotaiModal = require("./jotai/components/JotaiModal");
|
|
9
|
-
var _JotaiIcon = require("./jotai/components/JotaiIcon");
|
|
10
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
-
/**
|
|
12
|
-
* Pre-configured Jotai DevTools preset for FloatingDevTools
|
|
13
|
-
*
|
|
14
|
-
* ZERO-CONFIG: This preset is auto-discovered by FloatingDevTools!
|
|
15
|
-
* Just install @buoy-gg/jotai and call watchAtoms() with your atoms.
|
|
16
|
-
*
|
|
17
|
-
* @example Automatic (recommended)
|
|
18
|
-
* ```tsx
|
|
19
|
-
* import { getDefaultStore } from 'jotai';
|
|
20
|
-
* import { watchAtoms } from '@buoy-gg/jotai';
|
|
21
|
-
* import { countAtom, authAtom } from './atoms';
|
|
22
|
-
*
|
|
23
|
-
* watchAtoms(getDefaultStore(), { countAtom, authAtom });
|
|
24
|
-
*
|
|
25
|
-
* // The Jotai tool appears automatically in FloatingDevTools!
|
|
26
|
-
* <FloatingDevTools />
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* @example Manual (only for custom configuration)
|
|
30
|
-
* ```tsx
|
|
31
|
-
* import { createJotaiTool } from '@buoy-gg/jotai';
|
|
32
|
-
*
|
|
33
|
-
* const customJotaiTool = createJotaiTool({
|
|
34
|
-
* name: "ATOMS",
|
|
35
|
-
* iconColor: "#6C47FF",
|
|
36
|
-
* });
|
|
37
|
-
*
|
|
38
|
-
* <FloatingDevTools apps={[customJotaiTool]} />
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Pre-configured Jotai DevTools preset for FloatingDevTools.
|
|
44
|
-
* Includes:
|
|
45
|
-
* - Live atom change monitoring
|
|
46
|
-
* - Atom value inspection (JSON viewer)
|
|
47
|
-
* - Value diff visualization (tree + split)
|
|
48
|
-
* - Filter by atom label
|
|
49
|
-
* - Changed keys tracking for object atoms
|
|
50
|
-
*/
|
|
51
|
-
const jotaiToolPreset = exports.jotaiToolPreset = {
|
|
52
|
-
id: "jotai",
|
|
53
|
-
name: "JOTAI",
|
|
54
|
-
description: "Jotai atom & state inspector",
|
|
55
|
-
slot: "both",
|
|
56
|
-
icon: ({
|
|
57
|
-
size
|
|
58
|
-
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_JotaiIcon.JotaiIcon, {
|
|
59
|
-
size: size
|
|
60
|
-
}),
|
|
61
|
-
component: _JotaiModal.JotaiModal,
|
|
62
|
-
props: {
|
|
63
|
-
enableSharedModalDimensions: false
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Create a custom Jotai DevTools configuration.
|
|
69
|
-
* Use this if you want to override default settings.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```tsx
|
|
73
|
-
* import { createJotaiTool } from '@buoy-gg/jotai';
|
|
74
|
-
*
|
|
75
|
-
* const myJotaiTool = createJotaiTool({
|
|
76
|
-
* name: "ATOMS",
|
|
77
|
-
* iconColor: "#6C47FF",
|
|
78
|
-
* });
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
function createJotaiTool(options) {
|
|
82
|
-
return {
|
|
83
|
-
id: options?.id || "jotai",
|
|
84
|
-
name: options?.name || "JOTAI",
|
|
85
|
-
description: options?.description || "Jotai atom & state inspector",
|
|
86
|
-
slot: "both",
|
|
87
|
-
icon: ({
|
|
88
|
-
size
|
|
89
|
-
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_JotaiIcon.JotaiIcon, {
|
|
90
|
-
size: size,
|
|
91
|
-
color: options?.iconColor
|
|
92
|
-
}),
|
|
93
|
-
component: _JotaiModal.JotaiModal,
|
|
94
|
-
props: {
|
|
95
|
-
enableSharedModalDimensions: options?.enableSharedModalDimensions !== undefined ? options.enableSharedModalDimensions : false
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.createJotaiTool=createJotaiTool,exports.jotaiToolPreset=void 0;var _JotaiModal=require("./jotai/components/JotaiModal"),_JotaiIcon=require("./jotai/components/JotaiIcon"),_jsxRuntime=require("react/jsx-runtime");const jotaiToolPreset=exports.jotaiToolPreset={id:"jotai",name:"JOTAI",description:"Jotai atom & state inspector",slot:"both",icon:({size:o})=>(0,_jsxRuntime.jsx)(_JotaiIcon.JotaiIcon,{size:o}),component:_JotaiModal.JotaiModal,props:{enableSharedModalDimensions:!1}};function createJotaiTool(o){return{id:o?.id||"jotai",name:o?.name||"JOTAI",description:o?.description||"Jotai atom & state inspector",slot:"both",icon:({size:e})=>(0,_jsxRuntime.jsx)(_JotaiIcon.JotaiIcon,{size:e,color:o?.iconColor}),component:_JotaiModal.JotaiModal,props:{enableSharedModalDimensions:void 0!==o?.enableSharedModalDimensions&&o.enableSharedModalDimensions}}}
|
package/lib/module/index.js
CHANGED
|
@@ -1,74 +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
|
-
// =============================================================================
|
|
36
|
-
// PRESET (Primary entry point for FloatingDevTools)
|
|
37
|
-
// =============================================================================
|
|
38
|
-
export { jotaiToolPreset, createJotaiTool } from "./preset";
|
|
39
|
-
|
|
40
|
-
// =============================================================================
|
|
41
|
-
// WATCH ATOMS (Recommended — subscribe-only, non-intrusive)
|
|
42
|
-
// =============================================================================
|
|
43
|
-
export { watchAtoms } from "./jotai/utils/watchAtoms";
|
|
44
|
-
|
|
45
|
-
// =============================================================================
|
|
46
|
-
// CONVENIENCE (Default store shortcut)
|
|
47
|
-
// =============================================================================
|
|
48
|
-
export { watchDefaultStoreAtoms } from "./jotai/utils/watchAtoms";
|
|
49
|
-
|
|
50
|
-
// =============================================================================
|
|
51
|
-
// UTILITIES
|
|
52
|
-
// =============================================================================
|
|
53
|
-
export { isAtomWatched } from "./jotai/utils/watchAtoms";
|
|
54
|
-
// =============================================================================
|
|
55
|
-
// HOOKS (For consuming Jotai atom data)
|
|
56
|
-
// =============================================================================
|
|
57
|
-
export { useJotaiAtomChanges } from "./jotai/hooks/useJotaiAtomChanges";
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// COMPONENTS (For custom UI implementations)
|
|
60
|
-
// =============================================================================
|
|
61
|
-
export { JotaiModal } from "./jotai/components/JotaiModal";
|
|
62
|
-
export { JotaiAtomChangeItem } from "./jotai/components/JotaiAtomChangeItem";
|
|
63
|
-
export { JotaiAtomDetailContent, JotaiAtomDetailFooter } from "./jotai/components/JotaiAtomDetailContent";
|
|
64
|
-
export { JotaiIcon, JOTAI_ICON_COLOR } from "./jotai/components/JotaiIcon";
|
|
65
|
-
|
|
66
|
-
// =============================================================================
|
|
67
|
-
// TYPES
|
|
68
|
-
// =============================================================================
|
|
69
|
-
|
|
70
|
-
// =============================================================================
|
|
71
|
-
// INTERNAL EXPORTS (For @buoy-gg/* packages only - not part of public API)
|
|
72
|
-
// =============================================================================
|
|
73
|
-
/** @internal */
|
|
74
|
-
export { jotaiStateStore } from "./jotai/utils/jotaiStateStore";
|
|
1
|
+
"use strict";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}from"./jotai/components/JotaiModal";export{JotaiAtomChangeItem}from"./jotai/components/JotaiAtomChangeItem";export{JotaiAtomDetailContent,JotaiAtomDetailFooter}from"./jotai/components/JotaiAtomDetailContent";export{JotaiIcon,JOTAI_ICON_COLOR}from"./jotai/components/JotaiIcon";export{jotaiStateStore}from"./jotai/utils/jotaiStateStore";
|
|
@@ -1,296 +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.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { useState, useMemo, useCallback } from "react";
|
|
11
|
-
import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
|
|
12
|
-
import { CompactRow, macOSColors, buoyColors, Box, ExpandedInfoRow, PillBadge, parseValue } from "@buoy-gg/shared-ui";
|
|
13
|
-
import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
|
|
14
|
-
import { jotaiStateStore } from "../utils/jotaiStateStore";
|
|
15
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
16
|
-
function getValuePreview(atom) {
|
|
17
|
-
try {
|
|
18
|
-
const value = atom.getValue();
|
|
19
|
-
if (value === undefined) return "undefined";
|
|
20
|
-
if (value === null) return "null";
|
|
21
|
-
if (Array.isArray(value)) {
|
|
22
|
-
if (value.length === 0) return "[]";
|
|
23
|
-
return `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
24
|
-
}
|
|
25
|
-
if (typeof value === "object") {
|
|
26
|
-
const keys = Object.keys(value);
|
|
27
|
-
if (keys.length === 0) return "{}";
|
|
28
|
-
if (keys.length <= 3) return keys.join(", ");
|
|
29
|
-
return `${keys.slice(0, 2).join(", ")} +${keys.length - 2}`;
|
|
30
|
-
}
|
|
31
|
-
return String(value).slice(0, 40);
|
|
32
|
-
} catch {
|
|
33
|
-
return "";
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function getValueType(atom) {
|
|
37
|
-
try {
|
|
38
|
-
const value = atom.getValue();
|
|
39
|
-
if (value === null) return "null";
|
|
40
|
-
if (value === undefined) return "undefined";
|
|
41
|
-
if (Array.isArray(value)) return `array · ${value.length}`;
|
|
42
|
-
return typeof value;
|
|
43
|
-
} catch {
|
|
44
|
-
return "unknown";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function AtomExpandedContent({
|
|
48
|
-
atom,
|
|
49
|
-
onViewHistory
|
|
50
|
-
}) {
|
|
51
|
-
const value = atom.getValue();
|
|
52
|
-
const displayValue = useMemo(() => {
|
|
53
|
-
if (value && typeof value === "object") {
|
|
54
|
-
const filtered = {};
|
|
55
|
-
for (const [key, v] of Object.entries(value)) {
|
|
56
|
-
if (typeof v !== "function") filtered[key] = v;
|
|
57
|
-
}
|
|
58
|
-
return parseValue(filtered);
|
|
59
|
-
}
|
|
60
|
-
return parseValue(value);
|
|
61
|
-
}, [value]);
|
|
62
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
63
|
-
style: expandedStyles.container,
|
|
64
|
-
children: [/*#__PURE__*/_jsx(ExpandedInfoRow, {
|
|
65
|
-
label: "Type",
|
|
66
|
-
children: /*#__PURE__*/_jsx(PillBadge, {
|
|
67
|
-
color: atom.color,
|
|
68
|
-
children: "JOTAI"
|
|
69
|
-
})
|
|
70
|
-
}), atom.changeCount > 0 && /*#__PURE__*/_jsxs(ExpandedInfoRow, {
|
|
71
|
-
label: "Changes",
|
|
72
|
-
children: [/*#__PURE__*/_jsx(PillBadge, {
|
|
73
|
-
color: buoyColors.warning,
|
|
74
|
-
children: String(atom.changeCount)
|
|
75
|
-
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
76
|
-
onPress: () => onViewHistory(atom.label),
|
|
77
|
-
style: expandedStyles.viewHistoryButton,
|
|
78
|
-
hitSlop: {
|
|
79
|
-
top: 6,
|
|
80
|
-
bottom: 6,
|
|
81
|
-
left: 6,
|
|
82
|
-
right: 6
|
|
83
|
-
},
|
|
84
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
85
|
-
style: [expandedStyles.viewHistoryText, {
|
|
86
|
-
color: atom.color
|
|
87
|
-
}],
|
|
88
|
-
children: "view history \u2192"
|
|
89
|
-
})
|
|
90
|
-
})]
|
|
91
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
92
|
-
style: expandedStyles.dataContainer,
|
|
93
|
-
children: displayValue && typeof displayValue === "object" ? /*#__PURE__*/_jsx(DataViewer, {
|
|
94
|
-
title: "",
|
|
95
|
-
data: displayValue,
|
|
96
|
-
showTypeFilter: true,
|
|
97
|
-
rawMode: true,
|
|
98
|
-
initialExpanded: true
|
|
99
|
-
}) : /*#__PURE__*/_jsx(Text, {
|
|
100
|
-
style: expandedStyles.primitiveText,
|
|
101
|
-
children: String(value ?? "undefined")
|
|
102
|
-
})
|
|
103
|
-
})]
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
function EmptyBrowserState() {
|
|
107
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
108
|
-
style: styles.emptyState,
|
|
109
|
-
children: [/*#__PURE__*/_jsx(Box, {
|
|
110
|
-
size: 32,
|
|
111
|
-
color: macOSColors.text.muted
|
|
112
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
113
|
-
style: styles.emptyTitle,
|
|
114
|
-
children: "No atoms registered"
|
|
115
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
116
|
-
style: styles.emptyText,
|
|
117
|
-
children: "Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."
|
|
118
|
-
})]
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
export function JotaiAtomBrowser({
|
|
122
|
-
atoms,
|
|
123
|
-
searchQuery,
|
|
124
|
-
onViewHistory
|
|
125
|
-
}) {
|
|
126
|
-
const [expandedAtom, setExpandedAtom] = useState(null);
|
|
127
|
-
const filteredAtoms = useMemo(() => {
|
|
128
|
-
if (!searchQuery) return atoms;
|
|
129
|
-
const search = searchQuery.toLowerCase();
|
|
130
|
-
return atoms.filter(a => a.label.toLowerCase().includes(search));
|
|
131
|
-
}, [atoms, searchQuery]);
|
|
132
|
-
const handleAtomPress = useCallback(atom => {
|
|
133
|
-
setExpandedAtom(prev => prev === atom.label ? null : atom.label);
|
|
134
|
-
}, []);
|
|
135
|
-
if (filteredAtoms.length === 0 && !searchQuery) {
|
|
136
|
-
return /*#__PURE__*/_jsx(EmptyBrowserState, {});
|
|
137
|
-
}
|
|
138
|
-
if (filteredAtoms.length === 0 && searchQuery) {
|
|
139
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
140
|
-
style: styles.emptyState,
|
|
141
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
142
|
-
style: styles.emptyTitle,
|
|
143
|
-
children: "No matching atoms"
|
|
144
|
-
}), /*#__PURE__*/_jsxs(Text, {
|
|
145
|
-
style: styles.emptyText,
|
|
146
|
-
children: ["No atoms match \"", searchQuery, "\""]
|
|
147
|
-
})]
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
return /*#__PURE__*/_jsxs(ScrollView, {
|
|
151
|
-
style: styles.container,
|
|
152
|
-
contentContainerStyle: styles.scrollContent,
|
|
153
|
-
showsVerticalScrollIndicator: true,
|
|
154
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
155
|
-
style: styles.sectionHeader,
|
|
156
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
157
|
-
style: styles.sectionTitle,
|
|
158
|
-
children: "ATOMS"
|
|
159
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
160
|
-
style: styles.sectionCountBadge,
|
|
161
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
162
|
-
style: styles.sectionCountText,
|
|
163
|
-
children: filteredAtoms.length
|
|
164
|
-
})
|
|
165
|
-
})]
|
|
166
|
-
}), filteredAtoms.map(atom => {
|
|
167
|
-
const isExpanded = expandedAtom === atom.label;
|
|
168
|
-
const valuePreview = getValuePreview(atom);
|
|
169
|
-
const atomColor = jotaiStateStore.getAtomColor(atom.label);
|
|
170
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
171
|
-
style: styles.atomRowWrapper,
|
|
172
|
-
children: [/*#__PURE__*/_jsx(CompactRow, {
|
|
173
|
-
statusDotColor: atomColor,
|
|
174
|
-
statusLabel: atom.label,
|
|
175
|
-
statusSublabel: getValueType(atom),
|
|
176
|
-
primaryText: valuePreview,
|
|
177
|
-
showChevron: true,
|
|
178
|
-
isExpanded: isExpanded,
|
|
179
|
-
onPress: () => handleAtomPress(atom),
|
|
180
|
-
expandedContent: isExpanded ? /*#__PURE__*/_jsx(AtomExpandedContent, {
|
|
181
|
-
atom: atom,
|
|
182
|
-
onViewHistory: onViewHistory
|
|
183
|
-
}) : undefined
|
|
184
|
-
}), atom.changeCount > 0 && /*#__PURE__*/_jsx(View, {
|
|
185
|
-
style: [styles.absCountBadge, {
|
|
186
|
-
backgroundColor: atomColor + "22",
|
|
187
|
-
borderColor: atomColor + "55"
|
|
188
|
-
}],
|
|
189
|
-
pointerEvents: "none",
|
|
190
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
191
|
-
style: [styles.absCountText, {
|
|
192
|
-
color: atomColor
|
|
193
|
-
}],
|
|
194
|
-
children: String(atom.changeCount)
|
|
195
|
-
})
|
|
196
|
-
})]
|
|
197
|
-
}, atom.label);
|
|
198
|
-
})]
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
const styles = StyleSheet.create({
|
|
202
|
-
container: {
|
|
203
|
-
flex: 1
|
|
204
|
-
},
|
|
205
|
-
atomRowWrapper: {
|
|
206
|
-
position: "relative"
|
|
207
|
-
},
|
|
208
|
-
absCountBadge: {
|
|
209
|
-
position: "absolute",
|
|
210
|
-
top: 4,
|
|
211
|
-
right: 10,
|
|
212
|
-
paddingHorizontal: 5,
|
|
213
|
-
paddingVertical: 1,
|
|
214
|
-
borderRadius: 4,
|
|
215
|
-
borderWidth: 1,
|
|
216
|
-
zIndex: 1
|
|
217
|
-
},
|
|
218
|
-
absCountText: {
|
|
219
|
-
fontSize: 9,
|
|
220
|
-
fontWeight: "700",
|
|
221
|
-
fontFamily: "monospace"
|
|
222
|
-
},
|
|
223
|
-
scrollContent: {
|
|
224
|
-
paddingTop: 8,
|
|
225
|
-
paddingBottom: 20
|
|
226
|
-
},
|
|
227
|
-
sectionHeader: {
|
|
228
|
-
flexDirection: "row",
|
|
229
|
-
alignItems: "center",
|
|
230
|
-
paddingHorizontal: 16,
|
|
231
|
-
paddingVertical: 8,
|
|
232
|
-
gap: 8
|
|
233
|
-
},
|
|
234
|
-
sectionTitle: {
|
|
235
|
-
fontSize: 11,
|
|
236
|
-
fontWeight: "700",
|
|
237
|
-
letterSpacing: 0.5,
|
|
238
|
-
color: macOSColors.text.muted
|
|
239
|
-
},
|
|
240
|
-
sectionCountBadge: {
|
|
241
|
-
backgroundColor: buoyColors.primary + "26",
|
|
242
|
-
paddingHorizontal: 8,
|
|
243
|
-
paddingVertical: 2,
|
|
244
|
-
borderRadius: 4
|
|
245
|
-
},
|
|
246
|
-
sectionCountText: {
|
|
247
|
-
fontSize: 10,
|
|
248
|
-
fontWeight: "700",
|
|
249
|
-
color: buoyColors.primary,
|
|
250
|
-
fontFamily: "monospace"
|
|
251
|
-
},
|
|
252
|
-
emptyState: {
|
|
253
|
-
alignItems: "center",
|
|
254
|
-
paddingVertical: 40
|
|
255
|
-
},
|
|
256
|
-
emptyTitle: {
|
|
257
|
-
color: macOSColors.text.primary,
|
|
258
|
-
fontSize: 14,
|
|
259
|
-
fontWeight: "600",
|
|
260
|
-
marginTop: 12,
|
|
261
|
-
marginBottom: 6
|
|
262
|
-
},
|
|
263
|
-
emptyText: {
|
|
264
|
-
color: macOSColors.text.muted,
|
|
265
|
-
fontSize: 12,
|
|
266
|
-
textAlign: "center",
|
|
267
|
-
lineHeight: 18
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
const expandedStyles = StyleSheet.create({
|
|
271
|
-
container: {
|
|
272
|
-
gap: 10
|
|
273
|
-
},
|
|
274
|
-
viewHistoryButton: {
|
|
275
|
-
marginLeft: 4
|
|
276
|
-
},
|
|
277
|
-
viewHistoryText: {
|
|
278
|
-
fontSize: 10,
|
|
279
|
-
fontWeight: "600",
|
|
280
|
-
fontFamily: "monospace"
|
|
281
|
-
},
|
|
282
|
-
dataContainer: {
|
|
283
|
-
backgroundColor: buoyColors.base,
|
|
284
|
-
borderRadius: 6,
|
|
285
|
-
borderWidth: 1,
|
|
286
|
-
borderColor: buoyColors.border,
|
|
287
|
-
overflow: "hidden",
|
|
288
|
-
minHeight: 60
|
|
289
|
-
},
|
|
290
|
-
primitiveText: {
|
|
291
|
-
color: buoyColors.text,
|
|
292
|
-
fontSize: 12,
|
|
293
|
-
fontFamily: "monospace",
|
|
294
|
-
padding: 14
|
|
295
|
-
}
|
|
296
|
-
});
|
|
1
|
+
"use strict";import{useState,useMemo,useCallback}from"react";import{View,Text,StyleSheet,ScrollView,TouchableOpacity}from"react-native";import{CompactRow,macOSColors,buoyColors,Box,ExpandedInfoRow,PillBadge,parseValue}from"@buoy-gg/shared-ui";import{DataViewer}from"@buoy-gg/shared-ui/dataViewer";import{jotaiStateStore}from"../utils/jotaiStateStore";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function getValuePreview(e){try{const t=e.getValue();if(void 0===t)return"undefined";if(null===t)return"null";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.length<=3?e.join(", "):`${e.slice(0,2).join(", ")} +${e.length-2}`}return String(t).slice(0,40)}catch{return""}}function getValueType(e){try{const t=e.getValue();return null===t?"null":void 0===t?"undefined":Array.isArray(t)?`array · ${t.length}`:typeof t}catch{return"unknown"}}function AtomExpandedContent({atom:e,onViewHistory:t}){const o=e.getValue(),r=useMemo(()=>{if(o&&"object"==typeof o){const e={};for(const[t,r]of Object.entries(o))"function"!=typeof r&&(e[t]=r);return parseValue(e)}return parseValue(o)},[o]);return _jsxs(View,{style:expandedStyles.container,children:[_jsx(ExpandedInfoRow,{label:"Type",children:_jsx(PillBadge,{color:e.color,children:"JOTAI"})}),e.changeCount>0&&_jsxs(ExpandedInfoRow,{label:"Changes",children:[_jsx(PillBadge,{color:buoyColors.warning,children:String(e.changeCount)}),_jsx(TouchableOpacity,{onPress:()=>t(e.label),style:expandedStyles.viewHistoryButton,hitSlop:{top:6,bottom:6,left:6,right:6},children:_jsx(Text,{style:[expandedStyles.viewHistoryText,{color:e.color}],children:"view history →"})})]}),_jsx(View,{style:expandedStyles.dataContainer,children:r&&"object"==typeof r?_jsx(DataViewer,{title:"",data:r,showTypeFilter:!0,rawMode:!0,initialExpanded:!0}):_jsx(Text,{style:expandedStyles.primitiveText,children:String(o??"undefined")})})]})}function EmptyBrowserState(){return _jsxs(View,{style:styles.emptyState,children:[_jsx(Box,{size:32,color:macOSColors.text.muted}),_jsx(Text,{style:styles.emptyTitle,children:"No atoms registered"}),_jsx(Text,{style:styles.emptyText,children:"Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."})]})}export function JotaiAtomBrowser({atoms:e,searchQuery:t,onViewHistory:o}){const[r,n]=useState(null),i=useMemo(()=>{if(!t)return e;const o=t.toLowerCase();return e.filter(e=>e.label.toLowerCase().includes(o))},[e,t]),l=useCallback(e=>{n(t=>t===e.label?null:e.label)},[]);return 0!==i.length||t?0===i.length&&t?_jsxs(View,{style:styles.emptyState,children:[_jsx(Text,{style:styles.emptyTitle,children:"No matching atoms"}),_jsxs(Text,{style:styles.emptyText,children:['No atoms match "',t,'"']})]}):_jsxs(ScrollView,{style:styles.container,contentContainerStyle:styles.scrollContent,showsVerticalScrollIndicator:!0,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,children:i.length})})]}),i.map(e=>{const t=r===e.label,n=getValuePreview(e),i=jotaiStateStore.getAtomColor(e.label);return _jsxs(View,{style:styles.atomRowWrapper,children:[_jsx(CompactRow,{statusDotColor:i,statusLabel:e.label,statusSublabel:getValueType(e),primaryText:n,showChevron:!0,isExpanded:t,onPress:()=>l(e),expandedContent:t?_jsx(AtomExpandedContent,{atom:e,onViewHistory:o}):void 0}),e.changeCount>0&&_jsx(View,{style:[styles.absCountBadge,{backgroundColor:i+"22",borderColor:i+"55"}],pointerEvents:"none",children:_jsx(Text,{style:[styles.absCountText,{color:i}],children:String(e.changeCount)})})]},e.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:"monospace"},scrollContent:{paddingTop:8,paddingBottom:20},sectionHeader:{flexDirection:"row",alignItems:"center",paddingHorizontal:16,paddingVertical:8,gap:8},sectionTitle:{fontSize:11,fontWeight:"700",letterSpacing:.5,color:macOSColors.text.muted},sectionCountBadge:{backgroundColor:buoyColors.primary+"26",paddingHorizontal:8,paddingVertical:2,borderRadius:4},sectionCountText:{fontSize:10,fontWeight:"700",color:buoyColors.primary,fontFamily:"monospace"},emptyState:{alignItems:"center",paddingVertical:40},emptyTitle:{color:macOSColors.text.primary,fontSize:14,fontWeight:"600",marginTop:12,marginBottom:6},emptyText:{color:macOSColors.text.muted,fontSize:12,textAlign:"center",lineHeight:18}}),expandedStyles=StyleSheet.create({container:{gap:10},viewHistoryButton:{marginLeft:4},viewHistoryText:{fontSize:10,fontWeight:"600",fontFamily:"monospace"},dataContainer:{backgroundColor:buoyColors.base,borderRadius:6,borderWidth:1,borderColor:buoyColors.border,overflow:"hidden",minHeight:60},primitiveText:{color:buoyColors.text,fontSize:12,fontFamily:"monospace",padding:14}});
|
|
@@ -1,109 +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 { View, Text, StyleSheet } from "react-native";
|
|
10
|
-
import { CompactRow, buoyColors, Zap, useRelativeTime } from "@buoy-gg/shared-ui";
|
|
11
|
-
import { jotaiStateStore } from "../utils/jotaiStateStore";
|
|
12
|
-
import { jsx as _jsx, jsxs as _jsxs } 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 buoyColors.textMuted;
|
|
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
|
-
export function JotaiAtomChangeItem({
|
|
58
|
-
change,
|
|
59
|
-
onPress
|
|
60
|
-
}) {
|
|
61
|
-
const statusColor = getCategoryColor(change.category, change.atomLabel);
|
|
62
|
-
const statusLabel = getStatusLabel(change.category, change.atomLabel);
|
|
63
|
-
const sublabel = getSublabel(change);
|
|
64
|
-
const primaryText = getPrimaryText(change);
|
|
65
|
-
const badgeText = getBadgeText(change);
|
|
66
|
-
const relativeTime = useRelativeTime(change.timestamp);
|
|
67
|
-
const customBadge = change.hasValueChange ? /*#__PURE__*/_jsxs(View, {
|
|
68
|
-
style: styles.badgeContainer,
|
|
69
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
70
|
-
style: [styles.badgeText, {
|
|
71
|
-
color: statusColor
|
|
72
|
-
}],
|
|
73
|
-
children: badgeText
|
|
74
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
75
|
-
style: styles.changeBadge,
|
|
76
|
-
children: /*#__PURE__*/_jsx(Zap, {
|
|
77
|
-
size: 12,
|
|
78
|
-
color: buoyColors.warning
|
|
79
|
-
})
|
|
80
|
-
})]
|
|
81
|
-
}) : undefined;
|
|
82
|
-
return /*#__PURE__*/_jsx(CompactRow, {
|
|
83
|
-
statusDotColor: statusColor,
|
|
84
|
-
statusLabel: statusLabel,
|
|
85
|
-
statusSublabel: sublabel,
|
|
86
|
-
primaryText: primaryText,
|
|
87
|
-
bottomRightText: relativeTime,
|
|
88
|
-
customBadge: customBadge,
|
|
89
|
-
badgeText: customBadge ? undefined : badgeText,
|
|
90
|
-
badgeColor: statusColor,
|
|
91
|
-
showChevron: true,
|
|
92
|
-
onPress: () => onPress(change)
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
const styles = StyleSheet.create({
|
|
96
|
-
badgeContainer: {
|
|
97
|
-
flexDirection: "row",
|
|
98
|
-
alignItems: "center",
|
|
99
|
-
gap: 4
|
|
100
|
-
},
|
|
101
|
-
badgeText: {
|
|
102
|
-
fontSize: 11,
|
|
103
|
-
fontWeight: "600",
|
|
104
|
-
fontFamily: "monospace"
|
|
105
|
-
},
|
|
106
|
-
changeBadge: {
|
|
107
|
-
paddingHorizontal: 4
|
|
108
|
-
}
|
|
109
|
-
});
|
|
1
|
+
"use strict";import{View,Text,StyleSheet}from"react-native";import{CompactRow,buoyColors,Zap,useRelativeTime}from"@buoy-gg/shared-ui";import{jotaiStateStore}from"../utils/jotaiStateStore";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function getStatusLabel(e,t){return"initial"===e?"Initial":t.charAt(0).toUpperCase()+t.slice(1)}function getCategoryColor(e,t){return"initial"===e?buoyColors.textMuted:jotaiStateStore.getAtomColor(t)}function formatCompact(e,t=20){if(void 0===e)return"undefined";if(null===e)return"null";if("boolean"==typeof e)return String(e);if("number"==typeof e)return String(e);if("string"==typeof e)return`"${e.length>t?e.slice(0,t-1)+"…":e}"`;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.slice(0,2).join(", ")}${t.length>2?"…":""}}`}return String(e).slice(0,t)}function getSublabel(e){return e.hasValueChange?`${formatCompact(e.prevValue)} → ${formatCompact(e.nextValue)}`:"no change"}function getBadgeText(e){return"initial"===e.category?"INIT":"WRITE"}function getPrimaryText(e){return e.changedKeys.length>0&&e.changedKeys.length<=3?e.changedKeys.join(", "):e.changedKeys.length>3?`${e.changedKeys.slice(0,2).join(", ")} +${e.changedKeys.length-2}`:e.valuePreview||"atom()"}export function JotaiAtomChangeItem({change:e,onPress:t}){const o=getCategoryColor(e.category,e.atomLabel),a=getStatusLabel(e.category,e.atomLabel),n=getSublabel(e),r=getPrimaryText(e),i=getBadgeText(e),s=useRelativeTime(e.timestamp),l=e.hasValueChange?_jsxs(View,{style:styles.badgeContainer,children:[_jsx(Text,{style:[styles.badgeText,{color:o}],children:i}),_jsx(View,{style:styles.changeBadge,children:_jsx(Zap,{size:12,color:buoyColors.warning})})]}):void 0;return _jsx(CompactRow,{statusDotColor:o,statusLabel:a,statusSublabel:n,primaryText:r,bottomRightText:s,customBadge:l,badgeText:l?void 0:i,badgeColor:o,showChevron:!0,onPress:()=>t(e)})}const styles=StyleSheet.create({badgeContainer:{flexDirection:"row",alignItems:"center",gap:4},badgeText:{fontSize:11,fontWeight:"600",fontFamily:"monospace"},changeBadge:{paddingHorizontal:4}});
|