@buoy-gg/jotai 7.0.32 → 7.0.34

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 (35) hide show
  1. package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +20 -41
  2. package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +7 -52
  3. package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +8 -87
  4. package/lib/commonjs/jotai/components/JotaiEventFilterView.js +21 -299
  5. package/lib/commonjs/jotai/components/JotaiModal.js +82 -124
  6. package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +33 -49
  7. package/lib/commonjs/jotai/sync/jotaiSyncAdapter.js +19 -66
  8. package/lib/commonjs/jotai/utils/jotaiStateStore.js +23 -188
  9. package/lib/commonjs/jotai/utils/snapshotProvider.js +7 -25
  10. package/lib/commonjs/preset.js +14 -22
  11. package/lib/module/jotai/components/JotaiAtomBrowser.js +21 -42
  12. package/lib/module/jotai/components/JotaiAtomChangeItem.js +9 -54
  13. package/lib/module/jotai/components/JotaiAtomDetailContent.js +9 -88
  14. package/lib/module/jotai/components/JotaiEventFilterView.js +24 -302
  15. package/lib/module/jotai/components/JotaiModal.js +84 -126
  16. package/lib/module/jotai/hooks/useJotaiAtomChanges.js +34 -50
  17. package/lib/module/jotai/sync/jotaiSyncAdapter.js +20 -67
  18. package/lib/module/jotai/utils/jotaiStateStore.js +23 -188
  19. package/lib/module/jotai/utils/snapshotProvider.js +8 -26
  20. package/lib/module/preset.js +13 -20
  21. package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +1 -1
  22. package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +1 -1
  23. package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +1 -1
  24. package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts +2 -2
  25. package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +1 -1
  26. package/lib/typescript/jotai/components/JotaiModal.d.ts.map +1 -1
  27. package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts +2 -1
  28. package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +1 -1
  29. package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts +54 -68
  30. package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts.map +1 -1
  31. package/lib/typescript/jotai/utils/jotaiStateStore.d.ts +2 -25
  32. package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +1 -1
  33. package/lib/typescript/preset.d.ts +2 -8
  34. package/lib/typescript/preset.d.ts.map +1 -1
  35. package/package.json +3 -3
@@ -12,8 +12,8 @@
12
12
  */
13
13
 
14
14
  import React, { memo, useState, useCallback, useMemo } from "react";
15
- import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
16
- import { buoyColors, night, EventStepperFooter, formatRelativeTime, parseValue, Info, Zap, FileText, Database, GitBranch, copyToClipboard, ProUpgradeModal, DiffModeTabs, CompareBar } from "@buoy-gg/shared-ui";
15
+ import { View, Text, StyleSheet, ScrollView } from "react-native";
16
+ import { buoyColors, night, EventStepperFooter, formatRelativeTime, parseValue, Info, Zap, FileText, Database, GitBranch, copyToClipboard, ProUpgradeModal, DiffModeTabs, CompareBar, DetailViewToggle } from "@buoy-gg/shared-ui";
17
17
  import { DataViewer, SplitDiffViewer, TreeDiffViewer, diffThemes } from "@buoy-gg/shared-ui/dataViewer";
18
18
  import { useIsPro } from "@buoy-gg/license";
19
19
  import { jotaiStateStore } from "../utils/jotaiStateStore";
@@ -24,61 +24,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
24
  const VIEW_CONFIGS = [{
25
25
  key: "change",
26
26
  label: "CHANGE",
27
- icon: FileText,
28
- activeColor: night.color.accent
27
+ icon: FileText
29
28
  }, {
30
29
  key: "value",
31
30
  label: "VALUE",
32
- icon: Database,
33
- activeColor: night.color.accent
31
+ icon: Database
34
32
  }, {
35
33
  key: "diff",
36
34
  label: "DIFF",
37
- icon: GitBranch,
38
- activeColor: night.color.accent
35
+ icon: GitBranch
39
36
  }];
