@buoy-gg/zustand 2.1.11 → 2.1.13

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 (57) hide show
  1. package/LICENSE +58 -0
  2. package/lib/commonjs/index.js +1 -91
  3. package/lib/commonjs/preset.js +1 -102
  4. package/lib/commonjs/zustand/components/ZustandActionButton.js +1 -116
  5. package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +1 -134
  6. package/lib/commonjs/zustand/components/ZustandEventFilterView.js +1 -291
  7. package/lib/commonjs/zustand/components/ZustandIcon.js +1 -35
  8. package/lib/commonjs/zustand/components/ZustandModal.js +1 -603
  9. package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +1 -165
  10. package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +1 -352
  11. package/lib/commonjs/zustand/components/ZustandStateInfoView.js +1 -508
  12. package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +1 -307
  13. package/lib/commonjs/zustand/components/index.js +1 -73
  14. package/lib/commonjs/zustand/hooks/index.js +1 -12
  15. package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +1 -92
  16. package/lib/commonjs/zustand/index.js +1 -99
  17. package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +1 -220
  18. package/lib/commonjs/zustand/utils/index.js +1 -31
  19. package/lib/commonjs/zustand/utils/zustandStateStore.js +1 -361
  20. package/lib/module/index.js +1 -80
  21. package/lib/module/preset.js +1 -98
  22. package/lib/module/zustand/components/ZustandActionButton.js +1 -112
  23. package/lib/module/zustand/components/ZustandDetailViewToggle.js +1 -129
  24. package/lib/module/zustand/components/ZustandEventFilterView.js +1 -287
  25. package/lib/module/zustand/components/ZustandIcon.js +1 -32
  26. package/lib/module/zustand/components/ZustandModal.js +1 -599
  27. package/lib/module/zustand/components/ZustandStateChangeItem.js +1 -161
  28. package/lib/module/zustand/components/ZustandStateDetailContent.js +1 -348
  29. package/lib/module/zustand/components/ZustandStateInfoView.js +1 -503
  30. package/lib/module/zustand/components/ZustandStoreBrowser.js +1 -303
  31. package/lib/module/zustand/components/index.js +1 -10
  32. package/lib/module/zustand/hooks/index.js +1 -3
  33. package/lib/module/zustand/hooks/useZustandStateChanges.js +1 -88
  34. package/lib/module/zustand/index.js +1 -12
  35. package/lib/module/zustand/utils/buoyZustandMiddleware.js +1 -214
  36. package/lib/module/zustand/utils/index.js +1 -4
  37. package/lib/module/zustand/utils/zustandStateStore.js +1 -357
  38. package/package.json +10 -10
  39. package/lib/typescript/index.d.ts.map +0 -1
  40. package/lib/typescript/preset.d.ts.map +0 -1
  41. package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +0 -1
  42. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +0 -1
  43. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +0 -1
  44. package/lib/typescript/zustand/components/ZustandIcon.d.ts.map +0 -1
  45. package/lib/typescript/zustand/components/ZustandModal.d.ts.map +0 -1
  46. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +0 -1
  47. package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +0 -1
  48. package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +0 -1
  49. package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +0 -1
  50. package/lib/typescript/zustand/components/index.d.ts.map +0 -1
  51. package/lib/typescript/zustand/hooks/index.d.ts.map +0 -1
  52. package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +0 -1
  53. package/lib/typescript/zustand/index.d.ts.map +0 -1
  54. package/lib/typescript/zustand/types/index.d.ts.map +0 -1
  55. package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts.map +0 -1
  56. package/lib/typescript/zustand/utils/index.d.ts.map +0 -1
  57. package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +0 -1
