@buoy-gg/jotai 7.0.40 → 7.0.42
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/README.md +11 -76
- package/lib/commonjs/index.js +1 -112
- package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +1 -199
- package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +1 -85
- package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +1 -715
- package/lib/commonjs/jotai/components/JotaiAtomValueDetailContent.js +1 -444
- package/lib/commonjs/jotai/components/JotaiEventFilterView.js +1 -43
- package/lib/commonjs/jotai/components/JotaiIcon.js +1 -18
- package/lib/commonjs/jotai/components/JotaiModal.js +1 -743
- package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +1 -69
- package/lib/commonjs/jotai/sync/jotaiSyncAdapter.js +1 -306
- package/lib/commonjs/jotai/types/index.js +1 -1
- package/lib/commonjs/jotai/utils/jotaiStateStore.js +1 -321
- package/lib/commonjs/jotai/utils/snapshotProvider.js +1 -215
- package/lib/commonjs/jotai/utils/testIDs.js +1 -90
- package/lib/commonjs/jotai/utils/watchAtoms.js +1 -162
- package/lib/commonjs/jotai/utils/writeSemantics.js +1 -47
- package/lib/commonjs/preset.js +1 -90
- package/lib/module/index.js +1 -85
- package/lib/module/jotai/components/JotaiAtomBrowser.js +1 -195
- package/lib/module/jotai/components/JotaiAtomChangeItem.js +1 -81
- package/lib/module/jotai/components/JotaiAtomDetailContent.js +1 -710
- package/lib/module/jotai/components/JotaiAtomValueDetailContent.js +1 -442
- package/lib/module/jotai/components/JotaiEventFilterView.js +1 -39
- package/lib/module/jotai/components/JotaiIcon.js +1 -11
- package/lib/module/jotai/components/JotaiModal.js +1 -738
- package/lib/module/jotai/hooks/useJotaiAtomChanges.js +1 -65
- package/lib/module/jotai/sync/jotaiSyncAdapter.js +1 -303
- package/lib/module/jotai/types/index.js +1 -1
- package/lib/module/jotai/utils/jotaiStateStore.js +1 -317
- package/lib/module/jotai/utils/snapshotProvider.js +1 -214
- package/lib/module/jotai/utils/testIDs.js +1 -82
- package/lib/module/jotai/utils/watchAtoms.js +1 -157
- package/lib/module/jotai/utils/writeSemantics.js +1 -43
- package/lib/module/preset.js +1 -87
- package/lib/web/index.mjs +2 -0
- package/package.json +35 -12
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiAtomValueDetailContent.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiIcon.d.ts.map +0 -1
- package/lib/typescript/jotai/components/JotaiModal.d.ts.map +0 -1
- package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +0 -1
- package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/jotai/types/index.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/snapshotProvider.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/testIDs.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/watchAtoms.d.ts.map +0 -1
- package/lib/typescript/jotai/utils/writeSemantics.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
|
@@ -1,444 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.JotaiAtomValueDetailContent = JotaiAtomValueDetailContent;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _reactNative = require("react-native");
|
|
9
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
-
var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
|
|
11
|
-
var _jotaiStateStore = require("../utils/jotaiStateStore");
|
|
12
|
-
var _testIDs = require("../utils/testIDs");
|
|
13
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
-
/**
|
|
15
|
-
* One atom, on a screen of its own — the React Query detail-screen shape
|
|
16
|
-
* pointed at a live jotai atom. The jotai counterpart of zustand's
|
|
17
|
-
* `ZustandStoreDetailContent`; tapping an atom card opens this instead of
|
|
18
|
-
* expanding in place.
|
|
19
|
-
*
|
|
20
|
-
* 1. VALUE EDITOR — the shared LiveExplorer. No draft, no Save: an edit
|
|
21
|
-
* writes into the atom as you make it and the app reacts immediately.
|
|
22
|
-
* Typing commits on a short debounce (~300ms, flushed on blur) so a word
|
|
23
|
-
* is one recorded change, not one per keystroke — atom writes land in
|
|
24
|
-
* the change log and count against the free tier's cap.
|
|
25
|
-
* 2. ATOM DETAILS — what the expanded card used to say: type, write
|
|
26
|
-
* semantics, change count (with the road to history).
|
|
27
|
-
* 3. VALUE EXPLORER — the read-only tree of the same value.
|
|
28
|
-
*
|
|
29
|
-
* THE WRITE RULE — whole-value replace, jotai's own semantics. An atom is one
|
|
30
|
-
* value; there is no merge. However deep the edit, the writer rebuilds the
|
|
31
|
-
* whole value (`updateNestedDataByPath`) and hands it to `store.set(atom, …)`
|
|
32
|
-
* — so nested deletes are fine and only the ROOT itself can't be removed.
|
|
33
|
-
*
|
|
34
|
-
* Write-kind honesty (classified from jotai's own `defaultWrite`, see
|
|
35
|
-
* writeSemantics.ts):
|
|
36
|
-
* - "value" — primitive atom: `store.set` stores the edited value. Clean.
|
|
37
|
-
* - "action" — custom write (`atomWithStorage`, `atomWithReducer`, …): the
|
|
38
|
-
* edited value is passed to that write as its argument. For most
|
|
39
|
-
* (`atomWithStorage`) that IS a set; for a reducer it's an action. Still
|
|
40
|
-
* editable — the MCP's `setAtom` and Time Machine restore already write
|
|
41
|
-
* these — but the editor says what the write really does.
|
|
42
|
-
* - read-only derived — no setter exists; the editor section explains and
|
|
43
|
-
* the info/explorer sections still render.
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
/** How long typed edits coalesce before the single write fires. */const TYPING_COMMIT_MS = 300;
|
|
47
|
-
|
|
48
|
-
/** `buoy-jotai-atom-detail-…` — this screen's own handle root. */
|
|
49
|
-
const DETAIL_ID = `${_testIDs.JOTAI_TEST_ID}-atom-detail`;
|
|
50
|
-
function detailExplorerTestID(dataPath) {
|
|
51
|
-
const slug = part => part.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
52
|
-
return dataPath.length === 0 ? `${DETAIL_ID}-explorer-root` : `${DETAIL_ID}-explorer-${dataPath.map(slug).filter(Boolean).join("-")}`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Why this atom's value can't be live-edited, or null when it can.
|
|
57
|
-
*
|
|
58
|
-
* The path utils handle scalars, arrays, plain objects, Map and Set. What
|
|
59
|
-
* they can't faithfully rebuild is a class instance (a leaf edit would spread
|
|
60
|
-
* it into a plain object, dropping its prototype) — and a mirror's
|
|
61
|
-
* on-device marker or a function value aren't editable data at all.
|
|
62
|
-
*/
|
|
63
|
-
function editBlockedReasonFor(atom, value) {
|
|
64
|
-
if (!atom.setValue) {
|
|
65
|
-
return "Derived atom — its value recomputes from other atoms and has no setter. Edit the atoms it reads from instead.";
|
|
66
|
-
}
|
|
67
|
-
if (typeof value === "function") {
|
|
68
|
-
return "This atom holds a function — nothing here to edit as data.";
|
|
69
|
-
}
|
|
70
|
-
if (value && typeof value === "object" && value.__buoyValueOnDevice === true) {
|
|
71
|
-
return "The value stayed on the device (too large for the wire) — open the tool on-device to edit it.";
|
|
72
|
-
}
|
|
73
|
-
if (value && typeof value === "object") {
|
|
74
|
-
const proto = Object.getPrototypeOf(value);
|
|
75
|
-
const isPlain = proto === Object.prototype || proto === null || Array.isArray(value) || value instanceof Map || value instanceof Set;
|
|
76
|
-
if (!isPlain) {
|
|
77
|
-
const name = value.constructor?.name ?? "class";
|
|
78
|
-
return `This atom holds a ${name} instance — rebuilding it from edited fields would drop its prototype. Edit via app code.`;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
function valueTypeLabel(value) {
|
|
84
|
-
if (value === null) return "null";
|
|
85
|
-
if (value === undefined) return "undefined";
|
|
86
|
-
if (Array.isArray(value)) return `array · ${value.length}`;
|
|
87
|
-
return typeof value;
|
|
88
|
-
}
|
|
89
|
-
function JotaiAtomValueDetailContent({
|
|
90
|
-
atom,
|
|
91
|
-
onViewHistory
|
|
92
|
-
}) {
|
|
93
|
-
const rowID = (0, _testIDs.atomRowTestID)(atom.label);
|
|
94
|
-
|
|
95
|
-
// Re-render on every recorded change — our own edits included — so the
|
|
96
|
-
// editor, the read-only explorer, and the change count all track the live
|
|
97
|
-
// atom. Changes and registry updates arrive on separate listener sets, so
|
|
98
|
-
// subscribe to both. On a desktop mirror the snapshot refresh drives the
|
|
99
|
-
// same listeners.
|
|
100
|
-
const [version, setVersion] = (0, _react.useState)(0);
|
|
101
|
-
(0, _react.useEffect)(() => {
|
|
102
|
-
const bump = () => setVersion(v => v + 1);
|
|
103
|
-
const unsubChanges = _jotaiStateStore.jotaiStateStore.subscribe(bump);
|
|
104
|
-
const unsubAtoms = _jotaiStateStore.jotaiStateStore.subscribeToAtoms(bump);
|
|
105
|
-
return () => {
|
|
106
|
-
unsubChanges();
|
|
107
|
-
unsubAtoms();
|
|
108
|
-
};
|
|
109
|
-
}, []);
|
|
110
|
-
|
|
111
|
-
// Recomputed per change on purpose — this screen edits the LIVE atom, so
|
|
112
|
-
// every view of it derives from the atom's current answer, never a seed.
|
|
113
|
-
const value = (0, _react.useMemo)(() => {
|
|
114
|
-
try {
|
|
115
|
-
return atom.getValue();
|
|
116
|
-
} catch {
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
121
|
-
[atom, version]);
|
|
122
|
-
const blockedReason = editBlockedReasonFor(atom, value);
|
|
123
|
-
const [rawOpen, setRawOpen] = (0, _react.useState)(false);
|
|
124
|
-
const writer = (0, _react.useMemo)(() => {
|
|
125
|
-
if (blockedReason !== null) return undefined;
|
|
126
|
-
return {
|
|
127
|
-
update: (path, next) => {
|
|
128
|
-
const current = atom.getValue();
|
|
129
|
-
atom.setValue?.(path.length === 0 ? next : (0, _dataViewer.updateNestedDataByPath)(current, path, next));
|
|
130
|
-
},
|
|
131
|
-
remove: path => {
|
|
132
|
-
// Depth 0 is vetoed by canRemove; an atom is one value — you can
|
|
133
|
-
// empty it, not remove it.
|
|
134
|
-
if (path.length === 0) return;
|
|
135
|
-
const current = atom.getValue();
|
|
136
|
-
atom.setValue?.((0, _dataViewer.deleteNestedDataByPath)(current, path));
|
|
137
|
-
},
|
|
138
|
-
canRemove: path => path.length > 0
|
|
139
|
-
};
|
|
140
|
-
}, [atom, blockedReason]);
|
|
141
|
-
const displayValue = (0, _react.useMemo)(() => {
|
|
142
|
-
if (value && typeof value === "object") {
|
|
143
|
-
const filtered = {};
|
|
144
|
-
for (const [key, v] of Object.entries(value)) {
|
|
145
|
-
if (typeof v !== "function") filtered[key] = v;
|
|
146
|
-
}
|
|
147
|
-
return (0, _sharedUi.parseValue)(filtered);
|
|
148
|
-
}
|
|
149
|
-
return (0, _sharedUi.parseValue)(value);
|
|
150
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
151
|
-
}, [value, version]);
|
|
152
|
-
|
|
153
|
-
/** Raw-hatch save: whole-value edit, one write. */
|
|
154
|
-
const applyRaw = (0, _react.useCallback)(next => {
|
|
155
|
-
atom.setValue?.(next);
|
|
156
|
-
setRawOpen(false);
|
|
157
|
-
}, [atom]);
|
|
158
|
-
const writePill = atom.setValue === undefined ? {
|
|
159
|
-
color: _sharedUi.night.color.textTertiary,
|
|
160
|
-
label: "READ-ONLY (DERIVED)"
|
|
161
|
-
} : atom.writeKind === "action" ? {
|
|
162
|
-
color: _sharedUi.buoyColors.warning,
|
|
163
|
-
label: "CUSTOM WRITE"
|
|
164
|
-
} : {
|
|
165
|
-
color: _sharedUi.buoyColors.success,
|
|
166
|
-
label: "PRIMITIVE"
|
|
167
|
-
};
|
|
168
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
169
|
-
style: styles.root,
|
|
170
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
171
|
-
testID: `${DETAIL_ID}-scroll`,
|
|
172
|
-
style: styles.scroll,
|
|
173
|
-
contentContainerStyle: styles.scrollContent,
|
|
174
|
-
keyboardShouldPersistTaps: "handled",
|
|
175
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
176
|
-
style: styles.section,
|
|
177
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
178
|
-
style: styles.editorContainer,
|
|
179
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
180
|
-
style: styles.sectionHeaderRow,
|
|
181
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
182
|
-
testID: `${DETAIL_ID}-editor-header`,
|
|
183
|
-
style: styles.sectionHeaderText,
|
|
184
|
-
children: "Value Editor"
|
|
185
|
-
}), blockedReason === null ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
186
|
-
onPress: () => setRawOpen(true),
|
|
187
|
-
testID: `${DETAIL_ID}-raw`,
|
|
188
|
-
accessibilityRole: "button",
|
|
189
|
-
accessibilityLabel: "Edit raw JSON",
|
|
190
|
-
style: styles.rawButton,
|
|
191
|
-
hitSlop: {
|
|
192
|
-
top: 6,
|
|
193
|
-
bottom: 6,
|
|
194
|
-
left: 6,
|
|
195
|
-
right: 6
|
|
196
|
-
},
|
|
197
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FileJson, {
|
|
198
|
-
size: 13,
|
|
199
|
-
color: _sharedUi.night.color.accent
|
|
200
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
201
|
-
style: styles.rawButtonText,
|
|
202
|
-
children: "Raw"
|
|
203
|
-
})]
|
|
204
|
-
}) : null]
|
|
205
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
206
|
-
style: styles.sectionBody,
|
|
207
|
-
children: blockedReason === null ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
208
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.LiveExplorer, {
|
|
209
|
-
editable: true,
|
|
210
|
-
label: atom.label,
|
|
211
|
-
value: value,
|
|
212
|
-
defaultExpanded: [atom.label],
|
|
213
|
-
writer: writer,
|
|
214
|
-
dataVersion: version,
|
|
215
|
-
testIDForPath: detailExplorerTestID,
|
|
216
|
-
debounceMs: TYPING_COMMIT_MS
|
|
217
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
218
|
-
style: styles.editorHint,
|
|
219
|
-
children: atom.writeKind === "action" ? "This atom has a custom write — the edited value is handed to it as its argument (a set for atomWithStorage, an ACTION for a reducer atom)." : "Edits write into the live atom as you make them — the whole value is replaced, jotai's own semantics."
|
|
220
|
-
})]
|
|
221
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
222
|
-
style: styles.blockedText,
|
|
223
|
-
testID: `${DETAIL_ID}-edit-blocked`,
|
|
224
|
-
children: blockedReason
|
|
225
|
-
})
|
|
226
|
-
})]
|
|
227
|
-
})
|
|
228
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
229
|
-
style: styles.section,
|
|
230
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
231
|
-
style: styles.infoContainer,
|
|
232
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
233
|
-
style: styles.sectionHeaderTextPlain,
|
|
234
|
-
children: "Atom Details"
|
|
235
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
236
|
-
style: styles.infoBody,
|
|
237
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ExpandedInfoRow, {
|
|
238
|
-
label: "Type",
|
|
239
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
240
|
-
color: atom.color,
|
|
241
|
-
testID: `${rowID}-type`,
|
|
242
|
-
children: "JOTAI"
|
|
243
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
244
|
-
style: styles.valueTypeText,
|
|
245
|
-
testID: `${rowID}-valuetype`,
|
|
246
|
-
children: valueTypeLabel(value)
|
|
247
|
-
})]
|
|
248
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ExpandedInfoRow, {
|
|
249
|
-
label: "Write",
|
|
250
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
251
|
-
color: writePill.color,
|
|
252
|
-
testID: `${DETAIL_ID}-write`,
|
|
253
|
-
children: writePill.label
|
|
254
|
-
})
|
|
255
|
-
}), atom.changeCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ExpandedInfoRow, {
|
|
256
|
-
label: "Changes",
|
|
257
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
258
|
-
color: _sharedUi.buoyColors.warning,
|
|
259
|
-
testID: `${rowID}-changes`,
|
|
260
|
-
children: String(atom.changeCount)
|
|
261
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
262
|
-
onPress: () => onViewHistory(atom.label),
|
|
263
|
-
style: styles.inlineLinkButton,
|
|
264
|
-
hitSlop: {
|
|
265
|
-
top: 6,
|
|
266
|
-
bottom: 6,
|
|
267
|
-
left: 6,
|
|
268
|
-
right: 6
|
|
269
|
-
},
|
|
270
|
-
testID: `${rowID}-history`,
|
|
271
|
-
accessibilityRole: "button",
|
|
272
|
-
accessibilityLabel: `View ${atom.label} history`,
|
|
273
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
274
|
-
style: [styles.inlineLinkText, {
|
|
275
|
-
color: atom.color
|
|
276
|
-
}],
|
|
277
|
-
children: "view history \u2192"
|
|
278
|
-
})
|
|
279
|
-
})]
|
|
280
|
-
})]
|
|
281
|
-
})]
|
|
282
|
-
})
|
|
283
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
284
|
-
style: styles.section,
|
|
285
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
286
|
-
style: styles.infoContainer,
|
|
287
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
288
|
-
style: styles.sectionHeaderTextPlain,
|
|
289
|
-
children: "Value Explorer"
|
|
290
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
291
|
-
style: styles.viewerBody,
|
|
292
|
-
testID: `${rowID}-value`,
|
|
293
|
-
children: displayValue && typeof displayValue === "object" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
|
|
294
|
-
title: "",
|
|
295
|
-
data: displayValue,
|
|
296
|
-
showTypeFilter: true,
|
|
297
|
-
rawMode: true,
|
|
298
|
-
initialExpanded: false
|
|
299
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
300
|
-
style: styles.primitiveText,
|
|
301
|
-
testID: `${rowID}-primitive`,
|
|
302
|
-
children: String(value ?? "undefined")
|
|
303
|
-
})
|
|
304
|
-
})]
|
|
305
|
-
})
|
|
306
|
-
})]
|
|
307
|
-
}), rawOpen && blockedReason === null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.ValueEditModal, {
|
|
308
|
-
path: [],
|
|
309
|
-
value: value,
|
|
310
|
-
onSave: applyRaw,
|
|
311
|
-
onCancel: () => setRawOpen(false),
|
|
312
|
-
saveLabel: "Apply",
|
|
313
|
-
testIDPrefix: `${_testIDs.JOTAI_TEST_ID}-value`
|
|
314
|
-
}) : null]
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
const styles = _reactNative.StyleSheet.create({
|
|
318
|
-
root: {
|
|
319
|
-
flex: 1,
|
|
320
|
-
minHeight: 0
|
|
321
|
-
},
|
|
322
|
-
scroll: {
|
|
323
|
-
flex: 1
|
|
324
|
-
},
|
|
325
|
-
scrollContent: {
|
|
326
|
-
paddingHorizontal: 8,
|
|
327
|
-
paddingTop: 8,
|
|
328
|
-
paddingBottom: 24
|
|
329
|
-
},
|
|
330
|
-
section: {
|
|
331
|
-
marginBottom: 16
|
|
332
|
-
},
|
|
333
|
-
// The editable section wears the accent, like RQ's Data Editor — the one
|
|
334
|
-
// box on this screen that changes things should read differently from the
|
|
335
|
-
// two that don't.
|
|
336
|
-
editorContainer: {
|
|
337
|
-
minWidth: 200,
|
|
338
|
-
backgroundColor: _sharedUi.night.color.surface,
|
|
339
|
-
borderRadius: 6,
|
|
340
|
-
borderWidth: 1,
|
|
341
|
-
borderColor: _sharedUi.night.color.accent + "4D",
|
|
342
|
-
overflow: "hidden",
|
|
343
|
-
shadowColor: _sharedUi.night.color.accent,
|
|
344
|
-
shadowOffset: {
|
|
345
|
-
width: 0,
|
|
346
|
-
height: 0
|
|
347
|
-
},
|
|
348
|
-
shadowOpacity: 0.1,
|
|
349
|
-
shadowRadius: 6
|
|
350
|
-
},
|
|
351
|
-
sectionHeaderRow: {
|
|
352
|
-
flexDirection: "row",
|
|
353
|
-
alignItems: "center",
|
|
354
|
-
justifyContent: "space-between",
|
|
355
|
-
backgroundColor: _sharedUi.night.color.accent + "1A",
|
|
356
|
-
paddingHorizontal: 12,
|
|
357
|
-
paddingVertical: 8,
|
|
358
|
-
borderBottomWidth: 1,
|
|
359
|
-
borderBottomColor: _sharedUi.night.color.accent + "33"
|
|
360
|
-
},
|
|
361
|
-
sectionHeaderText: {
|
|
362
|
-
fontWeight: "600",
|
|
363
|
-
fontSize: 12,
|
|
364
|
-
color: _sharedUi.night.color.accent,
|
|
365
|
-
letterSpacing: 0.5,
|
|
366
|
-
textTransform: "uppercase",
|
|
367
|
-
fontFamily: _sharedUi.monoFont
|
|
368
|
-
},
|
|
369
|
-
rawButton: {
|
|
370
|
-
flexDirection: "row",
|
|
371
|
-
alignItems: "center",
|
|
372
|
-
gap: 4
|
|
373
|
-
},
|
|
374
|
-
rawButtonText: {
|
|
375
|
-
color: _sharedUi.night.color.accent,
|
|
376
|
-
fontSize: 11,
|
|
377
|
-
fontWeight: "700"
|
|
378
|
-
},
|
|
379
|
-
sectionBody: {
|
|
380
|
-
padding: 8
|
|
381
|
-
},
|
|
382
|
-
editorHint: {
|
|
383
|
-
color: _sharedUi.night.color.textTertiary,
|
|
384
|
-
fontSize: 10,
|
|
385
|
-
paddingTop: 8,
|
|
386
|
-
paddingHorizontal: 4,
|
|
387
|
-
lineHeight: 14
|
|
388
|
-
},
|
|
389
|
-
blockedText: {
|
|
390
|
-
color: _sharedUi.night.color.textSecondary,
|
|
391
|
-
fontSize: 12,
|
|
392
|
-
padding: 12,
|
|
393
|
-
lineHeight: 18
|
|
394
|
-
},
|
|
395
|
-
infoContainer: {
|
|
396
|
-
minWidth: 200,
|
|
397
|
-
backgroundColor: _sharedUi.night.color.surface,
|
|
398
|
-
borderRadius: 6,
|
|
399
|
-
borderWidth: 1,
|
|
400
|
-
borderColor: _sharedUi.night.color.border,
|
|
401
|
-
overflow: "hidden"
|
|
402
|
-
},
|
|
403
|
-
sectionHeaderTextPlain: {
|
|
404
|
-
backgroundColor: _sharedUi.night.color.surfaceElevated,
|
|
405
|
-
paddingHorizontal: 12,
|
|
406
|
-
paddingVertical: 8,
|
|
407
|
-
fontWeight: "600",
|
|
408
|
-
fontSize: 12,
|
|
409
|
-
color: _sharedUi.night.color.textSecondary,
|
|
410
|
-
borderBottomWidth: 1,
|
|
411
|
-
borderBottomColor: _sharedUi.night.color.border,
|
|
412
|
-
letterSpacing: 0.5,
|
|
413
|
-
textTransform: "uppercase",
|
|
414
|
-
fontFamily: _sharedUi.monoFont
|
|
415
|
-
},
|
|
416
|
-
infoBody: {
|
|
417
|
-
padding: 12,
|
|
418
|
-
gap: 10
|
|
419
|
-
},
|
|
420
|
-
viewerBody: {
|
|
421
|
-
backgroundColor: _sharedUi.night.color.bg,
|
|
422
|
-
minHeight: 60
|
|
423
|
-
},
|
|
424
|
-
primitiveText: {
|
|
425
|
-
color: _sharedUi.night.color.text,
|
|
426
|
-
fontSize: 12,
|
|
427
|
-
fontFamily: _sharedUi.monoFont,
|
|
428
|
-
padding: 14
|
|
429
|
-
},
|
|
430
|
-
valueTypeText: {
|
|
431
|
-
color: _sharedUi.night.color.textTertiary,
|
|
432
|
-
fontSize: 10,
|
|
433
|
-
fontFamily: _sharedUi.monoFont,
|
|
434
|
-
marginLeft: 6
|
|
435
|
-
},
|
|
436
|
-
inlineLinkButton: {
|
|
437
|
-
marginLeft: 4
|
|
438
|
-
},
|
|
439
|
-
inlineLinkText: {
|
|
440
|
-
fontSize: 10,
|
|
441
|
-
fontWeight: "600",
|
|
442
|
-
fontFamily: _sharedUi.monoFont
|
|
443
|
-
}
|
|
444
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.JotaiAtomValueDetailContent=JotaiAtomValueDetailContent;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _dataViewer=require("@buoy-gg/shared-ui/dataViewer");var _jotaiStateStore=require("../utils/jotaiStateStore");var _testIDs=require("../utils/testIDs");var _jsxRuntime=require("react/jsx-runtime");const TYPING_COMMIT_MS=300;const DETAIL_ID=`${_testIDs.JOTAI_TEST_ID}-atom-detail`;function detailExplorerTestID(e){const t=r=>r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return e.length===0?`${DETAIL_ID}-explorer-root`:`${DETAIL_ID}-explorer-${e.map(t).filter(Boolean).join("-")}`}function editBlockedReasonFor(e,t){if(!e.setValue){return"Derived atom \u2014 its value recomputes from other atoms and has no setter. Edit the atoms it reads from instead."}if(typeof t==="function"){return"This atom holds a function \u2014 nothing here to edit as data."}if(t&&typeof t==="object"&&t.__buoyValueOnDevice===true){return"The value stayed on the device (too large for the wire) \u2014 open the tool on-device to edit it."}if(t&&typeof t==="object"){const r=Object.getPrototypeOf(t);const a=r===Object.prototype||r===null||Array.isArray(t)||t instanceof Map||t instanceof Set;if(!a){const c=t.constructor?.name??"class";return`This atom holds a ${c} instance \u2014 rebuilding it from edited fields would drop its prototype. Edit via app code.`}}return null}function valueTypeLabel(e){if(e===null)return"null";if(e===void 0)return"undefined";if(Array.isArray(e))return`array \xB7 ${e.length}`;return typeof e}function JotaiAtomValueDetailContent({atom:e,onViewHistory:t}){const r=(0,_testIDs.atomRowTestID)(e.label);const[a,c]=(0,_react.useState)(0);(0,_react.useEffect)(()=>{const o=()=>c(p=>p+1);const n=_jotaiStateStore.jotaiStateStore.subscribe(o);const s=_jotaiStateStore.jotaiStateStore.subscribeToAtoms(o);return()=>{n();s()}},[]);const i=(0,_react.useMemo)(()=>{try{return e.getValue()}catch{return void 0}},[e,a]);const l=editBlockedReasonFor(e,i);const[f,d]=(0,_react.useState)(false);const g=(0,_react.useMemo)(()=>{if(l!==null)return void 0;return{update:(o,n)=>{const s=e.getValue();e.setValue?.(o.length===0?n:(0,_dataViewer.updateNestedDataByPath)(s,o,n))},remove:o=>{if(o.length===0)return;const n=e.getValue();e.setValue?.((0,_dataViewer.deleteNestedDataByPath)(n,o))},canRemove:o=>o.length>0}},[e,l]);const u=(0,_react.useMemo)(()=>{if(i&&typeof i==="object"){const o={};for(const[n,s]of Object.entries(i)){if(typeof s!=="function")o[n]=s}return(0,_sharedUi.parseValue)(o)}return(0,_sharedUi.parseValue)(i)},[i,a]);const y=(0,_react.useCallback)(o=>{e.setValue?.(o);d(false)},[e]);const h=e.setValue===void 0?{color:_sharedUi.night.color.textTertiary,label:"READ-ONLY (DERIVED)"}:e.writeKind==="action"?{color:_sharedUi.buoyColors.warning,label:"CUSTOM WRITE"}:{color:_sharedUi.buoyColors.success,label:"PRIMITIVE"};return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.root,children:[(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{testID:`${DETAIL_ID}-scroll`,style:styles.scroll,contentContainerStyle:styles.scrollContent,keyboardShouldPersistTaps:"handled",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.section,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.editorContainer,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sectionHeaderRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:`${DETAIL_ID}-editor-header`,style:styles.sectionHeaderText,children:"Value Editor"}),l===null?(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{onPress:()=>d(true),testID:`${DETAIL_ID}-raw`,accessibilityRole:"button",accessibilityLabel:"Edit raw JSON",style:styles.rawButton,hitSlop:{top:6,bottom:6,left:6,right:6},children:[(0,_jsxRuntime.jsx)(_sharedUi.FileJson,{size:13,color:_sharedUi.night.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rawButtonText,children:"Raw"})]}):null]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.sectionBody,children:l===null?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_dataViewer.LiveExplorer,{editable:true,label:e.label,value:i,defaultExpanded:[e.label],writer:g,dataVersion:a,testIDForPath:detailExplorerTestID,debounceMs:TYPING_COMMIT_MS}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.editorHint,children:e.writeKind==="action"?"This atom has a custom write \u2014 the edited value is handed to it as its argument (a set for atomWithStorage, an ACTION for a reducer atom).":"Edits write into the live atom as you make them \u2014 the whole value is replaced, jotai's own semantics."})]}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.blockedText,testID:`${DETAIL_ID}-edit-blocked`,children:l})})]})}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.section,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.infoContainer,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionHeaderTextPlain,children:"Atom Details"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.infoBody,children:[(0,_jsxRuntime.jsxs)(_sharedUi.ExpandedInfoRow,{label:"Type",children:[(0,_jsxRuntime.jsx)(_sharedUi.PillBadge,{color:e.color,testID:`${r}-type`,children:"JOTAI"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.valueTypeText,testID:`${r}-valuetype`,children:valueTypeLabel(i)})]}),(0,_jsxRuntime.jsx)(_sharedUi.ExpandedInfoRow,{label:"Write",children:(0,_jsxRuntime.jsx)(_sharedUi.PillBadge,{color:h.color,testID:`${DETAIL_ID}-write`,children:h.label})}),e.changeCount>0&&(0,_jsxRuntime.jsxs)(_sharedUi.ExpandedInfoRow,{label:"Changes",children:[(0,_jsxRuntime.jsx)(_sharedUi.PillBadge,{color:_sharedUi.buoyColors.warning,testID:`${r}-changes`,children:String(e.changeCount)}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:()=>t(e.label),style:styles.inlineLinkButton,hitSlop:{top:6,bottom:6,left:6,right:6},testID:`${r}-history`,accessibilityRole:"button",accessibilityLabel:`View ${e.label} history`,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.inlineLinkText,{color:e.color}],children:"view history \u2192"})})]})]})]})}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.section,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.infoContainer,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sectionHeaderTextPlain,children:"Value Explorer"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.viewerBody,testID:`${r}-value`,children:u&&typeof u==="object"?(0,_jsxRuntime.jsx)(_dataViewer.DataViewer,{title:"",data:u,showTypeFilter:true,rawMode:true,initialExpanded:false}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.primitiveText,testID:`${r}-primitive`,children:String(i??"undefined")})})]})})]}),f&&l===null?(0,_jsxRuntime.jsx)(_dataViewer.ValueEditModal,{path:[],value:i,onSave:y,onCancel:()=>d(false),saveLabel:"Apply",testIDPrefix:`${_testIDs.JOTAI_TEST_ID}-value`}):null]})}const styles=_reactNative.StyleSheet.create({root:{flex:1,minHeight:0},scroll:{flex:1},scrollContent:{paddingHorizontal:8,paddingTop:8,paddingBottom:24},section:{marginBottom:16},editorContainer:{minWidth:200,backgroundColor:_sharedUi.night.color.surface,borderRadius:6,borderWidth:1,borderColor:_sharedUi.night.color.accent+"4D",overflow:"hidden",shadowColor:_sharedUi.night.color.accent,shadowOffset:{width:0,height:0},shadowOpacity:.1,shadowRadius:6},sectionHeaderRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",backgroundColor:_sharedUi.night.color.accent+"1A",paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:_sharedUi.night.color.accent+"33"},sectionHeaderText:{fontWeight:"600",fontSize:12,color:_sharedUi.night.color.accent,letterSpacing:.5,textTransform:"uppercase",fontFamily:_sharedUi.monoFont},rawButton:{flexDirection:"row",alignItems:"center",gap:4},rawButtonText:{color:_sharedUi.night.color.accent,fontSize:11,fontWeight:"700"},sectionBody:{padding:8},editorHint:{color:_sharedUi.night.color.textTertiary,fontSize:10,paddingTop:8,paddingHorizontal:4,lineHeight:14},blockedText:{color:_sharedUi.night.color.textSecondary,fontSize:12,padding:12,lineHeight:18},infoContainer:{minWidth:200,backgroundColor:_sharedUi.night.color.surface,borderRadius:6,borderWidth:1,borderColor:_sharedUi.night.color.border,overflow:"hidden"},sectionHeaderTextPlain:{backgroundColor:_sharedUi.night.color.surfaceElevated,paddingHorizontal:12,paddingVertical:8,fontWeight:"600",fontSize:12,color:_sharedUi.night.color.textSecondary,borderBottomWidth:1,borderBottomColor:_sharedUi.night.color.border,letterSpacing:.5,textTransform:"uppercase",fontFamily:_sharedUi.monoFont},infoBody:{padding:12,gap:10},viewerBody:{backgroundColor:_sharedUi.night.color.bg,minHeight:60},primitiveText:{color:_sharedUi.night.color.text,fontSize:12,fontFamily:_sharedUi.monoFont,padding:14},valueTypeText:{color:_sharedUi.night.color.textTertiary,fontSize:10,fontFamily:_sharedUi.monoFont,marginLeft:6},inlineLinkButton:{marginLeft:4},inlineLinkText:{fontSize:10,fontWeight:"600",fontFamily:_sharedUi.monoFont}});
|
|
@@ -1,43 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.JotaiEventFilterView = JotaiEventFilterView;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
9
|
-
var _testIDs = require("../utils/testIDs");
|
|
10
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
-
/**
|
|
12
|
-
* JotaiEventFilterView
|
|
13
|
-
*
|
|
14
|
-
* The shared `EntityFilterView` with jotai's nouns: watched atoms you can
|
|
15
|
-
* tap to hide, active atom-name patterns, and how it works.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const EXAMPLES = ["• count -> hides countAtom from atoms & events", "• auth -> hides authAtom, authStatusAtom", "• user -> hides userAtom from both tabs"];
|
|
19
|
-
function JotaiEventFilterView({
|
|
20
|
-
ignoredPatterns,
|
|
21
|
-
onTogglePattern,
|
|
22
|
-
onAddPattern,
|
|
23
|
-
atoms
|
|
24
|
-
}) {
|
|
25
|
-
const entities = (0, _react.useMemo)(() => atoms.map(atom => ({
|
|
26
|
-
name: atom.label,
|
|
27
|
-
color: atom.color
|
|
28
|
-
})), [atoms]);
|
|
29
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EntityFilterView, {
|
|
30
|
-
entities: entities,
|
|
31
|
-
ignoredPatterns: ignoredPatterns,
|
|
32
|
-
onTogglePattern: onTogglePattern,
|
|
33
|
-
onAddPattern: onAddPattern,
|
|
34
|
-
entityNoun: "ATOMS",
|
|
35
|
-
entitySingular: "atom",
|
|
36
|
-
entityKey: "atom",
|
|
37
|
-
testIDPrefix: _testIDs.JOTAI_TEST_ID,
|
|
38
|
-
slug: _testIDs.slugForTestID,
|
|
39
|
-
howItWorks: "Patterns hide matching atoms from both the Atoms tab and the Events tab. Tap an atom above to quickly add it as a filter.",
|
|
40
|
-
examples: EXAMPLES,
|
|
41
|
-
emptyMessage: "No atoms are being watched yet."
|
|
42
|
-
});
|
|
43
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.JotaiEventFilterView=JotaiEventFilterView;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _testIDs=require("../utils/testIDs");var _jsxRuntime=require("react/jsx-runtime");const EXAMPLES=["\u2022 count -> hides countAtom from atoms & events","\u2022 auth -> hides authAtom, authStatusAtom","\u2022 user -> hides userAtom from both tabs"];function JotaiEventFilterView({ignoredPatterns:r,onTogglePattern:a,onAddPattern:s,atoms:t}){const o=(0,_react.useMemo)(()=>t.map(e=>({name:e.label,color:e.color})),[t]);return(0,_jsxRuntime.jsx)(_sharedUi.EntityFilterView,{entities:o,ignoredPatterns:r,onTogglePattern:a,onAddPattern:s,entityNoun:"ATOMS",entitySingular:"atom",entityKey:"atom",testIDPrefix:_testIDs.JOTAI_TEST_ID,slug:_testIDs.slugForTestID,howItWorks:"Patterns hide matching atoms from both the Atoms tab and the Events tab. Tap an atom above to quickly add it as a filter.",examples:EXAMPLES,emptyMessage:"No atoms are being watched yet."})}
|
|
@@ -1,18 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "JOTAI_ICON_COLOR", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _sharedUi.JOTAI_ICON_COLOR;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(exports, "JotaiIcon", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () {
|
|
15
|
-
return _sharedUi.JotaiIcon;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"JOTAI_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.JOTAI_ICON_COLOR}});Object.defineProperty(exports,"JotaiIcon",{enumerable:true,get:function(){return _sharedUi.JotaiIcon}});var _sharedUi=require("@buoy-gg/shared-ui");
|