@buoy-gg/jotai 7.0.33 → 7.0.35

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 (38) hide show
  1. package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +2 -2
  2. package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +7 -52
  3. package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +18 -97
  4. package/lib/commonjs/jotai/components/JotaiAtomValueDetailContent.js +5 -5
  5. package/lib/commonjs/jotai/components/JotaiEventFilterView.js +21 -299
  6. package/lib/commonjs/jotai/components/JotaiModal.js +20 -85
  7. package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +33 -49
  8. package/lib/commonjs/jotai/sync/jotaiSyncAdapter.js +19 -66
  9. package/lib/commonjs/jotai/utils/jotaiStateStore.js +23 -188
  10. package/lib/commonjs/jotai/utils/snapshotProvider.js +7 -25
  11. package/lib/commonjs/preset.js +14 -22
  12. package/lib/module/jotai/components/JotaiAtomBrowser.js +3 -3
  13. package/lib/module/jotai/components/JotaiAtomChangeItem.js +9 -54
  14. package/lib/module/jotai/components/JotaiAtomDetailContent.js +19 -98
  15. package/lib/module/jotai/components/JotaiAtomValueDetailContent.js +6 -6
  16. package/lib/module/jotai/components/JotaiEventFilterView.js +24 -302
  17. package/lib/module/jotai/components/JotaiModal.js +22 -87
  18. package/lib/module/jotai/hooks/useJotaiAtomChanges.js +34 -50
  19. package/lib/module/jotai/sync/jotaiSyncAdapter.js +20 -67
  20. package/lib/module/jotai/utils/jotaiStateStore.js +23 -188
  21. package/lib/module/jotai/utils/snapshotProvider.js +8 -26
  22. package/lib/module/preset.js +13 -20
  23. package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +1 -1
  24. package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +1 -1
  25. package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +1 -1
  26. package/lib/typescript/jotai/components/JotaiAtomValueDetailContent.d.ts.map +1 -1
  27. package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts +2 -2
  28. package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +1 -1
  29. package/lib/typescript/jotai/components/JotaiModal.d.ts.map +1 -1
  30. package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts +2 -1
  31. package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +1 -1
  32. package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts +54 -68
  33. package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts.map +1 -1
  34. package/lib/typescript/jotai/utils/jotaiStateStore.d.ts +2 -25
  35. package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +1 -1
  36. package/lib/typescript/preset.d.ts +2 -8
  37. package/lib/typescript/preset.d.ts.map +1 -1
  38. package/package.json +3 -3
