@buoy-gg/zustand 7.0.36 → 7.0.38

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 (63) hide show
  1. package/README.md +27 -5
  2. package/lib/commonjs/index.js +1 -105
  3. package/lib/commonjs/preset.js +1 -102
  4. package/lib/commonjs/zustand/components/ZustandActionButton.js +1 -118
  5. package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +1 -48
  6. package/lib/commonjs/zustand/components/ZustandEventFilterView.js +1 -43
  7. package/lib/commonjs/zustand/components/ZustandIcon.js +1 -18
  8. package/lib/commonjs/zustand/components/ZustandModal.js +1 -772
  9. package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +1 -117
  10. package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +1 -372
  11. package/lib/commonjs/zustand/components/ZustandStateInfoView.js +1 -488
  12. package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +1 -204
  13. package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +1 -471
  14. package/lib/commonjs/zustand/components/ZustandStoreEditorScreen.js +1 -393
  15. package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +1 -72
  16. package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +1 -382
  17. package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +1 -284
  18. package/lib/commonjs/zustand/utils/editableState.js +1 -139
  19. package/lib/commonjs/zustand/utils/snapshotProvider.js +1 -209
  20. package/lib/commonjs/zustand/utils/testIDs.js +1 -82
  21. package/lib/commonjs/zustand/utils/zustandStateStore.js +1 -375
  22. package/lib/module/index.js +1 -90
  23. package/lib/module/preset.js +1 -98
  24. package/lib/module/zustand/components/ZustandActionButton.js +1 -114
  25. package/lib/module/zustand/components/ZustandDetailViewToggle.js +1 -43
  26. package/lib/module/zustand/components/ZustandEventFilterView.js +1 -39
  27. package/lib/module/zustand/components/ZustandIcon.js +1 -11
  28. package/lib/module/zustand/components/ZustandModal.js +1 -767
  29. package/lib/module/zustand/components/ZustandStateChangeItem.js +1 -113
  30. package/lib/module/zustand/components/ZustandStateDetailContent.js +1 -368
  31. package/lib/module/zustand/components/ZustandStateInfoView.js +1 -483
  32. package/lib/module/zustand/components/ZustandStoreBrowser.js +1 -200
  33. package/lib/module/zustand/components/ZustandStoreDetailContent.js +1 -469
  34. package/lib/module/zustand/components/ZustandStoreEditorScreen.js +1 -389
  35. package/lib/module/zustand/hooks/useZustandStateChanges.js +1 -68
  36. package/lib/module/zustand/sync/zustandSyncAdapter.js +1 -380
  37. package/lib/module/zustand/utils/buoyZustandMiddleware.js +1 -278
  38. package/lib/module/zustand/utils/editableState.js +1 -131
  39. package/lib/module/zustand/utils/snapshotProvider.js +1 -209
  40. package/lib/module/zustand/utils/testIDs.js +1 -74
  41. package/lib/module/zustand/utils/zustandStateStore.js +1 -371
  42. package/package.json +4 -4
  43. package/lib/typescript/index.d.ts.map +0 -1
  44. package/lib/typescript/preset.d.ts.map +0 -1
  45. package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +0 -1
  46. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +0 -1
  47. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +0 -1
  48. package/lib/typescript/zustand/components/ZustandIcon.d.ts.map +0 -1
  49. package/lib/typescript/zustand/components/ZustandModal.d.ts.map +0 -1
  50. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +0 -1
  51. package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +0 -1
  52. package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +0 -1
  53. package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +0 -1
  54. package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +0 -1
  55. package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts.map +0 -1
  56. package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +0 -1
  57. package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +0 -1
  58. package/lib/typescript/zustand/types/index.d.ts.map +0 -1
  59. package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts.map +0 -1
  60. package/lib/typescript/zustand/utils/editableState.d.ts.map +0 -1
  61. package/lib/typescript/zustand/utils/snapshotProvider.d.ts.map +0 -1
  62. package/lib/typescript/zustand/utils/testIDs.d.ts.map +0 -1
  63. package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +0 -1
