@buoy-gg/zustand 7.0.30 → 7.0.32

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 (60) hide show
  1. package/lib/commonjs/zustand/components/ZustandActionButton.js +3 -1
  2. package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +7 -0
  3. package/lib/commonjs/zustand/components/ZustandEventFilterView.js +19 -4
  4. package/lib/commonjs/zustand/components/ZustandModal.js +174 -32
  5. package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +36 -37
  6. package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +22 -5
  7. package/lib/commonjs/zustand/components/ZustandStateInfoView.js +30 -7
  8. package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +23 -126
  9. package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +471 -0
  10. package/lib/commonjs/zustand/components/ZustandStoreEditorScreen.js +393 -0
  11. package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +54 -0
  12. package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +71 -7
  13. package/lib/commonjs/zustand/utils/editableState.js +139 -0
  14. package/lib/commonjs/zustand/utils/snapshotProvider.js +10 -37
  15. package/lib/commonjs/zustand/utils/testIDs.js +82 -0
  16. package/lib/commonjs/zustand/utils/zustandStateStore.js +16 -3
  17. package/lib/module/zustand/components/ZustandActionButton.js +3 -1
  18. package/lib/module/zustand/components/ZustandDetailViewToggle.js +7 -0
  19. package/lib/module/zustand/components/ZustandEventFilterView.js +19 -4
  20. package/lib/module/zustand/components/ZustandModal.js +175 -33
  21. package/lib/module/zustand/components/ZustandStateChangeItem.js +36 -37
  22. package/lib/module/zustand/components/ZustandStateDetailContent.js +22 -5
  23. package/lib/module/zustand/components/ZustandStateInfoView.js +30 -7
  24. package/lib/module/zustand/components/ZustandStoreBrowser.js +26 -129
  25. package/lib/module/zustand/components/ZustandStoreDetailContent.js +469 -0
  26. package/lib/module/zustand/components/ZustandStoreEditorScreen.js +389 -0
  27. package/lib/module/zustand/sync/zustandSyncAdapter.js +54 -0
  28. package/lib/module/zustand/utils/buoyZustandMiddleware.js +71 -7
  29. package/lib/module/zustand/utils/editableState.js +131 -0
  30. package/lib/module/zustand/utils/snapshotProvider.js +4 -30
  31. package/lib/module/zustand/utils/testIDs.js +74 -0
  32. package/lib/module/zustand/utils/zustandStateStore.js +16 -3
  33. package/lib/typescript/zustand/components/ZustandActionButton.d.ts +2 -1
  34. package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +1 -1
  35. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +1 -1
  36. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +1 -1
  37. package/lib/typescript/zustand/components/ZustandModal.d.ts.map +1 -1
  38. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts +6 -0
  39. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +1 -1
  40. package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +1 -1
  41. package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +1 -1
  42. package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts +7 -9
  43. package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +1 -1
  44. package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts +40 -0
  45. package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +1 -0
  46. package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts +42 -0
  47. package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts.map +1 -0
  48. package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts +35 -0
  49. package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +1 -1
  50. package/lib/typescript/zustand/types/index.d.ts +13 -0
  51. package/lib/typescript/zustand/types/index.d.ts.map +1 -1
  52. package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts +31 -3
  53. package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts.map +1 -1
  54. package/lib/typescript/zustand/utils/editableState.d.ts +65 -0
  55. package/lib/typescript/zustand/utils/editableState.d.ts.map +1 -0
  56. package/lib/typescript/zustand/utils/testIDs.d.ts +54 -0
  57. package/lib/typescript/zustand/utils/testIDs.d.ts.map +1 -0
  58. package/lib/typescript/zustand/utils/zustandStateStore.d.ts +1 -0
  59. package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +1 -1
  60. package/package.json +3 -3
@@ -12,6 +12,7 @@ var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
12
12
  var _ZustandDetailViewToggle = require("./ZustandDetailViewToggle");
13
13
  var _ZustandStateInfoView = require("./ZustandStateInfoView");
14
14
  var _zustandStateStore = require("../utils/zustandStateStore");
15
+ var _testIDs = require("../utils/testIDs");
15
16
  var _jsxRuntime = require("react/jsx-runtime");
