@buoy-gg/zustand 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 (45) hide show
  1. package/lib/commonjs/zustand/components/ZustandActionButton.js +1 -1
  2. package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +13 -107
  3. package/lib/commonjs/zustand/components/ZustandEventFilterView.js +24 -288
  4. package/lib/commonjs/zustand/components/ZustandModal.js +20 -85
  5. package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +8 -61
  6. package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +5 -5
  7. package/lib/commonjs/zustand/components/ZustandStateInfoView.js +8 -52
  8. package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +2 -2
  9. package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +4 -4
  10. package/lib/commonjs/zustand/components/ZustandStoreEditorScreen.js +3 -3
  11. package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +33 -53
  12. package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +24 -78
  13. package/lib/commonjs/zustand/utils/snapshotProvider.js +17 -60
  14. package/lib/commonjs/zustand/utils/zustandStateStore.js +37 -223
  15. package/lib/module/zustand/components/ZustandActionButton.js +2 -2
  16. package/lib/module/zustand/components/ZustandDetailViewToggle.js +15 -109
  17. package/lib/module/zustand/components/ZustandEventFilterView.js +28 -292
  18. package/lib/module/zustand/components/ZustandModal.js +22 -87
  19. package/lib/module/zustand/components/ZustandStateChangeItem.js +10 -63
  20. package/lib/module/zustand/components/ZustandStateDetailContent.js +6 -6
  21. package/lib/module/zustand/components/ZustandStateInfoView.js +7 -51
  22. package/lib/module/zustand/components/ZustandStoreBrowser.js +3 -3
  23. package/lib/module/zustand/components/ZustandStoreDetailContent.js +5 -5
  24. package/lib/module/zustand/components/ZustandStoreEditorScreen.js +4 -4
  25. package/lib/module/zustand/hooks/useZustandStateChanges.js +34 -54
  26. package/lib/module/zustand/sync/zustandSyncAdapter.js +25 -79
  27. package/lib/module/zustand/utils/snapshotProvider.js +18 -61
  28. package/lib/module/zustand/utils/zustandStateStore.js +37 -223
  29. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts +2 -1
  30. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +1 -1
  31. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts +6 -0
  32. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +1 -1
  33. package/lib/typescript/zustand/components/ZustandModal.d.ts.map +1 -1
  34. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +1 -1
  35. package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +1 -1
  36. package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +1 -1
  37. package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +1 -1
  38. package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts.map +1 -1
  39. package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts +2 -1
  40. package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +1 -1
  41. package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts +103 -117
  42. package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +1 -1
  43. package/lib/typescript/zustand/utils/zustandStateStore.d.ts +6 -26
  44. package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +1 -1
  45. package/package.json +3 -3
@@ -112,7 +112,7 @@ const styles = _reactNative.StyleSheet.create({
112
112
  fontWeight: "600",
113
113
  letterSpacing: 0.5,
114
114
  textTransform: "uppercase",
115
- fontFamily: "monospace",
115
+ fontFamily: _sharedUi.monoFont,
116
116
  height: 12
117
117
  }
118
118
  });
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.ZustandDetailViewToggle = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
- var _reactNative = require("react-native");
9
8
  var _sharedUi = require("@buoy-gg/shared-ui");
10
9
  var _jsxRuntime = require("react/jsx-runtime");
11
10
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -13,130 +12,37 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
13
12
  * ZustandDetailViewToggle
14
13
  *
15
14
  * Three-card toggle for switching between Change, State, and Diff views.
16
- * Mirrors ReduxDetailViewToggle.tsx
15
+ * The cards themselves are the shared `DetailViewToggle`; this file owns
16
+ * the zustand view list and testID prefix.
17
17
  */
18
18
 