@@ -1,113 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Compact list item for displaying a Zustand state change
5
- *
6
- * Mirrors ReduxActionItem.tsx - uses shared CompactRow for consistent styling
7
- */
8
-
9
- import { memo } from "react";
10
- import { ChangeRow, buoyColors, night } from "@buoy-gg/shared-ui";
11
- import { zustandStateStore } from "../utils/zustandStateStore";
12
- import { jsx as _jsx } from "react/jsx-runtime";
13
- /**
14
- * Get status label based on category
15
- */
16
- function getStatusLabel(category, storeName) {
17
- switch (category) {
18
- case "replace":
19
- return "Replace";
20
- case "persist":
21
- return "Hydrate";
22
- case "initial":
23
- return "Initial";
24
- default:
25
- return storeName.charAt(0).toUpperCase() + storeName.slice(1);
26
- }
27
- }
28
-
29
- /**
30
- * Get color for category
31
- */
32
- function getCategoryColor(category, storeName) {
33
- switch (category) {
34
- case "replace":
35
- return buoyColors.warning;
36
- case "persist":
37
- return buoyColors.info;
38
- case "initial":
39
- return night.color.textTertiary;
40
- default:
41
- return zustandStateStore.getStoreColor(storeName);
42
- }
43
- }
44
-
45
- /**
46
- * Get sublabel with duration and diff info
47
- */
48
- function getSublabel(change) {
49
- const parts = [];
50
- if (change.duration !== undefined && change.duration >= 0.1) {
51
- parts.push(`${change.duration.toFixed(1)}ms`);
52
- }
53
- if (change.hasStateChange) {
54
- if (change.changedKeysCount > 0) {
55
- parts.push(`${change.changedKeysCount} key${change.changedKeysCount > 1 ? "s" : ""} changed`);
56
- } else {
57
- parts.push(change.diffSummary || "state changed");
58
- }
59
- } else {
60
- parts.push("no state change");
61
- }
62
- return parts.join(" \u00B7 ");
63
- }
64
-
65
- /**
66
- * Get badge text for the change
67
- */
68
- function getBadgeText(change) {
69
- if (change.category === "replace") return "REPLACE";
70
- if (change.category === "persist") return "HYDRATE";
71
- if (change.category === "initial") return "INIT";
72
- return "SET";
73
- }
74
-
75
- /**
76
- * Get primary display text
77
- */
78
- function getPrimaryText(change) {
79
- if (change.changedKeys.length > 0 && change.changedKeys.length <= 3) {
80
- return change.changedKeys.join(", ");
81
- }
82
- if (change.changedKeys.length > 3) {
83
- return `${change.changedKeys.slice(0, 2).join(", ")} +${change.changedKeys.length - 2}`;
84
- }
85
- return change.partialPreview || "setState()";
86
- }
87
-
88
- // Memo justified by profiling (tool-bench 2026-07-06): unmemoized, every
89
- // visible row re-rendered on each store emission. Leaf w/ stable props
90
- // ({change, onPress} — onPress is a stable useCallback in the modal).
91
- export const ZustandStateChangeItem = /*#__PURE__*/memo(function ZustandStateChangeItem({
92
- change,
93
- onPress,
94
- testID
95
- }) {
96
- const statusColor = getCategoryColor(change.category, change.storeName);
97
- const statusLabel = getStatusLabel(change.category, change.storeName);
98
- const sublabel = getSublabel(change);
99
- const primaryText = getPrimaryText(change);
100
- const badgeText = getBadgeText(change);
101
- return /*#__PURE__*/_jsx(ChangeRow, {
102
- statusColor: statusColor,
103
- statusLabel: statusLabel,
104
- sublabel: sublabel,
105
- primaryText: primaryText,
106
- timestamp: change.timestamp,
107
- badgeText: badgeText,
108
- changed: change.hasStateChange,
109
- slow: change.isSlowUpdate,
110
- onPress: () => onPress(change),
111
- testID: testID
112
- });
113
- });
1
+ "use strict";import{memo}from"react";import{ChangeRow,buoyColors,night}from"@buoy-gg/shared-ui";import{zustandStateStore}from"../utils/zustandStateStore";import{jsx as _jsx}from"react/jsx-runtime";function getStatusLabel(e,t){switch(e){case"replace":return"Replace";case"persist":return"Hydrate";case"initial":return"Initial";default:return t.charAt(0).toUpperCase()+t.slice(1)}}function getCategoryColor(e,t){switch(e){case"replace":return buoyColors.warning;case"persist":return buoyColors.info;case"initial":return night.color.textTertiary;default:return zustandStateStore.getStoreColor(t)}}function getSublabel(e){const t=[];return void 0!==e.duration&&e.duration>=.1&&t.push(`${e.duration.toFixed(1)}ms`),e.hasStateChange?e.changedKeysCount>0?t.push(`${e.changedKeysCount} key${e.changedKeysCount>1?"s":""} changed`):t.push(e.diffSummary||"state changed"):t.push("no state change"),t.join(" · ")}function getBadgeText(e){return"replace"===e.category?"REPLACE":"persist"===e.category?"HYDRATE":"initial"===e.category?"INIT":"SET"}function getPrimaryText(e){return e.changedKeys.length>0&&e.changedKeys.length<=3?e.changedKeys.join(", "):e.changedKeys.length>3?`${e.changedKeys.slice(0,2).join(", ")} +${e.changedKeys.length-2}`:e.partialPreview||"setState()"}export const ZustandStateChangeItem=memo(function({change:e,onPress:t,testID:a}){const r=getCategoryColor(e.category,e.storeName),n=getStatusLabel(e.category,e.storeName),s=getSublabel(e),o=getPrimaryText(e),i=getBadgeText(e);return _jsx(ChangeRow,{statusColor:r,statusLabel:n,sublabel:s,primaryText:o,timestamp:e.timestamp,badgeText:i,changed:e.hasStateChange,slow:e.isSlowUpdate,onPress:()=>t(e),testID:a})});
@@ -1,368 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * ZustandStateDetailContent
5
- *
6
- * Detail view for a Zustand state change with 3 view modes:
7
- * - CHANGE: View change details, partial, metadata
8
- * - STATE: View current state after change
9
- * - DIFF: Compare prev vs next state
10
- *
11
- * Mirrors ReduxActionDetailContent.tsx
12
- */
13
-
14
- import { View, Text, StyleSheet, ScrollView } from "react-native";
15
- import { useState, useCallback, useMemo } from "react";
16
- import { night, EventStepperFooter, formatRelativeTime, parseValue, monoFont } from "@buoy-gg/shared-ui";
17
- import { DataViewer, SplitDiffViewer, TreeDiffViewer, diffThemes } from "@buoy-gg/shared-ui/dataViewer";
18
- import { ZustandDetailViewToggle } from "./ZustandDetailViewToggle";
19
- import { ZustandStateInfoView } from "./ZustandStateInfoView";
20
- import { DiffModeTabs, CompareBar } from "@buoy-gg/shared-ui";
21
- import { zustandStateStore } from "../utils/zustandStateStore";
22
- import { ZUSTAND_TEST_ID } from "../utils/testIDs";
23
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
- function getChangeColor(change) {
25
- return zustandStateStore.getStoreColor(change.storeName);
26
- }
27
- function getChangeLabel(change) {
28
- switch (change.category) {
29
- case "replace":
30
- return "REPLACE";
31
- case "persist":
32
- return "HYDRATE";
33
- case "initial":
34
- return "INIT";
35
- default:
36
- return "SET";
37
- }
38
- }
39
- function getValueType(value) {
40
- if (value === null) return "null";
41
- if (value === undefined) return "undefined";
42
- if (Array.isArray(value)) return "array";
43
- return typeof value;
44
- }
45
- function formatTimestamp(timestamp) {
46
- const date = new Date(timestamp);
47
- return date.toLocaleTimeString("en-US", {
48
- hour12: false,
49
- hour: "2-digit",
50
- minute: "2-digit",
51
- second: "2-digit"
52
- });
53
- }
54
- const DIFF_MODE_TABS = [{
55
- key: "tree",
56
- label: "TREE VIEW"
57
- }, {
58
- key: "split",
59
- label: "SPLIT VIEW"
60
- }];
61
- export function ZustandStateDetailContent({
62
- change,
63
- changes,
64
- selectedIndex,
65
- onIndexChange,
66
- disableInternalFooter = false,
67
- initialView = "change"
68
- }) {
69
- const [activeView, setActiveView] = useState(initialView);
70
- const [diffMode, setDiffMode] = useState("tree");
71
- const totalChanges = changes.length;
72
- const changeColor = getChangeColor(change);
73
- const changeLabel = getChangeLabel(change);
74
- const stateType = getValueType(parseValue(change.nextState));
75
-
76
- // Changes are in reverse chronological order (newest first)
77
- const chronologicalNumber = totalChanges - selectedIndex;
78
- const prevChronologicalNumber = chronologicalNumber - 1;
79
- const prevChangeIndex = selectedIndex < totalChanges - 1 ? selectedIndex + 1 : null;
80
- const prevChange = prevChangeIndex !== null ? changes[prevChangeIndex] : null;
81
-
82
- // Compare bar info
83
- const leftEvent = useMemo(() => ({
84
- index: prevChangeIndex ?? 0,
85
- label: prevChronologicalNumber > 0 ? `#${prevChronologicalNumber}` : "Initial",
86
- timestamp: prevChange ? formatTimestamp(prevChange.timestamp) : "",
87
- relativeTime: prevChange ? formatRelativeTime(new Date(prevChange.timestamp)) : "state",
88
- badge: prevChange ? /*#__PURE__*/_jsx(View, {
89
- style: [styles.changeBadgeSmall, {
90
- backgroundColor: `${getChangeColor(prevChange)}20`
91
- }],
92
- children: /*#__PURE__*/_jsx(Text, {
93
- style: [styles.changeTextSmall, {
94
- color: getChangeColor(prevChange)
95
- }],
96
- children: getChangeLabel(prevChange)
97
- })
98
- }) : undefined
99
- }), [prevChangeIndex, prevChange, prevChronologicalNumber]);
100
- const rightEvent = useMemo(() => ({
101
- index: selectedIndex,
102
- label: `#${chronologicalNumber}`,
103
- timestamp: formatTimestamp(change.timestamp),
104
- relativeTime: formatRelativeTime(new Date(change.timestamp)),
105
- badge: /*#__PURE__*/_jsx(View, {
106
- style: [styles.changeBadgeSmall, {
107
- backgroundColor: `${changeColor}20`
108
- }],
109
- children: /*#__PURE__*/_jsx(Text, {
110
- style: [styles.changeTextSmall, {
111
- color: changeColor
112
- }],
113
- children: changeLabel
114
- })
115
- })
116
- }), [selectedIndex, change.timestamp, changeColor, changeLabel, chronologicalNumber]);
117
- const renderStateView = useCallback(() => {
118
- const parsed = parseValue(change.nextState);
119
- return /*#__PURE__*/_jsxs(View, {
120
- style: styles.contentCard,
121
- testID: `${ZUSTAND_TEST_ID}-state-card`,
122
- children: [/*#__PURE__*/_jsxs(View, {
123
- style: styles.valueHeader,
124
- children: [/*#__PURE__*/_jsx(Text, {
125
- style: styles.valueLabel,
126
- children: "STATE AFTER CHANGE"
127
- }), /*#__PURE__*/_jsxs(View, {
128
- style: styles.valueHeaderBadges,
129
- children: [/*#__PURE__*/_jsx(View, {
130
- style: [styles.changeBadge, {
131
- backgroundColor: `${changeColor}20`
132
- }],
133
- children: /*#__PURE__*/_jsx(Text, {
134
- style: [styles.changeText, {
135
- color: changeColor
136
- }],
137
- children: changeLabel
138
- })
139
- }), /*#__PURE__*/_jsx(View, {
140
- style: styles.typeBadge,
141
- children: /*#__PURE__*/_jsx(Text, {
142
- style: styles.typeText,
143
- testID: `${ZUSTAND_TEST_ID}-state-type`,
144
- children: stateType.toUpperCase()
145
- })
146
- })]
147
- })]
148
- }), /*#__PURE__*/_jsx(View, {
149
- style: styles.dataViewerContainer,
150
- children: /*#__PURE__*/_jsx(DataViewer, {
151
- title: "",
152
- data: parsed,
153
- showTypeFilter: true,
154
- rawMode: true,
155
- initialExpanded: true
156
- })
157
- })]
158
- });
159
- }, [change.nextState, changeColor, changeLabel, stateType]);
160
- const renderDiffContent = useCallback(() => {
161
- const prevState = parseValue(change.prevState);
162
- const nextState = parseValue(change.nextState);
163
- if (diffMode === "split") {
164
- return /*#__PURE__*/_jsx(ScrollView, {
165
- style: {
166
- flex: 1
167
- },
168
- showsVerticalScrollIndicator: true,
169
- children: /*#__PURE__*/_jsx(SplitDiffViewer, {
170
- oldValue: prevState,
171
- newValue: nextState,
172
- theme: diffThemes.devToolsDefault,
173
- options: {
174
- hideLineNumbers: false,
175
- disableWordDiff: false,
176
- showDiffOnly: false,
177
- compareMethod: "words",
178
- contextLines: 3
179
- },
180
- showThemeName: false
181
- })
182
- });
183
- }
184
- return /*#__PURE__*/_jsx(TreeDiffViewer, {
185
- oldValue: prevState,
186
- newValue: nextState
187
- });
188
- }, [change.prevState, change.nextState, diffMode]);
189
- const handleFooterPrevious = useCallback(() => {
190
- onIndexChange(Math.min(totalChanges - 1, selectedIndex + 1));
191
- }, [selectedIndex, totalChanges, onIndexChange]);
192
- const handleFooterNext = useCallback(() => {
193
- onIndexChange(Math.max(0, selectedIndex - 1));
194
- }, [selectedIndex, onIndexChange]);
195
-
196
- // The diff compares THIS change's prevState/nextState — both live on the
197
- // change itself, so it needs no siblings. Gating on `changes.length` greyed
198
- // DIFF out for every zustand event opened from the Events timeline, which
199
- // hands this component a one-element array. Only a change with no captured
200
- // previous state (initial creation) has nothing to compare.
201
- const diffDisabled = change.prevState === undefined;
202
- const showInternalFooter = !disableInternalFooter && totalChanges > 1;
203
- return /*#__PURE__*/_jsxs(View, {
204
- style: styles.container,
205
- children: [/*#__PURE__*/_jsx(ZustandDetailViewToggle, {
206
- activeView: activeView,
207
- onViewChange: setActiveView,
208
- diffDisabled: diffDisabled
209
- }), /*#__PURE__*/_jsxs(View, {
210
- style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
211
- children: [activeView === "change" && /*#__PURE__*/_jsx(ZustandStateInfoView, {
212
- change: change
213
- }), activeView === "state" && /*#__PURE__*/_jsx(View, {
214
- style: styles.stateContainer,
215
- children: renderStateView()
216
- }), activeView === "diff" && /*#__PURE__*/_jsxs(View, {
217
- style: styles.diffContainer,
218
- testID: `${ZUSTAND_TEST_ID}-diff`,
219
- children: [/*#__PURE__*/_jsx(DiffModeTabs, {
220
- tabs: DIFF_MODE_TABS,
221
- activeTab: diffMode,
222
- onTabChange: setDiffMode,
223
- testIDPrefix: `${ZUSTAND_TEST_ID}-diff-tab`
224
- }), /*#__PURE__*/_jsx(CompareBar, {
225
- leftEvent: leftEvent,
226
- rightEvent: rightEvent
227
- }), /*#__PURE__*/_jsx(View, {
228
- style: styles.diffContent,
229
- testID: `${ZUSTAND_TEST_ID}-diff-content`,
230
- children: renderDiffContent()
231
- })]
232
- })]
233
- }), showInternalFooter && /*#__PURE__*/_jsx(EventStepperFooter, {
234
- currentIndex: chronologicalNumber - 1,
235
- totalItems: totalChanges,
236
- onPrevious: handleFooterPrevious,
237
- onNext: handleFooterNext,
238
- itemLabel: "Change",
239
- subtitle: formatRelativeTime(new Date(change.timestamp)),
240
- absolute: true
241
- })]
242
- });
243
- }
244
-
245
- /**
246
- * External footer component for modal use
247
- */
248
- export function ZustandStateDetailFooter({
249
- change,
250
- changes,
251
- selectedIndex,
252
- onIndexChange
253
- }) {
254
- const totalChanges = changes.length;
255
- if (totalChanges <= 1) return null;
256
- const chronologicalNumber = totalChanges - selectedIndex;
257
- return /*#__PURE__*/_jsx(EventStepperFooter, {
258
- currentIndex: chronologicalNumber - 1,
259
- totalItems: totalChanges,
260
- onPrevious: () => onIndexChange(Math.min(totalChanges - 1, selectedIndex + 1)),
261
- onNext: () => onIndexChange(Math.max(0, selectedIndex - 1)),
262
- itemLabel: "Change",
263
- subtitle: formatRelativeTime(new Date(change.timestamp))
264
- });
265
- }
266
- const styles = StyleSheet.create({
267
- container: {
268
- flex: 1,
269
- // Transparent so the night sheet's star field shows through.
270
- backgroundColor: "transparent"
271
- },
272
- contentArea: {
273
- flex: 1
274
- },
275
- // Clearance for the absolute EventStepperFooter — only when it renders,
276
- // otherwise hosts like the Events tool get a dead band at the sheet bottom.
277
- contentAreaFooterPad: {
278
- paddingBottom: 96
279
- },
280
- stateContainer: {
281
- flex: 1,
282
- padding: 14
283
- },
284
- contentCard: {
285
- backgroundColor: night.color.surface,
286
- borderRadius: 14,
287
- padding: 14,
288
- borderWidth: 1,
289
- borderColor: night.color.border
290
- },
291
- valueHeader: {
292
- flexDirection: "row",
293
- alignItems: "center",
294
- justifyContent: "space-between",
295
- marginBottom: 8
296
- },
297
- valueLabel: {
298
- fontSize: 10,
299
- color: night.color.textSecondary,
300
- fontFamily: monoFont,
301
- letterSpacing: 0.5,
302
- fontWeight: "600"
303
- },
304
- valueHeaderBadges: {
305
- flexDirection: "row",
306
- alignItems: "center",
307
- gap: 6
308
- },
309
- changeBadge: {
310
- paddingHorizontal: 8,
311
- paddingVertical: 2,
312
- borderRadius: 4
313
- },
314
- changeText: {
315
- fontSize: 9,
316
- fontWeight: "700",
317
- fontFamily: monoFont,
318
- letterSpacing: 0.3
319
- },
320
- typeBadge: {
321
- paddingHorizontal: 8,
322
- paddingVertical: 2,
323
- borderRadius: 4,
324
- backgroundColor: night.color.surfaceElevated
325
- },
326
- typeText: {
327
- fontSize: 9,
328
- fontWeight: "600",
329
- color: night.color.textTertiary,
330
- fontFamily: monoFont
331
- },
332
- valueBox: {
333
- // Inset code box — darker than the card, the night track color.
334
- backgroundColor: night.color.bg,
335
- borderRadius: 6,
336
- borderWidth: 1,
337
- borderColor: night.color.border,
338
- padding: 8
339
- },
340
- valueText: {
341
- fontSize: 12,
342
- color: night.color.text,
343
- fontFamily: monoFont,
344
- lineHeight: 18
345
- },
346
- diffContainer: {
347
- flex: 1
348
- },
349
- diffContent: {
350
- flex: 1,
351
- paddingHorizontal: 14
352
- },
353
- changeBadgeSmall: {
354
- paddingHorizontal: 6,
355
- paddingVertical: 1,
356
- borderRadius: 3
357
- },
358
- changeTextSmall: {
359
- fontSize: 8,
360
- fontWeight: "700",
361
- fontFamily: monoFont
362
- },
363
- dataViewerContainer: {
364
- marginTop: -12,
365
- marginHorizontal: -12,
366
- marginBottom: -12
367
- }
368
- });
1
+ "use strict";import{View,Text,StyleSheet,ScrollView}from"react-native";import{useState,useCallback,useMemo}from"react";import{night,EventStepperFooter,formatRelativeTime,parseValue,monoFont}from"@buoy-gg/shared-ui";import{DataViewer,SplitDiffViewer,TreeDiffViewer,diffThemes}from"@buoy-gg/shared-ui/dataViewer";import{ZustandDetailViewToggle}from"./ZustandDetailViewToggle";import{ZustandStateInfoView}from"./ZustandStateInfoView";import{DiffModeTabs,CompareBar}from"@buoy-gg/shared-ui";import{zustandStateStore}from"../utils/zustandStateStore";import{ZUSTAND_TEST_ID}from"../utils/testIDs";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function getChangeColor(e){return zustandStateStore.getStoreColor(e.storeName)}function getChangeLabel(e){switch(e.category){case"replace":return"REPLACE";case"persist":return"HYDRATE";case"initial":return"INIT";default:return"SET"}}function getValueType(e){return null===e?"null":void 0===e?"undefined":Array.isArray(e)?"array":typeof e}function formatTimestamp(e){return new Date(e).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})}const DIFF_MODE_TABS=[{key:"tree",label:"TREE VIEW"},{key:"split",label:"SPLIT VIEW"}];export function ZustandStateDetailContent({change:e,changes:t,selectedIndex:a,onIndexChange:n,disableInternalFooter:o=!1,initialView:r="change"}){const[i,l]=useState(r),[s,d]=useState("tree"),c=t.length,g=getChangeColor(e),m=getChangeLabel(e),u=getValueType(parseValue(e.nextState)),f=c-a,h=f-1,x=a<c-1?a+1:null,p=null!==x?t[x]:null,T=useMemo(()=>({index:x??0,label:h>0?`#${h}`:"Initial",timestamp:p?formatTimestamp(p.timestamp):"",relativeTime:p?formatRelativeTime(new Date(p.timestamp)):"state",badge:p?_jsx(View,{style:[styles.changeBadgeSmall,{backgroundColor:`${getChangeColor(p)}20`}],children:_jsx(Text,{style:[styles.changeTextSmall,{color:getChangeColor(p)}],children:getChangeLabel(p)})}):void 0}),[x,p,h]),y=useMemo(()=>({index:a,label:`#${f}`,timestamp:formatTimestamp(e.timestamp),relativeTime:formatRelativeTime(new Date(e.timestamp)),badge:_jsx(View,{style:[styles.changeBadgeSmall,{backgroundColor:`${g}20`}],children:_jsx(Text,{style:[styles.changeTextSmall,{color:g}],children:m})})}),[a,e.timestamp,g,m,f]),S=useCallback(()=>{const t=parseValue(e.nextState);return _jsxs(View,{style:styles.contentCard,testID:`${ZUSTAND_TEST_ID}-state-card`,children:[_jsxs(View,{style:styles.valueHeader,children:[_jsx(Text,{style:styles.valueLabel,children:"STATE AFTER CHANGE"}),_jsxs(View,{style:styles.valueHeaderBadges,children:[_jsx(View,{style:[styles.changeBadge,{backgroundColor:`${g}20`}],children:_jsx(Text,{style:[styles.changeText,{color:g}],children:m})}),_jsx(View,{style:styles.typeBadge,children:_jsx(Text,{style:styles.typeText,testID:`${ZUSTAND_TEST_ID}-state-type`,children:u.toUpperCase()})})]})]}),_jsx(View,{style:styles.dataViewerContainer,children:_jsx(DataViewer,{title:"",data:t,showTypeFilter:!0,rawMode:!0,initialExpanded:!0})})]})},[e.nextState,g,m,u]),b=useCallback(()=>{const t=parseValue(e.prevState),a=parseValue(e.nextState);return"split"===s?_jsx(ScrollView,{style:{flex:1},showsVerticalScrollIndicator:!0,children:_jsx(SplitDiffViewer,{oldValue:t,newValue:a,theme:diffThemes.devToolsDefault,options:{hideLineNumbers:!1,disableWordDiff:!1,showDiffOnly:!1,compareMethod:"words",contextLines:3},showThemeName:!1})}):_jsx(TreeDiffViewer,{oldValue:t,newValue:a})},[e.prevState,e.nextState,s]),w=useCallback(()=>{n(Math.min(c-1,a+1))},[a,c,n]),V=useCallback(()=>{n(Math.max(0,a-1))},[a,n]),C=void 0===e.prevState,D=!o&&c>1;return _jsxs(View,{style:styles.container,children:[_jsx(ZustandDetailViewToggle,{activeView:i,onViewChange:l,diffDisabled:C}),_jsxs(View,{style:[styles.contentArea,D&&styles.contentAreaFooterPad],children:["change"===i&&_jsx(ZustandStateInfoView,{change:e}),"state"===i&&_jsx(View,{style:styles.stateContainer,children:S()}),"diff"===i&&_jsxs(View,{style:styles.diffContainer,testID:`${ZUSTAND_TEST_ID}-diff`,children:[_jsx(DiffModeTabs,{tabs:DIFF_MODE_TABS,activeTab:s,onTabChange:d,testIDPrefix:`${ZUSTAND_TEST_ID}-diff-tab`}),_jsx(CompareBar,{leftEvent:T,rightEvent:y}),_jsx(View,{style:styles.diffContent,testID:`${ZUSTAND_TEST_ID}-diff-content`,children:b()})]})]}),D&&_jsx(EventStepperFooter,{currentIndex:f-1,totalItems:c,onPrevious:w,onNext:V,itemLabel:"Change",subtitle:formatRelativeTime(new Date(e.timestamp)),absolute:!0})]})}export function ZustandStateDetailFooter({change:e,changes:t,selectedIndex:a,onIndexChange:n}){const o=t.length;return o<=1?null:_jsx(EventStepperFooter,{currentIndex:o-a-1,totalItems:o,onPrevious:()=>n(Math.min(o-1,a+1)),onNext:()=>n(Math.max(0,a-1)),itemLabel:"Change",subtitle:formatRelativeTime(new Date(e.timestamp))})}const styles=StyleSheet.create({container:{flex:1,backgroundColor:"transparent"},contentArea:{flex:1},contentAreaFooterPad:{paddingBottom:96},stateContainer:{flex:1,padding:14},contentCard:{backgroundColor:night.color.surface,borderRadius:14,padding:14,borderWidth:1,borderColor:night.color.border},valueHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:8},valueLabel:{fontSize:10,color:night.color.textSecondary,fontFamily:monoFont,letterSpacing:.5,fontWeight:"600"},valueHeaderBadges:{flexDirection:"row",alignItems:"center",gap:6},changeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4},changeText:{fontSize:9,fontWeight:"700",fontFamily:monoFont,letterSpacing:.3},typeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4,backgroundColor:night.color.surfaceElevated},typeText:{fontSize:9,fontWeight:"600",color:night.color.textTertiary,fontFamily:monoFont},valueBox:{backgroundColor:night.color.bg,borderRadius:6,borderWidth:1,borderColor:night.color.border,padding:8},valueText:{fontSize:12,color:night.color.text,fontFamily:monoFont,lineHeight:18},diffContainer:{flex:1},diffContent:{flex:1,paddingHorizontal:14},changeBadgeSmall:{paddingHorizontal:6,paddingVertical:1,borderRadius:3},changeTextSmall:{fontSize:8,fontWeight:"700",fontFamily:monoFont},dataViewerContainer:{marginTop:-12,marginHorizontal:-12,marginBottom:-12}});