@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
@@ -53,20 +53,14 @@ function getWriteKindLabel(atom) {
53
53
  return atom.setValue ? "writable" : "derived";
54
54
  }
55
55
  function EmptyBrowserState() {
56
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
57
- style: styles.emptyState,
58
- testID: `${_testIDs.JOTAI_TEST_ID}-atoms-empty`,
59
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Box, {
60
- size: 32,
61
- color: _sharedUi.night.color.textTertiary
62
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
63
- style: styles.emptyTitle,
64
- testID: `${_testIDs.JOTAI_TEST_ID}-atoms-empty-title`,
65
- children: "No atoms registered"
66
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
67
- style: styles.emptyText,
68
- children: "Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."
69
- })]
56
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
57
+ testID: `${_testIDs.JOTAI_TEST_ID}-atoms-empty`
58
+ // scanning = "scanning for targets… and finding none". The registry is
59
+ // discovered, not configured, so an empty one is a scan result.
60
+ ,
61
+ otto: "scanning",
62
+ title: "No atoms registered",
63
+ message: "Use watchAtoms(store, { atomName }) to register your Jotai atoms.\nThey will appear here with their current value."
70
64
  });
71
65
  }
72
66
  function JotaiAtomBrowser({
@@ -83,17 +77,19 @@ function JotaiAtomBrowser({
83
77
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyBrowserState, {});
84
78
  }
85
79
  if (filteredAtoms.length === 0 && searchQuery) {
86
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
87
- style: styles.emptyState,
80
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
88
81
  testID: `${_testIDs.JOTAI_TEST_ID}-atoms-no-match`,
89
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
90
- style: styles.emptyTitle,
91
- testID: `${_testIDs.JOTAI_TEST_ID}-atoms-no-match-title`,
92
- children: "No matching atoms"
93
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
94
- style: styles.emptyText,
95
- children: ["No atoms match \"", searchQuery, "\""]
96
- })]
82
+ ...(0, _sharedUi.resolveListEmptyState)({
83
+ subject: "atoms",
84
+ verb: "registered",
85
+ search: searchQuery,
86
+ total: atoms.length,
87
+ waiting: {
88
+ otto: "scanning",
89
+ title: "No atoms registered",
90
+ message: "Use watchAtoms() to register your Jotai atoms."
91
+ }
92
+ })
97
93
  });
98
94
  }
99
95
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
@@ -199,22 +195,5 @@ const styles = _reactNative.StyleSheet.create({
199
195
  fontWeight: "700",
200
196
  color: _sharedUi.night.color.accent,
201
197
  fontFamily: "monospace"
202
- },
203
- emptyState: {
204
- alignItems: "center",
205
- paddingVertical: 40
206
- },
207
- emptyTitle: {
208
- color: _sharedUi.night.color.text,
209
- fontSize: 14,
210
- fontWeight: "600",
211
- marginTop: 12,
212
- marginBottom: 6
213
- },
214
- emptyText: {
215
- color: _sharedUi.night.color.textTertiary,
216
- fontSize: 12,
217
- textAlign: "center",
218
- lineHeight: 18
219
198
  }
220
199
  });
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.JotaiAtomChangeItem = void 0;
7
7
  var _react = require("react");
8
- var _reactNative = require("react-native");
9
8
  var _sharedUi = require("@buoy-gg/shared-ui");
10
9
  var _jotaiStateStore = require("../utils/jotaiStateStore");
11
10
  var _jsxRuntime = require("react/jsx-runtime");
