@buoy-gg/react-query 7.0.29 → 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.
@@ -7,199 +7,30 @@ exports.default = Explorer;
7
7
  var _react = require("react");
8
8
  var _reactQuery = require("@tanstack/react-query");
9
9
  var _updateNestedDataByPath = require("../../utils/updateNestedDataByPath");
10
- var _sharedUi = require("@buoy-gg/shared-ui");
11
10
  var _deleteItem = _interopRequireDefault(require("../../utils/actions/deleteItem"));
12
11
  var _testIDs = require("../../utils/testIDs");
13
- var _reactNative = require("react-native");
14
12
  var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
15
13
  var _jsxRuntime = require("react/jsx-runtime");
16
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
- // Stable constants to prevent re-renders [[memory:4875251]]
18
- const CHUNK_SIZE = 100;
19
- const HIT_SLOP_OPTIMIZED = {
20
- top: 8,
21
- bottom: 8,
22
- left: 8,
23
- right: 8
24
- };
25
- const EXPANDER_SIZE = 12;
26
-
27
- // Optimized chunking function moved to module scope [[memory:4875251]]
28
- const chunkArray = (array, size = CHUNK_SIZE) => {
29
- if (size < 1 || array.length === 0) return [];
30
- const result = [];
31
- for (let i = 0; i < array.length; i += size) {
32
- result.push(array.slice(i, i + size));
33
- }
34
- return result;
35
- };
36
- // Memoized Expander component for performance [[memory:4875251]]
37
- const Expander = /*#__PURE__*/(0, _react.memo)(({
38
- expanded,
39
- isFocused = false,
40
- isMain = false
41
- }) => {
42
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
43
- style: [styles.expanderIcon, isMain && styles.expanderIconMain, expanded ? styles.expanded : styles.collapsed],
44
- children: expanded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronDown, {
45
- size: isMain ? 14 : EXPANDER_SIZE,
46
- color: isFocused ? _sharedUi.night.color.accent : isMain ? _sharedUi.night.color.text : _sharedUi.night.color.textSecondary,
47
- strokeWidth: 2.5
48
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronRight, {
49
- size: isMain ? 14 : EXPANDER_SIZE,
50
- color: isFocused ? _sharedUi.night.color.accent : isMain ? _sharedUi.night.color.text : _sharedUi.night.color.textSecondary,
51
- strokeWidth: 2.5
52
- })
53
- });
54
- });
55
- Expander.displayName = "Expander";
56
- // Local wrapper for the shared CopyButton to maintain backward compatibility
57
- const CopyButton = /*#__PURE__*/(0, _react.memo)(({
58
- value,
59
- isFocused = false
60
- }) => {
61
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CopyButton, {
62
- value: value,
63
- isFocused: isFocused,
64
- buttonStyle: isFocused ? {
65
- ...styles.buttonStyle,
66
- ...styles.buttonStyleFocused
67
- } : styles.buttonStyle
68
- });
69
- });
70
- CopyButton.displayName = "CopyButton";
71
-
72
- // Memoized DeleteItemButton component [[memory:4875251]]
73
- const DeleteItemButton = /*#__PURE__*/(0, _react.memo)(({
74
- dataPath,
75
- activeQuery,
76
- isFocused = false
77
- }) => {
78
- const queryClient = (0, _reactQuery.useQueryClient)();
79
- const handleDelete = (0, _react.useCallback)(() => {
80
- if (!activeQuery) return;
81
- (0, _deleteItem.default)({
82
- queryClient,
83
- activeQuery: activeQuery,
84
- dataPath: dataPath
85
- });
86
- }, [queryClient, activeQuery, dataPath]);
87
- if (!activeQuery) return null;
88
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
89
- "sentry-label": "ignore devtools explorer delete button",
90
- testID: `${(0, _testIDs.explorerTestID)(dataPath)}-delete`,
91
- accessibilityRole: "button",
92
- onPress: handleDelete,
93
- style: [styles.deleteButton, isFocused && styles.deleteButtonFocused],
94
- accessibilityLabel: "Delete item",
95
- hitSlop: HIT_SLOP_OPTIMIZED,
96
- activeOpacity: 0.7,
97
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash, {
98
- size: 14,
99
- strokeWidth: 2,
100
- color: isFocused ? _sharedUi.night.color.danger : _sharedUi.night.color.danger + "CC"
101
- })
102
- });
103
- });
104
- DeleteItemButton.displayName = "DeleteItemButton";
105
- // Memoized ClearArrayButton component [[memory:4875251]]
106
- const ClearArrayButton = /*#__PURE__*/(0, _react.memo)(({
107
- dataPath,
108
- activeQuery,
109
- isFocused = false
110
- }) => {
111
- const queryClient = (0, _reactQuery.useQueryClient)();
112
- const handleClear = (0, _react.useCallback)(() => {
113
- if (!activeQuery) return;
114
- const oldData = activeQuery.state.data;
115
- const newData = (0, _updateNestedDataByPath.updateNestedDataByPath)(oldData, dataPath, []);
116
- queryClient.setQueryData(activeQuery.queryKey, newData);
117
- }, [queryClient, activeQuery, dataPath]);
118
- if (!activeQuery) return null;
119
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
120
- "sentry-label": "ignore devtools explorer clear button",
121
- testID: `${(0, _testIDs.explorerTestID)(dataPath)}-clear`,
122
- style: [styles.clearButton, isFocused && styles.clearButtonFocused],
123
- accessibilityRole: "button",
124
- accessibilityLabel: "Remove all items",
125
- "aria-label": "Remove all items",
126
- onPress: handleClear,
127
- hitSlop: HIT_SLOP_OPTIMIZED,
128
- activeOpacity: 0.7,
129
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
130
- style: [styles.clearButtonText, {
131
- color: isFocused ? _sharedUi.night.color.warning : _sharedUi.night.color.warning + "CC"
132
- }],
133
- children: "[]"
134
- })
135
- });
136
- });
137
- ClearArrayButton.displayName = "ClearArrayButton";
138
- // ToggleValueButton - not memoized because parent Explorer passes new dataPath array each render
139
- // which defeats memo anyway, and we need reliable re-renders when value changes
140
- function ToggleValueButton({
141
- dataPath,
142
- activeQuery,
143
- value,
144
- itemsDeletable
145
- }) {
146
- const queryClient = (0, _reactQuery.useQueryClient)();
147
- const handleClick = (0, _react.useCallback)(() => {
148
- if (!activeQuery) return;
149
- const oldData = activeQuery.state.data;
150
- const currentValue = typeof value === "boolean" ? value : false;
151
- const newData = (0, _updateNestedDataByPath.updateNestedDataByPath)(oldData, dataPath, !currentValue);
152
- queryClient.setQueryData(activeQuery.queryKey, newData);
153
- }, [queryClient, activeQuery, dataPath, value]);
154
- const handleDelete = (0, _react.useCallback)(() => {
155
- if (!activeQuery) return;
156
- (0, _deleteItem.default)({
157
- queryClient,
158
- activeQuery: activeQuery,
159
- dataPath: dataPath
160
- });
161
- }, [queryClient, activeQuery, dataPath]);
162
- if (!activeQuery) return null;
15
+ /**
16
+ * React Query's data explorer — now a thin wrapper over shared-ui's
17
+ * {@link LiveExplorer}, which is this component's own implementation hoisted
18
+ * so every tool (react-query, zustand, storage, whatever comes next) edits
19
+ * data through ONE live editor.
20
+ *
21
+ * Everything RQ-specific stays here and only here:
22
+ * - the WRITER: edits go through `queryClient.setQueryData` against the
23
+ * active query (deletes via `deleteItem`, which forces a fresh reference so
24
+ * observers re-render);
25
+ * - the HANDLE scheme: `explorerTestID` keeps every existing
26
+ * `buoy-rq-explorer-*` testID exactly as the Detox suite knows them;
27
+ * - the cadence: `debounceMs: 0` — a cache write is free and unlogged, so RQ
28
+ * keeps its original per-keystroke behavior.
29
+ */
163
30
 
164
- // Pre-compute styles based on value state
165
- const badgeStyle = value ? styles.toggleBadgeTrue : styles.toggleBadgeFalse;
166
- const textStyle = value ? styles.toggleTextTrue : styles.toggleTextFalse;
167
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
168
- "sentry-label": "ignore devtools explorer toggle button",
169
- testID: `${(0, _testIDs.explorerTestID)(dataPath)}-toggle`,
170
- accessibilityRole: "button",
171
- accessibilityLabel: `${dataPath[dataPath.length - 1] ?? "value"}, ${value ? "true" : "false"}`,
172
- style: styles.modernToggleButton,
173
- onPress: handleClick,
174
- hitSlop: HIT_SLOP_OPTIMIZED,
175
- activeOpacity: 0.8,
176
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
177
- style: [styles.toggleBadge, badgeStyle],
178
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
179
- style: [styles.toggleBadgeText, textStyle],
180
- children: value ? "TRUE" : "FALSE"
181
- })
182
- }), itemsDeletable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
183
- "sentry-label": "ignore devtools explorer delete button in toggle",
184
- testID: `${(0, _testIDs.explorerTestID)(dataPath)}-delete`,
185
- accessibilityRole: "button",
186
- onPress: handleDelete,
187
- style: styles.deleteButtonInToggle,
188
- accessibilityLabel: "Delete item",
189
- hitSlop: HIT_SLOP_OPTIMIZED,
190
- activeOpacity: 0.7,
191
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash, {
192
- size: 14,
193
- strokeWidth: 2,
194
- color: _sharedUi.night.color.danger + "CC"
195
- })
196
- })]
197
- });
198
- }
199
- // Optimized Explorer component following rule2 guidelines [[memory:4875251]]
200
31
  /**
201
- * Recursive data explorer component used for both editable and read-only JSON trees inside the
202
- * React Query dev tools.
32
+ * Recursive data explorer component used for both editable and read-only JSON
33
+ * trees inside the React Query dev tools.
203
34
  */
