@buoy-gg/shared-ui 7.0.30 → 7.0.31

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