@@ -72,59 +71,15 @@ const JotaiAtomChangeItem = exports.JotaiAtomChangeItem = /*#__PURE__*/(0, _reac
72
71
  const sublabel = getSublabel(change);
73
72
  const primaryText = getPrimaryText(change);
74
73
  const badgeText = getBadgeText(change);
75
-
76
- // Always a custom badge, even when there is no icon to hang off it. The
77
- // alternative — letting CompactRow draw `badgeText` itself — leaves the one
78
- // row whose badge matters most (a write that moved the atom's identity but
79
- // none of its contents) as the only row in the list with no handle on its
80
- // badge. Same call, and the same reason, as ZustandStateChangeItem.
81
- const customBadge = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
82
- style: styles.badgeContainer,
83
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
84
- style: [styles.badgeText, {
85
- color: statusColor
86
- }],
87
- testID: testID ? `${testID}-badge` : undefined,
88
- children: badgeText
89
- }), change.hasValueChange ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
90
- style: styles.changeBadge,
91
- testID: testID ? `${testID}-change` : undefined,
92
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
93
- size: 12,
94
- color: _sharedUi.buoyColors.warning
95
- })
96
- }) : null]
97
- });
98
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
99
- statusDotColor: statusColor,
74
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChangeRow, {
75
+ statusColor: statusColor,
100
76
  statusLabel: statusLabel,
101
- statusSublabel: sublabel,
77
+ sublabel: sublabel,
102
78
  primaryText: primaryText,
103
- bottomRightText: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RelativeTime, {
104
- timestamp: change.timestamp
105
- }),
106
- customBadge: customBadge,
107
- badgeColor: statusColor,
108
- showChevron: true,
79
+ timestamp: change.timestamp,
80
+ badgeText: badgeText,
81
+ changed: change.hasValueChange,
109
82
  onPress: () => onPress(change),
110
- testID: testID,
111
- statusTestID: testID ? `${testID}-status` : undefined,
112
- statusSublabelTestID: testID ? `${testID}-sublabel` : undefined,
113
- primaryTestID: testID ? `${testID}-keys` : undefined
83
+ testID: testID
114
84
  });
115
- });
116
- const styles = _reactNative.StyleSheet.create({
117
- badgeContainer: {
118
- flexDirection: "row",
119
- alignItems: "center",
120
- gap: 4
121
- },
122
- badgeText: {
123
- fontSize: 11,
124
- fontWeight: "600",
125
- fontFamily: "monospace"
126
- },
127
- changeBadge: {
128
- paddingHorizontal: 4
129
- }
130
85
  });
@@ -29,61 +29,17 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
29
29
  const VIEW_CONFIGS = [{
30
30
  key: "change",
31
31
  label: "CHANGE",
32
- icon: _sharedUi.FileText,
33
- activeColor: _sharedUi.night.color.accent
32
+ icon: _sharedUi.FileText
34
33
  }, {
35
34
  key: "value",
36
35
  label: "VALUE",
37
- icon: _sharedUi.Database,
38
- activeColor: _sharedUi.night.color.accent
36
+ icon: _sharedUi.Database
39
37
  }, {
40
38
  key: "diff",
41
39
  label: "DIFF",
42
- icon: _sharedUi.GitBranch,
43
- activeColor: _sharedUi.night.color.accent
40
+ icon: _sharedUi.GitBranch
44
41
  }];
45
- function DetailViewToggle({
46
- activeView,
47
- onViewChange,
48
- diffDisabled
49
- }) {
50
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
51
- style: toggleStyles.container,
52
- children: VIEW_CONFIGS.map(config => {
53
- const isActive = activeView === config.key;
54
- const isDisabled = config.key === "diff" && diffDisabled;
55
- const IconComponent = config.icon;
56
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
57
- style: [toggleStyles.card, isActive && [toggleStyles.cardActive, {
58
- borderColor: config.activeColor
59
- }], isDisabled && toggleStyles.cardDisabled],
60
- onPress: () => !isDisabled && onViewChange(config.key),
61
- activeOpacity: 0.7,
62
- testID: `${_testIDs.JOTAI_TEST_ID}-view-${config.key}`,
63
- accessibilityRole: "button",
64
- accessibilityLabel: config.label,
65
- accessibilityState: {
66
- disabled: isDisabled,
67
- selected: isActive
68
- },
69
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
70
- style: toggleStyles.cardContent,
71
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(IconComponent, {
72
- size: 14,
73
- color: isActive ? config.activeColor : isDisabled ? _sharedUi.night.color.textTertiary : _sharedUi.night.color.textSecondary
74
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
75
- style: [toggleStyles.cardLabel, isActive && {
76
- color: config.activeColor
77
- }, isDisabled && {
78
- color: _sharedUi.night.color.textTertiary
79
- }],
80
- children: config.label
81
- })]
82
- })
83
- }, config.key);
84
- })
85
- });
86
- }
42
+ const DIFF_DISABLED = ["diff"];
87
43
 