19
- const VIEW_CONFIGS = [{
19
+ const VIEWS = [{
20
20
  key: "change",
21
21
  label: "CHANGE",
22
22
  description: "View change details",
23
- icon: _sharedUi.FileText,
24
- activeColor: _sharedUi.night.color.accent
23
+ icon: _sharedUi.FileText
25
24
  }, {
26
25
  key: "state",
27
26
  label: "STATE",
28
27
  description: "View current state",
29
- icon: _sharedUi.Database,
30
- activeColor: _sharedUi.night.color.accent
28
+ icon: _sharedUi.Database
31
29
  }, {
32
30
  key: "diff",
33
31
  label: "DIFF",
34
32
  description: "Compare changes",
35
- icon: _sharedUi.GitBranch,
36
- activeColor: _sharedUi.night.color.accent
33
+ icon: _sharedUi.GitBranch
37
34
  }];
35
+ const DIFF_DISABLED = ["diff"];
38
36
  const ZustandDetailViewToggle = exports.ZustandDetailViewToggle = /*#__PURE__*/(0, _react.memo)(function ZustandDetailViewToggle({
39
37
  activeView,
40
38
  onViewChange,
41
39
  diffDisabled = false
42
40
  }) {
43
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
44
- style: styles.container,
45
- children: VIEW_CONFIGS.map(config => {
46
- const isActive = activeView === config.key;
47
- const isDisabled = config.key === "diff" && diffDisabled;
48
- const IconComponent = config.icon;
49
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
50
- style: [styles.card, isActive && [styles.cardActive, {
51
- borderColor: config.activeColor
52
- }], isDisabled && styles.cardDisabled],
53
- onPress: () => !isDisabled && onViewChange(config.key),
54
- activeOpacity: isDisabled ? 1 : 0.8,
55
- disabled: isDisabled,
56
- testID: `buoy-zustand-view-${config.key}`,
57
- accessibilityRole: "button",
58
- accessibilityLabel: config.label,
59
- accessibilityState: {
60
- disabled: isDisabled,
61
- selected: isActive
62
- },
63
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
64
- style: styles.cardContent,
65
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(IconComponent, {
66
- size: 14,
67
- color: isActive ? config.activeColor : isDisabled ? _sharedUi.night.color.textTertiary : _sharedUi.night.color.textSecondary
68
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
69
- style: [styles.cardLabel, isActive && [styles.cardLabelActive, {
70
- color: config.activeColor
71
- }], isDisabled && styles.cardLabelDisabled],
72
- children: config.label
73
- })]
74
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
75
- style: [styles.cardDescription, isActive && styles.cardDescriptionActive, isDisabled && styles.cardDescriptionDisabled],
76
- children: config.description
77
- })]
78
- }, config.key);
79
- })
41
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.DetailViewToggle, {
42
+ views: VIEWS,
43
+ activeView: activeView,
44
+ onViewChange: onViewChange,
45
+ disabledKeys: diffDisabled ? DIFF_DISABLED : undefined,
46
+ testIDPrefix: "buoy-zustand"
80
47
  });
81
- });
82
- const styles = _reactNative.StyleSheet.create({
83
- container: {
84
- flexDirection: "row",
85
- gap: 8,
86
- padding: 14,
87
- // Transparent so the night sheet's star field shows through.
88
- backgroundColor: "transparent"
89
- },
90
- card: {
91
- flex: 1,
92
- backgroundColor: _sharedUi.night.color.surface,
93
- borderRadius: 12,
94
- borderWidth: 1,
95
- borderColor: _sharedUi.night.color.border,
96
- padding: 10,
97
- gap: 4
98
- },
99
- cardActive: {
100
- borderWidth: 1.5,
101
- backgroundColor: _sharedUi.night.color.accentSoft,
102
- shadowColor: _sharedUi.night.color.accent,
103
- shadowOffset: {
104
- width: 0,
105
- height: 2
106
- },
107
- shadowOpacity: 0.1,
108
- shadowRadius: 8,
109
- elevation: 3
110
- },
111
- cardDisabled: {
112
- opacity: 0.5
113
- },
114
- cardContent: {
115
- flexDirection: "row",
116
- alignItems: "center",
117
- gap: 6
118
- },
119
- cardLabel: {
120
- fontSize: 10,
121
- fontWeight: "700",
122
- letterSpacing: 0.5,
123
- color: _sharedUi.night.color.textSecondary
124
- },
125
- cardLabelActive: {
126
- color: _sharedUi.night.color.text
127
- },
128
- cardLabelDisabled: {
129
- color: _sharedUi.night.color.textTertiary
130
- },
131
- cardDescription: {
132
- fontSize: 9,
133
- color: _sharedUi.night.color.textTertiary,
134
- lineHeight: 12
135
- },
136
- cardDescriptionActive: {
137
- color: _sharedUi.night.color.textSecondary
138
- },
139
- cardDescriptionDisabled: {
140
- color: _sharedUi.night.color.textTertiary
141
- }
142
48
  });
@@ -5,303 +5,39 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.ZustandEventFilterView = ZustandEventFilterView;
7
7
  var _react = require("react");
8
- var _reactNative = require("react-native");
9
8
  var _sharedUi = require("@buoy-gg/shared-ui");
