@buoy-gg/zustand 7.0.32 → 7.0.34
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.
- package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +13 -107
- package/lib/commonjs/zustand/components/ZustandEventFilterView.js +24 -288
- package/lib/commonjs/zustand/components/ZustandModal.js +83 -141
- package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +8 -61
- package/lib/commonjs/zustand/components/ZustandStateInfoView.js +2 -46
- package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +29 -54
- package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +33 -53
- package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +24 -78
- package/lib/commonjs/zustand/utils/snapshotProvider.js +17 -60
- package/lib/commonjs/zustand/utils/zustandStateStore.js +37 -223
- package/lib/module/zustand/components/ZustandDetailViewToggle.js +15 -109
- package/lib/module/zustand/components/ZustandEventFilterView.js +28 -292
- package/lib/module/zustand/components/ZustandModal.js +85 -143
- package/lib/module/zustand/components/ZustandStateChangeItem.js +10 -63
- package/lib/module/zustand/components/ZustandStateInfoView.js +1 -45
- package/lib/module/zustand/components/ZustandStoreBrowser.js +31 -56
- package/lib/module/zustand/hooks/useZustandStateChanges.js +34 -54
- package/lib/module/zustand/sync/zustandSyncAdapter.js +25 -79
- package/lib/module/zustand/utils/snapshotProvider.js +18 -61
- package/lib/module/zustand/utils/zustandStateStore.js +37 -223
- package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts +2 -1
- package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts +6 -0
- package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandModal.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +1 -1
- package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts +2 -1
- package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +1 -1
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts +103 -117
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts +6 -26
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -26,33 +26,32 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* `removeClippedSubviews` unmounts the views of rows scrolled out of the
|
|
32
|
-
* window, which is what makes a long change list cheap — and which makes
|
|
33
|
-
* Detox report a perfectly rendered row as un-hittable. The env var is
|
|
34
|
-
* inlined at bundle time, so a bundler that does NOT inline it leaves the
|
|
35
|
-
* production behaviour exactly as it was.
|
|
29
|
+
* The change log's "nothing here". Everything but the nouns is the shared
|
|
30
|
+
* precedence — see `ToolEmptyState` in shared-ui for why it lives there.
|
|
36
31
|
*/
|
|
37
|
-
const CLIP_OFFSCREEN_CELLS = !(typeof process !== "undefined" && process.env?.EXPO_PUBLIC_E2E);
|
|
38
32
|
function EventsEmptyState({
|
|
39
|
-
isEnabled
|
|
33
|
+
isEnabled,
|
|
34
|
+
searchText,
|
|
35
|
+
totalChanges
|
|
40
36
|
}) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
const content = (0, _sharedUi.resolveListEmptyState)({
|
|
38
|
+
subject: "changes",
|
|
39
|
+
search: searchText,
|
|
40
|
+
total: totalChanges,
|
|
41
|
+
capturing: isEnabled,
|
|
42
|
+
waiting: {
|
|
43
|
+
otto: "waiting",
|
|
44
|
+
title: "No state changes",
|
|
45
|
+
message: "State changes will appear here as stores update."
|
|
46
|
+
},
|
|
47
|
+
paused: {
|
|
48
|
+
title: "No state changes",
|
|
49
|
+
message: "Enable capture to start recording state changes"
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
53
|
+
...content,
|
|
54
|
+
testID: `${_testIDs.ZUSTAND_TEST_ID}-empty`
|
|
56
55
|
});
|
|
57
56
|
}
|
|
58
57
|
function ZustandModal({
|
|
@@ -82,6 +81,7 @@ function ZustandModal({
|
|
|
82
81
|
const [showFilters, setShowFilters] = (0, _react.useState)(false);
|
|
83
82
|
const [ignoredPatterns, setIgnoredPatterns] = (0, _react.useState)(new Set());
|
|
84
83
|
const {
|
|
84
|
+
stateChanges,
|
|
85
85
|
filteredChanges,
|
|
86
86
|
filter,
|
|
87
87
|
setFilter,
|
|
@@ -104,6 +104,16 @@ function ZustandModal({
|
|
|
104
104
|
return stores.filter(s => !Array.from(ignoredPatterns).some(p => s.name.toLowerCase().includes(p.toLowerCase())));
|
|
105
105
|
}, [stores, ignoredPatterns]);
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* How many changes this store has captured, before the search — the
|
|
109
|
+
* denominator the scoped empty state needs so "clear the search" is only
|
|
110
|
+
* offered when clearing it would actually show something.
|
|
111
|
+
*/
|
|
112
|
+
const scopedTotalForStore = (0, _react.useMemo)(() => {
|
|
113
|
+
if (!selectedHistoryStore) return 0;
|
|
114
|
+
return stateChanges.filter(c => c.storeName === selectedHistoryStore).length;
|
|
115
|
+
}, [stateChanges, selectedHistoryStore]);
|
|
116
|
+
|
|
107
117
|
// Scope to a store BEFORE the tier cap, not after.
|
|
108
118
|
//
|
|
109
119
|
// The other way round, the cap was applied to the whole log and a store's
|
|
@@ -369,49 +379,24 @@ function ZustandModal({
|
|
|
369
379
|
onBack: onBack
|
|
370
380
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
371
381
|
title: "",
|
|
372
|
-
children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// header went back to its TABS — whose counts are of the
|
|
391
|
-
// WHOLE capture on the stores side — while the list stayed
|
|
392
|
-
// filtered, so the tool showed "Stores (4)" above a single
|
|
393
|
-
// row and offered nothing to explain the gap. The only way
|
|
394
|
-
// back was to reopen a field the user had no reason to think
|
|
395
|
-
// was still armed.
|
|
396
|
-
,
|
|
397
|
-
onBlur: () => {
|
|
398
|
-
if (searchText.length === 0) setIsSearchActive(false);
|
|
399
|
-
},
|
|
400
|
-
accessibilityLabel: "Search Zustand stores and events",
|
|
401
|
-
autoCapitalize: "none",
|
|
402
|
-
autoCorrect: false,
|
|
403
|
-
returnKeyType: "search"
|
|
404
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
405
|
-
onPress: closeSearch,
|
|
406
|
-
style: styles.headerSearchClear,
|
|
407
|
-
testID: `${_testIDs.ZUSTAND_TEST_ID}-search-clear`,
|
|
408
|
-
accessibilityRole: "button",
|
|
409
|
-
accessibilityLabel: "Close search",
|
|
410
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
|
|
411
|
-
size: 14,
|
|
412
|
-
color: _sharedUi.night.color.textSecondary
|
|
413
|
-
})
|
|
414
|
-
})]
|
|
382
|
+
children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Search, {
|
|
383
|
+
value: searchText,
|
|
384
|
+
onChangeText: handleSearch,
|
|
385
|
+
onCancel: closeSearch,
|
|
386
|
+
placeholder: activeTab === "stores" ? "Search stores..." : "Search events...",
|
|
387
|
+
accessibilityLabel: "Search Zustand stores and events",
|
|
388
|
+
iconSize: 14,
|
|
389
|
+
testID: `${_testIDs.ZUSTAND_TEST_ID}-search-field`,
|
|
390
|
+
containerTestID: `${_testIDs.ZUSTAND_TEST_ID}-search`,
|
|
391
|
+
clearTestID: `${_testIDs.ZUSTAND_TEST_ID}-search-clear`
|
|
392
|
+
// Stay open while the query is still narrowing the list: the
|
|
393
|
+
// header would otherwise go back to its TABS — whose counts are
|
|
394
|
+
// of the WHOLE capture — above a filtered list, with nothing to
|
|
395
|
+
// explain the gap.
|
|
396
|
+
,
|
|
397
|
+
onBlur: () => {
|
|
398
|
+
if (searchText.length === 0) setIsSearchActive(false);
|
|
399
|
+
}
|
|
415
400
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TabSelector, {
|
|
416
401
|
tabs: [{
|
|
417
402
|
key: "stores",
|
|
@@ -506,24 +491,25 @@ function ZustandModal({
|
|
|
506
491
|
keyExtractor: keyExtractor,
|
|
507
492
|
contentContainerStyle: styles.listContent,
|
|
508
493
|
showsVerticalScrollIndicator: true,
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
maxToRenderPerBatch: 8,
|
|
512
|
-
windowSize: 5,
|
|
513
|
-
updateCellsBatchingPeriod: 50
|
|
514
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
515
|
-
style: styles.emptyState,
|
|
494
|
+
..._sharedUi.EVENT_LIST_PRESET
|
|
495
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
516
496
|
testID: `${_testIDs.ZUSTAND_TEST_ID}-history-empty`,
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
497
|
+
...(0, _sharedUi.resolveListEmptyState)({
|
|
498
|
+
subject: "changes",
|
|
499
|
+
search: searchText,
|
|
500
|
+
// Scoped to one store, so the count is this store's, not the log's.
|
|
501
|
+
total: searchText.trim() ? scopedTotalForStore : 0,
|
|
502
|
+
capturing: isEnabled,
|
|
503
|
+
waiting: {
|
|
504
|
+
otto: "waiting",
|
|
505
|
+
title: "No history yet",
|
|
506
|
+
message: `State changes for ${selectedHistoryStore} will appear here.`
|
|
507
|
+
},
|
|
508
|
+
paused: {
|
|
509
|
+
title: "No history yet",
|
|
510
|
+
message: `Capture is off, so nothing is being recorded for ${selectedHistoryStore}.`
|
|
511
|
+
}
|
|
512
|
+
})
|
|
527
513
|
});
|
|
528
514
|
}
|
|
529
515
|
|
|
@@ -539,19 +525,15 @@ function ZustandModal({
|
|
|
539
525
|
/*#__PURE__*/
|
|
540
526
|
// The store fell out of the registry mid-look (a remote mirror
|
|
541
527
|
// rebuilding, a dev reload). Say so rather than rendering nothing.
|
|
542
|
-
(0, _jsxRuntime.
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
552
|
-
style: styles.emptyText,
|
|
553
|
-
children: [selectedStoreName, " is not in the registry any more."]
|
|
554
|
-
})]
|
|
528
|
+
(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
529
|
+
testID: `${_testIDs.ZUSTAND_TEST_ID}-store-detail-gone`
|
|
530
|
+
// ghost = "stale or detached: an unmounted component, an old
|
|
531
|
+
// snapshot" — exactly what the store you are looking at has become.
|
|
532
|
+
// No other tool has this cause, so it skips the resolver.
|
|
533
|
+
,
|
|
534
|
+
otto: "ghost",
|
|
535
|
+
title: "Store no longer registered",
|
|
536
|
+
message: `${selectedStoreName} is not in the registry any more.`
|
|
555
537
|
});
|
|
556
538
|
}
|
|
557
539
|
|
|
@@ -605,13 +587,11 @@ function ZustandModal({
|
|
|
605
587
|
keyExtractor: keyExtractor,
|
|
606
588
|
contentContainerStyle: styles.listContent,
|
|
607
589
|
showsVerticalScrollIndicator: true,
|
|
608
|
-
|
|
609
|
-
initialNumToRender: 12,
|
|
610
|
-
maxToRenderPerBatch: 8,
|
|
611
|
-
windowSize: 5,
|
|
612
|
-
updateCellsBatchingPeriod: 50
|
|
590
|
+
..._sharedUi.EVENT_LIST_PRESET
|
|
613
591
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EventsEmptyState, {
|
|
614
|
-
isEnabled: isEnabled
|
|
592
|
+
isEnabled: isEnabled,
|
|
593
|
+
searchText: searchText,
|
|
594
|
+
totalChanges: stats.totalChanges
|
|
615
595
|
})]
|
|
616
596
|
});
|
|
617
597
|
};
|
|
@@ -720,27 +700,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
720
700
|
// Transparent so JsModal's ToolBackground shows through (the modal paints opaque base beneath it).
|
|
721
701
|
backgroundColor: "transparent"
|
|
722
702
|
},
|
|
723
|
-
headerSearchContainer: {
|
|
724
|
-
flexDirection: "row",
|
|
725
|
-
alignItems: "center",
|
|
726
|
-
backgroundColor: _sharedUi.night.color.surfaceElevated,
|
|
727
|
-
borderRadius: _sharedUi.night.radius.row,
|
|
728
|
-
borderWidth: 1,
|
|
729
|
-
borderColor: _sharedUi.night.color.border,
|
|
730
|
-
paddingHorizontal: 12,
|
|
731
|
-
paddingVertical: 5
|
|
732
|
-
},
|
|
733
|
-
headerSearchInput: {
|
|
734
|
-
flex: 1,
|
|
735
|
-
color: _sharedUi.night.color.text,
|
|
736
|
-
fontSize: 13,
|
|
737
|
-
marginLeft: 6,
|
|
738
|
-
paddingVertical: 2
|
|
739
|
-
},
|
|
740
|
-
headerSearchClear: {
|
|
741
|
-
marginLeft: 6,
|
|
742
|
-
padding: 4
|
|
743
|
-
},
|
|
744
703
|
headerActionButton: {
|
|
745
704
|
width: 32,
|
|
746
705
|
height: 32,
|
|
@@ -779,23 +738,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
779
738
|
paddingTop: 8,
|
|
780
739
|
paddingBottom: 20
|
|
781
740
|
},
|
|
782
|
-
emptyState: {
|
|
783
|
-
alignItems: "center",
|
|
784
|
-
paddingVertical: 40
|
|
785
|
-
},
|
|
786
|
-
emptyTitle: {
|
|
787
|
-
color: _sharedUi.night.color.text,
|
|
788
|
-
fontSize: 14,
|
|
789
|
-
fontWeight: "600",
|
|
790
|
-
marginTop: 12,
|
|
791
|
-
marginBottom: 6
|
|
792
|
-
},
|
|
793
|
-
emptyText: {
|
|
794
|
-
color: _sharedUi.night.color.textTertiary,
|
|
795
|
-
fontSize: 12,
|
|
796
|
-
textAlign: "center",
|
|
797
|
-
lineHeight: 18
|
|
798
|
-
},
|
|
799
741
|
lockedBanner: {
|
|
800
742
|
flexDirection: "row",
|
|
801
743
|
alignItems: "center",
|
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.ZustandStateChangeItem = void 0;
|
|
7
7
|
var _react = require("react");
|
|
8
|
-
var _reactNative = require("react-native");
|
|
9
8
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
9
|
var _zustandStateStore = require("../utils/zustandStateStore");
|
|
11
10
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
@@ -103,68 +102,16 @@ const ZustandStateChangeItem = exports.ZustandStateChangeItem = /*#__PURE__*/(0,
|
|
|
103
102
|
const sublabel = getSublabel(change);
|
|
104
103
|
const primaryText = getPrimaryText(change);
|
|
105
104
|
const badgeText = getBadgeText(change);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// alternative — letting CompactRow draw `badgeText` itself — leaves the one
|
|
109
|
-
// row whose badge matters most (a set that changed NOTHING) as the only row
|
|
110
|
-
// in the list with no handle on its badge.
|
|
111
|
-
const customBadge = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
112
|
-
style: styles.badgeContainer,
|
|
113
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
114
|
-
style: [styles.badgeText, {
|
|
115
|
-
color: statusColor
|
|
116
|
-
}],
|
|
117
|
-
testID: testID ? `${testID}-badge` : undefined,
|
|
118
|
-
children: badgeText
|
|
119
|
-
}), change.isSlowUpdate ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
120
|
-
style: styles.slowBadge,
|
|
121
|
-
testID: testID ? `${testID}-slow` : undefined,
|
|
122
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
|
|
123
|
-
size: 12,
|
|
124
|
-
color: _sharedUi.buoyColors.error
|
|
125
|
-
})
|
|
126
|
-
}) : change.hasStateChange ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
127
|
-
style: styles.changeBadge,
|
|
128
|
-
testID: testID ? `${testID}-change` : undefined,
|
|
129
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
130
|
-
size: 12,
|
|
131
|
-
color: _sharedUi.buoyColors.warning
|
|
132
|
-
})
|
|
133
|
-
}) : null]
|
|
134
|
-
});
|
|
135
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
|
|
136
|
-
statusDotColor: statusColor,
|
|
105
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChangeRow, {
|
|
106
|
+
statusColor: statusColor,
|
|
137
107
|
statusLabel: statusLabel,
|
|
138
|
-
|
|
108
|
+
sublabel: sublabel,
|
|
139
109
|
primaryText: primaryText,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
badgeColor: statusColor,
|
|
145
|
-
showChevron: true,
|
|
110
|
+
timestamp: change.timestamp,
|
|
111
|
+
badgeText: badgeText,
|
|
112
|
+
changed: change.hasStateChange,
|
|
113
|
+
slow: change.isSlowUpdate,
|
|
146
114
|
onPress: () => onPress(change),
|
|
147
|
-
testID: testID
|
|
148
|
-
statusTestID: testID ? `${testID}-status` : undefined,
|
|
149
|
-
statusSublabelTestID: testID ? `${testID}-sublabel` : undefined,
|
|
150
|
-
primaryTestID: testID ? `${testID}-keys` : undefined
|
|
115
|
+
testID: testID
|
|
151
116
|
});
|
|
152
|
-
});
|
|
153
|
-
const styles = _reactNative.StyleSheet.create({
|
|
154
|
-
badgeContainer: {
|
|
155
|
-
flexDirection: "row",
|
|
156
|
-
alignItems: "center",
|
|
157
|
-
gap: 4
|
|
158
|
-
},
|
|
159
|
-
badgeText: {
|
|
160
|
-
fontSize: 11,
|
|
161
|
-
fontWeight: "600",
|
|
162
|
-
fontFamily: "monospace"
|
|
163
|
-
},
|
|
164
|
-
changeBadge: {
|
|
165
|
-
paddingHorizontal: 4
|
|
166
|
-
},
|
|
167
|
-
slowBadge: {
|
|
168
|
-
paddingHorizontal: 4
|
|
169
|
-
}
|
|
170
117
|
});
|
|
@@ -79,29 +79,6 @@ function SectionHeader({
|
|
|
79
79
|
}), badge]
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
function InfoRow({
|
|
83
|
-
label,
|
|
84
|
-
value,
|
|
85
|
-
valueColor,
|
|
86
|
-
mono = false,
|
|
87
|
-
testID
|
|
88
|
-
}) {
|
|
89
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
90
|
-
style: styles.infoRow,
|
|
91
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
92
|
-
style: styles.infoLabel,
|
|
93
|
-
children: label
|
|
94
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
95
|
-
testID: testID,
|
|
96
|
-
style: [styles.infoValue, mono && styles.infoValueMono, valueColor ? {
|
|
97
|
-
color: valueColor
|
|
98
|
-
} : undefined],
|
|
99
|
-
numberOfLines: 1,
|
|
100
|
-
ellipsizeMode: "middle",
|
|
101
|
-
children: value
|
|
102
|
-
})]
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
82
|
function formatTime(timestamp) {
|
|
106
83
|
const date = new Date(timestamp);
|
|
107
84
|
const hours = date.getHours().toString().padStart(2, "0");
|
|
@@ -157,13 +134,13 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
|
|
|
157
134
|
title: "CHANGE INFO"
|
|
158
135
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
159
136
|
style: styles.cardContent,
|
|
160
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, {
|
|
137
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.InfoRow, {
|
|
161
138
|
label: "Store",
|
|
162
139
|
value: change.storeName,
|
|
163
140
|
mono: true,
|
|
164
141
|
valueColor: storeColor,
|
|
165
142
|
testID: `${_testIDs.ZUSTAND_TEST_ID}-info-store`
|
|
166
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, {
|
|
143
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.InfoRow, {
|
|
167
144
|
label: "Time",
|
|
168
145
|
value: formatTime(change.timestamp),
|
|
169
146
|
mono: true,
|
|
@@ -366,27 +343,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
366
343
|
padding: 14,
|
|
367
344
|
gap: 10
|
|
368
345
|
},
|
|
369
|
-
infoRow: {
|
|
370
|
-
flexDirection: "row",
|
|
371
|
-
alignItems: "center",
|
|
372
|
-
justifyContent: "space-between"
|
|
373
|
-
},
|
|
374
|
-
infoLabel: {
|
|
375
|
-
fontSize: 11,
|
|
376
|
-
color: _sharedUi.night.color.textTertiary,
|
|
377
|
-
fontWeight: "500"
|
|
378
|
-
},
|
|
379
|
-
infoValue: {
|
|
380
|
-
fontSize: 11,
|
|
381
|
-
color: _sharedUi.night.color.text,
|
|
382
|
-
fontWeight: "500",
|
|
383
|
-
flex: 1,
|
|
384
|
-
textAlign: "right",
|
|
385
|
-
marginLeft: 12
|
|
386
|
-
},
|
|
387
|
-
infoValueMono: {
|
|
388
|
-
fontFamily: "monospace"
|
|
389
|
-
},
|
|
390
346
|
badgeRow: {
|
|
391
347
|
flexDirection: "row",
|
|
392
348
|
flexWrap: "wrap",
|
|
@@ -44,36 +44,26 @@ function getKeysPreview(store) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
function LoadingBrowserState() {
|
|
47
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
57
|
-
style: styles.emptyText,
|
|
58
|
-
children: "Waiting for the device to send its registered stores."
|
|
59
|
-
})]
|
|
47
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
48
|
+
testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-loading`
|
|
49
|
+
// Replaces the spinner rather than joining it: two animated things
|
|
50
|
+
// stacked is clutter, and `loading` IS the indeterminate spinner in
|
|
51
|
+
// mascot form.
|
|
52
|
+
,
|
|
53
|
+
otto: "loading",
|
|
54
|
+
title: "Loading stores\u2026",
|
|
55
|
+
message: "Waiting for the device to send its registered stores."
|
|
60
56
|
});
|
|
61
57
|
}
|
|
62
58
|
function EmptyBrowserState() {
|
|
63
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-empty-title`,
|
|
72
|
-
children: "No stores registered"
|
|
73
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
74
|
-
style: styles.emptyText,
|
|
75
|
-
children: "Use watchStores() to register your Zustand stores.\nThey will appear here with their current state."
|
|
76
|
-
})]
|
|
59
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
60
|
+
testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-empty`
|
|
61
|
+
// scanning = "scanning for targets… and finding none". The registry is
|
|
62
|
+
// discovered, not configured, so an empty one is a scan result.
|
|
63
|
+
,
|
|
64
|
+
otto: "scanning",
|
|
65
|
+
title: "No stores registered",
|
|
66
|
+
message: "Use watchStores() to register your Zustand stores.\nThey will appear here with their current state."
|
|
77
67
|
});
|
|
78
68
|
}
|
|
79
69
|
function ZustandStoreBrowser({
|
|
@@ -92,17 +82,19 @@ function ZustandStoreBrowser({
|
|
|
92
82
|
return isLoading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LoadingBrowserState, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyBrowserState, {});
|
|
93
83
|
}
|
|
94
84
|
if (filteredStores.length === 0 && searchQuery) {
|
|
95
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
96
|
-
style: styles.emptyState,
|
|
85
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
|
|
97
86
|
testID: `${_testIDs.ZUSTAND_TEST_ID}-stores-no-match`,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
87
|
+
...(0, _sharedUi.resolveListEmptyState)({
|
|
88
|
+
subject: "stores",
|
|
89
|
+
verb: "registered",
|
|
90
|
+
search: searchQuery,
|
|
91
|
+
total: stores.length,
|
|
92
|
+
waiting: {
|
|
93
|
+
otto: "scanning",
|
|
94
|
+
title: "No stores registered",
|
|
95
|
+
message: "Use watchStores() to register your Zustand stores."
|
|
96
|
+
}
|
|
97
|
+
})
|
|
106
98
|
});
|
|
107
99
|
}
|
|
108
100
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
@@ -208,22 +200,5 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
208
200
|
fontWeight: "700",
|
|
209
201
|
color: _sharedUi.night.color.accent,
|
|
210
202
|
fontFamily: "monospace"
|
|
211
|
-
},
|
|
212
|
-
emptyState: {
|
|
213
|
-
alignItems: "center",
|
|
214
|
-
paddingVertical: 40
|
|
215
|
-
},
|
|
216
|
-
emptyTitle: {
|
|
217
|
-
color: _sharedUi.night.color.text,
|
|
218
|
-
fontSize: 14,
|
|
219
|
-
fontWeight: "600",
|
|
220
|
-
marginTop: 12,
|
|
221
|
-
marginBottom: 6
|
|
222
|
-
},
|
|
223
|
-
emptyText: {
|
|
224
|
-
color: _sharedUi.night.color.textTertiary,
|
|
225
|
-
fontSize: 12,
|
|
226
|
-
textAlign: "center",
|
|
227
|
-
lineHeight: 18
|
|
228
203
|
}
|
|
229
204
|
});
|