40
- function DetailViewToggle({
41
- activeView,
42
- onViewChange,
43
- diffDisabled
44
- }) {
45
- return /*#__PURE__*/_jsx(View, {
46
- style: toggleStyles.container,
47
- children: VIEW_CONFIGS.map(config => {
48
- const isActive = activeView === config.key;
49
- const isDisabled = config.key === "diff" && diffDisabled;
50
- const IconComponent = config.icon;
51
- return /*#__PURE__*/_jsx(TouchableOpacity, {
52
- style: [toggleStyles.card, isActive && [toggleStyles.cardActive, {
53
- borderColor: config.activeColor
54
- }], isDisabled && toggleStyles.cardDisabled],
55
- onPress: () => !isDisabled && onViewChange(config.key),
56
- activeOpacity: 0.7,
57
- testID: `${JOTAI_TEST_ID}-view-${config.key}`,
58
- accessibilityRole: "button",
59
- accessibilityLabel: config.label,
60
- accessibilityState: {
61
- disabled: isDisabled,
62
- selected: isActive
63
- },
64
- children: /*#__PURE__*/_jsxs(View, {
65
- style: toggleStyles.cardContent,
66
- children: [/*#__PURE__*/_jsx(IconComponent, {
67
- size: 14,
68
- color: isActive ? config.activeColor : isDisabled ? night.color.textTertiary : night.color.textSecondary
69
- }), /*#__PURE__*/_jsx(Text, {
70
- style: [toggleStyles.cardLabel, isActive && {
71
- color: config.activeColor
72
- }, isDisabled && {
73
- color: night.color.textTertiary
74
- }],
75
- children: config.label
76
- })]
77
- })
78
- }, config.key);
79
- })
80
- });
81
- }
37
+ const DIFF_DISABLED = ["diff"];
82
38
 
83
39
  // ---- Helpers ----
84
40
 