10
9
  var _zustandStateStore = require("../utils/zustandStateStore");
11
10
  var _testIDs = require("../utils/testIDs");
12
11
  var _jsxRuntime = require("react/jsx-runtime");
13
- /** Returns the store color for a given pattern if it exactly matches a registered store name */
14
- function getStoreColorForPattern(pattern, stores) {
15
- const match = stores.find(s => s.name.toLowerCase() === pattern.toLowerCase());
16
- return match ? _zustandStateStore.zustandStateStore.getStoreColor(match.name) : null;
17
- }
12
+ /**
13
+ * ZustandEventFilterView
14
+ *
15
+ * The shared `EntityFilterView` with zustand's nouns: registered stores you
16
+ * can tap to hide, active store-name patterns, and how it works.
17
+ */
18
18
 
19
- /** True if any active pattern filters out this store */
20
- function isStoreFiltered(store, ignoredPatterns) {
21
- return Array.from(ignoredPatterns).some(p => store.name.toLowerCase().includes(p.toLowerCase()));
22
- }
19
+ const EXAMPLES = ["• auth → hides authStore from stores & events", "• temp → hides tempStore, tempUserStore", "• cart → hides cartStore from both tabs"];
23
20
  function ZustandEventFilterView({
24
21
  ignoredPatterns,
25
22
  onTogglePattern,
26
23
  onAddPattern,
27
24
  stores
28
25
  }) {
29
- const [showAddInput, setShowAddInput] = (0, _react.useState)(false);
30
- const [inputValue, setInputValue] = (0, _react.useState)("");
31
- const handleAddPattern = () => {
32
- const trimmed = inputValue.trim();
33
- if (trimmed) {
34
- onAddPattern(trimmed);
35
- setInputValue("");
36
- setShowAddInput(false);
37
- }
38
- };
39
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
40
- style: styles.container,
41
- contentContainerStyle: styles.scrollContent,
42
- showsVerticalScrollIndicator: false,
43
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-scroll`,
44
- children: [stores.length > 0 && /*#__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.Title, {
48
- children: "REGISTERED STORES"
49
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Badge, {
50
- count: stores.length,
51
- color: _sharedUi.night.color.accent,
52
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-store-count`
53
- })]
54
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
55
- style: styles.storeList,
56
- contentContainerStyle: styles.storeListContent,
57
- showsVerticalScrollIndicator: true,
58
- nestedScrollEnabled: true,
59
- children: stores.map(store => {
60
- const storeColor = _zustandStateStore.zustandStateStore.getStoreColor(store.name);
61
- const filtered = isStoreFiltered(store, ignoredPatterns);
62
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
63
- style: [styles.storeRow, filtered && styles.storeRowFiltered],
64
- onPress: () => onAddPattern(store.name),
65
- disabled: filtered,
66
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-store-${(0, _testIDs.slugForTestID)(store.name)}`,
67
- accessibilityRole: "button",
68
- accessibilityLabel: `Hide ${store.name}`,
69
- accessibilityState: {
70
- disabled: filtered
71
- },
72
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
73
- style: [styles.storeDot, {
74
- backgroundColor: filtered ? _sharedUi.night.color.textTertiary : storeColor
75
- }]
76
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
77
- style: [styles.storeRowText, filtered && styles.storeRowTextFiltered, !filtered && {
78
- color: storeColor
79
- }],
80
- numberOfLines: 1,
81
- children: store.name
82
- }), filtered ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
83
- style: styles.filteredLabel,
84
- children: "hidden"
85
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
86
- style: [styles.addLabel, {
87
- color: storeColor + "99"
88
- }],
89
- children: "+ hide"
90
- })]
91
- }, store.name);
92
- })
93
- })]
94
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
95
- style: styles.section,
96
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
97
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
98
- icon: _sharedUi.Filter,
99
- color: _sharedUi.night.color.accent,
100
- size: 12
101
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
102
- children: "STORE NAME FILTERS"
103
- }), ignoredPatterns.size > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Badge, {
104
- count: ignoredPatterns.size,
105
- color: _sharedUi.night.color.accent,
106
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-count`
107
- })]
108
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
109
- style: styles.addInputWrapper,
110
- children: !showAddInput ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AddFilterButton, {
111
- onPress: () => setShowAddInput(true),
112
- color: _sharedUi.night.color.accent,
113
- label: "Add store name pattern",
114
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-add-open`
115
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AddFilterInput, {
116
- value: inputValue,
117
- onChange: setInputValue,
118
- onSubmit: handleAddPattern,
119
- onCancel: () => {
120
- setShowAddInput(false);
121
- setInputValue("");
122
- },
123
- placeholder: "Enter store name pattern to hide...",
124
- color: _sharedUi.night.color.accent,
125
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-add-input`
126
- })
127
- }), ignoredPatterns.size > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
128
- style: styles.patternList,
129
- children: Array.from(ignoredPatterns).map(pattern => {
130
- const storeColor = getStoreColorForPattern(pattern, stores);
131
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
132
- style: styles.patternRow,
133
- onPress: () => onTogglePattern(pattern),
134
- activeOpacity: 0.8,
135
- testID: `${_testIDs.ZUSTAND_TEST_ID}-filters-chip-${(0, _testIDs.slugForTestID)(pattern)}`,
136
- accessibilityRole: "button",
137
- accessibilityLabel: `Remove filter ${pattern}`,
138
- children: [storeColor ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
139
- style: [styles.storeDot, {
140
- backgroundColor: storeColor
141
- }]
142
- }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
143
- style: [styles.patternText, storeColor ? {
144
- color: storeColor
145
- } : null],
146
- numberOfLines: 1,
147
- children: pattern
148
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
149
- size: 12,
150
- color: _sharedUi.night.color.accent + "80"
151
- })]
152
- }, pattern);
153
- })
154
- })]
155
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
156
- style: styles.section,
157
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
158
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
159
- icon: _sharedUi.Filter,
160
- color: _sharedUi.night.color.textSecondary,
161
- size: 12
162
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
163
- children: "HOW EVENT FILTERS WORK"
164
- })]
165
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
166
- style: styles.howItWorksText,
167
- children: "Patterns hide matching stores from both the Stores tab and the Events tab. Tap a store above to quickly add it as a filter."
168
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
169
- style: styles.examplesContainer,
170
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
171
- style: styles.examplesTitle,
172
- children: "EXAMPLES:"
173
- }), ["• auth → hides authStore from stores & events", "• temp → hides tempStore, tempUserStore", "• cart → hides cartStore from both tabs"].map(ex => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
174
- style: styles.exampleItem,
175
- children: ex
176
- }, ex))]
177
- })]
178
- })]
26
+ const entities = (0, _react.useMemo)(() => stores.map(store => ({
27
+ name: store.name,
28
+ color: _zustandStateStore.zustandStateStore.getStoreColor(store.name)
29
+ })), [stores]);
30
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EntityFilterView, {
31
+ entities: entities,
32
+ ignoredPatterns: ignoredPatterns,
33
+ onTogglePattern: onTogglePattern,
34
+ onAddPattern: onAddPattern,
35
+ entityNoun: "STORES",
36
+ entitySingular: "store",
37
+ entityKey: "store",
38
+ testIDPrefix: _testIDs.ZUSTAND_TEST_ID,
39
+ slug: _testIDs.slugForTestID,
40
+ howItWorks: "Patterns hide matching stores from both the Stores tab and the Events tab. Tap a store above to quickly add it as a filter.",
41
+ examples: EXAMPLES
179
42
  });