88
44
  // ---- Helpers ----
89
45
 
@@ -432,10 +388,12 @@ function JotaiAtomDetailContent({
432
388
  const showInternalFooter = !disableInternalFooter && totalChanges > 1;
433
389
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
434
390
  style: styles.container,
435
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(DetailViewToggle, {
391
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.DetailViewToggle, {
392
+ views: VIEW_CONFIGS,
436
393
  activeView: activeView,
437
394
  onViewChange: setActiveView,
438
- diffDisabled: diffDisabled
395
+ disabledKeys: diffDisabled ? DIFF_DISABLED : undefined,
396
+ testIDPrefix: _testIDs.JOTAI_TEST_ID
439
397
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
440
398
  style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
441
399
  children: [activeView === "change" && /*#__PURE__*/(0, _jsxRuntime.jsx)(JotaiAtomInfoView, {
@@ -587,43 +545,6 @@ const styles = _reactNative.StyleSheet.create({
587
545
  fontFamily: "monospace"
588
546
  }
589
547
  });
590
- const toggleStyles = _reactNative.StyleSheet.create({
591
- container: {
592
- flexDirection: "row",
593
- gap: 8,
594
- padding: 14,
595
- // Transparent so the night sheet's star field shows through.
596
- backgroundColor: "transparent"
597
- },
598
- card: {
599
- flex: 1,
600
- backgroundColor: _sharedUi.night.color.surface,
601
- borderRadius: 12,
602
- borderWidth: 1,
603
- borderColor: _sharedUi.night.color.border,
604
- paddingVertical: 10,
605
- paddingHorizontal: 10,
606
- justifyContent: "center"
607
- },
608
- cardActive: {
609
- borderWidth: 1.5,
610
- backgroundColor: _sharedUi.night.color.accentSoft
611
- },
612
- cardDisabled: {
613
- opacity: 0.5
614
- },
615
- cardContent: {
616
- flexDirection: "row",
617
- alignItems: "center",
618
- gap: 6
619
- },
620
- cardLabel: {
621
- fontSize: 10,
622
- fontWeight: "700",
623
- letterSpacing: 0.5,
624
- color: _sharedUi.night.color.textSecondary
625
- }
626
- });
627
548
  const infoStyles = _reactNative.StyleSheet.create({
628
549
  container: {
629
550
  flex: 1
@@ -5,317 +5,39 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.JotaiEventFilterView = JotaiEventFilterView;
7
7
  var _react = require("react");
8
- var _reactNative = require("react-native");
9
8
  var _sharedUi = require("@buoy-gg/shared-ui");
10
- var _jotaiStateStore = require("../utils/jotaiStateStore");
11
9
  var _testIDs = require("../utils/testIDs");
12
10
  var _jsxRuntime = require("react/jsx-runtime");
13
11
  /**
14
12
  * JotaiEventFilterView
15
13
  *
16
- * Filter configuration UI for hiding atoms from the Atoms and Events tabs.
17
- * Mirrors ZustandEventFilterView.tsx from @buoy-gg/zustand.
14
+ * The shared `EntityFilterView` with jotai's nouns: watched atoms you can
15
+ * tap to hide, active atom-name patterns, and how it works.
18
16
  */
19
17
 
20
- function getAtomColorForPattern(pattern, atoms) {
21
- const match = atoms.find(a => a.label.toLowerCase().includes(pattern.toLowerCase()));
22
- return match ? match.color : null;
23
- }
18
+ const EXAMPLES = ["• count -> hides countAtom from atoms & events", "• auth -> hides authAtom, authStatusAtom", "• user -> hides userAtom from both tabs"];
24
19
  function JotaiEventFilterView({
25
20
  ignoredPatterns,
26
21
  onTogglePattern,
27
22
  onAddPattern,
28
23
  atoms
29
24
  }) {
30
- const [newPattern, setNewPattern] = (0, _react.useState)("");
31
- const handleAddPattern = () => {
32
- const trimmed = newPattern.trim();
33
- if (trimmed && !ignoredPatterns.has(trimmed)) {
34
- onAddPattern(trimmed);
35
- setNewPattern("");
36
- }
37
- };
38
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
39
- style: styles.container,
40
- contentContainerStyle: styles.scrollContent,
41
- showsVerticalScrollIndicator: false,
42
- nestedScrollEnabled: true,
43
- testID: `${_testIDs.JOTAI_TEST_ID}-filters-scroll`,
44
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
45
- style: styles.section,
46
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
47
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
48
- icon: _sharedUi.Filter,
49
- color: _sharedUi.night.color.textSecondary,
50
- size: 12
51
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
52
- children: "REGISTERED ATOMS"
53
- })]
54
- }), atoms.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
55
- style: styles.emptyText,
56
- testID: `${_testIDs.JOTAI_TEST_ID}-filters-atoms-empty`,
57
- children: "No atoms registered yet."
58
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
59
- style: styles.atomList,
60
- contentContainerStyle: styles.atomListContent,
61
- nestedScrollEnabled: true,
62
- testID: `${_testIDs.JOTAI_TEST_ID}-filters-atom-list`,
63
- children: atoms.map(atom => {
64
- const atomColor = _jotaiStateStore.jotaiStateStore.getAtomColor(atom.label);
65
- const isFiltered = Array.from(ignoredPatterns).some(p => atom.label.toLowerCase().includes(p.toLowerCase()));
66
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
67
- style: [styles.atomRow, isFiltered && styles.atomRowFiltered],
68
- onPress: () => onTogglePattern(atom.label),
69
- activeOpacity: 0.7,
70
- testID: `${_testIDs.JOTAI_TEST_ID}-filters-atom-${(0, _testIDs.slugForTestID)(atom.label)}`,
71
- accessibilityRole: "button",
72
- accessibilityLabel: isFiltered ? `Show ${atom.label}` : `Hide ${atom.label}`,
73
- accessibilityState: {
74
- selected: isFiltered
75
- },
76
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
77
- style: [styles.atomDot, {
78
- backgroundColor: atomColor
79
- }]
80
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
81
- style: [styles.atomRowText, {
82
- color: atomColor
83
- }, isFiltered && styles.atomRowTextFiltered],
84
- numberOfLines: 1,
85
- children: atom.label
86
- }), isFiltered ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
87
- style: styles.filteredLabel,
88
- children: "filtered"
89
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
90
- style: [styles.addLabel, {
91
- color: atomColor
92
- }],
93
- children: "+ add"
94
- })]
95
- }, atom.label);
96
- })
97
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
98
- style: styles.addInputWrapper,
99
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
100
- testID: `${_testIDs.JOTAI_TEST_ID}-filters-add-input`,
101
- accessibilityLabel: "Add an ignore pattern",
102
- value: newPattern,
103
- onChangeText: setNewPattern,
104
- onSubmitEditing: handleAddPattern,
105
- placeholder: "Type a pattern and press Enter...",
106
- placeholderTextColor: _sharedUi.night.color.placeholder,
107
- returnKeyType: "done",
108
- autoCapitalize: "none",
109
- autoCorrect: false,
110
- style: styles.patternInput
111
- })
112
- })]
113
- }), ignoredPatterns.size > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
114
- style: styles.section,
115
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
116
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
117
- icon: _sharedUi.Filter,
118
- color: _sharedUi.night.color.textSecondary,
119
- size: 12
120
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
121
- children: "ACTIVE FILTERS"
122
- })]
123
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
124
- style: styles.patternList,
125
- children: Array.from(ignoredPatterns).map(pattern => {
126
- const atomColor = getAtomColorForPattern(pattern, atoms);
127
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
128
- style: styles.patternRow,
129
- onPress: () => onTogglePattern(pattern),
130
- activeOpacity: 0.8,
131
- testID: `${_testIDs.JOTAI_TEST_ID}-filters-chip-${(0, _testIDs.slugForTestID)(pattern)}`,
132
- accessibilityRole: "button",
133
- accessibilityLabel: `Remove filter ${pattern}`,
134
- children: [atomColor ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
135
- style: [styles.atomDot, {
136
- backgroundColor: atomColor
137
- }]
138
- }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
139
- style: [styles.patternText, atomColor ? {
140
- color: atomColor
141
- } : null],
142
- numberOfLines: 1,
143
- children: pattern
144
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
145
- size: 12,
146
- color: _sharedUi.night.color.accent + "80"
147
- })]
148
- }, pattern);
149
- })
150
- })]
151
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
152
- style: styles.section,
153
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
154
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
155
- icon: _sharedUi.Filter,
156
- color: _sharedUi.night.color.textSecondary,
157
- size: 12
158
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
159
- children: "HOW ATOM FILTERS WORK"
160
- })]
161
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
162
- style: styles.howItWorksText,
163
- 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."
164
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
165
- style: styles.examplesContainer,
166
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
167
- style: styles.examplesTitle,
168
- children: "EXAMPLES:"
169
- }), ["• count -> hides countAtom from atoms & events", "• auth -> hides authAtom, authStatusAtom", "• user -> hides userAtom from both tabs"].map(ex => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
170
- style: styles.exampleItem,
171
- children: ex
172
- }, ex))]
173
- })]
174
- })]
25
+ const entities = (0, _react.useMemo)(() => atoms.map(atom => ({
26
+ name: atom.label,
27
+ color: atom.color
28
+ })), [atoms]);
29
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EntityFilterView, {
30
+ entities: entities,
31
+ ignoredPatterns: ignoredPatterns,
32
+ onTogglePattern: onTogglePattern,
33
+ onAddPattern: onAddPattern,
34
+ entityNoun: "ATOMS",
35
+ entitySingular: "atom",
36
+ entityKey: "atom",
37
+ testIDPrefix: _testIDs.JOTAI_TEST_ID,
38
+ slug: _testIDs.slugForTestID,
39
+ 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.",
40
+ examples: EXAMPLES,
41
+ emptyMessage: "No atoms are being watched yet."
175
42
  });
