@buoy-gg/shared-ui 7.0.3 → 7.0.5
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/colors/index.js +49 -0
- package/lib/commonjs/dataViewer/DataTreeActionBar.js +389 -0
- package/lib/commonjs/dataViewer/DataTreeActionDock.js +222 -0
- package/lib/commonjs/dataViewer/DataViewer.js +18 -3
- package/lib/commonjs/dataViewer/VirtualizedDataExplorer.js +227 -28
- package/lib/commonjs/dataViewer/index.js +88 -0
- package/lib/commonjs/dataViewer/jsonOps.js +320 -0
- package/lib/commonjs/dataViewer/lineDiff.js +285 -83
- package/lib/commonjs/dataViewer/tree/TreeDiffViewer.js +20 -5
- package/lib/commonjs/dataViewer/treeActions.js +167 -0
- package/lib/commonjs/env/EnvironmentSelector.js +2 -2
- package/lib/commonjs/env/EnvironmentSelectorInline.js +2 -2
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/icons/index.js +79 -3
- package/lib/commonjs/icons/lucide-icons-original-full.js +5 -1
- package/lib/commonjs/icons/lucide-icons.js +59 -2
- package/lib/commonjs/index.js +35 -0
- package/lib/commonjs/settings/components/BubbleSettingsSection.js +21 -19
- package/lib/commonjs/storage/devToolsStorageKeys.js +6 -3
- package/lib/commonjs/ui/components/Badge.js +2 -0
- package/lib/commonjs/ui/components/CompactRow.js +7 -0
- package/lib/commonjs/ui/components/CopyButton.js +27 -4
- package/lib/commonjs/ui/components/DevToolsCard.js +11 -0
- package/lib/commonjs/ui/components/DynamicFilterView.js +8 -1
- package/lib/commonjs/ui/components/EmptyState.js +12 -5
- package/lib/commonjs/ui/components/ErrorBoundary.js +3 -2
- package/lib/commonjs/ui/components/EventHistoryViewer/EventHistoryViewer.js +63 -11
- package/lib/commonjs/ui/components/ExpandableSection.js +4 -3
- package/lib/commonjs/ui/components/ExpandableSectionHeader.js +2 -1
- package/lib/commonjs/ui/components/FilterViewPattern.js +8 -7
- package/lib/commonjs/ui/components/ListItem.js +7 -5
- package/lib/commonjs/ui/components/PowerToggleButton.js +4 -1
- package/lib/commonjs/ui/components/TabSelector.js +3 -0
- package/lib/commonjs/ui/console/CyberpunkConsoleSection.js +1 -1
- package/lib/commonjs/ui/console/GalaxyButton.js +1 -1
- package/lib/commonjs/ui/gameUI/components/GameUICompactStats.js +2 -2
- package/lib/commonjs/ui/gameUI/constants/gameUIColors.js +28 -6
- package/lib/commonjs/ui/gameUI/constants/macOSDesignSystemColors.js +22 -4
- package/lib/commonjs/utils/index.js +25 -0
- package/lib/commonjs/utils/reloadApp.js +144 -0
- package/lib/module/colors/index.js +21 -0
- package/lib/module/dataViewer/DataTreeActionBar.js +384 -0
- package/lib/module/dataViewer/DataTreeActionDock.js +218 -0
- package/lib/module/dataViewer/DataViewer.js +18 -3
- package/lib/module/dataViewer/VirtualizedDataExplorer.js +228 -30
- package/lib/module/dataViewer/index.js +16 -1
- package/lib/module/dataViewer/jsonOps.js +311 -0
- package/lib/module/dataViewer/lineDiff.js +284 -82
- package/lib/module/dataViewer/tree/TreeDiffViewer.js +20 -5
- package/lib/module/dataViewer/treeActions.js +161 -0
- package/lib/module/env/EnvironmentSelector.js +2 -2
- package/lib/module/env/EnvironmentSelectorInline.js +2 -2
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/icons/index.js +10 -1
- package/lib/module/icons/lucide-icons-original-full.js +5 -1
- package/lib/module/icons/lucide-icons.js +56 -0
- package/lib/module/index.js +4 -0
- package/lib/module/settings/components/BubbleSettingsSection.js +21 -19
- package/lib/module/storage/devToolsStorageKeys.js +6 -3
- package/lib/module/ui/components/Badge.js +2 -0
- package/lib/module/ui/components/CompactRow.js +7 -0
- package/lib/module/ui/components/CopyButton.js +29 -6
- package/lib/module/ui/components/DevToolsCard.js +11 -0
- package/lib/module/ui/components/DynamicFilterView.js +8 -1
- package/lib/module/ui/components/EmptyState.js +12 -5
- package/lib/module/ui/components/ErrorBoundary.js +3 -2
- package/lib/module/ui/components/EventHistoryViewer/EventHistoryViewer.js +63 -11
- package/lib/module/ui/components/ExpandableSection.js +4 -3
- package/lib/module/ui/components/ExpandableSectionHeader.js +2 -1
- package/lib/module/ui/components/FilterViewPattern.js +9 -7
- package/lib/module/ui/components/ListItem.js +7 -5
- package/lib/module/ui/components/PowerToggleButton.js +4 -1
- package/lib/module/ui/components/TabSelector.js +3 -0
- package/lib/module/ui/console/CyberpunkConsoleSection.js +1 -1
- package/lib/module/ui/console/GalaxyButton.js +1 -1
- package/lib/module/ui/gameUI/components/GameUICompactStats.js +2 -2
- package/lib/module/ui/gameUI/constants/gameUIColors.js +27 -6
- package/lib/module/ui/gameUI/constants/macOSDesignSystemColors.js +19 -2
- package/lib/module/utils/index.js +1 -0
- package/lib/module/utils/reloadApp.js +137 -0
- package/lib/typescript/commonjs/colors/index.d.ts +22 -0
- package/lib/typescript/commonjs/colors/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/DataTreeActionBar.d.ts +53 -0
- package/lib/typescript/commonjs/dataViewer/DataTreeActionBar.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts +33 -0
- package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/DataViewer.d.ts +14 -1
- package/lib/typescript/commonjs/dataViewer/DataViewer.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/VirtualizedDataExplorer.d.ts +30 -1
- package/lib/typescript/commonjs/dataViewer/VirtualizedDataExplorer.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/__tests__/jsonOps.test.d.ts +19 -0
- package/lib/typescript/commonjs/dataViewer/__tests__/jsonOps.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/index.d.ts +5 -1
- package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/jsonOps.d.ts +124 -0
- package/lib/typescript/commonjs/dataViewer/jsonOps.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/lineDiff.d.ts +27 -0
- package/lib/typescript/commonjs/dataViewer/lineDiff.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/tree/TreeDiffViewer.d.ts +8 -1
- package/lib/typescript/commonjs/dataViewer/tree/TreeDiffViewer.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/treeActions.d.ts +83 -0
- package/lib/typescript/commonjs/dataViewer/treeActions.d.ts.map +1 -0
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/icons/index.d.ts +6 -1
- package/lib/typescript/commonjs/icons/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/icons/lucide-icons-original-full.d.ts.map +1 -1
- package/lib/typescript/commonjs/icons/lucide-icons.d.ts +9 -0
- package/lib/typescript/commonjs/icons/lucide-icons.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/settings/components/BubbleSettingsSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +5 -1
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/CopyButton.d.ts +7 -1
- package/lib/typescript/commonjs/ui/components/CopyButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/EventHistoryViewer.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/types.d.ts +23 -7
- package/lib/typescript/commonjs/ui/components/EventHistoryViewer/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ExpandableSection.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ExpandableSectionHeader.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FilterViewPattern.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ListItem.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/gameUI/constants/gameUIColors.d.ts +36 -30
- package/lib/typescript/commonjs/ui/gameUI/constants/gameUIColors.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/gameUI/constants/macOSDesignSystemColors.d.ts +5 -0
- package/lib/typescript/commonjs/ui/gameUI/constants/macOSDesignSystemColors.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/index.d.ts +1 -0
- package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/reloadApp.d.ts +68 -0
- package/lib/typescript/commonjs/utils/reloadApp.d.ts.map +1 -0
- package/lib/typescript/module/colors/index.d.ts +22 -0
- package/lib/typescript/module/colors/index.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/DataTreeActionBar.d.ts +53 -0
- package/lib/typescript/module/dataViewer/DataTreeActionBar.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts +33 -0
- package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/DataViewer.d.ts +14 -1
- package/lib/typescript/module/dataViewer/DataViewer.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/VirtualizedDataExplorer.d.ts +30 -1
- package/lib/typescript/module/dataViewer/VirtualizedDataExplorer.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/__tests__/jsonOps.test.d.ts +19 -0
- package/lib/typescript/module/dataViewer/__tests__/jsonOps.test.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/index.d.ts +5 -1
- package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/jsonOps.d.ts +124 -0
- package/lib/typescript/module/dataViewer/jsonOps.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/lineDiff.d.ts +27 -0
- package/lib/typescript/module/dataViewer/lineDiff.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/tree/TreeDiffViewer.d.ts +8 -1
- package/lib/typescript/module/dataViewer/tree/TreeDiffViewer.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/treeActions.d.ts +83 -0
- package/lib/typescript/module/dataViewer/treeActions.d.ts.map +1 -0
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/icons/index.d.ts +6 -1
- package/lib/typescript/module/icons/index.d.ts.map +1 -1
- package/lib/typescript/module/icons/lucide-icons-original-full.d.ts.map +1 -1
- package/lib/typescript/module/icons/lucide-icons.d.ts +9 -0
- package/lib/typescript/module/icons/lucide-icons.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/settings/components/BubbleSettingsSection.d.ts.map +1 -1
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +5 -1
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/CopyButton.d.ts +7 -1
- package/lib/typescript/module/ui/components/CopyButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/EventHistoryViewer.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/EventHistoryViewer/types.d.ts +23 -7
- package/lib/typescript/module/ui/components/EventHistoryViewer/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ExpandableSection.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ExpandableSectionHeader.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FilterViewPattern.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ListItem.d.ts.map +1 -1
- package/lib/typescript/module/ui/gameUI/constants/gameUIColors.d.ts +36 -30
- package/lib/typescript/module/ui/gameUI/constants/gameUIColors.d.ts.map +1 -1
- package/lib/typescript/module/ui/gameUI/constants/macOSDesignSystemColors.d.ts +5 -0
- package/lib/typescript/module/ui/gameUI/constants/macOSDesignSystemColors.d.ts.map +1 -1
- package/lib/typescript/module/utils/index.d.ts +1 -0
- package/lib/typescript/module/utils/index.d.ts.map +1 -1
- package/lib/typescript/module/utils/reloadApp.d.ts +68 -0
- package/lib/typescript/module/utils/reloadApp.d.ts.map +1 -0
- package/package.json +15 -4
- package/lib/commonjs/icons/ImageOverlayIcon.js +0 -142
- package/lib/module/icons/ImageOverlayIcon.js +0 -137
- package/lib/typescript/commonjs/icons/ImageOverlayIcon.d.ts +0 -14
- package/lib/typescript/commonjs/icons/ImageOverlayIcon.d.ts.map +0 -1
- package/lib/typescript/module/icons/ImageOverlayIcon.d.ts +0 -14
- package/lib/typescript/module/icons/ImageOverlayIcon.d.ts.map +0 -1
|
@@ -25,6 +25,8 @@ const CHUNK_SIZE = 50; // Process data in chunks to avoid blocking UI
|
|
|
25
25
|
const MAX_DEPTH_LIMIT = 15; // Prevent excessive nesting
|
|
26
26
|
const MAX_ITEMS_PER_LEVEL = 500; // Limit items to prevent memory issues
|
|
27
27
|
const LONG_KEY_THRESHOLD = 30; // Keys longer than this use vertical layout
|
|
28
|
+
/** Two presses inside this window count as a double-tap (RN has no dblclick). */
|
|
29
|
+
const DOUBLE_TAP_MS = 300;
|
|
28
30
|
|
|
29
31
|
// Pre-computed indent styles (VS Code-style width)
|
|
30
32
|
const INDENT_WIDTH = 16;
|
|
@@ -223,8 +225,48 @@ const STABLE_STYLES = _reactNative.StyleSheet.create({
|
|
|
223
225
|
}
|
|
224
226
|
});
|
|
225
227
|
|
|
228
|
+
/**
|
|
229
|
+
* A tree row as the HOST sees it.
|
|
230
|
+
*
|
|
231
|
+
* `item.path` is addressed for the TREE, which is seeded with a synthetic
|
|
232
|
+
* "root" node wrapping the caller's data — so the top row is `["root"]` and its
|
|
233
|
+
* first child `["root", "0"]`. Ops address the DATA, where those are `[]` and
|
|
234
|
+
* `["0"]`. Dropping the first segment is what reconciles the two, and doing it
|
|
235
|
+
* in ONE place is what keeps selection, inline editing and ops all agreeing.
|
|
236
|
+
*/
|
|
237
|
+
function selectionOf(item) {
|
|
238
|
+
return {
|
|
239
|
+
path: item.path.slice(1),
|
|
240
|
+
value: item.value,
|
|
241
|
+
label: item.key
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
226
245
|
// Type definitions for flattened data structure
|
|
227
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Node count, capped at `limit`.
|
|
249
|
+
*
|
|
250
|
+
* Deliberately short-circuits: this runs on every render to decide which
|
|
251
|
+
* flattening path to take, so it must cost O(limit), never O(document).
|
|
252
|
+
*/
|
|
253
|
+
function countNodesUpTo(value, limit, seen = 0) {
|
|
254
|
+
if (seen >= limit) return seen;
|
|
255
|
+
let n = seen + 1;
|
|
256
|
+
if (Array.isArray(value)) {
|
|
257
|
+
for (const child of value) {
|
|
258
|
+
if (n >= limit) return n;
|
|
259
|
+
n = countNodesUpTo(child, limit, n);
|
|
260
|
+
}
|
|
261
|
+
} else if (value !== null && typeof value === "object") {
|
|
262
|
+
for (const child of Object.values(value)) {
|
|
263
|
+
if (n >= limit) return n;
|
|
264
|
+
n = countNodesUpTo(child, limit, n);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return n;
|
|
268
|
+
}
|
|
269
|
+
|
|
228
270
|
// Enhanced type detection optimized for performance
|
|
229
271
|
const getValueType = value => {
|
|
230
272
|
if (value === null) return "null";
|
|
@@ -376,6 +418,16 @@ const useDataFlattening = (data, maxDepth = 10, autoExpandFirstLevel = false) =>
|
|
|
376
418
|
// Store circular cache outside of re-renders to prevent reset
|
|
377
419
|
const circularCacheRef = (0, _react.useRef)(new WeakSet());
|
|
378
420
|
const processingRef = (0, _react.useRef)(false);
|
|
421
|
+
/**
|
|
422
|
+
* Monotonic token identifying the newest flatten run.
|
|
423
|
+
*
|
|
424
|
+
* WHY: a cancelled run used to `return` without clearing `isProcessing`, so
|
|
425
|
+
* whenever renders arrived faster than the 10ms debounce + flatten, every run
|
|
426
|
+
* was superseded before it finished and the spinner never came down — the
|
|
427
|
+
* viewer sat on "Processing data…" forever. Now each run checks it is still
|
|
428
|
+
* the current one, and the run that ends up last ALWAYS resolves the flag.
|
|
429
|
+
*/
|
|
430
|
+
const runIdRef = (0, _react.useRef)(0);
|
|
379
431
|
const dataVersionRef = (0, _react.useRef)(0);
|
|
380
432
|
const lastActionRef = (0, _react.useRef)(undefined);
|
|
381
433
|
|
|
@@ -505,14 +557,16 @@ const useDataFlattening = (data, maxDepth = 10, autoExpandFirstLevel = false) =>
|
|
|
505
557
|
if (processingRef.current) {
|
|
506
558
|
return;
|
|
507
559
|
}
|
|
508
|
-
let isCancelled = false;
|
|
509
560
|
let timeoutId;
|
|
561
|
+
const runId = ++runIdRef.current;
|
|
562
|
+
/** True while this run is still the newest one scheduled. */
|
|
563
|
+
const isCurrent = () => runIdRef.current === runId;
|
|
510
564
|
processingRef.current = true;
|
|
511
565
|
setIsProcessing(true);
|
|
512
566
|
const processData = async () => {
|
|
513
567
|
// Failsafe timeout to prevent stuck processing
|
|
514
568
|
timeoutId = setTimeout(() => {
|
|
515
|
-
if (processingRef.current &&
|
|
569
|
+
if (processingRef.current && isCurrent()) {
|
|
516
570
|
setIsProcessing(false);
|
|
517
571
|
processingRef.current = false;
|
|
518
572
|
}
|
|
@@ -520,8 +574,10 @@ const useDataFlattening = (data, maxDepth = 10, autoExpandFirstLevel = false) =>
|
|
|
520
574
|
// Small delay to debounce rapid changes
|
|
521
575
|
// Small delay to batch rapid changes
|
|
522
576
|
await new Promise(resolve => setTimeout(() => resolve(), 10));
|
|
523
|
-
|
|
524
|
-
|
|
577
|
+
|
|
578
|
+
// Superseded by a newer run — that run now owns `isProcessing`, so leave
|
|
579
|
+
// the flag alone and let it resolve.
|
|
580
|
+
if (!isCurrent()) {
|
|
525
581
|
return;
|
|
526
582
|
}
|
|
527
583
|
try {
|
|
@@ -539,31 +595,26 @@ const useDataFlattening = (data, maxDepth = 10, autoExpandFirstLevel = false) =>
|
|
|
539
595
|
});
|
|
540
596
|
});
|
|
541
597
|
flatDataMapRef.current = newMap;
|
|
542
|
-
if (
|
|
598
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
599
|
+
if (isCurrent()) {
|
|
543
600
|
setFlatData(newFlatData);
|
|
544
601
|
setIsProcessing(false);
|
|
545
602
|
processingRef.current = false;
|
|
546
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
547
|
-
} else {
|
|
548
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
549
603
|
}
|
|
550
604
|
} catch (error) {
|
|
551
605
|
console.error(error);
|
|
552
606
|
// Reset to empty data on error
|
|
553
|
-
if (
|
|
607
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
608
|
+
if (isCurrent()) {
|
|
554
609
|
setFlatData([]);
|
|
555
610
|
flatDataMapRef.current = new Map();
|
|
556
611
|
setIsProcessing(false);
|
|
557
612
|
processingRef.current = false;
|
|
558
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
559
|
-
} else {
|
|
560
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
561
613
|
}
|
|
562
614
|
}
|
|
563
615
|
};
|
|
564
616
|
processData();
|
|
565
617
|
return () => {
|
|
566
|
-
isCancelled = true;
|
|
567
618
|
processingRef.current = false;
|
|
568
619
|
if (timeoutId) clearTimeout(timeoutId);
|
|
569
620
|
};
|
|
@@ -715,10 +766,50 @@ const useDataFlattening = (data, maxDepth = 10, autoExpandFirstLevel = false) =>
|
|
|
715
766
|
return newSet;
|
|
716
767
|
});
|
|
717
768
|
}, [updateFlatDataIncremental]);
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Small documents flatten SYNCHRONOUSLY, during render.
|
|
772
|
+
*
|
|
773
|
+
* The chunked effect above exists so a 500-node payload can't block a frame,
|
|
774
|
+
* and it pays for that with an async, multi-commit rebuild every time `data`
|
|
775
|
+
* changes identity. Editing is immutable, so that's every single op — which
|
|
776
|
+
* made a three-item array rebuild itself in stages on every tap, visibly, for
|
|
777
|
+
* machinery it never needed. Below the chunk threshold the entire flatten is
|
|
778
|
+
* cheaper than one of those commits, so derive it inline and let React
|
|
779
|
+
* reconcile the rows normally. The chunked path is untouched above that size.
|
|
780
|
+
*/
|
|
781
|
+
const isSmallDocument = countNodesUpTo(data, CHUNK_SIZE, 0) < CHUNK_SIZE;
|
|
782
|
+
const syncFlatData = (0, _react.useMemo)(() => {
|
|
783
|
+
if (!isSmallDocument) return null;
|
|
784
|
+
return flattenDataStable(data, expandedItems, new WeakSet(), "root", 0, undefined, [], 0, 1, []);
|
|
785
|
+
}, [isSmallDocument, data, expandedItems, flattenDataStable]);
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Expand a set of ancestor ids so a node deeper in the tree becomes visible.
|
|
789
|
+
*
|
|
790
|
+
* Needed because a host can relocate the selection to a node the user never
|
|
791
|
+
* expanded their way to — append into a collapsed array and the new entry is
|
|
792
|
+
* selected but off-tree, which reads as "nothing happened". Unlike
|
|
793
|
+
* `toggleExpanded` this doesn't patch `flatData` incrementally; the full
|
|
794
|
+
* flatten effect already re-runs on `expandedItems`, and a reveal is rare
|
|
795
|
+
* enough that the extra pass isn't worth a second incremental code path.
|
|
796
|
+
*/
|
|
797
|
+
const revealPath = (0, _react.useCallback)(ancestorIds => {
|
|
798
|
+
if (ancestorIds.length === 0) return;
|
|
799
|
+
setExpandedItems(prev => {
|
|
800
|
+
if (ancestorIds.every(id => prev.has(id))) return prev;
|
|
801
|
+
const next = new Set(prev);
|
|
802
|
+
for (const id of ancestorIds) next.add(id);
|
|
803
|
+
return next;
|
|
804
|
+
});
|
|
805
|
+
}, []);
|
|
718
806
|
return {
|
|
719
|
-
flatData,
|
|
720
|
-
|
|
721
|
-
|
|
807
|
+
flatData: syncFlatData ?? flatData,
|
|
808
|
+
// A synchronous list is never "processing" — the spinner would flash on
|
|
809
|
+
// every keystroke otherwise.
|
|
810
|
+
isProcessing: syncFlatData ? false : isProcessing,
|
|
811
|
+
toggleExpanded,
|
|
812
|
+
revealPath
|
|
722
813
|
};
|
|
723
814
|
};
|
|
724
815
|
|
|
@@ -728,10 +819,28 @@ const VirtualizedItemComponent = ({
|
|
|
728
819
|
onToggleExpanded,
|
|
729
820
|
index,
|
|
730
821
|
onSelect,
|
|
731
|
-
isSelected
|
|
822
|
+
isSelected,
|
|
823
|
+
selectable,
|
|
824
|
+
onRequestInlineEdit,
|
|
825
|
+
isInlineEditing,
|
|
826
|
+
inlineEditor
|
|
732
827
|
}) => {
|
|
733
828
|
const [isPressed, setIsPressed] = (0, _react.useState)(false);
|
|
734
829
|
const [showFullKey, setShowFullKey] = (0, _react.useState)(false);
|
|
830
|
+
const canEdit = selectable === true;
|
|
831
|
+
const lastPressRef = (0, _react.useRef)(0);
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* `item.path` is addressed for the TREE, which is seeded with a synthetic
|
|
835
|
+
* "root" node wrapping the caller's data — so the top row is `["root"]` and
|
|
836
|
+
* its first child `["root", "0"]`. Ops address the DATA, where those are `[]`
|
|
837
|
+
* and `["0"]`. Dropping the first segment is what reconciles the two.
|
|
838
|
+
*
|
|
839
|
+
* Worth stating plainly because getting it wrong fails silently: `applyJsonOp`
|
|
840
|
+
* treats an unresolvable path as a no-op, so every button would simply have
|
|
841
|
+
* done nothing rather than erroring.
|
|
842
|
+
*/
|
|
843
|
+
const dataPath = item.path.slice(1);
|
|
735
844
|
|
|
736
845
|
// Use pre-computed styles to avoid inline calculations [[memory:4875251]]
|
|
737
846
|
const indentStyle = INDENT_STYLES[Math.min(item.depth, MAX_DEPTH_LIMIT)] || INDENT_STYLES[0];
|
|
@@ -741,11 +850,40 @@ const VirtualizedItemComponent = ({
|
|
|
741
850
|
const isLongKey = false;
|
|
742
851
|
|
|
743
852
|
// Use inline handler since component is already memoized [[memory:4875251]]
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Row body. In editable mode this SELECTS only — pressing a container to see
|
|
856
|
+
* its actions would otherwise collapse the very subtree you're editing, and
|
|
857
|
+
* the expander already exists to do the toggling (the same split every tree
|
|
858
|
+
* view makes). Read-only mode keeps the original toggle-on-row-press.
|
|
859
|
+
*/
|
|
744
860
|
const handlePress = () => {
|
|
861
|
+
if (canEdit) {
|
|
862
|
+
// Double-tap opens the inline editor, matching the mockup's
|
|
863
|
+
// double-click. Detected by hand because RN has no dblclick: two presses
|
|
864
|
+
// inside DOUBLE_TAP_MS on an already-selected scalar row.
|
|
865
|
+
const now = Date.now();
|
|
866
|
+
const isDouble = now - lastPressRef.current < DOUBLE_TAP_MS;
|
|
867
|
+
lastPressRef.current = now;
|
|
868
|
+
if (isDouble && !item.isExpandable && onRequestInlineEdit) {
|
|
869
|
+
onRequestInlineEdit(item);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
onSelect(item);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (item.isExpandable) {
|
|
876
|
+
onToggleExpanded(item.id);
|
|
877
|
+
}
|
|
878
|
+
onSelect(item);
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
/** The chevron always toggles, in both modes. */
|
|
882
|
+
const handleExpanderPress = () => {
|
|
745
883
|
if (item.isExpandable) {
|
|
746
884
|
onToggleExpanded(item.id);
|
|
747
885
|
}
|
|
748
|
-
onSelect(
|
|
886
|
+
onSelect(item);
|
|
749
887
|
};
|
|
750
888
|
const handleKeyPress = () => {};
|
|
751
889
|
|
|
@@ -762,11 +900,16 @@ const VirtualizedItemComponent = ({
|
|
|
762
900
|
onPress: handlePress,
|
|
763
901
|
onPressIn: () => setIsPressed(true),
|
|
764
902
|
onPressOut: () => setIsPressed(false),
|
|
765
|
-
activeOpacity: item.isExpandable ? 0.7 : 1
|
|
766
|
-
|
|
903
|
+
activeOpacity: item.isExpandable || canEdit ? 0.7 : 1
|
|
904
|
+
// A leaf row has nothing to expand, so it was left unpressable. In
|
|
905
|
+
// editable mode the press IS the selection that reveals this row's
|
|
906
|
+
// actions, so scalars — the ones you most want to edit — have to be
|
|
907
|
+
// pressable too.
|
|
908
|
+
,
|
|
909
|
+
disabled: !item.isExpandable && !canEdit,
|
|
767
910
|
children: [item.isExpandable ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Expander, {
|
|
768
911
|
expanded: item.isExpanded,
|
|
769
|
-
onPress:
|
|
912
|
+
onPress: handleExpanderPress
|
|
770
913
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
771
914
|
style: STABLE_STYLES.expanderContainer
|
|
772
915
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -775,7 +918,7 @@ const VirtualizedItemComponent = ({
|
|
|
775
918
|
style: STABLE_STYLES.labelText,
|
|
776
919
|
numberOfLines: 1,
|
|
777
920
|
children: [item.key, ":"]
|
|
778
|
-
}), item.isExpandable ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
921
|
+
}), isInlineEditing && inlineEditor ? inlineEditor : item.isExpandable ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
779
922
|
style: [STABLE_STYLES.valueText, {
|
|
780
923
|
color: _index.gameUIColors.secondary
|
|
781
924
|
}],
|
|
@@ -812,13 +955,19 @@ const VirtualizedDataExplorer = ({
|
|
|
812
955
|
rawMode = false,
|
|
813
956
|
initialExpanded = false,
|
|
814
957
|
// disableCopy is accepted for API compatibility but CopyButton handles Pro gating internally
|
|
815
|
-
disableCopy: _disableCopy = false
|
|
958
|
+
disableCopy: _disableCopy = false,
|
|
959
|
+
onSelectionChange,
|
|
960
|
+
onRequestInlineEdit,
|
|
961
|
+
inlineEditPath,
|
|
962
|
+
renderInlineEditor,
|
|
963
|
+
selectPath
|
|
816
964
|
}) => {
|
|
817
965
|
const [isExpanded, setIsExpanded] = (0, _react.useState)(rawMode); // Auto-expand in raw mode
|
|
818
966
|
const {
|
|
819
967
|
flatData,
|
|
820
968
|
isProcessing,
|
|
821
|
-
toggleExpanded
|
|
969
|
+
toggleExpanded,
|
|
970
|
+
revealPath
|
|
822
971
|
} = useDataFlattening(data, maxDepth, initialExpanded);
|
|
823
972
|
|
|
824
973
|
// Track visible range for overlay rendering
|
|
@@ -867,8 +1016,54 @@ const VirtualizedDataExplorer = ({
|
|
|
867
1016
|
};
|
|
868
1017
|
|
|
869
1018
|
// Stable renderItem using module-scope function [[memory:4875251]]
|
|
870
|
-
|
|
871
|
-
|
|
1019
|
+
/**
|
|
1020
|
+
* Selection is tracked by the row's stable id (its path), NOT its index.
|
|
1021
|
+
*
|
|
1022
|
+
* An edit reshapes the list — removing item 1 slides everything up — so an
|
|
1023
|
+
* index-based selection would silently start pointing at a different node
|
|
1024
|
+
* and the action bar would operate on the wrong one. An id survives that, and
|
|
1025
|
+
* resolves to nothing when the node it named is gone.
|
|
1026
|
+
*/
|
|
1027
|
+
const [selectedId, setSelectedId] = (0, _react.useState)(null);
|
|
1028
|
+
const selectedItem = (0, _react.useMemo)(() => selectedId == null ? undefined : flatData.find(it => it.id === selectedId), [flatData, selectedId]);
|
|
1029
|
+
const activeDepth = selectedItem?.depth;
|
|
1030
|
+
|
|
1031
|
+
// Report the selection outward, re-emitting after each data change so the
|
|
1032
|
+
// action bar is looking at the CURRENT value of the node it has selected.
|
|
1033
|
+
(0, _react.useEffect)(() => {
|
|
1034
|
+
if (!onSelectionChange) return;
|
|
1035
|
+
onSelectionChange(selectedItem ? selectionOf(selectedItem) : null);
|
|
1036
|
+
}, [selectedItem, onSelectionChange]);
|
|
1037
|
+
|
|
1038
|
+
/** Tapping the selected row again clears it, so the bar can be dismissed. */
|
|
1039
|
+
const handleSelect = (0, _react.useCallback)(item => {
|
|
1040
|
+
setSelectedId(prev => prev === item.id ? null : item.id);
|
|
1041
|
+
}, []);
|
|
1042
|
+
|
|
1043
|
+
// Re-sync when the host relocates the selection. Keyed on the joined path so
|
|
1044
|
+
// an unchanged array identity (a fresh render) doesn't clobber a user's tap.
|
|
1045
|
+
const selectPathKey = selectPath === undefined ? undefined : selectPath === null ? "\u0000null" : selectPath.join(".");
|
|
1046
|
+
const lastSelectPathKey = (0, _react.useRef)(selectPathKey);
|
|
1047
|
+
(0, _react.useEffect)(() => {
|
|
1048
|
+
if (selectPathKey === lastSelectPathKey.current) return;
|
|
1049
|
+
lastSelectPathKey.current = selectPathKey;
|
|
1050
|
+
if (selectPathKey === undefined) return;
|
|
1051
|
+
if (selectPath == null) {
|
|
1052
|
+
setSelectedId(null);
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
// Reveal it first — a selection the user can't see reads as a no-op.
|
|
1056
|
+
const ancestors = ["root"];
|
|
1057
|
+
for (const segment of selectPath.slice(0, -1)) {
|
|
1058
|
+
ancestors.push(`${ancestors[ancestors.length - 1]}.${segment}`);
|
|
1059
|
+
}
|
|
1060
|
+
revealPath(ancestors);
|
|
1061
|
+
setSelectedId(["root", ...selectPath].join("."));
|
|
1062
|
+
}, [selectPathKey, selectPath, revealPath]);
|
|
1063
|
+
const handleRequestInlineEdit = (0, _react.useCallback)(item => {
|
|
1064
|
+
setSelectedId(item.id);
|
|
1065
|
+
onRequestInlineEdit?.(selectionOf(item));
|
|
1066
|
+
}, [onRequestInlineEdit]);
|
|
872
1067
|
const renderItem = ({
|
|
873
1068
|
item,
|
|
874
1069
|
index
|
|
@@ -876,8 +1071,12 @@ const VirtualizedDataExplorer = ({
|
|
|
876
1071
|
item: item,
|
|
877
1072
|
index: index,
|
|
878
1073
|
onToggleExpanded: toggleExpanded,
|
|
879
|
-
onSelect:
|
|
880
|
-
isSelected:
|
|
1074
|
+
onSelect: handleSelect,
|
|
1075
|
+
isSelected: selectedItem?.id === item.id,
|
|
1076
|
+
selectable: onSelectionChange != null,
|
|
1077
|
+
onRequestInlineEdit: handleRequestInlineEdit,
|
|
1078
|
+
isInlineEditing: inlineEditPath != null && inlineEditPath.join(".") === item.path.slice(1).join("."),
|
|
1079
|
+
inlineEditor: renderInlineEditor ? renderInlineEditor(selectionOf(item)) : null
|
|
881
1080
|
});
|
|
882
1081
|
|
|
883
1082
|
// Uniform row height for crisp guide geometry
|
|
@@ -3,12 +3,36 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "ABSENT_VALUE", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _lineDiff.ABSENT_VALUE;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
6
12
|
Object.defineProperty(exports, "CyberpunkInput", {
|
|
7
13
|
enumerable: true,
|
|
8
14
|
get: function () {
|
|
9
15
|
return _CyberpunkInput.CyberpunkInput;
|
|
10
16
|
}
|
|
11
17
|
});
|
|
18
|
+
Object.defineProperty(exports, "DataTreeActionBar", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _DataTreeActionBar.DataTreeActionBar;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "DataTreeActionDock", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _DataTreeActionDock.DataTreeActionDock;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "DataTreeInlineEditor", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _DataTreeActionBar.DataTreeInlineEditor;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
12
36
|
Object.defineProperty(exports, "DataViewer", {
|
|
13
37
|
enumerable: true,
|
|
14
38
|
get: function () {
|
|
@@ -63,6 +87,18 @@ Object.defineProperty(exports, "VirtualizedDataExplorer", {
|
|
|
63
87
|
return _VirtualizedDataExplorer.VirtualizedDataExplorer;
|
|
64
88
|
}
|
|
65
89
|
});
|
|
90
|
+
Object.defineProperty(exports, "applyJsonOp", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
get: function () {
|
|
93
|
+
return _jsonOps.applyJsonOp;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
Object.defineProperty(exports, "breadcrumb", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
get: function () {
|
|
99
|
+
return _treeActions.breadcrumb;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
66
102
|
Object.defineProperty(exports, "computeLineDiff", {
|
|
67
103
|
enumerable: true,
|
|
68
104
|
get: function () {
|
|
@@ -81,12 +117,60 @@ Object.defineProperty(exports, "diffThemes", {
|
|
|
81
117
|
return _diffThemes.diffThemes;
|
|
82
118
|
}
|
|
83
119
|
});
|
|
120
|
+
Object.defineProperty(exports, "getAtPath", {
|
|
121
|
+
enumerable: true,
|
|
122
|
+
get: function () {
|
|
123
|
+
return _jsonOps.getAtPath;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
84
126
|
Object.defineProperty(exports, "gitClassicTheme", {
|
|
85
127
|
enumerable: true,
|
|
86
128
|
get: function () {
|
|
87
129
|
return _diffThemes.gitClassicTheme;
|
|
88
130
|
}
|
|
89
131
|
});
|
|
132
|
+
Object.defineProperty(exports, "isAbsent", {
|
|
133
|
+
enumerable: true,
|
|
134
|
+
get: function () {
|
|
135
|
+
return _lineDiff.isAbsent;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
Object.defineProperty(exports, "isEditableContainer", {
|
|
139
|
+
enumerable: true,
|
|
140
|
+
get: function () {
|
|
141
|
+
return _jsonOps.isEditableContainer;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
Object.defineProperty(exports, "selectionPathAfterOp", {
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get: function () {
|
|
147
|
+
return _jsonOps.selectionPathAfterOp;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
Object.defineProperty(exports, "suggestedNewValue", {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function () {
|
|
153
|
+
return _jsonOps.suggestedNewValue;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
Object.defineProperty(exports, "treeActionMap", {
|
|
157
|
+
enumerable: true,
|
|
158
|
+
get: function () {
|
|
159
|
+
return _treeActions.treeActionMap;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
Object.defineProperty(exports, "treeActionsFor", {
|
|
163
|
+
enumerable: true,
|
|
164
|
+
get: function () {
|
|
165
|
+
return _treeActions.treeActionsFor;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
Object.defineProperty(exports, "typeLabel", {
|
|
169
|
+
enumerable: true,
|
|
170
|
+
get: function () {
|
|
171
|
+
return _treeActions.typeLabel;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
90
174
|
var _DataViewer = require("./DataViewer.js");
|
|
91
175
|
var _VirtualizedDataExplorer = require("./VirtualizedDataExplorer.js");
|
|
92
176
|
var _TypeLegend = require("./TypeLegend.js");
|
|
@@ -94,6 +178,10 @@ var _CyberpunkInput = require("./CyberpunkInput.js");
|
|
|
94
178
|
var _IndentGuides = require("./IndentGuides.js");
|
|
95
179
|
var _IndentGuidesOverlay = require("./IndentGuidesOverlay.js");
|
|
96
180
|
var _TreeDiffViewer = _interopRequireDefault(require("./tree/TreeDiffViewer.js"));
|
|
181
|
+
var _jsonOps = require("./jsonOps.js");
|
|
182
|
+
var _treeActions = require("./treeActions.js");
|
|
183
|
+
var _DataTreeActionBar = require("./DataTreeActionBar.js");
|
|
184
|
+
var _DataTreeActionDock = require("./DataTreeActionDock.js");
|
|
97
185
|
var _SplitDiffViewer = require("./SplitDiffViewer.js");
|
|
98
186
|
var _DiffSummary = require("./DiffSummary.js");
|
|
99
187
|
var _lineDiff = require("./lineDiff.js");
|