180
- }
181
- const styles = _reactNative.StyleSheet.create({
182
- container: {
183
- flex: 1,
184
- // Transparent so the night sheet's star field shows through.
185
- backgroundColor: "transparent"
186
- },
187
- scrollContent: {
188
- paddingTop: 16,
189
- paddingHorizontal: 16,
190
- paddingBottom: 24,
191
- gap: 16
192
- },
193
- section: {
194
- backgroundColor: _sharedUi.night.color.surface,
195
- borderRadius: 16,
196
- borderWidth: 1,
197
- borderColor: _sharedUi.night.color.border,
198
- overflow: "hidden"
199
- },
200
- storeList: {
201
- maxHeight: 180
202
- },
203
- storeListContent: {
204
- paddingHorizontal: 16,
205
- paddingTop: 8,
206
- paddingBottom: 16,
207
- gap: 10
208
- },
209
- storeRow: {
210
- flexDirection: "row",
211
- alignItems: "center",
212
- gap: 10,
213
- paddingVertical: 10,
214
- paddingHorizontal: 12,
215
- backgroundColor: _sharedUi.night.color.surfaceElevated,
216
- borderRadius: 8,
217
- borderWidth: 1,
218
- borderColor: _sharedUi.night.color.border
219
- },
220
- storeRowFiltered: {
221
- opacity: 0.45
222
- },
223
- storeDot: {
224
- width: 7,
225
- height: 7,
226
- borderRadius: 3.5
227
- },
228
- storeRowText: {
229
- flex: 1,
230
- fontSize: 12,
231
- fontWeight: "600",
232
- fontFamily: "monospace"
233
- },
234
- storeRowTextFiltered: {
235
- color: _sharedUi.night.color.textTertiary,
236
- textDecorationLine: "line-through"
237
- },
238
- filteredLabel: {
239
- fontSize: 10,
240
- fontWeight: "500",
241
- color: _sharedUi.night.color.textTertiary,
242
- fontFamily: "monospace"
243
- },
244
- addLabel: {
245
- fontSize: 10,
246
- fontWeight: "600",
247
- fontFamily: "monospace"
248
- },
249
- addInputWrapper: {
250
- paddingHorizontal: 16,
251
- paddingTop: 8,
252
- paddingBottom: 8
253
- },
254
- patternList: {
255
- paddingHorizontal: 16,
256
- paddingBottom: 16,
257
- gap: 8
258
- },
259
- patternRow: {
260
- flexDirection: "row",
261
- alignItems: "center",
262
- justifyContent: "space-between",
263
- paddingVertical: 10,
264
- paddingHorizontal: 12,
265
- backgroundColor: _sharedUi.night.color.surfaceElevated,
266
- borderRadius: 8,
267
- borderWidth: 1,
268
- borderColor: _sharedUi.night.color.border,
269
- gap: 8
270
- },
271
- patternText: {
272
- flex: 1,
273
- fontSize: 12,
274
- fontFamily: "monospace",
275
- color: _sharedUi.night.color.text
276
- },
277
- howItWorksText: {
278
- fontSize: 11,
279
- color: _sharedUi.night.color.textSecondary,
280
- lineHeight: 16,
281
- marginTop: 8,
282
- paddingHorizontal: 16,
283
- fontFamily: "monospace"
284
- },
285
- examplesContainer: {
286
- paddingTop: 8,
287
- paddingHorizontal: 16,
288
- paddingBottom: 16,
289
- borderTopWidth: 1,
290
- borderTopColor: _sharedUi.night.color.border,
291
- marginTop: 12
292
- },
293
- examplesTitle: {
294
- fontSize: 10,
295
- fontWeight: "600",
296
- color: _sharedUi.night.color.textTertiary,
297
- fontFamily: "monospace",
298
- letterSpacing: 0.5,
299
- marginBottom: 6
300
- },
301
- exampleItem: {
302
- fontSize: 10,
303
- color: _sharedUi.night.color.textTertiary,
304
- fontFamily: "monospace",
305
- lineHeight: 16
306
- }
307
- });
43
+ }
@@ -25,17 +25,6 @@ var _jsxRuntime = require("react/jsx-runtime");
25
25
  * - Events tab: Live state change monitoring with diffs
