@buoy-gg/zustand 7.0.41 → 7.0.43

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 +11 -76
  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/hooks/useZustandStateChanges.js +1 -74
  15. package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +1 -418
  16. package/lib/commonjs/zustand/types/index.js +1 -1
  17. package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +1 -284
  18. package/lib/commonjs/zustand/utils/editableState.js +1 -146
  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 -379
  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/hooks/useZustandStateChanges.js +1 -70
  35. package/lib/module/zustand/sync/zustandSyncAdapter.js +1 -415
  36. package/lib/module/zustand/types/index.js +1 -1
  37. package/lib/module/zustand/utils/buoyZustandMiddleware.js +1 -278
  38. package/lib/module/zustand/utils/editableState.js +1 -138
  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 -375
  42. package/lib/web/index.mjs +2 -3
  43. package/package.json +4 -7
  44. package/lib/typescript/index.d.ts.map +0 -1
  45. package/lib/typescript/preset.d.ts.map +0 -1
  46. package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +0 -1
  47. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +0 -1
  48. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +0 -1
  49. package/lib/typescript/zustand/components/ZustandIcon.d.ts.map +0 -1
  50. package/lib/typescript/zustand/components/ZustandModal.d.ts.map +0 -1
  51. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +0 -1
  52. package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +0 -1
  53. package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +0 -1
  54. package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +0 -1
  55. package/lib/typescript/zustand/components/ZustandStoreDetailContent.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 as d}from"react";import{ChangeRow as p,buoyColors as r,night as f}from"@buoy-gg/shared-ui";import{zustandStateStore as c}from"../utils/zustandStateStore";import{jsx as m}from"react/jsx-runtime";function y(t,e){switch(t){case"replace":return"Replace";case"persist":return"Hydrate";case"initial":return"Initial";default:return e.charAt(0).toUpperCase()+e.slice(1)}}function C(t,e){switch(t){case"replace":return r.warning;case"persist":return r.info;case"initial":return f.color.textTertiary;default:return c.getStoreColor(e)}}function g(t){const e=[];if(t.duration!==void 0&&t.duration>=.1){e.push(`${t.duration.toFixed(1)}ms`)}if(t.hasStateChange){if(t.changedKeysCount>0){e.push(`${t.changedKeysCount} key${t.changedKeysCount>1?"s":""} changed`)}else{e.push(t.diffSummary||"state changed")}}else{e.push("no state change")}return e.join(" \xB7 ")}function S(t){if(t.category==="replace")return"REPLACE";if(t.category==="persist")return"HYDRATE";if(t.category==="initial")return"INIT";return"SET"}function b(t){if(t.changedKeys.length>0&&t.changedKeys.length<=3){return t.changedKeys.join(", ")}if(t.changedKeys.length>3){return`${t.changedKeys.slice(0,2).join(", ")} +${t.changedKeys.length-2}`}return t.partialPreview||"setState()"}export const ZustandStateChangeItem=d(function t({change:e,onPress:s,testID:a}){const o=C(e.category,e.storeName);const i=y(e.category,e.storeName);const n=g(e);const u=b(e);const l=S(e);return m(p,{statusColor:o,statusLabel:i,sublabel:n,primaryText:u,timestamp:e.timestamp,badgeText:l,changed:e.hasStateChange,slow:e.isSlowUpdate,onPress:()=>s(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 as a,Text as m,StyleSheet as U,ScrollView as O}from"react-native";import{useState as H,useCallback as C,useMemo as N}from"react";import{night as i,EventStepperFooter as z,formatRelativeTime as w,parseValue as x,monoFont as p}from"@buoy-gg/shared-ui";import{DataViewer as G,SplitDiffViewer as Y,TreeDiffViewer as q,diffThemes as J}from"@buoy-gg/shared-ui/dataViewer";import{ZustandDetailViewToggle as K}from"./ZustandDetailViewToggle";import{ZustandStateInfoView as Q}from"./ZustandStateInfoView";import{DiffModeTabs as X,CompareBar as ee}from"@buoy-gg/shared-ui";import{zustandStateStore as te}from"../utils/zustandStateStore";import{ZUSTAND_TEST_ID as g}from"../utils/testIDs";import{jsx as t,jsxs as u}from"react/jsx-runtime";function E(e){return te.getStoreColor(e.storeName)}function L(e){switch(e.category){case"replace":return"REPLACE";case"persist":return"HYDRATE";case"initial":return"INIT";default:return"SET"}}function re(e){if(e===null)return"null";if(e===void 0)return"undefined";if(Array.isArray(e))return"array";return typeof e}function M(e){const s=new Date(e);return s.toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"})}const oe=[{key:"tree",label:"TREE VIEW"},{key:"split",label:"SPLIT VIEW"}];export function ZustandStateDetailContent({change:e,changes:s,selectedIndex:o,onIndexChange:l,disableInternalFooter:d=false,initialView:D="change"}){const[h,k]=H(D);const[v,R]=H("tree");const c=s.length;const f=E(e);const b=L(e);const F=re(x(e.nextState));const S=c-o;const V=S-1;const y=o<c-1?o+1:null;const n=y!==null?s[y]:null;const $=N(()=>({index:y??0,label:V>0?`#${V}`:"Initial",timestamp:n?M(n.timestamp):"",relativeTime:n?w(new Date(n.timestamp)):"state",badge:n?t(a,{style:[r.changeBadgeSmall,{backgroundColor:`${E(n)}20`}],children:t(m,{style:[r.changeTextSmall,{color:E(n)}],children:L(n)})}):void 0}),[y,n,V]);const I=N(()=>({index:o,label:`#${S}`,timestamp:M(e.timestamp),relativeTime:w(new Date(e.timestamp)),badge:t(a,{style:[r.changeBadgeSmall,{backgroundColor:`${f}20`}],children:t(m,{style:[r.changeTextSmall,{color:f}],children:b})})}),[o,e.timestamp,f,b,S]);const W=C(()=>{const T=x(e.nextState);return u(a,{style:r.contentCard,testID:`${g}-state-card`,children:[u(a,{style:r.valueHeader,children:[t(m,{style:r.valueLabel,children:"STATE AFTER CHANGE"}),u(a,{style:r.valueHeaderBadges,children:[t(a,{style:[r.changeBadge,{backgroundColor:`${f}20`}],children:t(m,{style:[r.changeText,{color:f}],children:b})}),t(a,{style:r.typeBadge,children:t(m,{style:r.typeText,testID:`${g}-state-type`,children:F.toUpperCase()})})]})]}),t(a,{style:r.dataViewerContainer,children:t(G,{title:"",data:T,showTypeFilter:true,rawMode:true,initialExpanded:true})})]})},[e.nextState,f,b,F]);const P=C(()=>{const T=x(e.prevState);const A=x(e.nextState);if(v==="split"){return t(O,{style:{flex:1},showsVerticalScrollIndicator:true,children:t(Y,{oldValue:T,newValue:A,theme:J.devToolsDefault,options:{hideLineNumbers:false,disableWordDiff:false,showDiffOnly:false,compareMethod:"words",contextLines:3},showThemeName:false})})}return t(q,{oldValue:T,newValue:A})},[e.prevState,e.nextState,v]);const _=C(()=>{l(Math.min(c-1,o+1))},[o,c,l]);const j=C(()=>{l(Math.max(0,o-1))},[o,l]);const Z=e.prevState===void 0;const B=!d&&c>1;return u(a,{style:r.container,children:[t(K,{activeView:h,onViewChange:k,diffDisabled:Z}),u(a,{style:[r.contentArea,B&&r.contentAreaFooterPad],children:[h==="change"&&t(Q,{change:e}),h==="state"&&t(a,{style:r.stateContainer,children:W()}),h==="diff"&&u(a,{style:r.diffContainer,testID:`${g}-diff`,children:[t(X,{tabs:oe,activeTab:v,onTabChange:R,testIDPrefix:`${g}-diff-tab`}),t(ee,{leftEvent:$,rightEvent:I}),t(a,{style:r.diffContent,testID:`${g}-diff-content`,children:P()})]})]}),B&&t(z,{currentIndex:S-1,totalItems:c,onPrevious:_,onNext:j,itemLabel:"Change",subtitle:w(new Date(e.timestamp)),absolute:true})]})}export function ZustandStateDetailFooter({change:e,changes:s,selectedIndex:o,onIndexChange:l}){const d=s.length;if(d<=1)return null;const D=d-o;return t(z,{currentIndex:D-1,totalItems:d,onPrevious:()=>l(Math.min(d-1,o+1)),onNext:()=>l(Math.max(0,o-1)),itemLabel:"Change",subtitle:w(new Date(e.timestamp))})}const r=U.create({container:{flex:1,backgroundColor:"transparent"},contentArea:{flex:1},contentAreaFooterPad:{paddingBottom:96},stateContainer:{flex:1,padding:14},contentCard:{backgroundColor:i.color.surface,borderRadius:14,padding:14,borderWidth:1,borderColor:i.color.border},valueHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:8},valueLabel:{fontSize:10,color:i.color.textSecondary,fontFamily:p,letterSpacing:.5,fontWeight:"600"},valueHeaderBadges:{flexDirection:"row",alignItems:"center",gap:6},changeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4},changeText:{fontSize:9,fontWeight:"700",fontFamily:p,letterSpacing:.3},typeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4,backgroundColor:i.color.surfaceElevated},typeText:{fontSize:9,fontWeight:"600",color:i.color.textTertiary,fontFamily:p},valueBox:{backgroundColor:i.color.bg,borderRadius:6,borderWidth:1,borderColor:i.color.border,padding:8},valueText:{fontSize:12,color:i.color.text,fontFamily:p,lineHeight:18},diffContainer:{flex:1},diffContent:{flex:1,paddingHorizontal:14},changeBadgeSmall:{paddingHorizontal:6,paddingVertical:1,borderRadius:3},changeTextSmall:{fontSize:8,fontWeight:"700",fontFamily:p},dataViewerContainer:{marginTop:-12,marginHorizontal:-12,marginBottom:-12}});