204
35
  function Explorer({
205
36
  editable,
@@ -212,793 +43,33 @@ function Explorer({
212
43
  dataVersion = 0
213
44
  }) {
214
45
  const queryClient = (0, _reactQuery.useQueryClient)();
215
- const [isRowFocused, setIsRowFocused] = (0, _react.useState)(false);
216
-
217
- // Local state for input value to handle typing properly
218
- const [localInputValue, setLocalInputValue] = (0, _react.useState)("");
219
-
220
- // Sync local state with prop value
221
- // ⚠️ CRITICAL: Do NOT add localInputValue to the dependency array!
222
- // Adding localInputValue causes a race condition where user edits get reverted:
223
- // 1. User types "5101" → setLocalInputValue("5101")
224
- // 2. Cache updates
225
- // 3. useEffect fires because localInputValue changed
226
- // 4. At this moment, value prop is still old (5100)
227
- // 5. Syncs back to 5100, reverting user's change ❌
228
- // Only sync when EXTERNAL changes happen (value, label, dataVersion)
229
- (0, _react.useEffect)(() => {
230
- if (value !== null && value !== undefined && (typeof value === "string" || typeof value === "number")) {
231
- const newValue = value.toString();
232
- setLocalInputValue(newValue);
233
- }
234
- }, [value, label, dataVersion]); // ⚠️ DO NOT add localInputValue here!
235
-
236
- // Determine if this is a main section
237
- const isMainSection = (0, _react.useMemo)(() => {
238
- const upperLabel = label.toUpperCase();
239
- return ["DATA", "QUERY", "QUERYKEY", "TYPES", "STATS", "OPTIONS", "OBSERVERS"].includes(upperLabel);
240
- }, [label]);
241
-
242
- // Explorer's section is expanded or collapsed
243
- const [isExpanded, setIsExpanded] = (0, _react.useState)((defaultExpanded || []).includes(label));
244
- // Remove unnecessary useCallback - simple state setter [[memory:4875251]]
245
- const toggleExpanded = () => setIsExpanded(old => !old);
246
- const [expandedPages, setExpandedPages] = (0, _react.useState)([]);
247
-
248
- // Optimized subEntries computation with early returns and limited processing [[memory:4875251]]
249
- const subEntries = (0, _react.useMemo)(() => {
250
- // Early return for primitive values to avoid unnecessary computation
251
- if (value === null || value === undefined || typeof value !== "object") {
252
- return [];
253
- }
254
- if (Array.isArray(value)) {
255
- // Limit array processing for performance [[memory:4875251]]
256
- const limitedValue = value.length > 1000 ? value.slice(0, 1000) : value;
257
- return limitedValue.map((d, i) => ({
258
- label: i.toString(),
259
- value: d
260
- }));
261
- }
262
- if (value instanceof Map) {
263
- // Limit Map entries for performance
264
- const entries = Array.from(value.entries()).slice(0, 1000);
265
- return entries.map(([key, val]) => ({
266
- label: key.toString(),
267
- value: val
268
- }));
269
- }
270
- if (value instanceof Set) {
271
- // Limit Set entries for performance
272
- const entries = Array.from(value).slice(0, 1000);
273
- return entries.map((val, i) => ({
274
- label: i.toString(),
275
- value: val
276
- }));
277
- }
278
-
279
- // Handle regular objects with key limiting
280
- const entries = Object.entries(value).slice(0, 1000);
281
- return entries.map(([key, val]) => ({
282
- label: key,
283
- value: val
284
- }));
285
- }, [value]);
286
-
287
- // Optimized valueType computation with early returns [[memory:4875251]]
288
- const valueType = (0, _react.useMemo)(() => {
289
- if (Array.isArray(value)) return "array";
290
- if (value === null || typeof value !== "object") return typeof value;
291
- if (value instanceof Map || value instanceof Set) return "Iterable";
292
- return "object";
293
- }, [value]);
294
-
295
- // Optimized chunking with stable chunk size [[memory:4875251]]
296
- const subEntryPages = (0, _react.useMemo)(() => {
297
- return chunkArray(subEntries, CHUNK_SIZE);
298
- }, [subEntries]);
299
- const currentDataPath = dataPath ?? [];
300
-
301
- // Optimize handleChange using refs to avoid dependency arrays [[memory:4875251]]
302
- const activeQueryRef = (0, _react.useRef)(activeQuery);
303
- const dataPathRef = (0, _react.useRef)(currentDataPath);
304
- const valueTypeRef = (0, _react.useRef)(valueType);
305
- activeQueryRef.current = activeQuery;
306
- dataPathRef.current = currentDataPath;
307
- valueTypeRef.current = valueType;
308
- const handleChange = (0, _react.useCallback)((isNumber, newValue) => {
309
- // Update local state immediately for responsive typing
310
- setLocalInputValue(newValue);
311
- if (!activeQueryRef.current) return;
312
- const oldData = activeQueryRef.current.state.data;
313
- if (isNumber && isNaN(Number(newValue))) return;
314
- const updatedValue = valueTypeRef.current === "number" ? Number(newValue) : newValue;
315
- const newData = (0, _updateNestedDataByPath.updateNestedDataByPath)(oldData, dataPathRef.current, updatedValue);
316
- queryClient.setQueryData(activeQueryRef.current.queryKey, newData);
317
- }, [queryClient, setLocalInputValue]);
318
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
319
- style: styles.minWidthWrapper,
320
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
321
- style: styles.fullWidthMarginRight,
322
- children: [subEntryPages.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
323
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
324
- style: [styles.flexRowItemsCenterGap, isMainSection && styles.flexRowItemsCenterGapMain],
325
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
326
- "sentry-label": "ignore devtools explorer expander button",
327
- style: styles.expanderButton,
328
- testID: (0, _testIDs.explorerTestID)(currentDataPath),
329
- accessibilityRole: "button",
330
- accessibilityLabel: `${label}, ${subEntries.length} ${subEntries.length === 1 ? "item" : "items"}`,
331
- accessibilityState: {
332
- expanded: isExpanded
333
- },
334
- onPress: toggleExpanded,
335
- hitSlop: HIT_SLOP_OPTIMIZED,
336
- activeOpacity: 0.6,
337
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Expander, {
338
- expanded: isExpanded,
339
- isFocused: isRowFocused,
340
- isMain: isMainSection
341
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
342
- style: [styles.labelText, isRowFocused && styles.labelTextFocused, isMainSection && styles.labelTextMain],
343
- children: label
344
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
345
- style: styles.textGray500,
346
- children: `${String(valueType).toLowerCase() === "iterable" ? "(Iterable) " : ""}${subEntries.length} ${subEntries.length > 1 ? `items` : `item`}`
347
- })]
348
- }), editable && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
349
- style: styles.flexRowGapItemsCenter,
350
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(CopyButton, {
351
- value: value,
352
- isFocused: isRowFocused
353
- }), itemsDeletable && activeQuery !== undefined && /*#__PURE__*/(0, _jsxRuntime.jsx)(DeleteItemButton, {
354
- activeQuery: activeQuery,
355
- dataPath: currentDataPath,
356
- isFocused: isRowFocused
357
- }), valueType === "array" && activeQuery !== undefined && /*#__PURE__*/(0, _jsxRuntime.jsx)(ClearArrayButton, {
358
- activeQuery: activeQuery,
359
- dataPath: currentDataPath,
360
- isFocused: isRowFocused
361
- })]
362
- })]
363
- }), isExpanded && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
364
- children: [subEntryPages.length === 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
365
- style: [styles.singleEntryContainer, isMainSection && styles.singleEntryContainerMain],
366
- children: subEntries.map((entry, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(Explorer, {
367
- defaultExpanded: defaultExpanded,
368
- label: entry.label,
369
- value: entry.value,
370
- editable: editable,
371
- dataPath: [...currentDataPath, entry.label],
372
- activeQuery: activeQuery,
373
- itemsDeletable: valueType === "array" || valueType === "Iterable" || valueType === "object",
374
- dataVersion: dataVersion
375
- }, entry.label + index))
376
- }), subEntryPages.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
377
- style: styles.multiEntryContainer,
378
- children: subEntryPages.map((entries, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
379
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
380
- style: styles.relativeOutlineNone,
381
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
382
- "sentry-label": "ignore devtools explorer page toggle",
383
- onPress: () => setExpandedPages(old => old.includes(index) ? old.filter(d => d !== index) : [...old, index]),
384
- style: styles.pageExpanderButton,
385
- hitSlop: HIT_SLOP_OPTIMIZED,
386
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Expander, {
387
- expanded: expandedPages.includes(index)
388
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
389
- style: styles.pageRangeText,
390
- children: ["[", index * CHUNK_SIZE, "...", index * CHUNK_SIZE + CHUNK_SIZE - 1, "]"]
391
- })]
392
- }), expandedPages.includes(index) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
393
- style: styles.entriesContainer,
394
- children: entries.map(entry => /*#__PURE__*/(0, _jsxRuntime.jsx)(Explorer, {
395
- defaultExpanded: defaultExpanded,
396
- label: entry.label,
397
- value: entry.value,
398
- editable: editable,
399
- dataPath: [...currentDataPath, entry.label],
400
- activeQuery: activeQuery,
401
- dataVersion: dataVersion
402
- }, entry.label))
403
- })]
404
- })
405
- }, index))
406
- })]
407
- })]
408
- }), subEntryPages.length === 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
409
- style: styles.flexRowGapFullWidth,
410
- children: [editable && activeQuery !== undefined && (valueType === "string" || valueType === "number" || valueType === "boolean") ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
411
- children: [editable && activeQuery && (valueType === "string" || valueType === "number") && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
412
- style: styles.nebulaInputWrapper,
413
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.CyberpunkInput, {
414
- label: label,
415
- testID: `${(0, _testIDs.explorerTestID)(currentDataPath)}-input`,
416
- accessibilityLabel: `${label}, editable value`,
417
- style: [valueType === "number" ? styles.textNumber : styles.textString],
418
- keyboardType: valueType === "number" ? "numeric" : "default",
419
- value: localInputValue,
420
- onChangeText: newValue => handleChange(valueType === "number", newValue),
421
- onFocus: () => setIsRowFocused(true),
422
- onBlur: () => setIsRowFocused(false),
423
- showNumberControls: valueType === "number",
424
- onIncrement: () => {
425
- const currentNum = Number(localInputValue) || 0;
426
- handleChange(true, String(currentNum + 1));
427
- },
428
- onDecrement: () => {
429
- const currentNum = Number(localInputValue) || 0;
430
- handleChange(true, String(currentNum - 1));
431
- },
432
- showDeleteButton: itemsDeletable,
433
- onDelete: () => {
434
- (0, _deleteItem.default)({
435
- queryClient,
436
- activeQuery,
437
- dataPath: currentDataPath
438
- });
439
- }
440
- })
441
- }), valueType === "boolean" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
442
- style: styles.booleanRowContainer,
443
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
444
- style: styles.booleanLabel,
445
- children: label
446
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
447
- style: styles.booleanToggleWrapper,
448
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ToggleValueButton, {
449
- activeQuery: activeQuery,
450
- dataPath: currentDataPath,
451
- value: value,
452
- itemsDeletable: itemsDeletable
453
- })
454
- })]
455
- })]
456
- }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
457
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
458
- style: styles.text344054,
459
- children: label
460
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
461
- testID: `${(0, _testIDs.explorerTestID)(currentDataPath)}-value`,
462
- style: styles.displayValueText,
463
- children: (0, _sharedUi.displayValue)(value)
464
- })]
465
- }), editable && itemsDeletable && activeQuery !== undefined && valueType !== "string" && valueType !== "number" && valueType !== "boolean" && /*#__PURE__*/(0, _jsxRuntime.jsx)(DeleteItemButton, {
466
- activeQuery: activeQuery,
467
- dataPath: currentDataPath,
468
- isFocused: isRowFocused
469
- })]
470
- })]
471
- })
46
+ const writer = (0, _react.useMemo)(() => {
47
+ if (!activeQuery) return undefined;
48
+ return {
49
+ update: (path, next) => {
50
+ const oldData = activeQuery.state.data;
51
+ const newData = (0, _updateNestedDataByPath.updateNestedDataByPath)(oldData, path, next);
52
+ queryClient.setQueryData(activeQuery.queryKey, newData);
53
+ },
54
+ remove: path => {
55
+ (0, _deleteItem.default)({
56
+ queryClient,
57
+ activeQuery,
58
+ dataPath: path
59
+ });
60
+ }
61
+ };
62
+ }, [queryClient, activeQuery]);
63
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.LiveExplorer, {
64
+ editable: editable,
65
+ label: label,
66
+ value: value,
67
+ defaultExpanded: defaultExpanded,
68
+ writer: writer,
69
+ dataPath: dataPath,
70
+ itemsDeletable: itemsDeletable,
71
+ dataVersion: dataVersion,
72
+ testIDForPath: _testIDs.explorerTestID,
73
+ debounceMs: 0
472
74
  });