@@ -1,603 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.ZustandModal = ZustandModal;
7
- var _react = require("react");
8
- var _reactNative = require("react-native");
9
- var _sharedUi = require("@buoy-gg/shared-ui");
10
- var _license = require("@buoy-gg/license");
11
- var _useZustandStateChanges = require("../hooks/useZustandStateChanges");
12
- var _ZustandStateChangeItem = require("./ZustandStateChangeItem");
13
- var _ZustandStateDetailContent = require("./ZustandStateDetailContent");
14
- var _ZustandStoreBrowser = require("./ZustandStoreBrowser");
15
- var _ZustandEventFilterView = require("./ZustandEventFilterView");
16
- var _jsxRuntime = require("react/jsx-runtime");
17
- /**
18
- * Main Zustand DevTools modal
19
- *
20
- * Two tabs mirroring the Storage DevTools pattern:
21
- * - Stores tab: Browse all registered stores and their current state
22
- * - Events tab: Live state change monitoring with diffs
23
- */
24
-
25
- /** Free tier limit for change history */
26
- const FREE_TIER_CHANGE_LIMIT = 25;
27
- function EventsEmptyState({
28
- isEnabled
29
- }) {
30
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
31
- style: styles.emptyState,
32
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Box, {
33
- size: 32,
34
- color: _sharedUi.macOSColors.text.muted
35
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
36
- style: styles.emptyTitle,
37
- children: "No state changes"
38
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
39
- style: styles.emptyText,
40
- children: isEnabled ? "State changes will appear here as stores update." : "Enable capture to start recording state changes"
41
- })]
42
- });
43
- }
44
- function ZustandModal({
45
- visible,
46
- onClose,
47
- onBack,
48
- onMinimize,
49
- enableSharedModalDimensions = false
50
- }) {
51
- const isPro = (0, _license.useIsPro)();
52
- const [showProModal, setShowProModal] = (0, _react.useState)(false);
53
- const [activeTab, setActiveTab] = (0, _react.useState)("stores");
54
- const [selectedHistoryStore, setSelectedHistoryStore] = (0, _react.useState)(null);
55
- const [showFilters, setShowFilters] = (0, _react.useState)(false);
56
- const [ignoredPatterns, setIgnoredPatterns] = (0, _react.useState)(new Set());
57
- const {
58
- filteredChanges,
59
- filter,
60
- setFilter,
61
- stats,
62
- stores,
63
- clearChanges,
64
- isEnabled,
65
- toggleCapture
66
- } = (0, _useZustandStateChanges.useZustandStateChanges)();
67
-
68
- // Apply ignored patterns on top of hook's filteredChanges
69
- const displayedChanges = (0, _react.useMemo)(() => {
70
- if (ignoredPatterns.size === 0) return filteredChanges;
71
- return filteredChanges.filter(c => !Array.from(ignoredPatterns).some(p => c.storeName.toLowerCase().includes(p.toLowerCase())));
72
- }, [filteredChanges, ignoredPatterns]);
73
-
74
- // Apply ignored patterns to stores list too
75
- const displayedStores = (0, _react.useMemo)(() => {
76
- if (ignoredPatterns.size === 0) return stores;
77
- return stores.filter(s => !Array.from(ignoredPatterns).some(p => s.name.toLowerCase().includes(p.toLowerCase())));
78
- }, [stores, ignoredPatterns]);
79
-
80
- // For free users, limit visible changes
81
- const visibleChanges = (0, _react.useMemo)(() => {
82
- if (isPro) return displayedChanges;
83
- return displayedChanges.slice(0, FREE_TIER_CHANGE_LIMIT);
84
- }, [displayedChanges, isPro]);
85
- const lockedChangeCount = (0, _react.useMemo)(() => {
86
- if (isPro) return 0;
87
- return Math.max(0, displayedChanges.length - FREE_TIER_CHANGE_LIMIT);
88
- }, [displayedChanges.length, isPro]);
89
- const hasLockedChanges = lockedChangeCount > 0;
90
-
91
- // When viewing a single store's history, scope the change list to that store
92
- const activeChanges = (0, _react.useMemo)(() => {
93
- if (selectedHistoryStore) {
94
- return visibleChanges.filter(c => c.storeName === selectedHistoryStore);
95
- }
96
- return visibleChanges;
97
- }, [visibleChanges, selectedHistoryStore]);
98
-
99
- // Selection state — track by ID so new events don't shift position
100
- const [selectedChangeId, setSelectedChangeId] = (0, _react.useState)(null);
101
- const selectedChangeIndex = (0, _react.useMemo)(() => {
102
- if (selectedChangeId === null) return null;
103
- const idx = activeChanges.findIndex(c => c.id === selectedChangeId);
104
- return idx >= 0 ? idx : null;
105
- }, [selectedChangeId, activeChanges]);
106
- const selectedChange = selectedChangeIndex !== null ? activeChanges[selectedChangeIndex] : null;
107
-
108
- // Search state — shared across tabs
109
- const [searchText, setSearchText] = (0, _react.useState)("");
110
- const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
111
- const searchInputRef = (0, _react.useRef)(null);
112
- const flatListRef = (0, _react.useRef)(null);
113
- const handleModeChange = (0, _react.useCallback)(_mode => {}, []);
114
- const handleSearch = text => {
115
- setSearchText(text);
116
- if (activeTab === "events") {
117
- setFilter(prev => ({
118
- ...prev,
119
- searchText: text
120
- }));
121
- }
122
- };
123
- const handleChangePress = (0, _react.useCallback)(change => {
124
- setSelectedChangeId(change.id);
125
- }, []);
126
- const handleUpgradePress = (0, _react.useCallback)(() => {
127
- setShowProModal(true);
128
- }, []);
129
- const handleBack = (0, _react.useCallback)(() => {
130
- setSelectedChangeId(null);
131
- }, []);
132
- const handleIndexChange = (0, _react.useCallback)(newIndex => {
133
- const change = activeChanges[newIndex];
134
- if (change) {
135
- setSelectedChangeId(change.id);
136
- }
137
- }, [activeChanges]);
138
- const handleViewHistory = (0, _react.useCallback)(storeName => {
139
- setSelectedHistoryStore(storeName);
140
- setSelectedChangeId(null);
141
- }, []);
142
- const handleBackFromHistory = (0, _react.useCallback)(() => {
143
- setSelectedHistoryStore(null);
144
- setSelectedChangeId(null);
145
- }, []);
146
- const getStoresSnapshot = (0, _react.useCallback)(() => {
147
- return displayedStores.reduce((acc, store) => {
148
- try {
149
- const state = store.api.getState();
150
- if (state && typeof state === "object") {
151
- const filtered = {};
152
- for (const [key, value] of Object.entries(state)) {
153
- if (typeof value !== "function") filtered[key] = (0, _sharedUi.truncatePayload)(value);
154
- }
155
- acc[store.name] = filtered;
156
- } else {
157
- acc[store.name] = (0, _sharedUi.truncatePayload)(state);
158
- }
159
- } catch {
160
- acc[store.name] = null;
161
- }
162
- return acc;
163
- }, {});
164
- }, [displayedStores]);
165
- const getEventsSnapshot = (0, _react.useCallback)(() => {
166
- return displayedChanges.map(change => ({
167
- id: change.id,
168
- storeName: change.storeName,
169
- timestamp: change.timestamp,
170
- prevState: (0, _sharedUi.truncatePayload)(change.prevState),
171
- nextState: (0, _sharedUi.truncatePayload)(change.nextState),
172
- hasStateChange: change.hasStateChange,
173
- changedKeys: change.changedKeys
174
- }));
175
- }, [displayedChanges]);
176
- const getHistorySnapshot = (0, _react.useCallback)(() => {
177
- return activeChanges.map(change => ({
178
- id: change.id,
179
- storeName: change.storeName,
180
- timestamp: change.timestamp,
181
- prevState: (0, _sharedUi.truncatePayload)(change.prevState),
182
- nextState: (0, _sharedUi.truncatePayload)(change.nextState),
183
- hasStateChange: change.hasStateChange,
184
- changedKeys: change.changedKeys
185
- }));
186
- }, [activeChanges]);
187
- const handleTogglePattern = (0, _react.useCallback)(pattern => {
188
- setIgnoredPatterns(prev => {
189
- const next = new Set(prev);
190
- if (next.has(pattern)) next.delete(pattern);else next.add(pattern);
191
- return next;
192
- });
193
- }, []);
194
- const handleAddPattern = (0, _react.useCallback)(pattern => {
195
- setIgnoredPatterns(prev => new Set([...prev, pattern]));
196
- }, []);
197
- const handleTabChange = (0, _react.useCallback)(tab => {
198
- setActiveTab(tab);
199
- setSelectedHistoryStore(null);
200
- setSelectedChangeId(null);
201
- setShowFilters(false);
202
- if (searchText) {
203
- setSearchText("");
204
- setFilter(prev => ({
205
- ...prev,
206
- searchText: ""
207
- }));
208
- }
209
- setIsSearchActive(false);
210
- }, [searchText, setFilter]);
211
- const keyExtractor = (0, _react.useCallback)(item => item.id, []);
212
- const renderItem = (0, _react.useCallback)(({
213
- item
214
- }) => {
215
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandStateChangeItem.ZustandStateChangeItem, {
216
- change: item,
217
- onPress: handleChangePress
218
- });
219
- }, [handleChangePress]);
220
-
221
- // ---- Header rendering ----
222
-
223
- const hasActiveFilters = ignoredPatterns.size > 0;
224
- const renderHeaderContent = () => {
225
- // Filter view header
226
- if (showFilters) {
227
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
228
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
229
- onBack: () => setShowFilters(false)
230
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
231
- title: "Filters",
232
- centered: true
233
- })]
234
- });
235
- }
236
-
237
- // Change detail header
238
- if (selectedChange) {
239
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
240
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
241
- onBack: handleBack
242
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
243
- title: `${selectedChange.storeName}/setState`,
244
- centered: true
245
- })]
246
- });
247
- }
248
-
249
- // Store history header
250
- if (selectedHistoryStore) {
251
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
252
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
253
- onBack: handleBackFromHistory
254
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
255
- title: `${selectedHistoryStore} History`,
256
- centered: true
257
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Actions, {
258
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
259
- value: getHistorySnapshot,
260
- disabled: activeChanges.length === 0,
261
- buttonStyle: styles.headerActionButton
262
- })
263
- })]
264
- });
265
- }
266
-
267
- // Main view with tabs
268
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
269
- children: [onBack && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
270
- onBack: onBack
271
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
272
- title: "",
273
- children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
274
- style: styles.headerSearchContainer,
275
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
276
- size: 14,
277
- color: _sharedUi.macOSColors.text.secondary
278
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
279
- ref: searchInputRef,
280
- style: styles.headerSearchInput,
281
- placeholder: activeTab === "stores" ? "Search stores..." : "Search events...",
282
- placeholderTextColor: _sharedUi.macOSColors.text.muted,
283
- value: searchText,
284
- onChangeText: handleSearch,
285
- onSubmitEditing: () => setIsSearchActive(false),
286
- onBlur: () => setIsSearchActive(false),
287
- autoCapitalize: "none",
288
- autoCorrect: false,
289
- returnKeyType: "search"
290
- }), searchText.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
291
- onPress: () => {
292
- handleSearch("");
293
- setIsSearchActive(false);
294
- },
295
- style: styles.headerSearchClear,
296
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
297
- size: 14,
298
- color: _sharedUi.macOSColors.text.secondary
299
- })
300
- })]
301
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TabSelector, {
302
- tabs: [{
303
- key: "stores",
304
- label: `Stores${displayedStores.length > 0 ? ` (${displayedStores.length})` : ""}`
305
- }, {
306
- key: "events",
307
- label: `Events${displayedChanges.length > 0 ? ` (${displayedChanges.length})` : ""}`
308
- }],
309
- activeTab: activeTab,
310
- onTabChange: handleTabChange
311
- })
312
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
313
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
314
- onPress: () => setIsSearchActive(true),
315
- style: styles.headerActionButton,
316
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
317
- size: 14,
318
- color: _sharedUi.macOSColors.text.secondary
319
- })
320
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
321
- onPress: () => setShowFilters(true),
322
- style: [styles.headerActionButton, hasActiveFilters && styles.headerActionButtonActive],
323
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
324
- size: 14,
325
- color: hasActiveFilters ? _sharedUi.macOSColors.semantic.debug : _sharedUi.macOSColors.text.secondary
326
- })
327
- }), activeTab === "stores" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
328
- value: getStoresSnapshot,
329
- disabled: displayedStores.length === 0,
330
- buttonStyle: styles.headerActionButton
331
- }), activeTab === "events" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
332
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
333
- value: getEventsSnapshot,
334
- disabled: displayedChanges.length === 0,
335
- buttonStyle: styles.headerActionButton
336
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
337
- isEnabled: isEnabled,
338
- onToggle: toggleCapture,
339
- accessibilityLabel: "Toggle Zustand state capture"
340
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarClearButton, {
341
- onPress: clearChanges,
342
- disabled: displayedChanges.length === 0,
343
- buttonStyle: styles.headerActionButton
344
- })]
345
- })]
346
- })]
347
- });
348
- };
349
-
350
- // ---- Content rendering ----
351
-
352
- const renderContent = () => {
353
- // Filter view (applies to both tabs)
354
- if (showFilters) {
355
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandEventFilterView.ZustandEventFilterView, {
356
- ignoredPatterns: ignoredPatterns,
357
- onTogglePattern: handleTogglePattern,
358
- onAddPattern: handleAddPattern,
359
- stores: stores
360
- });
361
- }
362
-
363
- // Change detail view (works for both events tab and store history)
364
- if (selectedChange && selectedChangeIndex !== null) {
365
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandStateDetailContent.ZustandStateDetailContent, {
366
- change: selectedChange,
367
- changes: activeChanges,
368
- selectedIndex: selectedChangeIndex,
369
- onIndexChange: handleIndexChange,
370
- disableInternalFooter: true
371
- });
372
- }
373
-
374
- // Store history view — filtered to one store
375
- if (selectedHistoryStore) {
376
- return activeChanges.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
377
- data: activeChanges,
378
- renderItem: renderItem,
379
- keyExtractor: keyExtractor,
380
- contentContainerStyle: styles.listContent,
381
- showsVerticalScrollIndicator: true,
382
- removeClippedSubviews: true,
383
- initialNumToRender: 15,
384
- maxToRenderPerBatch: 10,
385
- windowSize: 10,
386
- scrollEnabled: false
387
- }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
388
- style: styles.emptyState,
389
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Box, {
390
- size: 32,
391
- color: _sharedUi.macOSColors.text.muted
392
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
393
- style: styles.emptyTitle,
394
- children: "No history yet"
395
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
396
- style: styles.emptyText,
397
- children: ["State changes for ", selectedHistoryStore, " will appear here."]
398
- })]
399
- });
400
- }
401
-
402
- // Stores browse tab
403
- if (activeTab === "stores") {
404
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandStoreBrowser.ZustandStoreBrowser, {
405
- stores: displayedStores,
406
- searchQuery: searchText,
407
- onViewHistory: handleViewHistory
408
- });
409
- }
410
-
411
- // Events tab
412
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
413
- children: [!isEnabled && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
414
- style: styles.disabledBanner,
415
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Power, {
416
- size: 14,
417
- color: _sharedUi.macOSColors.semantic.warning
418
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
419
- style: styles.disabledText,
420
- children: "State capture is disabled"
421
- })]
422
- }), hasLockedChanges && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
423
- style: styles.lockedBanner,
424
- onPress: handleUpgradePress,
425
- activeOpacity: 0.8,
426
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Lock, {
427
- size: 14,
428
- color: _sharedUi.buoyColors.primary
429
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
430
- style: styles.lockedText,
431
- children: [lockedChangeCount, " older", " ", lockedChangeCount === 1 ? "change" : "changes", " locked"]
432
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
433
- style: styles.upgradeBadge,
434
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
435
- style: styles.upgradeBadgeText,
436
- children: "UPGRADE"
437
- })
438
- })]
439
- }), visibleChanges.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
440
- ref: flatListRef,
441
- data: visibleChanges,
442
- renderItem: renderItem,
443
- keyExtractor: keyExtractor,
444
- contentContainerStyle: styles.listContent,
445
- showsVerticalScrollIndicator: true,
446
- removeClippedSubviews: true,
447
- initialNumToRender: 15,
448
- maxToRenderPerBatch: 10,
449
- windowSize: 10,
450
- scrollEnabled: false
451
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EventsEmptyState, {
452
- isEnabled: isEnabled
453
- })]
454
- });
455
- };
456
- const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : "buoy-zustand-modal";
457
- if (!visible) return null;
458
- const footerNode = selectedChange && selectedChangeIndex !== null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ZustandStateDetailContent.ZustandStateDetailFooter, {
459
- change: selectedChange,
460
- changes: activeChanges,
461
- selectedIndex: selectedChangeIndex,
462
- onIndexChange: handleIndexChange
463
- }) : null;
464
- const footerHeight = selectedChange && activeChanges.length > 1 ? 68 : 0;
465
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.TickProvider, {
466
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
467
- visible: visible,
468
- onClose: onClose,
469
- onMinimize: onMinimize,
470
- persistenceKey: persistenceKey,
471
- header: {
472
- showToggleButton: true,
473
- customContent: renderHeaderContent()
474
- },
475
- onModeChange: handleModeChange,
476
- enablePersistence: true,
477
- initialMode: "bottomSheet",
478
- enableGlitchEffects: true,
479
- styles: {},
480
- footer: footerNode,
481
- footerHeight: footerHeight,
482
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
483
- style: styles.container,
484
- children: renderContent()
485
- })
486
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProUpgradeModal, {
487
- visible: showProModal,
488
- onClose: () => setShowProModal(false),
489
- featureName: "Full State History"
490
- })]
491
- });
492
- }
493
- const styles = _reactNative.StyleSheet.create({
494
- container: {
495
- flex: 1,
496
- backgroundColor: _sharedUi.macOSColors.background.base
497
- },
498
- headerSearchContainer: {
499
- flexDirection: "row",
500
- alignItems: "center",
501
- backgroundColor: _sharedUi.macOSColors.background.input,
502
- borderRadius: 10,
503
- borderWidth: 1,
504
- borderColor: _sharedUi.macOSColors.border.default,
505
- paddingHorizontal: 12,
506
- paddingVertical: 5
507
- },
508
- headerSearchInput: {
509
- flex: 1,
510
- color: _sharedUi.macOSColors.text.primary,
511
- fontSize: 13,
512
- marginLeft: 6,
513
- paddingVertical: 2
514
- },
515
- headerSearchClear: {
516
- marginLeft: 6,
517
- padding: 4
518
- },
519
- headerActionButton: {
520
- width: 32,
521
- height: 32,
522
- borderRadius: 8,
523
- backgroundColor: _sharedUi.macOSColors.background.hover,
524
- borderWidth: 1,
525
- borderColor: _sharedUi.macOSColors.border.default,
526
- alignItems: "center",
527
- justifyContent: "center"
528
- },
529
- headerActionButtonDisabled: {
530
- opacity: 0.55
531
- },
532
- headerActionButtonActive: {
533
- backgroundColor: _sharedUi.macOSColors.semantic.infoBackground
534
- },
535
- disabledBanner: {
536
- flexDirection: "row",
537
- alignItems: "center",
538
- gap: 8,
539
- padding: 10,
540
- marginHorizontal: 12,
541
- marginTop: 8,
542
- backgroundColor: _sharedUi.macOSColors.semantic.warningBackground,
543
- borderRadius: 8,
544
- borderWidth: 1,
545
- borderColor: _sharedUi.macOSColors.semantic.warning + "20"
546
- },
547
- disabledText: {
548
- color: _sharedUi.macOSColors.semantic.warning,
549
- fontSize: 11,
550
- flex: 1
551
- },
552
- listContent: {
553
- paddingTop: 8,
554
- paddingBottom: 20
555
- },
556
- emptyState: {
557
- alignItems: "center",
558
- paddingVertical: 40
559
- },
560
- emptyTitle: {
561
- color: _sharedUi.macOSColors.text.primary,
562
- fontSize: 14,
563
- fontWeight: "600",
564
- marginTop: 12,
565
- marginBottom: 6
566
- },
567
- emptyText: {
568
- color: _sharedUi.macOSColors.text.muted,
569
- fontSize: 12,
570
- textAlign: "center",
571
- lineHeight: 18
572
- },
573
- lockedBanner: {
574
- flexDirection: "row",
575
- alignItems: "center",
576
- gap: 8,
577
- padding: 10,
578
- marginHorizontal: 12,
579
- marginTop: 8,
580
- backgroundColor: _sharedUi.buoyColors.primary + "15",
581
- borderRadius: 8,
582
- borderWidth: 1,
583
- borderColor: _sharedUi.buoyColors.primary + "33"
584
- },
585
- lockedText: {
586
- color: _sharedUi.buoyColors.primary,
587
- fontSize: 11,
588
- fontWeight: "500",
589
- flex: 1
590
- },
591
- upgradeBadge: {
592
- backgroundColor: _sharedUi.buoyColors.primary,
593
- paddingHorizontal: 8,
594
- paddingVertical: 3,
595
- borderRadius: 4
596
- },
597
- upgradeBadgeText: {
598
- color: "#fff",
599
- fontSize: 9,
600
- fontWeight: "700",
601
- letterSpacing: 0.5
602
- }
603
- });
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ZustandModal=ZustandModal;var _react=require("react"),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_license=require("@buoy-gg/license"),_useZustandStateChanges=require("../hooks/useZustandStateChanges"),_ZustandStateChangeItem=require("./ZustandStateChangeItem"),_ZustandStateDetailContent=require("./ZustandStateDetailContent"),_ZustandStoreBrowser=require("./ZustandStoreBrowser"),_ZustandEventFilterView=require("./ZustandEventFilterView"),_jsxRuntime=require("react/jsx-runtime");const FREE_TIER_CHANGE_LIMIT=25;function EventsEmptyState({isEnabled:e}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.emptyState,children:[(0,_jsxRuntime.jsx)(_sharedUi.Box,{size:32,color:_sharedUi.macOSColors.text.muted}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.emptyTitle,children:"No state changes"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.emptyText,children:e?"State changes will appear here as stores update.":"Enable capture to start recording state changes"})]})}function ZustandModal({visible:e,onClose:t,onBack:a,onMinimize:s,enableSharedModalDimensions:r=!1}){const n=(0,_license.useIsPro)(),[i,o]=(0,_react.useState)(!1),[l,d]=(0,_react.useState)("stores"),[c,u]=(0,_react.useState)(null),[h,_]=(0,_react.useState)(!1),[m,x]=(0,_react.useState)(new Set),{filteredChanges:g,filter:j,setFilter:y,stats:C,stores:S,clearChanges:b,isEnabled:p,toggleCapture:R}=(0,_useZustandStateChanges.useZustandStateChanges)(),U=(0,_react.useMemo)(()=>0===m.size?g:g.filter(e=>!Array.from(m).some(t=>e.storeName.toLowerCase().includes(t.toLowerCase()))),[g,m]),v=(0,_react.useMemo)(()=>0===m.size?S:S.filter(e=>!Array.from(m).some(t=>e.name.toLowerCase().includes(t.toLowerCase()))),[S,m]),T=(0,_react.useMemo)(()=>n?U:U.slice(0,FREE_TIER_CHANGE_LIMIT),[U,n]),f=(0,_react.useMemo)(()=>n?0:Math.max(0,U.length-FREE_TIER_CHANGE_LIMIT),[U.length,n]),k=f>0,w=(0,_react.useMemo)(()=>c?T.filter(e=>e.storeName===c):T,[T,c]),[B,N]=(0,_react.useState)(null),M=(0,_react.useMemo)(()=>{if(null===B)return null;const e=w.findIndex(e=>e.id===B);return e>=0?e:null},[B,w]),E=null!==M?w[M]:null,[I,O]=(0,_react.useState)(""),[z,H]=(0,_react.useState)(!1),Z=(0,_react.useRef)(null),P=(0,_react.useRef)(null),A=(0,_react.useCallback)(e=>{},[]),F=e=>{O(e),"events"===l&&y(t=>({...t,searchText:e}))},V=(0,_react.useCallback)(e=>{N(e.id)},[]),L=(0,_react.useCallback)(()=>{o(!0)},[]),D=(0,_react.useCallback)(()=>{N(null)},[]),q=(0,_react.useCallback)(e=>{const t=w[e];t&&N(t.id)},[w]),K=(0,_react.useCallback)(e=>{u(e),N(null)},[]),W=(0,_react.useCallback)(()=>{u(null),N(null)},[]),G=(0,_react.useCallback)(()=>v.reduce((e,t)=>{try{const a=t.api.getState();if(a&&"object"==typeof a){const s={};for(const[e,t]of Object.entries(a))"function"!=typeof t&&(s[e]=(0,_sharedUi.truncatePayload)(t));e[t.name]=s}else e[t.name]=(0,_sharedUi.truncatePayload)(a)}catch{e[t.name]=null}return e},{}),[v]),$=(0,_react.useCallback)(()=>U.map(e=>({id:e.id,storeName:e.storeName,timestamp:e.timestamp,prevState:(0,_sharedUi.truncatePayload)(e.prevState),nextState:(0,_sharedUi.truncatePayload)(e.nextState),hasStateChange:e.hasStateChange,changedKeys:e.changedKeys})),[U]),J=(0,_react.useCallback)(()=>w.map(e=>({id:e.id,storeName:e.storeName,timestamp:e.timestamp,prevState:(0,_sharedUi.truncatePayload)(e.prevState),nextState:(0,_sharedUi.truncatePayload)(e.nextState),hasStateChange:e.hasStateChange,changedKeys:e.changedKeys})),[w]),Q=(0,_react.useCallback)(e=>{x(t=>{const a=new Set(t);return a.has(e)?a.delete(e):a.add(e),a})},[]),X=(0,_react.useCallback)(e=>{x(t=>new Set([...t,e]))},[]),Y=(0,_react.useCallback)(e=>{d(e),u(null),N(null),_(!1),I&&(O(""),y(e=>({...e,searchText:""}))),H(!1)},[I,y]),ee=(0,_react.useCallback)(e=>e.id,[]),te=(0,_react.useCallback)(({item:e})=>(0,_jsxRuntime.jsx)(_ZustandStateChangeItem.ZustandStateChangeItem,{change:e,onPress:V}),[V]),ae=m.size>0,se=r?_sharedUi.devToolsStorageKeys.modal.root():"buoy-zustand-modal";if(!e)return null;const re=E&&null!==M?(0,_jsxRuntime.jsx)(_ZustandStateDetailContent.ZustandStateDetailFooter,{change:E,changes:w,selectedIndex:M,onIndexChange:q}):null,ne=E&&w.length>1?68:0;return(0,_jsxRuntime.jsxs)(_sharedUi.TickProvider,{children:[(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:e,onClose:t,onMinimize:s,persistenceKey:se,header:{showToggleButton:!0,customContent:h?(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>_(!1)}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Filters",centered:!0})]}):E?(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:D}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:`${E.storeName}/setState`,centered:!0})]}):c?(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:W}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:`${c} History`,centered:!0}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Actions,{children:(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:J,disabled:0===w.length,buttonStyle:styles.headerActionButton})})]}):(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[a&&(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:a}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"",children:z?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.headerSearchContainer,children:[(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:14,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{ref:Z,style:styles.headerSearchInput,placeholder:"stores"===l?"Search stores...":"Search events...",placeholderTextColor:_sharedUi.macOSColors.text.muted,value:I,onChangeText:F,onSubmitEditing:()=>H(!1),onBlur:()=>H(!1),autoCapitalize:"none",autoCorrect:!1,returnKeyType:"search"}),I.length>0&&(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>{F(""),H(!1)},style:styles.headerSearchClear,children:(0,_jsxRuntime.jsx)(_sharedUi.X,{size:14,color:_sharedUi.macOSColors.text.secondary})})]}):(0,_jsxRuntime.jsx)(_sharedUi.TabSelector,{tabs:[{key:"stores",label:"Stores"+(v.length>0?` (${v.length})`:"")},{key:"events",label:"Events"+(U.length>0?` (${U.length})`:"")}],activeTab:l,onTabChange:Y})}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>H(!0),style:styles.headerActionButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:14,color:_sharedUi.macOSColors.text.secondary})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>_(!0),style:[styles.headerActionButton,ae&&styles.headerActionButtonActive],children:(0,_jsxRuntime.jsx)(_sharedUi.Filter,{size:14,color:ae?_sharedUi.macOSColors.semantic.debug:_sharedUi.macOSColors.text.secondary})}),"stores"===l&&(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:G,disabled:0===v.length,buttonStyle:styles.headerActionButton}),"events"===l&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:$,disabled:0===U.length,buttonStyle:styles.headerActionButton}),(0,_jsxRuntime.jsx)(_sharedUi.PowerToggleButton,{isEnabled:p,onToggle:R,accessibilityLabel:"Toggle Zustand state capture"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolbarClearButton,{onPress:b,disabled:0===U.length,buttonStyle:styles.headerActionButton})]})]})]})},onModeChange:A,enablePersistence:!0,initialMode:"bottomSheet",enableGlitchEffects:!0,styles:{},footer:re,footerHeight:ne,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.container,children:h?(0,_jsxRuntime.jsx)(_ZustandEventFilterView.ZustandEventFilterView,{ignoredPatterns:m,onTogglePattern:Q,onAddPattern:X,stores:S}):E&&null!==M?(0,_jsxRuntime.jsx)(_ZustandStateDetailContent.ZustandStateDetailContent,{change:E,changes:w,selectedIndex:M,onIndexChange:q,disableInternalFooter:!0}):c?w.length>0?(0,_jsxRuntime.jsx)(_reactNative.FlatList,{data:w,renderItem:te,keyExtractor:ee,contentContainerStyle:styles.listContent,showsVerticalScrollIndicator:!0,removeClippedSubviews:!0,initialNumToRender:15,maxToRenderPerBatch:10,windowSize:10,scrollEnabled:!1}):(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.emptyState,children:[(0,_jsxRuntime.jsx)(_sharedUi.Box,{size:32,color:_sharedUi.macOSColors.text.muted}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.emptyTitle,children:"No history yet"}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.emptyText,children:["State changes for ",c," will appear here."]})]}):"stores"===l?(0,_jsxRuntime.jsx)(_ZustandStoreBrowser.ZustandStoreBrowser,{stores:v,searchQuery:I,onViewHistory:K}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[!p&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.disabledBanner,children:[(0,_jsxRuntime.jsx)(_sharedUi.Power,{size:14,color:_sharedUi.macOSColors.semantic.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disabledText,children:"State capture is disabled"})]}),k&&(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.lockedBanner,onPress:L,activeOpacity:.8,children:[(0,_jsxRuntime.jsx)(_sharedUi.Lock,{size:14,color:_sharedUi.buoyColors.primary}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.lockedText,children:[f," older"," ",1===f?"change":"changes"," locked"]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.upgradeBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.upgradeBadgeText,children:"UPGRADE"})})]}),T.length>0?(0,_jsxRuntime.jsx)(_reactNative.FlatList,{ref:P,data:T,renderItem:te,keyExtractor:ee,contentContainerStyle:styles.listContent,showsVerticalScrollIndicator:!0,removeClippedSubviews:!0,initialNumToRender:15,maxToRenderPerBatch:10,windowSize:10,scrollEnabled:!1}):(0,_jsxRuntime.jsx)(EventsEmptyState,{isEnabled:p})]})})}),(0,_jsxRuntime.jsx)(_sharedUi.ProUpgradeModal,{visible:i,onClose:()=>o(!1),featureName:"Full State History"})]})}const styles=_reactNative.StyleSheet.create({container:{flex:1,backgroundColor:_sharedUi.macOSColors.background.base},headerSearchContainer:{flexDirection:"row",alignItems:"center",backgroundColor:_sharedUi.macOSColors.background.input,borderRadius:10,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default,paddingHorizontal:12,paddingVertical:5},headerSearchInput:{flex:1,color:_sharedUi.macOSColors.text.primary,fontSize:13,marginLeft:6,paddingVertical:2},headerSearchClear:{marginLeft:6,padding:4},headerActionButton:{width:32,height:32,borderRadius:8,backgroundColor:_sharedUi.macOSColors.background.hover,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default,alignItems:"center",justifyContent:"center"},headerActionButtonDisabled:{opacity:.55},headerActionButtonActive:{backgroundColor:_sharedUi.macOSColors.semantic.infoBackground},disabledBanner:{flexDirection:"row",alignItems:"center",gap:8,padding:10,marginHorizontal:12,marginTop:8,backgroundColor:_sharedUi.macOSColors.semantic.warningBackground,borderRadius:8,borderWidth:1,borderColor:_sharedUi.macOSColors.semantic.warning+"20"},disabledText:{color:_sharedUi.macOSColors.semantic.warning,fontSize:11,flex:1},listContent:{paddingTop:8,paddingBottom:20},emptyState:{alignItems:"center",paddingVertical:40},emptyTitle:{color:_sharedUi.macOSColors.text.primary,fontSize:14,fontWeight:"600",marginTop:12,marginBottom:6},emptyText:{color:_sharedUi.macOSColors.text.muted,fontSize:12,textAlign:"center",lineHeight:18},lockedBanner:{flexDirection:"row",alignItems:"center",gap:8,padding:10,marginHorizontal:12,marginTop:8,backgroundColor:_sharedUi.buoyColors.primary+"15",borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.primary+"33"},lockedText:{color:_sharedUi.buoyColors.primary,fontSize:11,fontWeight:"500",flex:1},upgradeBadge:{backgroundColor:_sharedUi.buoyColors.primary,paddingHorizontal:8,paddingVertical:3,borderRadius:4},upgradeBadgeText:{color:"#fff",fontSize:9,fontWeight:"700",letterSpacing:.5}});