176
- }
177
- const styles = _reactNative.StyleSheet.create({
178
- container: {
179
- flex: 1,
180
- // Transparent so the night sheet's star field shows through.
181
- backgroundColor: "transparent"
182
- },
183
- scrollContent: {
184
- paddingTop: 16,
185
- paddingHorizontal: 16,
186
- paddingBottom: 24,
187
- gap: 16
188
- },
189
- section: {
190
- backgroundColor: _sharedUi.night.color.surface,
191
- borderRadius: 16,
192
- borderWidth: 1,
193
- borderColor: _sharedUi.night.color.border,
194
- overflow: "hidden"
195
- },
196
- atomList: {
197
- maxHeight: 180
198
- },
199
- atomListContent: {
200
- paddingHorizontal: 16,
201
- paddingTop: 8,
202
- paddingBottom: 16,
203
- gap: 10
204
- },
205
- atomRow: {
206
- flexDirection: "row",
207
- alignItems: "center",
208
- gap: 10,
209
- paddingVertical: 10,
210
- paddingHorizontal: 12,
211
- backgroundColor: _sharedUi.night.color.surfaceElevated,
212
- borderRadius: 8,
213
- borderWidth: 1,
214
- borderColor: _sharedUi.night.color.border
215
- },
216
- atomRowFiltered: {
217
- opacity: 0.45
218
- },
219
- atomDot: {
220
- width: 7,
221
- height: 7,
222
- borderRadius: 3.5
223
- },
224
- atomRowText: {
225
- flex: 1,
226
- fontSize: 12,
227
- fontWeight: "600",
228
- fontFamily: "monospace"
229
- },
230
- atomRowTextFiltered: {
231
- color: _sharedUi.night.color.textTertiary,
232
- textDecorationLine: "line-through"
233
- },
234
- filteredLabel: {
235
- fontSize: 10,
236
- fontWeight: "500",
237
- color: _sharedUi.night.color.textTertiary,
238
- fontFamily: "monospace"
239
- },
240
- addLabel: {
241
- fontSize: 10,
242
- fontWeight: "600",
243
- fontFamily: "monospace"
244
- },
245
- addInputWrapper: {
246
- paddingHorizontal: 16,
247
- paddingTop: 8,
248
- paddingBottom: 8
249
- },
250
- patternList: {
251
- paddingHorizontal: 16,
252
- paddingBottom: 16,
253
- gap: 8
254
- },
255
- patternRow: {
256
- flexDirection: "row",
257
- alignItems: "center",
258
- justifyContent: "space-between",
259
- paddingVertical: 10,
260
- paddingHorizontal: 12,
261
- backgroundColor: _sharedUi.night.color.surfaceElevated,
262
- borderRadius: 8,
263
- borderWidth: 1,
264
- borderColor: _sharedUi.night.color.border,
265
- gap: 8
266
- },
267
- patternText: {
268
- flex: 1,
269
- fontSize: 12,
270
- fontFamily: "monospace",
271
- color: _sharedUi.night.color.text
272
- },
273
- howItWorksText: {
274
- fontSize: 11,
275
- color: _sharedUi.night.color.textSecondary,
276
- lineHeight: 16,
277
- marginTop: 8,
278
- paddingHorizontal: 16,
279
- fontFamily: "monospace"
280
- },
281
- examplesContainer: {
282
- paddingTop: 8,
283
- paddingHorizontal: 16,
284
- paddingBottom: 16,
285
- borderTopWidth: 1,
286
- borderTopColor: _sharedUi.night.color.border,
287
- marginTop: 12
288
- },
289
- examplesTitle: {
290
- fontSize: 10,
291
- fontWeight: "600",
292
- color: _sharedUi.night.color.textTertiary,
293
- fontFamily: "monospace",
294
- letterSpacing: 0.5,
295
- marginBottom: 6
296
- },
297
- exampleItem: {
298
- fontSize: 10,
299
- color: _sharedUi.night.color.textTertiary,
300
- fontFamily: "monospace",
301
- lineHeight: 16
302
- },
303
- emptyText: {
304
- fontSize: 11,
305
- color: _sharedUi.night.color.textTertiary,
306
- paddingHorizontal: 16,
307
- paddingVertical: 12,
308
- fontFamily: "monospace"
309
- },
310
- patternInput: {
311
- borderWidth: 1,
312
- borderColor: _sharedUi.night.color.accentBorder,
313
- borderRadius: 8,
314
- paddingHorizontal: 12,
315
- paddingVertical: 8,
316
- fontSize: 12,
317
- color: _sharedUi.night.color.text,
318
- fontFamily: "monospace",
319
- backgroundColor: _sharedUi.night.color.surfaceElevated
320
- }
321
- });
43
+ }