473
- }
474
- const styles = _reactNative.StyleSheet.create({
475
- buttonStyle: {
476
- backgroundColor: _sharedUi.night.color.surface + "E6",
477
- borderWidth: 1,
478
- borderColor: _sharedUi.night.color.textSecondary + "33",
479
- borderRadius: 6,
480
- flexDirection: "row",
481
- alignItems: "center",
482
- justifyContent: "center",
483
- width: 28,
484
- height: 28,
485
- position: "relative",
486
- shadowColor: "#000",
487
- shadowOffset: {
488
- width: 0,
489
- height: 1
490
- },
491
- shadowOpacity: 0.2,
492
- shadowRadius: 2
493
- },
494
- buttonStyleFocused: {
495
- borderColor: _sharedUi.night.color.accent + "CC",
496
- backgroundColor: _sharedUi.night.color.accent + "26",
497
- shadowColor: _sharedUi.night.color.accent,
498
- shadowOpacity: 0.3,
499
- shadowRadius: 4
500
- },
501
- deleteButton: {
502
- backgroundColor: _sharedUi.night.color.danger + "1A",
503
- borderColor: _sharedUi.night.color.danger + "4D",
504
- borderWidth: 1,
505
- borderRadius: 6,
506
- padding: 0,
507
- alignItems: "center",
508
- justifyContent: "center",
509
- width: 28,
510
- height: 28,
511
- position: "relative",
512
- shadowColor: _sharedUi.night.color.danger,
513
- shadowOffset: {
514
- width: 0,
515
- height: 0
516
- },
517
- shadowOpacity: 0.15,
518
- shadowRadius: 3
519
- },
520
- deleteButtonFocused: {
521
- borderColor: _sharedUi.night.color.danger + "CC",
522
- backgroundColor: _sharedUi.night.color.danger + "33",
523
- shadowOpacity: 0.3,
524
- shadowRadius: 5
525
- },
526
- deleteButtonInToggle: {
527
- backgroundColor: _sharedUi.night.color.danger + "1A",
528
- borderColor: _sharedUi.night.color.danger + "4D",
529
- borderWidth: 1,
530
- borderRadius: 6,
531
- padding: 0,
532
- alignItems: "center",
533
- justifyContent: "center",
534
- width: 28,
535
- height: 28,
536
- shadowColor: _sharedUi.night.color.danger,
537
- shadowOffset: {
538
- width: 0,
539
- height: 0
540
- },
541
- shadowOpacity: 0.15,
542
- shadowRadius: 3
543
- },
544
- clearButton: {
545
- backgroundColor: _sharedUi.night.color.warning + "1A",
546
- borderWidth: 1,
547
- borderColor: _sharedUi.night.color.warning + "4D",
548
- borderRadius: 6,
549
- flexDirection: "row",
550
- padding: 0,
551
- alignItems: "center",
552
- justifyContent: "center",
553
- width: 28,
554
- height: 28,
555
- position: "relative",
556
- zIndex: 10,
557
- shadowColor: _sharedUi.night.color.warning,
558
- shadowOffset: {
559
- width: 0,
560
- height: 0
561
- },
562
- shadowOpacity: 0.15,
563
- shadowRadius: 3
564
- },
565
- clearButtonFocused: {
566
- borderColor: _sharedUi.night.color.warning + "CC",
567
- backgroundColor: _sharedUi.night.color.warning + "33",
568
- shadowOpacity: 0.3,
569
- shadowRadius: 5
570
- },
571
- clearButtonText: {
572
- fontSize: 12,
573
- fontWeight: "700",
574
- fontFamily: "monospace"
575
- },
576
- expanderIcon: {
577
- width: 18,
578
- height: 18,
579
- alignItems: "center",
580
- justifyContent: "center",
581
- marginRight: 1,
582
- backgroundColor: _sharedUi.night.color.textSecondary + "14",
583
- borderRadius: 3
584
- },
585
- expanderIconMain: {
586
- backgroundColor: _sharedUi.night.color.textSecondary + "1A",
587
- width: 20,
588
- height: 20,
589
- borderRadius: 4,
590
- borderWidth: 0.5,
591
- borderColor: _sharedUi.night.color.textSecondary + "33"
592
- },
593
- expanded: {
594
- transform: [{
595
- rotate: "0deg"
596
- }]
597
- },
598
- collapsed: {
599
- transform: [{
600
- rotate: "0deg"
601
- }]
602
- },
603
- minWidthWrapper: {
604
- minWidth: 180,
605
- fontSize: 11,
606
- flexDirection: "row",
607
- flexWrap: "wrap",
608
- width: "100%",
609
- marginVertical: 0.5
610
- },
611
- fullWidthMarginRight: {
612
- position: "relative",
613
- width: "100%",
614
- marginRight: 1
615
- },
616
- flexRowItemsCenterGap: {
617
- flexDirection: "row",
618
- alignItems: "center",
619
- justifyContent: "space-between",
620
- paddingVertical: 3,
621
- paddingHorizontal: 6,
622
- marginVertical: 1,
623
- borderRadius: 4,
624
- backgroundColor: _sharedUi.night.color.surface + "66",
625
- borderWidth: 0.5,
626
- borderColor: _sharedUi.night.color.textSecondary + "1A"
627
- },
628
- flexRowItemsCenterGapMain: {
629
- backgroundColor: _sharedUi.night.color.surface + "E6",
630
- borderLeftWidth: 2.5,
631
- borderLeftColor: _sharedUi.night.color.textSecondary + "80",
632
- borderColor: _sharedUi.night.color.textSecondary + "26",
633
- paddingVertical: 5,
634
- paddingHorizontal: 8,
635
- marginBottom: 3,
636
- borderWidth: 1,
637
- shadowColor: "#000",
638
- shadowOffset: {
639
- width: 0,
640
- height: 0
641
- },
642
- shadowOpacity: 0.08,
643
- shadowRadius: 3
644
- },
645
- expanderButton: {
646
- flexDirection: "row",
647
- alignItems: "center",
648
- backgroundColor: "transparent",
649
- paddingVertical: 1,
650
- paddingHorizontal: 2,
651
- gap: 6,
652
- borderWidth: 0,
653
- minHeight: 24,
654
- flex: 1
655
- },
656
- labelText: {
657
- color: _sharedUi.night.color.textSecondary,
658
- fontSize: 10,
659
- fontWeight: "600",
660
- marginRight: 4,
661
- fontFamily: "monospace",
662
- letterSpacing: 0.4
663
- },
664
- labelTextFocused: {
665
- color: _sharedUi.night.color.text
666
- },
667
- labelTextMain: {
668
- color: _sharedUi.night.color.text,
669
- fontSize: 11,
670
- fontWeight: "700",
671
- letterSpacing: 0.6
672
- },
673
- textGray500: {
674
- color: _sharedUi.night.color.textTertiary,
675
- fontSize: 10,
676
- fontWeight: "400",
677
- fontFamily: "monospace",
678
- opacity: 0.7
679
- },
680
- pageRangeText: {
681
- color: _sharedUi.night.color.textSecondary,
682
- fontSize: 10,
683
- fontWeight: "600",
684
- fontFamily: "monospace"
685
- },
686
- flexRowGapItemsCenter: {
687
- flexDirection: "row",
688
- alignItems: "center",
689
- gap: 4,
690
- paddingLeft: 2
691
- },
692
- singleEntryContainer: {
693
- marginLeft: 2,
694
- marginTop: 2,
695
- paddingLeft: 8,
696
- borderLeftWidth: 1.5,
697
- borderLeftColor: _sharedUi.night.color.textSecondary + "40"
698
- },
699
- singleEntryContainerMain: {
700
- borderLeftColor: _sharedUi.night.color.textSecondary + "4D",
701
- marginLeft: 4,
702
- paddingLeft: 10
703
- },
704
- multiEntryContainer: {
705
- marginLeft: 2,
706
- marginTop: 2,
707
- paddingLeft: 8,
708
- borderLeftWidth: 1.5,
709
- borderLeftColor: _sharedUi.night.color.textSecondary + "40"
710
- },
711
- multiEntryContainerMain: {
712
- borderLeftColor: _sharedUi.night.color.textSecondary + "4D",
713
- marginLeft: 4,
714
- paddingLeft: 10
715
- },
716
- relativeOutlineNone: {
717
- position: "relative"
718
- },
719
- pageExpanderButton: {
720
- flexDirection: "row",
721
- alignItems: "center",
722
- backgroundColor: _sharedUi.night.color.surface + "66",
723
- paddingVertical: 3,
724
- paddingHorizontal: 6,
725
- gap: 6,
726
- borderRadius: 4,
727
- borderWidth: 0.5,
728
- borderColor: _sharedUi.night.color.textSecondary + "1A",
729
- marginBottom: 2,
730
- minHeight: 24
731
- },
732
- entriesContainer: {
733
- marginLeft: 2,
734
- paddingLeft: 8,
735
- marginTop: 2,
736
- borderLeftWidth: 1.5,
737
- borderLeftColor: _sharedUi.night.color.textSecondary + "40"
738
- },
739
- textNumber: {
740
- color: _sharedUi.night.color.text,
741
- fontWeight: "600",
742
- fontFamily: "monospace"
743
- },
744
- textString: {
745
- color: _sharedUi.night.color.text,
746
- fontFamily: "monospace"
747
- },
748
- flexRowGapFullWidth: {
749
- flexDirection: "row",
750
- width: "100%",
751
- alignItems: "center",
752
- marginVertical: 1,
753
- gap: 6,
754
- paddingHorizontal: 4,
755
- paddingVertical: 2,
756
- borderRadius: 3
757
- },
758
- text344054: {
759
- color: _sharedUi.night.color.textSecondary,
760
- fontWeight: "600",
761
- fontSize: 9,
762
- minWidth: 50,
763
- fontFamily: "monospace",
764
- letterSpacing: 0.4,
765
- opacity: 0.8
766
- },
767
- numberInputButtons: {
768
- position: "absolute",
769
- right: 8,
770
- top: "50%",
771
- transform: [{
772
- translateY: -18
773
- }],
774
- flexDirection: "row",
775
- gap: 4,
776
- zIndex: 10
777
- },
778
- touchableButton: {
779
- width: 32,
780
- height: 32,
781
- borderRadius: 6,
782
- backgroundColor: _sharedUi.night.color.surface + "E6",
783
- borderWidth: 1,
784
- borderColor: _sharedUi.night.color.textSecondary + "33",
785
- alignItems: "center",
786
- justifyContent: "center",
787
- marginLeft: 2,
788
- shadowColor: "#000",
789
- shadowOffset: {
790
- width: 0,
791
- height: 1
792
- },
793
- shadowOpacity: 0.2,
794
- shadowRadius: 2
795
- },
796
- touchableButtonFocused: {
797
- borderColor: _sharedUi.night.color.accent + "CC",
798
- backgroundColor: _sharedUi.night.color.accent + "26",
799
- shadowColor: _sharedUi.night.color.accent,
800
- shadowOffset: {
801
- width: 0,
802
- height: 0
803
- },
804
- shadowOpacity: 0.3,
805
- shadowRadius: 4,
806
- elevation: 3
807
- },
808
- nebulaInputWrapper: {
809
- flex: 1,
810
- width: "100%",
811
- position: "relative"
812
- },
813
- displayValueText: {
814
- flex: 1,
815
- color: _sharedUi.night.color.text,
816
- fontWeight: "400",
817
- fontFamily: "monospace",
818
- fontSize: 12,
819
- paddingVertical: 6,
820
- paddingHorizontal: 10,
821
- borderRadius: 6,
822
- borderWidth: 1,
823
- borderColor: _sharedUi.night.color.textTertiary + "66",
824
- minHeight: 34
825
- },
826
- // New redesigned styles (kept for future use)
827
- dataRow: {
828
- flexDirection: "row",
829
- alignItems: "center",
830
- paddingVertical: 4,
831
- paddingHorizontal: 8,
832
- minHeight: 44,
833
- gap: 12
834
- },
835
- dataLabel: {
836
- color: _sharedUi.night.color.textSecondary,
837
- fontSize: 13,
838
- fontWeight: "500",
839
- minWidth: 80,
840
- flexShrink: 0
841
- },
842
- dataValueContainer: {
843
- flex: 1,
844
- flexDirection: "row",
845
- alignItems: "center"
846
- },
847
- inputWithActions: {
848
- flex: 1,
849
- position: "relative"
850
- },
851
- numberControls: {
852
- position: "absolute",
853
- right: 8,
854
- top: "50%",
855
- transform: [{
856
- translateY: -16
857
- }],
858
- flexDirection: "column",
859
- gap: 2
860
- },
861
- numberButton: {
862
- width: 32,
863
- height: 16,
864
- borderRadius: 4,
865
- alignItems: "center",
866
- justifyContent: "center",
867
- borderWidth: 1,
868
- borderColor: _sharedUi.night.color.accent + "0F"
869
- },
870
- readOnlyValue: {
871
- color: _sharedUi.night.color.text,
872
- fontSize: 13,
873
- fontFamily: "monospace",
874
- paddingVertical: 8,
875
- paddingHorizontal: 12,
876
- borderRadius: 6,
877
- borderWidth: 1,
878
- borderColor: _sharedUi.night.color.textTertiary + "33",
879
- flex: 1
880
- },
881
- actionButtons: {
882
- flexDirection: "row",
883
- gap: 6,
884
- paddingLeft: 8
885
- },
886
- booleanContainer: {
887
- flexDirection: "row",
888
- alignItems: "center",
889
- padding: 8,
890
- borderRadius: 6,
891
- borderWidth: 1,
892
- borderColor: _sharedUi.night.color.textTertiary + "4D",
893
- flex: 1
894
- },
895
- booleanText: {
896
- marginLeft: 8,
897
- color: _sharedUi.night.color.warning,
898
- fontWeight: "500",
899
- fontFamily: "monospace"
900
- },
901
- modernToggleButton: {
902
- flexDirection: "row",
903
- alignItems: "center",
904
- justifyContent: "space-between",
905
- borderRadius: 6,
906
- borderWidth: 1,
907
- borderColor: _sharedUi.night.color.textTertiary + "99",
908
- paddingHorizontal: 8,
909
- paddingVertical: 6,
910
- marginVertical: 2,
911
- minHeight: 34,
912
- gap: 8
913
- },
914
- toggleIconContainer: {
915
- marginRight: 6
916
- },
917
- toggleIcon: {
918
- padding: 8,
919
- borderRadius: 8,
920
- alignItems: "center",
921
- justifyContent: "center",
922
- width: 32,
923
- height: 32
924
- },
925
- toggleIconSmall: {
926
- width: 8,
927
- height: 8,
928
- borderRadius: 4
929
- },
930
- toggleContent: {
931
- flex: 1,
932
- minWidth: 0
933
- },
934
- toggleLabel: {
935
- color: "#E5E7EB",
936
- fontSize: 11,
937
- fontWeight: "600",
938
- fontFamily: "monospace",
939
- letterSpacing: 0.3
940
- },
941
- toggleStatus: {
942
- color: "#9CA3AF",
943
- fontSize: 11
944
- },
945
- toggleBadge: {
946
- marginLeft: 6,
947
- paddingHorizontal: 6,
948
- paddingVertical: 3,
949
- borderRadius: 4,
950
- borderWidth: 1
951
- },
952
- toggleBadgeText: {
953
- fontSize: 9,
954
- fontWeight: "700",
955
- textTransform: "uppercase",
956
- letterSpacing: 0.8,
957
- fontFamily: "monospace"
958
- },
959
- // Pre-computed toggle icon styles to avoid inline objects [[memory:4875251]]
960
- toggleIconTrue: {
961
- backgroundColor: _sharedUi.night.color.accent
962
- },
963
- toggleIconFalse: {
964
- backgroundColor: _sharedUi.night.color.textTertiary
965
- },
966
- // Pre-computed toggle badge styles [[memory:4875251]]
967
- toggleBadgeTrue: {
968
- backgroundColor: _sharedUi.night.color.accent + "1A",
969
- borderColor: _sharedUi.night.color.accent + "4D"
970
- },
971
- toggleBadgeFalse: {
972
- backgroundColor: _sharedUi.night.color.textTertiary + "1A",
973
- borderColor: _sharedUi.night.color.textTertiary + "4D"
974
- },
975
- // Pre-computed toggle text styles [[memory:4875251]]
976
- toggleTextTrue: {
977
- color: _sharedUi.night.color.accent,
978
- fontWeight: "600"
979
- },
980
- toggleTextFalse: {
981
- color: _sharedUi.night.color.textSecondary,
982
- fontWeight: "500"
983
- },
984
- // Boolean row container styles
985
- booleanRowContainer: {
986
- flexDirection: "row",
987
- alignItems: "center",
988
- width: "100%",
989
- gap: 8,
990
- paddingVertical: 2
991
- },
992
- booleanLabel: {
993
- color: _sharedUi.night.color.textSecondary,
994
- fontSize: 10,
995
- fontWeight: "600",
996
- fontFamily: "monospace",
997
- letterSpacing: 0.4,
998
- minWidth: 60,
999
- flexShrink: 0
1000
- },
1001
- booleanToggleWrapper: {
1002
- flex: 1
1003
- }
1004
- });
75
+ }