@@ -428,9 +384,11 @@ export function JotaiAtomDetailContent({
428
384
  return /*#__PURE__*/_jsxs(View, {
429
385
  style: styles.container,
430
386
  children: [/*#__PURE__*/_jsx(DetailViewToggle, {
387
+ views: VIEW_CONFIGS,
431
388
  activeView: activeView,
432
389
  onViewChange: setActiveView,
433
- diffDisabled: diffDisabled
390
+ disabledKeys: diffDisabled ? DIFF_DISABLED : undefined,
391
+ testIDPrefix: JOTAI_TEST_ID
434
392
  }), /*#__PURE__*/_jsxs(View, {
435
393
  style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
436
394
  children: [activeView === "change" && /*#__PURE__*/_jsx(JotaiAtomInfoView, {
@@ -582,43 +540,6 @@ const styles = StyleSheet.create({
582
540
  fontFamily: "monospace"
583
541
  }
584
542
  });
585
- const toggleStyles = StyleSheet.create({
586
- container: {
587
- flexDirection: "row",
588
- gap: 8,
589
- padding: 14,
590
- // Transparent so the night sheet's star field shows through.
591
- backgroundColor: "transparent"
592
- },
593
- card: {
594
- flex: 1,
595
- backgroundColor: night.color.surface,
596
- borderRadius: 12,
597
- borderWidth: 1,
598
- borderColor: night.color.border,
599
- paddingVertical: 10,
600
- paddingHorizontal: 10,
601
- justifyContent: "center"
602
- },
603
- cardActive: {
604
- borderWidth: 1.5,
605
- backgroundColor: night.color.accentSoft
606
- },
607
- cardDisabled: {
608
- opacity: 0.5
609
- },
610
- cardContent: {
611
- flexDirection: "row",
612
- alignItems: "center",
613
- gap: 6
614
- },
615
- cardLabel: {
616
- fontSize: 10,
617
- fontWeight: "700",
618
- letterSpacing: 0.5,
619
- color: night.color.textSecondary
620
- }
621
- });
622
543
  const infoStyles = StyleSheet.create({
623
544
  container: {
624
545
  flex: 1
@@ -3,315 +3,37 @@
3
3
  /**
4
4
  * JotaiEventFilterView
5
5
  *
6
- * Filter configuration UI for hiding atoms from the Atoms and Events tabs.
7
- * Mirrors ZustandEventFilterView.tsx from @buoy-gg/zustand.
6
+ * The shared `EntityFilterView` with jotai's nouns: watched atoms you can
7
+ * tap to hide, active atom-name patterns, and how it works.
8
8
  */
9
9
 
10
- import { useState } from "react";
11
- import { View, Text, TextInput, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
12
- import { SectionHeader, night, Filter, X } from "@buoy-gg/shared-ui";
13
- import { jotaiStateStore } from "../utils/jotaiStateStore";
10
+ import { useMemo } from "react";
11
+ import { EntityFilterView } from "@buoy-gg/shared-ui";
14
12
  import { JOTAI_TEST_ID, slugForTestID } from "../utils/testIDs";
15
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
- function getAtomColorForPattern(pattern, atoms) {
17
- const match = atoms.find(a => a.label.toLowerCase().includes(pattern.toLowerCase()));
18
- return match ? match.color : null;
19
- }
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ const EXAMPLES = ["• count -> hides countAtom from atoms & events", "• auth -> hides authAtom, authStatusAtom", "• user -> hides userAtom from both tabs"];
20
15
  export function JotaiEventFilterView({
21
16
  ignoredPatterns,
22
17
  onTogglePattern,
23
18
  onAddPattern,
24
19
  atoms
25
20
  }) {
26
- const [newPattern, setNewPattern] = useState("");
27
- const handleAddPattern = () => {
28
- const trimmed = newPattern.trim();
29
- if (trimmed && !ignoredPatterns.has(trimmed)) {
30
- onAddPattern(trimmed);
31
- setNewPattern("");
32
- }
33
- };
34
- return /*#__PURE__*/_jsxs(ScrollView, {
35
- style: styles.container,
36
- contentContainerStyle: styles.scrollContent,
37
- showsVerticalScrollIndicator: false,
38
- nestedScrollEnabled: true,
39
- testID: `${JOTAI_TEST_ID}-filters-scroll`,
40
- children: [/*#__PURE__*/_jsxs(View, {
41
- style: styles.section,
42
- children: [/*#__PURE__*/_jsxs(SectionHeader, {
43
- children: [/*#__PURE__*/_jsx(SectionHeader.Icon, {
44
- icon: Filter,
45
- color: night.color.textSecondary,
46
- size: 12
47
- }), /*#__PURE__*/_jsx(SectionHeader.Title, {
48
- children: "REGISTERED ATOMS"
49
- })]
50
- }), atoms.length === 0 ? /*#__PURE__*/_jsx(Text, {
51
- style: styles.emptyText,
52
- testID: `${JOTAI_TEST_ID}-filters-atoms-empty`,
53
- children: "No atoms registered yet."
54
- }) : /*#__PURE__*/_jsx(ScrollView, {
55
- style: styles.atomList,
56
- contentContainerStyle: styles.atomListContent,
57
- nestedScrollEnabled: true,
58
- testID: `${JOTAI_TEST_ID}-filters-atom-list`,
59
- children: atoms.map(atom => {
60
- const atomColor = jotaiStateStore.getAtomColor(atom.label);
61
- const isFiltered = Array.from(ignoredPatterns).some(p => atom.label.toLowerCase().includes(p.toLowerCase()));
62
- return /*#__PURE__*/_jsxs(TouchableOpacity, {
63
- style: [styles.atomRow, isFiltered && styles.atomRowFiltered],
64
- onPress: () => onTogglePattern(atom.label),
65
- activeOpacity: 0.7,
66
- testID: `${JOTAI_TEST_ID}-filters-atom-${slugForTestID(atom.label)}`,
67
- accessibilityRole: "button",
68
- accessibilityLabel: isFiltered ? `Show ${atom.label}` : `Hide ${atom.label}`,
69
- accessibilityState: {
70
- selected: isFiltered
71
- },
72
- children: [/*#__PURE__*/_jsx(View, {
73
- style: [styles.atomDot, {
74
- backgroundColor: atomColor
75
- }]
76
- }), /*#__PURE__*/_jsx(Text, {
77
- style: [styles.atomRowText, {
78
- color: atomColor
79
- }, isFiltered && styles.atomRowTextFiltered],
80
- numberOfLines: 1,
81
- children: atom.label
82
- }), isFiltered ? /*#__PURE__*/_jsx(Text, {
83
- style: styles.filteredLabel,
84
- children: "filtered"
85
- }) : /*#__PURE__*/_jsx(Text, {
86
- style: [styles.addLabel, {
87
- color: atomColor
88
- }],
89
- children: "+ add"
90
- })]
91
- }, atom.label);
92
- })
93
- }), /*#__PURE__*/_jsx(View, {
94
- style: styles.addInputWrapper,
95
- children: /*#__PURE__*/_jsx(TextInput, {
96
- testID: `${JOTAI_TEST_ID}-filters-add-input`,
97
- accessibilityLabel: "Add an ignore pattern",
98
- value: newPattern,
99
- onChangeText: setNewPattern,
100
- onSubmitEditing: handleAddPattern,
101
- placeholder: "Type a pattern and press Enter...",
102
- placeholderTextColor: night.color.placeholder,
103
- returnKeyType: "done",
104
- autoCapitalize: "none",
105
- autoCorrect: false,
106
- style: styles.patternInput
107
- })
108
- })]
109
- }), ignoredPatterns.size > 0 && /*#__PURE__*/_jsxs(View, {
110
- style: styles.section,
111
- children: [/*#__PURE__*/_jsxs(SectionHeader, {
112
- children: [/*#__PURE__*/_jsx(SectionHeader.Icon, {
113
- icon: Filter,
114
- color: night.color.textSecondary,
115
- size: 12
116
- }), /*#__PURE__*/_jsx(SectionHeader.Title, {
117
- children: "ACTIVE FILTERS"
118
- })]
119
- }), /*#__PURE__*/_jsx(View, {
120
- style: styles.patternList,
121
- children: Array.from(ignoredPatterns).map(pattern => {
122
- const atomColor = getAtomColorForPattern(pattern, atoms);
123
- return /*#__PURE__*/_jsxs(TouchableOpacity, {
124
- style: styles.patternRow,
125
- onPress: () => onTogglePattern(pattern),
126
- activeOpacity: 0.8,
127
- testID: `${JOTAI_TEST_ID}-filters-chip-${slugForTestID(pattern)}`,
128
- accessibilityRole: "button",
129
- accessibilityLabel: `Remove filter ${pattern}`,
130
- children: [atomColor ? /*#__PURE__*/_jsx(View, {
131
- style: [styles.atomDot, {
132
- backgroundColor: atomColor
133
- }]
134
- }) : null, /*#__PURE__*/_jsx(Text, {
135
- style: [styles.patternText, atomColor ? {
136
- color: atomColor
137
- } : null],
138
- numberOfLines: 1,
139
- children: pattern
140
- }), /*#__PURE__*/_jsx(X, {
141
- size: 12,
142
- color: night.color.accent + "80"
143
- })]
144
- }, pattern);
145
- })
146
- })]
147
- }), /*#__PURE__*/_jsxs(View, {
148
- style: styles.section,
149
- children: [/*#__PURE__*/_jsxs(SectionHeader, {
150
- children: [/*#__PURE__*/_jsx(SectionHeader.Icon, {
151
- icon: Filter,
152
- color: night.color.textSecondary,
153
- size: 12
154
- }), /*#__PURE__*/_jsx(SectionHeader.Title, {
155
- children: "HOW ATOM FILTERS WORK"
156
- })]
157
- }), /*#__PURE__*/_jsx(Text, {
158
- style: styles.howItWorksText,
159
- children: "Patterns hide matching atoms from both the Atoms tab and the Events tab. Tap an atom above to quickly add it as a filter."
160
- }), /*#__PURE__*/_jsxs(View, {
161
- style: styles.examplesContainer,
162
- children: [/*#__PURE__*/_jsx(Text, {
163
- style: styles.examplesTitle,
164
- children: "EXAMPLES:"
165
- }), ["• count -> hides countAtom from atoms & events", "• auth -> hides authAtom, authStatusAtom", "• user -> hides userAtom from both tabs"].map(ex => /*#__PURE__*/_jsx(Text, {
166
- style: styles.exampleItem,
167
- children: ex
168
- }, ex))]
169
- })]
170
- })]
21
+ const entities = useMemo(() => atoms.map(atom => ({
22
+ name: atom.label,
23
+ color: atom.color
24
+ })), [atoms]);
25
+ return /*#__PURE__*/_jsx(EntityFilterView, {
26
+ entities: entities,
27
+ ignoredPatterns: ignoredPatterns,
28
+ onTogglePattern: onTogglePattern,
29
+ onAddPattern: onAddPattern,
30
+ entityNoun: "ATOMS",
31
+ entitySingular: "atom",
32
+ entityKey: "atom",
33
+ testIDPrefix: JOTAI_TEST_ID,
34
+ slug: slugForTestID,
35
+ howItWorks: "Patterns hide matching atoms from both the Atoms tab and the Events tab. Tap an atom above to quickly add it as a filter.",
36
+ examples: EXAMPLES,
37
+ emptyMessage: "No atoms are being watched yet."
171
38
  });
172
- }
173
- const styles = StyleSheet.create({
174
- container: {
175
- flex: 1,
176
- // Transparent so the night sheet's star field shows through.
177
- backgroundColor: "transparent"
178
- },
179
- scrollContent: {
180
- paddingTop: 16,
181
- paddingHorizontal: 16,
182
- paddingBottom: 24,
183
- gap: 16
184
- },
185
- section: {
186
- backgroundColor: night.color.surface,
187
- borderRadius: 16,
188
- borderWidth: 1,
189
- borderColor: night.color.border,
190
- overflow: "hidden"
191
- },
192
- atomList: {
193
- maxHeight: 180
194
- },
195
- atomListContent: {
196
- paddingHorizontal: 16,
197
- paddingTop: 8,
198
- paddingBottom: 16,
199
- gap: 10
200
- },
201
- atomRow: {
202
- flexDirection: "row",
203
- alignItems: "center",
204
- gap: 10,
205
- paddingVertical: 10,
206
- paddingHorizontal: 12,
207
- backgroundColor: night.color.surfaceElevated,
208
- borderRadius: 8,
209
- borderWidth: 1,
210
- borderColor: night.color.border
211
- },
212
- atomRowFiltered: {
213
- opacity: 0.45
214
- },
215
- atomDot: {
216
- width: 7,
217
- height: 7,
218
- borderRadius: 3.5
219
- },
220
- atomRowText: {
221
- flex: 1,
222
- fontSize: 12,
223
- fontWeight: "600",
224
- fontFamily: "monospace"
225
- },
226
- atomRowTextFiltered: {
227
- color: night.color.textTertiary,
228
- textDecorationLine: "line-through"
229
- },
230
- filteredLabel: {
231
- fontSize: 10,
232
- fontWeight: "500",
233
- color: night.color.textTertiary,
234
- fontFamily: "monospace"
235
- },
236
- addLabel: {
237
- fontSize: 10,
238
- fontWeight: "600",
239
- fontFamily: "monospace"
240
- },
241
- addInputWrapper: {
242
- paddingHorizontal: 16,
243
- paddingTop: 8,
244
- paddingBottom: 8
245
- },
246
- patternList: {
247
- paddingHorizontal: 16,
248
- paddingBottom: 16,
249
- gap: 8
250
- },
251
- patternRow: {
252
- flexDirection: "row",
253
- alignItems: "center",
254
- justifyContent: "space-between",
255
- paddingVertical: 10,
256
- paddingHorizontal: 12,
257
- backgroundColor: night.color.surfaceElevated,
258
- borderRadius: 8,
259
- borderWidth: 1,
260
- borderColor: night.color.border,
261
- gap: 8
262
- },
263
- patternText: {
264
- flex: 1,
265
- fontSize: 12,
266
- fontFamily: "monospace",
267
- color: night.color.text
268
- },
269
- howItWorksText: {
270
- fontSize: 11,
271
- color: night.color.textSecondary,
272
- lineHeight: 16,
273
- marginTop: 8,
274
- paddingHorizontal: 16,
275
- fontFamily: "monospace"
276
- },
277
- examplesContainer: {
278
- paddingTop: 8,
279
- paddingHorizontal: 16,
280
- paddingBottom: 16,
281
- borderTopWidth: 1,
282
- borderTopColor: night.color.border,
283
- marginTop: 12
284
- },
285
- examplesTitle: {
286
- fontSize: 10,
287
- fontWeight: "600",
288
- color: night.color.textTertiary,
289
- fontFamily: "monospace",
290
- letterSpacing: 0.5,
291
- marginBottom: 6
292
- },
293
- exampleItem: {
294
- fontSize: 10,
295
- color: night.color.textTertiary,
296
- fontFamily: "monospace",
297
- lineHeight: 16
298
- },
299
- emptyText: {
300
- fontSize: 11,
301
- color: night.color.textTertiary,
302
- paddingHorizontal: 16,
303
- paddingVertical: 12,
304
- fontFamily: "monospace"
305
- },
306
- patternInput: {
307
- borderWidth: 1,
308
- borderColor: night.color.accentBorder,
309
- borderRadius: 8,
310
- paddingHorizontal: 12,
311
- paddingVertical: 8,
312
- fontSize: 12,
313
- color: night.color.text,
314
- fontFamily: "monospace",
315
- backgroundColor: night.color.surfaceElevated
316
- }
317
- });
39
+ }