16
17
  /**
17
18
  * ZustandStateDetailContent
@@ -121,6 +122,7 @@ function ZustandStateDetailContent({
121
122
  const parsed = (0, _sharedUi.parseValue)(change.nextState);
122
123
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
123
124
  style: styles.contentCard,
125
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-state-card`,
124
126
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
125
127
  style: styles.valueHeader,
126
128
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -142,6 +144,7 @@ function ZustandStateDetailContent({
142
144
  style: styles.typeBadge,
143
145
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
144
146
  style: styles.typeText,
147
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-state-type`,
145
148
  children: stateType.toUpperCase()
146
149
  })
147
150
  })]
@@ -193,7 +196,14 @@ function ZustandStateDetailContent({
193
196
  const handleFooterNext = (0, _react.useCallback)(() => {
194
197
  onIndexChange(Math.max(0, selectedIndex - 1));
195
198
  }, [selectedIndex, onIndexChange]);
196
- const diffDisabled = totalChanges <= 1;
199
+
200
+ // The diff compares THIS change's prevState/nextState — both live on the
201
+ // change itself, so it needs no siblings. Gating on `changes.length` greyed
202
+ // DIFF out for every zustand event opened from the Events timeline, which
203
+ // hands this component a one-element array. Only a change with no captured
204
+ // previous state (initial creation) has nothing to compare.
205
+ const diffDisabled = change.prevState === undefined;
206
+ const showInternalFooter = !disableInternalFooter && totalChanges > 1;
197
207
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
198
208
  style: styles.container,
199
209
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandDetailViewToggle.ZustandDetailViewToggle, {
@@ -201,7 +211,7 @@ function ZustandStateDetailContent({
201
211
  onViewChange: setActiveView,
202
212
  diffDisabled: diffDisabled
203
213
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
204
- style: styles.contentArea,
214
+ style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
205
215
  children: [activeView === "change" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandStateInfoView.ZustandStateInfoView, {
206
216
  change: change
207
217
  }), activeView === "state" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
@@ -209,19 +219,22 @@ function ZustandStateDetailContent({
209
219
  children: renderStateView()
210
220
  }), activeView === "diff" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
211
221
  style: styles.diffContainer,
222
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-diff`,
212
223
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.DiffModeTabs, {
213
224
  tabs: DIFF_MODE_TABS,
214
225
  activeTab: diffMode,
215
- onTabChange: setDiffMode
226
+ onTabChange: setDiffMode,
227
+ testIDPrefix: `${_testIDs.ZUSTAND_TEST_ID}-diff-tab`
216
228
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompareBar, {
217
229
  leftEvent: leftEvent,
218
230
  rightEvent: rightEvent
219
231
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
220
232
  style: styles.diffContent,
233
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-diff-content`,
221
234
  children: renderDiffContent()
222
235
  })]
223
236
  })]
224
- }), !disableInternalFooter && totalChanges > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
237
+ }), showInternalFooter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
225
238
  currentIndex: chronologicalNumber - 1,
226
239
  totalItems: totalChanges,
227
240
  onPrevious: handleFooterPrevious,
@@ -261,7 +274,11 @@ const styles = _reactNative.StyleSheet.create({
261
274
  backgroundColor: "transparent"
262
275
  },
263
276
  contentArea: {
264
- flex: 1,
277
+ flex: 1
278
+ },
279
+ // Clearance for the absolute EventStepperFooter — only when it renders,
280
+ // otherwise hosts like the Events tool get a dead band at the sheet bottom.
281
+ contentAreaFooterPad: {
265
282
  paddingBottom: 96
266
283
  },
267
284
  stateContainer: {
@@ -11,6 +11,7 @@ var _license = require("@buoy-gg/license");
11
11
  var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
12
12
  var _ZustandActionButton = require("./ZustandActionButton");
13
13
  var _zustandStateStore = require("../utils/zustandStateStore");
14
+ var _testIDs = require("../utils/testIDs");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  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); }
16
17
  /**
@@ -60,10 +61,12 @@ function formatDuration(duration) {
60
61
  function SectionHeader({
61
62
  icon: Icon,
62
63
  title,
63
- badge
64
+ badge,
65
+ testID
64
66
  }) {
65
67
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
66
68
  style: styles.sectionHeader,
69
+ testID: testID,
67
70
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
68
71
  style: styles.sectionHeaderLeft,
69
72
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Icon, {
@@ -80,7 +83,8 @@ function InfoRow({
80
83
  label,
81
84
  value,
82
85
  valueColor,
83
- mono = false
86
+ mono = false,
87
+ testID
84
88
  }) {
85
89
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
86
90
  style: styles.infoRow,
@@ -88,6 +92,7 @@ function InfoRow({
88
92
  style: styles.infoLabel,
89
93
  children: label
90
94
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
95
+ testID: testID,
91
96
  style: [styles.infoValue, mono && styles.infoValueMono, valueColor ? {
92
97
  color: valueColor
93
98
  } : undefined],
@@ -143,8 +148,10 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
143
148
  style: styles.container,
144
149
  contentContainerStyle: styles.contentContainer,
145
150
  showsVerticalScrollIndicator: false,
151
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-detail-scroll`,
146
152
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
147
153
  style: styles.card,
154
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-card`,
148
155
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(SectionHeader, {
149
156
  icon: _sharedUi.Info,
150
157
  title: "CHANGE INFO"
@@ -154,11 +161,13 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
154
161
  label: "Store",
155
162
  value: change.storeName,
156
163
  mono: true,
157
- valueColor: storeColor
164
+ valueColor: storeColor,
165
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-store`
158
166
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, {
159
167
  label: "Time",
160
168
  value: formatTime(change.timestamp),
161
- mono: true
169
+ mono: true,
170
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-time`
162
171
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
163
172
  style: styles.badgeRow,
164
173
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
@@ -169,6 +178,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
169
178
  style: [styles.categoryText, {
170
179
  color: categoryInfo.color
171
180
  }],
181
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-category`,
172
182
  children: categoryInfo.label
173
183
  })
174
184
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
@@ -178,6 +188,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
178
188
  color: change.isSlowUpdate ? _sharedUi.buoyColors.error : _sharedUi.night.color.textSecondary
179
189
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
180
190
  style: [styles.durationText, change.isSlowUpdate && styles.durationTextSlow],
191
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-duration`,
181
192
  children: formatDuration(change.duration)
182
193
  }), change.isSlowUpdate && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
183
194
  size: 10,
@@ -190,12 +201,14 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
190
201
  color: _sharedUi.buoyColors.success
191
202
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
192
203
  style: styles.changesText,
204
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-changes`,
193
205
  children: change.diffSummary || "changed"
194
206
  })]
195
207
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
196
208
  style: styles.noChangesBadge,
197
209
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
198
210
  style: styles.noChangesText,
211
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-no-changes`,
199
212
  children: "no change"
200
213
  })
201
214
  }), change.isPersisted && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
@@ -205,6 +218,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
205
218
  color: _sharedUi.buoyColors.info
206
219
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
207
220
  style: styles.persistText,
221
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-info-persisted`,
208
222
  children: "PERSISTED"
209
223
  })]
210
224
  })]
@@ -212,6 +226,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
212
226
  })]
213
227
  }), hasChangedKeys && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
214
228
  style: styles.card,
229
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-keys-card`,
215
230
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(SectionHeader, {
216
231
  icon: _sharedUi.Zap,
217
232
  title: "CHANGED KEYS",
@@ -219,6 +234,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
219
234
  style: styles.countBadge,
220
235
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
221
236
  style: styles.countText,
237
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-keys-count`,
222
238
  children: change.changedKeys.length
223
239
  })
224
240
  })
@@ -230,6 +246,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
230
246
  style: styles.keyBadge,
231
247
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
232
248
  style: styles.keyText,
249
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-key-${key}`,
233
250
  children: key
234
251
  })
235
252
  }, key))
@@ -237,6 +254,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
237
254
  })]
238
255
  }), hasPartial && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
239
256
  style: styles.card,
257
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-partial-card`,
240
258
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(SectionHeader, {
241
259
  icon: _sharedUi.Box,
242
260
  title: "PARTIAL (setState argument)",
@@ -244,6 +262,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
244
262
  style: styles.typeBadge,
245
263
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
246
264
  style: styles.typeText,
265
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-partial-type`,
247
266
  children: Array.isArray(change.partial) ? "ARRAY" : typeof change.partial === "object" ? "OBJECT" : String(typeof change.partial).toUpperCase()
248
267
  })
249
268
  })
@@ -259,6 +278,7 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
259
278
  })]
260
279
  }), change.partial === "(updater fn)" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
261
280
  style: styles.card,
281
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-updater-card`,
262
282
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(SectionHeader, {
263
283
  icon: _sharedUi.Box,
264
284
  title: "SET STATE CALL"
@@ -277,15 +297,18 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
277
297
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandActionButton.ZustandActionButton, {
278
298
  type: "jump",
279
299
  text: "JUMP",
280
- onPress: handleJumpToState
300
+ onPress: handleJumpToState,
301
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-jump`
281
302
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandActionButton.ZustandActionButton, {
282
303
  type: "reset",
283
304
  text: "RESET STORE",
284
- onPress: handleResetStore
305
+ onPress: handleResetStore,
306
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-reset`
285
307
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandActionButton.ZustandActionButton, {
286
308
  type: "copy",
287
309
  text: "COPY STATE",
288
- onPress: handleCopyState
310
+ onPress: handleCopyState,
311
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-copy-state`
289
312
  })]
290
313
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProUpgradeModal, {
291
314
  visible: showProModal,
@@ -7,17 +7,16 @@ exports.ZustandStoreBrowser = ZustandStoreBrowser;
7
7
  var _react = require("react");
8
8
  var _reactNative = require("react-native");
9
9
  var _sharedUi = require("@buoy-gg/shared-ui");
10
- var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
11
10
  var _zustandStateStore = require("../utils/zustandStateStore");
11
+ var _testIDs = require("../utils/testIDs");
12
12
  var _jsxRuntime = require("react/jsx-runtime");
13
13
  /**
14
14
  * ZustandStoreBrowser
15
15
  *
16
- * Browse tab — shows all registered Zustand stores and their current state.
17
- * Mirrors the Storage Browser pattern from @buoy-gg/storage.
18
- *
19
- * Each store is shown as an expandable row with its current state viewable
20
- * via the shared DataViewer component.
16
+ * Browse tab — lists all registered Zustand stores. Tapping a card opens the
17
+ * store's detail screen (ZustandStoreDetailContent): live state editor on
18
+ * top, store details and the read-only tree below — the React Query
19
+ * interaction, replacing the old expand-in-place card.
21
20
  */
