@buoy-gg/shared-ui 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/JsModal.js +18 -2
- package/lib/commonjs/JsModal.web.js +7 -4
- package/lib/commonjs/dataViewer/DataTreeActionDock.js +4 -2
- package/lib/commonjs/dataViewer/LiveExplorer.js +930 -0
- package/lib/commonjs/dataViewer/ValueEditModal.js +385 -0
- package/lib/commonjs/dataViewer/index.js +47 -0
- package/lib/commonjs/dataViewer/nestedPath.js +115 -0
- package/lib/commonjs/dataViewer/treeActions.js +3 -2
- package/lib/commonjs/dataViewer/useTreeDraft.js +125 -0
- package/lib/commonjs/dataViewer/useTreeEditor.js +105 -0
- package/lib/commonjs/env/EnvironmentIndicator.js +7 -1
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/index.js +24 -0
- package/lib/commonjs/license/tierLimits.js +14 -0
- package/lib/commonjs/storage/devToolsStorageKeys.js +36 -0
- package/lib/commonjs/sync/toolActionRegistry.js +166 -0
- package/lib/commonjs/sync/toolUiBridge.js +74 -0
- package/lib/commonjs/ui/components/CompactRow.js +4 -0
- package/lib/commonjs/ui/components/EventHistoryViewer/DiffModeTabs.js +9 -1
- package/lib/commonjs/ui/components/ExpandedInfoRow.js +3 -1
- package/lib/commonjs/ui/components/ModalHeader.js +12 -4
- package/lib/commonjs/ui/components/SearchBar.js +5 -109
- package/lib/commonjs/ui/components/ToolButton.js +5 -2
- package/lib/commonjs/ui/components/index.js +13 -0
- package/lib/commonjs/ui/components/windowDrag.js +45 -0
- package/lib/module/JsModal.js +18 -2
- package/lib/module/JsModal.web.js +7 -4
- package/lib/module/dataViewer/DataTreeActionDock.js +4 -2
- package/lib/module/dataViewer/LiveExplorer.js +925 -0
- package/lib/module/dataViewer/ValueEditModal.js +381 -0
- package/lib/module/dataViewer/index.js +10 -1
- package/lib/module/dataViewer/nestedPath.js +109 -0
- package/lib/module/dataViewer/treeActions.js +3 -2
- package/lib/module/dataViewer/useTreeDraft.js +121 -0
- package/lib/module/dataViewer/useTreeEditor.js +101 -0
- package/lib/module/env/EnvironmentIndicator.js +7 -1
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/license/tierLimits.js +14 -0
- package/lib/module/storage/devToolsStorageKeys.js +36 -0
- package/lib/module/sync/toolActionRegistry.js +154 -0
- package/lib/module/sync/toolUiBridge.js +68 -0
- package/lib/module/ui/components/CompactRow.js +4 -0
- package/lib/module/ui/components/EventHistoryViewer/DiffModeTabs.js +9 -1
- package/lib/module/ui/components/ExpandedInfoRow.js +3 -1
- package/lib/module/ui/components/ModalHeader.js +12 -4
- package/lib/module/ui/components/SearchBar.js +8 -112
- package/lib/module/ui/components/ToolButton.js +5 -2
- package/lib/module/ui/components/index.js +1 -0
- package/lib/module/ui/components/windowDrag.js +41 -0
- package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/JsModal.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts +6 -1
- package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/LiveExplorer.d.ts +73 -0
- package/lib/typescript/commonjs/dataViewer/LiveExplorer.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/ValueEditModal.d.ts +40 -0
- package/lib/typescript/commonjs/dataViewer/ValueEditModal.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/index.d.ts +5 -0
- package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/nestedPath.d.ts +20 -0
- package/lib/typescript/commonjs/dataViewer/nestedPath.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/treeActions.d.ts +10 -0
- package/lib/typescript/commonjs/dataViewer/treeActions.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/useTreeDraft.d.ts +81 -0
- package/lib/typescript/commonjs/dataViewer/useTreeDraft.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/useTreeEditor.d.ts +52 -0
- package/lib/typescript/commonjs/dataViewer/useTreeEditor.d.ts.map +1 -0
- package/lib/typescript/commonjs/env/EnvironmentIndicator.d.ts.map +1 -1
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/tierLimits.d.ts +10 -0
- package/lib/typescript/commonjs/license/tierLimits.d.ts.map +1 -1
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +36 -0
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/sync/toolActionRegistry.d.ts +85 -0
- package/lib/typescript/commonjs/sync/toolActionRegistry.d.ts.map +1 -0
- package/lib/typescript/commonjs/sync/toolUiBridge.d.ts +39 -0
- package/lib/typescript/commonjs/sync/toolUiBridge.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/CompactRow.d.ts +5 -1
- package/lib/typescript/commonjs/ui/components/CompactRow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/DiffModeTabs.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/types.d.ts +6 -0
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ExpandedInfoRow.d.ts +7 -1
- package/lib/typescript/commonjs/ui/components/ExpandedInfoRow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/SearchBar.d.ts +1 -3
- package/lib/typescript/commonjs/ui/components/SearchBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ToolButton.d.ts +5 -1
- package/lib/typescript/commonjs/ui/components/ToolButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/index.d.ts +1 -0
- package/lib/typescript/commonjs/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/windowDrag.d.ts +39 -0
- package/lib/typescript/commonjs/ui/components/windowDrag.d.ts.map +1 -0
- package/lib/typescript/module/JsModal.d.ts.map +1 -1
- package/lib/typescript/module/JsModal.web.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts +6 -1
- package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/LiveExplorer.d.ts +73 -0
- package/lib/typescript/module/dataViewer/LiveExplorer.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/ValueEditModal.d.ts +40 -0
- package/lib/typescript/module/dataViewer/ValueEditModal.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/index.d.ts +5 -0
- package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/nestedPath.d.ts +20 -0
- package/lib/typescript/module/dataViewer/nestedPath.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/treeActions.d.ts +10 -0
- package/lib/typescript/module/dataViewer/treeActions.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/useTreeDraft.d.ts +81 -0
- package/lib/typescript/module/dataViewer/useTreeDraft.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/useTreeEditor.d.ts +52 -0
- package/lib/typescript/module/dataViewer/useTreeEditor.d.ts.map +1 -0
- package/lib/typescript/module/env/EnvironmentIndicator.d.ts.map +1 -1
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/license/tierLimits.d.ts +10 -0
- package/lib/typescript/module/license/tierLimits.d.ts.map +1 -1
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +36 -0
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/module/sync/toolActionRegistry.d.ts +85 -0
- package/lib/typescript/module/sync/toolActionRegistry.d.ts.map +1 -0
- package/lib/typescript/module/sync/toolUiBridge.d.ts +39 -0
- package/lib/typescript/module/sync/toolUiBridge.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/CompactRow.d.ts +5 -1
- package/lib/typescript/module/ui/components/CompactRow.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/DiffModeTabs.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/types.d.ts +6 -0
- package/lib/typescript/module/ui/components/EventHistoryViewer/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ExpandedInfoRow.d.ts +7 -1
- package/lib/typescript/module/ui/components/ExpandedInfoRow.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ModalHeader.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/SearchBar.d.ts +1 -3
- package/lib/typescript/module/ui/components/SearchBar.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ToolButton.d.ts +5 -1
- package/lib/typescript/module/ui/components/ToolButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/index.d.ts +1 -0
- package/lib/typescript/module/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/windowDrag.d.ts +39 -0
- package/lib/typescript/module/ui/components/windowDrag.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,925 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The LIVE data editor — a recursive JSON tree whose leaves are inputs.
|
|
5
|
+
*
|
|
6
|
+
* Hoisted from @buoy-gg/react-query's `query-browser/Explorer.tsx` (the Data
|
|
7
|
+
* Editor that tool has always shipped) so every tool edits data through ONE
|
|
8
|
+
* implementation: react-query wraps it with a setQueryData writer, zustand
|
|
9
|
+
* with a merge-only setState writer, storage with a whole-key writer. There
|
|
10
|
+
* is no draft and no Save: each change writes through immediately (or on a
|
|
11
|
+
* short debounce — see below) and the app reacts while you type.
|
|
12
|
+
*
|
|
13
|
+
* What a leaf renders as is the ORIGINAL value's type, which is also what
|
|
14
|
+
* keeps edits type-safe without asking anything: strings and numbers get an
|
|
15
|
+
* inline input (numbers with +/- steppers and a numeric keyboard), booleans a
|
|
16
|
+
* one-tap TRUE/FALSE toggle, container members a delete ✕, arrays a clear-[]
|
|
17
|
+
* button. Structural edits this tree can't express (add key, rename) belong
|
|
18
|
+
* to the host's Raw escape hatch, not here.
|
|
19
|
+
*
|
|
20
|
+
* The one knob the RQ original doesn't use: `debounceMs`. A cache write is
|
|
21
|
+
* free and unlogged, so RQ writes per keystroke (`debounceMs: 0`). Zustand
|
|
22
|
+
* and storage writes are RECORDED — events timeline, per-store change counts,
|
|
23
|
+
* the free tier's change cap — and storage's hit disk, so those hosts pass
|
|
24
|
+
* ~300ms: the input echoes instantly, the write lands one beat after you stop
|
|
25
|
+
* typing (flushed on blur/unmount), and "granola" is one recorded change
|
|
26
|
+
* instead of seven. Discrete gestures — toggle, stepper, delete, clear —
|
|
27
|
+
* always write immediately.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { useState, useMemo, useCallback, useRef, useEffect, memo } from "react";
|
|
31
|
+
import { Text, TouchableOpacity, View, StyleSheet } from "react-native";
|
|
32
|
+
import { displayValue } from "../utils/displayValue.js";
|
|
33
|
+
import { night } from "../ui/night/nightTheme.js";
|
|
34
|
+
import { CopyButton as SharedCopyButton } from "../ui/components/CopyButton.js";
|
|
35
|
+
import { ChevronRight, ChevronDown, Trash } from "../icons/index.js";
|
|
36
|
+
import { CyberpunkInput } from "./CyberpunkInput.js";
|
|
37
|
+
import { updateNestedDataByPath, deleteNestedDataByPath } from "./nestedPath.js";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* How the explorer writes into whatever owns the data. The tree never mutates
|
|
41
|
+
* anything itself — every edit is handed to the host through this.
|
|
42
|
+
*/
|
|
43
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
44
|
+
// Stable constants to prevent re-renders [[memory:4875251]]
|
|
45
|
+
const CHUNK_SIZE = 100;
|
|
46
|
+
const HIT_SLOP_OPTIMIZED = {
|
|
47
|
+
top: 8,
|
|
48
|
+
bottom: 8,
|
|
49
|
+
left: 8,
|
|
50
|
+
right: 8
|
|
51
|
+
};
|
|
52
|
+
const EXPANDER_SIZE = 12;
|
|
53
|
+
|
|
54
|
+
/** Section labels drawn with the heavier "main section" treatment. */
|
|
55
|
+
const MAIN_SECTION_LABELS = ["DATA", "STATE", "VALUE", "QUERY", "QUERYKEY", "TYPES", "STATS", "OPTIONS", "OBSERVERS"];
|
|
56
|
+
const slugPart = part => part.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
57
|
+
|
|
58
|
+
/** Default handle scheme; hosts pass their own to keep an existing namespace. */
|
|
59
|
+
function defaultTestIDForPath(dataPath) {
|
|
60
|
+
return dataPath.length === 0 ? "buoy-live-explorer-root" : `buoy-live-explorer-${dataPath.map(slugPart).filter(Boolean).join("-")}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Optimized chunking function moved to module scope [[memory:4875251]]
|
|
64
|
+
const chunkArray = (array, size = CHUNK_SIZE) => {
|
|
65
|
+
if (size < 1 || array.length === 0) return [];
|
|
66
|
+
const result = [];
|
|
67
|
+
for (let i = 0; i < array.length; i += size) {
|
|
68
|
+
result.push(array.slice(i, i + size));
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Memoized Expander component for performance [[memory:4875251]]
|
|
74
|
+
const Expander = /*#__PURE__*/memo(({
|
|
75
|
+
expanded,
|
|
76
|
+
isFocused = false,
|
|
77
|
+
isMain = false
|
|
78
|
+
}) => {
|
|
79
|
+
return /*#__PURE__*/_jsx(View, {
|
|
80
|
+
style: [styles.expanderIcon, isMain && styles.expanderIconMain, expanded ? styles.expanded : styles.collapsed],
|
|
81
|
+
children: expanded ? /*#__PURE__*/_jsx(ChevronDown, {
|
|
82
|
+
size: isMain ? 14 : EXPANDER_SIZE,
|
|
83
|
+
color: isFocused ? night.color.accent : isMain ? night.color.text : night.color.textSecondary,
|
|
84
|
+
strokeWidth: 2.5
|
|
85
|
+
}) : /*#__PURE__*/_jsx(ChevronRight, {
|
|
86
|
+
size: isMain ? 14 : EXPANDER_SIZE,
|
|
87
|
+
color: isFocused ? night.color.accent : isMain ? night.color.text : night.color.textSecondary,
|
|
88
|
+
strokeWidth: 2.5
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
Expander.displayName = "Expander";
|
|
93
|
+
const CopyButton = /*#__PURE__*/memo(({
|
|
94
|
+
value,
|
|
95
|
+
isFocused = false
|
|
96
|
+
}) => {
|
|
97
|
+
return /*#__PURE__*/_jsx(SharedCopyButton, {
|
|
98
|
+
value: value,
|
|
99
|
+
isFocused: isFocused,
|
|
100
|
+
buttonStyle: isFocused ? {
|
|
101
|
+
...styles.buttonStyle,
|
|
102
|
+
...styles.buttonStyleFocused
|
|
103
|
+
} : styles.buttonStyle
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
CopyButton.displayName = "CopyButton";
|
|
107
|
+
|
|
108
|
+
// Memoized DeleteItemButton component [[memory:4875251]]
|
|
109
|
+
const DeleteItemButton = /*#__PURE__*/memo(({
|
|
110
|
+
dataPath,
|
|
111
|
+
writer,
|
|
112
|
+
testID,
|
|
113
|
+
isFocused = false
|
|
114
|
+
}) => {
|
|
115
|
+
const handleDelete = useCallback(() => {
|
|
116
|
+
writer?.remove?.(dataPath);
|
|
117
|
+
}, [writer, dataPath]);
|
|
118
|
+
if (!writer?.remove) return null;
|
|
119
|
+
return /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
120
|
+
"sentry-label": "ignore devtools explorer delete button",
|
|
121
|
+
testID: `${testID}-delete`,
|
|
122
|
+
accessibilityRole: "button",
|
|
123
|
+
onPress: handleDelete,
|
|
124
|
+
style: [styles.deleteButton, isFocused && styles.deleteButtonFocused],
|
|
125
|
+
accessibilityLabel: "Delete item",
|
|
126
|
+
hitSlop: HIT_SLOP_OPTIMIZED,
|
|
127
|
+
activeOpacity: 0.7,
|
|
128
|
+
children: /*#__PURE__*/_jsx(Trash, {
|
|
129
|
+
size: 14,
|
|
130
|
+
strokeWidth: 2,
|
|
131
|
+
color: isFocused ? night.color.danger : night.color.danger + "CC"
|
|
132
|
+
})
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
DeleteItemButton.displayName = "DeleteItemButton";
|
|
136
|
+
|
|
137
|
+
// Memoized ClearArrayButton component [[memory:4875251]]
|
|
138
|
+
const ClearArrayButton = /*#__PURE__*/memo(({
|
|
139
|
+
dataPath,
|
|
140
|
+
writer,
|
|
141
|
+
testID,
|
|
142
|
+
isFocused = false
|
|
143
|
+
}) => {
|
|
144
|
+
const handleClear = useCallback(() => {
|
|
145
|
+
writer?.update(dataPath, []);
|
|
146
|
+
}, [writer, dataPath]);
|
|
147
|
+
if (!writer) return null;
|
|
148
|
+
return /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
149
|
+
"sentry-label": "ignore devtools explorer clear button",
|
|
150
|
+
testID: `${testID}-clear`,
|
|
151
|
+
style: [styles.clearButton, isFocused && styles.clearButtonFocused],
|
|
152
|
+
accessibilityRole: "button",
|
|
153
|
+
accessibilityLabel: "Remove all items",
|
|
154
|
+
"aria-label": "Remove all items",
|
|
155
|
+
onPress: handleClear,
|
|
156
|
+
hitSlop: HIT_SLOP_OPTIMIZED,
|
|
157
|
+
activeOpacity: 0.7,
|
|
158
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
159
|
+
style: [styles.clearButtonText, {
|
|
160
|
+
color: isFocused ? night.color.warning : night.color.warning + "CC"
|
|
161
|
+
}],
|
|
162
|
+
children: "[]"
|
|
163
|
+
})
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
ClearArrayButton.displayName = "ClearArrayButton";
|
|
167
|
+
|
|
168
|
+
// ToggleValueButton - not memoized because parent passes new dataPath array
|
|
169
|
+
// each render which defeats memo anyway, and we need reliable re-renders when
|
|
170
|
+
// value changes
|
|
171
|
+
function ToggleValueButton({
|
|
172
|
+
dataPath,
|
|
173
|
+
writer,
|
|
174
|
+
testID,
|
|
175
|
+
value,
|
|
176
|
+
removable
|
|
177
|
+
}) {
|
|
178
|
+
const handleClick = useCallback(() => {
|
|
179
|
+
if (!writer) return;
|
|
180
|
+
const currentValue = typeof value === "boolean" ? value : false;
|
|
181
|
+
writer.update(dataPath, !currentValue);
|
|
182
|
+
}, [writer, dataPath, value]);
|
|
183
|
+
const handleDelete = useCallback(() => {
|
|
184
|
+
writer?.remove?.(dataPath);
|
|
185
|
+
}, [writer, dataPath]);
|
|
186
|
+
if (!writer) return null;
|
|
187
|
+
|
|
188
|
+
// Pre-compute styles based on value state
|
|
189
|
+
const badgeStyle = value ? styles.toggleBadgeTrue : styles.toggleBadgeFalse;
|
|
190
|
+
const textStyle = value ? styles.toggleTextTrue : styles.toggleTextFalse;
|
|
191
|
+
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
192
|
+
"sentry-label": "ignore devtools explorer toggle button",
|
|
193
|
+
testID: `${testID}-toggle`,
|
|
194
|
+
accessibilityRole: "button",
|
|
195
|
+
accessibilityLabel: `${dataPath[dataPath.length - 1] ?? "value"}, ${value ? "true" : "false"}`,
|
|
196
|
+
style: styles.modernToggleButton,
|
|
197
|
+
onPress: handleClick,
|
|
198
|
+
hitSlop: HIT_SLOP_OPTIMIZED,
|
|
199
|
+
activeOpacity: 0.8,
|
|
200
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
201
|
+
style: [styles.toggleBadge, badgeStyle],
|
|
202
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
203
|
+
style: [styles.toggleBadgeText, textStyle],
|
|
204
|
+
children: value ? "TRUE" : "FALSE"
|
|
205
|
+
})
|
|
206
|
+
}), removable && writer.remove && /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
207
|
+
"sentry-label": "ignore devtools explorer delete button in toggle",
|
|
208
|
+
testID: `${testID}-delete`,
|
|
209
|
+
accessibilityRole: "button",
|
|
210
|
+
onPress: handleDelete,
|
|
211
|
+
style: styles.deleteButtonInToggle,
|
|
212
|
+
accessibilityLabel: "Delete item",
|
|
213
|
+
hitSlop: HIT_SLOP_OPTIMIZED,
|
|
214
|
+
activeOpacity: 0.7,
|
|
215
|
+
children: /*#__PURE__*/_jsx(Trash, {
|
|
216
|
+
size: 14,
|
|
217
|
+
strokeWidth: 2,
|
|
218
|
+
color: night.color.danger + "CC"
|
|
219
|
+
})
|
|
220
|
+
})]
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
// Optimized Explorer component following rule2 guidelines [[memory:4875251]]
|
|
224
|
+
/**
|
|
225
|
+
* Recursive live data explorer — see the module docstring. Used for both
|
|
226
|
+
* editable and read-only JSON trees.
|
|
227
|
+
*/
|
|
228
|
+
export function LiveExplorer({
|
|
229
|
+
editable,
|
|
230
|
+
label,
|
|
231
|
+
value,
|
|
232
|
+
defaultExpanded,
|
|
233
|
+
writer,
|
|
234
|
+
dataPath,
|
|
235
|
+
itemsDeletable,
|
|
236
|
+
dataVersion = 0,
|
|
237
|
+
testIDForPath = defaultTestIDForPath,
|
|
238
|
+
debounceMs = 0
|
|
239
|
+
}) {
|
|
240
|
+
const [isRowFocused, setIsRowFocused] = useState(false);
|
|
241
|
+
|
|
242
|
+
// Local state for input value to handle typing properly
|
|
243
|
+
const [localInputValue, setLocalInputValue] = useState("");
|
|
244
|
+
|
|
245
|
+
// Sync local state with prop value
|
|
246
|
+
// ⚠️ CRITICAL: Do NOT add localInputValue to the dependency array!
|
|
247
|
+
// Adding localInputValue causes a race condition where user edits get reverted:
|
|
248
|
+
// 1. User types "5101" → setLocalInputValue("5101")
|
|
249
|
+
// 2. The owner updates
|
|
250
|
+
// 3. useEffect fires because localInputValue changed
|
|
251
|
+
// 4. At this moment, value prop is still old (5100)
|
|
252
|
+
// 5. Syncs back to 5100, reverting user's change ❌
|
|
253
|
+
// Only sync when EXTERNAL changes happen (value, label, dataVersion)
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
if (value !== null && value !== undefined && (typeof value === "string" || typeof value === "number")) {
|
|
256
|
+
const newValue = value.toString();
|
|
257
|
+
setLocalInputValue(newValue);
|
|
258
|
+
}
|
|
259
|
+
}, [value, label, dataVersion]); // ⚠️ DO NOT add localInputValue here!
|
|
260
|
+
|
|
261
|
+
// Determine if this is a main section
|
|
262
|
+
const isMainSection = useMemo(() => {
|
|
263
|
+
return MAIN_SECTION_LABELS.includes(label.toUpperCase());
|
|
264
|
+
}, [label]);
|
|
265
|
+
|
|
266
|
+
// Explorer's section is expanded or collapsed
|
|
267
|
+
const [isExpanded, setIsExpanded] = useState((defaultExpanded || []).includes(label));
|
|
268
|
+
// Remove unnecessary useCallback - simple state setter [[memory:4875251]]
|
|
269
|
+
const toggleExpanded = () => setIsExpanded(old => !old);
|
|
270
|
+
const [expandedPages, setExpandedPages] = useState([]);
|
|
271
|
+
|
|
272
|
+
// Optimized subEntries computation with early returns [[memory:4875251]]
|
|
273
|
+
const subEntries = useMemo(() => {
|
|
274
|
+
if (value === null || value === undefined || typeof value !== "object") {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
if (Array.isArray(value)) {
|
|
278
|
+
const limitedValue = value.length > 1000 ? value.slice(0, 1000) : value;
|
|
279
|
+
return limitedValue.map((d, i) => ({
|
|
280
|
+
label: i.toString(),
|
|
281
|
+
value: d
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
if (value instanceof Map) {
|
|
285
|
+
const entries = Array.from(value.entries()).slice(0, 1000);
|
|
286
|
+
return entries.map(([key, val]) => ({
|
|
287
|
+
label: key.toString(),
|
|
288
|
+
value: val
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
if (value instanceof Set) {
|
|
292
|
+
const entries = Array.from(value).slice(0, 1000);
|
|
293
|
+
return entries.map((val, i) => ({
|
|
294
|
+
label: i.toString(),
|
|
295
|
+
value: val
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
const entries = Object.entries(value).slice(0, 1000);
|
|
299
|
+
return entries.map(([key, val]) => ({
|
|
300
|
+
label: key,
|
|
301
|
+
value: val
|
|
302
|
+
}));
|
|
303
|
+
}, [value]);
|
|
304
|
+
|
|
305
|
+
// Optimized valueType computation with early returns [[memory:4875251]]
|
|
306
|
+
const valueType = useMemo(() => {
|
|
307
|
+
if (Array.isArray(value)) return "array";
|
|
308
|
+
if (value === null || typeof value !== "object") return typeof value;
|
|
309
|
+
if (value instanceof Map || value instanceof Set) return "Iterable";
|
|
310
|
+
return "object";
|
|
311
|
+
}, [value]);
|
|
312
|
+
|
|
313
|
+
// Optimized chunking with stable chunk size [[memory:4875251]]
|
|
314
|
+
const subEntryPages = useMemo(() => {
|
|
315
|
+
return chunkArray(subEntries, CHUNK_SIZE);
|
|
316
|
+
}, [subEntries]);
|
|
317
|
+
const currentDataPath = dataPath ?? [];
|
|
318
|
+
const nodeTestID = testIDForPath(currentDataPath);
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Whether THIS node may be removed: the parent said its members are
|
|
322
|
+
* deletable, the writer can delete at all, and the writer doesn't veto this
|
|
323
|
+
* path (zustand's top-level keys).
|
|
324
|
+
*/
|
|
325
|
+
const removalAllowed = editable === true && itemsDeletable === true && writer?.remove != null && (writer.canRemove?.(currentDataPath) ?? true);
|
|
326
|
+
|
|
327
|
+
// Optimize handleChange using refs to avoid dependency arrays [[memory:4875251]]
|
|
328
|
+
const writerRef = useRef(writer);
|
|
329
|
+
const dataPathRef = useRef(currentDataPath);
|
|
330
|
+
const valueTypeRef = useRef(valueType);
|
|
331
|
+
writerRef.current = writer;
|
|
332
|
+
dataPathRef.current = currentDataPath;
|
|
333
|
+
valueTypeRef.current = valueType;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Debounced-commit machinery for TYPED input. The pending edit is flushed
|
|
337
|
+
* by the timer, by blur, and by unmount — whichever comes first — so a
|
|
338
|
+
* half-typed value can't be lost, only briefly deferred.
|
|
339
|
+
*/
|
|
340
|
+
const pendingRef = useRef(null);
|
|
341
|
+
const timerRef = useRef(null);
|
|
342
|
+
const flushPending = useCallback(() => {
|
|
343
|
+
if (timerRef.current) {
|
|
344
|
+
clearTimeout(timerRef.current);
|
|
345
|
+
timerRef.current = null;
|
|
346
|
+
}
|
|
347
|
+
const pending = pendingRef.current;
|
|
348
|
+
pendingRef.current = null;
|
|
349
|
+
if (pending) writerRef.current?.update(pending.path, pending.value);
|
|
350
|
+
}, []);
|
|
351
|
+
useEffect(() => () => flushPending(), [flushPending]);
|
|
352
|
+
const debounceMsRef = useRef(debounceMs);
|
|
353
|
+
debounceMsRef.current = debounceMs;
|
|
354
|
+
const handleChange = useCallback((isNumber, newValue) => {
|
|
355
|
+
// Update local state immediately for responsive typing
|
|
356
|
+
setLocalInputValue(newValue);
|
|
357
|
+
if (!writerRef.current) return;
|
|
358
|
+
if (isNumber && isNaN(Number(newValue))) return;
|
|
359
|
+
const updatedValue = valueTypeRef.current === "number" ? Number(newValue) : newValue;
|
|
360
|
+
const ms = debounceMsRef.current;
|
|
361
|
+
if (ms > 0) {
|
|
362
|
+
pendingRef.current = {
|
|
363
|
+
path: dataPathRef.current,
|
|
364
|
+
value: updatedValue
|
|
365
|
+
};
|
|
366
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
367
|
+
timerRef.current = setTimeout(flushPending, ms);
|
|
368
|
+
} else {
|
|
369
|
+
writerRef.current.update(dataPathRef.current, updatedValue);
|
|
370
|
+
}
|
|
371
|
+
}, [flushPending, setLocalInputValue]);
|
|
372
|
+
|
|
373
|
+
/** Steppers are a decision, not typing — commit immediately. */
|
|
374
|
+
const stepNumber = useCallback(delta => {
|
|
375
|
+
const currentNum = Number(localInputValue) || 0;
|
|
376
|
+
const next = currentNum + delta;
|
|
377
|
+
setLocalInputValue(String(next));
|
|
378
|
+
pendingRef.current = null;
|
|
379
|
+
if (timerRef.current) {
|
|
380
|
+
clearTimeout(timerRef.current);
|
|
381
|
+
timerRef.current = null;
|
|
382
|
+
}
|
|
383
|
+
writerRef.current?.update(dataPathRef.current, next);
|
|
384
|
+
}, [localInputValue]);
|
|
385
|
+
return /*#__PURE__*/_jsx(View, {
|
|
386
|
+
style: styles.minWidthWrapper,
|
|
387
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
388
|
+
style: styles.fullWidthMarginRight,
|
|
389
|
+
children: [subEntryPages.length > 0 && /*#__PURE__*/_jsxs(_Fragment, {
|
|
390
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
391
|
+
style: [styles.flexRowItemsCenterGap, isMainSection && styles.flexRowItemsCenterGapMain],
|
|
392
|
+
children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
393
|
+
"sentry-label": "ignore devtools explorer expander button",
|
|
394
|
+
style: styles.expanderButton,
|
|
395
|
+
testID: nodeTestID,
|
|
396
|
+
accessibilityRole: "button",
|
|
397
|
+
accessibilityLabel: `${label}, ${subEntries.length} ${subEntries.length === 1 ? "item" : "items"}`,
|
|
398
|
+
accessibilityState: {
|
|
399
|
+
expanded: isExpanded
|
|
400
|
+
},
|
|
401
|
+
onPress: toggleExpanded,
|
|
402
|
+
hitSlop: HIT_SLOP_OPTIMIZED,
|
|
403
|
+
activeOpacity: 0.6,
|
|
404
|
+
children: [/*#__PURE__*/_jsx(Expander, {
|
|
405
|
+
expanded: isExpanded,
|
|
406
|
+
isFocused: isRowFocused,
|
|
407
|
+
isMain: isMainSection
|
|
408
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
409
|
+
style: [styles.labelText, isRowFocused && styles.labelTextFocused, isMainSection && styles.labelTextMain],
|
|
410
|
+
children: label
|
|
411
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
412
|
+
style: styles.textGray500,
|
|
413
|
+
children: `${String(valueType).toLowerCase() === "iterable" ? "(Iterable) " : ""}${subEntries.length} ${subEntries.length > 1 ? `items` : `item`}`
|
|
414
|
+
})]
|
|
415
|
+
}), editable && /*#__PURE__*/_jsxs(View, {
|
|
416
|
+
style: styles.flexRowGapItemsCenter,
|
|
417
|
+
children: [/*#__PURE__*/_jsx(CopyButton, {
|
|
418
|
+
value: value,
|
|
419
|
+
isFocused: isRowFocused
|
|
420
|
+
}), removalAllowed && /*#__PURE__*/_jsx(DeleteItemButton, {
|
|
421
|
+
writer: writer,
|
|
422
|
+
dataPath: currentDataPath,
|
|
423
|
+
testID: nodeTestID,
|
|
424
|
+
isFocused: isRowFocused
|
|
425
|
+
}), valueType === "array" && writer !== undefined && /*#__PURE__*/_jsx(ClearArrayButton, {
|
|
426
|
+
writer: writer,
|
|
427
|
+
dataPath: currentDataPath,
|
|
428
|
+
testID: nodeTestID,
|
|
429
|
+
isFocused: isRowFocused
|
|
430
|
+
})]
|
|
431
|
+
})]
|
|
432
|
+
}), isExpanded && /*#__PURE__*/_jsxs(_Fragment, {
|
|
433
|
+
children: [subEntryPages.length === 1 && /*#__PURE__*/_jsx(View, {
|
|
434
|
+
style: [styles.singleEntryContainer, isMainSection && styles.singleEntryContainerMain],
|
|
435
|
+
children: subEntries.map((entry, index) => /*#__PURE__*/_jsx(LiveExplorer, {
|
|
436
|
+
defaultExpanded: defaultExpanded,
|
|
437
|
+
label: entry.label,
|
|
438
|
+
value: entry.value,
|
|
439
|
+
editable: editable,
|
|
440
|
+
dataPath: [...currentDataPath, entry.label],
|
|
441
|
+
writer: writer,
|
|
442
|
+
itemsDeletable: valueType === "array" || valueType === "Iterable" || valueType === "object",
|
|
443
|
+
dataVersion: dataVersion,
|
|
444
|
+
testIDForPath: testIDForPath,
|
|
445
|
+
debounceMs: debounceMs
|
|
446
|
+
}, entry.label + index))
|
|
447
|
+
}), subEntryPages.length > 1 && /*#__PURE__*/_jsx(View, {
|
|
448
|
+
style: styles.multiEntryContainer,
|
|
449
|
+
children: subEntryPages.map((entries, index) => /*#__PURE__*/_jsx(View, {
|
|
450
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
451
|
+
style: styles.relativeOutlineNone,
|
|
452
|
+
children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
453
|
+
"sentry-label": "ignore devtools explorer page toggle",
|
|
454
|
+
onPress: () => setExpandedPages(old => old.includes(index) ? old.filter(d => d !== index) : [...old, index]),
|
|
455
|
+
style: styles.pageExpanderButton,
|
|
456
|
+
hitSlop: HIT_SLOP_OPTIMIZED,
|
|
457
|
+
children: [/*#__PURE__*/_jsx(Expander, {
|
|
458
|
+
expanded: expandedPages.includes(index)
|
|
459
|
+
}), /*#__PURE__*/_jsxs(Text, {
|
|
460
|
+
style: styles.pageRangeText,
|
|
461
|
+
children: ["[", index * CHUNK_SIZE, "...", index * CHUNK_SIZE + CHUNK_SIZE - 1, "]"]
|
|
462
|
+
})]
|
|
463
|
+
}), expandedPages.includes(index) && /*#__PURE__*/_jsx(View, {
|
|
464
|
+
style: styles.entriesContainer,
|
|
465
|
+
children: entries.map(entry => /*#__PURE__*/_jsx(LiveExplorer, {
|
|
466
|
+
defaultExpanded: defaultExpanded,
|
|
467
|
+
label: entry.label,
|
|
468
|
+
value: entry.value,
|
|
469
|
+
editable: editable,
|
|
470
|
+
dataPath: [...currentDataPath, entry.label],
|
|
471
|
+
writer: writer,
|
|
472
|
+
dataVersion: dataVersion,
|
|
473
|
+
testIDForPath: testIDForPath,
|
|
474
|
+
debounceMs: debounceMs
|
|
475
|
+
}, entry.label))
|
|
476
|
+
})]
|
|
477
|
+
})
|
|
478
|
+
}, index))
|
|
479
|
+
})]
|
|
480
|
+
})]
|
|
481
|
+
}), subEntryPages.length === 0 && /*#__PURE__*/_jsxs(View, {
|
|
482
|
+
style: styles.flexRowGapFullWidth,
|
|
483
|
+
children: [editable && writer !== undefined && (valueType === "string" || valueType === "number" || valueType === "boolean") ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
484
|
+
children: [editable && writer && (valueType === "string" || valueType === "number") && /*#__PURE__*/_jsx(View, {
|
|
485
|
+
style: styles.nebulaInputWrapper,
|
|
486
|
+
children: /*#__PURE__*/_jsx(CyberpunkInput, {
|
|
487
|
+
label: label,
|
|
488
|
+
testID: `${nodeTestID}-input`,
|
|
489
|
+
accessibilityLabel: `${label}, editable value`,
|
|
490
|
+
style: [valueType === "number" ? styles.textNumber : styles.textString],
|
|
491
|
+
keyboardType: valueType === "number" ? "numeric" : "default",
|
|
492
|
+
value: localInputValue,
|
|
493
|
+
onChangeText: newValue => handleChange(valueType === "number", newValue),
|
|
494
|
+
onFocus: () => setIsRowFocused(true),
|
|
495
|
+
onBlur: () => {
|
|
496
|
+
// The pending debounced edit rides along with focus
|
|
497
|
+
// leaving the field — nothing typed is ever dropped.
|
|
498
|
+
flushPending();
|
|
499
|
+
setIsRowFocused(false);
|
|
500
|
+
},
|
|
501
|
+
showNumberControls: valueType === "number",
|
|
502
|
+
onIncrement: () => stepNumber(1),
|
|
503
|
+
onDecrement: () => stepNumber(-1),
|
|
504
|
+
showDeleteButton: removalAllowed,
|
|
505
|
+
onDelete: () => {
|
|
506
|
+
writer?.remove?.(currentDataPath);
|
|
507
|
+
}
|
|
508
|
+
})
|
|
509
|
+
}), valueType === "boolean" && /*#__PURE__*/_jsxs(View, {
|
|
510
|
+
style: styles.booleanRowContainer,
|
|
511
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
512
|
+
style: styles.booleanLabel,
|
|
513
|
+
children: label
|
|
514
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
515
|
+
style: styles.booleanToggleWrapper,
|
|
516
|
+
children: /*#__PURE__*/_jsx(ToggleValueButton, {
|
|
517
|
+
writer: writer,
|
|
518
|
+
dataPath: currentDataPath,
|
|
519
|
+
testID: nodeTestID,
|
|
520
|
+
value: value,
|
|
521
|
+
removable: removalAllowed
|
|
522
|
+
})
|
|
523
|
+
})]
|
|
524
|
+
})]
|
|
525
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
526
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
527
|
+
style: styles.text344054,
|
|
528
|
+
children: label
|
|
529
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
530
|
+
testID: `${nodeTestID}-value`,
|
|
531
|
+
style: styles.displayValueText,
|
|
532
|
+
children: displayValue(value)
|
|
533
|
+
})]
|
|
534
|
+
}), editable && removalAllowed && valueType !== "string" && valueType !== "number" && valueType !== "boolean" && /*#__PURE__*/_jsx(DeleteItemButton, {
|
|
535
|
+
writer: writer,
|
|
536
|
+
dataPath: currentDataPath,
|
|
537
|
+
testID: nodeTestID,
|
|
538
|
+
isFocused: isRowFocused
|
|
539
|
+
})]
|
|
540
|
+
})]
|
|
541
|
+
})
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/** A writer for plain local data — host supplies get/set of the whole root. */
|
|
546
|
+
export function makeRootWriter(options) {
|
|
547
|
+
return {
|
|
548
|
+
update: (path, value) => {
|
|
549
|
+
options.setRoot(updateNestedDataByPath(options.getRoot(), path, value));
|
|
550
|
+
},
|
|
551
|
+
remove: path => {
|
|
552
|
+
options.setRoot(deleteNestedDataByPath(options.getRoot(), path));
|
|
553
|
+
},
|
|
554
|
+
canRemove: options.canRemove
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
const styles = StyleSheet.create({
|
|
558
|
+
buttonStyle: {
|
|
559
|
+
backgroundColor: night.color.surface + "E6",
|
|
560
|
+
borderWidth: 1,
|
|
561
|
+
borderColor: night.color.textSecondary + "33",
|
|
562
|
+
borderRadius: 6,
|
|
563
|
+
flexDirection: "row",
|
|
564
|
+
alignItems: "center",
|
|
565
|
+
justifyContent: "center",
|
|
566
|
+
width: 28,
|
|
567
|
+
height: 28,
|
|
568
|
+
position: "relative",
|
|
569
|
+
shadowColor: "#000",
|
|
570
|
+
shadowOffset: {
|
|
571
|
+
width: 0,
|
|
572
|
+
height: 1
|
|
573
|
+
},
|
|
574
|
+
shadowOpacity: 0.2,
|
|
575
|
+
shadowRadius: 2
|
|
576
|
+
},
|
|
577
|
+
buttonStyleFocused: {
|
|
578
|
+
borderColor: night.color.accent + "CC",
|
|
579
|
+
backgroundColor: night.color.accent + "26",
|
|
580
|
+
shadowColor: night.color.accent,
|
|
581
|
+
shadowOpacity: 0.3,
|
|
582
|
+
shadowRadius: 4
|
|
583
|
+
},
|
|
584
|
+
deleteButton: {
|
|
585
|
+
backgroundColor: night.color.danger + "1A",
|
|
586
|
+
borderColor: night.color.danger + "4D",
|
|
587
|
+
borderWidth: 1,
|
|
588
|
+
borderRadius: 6,
|
|
589
|
+
padding: 0,
|
|
590
|
+
alignItems: "center",
|
|
591
|
+
justifyContent: "center",
|
|
592
|
+
width: 28,
|
|
593
|
+
height: 28,
|
|
594
|
+
position: "relative",
|
|
595
|
+
shadowColor: night.color.danger,
|
|
596
|
+
shadowOffset: {
|
|
597
|
+
width: 0,
|
|
598
|
+
height: 0
|
|
599
|
+
},
|
|
600
|
+
shadowOpacity: 0.15,
|
|
601
|
+
shadowRadius: 3
|
|
602
|
+
},
|
|
603
|
+
deleteButtonFocused: {
|
|
604
|
+
borderColor: night.color.danger + "CC",
|
|
605
|
+
backgroundColor: night.color.danger + "33",
|
|
606
|
+
shadowOpacity: 0.3,
|
|
607
|
+
shadowRadius: 5
|
|
608
|
+
},
|
|
609
|
+
deleteButtonInToggle: {
|
|
610
|
+
backgroundColor: night.color.danger + "1A",
|
|
611
|
+
borderColor: night.color.danger + "4D",
|
|
612
|
+
borderWidth: 1,
|
|
613
|
+
borderRadius: 6,
|
|
614
|
+
padding: 0,
|
|
615
|
+
alignItems: "center",
|
|
616
|
+
justifyContent: "center",
|
|
617
|
+
width: 28,
|
|
618
|
+
height: 28,
|
|
619
|
+
shadowColor: night.color.danger,
|
|
620
|
+
shadowOffset: {
|
|
621
|
+
width: 0,
|
|
622
|
+
height: 0
|
|
623
|
+
},
|
|
624
|
+
shadowOpacity: 0.15,
|
|
625
|
+
shadowRadius: 3
|
|
626
|
+
},
|
|
627
|
+
clearButton: {
|
|
628
|
+
backgroundColor: night.color.warning + "1A",
|
|
629
|
+
borderWidth: 1,
|
|
630
|
+
borderColor: night.color.warning + "4D",
|
|
631
|
+
borderRadius: 6,
|
|
632
|
+
flexDirection: "row",
|
|
633
|
+
padding: 0,
|
|
634
|
+
alignItems: "center",
|
|
635
|
+
justifyContent: "center",
|
|
636
|
+
width: 28,
|
|
637
|
+
height: 28,
|
|
638
|
+
position: "relative",
|
|
639
|
+
zIndex: 10,
|
|
640
|
+
shadowColor: night.color.warning,
|
|
641
|
+
shadowOffset: {
|
|
642
|
+
width: 0,
|
|
643
|
+
height: 0
|
|
644
|
+
},
|
|
645
|
+
shadowOpacity: 0.15,
|
|
646
|
+
shadowRadius: 3
|
|
647
|
+
},
|
|
648
|
+
clearButtonFocused: {
|
|
649
|
+
borderColor: night.color.warning + "CC",
|
|
650
|
+
backgroundColor: night.color.warning + "33",
|
|
651
|
+
shadowOpacity: 0.3,
|
|
652
|
+
shadowRadius: 5
|
|
653
|
+
},
|
|
654
|
+
clearButtonText: {
|
|
655
|
+
fontSize: 12,
|
|
656
|
+
fontWeight: "700",
|
|
657
|
+
fontFamily: "monospace"
|
|
658
|
+
},
|
|
659
|
+
expanderIcon: {
|
|
660
|
+
width: 18,
|
|
661
|
+
height: 18,
|
|
662
|
+
alignItems: "center",
|
|
663
|
+
justifyContent: "center",
|
|
664
|
+
marginRight: 1,
|
|
665
|
+
backgroundColor: night.color.textSecondary + "14",
|
|
666
|
+
borderRadius: 3
|
|
667
|
+
},
|
|
668
|
+
expanderIconMain: {
|
|
669
|
+
backgroundColor: night.color.textSecondary + "1A",
|
|
670
|
+
width: 20,
|
|
671
|
+
height: 20,
|
|
672
|
+
borderRadius: 4,
|
|
673
|
+
borderWidth: 0.5,
|
|
674
|
+
borderColor: night.color.textSecondary + "33"
|
|
675
|
+
},
|
|
676
|
+
expanded: {
|
|
677
|
+
transform: [{
|
|
678
|
+
rotate: "0deg"
|
|
679
|
+
}]
|
|
680
|
+
},
|
|
681
|
+
collapsed: {
|
|
682
|
+
transform: [{
|
|
683
|
+
rotate: "0deg"
|
|
684
|
+
}]
|
|
685
|
+
},
|
|
686
|
+
minWidthWrapper: {
|
|
687
|
+
minWidth: 180,
|
|
688
|
+
fontSize: 11,
|
|
689
|
+
flexDirection: "row",
|
|
690
|
+
flexWrap: "wrap",
|
|
691
|
+
width: "100%",
|
|
692
|
+
marginVertical: 0.5
|
|
693
|
+
},
|
|
694
|
+
fullWidthMarginRight: {
|
|
695
|
+
position: "relative",
|
|
696
|
+
width: "100%",
|
|
697
|
+
marginRight: 1
|
|
698
|
+
},
|
|
699
|
+
flexRowItemsCenterGap: {
|
|
700
|
+
flexDirection: "row",
|
|
701
|
+
alignItems: "center",
|
|
702
|
+
justifyContent: "space-between",
|
|
703
|
+
paddingVertical: 3,
|
|
704
|
+
paddingHorizontal: 6,
|
|
705
|
+
marginVertical: 1,
|
|
706
|
+
borderRadius: 4,
|
|
707
|
+
backgroundColor: night.color.surface + "66",
|
|
708
|
+
borderWidth: 0.5,
|
|
709
|
+
borderColor: night.color.textSecondary + "1A"
|
|
710
|
+
},
|
|
711
|
+
flexRowItemsCenterGapMain: {
|
|
712
|
+
backgroundColor: night.color.surface + "E6",
|
|
713
|
+
borderLeftWidth: 2.5,
|
|
714
|
+
borderLeftColor: night.color.textSecondary + "80",
|
|
715
|
+
borderColor: night.color.textSecondary + "26",
|
|
716
|
+
paddingVertical: 5,
|
|
717
|
+
paddingHorizontal: 8,
|
|
718
|
+
marginBottom: 3,
|
|
719
|
+
borderWidth: 1,
|
|
720
|
+
shadowColor: "#000",
|
|
721
|
+
shadowOffset: {
|
|
722
|
+
width: 0,
|
|
723
|
+
height: 0
|
|
724
|
+
},
|
|
725
|
+
shadowOpacity: 0.08,
|
|
726
|
+
shadowRadius: 3
|
|
727
|
+
},
|
|
728
|
+
expanderButton: {
|
|
729
|
+
flexDirection: "row",
|
|
730
|
+
alignItems: "center",
|
|
731
|
+
backgroundColor: "transparent",
|
|
732
|
+
paddingVertical: 1,
|
|
733
|
+
paddingHorizontal: 2,
|
|
734
|
+
gap: 6,
|
|
735
|
+
borderWidth: 0,
|
|
736
|
+
minHeight: 24,
|
|
737
|
+
flex: 1
|
|
738
|
+
},
|
|
739
|
+
labelText: {
|
|
740
|
+
color: night.color.textSecondary,
|
|
741
|
+
fontSize: 10,
|
|
742
|
+
fontWeight: "600",
|
|
743
|
+
marginRight: 4,
|
|
744
|
+
fontFamily: "monospace",
|
|
745
|
+
letterSpacing: 0.4
|
|
746
|
+
},
|
|
747
|
+
labelTextFocused: {
|
|
748
|
+
color: night.color.text
|
|
749
|
+
},
|
|
750
|
+
labelTextMain: {
|
|
751
|
+
color: night.color.text,
|
|
752
|
+
fontSize: 11,
|
|
753
|
+
fontWeight: "700",
|
|
754
|
+
letterSpacing: 0.6
|
|
755
|
+
},
|
|
756
|
+
textGray500: {
|
|
757
|
+
color: night.color.textTertiary,
|
|
758
|
+
fontSize: 10,
|
|
759
|
+
fontWeight: "400",
|
|
760
|
+
fontFamily: "monospace",
|
|
761
|
+
opacity: 0.7
|
|
762
|
+
},
|
|
763
|
+
pageRangeText: {
|
|
764
|
+
color: night.color.textSecondary,
|
|
765
|
+
fontSize: 10,
|
|
766
|
+
fontWeight: "600",
|
|
767
|
+
fontFamily: "monospace"
|
|
768
|
+
},
|
|
769
|
+
flexRowGapItemsCenter: {
|
|
770
|
+
flexDirection: "row",
|
|
771
|
+
alignItems: "center",
|
|
772
|
+
gap: 4,
|
|
773
|
+
paddingLeft: 2
|
|
774
|
+
},
|
|
775
|
+
singleEntryContainer: {
|
|
776
|
+
marginLeft: 2,
|
|
777
|
+
marginTop: 2,
|
|
778
|
+
paddingLeft: 8,
|
|
779
|
+
borderLeftWidth: 1.5,
|
|
780
|
+
borderLeftColor: night.color.textSecondary + "40"
|
|
781
|
+
},
|
|
782
|
+
singleEntryContainerMain: {
|
|
783
|
+
borderLeftColor: night.color.textSecondary + "4D",
|
|
784
|
+
marginLeft: 4,
|
|
785
|
+
paddingLeft: 10
|
|
786
|
+
},
|
|
787
|
+
multiEntryContainer: {
|
|
788
|
+
marginLeft: 2,
|
|
789
|
+
marginTop: 2,
|
|
790
|
+
paddingLeft: 8,
|
|
791
|
+
borderLeftWidth: 1.5,
|
|
792
|
+
borderLeftColor: night.color.textSecondary + "40"
|
|
793
|
+
},
|
|
794
|
+
relativeOutlineNone: {
|
|
795
|
+
position: "relative"
|
|
796
|
+
},
|
|
797
|
+
pageExpanderButton: {
|
|
798
|
+
flexDirection: "row",
|
|
799
|
+
alignItems: "center",
|
|
800
|
+
backgroundColor: night.color.surface + "66",
|
|
801
|
+
paddingVertical: 3,
|
|
802
|
+
paddingHorizontal: 6,
|
|
803
|
+
gap: 6,
|
|
804
|
+
borderRadius: 4,
|
|
805
|
+
borderWidth: 0.5,
|
|
806
|
+
borderColor: night.color.textSecondary + "1A",
|
|
807
|
+
marginBottom: 2,
|
|
808
|
+
minHeight: 24
|
|
809
|
+
},
|
|
810
|
+
entriesContainer: {
|
|
811
|
+
marginLeft: 2,
|
|
812
|
+
paddingLeft: 8,
|
|
813
|
+
marginTop: 2,
|
|
814
|
+
borderLeftWidth: 1.5,
|
|
815
|
+
borderLeftColor: night.color.textSecondary + "40"
|
|
816
|
+
},
|
|
817
|
+
textNumber: {
|
|
818
|
+
color: night.color.text,
|
|
819
|
+
fontWeight: "600",
|
|
820
|
+
fontFamily: "monospace"
|
|
821
|
+
},
|
|
822
|
+
textString: {
|
|
823
|
+
color: night.color.text,
|
|
824
|
+
fontFamily: "monospace"
|
|
825
|
+
},
|
|
826
|
+
flexRowGapFullWidth: {
|
|
827
|
+
flexDirection: "row",
|
|
828
|
+
width: "100%",
|
|
829
|
+
alignItems: "center",
|
|
830
|
+
marginVertical: 1,
|
|
831
|
+
gap: 6,
|
|
832
|
+
paddingHorizontal: 4,
|
|
833
|
+
paddingVertical: 2,
|
|
834
|
+
borderRadius: 3
|
|
835
|
+
},
|
|
836
|
+
text344054: {
|
|
837
|
+
color: night.color.textSecondary,
|
|
838
|
+
fontWeight: "600",
|
|
839
|
+
fontSize: 9,
|
|
840
|
+
minWidth: 50,
|
|
841
|
+
fontFamily: "monospace",
|
|
842
|
+
letterSpacing: 0.4,
|
|
843
|
+
opacity: 0.8
|
|
844
|
+
},
|
|
845
|
+
nebulaInputWrapper: {
|
|
846
|
+
flex: 1,
|
|
847
|
+
width: "100%",
|
|
848
|
+
position: "relative"
|
|
849
|
+
},
|
|
850
|
+
displayValueText: {
|
|
851
|
+
flex: 1,
|
|
852
|
+
color: night.color.text,
|
|
853
|
+
fontWeight: "400",
|
|
854
|
+
fontFamily: "monospace",
|
|
855
|
+
fontSize: 12,
|
|
856
|
+
paddingVertical: 6,
|
|
857
|
+
paddingHorizontal: 10,
|
|
858
|
+
borderRadius: 6,
|
|
859
|
+
borderWidth: 1,
|
|
860
|
+
borderColor: night.color.textTertiary + "66",
|
|
861
|
+
minHeight: 34
|
|
862
|
+
},
|
|
863
|
+
modernToggleButton: {
|
|
864
|
+
flexDirection: "row",
|
|
865
|
+
alignItems: "center",
|
|
866
|
+
justifyContent: "space-between",
|
|
867
|
+
borderRadius: 6,
|
|
868
|
+
borderWidth: 1,
|
|
869
|
+
borderColor: night.color.textTertiary + "99",
|
|
870
|
+
paddingHorizontal: 8,
|
|
871
|
+
paddingVertical: 6,
|
|
872
|
+
marginVertical: 2,
|
|
873
|
+
minHeight: 34,
|
|
874
|
+
gap: 8
|
|
875
|
+
},
|
|
876
|
+
toggleBadge: {
|
|
877
|
+
marginLeft: 6,
|
|
878
|
+
paddingHorizontal: 6,
|
|
879
|
+
paddingVertical: 3,
|
|
880
|
+
borderRadius: 4,
|
|
881
|
+
borderWidth: 1
|
|
882
|
+
},
|
|
883
|
+
toggleBadgeText: {
|
|
884
|
+
fontSize: 9,
|
|
885
|
+
fontWeight: "700",
|
|
886
|
+
textTransform: "uppercase",
|
|
887
|
+
letterSpacing: 0.8,
|
|
888
|
+
fontFamily: "monospace"
|
|
889
|
+
},
|
|
890
|
+
toggleBadgeTrue: {
|
|
891
|
+
backgroundColor: night.color.accent + "1A",
|
|
892
|
+
borderColor: night.color.accent + "4D"
|
|
893
|
+
},
|
|
894
|
+
toggleBadgeFalse: {
|
|
895
|
+
backgroundColor: night.color.textTertiary + "1A",
|
|
896
|
+
borderColor: night.color.textTertiary + "4D"
|
|
897
|
+
},
|
|
898
|
+
toggleTextTrue: {
|
|
899
|
+
color: night.color.accent,
|
|
900
|
+
fontWeight: "600"
|
|
901
|
+
},
|
|
902
|
+
toggleTextFalse: {
|
|
903
|
+
color: night.color.textSecondary,
|
|
904
|
+
fontWeight: "500"
|
|
905
|
+
},
|
|
906
|
+
booleanRowContainer: {
|
|
907
|
+
flexDirection: "row",
|
|
908
|
+
alignItems: "center",
|
|
909
|
+
width: "100%",
|
|
910
|
+
gap: 8,
|
|
911
|
+
paddingVertical: 2
|
|
912
|
+
},
|
|
913
|
+
booleanLabel: {
|
|
914
|
+
color: night.color.textSecondary,
|
|
915
|
+
fontSize: 10,
|
|
916
|
+
fontWeight: "600",
|
|
917
|
+
fontFamily: "monospace",
|
|
918
|
+
letterSpacing: 0.4,
|
|
919
|
+
minWidth: 60,
|
|
920
|
+
flexShrink: 0
|
|
921
|
+
},
|
|
922
|
+
booleanToggleWrapper: {
|
|
923
|
+
flex: 1
|
|
924
|
+
}
|
|
925
|
+
});
|