@buoy-gg/jotai 2.1.12 → 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.
Files changed (41) hide show
  1. package/lib/commonjs/index.js +1 -91
  2. package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +1 -300
  3. package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +1 -113
  4. package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +1 -754
  5. package/lib/commonjs/jotai/components/JotaiEventFilterView.js +1 -305
  6. package/lib/commonjs/jotai/components/JotaiIcon.js +1 -35
  7. package/lib/commonjs/jotai/components/JotaiModal.js +1 -567
  8. package/lib/commonjs/jotai/components/index.js +1 -59
  9. package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +1 -83
  10. package/lib/commonjs/jotai/index.js +1 -85
  11. package/lib/commonjs/jotai/utils/jotaiStateStore.js +1 -322
  12. package/lib/commonjs/jotai/utils/watchAtoms.js +1 -149
  13. package/lib/commonjs/preset.js +1 -98
  14. package/lib/module/index.js +1 -74
  15. package/lib/module/jotai/components/JotaiAtomBrowser.js +1 -296
  16. package/lib/module/jotai/components/JotaiAtomChangeItem.js +1 -109
  17. package/lib/module/jotai/components/JotaiAtomDetailContent.js +1 -748
  18. package/lib/module/jotai/components/JotaiEventFilterView.js +1 -301
  19. package/lib/module/jotai/components/JotaiIcon.js +1 -31
  20. package/lib/module/jotai/components/JotaiModal.js +1 -563
  21. package/lib/module/jotai/components/index.js +1 -8
  22. package/lib/module/jotai/hooks/useJotaiAtomChanges.js +1 -79
  23. package/lib/module/jotai/index.js +1 -10
  24. package/lib/module/jotai/utils/jotaiStateStore.js +1 -318
  25. package/lib/module/jotai/utils/watchAtoms.js +1 -144
  26. package/lib/module/preset.js +1 -94
  27. package/package.json +3 -3
  28. package/lib/typescript/index.d.ts.map +0 -1
  29. package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +0 -1
  30. package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +0 -1
  31. package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +0 -1
  32. package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +0 -1
  33. package/lib/typescript/jotai/components/JotaiIcon.d.ts.map +0 -1
  34. package/lib/typescript/jotai/components/JotaiModal.d.ts.map +0 -1
  35. package/lib/typescript/jotai/components/index.d.ts.map +0 -1
  36. package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +0 -1
  37. package/lib/typescript/jotai/index.d.ts.map +0 -1
  38. package/lib/typescript/jotai/types/index.d.ts.map +0 -1
  39. package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +0 -1
  40. package/lib/typescript/jotai/utils/watchAtoms.d.ts.map +0 -1
  41. package/lib/typescript/preset.d.ts.map +0 -1