22
21
 
23
22
  /**
@@ -44,80 +43,10 @@ function getKeysPreview(store) {
44
43
  return "";
45
44
  }
46
45
  }
47
- function StoreExpandedContent({
48
- store,
49
- onViewHistory
50
- }) {
51
- const state = store.api.getState();
52
- const displayState = (0, _react.useMemo)(() => {
53
- if (state && typeof state === "object") {
54
- const filtered = {};
55
- for (const [key, value] of Object.entries(state)) {
56
- if (typeof value !== "function") {
57
- filtered[key] = value;
58
- }
59
- }
60
- return (0, _sharedUi.parseValue)(filtered);
61
- }
62
- return (0, _sharedUi.parseValue)(state);
63
- }, [state]);
64
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
65
- style: expandedStyles.container,
66
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ExpandedInfoRow, {
67
- label: "Type",
68
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
69
- color: store.color,
70
- children: "ZUSTAND"
71
- })
72
- }), store.stateChangeCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ExpandedInfoRow, {
73
- label: "Changes",
74
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
75
- color: _sharedUi.buoyColors.warning,
76
- children: String(store.stateChangeCount)
77
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
78
- onPress: () => onViewHistory(store.name),
79
- style: expandedStyles.viewHistoryButton,
80
- hitSlop: {
81
- top: 6,
82
- bottom: 6,
83
- left: 6,
84
- right: 6
85
- },
86
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
87
- style: [expandedStyles.viewHistoryText, {
88
- color: store.color
89
- }],
90
- children: "view history \u2192"
91
- })
92
- })]
93
- }), store.isPersisted && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ExpandedInfoRow, {
94
- label: "Persist",
95
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
96
- color: _sharedUi.buoyColors.info,
97
- icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
98
- size: 9,
99
- color: _sharedUi.buoyColors.info
100
- }),
101
- children: store.persistName || "persisted"
102
- })
103
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
104
- style: expandedStyles.dataContainer,
105
- children: displayState && typeof displayState === "object" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
106
- title: "",
107
- data: displayState,
108
- showTypeFilter: true,
109
- rawMode: true,
110
- initialExpanded: true
111
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
112
- style: expandedStyles.emptyText,
113
- children: "Empty state"
114
- })
115
- })]
116
- });
117
- }
118
46
  function LoadingBrowserState() {
119
47
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
120
48
  style: styles.emptyState,
49
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-loading`,
121
50
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
122
51
  size: "small",
123
52
  color: _sharedUi.night.color.textTertiary
@@ -133,11 +62,13 @@ function LoadingBrowserState() {
133
62
  function EmptyBrowserState() {
134
63
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
135
64
  style: styles.emptyState,
65
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-empty`,
136
66
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Box, {
137
67
  size: 32,
138
68
  color: _sharedUi.night.color.textTertiary
139
69
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
140
70
  style: styles.emptyTitle,
71
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-empty-title`,
141
72
  children: "No stores registered"
142
73
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
143
74
  style: styles.emptyText,
@@ -148,33 +79,25 @@ function EmptyBrowserState() {
148
79
  function ZustandStoreBrowser({
149
80
  stores,
150
81
  searchQuery,
151
- onViewHistory,
152
82
  isLoading = false,
153
- onStoreExpand
83
+ onOpenStore
154
84
  }) {
155
- const [expandedStore, setExpandedStore] = (0, _react.useState)(null);
156
-
157
85
  // Filter stores by search query
158
86
  const filteredStores = (0, _react.useMemo)(() => {
159
87
  if (!searchQuery) return stores;
160
88
  const search = searchQuery.toLowerCase();
161
89
  return stores.filter(s => s.name.toLowerCase().includes(search) || s.persistName && s.persistName.toLowerCase().includes(search));
162
90
  }, [stores, searchQuery]);
163
- const handleStorePress = (0, _react.useCallback)(store => {
164
- setExpandedStore(prev => {
165
- const next = prev === store.name ? null : store.name;
166
- if (next) onStoreExpand?.(store.name);
167
- return next;
168
- });
169
- }, [onStoreExpand]);
170
91
  if (filteredStores.length === 0 && !searchQuery) {
171
92
  return isLoading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LoadingBrowserState, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyBrowserState, {});
172
93
  }
173
94
  if (filteredStores.length === 0 && searchQuery) {
174
95
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
175
96
  style: styles.emptyState,
97
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-no-match`,
176
98
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
177
99
  style: styles.emptyTitle,
100
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-no-match-title`,
178
101
  children: "No matching stores"
179
102
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
180
103
  style: styles.emptyText,
@@ -186,6 +109,7 @@ function ZustandStoreBrowser({
186
109
  style: styles.container,
187
110
  contentContainerStyle: styles.scrollContent,
188
111
  showsVerticalScrollIndicator: true,
112
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-scroll`,
189
113
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
190
114
  style: styles.sectionHeader,
191
115
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -195,27 +119,27 @@ function ZustandStoreBrowser({
195
119
  style: styles.sectionCountBadge,
196
120
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
197
121
  style: styles.sectionCountText,
122
+ testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-count`,
198
123
  children: filteredStores.length
199
124
  })
200
125
  })]
201
126
  }), filteredStores.map(store => {
202
- const isExpanded = expandedStore === store.name;
203
127
  const keysPreview = getKeysPreview(store);
204
128
  const storeColor = _zustandStateStore.zustandStateStore.getStoreColor(store.name);
129
+ const rowID = (0, _testIDs.storeRowTestID)(store.name);
205
130
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
206
131
  style: styles.storeRowWrapper,
207
132
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
208
133
  statusDotColor: storeColor,
209
- statusLabel: store.name,
210
- statusSublabel: store.isPersisted ? "persisted" : "in-memory",
211
- primaryText: keysPreview,
134
+ statusLabel: store.isPersisted ? "persisted" : "in-memory",
135
+ primaryText: store.name,
136
+ secondaryText: keysPreview || undefined,
212
137
  showChevron: true,
213
- isExpanded: isExpanded,
214
- onPress: () => handleStorePress(store),
215
- expandedContent: isExpanded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(StoreExpandedContent, {
216
- store: store,
217
- onViewHistory: onViewHistory
218
- }) : undefined
138
+ onPress: () => onOpenStore(store.name),
139
+ testID: rowID,
140
+ statusTestID: `${rowID}-backing`,
141
+ primaryTestID: `${rowID}-name`,
142
+ secondaryTestID: `${rowID}-keys`
219
143
  }), store.stateChangeCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
220
144
  style: [styles.absCountBadge, {
221
145
  backgroundColor: storeColor + "22",
@@ -226,6 +150,7 @@ function ZustandStoreBrowser({
226
150
  style: [styles.absCountText, {
227
151
  color: storeColor
228
152
  }],
153
+ testID: `${rowID}-count`,
229
154
  children: String(store.stateChangeCount)
230
155
  })
231
156
  })]
@@ -301,32 +226,4 @@ const styles = _reactNative.StyleSheet.create({
301
226
  textAlign: "center",
302
227
  lineHeight: 18
303
228
  }
304
- });
305
- const expandedStyles = _reactNative.StyleSheet.create({
306
- container: {
307
- gap: 10
308
- },
309
- viewHistoryButton: {
310
- marginLeft: 4
311
- },
312
- viewHistoryText: {
313
- fontSize: 10,
314
- fontWeight: "600",
315
- fontFamily: "monospace"
316
- },
317
- dataContainer: {
318
- // Inset display panel — darker than the card, the night track color.
319
- backgroundColor: _sharedUi.night.color.bg,
320
- borderRadius: 6,
321
- borderWidth: 1,
322
- borderColor: _sharedUi.night.color.border,
323
- overflow: "hidden",
324
- minHeight: 60
325
- },
326
- emptyText: {
327
- color: _sharedUi.night.color.textTertiary,
328
- fontSize: 12,
329
- padding: 14,
330
- fontStyle: "italic"
331
- }
332
229
  });