@buoy-gg/zustand 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/zustand/components/ZustandActionButton.js +3 -1
- package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +7 -0
- package/lib/commonjs/zustand/components/ZustandEventFilterView.js +19 -4
- package/lib/commonjs/zustand/components/ZustandModal.js +174 -32
- package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +36 -37
- package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +22 -5
- package/lib/commonjs/zustand/components/ZustandStateInfoView.js +30 -7
- package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +23 -126
- package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +471 -0
- package/lib/commonjs/zustand/components/ZustandStoreEditorScreen.js +393 -0
- package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +54 -0
- package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +71 -7
- package/lib/commonjs/zustand/utils/editableState.js +139 -0
- package/lib/commonjs/zustand/utils/snapshotProvider.js +10 -37
- package/lib/commonjs/zustand/utils/testIDs.js +82 -0
- package/lib/commonjs/zustand/utils/zustandStateStore.js +16 -3
- package/lib/module/zustand/components/ZustandActionButton.js +3 -1
- package/lib/module/zustand/components/ZustandDetailViewToggle.js +7 -0
- package/lib/module/zustand/components/ZustandEventFilterView.js +19 -4
- package/lib/module/zustand/components/ZustandModal.js +175 -33
- package/lib/module/zustand/components/ZustandStateChangeItem.js +36 -37
- package/lib/module/zustand/components/ZustandStateDetailContent.js +22 -5
- package/lib/module/zustand/components/ZustandStateInfoView.js +30 -7
- package/lib/module/zustand/components/ZustandStoreBrowser.js +26 -129
- package/lib/module/zustand/components/ZustandStoreDetailContent.js +469 -0
- package/lib/module/zustand/components/ZustandStoreEditorScreen.js +389 -0
- package/lib/module/zustand/sync/zustandSyncAdapter.js +54 -0
- package/lib/module/zustand/utils/buoyZustandMiddleware.js +71 -7
- package/lib/module/zustand/utils/editableState.js +131 -0
- package/lib/module/zustand/utils/snapshotProvider.js +4 -30
- package/lib/module/zustand/utils/testIDs.js +74 -0
- package/lib/module/zustand/utils/zustandStateStore.js +16 -3
- package/lib/typescript/zustand/components/ZustandActionButton.d.ts +2 -1
- package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +1 -1
- 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 +6 -0
- package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts +7 -9
- package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts +40 -0
- package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +1 -0
- package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts +42 -0
- package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts.map +1 -0
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts +35 -0
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/zustand/types/index.d.ts +13 -0
- package/lib/typescript/zustand/types/index.d.ts.map +1 -1
- package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts +31 -3
- package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts.map +1 -1
- package/lib/typescript/zustand/utils/editableState.d.ts +65 -0
- package/lib/typescript/zustand/utils/editableState.d.ts.map +1 -0
- package/lib/typescript/zustand/utils/testIDs.d.ts +54 -0
- package/lib/typescript/zustand/utils/testIDs.d.ts.map +1 -0
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts +1 -0
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One store, on a screen of its own — the React Query detail-screen shape
|
|
5
|
+
* pointed at a live zustand store.
|
|
6
|
+
*
|
|
7
|
+
* Tapping a store card opens this instead of expanding in place. Top to
|
|
8
|
+
* bottom, mirroring RQ's `DataEditorMode`:
|
|
9
|
+
*
|
|
10
|
+
* 1. STATE EDITOR — the shared LiveExplorer. No draft, no Save: an edit
|
|
11
|
+
* writes into the live store as you make it and the app reacts
|
|
12
|
+
* immediately. Typing commits on a short debounce (~300ms, flushed on
|
|
13
|
+
* blur) so a word is one recorded change, not one per keystroke —
|
|
14
|
+
* zustand writes land in the change log and count against the free
|
|
15
|
+
* tier's cap, which is the one way this tool differs from RQ's
|
|
16
|
+
* unlogged cache writes.
|
|
17
|
+
* 2. STORE DETAILS — what the expanded card used to say: backing,
|
|
18
|
+
* change count (with the road to history), the store's actions.
|
|
19
|
+
* 3. STATE EXPLORER — the read-only tree of the same state.
|
|
20
|
+
*
|
|
21
|
+
* THE WRITE RULE (unchanged from the previous editor — see editableState.ts):
|
|
22
|
+
* merge-only, always. However deep the edit, it is written as
|
|
23
|
+
* `setState({ [topKey]: rewritten }, false)`, which cannot delete a top-level
|
|
24
|
+
* key and cannot touch the action functions stores keep in state. The
|
|
25
|
+
* explorer's delete affordance is therefore vetoed at depth 1 via
|
|
26
|
+
* `canRemove`, and the Raw escape hatch (whole-state JSON, for the add-key /
|
|
27
|
+
* restructure cases live editing can't express) refuses drops through
|
|
28
|
+
* `computeMergePartial`, naming the key.
|
|
29
|
+
*
|
|
30
|
+
* On a desktop mirror the same writes go over the wire: the mirrored store's
|
|
31
|
+
* `api.setState` forwards to the device's sync adapter (the time-travel
|
|
32
|
+
* path), fire-and-forget, with the next snapshot as confirmation.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
36
|
+
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
37
|
+
import { buoyColors, Database, ExpandedInfoRow, FileJson, night, PillBadge, parseValue } from "@buoy-gg/shared-ui";
|
|
38
|
+
import { DataViewer, LiveExplorer, ValueEditModal, updateNestedDataByPath, deleteNestedDataByPath } from "@buoy-gg/shared-ui/dataViewer";
|
|
39
|
+
import { computeMergePartial, editableStateOf, isPlainObjectLike } from "../utils/editableState";
|
|
40
|
+
import { ZUSTAND_TEST_ID, storeRowTestID } from "../utils/testIDs";
|
|
41
|
+
|
|
42
|
+
/** How long typed edits coalesce before the single merge write fires. */
|
|
43
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
44
|
+
const TYPING_COMMIT_MS = 300;
|
|
45
|
+
|
|
46
|
+
/** `buoy-zustand-detail-…` — this screen's own handle root. */
|
|
47
|
+
const DETAIL_ID = `${ZUSTAND_TEST_ID}-detail`;
|
|
48
|
+
function detailExplorerTestID(dataPath) {
|
|
49
|
+
const slug = part => part.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
50
|
+
return dataPath.length === 0 ? `${DETAIL_ID}-explorer-root` : `${DETAIL_ID}-explorer-${dataPath.map(slug).filter(Boolean).join("-")}`;
|
|
51
|
+
}
|
|
52
|
+
export function ZustandStoreDetailContent({
|
|
53
|
+
store,
|
|
54
|
+
onViewHistory
|
|
55
|
+
}) {
|
|
56
|
+
const rowID = storeRowTestID(store.name);
|
|
57
|
+
|
|
58
|
+
// Re-render on every store write — our own edits included — so the tree,
|
|
59
|
+
// the read-only explorer, and the change count all track the live store.
|
|
60
|
+
// On a desktop mirror the stub subscribe is a no-op and the re-render
|
|
61
|
+
// arrives via the stores snapshot refreshing this component's props.
|
|
62
|
+
const [version, setVersion] = useState(0);
|
|
63
|
+
useEffect(() => store.api.subscribe(() => setVersion(v => v + 1)), [store.api]);
|
|
64
|
+
const state = store.api.getState();
|
|
65
|
+
// Recomputed per write on purpose — this screen edits LIVE state, so every
|
|
66
|
+
// view of it derives from the store's current answer, never a seed.
|
|
67
|
+
const editable = useMemo(() => editableStateOf(state),
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
[state, version]);
|
|
70
|
+
const [rawOpen, setRawOpen] = useState(false);
|
|
71
|
+
const writer = useMemo(() => {
|
|
72
|
+
if (editable.data === null) return undefined;
|
|
73
|
+
return {
|
|
74
|
+
update: (path, value) => {
|
|
75
|
+
const current = store.api.getState();
|
|
76
|
+
if (!isPlainObjectLike(current) || path.length === 0) return;
|
|
77
|
+
const topKey = path[0];
|
|
78
|
+
const nextTop = path.length === 1 ? value : updateNestedDataByPath(
|
|
79
|
+
// The live value, not the stripped view — although below the
|
|
80
|
+
// top level they are the same thing (a store with functions
|
|
81
|
+
// nested in data keys is refused editing entirely).
|
|
82
|
+
current[topKey], path.slice(1), value);
|
|
83
|
+
store.api.setState({
|
|
84
|
+
[topKey]: nextTop
|
|
85
|
+
}, false);
|
|
86
|
+
},
|
|
87
|
+
remove: path => {
|
|
88
|
+
// Depth 1 is vetoed by canRemove; this guard is the belt to that
|
|
89
|
+
// suspender — a merge write cannot delete a top-level key.
|
|
90
|
+
const current = store.api.getState();
|
|
91
|
+
if (!isPlainObjectLike(current) || path.length <= 1) return;
|
|
92
|
+
const topKey = path[0];
|
|
93
|
+
const nextTop = deleteNestedDataByPath(current[topKey], path.slice(1));
|
|
94
|
+
store.api.setState({
|
|
95
|
+
[topKey]: nextTop
|
|
96
|
+
}, false);
|
|
97
|
+
},
|
|
98
|
+
canRemove: path => path.length > 1
|
|
99
|
+
};
|
|
100
|
+
}, [store.api, editable.data === null]);
|
|
101
|
+
|
|
102
|
+
/** Raw-hatch save: whole-document edit diffed into one merge write. */
|
|
103
|
+
const applyRaw = useCallback(next => {
|
|
104
|
+
const current = editableStateOf(store.api.getState());
|
|
105
|
+
if (current.data === null) return;
|
|
106
|
+
const partial = computeMergePartial(current.data, next);
|
|
107
|
+
if (Object.keys(partial).length > 0) {
|
|
108
|
+
store.api.setState(partial, false);
|
|
109
|
+
}
|
|
110
|
+
setRawOpen(false);
|
|
111
|
+
}, [store.api]);
|
|
112
|
+
const displayState = useMemo(() => {
|
|
113
|
+
if (state && typeof state === "object") {
|
|
114
|
+
const filtered = {};
|
|
115
|
+
for (const [key, value] of Object.entries(state)) {
|
|
116
|
+
if (typeof value !== "function") filtered[key] = value;
|
|
117
|
+
}
|
|
118
|
+
return parseValue(filtered);
|
|
119
|
+
}
|
|
120
|
+
return parseValue(state);
|
|
121
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
122
|
+
}, [state, version]);
|
|
123
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
124
|
+
style: styles.root,
|
|
125
|
+
children: [/*#__PURE__*/_jsxs(ScrollView, {
|
|
126
|
+
testID: `${DETAIL_ID}-scroll`,
|
|
127
|
+
style: styles.scroll,
|
|
128
|
+
contentContainerStyle: styles.scrollContent,
|
|
129
|
+
keyboardShouldPersistTaps: "handled",
|
|
130
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
131
|
+
style: styles.section,
|
|
132
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
133
|
+
style: styles.editorContainer,
|
|
134
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
135
|
+
style: styles.sectionHeaderRow,
|
|
136
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
137
|
+
testID: `${DETAIL_ID}-editor-header`,
|
|
138
|
+
style: styles.sectionHeaderText,
|
|
139
|
+
children: "State Editor"
|
|
140
|
+
}), editable.data !== null ? /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
141
|
+
onPress: () => setRawOpen(true),
|
|
142
|
+
testID: `${DETAIL_ID}-raw`,
|
|
143
|
+
accessibilityRole: "button",
|
|
144
|
+
accessibilityLabel: "Edit raw JSON",
|
|
145
|
+
style: styles.rawButton,
|
|
146
|
+
hitSlop: {
|
|
147
|
+
top: 6,
|
|
148
|
+
bottom: 6,
|
|
149
|
+
left: 6,
|
|
150
|
+
right: 6
|
|
151
|
+
},
|
|
152
|
+
children: [/*#__PURE__*/_jsx(FileJson, {
|
|
153
|
+
size: 13,
|
|
154
|
+
color: night.color.accent
|
|
155
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
156
|
+
style: styles.rawButtonText,
|
|
157
|
+
children: "Raw"
|
|
158
|
+
})]
|
|
159
|
+
}) : null]
|
|
160
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
161
|
+
style: styles.sectionBody,
|
|
162
|
+
children: editable.data !== null ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
163
|
+
children: [/*#__PURE__*/_jsx(LiveExplorer, {
|
|
164
|
+
editable: true,
|
|
165
|
+
label: "State",
|
|
166
|
+
value: editable.data,
|
|
167
|
+
defaultExpanded: ["State"],
|
|
168
|
+
writer: writer,
|
|
169
|
+
dataVersion: version,
|
|
170
|
+
testIDForPath: detailExplorerTestID,
|
|
171
|
+
debounceMs: TYPING_COMMIT_MS
|
|
172
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
173
|
+
style: styles.editorHint,
|
|
174
|
+
children: "Edits write into the live store as you make them \u2014 merged, so the store's actions and untouched keys survive."
|
|
175
|
+
})]
|
|
176
|
+
}) : /*#__PURE__*/_jsx(Text, {
|
|
177
|
+
style: styles.blockedText,
|
|
178
|
+
testID: `${DETAIL_ID}-edit-blocked`,
|
|
179
|
+
children: editable.blockedReason
|
|
180
|
+
})
|
|
181
|
+
})]
|
|
182
|
+
})
|
|
183
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
184
|
+
style: styles.section,
|
|
185
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
186
|
+
style: styles.infoContainer,
|
|
187
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
188
|
+
style: styles.sectionHeaderTextPlain,
|
|
189
|
+
children: "Store Details"
|
|
190
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
191
|
+
style: styles.infoBody,
|
|
192
|
+
children: [/*#__PURE__*/_jsx(ExpandedInfoRow, {
|
|
193
|
+
label: "Type",
|
|
194
|
+
children: /*#__PURE__*/_jsx(PillBadge, {
|
|
195
|
+
color: store.color,
|
|
196
|
+
testID: `${rowID}-type`,
|
|
197
|
+
children: "ZUSTAND"
|
|
198
|
+
})
|
|
199
|
+
}), /*#__PURE__*/_jsxs(ExpandedInfoRow, {
|
|
200
|
+
label: "Backing",
|
|
201
|
+
children: [/*#__PURE__*/_jsx(PillBadge, {
|
|
202
|
+
color: buoyColors.info,
|
|
203
|
+
icon: store.isPersisted ? /*#__PURE__*/_jsx(Database, {
|
|
204
|
+
size: 9,
|
|
205
|
+
color: buoyColors.info
|
|
206
|
+
}) : undefined,
|
|
207
|
+
testID: `${rowID}-persist`,
|
|
208
|
+
children: store.isPersisted ? store.persistName || "persisted" : "in-memory"
|
|
209
|
+
}), store.isPersisted ? /*#__PURE__*/_jsx(RereadSavedValue, {
|
|
210
|
+
store: store,
|
|
211
|
+
rowID: rowID
|
|
212
|
+
}) : null]
|
|
213
|
+
}), store.stateChangeCount > 0 && /*#__PURE__*/_jsxs(ExpandedInfoRow, {
|
|
214
|
+
label: "Changes",
|
|
215
|
+
children: [/*#__PURE__*/_jsx(PillBadge, {
|
|
216
|
+
color: buoyColors.warning,
|
|
217
|
+
testID: `${rowID}-changes`,
|
|
218
|
+
children: String(store.stateChangeCount)
|
|
219
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
220
|
+
onPress: () => onViewHistory(store.name),
|
|
221
|
+
style: styles.inlineLinkButton,
|
|
222
|
+
hitSlop: {
|
|
223
|
+
top: 6,
|
|
224
|
+
bottom: 6,
|
|
225
|
+
left: 6,
|
|
226
|
+
right: 6
|
|
227
|
+
},
|
|
228
|
+
testID: `${rowID}-history`,
|
|
229
|
+
accessibilityRole: "button",
|
|
230
|
+
accessibilityLabel: `View ${store.name} history`,
|
|
231
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
232
|
+
style: [styles.inlineLinkText, {
|
|
233
|
+
color: store.color
|
|
234
|
+
}],
|
|
235
|
+
children: "view history \u2192"
|
|
236
|
+
})
|
|
237
|
+
})]
|
|
238
|
+
}), editable.fnPaths.length > 0 && /*#__PURE__*/_jsx(ExpandedInfoRow, {
|
|
239
|
+
label: "Actions",
|
|
240
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
241
|
+
style: styles.actionsText,
|
|
242
|
+
testID: `${DETAIL_ID}-actions`,
|
|
243
|
+
numberOfLines: 2,
|
|
244
|
+
children: editable.fnPaths.join(" · ")
|
|
245
|
+
})
|
|
246
|
+
})]
|
|
247
|
+
})]
|
|
248
|
+
})
|
|
249
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
250
|
+
style: styles.section,
|
|
251
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
252
|
+
style: styles.infoContainer,
|
|
253
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
254
|
+
style: styles.sectionHeaderTextPlain,
|
|
255
|
+
children: "State Explorer"
|
|
256
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
257
|
+
style: styles.viewerBody,
|
|
258
|
+
testID: `${rowID}-state`,
|
|
259
|
+
children: displayState && typeof displayState === "object" ? /*#__PURE__*/_jsx(DataViewer, {
|
|
260
|
+
title: "",
|
|
261
|
+
data: displayState,
|
|
262
|
+
showTypeFilter: true,
|
|
263
|
+
rawMode: true,
|
|
264
|
+
initialExpanded: false
|
|
265
|
+
}) : /*#__PURE__*/_jsx(Text, {
|
|
266
|
+
style: styles.blockedText,
|
|
267
|
+
children: "Empty state"
|
|
268
|
+
})
|
|
269
|
+
})]
|
|
270
|
+
})
|
|
271
|
+
})]
|
|
272
|
+
}), rawOpen && editable.data !== null ? /*#__PURE__*/_jsx(ValueEditModal, {
|
|
273
|
+
path: [],
|
|
274
|
+
value: editable.data,
|
|
275
|
+
onSave: next => {
|
|
276
|
+
try {
|
|
277
|
+
applyRaw(next);
|
|
278
|
+
} catch {
|
|
279
|
+
// computeMergePartial refuses dropped top-level keys; the modal
|
|
280
|
+
// stays open with its own validation, so just don't close it.
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
onCancel: () => setRawOpen(false),
|
|
284
|
+
saveLabel: "Apply",
|
|
285
|
+
testIDPrefix: `${ZUSTAND_TEST_ID}-value`
|
|
286
|
+
}) : null]
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Pull this store's saved value back into memory.
|
|
292
|
+
*
|
|
293
|
+
* Lives on the store rather than in the Storage tool because here there is
|
|
294
|
+
* nothing to infer: `store.rehydrate` IS the store's own `persist.rehydrate`.
|
|
295
|
+
* The merge keeps the store's action functions, and it does not write back
|
|
296
|
+
* unless a version migration ran. A store registered before its persist
|
|
297
|
+
* middleware attached has no handle — then there is simply no button.
|
|
298
|
+
*/
|
|
299
|
+
function RereadSavedValue({
|
|
300
|
+
store,
|
|
301
|
+
rowID
|
|
302
|
+
}) {
|
|
303
|
+
const [busy, setBusy] = useState(false);
|
|
304
|
+
const [error, setError] = useState(null);
|
|
305
|
+
if (!store.rehydrate) return null;
|
|
306
|
+
const reread = () => {
|
|
307
|
+
setBusy(true);
|
|
308
|
+
setError(null);
|
|
309
|
+
void (async () => {
|
|
310
|
+
try {
|
|
311
|
+
await store.rehydrate?.();
|
|
312
|
+
} catch (e) {
|
|
313
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
314
|
+
} finally {
|
|
315
|
+
setBusy(false);
|
|
316
|
+
}
|
|
317
|
+
})();
|
|
318
|
+
};
|
|
319
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
320
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
321
|
+
onPress: reread,
|
|
322
|
+
disabled: busy,
|
|
323
|
+
style: styles.inlineLinkButton,
|
|
324
|
+
hitSlop: {
|
|
325
|
+
top: 6,
|
|
326
|
+
bottom: 6,
|
|
327
|
+
left: 6,
|
|
328
|
+
right: 6
|
|
329
|
+
},
|
|
330
|
+
testID: `${rowID}-reread`,
|
|
331
|
+
accessibilityRole: "button",
|
|
332
|
+
accessibilityLabel: `Re-read ${store.name} from storage`,
|
|
333
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
334
|
+
style: [styles.inlineLinkText, {
|
|
335
|
+
color: store.color
|
|
336
|
+
}],
|
|
337
|
+
children: busy ? "re-reading…" : "re-read saved value →"
|
|
338
|
+
})
|
|
339
|
+
}), error ? /*#__PURE__*/_jsx(Text, {
|
|
340
|
+
style: [styles.inlineLinkText, {
|
|
341
|
+
color: night.color.danger
|
|
342
|
+
}],
|
|
343
|
+
children: error
|
|
344
|
+
}) : null]
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
const styles = StyleSheet.create({
|
|
348
|
+
root: {
|
|
349
|
+
flex: 1,
|
|
350
|
+
minHeight: 0
|
|
351
|
+
},
|
|
352
|
+
scroll: {
|
|
353
|
+
flex: 1
|
|
354
|
+
},
|
|
355
|
+
scrollContent: {
|
|
356
|
+
paddingHorizontal: 8,
|
|
357
|
+
paddingTop: 8,
|
|
358
|
+
paddingBottom: 24
|
|
359
|
+
},
|
|
360
|
+
section: {
|
|
361
|
+
marginBottom: 16
|
|
362
|
+
},
|
|
363
|
+
// The editable section wears the accent, like RQ's Data Editor — the one
|
|
364
|
+
// box on this screen that changes things should read differently from the
|
|
365
|
+
// two that don't.
|
|
366
|
+
editorContainer: {
|
|
367
|
+
minWidth: 200,
|
|
368
|
+
backgroundColor: night.color.surface,
|
|
369
|
+
borderRadius: 6,
|
|
370
|
+
borderWidth: 1,
|
|
371
|
+
borderColor: night.color.accent + "4D",
|
|
372
|
+
overflow: "hidden",
|
|
373
|
+
shadowColor: night.color.accent,
|
|
374
|
+
shadowOffset: {
|
|
375
|
+
width: 0,
|
|
376
|
+
height: 0
|
|
377
|
+
},
|
|
378
|
+
shadowOpacity: 0.1,
|
|
379
|
+
shadowRadius: 6
|
|
380
|
+
},
|
|
381
|
+
sectionHeaderRow: {
|
|
382
|
+
flexDirection: "row",
|
|
383
|
+
alignItems: "center",
|
|
384
|
+
justifyContent: "space-between",
|
|
385
|
+
backgroundColor: night.color.accent + "1A",
|
|
386
|
+
paddingHorizontal: 12,
|
|
387
|
+
paddingVertical: 8,
|
|
388
|
+
borderBottomWidth: 1,
|
|
389
|
+
borderBottomColor: night.color.accent + "33"
|
|
390
|
+
},
|
|
391
|
+
sectionHeaderText: {
|
|
392
|
+
fontWeight: "600",
|
|
393
|
+
fontSize: 12,
|
|
394
|
+
color: night.color.accent,
|
|
395
|
+
letterSpacing: 0.5,
|
|
396
|
+
textTransform: "uppercase",
|
|
397
|
+
fontFamily: "monospace"
|
|
398
|
+
},
|
|
399
|
+
rawButton: {
|
|
400
|
+
flexDirection: "row",
|
|
401
|
+
alignItems: "center",
|
|
402
|
+
gap: 4
|
|
403
|
+
},
|
|
404
|
+
rawButtonText: {
|
|
405
|
+
color: night.color.accent,
|
|
406
|
+
fontSize: 11,
|
|
407
|
+
fontWeight: "700"
|
|
408
|
+
},
|
|
409
|
+
sectionBody: {
|
|
410
|
+
padding: 8
|
|
411
|
+
},
|
|
412
|
+
editorHint: {
|
|
413
|
+
color: night.color.textTertiary,
|
|
414
|
+
fontSize: 10,
|
|
415
|
+
paddingTop: 8,
|
|
416
|
+
paddingHorizontal: 4,
|
|
417
|
+
lineHeight: 14
|
|
418
|
+
},
|
|
419
|
+
blockedText: {
|
|
420
|
+
color: night.color.textSecondary,
|
|
421
|
+
fontSize: 12,
|
|
422
|
+
padding: 12,
|
|
423
|
+
lineHeight: 18
|
|
424
|
+
},
|
|
425
|
+
infoContainer: {
|
|
426
|
+
minWidth: 200,
|
|
427
|
+
backgroundColor: night.color.surface,
|
|
428
|
+
borderRadius: 6,
|
|
429
|
+
borderWidth: 1,
|
|
430
|
+
borderColor: night.color.border,
|
|
431
|
+
overflow: "hidden"
|
|
432
|
+
},
|
|
433
|
+
sectionHeaderTextPlain: {
|
|
434
|
+
backgroundColor: night.color.surfaceElevated,
|
|
435
|
+
paddingHorizontal: 12,
|
|
436
|
+
paddingVertical: 8,
|
|
437
|
+
fontWeight: "600",
|
|
438
|
+
fontSize: 12,
|
|
439
|
+
color: night.color.textSecondary,
|
|
440
|
+
borderBottomWidth: 1,
|
|
441
|
+
borderBottomColor: night.color.border,
|
|
442
|
+
letterSpacing: 0.5,
|
|
443
|
+
textTransform: "uppercase",
|
|
444
|
+
fontFamily: "monospace"
|
|
445
|
+
},
|
|
446
|
+
infoBody: {
|
|
447
|
+
padding: 12,
|
|
448
|
+
gap: 10
|
|
449
|
+
},
|
|
450
|
+
viewerBody: {
|
|
451
|
+
backgroundColor: night.color.bg,
|
|
452
|
+
minHeight: 60
|
|
453
|
+
},
|
|
454
|
+
inlineLinkButton: {
|
|
455
|
+
marginLeft: 4
|
|
456
|
+
},
|
|
457
|
+
inlineLinkText: {
|
|
458
|
+
fontSize: 10,
|
|
459
|
+
fontWeight: "600",
|
|
460
|
+
fontFamily: "monospace"
|
|
461
|
+
},
|
|
462
|
+
actionsText: {
|
|
463
|
+
flex: 1,
|
|
464
|
+
color: night.color.textSecondary,
|
|
465
|
+
fontSize: 10,
|
|
466
|
+
fontFamily: "monospace",
|
|
467
|
+
lineHeight: 15
|
|
468
|
+
}
|
|
469
|
+
});
|