@@ -165,7 +165,7 @@ const styles = _reactNative.StyleSheet.create({
165
165
  absCountText: {
166
166
  fontSize: 9,
167
167
  fontWeight: "700",
168
- fontFamily: "monospace"
168
+ fontFamily: _sharedUi.monoFont
169
169
  },
170
170
  scrollContent: {
171
171
  paddingTop: 8,
@@ -194,6 +194,6 @@ const styles = _reactNative.StyleSheet.create({
194
194
  fontSize: 10,
195
195
  fontWeight: "700",
196
196
  color: _sharedUi.night.color.accent,
197
- fontFamily: "monospace"
197
+ fontFamily: _sharedUi.monoFont
198
198
  }
199
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, {
@@ -523,7 +481,7 @@ const styles = _reactNative.StyleSheet.create({
523
481
  valueLabel: {
524
482
  fontSize: 10,
525
483
  color: _sharedUi.night.color.textSecondary,
526
- fontFamily: "monospace",
484
+ fontFamily: _sharedUi.monoFont,
527
485
  letterSpacing: 0.5,
528
486
  fontWeight: "600"
529
487
  },
@@ -540,7 +498,7 @@ const styles = _reactNative.StyleSheet.create({
540
498
  changeText: {
541
499
  fontSize: 9,
542
500
  fontWeight: "700",
543
- fontFamily: "monospace",
501
+ fontFamily: _sharedUi.monoFont,
544
502
  letterSpacing: 0.3
545
503
  },
546
504
  typeBadge: {
@@ -553,7 +511,7 @@ const styles = _reactNative.StyleSheet.create({
553
511
  fontSize: 9,
554
512
  fontWeight: "600",
555
513
  color: _sharedUi.night.color.textTertiary,
556
- fontFamily: "monospace"
514
+ fontFamily: _sharedUi.monoFont
557
515
  },
558
516
  valueBox: {
559
517
  // Inset code box — darker than the card, the night track color.
@@ -566,7 +524,7 @@ const styles = _reactNative.StyleSheet.create({
566
524
  valueText: {
567
525
  fontSize: 12,
568
526
  color: _sharedUi.night.color.text,
569
- fontFamily: "monospace",
527
+ fontFamily: _sharedUi.monoFont,
570
528
  lineHeight: 18
571
529
  },
572
530
  diffContainer: {
@@ -584,44 +542,7 @@ const styles = _reactNative.StyleSheet.create({
584
542
  changeTextSmall: {
585
543
  fontSize: 8,
586
544
  fontWeight: "700",
587
- fontFamily: "monospace"
588
- }
589
- });
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
545
+ fontFamily: _sharedUi.monoFont
625
546
  }
626
547
  });
627
548
  const infoStyles = _reactNative.StyleSheet.create({
@@ -667,7 +588,7 @@ const infoStyles = _reactNative.StyleSheet.create({
667
588
  fontWeight: "600",
668
589
  letterSpacing: 0.5,
669
590
  color: _sharedUi.night.color.accent,
670
- fontFamily: "monospace"
591
+ fontFamily: _sharedUi.monoFont
671
592
  },
672
593
  cardContent: {
673
594
  padding: 14,
@@ -692,7 +613,7 @@ const infoStyles = _reactNative.StyleSheet.create({
692
613
  marginLeft: 12
693
614
  },
694
615
  infoValueMono: {
695
- fontFamily: "monospace"
616
+ fontFamily: _sharedUi.monoFont
696
617
  },
697
618
  badgeRow: {
698
619
  flexDirection: "row",
@@ -752,7 +673,7 @@ const infoStyles = _reactNative.StyleSheet.create({
752
673
  fontSize: 11,
753
674
  fontWeight: "600",
754
675
  color: _sharedUi.night.color.accent,
755
- fontFamily: "monospace"
676
+ fontFamily: _sharedUi.monoFont
756
677
  },
757
678
  countBadge: {
758
679
  paddingHorizontal: 8,
@@ -764,7 +685,7 @@ const infoStyles = _reactNative.StyleSheet.create({
764
685
  fontSize: 9,
765
686
  fontWeight: "700",
766
687
  color: _sharedUi.night.color.accent,
767
- fontFamily: "monospace"
688
+ fontFamily: _sharedUi.monoFont
768
689
  },
769
690
  actionsRow: {
770
691
  flexDirection: "row",
@@ -783,7 +704,7 @@ const infoStyles = _reactNative.StyleSheet.create({
783
704
  actionButtonText: {
784
705
  fontSize: 10,
785
706
  fontWeight: "700",
786
- fontFamily: "monospace",
707
+ fontFamily: _sharedUi.monoFont,
787
708
  letterSpacing: 0.3
788
709
  },
789
710
  dataViewerContainer: {
@@ -364,7 +364,7 @@ const styles = _reactNative.StyleSheet.create({
364
364
  color: _sharedUi.night.color.accent,
365
365
  letterSpacing: 0.5,
366
366
  textTransform: "uppercase",
367
- fontFamily: "monospace"
367
+ fontFamily: _sharedUi.monoFont
368
368
  },
369
369
  rawButton: {
370
370
  flexDirection: "row",
@@ -411,7 +411,7 @@ const styles = _reactNative.StyleSheet.create({
411
411
  borderBottomColor: _sharedUi.night.color.border,
412
412
  letterSpacing: 0.5,
413
413
  textTransform: "uppercase",
414
- fontFamily: "monospace"
414
+ fontFamily: _sharedUi.monoFont
415
415
  },
416
416
  infoBody: {
417
417
  padding: 12,
@@ -424,13 +424,13 @@ const styles = _reactNative.StyleSheet.create({
424
424
  primitiveText: {
425
425
  color: _sharedUi.night.color.text,
426
426
  fontSize: 12,
427
- fontFamily: "monospace",
427
+ fontFamily: _sharedUi.monoFont,
428
428
  padding: 14
429
429
  },
430
430
  valueTypeText: {
431
431
  color: _sharedUi.night.color.textTertiary,
432
432
  fontSize: 10,
433
- fontFamily: "monospace",
433
+ fontFamily: _sharedUi.monoFont,
434
434
  marginLeft: 6
435
435
  },
436
436
  inlineLinkButton: {
@@ -439,6 +439,6 @@ const styles = _reactNative.StyleSheet.create({
439
439
  inlineLinkText: {
440
440
  fontSize: 10,
441
441
  fontWeight: "600",
442
- fontFamily: "monospace"
442
+ fontFamily: _sharedUi.monoFont
443
443
  }
444
444
  });
@@ -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
+ }