@@ -1,83 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.useJotaiAtomChanges = useJotaiAtomChanges;
7
- var _react = require("react");
8
- var _jotaiStateStore = require("../utils/jotaiStateStore");
9
- /**
10
- * Hook for consuming Jotai atom changes from the store
11
- *
12
- * Mirrors useZustandStateChanges.ts from @buoy-gg/zustand
13
- */
14
-
15
- function useJotaiAtomChanges() {
16
- const [atomChanges, setAtomChanges] = (0, _react.useState)(() => _jotaiStateStore.jotaiStateStore.getAtomChanges());
17
- const [atoms, setAtoms] = (0, _react.useState)(() => _jotaiStateStore.jotaiStateStore.getAtoms());
18
- const [filter, setFilter] = (0, _react.useState)({});
19
- const [isEnabled, setIsEnabled] = (0, _react.useState)(() => _jotaiStateStore.jotaiStateStore.getEnabled());
20
- (0, _react.useEffect)(() => {
21
- const unsubChanges = _jotaiStateStore.jotaiStateStore.subscribe(newChanges => {
22
- setAtomChanges(newChanges);
23
- });
24
- const unsubAtoms = _jotaiStateStore.jotaiStateStore.subscribeToAtoms(newAtoms => {
25
- setAtoms(newAtoms);
26
- });
27
- return () => {
28
- unsubChanges();
29
- unsubAtoms();
30
- };
31
- }, []);
32
- const filteredChanges = (0, _react.useMemo)(() => {
33
- let filtered = atomChanges;
34
- if (filter.searchText) {
35
- const search = filter.searchText.toLowerCase();
36
- filtered = filtered.filter(c => c.atomLabel.toLowerCase().includes(search) || c.valuePreview.toLowerCase().includes(search) || c.changedKeys.some(k => k.toLowerCase().includes(search)));
37
- }
38
- if (filter.atomLabels && filter.atomLabels.length > 0) {
39
- filtered = filtered.filter(c => filter.atomLabels.includes(c.atomLabel));
40
- }
41
- if (filter.onlyWithChanges) {
42
- filtered = filtered.filter(c => c.hasValueChange);
43
- }
44
- return filtered;
45
- }, [atomChanges, filter]);
46
- const stats = (0, _react.useMemo)(() => {
47
- const total = atomChanges.length;
48
- const withChanges = atomChanges.filter(c => c.hasValueChange).length;
49
- return {
50
- totalChanges: total,
51
- changesWithValueChange: withChanges,
52
- changesWithoutValueChange: total - withChanges,
53
- atomCount: atoms.length
54
- };
55
- }, [atomChanges, atoms]);
56
- const atomLabels = (0, _react.useMemo)(() => {
57
- return _jotaiStateStore.jotaiStateStore.getUniqueAtomLabels();
58
- }, [atoms]);
59
- const clearChanges = (0, _react.useCallback)(() => {
60
- _jotaiStateStore.jotaiStateStore.clearAtomChanges();
61
- }, []);
62
- const toggleCapture = (0, _react.useCallback)(() => {
63
- const newEnabled = !isEnabled;
64
- _jotaiStateStore.jotaiStateStore.setEnabled(newEnabled);
65
- setIsEnabled(newEnabled);
66
- }, [isEnabled]);
67
- const getChangeById = (0, _react.useCallback)(id => {
68
- return _jotaiStateStore.jotaiStateStore.getAtomChangeById(id);
69
- }, []);
70
- return {
71
- atomChanges,
72
- filteredChanges,
73
- filter,
74
- setFilter,
75
- stats,
76
- atoms,
77
- clearChanges,
78
- isEnabled,
79
- toggleCapture,
80
- atomLabels,
81
- getChangeById
82
- };
83
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useJotaiAtomChanges=useJotaiAtomChanges;var _react=require("react"),_jotaiStateStore=require("../utils/jotaiStateStore");function useJotaiAtomChanges(){const[t,e]=(0,_react.useState)(()=>_jotaiStateStore.jotaiStateStore.getAtomChanges()),[a,o]=(0,_react.useState)(()=>_jotaiStateStore.jotaiStateStore.getAtoms()),[r,s]=(0,_react.useState)({}),[i,n]=(0,_react.useState)(()=>_jotaiStateStore.jotaiStateStore.getEnabled());(0,_react.useEffect)(()=>{const t=_jotaiStateStore.jotaiStateStore.subscribe(t=>{e(t)}),a=_jotaiStateStore.jotaiStateStore.subscribeToAtoms(t=>{o(t)});return()=>{t(),a()}},[]);const l=(0,_react.useMemo)(()=>{let e=t;if(r.searchText){const t=r.searchText.toLowerCase();e=e.filter(e=>e.atomLabel.toLowerCase().includes(t)||e.valuePreview.toLowerCase().includes(t)||e.changedKeys.some(e=>e.toLowerCase().includes(t)))}return r.atomLabels&&r.atomLabels.length>0&&(e=e.filter(t=>r.atomLabels.includes(t.atomLabel))),r.onlyWithChanges&&(e=e.filter(t=>t.hasValueChange)),e},[t,r]),S=(0,_react.useMemo)(()=>{const e=t.length,o=t.filter(t=>t.hasValueChange).length;return{totalChanges:e,changesWithValueChange:o,changesWithoutValueChange:e-o,atomCount:a.length}},[t,a]),u=(0,_react.useMemo)(()=>_jotaiStateStore.jotaiStateStore.getUniqueAtomLabels(),[a]),c=(0,_react.useCallback)(()=>{_jotaiStateStore.jotaiStateStore.clearAtomChanges()},[]),g=(0,_react.useCallback)(()=>{const t=!i;_jotaiStateStore.jotaiStateStore.setEnabled(t),n(t)},[i]),h=(0,_react.useCallback)(t=>_jotaiStateStore.jotaiStateStore.getAtomChangeById(t),[]);return{atomChanges:t,filteredChanges:l,filter:r,setFilter:s,stats:S,atoms:a,clearChanges:c,isEnabled:i,toggleCapture:g,atomLabels:u,getChangeById:h}}
@@ -1,85 +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, "JotaiAtomBrowser", {
13
- enumerable: true,
14
- get: function () {
15
- return _JotaiAtomBrowser.JotaiAtomBrowser;
16
- }
17
- });
18
- Object.defineProperty(exports, "JotaiAtomChangeItem", {
19
- enumerable: true,
20
- get: function () {
21
- return _JotaiAtomChangeItem.JotaiAtomChangeItem;
22
- }
23
- });
24
- Object.defineProperty(exports, "JotaiAtomDetailContent", {
25
- enumerable: true,
26
- get: function () {
27
- return _JotaiAtomDetailContent.JotaiAtomDetailContent;
28
- }
29
- });
30
- Object.defineProperty(exports, "JotaiAtomDetailFooter", {
31
- enumerable: true,
32
- get: function () {
33
- return _JotaiAtomDetailContent.JotaiAtomDetailFooter;
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, "isAtomWatched", {
49
- enumerable: true,
50
- get: function () {
51
- return _watchAtoms.isAtomWatched;
52
- }
53
- });
54
- Object.defineProperty(exports, "jotaiStateStore", {
55
- enumerable: true,
56
- get: function () {
57
- return _jotaiStateStore.jotaiStateStore;
58
- }
59
- });
60
- Object.defineProperty(exports, "useJotaiAtomChanges", {
61
- enumerable: true,
62
- get: function () {
63
- return _useJotaiAtomChanges.useJotaiAtomChanges;
64
- }
65
- });
66
- Object.defineProperty(exports, "watchAtoms", {
67
- enumerable: true,
68
- get: function () {
69
- return _watchAtoms.watchAtoms;
70
- }
71
- });
72
- Object.defineProperty(exports, "watchDefaultStoreAtoms", {
73
- enumerable: true,
74
- get: function () {
75
- return _watchAtoms.watchDefaultStoreAtoms;
76
- }
77
- });
78
- var _JotaiModal = require("./components/JotaiModal");
79
- var _JotaiIcon = require("./components/JotaiIcon");
80
- var _JotaiAtomChangeItem = require("./components/JotaiAtomChangeItem");
81
- var _JotaiAtomDetailContent = require("./components/JotaiAtomDetailContent");
82
- var _JotaiAtomBrowser = require("./components/JotaiAtomBrowser");
83
- var _jotaiStateStore = require("./utils/jotaiStateStore");
84
- var _watchAtoms = require("./utils/watchAtoms");
85
- var _useJotaiAtomChanges = require("./hooks/useJotaiAtomChanges");
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"JOTAI_ICON_COLOR",{enumerable:!0,get:function(){return _JotaiIcon.JOTAI_ICON_COLOR}}),Object.defineProperty(exports,"JotaiAtomBrowser",{enumerable:!0,get:function(){return _JotaiAtomBrowser.JotaiAtomBrowser}}),Object.defineProperty(exports,"JotaiAtomChangeItem",{enumerable:!0,get:function(){return _JotaiAtomChangeItem.JotaiAtomChangeItem}}),Object.defineProperty(exports,"JotaiAtomDetailContent",{enumerable:!0,get:function(){return _JotaiAtomDetailContent.JotaiAtomDetailContent}}),Object.defineProperty(exports,"JotaiAtomDetailFooter",{enumerable:!0,get:function(){return _JotaiAtomDetailContent.JotaiAtomDetailFooter}}),Object.defineProperty(exports,"JotaiIcon",{enumerable:!0,get:function(){return _JotaiIcon.JotaiIcon}}),Object.defineProperty(exports,"JotaiModal",{enumerable:!0,get:function(){return _JotaiModal.JotaiModal}}),Object.defineProperty(exports,"isAtomWatched",{enumerable:!0,get:function(){return _watchAtoms.isAtomWatched}}),Object.defineProperty(exports,"jotaiStateStore",{enumerable:!0,get:function(){return _jotaiStateStore.jotaiStateStore}}),Object.defineProperty(exports,"useJotaiAtomChanges",{enumerable:!0,get:function(){return _useJotaiAtomChanges.useJotaiAtomChanges}}),Object.defineProperty(exports,"watchAtoms",{enumerable:!0,get:function(){return _watchAtoms.watchAtoms}}),Object.defineProperty(exports,"watchDefaultStoreAtoms",{enumerable:!0,get:function(){return _watchAtoms.watchDefaultStoreAtoms}});var _JotaiModal=require("./components/JotaiModal"),_JotaiIcon=require("./components/JotaiIcon"),_JotaiAtomChangeItem=require("./components/JotaiAtomChangeItem"),_JotaiAtomDetailContent=require("./components/JotaiAtomDetailContent"),_JotaiAtomBrowser=require("./components/JotaiAtomBrowser"),_jotaiStateStore=require("./utils/jotaiStateStore"),_watchAtoms=require("./utils/watchAtoms"),_useJotaiAtomChanges=require("./hooks/useJotaiAtomChanges");
@@ -1,322 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.jotaiStateStore = void 0;
7
- /**
8
- * Jotai state store — captures and stores Jotai atom changes
9
- *
10
- * Mirrors the architecture of zustandStateStore.ts from @buoy-gg/zustand
11
- */
12
-
13
- // ============================================
14
- // Atom Color Palette
15
- // ============================================
16
-
17
- const ATOM_COLORS = {
18
- count: "#10B981",
19
- // emerald
20
- auth: "#8B5CF6",
21
- // purple
22
- user: "#3B82F6",
23
- // blue
24
- cart: "#EC4899",
25
- // pink
26
- app: "#6366F1",
27
- // indigo
28
- ui: "#F59E0B",
29
- // amber
30
- settings: "#14B8A6",
31
- // teal
32
- theme: "#06B6D4",
33
- // cyan
34
- nav: "#F97316",
35
- // orange
36
- form: "#EF4444",
37
- // red
38
- modal: "#A855F7",
39
- // violet
40
- filter: "#84CC16" // lime
41
- };
42
- function getAtomColor(label) {
43
- const lower = label.toLowerCase();
44
- if (ATOM_COLORS[lower]) return ATOM_COLORS[lower];
45
- for (const [key, color] of Object.entries(ATOM_COLORS)) {
46
- if (lower.includes(key)) return color;
47
- }
48
-
49
- // Generate consistent hex from name hash
50
- const hash = label.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0);
51
- const hue = hash * 137 % 360;
52
- const s = 0.7;
53
- const l = 0.6;
54
- const c = (1 - Math.abs(2 * l - 1)) * s;
55
- const x = c * (1 - Math.abs(hue / 60 % 2 - 1));
56
- const m = l - c / 2;
57
- let r = 0,
58
- g = 0,
59
- b = 0;
60
- if (hue < 60) {
61
- r = c;
62
- g = x;
63
- } else if (hue < 120) {
64
- r = x;
65
- g = c;
66
- } else if (hue < 180) {
67
- g = c;
68
- b = x;
69
- } else if (hue < 240) {
70
- g = x;
71
- b = c;
72
- } else if (hue < 300) {
73
- r = x;
74
- b = c;
75
- } else {
76
- r = c;
77
- b = x;
78
- }
79
- const toHex = v => Math.round((v + m) * 255).toString(16).padStart(2, "0");
80
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
81
- }
82
-
83
- // ============================================
84
- // Helper Functions
85
- // ============================================
86
-
87
- function formatValuePreview(value, maxLength = 40) {
88
- if (value === undefined) return "undefined";
89
- if (value === null) return "null";
90
- try {
91
- if (typeof value === "function") return "(fn)";
92
- if (typeof value === "string") {
93
- return value.length > maxLength ? `"${value.slice(0, maxLength - 3)}..."` : `"${value}"`;
94
- }
95
- if (typeof value === "number" || typeof value === "boolean") {
96
- return String(value);
97
- }
98
- if (Array.isArray(value)) {
99
- if (value.length === 0) return "[]";
100
- const preview = JSON.stringify(value);
101
- return preview.length > maxLength ? `[${value.length} items]` : preview;
102
- }
103
- if (typeof value === "object") {
104
- const keys = Object.keys(value);
105
- if (keys.length === 0) return "{}";
106
- const preview = JSON.stringify(value);
107
- if (preview.length <= maxLength) return preview;
108
- return `{ ${keys.length} keys }`;
109
- }
110
- return String(value).slice(0, maxLength);
111
- } catch {
112
- return "[complex]";
113
- }
114
- }
115
- function getValueDiffSummary(prevValue, nextValue) {
116
- if (prevValue === nextValue) {
117
- return {
118
- summary: "no change",
119
- changedKeys: [],
120
- changedCount: 0
121
- };
122
- }
123
- if (typeof prevValue !== "object" || typeof nextValue !== "object" || prevValue === null || nextValue === null) {
124
- return {
125
- summary: "changed",
126
- changedKeys: [],
127
- changedCount: 0
128
- };
129
- }
130
- const prevKeys = Object.keys(prevValue);
131
- const nextKeys = Object.keys(nextValue);
132
- const added = nextKeys.filter(k => !prevKeys.includes(k));
133
- const removed = prevKeys.filter(k => !nextKeys.includes(k));
134
- const changed = [];
135
- for (const key of prevKeys) {
136
- if (nextKeys.includes(key) && prevValue[key] !== nextValue[key]) {
137
- changed.push(key);
138
- }
139
- }
140
- const allChangedKeys = [...added, ...removed, ...changed];
141
- const parts = [];
142
- if (added.length > 0) parts.push(`+${added.length}`);
143
- if (removed.length > 0) parts.push(`-${removed.length}`);
144
- if (changed.length > 0) parts.push(`~${changed.length}`);
145
- const total = allChangedKeys.length;
146
- if (parts.length === 0) {
147
- return {
148
- summary: "nested change",
149
- changedKeys: [],
150
- changedCount: 0
151
- };
152
- }
153
- return {
154
- summary: `${parts.join(" ")} ${total === 1 ? "key" : "keys"}`,
155
- changedKeys: allChangedKeys,
156
- changedCount: total
157
- };
158
- }
159
-
160
- // ============================================
161
- // Jotai State Store
162
- // ============================================
163
-
164
- class JotaiStateStore {
165
- atomChanges = [];
166
- atoms = new Map();
167
- listeners = new Set();
168
- atomListeners = new Set();
169
- maxChanges = 200;
170
- idCounter = 0;
171
- isEnabled = true;
172
-
173
- // ---- Change Tracking ----
174
-
175
- addAtomChange(params) {
176
- if (!this.isEnabled) return;
177
- const {
178
- atomLabel,
179
- prevValue,
180
- nextValue,
181
- category = "write"
182
- } = params;
183
- const hasValueChange = prevValue !== nextValue;
184
- const {
185
- summary,
186
- changedKeys,
187
- changedCount
188
- } = getValueDiffSummary(prevValue, nextValue);
189
- const valuePreview = formatValuePreview(nextValue);
190
- const change = {
191
- id: `${Date.now()}-${++this.idCounter}`,
192
- atomLabel,
193
- timestamp: Date.now(),
194
- prevValue,
195
- nextValue,
196
- hasValueChange,
197
- category,
198
- changedKeys,
199
- changedKeysCount: changedCount,
200
- diffSummary: summary,
201
- valuePreview,
202
- isSlowUpdate: false
203
- };
204
- this.atomChanges = [change, ...this.atomChanges].slice(0, this.maxChanges);
205
- const atomInfo = this.atoms.get(atomLabel);
206
- if (atomInfo) {
207
- atomInfo.changeCount++;
208
- }
209
- this.notifyListeners();
210
- this.notifyAtomListeners();
211
- }
212
- getAtomChanges() {
213
- return [...this.atomChanges];
214
- }
215
- getAtomChangeById(id) {
216
- return this.atomChanges.find(c => c.id === id);
217
- }
218
- clearAtomChanges() {
219
- this.atomChanges = [];
220
- for (const atom of this.atoms.values()) {
221
- atom.changeCount = 0;
222
- }
223
- this.notifyListeners();
224
- this.notifyAtomListeners();
225
- }
226
-
227
- // ---- Atom Registry ----
228
-
229
- registerAtom(label, getValue) {
230
- if (this.atoms.has(label)) return;
231
- const atomInfo = {
232
- label,
233
- changeCount: 0,
234
- color: getAtomColor(label),
235
- getValue
236
- };
237
- this.atoms.set(label, atomInfo);
238
- this.notifyAtomListeners();
239
- }
240
- unregisterAtom(label) {
241
- this.atoms.delete(label);
242
- this.notifyAtomListeners();
243
- }
244
- getAtoms() {
245
- return Array.from(this.atoms.values());
246
- }
247
- getAtom(label) {
248
- return this.atoms.get(label);
249
- }
250
- getAtomColor(label) {
251
- return this.atoms.get(label)?.color ?? getAtomColor(label);
252
- }
253
-
254
- // ---- Filtering ----
255
-
256
- filterAtomChanges(filter) {
257
- let filtered = [...this.atomChanges];
258
- if (filter.searchText) {
259
- const search = filter.searchText.toLowerCase();
260
- filtered = filtered.filter(c => c.atomLabel.toLowerCase().includes(search) || c.valuePreview.toLowerCase().includes(search) || c.changedKeys.some(k => k.toLowerCase().includes(search)));
261
- }
262
- if (filter.atomLabels && filter.atomLabels.length > 0) {
263
- filtered = filtered.filter(c => filter.atomLabels.includes(c.atomLabel));
264
- }
265
- if (filter.onlyWithChanges) {
266
- filtered = filtered.filter(c => c.hasValueChange);
267
- }
268
- return filtered;
269
- }
270
-
271
- // ---- Stats ----
272
-
273
- getStats() {
274
- const total = this.atomChanges.length;
275
- const withChanges = this.atomChanges.filter(c => c.hasValueChange).length;
276
- return {
277
- totalChanges: total,
278
- changesWithValueChange: withChanges,
279
- changesWithoutValueChange: total - withChanges,
280
- atomCount: this.atoms.size
281
- };
282
- }
283
- getUniqueAtomLabels() {
284
- return Array.from(this.atoms.keys()).sort();
285
- }
286
-
287
- // ---- Enable / Disable ----
288
-
289
- setEnabled(enabled) {
290
- this.isEnabled = enabled;
291
- }
292
- getEnabled() {
293
- return this.isEnabled;
294
- }
295
- setMaxChanges(max) {
296
- this.maxChanges = max;
297
- if (this.atomChanges.length > max) {
298
- this.atomChanges = this.atomChanges.slice(0, max);
299
- this.notifyListeners();
300
- }
301
- }
302
-
303
- // ---- Subscriptions ----
304
-
305
- subscribe(listener) {
306
- this.listeners.add(listener);
307
- return () => this.listeners.delete(listener);
308
- }
309
- subscribeToAtoms(listener) {
310
- this.atomListeners.add(listener);
311
- return () => this.atomListeners.delete(listener);
312
- }
313
- notifyListeners() {
314
- const changes = this.getAtomChanges();
315
- this.listeners.forEach(listener => listener(changes));
316
- }
317
- notifyAtomListeners() {
318
- const atoms = this.getAtoms();
319
- this.atomListeners.forEach(listener => listener(atoms));
320
- }
321
- }
322
- const jotaiStateStore = exports.jotaiStateStore = new JotaiStateStore();
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.jotaiStateStore=void 0;const ATOM_COLORS={count:"#10B981",auth:"#8B5CF6",user:"#3B82F6",cart:"#EC4899",app:"#6366F1",ui:"#F59E0B",settings:"#14B8A6",theme:"#06B6D4",nav:"#F97316",form:"#EF4444",modal:"#A855F7",filter:"#84CC16"};function getAtomColor(t){const e=t.toLowerCase();if(ATOM_COLORS[e])return ATOM_COLORS[e];for(const[t,s]of Object.entries(ATOM_COLORS))if(e.includes(t))return s;const s=137*t.split("").reduce((t,e)=>t+e.charCodeAt(0),0)%360,n=.7*(1-Math.abs(1.2-1)),a=n*(1-Math.abs(s/60%2-1)),o=.6-n/2;let r=0,i=0,h=0;s<60?(r=n,i=a):s<120?(r=a,i=n):s<180?(i=n,h=a):s<240?(i=a,h=n):s<300?(r=a,h=n):(r=n,h=a);const l=t=>Math.round(255*(t+o)).toString(16).padStart(2,"0");return`#${l(r)}${l(i)}${l(h)}`}function formatValuePreview(t,e=40){if(void 0===t)return"undefined";if(null===t)return"null";try{if("function"==typeof t)return"(fn)";if("string"==typeof t)return t.length>e?`"${t.slice(0,e-3)}..."`:`"${t}"`;if("number"==typeof t||"boolean"==typeof t)return String(t);if(Array.isArray(t)){if(0===t.length)return"[]";const s=JSON.stringify(t);return s.length>e?`[${t.length} items]`:s}if("object"==typeof t){const s=Object.keys(t);if(0===s.length)return"{}";const n=JSON.stringify(t);return n.length<=e?n:`{ ${s.length} keys }`}return String(t).slice(0,e)}catch{return"[complex]"}}function getValueDiffSummary(t,e){if(t===e)return{summary:"no change",changedKeys:[],changedCount:0};if("object"!=typeof t||"object"!=typeof e||null===t||null===e)return{summary:"changed",changedKeys:[],changedCount:0};const s=Object.keys(t),n=Object.keys(e),a=n.filter(t=>!s.includes(t)),o=s.filter(t=>!n.includes(t)),r=[];for(const a of s)n.includes(a)&&t[a]!==e[a]&&r.push(a);const i=[...a,...o,...r],h=[];a.length>0&&h.push(`+${a.length}`),o.length>0&&h.push(`-${o.length}`),r.length>0&&h.push(`~${r.length}`);const l=i.length;return 0===h.length?{summary:"nested change",changedKeys:[],changedCount:0}:{summary:`${h.join(" ")} ${1===l?"key":"keys"}`,changedKeys:i,changedCount:l}}class JotaiStateStore{atomChanges=[];atoms=new Map;listeners=new Set;atomListeners=new Set;maxChanges=200;idCounter=0;isEnabled=!0;addAtomChange(t){if(!this.isEnabled)return;const{atomLabel:e,prevValue:s,nextValue:n,category:a="write"}=t,o=s!==n,{summary:r,changedKeys:i,changedCount:h}=getValueDiffSummary(s,n),l=formatValuePreview(n),u={id:`${Date.now()}-${++this.idCounter}`,atomLabel:e,timestamp:Date.now(),prevValue:s,nextValue:n,hasValueChange:o,category:a,changedKeys:i,changedKeysCount:h,diffSummary:r,valuePreview:l,isSlowUpdate:!1};this.atomChanges=[u,...this.atomChanges].slice(0,this.maxChanges);const g=this.atoms.get(e);g&&g.changeCount++,this.notifyListeners(),this.notifyAtomListeners()}getAtomChanges(){return[...this.atomChanges]}getAtomChangeById(t){return this.atomChanges.find(e=>e.id===t)}clearAtomChanges(){this.atomChanges=[];for(const t of this.atoms.values())t.changeCount=0;this.notifyListeners(),this.notifyAtomListeners()}registerAtom(t,e){if(this.atoms.has(t))return;const s={label:t,changeCount:0,color:getAtomColor(t),getValue:e};this.atoms.set(t,s),this.notifyAtomListeners()}unregisterAtom(t){this.atoms.delete(t),this.notifyAtomListeners()}getAtoms(){return Array.from(this.atoms.values())}getAtom(t){return this.atoms.get(t)}getAtomColor(t){return this.atoms.get(t)?.color??getAtomColor(t)}filterAtomChanges(t){let e=[...this.atomChanges];if(t.searchText){const s=t.searchText.toLowerCase();e=e.filter(t=>t.atomLabel.toLowerCase().includes(s)||t.valuePreview.toLowerCase().includes(s)||t.changedKeys.some(t=>t.toLowerCase().includes(s)))}return t.atomLabels&&t.atomLabels.length>0&&(e=e.filter(e=>t.atomLabels.includes(e.atomLabel))),t.onlyWithChanges&&(e=e.filter(t=>t.hasValueChange)),e}getStats(){const t=this.atomChanges.length,e=this.atomChanges.filter(t=>t.hasValueChange).length;return{totalChanges:t,changesWithValueChange:e,changesWithoutValueChange:t-e,atomCount:this.atoms.size}}getUniqueAtomLabels(){return Array.from(this.atoms.keys()).sort()}setEnabled(t){this.isEnabled=t}getEnabled(){return this.isEnabled}setMaxChanges(t){this.maxChanges=t,this.atomChanges.length>t&&(this.atomChanges=this.atomChanges.slice(0,t),this.notifyListeners())}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}subscribeToAtoms(t){return this.atomListeners.add(t),()=>this.atomListeners.delete(t)}notifyListeners(){const t=this.getAtomChanges();this.listeners.forEach(e=>e(t))}notifyAtomListeners(){const t=this.getAtoms();this.atomListeners.forEach(e=>e(t))}}const jotaiStateStore=exports.jotaiStateStore=new JotaiStateStore;
@@ -1,149 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isAtomWatched = isAtomWatched;
7
- exports.watchAtoms = watchAtoms;
8
- exports.watchDefaultStoreAtoms = watchDefaultStoreAtoms;
9
- var _jotaiStateStore = require("./jotaiStateStore");
10
- /**
11
- * Buoy Jotai DevTools — Atom instrumentation
12
- *
13
- * watchAtoms() — RECOMMENDED. Pass a Jotai store and a named atom map.
14
- * Uses store.sub() to observe each atom externally. Never touches atom internals.
15
- *
16
- * watchDefaultStoreAtoms() — Convenience wrapper that uses getDefaultStore().
17
- */
18
-
19
- /** Any Jotai atom — alias for Atom<unknown> for readability */
20
-
21
- /** Minimal store shape — what Jotai's createStore() / getDefaultStore() returns */
22
-
23
- /**
24
- * Watch a set of Jotai atoms for value changes.
25
- *
26
- * Pass a Jotai store and an object mapping display names to atoms.
27
- * Uses store.sub() to observe each atom — never modifies atom internals.
28
- *
29
- * @example
30
- * ```tsx
31
- * import { getDefaultStore } from 'jotai';
32
- * import { watchAtoms } from '@buoy-gg/jotai';
33
- * import { countAtom } from './atoms/count';
34
- * import { authAtom } from './atoms/auth';
35
- *
36
- * watchAtoms(getDefaultStore(), {
37
- * countAtom,
38
- * authAtom,
39
- * });
40
- * ```
41
- *
42
- * @param store - Jotai store (from createStore() or getDefaultStore())
43
- * @param atoms - Object mapping display labels to Jotai atoms
44
- * @param options - Optional configuration
45
- * @returns Cleanup function that removes all subscriptions
46
- */
47
- function watchAtoms(store, atoms, options) {
48
- const enabled = options?.enabled !== false;
49
- const cleanups = [];
50
- for (const [label, atom] of Object.entries(atoms)) {
51
- // Skip if already watched under this label
52
- const atomAny = atom;
53
- const watchedKey = Symbol.for(`@@buoy-jotai/watched/${label}`);
54
- if (atomAny[watchedKey]) continue;
55
- atomAny[watchedKey] = true;
56
- let prevValue;
57
- try {
58
- prevValue = store.get(atom);
59
- } catch {
60
- prevValue = undefined;
61
- }
62
-
63
- // Register the atom for the browser view
64
- _jotaiStateStore.jotaiStateStore.registerAtom(label, () => {
65
- try {
66
- return store.get(atom);
67
- } catch {
68
- return undefined;
69
- }
70
- });
71
-
72
- // Record initial value
73
- if (enabled) {
74
- _jotaiStateStore.jotaiStateStore.addAtomChange({
75
- atomLabel: label,
76
- prevValue: undefined,
77
- nextValue: prevValue,
78
- category: "initial"
79
- });
80
- }
81
-
82
- // Subscribe to future changes
83
- const unsubscribe = store.sub(atom, () => {
84
- try {
85
- const nextValue = store.get(atom);
86
- _jotaiStateStore.jotaiStateStore.addAtomChange({
87
- atomLabel: label,
88
- prevValue,
89
- nextValue,
90
- category: "write"
91
- });
92
- prevValue = nextValue;
93
- } catch {
94
- // Silently catch — our bug must never propagate into the store
95
- }
96
- });
97
- cleanups.push(() => {
98
- unsubscribe();
99
- delete atomAny[watchedKey];
100
- _jotaiStateStore.jotaiStateStore.unregisterAtom(label);
101
- });
102
- }
103
- return () => cleanups.forEach(fn => fn());
104
- }
105
-
106
- /**
107
- * Watch atoms using Jotai's default store (no Provider setup required).
108
- *
109
- * Convenience wrapper around watchAtoms() — auto-imports getDefaultStore.
110
- *
111
- * @example
112
- * ```tsx
113
- * import { watchDefaultStoreAtoms } from '@buoy-gg/jotai';
114
- * import { countAtom, authAtom } from './atoms';
115
- *
116
- * watchDefaultStoreAtoms({ countAtom, authAtom });
117
- * ```
118
- */
119
- function watchDefaultStoreAtoms(atoms, options) {
120
- // Dynamic import to avoid bundling jotai internals when not needed
121
- let store;
122
- try {
123
- // eslint-disable-next-line @typescript-eslint/no-var-requires
124
- const {
125
- getDefaultStore
126
- } = require("jotai/vanilla");
127
- store = getDefaultStore();
128
- } catch {
129
- // Try the main jotai entry (React Native)
130
- try {
131
- // eslint-disable-next-line @typescript-eslint/no-var-requires
132
- const {
133
- getDefaultStore
134
- } = require("jotai");
135
- store = getDefaultStore();
136
- } catch {
137
- console.warn("[@buoy-gg/jotai] Could not find getDefaultStore from jotai. " + "Pass the store explicitly via watchAtoms(store, atoms) instead.");
138
- return () => {};
139
- }
140
- }
141
- return watchAtoms(store, atoms, options);
142
- }
143
-
144
- /**
145
- * Check if an atom label is currently being watched
146
- */
147
- function isAtomWatched(label) {
148
- return _jotaiStateStore.jotaiStateStore.getAtom(label) !== undefined;
149
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.isAtomWatched=isAtomWatched,exports.watchAtoms=watchAtoms,exports.watchDefaultStoreAtoms=watchDefaultStoreAtoms;var _jotaiStateStore=require("./jotaiStateStore");function watchAtoms(t,e,o){const a=!1!==o?.enabled,r=[];for(const[o,i]of Object.entries(e)){const e=i,c=Symbol.for(`@@buoy-jotai/watched/${o}`);if(e[c])continue;let s;e[c]=!0;try{s=t.get(i)}catch{s=void 0}_jotaiStateStore.jotaiStateStore.registerAtom(o,()=>{try{return t.get(i)}catch{return}}),a&&_jotaiStateStore.jotaiStateStore.addAtomChange({atomLabel:o,prevValue:void 0,nextValue:s,category:"initial"});const n=t.sub(i,()=>{try{const e=t.get(i);_jotaiStateStore.jotaiStateStore.addAtomChange({atomLabel:o,prevValue:s,nextValue:e,category:"write"}),s=e}catch{}});r.push(()=>{n(),delete e[c],_jotaiStateStore.jotaiStateStore.unregisterAtom(o)})}return()=>r.forEach(t=>t())}function watchDefaultStoreAtoms(t,e){let o;try{const{getDefaultStore:t}=require("jotai/vanilla");o=t()}catch{try{const{getDefaultStore:t}=require("jotai");o=t()}catch{return console.warn("[@buoy-gg/jotai] Could not find getDefaultStore from jotai. Pass the store explicitly via watchAtoms(store, atoms) instead."),()=>{}}}return watchAtoms(o,t,e)}function isAtomWatched(t){return void 0!==_jotaiStateStore.jotaiStateStore.getAtom(t)}