@buoy-gg/jotai 7.0.30 → 7.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +30 -119
- package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +19 -7
- package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +41 -5
- package/lib/commonjs/jotai/components/JotaiAtomValueDetailContent.js +444 -0
- package/lib/commonjs/jotai/components/JotaiEventFilterView.js +15 -0
- package/lib/commonjs/jotai/components/JotaiModal.js +159 -23
- package/lib/commonjs/jotai/utils/jotaiStateStore.js +9 -4
- package/lib/commonjs/jotai/utils/testIDs.js +90 -0
- package/lib/commonjs/jotai/utils/watchAtoms.js +8 -2
- package/lib/commonjs/jotai/utils/writeSemantics.js +47 -0
- package/lib/module/index.js +1 -0
- package/lib/module/jotai/components/JotaiAtomBrowser.js +33 -122
- package/lib/module/jotai/components/JotaiAtomChangeItem.js +19 -7
- package/lib/module/jotai/components/JotaiAtomDetailContent.js +41 -5
- package/lib/module/jotai/components/JotaiAtomValueDetailContent.js +442 -0
- package/lib/module/jotai/components/JotaiEventFilterView.js +15 -0
- package/lib/module/jotai/components/JotaiModal.js +160 -24
- package/lib/module/jotai/utils/jotaiStateStore.js +9 -4
- package/lib/module/jotai/utils/testIDs.js +82 -0
- package/lib/module/jotai/utils/watchAtoms.js +8 -2
- package/lib/module/jotai/utils/writeSemantics.js +43 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts +6 -5
- package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +1 -1
- package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts +5 -0
- package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +1 -1
- package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +1 -1
- package/lib/typescript/jotai/components/JotaiAtomValueDetailContent.d.ts +40 -0
- package/lib/typescript/jotai/components/JotaiAtomValueDetailContent.d.ts.map +1 -0
- package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +1 -1
- package/lib/typescript/jotai/components/JotaiModal.d.ts.map +1 -1
- package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts +1 -0
- package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/jotai/types/index.d.ts +12 -0
- package/lib/typescript/jotai/types/index.d.ts.map +1 -1
- package/lib/typescript/jotai/utils/jotaiStateStore.d.ts +1 -1
- package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +1 -1
- package/lib/typescript/jotai/utils/testIDs.d.ts +62 -0
- package/lib/typescript/jotai/utils/testIDs.d.ts.map +1 -0
- package/lib/typescript/jotai/utils/watchAtoms.d.ts +8 -2
- package/lib/typescript/jotai/utils/watchAtoms.d.ts.map +1 -1
- package/lib/typescript/jotai/utils/writeSemantics.d.ts +25 -0
- package/lib/typescript/jotai/utils/writeSemantics.d.ts.map +1 -0
- package/package.json +3 -3
package/lib/commonjs/index.js
CHANGED
|
@@ -27,6 +27,12 @@ Object.defineProperty(exports, "JotaiAtomDetailFooter", {
|
|
|
27
27
|
return _JotaiAtomDetailContent.JotaiAtomDetailFooter;
|
|
28
28
|
}
|
|
29
29
|
});
|
|
30
|
+
Object.defineProperty(exports, "JotaiAtomValueDetailContent", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _JotaiAtomValueDetailContent.JotaiAtomValueDetailContent;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
30
36
|
Object.defineProperty(exports, "JotaiIcon", {
|
|
31
37
|
enumerable: true,
|
|
32
38
|
get: function () {
|
|
@@ -100,6 +106,7 @@ var _useJotaiAtomChanges = require("./jotai/hooks/useJotaiAtomChanges");
|
|
|
100
106
|
var _JotaiModal = require("./jotai/components/JotaiModal");
|
|
101
107
|
var _JotaiAtomChangeItem = require("./jotai/components/JotaiAtomChangeItem");
|
|
102
108
|
var _JotaiAtomDetailContent = require("./jotai/components/JotaiAtomDetailContent");
|
|
109
|
+
var _JotaiAtomValueDetailContent = require("./jotai/components/JotaiAtomValueDetailContent");
|
|
103
110
|
var _JotaiIcon = require("./jotai/components/JotaiIcon");
|
|
104
111
|
var _jotaiSyncAdapter = require("./jotai/sync/jotaiSyncAdapter");
|
|
105
112
|
var _jotaiStateStore = require("./jotai/utils/jotaiStateStore");
|
|
@@ -7,14 +7,16 @@ exports.JotaiAtomBrowser = JotaiAtomBrowser;
|
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
-
var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
|
|
11
10
|
var _jotaiStateStore = require("../utils/jotaiStateStore");
|
|
11
|
+
var _testIDs = require("../utils/testIDs");
|
|
12
12
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
13
|
/**
|
|
14
14
|
* JotaiAtomBrowser
|
|
15
15
|
*
|
|
16
16
|
* Atoms tab — shows all registered Jotai atoms and their current value.
|
|
17
|
-
* Mirrors ZustandStoreBrowser.tsx from @buoy-gg/zustand
|
|
17
|
+
* Mirrors ZustandStoreBrowser.tsx from @buoy-gg/zustand: tapping a card
|
|
18
|
+
* NAVIGATES to the atom's detail screen (live editor + details + read-only
|
|
19
|
+
* tree) rather than expanding in place — the modal owns that selection.
|
|
18
20
|
*/
|
|
19
21
|
|
|
20
22
|
function getValuePreview(atom) {
|
|
@@ -40,84 +42,26 @@ function getValuePreview(atom) {
|
|
|
40
42
|
return "";
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function AtomExpandedContent({
|
|
55
|
-
atom,
|
|
56
|
-
onViewHistory
|
|
57
|
-
}) {
|
|
58
|
-
const value = atom.getValue();
|
|
59
|
-
const displayValue = (0, _react.useMemo)(() => {
|
|
60
|
-
if (value && typeof value === "object") {
|
|
61
|
-
const filtered = {};
|
|
62
|
-
for (const [key, v] of Object.entries(value)) {
|
|
63
|
-
if (typeof v !== "function") filtered[key] = v;
|
|
64
|
-
}
|
|
65
|
-
return (0, _sharedUi.parseValue)(filtered);
|
|
66
|
-
}
|
|
67
|
-
return (0, _sharedUi.parseValue)(value);
|
|
68
|
-
}, [value]);
|
|
69
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
70
|
-
style: expandedStyles.container,
|
|
71
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ExpandedInfoRow, {
|
|
72
|
-
label: "Type",
|
|
73
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
74
|
-
color: atom.color,
|
|
75
|
-
children: "JOTAI"
|
|
76
|
-
})
|
|
77
|
-
}), atom.changeCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ExpandedInfoRow, {
|
|
78
|
-
label: "Changes",
|
|
79
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
80
|
-
color: _sharedUi.buoyColors.warning,
|
|
81
|
-
children: String(atom.changeCount)
|
|
82
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
83
|
-
onPress: () => onViewHistory(atom.label),
|
|
84
|
-
style: expandedStyles.viewHistoryButton,
|
|
85
|
-
hitSlop: {
|
|
86
|
-
top: 6,
|
|
87
|
-
bottom: 6,
|
|
88
|
-
left: 6,
|
|
89
|
-
right: 6
|
|
90
|
-
},
|
|
91
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
92
|
-
style: [expandedStyles.viewHistoryText, {
|
|
93
|
-
color: atom.color
|
|
94
|
-
}],
|
|
95
|
-
children: "view history \u2192"
|
|
96
|
-
})
|
|
97
|
-
})]
|
|
98
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
99
|
-
style: expandedStyles.dataContainer,
|
|
100
|
-
children: displayValue && typeof displayValue === "object" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
|
|
101
|
-
title: "",
|
|
102
|
-
data: displayValue,
|
|
103
|
-
showTypeFilter: true,
|
|
104
|
-
rawMode: true,
|
|
105
|
-
initialExpanded: true
|
|
106
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
107
|
-
style: expandedStyles.primitiveText,
|
|
108
|
-
children: String(value ?? "undefined")
|
|
109
|
-
})
|
|
110
|
-
})]
|
|
111
|
-
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The card's categorical slot — the atom's write story, mirroring the
|
|
48
|
+
* zustand card's "persisted"/"in-memory" backing label.
|
|
49
|
+
*/
|
|
50
|
+
function getWriteKindLabel(atom) {
|
|
51
|
+
if (atom.writeKind === "value") return "primitive";
|
|
52
|
+
if (atom.writeKind === "action") return "custom write";
|
|
53
|
+
return atom.setValue ? "writable" : "derived";
|
|
112
54
|
}
|
|
113
55
|
function EmptyBrowserState() {
|
|
114
56
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
115
57
|
style: styles.emptyState,
|
|
58
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-empty`,
|
|
116
59
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Box, {
|
|
117
60
|
size: 32,
|
|
118
61
|
color: _sharedUi.night.color.textTertiary
|
|
119
62
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
120
63
|
style: styles.emptyTitle,
|
|
64
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-empty-title`,
|
|
121
65
|
children: "No atoms registered"
|
|
122
66
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
123
67
|
style: styles.emptyText,
|
|
@@ -128,30 +72,23 @@ function EmptyBrowserState() {
|
|
|
128
72
|
function JotaiAtomBrowser({
|
|
129
73
|
atoms,
|
|
130
74
|
searchQuery,
|
|
131
|
-
|
|
132
|
-
onAtomExpand
|
|
75
|
+
onOpenAtom
|
|
133
76
|
}) {
|
|
134
|
-
const [expandedAtom, setExpandedAtom] = (0, _react.useState)(null);
|
|
135
77
|
const filteredAtoms = (0, _react.useMemo)(() => {
|
|
136
78
|
if (!searchQuery) return atoms;
|
|
137
79
|
const search = searchQuery.toLowerCase();
|
|
138
80
|
return atoms.filter(a => a.label.toLowerCase().includes(search));
|
|
139
81
|
}, [atoms, searchQuery]);
|
|
140
|
-
const handleAtomPress = (0, _react.useCallback)(atom => {
|
|
141
|
-
setExpandedAtom(prev => {
|
|
142
|
-
const next = prev === atom.label ? null : atom.label;
|
|
143
|
-
if (next) onAtomExpand?.(atom.label);
|
|
144
|
-
return next;
|
|
145
|
-
});
|
|
146
|
-
}, [onAtomExpand]);
|
|
147
82
|
if (filteredAtoms.length === 0 && !searchQuery) {
|
|
148
83
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyBrowserState, {});
|
|
149
84
|
}
|
|
150
85
|
if (filteredAtoms.length === 0 && searchQuery) {
|
|
151
86
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
152
87
|
style: styles.emptyState,
|
|
88
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-no-match`,
|
|
153
89
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
154
90
|
style: styles.emptyTitle,
|
|
91
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-no-match-title`,
|
|
155
92
|
children: "No matching atoms"
|
|
156
93
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
157
94
|
style: styles.emptyText,
|
|
@@ -163,6 +100,7 @@ function JotaiAtomBrowser({
|
|
|
163
100
|
style: styles.container,
|
|
164
101
|
contentContainerStyle: styles.scrollContent,
|
|
165
102
|
showsVerticalScrollIndicator: true,
|
|
103
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-scroll`,
|
|
166
104
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
167
105
|
style: styles.sectionHeader,
|
|
168
106
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -172,27 +110,27 @@ function JotaiAtomBrowser({
|
|
|
172
110
|
style: styles.sectionCountBadge,
|
|
173
111
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
174
112
|
style: styles.sectionCountText,
|
|
113
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-atoms-count`,
|
|
175
114
|
children: filteredAtoms.length
|
|
176
115
|
})
|
|
177
116
|
})]
|
|
178
117
|
}), filteredAtoms.map(atom => {
|
|
179
|
-
const isExpanded = expandedAtom === atom.label;
|
|
180
118
|
const valuePreview = getValuePreview(atom);
|
|
181
119
|
const atomColor = _jotaiStateStore.jotaiStateStore.getAtomColor(atom.label);
|
|
120
|
+
const rowID = (0, _testIDs.atomRowTestID)(atom.label);
|
|
182
121
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
183
122
|
style: styles.atomRowWrapper,
|
|
184
123
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
|
|
185
124
|
statusDotColor: atomColor,
|
|
186
|
-
statusLabel: atom
|
|
187
|
-
|
|
188
|
-
|
|
125
|
+
statusLabel: getWriteKindLabel(atom),
|
|
126
|
+
primaryText: atom.label,
|
|
127
|
+
secondaryText: valuePreview || undefined,
|
|
189
128
|
showChevron: true,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}) : undefined
|
|
129
|
+
onPress: () => onOpenAtom(atom.label),
|
|
130
|
+
testID: rowID,
|
|
131
|
+
statusTestID: `${rowID}-kind`,
|
|
132
|
+
primaryTestID: `${rowID}-name`,
|
|
133
|
+
secondaryTestID: `${rowID}-preview`
|
|
196
134
|
}), atom.changeCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
197
135
|
style: [styles.absCountBadge, {
|
|
198
136
|
backgroundColor: atomColor + "22",
|
|
@@ -203,6 +141,7 @@ function JotaiAtomBrowser({
|
|
|
203
141
|
style: [styles.absCountText, {
|
|
204
142
|
color: atomColor
|
|
205
143
|
}],
|
|
144
|
+
testID: `${rowID}-count`,
|
|
206
145
|
children: String(atom.changeCount)
|
|
207
146
|
})
|
|
208
147
|
})]
|
|
@@ -278,32 +217,4 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
278
217
|
textAlign: "center",
|
|
279
218
|
lineHeight: 18
|
|
280
219
|
}
|
|
281
|
-
});
|
|
282
|
-
const expandedStyles = _reactNative.StyleSheet.create({
|
|
283
|
-
container: {
|
|
284
|
-
gap: 10
|
|
285
|
-
},
|
|
286
|
-
viewHistoryButton: {
|
|
287
|
-
marginLeft: 4
|
|
288
|
-
},
|
|
289
|
-
viewHistoryText: {
|
|
290
|
-
fontSize: 10,
|
|
291
|
-
fontWeight: "600",
|
|
292
|
-
fontFamily: "monospace"
|
|
293
|
-
},
|
|
294
|
-
dataContainer: {
|
|
295
|
-
// Inset display panel — darker than the card, the night track color.
|
|
296
|
-
backgroundColor: _sharedUi.night.color.bg,
|
|
297
|
-
borderRadius: 6,
|
|
298
|
-
borderWidth: 1,
|
|
299
|
-
borderColor: _sharedUi.night.color.border,
|
|
300
|
-
overflow: "hidden",
|
|
301
|
-
minHeight: 60
|
|
302
|
-
},
|
|
303
|
-
primitiveText: {
|
|
304
|
-
color: _sharedUi.night.color.text,
|
|
305
|
-
fontSize: 12,
|
|
306
|
-
fontFamily: "monospace",
|
|
307
|
-
padding: 14
|
|
308
|
-
}
|
|
309
220
|
});
|
|
@@ -64,28 +64,37 @@ function getPrimaryText(change) {
|
|
|
64
64
|
// ZustandStateChangeItem (same pattern).
|
|
65
65
|
const JotaiAtomChangeItem = exports.JotaiAtomChangeItem = /*#__PURE__*/(0, _react.memo)(function JotaiAtomChangeItem({
|
|
66
66
|
change,
|
|
67
|
-
onPress
|
|
67
|
+
onPress,
|
|
68
|
+
testID
|
|
68
69
|
}) {
|
|
69
70
|
const statusColor = getCategoryColor(change.category, change.atomLabel);
|
|
70
71
|
const statusLabel = getStatusLabel(change.category, change.atomLabel);
|
|
71
72
|
const sublabel = getSublabel(change);
|
|
72
73
|
const primaryText = getPrimaryText(change);
|
|
73
74
|
const badgeText = getBadgeText(change);
|
|
74
|
-
|
|
75
|
+
|
|
76
|
+
// Always a custom badge, even when there is no icon to hang off it. The
|
|
77
|
+
// alternative — letting CompactRow draw `badgeText` itself — leaves the one
|
|
78
|
+
// row whose badge matters most (a write that moved the atom's identity but
|
|
79
|
+
// none of its contents) as the only row in the list with no handle on its
|
|
80
|
+
// badge. Same call, and the same reason, as ZustandStateChangeItem.
|
|
81
|
+
const customBadge = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
75
82
|
style: styles.badgeContainer,
|
|
76
83
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
77
84
|
style: [styles.badgeText, {
|
|
78
85
|
color: statusColor
|
|
79
86
|
}],
|
|
87
|
+
testID: testID ? `${testID}-badge` : undefined,
|
|
80
88
|
children: badgeText
|
|
81
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
89
|
+
}), change.hasValueChange ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
82
90
|
style: styles.changeBadge,
|
|
91
|
+
testID: testID ? `${testID}-change` : undefined,
|
|
83
92
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
84
93
|
size: 12,
|
|
85
94
|
color: _sharedUi.buoyColors.warning
|
|
86
95
|
})
|
|
87
|
-
})]
|
|
88
|
-
})
|
|
96
|
+
}) : null]
|
|
97
|
+
});
|
|
89
98
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
|
|
90
99
|
statusDotColor: statusColor,
|
|
91
100
|
statusLabel: statusLabel,
|
|
@@ -95,10 +104,13 @@ const JotaiAtomChangeItem = exports.JotaiAtomChangeItem = /*#__PURE__*/(0, _reac
|
|
|
95
104
|
timestamp: change.timestamp
|
|
96
105
|
}),
|
|
97
106
|
customBadge: customBadge,
|
|
98
|
-
badgeText: customBadge ? undefined : badgeText,
|
|
99
107
|
badgeColor: statusColor,
|
|
100
108
|
showChevron: true,
|
|
101
|
-
onPress: () => onPress(change)
|
|
109
|
+
onPress: () => onPress(change),
|
|
110
|
+
testID: testID,
|
|
111
|
+
statusTestID: testID ? `${testID}-status` : undefined,
|
|
112
|
+
statusSublabelTestID: testID ? `${testID}-sublabel` : undefined,
|
|
113
|
+
primaryTestID: testID ? `${testID}-keys` : undefined
|
|
102
114
|
});
|
|
103
115
|
});
|
|
104
116
|
const styles = _reactNative.StyleSheet.create({
|
|
@@ -11,6 +11,7 @@ var _sharedUi = require("@buoy-gg/shared-ui");
|
|
|
11
11
|
var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
|
|
12
12
|
var _license = require("@buoy-gg/license");
|
|
13
13
|
var _jotaiStateStore = require("../utils/jotaiStateStore");
|
|
14
|
+
var _testIDs = require("../utils/testIDs");
|
|
14
15
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
16
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
16
17
|
/**
|
|
@@ -58,6 +59,13 @@ function DetailViewToggle({
|
|
|
58
59
|
}], isDisabled && toggleStyles.cardDisabled],
|
|
59
60
|
onPress: () => !isDisabled && onViewChange(config.key),
|
|
60
61
|
activeOpacity: 0.7,
|
|
62
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-view-${config.key}`,
|
|
63
|
+
accessibilityRole: "button",
|
|
64
|
+
accessibilityLabel: config.label,
|
|
65
|
+
accessibilityState: {
|
|
66
|
+
disabled: isDisabled,
|
|
67
|
+
selected: isActive
|
|
68
|
+
},
|
|
61
69
|
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
62
70
|
style: toggleStyles.cardContent,
|
|
63
71
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(IconComponent, {
|
|
@@ -148,8 +156,10 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
148
156
|
style: infoStyles.container,
|
|
149
157
|
contentContainerStyle: infoStyles.content,
|
|
150
158
|
showsVerticalScrollIndicator: false,
|
|
159
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-detail-scroll`,
|
|
151
160
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
152
161
|
style: infoStyles.card,
|
|
162
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-info-card`,
|
|
153
163
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
154
164
|
style: infoStyles.sectionHeader,
|
|
155
165
|
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -175,6 +185,7 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
175
185
|
}],
|
|
176
186
|
numberOfLines: 1,
|
|
177
187
|
ellipsizeMode: "middle",
|
|
188
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-info-atom`,
|
|
178
189
|
children: change.atomLabel
|
|
179
190
|
})]
|
|
180
191
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -184,6 +195,7 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
184
195
|
children: "Time"
|
|
185
196
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
186
197
|
style: [infoStyles.infoValue, infoStyles.infoValueMono],
|
|
198
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-info-time`,
|
|
187
199
|
children: formatTime(change.timestamp)
|
|
188
200
|
})]
|
|
189
201
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -196,6 +208,7 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
196
208
|
style: [infoStyles.categoryText, {
|
|
197
209
|
color: categoryInfo.color
|
|
198
210
|
}],
|
|
211
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-info-category`,
|
|
199
212
|
children: categoryInfo.label
|
|
200
213
|
})
|
|
201
214
|
}), change.hasValueChange ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -205,12 +218,14 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
205
218
|
color: _sharedUi.buoyColors.success
|
|
206
219
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
207
220
|
style: infoStyles.changesText,
|
|
221
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-info-changes`,
|
|
208
222
|
children: change.diffSummary || "changed"
|
|
209
223
|
})]
|
|
210
224
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
211
225
|
style: infoStyles.noChangesBadge,
|
|
212
226
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
213
227
|
style: infoStyles.noChangesText,
|
|
228
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-info-no-changes`,
|
|
214
229
|
children: "no change"
|
|
215
230
|
})
|
|
216
231
|
})]
|
|
@@ -218,6 +233,7 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
218
233
|
})]
|
|
219
234
|
}), change.changedKeys.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
220
235
|
style: infoStyles.card,
|
|
236
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-keys-card`,
|
|
221
237
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
222
238
|
style: infoStyles.sectionHeader,
|
|
223
239
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -233,6 +249,7 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
233
249
|
style: infoStyles.countBadge,
|
|
234
250
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
235
251
|
style: infoStyles.countText,
|
|
252
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-keys-count`,
|
|
236
253
|
children: change.changedKeys.length
|
|
237
254
|
})
|
|
238
255
|
})]
|
|
@@ -244,6 +261,7 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
244
261
|
style: infoStyles.keyBadge,
|
|
245
262
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
246
263
|
style: infoStyles.keyText,
|
|
264
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-key-${(0, _testIDs.slugForTestID)(key)}`,
|
|
247
265
|
children: key
|
|
248
266
|
})
|
|
249
267
|
}, key))
|
|
@@ -254,6 +272,9 @@ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoVi
|
|
|
254
272
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
255
273
|
style: [infoStyles.actionButton, infoStyles.actionButtonCopy],
|
|
256
274
|
onTouchEnd: handleCopyValue,
|
|
275
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-copy-value`,
|
|
276
|
+
accessibilityRole: "button",
|
|
277
|
+
accessibilityLabel: "Copy value",
|
|
257
278
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
258
279
|
style: [infoStyles.actionButtonText, {
|
|
259
280
|
color: _sharedUi.night.color.accent
|
|
@@ -328,6 +349,7 @@ function JotaiAtomDetailContent({
|
|
|
328
349
|
const parsed = (0, _sharedUi.parseValue)(change.nextValue);
|
|
329
350
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
330
351
|
style: styles.contentCard,
|
|
352
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-value-card`,
|
|
331
353
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
332
354
|
style: styles.valueHeader,
|
|
333
355
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -349,6 +371,7 @@ function JotaiAtomDetailContent({
|
|
|
349
371
|
style: styles.typeBadge,
|
|
350
372
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
351
373
|
style: styles.typeText,
|
|
374
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-value-type`,
|
|
352
375
|
children: valueType.toUpperCase()
|
|
353
376
|
})
|
|
354
377
|
})]
|
|
@@ -400,7 +423,13 @@ function JotaiAtomDetailContent({
|
|
|
400
423
|
const handleFooterNext = (0, _react.useCallback)(() => {
|
|
401
424
|
onIndexChange(Math.max(0, selectedIndex - 1));
|
|
402
425
|
}, [selectedIndex, onIndexChange]);
|
|
403
|
-
|
|
426
|
+
|
|
427
|
+
// The diff compares THIS change's prevValue/nextValue — no siblings needed.
|
|
428
|
+
// Gating on `changes.length` greyed DIFF out for every jotai event opened
|
|
429
|
+
// from the Events timeline (a one-element array). Only a change with no
|
|
430
|
+
// captured previous value has nothing to compare.
|
|
431
|
+
const diffDisabled = change.prevValue === undefined;
|
|
432
|
+
const showInternalFooter = !disableInternalFooter && totalChanges > 1;
|
|
404
433
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
405
434
|
style: styles.container,
|
|
406
435
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(DetailViewToggle, {
|
|
@@ -408,7 +437,7 @@ function JotaiAtomDetailContent({
|
|
|
408
437
|
onViewChange: setActiveView,
|
|
409
438
|
diffDisabled: diffDisabled
|
|
410
439
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
411
|
-
style: styles.contentArea,
|
|
440
|
+
style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
|
|
412
441
|
children: [activeView === "change" && /*#__PURE__*/(0, _jsxRuntime.jsx)(JotaiAtomInfoView, {
|
|
413
442
|
change: change
|
|
414
443
|
}), activeView === "value" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
@@ -416,19 +445,22 @@ function JotaiAtomDetailContent({
|
|
|
416
445
|
children: renderValueView()
|
|
417
446
|
}), activeView === "diff" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
418
447
|
style: styles.diffContainer,
|
|
448
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-diff`,
|
|
419
449
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.DiffModeTabs, {
|
|
420
450
|
tabs: DIFF_MODE_TABS,
|
|
421
451
|
activeTab: diffMode,
|
|
422
|
-
onTabChange: setDiffMode
|
|
452
|
+
onTabChange: setDiffMode,
|
|
453
|
+
testIDPrefix: `${_testIDs.JOTAI_TEST_ID}-diff-tab`
|
|
423
454
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompareBar, {
|
|
424
455
|
leftEvent: leftEvent,
|
|
425
456
|
rightEvent: rightEvent
|
|
426
457
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
427
458
|
style: styles.diffContent,
|
|
459
|
+
testID: `${_testIDs.JOTAI_TEST_ID}-diff-content`,
|
|
428
460
|
children: renderDiffContent()
|
|
429
461
|
})]
|
|
430
462
|
})]
|
|
431
|
-
}),
|
|
463
|
+
}), showInternalFooter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
|
|
432
464
|
currentIndex: chronologicalNumber - 1,
|
|
433
465
|
totalItems: totalChanges,
|
|
434
466
|
onPrevious: handleFooterPrevious,
|
|
@@ -464,7 +496,11 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
464
496
|
backgroundColor: "transparent"
|
|
465
497
|
},
|
|
466
498
|
contentArea: {
|
|
467
|
-
flex: 1
|
|
499
|
+
flex: 1
|
|
500
|
+
},
|
|
501
|
+
// Clearance for the absolute EventStepperFooter — only when it renders,
|
|
502
|
+
// otherwise hosts like the Events tool get a dead band at the sheet bottom.
|
|
503
|
+
contentAreaFooterPad: {
|
|
468
504
|
paddingBottom: 96
|
|
469
505
|
},
|
|
470
506
|
stateContainer: {
|