26
26
  */
27
27
 
28
- /**
29
- * Cell clipping, off in e2e bundles only.
30
- *
31
- * `removeClippedSubviews` unmounts the views of rows scrolled out of the
32
- * window, which is what makes a long change list cheap — and which makes
33
- * Detox report a perfectly rendered row as un-hittable. The env var is
34
- * inlined at bundle time, so a bundler that does NOT inline it leaves the
35
- * production behaviour exactly as it was.
36
- */
37
- const CLIP_OFFSCREEN_CELLS = !(typeof process !== "undefined" && process.env?.EXPO_PUBLIC_E2E);
38
-
39
28
  /**
40
29
  * The change log's "nothing here". Everything but the nouns is the shared
41
30
  * precedence — see `ToolEmptyState` in shared-ui for why it lives there.
@@ -390,49 +379,24 @@ function ZustandModal({
390
379
  onBack: onBack
391
380
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
392
381
  title: "",
393
- children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
394
- style: styles.headerSearchContainer,
395
- testID: `${_testIDs.ZUSTAND_TEST_ID}-search`,
396
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
397
- size: 14,
398
- color: _sharedUi.night.color.textSecondary
399
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
400
- ref: searchInputRef,
401
- testID: `${_testIDs.ZUSTAND_TEST_ID}-search-field`,
402
- style: styles.headerSearchInput,
403
- placeholder: activeTab === "stores" ? "Search stores..." : "Search events...",
404
- placeholderTextColor: _sharedUi.night.color.placeholder,
405
- value: searchText,
406
- onChangeText: handleSearch,
407
- onSubmitEditing: () => searchInputRef.current?.blur()
408
- // Stay open while the query is still narrowing the list.
409
- //
410
- // Collapsing on blur hid the reason rows were missing: the
411
- // header went back to its TABS — whose counts are of the
412
- // WHOLE capture on the stores side — while the list stayed
413
- // filtered, so the tool showed "Stores (4)" above a single
414
- // row and offered nothing to explain the gap. The only way
415
- // back was to reopen a field the user had no reason to think
416
- // was still armed.
417
- ,
418
- onBlur: () => {
419
- if (searchText.length === 0) setIsSearchActive(false);
420
- },
421
- accessibilityLabel: "Search Zustand stores and events",
422
- autoCapitalize: "none",
423
- autoCorrect: false,
424
- returnKeyType: "search"
425
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
426
- onPress: closeSearch,
427
- style: styles.headerSearchClear,
428
- testID: `${_testIDs.ZUSTAND_TEST_ID}-search-clear`,
429
- accessibilityRole: "button",
430
- accessibilityLabel: "Close search",
431
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
432
- size: 14,
433
- color: _sharedUi.night.color.textSecondary
434
- })
435
- })]
382
+ children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Search, {
383
+ value: searchText,
384
+ onChangeText: handleSearch,
385
+ onCancel: closeSearch,
386
+ placeholder: activeTab === "stores" ? "Search stores..." : "Search events...",
387
+ accessibilityLabel: "Search Zustand stores and events",
388
+ iconSize: 14,
389
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-search-field`,
390
+ containerTestID: `${_testIDs.ZUSTAND_TEST_ID}-search`,
391
+ clearTestID: `${_testIDs.ZUSTAND_TEST_ID}-search-clear`
392
+ // Stay open while the query is still narrowing the list: the
393
+ // header would otherwise go back to its TABS — whose counts are
394
+ // of the WHOLE capture — above a filtered list, with nothing to
395
+ // explain the gap.
396
+ ,
397
+ onBlur: () => {
398
+ if (searchText.length === 0) setIsSearchActive(false);
399
+ }
436
400
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TabSelector, {
437
401
  tabs: [{
438
402
  key: "stores",
@@ -527,11 +491,7 @@ function ZustandModal({
527
491
  keyExtractor: keyExtractor,
528
492
  contentContainerStyle: styles.listContent,
529
493
  showsVerticalScrollIndicator: true,
530
- removeClippedSubviews: CLIP_OFFSCREEN_CELLS,
531
- initialNumToRender: 12,
532
- maxToRenderPerBatch: 8,
533
- windowSize: 5,
534
- updateCellsBatchingPeriod: 50
494
+ ..._sharedUi.EVENT_LIST_PRESET
535
495
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
536
496
  testID: `${_testIDs.ZUSTAND_TEST_ID}-history-empty`,
537
497
  ...(0, _sharedUi.resolveListEmptyState)({
@@ -627,11 +587,7 @@ function ZustandModal({
627
587
  keyExtractor: keyExtractor,
628
588
  contentContainerStyle: styles.listContent,
629
589
  showsVerticalScrollIndicator: true,
630
- removeClippedSubviews: CLIP_OFFSCREEN_CELLS,
631
- initialNumToRender: 12,
632
- maxToRenderPerBatch: 8,
633
- windowSize: 5,
634
- updateCellsBatchingPeriod: 50
590
+ ..._sharedUi.EVENT_LIST_PRESET
635
591
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EventsEmptyState, {
636
592
  isEnabled: isEnabled,
637
593
  searchText: searchText,
@@ -744,27 +700,6 @@ const styles = _reactNative.StyleSheet.create({
744
700
  // Transparent so JsModal's ToolBackground shows through (the modal paints opaque base beneath it).
745
701
  backgroundColor: "transparent"
746
702
  },
747
- headerSearchContainer: {
748
- flexDirection: "row",
749
- alignItems: "center",
750
- backgroundColor: _sharedUi.night.color.surfaceElevated,
751
- borderRadius: _sharedUi.night.radius.row,
752
- borderWidth: 1,
753
- borderColor: _sharedUi.night.color.border,
754
- paddingHorizontal: 12,
755
- paddingVertical: 5
756
- },
757
- headerSearchInput: {
758
- flex: 1,
759
- color: _sharedUi.night.color.text,
760
- fontSize: 13,
761
- marginLeft: 6,
762
- paddingVertical: 2
763
- },
764
- headerSearchClear: {
765
- marginLeft: 6,
766
- padding: 4
767
- },
768
703
  headerActionButton: {
769
704
  width: 32,
770
705
  height: 32,